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 2019 Nexenta Systems, Inc. All rights reserved.
14 * Copyright 2024 RackTop Systems, Inc.
15 */
16
17 /*
18 * Support for SMB3 encryption (message privacy)
19 */
20
21 #include <sys/param.h>
22 #include <sys/systm.h>
23 #include <sys/conf.h>
24 #include <sys/proc.h>
25 #include <sys/fcntl.h>
26 #include <sys/socket.h>
27 #include <sys/kmem.h>
28 #include <sys/errno.h>
29 #include <sys/cmn_err.h>
30 #include <sys/random.h>
31 #include <sys/stream.h>
32 #include <sys/strsun.h>
33 #include <sys/sdt.h>
34
35 #include <netsmb/smb_osdep.h>
36 #include <netsmb/smb2.h>
37 #include <netsmb/smb_conn.h>
38 #include <netsmb/smb_subr.h>
39 #include <netsmb/smb_dev.h>
40 #include <netsmb/smb_rq.h>
41
42 #include <netsmb/nsmb_kcrypt.h>
43
44 #define SMB3_TFORM_HDR_SIZE 52
45 #define SMB3_NONCE_OFFS 20
46 #define SMB3_SIG_OFFS 4
47
48 static const uint8_t SMB3_CRYPT_SIG[4] = { 0xFD, 'S', 'M', 'B' };
49
50 /*
51 * Initialize crypto mechanisms we'll need.
52 * Called after negotiate.
53 */
54 void
nsmb_crypt_init_mech(struct smb_vc * vcp)55 nsmb_crypt_init_mech(struct smb_vc *vcp)
56 {
57 smb_crypto_mech_t *mech;
58 int rc;
59
60 if (vcp->vc3_crypt_mech != NULL)
61 return;
62
63 mech = kmem_zalloc(sizeof (*mech), KM_SLEEP);
64
65 /* Always CCM for now. */
66 rc = nsmb_aes_ccm_getmech(mech);
67 if (rc != 0) {
68 kmem_free(mech, sizeof (*mech));
69 cmn_err(CE_NOTE, "SMB3 found no AES mechanism"
70 " (encryption disabled)");
71 return;
72 }
73 vcp->vc3_crypt_mech = mech;
74 }
75
76 void
nsmb_crypt_free_mech(struct smb_vc * vcp)77 nsmb_crypt_free_mech(struct smb_vc *vcp)
78 {
79 smb_crypto_mech_t *mech;
80
81 if ((mech = vcp->vc3_crypt_mech) == NULL)
82 return;
83
84 kmem_free(mech, sizeof (*mech));
85 }
86
87 /*
88 * Initialize keys for encryption
89 * Called after session setup.
90 */
91 void
nsmb_crypt_init_keys(struct smb_vc * vcp)92 nsmb_crypt_init_keys(struct smb_vc *vcp)
93 {
94
95 /*
96 * If we don't have a session key, we'll fail later when a
97 * request that requires (en/de)cryption can't be (en/de)crypted.
98 * Also don't bother initializing if we don't have a mechanism.
99 */
100 if (vcp->vc3_crypt_mech == NULL ||
101 vcp->vc_ssnkeylen <= 0)
102 return;
103
104 /*
105 * For SMB3, the encrypt/decrypt keys are derived from
106 * the session key using KDF in counter mode.
107 */
108 if (nsmb_kdf(vcp->vc3_encrypt_key, SMB3_KEYLEN,
109 vcp->vc_ssnkey, vcp->vc_ssnkeylen,
110 (uint8_t *)"SMB2AESCCM", 11,
111 (uint8_t *)"ServerIn ", 10) != 0)
112 return;
113
114 if (nsmb_kdf(vcp->vc3_decrypt_key, SMB3_KEYLEN,
115 vcp->vc_ssnkey, vcp->vc_ssnkeylen,
116 (uint8_t *)"SMB2AESCCM", 11,
117 (uint8_t *)"ServerOut", 10) != 0)
118 return;
119
120 vcp->vc3_encrypt_key_len = SMB3_KEYLEN;
121 vcp->vc3_decrypt_key_len = SMB3_KEYLEN;
122
123 (void) random_get_pseudo_bytes(
124 (uint8_t *)&vcp->vc3_nonce_low,
125 sizeof (vcp->vc3_nonce_low));
126 (void) random_get_pseudo_bytes(
127 (uint8_t *)&vcp->vc3_nonce_high,
128 sizeof (vcp->vc3_nonce_high));
129 }
130
131 /*
132 * Encrypt the message in *mpp, in place, prepending the
133 * SMB3 transform header.
134 *
135 * Any non-zero return is an error (values not used).
136 */
137 int
smb3_msg_encrypt(struct smb_vc * vcp,mblk_t ** mpp)138 smb3_msg_encrypt(struct smb_vc *vcp, mblk_t **mpp)
139 {
140 smb_enc_ctx_t ctx;
141 mblk_t *body, *thdr, *lastm;
142 struct mbchain mbp_store;
143 struct mbchain *mbp = &mbp_store;
144 uint32_t bodylen;
145 uint8_t *authdata;
146 size_t authlen;
147 int rc;
148
149 ASSERT(RW_WRITE_HELD(&vcp->iod_rqlock));
150
151 if (vcp->vc3_crypt_mech == NULL ||
152 vcp->vc3_encrypt_key_len != SMB3_KEYLEN) {
153 return (ENOTSUP);
154 }
155
156 bzero(&ctx, sizeof (ctx));
157 ctx.mech = *((smb_crypto_mech_t *)vcp->vc3_crypt_mech);
158
159 body = *mpp;
160 bodylen = msgdsize(body);
161
162 /*
163 * Get a new "nonce". Access to these counters is
164 * serialized by iod_rqlock (assert above).
165 */
166 vcp->vc3_nonce_low++;
167 if (vcp->vc3_nonce_low == 0) {
168 vcp->vc3_nonce_low++;
169 vcp->vc3_nonce_high++;
170 }
171
172 /*
173 * Build the transform header, keeping pointers to the various
174 * parts of it that we'll need to refer to later.
175 */
176 (void) mb_init(mbp);
177 thdr = mbp->mb_top;
178 ASSERT(MBLKTAIL(thdr) >= SMB3_TFORM_HDR_SIZE);
179 mb_put_mem(mbp, SMB3_CRYPT_SIG, 4, MB_MSYSTEM);
180 mb_put_mem(mbp, NULL, SMB2_SIG_SIZE, MB_MZERO); // signature (later)
181 mb_put_uint64le(mbp, vcp->vc3_nonce_low);
182 mb_put_uint64le(mbp, vcp->vc3_nonce_high);
183 /* Zero last 5 bytes of nonce per. spec. */
184 bzero(thdr->b_wptr - 5, 5);
185 mb_put_uint32le(mbp, bodylen);
186 mb_put_uint16le(mbp, 0); // reserved
187 mb_put_uint16le(mbp, 1); // flags
188 mb_put_uint64le(mbp, vcp->vc2_session_id);
189 mbp->mb_top = NULL; // keeping thdr
190 mb_done(mbp);
191
192 /*
193 * Need pointers to the part of the transfor header
194 * after the signature (starting with the nonce).
195 */
196 authdata = thdr->b_rptr + SMB3_NONCE_OFFS;
197 authlen = SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS;
198
199 nsmb_crypto_init_ccm_param(&ctx,
200 authdata, SMB2_SIG_SIZE,
201 authdata, authlen, bodylen);
202
203 rc = nsmb_encrypt_init(&ctx,
204 vcp->vc3_encrypt_key, vcp->vc3_encrypt_key_len);
205 if (rc != 0)
206 goto errout;
207
208 /*
209 * Temporarily append the transform header onto the
210 * body mblk chain with its r/w pointers set to cover
211 * just the signature, needed for how encrypt works.
212 * Could just use linkb() but we need to unlink the
213 * block as well so just find the tail ourselves.
214 */
215 ASSERT(MBLKL(thdr) == SMB3_TFORM_HDR_SIZE);
216 thdr->b_rptr += SMB3_SIG_OFFS;
217 thdr->b_wptr = thdr->b_rptr + SMB2_SIG_SIZE;
218 lastm = body;
219 while (lastm->b_cont != NULL)
220 lastm = lastm->b_cont;
221 lastm->b_cont = thdr;
222
223 /*
224 * The mblk chain is ready. Encrypt!
225 */
226 rc = nsmb_encrypt_mblks(&ctx, body, bodylen);
227 /* check rc below */
228
229 /* Unlink thdr and restore r/w pointers. */
230 lastm->b_cont = NULL;
231 thdr->b_rptr -= SMB3_SIG_OFFS;
232 thdr->b_wptr = thdr->b_rptr + SMB3_TFORM_HDR_SIZE;
233
234 /* Now check rc from encrypt */
235 if (rc != 0)
236 goto errout;
237
238 /*
239 * Lastly, prepend the transform header.
240 */
241 thdr->b_cont = body;
242 *mpp = thdr;
243 nsmb_enc_ctx_done(&ctx);
244 return (0);
245
246 errout:
247 freeb(thdr);
248 nsmb_enc_ctx_done(&ctx);
249 return (rc);
250 }
251
252 /*
253 * Decrypt the message in *mpp, in place, removing the
254 * SMB3 transform header.
255 *
256 * Any non-zero return is an error (values not used).
257 */
258 int
smb3_msg_decrypt(struct smb_vc * vcp,mblk_t ** mpp)259 smb3_msg_decrypt(struct smb_vc *vcp, mblk_t **mpp)
260 {
261 smb_enc_ctx_t ctx;
262 uint8_t th_sig[4];
263 mblk_t *body, *thdr, *lastm;
264 struct mdchain mdp_store;
265 struct mdchain *mdp = &mdp_store;
266 uint64_t th_ssnid;
267 uint32_t bodylen, tlen;
268 uint16_t th_flags;
269 uint8_t *authdata;
270 size_t authlen;
271 int rc;
272
273 if (vcp->vc3_crypt_mech == NULL ||
274 vcp->vc3_encrypt_key_len != SMB3_KEYLEN) {
275 return (ENOTSUP);
276 }
277
278 bzero(&ctx, sizeof (ctx));
279 ctx.mech = *((smb_crypto_mech_t *)vcp->vc3_crypt_mech);
280
281 /*
282 * Split off the transform header
283 * We need it contiguous.
284 */
285 thdr = *mpp;
286 body = m_split(thdr, SMB3_TFORM_HDR_SIZE, 1);
287 if (body == NULL)
288 return (ENOSR);
289 thdr = m_pullup(thdr, SMB3_TFORM_HDR_SIZE);
290 if (thdr == NULL)
291 return (ENOSR);
292
293 /*
294 * Decode the transform header
295 */
296 (void) md_initm(mdp, thdr);
297 md_get_mem(mdp, th_sig, 4, MB_MSYSTEM);
298 md_get_mem(mdp, NULL, SMB2_SIG_SIZE, MB_MZERO); // signature
299 md_get_mem(mdp, NULL, SMB2_SIG_SIZE, MB_MZERO); // nonce
300 md_get_uint32le(mdp, &bodylen);
301 md_get_uint16le(mdp, NULL); // reserved
302 md_get_uint16le(mdp, &th_flags);
303 md_get_uint64le(mdp, &th_ssnid);
304 mdp->md_top = NULL; // keeping thdr
305 md_done(mdp);
306
307 /*
308 * Validate transform header fields
309 */
310 if (bcmp(th_sig, SMB3_CRYPT_SIG, 4) != 0) {
311 rc = EPROTO;
312 goto errout;
313 }
314 if (th_flags != 1 || th_ssnid != vcp->vc2_session_id) {
315 rc = EINVAL;
316 goto errout;
317 }
318
319 /*
320 * Check actual body length (trim if necessary)
321 */
322 tlen = msgdsize(body);
323 if (tlen < bodylen) {
324 rc = EINVAL;
325 goto errout;
326 }
327 if (tlen > bodylen) {
328 /* trim from tail */
329 ssize_t adj;
330
331 adj = bodylen - tlen;
332 ASSERT(adj < 0);
333 (void) adjmsg(body, adj);
334 }
335
336 /*
337 * Need pointers to the part of the transfor header
338 * after the signature (starting with the nonce).
339 * tlen is now length of ciphertext
340 */
341 authdata = thdr->b_rptr + SMB3_NONCE_OFFS;
342 authlen = SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS;
343 tlen = bodylen + SMB2_SIG_SIZE;
344
345 nsmb_crypto_init_ccm_param(&ctx,
346 authdata, SMB2_SIG_SIZE,
347 authdata, authlen, tlen);
348
349 rc = nsmb_decrypt_init(&ctx,
350 vcp->vc3_decrypt_key, vcp->vc3_decrypt_key_len);
351 if (rc != 0)
352 goto errout;
353
354 /*
355 * Temporarily append the transform header onto the
356 * body mblk chain with its r/w pointers set to cover
357 * just the signature, needed for how decrypt works.
358 * Could just use linkb() but we need to unlink the
359 * block as well so just find the tail ourselves.
360 */
361 thdr->b_rptr += SMB3_SIG_OFFS;
362 thdr->b_wptr = thdr->b_rptr + SMB2_SIG_SIZE;
363 lastm = body;
364 while (lastm->b_cont != NULL)
365 lastm = lastm->b_cont;
366 lastm->b_cont = thdr;
367
368 /*
369 * The mblk chain is ready. Decrypt!
370 */
371 rc = nsmb_decrypt_mblks(&ctx, body, tlen);
372 /* check rc below */
373
374 /* Unlink thdr and restore r/w pointers. */
375 lastm->b_cont = NULL;
376 thdr->b_rptr -= SMB3_SIG_OFFS;
377 thdr->b_wptr = thdr->b_rptr + SMB3_TFORM_HDR_SIZE;
378
379 /* Now check rc from decrypt */
380 if (rc != 0)
381 goto errout;
382
383 /*
384 * Lastly, discard the transform header
385 * and return the body.
386 */
387 freeb(thdr);
388 *mpp = body;
389 nsmb_enc_ctx_done(&ctx);
390 return (0);
391
392 errout:
393 freeb(thdr);
394 nsmb_enc_ctx_done(&ctx);
395 return (rc);
396 }
397