xref: /onnv-gate/usr/src/common/crypto/fips/fips_ecc_util.c (revision 10979:00cad6413daf)
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(&params->fieldID.u.prime, B_FALSE);
248*10979SHai-May.Chao@Sun.COM 	SECITEM_FreeItem(&params->curve.a, B_FALSE);
249*10979SHai-May.Chao@Sun.COM 	SECITEM_FreeItem(&params->curve.b, B_FALSE);
250*10979SHai-May.Chao@Sun.COM 	SECITEM_FreeItem(&params->curve.seed, B_FALSE);
251*10979SHai-May.Chao@Sun.COM 	SECITEM_FreeItem(&params->base, B_FALSE);
252*10979SHai-May.Chao@Sun.COM 	SECITEM_FreeItem(&params->order, B_FALSE);
253*10979SHai-May.Chao@Sun.COM 	SECITEM_FreeItem(&params->DEREncoding, B_FALSE);
254*10979SHai-May.Chao@Sun.COM 	SECITEM_FreeItem(&params->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