xref: /titanic_44/usr/src/lib/pkcs11/pkcs11_softtoken/common/softEC.c (revision c651b32e568cbf9b715a127805fe1cba321be5b0)
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 <sys/crypto/common.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 "softEC.h"
40 #include "softRandom.h"
41 #include "softCrypt.h"
42 #include "softOps.h"
43 #include "softMAC.h"
44 
45 void
46 soft_free_ecparams(ECParams *params, boolean_t freeit)
47 {
48 	SECITEM_FreeItem(&params->fieldID.u.prime, B_FALSE);
49 	SECITEM_FreeItem(&params->curve.a, B_FALSE);
50 	SECITEM_FreeItem(&params->curve.b, B_FALSE);
51 	SECITEM_FreeItem(&params->curve.seed, B_FALSE);
52 	SECITEM_FreeItem(&params->base, B_FALSE);
53 	SECITEM_FreeItem(&params->order, B_FALSE);
54 	SECITEM_FreeItem(&params->DEREncoding, B_FALSE);
55 	SECITEM_FreeItem(&params->curveOID, B_FALSE);
56 	if (freeit)
57 		free(params);
58 }
59 
60 static void
61 soft_free_ecc_context(soft_ecc_ctx_t *ecc_ctx)
62 {
63 	if (ecc_ctx != NULL) {
64 		if (ecc_ctx->key != NULL) {
65 			soft_cleanup_object(ecc_ctx->key);
66 			free(ecc_ctx->key);
67 		}
68 
69 		soft_free_ecparams(&ecc_ctx->ecparams, B_FALSE);
70 		free(ecc_ctx);
71 	}
72 }
73 
74 void
75 soft_free_ecprivkey(ECPrivateKey *key)
76 {
77 	soft_free_ecparams(&key->ecParams, B_FALSE);
78 	/*
79 	 * Don't free publicValue or privateValue
80 	 * as these values are copied into objects.
81 	 */
82 	SECITEM_FreeItem(&key->version, B_FALSE);
83 	free(key);
84 }
85 
86 /*
87  * Called from init routines to do basic sanity checks. Init routines,
88  * e.g. sign_init should fail rather than subsequent operations.
89  */
90 static int
91 check_key(soft_object_t *key_p, boolean_t sign)
92 {
93 	biginteger_t *p;
94 	ulong_t len;
95 
96 	if (sign) {
97 		if ((key_p->class != CKO_PRIVATE_KEY) ||
98 		    (key_p->key_type != CKK_EC))
99 			return (CKR_KEY_TYPE_INCONSISTENT);
100 
101 		p = OBJ_PRI_EC_VALUE(key_p);
102 		len = p->big_value_len;
103 		if (p->big_value == NULL)
104 			len = 0;
105 
106 		if (len < CRYPTO_BITS2BYTES(EC_MIN_KEY_LEN) ||
107 		    len > CRYPTO_BITS2BYTES(EC_MAX_KEY_LEN))
108 			return (CKR_KEY_SIZE_RANGE);
109 	} else {
110 		if ((key_p->class != CKO_PUBLIC_KEY) ||
111 		    (key_p->key_type != CKK_EC))
112 			return (CKR_KEY_TYPE_INCONSISTENT);
113 
114 		p = OBJ_PUB_EC_POINT(key_p);
115 		len = p->big_value_len;
116 		if (p->big_value == NULL)
117 			len = 0;
118 
119 		if (len < CRYPTO_BITS2BYTES(EC_MIN_KEY_LEN) * 2 + 1 ||
120 		    len > CRYPTO_BITS2BYTES(EC_MAX_KEY_LEN) * 2 + 1)
121 			return (CKR_KEY_SIZE_RANGE);
122 	}
123 
124 	return (CKR_OK);
125 }
126 
127 /*
128  * This function places the octet string of the specified attribute
129  * into the corresponding key object.
130  */
131 static void
132 soft_genECkey_set_attribute(soft_object_t *key, biginteger_t *bi,
133     CK_ATTRIBUTE_TYPE type)
134 {
135 	biginteger_t *dst;
136 
137 	switch (type) {
138 	case CKA_VALUE:
139 		dst = OBJ_PRI_EC_VALUE(key);
140 		break;
141 
142 	case CKA_EC_POINT:
143 		dst = OBJ_PUB_EC_POINT(key);
144 		break;
145 	}
146 	copy_bigint_attr(bi, dst);
147 }
148 
149 CK_RV
150 soft_ec_genkey_pair(soft_object_t *pubkey, soft_object_t *prikey)
151 {
152 	CK_RV rv;
153 	CK_ATTRIBUTE template;
154 	ECPrivateKey *privKey;	/* contains both public and private values */
155 	ECParams *ecparams;
156 	SECKEYECParams params_item;
157 	biginteger_t bi;
158 	uchar_t param_buffer[EC_MAX_OID_LEN];
159 	uint_t paramlen;
160 
161 	if ((pubkey->class != CKO_PUBLIC_KEY) ||
162 	    (pubkey->key_type != CKK_EC))
163 		return (CKR_KEY_TYPE_INCONSISTENT);
164 
165 	if ((prikey->class != CKO_PRIVATE_KEY) ||
166 	    (prikey->key_type != CKK_EC))
167 		return (CKR_KEY_TYPE_INCONSISTENT);
168 
169 	template.type = CKA_EC_PARAMS;
170 	template.pValue = param_buffer;
171 	template.ulValueLen = sizeof (param_buffer);
172 	rv = soft_get_public_key_attribute(pubkey, &template);
173 	if (rv != CKR_OK) {
174 		return (rv);
175 	}
176 	paramlen = template.ulValueLen;
177 
178 	/* private key also has CKA_EC_PARAMS attribute */
179 	rv = set_extra_attr_to_object(prikey, CKA_EC_PARAMS, &template);
180 	if (rv != CKR_OK) {
181 		return (rv);
182 	}
183 
184 	/* ASN1 check */
185 	if (param_buffer[0] != 0x06 ||
186 	    param_buffer[1] != paramlen - 2) {
187 		return (CKR_ATTRIBUTE_VALUE_INVALID);
188 	}
189 	params_item.len = paramlen;
190 	params_item.data = param_buffer;
191 	if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
192 		/* bad curve OID */
193 		return (CKR_ARGUMENTS_BAD);
194 	}
195 
196 	if (EC_NewKey(ecparams, &privKey, 0) != SECSuccess) {
197 		soft_free_ecparams(ecparams, B_TRUE);
198 		return (CKR_FUNCTION_FAILED);
199 	}
200 
201 	bi.big_value = privKey->privateValue.data;
202 	bi.big_value_len = privKey->privateValue.len;
203 	soft_genECkey_set_attribute(prikey, &bi, CKA_VALUE);
204 
205 	bi.big_value = privKey->publicValue.data;
206 	bi.big_value_len = privKey->publicValue.len;
207 	soft_genECkey_set_attribute(pubkey, &bi, CKA_EC_POINT);
208 
209 	soft_free_ecprivkey(privKey);
210 	soft_free_ecparams(ecparams, B_TRUE);
211 
212 	return (CKR_OK);
213 }
214 
215 CK_RV
216 soft_ec_key_derive(soft_object_t *basekey, soft_object_t *secretkey,
217     void *mech_params, size_t mech_params_len)
218 {
219 	CK_RV		rv;
220 	CK_ATTRIBUTE	template;
221 	CK_ECDH1_DERIVE_PARAMS *ecdh1_derive_params = mech_params;
222 	uchar_t		value[EC_MAX_VALUE_LEN];
223 	uint32_t	value_len = sizeof (value);
224 	uchar_t		params[EC_MAX_OID_LEN];
225 	uint32_t	params_len = sizeof (params);
226 	uint32_t	keylen;
227 	ECParams	*ecparams;
228 	SECKEYECParams	params_item;
229 	SECItem		public_value_item, private_value_item, secret_item;
230 	uchar_t		*buf;
231 
232 	if (mech_params_len != sizeof (CK_ECDH1_DERIVE_PARAMS) ||
233 	    ecdh1_derive_params->kdf != CKD_NULL) {
234 		return (CKR_MECHANISM_PARAM_INVALID);
235 	}
236 
237 	template.type = CKA_VALUE;
238 	template.pValue = value;
239 	template.ulValueLen = value_len;
240 	rv = soft_get_private_key_attribute(basekey, &template);
241 	if (rv != CKR_OK) {
242 		return (rv);
243 	}
244 	value_len = template.ulValueLen;
245 	private_value_item.data = value;
246 	private_value_item.len = value_len;
247 
248 	template.type = CKA_EC_PARAMS;
249 	template.pValue = params;
250 	template.ulValueLen = params_len;
251 	rv = soft_get_private_key_attribute(basekey, &template);
252 	if (rv != CKR_OK) {
253 		return (rv);
254 	}
255 	params_len = template.ulValueLen;
256 
257 	switch (secretkey->key_type) {
258 	case CKK_DES:
259 		keylen = DES_KEYSIZE;
260 		break;
261 	case CKK_DES2:
262 		keylen = DES2_KEYSIZE;
263 		break;
264 	case CKK_DES3:
265 		keylen = DES3_KEYSIZE;
266 		break;
267 	case CKK_RC4:
268 	case CKK_AES:
269 	case CKK_GENERIC_SECRET:
270 #ifdef	__sparcv9
271 		/* LINTED */
272 		keylen = (uint32_t)OBJ_SEC_VALUE_LEN(secretkey);
273 #else	/* !__sparcv9 */
274 		keylen = OBJ_SEC_VALUE_LEN(secretkey);
275 #endif	/* __sparcv9 */
276 		break;
277 	}
278 
279 	/* ASN1 check */
280 	if (params[0] != 0x06 ||
281 	    params[1] != params_len - 2) {
282 		return (CKR_ATTRIBUTE_VALUE_INVALID);
283 	}
284 	params_item.data = params;
285 	params_item.len = params_len;
286 	if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
287 		/* bad curve OID */
288 		return (CKR_ARGUMENTS_BAD);
289 	}
290 
291 	public_value_item.data = ecdh1_derive_params->pPublicData;
292 	public_value_item.len = ecdh1_derive_params->ulPublicDataLen;
293 
294 	secret_item.data = NULL;
295 	secret_item.len = 0;
296 
297 	if (ECDH_Derive(&public_value_item, ecparams, &private_value_item,
298 	    B_FALSE, &secret_item, 0) != SECSuccess) {
299 		soft_free_ecparams(ecparams, B_TRUE);
300 		return (CKR_FUNCTION_FAILED);
301 	} else {
302 		rv = CKR_OK;
303 	}
304 
305 	if (keylen == 0)
306 		keylen = secret_item.len;
307 
308 	if (keylen > secret_item.len) {
309 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
310 		goto out;
311 	}
312 	buf = malloc(keylen);
313 	if (buf == NULL) {
314 		rv = CKR_HOST_MEMORY;
315 		goto out;
316 	}
317 	bcopy(secret_item.data + secret_item.len - keylen, buf, keylen);
318 	OBJ_SEC_VALUE_LEN(secretkey) = keylen;
319 	OBJ_SEC_VALUE(secretkey) = buf;
320 
321 out:
322 	soft_free_ecparams(ecparams, B_TRUE);
323 	SECITEM_FreeItem(&secret_item, B_FALSE);
324 
325 	return (rv);
326 }
327 
328 /*
329  * Allocate a ECC context for the active sign or verify operation.
330  * This function is called without the session lock held.
331  */
332 CK_RV
333 soft_ecc_sign_verify_init_common(soft_session_t *session_p,
334     CK_MECHANISM_PTR pMechanism, soft_object_t *key_p,
335     boolean_t sign)
336 {
337 	CK_RV rv;
338 	CK_ATTRIBUTE template;
339 	CK_MECHANISM digest_mech;
340 	soft_ecc_ctx_t *ecc_ctx;
341 	soft_object_t *tmp_key = NULL;
342 	uchar_t params[EC_MAX_OID_LEN];
343 	ECParams *ecparams;
344 	SECKEYECParams params_item;
345 
346 	if ((rv = check_key(key_p, sign)) != CKR_OK)
347 		return (rv);
348 
349 	if (pMechanism->mechanism == CKM_ECDSA_SHA1) {
350 		digest_mech.mechanism = CKM_SHA_1;
351 		rv = soft_digest_init_internal(session_p, &digest_mech);
352 		if (rv != CKR_OK)
353 			return (rv);
354 	}
355 
356 	ecc_ctx = malloc(sizeof (soft_ecc_ctx_t));
357 	if (ecc_ctx == NULL) {
358 		return (CKR_HOST_MEMORY);
359 	}
360 
361 	/*
362 	 * Make a copy of the signature or verification key, and save it
363 	 * in the ECC crypto context since it will be used later for
364 	 * signing/verification. We don't want to hold any object reference
365 	 * on this original key while doing signing/verification.
366 	 */
367 	(void) pthread_mutex_lock(&key_p->object_mutex);
368 	rv = soft_copy_object(key_p, &tmp_key, SOFT_COPY_OBJ_ORIG_SH, NULL);
369 	if ((rv != CKR_OK) || (tmp_key == NULL)) {
370 		/* Most likely we ran out of space. */
371 		(void) pthread_mutex_unlock(&key_p->object_mutex);
372 		free(ecc_ctx);
373 		return (rv);
374 	}
375 
376 
377 	template.type = CKA_EC_PARAMS;
378 	template.pValue = params;
379 	template.ulValueLen = sizeof (params);
380 	rv = soft_get_private_key_attribute(key_p, &template);
381 	(void) pthread_mutex_unlock(&key_p->object_mutex);
382 	if (rv != CKR_OK) {
383 		goto out;
384 	}
385 
386 	/* ASN1 check */
387 	if (params[0] != 0x06 ||
388 	    params[1] != template.ulValueLen - 2) {
389 		rv = CKR_ATTRIBUTE_VALUE_INVALID;
390 		goto out;
391 	}
392 	params_item.data = params;
393 	params_item.len = template.ulValueLen;
394 
395 	ecc_ctx->key = tmp_key;
396 
397 	if (EC_DecodeParams(&params_item, &ecparams, 0) != SECSuccess) {
398 		/* bad curve OID */
399 		rv = CKR_ARGUMENTS_BAD;
400 		goto out;
401 	}
402 	ecc_ctx->ecparams = *ecparams;
403 	free(ecparams);
404 
405 	(void) pthread_mutex_lock(&session_p->session_mutex);
406 
407 	if (sign) {
408 		session_p->sign.context = ecc_ctx;
409 		session_p->sign.mech.mechanism = pMechanism->mechanism;
410 	} else {
411 		session_p->verify.context = ecc_ctx;
412 		session_p->verify.mech.mechanism = pMechanism->mechanism;
413 	}
414 
415 	(void) pthread_mutex_unlock(&session_p->session_mutex);
416 	return (CKR_OK);
417 
418 out:
419 	soft_cleanup_object(tmp_key);
420 	free(tmp_key);
421 	free(ecc_ctx);
422 
423 	return (rv);
424 }
425 
426 CK_RV
427 soft_ecc_digest_sign_common(soft_session_t *session_p, CK_BYTE_PTR pData,
428     CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
429     CK_ULONG_PTR pulSignedLen, boolean_t Final)
430 {
431 	CK_RV rv = CKR_OK;
432 	CK_BYTE hash[SHA1_HASH_SIZE];
433 	CK_ULONG hash_len = SHA1_HASH_SIZE;
434 
435 	if (pSigned != NULL) {
436 		if (Final) {
437 			rv = soft_digest_final(session_p, hash, &hash_len);
438 		} else {
439 			rv = soft_digest(session_p, pData, ulDataLen, hash,
440 			    &hash_len);
441 		}
442 
443 		if (rv != CKR_OK) {
444 			(void) pthread_mutex_lock(&session_p->session_mutex);
445 			soft_free_ecc_context(session_p->sign.context);
446 			session_p->sign.context = NULL;
447 			session_p->digest.flags = 0;
448 			(void) pthread_mutex_unlock(&session_p->session_mutex);
449 			return (rv);
450 		}
451 	}
452 
453 	rv = soft_ecc_sign(session_p, hash, hash_len, pSigned, pulSignedLen);
454 
455 clean_exit:
456 	(void) pthread_mutex_lock(&session_p->session_mutex);
457 	/* soft_digest_common() has freed the digest context */
458 	session_p->digest.flags = 0;
459 	(void) pthread_mutex_unlock(&session_p->session_mutex);
460 
461 clean1:
462 	return (rv);
463 }
464 
465 CK_RV
466 soft_ecc_sign(soft_session_t *session_p, CK_BYTE_PTR pData,
467     CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
468     CK_ULONG_PTR pulSignedLen)
469 {
470 	CK_RV rv = CKR_OK;
471 	SECStatus ss;
472 	soft_ecc_ctx_t *ecc_ctx = session_p->sign.context;
473 	soft_object_t *key = ecc_ctx->key;
474 	uchar_t value[EC_MAX_VALUE_LEN];
475 	ECPrivateKey ECkey;
476 	SECItem signature_item;
477 	SECItem digest_item;
478 	uint_t value_len;
479 
480 	if ((key->class != CKO_PRIVATE_KEY) || (key->key_type != CKK_EC)) {
481 		rv = CKR_KEY_TYPE_INCONSISTENT;
482 		goto clean_exit;
483 	}
484 
485 	if (ulDataLen > EC_MAX_DIGEST_LEN) {
486 		rv = CKR_DATA_LEN_RANGE;
487 		goto clean_exit;
488 	}
489 
490 	/* structure assignment */
491 	ECkey.ecParams = ecc_ctx->ecparams;
492 
493 	value_len = EC_MAX_VALUE_LEN;
494 	rv = soft_get_private_value(key, CKA_VALUE, value, &value_len);
495 	if (rv != CKR_OK) {
496 		goto clean_exit;
497 	}
498 
499 	ECkey.privateValue.data = value;
500 	ECkey.privateValue.len = value_len;
501 
502 	signature_item.data = pSigned;
503 	signature_item.len = *pulSignedLen;
504 
505 	digest_item.data = pData;
506 	digest_item.len = ulDataLen;
507 
508 	if ((ss = ECDSA_SignDigest(&ECkey, &signature_item, &digest_item, 0))
509 	    != SECSuccess) {
510 		if (ss == SECBufferTooSmall)
511 			return (CKR_BUFFER_TOO_SMALL);
512 
513 		rv = CKR_FUNCTION_FAILED;
514 		goto clean_exit;
515 	}
516 
517 	if (rv == CKR_OK) {
518 		*pulSignedLen = signature_item.len;
519 		if (pSigned == NULL)
520 			return (rv);
521 	}
522 
523 clean_exit:
524 	(void) pthread_mutex_lock(&session_p->session_mutex);
525 	soft_free_ecc_context(session_p->sign.context);
526 	session_p->sign.context = NULL;
527 	(void) pthread_mutex_unlock(&session_p->session_mutex);
528 	return (rv);
529 }
530 
531 CK_RV
532 soft_ecc_verify(soft_session_t *session_p, CK_BYTE_PTR pData,
533     CK_ULONG ulDataLen, CK_BYTE_PTR pSignature,
534     CK_ULONG ulSignatureLen)
535 {
536 	CK_RV rv = CKR_OK;
537 	soft_ecc_ctx_t *ecc_ctx = session_p->verify.context;
538 	soft_object_t *key = ecc_ctx->key;
539 	uchar_t point[EC_MAX_POINT_LEN];
540 	CK_ATTRIBUTE template;
541 	ECPublicKey ECkey;
542 	SECItem signature_item;
543 	SECItem digest_item;
544 
545 	if ((key->class != CKO_PUBLIC_KEY) ||(key->key_type != CKK_EC)) {
546 		rv = CKR_KEY_TYPE_INCONSISTENT;
547 		goto clean_exit;
548 	}
549 
550 	if (ulSignatureLen > EC_MAX_SIG_LEN) {
551 		rv = CKR_SIGNATURE_LEN_RANGE;
552 		goto clean_exit;
553 	}
554 
555 	if (ulDataLen > EC_MAX_DIGEST_LEN) {
556 		rv = CKR_DATA_LEN_RANGE;
557 		goto clean_exit;
558 	}
559 
560 	/* structure assignment */
561 	ECkey.ecParams = ecc_ctx->ecparams;
562 
563 	template.type = CKA_EC_POINT;
564 	template.pValue = point;
565 	template.ulValueLen = sizeof (point);
566 	rv = soft_get_public_key_attribute(key, &template);
567 	if (rv != CKR_OK) {
568 		goto clean_exit;
569 	}
570 
571 	ECkey.publicValue.data = point;
572 	ECkey.publicValue.len = template.ulValueLen;
573 
574 	signature_item.data = pSignature;
575 	signature_item.len = ulSignatureLen;
576 
577 	digest_item.data = pData;
578 	digest_item.len = ulDataLen;
579 
580 	if (ECDSA_VerifyDigest(&ECkey, &signature_item, &digest_item, 0)
581 	    != SECSuccess) {
582 		rv = CKR_SIGNATURE_INVALID;
583 	} else {
584 		rv = CKR_OK;
585 	}
586 
587 clean_exit:
588 	(void) pthread_mutex_lock(&session_p->session_mutex);
589 	soft_free_ecc_context(session_p->verify.context);
590 	session_p->verify.context = NULL;
591 	(void) pthread_mutex_unlock(&session_p->session_mutex);
592 	return (rv);
593 }
594 
595 
596 CK_RV
597 soft_ecc_digest_verify_common(soft_session_t *session_p, CK_BYTE_PTR pData,
598     CK_ULONG ulDataLen, CK_BYTE_PTR pSigned,
599     CK_ULONG ulSignedLen, boolean_t Final)
600 {
601 	CK_RV rv;
602 	CK_BYTE hash[SHA1_HASH_SIZE];
603 	CK_ULONG hash_len = SHA1_HASH_SIZE;
604 
605 	if (Final) {
606 		rv = soft_digest_final(session_p, hash, &hash_len);
607 	} else {
608 		rv = soft_digest(session_p, pData, ulDataLen, hash, &hash_len);
609 	}
610 
611 	if (rv != CKR_OK) {
612 		(void) pthread_mutex_lock(&session_p->session_mutex);
613 		soft_free_ecc_context(session_p->verify.context);
614 		session_p->verify.context = NULL;
615 		session_p->digest.flags = 0;
616 		(void) pthread_mutex_unlock(&session_p->session_mutex);
617 		return (rv);
618 	}
619 
620 	/*
621 	 * Now, we are ready to verify the data using signature.
622 	 * soft_ecc_verify() will free the verification key.
623 	 */
624 	rv = soft_ecc_verify(session_p, hash, hash_len,
625 	    pSigned, ulSignedLen);
626 
627 clean_exit:
628 	(void) pthread_mutex_lock(&session_p->session_mutex);
629 	/* soft_digest_common() has freed the digest context */
630 	session_p->digest.flags = 0;
631 	(void) pthread_mutex_unlock(&session_p->session_mutex);
632 	return (rv);
633 }
634