xref: /titanic_44/usr/src/lib/pkcs11/pkcs11_softtoken/common/softDH.c (revision 8eea8e29cc4374d1ee24c25a07f45af132db3499)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  */
22 /*
23  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 #include <stdlib.h>
30 #include <string.h>
31 #include <strings.h>
32 #include <sys/types.h>
33 #include <security/cryptoki.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 + 3) & ~3)) == NULL) {
66 		rv = CKR_HOST_MEMORY;
67 		goto cleanexit;
68 	}
69 
70 	buflen = bn->len * (int)sizeof (uint32_t);
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 
129 	if ((pubkey->class != CKO_PUBLIC_KEY) ||
130 	    (pubkey->key_type != CKK_DH))
131 		return (CKR_KEY_TYPE_INCONSISTENT);
132 
133 	if ((prikey->class != CKO_PRIVATE_KEY) ||
134 	    (prikey->key_type != CKK_DH))
135 		return (CKR_KEY_TYPE_INCONSISTENT);
136 
137 	/*
138 	 * The input to the first phase shall be the Diffie-Hellman
139 	 * parameters, which include prime, base, and private-value length.
140 	 */
141 	rv = soft_get_public_attr(pubkey, CKA_PRIME, prime, &prime_len);
142 
143 	if (rv != CKR_OK) {
144 		return (rv);
145 	}
146 
147 	if ((prime_len < (MIN_DH_KEYLENGTH / 8)) ||
148 	    (prime_len > (MAX_DH_KEYLENGTH / 8))) {
149 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
150 		goto ret0;
151 	}
152 
153 	if ((brv = big_init(&bnprime, (prime_len + 3)/4)) != BIG_OK) {
154 		rv = convert_rv(brv);
155 		goto ret0;
156 	}
157 
158 	/* Convert the prime octet string to big integer format. */
159 	bytestring2bignum(&bnprime, prime, prime_len);
160 
161 	rv = soft_get_public_attr(pubkey, CKA_BASE, base, &base_len);
162 
163 	if (rv != CKR_OK) {
164 		goto ret1;
165 	}
166 
167 	if ((brv = big_init(&bnbase, (base_len + 3)/4)) != BIG_OK) {
168 		rv = convert_rv(brv);
169 		goto ret1;
170 	}
171 
172 	/* Convert the base octet string to big integer format. */
173 	bytestring2bignum(&bnbase, base, base_len);
174 
175 	if (big_cmp_abs(&bnbase, &bnprime) >= 0) {
176 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
177 		goto ret2;
178 	}
179 
180 	primebit_len = big_bitlength(&bnprime);
181 
182 	template.pValue = malloc(sizeof (CK_ULONG));
183 
184 	if (template.pValue == NULL) {
185 		rv = CKR_HOST_MEMORY;
186 		goto ret2;
187 	}
188 
189 	template.ulValueLen = sizeof (CK_ULONG);
190 
191 	rv = get_ulong_attr_from_object(OBJ_PRI_DH_VAL_BITS(prikey),
192 	    &template);
193 
194 	if (rv != CKR_OK) {
195 		goto ret2;
196 	}
197 
198 	/*
199 	 * The intention of selecting a private-value length is to reduce
200 	 * the computation time for key agreement, while maintaining a
201 	 * given level of security.
202 	 */
203 
204 #ifdef	__sparcv9
205 	/* LINTED */
206 	value_bits = (uint32_t)(*((CK_ULONG *)(template.pValue)));
207 #else	/* !__sparcv9 */
208 	value_bits = *((CK_ULONG *)(template.pValue));
209 #endif	/* __sparcv9 */
210 
211 	if (value_bits > primebit_len) {
212 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
213 		goto ret3;
214 	}
215 
216 	/* Generate DH key pair private and public values. */
217 	if ((brv = big_init(&bnprival, (prime_len + 3)/4)) != BIG_OK) {
218 		rv = convert_rv(brv);
219 		goto ret3;
220 	}
221 
222 	if ((brv = big_init(&bnpubval, (prime_len + 3)/4)) != BIG_OK) {
223 		rv = convert_rv(brv);
224 		goto ret4;
225 	}
226 
227 	/*
228 	 * The big integer of the private value shall be generated privately
229 	 * and randomly.
230 	 */
231 	if ((brv = random_bignum(&bnprival, (value_bits == 0) ?
232 	    primebit_len : value_bits, (IS_TOKEN_OBJECT(pubkey) ||
233 	    IS_TOKEN_OBJECT(prikey)))) != BIG_OK) {
234 		rv = convert_rv(brv);
235 		goto ret5;
236 	}
237 
238 	/*
239 	 * The base g shall be raised to the private value x modulo p to
240 	 * give an integer y, the integer public value.
241 	 */
242 	if ((brv = big_modexp(&bnpubval,
243 	    &bnbase, &bnprival, &bnprime, NULL)) != BIG_OK) {
244 		rv = convert_rv(brv);
245 		goto ret5;
246 	}
247 
248 	/*
249 	 * The integer public value y shall be converted to an octet
250 	 * string PV of length k, the public value.
251 	 */
252 	if ((rv = soft_genDHkey_set_attribute(pubkey, &bnpubval,
253 	    CKA_VALUE, prime_len, B_TRUE)) != CKR_OK) {
254 		goto ret5;
255 	}
256 
257 	/* Convert the big integer private value to an octet string. */
258 	if ((rv = soft_genDHkey_set_attribute(prikey, &bnprival,
259 	    CKA_VALUE, prime_len, B_FALSE)) != CKR_OK) {
260 		goto ret5;
261 	}
262 
263 	/* Convert the big integer prime to an octet string. */
264 	if ((rv = soft_genDHkey_set_attribute(prikey, &bnprime,
265 	    CKA_PRIME, prime_len, B_FALSE)) != CKR_OK) {
266 		goto ret5;
267 	}
268 
269 	/* Convert the big integer base to an octet string. */
270 	if ((rv = soft_genDHkey_set_attribute(prikey, &bnbase,
271 	    CKA_BASE, prime_len, B_FALSE)) != CKR_OK) {
272 		goto ret5;
273 	}
274 
275 	if (value_bits == 0) {
276 		OBJ_PRI_DH_VAL_BITS(prikey) = primebit_len;
277 	}
278 
279 
280 ret5:
281 	big_finish(&bnpubval);
282 ret4:
283 	big_finish(&bnprival);
284 ret3:
285 	free(template.pValue);
286 ret2:
287 	big_finish(&bnbase);
288 ret1:
289 	big_finish(&bnprime);
290 ret0:
291 	return (rv);
292 }
293 
294 CK_RV
295 soft_dh_key_derive(soft_object_t *basekey, soft_object_t *secretkey,
296     void *publicvalue, size_t publicvaluelen)
297 {
298 	uchar_t		privatevalue[MAX_KEY_ATTR_BUFLEN];
299 	uint32_t	privatevaluelen = sizeof (privatevalue);
300 	uchar_t		privateprime[MAX_KEY_ATTR_BUFLEN];
301 	uint32_t	privateprimelen = sizeof (privateprime);
302 	uchar_t		*value;
303 	uint32_t	valuelen;
304 	uint32_t	keylen;
305 	uchar_t		*buf = NULL;
306 	CK_RV		rv;
307 	BIG_ERR_CODE	brv;
308 	BIGNUM		bnprime;
309 	BIGNUM		bnpublic;
310 	BIGNUM		bnprivate;
311 	BIGNUM		bnsecret;
312 
313 
314 	rv = soft_get_private_attr(basekey, CKA_VALUE, privatevalue,
315 	    &privatevaluelen);
316 	if (rv != CKR_OK) {
317 		return (rv);
318 	}
319 
320 	rv = soft_get_private_attr(basekey, CKA_PRIME, privateprime,
321 	    &privateprimelen);
322 	if (rv != CKR_OK) {
323 		goto ret0;
324 	}
325 
326 	if ((brv = big_init(&bnprime, (privateprimelen + 3)/4)) != BIG_OK) {
327 		rv = convert_rv(brv);
328 		goto ret0;
329 	}
330 
331 	bytestring2bignum(&bnprime, privateprime, privateprimelen);
332 
333 	if ((brv = big_init(&bnprivate, (privatevaluelen + 3)/4)) != BIG_OK) {
334 		rv = convert_rv(brv);
335 		goto ret1;
336 	}
337 
338 	bytestring2bignum(&bnprivate, privatevalue, privatevaluelen);
339 
340 #ifdef	__sparcv9
341 	/* LINTED */
342 	if ((brv = big_init(&bnpublic, (int)(publicvaluelen + 3)/4)) !=
343 	    BIG_OK) {
344 #else	/* !__sparcv9 */
345 	if ((brv = big_init(&bnpublic, (publicvaluelen + 3)/4)) != BIG_OK) {
346 #endif	/* __sparcv9 */
347 		rv = convert_rv(brv);
348 		goto ret2;
349 	}
350 
351 	bytestring2bignum(&bnpublic, (uchar_t *)publicvalue, publicvaluelen);
352 
353 	if ((brv = big_init(&bnsecret, (privateprimelen + 3)/4)) != BIG_OK) {
354 		rv = convert_rv(brv);
355 		goto ret3;
356 	}
357 
358 	if ((brv = big_modexp(&bnsecret, &bnpublic, &bnprivate, &bnprime,
359 	    NULL)) != BIG_OK) {
360 		rv = convert_rv(brv);
361 		goto ret4;
362 	}
363 
364 	if ((buf = malloc((privateprimelen + 3) & ~3)) == NULL) {
365 		rv = CKR_HOST_MEMORY;
366 		goto ret4;
367 	}
368 
369 	value = buf;
370 	valuelen = bnsecret.len * (int)sizeof (uint32_t);
371 	bignum2bytestring(value, &bnsecret, valuelen);
372 
373 	switch (secretkey->key_type) {
374 
375 	case CKK_DES:
376 		keylen = DES_KEYSIZE;
377 		break;
378 	case CKK_DES2:
379 		keylen = DES2_KEYSIZE;
380 		break;
381 	case CKK_DES3:
382 		keylen = DES3_KEYSIZE;
383 		break;
384 	case CKK_RC4:
385 	case CKK_AES:
386 	case CKK_GENERIC_SECRET:
387 #ifdef	__sparcv9
388 		/* LINTED */
389 		keylen = (uint32_t)OBJ_SEC_VALUE_LEN(secretkey);
390 #else	/* !__sparcv9 */
391 		keylen = OBJ_SEC_VALUE_LEN(secretkey);
392 #endif	/* __sparcv9 */
393 		break;
394 	}
395 
396 	if (keylen == 0) {
397 		/*
398 		 * keylen == 0 only if CKA_VALUE_LEN did not specify.
399 		 */
400 		keylen = valuelen;
401 	}
402 	/*
403 	 * Note: No need to have "default:" case here since invalid key type
404 	 * if any has been detected at function soft_build_secret_key_object()
405 	 * before it gets here.
406 	 */
407 
408 	if (keylen > valuelen) {
409 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
410 		goto ret5;
411 	}
412 
413 	if ((OBJ_SEC_VALUE(secretkey) = malloc(keylen)) == NULL) {
414 		rv = CKR_HOST_MEMORY;
415 		goto ret5;
416 	}
417 	OBJ_SEC_VALUE_LEN(secretkey) = keylen;
418 
419 	/*
420 	 * The truncation removes bytes from the leading end of the
421 	 * secret value.
422 	 */
423 	(void) memcpy(OBJ_SEC_VALUE(secretkey), (value + valuelen - keylen),
424 	    keylen);
425 
426 ret5:
427 	free(buf);
428 ret4:
429 	big_finish(&bnsecret);
430 ret3:
431 	big_finish(&bnpublic);
432 ret2:
433 	big_finish(&bnprivate);
434 ret1:
435 	big_finish(&bnprime);
436 ret0:
437 	return (rv);
438 }
439