xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_signing.c (revision 811599a462e8920d70cf548f4002182d3c222d13)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
24  */
25 /*
26  * These routines provide the SMB MAC signing for the SMB2 server.
27  * The routines calculate the signature of a SMB message in an mbuf chain.
28  *
29  * The following table describes the client server
30  * signing registry relationship
31  *
32  *		| Required	| Enabled     | Disabled
33  * -------------+---------------+------------ +--------------
34  * Required	| Signed	| Signed      | Fail
35  * -------------+---------------+-------------+-----------------
36  * Enabled	| Signed	| Signed      | Not Signed
37  * -------------+---------------+-------------+----------------
38  * Disabled	| Fail		| Not Signed  | Not Signed
39  */
40 
41 #include <sys/uio.h>
42 #include <smbsrv/smb_kproto.h>
43 #include <smbsrv/smb_signing.h>
44 #include <sys/isa_defs.h>
45 #include <sys/byteorder.h>
46 #include <sys/cmn_err.h>
47 
48 #define	SMB2_SIG_OFFS	48
49 #define	SMB2_SIG_SIZE	16
50 
51 typedef struct mac_ops {
52 	int (*mac_init)(smb_sign_ctx_t *, smb_sign_mech_t *,
53 			uint8_t *, size_t);
54 	int (*mac_update)(smb_sign_ctx_t, uint8_t *, size_t);
55 	int (*mac_final)(smb_sign_ctx_t, uint8_t *);
56 } mac_ops_t;
57 
58 static int smb2_sign_calc_common(smb_request_t *, struct mbuf_chain *,
59     uint8_t *, mac_ops_t *);
60 
61 static int smb3_do_kdf(void *, void *, size_t, uint8_t *, uint32_t);
62 
63 /*
64  * SMB2 wrapper functions
65  */
66 
67 static mac_ops_t
68 smb2_sign_ops = {
69 	smb2_hmac_init,
70 	smb2_hmac_update,
71 	smb2_hmac_final
72 };
73 
74 static int
75 smb2_sign_calc(smb_request_t *sr,
76     struct mbuf_chain *mbc,
77     uint8_t *digest16)
78 {
79 	int rv;
80 
81 	rv = smb2_sign_calc_common(sr, mbc, digest16, &smb2_sign_ops);
82 
83 	return (rv);
84 }
85 
86 /*
87  * Called during session destroy.
88  */
89 static void
90 smb2_sign_fini(smb_session_t *s)
91 {
92 	smb_sign_mech_t *mech;
93 
94 	if ((mech = s->sign_mech) != NULL) {
95 		kmem_free(mech, sizeof (*mech));
96 		s->sign_mech = NULL;
97 	}
98 }
99 
100 /*
101  * SMB3 wrapper functions
102  */
103 
104 static struct mac_ops
105 smb3_sign_ops = {
106 	smb3_cmac_init,
107 	smb3_cmac_update,
108 	smb3_cmac_final
109 };
110 
111 static int
112 smb3_sign_calc(smb_request_t *sr,
113     struct mbuf_chain *mbc,
114     uint8_t *digest16)
115 {
116 	int rv;
117 
118 	rv = smb2_sign_calc_common(sr, mbc, digest16, &smb3_sign_ops);
119 
120 	return (rv);
121 }
122 
123 /*
124  * Input to KDF for SigningKey.
125  * See comment for smb3_do_kdf for content.
126  */
127 static uint8_t sign_kdf_input[29] = {
128 	0, 0, 0, 1, 'S', 'M', 'B', '2',
129 	'A', 'E', 'S', 'C', 'M', 'A', 'C', 0,
130 	0, 'S', 'm', 'b', 'S', 'i', 'g', 'n',
131 	0, 0, 0, 0, 0x80 };
132 
133 void
134 smb2_sign_init_mech(smb_session_t *s)
135 {
136 	smb_sign_mech_t *mech;
137 	int (*get_mech)(smb_sign_mech_t *);
138 	int (*sign_calc)(smb_request_t *, struct mbuf_chain *, uint8_t *);
139 	int rc;
140 
141 	if (s->sign_mech != NULL)
142 		return;
143 
144 	if (s->dialect >= SMB_VERS_3_0) {
145 		get_mech = smb3_cmac_getmech;
146 		sign_calc = smb3_sign_calc;
147 	} else {
148 		get_mech = smb2_hmac_getmech;
149 		sign_calc = smb2_sign_calc;
150 	}
151 
152 	mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
153 	rc = get_mech(mech);
154 	if (rc != 0) {
155 		kmem_free(mech, sizeof (*mech));
156 		return;
157 	}
158 	s->sign_mech = mech;
159 	s->sign_calc = sign_calc;
160 	s->sign_fini = smb2_sign_fini;
161 }
162 
163 /*
164  * smb2_sign_begin
165  * Handles both SMB2 & SMB3
166  *
167  * Get the mechanism info.
168  * Intializes MAC key based on the user session key and store it in
169  * the signing structure.  This begins signing on this session.
170  */
171 void
172 smb2_sign_begin(smb_request_t *sr, smb_token_t *token)
173 {
174 	smb_session_t *s = sr->session;
175 	smb_user_t *u = sr->uid_user;
176 	struct smb_key *sign_key = &u->u_sign_key;
177 
178 	sign_key->len = 0;
179 
180 	/*
181 	 * We should normally have a session key here because
182 	 * our caller filters out Anonymous and Guest logons.
183 	 * However, buggy clients could get us here without a
184 	 * session key, in which case we'll fail later when a
185 	 * request that requires signing can't be checked.
186 	 * Also, don't bother initializing if we don't have a mechanism.
187 	 */
188 	if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0 ||
189 	    s->sign_mech == NULL)
190 		return;
191 
192 	/*
193 	 * Compute and store the signing key, which lives in
194 	 * the user structure.
195 	 */
196 	if (s->dialect >= SMB_VERS_3_0) {
197 		/*
198 		 * For SMB3, the signing key is a "KDF" hash of the
199 		 * session key.
200 		 */
201 		if (smb3_do_kdf(sign_key->key, sign_kdf_input,
202 		    sizeof (sign_kdf_input), token->tkn_ssnkey.val,
203 		    token->tkn_ssnkey.len) != 0)
204 			return;
205 		sign_key->len = SMB3_KEYLEN;
206 	} else {
207 		/*
208 		 * For SMB2, the signing key is just the first 16 bytes
209 		 * of the session key (truncated or padded with zeros).
210 		 * [MS-SMB2] 3.2.5.3.1
211 		 */
212 		sign_key->len = SMB2_SIG_SIZE;
213 		bcopy(token->tkn_ssnkey.val, sign_key->key,
214 		    MIN(token->tkn_ssnkey.len, sign_key->len));
215 	}
216 
217 	mutex_enter(&u->u_mutex);
218 	if (s->secmode & SMB2_NEGOTIATE_SIGNING_ENABLED)
219 		u->u_sign_flags |= SMB_SIGNING_ENABLED;
220 	if (s->secmode & SMB2_NEGOTIATE_SIGNING_REQUIRED)
221 		u->u_sign_flags |=
222 		    SMB_SIGNING_ENABLED | SMB_SIGNING_CHECK;
223 	mutex_exit(&u->u_mutex);
224 
225 	/*
226 	 * If we just turned on signing, the current request
227 	 * (an SMB2 session setup) will have come in without
228 	 * SMB2_FLAGS_SIGNED (and not signed) but the response
229 	 * is is supposed to be signed. [MS-SMB2] 3.3.5.5
230 	 */
231 	if (u->u_sign_flags & SMB_SIGNING_ENABLED)
232 		sr->smb2_hdr_flags |= SMB2_FLAGS_SIGNED;
233 }
234 
235 /*
236  * smb2_sign_calc_common
237  *
238  * Calculates MAC signature for the given buffer and returns
239  * it in the mac_sign parameter.
240  *
241  * The signature algorithm is to compute HMAC SHA256 or AES_CMAC
242  * over the entire command, with the signature field set to zeros.
243  *
244  * Return 0 if  success else -1
245  */
246 
247 static int
248 smb2_sign_calc_common(smb_request_t *sr, struct mbuf_chain *mbc,
249     uint8_t *digest, mac_ops_t *ops)
250 {
251 	uint8_t tmp_hdr[SMB2_HDR_SIZE];
252 	smb_sign_ctx_t ctx = 0;
253 	smb_session_t *s = sr->session;
254 	smb_user_t *u = sr->uid_user;
255 	struct smb_key *sign_key = &u->u_sign_key;
256 	struct mbuf *mbuf;
257 	int offset, resid, tlen, rc;
258 
259 	if (s->sign_mech == NULL || sign_key->len == 0)
260 		return (-1);
261 
262 	/* smb2_hmac_init or smb3_cmac_init */
263 	rc = ops->mac_init(&ctx, s->sign_mech, sign_key->key, sign_key->len);
264 	if (rc != 0)
265 		return (rc);
266 
267 	/*
268 	 * Work with a copy of the SMB2 header so we can
269 	 * clear the signature field without modifying
270 	 * the original message.
271 	 */
272 	tlen = SMB2_HDR_SIZE;
273 	offset = mbc->chain_offset;
274 	resid = mbc->max_bytes - offset;
275 	if (smb_mbc_peek(mbc, offset, "#c", tlen, tmp_hdr) != 0)
276 		return (-1);
277 	bzero(tmp_hdr + SMB2_SIG_OFFS, SMB2_SIG_SIZE);
278 	/* smb2_hmac_update or smb3_cmac_update */
279 	if ((rc = ops->mac_update(ctx, tmp_hdr, tlen)) != 0)
280 		return (rc);
281 	offset += tlen;
282 	resid -= tlen;
283 
284 	/*
285 	 * Digest the rest of the SMB packet, starting at the data
286 	 * just after the SMB header.
287 	 *
288 	 * Advance to the src mbuf where we start digesting.
289 	 */
290 	mbuf = mbc->chain;
291 	while (mbuf != NULL && (offset >= mbuf->m_len)) {
292 		offset -= mbuf->m_len;
293 		mbuf = mbuf->m_next;
294 	}
295 
296 	if (mbuf == NULL)
297 		return (-1);
298 
299 	/*
300 	 * Digest the remainder of this mbuf, limited to the
301 	 * residual count, and starting at the current offset.
302 	 * (typically SMB2_HDR_SIZE)
303 	 */
304 	tlen = mbuf->m_len - offset;
305 	if (tlen > resid)
306 		tlen = resid;
307 	/* smb2_hmac_update or smb3_cmac_update */
308 	rc = ops->mac_update(ctx, (uint8_t *)mbuf->m_data + offset, tlen);
309 	if (rc != 0)
310 		return (rc);
311 	resid -= tlen;
312 
313 	/*
314 	 * Digest any more mbufs in the chain.
315 	 */
316 	while (resid > 0) {
317 		mbuf = mbuf->m_next;
318 		if (mbuf == NULL)
319 			return (-1);
320 		tlen = mbuf->m_len;
321 		if (tlen > resid)
322 			tlen = resid;
323 		rc = ops->mac_update(ctx, (uint8_t *)mbuf->m_data, tlen);
324 		if (rc != 0)
325 			return (rc);
326 		resid -= tlen;
327 	}
328 
329 	/*
330 	 * smb2_hmac_final or smb3_cmac_final
331 	 * Note: digest is _always_ SMB2_SIG_SIZE,
332 	 * even if the mech uses a longer one.
333 	 *
334 	 * smb2_hmac_update or smb3_cmac_update
335 	 */
336 	if ((rc = ops->mac_final(ctx, digest)) != 0)
337 		return (rc);
338 
339 	return (0);
340 }
341 
342 /*
343  * smb2_sign_check_request
344  *
345  * Calculates MAC signature for the request mbuf chain
346  * using the next expected sequence number and compares
347  * it to the given signature.
348  *
349  * Note it does not check the signature for secondary transactions
350  * as their sequence number is the same as the original request.
351  *
352  * Return 0 if the signature verifies, otherwise, returns -1;
353  *
354  */
355 int
356 smb2_sign_check_request(smb_request_t *sr)
357 {
358 	uint8_t req_sig[SMB2_SIG_SIZE];
359 	uint8_t vfy_sig[SMB2_SIG_SIZE];
360 	struct mbuf_chain *mbc = &sr->smb_data;
361 	smb_session_t *s = sr->session;
362 	smb_user_t *u = sr->uid_user;
363 	int sig_off;
364 
365 	/*
366 	 * Don't check commands with a zero session ID.
367 	 * [MS-SMB2] 3.3.4.1.1
368 	 */
369 	if (sr->smb2_ssnid == 0 || u == NULL)
370 		return (0);
371 
372 	/* In case _sign_begin failed. */
373 	if (s->sign_calc == NULL)
374 		return (-1);
375 
376 	/* Get the request signature. */
377 	sig_off = sr->smb2_cmd_hdr + SMB2_SIG_OFFS;
378 	if (smb_mbc_peek(mbc, sig_off, "#c", SMB2_SIG_SIZE, req_sig) != 0)
379 		return (-1);
380 
381 	/*
382 	 * Compute the correct signature and compare.
383 	 * smb2_sign_calc() or smb3_sign_calc()
384 	 */
385 	if (s->sign_calc(sr, mbc, vfy_sig) != 0)
386 		return (-1);
387 	if (memcmp(vfy_sig, req_sig, SMB2_SIG_SIZE) != 0) {
388 		cmn_err(CE_NOTE, "smb2_sign_check_request: bad signature");
389 		return (-1);
390 	}
391 
392 	return (0);
393 }
394 
395 /*
396  * smb2_sign_reply
397  *
398  * Calculates MAC signature for the given mbuf chain,
399  * and write it to the signature field in the mbuf.
400  *
401  */
402 void
403 smb2_sign_reply(smb_request_t *sr)
404 {
405 	uint8_t reply_sig[SMB2_SIG_SIZE];
406 	struct mbuf_chain tmp_mbc;
407 	smb_session_t *s = sr->session;
408 	smb_user_t *u = sr->uid_user;
409 	int hdr_off, msg_len;
410 
411 	if (u == NULL)
412 		return;
413 	if (s->sign_calc == NULL)
414 		return;
415 
416 	msg_len = sr->reply.chain_offset - sr->smb2_reply_hdr;
417 	(void) MBC_SHADOW_CHAIN(&tmp_mbc, &sr->reply,
418 	    sr->smb2_reply_hdr, msg_len);
419 
420 	/*
421 	 * Calculate the MAC signature for this reply.
422 	 * smb2_sign_calc() or smb3_sign_calc()
423 	 */
424 	if (s->sign_calc(sr, &tmp_mbc, reply_sig) != 0)
425 		return;
426 
427 	/*
428 	 * Poke the signature into the response.
429 	 */
430 	hdr_off = sr->smb2_reply_hdr + SMB2_SIG_OFFS;
431 	(void) smb_mbc_poke(&sr->reply, hdr_off, "#c",
432 	    SMB2_SIG_SIZE, reply_sig);
433 }
434 
435 /*
436  * Derive SMB3 key as described in [MS-SMB2] 3.1.4.2
437  * and [NIST SP800-108]
438  *
439  * r = 32, L = 128, PRF = HMAC-SHA256, key = (session key)
440  *
441  * Note that these describe pre-3.1.1 inputs.
442  *
443  * Session.SigningKey for binding a session:
444  * - Session.SessionKey as K1
445  * - label = SMB2AESCMAC (size 12)
446  * - context = SmbSign (size 8)
447  * Channel.SigningKey for for all other requests
448  * - if SMB2_SESSION_FLAG_BINDING, GSS key (in Session.SessionKey?) as K1;
449  * - otherwise, Session.SessionKey as K1
450  * - label = SMB2AESCMAC (size 12)
451  * - context = SmbSign (size 8)
452  * Session.ApplicationKey for ... (not sure what yet)
453  * - Session.SessionKey as K1
454  * - label = SMB2APP (size 8)
455  * - context = SmbRpc (size 7)
456  */
457 static int
458 smb3_do_kdf(void *outbuf, void *input, size_t input_len,
459     uint8_t *key, uint32_t key_len)
460 {
461 	uint8_t digest32[SHA256_DIGEST_LENGTH];
462 	smb_sign_mech_t mech;
463 	smb_sign_ctx_t hctx = 0;
464 	int rc;
465 
466 	bzero(&mech, sizeof (mech));
467 	if ((rc = smb2_hmac_getmech(&mech)) != 0)
468 		return (rc);
469 
470 	/* Limit the SessionKey input to its maximum size (16 bytes) */
471 	rc = smb2_hmac_init(&hctx, &mech, key, MIN(key_len, SMB2_KEYLEN));
472 	if (rc != 0)
473 		return (rc);
474 
475 	if ((rc = smb2_hmac_update(hctx, input, input_len)) != 0)
476 		return (rc);
477 
478 	if ((rc = smb2_hmac_final(hctx, digest32)) != 0)
479 		return (rc);
480 
481 	/* Output is first 16 bytes of digest. */
482 	bcopy(digest32, outbuf, SMB3_KEYLEN);
483 	return (0);
484 }
485