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