s3: add Darwin sendfile support and merge with the FreeBSD code
[Samba/id10ts.git] / libcli / auth / schannel_sign.c
blobebd8f1c2688d85fc34d2b4407585a1f27205c6b9
1 /*
2 Unix SMB/CIFS implementation.
4 schannel library code
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2005
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 3 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "includes.h"
24 #include "../libcli/auth/schannel.h"
25 #include "../lib/crypto/crypto.h"
27 static void netsec_offset_and_sizes(struct schannel_state *state,
28 bool do_seal,
29 uint32_t *_min_sig_size,
30 uint32_t *_used_sig_size,
31 uint32_t *_checksum_length,
32 uint32_t *_confounder_ofs)
34 uint32_t min_sig_size;
35 uint32_t used_sig_size;
36 uint32_t checksum_length;
37 uint32_t confounder_ofs;
39 if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
40 min_sig_size = 48;
41 used_sig_size = 56;
43 * Note: windows has a bug here and uses the old values...
45 * checksum_length = 32;
46 * confounder_ofs = 48;
48 checksum_length = 8;
49 confounder_ofs = 24;
50 } else {
51 min_sig_size = 24;
52 used_sig_size = 32;
53 checksum_length = 8;
54 confounder_ofs = 24;
57 if (do_seal) {
58 min_sig_size += 8;
61 if (_min_sig_size) {
62 *_min_sig_size = min_sig_size;
65 if (_used_sig_size) {
66 *_used_sig_size = used_sig_size;
69 if (_checksum_length) {
70 *_checksum_length = checksum_length;
73 if (_confounder_ofs) {
74 *_confounder_ofs = confounder_ofs;
78 /*******************************************************************
79 Encode or Decode the sequence number (which is symmetric)
80 ********************************************************************/
81 static void netsec_do_seq_num(struct schannel_state *state,
82 const uint8_t *checksum,
83 uint32_t checksum_length,
84 uint8_t seq_num[8])
86 if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
87 AES_KEY key;
88 uint8_t iv[AES_BLOCK_SIZE];
90 AES_set_encrypt_key(state->creds->session_key, 128, &key);
91 ZERO_STRUCT(iv);
92 memcpy(iv+0, checksum, 8);
93 memcpy(iv+8, checksum, 8);
95 aes_cfb8_encrypt(seq_num, seq_num, 8, &key, iv, AES_ENCRYPT);
96 } else {
97 static const uint8_t zeros[4];
98 uint8_t sequence_key[16];
99 uint8_t digest1[16];
101 hmac_md5(state->creds->session_key, zeros, sizeof(zeros), digest1);
102 hmac_md5(digest1, checksum, checksum_length, sequence_key);
103 arcfour_crypt(seq_num, sequence_key, 8);
106 state->seq_num++;
109 static void netsec_do_seal(struct schannel_state *state,
110 const uint8_t seq_num[8],
111 uint8_t confounder[8],
112 uint8_t *data, uint32_t length,
113 bool forward)
115 if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
116 AES_KEY key;
117 uint8_t iv[AES_BLOCK_SIZE];
118 uint8_t sess_kf0[16];
119 int i;
121 for (i = 0; i < 16; i++) {
122 sess_kf0[i] = state->creds->session_key[i] ^ 0xf0;
125 AES_set_encrypt_key(sess_kf0, 128, &key);
126 ZERO_STRUCT(iv);
127 memcpy(iv+0, seq_num, 8);
128 memcpy(iv+8, seq_num, 8);
130 if (forward) {
131 aes_cfb8_encrypt(confounder, confounder, 8, &key, iv, AES_ENCRYPT);
132 aes_cfb8_encrypt(data, data, length, &key, iv, AES_ENCRYPT);
133 } else {
134 aes_cfb8_encrypt(confounder, confounder, 8, &key, iv, AES_DECRYPT);
135 aes_cfb8_encrypt(data, data, length, &key, iv, AES_DECRYPT);
137 } else {
138 uint8_t sealing_key[16];
139 static const uint8_t zeros[4];
140 uint8_t digest2[16];
141 uint8_t sess_kf0[16];
142 int i;
144 for (i = 0; i < 16; i++) {
145 sess_kf0[i] = state->creds->session_key[i] ^ 0xf0;
148 hmac_md5(sess_kf0, zeros, 4, digest2);
149 hmac_md5(digest2, seq_num, 8, sealing_key);
151 arcfour_crypt(confounder, sealing_key, 8);
152 arcfour_crypt(data, sealing_key, length);
156 /*******************************************************************
157 Create a digest over the entire packet (including the data), and
158 MD5 it with the session key.
159 ********************************************************************/
160 static void netsec_do_sign(struct schannel_state *state,
161 const uint8_t *confounder,
162 const uint8_t *data, size_t length,
163 uint8_t header[8],
164 uint8_t *checksum)
166 if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
167 struct HMACSHA256Context ctx;
169 hmac_sha256_init(state->creds->session_key,
170 sizeof(state->creds->session_key),
171 &ctx);
173 if (confounder) {
174 SSVAL(header, 0, NL_SIGN_HMAC_SHA256);
175 SSVAL(header, 2, NL_SEAL_AES128);
176 SSVAL(header, 4, 0xFFFF);
177 SSVAL(header, 6, 0x0000);
179 hmac_sha256_update(header, 8, &ctx);
180 hmac_sha256_update(confounder, 8, &ctx);
181 } else {
182 SSVAL(header, 0, NL_SIGN_HMAC_SHA256);
183 SSVAL(header, 2, NL_SEAL_NONE);
184 SSVAL(header, 4, 0xFFFF);
185 SSVAL(header, 6, 0x0000);
187 hmac_sha256_update(header, 8, &ctx);
190 hmac_sha256_update(data, length, &ctx);
192 hmac_sha256_final(checksum, &ctx);
193 } else {
194 uint8_t packet_digest[16];
195 static const uint8_t zeros[4];
196 struct MD5Context ctx;
198 MD5Init(&ctx);
199 MD5Update(&ctx, zeros, 4);
200 if (confounder) {
201 SSVAL(header, 0, NL_SIGN_HMAC_MD5);
202 SSVAL(header, 2, NL_SEAL_RC4);
203 SSVAL(header, 4, 0xFFFF);
204 SSVAL(header, 6, 0x0000);
206 MD5Update(&ctx, header, 8);
207 MD5Update(&ctx, confounder, 8);
208 } else {
209 SSVAL(header, 0, NL_SIGN_HMAC_MD5);
210 SSVAL(header, 2, NL_SEAL_NONE);
211 SSVAL(header, 4, 0xFFFF);
212 SSVAL(header, 6, 0x0000);
214 MD5Update(&ctx, header, 8);
216 MD5Update(&ctx, data, length);
217 MD5Final(packet_digest, &ctx);
219 hmac_md5(state->creds->session_key,
220 packet_digest, sizeof(packet_digest),
221 checksum);
225 NTSTATUS netsec_incoming_packet(struct schannel_state *state,
226 bool do_unseal,
227 uint8_t *data, size_t length,
228 const DATA_BLOB *sig)
230 uint32_t min_sig_size = 0;
231 uint8_t header[8];
232 uint8_t checksum[32];
233 uint32_t checksum_length = sizeof(checksum_length);
234 uint8_t _confounder[8];
235 uint8_t *confounder = NULL;
236 uint32_t confounder_ofs = 0;
237 uint8_t seq_num[8];
238 int ret;
240 netsec_offset_and_sizes(state,
241 do_unseal,
242 &min_sig_size,
243 NULL,
244 &checksum_length,
245 &confounder_ofs);
247 if (sig->length < min_sig_size) {
248 return NT_STATUS_ACCESS_DENIED;
251 if (do_unseal) {
252 confounder = _confounder;
253 memcpy(confounder, sig->data+confounder_ofs, 8);
254 } else {
255 confounder = NULL;
258 RSIVAL(seq_num, 0, state->seq_num);
259 SIVAL(seq_num, 4, state->initiator?0:0x80);
261 if (do_unseal) {
262 netsec_do_seal(state, seq_num,
263 confounder,
264 data, length,
265 false);
268 netsec_do_sign(state, confounder,
269 data, length,
270 header, checksum);
272 ret = memcmp(checksum, sig->data+16, checksum_length);
273 if (ret != 0) {
274 dump_data_pw("calc digest:", checksum, checksum_length);
275 dump_data_pw("wire digest:", sig->data+16, checksum_length);
276 return NT_STATUS_ACCESS_DENIED;
279 netsec_do_seq_num(state, checksum, checksum_length, seq_num);
281 ret = memcmp(seq_num, sig->data+8, 8);
282 if (ret != 0) {
283 dump_data_pw("calc seq num:", seq_num, 8);
284 dump_data_pw("wire seq num:", sig->data+8, 8);
285 return NT_STATUS_ACCESS_DENIED;
288 return NT_STATUS_OK;
291 uint32_t netsec_outgoing_sig_size(struct schannel_state *state)
293 uint32_t sig_size = 0;
295 netsec_offset_and_sizes(state,
296 true,
297 NULL,
298 &sig_size,
299 NULL,
300 NULL);
302 return sig_size;
305 NTSTATUS netsec_outgoing_packet(struct schannel_state *state,
306 TALLOC_CTX *mem_ctx,
307 bool do_seal,
308 uint8_t *data, size_t length,
309 DATA_BLOB *sig)
311 uint32_t min_sig_size = 0;
312 uint32_t used_sig_size = 0;
313 uint8_t header[8];
314 uint8_t checksum[32];
315 uint32_t checksum_length = sizeof(checksum_length);
316 uint8_t _confounder[8];
317 uint8_t *confounder = NULL;
318 uint32_t confounder_ofs = 0;
319 uint8_t seq_num[8];
321 netsec_offset_and_sizes(state,
322 do_seal,
323 &min_sig_size,
324 &used_sig_size,
325 &checksum_length,
326 &confounder_ofs);
328 RSIVAL(seq_num, 0, state->seq_num);
329 SIVAL(seq_num, 4, state->initiator?0x80:0);
331 if (do_seal) {
332 confounder = _confounder;
333 generate_random_buffer(confounder, 8);
334 } else {
335 confounder = NULL;
338 netsec_do_sign(state, confounder,
339 data, length,
340 header, checksum);
342 if (do_seal) {
343 netsec_do_seal(state, seq_num,
344 confounder,
345 data, length,
346 true);
349 netsec_do_seq_num(state, checksum, checksum_length, seq_num);
351 (*sig) = data_blob_talloc_zero(mem_ctx, used_sig_size);
353 memcpy(sig->data, header, 8);
354 memcpy(sig->data+8, seq_num, 8);
355 memcpy(sig->data+16, checksum, checksum_length);
357 if (confounder) {
358 memcpy(sig->data+confounder_ofs, confounder, 8);
361 dump_data_pw("signature:", sig->data+ 0, 8);
362 dump_data_pw("seq_num :", sig->data+ 8, 8);
363 dump_data_pw("digest :", sig->data+16, checksum_length);
364 dump_data_pw("confound :", sig->data+confounder_ofs, 8);
366 return NT_STATUS_OK;