2 Unix SMB/CIFS implementation.
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/>.
24 #include "../libcli/auth/schannel.h"
25 #include "../lib/crypto/crypto.h"
27 struct schannel_state
{
30 struct netlogon_creds_CredentialState
*creds
;
33 #define SETUP_SEQNUM(state, buf, initiator) do { \
34 uint8_t *_buf = buf; \
35 uint32_t _seq_num_low = (state)->seq_num & UINT32_MAX; \
36 uint32_t _seq_num_high = (state)->seq_num >> 32; \
38 _seq_num_high |= 0x80000000; \
40 RSIVAL(_buf, 0, _seq_num_low); \
41 RSIVAL(_buf, 4, _seq_num_high); \
44 struct schannel_state
*netsec_create_state(TALLOC_CTX
*mem_ctx
,
45 struct netlogon_creds_CredentialState
*creds
,
48 struct schannel_state
*state
;
50 state
= talloc(mem_ctx
, struct schannel_state
);
55 state
->initiator
= initiator
;
57 state
->creds
= netlogon_creds_copy(state
, creds
);
58 if (state
->creds
== NULL
) {
66 static void netsec_offset_and_sizes(struct schannel_state
*state
,
68 uint32_t *_min_sig_size
,
69 uint32_t *_used_sig_size
,
70 uint32_t *_checksum_length
,
71 uint32_t *_confounder_ofs
)
73 uint32_t min_sig_size
;
74 uint32_t used_sig_size
;
75 uint32_t checksum_length
;
76 uint32_t confounder_ofs
;
78 if (state
->creds
->negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
82 * Note: windows has a bug here and uses the old values...
84 * checksum_length = 32;
85 * confounder_ofs = 48;
101 *_min_sig_size
= min_sig_size
;
104 if (_used_sig_size
) {
105 *_used_sig_size
= used_sig_size
;
108 if (_checksum_length
) {
109 *_checksum_length
= checksum_length
;
112 if (_confounder_ofs
) {
113 *_confounder_ofs
= confounder_ofs
;
117 /*******************************************************************
118 Encode or Decode the sequence number (which is symmetric)
119 ********************************************************************/
120 static void netsec_do_seq_num(struct schannel_state
*state
,
121 const uint8_t *checksum
,
122 uint32_t checksum_length
,
125 if (state
->creds
->negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
127 uint8_t iv
[AES_BLOCK_SIZE
];
129 AES_set_encrypt_key(state
->creds
->session_key
, 128, &key
);
131 memcpy(iv
+0, checksum
, 8);
132 memcpy(iv
+8, checksum
, 8);
134 aes_cfb8_encrypt(seq_num
, seq_num
, 8, &key
, iv
, AES_ENCRYPT
);
136 static const uint8_t zeros
[4];
137 uint8_t sequence_key
[16];
140 hmac_md5(state
->creds
->session_key
, zeros
, sizeof(zeros
), digest1
);
141 hmac_md5(digest1
, checksum
, checksum_length
, sequence_key
);
142 arcfour_crypt(seq_num
, sequence_key
, 8);
148 static void netsec_do_seal(struct schannel_state
*state
,
149 const uint8_t seq_num
[8],
150 uint8_t confounder
[8],
151 uint8_t *data
, uint32_t length
,
154 if (state
->creds
->negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
156 uint8_t iv
[AES_BLOCK_SIZE
];
157 uint8_t sess_kf0
[16];
160 for (i
= 0; i
< 16; i
++) {
161 sess_kf0
[i
] = state
->creds
->session_key
[i
] ^ 0xf0;
164 AES_set_encrypt_key(sess_kf0
, 128, &key
);
166 memcpy(iv
+0, seq_num
, 8);
167 memcpy(iv
+8, seq_num
, 8);
170 aes_cfb8_encrypt(confounder
, confounder
, 8, &key
, iv
, AES_ENCRYPT
);
171 aes_cfb8_encrypt(data
, data
, length
, &key
, iv
, AES_ENCRYPT
);
173 aes_cfb8_encrypt(confounder
, confounder
, 8, &key
, iv
, AES_DECRYPT
);
174 aes_cfb8_encrypt(data
, data
, length
, &key
, iv
, AES_DECRYPT
);
177 uint8_t sealing_key
[16];
178 static const uint8_t zeros
[4];
180 uint8_t sess_kf0
[16];
183 for (i
= 0; i
< 16; i
++) {
184 sess_kf0
[i
] = state
->creds
->session_key
[i
] ^ 0xf0;
187 hmac_md5(sess_kf0
, zeros
, 4, digest2
);
188 hmac_md5(digest2
, seq_num
, 8, sealing_key
);
190 arcfour_crypt(confounder
, sealing_key
, 8);
191 arcfour_crypt(data
, sealing_key
, length
);
195 /*******************************************************************
196 Create a digest over the entire packet (including the data), and
197 MD5 it with the session key.
198 ********************************************************************/
199 static void netsec_do_sign(struct schannel_state
*state
,
200 const uint8_t *confounder
,
201 const uint8_t *data
, size_t length
,
205 if (state
->creds
->negotiate_flags
& NETLOGON_NEG_SUPPORTS_AES
) {
206 struct HMACSHA256Context ctx
;
208 hmac_sha256_init(state
->creds
->session_key
,
209 sizeof(state
->creds
->session_key
),
213 SSVAL(header
, 0, NL_SIGN_HMAC_SHA256
);
214 SSVAL(header
, 2, NL_SEAL_AES128
);
215 SSVAL(header
, 4, 0xFFFF);
216 SSVAL(header
, 6, 0x0000);
218 hmac_sha256_update(header
, 8, &ctx
);
219 hmac_sha256_update(confounder
, 8, &ctx
);
221 SSVAL(header
, 0, NL_SIGN_HMAC_SHA256
);
222 SSVAL(header
, 2, NL_SEAL_NONE
);
223 SSVAL(header
, 4, 0xFFFF);
224 SSVAL(header
, 6, 0x0000);
226 hmac_sha256_update(header
, 8, &ctx
);
229 hmac_sha256_update(data
, length
, &ctx
);
231 hmac_sha256_final(checksum
, &ctx
);
233 uint8_t packet_digest
[16];
234 static const uint8_t zeros
[4];
238 MD5Update(&ctx
, zeros
, 4);
240 SSVAL(header
, 0, NL_SIGN_HMAC_MD5
);
241 SSVAL(header
, 2, NL_SEAL_RC4
);
242 SSVAL(header
, 4, 0xFFFF);
243 SSVAL(header
, 6, 0x0000);
245 MD5Update(&ctx
, header
, 8);
246 MD5Update(&ctx
, confounder
, 8);
248 SSVAL(header
, 0, NL_SIGN_HMAC_MD5
);
249 SSVAL(header
, 2, NL_SEAL_NONE
);
250 SSVAL(header
, 4, 0xFFFF);
251 SSVAL(header
, 6, 0x0000);
253 MD5Update(&ctx
, header
, 8);
255 MD5Update(&ctx
, data
, length
);
256 MD5Final(packet_digest
, &ctx
);
258 hmac_md5(state
->creds
->session_key
,
259 packet_digest
, sizeof(packet_digest
),
264 NTSTATUS
netsec_incoming_packet(struct schannel_state
*state
,
266 uint8_t *data
, size_t length
,
267 const DATA_BLOB
*sig
)
269 uint32_t min_sig_size
= 0;
271 uint8_t checksum
[32];
272 uint32_t checksum_length
= sizeof(checksum_length
);
273 uint8_t _confounder
[8];
274 uint8_t *confounder
= NULL
;
275 uint32_t confounder_ofs
= 0;
279 netsec_offset_and_sizes(state
,
286 if (sig
->length
< min_sig_size
) {
287 return NT_STATUS_ACCESS_DENIED
;
291 confounder
= _confounder
;
292 memcpy(confounder
, sig
->data
+confounder_ofs
, 8);
297 SETUP_SEQNUM(state
, seq_num
, !state
->initiator
);
300 netsec_do_seal(state
, seq_num
,
306 netsec_do_sign(state
, confounder
,
310 ret
= memcmp(checksum
, sig
->data
+16, checksum_length
);
312 dump_data_pw("calc digest:", checksum
, checksum_length
);
313 dump_data_pw("wire digest:", sig
->data
+16, checksum_length
);
314 return NT_STATUS_ACCESS_DENIED
;
317 netsec_do_seq_num(state
, checksum
, checksum_length
, seq_num
);
319 ret
= memcmp(seq_num
, sig
->data
+8, 8);
321 dump_data_pw("calc seq num:", seq_num
, 8);
322 dump_data_pw("wire seq num:", sig
->data
+8, 8);
323 return NT_STATUS_ACCESS_DENIED
;
329 uint32_t netsec_outgoing_sig_size(struct schannel_state
*state
)
331 uint32_t sig_size
= 0;
333 netsec_offset_and_sizes(state
,
343 NTSTATUS
netsec_outgoing_packet(struct schannel_state
*state
,
346 uint8_t *data
, size_t length
,
349 uint32_t min_sig_size
= 0;
350 uint32_t used_sig_size
= 0;
352 uint8_t checksum
[32];
353 uint32_t checksum_length
= sizeof(checksum_length
);
354 uint8_t _confounder
[8];
355 uint8_t *confounder
= NULL
;
356 uint32_t confounder_ofs
= 0;
359 netsec_offset_and_sizes(state
,
366 SETUP_SEQNUM(state
, seq_num
, state
->initiator
);
369 confounder
= _confounder
;
370 generate_random_buffer(confounder
, 8);
375 netsec_do_sign(state
, confounder
,
380 netsec_do_seal(state
, seq_num
,
386 netsec_do_seq_num(state
, checksum
, checksum_length
, seq_num
);
388 (*sig
) = data_blob_talloc_zero(mem_ctx
, used_sig_size
);
390 memcpy(sig
->data
, header
, 8);
391 memcpy(sig
->data
+8, seq_num
, 8);
392 memcpy(sig
->data
+16, checksum
, checksum_length
);
395 memcpy(sig
->data
+confounder_ofs
, confounder
, 8);
398 dump_data_pw("signature:", sig
->data
+ 0, 8);
399 dump_data_pw("seq_num :", sig
->data
+ 8, 8);
400 dump_data_pw("digest :", sig
->data
+16, checksum_length
);
401 dump_data_pw("confound :", sig
->data
+confounder_ofs
, 8);