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 CK_RV
dh_genkey_pair(DHbytekey * bkey)116 dh_genkey_pair(DHbytekey *bkey)
117 {
118 CK_RV rv = CKR_OK;
119 BIG_ERR_CODE brv;
120 uint32_t primebit_len;
121 DHkey dhkey;
122 int (*rf)(void *, size_t);
123 uint32_t prime_bytes;
124
125 if (bkey == NULL)
126 return (CKR_ARGUMENTS_BAD);
127
128 /* Must have prime and base set, value bits can be 0 or non-0 */
129 if (bkey->prime_bits == 0 || bkey->prime == NULL ||
130 bkey->base_bytes == 0 || bkey->base == NULL)
131 return (CKR_ARGUMENTS_BAD);
132
133 prime_bytes = CRYPTO_BITS2BYTES(bkey->prime_bits);
134
135 if ((prime_bytes < MIN_DH_KEYLENGTH_IN_BYTES) ||
136 (prime_bytes > MAX_DH_KEYLENGTH_IN_BYTES)) {
137 return (CKR_KEY_SIZE_RANGE);
138 }
139
140 /*
141 * Initialize the DH key.
142 * Note: big_extend takes length in words.
143 */
144 if ((brv = DH_key_init(&dhkey, bkey->prime_bits)) != BIG_OK) {
145 rv = convert_rv(brv);
146 goto ret;
147 }
148
149 /* Convert prime p to bignum. */
150 if ((brv = big_extend(&(dhkey.p), CHARLEN2BIGNUMLEN(prime_bytes))) !=
151 BIG_OK) {
152 rv = convert_rv(brv);
153 goto ret;
154 }
155 bytestring2bignum(&(dhkey.p), bkey->prime, prime_bytes);
156
157 /* Convert base g to bignum. */
158 if ((brv = big_extend(&(dhkey.g),
159 CHARLEN2BIGNUMLEN(bkey->base_bytes))) != BIG_OK) {
160 rv = convert_rv(brv);
161 goto ret;
162 }
163 bytestring2bignum(&(dhkey.g), bkey->base, bkey->base_bytes);
164
165 /* Base g cannot be greater than prime p. */
166 if (big_cmp_abs(&(dhkey.g), &(dhkey.p)) >= 0) {
167 rv = CKR_ATTRIBUTE_VALUE_INVALID;
168 goto ret;
169 }
170
171 /*
172 * The intention of selecting a private-value length is to reduce
173 * the computation time for key agreement, while maintaining a
174 * given level of security.
175 */
176
177 /* Maximum bit length for private-value x is bit length of prime p */
178 primebit_len = big_bitlength(&(dhkey.p));
179
180 if (bkey->value_bits == 0)
181 bkey->value_bits = primebit_len;
182
183 if (bkey->value_bits > primebit_len) {
184 rv = CKR_ATTRIBUTE_VALUE_INVALID;
185 goto ret;
186 }
187
188 /* Generate DH key pair private and public values. */
189 if ((brv = big_extend(&(dhkey.x), CHARLEN2BIGNUMLEN(prime_bytes)))
190 != BIG_OK) {
191 rv = convert_rv(brv);
192 goto ret;
193 }
194
195 if ((brv = big_extend(&(dhkey.y), CHARLEN2BIGNUMLEN(prime_bytes)))
196 != BIG_OK) {
197 rv = convert_rv(brv);
198 goto ret;
199 }
200
201 /*
202 * The big integer of the private value shall be generated privately
203 * and randomly.
204 */
205 rf = bkey->rfunc;
206 if (rf == NULL) {
207 #ifdef _KERNEL
208 rf = random_get_pseudo_bytes;
209 #else
210 rf = pkcs11_get_urandom;
211 #endif
212 }
213
214 if ((brv = big_random(&(dhkey.x), bkey->value_bits, rf)) != BIG_OK) {
215 rv = convert_rv(brv);
216 goto ret;
217 }
218
219 /*
220 * The base g shall be raised to the private value x modulo p to
221 * give an integer y, the integer public value, i.e. y = (g^x) mod p.
222 */
223 if ((brv = big_modexp(&(dhkey.y), &(dhkey.g), &(dhkey.x),
224 &(dhkey.p), NULL)) != BIG_OK) {
225 rv = convert_rv(brv);
226 goto ret;
227 }
228
229 bignum2bytestring(bkey->private_x, &(dhkey.x), prime_bytes);
230 bignum2bytestring(bkey->public_y, &(dhkey.y), prime_bytes);
231
232 ret:
233 DH_key_finish(&dhkey);
234
235 return (rv);
236 }
237
238 /*
239 * DH key derive operation
240 */
241 CK_RV
dh_key_derive(DHbytekey * bkey,uint32_t key_type,uchar_t * secretkey,uint32_t * secretkey_len)242 dh_key_derive(DHbytekey *bkey, uint32_t key_type, /* = CKK_KEY_TYPE */
243 uchar_t *secretkey, uint32_t *secretkey_len) /* derived secret */
244 {
245 CK_RV rv = CKR_OK;
246 BIG_ERR_CODE brv;
247 DHkey dhkey;
248 uchar_t *s = NULL;
249 uint32_t s_bytes = 0;
250 uint32_t prime_bytes;
251 uint32_t value_bytes;
252
253 if (bkey == NULL)
254 return (CKR_ARGUMENTS_BAD);
255
256 /* Must have prime, private value and public value */
257 if (bkey->prime_bits == 0 || bkey->prime == NULL ||
258 bkey->value_bits == 0 || bkey->private_x == NULL ||
259 bkey->public_y == NULL)
260 return (CKR_ARGUMENTS_BAD);
261
262 if (secretkey == NULL) {
263 return (CKR_ARGUMENTS_BAD);
264 }
265
266 prime_bytes = CRYPTO_BITS2BYTES(bkey->prime_bits);
267 value_bytes = CRYPTO_BITS2BYTES(bkey->value_bits);
268
269 /*
270 * Initialize the DH key.
271 * Note: big_extend takes length in words.
272 */
273 if ((brv = DH_key_init(&dhkey, bkey->prime_bits)) != BIG_OK) {
274 rv = convert_rv(brv);
275 goto ret;
276 }
277
278 /* Convert prime p to bignum. */
279 if ((brv = big_extend(&(dhkey.p), CHARLEN2BIGNUMLEN(prime_bytes))) !=
280 BIG_OK) {
281 rv = convert_rv(brv);
282 goto ret;
283 }
284 bytestring2bignum(&(dhkey.p), bkey->prime, prime_bytes);
285
286 /* Convert private-value x to bignum. */
287 if ((brv = big_extend(&(dhkey.x), CHARLEN2BIGNUMLEN(value_bytes))) !=
288 BIG_OK) {
289 rv = convert_rv(brv);
290 goto ret;
291 }
292 bytestring2bignum(&(dhkey.x), bkey->private_x, value_bytes);
293
294 /* Convert public-value y to bignum. */
295 if ((brv = big_extend(&(dhkey.y), CHARLEN2BIGNUMLEN(value_bytes))) !=
296 BIG_OK) {
297 rv = convert_rv(brv);
298 goto ret;
299 }
300 bytestring2bignum(&(dhkey.y), bkey->public_y, value_bytes);
301
302 /*
303 * Recycle base g as a temporary variable to compute the derived
304 * secret value which is "g" = (y^x) mod p. (Not recomputing g.)
305 */
306 if ((brv = big_extend(&(dhkey.g), CHARLEN2BIGNUMLEN(prime_bytes))) !=
307 BIG_OK) {
308 rv = convert_rv(brv);
309 goto ret;
310 }
311
312 if ((brv = big_modexp(&(dhkey.g), &(dhkey.y), &(dhkey.x),
313 &(dhkey.p), NULL)) != BIG_OK) {
314 rv = convert_rv(brv);
315 goto ret;
316 }
317
318 #ifdef _KERNEL
319 if ((s = kmem_alloc(P2ROUNDUP_TYPED(prime_bytes,
320 sizeof (BIG_CHUNK_SIZE), size_t))) == NULL) {
321 #else
322 if ((s = malloc(P2ROUNDUP_TYPED(prime_bytes,
323 sizeof (BIG_CHUNK_SIZE), size_t))) == NULL) {
324 #endif
325 rv = CKR_HOST_MEMORY;
326 goto ret;
327 }
328 s_bytes = dhkey.g.len * (int)sizeof (BIG_CHUNK_TYPE);
329 bignum2bytestring(s, &(dhkey.g), s_bytes);
330
331 switch (key_type) {
332
333 case CKK_DES:
334 *secretkey_len = DES_KEYSIZE;
335 break;
336 case CKK_DES2:
337 *secretkey_len = DES2_KEYSIZE;
338 break;
339 case CKK_DES3:
340 *secretkey_len = DES3_KEYSIZE;
341 break;
342 case CKK_RC4:
343 case CKK_AES:
344 case CKK_GENERIC_SECRET:
345 /* use provided secret key length, if any */
346 break;
347 default:
348 /* invalid key type */
349 rv = CKR_ATTRIBUTE_TYPE_INVALID;
350 goto ret;
351 }
352
353 if (*secretkey_len == 0) {
354 *secretkey_len = s_bytes;
355 }
356
357 if (*secretkey_len > s_bytes) {
358 rv = CKR_ATTRIBUTE_VALUE_INVALID;
359 goto ret;
360 }
361
362 /*
363 * The truncation removes bytes from the leading end of the
364 * secret value.
365 */
366 (void) memcpy(secretkey, (s + s_bytes - *secretkey_len),
367 *secretkey_len);
368
369 ret:
370 if (s != NULL)
371 #ifdef _KERNEL
372 kmem_free(s, sizeof (BIG_CHUNK_SIZE));
373 #else
374 free(s);
375 #endif
376
377 DH_key_finish(&dhkey);
378
379 return (rv);
380 }
381