xref: /illumos-gate/usr/src/lib/pkcs11/pkcs11_softtoken/common/softDH.c (revision 581cede61ac9c14d8d4ea452562a567189eead78)
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  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <stdlib.h>
29 #include <string.h>
30 #include <strings.h>
31 #include <sys/types.h>
32 #include <security/cryptoki.h>
33 #include <sys/crypto/common.h>
34 #include <bignum.h>
35 #include <des_impl.h>
36 #include "softGlobal.h"
37 #include "softSession.h"
38 #include "softObject.h"
39 #include "softDH.h"
40 #include "softRandom.h"
41 #include "softCrypt.h"
42 
43 
44 /*
45  * This function converts the big integer of the specified attribute
46  * to an octet string and store it in the corresponding key object.
47  */
48 CK_RV
49 soft_genDHkey_set_attribute(soft_object_t *key, BIGNUM *bn,
50     CK_ATTRIBUTE_TYPE type, uint32_t prime_len, boolean_t public)
51 {
52 
53 	uchar_t	*buf;
54 	uint32_t buflen;
55 	CK_RV rv = CKR_OK;
56 	biginteger_t *dst = NULL;
57 	biginteger_t src;
58 
59 	/*
60 	 * Allocate the buffer used to store the value of key fields
61 	 * for bignum2bytestring. Since bignum only deals with a buffer
62 	 * whose size is multiple of 4, prime_len is rounded up to be
63 	 * multiple of 4.
64 	 */
65 	if ((buf = malloc((prime_len + sizeof (BIG_CHUNK_TYPE) - 1) &
66 	    ~(sizeof (BIG_CHUNK_TYPE) - 1))) == NULL) {
67 		rv = CKR_HOST_MEMORY;
68 		goto cleanexit;
69 	}
70 
71 	buflen = bn->len * (int)sizeof (BIG_CHUNK_TYPE);
72 	bignum2bytestring(buf, bn, buflen);
73 
74 	switch (type) {
75 
76 	case CKA_VALUE:
77 		if (public)
78 			dst = OBJ_PUB_DH_VALUE(key);
79 		else
80 			dst = OBJ_PRI_DH_VALUE(key);
81 		break;
82 
83 	case CKA_PRIME:
84 		dst = OBJ_PRI_DH_PRIME(key);
85 		break;
86 
87 	case CKA_BASE:
88 		dst = OBJ_PRI_DH_BASE(key);
89 		break;
90 	}
91 
92 	src.big_value_len = buflen;
93 
94 	if ((src.big_value = malloc(buflen)) == NULL) {
95 		rv = CKR_HOST_MEMORY;
96 		goto cleanexit;
97 	}
98 	(void) memcpy(src.big_value, buf, buflen);
99 
100 	/* Copy the attribute in the key object. */
101 	copy_bigint_attr(&src, dst);
102 
103 cleanexit:
104 	free(buf);
105 	return (rv);
106 
107 }
108 
109 /*
110  * This function covers the DH Key agreement.
111  */
112 CK_RV
113 soft_dh_genkey_pair(soft_object_t *pubkey, soft_object_t *prikey)
114 {
115 	CK_RV		rv;
116 	BIG_ERR_CODE	brv;
117 	uchar_t		prime[MAX_KEY_ATTR_BUFLEN];
118 	uint32_t	prime_len = sizeof (prime);
119 	uint32_t	primebit_len;
120 	uint32_t	value_bits;
121 	uchar_t		base[MAX_KEY_ATTR_BUFLEN];
122 	uint32_t	base_len = sizeof (base);
123 	BIGNUM		bnprime;
124 	BIGNUM		bnbase;
125 	BIGNUM		bnprival;
126 	BIGNUM		bnpubval;
127 	CK_ATTRIBUTE 	template;
128 
129 	if ((pubkey->class != CKO_PUBLIC_KEY) ||
130 	    (pubkey->key_type != CKK_DH)) {
131 		return (CKR_KEY_TYPE_INCONSISTENT);
132 	}
133 
134 	if ((prikey->class != CKO_PRIVATE_KEY) ||
135 	    (prikey->key_type != CKK_DH)) {
136 		return (CKR_KEY_TYPE_INCONSISTENT);
137 	}
138 
139 	/*
140 	 * The input to the first phase shall be the Diffie-Hellman
141 	 * parameters, which include prime, base, and private-value length.
142 	 */
143 	rv = soft_get_public_value(pubkey, CKA_PRIME, prime, &prime_len);
144 
145 	if (rv != CKR_OK) {
146 		return (rv);
147 	}
148 
149 	if ((prime_len < (MIN_DH_KEYLENGTH / 8)) ||
150 	    (prime_len > (MAX_DH_KEYLENGTH / 8))) {
151 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
152 		goto ret0;
153 	}
154 
155 	if ((brv = big_init(&bnprime, CHARLEN2BIGNUMLEN(prime_len))) !=
156 	    BIG_OK) {
157 		rv = convert_rv(brv);
158 		goto ret0;
159 	}
160 
161 	/* Convert the prime octet string to big integer format. */
162 	bytestring2bignum(&bnprime, prime, prime_len);
163 
164 	rv = soft_get_public_value(pubkey, CKA_BASE, base, &base_len);
165 
166 	if (rv != CKR_OK) {
167 		goto ret1;
168 	}
169 
170 	if ((brv = big_init(&bnbase, CHARLEN2BIGNUMLEN(base_len))) != BIG_OK) {
171 		rv = convert_rv(brv);
172 		goto ret1;
173 	}
174 
175 	/* Convert the base octet string to big integer format. */
176 	bytestring2bignum(&bnbase, base, base_len);
177 
178 	if (big_cmp_abs(&bnbase, &bnprime) >= 0) {
179 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
180 		goto ret2;
181 	}
182 
183 	primebit_len = big_bitlength(&bnprime);
184 
185 	template.pValue = malloc(sizeof (CK_ULONG));
186 
187 	if (template.pValue == NULL) {
188 		rv = CKR_HOST_MEMORY;
189 		goto ret2;
190 	}
191 
192 	template.ulValueLen = sizeof (CK_ULONG);
193 
194 	rv = get_ulong_attr_from_object(OBJ_PRI_DH_VAL_BITS(prikey),
195 	    &template);
196 
197 	if (rv != CKR_OK) {
198 		goto ret2;
199 	}
200 
201 	/*
202 	 * The intention of selecting a private-value length is to reduce
203 	 * the computation time for key agreement, while maintaining a
204 	 * given level of security.
205 	 */
206 
207 #ifdef	__sparcv9
208 	/* LINTED */
209 	value_bits = (uint32_t)(*((CK_ULONG *)(template.pValue)));
210 #else	/* !__sparcv9 */
211 	value_bits = *((CK_ULONG *)(template.pValue));
212 #endif	/* __sparcv9 */
213 
214 	if (value_bits > primebit_len) {
215 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
216 		goto ret3;
217 	}
218 
219 	/* Generate DH key pair private and public values. */
220 	if ((brv = big_init(&bnprival, CHARLEN2BIGNUMLEN(prime_len)))
221 	    != BIG_OK) {
222 		rv = convert_rv(brv);
223 		goto ret3;
224 	}
225 
226 	if ((brv = big_init(&bnpubval, CHARLEN2BIGNUMLEN(prime_len)))
227 	    != BIG_OK) {
228 		rv = convert_rv(brv);
229 		goto ret4;
230 	}
231 
232 	/*
233 	 * The big integer of the private value shall be generated privately
234 	 * and randomly.
235 	 */
236 	if ((brv = random_bignum(&bnprival, (value_bits == 0) ?
237 	    primebit_len : value_bits, (IS_TOKEN_OBJECT(pubkey) ||
238 	    IS_TOKEN_OBJECT(prikey)))) != BIG_OK) {
239 		rv = convert_rv(brv);
240 		goto ret5;
241 	}
242 
243 	/*
244 	 * The base g shall be raised to the private value x modulo p to
245 	 * give an integer y, the integer public value.
246 	 */
247 	if ((brv = big_modexp(&bnpubval,
248 	    &bnbase, &bnprival, &bnprime, NULL)) != BIG_OK) {
249 		rv = convert_rv(brv);
250 		goto ret5;
251 	}
252 
253 	/*
254 	 * The integer public value y shall be converted to an octet
255 	 * string PV of length k, the public value.
256 	 */
257 	if ((rv = soft_genDHkey_set_attribute(pubkey, &bnpubval,
258 	    CKA_VALUE, prime_len, B_TRUE)) != CKR_OK) {
259 		goto ret5;
260 	}
261 
262 	/* Convert the big integer private value to an octet string. */
263 	if ((rv = soft_genDHkey_set_attribute(prikey, &bnprival,
264 	    CKA_VALUE, prime_len, B_FALSE)) != CKR_OK) {
265 		goto ret5;
266 	}
267 
268 	/* Convert the big integer prime to an octet string. */
269 	if ((rv = soft_genDHkey_set_attribute(prikey, &bnprime,
270 	    CKA_PRIME, prime_len, B_FALSE)) != CKR_OK) {
271 		goto ret5;
272 	}
273 
274 	/* Convert the big integer base to an octet string. */
275 	if ((rv = soft_genDHkey_set_attribute(prikey, &bnbase,
276 	    CKA_BASE, prime_len, B_FALSE)) != CKR_OK) {
277 		goto ret5;
278 	}
279 
280 	if (value_bits == 0) {
281 		OBJ_PRI_DH_VAL_BITS(prikey) = primebit_len;
282 	}
283 
284 
285 ret5:
286 	big_finish(&bnpubval);
287 ret4:
288 	big_finish(&bnprival);
289 ret3:
290 	free(template.pValue);
291 ret2:
292 	big_finish(&bnbase);
293 ret1:
294 	big_finish(&bnprime);
295 ret0:
296 	return (rv);
297 }
298 
299 CK_RV
300 soft_dh_key_derive(soft_object_t *basekey, soft_object_t *secretkey,
301     void *publicvalue, size_t publicvaluelen)
302 {
303 	uchar_t		privatevalue[MAX_KEY_ATTR_BUFLEN];
304 	uint32_t	privatevaluelen = sizeof (privatevalue);
305 	uchar_t		privateprime[MAX_KEY_ATTR_BUFLEN];
306 	uint32_t	privateprimelen = sizeof (privateprime);
307 	uchar_t		*value;
308 	uint32_t	valuelen;
309 	uint32_t	keylen;
310 	uchar_t		*buf = NULL;
311 	CK_RV		rv;
312 	BIG_ERR_CODE	brv;
313 	BIGNUM		bnprime;
314 	BIGNUM		bnpublic;
315 	BIGNUM		bnprivate;
316 	BIGNUM		bnsecret;
317 
318 	rv = soft_get_private_value(basekey, CKA_VALUE, privatevalue,
319 	    &privatevaluelen);
320 	if (rv != CKR_OK) {
321 		return (rv);
322 	}
323 
324 	rv = soft_get_private_value(basekey, CKA_PRIME, privateprime,
325 	    &privateprimelen);
326 	if (rv != CKR_OK) {
327 		goto ret0;
328 	}
329 
330 	if ((brv = big_init(&bnprime, CHARLEN2BIGNUMLEN(privateprimelen))) !=
331 	    BIG_OK) {
332 		rv = convert_rv(brv);
333 		goto ret0;
334 	}
335 
336 	bytestring2bignum(&bnprime, privateprime, privateprimelen);
337 
338 	if ((brv = big_init(&bnprivate, CHARLEN2BIGNUMLEN(privatevaluelen))) !=
339 	    BIG_OK) {
340 		rv = convert_rv(brv);
341 		goto ret1;
342 	}
343 
344 	bytestring2bignum(&bnprivate, privatevalue, privatevaluelen);
345 
346 #ifdef	__sparcv9
347 	if ((brv = big_init(&bnpublic,
348 	    (int)CHARLEN2BIGNUMLEN(publicvaluelen))) != BIG_OK) {
349 #else	/* !__sparcv9 */
350 	if ((brv = big_init(&bnpublic,
351 	    CHARLEN2BIGNUMLEN(publicvaluelen))) != BIG_OK) {
352 #endif	/* __sparcv9 */
353 		rv = convert_rv(brv);
354 		goto ret2;
355 	}
356 
357 	bytestring2bignum(&bnpublic, (uchar_t *)publicvalue, publicvaluelen);
358 
359 	if ((brv = big_init(&bnsecret,
360 	    CHARLEN2BIGNUMLEN(privateprimelen))) != BIG_OK) {
361 		rv = convert_rv(brv);
362 		goto ret3;
363 	}
364 
365 	if ((brv = big_modexp(&bnsecret, &bnpublic, &bnprivate, &bnprime,
366 	    NULL)) != BIG_OK) {
367 		rv = convert_rv(brv);
368 		goto ret4;
369 	}
370 
371 	if ((buf = malloc((privateprimelen + sizeof (BIG_CHUNK_TYPE) - 1) &
372 	    ~(sizeof (BIG_CHUNK_TYPE) - 1))) == NULL) {
373 		rv = CKR_HOST_MEMORY;
374 		goto ret4;
375 	}
376 
377 	value = buf;
378 	valuelen = bnsecret.len * (int)sizeof (BIG_CHUNK_TYPE);
379 	bignum2bytestring(value, &bnsecret, valuelen);
380 
381 	switch (secretkey->key_type) {
382 
383 	case CKK_DES:
384 		keylen = DES_KEYSIZE;
385 		break;
386 	case CKK_DES2:
387 		keylen = DES2_KEYSIZE;
388 		break;
389 	case CKK_DES3:
390 		keylen = DES3_KEYSIZE;
391 		break;
392 	case CKK_RC4:
393 	case CKK_AES:
394 	case CKK_GENERIC_SECRET:
395 #ifdef	__sparcv9
396 		/* LINTED */
397 		keylen = (uint32_t)OBJ_SEC_VALUE_LEN(secretkey);
398 #else	/* !__sparcv9 */
399 		keylen = OBJ_SEC_VALUE_LEN(secretkey);
400 #endif	/* __sparcv9 */
401 		break;
402 	}
403 
404 	if (keylen == 0) {
405 		/*
406 		 * keylen == 0 only if CKA_VALUE_LEN did not specify.
407 		 */
408 		keylen = valuelen;
409 	}
410 	/*
411 	 * Note: No need to have "default:" case here since invalid key type
412 	 * if any has been detected at function soft_build_secret_key_object()
413 	 * before it gets here.
414 	 */
415 
416 	if (keylen > valuelen) {
417 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
418 		goto ret5;
419 	}
420 
421 	if ((OBJ_SEC_VALUE(secretkey) = malloc(keylen)) == NULL) {
422 		rv = CKR_HOST_MEMORY;
423 		goto ret5;
424 	}
425 	OBJ_SEC_VALUE_LEN(secretkey) = keylen;
426 
427 	/*
428 	 * The truncation removes bytes from the leading end of the
429 	 * secret value.
430 	 */
431 	(void) memcpy(OBJ_SEC_VALUE(secretkey), (value + valuelen - keylen),
432 	    keylen);
433 
434 ret5:
435 	free(buf);
436 ret4:
437 	big_finish(&bnsecret);
438 ret3:
439 	big_finish(&bnpublic);
440 ret2:
441 	big_finish(&bnprivate);
442 ret1:
443 	big_finish(&bnprime);
444 ret0:
445 	return (rv);
446 }
447