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
soft_free_ecparams(ECParams * params,boolean_t freeit)43 soft_free_ecparams(ECParams *params, boolean_t freeit)
44 {
45 SECITEM_FreeItem(¶ms->fieldID.u.prime, B_FALSE);
46 SECITEM_FreeItem(¶ms->curve.a, B_FALSE);
47 SECITEM_FreeItem(¶ms->curve.b, B_FALSE);
48 SECITEM_FreeItem(¶ms->curve.seed, B_FALSE);
49 SECITEM_FreeItem(¶ms->base, B_FALSE);
50 SECITEM_FreeItem(¶ms->order, B_FALSE);
51 SECITEM_FreeItem(¶ms->DEREncoding, B_FALSE);
52 SECITEM_FreeItem(¶ms->curveOID, B_FALSE);
53 if (freeit)
54 free(params);
55 }
56
57 static void
soft_free_ecc_context(soft_ecc_ctx_t * ecc_ctx)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
soft_free_ecprivkey(ECPrivateKey * key)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
check_key(soft_object_t * key_p,boolean_t sign)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
soft_genECkey_set_attribute(soft_object_t * key,biginteger_t * bi,CK_ATTRIBUTE_TYPE type)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
soft_ec_genkey_pair(soft_object_t * pubkey,soft_object_t * prikey)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(¶ms_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
soft_ec_key_derive(soft_object_t * basekey,soft_object_t * secretkey,void * mech_params,size_t mech_params_len)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(¶ms_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
soft_ecc_sign_verify_init_common(soft_session_t * session_p,CK_MECHANISM_PTR pMechanism,soft_object_t * key_p,boolean_t sign)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(¶ms_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
soft_ecc_digest_sign_common(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSigned,CK_ULONG_PTR pulSignedLen,boolean_t Final)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
soft_ecc_sign(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSigned,CK_ULONG_PTR pulSignedLen)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
soft_ecc_verify(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSignature,CK_ULONG ulSignatureLen)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
soft_ecc_digest_verify_common(soft_session_t * session_p,CK_BYTE_PTR pData,CK_ULONG ulDataLen,CK_BYTE_PTR pSigned,CK_ULONG ulSignedLen,boolean_t Final)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