110500SHai-May.Chao@Sun.COM /*
210500SHai-May.Chao@Sun.COM * CDDL HEADER START
310500SHai-May.Chao@Sun.COM *
410500SHai-May.Chao@Sun.COM * The contents of this file are subject to the terms of the
510500SHai-May.Chao@Sun.COM * Common Development and Distribution License (the "License").
610500SHai-May.Chao@Sun.COM * You may not use this file except in compliance with the License.
710500SHai-May.Chao@Sun.COM *
810500SHai-May.Chao@Sun.COM * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
910500SHai-May.Chao@Sun.COM * or http://www.opensolaris.org/os/licensing.
1010500SHai-May.Chao@Sun.COM * See the License for the specific language governing permissions
1110500SHai-May.Chao@Sun.COM * and limitations under the License.
1210500SHai-May.Chao@Sun.COM *
1310500SHai-May.Chao@Sun.COM * When distributing Covered Code, include this CDDL HEADER in each
1410500SHai-May.Chao@Sun.COM * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1510500SHai-May.Chao@Sun.COM * If applicable, add the following below this CDDL HEADER, with the
1610500SHai-May.Chao@Sun.COM * fields enclosed by brackets "[]" replaced with your own identifying
1710500SHai-May.Chao@Sun.COM * information: Portions Copyright [yyyy] [name of copyright owner]
1810500SHai-May.Chao@Sun.COM *
1910500SHai-May.Chao@Sun.COM * CDDL HEADER END
2010500SHai-May.Chao@Sun.COM */
2110500SHai-May.Chao@Sun.COM /*
2210500SHai-May.Chao@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
2310500SHai-May.Chao@Sun.COM * Use is subject to license terms.
2410500SHai-May.Chao@Sun.COM */
2510500SHai-May.Chao@Sun.COM
2610500SHai-May.Chao@Sun.COM #include <sys/types.h>
2710500SHai-May.Chao@Sun.COM #include <sys/errno.h>
2810500SHai-May.Chao@Sun.COM #include <sys/fcntl.h>
2910500SHai-May.Chao@Sun.COM #include <sys/time.h>
3010500SHai-May.Chao@Sun.COM #include <sys/unistd.h>
3110500SHai-May.Chao@Sun.COM #include <sys/kmem.h>
3210500SHai-May.Chao@Sun.COM #include <sys/systm.h>
3310500SHai-May.Chao@Sun.COM #include <sys/sysmacros.h>
3410500SHai-May.Chao@Sun.COM #include <sys/crypto/common.h>
3510500SHai-May.Chao@Sun.COM #include <sys/cmn_err.h>
3610500SHai-May.Chao@Sun.COM #include <sys/sha1.h>
3710500SHai-May.Chao@Sun.COM #ifndef _KERNEL
3810500SHai-May.Chao@Sun.COM #include <stdlib.h>
3910500SHai-May.Chao@Sun.COM #include <string.h>
4010500SHai-May.Chao@Sun.COM #include <strings.h>
4110500SHai-May.Chao@Sun.COM #include <stdio.h>
4210500SHai-May.Chao@Sun.COM #include <security/cryptoki.h>
4310500SHai-May.Chao@Sun.COM #include "softMAC.h"
4410500SHai-May.Chao@Sun.COM #include "softEC.h"
4510500SHai-May.Chao@Sun.COM #endif
4610500SHai-May.Chao@Sun.COM #include <fips/fips_post.h>
4710500SHai-May.Chao@Sun.COM #include <ecc/ecc_impl.h>
4810500SHai-May.Chao@Sun.COM
4910500SHai-May.Chao@Sun.COM
5010500SHai-May.Chao@Sun.COM #define MAX_ECKEY_LEN 72
5110500SHai-May.Chao@Sun.COM #define SHA1_DIGEST_SIZE 20
5210500SHai-May.Chao@Sun.COM
53*10979SHai-May.Chao@Sun.COM static void free_ecparams(ECParams *, boolean_t);
54*10979SHai-May.Chao@Sun.COM static void free_ecprivkey(ECPrivateKey *);
55*10979SHai-May.Chao@Sun.COM static void free_ecpubkey(ECPublicKey *);
56*10979SHai-May.Chao@Sun.COM
5710500SHai-May.Chao@Sun.COM static int
fips_ecdsa_sign_verify(uint8_t * encodedParams,unsigned int encodedParamsLen,uint8_t * knownSignature,unsigned int knownSignatureLen)5810500SHai-May.Chao@Sun.COM fips_ecdsa_sign_verify(uint8_t *encodedParams,
5910500SHai-May.Chao@Sun.COM unsigned int encodedParamsLen,
6010500SHai-May.Chao@Sun.COM uint8_t *knownSignature,
6110500SHai-May.Chao@Sun.COM unsigned int knownSignatureLen) {
6210500SHai-May.Chao@Sun.COM
6310500SHai-May.Chao@Sun.COM /* ECDSA Known Seed info for curves nistp256 */
6410500SHai-May.Chao@Sun.COM static uint8_t ecdsa_Known_Seed[] = {
6510500SHai-May.Chao@Sun.COM 0x6a, 0x9b, 0xf6, 0xf7, 0xce, 0xed, 0x79, 0x11,
6610500SHai-May.Chao@Sun.COM 0xf0, 0xc7, 0xc8, 0x9a, 0xa5, 0xd1, 0x57, 0xb1,
6710500SHai-May.Chao@Sun.COM 0x7b, 0x5a, 0x3b, 0x76, 0x4e, 0x7b, 0x7c, 0xbc,
6810500SHai-May.Chao@Sun.COM 0xf2, 0x76, 0x1c, 0x1c, 0x7f, 0xc5, 0x53, 0x2f
6910500SHai-May.Chao@Sun.COM };
7010500SHai-May.Chao@Sun.COM
7110500SHai-May.Chao@Sun.COM static uint8_t msg[] = {
7210500SHai-May.Chao@Sun.COM "Sun Microsystems Solaris is awesome!"
7310500SHai-May.Chao@Sun.COM };
7410500SHai-May.Chao@Sun.COM
7510500SHai-May.Chao@Sun.COM unsigned char sha1[SHA1_DIGEST_SIZE]; /* SHA-1 hash (160 bits) */
7610500SHai-May.Chao@Sun.COM unsigned char sig[2*MAX_ECKEY_LEN];
7710500SHai-May.Chao@Sun.COM SECItem signature, digest;
7810500SHai-May.Chao@Sun.COM SECItem encodedparams;
7910500SHai-May.Chao@Sun.COM ECParams *ecparams = NULL;
8010500SHai-May.Chao@Sun.COM ECPrivateKey *ecdsa_private_key = NULL;
8110500SHai-May.Chao@Sun.COM ECPublicKey ecdsa_public_key;
8210500SHai-May.Chao@Sun.COM SECStatus ecdsaStatus = SECSuccess;
8310500SHai-May.Chao@Sun.COM SHA1_CTX *sha1_context = NULL;
84*10979SHai-May.Chao@Sun.COM int rv = CKR_DEVICE_ERROR;
8510500SHai-May.Chao@Sun.COM
86*10979SHai-May.Chao@Sun.COM (void) memset(&ecdsa_public_key, 0, sizeof (ECPublicKey));
8710500SHai-May.Chao@Sun.COM /* construct the ECDSA private/public key pair */
8810500SHai-May.Chao@Sun.COM encodedparams.type = siBuffer;
8910500SHai-May.Chao@Sun.COM encodedparams.data = (unsigned char *) encodedParams;
9010500SHai-May.Chao@Sun.COM encodedparams.len = encodedParamsLen;
9110500SHai-May.Chao@Sun.COM
9210500SHai-May.Chao@Sun.COM if (EC_DecodeParams(&encodedparams, &ecparams, 0) != SECSuccess) {
9310500SHai-May.Chao@Sun.COM return (CKR_ARGUMENTS_BAD);
9410500SHai-May.Chao@Sun.COM }
9510500SHai-May.Chao@Sun.COM
9610500SHai-May.Chao@Sun.COM /*
9710500SHai-May.Chao@Sun.COM * Generates a new EC key pair. The private key is a supplied
9810500SHai-May.Chao@Sun.COM * random value (in seed) and the public key is the result of
9910500SHai-May.Chao@Sun.COM * performing a scalar point multiplication of that value with
10010500SHai-May.Chao@Sun.COM * the curve's base point.
10110500SHai-May.Chao@Sun.COM */
10210500SHai-May.Chao@Sun.COM
10310500SHai-May.Chao@Sun.COM ecdsaStatus = ec_NewKey(ecparams, &ecdsa_private_key,
10410500SHai-May.Chao@Sun.COM ecdsa_Known_Seed, sizeof (ecdsa_Known_Seed), 0);
10510500SHai-May.Chao@Sun.COM
10610500SHai-May.Chao@Sun.COM if (ecdsaStatus != SECSuccess) {
107*10979SHai-May.Chao@Sun.COM goto loser;
10810500SHai-May.Chao@Sun.COM }
10910500SHai-May.Chao@Sun.COM
11010500SHai-May.Chao@Sun.COM /* construct public key from private key. */
11110500SHai-May.Chao@Sun.COM ecdsaStatus = EC_CopyParams(ecdsa_private_key->ecParams.arena,
11210500SHai-May.Chao@Sun.COM &ecdsa_public_key.ecParams, &ecdsa_private_key->ecParams);
11310500SHai-May.Chao@Sun.COM
11410500SHai-May.Chao@Sun.COM if (ecdsaStatus != SECSuccess) {
11510500SHai-May.Chao@Sun.COM goto loser;
11610500SHai-May.Chao@Sun.COM }
11710500SHai-May.Chao@Sun.COM
11810500SHai-May.Chao@Sun.COM ecdsa_public_key.publicValue = ecdsa_private_key->publicValue;
11910500SHai-May.Chao@Sun.COM
12010500SHai-May.Chao@Sun.COM /* validate public key value */
12110500SHai-May.Chao@Sun.COM ecdsaStatus = EC_ValidatePublicKey(&ecdsa_public_key.ecParams,
12210500SHai-May.Chao@Sun.COM &ecdsa_public_key.publicValue, 0);
12310500SHai-May.Chao@Sun.COM
12410500SHai-May.Chao@Sun.COM if (ecdsaStatus != SECSuccess) {
12510500SHai-May.Chao@Sun.COM goto loser;
12610500SHai-May.Chao@Sun.COM }
12710500SHai-May.Chao@Sun.COM
12810500SHai-May.Chao@Sun.COM /* validate public key value */
12910500SHai-May.Chao@Sun.COM ecdsaStatus = EC_ValidatePublicKey(&ecdsa_private_key->ecParams,
13010500SHai-May.Chao@Sun.COM &ecdsa_private_key->publicValue, 0);
13110500SHai-May.Chao@Sun.COM
13210500SHai-May.Chao@Sun.COM if (ecdsaStatus != SECSuccess) {
13310500SHai-May.Chao@Sun.COM goto loser;
13410500SHai-May.Chao@Sun.COM }
13510500SHai-May.Chao@Sun.COM
13610500SHai-May.Chao@Sun.COM /*
13710500SHai-May.Chao@Sun.COM * ECDSA Known Answer Signature Test.
13810500SHai-May.Chao@Sun.COM */
13910500SHai-May.Chao@Sun.COM #ifdef _KERNEL
14010500SHai-May.Chao@Sun.COM if ((sha1_context = kmem_zalloc(sizeof (SHA1_CTX),
141*10979SHai-May.Chao@Sun.COM KM_SLEEP)) == NULL) {
14210500SHai-May.Chao@Sun.COM #else
143*10979SHai-May.Chao@Sun.COM if ((sha1_context = malloc(sizeof (SHA1_CTX))) == NULL) {
14410500SHai-May.Chao@Sun.COM #endif
145*10979SHai-May.Chao@Sun.COM ecdsaStatus = SECFailure;
146*10979SHai-May.Chao@Sun.COM rv = CKR_HOST_MEMORY;
147*10979SHai-May.Chao@Sun.COM goto loser;
148*10979SHai-May.Chao@Sun.COM }
14910500SHai-May.Chao@Sun.COM
15010500SHai-May.Chao@Sun.COM SHA1Init(sha1_context);
15110500SHai-May.Chao@Sun.COM
15210500SHai-May.Chao@Sun.COM #ifdef __sparcv9
15310500SHai-May.Chao@Sun.COM SHA1Update(sha1_context, msg, (uint_t)sizeof (msg));
15410500SHai-May.Chao@Sun.COM #else /* !__sparcv9 */
15510500SHai-May.Chao@Sun.COM SHA1Update(sha1_context, msg, sizeof (msg));
15610500SHai-May.Chao@Sun.COM #endif /* __sparcv9 */
15710500SHai-May.Chao@Sun.COM SHA1Final(sha1, sha1_context);
15810500SHai-May.Chao@Sun.COM
15910500SHai-May.Chao@Sun.COM digest.type = siBuffer;
16010500SHai-May.Chao@Sun.COM digest.data = sha1;
16110500SHai-May.Chao@Sun.COM digest.len = SHA1_DIGEST_SIZE;
16210500SHai-May.Chao@Sun.COM
16310500SHai-May.Chao@Sun.COM (void) memset(sig, 0, sizeof (sig));
16410500SHai-May.Chao@Sun.COM signature.type = siBuffer;
16510500SHai-May.Chao@Sun.COM signature.data = sig;
16610500SHai-May.Chao@Sun.COM signature.len = sizeof (sig);
16710500SHai-May.Chao@Sun.COM
16810500SHai-May.Chao@Sun.COM ecdsaStatus = ECDSA_SignDigestWithSeed(ecdsa_private_key, &signature,
16910500SHai-May.Chao@Sun.COM &digest, ecdsa_Known_Seed, sizeof (ecdsa_Known_Seed), 0);
17010500SHai-May.Chao@Sun.COM
17110500SHai-May.Chao@Sun.COM if (ecdsaStatus != SECSuccess) {
17210500SHai-May.Chao@Sun.COM goto loser;
17310500SHai-May.Chao@Sun.COM }
17410500SHai-May.Chao@Sun.COM
17510500SHai-May.Chao@Sun.COM if ((signature.len != knownSignatureLen) ||
17610500SHai-May.Chao@Sun.COM (memcmp(signature.data, knownSignature,
17710500SHai-May.Chao@Sun.COM knownSignatureLen) != 0)) {
17810500SHai-May.Chao@Sun.COM ecdsaStatus = SECFailure;
17910500SHai-May.Chao@Sun.COM goto loser;
18010500SHai-May.Chao@Sun.COM }
18110500SHai-May.Chao@Sun.COM
18210500SHai-May.Chao@Sun.COM /*
18310500SHai-May.Chao@Sun.COM * ECDSA Known Answer Verification Test.
18410500SHai-May.Chao@Sun.COM */
18510500SHai-May.Chao@Sun.COM ecdsaStatus = ECDSA_VerifyDigest(&ecdsa_public_key, &signature,
18610500SHai-May.Chao@Sun.COM &digest, 0);
18710500SHai-May.Chao@Sun.COM
18810500SHai-May.Chao@Sun.COM loser:
189*10979SHai-May.Chao@Sun.COM if (ecdsa_public_key.publicValue.data != NULL)
190*10979SHai-May.Chao@Sun.COM free_ecpubkey(&ecdsa_public_key);
191*10979SHai-May.Chao@Sun.COM if (ecdsa_private_key != NULL)
192*10979SHai-May.Chao@Sun.COM free_ecprivkey(ecdsa_private_key);
193*10979SHai-May.Chao@Sun.COM free_ecparams(ecparams, B_TRUE);
194*10979SHai-May.Chao@Sun.COM
195*10979SHai-May.Chao@Sun.COM if (sha1_context != NULL)
196*10979SHai-May.Chao@Sun.COM #ifdef _KERNEL
197*10979SHai-May.Chao@Sun.COM kmem_free(sha1_context, sizeof (SHA1_CTX));
198*10979SHai-May.Chao@Sun.COM #else
199*10979SHai-May.Chao@Sun.COM free(sha1_context);
200*10979SHai-May.Chao@Sun.COM #endif
201*10979SHai-May.Chao@Sun.COM
20210500SHai-May.Chao@Sun.COM if (ecdsaStatus != SECSuccess) {
203*10979SHai-May.Chao@Sun.COM return (rv);
20410500SHai-May.Chao@Sun.COM }
20510500SHai-May.Chao@Sun.COM
20610500SHai-May.Chao@Sun.COM return (CKR_OK);
20710500SHai-May.Chao@Sun.COM }
20810500SHai-May.Chao@Sun.COM
20910500SHai-May.Chao@Sun.COM int
21010500SHai-May.Chao@Sun.COM fips_ecdsa_post() {
21110500SHai-May.Chao@Sun.COM
21210500SHai-May.Chao@Sun.COM /* ECDSA Known curve nistp256 == SEC_OID_SECG_EC_SECP256R1 params */
21310500SHai-May.Chao@Sun.COM static uint8_t ecdsa_known_P256_EncodedParams[] = {
21410500SHai-May.Chao@Sun.COM 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03,
21510500SHai-May.Chao@Sun.COM 0x01, 0x07
21610500SHai-May.Chao@Sun.COM };
21710500SHai-May.Chao@Sun.COM
21810500SHai-May.Chao@Sun.COM static uint8_t ecdsa_known_P256_signature[] = {
21910500SHai-May.Chao@Sun.COM 0x07, 0xb1, 0xcb, 0x57, 0x20, 0xa7, 0x10, 0xd6,
22010500SHai-May.Chao@Sun.COM 0x9d, 0x37, 0x4b, 0x1c, 0xdc, 0x35, 0x90, 0xff,
22110500SHai-May.Chao@Sun.COM 0x1a, 0x2d, 0x98, 0x95, 0x1b, 0x2f, 0xeb, 0x7f,
22210500SHai-May.Chao@Sun.COM 0xbb, 0x81, 0xca, 0xc0, 0x69, 0x75, 0xea, 0xc5,
22310500SHai-May.Chao@Sun.COM 0x2b, 0xdb, 0x86, 0x76, 0xe7, 0x32, 0xba, 0x13,
22410500SHai-May.Chao@Sun.COM 0x03, 0x7f, 0x7f, 0x92, 0x77, 0xd8, 0x35, 0xfe,
22510500SHai-May.Chao@Sun.COM 0x99, 0xb4, 0xb7, 0x85, 0x5a, 0xfb, 0xfb, 0xce,
22610500SHai-May.Chao@Sun.COM 0x5d, 0x0e, 0xbc, 0x01, 0xfa, 0x44, 0x97, 0x7e
22710500SHai-May.Chao@Sun.COM };
22810500SHai-May.Chao@Sun.COM
22910500SHai-May.Chao@Sun.COM int rv;
23010500SHai-May.Chao@Sun.COM
23110500SHai-May.Chao@Sun.COM /* ECDSA GF(p) prime field curve test */
23210500SHai-May.Chao@Sun.COM rv = fips_ecdsa_sign_verify(ecdsa_known_P256_EncodedParams,
23310500SHai-May.Chao@Sun.COM sizeof (ecdsa_known_P256_EncodedParams),
23410500SHai-May.Chao@Sun.COM ecdsa_known_P256_signature,
23510500SHai-May.Chao@Sun.COM sizeof (ecdsa_known_P256_signature));
23610500SHai-May.Chao@Sun.COM
23710500SHai-May.Chao@Sun.COM if (rv != CKR_OK) {
23810500SHai-May.Chao@Sun.COM return (CKR_DEVICE_ERROR);
23910500SHai-May.Chao@Sun.COM }
24010500SHai-May.Chao@Sun.COM
24110500SHai-May.Chao@Sun.COM return (CKR_OK);
24210500SHai-May.Chao@Sun.COM }
243*10979SHai-May.Chao@Sun.COM
244*10979SHai-May.Chao@Sun.COM static void
245*10979SHai-May.Chao@Sun.COM free_ecparams(ECParams *params, boolean_t freeit)
246*10979SHai-May.Chao@Sun.COM {
247*10979SHai-May.Chao@Sun.COM SECITEM_FreeItem(¶ms->fieldID.u.prime, B_FALSE);
248*10979SHai-May.Chao@Sun.COM SECITEM_FreeItem(¶ms->curve.a, B_FALSE);
249*10979SHai-May.Chao@Sun.COM SECITEM_FreeItem(¶ms->curve.b, B_FALSE);
250*10979SHai-May.Chao@Sun.COM SECITEM_FreeItem(¶ms->curve.seed, B_FALSE);
251*10979SHai-May.Chao@Sun.COM SECITEM_FreeItem(¶ms->base, B_FALSE);
252*10979SHai-May.Chao@Sun.COM SECITEM_FreeItem(¶ms->order, B_FALSE);
253*10979SHai-May.Chao@Sun.COM SECITEM_FreeItem(¶ms->DEREncoding, B_FALSE);
254*10979SHai-May.Chao@Sun.COM SECITEM_FreeItem(¶ms->curveOID, B_FALSE);
255*10979SHai-May.Chao@Sun.COM if (freeit)
256*10979SHai-May.Chao@Sun.COM #ifdef _KERNEL
257*10979SHai-May.Chao@Sun.COM kmem_free(params, sizeof (ECParams));
258*10979SHai-May.Chao@Sun.COM #else
259*10979SHai-May.Chao@Sun.COM free(params);
260*10979SHai-May.Chao@Sun.COM #endif
261*10979SHai-May.Chao@Sun.COM }
262*10979SHai-May.Chao@Sun.COM
263*10979SHai-May.Chao@Sun.COM static void
264*10979SHai-May.Chao@Sun.COM free_ecprivkey(ECPrivateKey *key)
265*10979SHai-May.Chao@Sun.COM {
266*10979SHai-May.Chao@Sun.COM free_ecparams(&key->ecParams, B_FALSE);
267*10979SHai-May.Chao@Sun.COM SECITEM_FreeItem(&key->publicValue, B_FALSE);
268*10979SHai-May.Chao@Sun.COM bzero(key->privateValue.data, key->privateValue.len);
269*10979SHai-May.Chao@Sun.COM SECITEM_FreeItem(&key->privateValue, B_FALSE);
270*10979SHai-May.Chao@Sun.COM SECITEM_FreeItem(&key->version, B_FALSE);
271*10979SHai-May.Chao@Sun.COM #ifdef _KERNEL
272*10979SHai-May.Chao@Sun.COM kmem_free(key, sizeof (ECPrivateKey));
273*10979SHai-May.Chao@Sun.COM #else
274*10979SHai-May.Chao@Sun.COM free(key);
275*10979SHai-May.Chao@Sun.COM #endif
276*10979SHai-May.Chao@Sun.COM }
277*10979SHai-May.Chao@Sun.COM
278*10979SHai-May.Chao@Sun.COM static void
279*10979SHai-May.Chao@Sun.COM free_ecpubkey(ECPublicKey *key)
280*10979SHai-May.Chao@Sun.COM {
281*10979SHai-May.Chao@Sun.COM free_ecparams(&key->ecParams, B_FALSE);
282*10979SHai-May.Chao@Sun.COM }
283