vfs_io_uring: make use of sys_valid_io_range() in vfs_io_uring_pwrite_send()
[Samba.git] / auth / gensec / schannel.c
blob0cdae141ead1767b9cbeee41c4e8da83315f8652
1 /*
2 Unix SMB/CIFS implementation.
4 dcerpc schannel operations
6 Copyright (C) Andrew Tridgell 2004
7 Copyright (C) Andrew Bartlett <abartlet@samba.org> 2004-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 <tevent.h>
25 #include "lib/util/tevent_ntstatus.h"
26 #include "librpc/gen_ndr/ndr_schannel.h"
27 #include "auth/auth.h"
28 #include "auth/credentials/credentials.h"
29 #include "auth/gensec/gensec.h"
30 #include "auth/gensec/gensec_internal.h"
31 #include "auth/gensec/gensec_proto.h"
32 #include "../libcli/auth/schannel.h"
33 #include "librpc/gen_ndr/dcerpc.h"
34 #include "param/param.h"
35 #include "auth/gensec/gensec_toplevel_proto.h"
36 #include "libds/common/roles.h"
38 #ifndef HAVE_GNUTLS_AES_CFB8
39 #include "lib/crypto/aes.h"
40 #endif
42 #include "lib/crypto/gnutls_helpers.h"
43 #include <gnutls/gnutls.h>
44 #include <gnutls/crypto.h>
46 #undef DBGC_CLASS
47 #define DBGC_CLASS DBGC_AUTH
49 struct schannel_state {
50 struct gensec_security *gensec;
51 uint64_t seq_num;
52 bool initiator;
53 struct netlogon_creds_CredentialState *creds;
54 struct auth_user_info_dc *user_info_dc;
57 #define SETUP_SEQNUM(state, buf, initiator) do { \
58 uint8_t *_buf = buf; \
59 uint32_t _seq_num_low = (state)->seq_num & UINT32_MAX; \
60 uint32_t _seq_num_high = (state)->seq_num >> 32; \
61 if (initiator) { \
62 _seq_num_high |= 0x80000000; \
63 } \
64 RSIVAL(_buf, 0, _seq_num_low); \
65 RSIVAL(_buf, 4, _seq_num_high); \
66 } while(0)
68 static struct schannel_state *netsec_create_state(
69 struct gensec_security *gensec,
70 struct netlogon_creds_CredentialState *creds,
71 bool initiator)
73 struct schannel_state *state;
75 state = talloc_zero(gensec, struct schannel_state);
76 if (state == NULL) {
77 return NULL;
80 state->gensec = gensec;
81 state->initiator = initiator;
82 state->creds = netlogon_creds_copy(state, creds);
83 if (state->creds == NULL) {
84 talloc_free(state);
85 return NULL;
88 gensec->private_data = state;
90 return state;
93 static void netsec_offset_and_sizes(struct schannel_state *state,
94 bool do_seal,
95 uint32_t *_min_sig_size,
96 uint32_t *_used_sig_size,
97 uint32_t *_checksum_length,
98 uint32_t *_confounder_ofs)
100 uint32_t min_sig_size;
101 uint32_t used_sig_size;
102 uint32_t checksum_length;
103 uint32_t confounder_ofs;
105 if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
106 min_sig_size = 48;
107 used_sig_size = 56;
109 * Note: windows has a bug here and uses the old values...
111 * checksum_length = 32;
112 * confounder_ofs = 48;
114 checksum_length = 8;
115 confounder_ofs = 24;
116 } else {
117 min_sig_size = 24;
118 used_sig_size = 32;
119 checksum_length = 8;
120 confounder_ofs = 24;
123 if (do_seal) {
124 min_sig_size += 8;
127 if (_min_sig_size) {
128 *_min_sig_size = min_sig_size;
131 if (_used_sig_size) {
132 *_used_sig_size = used_sig_size;
135 if (_checksum_length) {
136 *_checksum_length = checksum_length;
139 if (_confounder_ofs) {
140 *_confounder_ofs = confounder_ofs;
144 /*******************************************************************
145 Encode or Decode the sequence number (which is symmetric)
146 ********************************************************************/
147 static NTSTATUS netsec_do_seq_num(struct schannel_state *state,
148 const uint8_t *checksum,
149 uint32_t checksum_length,
150 uint8_t seq_num[8])
152 if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
153 #ifdef HAVE_GNUTLS_AES_CFB8
154 gnutls_cipher_hd_t cipher_hnd = NULL;
155 gnutls_datum_t key = {
156 .data = state->creds->session_key,
157 .size = sizeof(state->creds->session_key),
159 uint32_t iv_size =
160 gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
161 uint8_t _iv[iv_size];
162 gnutls_datum_t iv = {
163 .data = _iv,
164 .size = iv_size,
166 int rc;
168 ZERO_ARRAY(_iv);
170 memcpy(iv.data + 0, checksum, 8);
171 memcpy(iv.data + 8, checksum, 8);
173 rc = gnutls_cipher_init(&cipher_hnd,
174 GNUTLS_CIPHER_AES_128_CFB8,
175 &key,
176 &iv);
177 if (rc < 0) {
178 return gnutls_error_to_ntstatus(rc,
179 NT_STATUS_CRYPTO_SYSTEM_INVALID);
182 rc = gnutls_cipher_encrypt(cipher_hnd, seq_num, 8);
183 gnutls_cipher_deinit(cipher_hnd);
184 if (rc < 0) {
185 return gnutls_error_to_ntstatus(rc,
186 NT_STATUS_CRYPTO_SYSTEM_INVALID);
189 #else /* NOT HAVE_GNUTLS_AES_CFB8 */
190 AES_KEY key;
191 uint8_t iv[AES_BLOCK_SIZE];
193 AES_set_encrypt_key(state->creds->session_key, 128, &key);
194 ZERO_STRUCT(iv);
195 memcpy(iv+0, checksum, 8);
196 memcpy(iv+8, checksum, 8);
198 aes_cfb8_encrypt(seq_num, seq_num, 8, &key, iv, AES_ENCRYPT);
199 #endif /* HAVE_GNUTLS_AES_CFB8 */
200 } else {
201 static const uint8_t zeros[4];
202 uint8_t _sequence_key[16];
203 gnutls_cipher_hd_t cipher_hnd;
204 gnutls_datum_t sequence_key = {
205 .data = _sequence_key,
206 .size = sizeof(_sequence_key),
208 uint8_t digest1[16];
209 int rc;
211 rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
212 state->creds->session_key,
213 sizeof(state->creds->session_key),
214 zeros,
215 sizeof(zeros),
216 digest1);
217 if (rc < 0) {
218 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
221 rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
222 digest1,
223 sizeof(digest1),
224 checksum,
225 checksum_length,
226 _sequence_key);
227 if (rc < 0) {
228 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
231 ZERO_ARRAY(digest1);
233 rc = gnutls_cipher_init(&cipher_hnd,
234 GNUTLS_CIPHER_ARCFOUR_128,
235 &sequence_key,
236 NULL);
237 if (rc < 0) {
238 ZERO_ARRAY(_sequence_key);
239 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
242 rc = gnutls_cipher_encrypt(cipher_hnd,
243 seq_num,
245 gnutls_cipher_deinit(cipher_hnd);
246 ZERO_ARRAY(_sequence_key);
247 if (rc < 0) {
248 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
252 state->seq_num++;
254 return NT_STATUS_OK;
257 static NTSTATUS netsec_do_seal(struct schannel_state *state,
258 const uint8_t seq_num[8],
259 uint8_t confounder[8],
260 uint8_t *data, uint32_t length,
261 bool forward)
263 if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
264 #ifdef HAVE_GNUTLS_AES_CFB8
265 gnutls_cipher_hd_t cipher_hnd = NULL;
266 uint8_t sess_kf0[16] = {0};
267 gnutls_datum_t key = {
268 .data = sess_kf0,
269 .size = sizeof(sess_kf0),
271 uint32_t iv_size =
272 gnutls_cipher_get_iv_size(GNUTLS_CIPHER_AES_128_CFB8);
273 uint8_t _iv[iv_size];
274 gnutls_datum_t iv = {
275 .data = _iv,
276 .size = iv_size,
278 uint32_t i;
279 int rc;
281 for (i = 0; i < key.size; i++) {
282 key.data[i] = state->creds->session_key[i] ^ 0xf0;
285 ZERO_ARRAY(_iv);
287 memcpy(iv.data + 0, seq_num, 8);
288 memcpy(iv.data + 8, seq_num, 8);
290 rc = gnutls_cipher_init(&cipher_hnd,
291 GNUTLS_CIPHER_AES_128_CFB8,
292 &key,
293 &iv);
294 if (rc < 0) {
295 DBG_ERR("ERROR: gnutls_cipher_init: %s\n",
296 gnutls_strerror(rc));
297 return NT_STATUS_NO_MEMORY;
300 if (forward) {
301 rc = gnutls_cipher_encrypt(cipher_hnd,
302 confounder,
304 if (rc < 0) {
305 gnutls_cipher_deinit(cipher_hnd);
306 return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
309 rc = gnutls_cipher_encrypt(cipher_hnd,
310 data,
311 length);
312 if (rc < 0) {
313 gnutls_cipher_deinit(cipher_hnd);
314 return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
316 } else {
319 * Workaround bug present in gnutls 3.6.8:
321 * gnutls_cipher_decrypt() uses an optimization
322 * internally that breaks decryption when processing
323 * buffers with their length not being a multiple
324 * of the blocksize.
327 uint8_t tmp[16] = { 0, };
328 uint32_t tmp_dlength = MIN(length, sizeof(tmp) - 8);
330 memcpy(tmp, confounder, 8);
331 memcpy(tmp + 8, data, tmp_dlength);
333 rc = gnutls_cipher_decrypt(cipher_hnd,
334 tmp,
335 8 + tmp_dlength);
336 if (rc < 0) {
337 ZERO_STRUCT(tmp);
338 gnutls_cipher_deinit(cipher_hnd);
339 return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
342 memcpy(confounder, tmp, 8);
343 memcpy(data, tmp + 8, tmp_dlength);
344 ZERO_STRUCT(tmp);
346 if (length > tmp_dlength) {
347 rc = gnutls_cipher_decrypt(cipher_hnd,
348 data + tmp_dlength,
349 length - tmp_dlength);
350 if (rc < 0) {
351 gnutls_cipher_deinit(cipher_hnd);
352 return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
356 gnutls_cipher_deinit(cipher_hnd);
357 #else /* NOT HAVE_GNUTLS_AES_CFB8 */
358 AES_KEY key;
359 uint8_t iv[AES_BLOCK_SIZE];
360 uint8_t sess_kf0[16];
361 int i;
363 for (i = 0; i < 16; i++) {
364 sess_kf0[i] = state->creds->session_key[i] ^ 0xf0;
367 AES_set_encrypt_key(sess_kf0, 128, &key);
368 ZERO_STRUCT(iv);
369 memcpy(iv+0, seq_num, 8);
370 memcpy(iv+8, seq_num, 8);
372 if (forward) {
373 aes_cfb8_encrypt(confounder, confounder, 8, &key, iv, AES_ENCRYPT);
374 aes_cfb8_encrypt(data, data, length, &key, iv, AES_ENCRYPT);
375 } else {
376 aes_cfb8_encrypt(confounder, confounder, 8, &key, iv, AES_DECRYPT);
377 aes_cfb8_encrypt(data, data, length, &key, iv, AES_DECRYPT);
379 #endif /* HAVE_GNUTLS_AES_CFB8 */
380 } else {
381 gnutls_cipher_hd_t cipher_hnd;
382 uint8_t _sealing_key[16];
383 gnutls_datum_t sealing_key = {
384 .data = _sealing_key,
385 .size = sizeof(_sealing_key),
387 static const uint8_t zeros[4];
388 uint8_t digest2[16];
389 uint8_t sess_kf0[16];
390 int rc;
391 int i;
393 for (i = 0; i < 16; i++) {
394 sess_kf0[i] = state->creds->session_key[i] ^ 0xf0;
397 rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
398 sess_kf0,
399 sizeof(sess_kf0),
400 zeros,
402 digest2);
403 if (rc < 0) {
404 ZERO_ARRAY(digest2);
405 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
408 rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
409 digest2,
410 sizeof(digest2),
411 seq_num,
413 _sealing_key);
415 ZERO_ARRAY(digest2);
416 if (rc < 0) {
417 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
420 rc = gnutls_cipher_init(&cipher_hnd,
421 GNUTLS_CIPHER_ARCFOUR_128,
422 &sealing_key,
423 NULL);
424 if (rc < 0) {
425 ZERO_ARRAY(_sealing_key);
426 return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
428 rc = gnutls_cipher_encrypt(cipher_hnd,
429 confounder,
431 if (rc < 0) {
432 ZERO_ARRAY(_sealing_key);
433 return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
435 gnutls_cipher_deinit(cipher_hnd);
436 rc = gnutls_cipher_init(&cipher_hnd,
437 GNUTLS_CIPHER_ARCFOUR_128,
438 &sealing_key,
439 NULL);
440 if (rc < 0) {
441 ZERO_ARRAY(_sealing_key);
442 return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
444 rc = gnutls_cipher_encrypt(cipher_hnd,
445 data,
446 length);
447 gnutls_cipher_deinit(cipher_hnd);
448 ZERO_ARRAY(_sealing_key);
449 if (rc < 0) {
450 return gnutls_error_to_ntstatus(rc, NT_STATUS_CRYPTO_SYSTEM_INVALID);
454 return NT_STATUS_OK;
457 /*******************************************************************
458 Create a digest over the entire packet (including the data), and
459 MD5 it with the session key.
460 ********************************************************************/
461 static NTSTATUS netsec_do_sign(struct schannel_state *state,
462 const uint8_t *confounder,
463 const uint8_t *data, size_t length,
464 uint8_t header[8],
465 uint8_t *checksum)
467 if (state->creds->negotiate_flags & NETLOGON_NEG_SUPPORTS_AES) {
468 gnutls_hmac_hd_t hmac_hnd = NULL;
469 int rc;
471 rc = gnutls_hmac_init(&hmac_hnd,
472 GNUTLS_MAC_SHA256,
473 state->creds->session_key,
474 sizeof(state->creds->session_key));
475 if (rc < 0) {
476 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
479 if (confounder) {
480 SSVAL(header, 0, NL_SIGN_HMAC_SHA256);
481 SSVAL(header, 2, NL_SEAL_AES128);
482 SSVAL(header, 4, 0xFFFF);
483 SSVAL(header, 6, 0x0000);
485 rc = gnutls_hmac(hmac_hnd, header, 8);
486 if (rc < 0) {
487 gnutls_hmac_deinit(hmac_hnd, NULL);
488 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
490 rc = gnutls_hmac(hmac_hnd, confounder, 8);
491 if (rc < 0) {
492 gnutls_hmac_deinit(hmac_hnd, NULL);
493 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
495 } else {
496 SSVAL(header, 0, NL_SIGN_HMAC_SHA256);
497 SSVAL(header, 2, NL_SEAL_NONE);
498 SSVAL(header, 4, 0xFFFF);
499 SSVAL(header, 6, 0x0000);
501 rc = gnutls_hmac(hmac_hnd, header, 8);
502 if (rc < 0) {
503 gnutls_hmac_deinit(hmac_hnd, NULL);
504 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
508 rc = gnutls_hmac(hmac_hnd, data, length);
509 if (rc < 0) {
510 gnutls_hmac_deinit(hmac_hnd, NULL);
511 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
514 gnutls_hmac_deinit(hmac_hnd, checksum);
515 } else {
516 uint8_t packet_digest[16];
517 static const uint8_t zeros[4];
518 gnutls_hash_hd_t hash_hnd = NULL;
519 int rc;
521 rc = gnutls_hash_init(&hash_hnd, GNUTLS_DIG_MD5);
522 if (rc < 0) {
523 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
526 rc = gnutls_hash(hash_hnd, zeros, sizeof(zeros));
527 if (rc < 0) {
528 gnutls_hash_deinit(hash_hnd, NULL);
529 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
531 if (confounder) {
532 SSVAL(header, 0, NL_SIGN_HMAC_MD5);
533 SSVAL(header, 2, NL_SEAL_RC4);
534 SSVAL(header, 4, 0xFFFF);
535 SSVAL(header, 6, 0x0000);
537 rc = gnutls_hash(hash_hnd, header, 8);
538 if (rc < 0) {
539 gnutls_hash_deinit(hash_hnd, NULL);
540 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
542 rc = gnutls_hash(hash_hnd, confounder, 8);
543 if (rc < 0) {
544 gnutls_hash_deinit(hash_hnd, NULL);
545 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
547 } else {
548 SSVAL(header, 0, NL_SIGN_HMAC_MD5);
549 SSVAL(header, 2, NL_SEAL_NONE);
550 SSVAL(header, 4, 0xFFFF);
551 SSVAL(header, 6, 0x0000);
553 rc = gnutls_hash(hash_hnd, header, 8);
554 if (rc < 0) {
555 gnutls_hash_deinit(hash_hnd, NULL);
556 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
559 rc = gnutls_hash(hash_hnd, data, length);
560 if (rc < 0) {
561 gnutls_hash_deinit(hash_hnd, NULL);
562 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
564 gnutls_hash_deinit(hash_hnd, packet_digest);
566 rc = gnutls_hmac_fast(GNUTLS_MAC_MD5,
567 state->creds->session_key,
568 sizeof(state->creds->session_key),
569 packet_digest,
570 sizeof(packet_digest),
571 checksum);
572 ZERO_ARRAY(packet_digest);
573 if (rc < 0) {
574 return gnutls_error_to_ntstatus(rc, NT_STATUS_HMAC_NOT_SUPPORTED);
578 return NT_STATUS_OK;
581 static NTSTATUS netsec_incoming_packet(struct schannel_state *state,
582 bool do_unseal,
583 uint8_t *data, size_t length,
584 const uint8_t *whole_pdu, size_t pdu_length,
585 const DATA_BLOB *sig)
587 uint32_t min_sig_size = 0;
588 uint8_t header[8];
589 uint8_t checksum[32];
590 uint32_t checksum_length = sizeof(checksum_length);
591 uint8_t _confounder[8];
592 uint8_t *confounder = NULL;
593 uint32_t confounder_ofs = 0;
594 uint8_t seq_num[8];
595 int ret;
596 const uint8_t *sign_data = NULL;
597 size_t sign_length = 0;
598 NTSTATUS status;
600 netsec_offset_and_sizes(state,
601 do_unseal,
602 &min_sig_size,
603 NULL,
604 &checksum_length,
605 &confounder_ofs);
607 if (sig->length < min_sig_size) {
608 return NT_STATUS_ACCESS_DENIED;
611 if (do_unseal) {
612 confounder = _confounder;
613 memcpy(confounder, sig->data+confounder_ofs, 8);
614 } else {
615 confounder = NULL;
618 SETUP_SEQNUM(state, seq_num, !state->initiator);
620 if (do_unseal) {
621 status = netsec_do_seal(state,
622 seq_num,
623 confounder,
624 data,
625 length,
626 false);
627 if (!NT_STATUS_IS_OK(status)) {
628 DBG_WARNING("netsec_do_seal failed: %s\n", nt_errstr(status));
629 return NT_STATUS_ACCESS_DENIED;
633 if (state->gensec->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
634 sign_data = whole_pdu;
635 sign_length = pdu_length;
636 } else {
637 sign_data = data;
638 sign_length = length;
641 status = netsec_do_sign(state,
642 confounder,
643 sign_data,
644 sign_length,
645 header,
646 checksum);
647 if (!NT_STATUS_IS_OK(status)) {
648 DBG_WARNING("netsec_do_sign failed: %s\n", nt_errstr(status));
649 return NT_STATUS_ACCESS_DENIED;
652 ret = memcmp(checksum, sig->data+16, checksum_length);
653 if (ret != 0) {
654 dump_data_pw("calc digest:", checksum, checksum_length);
655 dump_data_pw("wire digest:", sig->data+16, checksum_length);
656 return NT_STATUS_ACCESS_DENIED;
659 status = netsec_do_seq_num(state, checksum, checksum_length, seq_num);
660 if (!NT_STATUS_IS_OK(status)) {
661 DBG_WARNING("netsec_do_seq_num failed: %s\n",
662 nt_errstr(status));
663 return status;
666 ZERO_ARRAY(checksum);
668 ret = memcmp(seq_num, sig->data+8, 8);
669 if (ret != 0) {
670 dump_data_pw("calc seq num:", seq_num, 8);
671 dump_data_pw("wire seq num:", sig->data+8, 8);
672 return NT_STATUS_ACCESS_DENIED;
675 return NT_STATUS_OK;
678 static uint32_t netsec_outgoing_sig_size(struct schannel_state *state)
680 uint32_t sig_size = 0;
682 netsec_offset_and_sizes(state,
683 true,
684 NULL,
685 &sig_size,
686 NULL,
687 NULL);
689 return sig_size;
692 static NTSTATUS netsec_outgoing_packet(struct schannel_state *state,
693 TALLOC_CTX *mem_ctx,
694 bool do_seal,
695 uint8_t *data, size_t length,
696 const uint8_t *whole_pdu, size_t pdu_length,
697 DATA_BLOB *sig)
699 uint32_t min_sig_size = 0;
700 uint32_t used_sig_size = 0;
701 uint8_t header[8];
702 uint8_t checksum[32];
703 uint32_t checksum_length = sizeof(checksum_length);
704 uint8_t _confounder[8];
705 uint8_t *confounder = NULL;
706 uint32_t confounder_ofs = 0;
707 uint8_t seq_num[8];
708 const uint8_t *sign_data = NULL;
709 size_t sign_length = 0;
710 NTSTATUS status;
712 netsec_offset_and_sizes(state,
713 do_seal,
714 &min_sig_size,
715 &used_sig_size,
716 &checksum_length,
717 &confounder_ofs);
719 SETUP_SEQNUM(state, seq_num, state->initiator);
721 if (do_seal) {
722 confounder = _confounder;
723 generate_random_buffer(confounder, 8);
724 } else {
725 confounder = NULL;
728 if (state->gensec->want_features & GENSEC_FEATURE_SIGN_PKT_HEADER) {
729 sign_data = whole_pdu;
730 sign_length = pdu_length;
731 } else {
732 sign_data = data;
733 sign_length = length;
736 status = netsec_do_sign(state,
737 confounder,
738 sign_data,
739 sign_length,
740 header,
741 checksum);
742 if (!NT_STATUS_IS_OK(status)) {
743 DBG_WARNING("netsec_do_sign failed: %s\n", nt_errstr(status));
744 return NT_STATUS_ACCESS_DENIED;
747 if (do_seal) {
748 status = netsec_do_seal(state,
749 seq_num,
750 confounder,
751 data,
752 length,
753 true);
754 if (!NT_STATUS_IS_OK(status)) {
755 DBG_WARNING("netsec_do_seal failed: %s\n",
756 nt_errstr(status));
757 return status;
761 status = netsec_do_seq_num(state, checksum, checksum_length, seq_num);
762 if (!NT_STATUS_IS_OK(status)) {
763 DBG_WARNING("netsec_do_seq_num failed: %s\n",
764 nt_errstr(status));
765 return status;
768 (*sig) = data_blob_talloc_zero(mem_ctx, used_sig_size);
770 memcpy(sig->data, header, 8);
771 memcpy(sig->data+8, seq_num, 8);
772 memcpy(sig->data+16, checksum, checksum_length);
774 if (confounder) {
775 memcpy(sig->data+confounder_ofs, confounder, 8);
778 dump_data_pw("signature:", sig->data+ 0, 8);
779 dump_data_pw("seq_num :", sig->data+ 8, 8);
780 dump_data_pw("digest :", sig->data+16, checksum_length);
781 dump_data_pw("confound :", sig->data+confounder_ofs, 8);
783 return NT_STATUS_OK;
786 _PUBLIC_ NTSTATUS gensec_schannel_init(TALLOC_CTX *ctx);
788 static size_t schannel_sig_size(struct gensec_security *gensec_security, size_t data_size)
790 struct schannel_state *state =
791 talloc_get_type_abort(gensec_security->private_data,
792 struct schannel_state);
794 return netsec_outgoing_sig_size(state);
797 struct schannel_update_state {
798 NTSTATUS status;
799 DATA_BLOB out;
802 static NTSTATUS schannel_update_internal(struct gensec_security *gensec_security,
803 TALLOC_CTX *out_mem_ctx,
804 const DATA_BLOB in, DATA_BLOB *out);
806 static struct tevent_req *schannel_update_send(TALLOC_CTX *mem_ctx,
807 struct tevent_context *ev,
808 struct gensec_security *gensec_security,
809 const DATA_BLOB in)
811 struct tevent_req *req;
812 struct schannel_update_state *state = NULL;
813 NTSTATUS status;
815 req = tevent_req_create(mem_ctx, &state,
816 struct schannel_update_state);
817 if (req == NULL) {
818 return NULL;
821 status = schannel_update_internal(gensec_security,
822 state, in,
823 &state->out);
824 state->status = status;
825 if (NT_STATUS_EQUAL(status, NT_STATUS_MORE_PROCESSING_REQUIRED)) {
826 status = NT_STATUS_OK;
828 if (tevent_req_nterror(req, status)) {
829 return tevent_req_post(req, ev);
832 tevent_req_done(req);
833 return tevent_req_post(req, ev);
836 static NTSTATUS schannel_update_internal(struct gensec_security *gensec_security,
837 TALLOC_CTX *out_mem_ctx,
838 const DATA_BLOB in, DATA_BLOB *out)
840 struct schannel_state *state =
841 talloc_get_type(gensec_security->private_data,
842 struct schannel_state);
843 NTSTATUS status;
844 enum ndr_err_code ndr_err;
845 struct NL_AUTH_MESSAGE bind_schannel = {
846 .Flags = 0,
848 struct NL_AUTH_MESSAGE bind_schannel_ack;
849 struct netlogon_creds_CredentialState *creds;
850 const char *workstation;
851 const char *domain;
853 *out = data_blob(NULL, 0);
855 if (gensec_security->dcerpc_auth_level < DCERPC_AUTH_LEVEL_INTEGRITY) {
856 switch (gensec_security->gensec_role) {
857 case GENSEC_CLIENT:
858 return NT_STATUS_INVALID_PARAMETER_MIX;
859 case GENSEC_SERVER:
860 return NT_STATUS_INVALID_PARAMETER;
862 return NT_STATUS_INTERNAL_ERROR;
865 switch (gensec_security->gensec_role) {
866 case GENSEC_CLIENT:
867 if (state != NULL) {
868 /* we could parse the bind ack, but we don't know what it is yet */
869 return NT_STATUS_OK;
872 creds = cli_credentials_get_netlogon_creds(gensec_security->credentials);
873 if (creds == NULL) {
874 return NT_STATUS_INVALID_PARAMETER_MIX;
877 state = netsec_create_state(gensec_security,
878 creds, true /* initiator */);
879 if (state == NULL) {
880 return NT_STATUS_NO_MEMORY;
883 bind_schannel.MessageType = NL_NEGOTIATE_REQUEST;
885 bind_schannel.Flags = NL_FLAG_OEM_NETBIOS_DOMAIN_NAME |
886 NL_FLAG_OEM_NETBIOS_COMPUTER_NAME;
887 bind_schannel.oem_netbios_domain.a = cli_credentials_get_domain(gensec_security->credentials);
888 bind_schannel.oem_netbios_computer.a = creds->computer_name;
890 if (creds->secure_channel_type == SEC_CHAN_DNS_DOMAIN) {
891 bind_schannel.Flags |= NL_FLAG_UTF8_DNS_DOMAIN_NAME;
892 bind_schannel.utf8_dns_domain.u = cli_credentials_get_realm(gensec_security->credentials);
894 bind_schannel.Flags |= NL_FLAG_UTF8_NETBIOS_COMPUTER_NAME;
895 bind_schannel.utf8_netbios_computer.u = creds->computer_name;
898 ndr_err = ndr_push_struct_blob(out, out_mem_ctx, &bind_schannel,
899 (ndr_push_flags_fn_t)ndr_push_NL_AUTH_MESSAGE);
900 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
901 status = ndr_map_error2ntstatus(ndr_err);
902 DEBUG(3, ("Could not create schannel bind: %s\n",
903 nt_errstr(status)));
904 return status;
907 return NT_STATUS_MORE_PROCESSING_REQUIRED;
908 case GENSEC_SERVER:
910 if (state != NULL) {
911 /* no third leg on this protocol */
912 return NT_STATUS_INVALID_PARAMETER;
915 /* parse the schannel startup blob */
916 ndr_err = ndr_pull_struct_blob(&in, out_mem_ctx, &bind_schannel,
917 (ndr_pull_flags_fn_t)ndr_pull_NL_AUTH_MESSAGE);
918 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
919 status = ndr_map_error2ntstatus(ndr_err);
920 DEBUG(3, ("Could not parse incoming schannel bind: %s\n",
921 nt_errstr(status)));
922 return status;
925 if (bind_schannel.Flags & NL_FLAG_OEM_NETBIOS_DOMAIN_NAME) {
926 domain = bind_schannel.oem_netbios_domain.a;
927 if (strcasecmp_m(domain, lpcfg_workgroup(gensec_security->settings->lp_ctx)) != 0) {
928 DEBUG(3, ("Request for schannel to incorrect domain: %s != our domain %s\n",
929 domain, lpcfg_workgroup(gensec_security->settings->lp_ctx)));
930 return NT_STATUS_LOGON_FAILURE;
932 } else if (bind_schannel.Flags & NL_FLAG_UTF8_DNS_DOMAIN_NAME) {
933 domain = bind_schannel.utf8_dns_domain.u;
934 if (strcasecmp_m(domain, lpcfg_dnsdomain(gensec_security->settings->lp_ctx)) != 0) {
935 DEBUG(3, ("Request for schannel to incorrect domain: %s != our domain %s\n",
936 domain, lpcfg_dnsdomain(gensec_security->settings->lp_ctx)));
937 return NT_STATUS_LOGON_FAILURE;
939 } else {
940 DEBUG(3, ("Request for schannel to without domain\n"));
941 return NT_STATUS_LOGON_FAILURE;
944 if (bind_schannel.Flags & NL_FLAG_OEM_NETBIOS_COMPUTER_NAME) {
945 workstation = bind_schannel.oem_netbios_computer.a;
946 } else if (bind_schannel.Flags & NL_FLAG_UTF8_NETBIOS_COMPUTER_NAME) {
947 workstation = bind_schannel.utf8_netbios_computer.u;
948 } else {
949 DEBUG(3, ("Request for schannel to without netbios workstation\n"));
950 return NT_STATUS_LOGON_FAILURE;
953 status = schannel_get_creds_state(out_mem_ctx,
954 gensec_security->settings->lp_ctx,
955 workstation, &creds);
956 if (!NT_STATUS_IS_OK(status)) {
957 DEBUG(3, ("Could not find session key for attempted schannel connection from %s: %s\n",
958 workstation, nt_errstr(status)));
959 if (NT_STATUS_EQUAL(status, NT_STATUS_INVALID_HANDLE)) {
960 return NT_STATUS_LOGON_FAILURE;
962 return status;
965 state = netsec_create_state(gensec_security,
966 creds, false /* not initiator */);
967 if (state == NULL) {
968 return NT_STATUS_NO_MEMORY;
971 status = auth_anonymous_user_info_dc(state,
972 lpcfg_netbios_name(gensec_security->settings->lp_ctx),
973 &state->user_info_dc);
974 if (!NT_STATUS_IS_OK(status)) {
975 return status;
978 bind_schannel_ack.MessageType = NL_NEGOTIATE_RESPONSE;
979 bind_schannel_ack.Flags = 0;
980 bind_schannel_ack.Buffer.dummy = 0x6c0000; /* actually I think
981 * this does not have
982 * any meaning here
983 * - gd */
985 ndr_err = ndr_push_struct_blob(out, out_mem_ctx, &bind_schannel_ack,
986 (ndr_push_flags_fn_t)ndr_push_NL_AUTH_MESSAGE);
987 if (!NDR_ERR_CODE_IS_SUCCESS(ndr_err)) {
988 status = ndr_map_error2ntstatus(ndr_err);
989 DEBUG(3, ("Could not return schannel bind ack for client %s: %s\n",
990 workstation, nt_errstr(status)));
991 return status;
994 return NT_STATUS_OK;
996 return NT_STATUS_INVALID_PARAMETER;
999 static NTSTATUS schannel_update_recv(struct tevent_req *req,
1000 TALLOC_CTX *out_mem_ctx,
1001 DATA_BLOB *out)
1003 struct schannel_update_state *state =
1004 tevent_req_data(req,
1005 struct schannel_update_state);
1006 NTSTATUS status;
1008 *out = data_blob_null;
1010 if (tevent_req_is_nterror(req, &status)) {
1011 tevent_req_received(req);
1012 return status;
1015 status = state->status;
1016 talloc_steal(out_mem_ctx, state->out.data);
1017 *out = state->out;
1018 tevent_req_received(req);
1019 return status;
1023 * Returns anonymous credentials for schannel, matching Win2k3.
1027 static NTSTATUS schannel_session_info(struct gensec_security *gensec_security,
1028 TALLOC_CTX *mem_ctx,
1029 struct auth_session_info **_session_info)
1031 struct schannel_state *state =
1032 talloc_get_type(gensec_security->private_data,
1033 struct schannel_state);
1034 struct auth4_context *auth_ctx = gensec_security->auth_context;
1035 struct auth_session_info *session_info = NULL;
1036 uint32_t session_info_flags = 0;
1037 NTSTATUS status;
1039 if (auth_ctx == NULL) {
1040 DEBUG(0, ("Cannot generate a session_info without the auth_context\n"));
1041 return NT_STATUS_INTERNAL_ERROR;
1044 if (auth_ctx->generate_session_info == NULL) {
1045 DEBUG(0, ("Cannot generate a session_info without the generate_session_info hook\n"));
1046 return NT_STATUS_INTERNAL_ERROR;
1049 if (gensec_security->want_features & GENSEC_FEATURE_UNIX_TOKEN) {
1050 session_info_flags |= AUTH_SESSION_INFO_UNIX_TOKEN;
1053 session_info_flags |= AUTH_SESSION_INFO_SIMPLE_PRIVILEGES;
1055 status = auth_ctx->generate_session_info(
1056 auth_ctx,
1057 mem_ctx,
1058 state->user_info_dc,
1059 state->user_info_dc->info->account_name,
1060 session_info_flags,
1061 &session_info);
1062 if (!NT_STATUS_IS_OK(status)) {
1063 return status;
1066 *_session_info = session_info;
1067 return NT_STATUS_OK;
1071 * Reduce the attack surface by ensuring schannel is not availble when
1072 * we are not a DC
1074 static NTSTATUS schannel_server_start(struct gensec_security *gensec_security)
1076 enum server_role server_role
1077 = lpcfg_server_role(gensec_security->settings->lp_ctx);
1079 switch (server_role) {
1080 case ROLE_DOMAIN_BDC:
1081 case ROLE_DOMAIN_PDC:
1082 case ROLE_ACTIVE_DIRECTORY_DC:
1083 return NT_STATUS_OK;
1084 default:
1085 return NT_STATUS_NOT_IMPLEMENTED;
1089 static NTSTATUS schannel_client_start(struct gensec_security *gensec_security)
1091 return NT_STATUS_OK;
1094 static bool schannel_have_feature(struct gensec_security *gensec_security,
1095 uint32_t feature)
1097 if (gensec_security->dcerpc_auth_level >= DCERPC_AUTH_LEVEL_INTEGRITY) {
1098 if (feature & GENSEC_FEATURE_SIGN) {
1099 return true;
1102 if (gensec_security->dcerpc_auth_level == DCERPC_AUTH_LEVEL_PRIVACY) {
1103 if (feature & GENSEC_FEATURE_SEAL) {
1104 return true;
1107 if (feature & GENSEC_FEATURE_DCE_STYLE) {
1108 return true;
1110 if (feature & GENSEC_FEATURE_SIGN_PKT_HEADER) {
1111 return true;
1113 return false;
1117 unseal a packet
1119 static NTSTATUS schannel_unseal_packet(struct gensec_security *gensec_security,
1120 uint8_t *data, size_t length,
1121 const uint8_t *whole_pdu, size_t pdu_length,
1122 const DATA_BLOB *sig)
1124 struct schannel_state *state =
1125 talloc_get_type_abort(gensec_security->private_data,
1126 struct schannel_state);
1128 return netsec_incoming_packet(state, true,
1129 discard_const_p(uint8_t, data),
1130 length,
1131 whole_pdu, pdu_length,
1132 sig);
1136 check the signature on a packet
1138 static NTSTATUS schannel_check_packet(struct gensec_security *gensec_security,
1139 const uint8_t *data, size_t length,
1140 const uint8_t *whole_pdu, size_t pdu_length,
1141 const DATA_BLOB *sig)
1143 struct schannel_state *state =
1144 talloc_get_type_abort(gensec_security->private_data,
1145 struct schannel_state);
1147 return netsec_incoming_packet(state, false,
1148 discard_const_p(uint8_t, data),
1149 length,
1150 whole_pdu, pdu_length,
1151 sig);
1154 seal a packet
1156 static NTSTATUS schannel_seal_packet(struct gensec_security *gensec_security,
1157 TALLOC_CTX *mem_ctx,
1158 uint8_t *data, size_t length,
1159 const uint8_t *whole_pdu, size_t pdu_length,
1160 DATA_BLOB *sig)
1162 struct schannel_state *state =
1163 talloc_get_type_abort(gensec_security->private_data,
1164 struct schannel_state);
1166 return netsec_outgoing_packet(state, mem_ctx, true,
1167 data, length,
1168 whole_pdu, pdu_length,
1169 sig);
1173 sign a packet
1175 static NTSTATUS schannel_sign_packet(struct gensec_security *gensec_security,
1176 TALLOC_CTX *mem_ctx,
1177 const uint8_t *data, size_t length,
1178 const uint8_t *whole_pdu, size_t pdu_length,
1179 DATA_BLOB *sig)
1181 struct schannel_state *state =
1182 talloc_get_type_abort(gensec_security->private_data,
1183 struct schannel_state);
1185 return netsec_outgoing_packet(state, mem_ctx, false,
1186 discard_const_p(uint8_t, data),
1187 length,
1188 whole_pdu, pdu_length,
1189 sig);
1192 static const struct gensec_security_ops gensec_schannel_security_ops = {
1193 .name = "schannel",
1194 .auth_type = DCERPC_AUTH_TYPE_SCHANNEL,
1195 .client_start = schannel_client_start,
1196 .server_start = schannel_server_start,
1197 .update_send = schannel_update_send,
1198 .update_recv = schannel_update_recv,
1199 .seal_packet = schannel_seal_packet,
1200 .sign_packet = schannel_sign_packet,
1201 .check_packet = schannel_check_packet,
1202 .unseal_packet = schannel_unseal_packet,
1203 .session_info = schannel_session_info,
1204 .sig_size = schannel_sig_size,
1205 .have_feature = schannel_have_feature,
1206 .enabled = true,
1207 .priority = GENSEC_SCHANNEL
1210 _PUBLIC_ NTSTATUS gensec_schannel_init(TALLOC_CTX *ctx)
1212 NTSTATUS ret;
1213 ret = gensec_register(ctx, &gensec_schannel_security_ops);
1214 if (!NT_STATUS_IS_OK(ret)) {
1215 DEBUG(0,("Failed to register '%s' gensec backend!\n",
1216 gensec_schannel_security_ops.name));
1217 return ret;
1220 return ret;