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