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
convert_rv(BIG_ERR_CODE err)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
DH_key_init(DHkey * key,int size)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
DH_key_finish(DHkey * key)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
dh_genkey_pair(DHbytekey * bkey)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
dh_key_derive(DHbytekey * bkey,uint32_t key_type,uchar_t * secretkey,uint32_t * secretkey_len,int flag)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