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 2017-2021 Tintri by DDN, Inc. All rights reserved. 14 * Copyright 2022 RackTop Systems, Inc. 15 */ 16 17 /* 18 * Routines for smb3 encryption. 19 */ 20 21 #include <smbsrv/smb2_kproto.h> 22 #include <smbsrv/smb_kcrypt.h> 23 #include <sys/random.h> 24 #include <sys/cmn_err.h> 25 26 #define SMB3_NONCE_OFFS 20 27 #define SMB3_SIG_OFFS 4 28 29 /* 30 * Arbitrary value used to prevent nonce reuse via overflow. Currently 31 * 2^64 - 2^32 - 1. Assumes we can't have (or are unlikely to have) 32 * 2^32 concurrent messages when we hit this number. 33 */ 34 static uint64_t smb3_max_nonce = 0xffffffff00000000ULL; 35 36 /* 37 * Nonce generation based on draft-mcgrew-iv-gen-01 38 * "Generation of Deterministic Initialization Vectors (IVs) and Nonces" 39 * 40 * Generate an 8-byte random salt and a 3-byte random 'fixed' value. 41 * then, nonce = (++counter ^ salt) || fixed 42 * 43 * This protects against nonce-reuse (8-byte counter), as well as known 44 * attacks on reusing nonces with different keys 45 */ 46 47 void 48 smb3_encrypt_init_nonce(smb_user_t *user) 49 { 50 user->u_nonce_cnt = 0; 51 (void) random_get_pseudo_bytes(user->u_nonce_fixed, 52 sizeof (user->u_nonce_fixed)); 53 (void) random_get_pseudo_bytes((uint8_t *)&user->u_salt, 54 sizeof (user->u_salt)); 55 } 56 57 static int 58 smb3_encrypt_gen_nonce(smb_user_t *user, uint8_t *buf, size_t len) 59 { 60 uint64_t cnt; 61 62 /* 63 * Nonces must be unique per-key for the life of the key. 64 * Bail before we roll over to avoid breaking the crypto. 65 */ 66 cnt = atomic_inc_64_nv(&user->u_nonce_cnt); 67 if (cnt > smb3_max_nonce) 68 return (-1); 69 70 cnt ^= user->u_salt; 71 72 bcopy((uint8_t *)&cnt, buf, sizeof (cnt)); 73 74 ASSERT(len <= 16); // th_nonce 75 ASSERT(len > sizeof (cnt)); 76 bcopy(user->u_nonce_fixed, buf + sizeof (cnt), len - sizeof (cnt)); 77 return (0); 78 } 79 80 int 81 smb3_encrypt_init_mech(smb_session_t *s) 82 { 83 smb_crypto_mech_t *mech; 84 int rc; 85 86 if (s->enc_mech != NULL) 87 return (0); 88 89 mech = kmem_zalloc(sizeof (*mech), KM_SLEEP); 90 91 switch (s->smb31_enc_cipherid) { 92 case SMB3_CIPHER_AES256_GCM: 93 case SMB3_CIPHER_AES128_GCM: 94 rc = smb3_aes_gcm_getmech(mech); 95 break; 96 case SMB3_CIPHER_AES256_CCM: 97 case SMB3_CIPHER_AES128_CCM: 98 rc = smb3_aes_ccm_getmech(mech); 99 break; 100 default: 101 rc = -1; 102 break; 103 } 104 105 if (rc != 0) { 106 kmem_free(mech, sizeof (*mech)); 107 return (rc); 108 } 109 s->enc_mech = mech; 110 111 return (0); 112 } 113 114 /* 115 * Initializes keys/state required for SMB3 Encryption. 116 * Note: If a failure occurs here, don't fail the request. 117 * Instead, return an error when we attempt to encrypt/decrypt. 118 */ 119 void 120 smb3_encrypt_begin(smb_user_t *u, smb_token_t *token) 121 { 122 smb_session_t *s = u->u_session; 123 struct smb_key *enc_key = &u->u_enc_key; 124 struct smb_key *dec_key = &u->u_dec_key; 125 uint32_t derived_keylen, input_keylen; 126 127 /* 128 * In order to enforce encryption, all users need to 129 * have Session.EncryptData properly set, even anon/guest. 130 */ 131 u->u_encrypt = s->s_server->sv_cfg.skc_encrypt; 132 enc_key->len = 0; 133 dec_key->len = 0; 134 135 /* 136 * If we don't have a session key, we'll fail later when a 137 * request that requires (en/de)cryption can't be (en/de)crypted. 138 * Also don't bother initializing if we don't have a mechanism. 139 */ 140 if (token->tkn_ssnkey.val == NULL || token->tkn_ssnkey.len == 0 || 141 s->enc_mech == NULL) 142 return; 143 144 /* 145 * Compute and store the encryption keys, which live in 146 * the user structure. 147 */ 148 149 /* 150 * For SMB3, the encrypt/decrypt keys are derived from 151 * the session key using KDF in counter mode. 152 * 153 * AES256 Keys are derived from the 'FullSessionKey', which is the 154 * entirety of what we got in the token; AES128 Keys are derived from 155 * the 'SessionKey', which is the first 16 bytes of the key we got in 156 * the token. 157 */ 158 if (s->dialect >= SMB_VERS_3_11) { 159 if (s->smb31_enc_cipherid == SMB3_CIPHER_AES256_GCM || 160 s->smb31_enc_cipherid == SMB3_CIPHER_AES256_CCM) { 161 derived_keylen = AES256_KEY_LENGTH; 162 input_keylen = token->tkn_ssnkey.len; 163 } else { 164 derived_keylen = AES128_KEY_LENGTH; 165 input_keylen = MIN(SMB2_SSN_KEYLEN, 166 token->tkn_ssnkey.len); 167 } 168 169 if (smb3_kdf(enc_key->key, derived_keylen, 170 token->tkn_ssnkey.val, input_keylen, 171 (uint8_t *)"SMBS2CCipherKey", 16, 172 u->u_preauth_hashval, SHA512_DIGEST_LENGTH) != 0) 173 return; 174 175 if (smb3_kdf(dec_key->key, derived_keylen, 176 token->tkn_ssnkey.val, input_keylen, 177 (uint8_t *)"SMBC2SCipherKey", 16, 178 u->u_preauth_hashval, SHA512_DIGEST_LENGTH) != 0) 179 return; 180 181 enc_key->len = derived_keylen; 182 dec_key->len = derived_keylen; 183 } else { 184 derived_keylen = AES128_KEY_LENGTH; 185 input_keylen = MIN(SMB2_SSN_KEYLEN, token->tkn_ssnkey.len); 186 187 if (smb3_kdf(enc_key->key, derived_keylen, 188 token->tkn_ssnkey.val, input_keylen, 189 (uint8_t *)"SMB2AESCCM", 11, 190 (uint8_t *)"ServerOut", 10) != 0) 191 return; 192 193 if (smb3_kdf(dec_key->key, derived_keylen, 194 token->tkn_ssnkey.val, input_keylen, 195 (uint8_t *)"SMB2AESCCM", 11, 196 (uint8_t *)"ServerIn ", 10) != 0) 197 return; 198 199 enc_key->len = derived_keylen; 200 dec_key->len = derived_keylen; 201 } 202 203 smb3_encrypt_init_nonce(u); 204 205 /* 206 * XXX todo: setup crypto context for enc_key, dec_key. 207 * See crypto_create_ctx_template(mech, key, tmpl,...) 208 * 209 * Will need a new indirect functions eg. 210 * smb3_encrypt_init_templ(s->enc_mech, enc_key); 211 * smb3_encrypt_init_templ(s->enc_mech, dec_key); 212 * where struct smb_key gains a new member: 213 * void *template; 214 * 215 * Already have s->enc_mech from smb3_encrypt_init_mech(). 216 */ 217 } 218 219 static int 220 smb3_decode_tform_header(smb_request_t *sr, struct mbuf_chain *mbc) 221 { 222 uint32_t protocolid; 223 uint16_t flags; 224 int rc; 225 226 rc = smb_mbc_decodef( 227 mbc, "l16c16cl..wq", 228 &protocolid, /* l */ 229 sr->smb2_sig, /* 16c */ 230 sr->th_nonce, /* 16c */ 231 &sr->th_msglen, /* l */ 232 /* reserved .. */ 233 &flags, /* w */ 234 &sr->th_ssnid); /* q */ 235 if (rc) 236 return (rc); 237 238 /* This was checked in smb2sr_newrq() */ 239 ASSERT3U(protocolid, ==, SMB3_ENCRYPTED_MAGIC); 240 241 if (flags != 1) { 242 #ifdef DEBUG 243 cmn_err(CE_NOTE, "flags field not 1: %x", flags); 244 #endif 245 return (-1); 246 } 247 248 return (rc); 249 } 250 251 static int 252 smb3_encode_tform_header(smb_request_t *sr, struct mbuf_chain *mbc) 253 { 254 int rc; 255 256 rc = smb_mbc_encodef( 257 mbc, "l16.16clwwq", 258 SMB3_ENCRYPTED_MAGIC, /* l */ 259 /* signature(16) 16. (filled in later) */ 260 sr->th_nonce, /* 16c */ 261 sr->th_msglen, /* l */ 262 0, /* reserved w */ 263 1, /* flags w */ 264 sr->th_ssnid); /* q */ 265 266 return (rc); 267 } 268 269 /* 270 * Get an smb_vdb_t and initialize it. 271 * Free'd via smb_request_free 272 */ 273 static smb_vdb_t * 274 smb3_get_vdb(smb_request_t *sr) 275 { 276 smb_vdb_t *vdb; 277 278 vdb = smb_srm_zalloc(sr, sizeof (*vdb)); 279 vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0]; 280 vdb->vdb_uio.uio_iovcnt = MAX_IOVEC; 281 vdb->vdb_uio.uio_segflg = UIO_SYSSPACE; 282 vdb->vdb_uio.uio_extflg = UIO_COPY_DEFAULT; 283 284 return (vdb); 285 } 286 287 /* 288 * Decrypt the request in mbc_in into out_mbc which as been 289 * setup by the caller. The caller will replace sr->command 290 * with out_mbc if this succeeds, or will free which ever one 291 * ends up not being used as sr->command. 292 * 293 * The encrypted request in in_mbc is left unmodified here, 294 * and free'd by the caller when appropriate. 295 * 296 * Error return values here are just for visibility in dtrace. 297 * Anything non-zero results in a connection drop. 298 */ 299 int 300 smb3_decrypt_sr(smb_request_t *sr, 301 struct mbuf_chain *in_mbc, // transform header + ciphertext 302 struct mbuf_chain *out_mbc) // cleartext 303 { 304 smb_enc_ctx_t ctx; 305 uint8_t th_raw[SMB3_TFORM_HDR_SIZE]; 306 uint8_t *authdata; 307 size_t authlen; 308 size_t cipherlen; 309 smb_vdb_t *in_vdb = NULL; 310 smb_vdb_t *out_vdb = NULL; 311 smb_session_t *s = sr->session; 312 smb_user_t *u; 313 struct smb_key *dec_key; 314 int cnt, rc; 315 boolean_t gcm; 316 size_t nonce_size; 317 uint_t keylen; 318 319 if (s->enc_mech == NULL) 320 return (SET_ERROR(-1)); 321 322 switch (s->smb31_enc_cipherid) { 323 default: 324 ASSERT(0); 325 /* fallthrough */ 326 case SMB3_CIPHER_AES128_CCM: // 1 327 gcm = B_FALSE; 328 nonce_size = SMB3_AES_CCM_NONCE_SIZE; 329 keylen = AES128_KEY_LENGTH; 330 break; 331 case SMB3_CIPHER_AES128_GCM: // 2 332 gcm = B_TRUE; 333 nonce_size = SMB3_AES_GCM_NONCE_SIZE; 334 keylen = AES128_KEY_LENGTH; 335 break; 336 case SMB3_CIPHER_AES256_CCM: // 3 337 gcm = B_FALSE; 338 nonce_size = SMB3_AES_CCM_NONCE_SIZE; 339 keylen = AES256_KEY_LENGTH; 340 break; 341 case SMB3_CIPHER_AES256_GCM: // 4 342 gcm = B_TRUE; 343 nonce_size = SMB3_AES_GCM_NONCE_SIZE; 344 keylen = AES256_KEY_LENGTH; 345 break; 346 } 347 348 /* 349 * Get the transform header, in both raw form and decoded, 350 * then remove the transform header from the message. 351 * Note: the signature lands in sr->smb2_sig 352 */ 353 if (smb_mbc_peek(in_mbc, 0, "#c", 354 SMB3_TFORM_HDR_SIZE, th_raw) != 0) { 355 return (SET_ERROR(-2)); 356 } 357 rc = smb3_decode_tform_header(sr, in_mbc); 358 if (rc != 0) { 359 return (SET_ERROR(-3)); 360 } 361 m_adjust(in_mbc->chain, SMB3_TFORM_HDR_SIZE); 362 ASSERT(in_mbc->max_bytes > SMB3_TFORM_HDR_SIZE); 363 in_mbc->max_bytes -= SMB3_TFORM_HDR_SIZE; 364 in_mbc->chain_offset = 0; 365 366 /* 367 * Bounds-check the stated length of the encapsulated message. 368 */ 369 if (sr->th_msglen < SMB2_HDR_SIZE || 370 sr->th_msglen > in_mbc->max_bytes) { 371 return (SET_ERROR(-4)); 372 } 373 cipherlen = sr->th_msglen + SMB2_SIG_SIZE; 374 375 /* 376 * Lookup/validate the transform session ID so we'll 377 * have the key we'll need. Release for this happens 378 * in smb_request_free(). 379 */ 380 u = smb_session_lookup_ssnid(s, sr->th_ssnid); 381 if (u == NULL) { 382 return (SET_ERROR(-5)); 383 } 384 sr->th_sid_user = u; 385 dec_key = &u->u_dec_key; 386 if (dec_key->len != keylen) { 387 return (SET_ERROR(-6)); 388 } 389 390 /* 391 * Initialize crypto I/F: mech, params, key 392 * 393 * Unlike signing, which uses one global mech struct, 394 * encryption requires modifying the mech to add a 395 * per-use param struct. Thus, we need to make a copy. 396 */ 397 bzero(&ctx, sizeof (ctx)); 398 ctx.mech = *((smb_crypto_mech_t *)s->enc_mech); 399 400 /* 401 * The transform header, minus the PROTOCOL_ID and the 402 * SIGNATURE, is authenticated but not encrypted. 403 * (That's the "auth data" passed to init) 404 * 405 * Param init for CCM also needs the cipher length, which is 406 * the clear length + 16, but note that the last 16 bytes is 407 * the signature in the transform header. 408 */ 409 authdata = th_raw + SMB3_NONCE_OFFS; 410 authlen = SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS; 411 412 if (gcm) { 413 smb3_crypto_init_gcm_param(&ctx, 414 sr->th_nonce, nonce_size, 415 authdata, authlen); 416 } else { 417 smb3_crypto_init_ccm_param(&ctx, 418 sr->th_nonce, nonce_size, 419 authdata, authlen, cipherlen); 420 } 421 422 rc = smb3_decrypt_init(&ctx, 423 dec_key->key, dec_key->len); 424 if (rc != 0) 425 return (SET_ERROR(-7)); 426 427 /* 428 * Build a UIO vector for the ciphertext (in) 429 * a: remainder of the 1s segment after the transform header 430 * b: all subsequent segments of this message 431 * c: final 16 byte signature from the transform header 432 */ 433 in_vdb = smb3_get_vdb(sr); 434 in_vdb->vdb_uio.uio_resid = sr->th_msglen; 435 rc = smb_mbuf_mkuio(in_mbc->chain, &in_vdb->vdb_uio); 436 if (rc != 0) 437 return (SET_ERROR(-8)); 438 439 /* Add one more uio seg. for the signature. */ 440 cnt = in_vdb->vdb_uio.uio_iovcnt; 441 if ((cnt + 1) > MAX_IOVEC) 442 return (SET_ERROR(-9)); 443 in_vdb->vdb_uio.uio_iov[cnt].iov_base = (void *)sr->smb2_sig; 444 in_vdb->vdb_uio.uio_iov[cnt].iov_len = SMB2_SIG_SIZE; 445 in_vdb->vdb_uio.uio_iovcnt = cnt + 1; 446 in_vdb->vdb_uio.uio_resid += SMB2_SIG_SIZE; 447 448 /* 449 * Build a UIO vector for the cleartext (out) 450 */ 451 out_vdb = smb3_get_vdb(sr); 452 out_vdb->vdb_uio.uio_resid = sr->th_msglen; 453 rc = smb_mbuf_mkuio(out_mbc->chain, &out_vdb->vdb_uio); 454 if (rc != 0) 455 return (SET_ERROR(-10)); 456 457 /* 458 * Have in/out UIO descriptors. Decrypt! 459 */ 460 rc = smb3_decrypt_uio(&ctx, &in_vdb->vdb_uio, &out_vdb->vdb_uio); 461 if (rc != 0) { 462 #ifdef DEBUG 463 cmn_err(CE_WARN, "smb3_decrypt_uio failed"); 464 #endif 465 return (SET_ERROR(-11)); 466 } 467 468 return (rc); 469 } 470 471 /* 472 * Encrypt the response in in_mbc into out_mbc which as been 473 * setup by the caller. The caller will send out_mbc if this 474 * returns success, and otherwise will free out_mbc. 475 * 476 * The cleartext response in in_mbc is left unmodified here, 477 * and free'd in smb_request_free. 478 * 479 * Error return values here are just for visibility in dtrace. 480 * Anything non-zero results in a connection drop. 481 */ 482 int 483 smb3_encrypt_sr(smb_request_t *sr, 484 struct mbuf_chain *in_mbc, // cleartext 485 struct mbuf_chain *out_mbc) // transform header + ciphertext 486 { 487 smb_enc_ctx_t ctx; 488 uint8_t th_raw[SMB3_TFORM_HDR_SIZE]; 489 uint8_t *authdata; 490 size_t authlen; 491 smb_vdb_t *in_vdb = NULL; 492 smb_vdb_t *out_vdb = NULL; 493 smb_session_t *s = sr->session; 494 smb_user_t *u = sr->th_sid_user; 495 struct smb_key *enc_key = &u->u_enc_key; 496 int cnt, rc; 497 boolean_t gcm; 498 size_t nonce_size; 499 uint_t keylen; 500 501 VERIFY(u != NULL); // and have sr->th_ssnid 502 503 switch (s->smb31_enc_cipherid) { 504 default: 505 ASSERT(0); 506 /* fallthrough */ 507 case SMB3_CIPHER_AES128_CCM: // 1 508 gcm = B_FALSE; 509 nonce_size = SMB3_AES_CCM_NONCE_SIZE; 510 keylen = AES128_KEY_LENGTH; 511 break; 512 case SMB3_CIPHER_AES128_GCM: // 2 513 gcm = B_TRUE; 514 nonce_size = SMB3_AES_GCM_NONCE_SIZE; 515 keylen = AES128_KEY_LENGTH; 516 break; 517 case SMB3_CIPHER_AES256_CCM: // 3 518 gcm = B_FALSE; 519 nonce_size = SMB3_AES_CCM_NONCE_SIZE; 520 keylen = AES256_KEY_LENGTH; 521 break; 522 case SMB3_CIPHER_AES256_GCM: // 4 523 gcm = B_TRUE; 524 nonce_size = SMB3_AES_GCM_NONCE_SIZE; 525 keylen = AES256_KEY_LENGTH; 526 break; 527 } 528 if (s->enc_mech == NULL || enc_key->len != keylen) { 529 return (SET_ERROR(-1)); 530 } 531 532 /* 533 * Need to fill in the transform header for everything 534 * after the signature, needed as the "auth" data. 535 * The signature is stuffed in later. So we need: 536 * the nonce, msgsize, flags, th_ssnid 537 */ 538 rc = smb3_encrypt_gen_nonce(u, sr->th_nonce, nonce_size); 539 if (rc != 0) { 540 cmn_err(CE_WARN, "ran out of nonces"); 541 return (SET_ERROR(-2)); 542 } 543 if (smb3_encode_tform_header(sr, out_mbc) != 0) { 544 cmn_err(CE_WARN, "couldn't encode transform header"); 545 return (SET_ERROR(-3)); 546 } 547 548 /* Get the raw header to use as auth data */ 549 if (smb_mbc_peek(out_mbc, 0, "#c", 550 SMB3_TFORM_HDR_SIZE, th_raw) != 0) 551 return (SET_ERROR(-4)); 552 553 /* 554 * Initialize crypto I/F: mech, params, key 555 * 556 * Unlike signing, which uses one global mech struct, 557 * encryption requires modifying the mech to add a 558 * per-use param struct. Thus, we need to make a copy. 559 */ 560 bzero(&ctx, sizeof (ctx)); 561 ctx.mech = *((smb_crypto_mech_t *)s->enc_mech); 562 563 /* 564 * The transform header, minus the PROTOCOL_ID and the 565 * SIGNATURE, is authenticated but not encrypted. 566 * (That's the "auth data" passed to init) 567 * 568 * Param init for CCM also needs the cipher length, which is 569 * the clear length + 16, but note that the last 16 bytes is 570 * the signature in the transform header. 571 * 572 * Note: sr->th_msglen already set by caller 573 */ 574 authdata = th_raw + SMB3_NONCE_OFFS; 575 authlen = SMB3_TFORM_HDR_SIZE - SMB3_NONCE_OFFS; 576 577 if (gcm) { 578 smb3_crypto_init_gcm_param(&ctx, 579 sr->th_nonce, nonce_size, 580 authdata, authlen); 581 } else { 582 smb3_crypto_init_ccm_param(&ctx, 583 sr->th_nonce, nonce_size, 584 authdata, authlen, sr->th_msglen); 585 } 586 587 rc = smb3_encrypt_init(&ctx, 588 enc_key->key, enc_key->len); 589 if (rc != 0) 590 return (SET_ERROR(-5)); 591 592 /* 593 * Build a UIO vector for the cleartext (in) 594 */ 595 in_vdb = smb3_get_vdb(sr); 596 in_vdb->vdb_uio.uio_resid = sr->th_msglen; 597 rc = smb_mbuf_mkuio(in_mbc->chain, &in_vdb->vdb_uio); 598 if (rc != 0) 599 return (SET_ERROR(-6)); 600 601 /* 602 * Build a UIO vector for the ciphertext (out) 603 * a: remainder of the 1s segment after the transform header 604 * b: all subsequent segments of this message 605 * c: final 16 byte signature that will go in the TH 606 * 607 * Caller puts transform header in its own mblk so we can 608 * just skip the first mlbk when building the uio. 609 */ 610 out_vdb = smb3_get_vdb(sr); 611 out_vdb->vdb_uio.uio_resid = sr->th_msglen; 612 rc = smb_mbuf_mkuio(out_mbc->chain->m_next, &out_vdb->vdb_uio); 613 if (rc != 0) 614 return (SET_ERROR(-7)); 615 616 /* Add one more uio seg. for the signature. */ 617 cnt = out_vdb->vdb_uio.uio_iovcnt; 618 if ((cnt + 1) > MAX_IOVEC) 619 return (SET_ERROR(-8)); 620 out_vdb->vdb_uio.uio_iov[cnt].iov_base = (void *)sr->smb2_sig; 621 out_vdb->vdb_uio.uio_iov[cnt].iov_len = SMB2_SIG_SIZE; 622 out_vdb->vdb_uio.uio_iovcnt = cnt + 1; 623 out_vdb->vdb_uio.uio_resid += SMB2_SIG_SIZE; 624 625 /* 626 * Have in/out UIO descriptors. Encrypt! 627 */ 628 rc = smb3_encrypt_uio(&ctx, &in_vdb->vdb_uio, &out_vdb->vdb_uio); 629 if (rc != 0) { 630 #ifdef DEBUG 631 cmn_err(CE_WARN, "smb3_encrypt_uio failed"); 632 #endif 633 return (SET_ERROR(-9)); 634 } 635 636 /* 637 * Now patch the final signature into the transform header 638 */ 639 (void) smb_mbc_poke(out_mbc, SMB3_SIG_OFFS, "#c", 640 SMB2_SIG_SIZE, sr->smb2_sig); 641 642 return (rc); 643 } 644 645 void 646 smb3_encrypt_ssn_fini(smb_session_t *s) 647 { 648 smb_crypto_mech_t *mech; 649 650 if ((mech = s->enc_mech) != NULL) { 651 kmem_free(mech, sizeof (*mech)); 652 s->enc_mech = NULL; 653 } 654 } 655