1726fad2aSDina K Nimeh /* 2726fad2aSDina K Nimeh * CDDL HEADER START 3726fad2aSDina K Nimeh * 4726fad2aSDina K Nimeh * The contents of this file are subject to the terms of the 5726fad2aSDina K Nimeh * Common Development and Distribution License (the "License"). 6726fad2aSDina K Nimeh * You may not use this file except in compliance with the License. 7726fad2aSDina K Nimeh * 8726fad2aSDina K Nimeh * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9726fad2aSDina K Nimeh * or http://www.opensolaris.org/os/licensing. 10726fad2aSDina K Nimeh * See the License for the specific language governing permissions 11726fad2aSDina K Nimeh * and limitations under the License. 12726fad2aSDina K Nimeh * 13726fad2aSDina K Nimeh * When distributing Covered Code, include this CDDL HEADER in each 14726fad2aSDina K Nimeh * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15726fad2aSDina K Nimeh * If applicable, add the following below this CDDL HEADER, with the 16726fad2aSDina K Nimeh * fields enclosed by brackets "[]" replaced with your own identifying 17726fad2aSDina K Nimeh * information: Portions Copyright [yyyy] [name of copyright owner] 18726fad2aSDina K Nimeh * 19726fad2aSDina K Nimeh * CDDL HEADER END 20726fad2aSDina K Nimeh */ 21726fad2aSDina K Nimeh 22726fad2aSDina K Nimeh /* 23726fad2aSDina K Nimeh * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 24726fad2aSDina K Nimeh */ 25726fad2aSDina K Nimeh 26726fad2aSDina K Nimeh /* 27726fad2aSDina K Nimeh * This file contains DH helper routines common to 28726fad2aSDina K Nimeh * the PKCS11 soft token code and the kernel DH code. 29726fad2aSDina K Nimeh */ 30726fad2aSDina K Nimeh 31726fad2aSDina K Nimeh #include <sys/types.h> 32726fad2aSDina K Nimeh #include <sys/sysmacros.h> 33726fad2aSDina K Nimeh #include <bignum.h> 34726fad2aSDina K Nimeh 35726fad2aSDina K Nimeh #ifdef _KERNEL 36726fad2aSDina K Nimeh #include <sys/param.h> 37726fad2aSDina K Nimeh #else 38726fad2aSDina K Nimeh #include <strings.h> 39726fad2aSDina K Nimeh #include <cryptoutil.h> 40726fad2aSDina K Nimeh #endif 41726fad2aSDina K Nimeh 42726fad2aSDina K Nimeh #include <sys/crypto/common.h> 43726fad2aSDina K Nimeh #include <des/des_impl.h> 44726fad2aSDina K Nimeh #include "dh_impl.h" 45726fad2aSDina K Nimeh 46726fad2aSDina K Nimeh 47726fad2aSDina K Nimeh static CK_RV 48726fad2aSDina K Nimeh convert_rv(BIG_ERR_CODE err) 49726fad2aSDina K Nimeh { 50726fad2aSDina K Nimeh switch (err) { 51726fad2aSDina K Nimeh 52726fad2aSDina K Nimeh case BIG_OK: 53726fad2aSDina K Nimeh return (CKR_OK); 54726fad2aSDina K Nimeh 55726fad2aSDina K Nimeh case BIG_NO_MEM: 56726fad2aSDina K Nimeh return (CKR_HOST_MEMORY); 57726fad2aSDina K Nimeh 58726fad2aSDina K Nimeh case BIG_NO_RANDOM: 59726fad2aSDina K Nimeh return (CKR_DEVICE_ERROR); 60726fad2aSDina K Nimeh 61726fad2aSDina K Nimeh case BIG_INVALID_ARGS: 62726fad2aSDina K Nimeh return (CKR_ARGUMENTS_BAD); 63726fad2aSDina K Nimeh 64726fad2aSDina K Nimeh case BIG_DIV_BY_0: 65726fad2aSDina K Nimeh default: 66726fad2aSDina K Nimeh return (CKR_GENERAL_ERROR); 67726fad2aSDina K Nimeh } 68726fad2aSDina K Nimeh } 69726fad2aSDina K Nimeh 70726fad2aSDina K Nimeh /* size is in bits */ 71726fad2aSDina K Nimeh static BIG_ERR_CODE 72726fad2aSDina K Nimeh DH_key_init(DHkey *key, int size) 73726fad2aSDina K Nimeh { 74726fad2aSDina K Nimeh BIG_ERR_CODE err = BIG_OK; 75726fad2aSDina K Nimeh int len; 76726fad2aSDina K Nimeh 77726fad2aSDina K Nimeh len = BITLEN2BIGNUMLEN(size); 78726fad2aSDina K Nimeh key->size = size; 79726fad2aSDina K Nimeh 80726fad2aSDina K Nimeh if ((err = big_init(&(key->p), len)) != BIG_OK) 81726fad2aSDina K Nimeh return (err); 82726fad2aSDina K Nimeh if ((err = big_init(&(key->g), len)) != BIG_OK) 83726fad2aSDina K Nimeh goto ret1; 84726fad2aSDina K Nimeh if ((err = big_init(&(key->x), len)) != BIG_OK) 85726fad2aSDina K Nimeh goto ret2; 86726fad2aSDina K Nimeh if ((err = big_init(&(key->y), len)) != BIG_OK) 87726fad2aSDina K Nimeh goto ret3; 88726fad2aSDina K Nimeh 89726fad2aSDina K Nimeh return (BIG_OK); 90726fad2aSDina K Nimeh 91726fad2aSDina K Nimeh ret3: 92726fad2aSDina K Nimeh big_finish(&(key->x)); 93726fad2aSDina K Nimeh ret2: 94726fad2aSDina K Nimeh big_finish(&(key->g)); 95726fad2aSDina K Nimeh ret1: 96726fad2aSDina K Nimeh big_finish(&(key->p)); 97726fad2aSDina K Nimeh return (err); 98726fad2aSDina K Nimeh } 99726fad2aSDina K Nimeh 100726fad2aSDina K Nimeh static void 101726fad2aSDina K Nimeh DH_key_finish(DHkey *key) 102726fad2aSDina K Nimeh { 103726fad2aSDina K Nimeh 104726fad2aSDina K Nimeh big_finish(&(key->y)); 105726fad2aSDina K Nimeh big_finish(&(key->x)); 106726fad2aSDina K Nimeh big_finish(&(key->g)); 107726fad2aSDina K Nimeh big_finish(&(key->p)); 108726fad2aSDina K Nimeh 109726fad2aSDina K Nimeh } 110726fad2aSDina K Nimeh 111726fad2aSDina K Nimeh /* 112726fad2aSDina K Nimeh * Generate DH key pair x and y, given prime p and base g. 113726fad2aSDina K Nimeh * Can optionally provided bit length of x, not to exceed bit length of p. 114*53a3dbbbSJason King * 115*53a3dbbbSJason King * For those not familiar with DH keys, there are 4 components: 116*53a3dbbbSJason King * p - a known prime 117*53a3dbbbSJason King * g - the base 0 < g < p 118*53a3dbbbSJason King * x - a random number 0 < x < p-1, or if a smaller value is desired, 119*53a3dbbbSJason King * 2^(len-1) <= x < 2^(len) 120*53a3dbbbSJason King * y = g^x mod p, this implies 0 < y < p. That is important! 121726fad2aSDina K Nimeh */ 122726fad2aSDina K Nimeh CK_RV 123726fad2aSDina K Nimeh dh_genkey_pair(DHbytekey *bkey) 124726fad2aSDina K Nimeh { 125726fad2aSDina K Nimeh CK_RV rv = CKR_OK; 126726fad2aSDina K Nimeh BIG_ERR_CODE brv; 127726fad2aSDina K Nimeh uint32_t primebit_len; 128726fad2aSDina K Nimeh DHkey dhkey; 129726fad2aSDina K Nimeh int (*rf)(void *, size_t); 130726fad2aSDina K Nimeh uint32_t prime_bytes; 131726fad2aSDina K Nimeh 132726fad2aSDina K Nimeh if (bkey == NULL) 133726fad2aSDina K Nimeh return (CKR_ARGUMENTS_BAD); 134726fad2aSDina K Nimeh 135726fad2aSDina K Nimeh /* Must have prime and base set, value bits can be 0 or non-0 */ 136726fad2aSDina K Nimeh if (bkey->prime_bits == 0 || bkey->prime == NULL || 137726fad2aSDina K Nimeh bkey->base_bytes == 0 || bkey->base == NULL) 138726fad2aSDina K Nimeh return (CKR_ARGUMENTS_BAD); 139726fad2aSDina K Nimeh 140726fad2aSDina K Nimeh prime_bytes = CRYPTO_BITS2BYTES(bkey->prime_bits); 141726fad2aSDina K Nimeh 142726fad2aSDina K Nimeh if ((prime_bytes < MIN_DH_KEYLENGTH_IN_BYTES) || 143726fad2aSDina K Nimeh (prime_bytes > MAX_DH_KEYLENGTH_IN_BYTES)) { 144726fad2aSDina K Nimeh return (CKR_KEY_SIZE_RANGE); 145726fad2aSDina K Nimeh } 146726fad2aSDina K Nimeh 147726fad2aSDina K Nimeh /* 148726fad2aSDina K Nimeh * Initialize the DH key. 149726fad2aSDina K Nimeh * Note: big_extend takes length in words. 150726fad2aSDina K Nimeh */ 151726fad2aSDina K Nimeh if ((brv = DH_key_init(&dhkey, bkey->prime_bits)) != BIG_OK) { 152726fad2aSDina K Nimeh rv = convert_rv(brv); 153726fad2aSDina K Nimeh goto ret; 154726fad2aSDina K Nimeh } 155726fad2aSDina K Nimeh 156726fad2aSDina K Nimeh /* Convert prime p to bignum. */ 157726fad2aSDina K Nimeh if ((brv = big_extend(&(dhkey.p), CHARLEN2BIGNUMLEN(prime_bytes))) != 158726fad2aSDina K Nimeh BIG_OK) { 159726fad2aSDina K Nimeh rv = convert_rv(brv); 160726fad2aSDina K Nimeh goto ret; 161726fad2aSDina K Nimeh } 162726fad2aSDina K Nimeh bytestring2bignum(&(dhkey.p), bkey->prime, prime_bytes); 163726fad2aSDina K Nimeh 164726fad2aSDina K Nimeh /* Convert base g to bignum. */ 165726fad2aSDina K Nimeh if ((brv = big_extend(&(dhkey.g), 166726fad2aSDina K Nimeh CHARLEN2BIGNUMLEN(bkey->base_bytes))) != BIG_OK) { 167726fad2aSDina K Nimeh rv = convert_rv(brv); 168726fad2aSDina K Nimeh goto ret; 169726fad2aSDina K Nimeh } 170726fad2aSDina K Nimeh bytestring2bignum(&(dhkey.g), bkey->base, bkey->base_bytes); 171726fad2aSDina K Nimeh 172726fad2aSDina K Nimeh /* Base g cannot be greater than prime p. */ 173726fad2aSDina K Nimeh if (big_cmp_abs(&(dhkey.g), &(dhkey.p)) >= 0) { 174726fad2aSDina K Nimeh rv = CKR_ATTRIBUTE_VALUE_INVALID; 175726fad2aSDina K Nimeh goto ret; 176726fad2aSDina K Nimeh } 177726fad2aSDina K Nimeh 178726fad2aSDina K Nimeh /* 179726fad2aSDina K Nimeh * The intention of selecting a private-value length is to reduce 180726fad2aSDina K Nimeh * the computation time for key agreement, while maintaining a 181726fad2aSDina K Nimeh * given level of security. 182726fad2aSDina K Nimeh */ 183726fad2aSDina K Nimeh 184726fad2aSDina K Nimeh /* Maximum bit length for private-value x is bit length of prime p */ 185726fad2aSDina K Nimeh primebit_len = big_bitlength(&(dhkey.p)); 186726fad2aSDina K Nimeh 187726fad2aSDina K Nimeh if (bkey->value_bits == 0) 188726fad2aSDina K Nimeh bkey->value_bits = primebit_len; 189726fad2aSDina K Nimeh 190726fad2aSDina K Nimeh if (bkey->value_bits > primebit_len) { 191726fad2aSDina K Nimeh rv = CKR_ATTRIBUTE_VALUE_INVALID; 192726fad2aSDina K Nimeh goto ret; 193726fad2aSDina K Nimeh } 194726fad2aSDina K Nimeh 195726fad2aSDina K Nimeh /* Generate DH key pair private and public values. */ 196*53a3dbbbSJason King if ((brv = big_extend(&(dhkey.x), BITLEN2BIGNUMLEN(bkey->value_bits))) 197726fad2aSDina K Nimeh != BIG_OK) { 198726fad2aSDina K Nimeh rv = convert_rv(brv); 199726fad2aSDina K Nimeh goto ret; 200726fad2aSDina K Nimeh } 201726fad2aSDina K Nimeh 202726fad2aSDina K Nimeh if ((brv = big_extend(&(dhkey.y), CHARLEN2BIGNUMLEN(prime_bytes))) 203726fad2aSDina K Nimeh != BIG_OK) { 204726fad2aSDina K Nimeh rv = convert_rv(brv); 205726fad2aSDina K Nimeh goto ret; 206726fad2aSDina K Nimeh } 207726fad2aSDina K Nimeh 208726fad2aSDina K Nimeh /* 209726fad2aSDina K Nimeh * The big integer of the private value shall be generated privately 210726fad2aSDina K Nimeh * and randomly. 211726fad2aSDina K Nimeh */ 212726fad2aSDina K Nimeh rf = bkey->rfunc; 213726fad2aSDina K Nimeh if (rf == NULL) { 214726fad2aSDina K Nimeh #ifdef _KERNEL 215726fad2aSDina K Nimeh rf = random_get_pseudo_bytes; 216726fad2aSDina K Nimeh #else 217726fad2aSDina K Nimeh rf = pkcs11_get_urandom; 218726fad2aSDina K Nimeh #endif 219726fad2aSDina K Nimeh } 220726fad2aSDina K Nimeh 221726fad2aSDina K Nimeh if ((brv = big_random(&(dhkey.x), bkey->value_bits, rf)) != BIG_OK) { 222726fad2aSDina K Nimeh rv = convert_rv(brv); 223726fad2aSDina K Nimeh goto ret; 224726fad2aSDina K Nimeh } 225726fad2aSDina K Nimeh 226726fad2aSDina K Nimeh /* 227726fad2aSDina K Nimeh * The base g shall be raised to the private value x modulo p to 228726fad2aSDina K Nimeh * give an integer y, the integer public value, i.e. y = (g^x) mod p. 229726fad2aSDina K Nimeh */ 230726fad2aSDina K Nimeh if ((brv = big_modexp(&(dhkey.y), &(dhkey.g), &(dhkey.x), 231726fad2aSDina K Nimeh &(dhkey.p), NULL)) != BIG_OK) { 232726fad2aSDina K Nimeh rv = convert_rv(brv); 233726fad2aSDina K Nimeh goto ret; 234726fad2aSDina K Nimeh } 235726fad2aSDina K Nimeh 236*53a3dbbbSJason King bignum2bytestring(bkey->private_x, &(dhkey.x), 237*53a3dbbbSJason King CRYPTO_BITS2BYTES(bkey->value_bits)); 238726fad2aSDina K Nimeh bignum2bytestring(bkey->public_y, &(dhkey.y), prime_bytes); 239726fad2aSDina K Nimeh 240726fad2aSDina K Nimeh ret: 241726fad2aSDina K Nimeh DH_key_finish(&dhkey); 242726fad2aSDina K Nimeh 243726fad2aSDina K Nimeh return (rv); 244726fad2aSDina K Nimeh } 245726fad2aSDina K Nimeh 246726fad2aSDina K Nimeh /* 247*53a3dbbbSJason King * DH key derive operation, flag is ignored in userland 248726fad2aSDina K Nimeh */ 249726fad2aSDina K Nimeh CK_RV 250726fad2aSDina K Nimeh dh_key_derive(DHbytekey *bkey, uint32_t key_type, /* = CKK_KEY_TYPE */ 251*53a3dbbbSJason King uchar_t *secretkey, uint32_t *secretkey_len, /* derived secret */ 252*53a3dbbbSJason King int flag) 253726fad2aSDina K Nimeh { 254726fad2aSDina K Nimeh CK_RV rv = CKR_OK; 255726fad2aSDina K Nimeh BIG_ERR_CODE brv; 256726fad2aSDina K Nimeh DHkey dhkey; 257726fad2aSDina K Nimeh uchar_t *s = NULL; 258726fad2aSDina K Nimeh uint32_t s_bytes = 0; 259726fad2aSDina K Nimeh uint32_t prime_bytes; 260726fad2aSDina K Nimeh uint32_t value_bytes; 261*53a3dbbbSJason King size_t s_alloc; 262726fad2aSDina K Nimeh 263726fad2aSDina K Nimeh if (bkey == NULL) 264726fad2aSDina K Nimeh return (CKR_ARGUMENTS_BAD); 265726fad2aSDina K Nimeh 266726fad2aSDina K Nimeh /* Must have prime, private value and public value */ 267726fad2aSDina K Nimeh if (bkey->prime_bits == 0 || bkey->prime == NULL || 268726fad2aSDina K Nimeh bkey->value_bits == 0 || bkey->private_x == NULL || 269726fad2aSDina K Nimeh bkey->public_y == NULL) 270726fad2aSDina K Nimeh return (CKR_ARGUMENTS_BAD); 271726fad2aSDina K Nimeh 272726fad2aSDina K Nimeh if (secretkey == NULL) { 273726fad2aSDina K Nimeh return (CKR_ARGUMENTS_BAD); 274726fad2aSDina K Nimeh } 275726fad2aSDina K Nimeh 276726fad2aSDina K Nimeh prime_bytes = CRYPTO_BITS2BYTES(bkey->prime_bits); 277726fad2aSDina K Nimeh value_bytes = CRYPTO_BITS2BYTES(bkey->value_bits); 278726fad2aSDina K Nimeh 279726fad2aSDina K Nimeh /* 280726fad2aSDina K Nimeh * Initialize the DH key. 281726fad2aSDina K Nimeh * Note: big_extend takes length in words. 282726fad2aSDina K Nimeh */ 283726fad2aSDina K Nimeh if ((brv = DH_key_init(&dhkey, bkey->prime_bits)) != BIG_OK) { 284726fad2aSDina K Nimeh rv = convert_rv(brv); 285726fad2aSDina K Nimeh goto ret; 286726fad2aSDina K Nimeh } 287726fad2aSDina K Nimeh 288726fad2aSDina K Nimeh /* Convert prime p to bignum. */ 289726fad2aSDina K Nimeh if ((brv = big_extend(&(dhkey.p), CHARLEN2BIGNUMLEN(prime_bytes))) != 290726fad2aSDina K Nimeh BIG_OK) { 291726fad2aSDina K Nimeh rv = convert_rv(brv); 292726fad2aSDina K Nimeh goto ret; 293726fad2aSDina K Nimeh } 294726fad2aSDina K Nimeh bytestring2bignum(&(dhkey.p), bkey->prime, prime_bytes); 295726fad2aSDina K Nimeh 296726fad2aSDina K Nimeh /* Convert private-value x to bignum. */ 297726fad2aSDina K Nimeh if ((brv = big_extend(&(dhkey.x), CHARLEN2BIGNUMLEN(value_bytes))) != 298726fad2aSDina K Nimeh BIG_OK) { 299726fad2aSDina K Nimeh rv = convert_rv(brv); 300726fad2aSDina K Nimeh goto ret; 301726fad2aSDina K Nimeh } 302726fad2aSDina K Nimeh bytestring2bignum(&(dhkey.x), bkey->private_x, value_bytes); 303726fad2aSDina K Nimeh 304726fad2aSDina K Nimeh /* Convert public-value y to bignum. */ 305*53a3dbbbSJason King if ((brv = big_extend(&(dhkey.y), CHARLEN2BIGNUMLEN(prime_bytes))) != 306726fad2aSDina K Nimeh BIG_OK) { 307726fad2aSDina K Nimeh rv = convert_rv(brv); 308726fad2aSDina K Nimeh goto ret; 309726fad2aSDina K Nimeh } 310*53a3dbbbSJason King bytestring2bignum(&(dhkey.y), bkey->public_y, prime_bytes); 311726fad2aSDina K Nimeh 312726fad2aSDina K Nimeh /* 313726fad2aSDina K Nimeh * Recycle base g as a temporary variable to compute the derived 314726fad2aSDina K Nimeh * secret value which is "g" = (y^x) mod p. (Not recomputing g.) 315726fad2aSDina K Nimeh */ 316726fad2aSDina K Nimeh if ((brv = big_extend(&(dhkey.g), CHARLEN2BIGNUMLEN(prime_bytes))) != 317726fad2aSDina K Nimeh BIG_OK) { 318726fad2aSDina K Nimeh rv = convert_rv(brv); 319726fad2aSDina K Nimeh goto ret; 320726fad2aSDina K Nimeh } 321726fad2aSDina K Nimeh 322726fad2aSDina K Nimeh if ((brv = big_modexp(&(dhkey.g), &(dhkey.y), &(dhkey.x), 323726fad2aSDina K Nimeh &(dhkey.p), NULL)) != BIG_OK) { 324726fad2aSDina K Nimeh rv = convert_rv(brv); 325726fad2aSDina K Nimeh goto ret; 326726fad2aSDina K Nimeh } 327726fad2aSDina K Nimeh 328*53a3dbbbSJason King s_alloc = P2ROUNDUP_TYPED(prime_bytes, sizeof (BIG_CHUNK_TYPE), size_t); 329*53a3dbbbSJason King 330726fad2aSDina K Nimeh #ifdef _KERNEL 331*53a3dbbbSJason King if ((s = kmem_alloc(s_alloc, flag)) == NULL) { 332726fad2aSDina K Nimeh rv = CKR_HOST_MEMORY; 333726fad2aSDina K Nimeh goto ret; 334726fad2aSDina K Nimeh } 335*53a3dbbbSJason King #else 336*53a3dbbbSJason King if ((s = malloc(s_alloc)) == NULL) { 337*53a3dbbbSJason King rv = CKR_HOST_MEMORY; 338*53a3dbbbSJason King goto ret; 339*53a3dbbbSJason King } 340*53a3dbbbSJason King #endif 341726fad2aSDina K Nimeh s_bytes = dhkey.g.len * (int)sizeof (BIG_CHUNK_TYPE); 342726fad2aSDina K Nimeh bignum2bytestring(s, &(dhkey.g), s_bytes); 343726fad2aSDina K Nimeh 344726fad2aSDina K Nimeh switch (key_type) { 345726fad2aSDina K Nimeh 346726fad2aSDina K Nimeh case CKK_DES: 347726fad2aSDina K Nimeh *secretkey_len = DES_KEYSIZE; 348726fad2aSDina K Nimeh break; 349726fad2aSDina K Nimeh case CKK_DES2: 350726fad2aSDina K Nimeh *secretkey_len = DES2_KEYSIZE; 351726fad2aSDina K Nimeh break; 352726fad2aSDina K Nimeh case CKK_DES3: 353726fad2aSDina K Nimeh *secretkey_len = DES3_KEYSIZE; 354726fad2aSDina K Nimeh break; 355726fad2aSDina K Nimeh case CKK_RC4: 356726fad2aSDina K Nimeh case CKK_AES: 357726fad2aSDina K Nimeh case CKK_GENERIC_SECRET: 358726fad2aSDina K Nimeh /* use provided secret key length, if any */ 359726fad2aSDina K Nimeh break; 360726fad2aSDina K Nimeh default: 361726fad2aSDina K Nimeh /* invalid key type */ 362726fad2aSDina K Nimeh rv = CKR_ATTRIBUTE_TYPE_INVALID; 363726fad2aSDina K Nimeh goto ret; 364726fad2aSDina K Nimeh } 365726fad2aSDina K Nimeh 366726fad2aSDina K Nimeh if (*secretkey_len == 0) { 367726fad2aSDina K Nimeh *secretkey_len = s_bytes; 368726fad2aSDina K Nimeh } 369726fad2aSDina K Nimeh 370726fad2aSDina K Nimeh if (*secretkey_len > s_bytes) { 371726fad2aSDina K Nimeh rv = CKR_ATTRIBUTE_VALUE_INVALID; 372726fad2aSDina K Nimeh goto ret; 373726fad2aSDina K Nimeh } 374726fad2aSDina K Nimeh 375726fad2aSDina K Nimeh /* 376726fad2aSDina K Nimeh * The truncation removes bytes from the leading end of the 377726fad2aSDina K Nimeh * secret value. 378726fad2aSDina K Nimeh */ 379726fad2aSDina K Nimeh (void) memcpy(secretkey, (s + s_bytes - *secretkey_len), 380726fad2aSDina K Nimeh *secretkey_len); 381726fad2aSDina K Nimeh 382726fad2aSDina K Nimeh ret: 383726fad2aSDina K Nimeh if (s != NULL) 384726fad2aSDina K Nimeh #ifdef _KERNEL 385*53a3dbbbSJason King kmem_free(s, s_alloc); 386726fad2aSDina K Nimeh #else 387726fad2aSDina K Nimeh free(s); 388726fad2aSDina K Nimeh #endif 389726fad2aSDina K Nimeh 390726fad2aSDina K Nimeh DH_key_finish(&dhkey); 391726fad2aSDina K Nimeh 392726fad2aSDina K Nimeh return (rv); 393726fad2aSDina K Nimeh } 394