1 /*
2 * This file and its contents are supplied under the terms of the
3 * Common Development and Distribution License ("CDDL"), version 1.0.
4 * You may only use this file in accordance with the terms of version
5 * 1.0 of the CDDL.
6 *
7 * A full copy of the text of the CDDL should have accompanied this
8 * source. A copy of the CDDL is also available via the Internet at
9 * http://www.illumos.org/license/CDDL.
10 */
11
12 /*
13 * Copyright 2020 Tintri by DDN, Inc. All Rights Reserved.
14 * Copyright 2023 RackTop Systems, Inc.
15 */
16
17 #include <sys/md5.h>
18 #include <sys/debug.h>
19 #include <strings.h>
20 #include <stdio.h>
21 #include <smbsrv/netrauth.h>
22 #include <smbsrv/string.h>
23 #include <smbsrv/libsmb.h>
24 #include <libmlsvc.h>
25 #include <resolv.h>
26
27 /*
28 * NETLOGON SSP for "Secure RPC" works as follows:
29 * 1. The client binds to the DC without RPC-level authentication.
30 * 2. The client and server negotiate a Session Key using a client
31 * and server challenge, plus a shared secret (the machine password).
32 * This happens via NetrServerReqChallenge and NetrServerAuthenticate.
33 * The key is bound to a particular Computer/Server Name pair.
34 * 3. The client then establishes a new bind (or alters its existing one),
35 * this time requesting the NETLOGON provider for RPC-level authentication.
36 * The server uses the Computer and Domain names provided in the
37 * authentication token in the bind request in order to find
38 * the previously-negotiated Session Key (and rejects the bind if none
39 * exists).
40 * 4. The client and server then use this Session Key to provide
41 * integrity and/or confidentiality to future NETLOGON RPC messages.
42 *
43 * The functions in this file implement the NETLOGON SSP, as defined in
44 * [MS-NRPC] 3.3 "Netlogon as a Security Support Provider".
45 *
46 * Session Key negotiation is implemented in netr_auth.c.
47 * It is the same key that is used for generating NETLOGON credentials.
48 */
49
50 enum nl_token_type {
51 NL_AUTH_REQUEST = 0x00000000,
52 NL_AUTH_RESPONSE = 0x00000001
53 };
54
55 /*
56 * DOMAIN = domain name
57 * COMPUTER = client computer name
58 * HOST = client host name
59 *
60 * NB = NetBios format
61 * DNS = FQDN
62 *
63 * OEM = OEM_STRING
64 * COMPRESSED = Compressed UTF-8 string
65 *
66 * Each of these is NULL-terminated, and delinated by such.
67 * They are always found in this order, when specified.
68 *
69 * We currently use everything but NL_HOST_DNS_COMPRESSED_FLAG.
70 */
71 #define NL_DOMAIN_NB_OEM_FLAG 0x00000001
72 #define NL_COMPUTER_NB_OEM_FLAG 0x00000002
73 #define NL_DOMAIN_DNS_COMPRESSED_FLAG 0x00000004
74 #define NL_HOST_DNS_COMPRESSED_FLAG 0x00000008
75 #define NL_COMPUTER_NB_COMPRESSED_FLAG 0x00000010
76
77 #define NL_DOMAIN_FLAGS \
78 (NL_DOMAIN_NB_OEM_FLAG|NL_DOMAIN_DNS_COMPRESSED_FLAG)
79 #define NL_COMPUTER_FLAGS \
80 (NL_COMPUTER_NB_OEM_FLAG| \
81 NL_HOST_DNS_COMPRESSED_FLAG| \
82 NL_COMPUTER_NB_COMPRESSED_FLAG)
83
84 #define MD_DIGEST_LEN 16
85
86 /* These structures are OPAQUE at the RPC level - not marshalled. */
87 typedef struct nl_auth_message {
88 uint32_t nam_type;
89 uint32_t nam_flags;
90 uchar_t nam_str[1];
91 } nl_auth_message_t;
92
93 /*
94 * The size of this structure is used for space accounting.
95 * The confounder is not present on the wire unless confidentiality
96 * has been negotiated. When generating a token, we'll adjust space accounting
97 * based on whether the confounder is present.
98 */
99 #define NL_AUTH_CONFOUNDER_SIZE 8
100 typedef struct nl_auth_sig {
101 uint16_t nas_sig_alg;
102 uint16_t nas_seal_alg;
103 uint16_t nas_pad;
104 uint16_t nas_flags;
105 uchar_t nas_seqnum[8];
106 uchar_t nas_sig[8];
107 uchar_t nas_confounder[NL_AUTH_CONFOUNDER_SIZE]; /* Sealing only */
108 } nl_auth_sig_t;
109
110 #define NL_AUTH_SIG_SIGN_SIZE 24
111 #define NL_AUTH_SIG_SEAL_SIZE 32
112
113 void
netr_show_msg(nl_auth_message_t * nam,ndr_stream_t * nds)114 netr_show_msg(nl_auth_message_t *nam, ndr_stream_t *nds)
115 {
116 ndo_printf(nds, NULL, "nl_auth_message: type=0x%x flags=0x%x");
117 }
118
119 void
netr_show_sig(nl_auth_sig_t * nas,ndr_stream_t * nds)120 netr_show_sig(nl_auth_sig_t *nas, ndr_stream_t *nds)
121 {
122 ndo_printf(nds, NULL, "nl_auth_sig: SignatureAlg=0x%x SealAlg=0x%x "
123 "pad=0x%x flags=0x%x SequenceNumber=%llu Signature=0x%x "
124 "Confounder=0x%x",
125 nas->nas_sig_alg, nas->nas_seal_alg, nas->nas_pad,
126 nas->nas_flags, *(uint64_t *)nas->nas_seqnum,
127 *(uint64_t *)nas->nas_sig, *(uint64_t *)nas->nas_confounder);
128 }
129
130 /*
131 * NETLOGON SSP gss_init_sec_context equivalent
132 * [MS-NRPC] 3.3.4.1.1 "Generating an Initial NL_AUTH_MESSAGE"
133 *
134 * We need to encode at least one Computer name and at least one
135 * Domain name. The server uses this to find the Session Key
136 * negotiated earlier between this client and server.
137 *
138 * We attempt to provide NL_DOMAIN_NB_OEM_FLAG, NL_COMPUTER_NB_OEM_FLAG,
139 * NL_DOMAIN_DNS_COMPRESSED_FLAG, and NL_COMPUTER_NB_COMPRESSED_FLAG.
140 *
141 * See the above comments for how these are encoded.
142 */
143 int
netr_ssp_init(void * arg,ndr_xa_t * mxa)144 netr_ssp_init(void *arg, ndr_xa_t *mxa)
145 {
146 netr_info_t *auth = arg;
147 ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
148 nl_auth_message_t *nam;
149 size_t domain_len, comp_len, len;
150 int slen;
151 uchar_t *dnptrs[3], **dnlastptr;
152
153 domain_len = smb_sbequiv_strlen(auth->nb_domain);
154 comp_len = smb_sbequiv_strlen(auth->hostname);
155
156 /*
157 * Need to allocate length for two OEM_STRINGs + NULL bytes, plus space
158 * sufficient for two NULL-terminated compressed UTF-8 strings.
159 * For the UTF-8 strings, use 2*len as a heuristic.
160 */
161 len = domain_len + 1 + comp_len + 1 +
162 strlen(auth->hostname) * 2 + strlen(auth->fqdn_domain) * 2;
163
164 hdr->auth_length = 0;
165
166 nam = NDR_MALLOC(mxa, len);
167 if (nam == NULL)
168 return (NDR_DRC_FAULT_SEC_OUT_OF_MEMORY);
169
170 nam->nam_type = NL_AUTH_REQUEST;
171 nam->nam_flags = 0;
172
173 if (domain_len != -1) {
174 slen = smb_mbstooem(nam->nam_str, auth->nb_domain, domain_len);
175 if (slen >= 0) {
176 hdr->auth_length += slen + 1;
177 nam->nam_str[hdr->auth_length - 1] = '\0';
178 nam->nam_flags |= NL_DOMAIN_NB_OEM_FLAG;
179 }
180 }
181
182 if (comp_len != -1) {
183 slen = smb_mbstooem(nam->nam_str + hdr->auth_length,
184 auth->hostname, comp_len);
185 if (slen >= 0) {
186 hdr->auth_length += slen + 1;
187 nam->nam_str[hdr->auth_length - 1] = '\0';
188 nam->nam_flags |= NL_COMPUTER_NB_OEM_FLAG;
189 }
190 }
191
192 dnptrs[0] = NULL;
193 dnlastptr = &dnptrs[sizeof (dnptrs) / sizeof (dnptrs[0])];
194
195 slen = dn_comp(auth->fqdn_domain, nam->nam_str + hdr->auth_length,
196 len - hdr->auth_length, dnptrs, dnlastptr);
197
198 if (slen >= 0) {
199 hdr->auth_length += slen;
200 nam->nam_str[hdr->auth_length] = '\0';
201 nam->nam_flags |= NL_DOMAIN_DNS_COMPRESSED_FLAG;
202 }
203
204 slen = dn_comp(auth->hostname, nam->nam_str + hdr->auth_length,
205 len - hdr->auth_length, dnptrs, dnlastptr);
206 if (slen >= 0) {
207 hdr->auth_length += slen;
208 nam->nam_str[hdr->auth_length] = '\0';
209 nam->nam_flags |= NL_COMPUTER_NB_COMPRESSED_FLAG;
210 }
211
212 /* We must provide at least one Domain Name and Computer Name */
213 if ((nam->nam_flags & NL_DOMAIN_FLAGS) == 0 ||
214 (nam->nam_flags & NL_COMPUTER_FLAGS) == 0)
215 return (NDR_DRC_FAULT_SEC_ENCODE_FAILED);
216
217 mxa->send_auth.auth_value = (void *)nam;
218 hdr->auth_length += sizeof (nam->nam_flags) + sizeof (nam->nam_type);
219
220 return (0);
221 }
222
223 /*
224 * NETLOGON SSP response-side gss_init_sec_context equivalent
225 * [MS-NRPC] 3.3.4.1.4 "Receiving a Return NL_AUTH_MESSAGE"
226 */
227 int
netr_ssp_recv(void * arg,ndr_xa_t * mxa)228 netr_ssp_recv(void *arg, ndr_xa_t *mxa)
229 {
230 netr_info_t *auth = arg;
231 ndr_common_header_t *ahdr = &mxa->recv_hdr.common_hdr;
232 ndr_sec_t *ack_secp = &mxa->recv_auth;
233 nl_auth_message_t *nam;
234 int rc;
235
236 nam = (nl_auth_message_t *)ack_secp->auth_value;
237
238 /* We only need to verify the length ("at least 12") and the type */
239 if (ahdr->auth_length < 12) {
240 rc = NDR_DRC_FAULT_SEC_AUTH_LENGTH_INVALID;
241 goto errout;
242 }
243 if (nam->nam_type != NL_AUTH_RESPONSE) {
244 rc = NDR_DRC_FAULT_SEC_META_INVALID;
245 goto errout;
246 }
247 auth->clh_seqnum = 0;
248
249 return (NDR_DRC_OK);
250
251 errout:
252 netr_show_msg(nam, &mxa->recv_nds);
253 return (rc);
254 }
255
256 /* returns byte N of seqnum */
257 #define CLS_BYTE(n, seqnum) ((seqnum >> (8 * (n))) & 0xff)
258
259 /*
260 * Perform key derivation using HMAC-MD5, as specified in MS-NRPC.
261 * This generates an intermediate key using HMAC-MD5 over zeroes using
262 * the input key, then generates the final key using HMAC-MD5 over some
263 * caller-specified data using the intermediate key.
264 * See callers for spec references (there are multiple!).
265 */
266 int
netr_ssp_derive_key(uchar_t * input_key,uint_t key_len,uchar_t * data,uint_t data_len,uchar_t * out_key)267 netr_ssp_derive_key(uchar_t *input_key, uint_t key_len,
268 uchar_t *data, uint_t data_len, uchar_t *out_key)
269 {
270 int rc;
271 uint32_t zeroes = 0;
272
273 rc = smb_auth_hmac_md5((uchar_t *)&zeroes, 4,
274 input_key, key_len,
275 out_key);
276
277 if (rc == 0)
278 rc = smb_auth_hmac_md5(data, data_len,
279 out_key, MD_DIGEST_LEN,
280 out_key);
281
282 return (rc);
283 }
284 /*
285 * [MS-NRPC] 3.3.4.2.1 "Generating a Client Netlogon Signature Token"
286 *
287 * Set up the metadata, encrypt and increment the SequenceNumber,
288 * and sign the PDU body. If a confounder is provided, encrypt it and
289 * the PDU body.
290 * Encryption happens here because the RC4 key is derived from data
291 * generated locally for signing/verification.
292 */
293 int
netr_ssp_make_token(netr_info_t * auth,ndr_stream_t * nds,nl_auth_sig_t * nas,uchar_t * confounder)294 netr_ssp_make_token(netr_info_t *auth, ndr_stream_t *nds, nl_auth_sig_t *nas,
295 uchar_t *confounder)
296 {
297 uint32_t zeroes = 0;
298 MD5_CTX md5h;
299 BYTE local_sig[MD_DIGEST_LEN];
300 BYTE enc_key[MD_DIGEST_LEN];
301 uchar_t *pdu_body = nds->pdu_base_addr + nds->pdu_body_offset;
302
303 /*
304 * SignatureAlgorithm is first byte 0x77, second byte 00 for HMAC-MD5
305 * or 0x13, 0x00 for AES-HMAC-SHA256.
306 *
307 * SealAlgorithm is first byte 0x7A, second byte 00 for RC4
308 * or 0x1A, 0x00 for AES-CFB8, or 0xffff for No Sealing.
309 *
310 * Pad is always 0xffff, and flags is always 0x0000.
311 *
312 * SequenceNumber is a computed, encrypted, 64-bit number.
313 *
314 * Each of these is always encoded in little-endian order.
315 */
316 nas->nas_sig_alg = 0x0077;
317 if (confounder != NULL)
318 nas->nas_seal_alg = 0x007A;
319 else
320 nas->nas_seal_alg = 0xffff;
321 nas->nas_pad = 0xffff;
322 nas->nas_flags = 0;
323
324 /*
325 * Calculate the SequenceNumber.
326 * Note that byte 4 gets modified, as per the spec -
327 * It's the only byte that is not just set to some other byte.
328 */
329 nas->nas_seqnum[0] = CLS_BYTE(3, auth->clh_seqnum);
330 nas->nas_seqnum[1] = CLS_BYTE(2, auth->clh_seqnum);
331 nas->nas_seqnum[2] = CLS_BYTE(1, auth->clh_seqnum);
332 nas->nas_seqnum[3] = CLS_BYTE(0, auth->clh_seqnum);
333 nas->nas_seqnum[4] = CLS_BYTE(7, auth->clh_seqnum) | 0x80;
334 nas->nas_seqnum[5] = CLS_BYTE(6, auth->clh_seqnum);
335 nas->nas_seqnum[6] = CLS_BYTE(5, auth->clh_seqnum);
336 nas->nas_seqnum[7] = CLS_BYTE(4, auth->clh_seqnum);
337
338 auth->clh_seqnum++;
339
340 /*
341 * The HMAC-MD5 signature is computed as follows:
342 * First 8 bytes of
343 * HMAC_MD5(
344 * MD5(0x00000000 | sig_alg | seal_alg | pad | flags |
345 * <confounder if present> | PDU body),
346 * session_key)
347 */
348 MD5Init(&md5h);
349 MD5Update(&md5h, (uchar_t *)&zeroes, 4);
350 MD5Update(&md5h, (uchar_t *)nas, 8);
351 if (confounder != NULL)
352 MD5Update(&md5h, confounder, NL_AUTH_CONFOUNDER_SIZE);
353 MD5Update(&md5h, pdu_body, nds->pdu_body_size);
354
355 MD5Final(local_sig, &md5h);
356 if (smb_auth_hmac_md5(local_sig, sizeof (local_sig),
357 auth->session_key.key, auth->session_key.len,
358 local_sig) != 0)
359 return (NDR_DRC_FAULT_SEC_SSP_FAILED);
360
361 bcopy(local_sig, nas->nas_sig, 8);
362
363 /*
364 * [MS-NRPC] 3.3.4.2.1 "Generating a Client Netlogon Signature Token"
365 * Encrypt the Confounder and PDU Body.
366 * For RC4 Encryption, the EncryptionKey is computed as follows:
367 * XorKey = (XOR each byte of session_key with 0xf0)
368 * HMAC_MD5(local_seqnum, HMAC_MD5(0x00000000, xor_key))
369 *
370 * Step 8 says "the Confounder field and the data MUST be encrypted,
371 * in that order, using the same encryption algorithm". It also says
372 * "The server MUST initialize RC4 only once, before encrypting the
373 * Confounder field".
374 * However, that's a lie! They're encrypted independently for RC4.
375 */
376 if (confounder != NULL) {
377 int rc;
378
379 rc = netr_ssp_derive_key(
380 auth->rpc_seal_key.key, auth->rpc_seal_key.len,
381 (uchar_t *)nas->nas_seqnum, sizeof (nas->nas_seqnum),
382 enc_key);
383
384 if (rc != 0)
385 goto errout;
386
387 if (smb_auth_RC4(nas->nas_confounder,
388 sizeof (nas->nas_confounder),
389 enc_key, sizeof (enc_key),
390 confounder, NL_AUTH_CONFOUNDER_SIZE) != 0)
391 goto errout;
392
393 if (smb_auth_RC4(pdu_body, nds->pdu_body_size,
394 enc_key, sizeof (enc_key),
395 pdu_body, nds->pdu_body_size) != 0)
396 goto errout;
397 }
398
399 /*
400 * Encrypt the SequenceNumber.
401 * For RC4 Encryption, the EncryptionKey is computed as follows:
402 * HMAC_MD5(signature, HMAC_MD5(0x00000000, session_key))
403 */
404 if (netr_ssp_derive_key(auth->session_key.key, auth->session_key.len,
405 (uchar_t *)nas->nas_sig, sizeof (nas->nas_sig), enc_key) != 0)
406 goto errout;
407
408 if (smb_auth_RC4(nas->nas_seqnum, sizeof (nas->nas_seqnum),
409 enc_key, sizeof (enc_key),
410 nas->nas_seqnum, sizeof (nas->nas_seqnum)) != 0)
411 goto errout;
412
413 explicit_bzero(enc_key, sizeof (enc_key));
414 return (NDR_DRC_OK);
415
416 errout:
417 explicit_bzero(enc_key, sizeof (enc_key));
418 return (NDR_DRC_FAULT_SEC_SSP_FAILED);
419 }
420
421 /*
422 * [MS-NRPC] 3.3.4.2.4 "Receiving a Server Netlogon Signature Token"
423 *
424 * Verify the metadata; decrypt, verify, and increment the SequenceNumber;
425 * and validate the PDU body against the provided signature.
426 * If the confounder is present, decrypt it and the PDU body. This is done here
427 * because the key relies on local_seqnum ("CopySeqNumber"), which can only be
428 * retrieved here.
429 */
430 int
netr_ssp_check_token(netr_info_t * auth,ndr_stream_t * nds,nl_auth_sig_t * nas,boolean_t verify_resp,boolean_t has_confounder)431 netr_ssp_check_token(netr_info_t *auth, ndr_stream_t *nds, nl_auth_sig_t *nas,
432 boolean_t verify_resp, boolean_t has_confounder)
433 {
434 uint32_t zeroes = 0;
435 MD5_CTX md5h;
436 BYTE local_sig[MD_DIGEST_LEN];
437 BYTE dec_key[MD_DIGEST_LEN];
438 BYTE local_seqnum[8];
439 uchar_t confounder[NL_AUTH_CONFOUNDER_SIZE];
440 uchar_t *pdu_body = nds->pdu_base_addr + nds->pdu_body_offset;
441 int rc;
442 boolean_t seqnum_bumped = B_FALSE;
443
444 /*
445 * Verify SignatureAlgorithm, SealAlgorithm, and Pad are as expected.
446 * These follow the same values as in the Client Signature.
447 */
448 if (nas->nas_sig_alg != 0x0077 ||
449 nas->nas_seal_alg != (has_confounder ? 0x007A : 0xffff) ||
450 nas->nas_pad != 0xffff) {
451 rc = NDR_DRC_FAULT_SEC_META_INVALID;
452 goto errout;
453 }
454
455 /* Decrypt the SequenceNumber. This is done the same as the Client. */
456 if (netr_ssp_derive_key(auth->session_key.key, auth->session_key.len,
457 (uchar_t *)nas->nas_sig, sizeof (nas->nas_sig), dec_key) != 0) {
458 rc = NDR_DRC_FAULT_SEC_SSP_FAILED;
459 goto errout;
460 }
461 if (smb_auth_RC4(nas->nas_seqnum, sizeof (nas->nas_seqnum),
462 dec_key, sizeof (dec_key),
463 nas->nas_seqnum, sizeof (nas->nas_seqnum)) != 0) {
464 rc = NDR_DRC_FAULT_SEC_SSP_FAILED;
465 goto errout;
466 }
467
468 /*
469 * Calculate a local version of the SequenceNumber.
470 * Note that byte 4 does NOT get modified, unlike the client.
471 */
472 local_seqnum[0] = CLS_BYTE(3, auth->clh_seqnum);
473 local_seqnum[1] = CLS_BYTE(2, auth->clh_seqnum);
474 local_seqnum[2] = CLS_BYTE(1, auth->clh_seqnum);
475 local_seqnum[3] = CLS_BYTE(0, auth->clh_seqnum);
476 local_seqnum[4] = CLS_BYTE(7, auth->clh_seqnum);
477 local_seqnum[5] = CLS_BYTE(6, auth->clh_seqnum);
478 local_seqnum[6] = CLS_BYTE(5, auth->clh_seqnum);
479 local_seqnum[7] = CLS_BYTE(4, auth->clh_seqnum);
480
481 /* If the SequenceNumbers don't match, this is out of order - drop it */
482 if (bcmp(local_seqnum, nas->nas_seqnum, sizeof (local_seqnum)) != 0) {
483 ndo_printf(nds, NULL, "CalculatedSeqnum: %llu "
484 "DecryptedSeqnum: %llu",
485 *(uint64_t *)local_seqnum, *(uint64_t *)nas->nas_seqnum);
486 rc = NDR_DRC_FAULT_SEC_SEQNUM_INVALID;
487 goto errout;
488 }
489
490 auth->clh_seqnum++;
491 seqnum_bumped = B_TRUE;
492
493 /*
494 * Decrypt the Confounder and PDU Body.
495 * For RC4 Encryption, the EncryptionKey is computed as follows:
496 * XorKey = (XOR each byte of session_key with 0xf0)
497 * HMAC_MD5(local_seqnum, HMAC_MD5(0x00000000, xor_key))
498 */
499 if (has_confounder) {
500 if (netr_ssp_derive_key(
501 auth->rpc_seal_key.key, auth->rpc_seal_key.len,
502 (uchar_t *)local_seqnum, sizeof (local_seqnum),
503 dec_key) != 0) {
504 rc = NDR_DRC_FAULT_SEC_SSP_FAILED;
505 goto errout;
506 }
507
508 if (smb_auth_RC4(confounder, NL_AUTH_CONFOUNDER_SIZE,
509 dec_key, sizeof (dec_key),
510 nas->nas_confounder, sizeof (nas->nas_confounder)) != 0) {
511 rc = NDR_DRC_FAULT_SEC_SSP_FAILED;
512 goto errout;
513 }
514 if (smb_auth_RC4(pdu_body, nds->pdu_body_size,
515 dec_key, sizeof (dec_key),
516 pdu_body, nds->pdu_body_size) != 0) {
517 rc = NDR_DRC_FAULT_SEC_SSP_FAILED;
518 goto errout;
519 }
520 }
521
522 /*
523 * Calculate the signature.
524 * This is done the same as the Client.
525 */
526 MD5Init(&md5h);
527 MD5Update(&md5h, (uchar_t *)&zeroes, 4);
528 MD5Update(&md5h, (uchar_t *)nas, 8);
529 if (has_confounder)
530 MD5Update(&md5h, confounder, NL_AUTH_CONFOUNDER_SIZE);
531 MD5Update(&md5h, pdu_body, nds->pdu_body_size);
532 MD5Final(local_sig, &md5h);
533 if (smb_auth_hmac_md5(local_sig, sizeof (local_sig),
534 auth->session_key.key, auth->session_key.len,
535 local_sig) != 0) {
536 rc = NDR_DRC_FAULT_SEC_SSP_FAILED;
537 goto errout;
538 }
539
540 /* If the first 8 bytes don't match, drop it */
541 if (bcmp(local_sig, nas->nas_sig, 8) != 0) {
542 ndo_printf(nds, NULL, "CalculatedSig: %llu "
543 "PacketSig: %llu",
544 *(uint64_t *)local_sig, *(uint64_t *)nas->nas_sig);
545 rc = NDR_DRC_FAULT_SEC_SIG_INVALID;
546 goto errout;
547 }
548
549 explicit_bzero(dec_key, sizeof (dec_key));
550 return (NDR_DRC_OK);
551
552 errout:
553 netr_show_sig(nas, nds);
554
555 explicit_bzero(dec_key, sizeof (dec_key));
556 if (!verify_resp) {
557 if (!seqnum_bumped)
558 auth->clh_seqnum++;
559 return (NDR_DRC_OK);
560 }
561
562 return (rc);
563 }
564
565 /*
566 * NETLOGON SSP gss_MICEx equivalent.
567 * Note that auth_length does NOT include the length of the confounder.
568 */
569 int
netr_ssp_sign(void * arg,ndr_xa_t * mxa)570 netr_ssp_sign(void *arg, ndr_xa_t *mxa)
571 {
572 ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
573 nl_auth_sig_t *nas;
574
575 hdr->auth_length = NL_AUTH_SIG_SIGN_SIZE;
576 CTASSERT(NL_AUTH_SIG_SIGN_SIZE ==
577 (offsetof(nl_auth_sig_t, nas_sig) + sizeof (nas->nas_sig)));
578 nas = NDR_MALLOC(mxa, sizeof (*nas));
579 if (nas == NULL)
580 return (NDR_DRC_FAULT_SEC_OUT_OF_MEMORY);
581
582 mxa->send_auth.auth_value = (void *)nas;
583
584 return (netr_ssp_make_token(arg, &mxa->send_nds, nas, NULL));
585 }
586
587 /*
588 * NETLOGON SSP gss_VerifyMICEx equivalent.
589 */
590 int
netr_ssp_verify(void * arg,ndr_xa_t * mxa,boolean_t verify_resp)591 netr_ssp_verify(void *arg, ndr_xa_t *mxa, boolean_t verify_resp)
592 {
593 ndr_common_header_t *hdr = &mxa->recv_hdr.common_hdr;
594 ndr_sec_t *secp = &mxa->recv_auth;
595 nl_auth_sig_t *nas = (nl_auth_sig_t *)secp->auth_value;
596
597 if (hdr->auth_length < NL_AUTH_SIG_SIGN_SIZE)
598 return (NDR_DRC_FAULT_SEC_AUTH_LENGTH_INVALID);
599
600 return (netr_ssp_check_token(arg, &mxa->recv_nds, nas, verify_resp,
601 B_FALSE));
602 }
603
604 /*
605 * NETLOGON SSP gss_WrapEx equivalent.
606 * Generate a cryptographically random confounder before signing/sealing.
607 * It is included in auth_length here.
608 */
609 int
netr_ssp_encrypt(void * arg,ndr_xa_t * mxa)610 netr_ssp_encrypt(void *arg, ndr_xa_t *mxa)
611 {
612 uchar_t confounder[NL_AUTH_CONFOUNDER_SIZE];
613 ndr_common_header_t *hdr = &mxa->send_hdr.common_hdr;
614 nl_auth_sig_t *nas;
615
616 hdr->auth_length = NL_AUTH_SIG_SEAL_SIZE;
617 CTASSERT(NL_AUTH_SIG_SEAL_SIZE == sizeof (*nas));
618 nas = NDR_MALLOC(mxa, sizeof (*nas));
619 if (nas == NULL)
620 return (NDR_DRC_FAULT_SEC_OUT_OF_MEMORY);
621
622 mxa->send_auth.auth_value = (void *)nas;
623
624 arc4random_buf(confounder, NL_AUTH_CONFOUNDER_SIZE);
625 return (netr_ssp_make_token(arg, &mxa->send_nds, nas, confounder));
626 }
627
628 /*
629 * NETLOGON SSP gss_UnwrapEx equivalent.
630 * Note that the Confounder is only used for calculating the signature.
631 */
632 int
netr_ssp_decrypt(void * arg,ndr_xa_t * mxa,boolean_t verify_resp)633 netr_ssp_decrypt(void *arg, ndr_xa_t *mxa, boolean_t verify_resp)
634 {
635 ndr_common_header_t *hdr = &mxa->recv_hdr.common_hdr;
636 ndr_sec_t *secp = &mxa->recv_auth;
637 nl_auth_sig_t *nas = (nl_auth_sig_t *)secp->auth_value;
638
639 if (hdr->auth_length < NL_AUTH_SIG_SEAL_SIZE)
640 return (NDR_DRC_FAULT_SEC_AUTH_LENGTH_INVALID);
641
642 return (netr_ssp_check_token(arg, &mxa->recv_nds, nas, verify_resp,
643 B_TRUE));
644 }
645
646 extern struct netr_info netr_global_info;
647
648 ndr_auth_ctx_t netr_ssp_ctx = {
649 .auth_ops = {
650 .nao_init = netr_ssp_init,
651 .nao_recv = netr_ssp_recv,
652 .nao_sign = netr_ssp_sign,
653 .nao_verify = netr_ssp_verify,
654 .nao_encrypt = netr_ssp_encrypt,
655 .nao_decrypt = netr_ssp_decrypt
656 },
657 .auth_ctx = &netr_global_info,
658 .auth_context_id = 0,
659 .auth_type = NDR_C_AUTHN_GSS_NETLOGON,
660 .auth_level = NDR_C_AUTHN_LEVEL_PKT_PRIVACY,
661 .auth_verify_resp = B_TRUE
662 };
663