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.
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.
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]
22 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
23 * Use is subject to license terms.
29 #include <sys/types.h>
30 #include <sys/crypto/common.h>
31 #include <security/cryptoki.h>
34 #include "softGlobal.h"
35 #include "softSession.h"
36 #include "softObject.h"
38 #include "softCrypt.h"
43 soft_free_ecparams(ECParams
*params
, boolean_t freeit
)
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
);
58 soft_free_ecc_context(soft_ecc_ctx_t
*ecc_ctx
)
60 if (ecc_ctx
!= NULL
) {
61 if (ecc_ctx
->key
!= NULL
) {
62 soft_cleanup_object(ecc_ctx
->key
);
66 soft_free_ecparams(&ecc_ctx
->ecparams
, B_FALSE
);
72 soft_free_ecprivkey(ECPrivateKey
*key
)
74 soft_free_ecparams(&key
->ecParams
, B_FALSE
);
76 * Don't free publicValue or privateValue
77 * as these values are copied into objects.
79 SECITEM_FreeItem(&key
->version
, B_FALSE
);
84 * Called from init routines to do basic sanity checks. Init routines,
85 * e.g. sign_init should fail rather than subsequent operations.
88 check_key(soft_object_t
*key_p
, boolean_t sign
)
94 if ((key_p
->class != CKO_PRIVATE_KEY
) ||
95 (key_p
->key_type
!= CKK_EC
))
96 return (CKR_KEY_TYPE_INCONSISTENT
);
98 p
= OBJ_PRI_EC_VALUE(key_p
);
99 len
= p
->big_value_len
;
100 if (p
->big_value
== NULL
)
103 if (len
< CRYPTO_BITS2BYTES(EC_MIN_KEY_LEN
) ||
104 len
> CRYPTO_BITS2BYTES(EC_MAX_KEY_LEN
))
105 return (CKR_KEY_SIZE_RANGE
);
107 if ((key_p
->class != CKO_PUBLIC_KEY
) ||
108 (key_p
->key_type
!= CKK_EC
))
109 return (CKR_KEY_TYPE_INCONSISTENT
);
111 p
= OBJ_PUB_EC_POINT(key_p
);
112 len
= p
->big_value_len
;
113 if (p
->big_value
== NULL
)
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
);
125 * This function places the octet string of the specified attribute
126 * into the corresponding key object.
129 soft_genECkey_set_attribute(soft_object_t
*key
, biginteger_t
*bi
,
130 CK_ATTRIBUTE_TYPE type
)
136 dst
= OBJ_PRI_EC_VALUE(key
);
140 dst
= OBJ_PUB_EC_POINT(key
);
143 copy_bigint_attr(bi
, dst
);
147 soft_ec_genkey_pair(soft_object_t
*pubkey
, soft_object_t
*prikey
)
150 CK_ATTRIBUTE
template;
151 ECPrivateKey
*privKey
; /* contains both public and private values */
153 SECKEYECParams params_item
;
155 uchar_t param_buffer
[EC_MAX_OID_LEN
];
158 if ((pubkey
->class != CKO_PUBLIC_KEY
) ||
159 (pubkey
->key_type
!= CKK_EC
))
160 return (CKR_KEY_TYPE_INCONSISTENT
);
162 if ((prikey
->class != CKO_PRIVATE_KEY
) ||
163 (prikey
->key_type
!= CKK_EC
))
164 return (CKR_KEY_TYPE_INCONSISTENT
);
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);
173 paramlen
= template.ulValueLen
;
175 /* private key also has CKA_EC_PARAMS attribute */
176 rv
= set_extra_attr_to_object(prikey
, CKA_EC_PARAMS
, &template);
182 if (param_buffer
[0] != 0x06 ||
183 param_buffer
[1] != paramlen
- 2) {
184 return (CKR_ATTRIBUTE_VALUE_INVALID
);
186 params_item
.len
= paramlen
;
187 params_item
.data
= param_buffer
;
188 if (EC_DecodeParams(¶ms_item
, &ecparams
, 0) != SECSuccess
) {
190 return (CKR_ARGUMENTS_BAD
);
193 if (EC_NewKey(ecparams
, &privKey
, 0) != SECSuccess
) {
194 soft_free_ecparams(ecparams
, B_TRUE
);
195 return (CKR_FUNCTION_FAILED
);
198 bi
.big_value
= privKey
->privateValue
.data
;
199 bi
.big_value_len
= privKey
->privateValue
.len
;
200 soft_genECkey_set_attribute(prikey
, &bi
, CKA_VALUE
);
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
);
206 soft_free_ecprivkey(privKey
);
207 soft_free_ecparams(ecparams
, B_TRUE
);
213 soft_ec_key_derive(soft_object_t
*basekey
, soft_object_t
*secretkey
,
214 void *mech_params
, size_t mech_params_len
)
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
);
225 SECKEYECParams params_item
;
226 SECItem public_value_item
, private_value_item
, secret_item
;
229 if (mech_params_len
!= sizeof (CK_ECDH1_DERIVE_PARAMS
) ||
230 ecdh1_derive_params
->kdf
!= CKD_NULL
) {
231 return (CKR_MECHANISM_PARAM_INVALID
);
234 template.type
= CKA_VALUE
;
235 template.pValue
= value
;
236 template.ulValueLen
= value_len
;
237 rv
= soft_get_private_key_attribute(basekey
, &template);
241 value_len
= template.ulValueLen
;
242 private_value_item
.data
= value
;
243 private_value_item
.len
= value_len
;
245 template.type
= CKA_EC_PARAMS
;
246 template.pValue
= params
;
247 template.ulValueLen
= params_len
;
248 rv
= soft_get_private_key_attribute(basekey
, &template);
252 params_len
= template.ulValueLen
;
254 switch (secretkey
->key_type
) {
256 keylen
= DES_KEYSIZE
;
259 keylen
= DES2_KEYSIZE
;
262 keylen
= DES3_KEYSIZE
;
266 case CKK_GENERIC_SECRET
:
269 keylen
= (uint32_t)OBJ_SEC_VALUE_LEN(secretkey
);
270 #else /* !__sparcv9 */
271 keylen
= OBJ_SEC_VALUE_LEN(secretkey
);
272 #endif /* __sparcv9 */
277 if (params
[0] != 0x06 ||
278 params
[1] != params_len
- 2) {
279 return (CKR_ATTRIBUTE_VALUE_INVALID
);
281 params_item
.data
= params
;
282 params_item
.len
= params_len
;
283 if (EC_DecodeParams(¶ms_item
, &ecparams
, 0) != SECSuccess
) {
285 return (CKR_ARGUMENTS_BAD
);
288 public_value_item
.data
= ecdh1_derive_params
->pPublicData
;
289 public_value_item
.len
= ecdh1_derive_params
->ulPublicDataLen
;
291 secret_item
.data
= NULL
;
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
);
303 keylen
= secret_item
.len
;
305 if (keylen
> secret_item
.len
) {
306 rv
= CKR_ATTRIBUTE_VALUE_INVALID
;
309 buf
= malloc(keylen
);
311 rv
= CKR_HOST_MEMORY
;
314 bcopy(secret_item
.data
+ secret_item
.len
- keylen
, buf
, keylen
);
315 OBJ_SEC_VALUE_LEN(secretkey
) = keylen
;
316 OBJ_SEC_VALUE(secretkey
) = buf
;
319 soft_free_ecparams(ecparams
, B_TRUE
);
320 SECITEM_FreeItem(&secret_item
, B_FALSE
);
326 * Allocate a ECC context for the active sign or verify operation.
327 * This function is called without the session lock held.
330 soft_ecc_sign_verify_init_common(soft_session_t
*session_p
,
331 CK_MECHANISM_PTR pMechanism
, soft_object_t
*key_p
,
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
];
341 SECKEYECParams params_item
;
343 if ((rv
= check_key(key_p
, sign
)) != CKR_OK
)
346 if (pMechanism
->mechanism
== CKM_ECDSA_SHA1
) {
347 digest_mech
.mechanism
= CKM_SHA_1
;
348 rv
= soft_digest_init_internal(session_p
, &digest_mech
);
353 ecc_ctx
= malloc(sizeof (soft_ecc_ctx_t
));
354 if (ecc_ctx
== NULL
) {
355 return (CKR_HOST_MEMORY
);
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.
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
);
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
);
384 if (params
[0] != 0x06 ||
385 params
[1] != template.ulValueLen
- 2) {
386 rv
= CKR_ATTRIBUTE_VALUE_INVALID
;
389 params_item
.data
= params
;
390 params_item
.len
= template.ulValueLen
;
392 ecc_ctx
->key
= tmp_key
;
394 if (EC_DecodeParams(¶ms_item
, &ecparams
, 0) != SECSuccess
) {
396 rv
= CKR_ARGUMENTS_BAD
;
399 ecc_ctx
->ecparams
= *ecparams
;
402 (void) pthread_mutex_lock(&session_p
->session_mutex
);
405 session_p
->sign
.context
= ecc_ctx
;
406 session_p
->sign
.mech
.mechanism
= pMechanism
->mechanism
;
408 session_p
->verify
.context
= ecc_ctx
;
409 session_p
->verify
.mech
.mechanism
= pMechanism
->mechanism
;
412 (void) pthread_mutex_unlock(&session_p
->session_mutex
);
416 soft_cleanup_object(tmp_key
);
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
)
429 CK_BYTE hash
[SHA1_HASH_SIZE
];
430 CK_ULONG hash_len
= SHA1_HASH_SIZE
;
432 if (pSigned
!= NULL
) {
434 rv
= soft_digest_final(session_p
, hash
, &hash_len
);
436 rv
= soft_digest(session_p
, pData
, ulDataLen
, hash
,
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
);
450 rv
= soft_ecc_sign(session_p
, hash
, hash_len
, pSigned
, pulSignedLen
);
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
);
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
)
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
];
473 SECItem signature_item
;
477 if ((key
->class != CKO_PRIVATE_KEY
) || (key
->key_type
!= CKK_EC
)) {
478 rv
= CKR_KEY_TYPE_INCONSISTENT
;
482 if (ulDataLen
> EC_MAX_DIGEST_LEN
) {
483 rv
= CKR_DATA_LEN_RANGE
;
487 /* structure assignment */
488 ECkey
.ecParams
= ecc_ctx
->ecparams
;
490 value_len
= EC_MAX_VALUE_LEN
;
491 rv
= soft_get_private_value(key
, CKA_VALUE
, value
, &value_len
);
496 ECkey
.privateValue
.data
= value
;
497 ECkey
.privateValue
.len
= value_len
;
499 signature_item
.data
= pSigned
;
500 signature_item
.len
= *pulSignedLen
;
502 digest_item
.data
= pData
;
503 digest_item
.len
= ulDataLen
;
505 if ((ss
= ECDSA_SignDigest(&ECkey
, &signature_item
, &digest_item
, 0))
507 if (ss
== SECBufferTooSmall
)
508 return (CKR_BUFFER_TOO_SMALL
);
510 rv
= CKR_FUNCTION_FAILED
;
515 *pulSignedLen
= signature_item
.len
;
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
);
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
)
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;
539 SECItem signature_item
;
542 if ((key
->class != CKO_PUBLIC_KEY
) ||(key
->key_type
!= CKK_EC
)) {
543 rv
= CKR_KEY_TYPE_INCONSISTENT
;
547 if (ulSignatureLen
> EC_MAX_SIG_LEN
) {
548 rv
= CKR_SIGNATURE_LEN_RANGE
;
552 if (ulDataLen
> EC_MAX_DIGEST_LEN
) {
553 rv
= CKR_DATA_LEN_RANGE
;
557 /* structure assignment */
558 ECkey
.ecParams
= ecc_ctx
->ecparams
;
560 template.type
= CKA_EC_POINT
;
561 template.pValue
= point
;
562 template.ulValueLen
= sizeof (point
);
563 rv
= soft_get_public_key_attribute(key
, &template);
568 ECkey
.publicValue
.data
= point
;
569 ECkey
.publicValue
.len
= template.ulValueLen
;
571 signature_item
.data
= pSignature
;
572 signature_item
.len
= ulSignatureLen
;
574 digest_item
.data
= pData
;
575 digest_item
.len
= ulDataLen
;
577 if (ECDSA_VerifyDigest(&ECkey
, &signature_item
, &digest_item
, 0)
579 rv
= CKR_SIGNATURE_INVALID
;
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
);
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
)
599 CK_BYTE hash
[SHA1_HASH_SIZE
];
600 CK_ULONG hash_len
= SHA1_HASH_SIZE
;
603 rv
= soft_digest_final(session_p
, hash
, &hash_len
);
605 rv
= soft_digest(session_p
, pData
, ulDataLen
, hash
, &hash_len
);
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
);
618 * Now, we are ready to verify the data using signature.
619 * soft_ecc_verify() will free the verification key.
621 rv
= soft_ecc_verify(session_p
, hash
, hash_len
,
622 pSigned
, ulSignedLen
);
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
);