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 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 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 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 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 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