xref: /titanic_52/usr/src/common/crypto/dh/dh_impl.c (revision 53a3dbbbad58b810bf04c5f94c0ac119a1d8d348)
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