xref: /illumos-gate/usr/src/uts/common/fs/smbclnt/netsmb/smb3_negctx.c (revision fb217153ae25423b48522eea4456af6b24de0a3c)
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 2021-2025 RackTop Systems, Inc.
14  */
15 
16 #include <sys/param.h>
17 #include <sys/random.h>
18 #include <sys/sunddi.h>
19 #include <sys/sysmacros.h>
20 #include <sys/sdt.h>
21 
22 #include <netsmb/smb_osdep.h>
23 
24 #include <netsmb/smb.h>
25 #include <netsmb/smb2.h>
26 #include <netsmb/smb_conn.h>
27 #include <netsmb/smb_subr.h>
28 #include <netsmb/mchain.h>
29 
30 #include <netsmb/nsmb_kcrypt.h>
31 
32 #define	NEG_CTX_MAX_COUNT	(16)
33 #define	NEG_CTX_MAX_DATALEN	(256)
34 
35 enum smb2_neg_ctx_type {
36 	SMB2_PREAUTH_INTEGRITY_CAPS		= 1,
37 	SMB2_ENCRYPTION_CAPS			= 2,
38 	SMB2_COMPRESSION_CAPS			= 3,	/* not implemented */
39 	SMB2_NETNAME_NEGOTIATE_CONTEXT_ID	= 5	/* not implemented */
40 };
41 
42 typedef struct smb2_negotiate_ctx {
43 	uint16_t	type;
44 	uint16_t	datalen;
45 } smb2_neg_ctx_t;
46 
47 /*
48  * SMB 3.1.1 specifies only one pre-auth hash algorithm: SHA-512
49  * and four encryption ones: AES128-CCM/GCM, AES256-CCM/GCM
50  */
51 #define	MAX_HASHID_NUM	(1)
52 #define	MAX_CIPHER_NUM	(4)
53 
54 #define	SMB31_PREAUTH_CTX_SALT_LEN	32
55 
56 typedef struct smb2_preauth_integrity_caps {
57 	uint16_t	picap_hash_count;
58 	uint16_t	picap_salt_len;
59 	uint16_t	picap_hash_id;
60 	uint8_t		picap_salt[SMB31_PREAUTH_CTX_SALT_LEN];
61 } smb2_preauth_caps_t;
62 
63 typedef struct smb2_encryption_caps {
64 	uint16_t	encap_cipher_count;
65 	uint16_t	encap_cipher_ids[MAX_CIPHER_NUM];
66 } smb2_encrypt_caps_t;
67 
68 /*
69  * The contexts we support
70  */
71 typedef struct smb2_preauth_neg_ctx {
72 	smb2_neg_ctx_t		neg_ctx;
73 	smb2_preauth_caps_t	preauth_caps;
74 } smb2_preauth_neg_ctx_t;
75 
76 typedef struct smb2_encrypt_neg_ctx {
77 	smb2_neg_ctx_t		neg_ctx;
78 	smb2_encrypt_caps_t	encrypt_caps;
79 } smb2_encrypt_neg_ctx_t;
80 
81 typedef struct smb2_neg_ctxs {
82 	uint32_t		offset;
83 	uint16_t		count;
84 	smb2_preauth_neg_ctx_t	preauth_ctx;
85 	smb2_encrypt_neg_ctx_t	encrypt_ctx;
86 } smb2_neg_ctxs_t;
87 
88 
89 /*
90  * SMB 3.1.1 Negotiate Contexts
91  */
92 
93 /*
94  * Bit mask used during testing to simulate not supporting certain
95  * encryption ciphers.  Bit N-1 corresponds to SMB3_CIPHER_* value N,
96  * so the default 0xf advertises all four ciphers.  Settable via mdb(1).
97  * Make sure at least one of these bits is set: 1, 2, 4, 8
98  */
99 int nsmb_ciphers_enabled = 0xf;
100 
101 /*
102  * Put neg. contexts
103  */
104 int
smb3_negctxs_encode(struct smb_vc * vcp,struct mbchain * mbp,uint32_t * negctx_off_p,uint16_t * negctx_cnt_p)105 smb3_negctxs_encode(struct smb_vc *vcp, struct mbchain *mbp,
106 	uint32_t *negctx_off_p, uint16_t *negctx_cnt_p)
107 {
108 
109 	uint8_t salt[SMB31_PREAUTH_CTX_SALT_LEN];
110 	size_t saltlen = sizeof (salt);
111 	int start;
112 	uint16_t *ccnt_p;
113 	uint16_t *len_p;
114 	uint16_t len;
115 	uint16_t ctx_cnt = 0;
116 	uint16_t ccnt = 0;
117 
118 	(void) random_get_pseudo_bytes(salt, saltlen);
119 
120 	/*
121 	 * Put Contexts. Align 8 first.
122 	 */
123 	mb_put_align8(mbp);
124 	*negctx_off_p = htolel(mbp->mb_count);
125 
126 	/*
127 	 * 2.2.3.1.1 SMB2_PREAUTH_INTEGRITY_CAPABILITIES
128 	 * This one is _required_ for SMB 3.1.1
129 	 */
130 	mb_put_uint16le(mbp, SMB2_PREAUTH_INTEGRITY_CAPS);
131 	len_p = mb_reserve(mbp, 2);
132 	mb_put_uint32le(mbp, 0);	/* Reserved */
133 	start = mbp->mb_count;
134 
135 	mb_put_uint16le(mbp, 1);	/* HashAlgorithmCount */
136 	mb_put_uint16le(mbp, saltlen);	/* SaltLength */
137 
138 	/* The only supported hash algo - SHA-512 */
139 	mb_put_uint16le(mbp, SMB3_HASH_SHA512);
140 	/* Salt */
141 	mb_put_mem(mbp, salt, saltlen, MB_MSYSTEM);
142 
143 	len = mbp->mb_count - start;
144 	*len_p = htoles(len);
145 	ctx_cnt++;
146 
147 	/*
148 	 * 2.2.3.1.2 SMB2_ENCRYPTION_CAPABILITIES
149 	 * List ciphers most preferred first.
150 	 * Todo: make these configurable
151 	 */
152 	mb_put_align8(mbp);
153 
154 	mb_put_uint16le(mbp, SMB2_ENCRYPTION_CAPS);
155 	len_p = mb_reserve(mbp, 2);
156 	mb_put_uint32le(mbp, 0);	/* Reserved */
157 	start = mbp->mb_count;
158 
159 	ccnt_p = mb_reserve(mbp, 2);	/* CipherCount */
160 
161 	/*
162 	 * Ciphers, in order of preference.
163 	 * Prefer 256-bit ciphers, and then GCM over CCM
164 	 * (because GCM is more efficient than CCM)
165 	 * With modern servers, always AES256_GCM
166 	 */
167 	if (nsmb_ciphers_enabled & (1 << (SMB3_CIPHER_AES256_GCM - 1))) {
168 		mb_put_uint16le(mbp, SMB3_CIPHER_AES256_GCM);
169 		ccnt++;
170 	}
171 	if (nsmb_ciphers_enabled & (1 << (SMB3_CIPHER_AES256_CCM - 1))) {
172 		mb_put_uint16le(mbp, SMB3_CIPHER_AES256_CCM);
173 		ccnt++;
174 	}
175 	if (nsmb_ciphers_enabled & (1 << (SMB3_CIPHER_AES128_GCM - 1))) {
176 		mb_put_uint16le(mbp, SMB3_CIPHER_AES128_GCM);
177 		ccnt++;
178 	}
179 	if (nsmb_ciphers_enabled & (1 << (SMB3_CIPHER_AES128_CCM - 1))) {
180 		mb_put_uint16le(mbp, SMB3_CIPHER_AES128_CCM);
181 		ccnt++;
182 	}
183 
184 	*ccnt_p = htoles(ccnt);
185 
186 	len = mbp->mb_count - start;
187 	*len_p = htoles(len);
188 	ctx_cnt++;
189 
190 	*negctx_cnt_p = htoles(ctx_cnt);
191 
192 	return (0);
193 }
194 
195 
196 /*
197  * Decode the SMB2 NEGOTIATE_CONTEXT section.
198  * [MS-SMB2] 2.2.4.1 SMB2 NEGOTIATE_CONTEXT Response Values
199  *
200  * This function should be called only for dialect >= 0x311
201  * Negotiate context list should contain exactly one
202  * SMB2_PREAUTH_INTEGRITY_CAPS context.  Spec. ref:
203  * [MS-SMB2] 3.2.5.2 ... SMB2 NEGOTIATE Response
204  *
205  * The response contains the encryption cipher the server selected
206  * from among those we offered, or NONE if there was no overlap.
207  *
208  * This returns Unix-style error codes in cases where the response
209  * could not be decoded or otherwise faulty in ways that mean we
210  * cannot continue with it.  Returning an error here means the
211  * caller will drop the connection and give up.
212  *
213  * SMB 3.1.1 specifies the only hashing algorithm - SHA-512.
214  * SMB 3.1.1 specifies four encryption algorithms:
215  * AES-128-CCM, AES-128-GCM, AES-256-CCM, AES-256-GCM
216  */
217 int
smb3_negctxs_decode(struct smb_vc * vcp,struct mdchain * mdp,uint16_t negctx_cnt)218 smb3_negctxs_decode(struct smb_vc *vcp, struct mdchain *mdp,
219     uint16_t negctx_cnt)
220 {
221 	smb2_neg_ctxs_t negctxs_stor;
222 	smb2_neg_ctxs_t *neg_ctxs = &negctxs_stor;
223 	smb2_preauth_caps_t *picap = &neg_ctxs->preauth_ctx.preauth_caps;
224 	smb2_encrypt_caps_t *encap = &neg_ctxs->encrypt_ctx.encrypt_caps;
225 	uint16_t cipher = 0;
226 	int found_preauth_ctx = 0;
227 	int found_encrypt_ctx = 0;
228 	int err = 0;
229 	int rc;
230 
231 	bzero(neg_ctxs, sizeof (*neg_ctxs));
232 	neg_ctxs->offset = md_tell(mdp);
233 	neg_ctxs->count = negctx_cnt;
234 
235 	/*
236 	 * There should be exactly 1 SMB2_PREAUTH_INTEGRITY_CAPS negotiate ctx.
237 	 * SMB2_ENCRYPTION_CAPS is optional one.
238 	 * If there is no contexts or there are too many then stop parsing.
239 	 */
240 	if (neg_ctxs->count < 1 || neg_ctxs->count > NEG_CTX_MAX_COUNT) {
241 		err = EINVAL;
242 		goto errout;
243 	}
244 
245 	/*
246 	 * Parse negotiate contexts. Ignore non-decoding errors to fill
247 	 * as much as possible data for dtrace probe.  Decode into the
248 	 * temporary neg_ctx, and then once we know which type it is
249 	 * (in the switch below) copy it to the specific member, eg
250 	 * neg_ctxs->preauth_ctx.neg_ctx (do this copying even if
251 	 * we detect errors so we have better data in neg_ctxs
252 	 * for the dtrace probe later in this function).
253 	 */
254 	for (int i = 0; i < neg_ctxs->count; i++) {
255 		smb2_neg_ctx_t neg_ctx;
256 		uint32_t ctx_start;
257 		uint32_t ctx_end_off;
258 		uint32_t ctx_next_off;
259 
260 		/*
261 		 * Every context must be 8-byte aligned.
262 		 */
263 		ctx_start = md_tell(mdp);
264 		if ((ctx_start % 8) != 0) {
265 			err = EINVAL;
266 			goto errout;
267 		}
268 
269 		/*
270 		 * Get Type, len, and "reserved"
271 		 */
272 		if (md_get_uint16le(mdp, &neg_ctx.type) != 0 ||
273 		    md_get_uint16le(mdp, &neg_ctx.datalen) != 0 ||
274 		    md_get_uint32le(mdp, NULL) != 0) {
275 			err = EINVAL;
276 			goto errout;
277 		}
278 		DTRACE_PROBE1(neg_ctx, smb2_neg_ctx_t *, &neg_ctx);
279 
280 		/*
281 		 * We got something crazy?
282 		 */
283 		if (neg_ctx.datalen > NEG_CTX_MAX_DATALEN) {
284 			err = EINVAL;
285 			goto errout;
286 		}
287 
288 		/*
289 		 * Figure out where the next ctx should be.
290 		 * We're now at position: ctx_start + 8
291 		 */
292 		ctx_end_off = ctx_start + 8 + neg_ctx.datalen;
293 		ctx_next_off = P2ROUNDUP(ctx_end_off, 8);
294 
295 		switch (neg_ctx.type) {
296 		case SMB2_PREAUTH_INTEGRITY_CAPS:
297 			memcpy(&neg_ctxs->preauth_ctx.neg_ctx, &neg_ctx,
298 			    sizeof (neg_ctx));
299 
300 			/*
301 			 * There should be exactly one of these,
302 			 * per. [MS-SMB2] sec. 3.2.5.2
303 			 */
304 			if (found_preauth_ctx++ != 0) {
305 				err = EINVAL;
306 				goto errout;
307 			}
308 
309 			rc = md_get_uint16le(mdp, &picap->picap_hash_count);
310 			if (rc != 0) {
311 				err = EINVAL;
312 				goto errout;
313 			}
314 
315 			rc = md_get_uint16le(mdp, &picap->picap_salt_len);
316 			if (rc != 0) {
317 				err = EINVAL;
318 				goto errout;
319 			}
320 
321 			/*
322 			 * Get hash id.  Must have exactly one
323 			 * here in the reply to the client.
324 			 */
325 			if (picap->picap_hash_count != 1) {
326 				err = EINVAL;
327 				goto errout;
328 			}
329 			rc = md_get_uint16le(mdp, &picap->picap_hash_id);
330 			if (rc != 0) {
331 				err = EINVAL;
332 				goto errout;
333 			}
334 
335 			/*
336 			 * Skip salt from the server reply.
337 			 * We don't use it directly.  It's there
338 			 * just to make the hash less predictable.
339 			 * Skip the space it occupies.
340 			 */
341 			rc = md_get_mem(mdp, NULL,
342 			    picap->picap_salt_len, MB_MSYSTEM);
343 			if (rc != 0) {
344 				err = EINVAL;
345 				goto errout;
346 			}
347 			break;
348 
349 		case SMB2_ENCRYPTION_CAPS:
350 			memcpy(&neg_ctxs->encrypt_ctx.neg_ctx, &neg_ctx,
351 			    sizeof (neg_ctx));
352 
353 			if (found_encrypt_ctx++ != 0) {
354 				err = EINVAL;
355 				goto errout;
356 			}
357 
358 			/*
359 			 * Get the cipher.  Should be exactly one,
360 			 * per. [MS-SMB2] sec. 3.2.5.2
361 			 */
362 			rc = md_get_uint16le(mdp, &encap->encap_cipher_count);
363 			if (rc != 0 || encap->encap_cipher_count != 1) {
364 				err = EINVAL;
365 				goto errout;
366 			}
367 			rc = md_get_uint16le(mdp,
368 			    &encap->encap_cipher_ids[0]);
369 			if (rc != 0) {
370 				err = EINVAL;
371 				goto errout;
372 			}
373 			cipher = encap->encap_cipher_ids[0];
374 			break;
375 
376 		default:
377 			/*
378 			 * Unknown context types are ignored.
379 			 * We should only get context types that
380 			 * correspond to what we sent, but there's
381 			 * not really any need to enforce that.
382 			 */
383 			SMBSDEBUG("Unknown neg. ctx. type: 0x%x",
384 			    neg_ctx.type);
385 			break;
386 		}
387 
388 		/*
389 		 * If there's another context after this,
390 		 * skip any padding that might remain, or
391 		 * parts we didn't bother to decode.
392 		 */
393 		if ((i + 1) < neg_ctxs->count) {
394 			int skip = ctx_next_off - md_tell(mdp);
395 			if (skip < 0) {
396 				err = EINVAL;
397 				goto errout;
398 			}
399 			if (skip > 0) {
400 				(void) md_get_mem(mdp, NULL, skip, MB_MSYSTEM);
401 			}
402 		}
403 
404 	}
405 
406 	if (err != 0)
407 		goto errout;
408 
409 	DTRACE_PROBE1(decoded, smb2_neg_ctxs_t *, neg_ctxs);
410 
411 	/*
412 	 * In SMB 0x311 there should be exactly 1 preauth
413 	 * negotiate context, and there should be exactly 1
414 	 * hash value in the list - SHA512.
415 	 */
416 	if (found_preauth_ctx != 1 || picap->picap_hash_count != 1) {
417 		err = EINVAL;
418 		goto errout;
419 	}
420 	if (picap->picap_hash_id != SMB3_HASH_SHA512) {
421 		/* STATUS_SMB_NO_PREAUTH_INEGRITY_HASH_OVERLAP */
422 		err = EAUTH;
423 		goto errout;
424 	}
425 	vcp->vc3_preauth_hashid = SMB3_HASH_SHA512;
426 
427 	/*
428 	 * Negotiation response for the encryption cipher we'll use.
429 	 *
430 	 * In our negotiate request we provided a list of ciphers
431 	 * we're willing to use.  If the server has any in common
432 	 * with our list, it will have chosen one and put that
433 	 * cipher ID in the response now in the "cipher" variable.
434 	 * If there were no mutually acceptable ciphers. we'll have
435 	 * cipher = SMB3_CIPHER_NONE.  If the server does not know
436 	 * about cipher negotiation, the SMB2_ENCRYPTION_CAPS neg.
437 	 * context might be absent, and we treat that the same as
438 	 * the "no overlap" case (cipher = SMB3_CIPHER_NONE).
439 	 *
440 	 * If the result of this cipher negotiaion gives us
441 	 * cipher = SMB3_CIPHER_NONE, that means we cannot use
442 	 * SMB2 encrypted messages.  In general, that alone is
443 	 * not a problem so severe that we should give up on this
444 	 * connection.  We can use SMB2/3 requests and responses
445 	 * without encryption if the server permits that.
446 	 *
447 	 * If encryption is mandatory based on server policy, eg
448 	 * when some share is marked as "encryption required",
449 	 * then our later SMB Tree Connect (smbfs mount) will fail.
450 	 * Similarly if the server requires encryption for all
451 	 * connections, we'll get an error from the server after
452 	 * sending a mesage that should have been encrypted.
453 	 */
454 	if (found_encrypt_ctx == 0) {
455 		vcp->vc3_enc_cipherid = SMB3_CIPHER_NONE;
456 	} else {
457 		/* Sanity check what we got. */
458 		switch (cipher) {
459 		case SMB3_CIPHER_AES256_GCM:
460 		case SMB3_CIPHER_AES128_GCM:
461 			vcp->vc3_enc_cipherid = cipher;
462 			break;
463 		case SMB3_CIPHER_AES256_CCM:
464 		case SMB3_CIPHER_AES128_CCM:
465 			vcp->vc3_enc_cipherid = cipher;
466 			break;
467 		default:
468 			vcp->vc3_enc_cipherid = SMB3_CIPHER_NONE;
469 			break;
470 		}
471 	}
472 
473 errout:
474 	return (err);
475 }
476