1 /*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9 * or http://www.opensolaris.org/os/licensing.
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22 /*
23 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
24 */
25
26 /*
27 * This file contains DH helper routines common to
28 * the PKCS11 soft token code and the kernel DH code.
29 */
30
31 #include <sys/types.h>
32 #include <sys/sysmacros.h>
33 #include <bignum.h>
34
35 #ifdef _KERNEL
36 #include <sys/param.h>
37 #else
38 #include <strings.h>
39 #include <cryptoutil.h>
40 #endif
41
42 #include <sys/crypto/common.h>
43 #include <des/des_impl.h>
44 #include "dh_impl.h"
45
46
47 static CK_RV
convert_rv(BIG_ERR_CODE err)48 convert_rv(BIG_ERR_CODE err)
49 {
50 switch (err) {
51
52 case BIG_OK:
53 return (CKR_OK);
54
55 case BIG_NO_MEM:
56 return (CKR_HOST_MEMORY);
57
58 case BIG_NO_RANDOM:
59 return (CKR_DEVICE_ERROR);
60
61 case BIG_INVALID_ARGS:
62 return (CKR_ARGUMENTS_BAD);
63
64 case BIG_DIV_BY_0:
65 default:
66 return (CKR_GENERAL_ERROR);
67 }
68 }
69
70 /* size is in bits */
71 static BIG_ERR_CODE
DH_key_init(DHkey * key,int size)72 DH_key_init(DHkey *key, int size)
73 {
74 BIG_ERR_CODE err = BIG_OK;
75 int len;
76
77 len = BITLEN2BIGNUMLEN(size);
78 key->size = size;
79
80 if ((err = big_init(&(key->p), len)) != BIG_OK)
81 return (err);
82 if ((err = big_init(&(key->g), len)) != BIG_OK)
83 goto ret1;
84 if ((err = big_init(&(key->x), len)) != BIG_OK)
85 goto ret2;
86 if ((err = big_init(&(key->y), len)) != BIG_OK)
87 goto ret3;
88
89 return (BIG_OK);
90
91 ret3:
92 big_finish(&(key->x));
93 ret2:
94 big_finish(&(key->g));
95 ret1:
96 big_finish(&(key->p));
97 return (err);
98 }
99
100 static void
DH_key_finish(DHkey * key)101 DH_key_finish(DHkey *key)
102 {
103
104 big_finish(&(key->y));
105 big_finish(&(key->x));
106 big_finish(&(key->g));
107 big_finish(&(key->p));
108
109 }
110
111 /*
112 * Generate DH key pair x and y, given prime p and base g.
113 * Can optionally provided bit length of x, not to exceed bit length of p.
114 *
115 * For those not familiar with DH keys, there are 4 components:
116 * p - a known prime
117 * g - the base 0 < g < p
118 * x - a random number 0 < x < p-1, or if a smaller value is desired,
119 * 2^(len-1) <= x < 2^(len)
120 * y = g^x mod p, this implies 0 < y < p. That is important!
121 */
122 CK_RV
dh_genkey_pair(DHbytekey * bkey)123 dh_genkey_pair(DHbytekey *bkey)
124 {
125 CK_RV rv = CKR_OK;
126 BIG_ERR_CODE brv;
127 uint32_t primebit_len;
128 DHkey dhkey;
129 int (*rf)(void *, size_t);
130 uint32_t prime_bytes;
131
132 if (bkey == NULL)
133 return (CKR_ARGUMENTS_BAD);
134
135 /* Must have prime and base set, value bits can be 0 or non-0 */
136 if (bkey->prime_bits == 0 || bkey->prime == NULL ||
137 bkey->base_bytes == 0 || bkey->base == NULL)
138 return (CKR_ARGUMENTS_BAD);
139
140 prime_bytes = CRYPTO_BITS2BYTES(bkey->prime_bits);
141
142 if ((prime_bytes < MIN_DH_KEYLENGTH_IN_BYTES) ||
143 (prime_bytes > MAX_DH_KEYLENGTH_IN_BYTES)) {
144 return (CKR_KEY_SIZE_RANGE);
145 }
146
147 /*
148 * Initialize the DH key.
149 * Note: big_extend takes length in words.
150 */
151 if ((brv = DH_key_init(&dhkey, bkey->prime_bits)) != BIG_OK) {
152 rv = convert_rv(brv);
153 goto ret;
154 }
155
156 /* Convert prime p to bignum. */
157 if ((brv = big_extend(&(dhkey.p), CHARLEN2BIGNUMLEN(prime_bytes))) !=
158 BIG_OK) {
159 rv = convert_rv(brv);
160 goto ret;
161 }
162 bytestring2bignum(&(dhkey.p), bkey->prime, prime_bytes);
163
164 /* Convert base g to bignum. */
165 if ((brv = big_extend(&(dhkey.g),
166 CHARLEN2BIGNUMLEN(bkey->base_bytes))) != BIG_OK) {
167 rv = convert_rv(brv);
168 goto ret;
169 }
170 bytestring2bignum(&(dhkey.g), bkey->base, bkey->base_bytes);
171
172 /* Base g cannot be greater than prime p. */
173 if (big_cmp_abs(&(dhkey.g), &(dhkey.p)) >= 0) {
174 rv = CKR_ATTRIBUTE_VALUE_INVALID;
175 goto ret;
176 }
177
178 /*
179 * The intention of selecting a private-value length is to reduce
180 * the computation time for key agreement, while maintaining a
181 * given level of security.
182 */
183
184 /* Maximum bit length for private-value x is bit length of prime p */
185 primebit_len = big_bitlength(&(dhkey.p));
186
187 if (bkey->value_bits == 0)
188 bkey->value_bits = primebit_len;
189
190 if (bkey->value_bits > primebit_len) {
191 rv = CKR_ATTRIBUTE_VALUE_INVALID;
192 goto ret;
193 }
194
195 /* Generate DH key pair private and public values. */
196 if ((brv = big_extend(&(dhkey.x), BITLEN2BIGNUMLEN(bkey->value_bits)))
197 != BIG_OK) {
198 rv = convert_rv(brv);
199 goto ret;
200 }
201
202 if ((brv = big_extend(&(dhkey.y), CHARLEN2BIGNUMLEN(prime_bytes)))
203 != BIG_OK) {
204 rv = convert_rv(brv);
205 goto ret;
206 }
207
208 /*
209 * The big integer of the private value shall be generated privately
210 * and randomly.
211 */
212 rf = bkey->rfunc;
213 if (rf == NULL) {
214 #ifdef _KERNEL
215 rf = random_get_pseudo_bytes;
216 #else
217 rf = pkcs11_get_urandom;
218 #endif
219 }
220
221 if ((brv = big_random(&(dhkey.x), bkey->value_bits, rf)) != BIG_OK) {
222 rv = convert_rv(brv);
223 goto ret;
224 }
225
226 /*
227 * The base g shall be raised to the private value x modulo p to
228 * give an integer y, the integer public value, i.e. y = (g^x) mod p.
229 */
230 if ((brv = big_modexp(&(dhkey.y), &(dhkey.g), &(dhkey.x),
231 &(dhkey.p), NULL)) != BIG_OK) {
232 rv = convert_rv(brv);
233 goto ret;
234 }
235
236 bignum2bytestring(bkey->private_x, &(dhkey.x),
237 CRYPTO_BITS2BYTES(bkey->value_bits));
238 bignum2bytestring(bkey->public_y, &(dhkey.y), prime_bytes);
239
240 ret:
241 DH_key_finish(&dhkey);
242
243 return (rv);
244 }
245
246 /*
247 * DH key derive operation, flag is ignored in userland
248 */
249 CK_RV
dh_key_derive(DHbytekey * bkey,uint32_t key_type,uchar_t * secretkey,uint32_t * secretkey_len,int flag)250 dh_key_derive(DHbytekey *bkey, uint32_t key_type, /* = CKK_KEY_TYPE */
251 uchar_t *secretkey, uint32_t *secretkey_len, /* derived secret */
252 int flag)
253 {
254 CK_RV rv = CKR_OK;
255 BIG_ERR_CODE brv;
256 DHkey dhkey;
257 uchar_t *s = NULL;
258 uint32_t s_bytes = 0;
259 uint32_t prime_bytes;
260 uint32_t value_bytes;
261 size_t s_alloc;
262
263 if (bkey == NULL)
264 return (CKR_ARGUMENTS_BAD);
265
266 /* Must have prime, private value and public value */
267 if (bkey->prime_bits == 0 || bkey->prime == NULL ||
268 bkey->value_bits == 0 || bkey->private_x == NULL ||
269 bkey->public_y == NULL)
270 return (CKR_ARGUMENTS_BAD);
271
272 if (secretkey == NULL) {
273 return (CKR_ARGUMENTS_BAD);
274 }
275
276 prime_bytes = CRYPTO_BITS2BYTES(bkey->prime_bits);
277 value_bytes = CRYPTO_BITS2BYTES(bkey->value_bits);
278
279 /*
280 * Initialize the DH key.
281 * Note: big_extend takes length in words.
282 */
283 if ((brv = DH_key_init(&dhkey, bkey->prime_bits)) != BIG_OK) {
284 rv = convert_rv(brv);
285 goto ret;
286 }
287
288 /* Convert prime p to bignum. */
289 if ((brv = big_extend(&(dhkey.p), CHARLEN2BIGNUMLEN(prime_bytes))) !=
290 BIG_OK) {
291 rv = convert_rv(brv);
292 goto ret;
293 }
294 bytestring2bignum(&(dhkey.p), bkey->prime, prime_bytes);
295
296 /* Convert private-value x to bignum. */
297 if ((brv = big_extend(&(dhkey.x), CHARLEN2BIGNUMLEN(value_bytes))) !=
298 BIG_OK) {
299 rv = convert_rv(brv);
300 goto ret;
301 }
302 bytestring2bignum(&(dhkey.x), bkey->private_x, value_bytes);
303
304 /* Convert public-value y to bignum. */
305 if ((brv = big_extend(&(dhkey.y), CHARLEN2BIGNUMLEN(prime_bytes))) !=
306 BIG_OK) {
307 rv = convert_rv(brv);
308 goto ret;
309 }
310 bytestring2bignum(&(dhkey.y), bkey->public_y, prime_bytes);
311
312 /*
313 * Recycle base g as a temporary variable to compute the derived
314 * secret value which is "g" = (y^x) mod p. (Not recomputing g.)
315 */
316 if ((brv = big_extend(&(dhkey.g), CHARLEN2BIGNUMLEN(prime_bytes))) !=
317 BIG_OK) {
318 rv = convert_rv(brv);
319 goto ret;
320 }
321
322 if ((brv = big_modexp(&(dhkey.g), &(dhkey.y), &(dhkey.x),
323 &(dhkey.p), NULL)) != BIG_OK) {
324 rv = convert_rv(brv);
325 goto ret;
326 }
327
328 s_alloc = P2ROUNDUP_TYPED(prime_bytes, sizeof (BIG_CHUNK_TYPE), size_t);
329
330 #ifdef _KERNEL
331 if ((s = kmem_alloc(s_alloc, flag)) == NULL) {
332 rv = CKR_HOST_MEMORY;
333 goto ret;
334 }
335 #else
336 if ((s = malloc(s_alloc)) == NULL) {
337 rv = CKR_HOST_MEMORY;
338 goto ret;
339 }
340 #endif
341 s_bytes = dhkey.g.len * (int)sizeof (BIG_CHUNK_TYPE);
342 bignum2bytestring(s, &(dhkey.g), s_bytes);
343
344 switch (key_type) {
345
346 case CKK_DES:
347 *secretkey_len = DES_KEYSIZE;
348 break;
349 case CKK_DES2:
350 *secretkey_len = DES2_KEYSIZE;
351 break;
352 case CKK_DES3:
353 *secretkey_len = DES3_KEYSIZE;
354 break;
355 case CKK_RC4:
356 case CKK_AES:
357 case CKK_GENERIC_SECRET:
358 /* use provided secret key length, if any */
359 break;
360 default:
361 /* invalid key type */
362 rv = CKR_ATTRIBUTE_TYPE_INVALID;
363 goto ret;
364 }
365
366 if (*secretkey_len == 0) {
367 *secretkey_len = s_bytes;
368 }
369
370 if (*secretkey_len > s_bytes) {
371 rv = CKR_ATTRIBUTE_VALUE_INVALID;
372 goto ret;
373 }
374
375 /*
376 * The truncation removes bytes from the leading end of the
377 * secret value.
378 */
379 (void) memcpy(secretkey, (s + s_bytes - *secretkey_len),
380 *secretkey_len);
381
382 ret:
383 if (s != NULL)
384 #ifdef _KERNEL
385 kmem_free(s, s_alloc);
386 #else
387 free(s);
388 #endif
389
390 DH_key_finish(&dhkey);
391
392 return (rv);
393 }
394