From f87129ad8722656f3fd3ea2dd2b51d802c9e8efa Mon Sep 17 00:00:00 2001 From: "nelsonb%netscape.com" Date: Thu, 27 Feb 2003 01:31:38 +0000 Subject: [PATCH] Add support for Elliptic Curve Cryptography. Bug 195135. Modified Files: cmd/lib/SECerrs.h cmd/selfserv/selfserv.c cmd/tstclnt/tstclnt.c lib/cryptohi/keyhi.h lib/cryptohi/keythi.h lib/cryptohi/seckey.c lib/cryptohi/secvfy.c lib/freebl/Makefile lib/freebl/blapi.h lib/freebl/blapit.h lib/freebl/ldvector.c lib/freebl/loader.c lib/freebl/loader.h lib/freebl/manifest.mn lib/nss/nss.def lib/pk11wrap/pk11skey.c lib/pk11wrap/pk11slot.c lib/softoken/lowkeyti.h lib/softoken/manifest.mn lib/softoken/pkcs11.c lib/softoken/pkcs11c.c lib/softoken/pkcs11t.h lib/ssl/ssl3con.c lib/ssl/ssl3prot.h lib/ssl/sslcon.c lib/ssl/sslenum.c lib/ssl/sslimpl.h lib/ssl/sslinfo.c lib/ssl/sslproto.h lib/ssl/sslsecur.c lib/ssl/sslsock.c lib/ssl/sslt.h lib/util/secerr.h lib/util/secoid.c lib/util/secoidt.h Added Files: lib/freebl/GFp_ecl.c lib/freebl/GFp_ecl.h lib/freebl/ec.c lib/freebl/ec.h lib/softoken/ecdecode.c --- security/nss/cmd/lib/SECerrs.h | 14 + security/nss/cmd/selfserv/selfserv.c | 49 +- security/nss/cmd/tstclnt/tstclnt.c | 43 +- security/nss/lib/cryptohi/keyhi.h | 19 +- security/nss/lib/cryptohi/keythi.h | 29 +- security/nss/lib/cryptohi/seckey.c | 212 +++++- security/nss/lib/cryptohi/secvfy.c | 97 ++- security/nss/lib/freebl/GFp_ecl.c | 647 +++++++++++++++++ security/nss/lib/freebl/GFp_ecl.h | 126 ++++ security/nss/lib/freebl/Makefile | 2 +- security/nss/lib/freebl/blapi.h | 70 +- security/nss/lib/freebl/blapit.h | 82 ++- security/nss/lib/freebl/ec.c | 958 ++++++++++++++++++++++++++ security/nss/lib/freebl/ec.h | 50 ++ security/nss/lib/freebl/ldvector.c | 16 +- security/nss/lib/freebl/loader.c | 72 +- security/nss/lib/freebl/loader.h | 42 +- security/nss/lib/freebl/manifest.mn | 9 + security/nss/lib/nss/nss.def | 6 + security/nss/lib/pk11wrap/pk11skey.c | 161 ++++- security/nss/lib/pk11wrap/pk11slot.c | 25 +- security/nss/lib/softoken/ecdecode.c | 672 ++++++++++++++++++ security/nss/lib/softoken/lowkeyti.h | 9 +- security/nss/lib/softoken/manifest.mn | 1 + security/nss/lib/softoken/pkcs11.c | 99 ++- security/nss/lib/softoken/pkcs11c.c | 243 ++++++- security/nss/lib/softoken/pkcs11t.h | 23 + security/nss/lib/ssl/ssl3con.c | 813 +++++++++++++++++++++- security/nss/lib/ssl/ssl3prot.h | 12 +- security/nss/lib/ssl/sslcon.c | 8 +- security/nss/lib/ssl/sslenum.c | 34 +- security/nss/lib/ssl/sslimpl.h | 19 +- security/nss/lib/ssl/sslinfo.c | 30 +- security/nss/lib/ssl/sslproto.h | 29 +- security/nss/lib/ssl/sslsecur.c | 8 +- security/nss/lib/ssl/sslsock.c | 24 +- security/nss/lib/ssl/sslt.h | 14 +- security/nss/lib/util/secerr.h | 7 +- security/nss/lib/util/secoid.c | 137 ++++ security/nss/lib/util/secoidt.h | 39 +- 40 files changed, 4875 insertions(+), 75 deletions(-) create mode 100644 security/nss/lib/freebl/GFp_ecl.c create mode 100644 security/nss/lib/freebl/GFp_ecl.h create mode 100644 security/nss/lib/freebl/ec.c create mode 100644 security/nss/lib/freebl/ec.h create mode 100644 security/nss/lib/softoken/ecdecode.c diff --git a/security/nss/cmd/lib/SECerrs.h b/security/nss/cmd/lib/SECerrs.h index 9496b74e5b86..e566e3983f39 100644 --- a/security/nss/cmd/lib/SECerrs.h +++ b/security/nss/cmd/lib/SECerrs.h @@ -460,3 +460,17 @@ ER3(SEC_ERROR_REUSED_ISSUER_AND_SERIAL, (SEC_ERROR_BASE + 138), "You are attempting to import a cert with the same issuer/serial as \ an existing cert, but that is not the same cert.") +ER3(SEC_ERROR_BUSY, (SEC_ERROR_BASE + 139), +"NSS could not shutdown. Objects are still in use.") + +ER3(SEC_ERROR_EXTRA_INPUT, (SEC_ERROR_BASE + 140), +"DER-encoded message contained extra usused data.") + +ER3(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE, (SEC_ERROR_BASE + 141), +"Unsupported elliptic curve.") + +ER3(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM, (SEC_ERROR_BASE + 142), +"Unsupported elliptic curve point form.") + +ER3(SEC_ERROR_UNRECOGNIZED_OID, (SEC_ERROR_BASE + 143), +"Unrecognized Object IDentifier.") diff --git a/security/nss/cmd/selfserv/selfserv.c b/security/nss/cmd/selfserv/selfserv.c index ea07970733b0..044f1476ebfe 100644 --- a/security/nss/cmd/selfserv/selfserv.c +++ b/security/nss/cmd/selfserv/selfserv.c @@ -15,8 +15,12 @@ * Communications Corporation. Portions created by Netscape are * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. - * + * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -101,6 +105,28 @@ const int ssl2CipherSuites[] = { SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */ SSL_EN_DES_64_CBC_WITH_MD5, /* E */ SSL_EN_DES_192_EDE3_CBC_WITH_MD5, /* F */ +#ifdef NSS_ENABLE_ECC + /* NOTE: Since no new SSL2 ciphersuites are being + * invented, and we've run out of lowercase letters + * for SSL3 ciphers, we use letters G and beyond + * for new SSL3 ciphers. A -1 indicates the cipher + * is not currently implemented. + */ + -1, /* TLS_ECDH_ECDSA_WITH_NULL_SHA, * G */ + -1, /* TLS_ECDH_ECDSA_WITH_RC4_128_SHA, * H */ + -1, /* TLS_ECDH_ECDSA_WITH_DES_CBC_SHA, * I */ + -1, /* TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, * J */ + -1, /* TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, * K */ + -1, /* TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, * L */ + -1, /* TLS_ECDH_RSA_WITH_NULL_SHA, * M */ + -1, /* TLS_ECDH_RSA_WITH_RC4_128_SHA, * N */ + -1, /* TLS_ECDH_RSA_WITH_DES_CBC_SHA, * O */ + -1, /* TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, * P */ + -1, /* TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, * Q */ + -1, /* TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, * R */ + -1, /* TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, * S */ + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* T */ +#endif /* NSS_ENABLE_ECC */ 0 }; @@ -119,16 +145,16 @@ const int ssl3CipherSuites[] = { TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, /* l */ TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, /* m */ SSL_RSA_WITH_RC4_128_SHA, /* n */ - TLS_DHE_DSS_WITH_RC4_128_SHA, /* o */ - SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, /* p */ - SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, /* q */ - SSL_DHE_RSA_WITH_DES_CBC_SHA, /* r */ - SSL_DHE_DSS_WITH_DES_CBC_SHA, /* s */ - TLS_DHE_DSS_WITH_AES_128_CBC_SHA, /* t */ - TLS_DHE_RSA_WITH_AES_128_CBC_SHA, /* u */ + -1, /* TLS_DHE_DSS_WITH_RC4_128_SHA, * o */ + -1, /* SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, * p */ + -1, /* SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, * q */ + -1, /* SSL_DHE_RSA_WITH_DES_CBC_SHA, * r */ + -1, /* SSL_DHE_DSS_WITH_DES_CBC_SHA, * s */ + -1, /* TLS_DHE_DSS_WITH_AES_128_CBC_SHA, * t */ + -1, /* TLS_DHE_RSA_WITH_AES_128_CBC_SHA, * u */ TLS_RSA_WITH_AES_128_CBC_SHA, /* v */ - TLS_DHE_DSS_WITH_AES_256_CBC_SHA, /* w */ - TLS_DHE_RSA_WITH_AES_256_CBC_SHA, /* x */ + -1, /* TLS_DHE_DSS_WITH_AES_256_CBC_SHA, * w */ + -1, /* TLS_DHE_RSA_WITH_AES_256_CBC_SHA, * x */ TLS_RSA_WITH_AES_256_CBC_SHA, /* y */ SSL_RSA_WITH_NULL_SHA, /* z */ 0 @@ -199,6 +225,9 @@ Usage(const char *progName) "D SSL2 RC2 128 CBC EXPORT40 WITH MD5\n" "E SSL2 DES 64 CBC WITH MD5\n" "F SSL2 DES 192 EDE3 CBC WITH MD5\n" +#ifdef NSS_ENABLE_ECC +"T TLS ECDHE RSA WITH AES 128 CBC SHA\n" +#endif /* NSS_ENABLE_ECC */ "\n" "a SSL3 FORTEZZA DMS WITH FORTEZZA CBC SHA\n" "b SSL3 FORTEZZA DMS WITH RC4 128 SHA\n" diff --git a/security/nss/cmd/tstclnt/tstclnt.c b/security/nss/cmd/tstclnt/tstclnt.c index 860635f92175..84f08f3a62c6 100644 --- a/security/nss/cmd/tstclnt/tstclnt.c +++ b/security/nss/cmd/tstclnt/tstclnt.c @@ -15,8 +15,12 @@ * Communications Corporation. Portions created by Netscape are * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. - * + * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -74,6 +78,27 @@ int ssl2CipherSuites[] = { SSL_EN_RC2_128_CBC_EXPORT40_WITH_MD5, /* D */ SSL_EN_DES_64_CBC_WITH_MD5, /* E */ SSL_EN_DES_192_EDE3_CBC_WITH_MD5, /* F */ +#ifdef NSS_ENABLE_ECC + /* NOTE: Since no new SSL2 ciphersuites are being + * invented, and we've run out of lowercase letters + * for SSL3 ciphers, we use letters G and beyond + * for new SSL3 ciphers. + */ + TLS_ECDH_ECDSA_WITH_NULL_SHA, /* G */ + TLS_ECDH_ECDSA_WITH_RC4_128_SHA, /* H */ + TLS_ECDH_ECDSA_WITH_DES_CBC_SHA, /* I */ + TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, /* J */ + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, /* K */ + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, /* L */ + TLS_ECDH_RSA_WITH_NULL_SHA, /* M */ + TLS_ECDH_RSA_WITH_RC4_128_SHA, /* N */ + TLS_ECDH_RSA_WITH_DES_CBC_SHA, /* O */ + TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, /* P */ + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, /* Q */ + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, /* R */ + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, /* S */ + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, /* T */ +#endif /* NSS_ENABLE_ECC */ 0 }; @@ -206,6 +231,22 @@ static void Usage(const char *progName) "D SSL2 RC2 128 CBC EXPORT40 WITH MD5\n" "E SSL2 DES 64 CBC WITH MD5\n" "F SSL2 DES 192 EDE3 CBC WITH MD5\n" +#ifdef NSS_ENABLE_ECC +"G TLS ECDH ECDSA WITH NULL SHA\n" +"H TLS ECDH ECDSA WITH RC4 128 CBC SHA\n" +"I TLS ECDH ECDSA WITH DES CBC SHA\n" +"J TLS ECDH ECDSA WITH 3DES EDE CBC SHA\n" +"K TLS ECDH ECDSA WITH AES 128 CBC SHA\n" +"L TLS ECDH ECDSA WITH AES 256 CBC SHA\n" +"M TLS ECDH RSA WITH NULL SHA\n" +"N TLS ECDH RSA WITH RC4 128 CBC SHA\n" +"O TLS ECDH RSA WITH DES CBC SHA\n" +"P TLS ECDH RSA WITH 3DES EDE CBC SHA\n" +"Q TLS ECDH RSA WITH AES 128 CBC SHA\n" +"R TLS ECDH RSA WITH AES 256 CBC SHA\n" +"S TLS ECDHE ECDSA WITH AES 128 CBC SHA\n" +"T TLS ECDHE RSA WITH AES 128 CBC SHA\n" +#endif /* NSS_ENABLE_ECC */ "\n" "a SSL3 FORTEZZA DMS WITH FORTEZZA CBC SHA\n" "b SSL3 FORTEZZA DMS WITH RC4 128 SHA\n" diff --git a/security/nss/lib/cryptohi/keyhi.h b/security/nss/lib/cryptohi/keyhi.h index 6e2c99c1fb71..fd36f97061e8 100644 --- a/security/nss/lib/cryptohi/keyhi.h +++ b/security/nss/lib/cryptohi/keyhi.h @@ -16,8 +16,12 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): * Dr Stephen Henson + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -33,7 +37,7 @@ * * key.h - public data structures and prototypes for the private key library * - * $Id: keyhi.h,v 1.7 2002/02/03 03:37:17 relyea%netscape.com Exp $ + * $Id: keyhi.h,v 1.8 2003/02/27 01:31:04 nelsonb%netscape.com Exp $ */ #ifndef _KEYHI_H_ @@ -79,10 +83,14 @@ extern SECStatus SECKEY_KEAParamCompare(CERTCertificate *cert1,CERTCertificate *cert2); /* -** Return the strength of the public key +** Return the strength of the public key in bytes */ extern unsigned SECKEY_PublicKeyStrength(SECKEYPublicKey *pubk); +/* +** Return the strength of the public key in bits +*/ +extern unsigned SECKEY_PublicKeyStrengthInBits(SECKEYPublicKey *pubk); /* ** Make a copy of the private key "privKey" @@ -110,6 +118,13 @@ SECKEYPrivateKey *SECKEY_CreateRSAPrivateKey(int keySizeInBits, */ SECKEYPrivateKey *SECKEY_CreateDHPrivateKey(SECKEYDHParams *param, SECKEYPublicKey **pubk, void *cx); + +/* + * create a new EC key pair. The private Key is returned... + */ +SECKEYPrivateKey *SECKEY_CreateECPrivateKey(SECKEYECParams *param, + SECKEYPublicKey **pubk, void *cx); + /* ** Create a subject-public-key-info based on a public key. */ diff --git a/security/nss/lib/cryptohi/keythi.h b/security/nss/lib/cryptohi/keythi.h index 7b864b8681a1..6c4f3aaf32da 100644 --- a/security/nss/lib/cryptohi/keythi.h +++ b/security/nss/lib/cryptohi/keythi.h @@ -16,7 +16,11 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * - * Contributor(s): + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -44,7 +48,8 @@ typedef enum { dsaKey = 2, fortezzaKey = 3, dhKey = 4, - keaKey = 5 + keaKey = 5, + ecKey = 6 } KeyType; /* @@ -117,6 +122,25 @@ struct SECKEYDHPublicKeyStr { }; typedef struct SECKEYDHPublicKeyStr SECKEYDHPublicKey; +/* +** Elliptic curve Public Key structure +** The PKCS#11 layer needs DER encoding of ANSI X9.62 +** parameters value +*/ +typedef SECItem SECKEYECParams; + +struct SECKEYECPublicKeyStr { + SECKEYECParams DEREncodedParams; + int size; /* size in bits */ + SECItem publicValue; /* encoded point */ + /* XXX Even though the PKCS#11 interface takes encoded parameters, + * we may still wish to decode them above PKCS#11 for things like + * printing key information. For named curves, which is what + * we initially support, we ought to have the curve name at the + * very least. + */ +}; +typedef struct SECKEYECPublicKeyStr SECKEYECPublicKey; /* ** FORTEZZA Public Key structures @@ -173,6 +197,7 @@ struct SECKEYPublicKeyStr { SECKEYDHPublicKey dh; SECKEYKEAPublicKey kea; SECKEYFortezzaPublicKey fortezza; + SECKEYECPublicKey ec; } u; }; typedef struct SECKEYPublicKeyStr SECKEYPublicKey; diff --git a/security/nss/lib/cryptohi/seckey.c b/security/nss/lib/cryptohi/seckey.c index 92c36b74dbde..48a7c27ff5d2 100644 --- a/security/nss/lib/cryptohi/seckey.c +++ b/security/nss/lib/cryptohi/seckey.c @@ -16,8 +16,12 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): * Dr Stephen Henson + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -44,6 +48,7 @@ #include "secerr.h" #include "secdig.h" #include "prtime.h" +#include "ec.h" const SEC_ASN1Template CERT_SubjectPublicKeyInfoTemplate[] = { { SEC_ASN1_SEQUENCE, @@ -229,6 +234,33 @@ SECKEY_CreateDHPrivateKey(SECKEYDHParams *param, SECKEYPublicKey **pubk, void *c return(privk); } +/* Create an EC key pair in any slot able to do so, +** This is a "session" (temporary), not "token" (permanent) key. +** Because of the high probability that this key will need to be moved to +** another token, and the high cost of moving "sensitive" keys, we attempt +** to create this key pair without the "sensitive" attribute, but revert to +** creating a "sensitive" key if necessary. +*/ +SECKEYPrivateKey * +SECKEY_CreateECPrivateKey(SECKEYECParams *param, SECKEYPublicKey **pubk, void *cx) +{ +#ifdef NSS_ENABLE_ECC + SECKEYPrivateKey *privk; + PK11SlotInfo *slot = PK11_GetBestSlot(CKM_EC_KEY_PAIR_GEN,cx); + + privk = PK11_GenerateKeyPair(slot, CKM_EC_KEY_PAIR_GEN, param, + pubk, PR_FALSE, PR_FALSE, cx); + if (!privk) + privk = PK11_GenerateKeyPair(slot, CKM_EC_KEY_PAIR_GEN, param, + pubk, PR_FALSE, PR_TRUE, cx); + + PK11_FreeSlot(slot); + return(privk); +#else + return NULL; +#endif /* NSS_ENABLE_ECC */ +} + void SECKEY_DestroyPrivateKey(SECKEYPrivateKey *privk) { @@ -433,7 +465,8 @@ seckey_UpdateCertPQGChain(CERTCertificate * subjectCert, int count) (tag != SEC_OID_ANSIX9_DSA_SIGNATURE) && (tag != SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) && (tag != SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST) && - (tag != SEC_OID_SDN702_DSA_SIGNATURE) ) { + (tag != SEC_OID_SDN702_DSA_SIGNATURE) && + (tag != SEC_OID_ANSIX962_EC_PUBLIC_KEY) ) { return SECSuccess; } @@ -480,8 +513,8 @@ seckey_UpdateCertPQGChain(CERTCertificate * subjectCert, int count) (tag != SEC_OID_ANSIX9_DSA_SIGNATURE) && (tag != SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST) && (tag != SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST) && - (tag != SEC_OID_SDN702_DSA_SIGNATURE) ) { - + (tag != SEC_OID_SDN702_DSA_SIGNATURE) && + (tag != SEC_OID_ANSIX962_EC_PUBLIC_KEY) ) { return SECFailure; } } else { @@ -881,12 +914,49 @@ CERT_GetCertKeyType (CERTSubjectPublicKeyInfo *spki) { case SEC_OID_X942_DIFFIE_HELMAN_KEY: keyType = dhKey; break; + case SEC_OID_ANSIX962_EC_PUBLIC_KEY: + keyType = ecKey; + break; default: keyType = nullKey; } return keyType; } +#ifdef NSS_ENABLE_ECC +static int +seckey_supportedECParams(SECItem *encodedParams) +{ + SECOidTag tag; + SECItem oid = { siBuffer, NULL, 0}; + + /* We do not currently support explicit DER encoding of curve + * parameters. Make sure the encoding takes the form of + * an object identifier (this is how named curves are encoded). + */ + if (encodedParams->data[0] != SEC_ASN1_OBJECT_ID) return 0; + + /* The encodedParams data contains 0x06 (SEC_ASN1_OBJECT_ID), + * followed by the length of the curve oid and the curve oid. + */ + oid.len = encodedParams->data[1]; + oid.data = encodedParams->data + 2; + tag = SECOID_FindOIDTag(&oid); + + return (((tag >= SEC_OID_ANSIX962_EC_PRIME192V1) + && (tag <= SEC_OID_ANSIX962_EC_PRIME256V1)) || + ((tag >= SEC_OID_SECG_EC_SECP112R1) + && (tag <= SEC_OID_SECG_EC_SECP521R1))); +} + +static int +seckey_supportedECPointForm(SECItem *ecPoint) +{ + /* For now, we only support uncompressed points */ + return (ecPoint->data[0] == EC_POINT_FORM_UNCOMPRESSED); +} +#endif /* NSS_ENABLE_ECC */ + static SECKEYPublicKey * seckey_ExtractPublicKey(CERTSubjectPublicKeyInfo *spki) { @@ -1012,6 +1082,46 @@ seckey_ExtractPublicKey(CERTSubjectPublicKeyInfo *spki) break; +#ifdef NSS_ENABLE_ECC + case SEC_OID_ANSIX962_EC_PUBLIC_KEY: + pubk->keyType = ecKey; + pubk->u.ec.size = 0; +#if 0 + /* If we uncomment these checks, ssl3con.c produces an "SSL + * was unable to extract the public key from the peer's + * certificate" error upon encountering an EC certificate with + * an unsupported curve or point form. It isn't clear that we + * should be triggering this error because the EC key was + * *successfully extracted* even though we can't use + * it. Commenting these checks delays detection of unsupported + * curves to a later point in the handshake (e.g. when a + * client attempts to generate a key pair before sending the + * ClientKeyExchange message). + */ + if (!seckey_supportedECParams(&spki->algorithm.parameters)) { + PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); + rv = SECFailure; + break; + } + + if (!seckey_supportedECPointForm(&newOs)) { + PORT_SetError(SEC_ERROR_UNSUPPORTED_EC_POINT_FORM); + rv = SECFailure; + break; + } +#endif + + /* Since PKCS#11 directly takes the DER encoding of EC params + * and public value, we don't need any decoding here. + */ + rv = SECITEM_CopyItem(arena, &pubk->u.ec.DEREncodedParams, + &spki->algorithm.parameters); + if ( rv != SECSuccess ) + break; + rv = SECITEM_CopyItem(arena, &pubk->u.ec.publicValue, &newOs); + if (rv == SECSuccess) return pubk; + break; +#endif /* NSS_ENABLE_ECC */ default: rv = SECFailure; @@ -1053,6 +1163,59 @@ CERT_KMIDPublicKey(CERTCertificate *cert) return seckey_ExtractPublicKey(&cert->subjectPublicKeyInfo); } +#ifdef NSS_ENABLE_ECC +static int +seckey_ECParams2KeySize(SECItem *encodedParams) +{ + SECOidTag tag; + SECItem oid = { siBuffer, NULL, 0}; + + /* The encodedParams data contains 0x06 (SEC_ASN1_OBJECT_ID), + * followed by the length of the curve oid and the curve oid. + */ + oid.len = encodedParams->data[1]; + oid.data = encodedParams->data + 2; + if ((tag = SECOID_FindOIDTag(&oid)) == SEC_OID_UNKNOWN) + return 0; + switch (tag) { + case SEC_OID_ANSIX962_EC_PRIME192V1: + case SEC_OID_ANSIX962_EC_PRIME192V2: + case SEC_OID_ANSIX962_EC_PRIME192V3: + return 192; + case SEC_OID_ANSIX962_EC_PRIME239V1: + case SEC_OID_ANSIX962_EC_PRIME239V2: + case SEC_OID_ANSIX962_EC_PRIME239V3: + return 239; + case SEC_OID_ANSIX962_EC_PRIME256V1: + return 256; + + case SEC_OID_SECG_EC_SECP112R1: + case SEC_OID_SECG_EC_SECP112R2: + return 112; + case SEC_OID_SECG_EC_SECP128R1: + case SEC_OID_SECG_EC_SECP128R2: + return 128; + case SEC_OID_SECG_EC_SECP160K1: + case SEC_OID_SECG_EC_SECP160R1: + case SEC_OID_SECG_EC_SECP160R2: + return 160; + case SEC_OID_SECG_EC_SECP192K1: + return 192; + case SEC_OID_SECG_EC_SECP224K1: + case SEC_OID_SECG_EC_SECP224R1: + return 224; + case SEC_OID_SECG_EC_SECP256K1: + return 256; + case SEC_OID_SECG_EC_SECP384R1: + return 384; + case SEC_OID_SECG_EC_SECP521R1: + return 521; + default: + return 0; + } +} +#endif /* NSS_ENABLE_ECC */ + /* returns key strength in bytes (not bits) */ unsigned SECKEY_PublicKeyStrength(SECKEYPublicKey *pubk) @@ -1076,6 +1239,39 @@ SECKEY_PublicKeyStrength(SECKEYPublicKey *pubk) pubk->u.dh.publicValue.len - 1; case fortezzaKey: return PR_MAX(pubk->u.fortezza.KEAKey.len, pubk->u.fortezza.DSSKey.len); +#ifdef NSS_ENABLE_ECC + case ecKey: + /* Get the key size in bits and adjust */ + if (pubk->u.ec.size == 0) { + pubk->u.ec.size = + seckey_ECParams2KeySize(&pubk->u.ec.DEREncodedParams); + } + return (pubk->u.ec.size + 7)/8; +#endif /* NSS_ENABLE_ECC */ + default: + break; + } + return 0; +} + +/* returns key strength in bits */ +unsigned +SECKEY_PublicKeyStrengthInBits(SECKEYPublicKey *pubk) +{ + switch (pubk->keyType) { + case rsaKey: + case dsaKey: + case dhKey: + case fortezzaKey: + return SECKEY_PublicKeyStrength(pubk) * 8; /* 1 byte = 8 bits */ +#ifdef NSS_ENABLE_ECC + case ecKey: + if (pubk->u.ec.size == 0) { + pubk->u.ec.size = + seckey_ECParams2KeySize(&pubk->u.ec.DEREncodedParams); + } + return pubk->u.ec.size; +#endif /* NSS_ENABLE_ECC */ default: break; } @@ -1230,6 +1426,16 @@ SECKEY_CopyPublicKey(SECKEYPublicKey *pubk) rv = SECITEM_CopyItem(arena, ©k->u.dh.publicValue, &pubk->u.dh.publicValue); break; +#ifdef NSS_ENABLE_ECC + case ecKey: + copyk->u.ec.size = pubk->u.ec.size; + rv = SECITEM_CopyItem(arena,©k->u.ec.DEREncodedParams, + &pubk->u.ec.DEREncodedParams); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena,©k->u.ec.publicValue, + &pubk->u.ec.publicValue); + break; +#endif /* NSS_ENABLE_ECC */ case nullKey: return copyk; default: diff --git a/security/nss/lib/cryptohi/secvfy.c b/security/nss/lib/cryptohi/secvfy.c index caed804fcb7c..1e8b69d6cbf9 100644 --- a/security/nss/lib/cryptohi/secvfy.c +++ b/security/nss/lib/cryptohi/secvfy.c @@ -18,7 +18,11 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -32,7 +36,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: secvfy.c,v 1.7 2002/12/12 06:05:17 nelsonb%netscape.com Exp $ + * $Id: secvfy.c,v 1.8 2003/02/27 01:31:07 nelsonb%netscape.com Exp $ */ #include @@ -106,7 +110,7 @@ DecryptSigBlock(int *tagp, unsigned char *digest, SECKEYPublicKey *key, return rv; } -typedef enum { VFY_RSA, VFY_DSA} VerifyType; +typedef enum { VFY_RSA, VFY_DSA, VFY_ECDSA } VerifyType; struct VFYContextStr { SECOidTag alg; @@ -119,6 +123,7 @@ struct VFYContextStr { const SECHashObject *hashobj; SECOidTag sigAlg; PRBool hasSignature; + unsigned char ecdsadigest[2 * MAX_ECKEY_LEN]; }; /* @@ -211,12 +216,60 @@ decodeSigAlg(SECOidTag alg, SECOidTag *hashalg) return SECSuccess; } +#ifdef NSS_ENABLE_ECC +/* + * decode the ECDSA signature from it's DER wrapping. + */ +static SECStatus +decodeECDSASignature(SECOidTag algid, SECItem *sig, + unsigned char *digest, int len) +{ + SECStatus rv=SECSuccess; + + if (len > MAX_ECKEY_LEN * 2) { + rv = SECFailure; + goto loser; + } + + /* if this is a DER encoded signature, decode it first */ + if (algid == SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST) { + /* XXX Use a better decoder */ + if ((sig->len < len + 6) || + (sig->data[0] != 0x30) || /* must start with a SEQUENCE */ + (sig->data[1] != sig->len - 2) || + (sig->data[2] != 0x02) || /* 1st INTEGER, r */ + (sig->data[3] < len/2) || + (sig->data[4 + sig->data[3]] != 0x02) || /* 2nd INTEGER, s */ + (sig->data[5 + sig->data[3]] < len/2)) { + rv = SECFailure; + goto loser; + } + + PORT_Memcpy(digest, sig->data + 4 + (sig->data[3]-len/2), len/2); + PORT_Memcpy(digest + len/2, sig->data + sig->len - len/2, len/2); + } else { + if (sig->len != len) { + rv = SECFailure; + goto loser; + } + PORT_Memcpy(digest, sig->data, sig->len); + } + +loser: + if (rv == SECFailure) PORT_SetError(SEC_ERROR_BAD_DER); + return rv; +} +#endif /* NSS_ENABLE_ECC */ + VFYContext * VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag algid, void *wincx) { VFYContext *cx; SECStatus rv; +#ifdef NSS_ENABLE_ECC + int sigLen; +#endif /* NSS_ENABLE_ECC */ cx = (VFYContext*) PORT_ZAlloc(sizeof(VFYContext)); if (cx) { @@ -246,6 +299,21 @@ VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag algid, rv = decodeDSASignature(algid,sig,&cx->digest[0]); } break; +#ifdef NSS_ENABLE_ECC + case ecKey: + cx->type = VFY_ECDSA; + cx->alg = SEC_OID_SHA1; + cx->key = SECKEY_CopyPublicKey(key); + /* Unlike DSA, EDSA does not have a fixed signature length + * (it depends on the key size) + */ + sigLen = SECKEY_PublicKeyStrength(key) * 2; + if (sig) { + rv = decodeECDSASignature(algid,sig,&cx->ecdsadigest[0], + sigLen); + } + break; +#endif /* NSS_ENABLE_ECC */ default: rv = SECFailure; break; @@ -326,6 +394,9 @@ VFY_EndWithSignature(VFYContext *cx, SECItem *sig) unsigned part; SECItem hash,dsasig; SECStatus rv; +#ifdef NSS_ENABLE_ECC + SECItem ecdsasig; +#endif /* NSS_ENABLE_ECC */ if ((cx->hasSignature == PR_FALSE) && (sig == NULL)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -370,6 +441,28 @@ VFY_EndWithSignature(VFYContext *cx, SECItem *sig) return SECFailure; } break; + +#ifdef NSS_ENABLE_ECC + case VFY_ECDSA: + if (sig) { + rv = decodeECDSASignature(cx->sigAlg,sig,&cx->ecdsadigest[0], + SECKEY_PublicKeyStrength(cx->key) * 2); + if (rv != SECSuccess) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + return SECFailure; + } + } + ecdsasig.data = cx->ecdsadigest; + ecdsasig.len = SECKEY_PublicKeyStrength(cx->key) * 2; + hash.data = final; + hash.len = part; + if (PK11_Verify(cx->key,&ecdsasig,&hash,cx->wincx) != SECSuccess) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + return SECFailure; + } + break; +#endif /* NSS_ENABLE_ECC */ + default: PORT_SetError(SEC_ERROR_BAD_SIGNATURE); return SECFailure; /* shouldn't happen */ diff --git a/security/nss/lib/freebl/GFp_ecl.c b/security/nss/lib/freebl/GFp_ecl.c new file mode 100644 index 000000000000..1b662b827a73 --- /dev/null +++ b/security/nss/lib/freebl/GFp_ecl.c @@ -0,0 +1,647 @@ +/* + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the elliptic curve math library for prime + * field curves. + * + * The Initial Developer of the Original Code is Sun Microsystems, Inc. + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Sheueling Chang Shantz and + * Douglas Stebila , Sun Microsystems Laboratories + * + * Bodo Moeller , + * Nils Larsch , and + * Lenka Fibikova , the OpenSSL Project. + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + */ +#ifdef NSS_ENABLE_ECC +/* + * GFp_ecl.c: Contains an implementation of elliptic curve math library + * for curves over GFp. + * + * XXX Can be moved to a separate subdirectory later. + * + */ + +#include "GFp_ecl.h" +#include "mpi/mplogic.h" + +/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */ +mp_err +GFp_ec_pt_is_inf_aff(const mp_int *px, const mp_int *py) +{ + + if ((mp_cmp_z(px) == 0) && (mp_cmp_z(py) == 0)) { + return MP_YES; + } else { + return MP_NO; + } + +} + +/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */ +mp_err +GFp_ec_pt_set_inf_aff(mp_int *px, mp_int *py) +{ + mp_zero(px); + mp_zero(py); + return MP_OKAY; +} + +/* Computes R = P + Q based on IEEE P1363 A.10.1. + * Elliptic curve points P, Q, and R can all be identical. + * Uses affine coordinates. + */ +mp_err +GFp_ec_pt_add_aff(const mp_int *p, const mp_int *a, const mp_int *px, + const mp_int *py, const mp_int *qx, const mp_int *qy, + mp_int *rx, mp_int *ry) +{ + mp_err err = MP_OKAY; + mp_int lambda, temp, xtemp, ytemp; + + CHECK_MPI_OK( mp_init(&lambda) ); + CHECK_MPI_OK( mp_init(&temp) ); + CHECK_MPI_OK( mp_init(&xtemp) ); + CHECK_MPI_OK( mp_init(&ytemp) ); + /* if P = inf, then R = Q */ + if (GFp_ec_pt_is_inf_aff(px, py) == 0) { + CHECK_MPI_OK( mp_copy(qx, rx) ); + CHECK_MPI_OK( mp_copy(qy, ry) ); + err = MP_OKAY; + goto cleanup; + } + /* if Q = inf, then R = P */ + if (GFp_ec_pt_is_inf_aff(qx, qy) == 0) { + CHECK_MPI_OK( mp_copy(px, rx) ); + CHECK_MPI_OK( mp_copy(py, ry) ); + err = MP_OKAY; + goto cleanup; + } + /* if px != qx, then lambda = (py-qy) / (px-qx) */ + if (mp_cmp(px, qx) != 0) { + CHECK_MPI_OK( mp_submod(py, qy, p, &ytemp) ); + CHECK_MPI_OK( mp_submod(px, qx, p, &xtemp) ); + CHECK_MPI_OK( mp_invmod(&xtemp, p, &xtemp) ); + CHECK_MPI_OK( mp_mulmod(&ytemp, &xtemp, p, &lambda) ); + } else { + /* if py != qy or qy = 0, then R = inf */ + if (((mp_cmp(py, qy) != 0)) || (mp_cmp_z(qy) == 0)) { + mp_zero(rx); + mp_zero(ry); + err = MP_OKAY; + goto cleanup; + } + /* lambda = (3qx^2+a) / (2qy) */ + CHECK_MPI_OK( mp_sqrmod(qx, p, &xtemp) ); + mp_set(&temp, 0x3); + CHECK_MPI_OK( mp_mulmod(&xtemp, &temp, p, &xtemp) ); + CHECK_MPI_OK( mp_addmod(&xtemp, a, p, &xtemp) ); + mp_set(&temp, 0x2); + CHECK_MPI_OK( mp_mulmod(qy, &temp, p, &ytemp) ); + CHECK_MPI_OK( mp_invmod(&ytemp, p, &ytemp) ); + CHECK_MPI_OK( mp_mulmod(&xtemp, &ytemp, p, &lambda) ); + } + /* rx = lambda^2 - px - qx */ + CHECK_MPI_OK( mp_sqrmod(&lambda, p, &xtemp) ); + CHECK_MPI_OK( mp_submod(&xtemp, px, p, &xtemp) ); + CHECK_MPI_OK( mp_submod(&xtemp, qx, p, &xtemp) ); + /* ry = (x1-x2) * lambda - y1 */ + CHECK_MPI_OK( mp_submod(qx, &xtemp, p, &ytemp) ); + CHECK_MPI_OK( mp_mulmod(&ytemp, &lambda, p, &ytemp) ); + CHECK_MPI_OK( mp_submod(&ytemp, qy, p, &ytemp) ); + CHECK_MPI_OK( mp_copy(&xtemp, rx) ); + CHECK_MPI_OK( mp_copy(&ytemp, ry) ); + +cleanup: + mp_clear(&lambda); + mp_clear(&temp); + mp_clear(&xtemp); + mp_clear(&ytemp); + return err; +} + +/* Computes R = P - Q. + * Elliptic curve points P, Q, and R can all be identical. + * Uses affine coordinates. + */ +mp_err +GFp_ec_pt_sub_aff(const mp_int *p, const mp_int *a, const mp_int *px, + const mp_int *py, const mp_int *qx, const mp_int *qy, + mp_int *rx, mp_int *ry) +{ + mp_err err = MP_OKAY; + mp_int nqy; + MP_DIGITS(&nqy) = 0; + CHECK_MPI_OK( mp_init(&nqy) ); + /* nqy = -qy */ + CHECK_MPI_OK( mp_neg(qy, &nqy) ); + err = GFp_ec_pt_add_aff(p, a, px, py, qx, &nqy, rx, ry); +cleanup: + mp_clear(&nqy); + return err; +} + +/* Computes R = 2P. + * Elliptic curve points P and R can be identical. + * Uses affine coordinates. + */ +mp_err +GFp_ec_pt_dbl_aff(const mp_int *p, const mp_int *a, const mp_int *px, + const mp_int *py, mp_int *rx, mp_int *ry) +{ + return GFp_ec_pt_add_aff(p, a, px, py, px, py, rx, ry); +} + +/* Gets the i'th bit in the binary representation of a. + * If i >= length(a), then return 0. + * (The above behaviour differs from mpl_get_bit, which + * causes an error if i >= length(a).) + */ +#define MP_GET_BIT(a, i) \ + ((i) >= mpl_significant_bits((a))) ? 0 : mpl_get_bit((a), (i)) + +/* Computes R = nP based on IEEE P1363 A.10.3. + * Elliptic curve points P and R can be identical. + * Uses affine coordinates. + */ +mp_err +GFp_ec_pt_mul_aff(const mp_int *p, const mp_int *a, const mp_int *b, + const mp_int *px, const mp_int *py, const mp_int *n, mp_int *rx, + mp_int *ry) +{ + mp_err err = MP_OKAY; + mp_int k, k3, qx, qy, sx, sy; + int b1, b3, i, l; + + MP_DIGITS(&k) = 0; + MP_DIGITS(&k3) = 0; + MP_DIGITS(&qx) = 0; + MP_DIGITS(&qy) = 0; + MP_DIGITS(&sx) = 0; + MP_DIGITS(&sy) = 0; + CHECK_MPI_OK( mp_init(&k) ); + CHECK_MPI_OK( mp_init(&k3) ); + CHECK_MPI_OK( mp_init(&qx) ); + CHECK_MPI_OK( mp_init(&qy) ); + CHECK_MPI_OK( mp_init(&sx) ); + CHECK_MPI_OK( mp_init(&sy) ); + + /* if n = 0 then r = inf */ + if (mp_cmp_z(n) == 0) { + mp_zero(rx); + mp_zero(ry); + err = MP_OKAY; + goto cleanup; + } + /* Q = P, k = n */ + CHECK_MPI_OK( mp_copy(px, &qx) ); + CHECK_MPI_OK( mp_copy(py, &qy) ); + CHECK_MPI_OK( mp_copy(n, &k) ); + /* if n < 0 Q = -Q, k = -k */ + if (mp_cmp_z(n) < 0) { + CHECK_MPI_OK( mp_neg(&qy, &qy) ); + CHECK_MPI_OK( mp_mod(&qy, p, &qy) ); + CHECK_MPI_OK( mp_neg(&k, &k) ); + CHECK_MPI_OK( mp_mod(&k, p, &k) ); + } +#ifdef EC_DEBUG /* basic double and add method */ + l = mpl_significant_bits(&k) - 1; + mp_zero(&sx); + mp_zero(&sy); + for (i = l; i >= 0; i--) { + /* if k_i = 1, then S = S + Q */ + if (mpl_get_bit(&k, i) != 0) { + CHECK_MPI_OK( GFp_ec_pt_add_aff(p, a, &sx, &sy, + &qx, &qy, &sx, &sy) ); + } + if (i > 0) { + /* S = 2S */ + CHECK_MPI_OK( GFp_ec_pt_dbl_aff(p, a, &sx, &sy, &sx, &sy) ); + } + } +#else /* double and add/subtract method from standard */ + /* k3 = 3 * k */ + mp_set(&k3, 0x3); + CHECK_MPI_OK( mp_mul(&k, &k3, &k3) ); + /* S = Q */ + CHECK_MPI_OK( mp_copy(&qx, &sx) ); + CHECK_MPI_OK( mp_copy(&qy, &sy) ); + /* l = index of high order bit in binary representation of 3*k */ + l = mpl_significant_bits(&k3) - 1; + /* for i = l-1 downto 1 */ + for (i = l - 1; i >= 1; i--) { + /* S = 2S */ + CHECK_MPI_OK( GFp_ec_pt_dbl_aff(p, a, &sx, &sy, &sx, &sy) ); + b3 = MP_GET_BIT(&k3, i); + b1 = MP_GET_BIT(&k, i); + /* if k3_i = 1 and k_i = 0, then S = S + Q */ + if ((b3 == 1) && (b1 == 0)) { + CHECK_MPI_OK( GFp_ec_pt_add_aff(p, a, &sx, &sy, + &qx, &qy, &sx, &sy) ); + /* if k3_i = 0 and k_i = 1, then S = S - Q */ + } else if ((b3 == 0) && (b1 == 1)) { + CHECK_MPI_OK( GFp_ec_pt_sub_aff(p, a, &sx, &sy, + &qx, &qy, &sx, &sy) ); + } + } +#endif + /* output S */ + CHECK_MPI_OK( mp_copy(&sx, rx) ); + CHECK_MPI_OK( mp_copy(&sy, ry) ); + +cleanup: + mp_clear(&k); + mp_clear(&k3); + mp_clear(&qx); + mp_clear(&qy); + mp_clear(&sx); + mp_clear(&sy); + return err; +} + +/* Converts a point P(px, py, pz) from Jacobian projective coordinates to + * affine coordinates R(rx, ry). P and R can share x and y coordinates. + */ +mp_err +GFp_ec_pt_jac2aff(const mp_int *px, const mp_int *py, const mp_int *pz, + const mp_int *p, mp_int *rx, mp_int *ry) +{ + mp_err err = MP_OKAY; + mp_int z1, z2, z3; + MP_DIGITS(&z1) = 0; + MP_DIGITS(&z2) = 0; + MP_DIGITS(&z3) = 0; + CHECK_MPI_OK( mp_init(&z1) ); + CHECK_MPI_OK( mp_init(&z2) ); + CHECK_MPI_OK( mp_init(&z3) ); + + /* if point at infinity, then set point at infinity and exit */ + if (GFp_ec_pt_is_inf_jac(px, py, pz) == MP_YES) { + CHECK_MPI_OK( GFp_ec_pt_set_inf_aff(rx, ry) ); + goto cleanup; + } + + /* transform (px, py, pz) into (px / pz^2, py / pz^3) */ + if (mp_cmp_d(pz, 1) == 0) { + CHECK_MPI_OK( mp_copy(px, rx) ); + CHECK_MPI_OK( mp_copy(py, ry) ); + } else { + CHECK_MPI_OK( mp_invmod(pz, p, &z1) ); + CHECK_MPI_OK( mp_sqrmod(&z1, p, &z2) ); + CHECK_MPI_OK( mp_mulmod(&z1, &z2, p, &z3) ); + CHECK_MPI_OK( mp_mulmod(px, &z2, p, rx) ); + CHECK_MPI_OK( mp_mulmod(py, &z3, p, ry) ); + } + +cleanup: + mp_clear(&z1); + mp_clear(&z2); + mp_clear(&z3); + return err; +} + +/* Checks if point P(px, py, pz) is at infinity. + * Uses Jacobian coordinates. + */ +mp_err +GFp_ec_pt_is_inf_jac(const mp_int *px, const mp_int *py, const mp_int *pz) +{ + return mp_cmp_z(pz); +} + +/* Sets P(px, py, pz) to be the point at infinity. Uses Jacobian + * coordinates. + */ +mp_err +GFp_ec_pt_set_inf_jac(mp_int *px, mp_int *py, mp_int *pz) +{ + mp_zero(pz); + return MP_OKAY; +} + +/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and + * Q is (qx, qy, qz). Elliptic curve points P, Q, and R can all be + * identical. Uses Jacobian coordinates. + * + * This routine implements Point Addition in the Jacobian Projective + * space as described in the paper "Efficient elliptic curve exponentiation + * using mixed coordinates", by H. Cohen, A Miyaji, T. Ono. + */ +mp_err +GFp_ec_pt_add_jac(const mp_int *p, const mp_int *a, const mp_int *px, + const mp_int *py, const mp_int *pz, const mp_int *qx, + const mp_int *qy, const mp_int *qz, mp_int *rx, mp_int *ry, mp_int *rz) +{ + mp_err err = MP_OKAY; + mp_int n0, u1, u2, s1, s2, H, G; + MP_DIGITS(&n0) = 0; + MP_DIGITS(&u1) = 0; + MP_DIGITS(&u2) = 0; + MP_DIGITS(&s1) = 0; + MP_DIGITS(&s2) = 0; + MP_DIGITS(&H) = 0; + MP_DIGITS(&G) = 0; + CHECK_MPI_OK( mp_init(&n0) ); + CHECK_MPI_OK( mp_init(&u1) ); + CHECK_MPI_OK( mp_init(&u2) ); + CHECK_MPI_OK( mp_init(&s1) ); + CHECK_MPI_OK( mp_init(&s2) ); + CHECK_MPI_OK( mp_init(&H) ); + CHECK_MPI_OK( mp_init(&G) ); + + /* Use point double if pointers are equal. */ + if ((px == qx) && (py == qy) && (pz == qz)) { + err = GFp_ec_pt_dbl_jac(p, a, px, py, pz, rx, ry, rz); + goto cleanup; + } + + /* If either P or Q is the point at infinity, then return + * the other point + */ + if (GFp_ec_pt_is_inf_jac(px, py, pz) == MP_YES) { + CHECK_MPI_OK( mp_copy(qx, rx) ); + CHECK_MPI_OK( mp_copy(qy, ry) ); + CHECK_MPI_OK( mp_copy(qz, rz) ); + goto cleanup; + } + if (GFp_ec_pt_is_inf_jac(qx, qy, qz) == MP_YES) { + CHECK_MPI_OK( mp_copy(px, rx) ); + CHECK_MPI_OK( mp_copy(py, ry) ); + CHECK_MPI_OK( mp_copy(pz, rz) ); + goto cleanup; + } + + /* Compute u1 = px * qz^2, s1 = py * qz^3 */ + if (mp_cmp_d(qz, 1) == 0) { + CHECK_MPI_OK( mp_copy(px, &u1) ); + CHECK_MPI_OK( mp_copy(py, &s1) ); + } else { + CHECK_MPI_OK( mp_sqrmod(qz, p, &n0) ); + CHECK_MPI_OK( mp_mulmod(px, &n0, p, &u1) ); + CHECK_MPI_OK( mp_mulmod(&n0, qz, p, &n0) ); + CHECK_MPI_OK( mp_mulmod(py, &n0, p, &s1) ); + } + + /* Compute u2 = qx * pz^2, s2 = qy * pz^3 */ + if (mp_cmp_d(pz, 1) == 0) { + CHECK_MPI_OK( mp_copy(qx, &u2) ); + CHECK_MPI_OK( mp_copy(qy, &s2) ); + } else { + CHECK_MPI_OK( mp_sqrmod(pz, p, &n0) ); + CHECK_MPI_OK( mp_mulmod(qx, &n0, p, &u2) ); + CHECK_MPI_OK( mp_mulmod(&n0, pz, p, &n0) ); + CHECK_MPI_OK( mp_mulmod(qy, &n0, p, &s2) ); + } + + /* Compute H = u2 - u1 ; G = s2 - s1 */ + CHECK_MPI_OK( mp_submod(&u2, &u1, p, &H) ); + CHECK_MPI_OK( mp_submod(&s2, &s1, p, &G) ); + + if (mp_cmp_z(&H) == 0) { + if (mp_cmp_z(&G) == 0) { + /* P = Q; double */ + err = GFp_ec_pt_dbl_jac(p, a, px, py, pz, + rx, ry, rz); + goto cleanup; + } else { + /* P = -Q; return point at infinity */ + CHECK_MPI_OK( GFp_ec_pt_set_inf_jac(rx, ry, rz) ); + goto cleanup; + } + } + + /* rz = pz * qz * H */ + if (mp_cmp_d(pz, 1) == 0) { + if (mp_cmp_d(qz, 1) == 0) { + /* if pz == qz == 1, then rz = H */ + CHECK_MPI_OK( mp_copy(&H, rz) ); + } else { + CHECK_MPI_OK( mp_mulmod(qz, &H, p, rz) ); + } + } else { + if (mp_cmp_d(qz, 1) == 0) { + CHECK_MPI_OK( mp_mulmod(pz, &H, p, rz) ); + } else { + CHECK_MPI_OK( mp_mulmod(pz, qz, p, &n0) ); + CHECK_MPI_OK( mp_mulmod(&n0, &H, p, rz) ); + } + } + + /* rx = G^2 - H^3 - 2 * u1 * H^2 */ + CHECK_MPI_OK( mp_sqrmod(&G, p, rx) ); + CHECK_MPI_OK( mp_sqrmod(&H, p, &n0) ); + CHECK_MPI_OK( mp_mulmod(&n0, &u1, p, &u1) ); + CHECK_MPI_OK( mp_addmod(&u1, &u1, p, &u2) ); + CHECK_MPI_OK( mp_mulmod(&H, &n0, p, &H) ); + CHECK_MPI_OK( mp_submod(rx, &H, p, rx) ); + CHECK_MPI_OK( mp_submod(rx, &u2, p, rx) ); + + /* ry = - s1 * H^3 + G * (u1 * H^2 - rx) */ + /* (formula based on values of variables before block above) */ + CHECK_MPI_OK( mp_submod(&u1, rx, p, &u1) ); + CHECK_MPI_OK( mp_mulmod(&G, &u1, p, ry) ); + CHECK_MPI_OK( mp_mulmod(&s1, &H, p, &s1) ); + CHECK_MPI_OK( mp_submod(ry, &s1, p, ry) ); + +cleanup: + mp_clear(&n0); + mp_clear(&u1); + mp_clear(&u2); + mp_clear(&s1); + mp_clear(&s2); + mp_clear(&H); + mp_clear(&G); + return err; +} + +/* Computes R = 2P. Elliptic curve points P and R can be identical. Uses + * Jacobian coordinates. + * + * This routine implements Point Doubling in the Jacobian Projective + * space as described in the paper "Efficient elliptic curve exponentiation + * using mixed coordinates", by H. Cohen, A Miyaji, T. Ono. + */ +mp_err +GFp_ec_pt_dbl_jac(const mp_int *p, const mp_int *a, const mp_int *px, + const mp_int *py, const mp_int *pz, mp_int *rx, mp_int *ry, mp_int *rz) +{ + mp_err err = MP_OKAY; + mp_int t0, t1, M, S; + MP_DIGITS(&t0) = 0; + MP_DIGITS(&t1) = 0; + MP_DIGITS(&M) = 0; + MP_DIGITS(&S) = 0; + CHECK_MPI_OK( mp_init(&t0) ); + CHECK_MPI_OK( mp_init(&t1) ); + CHECK_MPI_OK( mp_init(&M) ); + CHECK_MPI_OK( mp_init(&S) ); + + if (GFp_ec_pt_is_inf_jac(px, py, pz) == MP_YES) { + CHECK_MPI_OK( GFp_ec_pt_set_inf_jac(rx, ry, rz) ); + goto cleanup; + } + + if (mp_cmp_d(pz, 1) == 0) { + /* M = 3 * px^2 + a */ + CHECK_MPI_OK( mp_sqrmod(px, p, &t0) ); + CHECK_MPI_OK( mp_addmod(&t0, &t0, p, &M) ); + CHECK_MPI_OK( mp_addmod(&t0, &M, p, &t0) ); + CHECK_MPI_OK( mp_addmod(&t0, a, p, &M) ); + } else if (mp_cmp_int(a, -3) == 0) { + /* M = 3 * (px + pz^2) * (px - pz) */ + CHECK_MPI_OK( mp_sqrmod(pz, p, &M) ); + CHECK_MPI_OK( mp_addmod(px, &M, p, &t0) ); + CHECK_MPI_OK( mp_submod(px, &M, p, &t1) ); + CHECK_MPI_OK( mp_mulmod(&t0, &t1, p, &M) ); + CHECK_MPI_OK( mp_addmod(&M, &M, p, &t0) ); + CHECK_MPI_OK( mp_addmod(&t0, &M, p, &M) ); + } else { + CHECK_MPI_OK( mp_sqrmod(px, p, &t0) ); + CHECK_MPI_OK( mp_addmod(&t0, &t0, p, &M) ); + CHECK_MPI_OK( mp_addmod(&t0, &M, p, &t0) ); + CHECK_MPI_OK( mp_sqrmod(pz, p, &M) ); + CHECK_MPI_OK( mp_sqrmod(&M, p, &M) ); + CHECK_MPI_OK( mp_mulmod(&M, a, p, &M) ); + CHECK_MPI_OK( mp_addmod(&M, &t0, p, &M) ); + } + + /* rz = 2 * py * pz */ + if (mp_cmp_d(pz, 1) == 0) { + CHECK_MPI_OK( mp_addmod(py, py, p, rz) ); + CHECK_MPI_OK( mp_sqrmod(rz, p, &t0) ); + } else { + CHECK_MPI_OK( mp_addmod(py, py, p, &t0) ); + CHECK_MPI_OK( mp_mulmod(&t0, pz, p, rz) ); + CHECK_MPI_OK( mp_sqrmod(&t0, p, &t0) ); + } + + /* S = 4 * px * py^2 = pz * (2 * py)^2 */ + CHECK_MPI_OK( mp_mulmod(px, &t0, p, &S) ); + + /* rx = M^2 - 2 * S */ + CHECK_MPI_OK( mp_addmod(&S, &S, p, &t1) ); + CHECK_MPI_OK( mp_sqrmod(&M, p, rx) ); + CHECK_MPI_OK( mp_submod(rx, &t1, p, rx) ); + + /* ry = M * (S - rx) - 8 * py^4 */ + CHECK_MPI_OK( mp_sqrmod(&t0, p, &t1) ); + if (mp_isodd(&t1)) { + CHECK_MPI_OK( mp_add(&t1, p, &t1) ); + } + CHECK_MPI_OK( mp_div_2(&t1, &t1) ); + CHECK_MPI_OK( mp_submod(&S, rx, p, &S) ); + CHECK_MPI_OK( mp_mulmod(&M, &S, p, &M) ); + CHECK_MPI_OK( mp_submod(&M, &t1, p, ry) ); + +cleanup: + mp_clear(&t0); + mp_clear(&t1); + mp_clear(&M); + mp_clear(&S); + return err; +} + +/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters + * a, b and p are the elliptic curve coefficients and the prime that + * determines the field GFp. Elliptic curve points P and R can be + * identical. Uses Jacobian coordinates. + */ +mp_err +GFp_ec_pt_mul_jac(const mp_int *p, const mp_int *a, const mp_int *b, + const mp_int *px, const mp_int *py, const mp_int *n, + mp_int *rx, mp_int *ry) +{ + mp_err err = MP_OKAY; + mp_int k, qx, qy, qz, sx, sy, sz; + int i, l; + + MP_DIGITS(&k) = 0; + MP_DIGITS(&qx) = 0; + MP_DIGITS(&qy) = 0; + MP_DIGITS(&qz) = 0; + MP_DIGITS(&sx) = 0; + MP_DIGITS(&sy) = 0; + MP_DIGITS(&sz) = 0; + CHECK_MPI_OK( mp_init(&k) ); + CHECK_MPI_OK( mp_init(&qx) ); + CHECK_MPI_OK( mp_init(&qy) ); + CHECK_MPI_OK( mp_init(&qz) ); + CHECK_MPI_OK( mp_init(&sx) ); + CHECK_MPI_OK( mp_init(&sy) ); + CHECK_MPI_OK( mp_init(&sz) ); + + /* if n = 0 then r = inf */ + if (mp_cmp_z(n) == 0) { + mp_zero(rx); + mp_zero(ry); + err = MP_OKAY; + goto cleanup; + /* if n < 0 then out of range error */ + } else if (mp_cmp_z(n) < 0) { + err = MP_RANGE; + goto cleanup; + } + /* Q = P, k = n */ + CHECK_MPI_OK( mp_copy(px, &qx) ); + CHECK_MPI_OK( mp_copy(py, &qy) ); + CHECK_MPI_OK( mp_set_int(&qz, 1) ); + CHECK_MPI_OK( mp_copy(n, &k) ); + + /* double and add method */ + l = mpl_significant_bits(&k) - 1; + mp_zero(&sx); + mp_zero(&sy); + mp_zero(&sz); + for (i = l; i >= 0; i--) { + /* if k_i = 1, then S = S + Q */ + if (MP_GET_BIT(&k, i) != 0) { + CHECK_MPI_OK( GFp_ec_pt_add_jac(p, a, &sx, &sy, &sz, + &qx, &qy, &qz, &sx, &sy, &sz) ); + } + if (i > 0) { + /* S = 2S */ + CHECK_MPI_OK( GFp_ec_pt_dbl_jac(p, a, &sx, &sy, &sz, + &sx, &sy, &sz) ); + } + } + + /* convert result S to affine coordinates */ + CHECK_MPI_OK( GFp_ec_pt_jac2aff(&sx, &sy, &sz, p, rx, ry) ); + +cleanup: + mp_clear(&k); + mp_clear(&qx); + mp_clear(&qy); + mp_clear(&qz); + mp_clear(&sx); + mp_clear(&sy); + mp_clear(&sz); + return err; +} +#endif /* NSS_ENABLE_ECC */ diff --git a/security/nss/lib/freebl/GFp_ecl.h b/security/nss/lib/freebl/GFp_ecl.h new file mode 100644 index 000000000000..20f596bc2d1a --- /dev/null +++ b/security/nss/lib/freebl/GFp_ecl.h @@ -0,0 +1,126 @@ +/* + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the elliptic curve math library for prime + * field curves. + * + * The Initial Developer of the Original Code is Sun Microsystems, Inc. + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Douglas Stebila , Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + */ + +#ifndef __gfp_ecl_h_ +#define __gfp_ecl_h_ +#ifdef NSS_ENABLE_ECC + +#include "secmpi.h" + +/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */ +extern mp_err GFp_ec_pt_is_inf_aff(const mp_int *px, const mp_int *py); + +/* Sets P(px, py) to be the point at infinity. Uses affine coordinates. */ +extern mp_err GFp_ec_pt_set_inf_aff(mp_int *px, mp_int *py); + +/* Computes R = P + Q where R is (rx, ry), P is (px, py) and Q is (qx, qy). + * Uses affine coordinates. + */ +extern mp_err GFp_ec_pt_add_aff(const mp_int *p, const mp_int *a, + const mp_int *px, const mp_int *py, const mp_int *qx, const mp_int *qy, + mp_int *rx, mp_int *ry); + +/* Computes R = P - Q. Uses affine coordinates. */ +extern mp_err GFp_ec_pt_sub_aff(const mp_int *p, const mp_int *a, + const mp_int *px, const mp_int *py, const mp_int *qx, const mp_int *qy, + mp_int *rx, mp_int *ry); + +/* Computes R = 2P. Uses affine coordinates. */ +extern mp_err GFp_ec_pt_dbl_aff(const mp_int *p, const mp_int *a, + const mp_int *px, const mp_int *py, mp_int *rx, mp_int *ry); + +/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters + * a, b and p are the elliptic curve coefficients and the prime that + * determines the field GFp. Uses affine coordinates. + */ +extern mp_err GFp_ec_pt_mul_aff(const mp_int *p, const mp_int *a, + const mp_int *b, const mp_int *px, const mp_int *py, const mp_int *n, + mp_int *rx, mp_int *ry); + +/* Converts a point P(px, py, pz) from Jacobian projective coordinates to + * affine coordinates R(rx, ry). + */ +extern mp_err GFp_ec_pt_jac2aff(const mp_int *px, const mp_int *py, + const mp_int *pz, const mp_int *p, mp_int *rx, mp_int *ry); + +/* Checks if point P(px, py, pz) is at infinity. Uses Jacobian + * coordinates. + */ +extern mp_err GFp_ec_pt_is_inf_jac(const mp_int *px, const mp_int *py, + const mp_int *pz); + +/* Sets P(px, py, pz) to be the point at infinity. Uses Jacobian + * coordinates. + */ +extern mp_err GFp_ec_pt_set_inf_jac(mp_int *px, mp_int *py, mp_int *pz); + +/* Computes R = P + Q where R is (rx, ry, rz), P is (px, py, pz) and + * Q is (qx, qy, qz). Uses Jacobian coordinates. + */ +extern mp_err GFp_ec_pt_add_jac(const mp_int *p, const mp_int *a, + const mp_int *px, const mp_int *py, const mp_int *pz, + const mp_int *qx, const mp_int *qy, const mp_int *qz, + mp_int *rx, mp_int *ry, mp_int *rz); + +/* Computes R = 2P. Uses Jacobian coordinates. */ +extern mp_err GFp_ec_pt_dbl_jac(const mp_int *p, const mp_int *a, + const mp_int *px, const mp_int *py, const mp_int *pz, + mp_int *rx, mp_int *ry, mp_int *rz); + +/* Computes R = nP where R is (rx, ry) and P is (px, py). The parameters + * a, b and p are the elliptic curve coefficients and the prime that + * determines the field GFp. Uses Jacobian coordinates. + */ +mp_err GFp_ec_pt_mul_jac(const mp_int *p, const mp_int *a, const mp_int *b, + const mp_int *px, const mp_int *py, const mp_int *n, + mp_int *rx, mp_int *ry); + +#define GFp_ec_pt_is_inf(px, py) GFp_ec_pt_is_inf_aff((px), (py)) +#define GFp_ec_pt_add(p, a, px, py, qx, qy, rx, ry) \ + GFp_ec_pt_add_aff((p), (a), (px), (py), (qx), (qy), (rx), (ry)) + +#define GFp_ECL_JACOBIAN +#ifdef GFp_ECL_AFFINE +#define GFp_ec_pt_mul(p, a, b, px, py, n, rx, ry) \ + GFp_ec_pt_mul_aff((p), (a), (b), (px), (py), (n), (rx), (ry)) +#elif defined(GFp_ECL_JACOBIAN) +#define GFp_ec_pt_mul(p, a, b, px, py, n, rx, ry) \ + GFp_ec_pt_mul_jac((p), (a), (b), (px), (py), (n), (rx), (ry)) +#endif /* GFp_ECL_AFFINE or GFp_ECL_JACOBIAN*/ + +#endif /* NSS_ENABLE_ECC */ +#endif /* __gfp_ecl_h_ */ diff --git a/security/nss/lib/freebl/Makefile b/security/nss/lib/freebl/Makefile index da108eddd48f..632895e2f7b9 100644 --- a/security/nss/lib/freebl/Makefile +++ b/security/nss/lib/freebl/Makefile @@ -264,7 +264,7 @@ endif DEFINES += -DMP_API_COMPATIBLE -MPI_USERS = dh.c pqg.c dsa.c rsa.c +MPI_USERS = dh.c pqg.c dsa.c rsa.c ec.c GFp_ecl.c MPI_OBJS = $(addprefix $(OBJDIR)/$(PROG_PREFIX), $(MPI_SRCS:.c=$(OBJ_SUFFIX))) MPI_OBJS += $(addprefix $(OBJDIR)/$(PROG_PREFIX), $(MPI_USERS:.c=$(OBJ_SUFFIX))) diff --git a/security/nss/lib/freebl/blapi.h b/security/nss/lib/freebl/blapi.h index af6489149e51..1cf0f637d22a 100644 --- a/security/nss/lib/freebl/blapi.h +++ b/security/nss/lib/freebl/blapi.h @@ -18,7 +18,11 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -32,7 +36,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: blapi.h,v 1.14 2003/01/30 23:36:35 relyea%netscape.com Exp $ + * $Id: blapi.h,v 1.15 2003/02/27 01:31:11 nelsonb%netscape.com Exp $ */ #ifndef _BLAPI_H_ @@ -186,6 +190,70 @@ extern SECStatus KEA_Derive(SECItem *prime, */ extern PRBool KEA_Verify(SECItem *Y, SECItem *prime, SECItem *subPrime); +/****************************************************** +** Elliptic Curve algorithms +*/ + +/* Generates a public and private key, both of which are encoded +** in a single ECPrivateKey struct. Params is input, privKey are +** output. +*/ +extern SECStatus EC_NewKey(ECParams * params, + ECPrivateKey ** privKey); + +extern SECStatus EC_NewKeyFromSeed(ECParams * params, + ECPrivateKey ** privKey, + const unsigned char* seed, + int seedlen); + +/* Validates an EC public key as described in Section 5.2.2 of + * X9.63. Such validation prevents against small subgroup attacks + * when the ECDH primitive is used with the cofactor. + */ +extern SECStatus EC_ValidatePublicKey(ECParams * params, + SECItem * publicValue); + +/* +** ECDH_Derive performs a scalar point multiplication of a point +** representing a (peer's) public key and a large integer representing +** a private key (its own). Both keys must use the same elliptic curve +** parameters. If the withCofactor parameter is true, the +** multiplication also uses the cofactor associated with the curve +** parameters. The output of this scheme is the x-coordinate of the +** resulting point. If successful, derivedSecret->data is set to the +** address of the newly allocated buffer containing the derived +** secret, and derivedSecret->len is the size of the secret +** produced. It is the caller's responsibility to free the allocated +** buffer containing the derived secret. +*/ +extern SECStatus ECDH_Derive(SECItem * publicValue, + ECParams * params, + SECItem * privateValue, + PRBool withCofactor, + SECItem * derivedSecret); + +/* On input, signature->len == size of buffer to hold signature. +** digest->len == size of digest. +** On output, signature->len == size of signature in buffer. +** Uses a random seed. +*/ +extern SECStatus ECDSA_SignDigest(ECPrivateKey *key, + SECItem *signature, + const SECItem *digest); + +/* On input, signature->len == size of buffer to hold signature. +** digest->len == size of digest. +*/ +extern SECStatus ECDSA_VerifyDigest(ECPublicKey *key, + const SECItem *signature, + const SECItem *digest); + +/* Uses the provided seed. */ +extern SECStatus ECDSA_SignDigestWithSeed(ECPrivateKey *key, + SECItem *signature, + const SECItem *digest, + const unsigned char *seed, + const int seedlen); /******************************************/ /* diff --git a/security/nss/lib/freebl/blapit.h b/security/nss/lib/freebl/blapit.h index f569ba3bd683..8516f0c456e1 100644 --- a/security/nss/lib/freebl/blapit.h +++ b/security/nss/lib/freebl/blapit.h @@ -18,7 +18,11 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -32,7 +36,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: blapit.h,v 1.8 2003/01/30 23:36:36 relyea%netscape.com Exp $ + * $Id: blapit.h,v 1.9 2003/02/27 01:31:12 nelsonb%netscape.com Exp $ */ #ifndef _BLAPIT_H_ @@ -66,6 +70,14 @@ #define DSA_SIGNATURE_LEN 40 /* Bytes */ #define DSA_SUBPRIME_LEN 20 /* Bytes */ +/* XXX We shouldn't have to hard code this limit. For + * now, this is the quickest way to support ECDSA signature + * processing (ECDSA signature lengths depend on curve + * size). This limit is sufficient for curves upto + * 576 bits. + */ +#define MAX_ECKEY_LEN 72 /* Bytes */ + /* * Number of bytes each hash algorithm produces */ @@ -252,5 +264,73 @@ struct DHPrivateKeyStr { }; typedef struct DHPrivateKeyStr DHPrivateKey; +/*************************************************************************** +** Data structures used for elliptic curve parameters and +** public and private keys. +*/ + +/* +** The ECParams data structures can encode elliptic curve +** parameters for both GFp and GF2m curves. +*/ + +typedef enum { ec_params_explicit, + ec_params_named +} ECParamsType; + +typedef enum { ec_field_GFp = 1, + ec_field_GF2m +} ECFieldType; + +struct ECFieldIDStr { + int size; /* field size in bits */ + ECFieldType type; + union { + SECItem prime; /* prime p for (GFp) */ + SECItem m; /* integer m for (GF2m) */ + } u; + int k1; /* first coefficient of pentanomial or + * the only coefficient of trinomial + */ + int k2; /* two remaining coefficients of pentanomial */ + int k3; +}; +typedef struct ECFieldIDStr ECFieldID; + +struct ECCurveStr { + SECItem a; /* contains octet stream encoding of + * field element (X9.62 section 4.3.3) + */ + SECItem b; + SECItem seed; +}; +typedef struct ECCurveStr ECCurve; + +struct ECParamsStr { + PRArenaPool * arena; + ECParamsType type; + ECFieldID fieldID; + ECCurve curve; + SECItem base; + SECItem order; + int cofactor; + SECItem DEREncoding; +}; +typedef struct ECParamsStr ECParams; + +struct ECPublicKeyStr { + ECParams ecParams; + SECItem publicValue; /* elliptic curve point encoded as + * octet stream. + */ +}; +typedef struct ECPublicKeyStr ECPublicKey; + +struct ECPrivateKeyStr { + ECParams ecParams; + SECItem publicValue; /* encoded ec point */ + SECItem privateValue; /* private big integer */ +}; +typedef struct ECPrivateKeyStr ECPrivateKey; #endif /* _BLAPIT_H_ */ diff --git a/security/nss/lib/freebl/ec.c b/security/nss/lib/freebl/ec.c new file mode 100644 index 000000000000..db1fefd5bcab --- /dev/null +++ b/security/nss/lib/freebl/ec.c @@ -0,0 +1,958 @@ +/* + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Elliptic Curve Cryptography library. + * + * The Initial Developer of the Original Code is Sun Microsystems, Inc. + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + */ + +#include "blapi.h" +#include "prerr.h" +#include "secerr.h" +#include "secmpi.h" +#include "secitem.h" +#include "ec.h" +#include "GFp_ecl.h" + +#ifdef NSS_ENABLE_ECC + +/* + * Returns true if pointP is the point at infinity, false otherwise + */ +PRBool +ec_point_at_infinity(SECItem *pointP) +{ + int i; + + for (i = 1; i < pointP->len; i++) { + if (pointP->data[i] != 0x00) return PR_FALSE; + } + + return PR_TRUE; +} + +/* + * Computes point addition R = P + Q for the curve whose + * parameters are encoded in params. Two or more of P, Q, + * R may point to the same memory location. + */ +SECStatus +ec_point_add(ECParams *params, SECItem *pointP, + SECItem *pointQ, SECItem *pointR) +{ + mp_int Px, Py, Qx, Qy, Rx, Ry; + mp_int prime, a; + SECStatus rv = SECFailure; + mp_err err = MP_OKAY; + int len; + +#if EC_DEBUG + int i; + + printf("ec_point_add: params [len=%d]:", params->DEREncoding.len); + for (i = 0; i < params->DEREncoding.len; i++) + printf("%02x:", params->DEREncoding.data[i]); + printf("\n"); + + printf("ec_point_add: pointP [len=%d]:", pointP->len); + for (i = 0; i < pointP->len; i++) + printf("%02x:", pointP->data[i]); + printf("\n"); + + printf("ec_point_add: pointQ [len=%d]:", pointQ->len); + for (i = 0; i < pointQ->len; i++) + printf("%02x:", pointQ->data[i]); + printf("\n"); +#endif + + /* NOTE: We only support prime field curves for now */ + len = (params->fieldID.size + 7) >> 3; + if ((pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) || + (pointP->len != (2 * len + 1)) || + (pointQ->data[0] != EC_POINT_FORM_UNCOMPRESSED) || + (pointQ->len != (2 * len + 1))) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + MP_DIGITS(&Px) = 0; + MP_DIGITS(&Py) = 0; + MP_DIGITS(&Qx) = 0; + MP_DIGITS(&Qy) = 0; + MP_DIGITS(&Rx) = 0; + MP_DIGITS(&Ry) = 0; + MP_DIGITS(&prime) = 0; + MP_DIGITS(&a) = 0; + CHECK_MPI_OK( mp_init(&Px) ); + CHECK_MPI_OK( mp_init(&Py) ); + CHECK_MPI_OK( mp_init(&Qx) ); + CHECK_MPI_OK( mp_init(&Qy) ); + CHECK_MPI_OK( mp_init(&Rx) ); + CHECK_MPI_OK( mp_init(&Ry) ); + CHECK_MPI_OK( mp_init(&prime) ); + CHECK_MPI_OK( mp_init(&a) ); + + /* Initialize Px and Py */ + CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1, + (mp_size) len) ); + CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len, + (mp_size) len) ); + + /* Initialize Qx and Qy */ + CHECK_MPI_OK( mp_read_unsigned_octets(&Qx, pointQ->data + 1, + (mp_size) len) ); + CHECK_MPI_OK( mp_read_unsigned_octets(&Qy, pointQ->data + 1 + len, + (mp_size) len) ); + + /* Set up the prime and curve coefficient */ + SECITEM_TO_MPINT( params->fieldID.u.prime, &prime ); + SECITEM_TO_MPINT( params->curve.a, &a ); + + /* Compute R = P + Q */ + if (GFp_ec_pt_add(&prime, &a, &Px, &Py, &Qx, &Qy, + &Rx, &Ry) != SECSuccess) + goto cleanup; + + /* Construct the SECItem representation of the result */ + pointR->data[0] = EC_POINT_FORM_UNCOMPRESSED; + CHECK_MPI_OK( mp_to_fixlen_octets(&Rx, pointR->data + 1, + (mp_size) len) ); + CHECK_MPI_OK( mp_to_fixlen_octets(&Ry, pointR->data + 1 + len, + (mp_size) len) ); + rv = SECSuccess; + +#if EC_DEBUG + printf("ec_point_add: pointR [len=%d]:", pointR->len); + for (i = 0; i < pointR->len; i++) + printf("%02x:", pointR->data[i]); + printf("\n"); +#endif + +cleanup: + mp_clear(&Px); + mp_clear(&Py); + mp_clear(&Qx); + mp_clear(&Qy); + mp_clear(&Rx); + mp_clear(&Ry); + mp_clear(&prime); + mp_clear(&a); + if (err) { + MP_TO_SEC_ERROR(err); + rv = SECFailure; + } + + return rv; +} + +/* + * Computes scalar point multiplication pointQ = k * pointP for + * the curve whose parameters are encoded in params. + */ +SECStatus +ec_point_mul(ECParams *params, mp_int *k, + SECItem *pointP, SECItem *pointQ) +{ + mp_int Px, Py, Qx, Qy; + mp_int prime, a, b; + SECStatus rv = SECFailure; + mp_err err = MP_OKAY; + int len; + +#if EC_DEBUG + int i; + char mpstr[256]; + + printf("ec_point_mul: params [len=%d]:", params->DEREncoding.len); + for (i = 0; i < params->DEREncoding.len; i++) + printf("%02x:", params->DEREncoding.data[i]); + printf("\n"); + + mp_tohex(k, mpstr); + printf("ec_point_mul: scalar : %s\n", mpstr); + mp_todecimal(k, mpstr); + printf("ec_point_mul: scalar : %s (dec)\n", mpstr); + + printf("ec_point_mul: pointP [len=%d]:", pointP->len); + for (i = 0; i < pointP->len; i++) + printf("%02x:", pointP->data[i]); + printf("\n"); +#endif + + /* NOTE: We only support prime field curves for now */ + len = (params->fieldID.size + 7) >> 3; + if ((params->fieldID.type != ec_field_GFp) || + (pointP->data[0] != EC_POINT_FORM_UNCOMPRESSED) || + (pointP->len != (2 * len + 1))) { + return SECFailure; + }; + + MP_DIGITS(&Px) = 0; + MP_DIGITS(&Py) = 0; + MP_DIGITS(&Qx) = 0; + MP_DIGITS(&Qy) = 0; + MP_DIGITS(&prime) = 0; + MP_DIGITS(&a) = 0; + MP_DIGITS(&b) = 0; + CHECK_MPI_OK( mp_init(&Px) ); + CHECK_MPI_OK( mp_init(&Py) ); + CHECK_MPI_OK( mp_init(&Qx) ); + CHECK_MPI_OK( mp_init(&Qy) ); + CHECK_MPI_OK( mp_init(&prime) ); + CHECK_MPI_OK( mp_init(&a) ); + CHECK_MPI_OK( mp_init(&b) ); + + + /* Initialize Px and Py */ + CHECK_MPI_OK( mp_read_unsigned_octets(&Px, pointP->data + 1, + (mp_size) len) ); + CHECK_MPI_OK( mp_read_unsigned_octets(&Py, pointP->data + 1 + len, + (mp_size) len) ); + + /* Set up mp_ints containing the prime and curve coefficients */ + SECITEM_TO_MPINT( params->fieldID.u.prime, &prime ); + SECITEM_TO_MPINT( params->curve.a, &a ); + SECITEM_TO_MPINT( params->curve.b, &b ); + + /* Compute Q = k * P */ + if (GFp_ec_pt_mul(&prime, &a, &b, &Px, &Py, k, + &Qx, &Qy) != SECSuccess) + goto cleanup; + + /* Construct the SECItem representation of point Q */ + pointQ->data[0] = EC_POINT_FORM_UNCOMPRESSED; + CHECK_MPI_OK( mp_to_fixlen_octets(&Qx, pointQ->data + 1, + (mp_size) len) ); + CHECK_MPI_OK( mp_to_fixlen_octets(&Qy, pointQ->data + 1 + len, + (mp_size) len) ); + rv = SECSuccess; + +#if EC_DEBUG + printf("ec_point_mul: pointQ [len=%d]:", pointQ->len); + for (i = 0; i < pointQ->len; i++) + printf("%02x:", pointQ->data[i]); + printf("\n"); +#endif + +cleanup: + mp_clear(&Px); + mp_clear(&Py); + mp_clear(&Qx); + mp_clear(&Qy); + mp_clear(&prime); + mp_clear(&a); + mp_clear(&b); + if (err) { + MP_TO_SEC_ERROR(err); + rv = SECFailure; + } + + return rv; +} + +static unsigned char bitmask[] = { + 0xff, 0x7f, 0x3f, 0x1f, + 0x0f, 0x07, 0x03, 0x01 +}; +#endif /* NSS_ENABLE_ECC */ + +/* Generates a new EC key pair. The private key is a supplied + * random value (in seed) and the public key is the result of + * performing a scalar point multiplication of that value with + * the curve's base point. + */ +SECStatus +EC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey, + const unsigned char *seed, int seedlen) +{ + SECStatus rv = SECFailure; +#ifdef NSS_ENABLE_ECC + PRArenaPool *arena; + ECPrivateKey *key; + mp_int k; + mp_err err = MP_OKAY; + int len; + +#if EC_DEBUG + printf("EC_NewKeyFromSeed called\n"); +#endif + + if (!ecParams || !privKey || !seed || (seedlen < 0)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + /* Initialize an arena for the EC key. */ + if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE))) + return SECFailure; + + key = (ECPrivateKey *)PORT_ArenaZAlloc(arena, sizeof(ECPrivateKey)); + if (!key) { + PORT_FreeArena(arena, PR_TRUE); + return SECFailure; + } + + + /* Copy all of the fields from the ECParams argument to the + * ECParams structure within the private key. + */ + key->ecParams.arena = arena; + key->ecParams.type = ecParams->type; + key->ecParams.fieldID.size = ecParams->fieldID.size; + key->ecParams.fieldID.type = ecParams->fieldID.type; + CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.fieldID.u.prime, + &ecParams->fieldID.u.prime)); + key->ecParams.fieldID.k1 = ecParams->fieldID.k1; + key->ecParams.fieldID.k2 = ecParams->fieldID.k2; + key->ecParams.fieldID.k3 = ecParams->fieldID.k3; + CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.a, + &ecParams->curve.a)); + CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.b, + &ecParams->curve.b)); + CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.curve.seed, + &ecParams->curve.seed)); + CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.base, + &ecParams->base)); + CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.order, + &ecParams->order)); + key->ecParams.cofactor = ecParams->cofactor; + CHECK_SEC_OK(SECITEM_CopyItem(arena, &key->ecParams.DEREncoding, + &ecParams->DEREncoding)); + + len = (ecParams->fieldID.size + 7) >> 3; + SECITEM_AllocItem(arena, &key->privateValue, len); + SECITEM_AllocItem(arena, &key->publicValue, 2*len + 1); + + /* Copy private key */ + if (seedlen >= len) { + memcpy(key->privateValue.data, seed, len); + } else { + memset(key->privateValue.data, 0, (len - seedlen)); + memcpy(key->privateValue.data + (len - seedlen), seed, seedlen); + } + + /* Compute corresponding public key */ + MP_DIGITS(&k) = 0; + CHECK_MPI_OK( mp_init(&k) ); + CHECK_MPI_OK( mp_read_unsigned_octets(&k, key->privateValue.data, + (mp_size) len) ); + + rv = ec_point_mul(ecParams, &k, &(ecParams->base), &(key->publicValue)); + if (rv != SECSuccess) goto cleanup; + *privKey = key; + +cleanup: + mp_clear(&k); + if (rv) + PORT_FreeArena(arena, PR_TRUE); + +#if EC_DEBUG + printf("EC_NewKeyFromSeed returning %s\n", + (rv == SECSuccess) ? "success" : "failure"); +#endif +#else + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); +#endif /* NSS_ENABLE_ECC */ + + return rv; + +} + +/* Generates a new EC key pair. The private key is a random value and + * the public key is the result of performing a scalar point multiplication + * of that value with the curve's base point. + */ +SECStatus +EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey) +{ + SECStatus rv = SECFailure; +#ifdef NSS_ENABLE_ECC + int len; + unsigned char *seed; + + if (!ecParams || !privKey) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + /* Generate random private key */ + len = (ecParams->fieldID.size + 7) >> 3; + if ((seed = PORT_Alloc(len)) == NULL) goto cleanup; + if (RNG_GenerateGlobalRandomBytes(seed, len) != SECSuccess) goto cleanup; + + /* Fit private key to the field size */ + seed[0] &= bitmask[len * 8 - ecParams->fieldID.size]; + rv = EC_NewKeyFromSeed(ecParams, privKey, seed, len); + +cleanup: + if (!seed) { + PORT_ZFree(seed, len); + } +#if EC_DEBUG + printf("EC_NewKey returning %s\n", + (rv == SECSuccess) ? "success" : "failure"); +#endif +#else + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); +#endif /* NSS_ENABLE_ECC */ + + return rv; +} + +/* Validates an EC public key as described in Section 5.2.2 of + * X9.63. The ECDH primitive when used without the cofactor does + * not address small subgroup attacks, which may occur when the + * public key is not valid. These attacks can be prevented by + * validating the public key before using ECDH. + */ +SECStatus +EC_ValidatePublicKey(ECParams *ecParams, SECItem *publicValue) +{ +#ifdef NSS_ENABLE_ECC + if (!ecParams || !publicValue) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + /* XXX Add actual checks here. */ + return SECSuccess; +#else + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); + return SECFailure; +#endif /* NSS_ENABLE_ECC */ +} + +/* +** Performs an ECDH key derivation by computing the scalar point +** multiplication of privateValue and publicValue (with or without the +** cofactor) and returns the x-coordinate of the resulting elliptic +** curve point in derived secret. If successful, derivedSecret->data +** is set to the address of the newly allocated buffer containing the +** derived secret, and derivedSecret->len is the size of the secret +** produced. It is the caller's responsibility to free the allocated +** buffer containing the derived secret. +*/ +SECStatus +ECDH_Derive(SECItem *publicValue, + ECParams *ecParams, + SECItem *privateValue, + PRBool withCofactor, + SECItem *derivedSecret) +{ + SECStatus rv = SECFailure; +#ifdef NSS_ENABLE_ECC + unsigned int len = 0; + SECItem pointQ = {siBuffer, NULL, 0}; + mp_int k; /* to hold the private value */ + mp_int cofactor; + mp_err err = MP_OKAY; +#if EC_DEBUG + int i; +#endif + + if (!publicValue || !ecParams || !privateValue || + !derivedSecret) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + memset(derivedSecret, 0, sizeof *derivedSecret); + len = (ecParams->fieldID.size + 7) >> 3; + pointQ.len = 2*len + 1; + if ((pointQ.data = PORT_Alloc(2*len + 1)) == NULL) goto cleanup; + + MP_DIGITS(&k) = 0; + CHECK_MPI_OK( mp_init(&k) ); + CHECK_MPI_OK( mp_read_unsigned_octets(&k, privateValue->data, + (mp_size) privateValue->len) ); + + if (withCofactor && (ecParams->cofactor != 1)) { + /* multiply k with the cofactor */ + MP_DIGITS(&cofactor) = 0; + CHECK_MPI_OK( mp_init(&cofactor) ); + mp_set(&cofactor, ecParams->cofactor); + CHECK_MPI_OK( mp_mul(&k, &cofactor, &k) ); + } + + /* Multiply our private key and peer's public point */ + if ((ec_point_mul(ecParams, &k, publicValue, &pointQ) != SECSuccess) || + ec_point_at_infinity(&pointQ)) + goto cleanup; + + /* Allocate memory for the derived secret and copy + * the x co-ordinate of pointQ into it. + */ + SECITEM_AllocItem(NULL, derivedSecret, len); + memcpy(derivedSecret->data, pointQ.data + 1, len); + + rv = SECSuccess; + +#if EC_DEBUG + printf("derived_secret:\n"); + for (i = 0; i < derivedSecret->len; i++) + printf("%02x:", derivedSecret->data[i]); + printf("\n"); +#endif + +cleanup: + mp_clear(&k); + + if (pointQ.data) { + PORT_ZFree(pointQ.data, 2*len + 1); + } +#else + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); +#endif /* NSS_ENABLE_ECC */ + + return rv; +} + +/* Computes the ECDSA signature (a concatenation of two values r and s) + * on the digest using the given key and the random value kb (used in + * computing s). + */ +SECStatus +ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, + const SECItem *digest, const unsigned char *kb, const int kblen) +{ + SECStatus rv = SECFailure; +#ifdef NSS_ENABLE_ECC + mp_int x1; + mp_int d, k; /* private key, random integer */ + mp_int r, s; /* tuple (r, s) is the signature */ + mp_int n; + mp_err err = MP_OKAY; + ECParams *ecParams = NULL; + SECItem kGpoint = { siBuffer, NULL, 0}; + int len = 0; + +#if EC_DEBUG + char mpstr[256]; +#endif + + /* Check args */ + if (!key || !signature || !digest || !kb || (kblen < 0) || + (digest->len != SHA1_LENGTH)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + goto cleanup; + } + + ecParams = &(key->ecParams); + len = (ecParams->fieldID.size + 7) >> 3; + if (signature->len < 2*len) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + goto cleanup; + } + + /* Initialize MPI integers. */ + MP_DIGITS(&x1) = 0; + MP_DIGITS(&d) = 0; + MP_DIGITS(&k) = 0; + MP_DIGITS(&r) = 0; + MP_DIGITS(&s) = 0; + MP_DIGITS(&n) = 0; + CHECK_MPI_OK( mp_init(&x1) ); + CHECK_MPI_OK( mp_init(&d) ); + CHECK_MPI_OK( mp_init(&k) ); + CHECK_MPI_OK( mp_init(&r) ); + CHECK_MPI_OK( mp_init(&s) ); + CHECK_MPI_OK( mp_init(&n) ); + + SECITEM_TO_MPINT( ecParams->order, &n ); + SECITEM_TO_MPINT( key->privateValue, &d ); + CHECK_MPI_OK( mp_read_unsigned_octets(&k, kb, kblen) ); + /* Make sure k is in the interval [1, n-1] */ + if ((mp_cmp_z(&k) <= 0) || (mp_cmp(&k, &n) >= 0)) { + PORT_SetError(SEC_ERROR_NEED_RANDOM); + goto cleanup; + } + + /* + ** ANSI X9.62, Section 5.3.2, Step 2 + ** + ** Compute kG + */ + kGpoint.len = 2*len + 1; + kGpoint.data = PORT_Alloc(2*len + 1); + if ((kGpoint.data == NULL) || + (ec_point_mul(ecParams, &k, &(ecParams->base), &kGpoint) + != SECSuccess)) + goto cleanup; + + /* + ** ANSI X9.62, Section 5.3.3, Step 1 + ** + ** Extract the x co-ordinate of kG into x1 + */ + CHECK_MPI_OK( mp_read_unsigned_octets(&x1, kGpoint.data + 1, + (mp_size) len) ); + + /* + ** ANSI X9.62, Section 5.3.3, Step 2 + ** + ** r = x1 mod n NOTE: n is the order of the curve + */ + CHECK_MPI_OK( mp_mod(&x1, &n, &r) ); + + /* + ** ANSI X9.62, Section 5.3.3, Step 3 + ** + ** verify r != 0 + */ + if (mp_cmp_z(&r) == 0) { + PORT_SetError(SEC_ERROR_NEED_RANDOM); + goto cleanup; + } + + /* + ** ANSI X9.62, Section 5.3.3, Step 4 + ** + ** s = (k**-1 * (SHA1(M) + d*r)) mod n + */ + SECITEM_TO_MPINT(*digest, &s); /* s = SHA1(M) */ + +#if EC_DEBUG + mp_todecimal(&n, mpstr); + printf("n : %s (dec)\n", mpstr); + mp_todecimal(&d, mpstr); + printf("d : %s (dec)\n", mpstr); + mp_tohex(&x1, mpstr); + printf("x1: %s\n", mpstr); + mp_todecimal(&s, mpstr); + printf("digest: %s (decimal)\n", mpstr); + mp_todecimal(&r, mpstr); + printf("r : %s (dec)\n", mpstr); +#endif + + CHECK_MPI_OK( mp_invmod(&k, &n, &k) ); /* k = k**-1 mod n */ + CHECK_MPI_OK( mp_mulmod(&d, &r, &n, &d) ); /* d = d * r mod n */ + CHECK_MPI_OK( mp_addmod(&s, &d, &n, &s) ); /* s = s + d mod n */ + CHECK_MPI_OK( mp_mulmod(&s, &k, &n, &s) ); /* s = s * k mod n */ + +#if EC_DEBUG + mp_todecimal(&s, mpstr); + printf("s : %s (dec)\n", mpstr); +#endif + + /* + ** ANSI X9.62, Section 5.3.3, Step 5 + ** + ** verify s != 0 + */ + if (mp_cmp_z(&s) == 0) { + PORT_SetError(SEC_ERROR_NEED_RANDOM); + goto cleanup; + } + + /* + ** + ** Signature is tuple (r, s) + */ + CHECK_MPI_OK( mp_to_fixlen_octets(&r, signature->data, len) ); + CHECK_MPI_OK( mp_to_fixlen_octets(&s, signature->data + len, len) ); + signature->len = 2*len; + + rv = SECSuccess; + err = MP_OKAY; +cleanup: + mp_clear(&x1); + mp_clear(&d); + mp_clear(&k); + mp_clear(&r); + mp_clear(&s); + mp_clear(&n); + + if (kGpoint.data) { + PORT_ZFree(kGpoint.data, 2*len + 1); + } + + if (err) { + MP_TO_SEC_ERROR(err); + rv = SECFailure; + } + +#if EC_DEBUG + printf("ECDSA signing with seed %s\n", + (rv == SECSuccess) ? "succeeded" : "failed"); +#endif +#else + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); +#endif /* NSS_ENABLE_ECC */ + + return rv; +} + +/* +** Computes the ECDSA signature on the digest using the given key +** and a random seed. +*/ +SECStatus +ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest) +{ + SECStatus rv = SECFailure; +#ifdef NSS_ENABLE_ECC + int prerr = 0; + int n = (key->ecParams.fieldID.size + 7) >> 3; + unsigned char mask = bitmask[n * 8 - key->ecParams.fieldID.size]; + unsigned char *kseed = NULL; + + /* Generate random seed of appropriate size as dictated + * by field size. + */ + if ((kseed = PORT_Alloc(n)) == NULL) return SECFailure; + + do { + if (RNG_GenerateGlobalRandomBytes(kseed, n) != SECSuccess) + goto cleanup; + *kseed &= mask; + rv = ECDSA_SignDigestWithSeed(key, signature, digest, kseed, n); + if (rv) prerr = PORT_GetError(); + } while ((rv != SECSuccess) && (prerr == SEC_ERROR_NEED_RANDOM)); + +cleanup: + if (kseed) PORT_ZFree(kseed, n); + +#if EC_DEBUG + printf("ECDSA signing %s\n", + (rv == SECSuccess) ? "succeeded" : "failed"); +#endif +#else + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); +#endif /* NSS_ENABLE_ECC */ + + return rv; +} + +/* +** Checks the signature on the given digest using the key provided. +*/ +SECStatus +ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature, + const SECItem *digest) +{ + SECStatus rv = SECFailure; +#ifdef NSS_ENABLE_ECC + mp_int r_, s_; /* tuple (r', s') is received signature) */ + mp_int c, u1, u2, v; /* intermediate values used in verification */ + mp_int x1, y1; + mp_int x2, y2; + mp_int n; + mp_err err = MP_OKAY; + PRArenaPool *arena = NULL; + ECParams *ecParams = NULL; + SECItem pointA = { siBuffer, NULL, 0 }; + SECItem pointB = { siBuffer, NULL, 0 }; + SECItem pointC = { siBuffer, NULL, 0 }; + int len; + +#if EC_DEBUG + char mpstr[256]; + printf("ECDSA verification called\n"); +#endif + + /* Check args */ + if (!key || !signature || !digest || + (digest->len != SHA1_LENGTH)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + goto cleanup; + } + + ecParams = &(key->ecParams); + len = (ecParams->fieldID.size + 7) >> 3; + printf("len is %d\n", len); + if (signature->len < 2*len) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + goto cleanup; + } + + /* Initialize an arena for pointA, pointB and pointC */ + if ((arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)) == NULL) + goto cleanup; + + SECITEM_AllocItem(arena, &pointA, 2*len + 1); + SECITEM_AllocItem(arena, &pointB, 2*len + 1); + SECITEM_AllocItem(arena, &pointC, 2*len + 1); + if (pointA.data == NULL || pointB.data == NULL || pointC.data == NULL) + goto cleanup; + + /* Initialize MPI integers. */ + MP_DIGITS(&r_) = 0; + MP_DIGITS(&s_) = 0; + MP_DIGITS(&c) = 0; + MP_DIGITS(&u1) = 0; + MP_DIGITS(&u2) = 0; + MP_DIGITS(&x1) = 0; + MP_DIGITS(&y1) = 0; + MP_DIGITS(&x2) = 0; + MP_DIGITS(&y2) = 0; + MP_DIGITS(&v) = 0; + MP_DIGITS(&n) = 0; + CHECK_MPI_OK( mp_init(&r_) ); + CHECK_MPI_OK( mp_init(&s_) ); + CHECK_MPI_OK( mp_init(&c) ); + CHECK_MPI_OK( mp_init(&u1) ); + CHECK_MPI_OK( mp_init(&u2) ); + CHECK_MPI_OK( mp_init(&x1) ); + CHECK_MPI_OK( mp_init(&y1) ); + CHECK_MPI_OK( mp_init(&x2) ); + CHECK_MPI_OK( mp_init(&y2) ); + CHECK_MPI_OK( mp_init(&v) ); + CHECK_MPI_OK( mp_init(&n) ); + + /* + ** Convert received signature (r', s') into MPI integers. + */ + CHECK_MPI_OK( mp_read_unsigned_octets(&r_, signature->data, len) ); + CHECK_MPI_OK( mp_read_unsigned_octets(&s_, signature->data + len, len) ); + + /* + ** ANSI X9.62, Section 5.4.2, Steps 1 and 2 + ** + ** Verify that 0 < r' < n and 0 < s' < n + */ + SECITEM_TO_MPINT(ecParams->order, &n); + if (mp_cmp_z(&r_) <= 0 || mp_cmp_z(&s_) <= 0 || + mp_cmp(&r_, &n) >= 0 || mp_cmp(&s_, &n) >= 0) + goto cleanup; /* will return rv == SECFailure */ + + /* + ** ANSI X9.62, Section 5.4.2, Step 3 + ** + ** c = (s')**-1 mod n + */ + CHECK_MPI_OK( mp_invmod(&s_, &n, &c) ); /* c = (s')**-1 mod n */ + + /* + ** ANSI X9.62, Section 5.4.2, Step 4 + ** + ** u1 = ((SHA1(M')) * c) mod n + */ + SECITEM_TO_MPINT(*digest, &u1); /* u1 = SHA1(M') */ + +#if EC_DEBUG + mp_todecimal(&r_, mpstr); + printf("r_: %s (dec)\n", mpstr); + mp_todecimal(&s_, mpstr); + printf("s_: %s (dec)\n", mpstr); + mp_todecimal(&c, mpstr); + printf("c : %s (dec)\n", mpstr); + mp_todecimal(&u1, mpstr); + printf("digest: %s (dec)\n", mpstr); +#endif + + CHECK_MPI_OK( mp_mulmod(&u1, &c, &n, &u1) ); /* u1 = u1 * c mod n */ + + /* + ** ANSI X9.62, Section 5.4.2, Step 4 + ** + ** u2 = ((r') * c) mod n + */ + CHECK_MPI_OK( mp_mulmod(&r_, &c, &n, &u2) ); + + /* + ** ANSI X9.62, Section 5.4.3, Step 1 + ** + ** Compute u1*G + u2*Q + ** Here, A = u1.G B = u2.Q and C = A + B + ** If the result, C, is the point at infinity, reject the signature + */ + if ((ec_point_mul(ecParams, &u1, &ecParams->base, &pointA) + == SECFailure) || + (ec_point_mul(ecParams, &u2, &key->publicValue, &pointB) + == SECFailure) || + (ec_point_add(ecParams, &pointA, &pointB, &pointC) == SECFailure) || + ec_point_at_infinity(&pointC)) { + rv = SECFailure; + goto cleanup; + } + + CHECK_MPI_OK( mp_read_unsigned_octets(&x1, pointC.data + 1, len) ); + + /* + ** ANSI X9.62, Section 5.4.4, Step 2 + ** + ** v = x1 mod n + */ + CHECK_MPI_OK( mp_mod(&x1, &n, &v) ); + + /* + ** ANSI X9.62, Section 5.4.4, Step 3 + ** + ** Verification: v == r' + */ + if (mp_cmp(&v, &r_)) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + rv = SECFailure; /* Signature failed to verify. */ + } else { + rv = SECSuccess; /* Signature verified. */ + } + +#if EC_DEBUG + mp_todecimal(&u1, mpstr); + printf("u1: %s (dec)\n", mpstr); + mp_todecimal(&u2, mpstr); + printf("u2: %s (dec)\n", mpstr); + mp_tohex(&x1, mpstr); + printf("x1: %s\n", mpstr); + mp_todecimal(&v, mpstr); + printf("v : %s (dec)\n", mpstr); +#endif + +cleanup: + mp_clear(&r_); + mp_clear(&s_); + mp_clear(&c); + mp_clear(&u1); + mp_clear(&u2); + mp_clear(&x1); + mp_clear(&y1); + mp_clear(&x2); + mp_clear(&y2); + mp_clear(&v); + mp_clear(&n); + + if (arena) PORT_FreeArena(arena, PR_TRUE); + if (err) { + MP_TO_SEC_ERROR(err); + rv = SECFailure; + } + +#if EC_DEBUG + printf("ECDSA verification %s\n", + (rv == SECSuccess) ? "succeeded" : "failed"); +#endif +#else + PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); +#endif /* NSS_ENABLE_ECC */ + + return rv; +} + diff --git a/security/nss/lib/freebl/ec.h b/security/nss/lib/freebl/ec.h new file mode 100644 index 000000000000..1dad3fea4a63 --- /dev/null +++ b/security/nss/lib/freebl/ec.h @@ -0,0 +1,50 @@ +/* + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Elliptic Curve Cryptography library. + * + * The Initial Developer of the Original Code is Sun Microsystems, Inc. + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + */ + +#ifndef __ec_h_ +#define __ec_h_ + +#define EC_DEBUG 0 +#define EC_POINT_FORM_COMPRESSED_Y0 0x02 +#define EC_POINT_FORM_COMPRESSED_Y1 0x03 +#define EC_POINT_FORM_UNCOMPRESSED 0x04 +#define EC_POINT_FORM_HYBRID_Y0 0x06 +#define EC_POINT_FORM_HYBRID_Y1 0x07 + +#define ANSI_X962_CURVE_OID_TOTAL_LEN 10 +#define SECG_CURVE_OID_TOTAL_LEN 7 + +#endif /* __ec_h_ */ diff --git a/security/nss/lib/freebl/ldvector.c b/security/nss/lib/freebl/ldvector.c index 70e7473cfdc0..76875c7aacbb 100644 --- a/security/nss/lib/freebl/ldvector.c +++ b/security/nss/lib/freebl/ldvector.c @@ -18,7 +18,11 @@ * Copyright (C) 2000 Netscape Communications Corporation. All * Rights Reserved. * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -32,7 +36,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: ldvector.c,v 1.5 2003/01/30 23:36:36 relyea%netscape.com Exp $ + * $Id: ldvector.c,v 1.6 2003/02/27 01:31:13 nelsonb%netscape.com Exp $ */ #include "loader.h" @@ -171,6 +175,16 @@ static const struct FREEBLVectorStr vector = { BLAPI_VerifySelf, /* End of Version 3.005. */ + + EC_NewKey, + EC_NewKeyFromSeed, + EC_ValidatePublicKey, + ECDH_Derive, + ECDSA_SignDigest, + ECDSA_VerifyDigest, + ECDSA_SignDigestWithSeed, + + /* End of Version 3.006. */ }; diff --git a/security/nss/lib/freebl/loader.c b/security/nss/lib/freebl/loader.c index d0c7b32c43dd..7bbe8d6ac137 100644 --- a/security/nss/lib/freebl/loader.c +++ b/security/nss/lib/freebl/loader.c @@ -18,7 +18,11 @@ * Copyright (C) 2000 Netscape Communications Corporation. All * Rights Reserved. * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -32,7 +36,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: loader.c,v 1.13 2003/01/30 23:36:36 relyea%netscape.com Exp $ + * $Id: loader.c,v 1.14 2003/02/27 01:31:14 nelsonb%netscape.com Exp $ */ #include "loader.h" @@ -1294,3 +1298,69 @@ BLAPI_VerifySelf(const char *name) return PR_FALSE; return vector->p_BLAPI_VerifySelf(libraryName); } + +/* ============== New for 3.006 =============================== */ + +SECStatus +EC_NewKey(ECParams * params, ECPrivateKey ** privKey) +{ + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) + return SECFailure; + return (vector->p_EC_NewKey)( params, privKey ); +} + +SECStatus +EC_NewKeyFromSeed(ECParams * params, ECPrivateKey ** privKey, + const unsigned char *seed, int seedlen) +{ + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) + return SECFailure; + return (vector->p_EC_NewKeyFromSeed)( params, privKey, seed, seedlen ); +} + +SECStatus +EC_ValidatePublicKey(ECParams * params, SECItem * publicValue) +{ + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) + return SECFailure; + return (vector->p_EC_ValidatePublicKey)( params, publicValue ); +} + +SECStatus +ECDH_Derive(SECItem * publicValue, ECParams * params, SECItem * privateValue, + PRBool withCofactor, SECItem * derivedSecret) +{ + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) + return SECFailure; + return (vector->p_ECDH_Derive)( publicValue, params, privateValue, + withCofactor, derivedSecret ); +} + +SECStatus +ECDSA_SignDigest(ECPrivateKey * key, SECItem * signature, + const SECItem * digest) +{ + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) + return SECFailure; + return (vector->p_ECDSA_SignDigest)( key, signature, digest ); +} + +SECStatus +ECDSA_VerifyDigest(ECPublicKey * key, const SECItem * signature, + const SECItem * digest) +{ + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) + return SECFailure; + return (vector->p_ECDSA_VerifyDigest)( key, signature, digest ); +} + +SECStatus +ECDSA_SignDigestWithSeed(ECPrivateKey * key, SECItem * signature, + const SECItem * digest, const unsigned char *seed, const int seedlen) +{ + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) + return SECFailure; + return (vector->p_ECDSA_SignDigestWithSeed)( key, signature, digest, + seed, seedlen ); +} + diff --git a/security/nss/lib/freebl/loader.h b/security/nss/lib/freebl/loader.h index 8249d3c2803f..b55d845c8d8a 100644 --- a/security/nss/lib/freebl/loader.h +++ b/security/nss/lib/freebl/loader.h @@ -18,7 +18,11 @@ * Copyright (C) 2000 Netscape Communications Corporation. All * Rights Reserved. * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -32,7 +36,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: loader.h,v 1.8 2003/01/30 23:36:37 relyea%netscape.com Exp $ + * $Id: loader.h,v 1.9 2003/02/27 01:31:14 nelsonb%netscape.com Exp $ */ #ifndef _LOADER_H_ @@ -40,7 +44,7 @@ #include "blapi.h" -#define FREEBL_VERSION 0x0305 +#define FREEBL_VERSION 0x0306 struct FREEBLVectorStr { @@ -333,6 +337,40 @@ struct FREEBLVectorStr { PRBool (*p_BLAPI_VerifySelf)(const char *name); /* Version 3.005 came to here */ + + SECStatus (* p_EC_NewKey)(ECParams * params, + ECPrivateKey ** privKey); + + SECStatus (* p_EC_NewKeyFromSeed)(ECParams * params, + ECPrivateKey ** privKey, + const unsigned char * seed, + int seedlen); + + SECStatus (* p_EC_ValidatePublicKey)(ECParams * params, + SECItem * publicValue); + + SECStatus (* p_ECDH_Derive)(SECItem * publicValue, + ECParams * params, + SECItem * privateValue, + PRBool withCofactor, + SECItem * derivedSecret); + + SECStatus (* p_ECDSA_SignDigest)(ECPrivateKey * key, + SECItem * signature, + const SECItem * digest); + + SECStatus (* p_ECDSA_VerifyDigest)(ECPublicKey * key, + const SECItem * signature, + const SECItem * digest); + + SECStatus (* p_ECDSA_SignDigestWithSeed)(ECPrivateKey * key, + SECItem * signature, + const SECItem * digest, + const unsigned char * seed, + const int seedlen); + + /* Version 3.006 came to here */ + }; typedef struct FREEBLVectorStr FREEBLVector; diff --git a/security/nss/lib/freebl/manifest.mn b/security/nss/lib/freebl/manifest.mn index 409c10d00c67..c68ecb90f304 100644 --- a/security/nss/lib/freebl/manifest.mn +++ b/security/nss/lib/freebl/manifest.mn @@ -16,7 +16,11 @@ # Copyright (C) 1994-2000 Netscape Communications Corporation. All # Rights Reserved. # +# Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 +# Sun Microsystems, Inc. All Rights Reserved. +# # Contributor(s): +# Dr Vipul Gupta , Sun Microsystems Laboratories # # Alternatively, the contents of this file may be used under the # terms of the GNU General Public License Version 2 or later (the @@ -61,6 +65,7 @@ EXPORTS = \ PRIVATE_EXPORTS = \ secmpi.h \ + ec.h \ $(NULL) MPI_HDRS = mpi-config.h mpi.h mpi-priv.h mplogic.h mpprime.h logtab.h @@ -93,6 +98,8 @@ CSRCS = \ rijndael.c \ aeskeywrap.c \ dh.c \ + ec.c \ + GFp_ecl.c \ pqg.c \ dsa.c \ rsa.c \ @@ -107,6 +114,8 @@ ALL_HDRS = \ blapi.h \ blapit.h \ des.h \ + ec.h \ + GFp_ecl.h \ loader.h \ rijndael.h \ secmpi.h \ diff --git a/security/nss/lib/nss/nss.def b/security/nss/lib/nss/nss.def index 3838f702fe60..ccffb93a7232 100644 --- a/security/nss/lib/nss/nss.def +++ b/security/nss/lib/nss/nss.def @@ -16,8 +16,12 @@ ;+# Copyright (C) 2000 Netscape Communications Corporation. All ;+# Rights Reserved. ;+# +;+# Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 +;+# Sun Microsystems, Inc. All Rights Reserved. +;+# ;+# Contributor(s): ;+# Dr Stephen Henson +;+# Dr Vipul Gupta , Sun Microsystems Laboratories ;+# ;+# Alternatively, the contents of this file may be used under the ;+# terms of the GNU General Public License Version 2 or later (the @@ -746,6 +750,8 @@ PK11_UpdateSlotAttribute; PK11_UserEnableSlot; PK11_UserDisableSlot; SECITEM_ItemsAreEqual; +SECKEY_CreateECPrivateKey; +SECKEY_PublicKeyStrengthInBits; ;+ local: ;+ *; ;+}; diff --git a/security/nss/lib/pk11wrap/pk11skey.c b/security/nss/lib/pk11wrap/pk11skey.c index 1b745aa80d53..430b40f3e778 100644 --- a/security/nss/lib/pk11wrap/pk11skey.c +++ b/security/nss/lib/pk11wrap/pk11skey.c @@ -16,8 +16,12 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * - * Contributor(s): + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): * Dr Stephen Henson + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -50,6 +54,7 @@ #include "cert.h" #include "secerr.h" #include "secpkcs5.h" +#include "ec.h" #define PAIRWISE_SECITEM_TYPE siBuffer #define PAIRWISE_DIGEST_LENGTH SHA1_LENGTH /* 160-bits */ @@ -572,7 +577,19 @@ PK11_ImportPublicKey(PK11SlotInfo *slot, SECKEYPublicKey *pubKey, PK11_SETATTRS(attrs, CKA_VALUE, pubKey->u.dh.publicValue.data, pubKey->u.dh.publicValue.len); attrs++; break; - /* what about fortezza??? */ +#ifdef NSS_ENABLE_ECC + case ecKey: + keyType = CKK_EC; + PK11_SETATTRS(attrs, CKA_VERIFY, &cktrue, sizeof(CK_BBOOL));attrs++; + PK11_SETATTRS(attrs, CKA_DERIVE, &cktrue, sizeof(CK_BBOOL));attrs++; + signedattr = attrs; + PK11_SETATTRS(attrs, CKA_EC_PARAMS, + pubKey->u.ec.DEREncodedParams.data, + pubKey->u.ec.DEREncodedParams.len); attrs++; + PK11_SETATTRS(attrs, CKA_EC_POINT, pubKey->u.ec.publicValue.data, + pubKey->u.ec.publicValue.len); attrs++; + break; +#endif /* NSS_ENABLE_ECC */ default: PORT_SetError( SEC_ERROR_BAD_KEY ); return CK_INVALID_HANDLE; @@ -767,6 +784,9 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot,KeyType keyType,CK_OBJECT_HANDLE id) CK_ATTRIBUTE template[8]; CK_ATTRIBUTE *attrs= template; CK_ATTRIBUTE *modulus,*exponent,*base,*prime,*subprime,*value; +#ifdef NSS_ENABLE_ECC + CK_ATTRIBUTE *ecparams; +#endif /* NSS_ENABLE_ECC */ /* if we didn't know the key type, get it */ if (keyType== nullKey) { @@ -785,6 +805,11 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot,KeyType keyType,CK_OBJECT_HANDLE id) case CKK_DH: keyType = dhKey; break; +#ifdef NSS_ENABLE_ECC + case CKK_EC: + keyType = ecKey; + break; +#endif /* NSS_ENABLE_ECC */ default: PORT_SetError( SEC_ERROR_BAD_KEY ); return NULL; @@ -889,6 +914,30 @@ PK11_ExtractPublicKey(PK11SlotInfo *slot,KeyType keyType,CK_OBJECT_HANDLE id) crv = pk11_Attr2SecItem(arena,value,&pubKey->u.dh.publicValue); if (crv != CKR_OK) break; break; +#ifdef NSS_ENABLE_ECC + case ecKey: + pubKey->u.ec.size = 0; + ecparams = attrs; + PK11_SETATTRS(attrs, CKA_EC_PARAMS, NULL, 0); attrs++; + value =attrs; + PK11_SETATTRS(attrs, CKA_EC_POINT, NULL, 0); attrs++; + templateCount = attrs - template; + PR_ASSERT(templateCount <= sizeof(template)/sizeof(CK_ATTRIBUTE)); + crv = PK11_GetAttributes(tmp_arena,slot,id,template,templateCount); + if (crv != CKR_OK) break; + + if ((keyClass != CKO_PUBLIC_KEY) || (pk11KeyType != CKK_EC)) { + crv = CKR_OBJECT_HANDLE_INVALID; + break; + } + + crv = pk11_Attr2SecItem(arena,ecparams, + &pubKey->u.ec.DEREncodedParams); + if (crv != CKR_OK) break; + crv = pk11_Attr2SecItem(arena,value,&pubKey->u.ec.publicValue); + if (crv != CKR_OK) break; + break; +#endif /* NSS_ENABLE_ECC */ case fortezzaKey: case nullKey: default: @@ -929,6 +978,9 @@ PK11_MakePrivKey(PK11SlotInfo *slot, KeyType keyType, case CKK_DSA: keyType = dsaKey; break; case CKK_DH: keyType = dhKey; break; case CKK_KEA: keyType = fortezzaKey; break; +#ifdef NSS_ENABLE_ECC + case CKK_EC: keyType = ecKey; break; +#endif /* NSS_ENABLE_ECC */ default: break; } @@ -1088,6 +1140,10 @@ pk11_mapSignKeyType(KeyType keyType) case fortezzaKey: case dsaKey: return CKM_DSA; +#ifdef NSS_ENABLE_ECC + case ecKey: + return CKM_ECDSA; +#endif /* NSS_ENABLE_ECC */ case dhKey: default: break; @@ -1660,6 +1716,7 @@ pk11_PairwiseConsistencyCheck(SECKEYPublicKey *pubKey, /* * We are not doing consistency check for Diffie-Hellman Key - * otherwise it would be here + * This is also true for Elliptic Curve Diffie-Hellman keys */ } @@ -1876,6 +1933,19 @@ PK11_GenerateKeyPair(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, { CKA_VERIFY_RECOVER, NULL, 0}, { CKA_ENCRYPT, NULL, 0}, }; +#ifdef NSS_ENABLE_ECC + CK_ATTRIBUTE ecPubTemplate[] = { + { CKA_EC_PARAMS, NULL, 0 }, + { CKA_TOKEN, NULL, 0}, + { CKA_DERIVE, NULL, 0}, + { CKA_WRAP, NULL, 0}, + { CKA_VERIFY, NULL, 0}, + { CKA_VERIFY_RECOVER, NULL, 0}, + { CKA_ENCRYPT, NULL, 0}, + }; + int ecPubCount = sizeof(ecPubTemplate)/sizeof(ecPubTemplate[0]); + SECKEYECParams * ecParams; +#endif /* NSS_ENABLE_ECC */ int dsaPubCount = sizeof(dsaPubTemplate)/sizeof(dsaPubTemplate[0]); /*CK_ULONG key_size = 0;*/ @@ -2019,6 +2089,23 @@ PK11_GenerateKeyPair(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, keyType = dhKey; test_mech.mechanism = CKM_DH_PKCS_DERIVE; break; +#ifdef NSS_ENABLE_ECC + case CKM_EC_KEY_PAIR_GEN: + ecParams = (SECKEYECParams *)param; + attrs = ecPubTemplate; + PK11_SETATTRS(attrs, CKA_EC_PARAMS, ecParams->data, + ecParams->len); attrs++; + pubTemplate = ecPubTemplate; + pubCount = ecPubCount; + keyType = ecKey; + /* XXX An EC key can be used for other mechanisms too such + * as CKM_ECDSA and CKM_ECDSA_SHA1. How can we reflect + * that in test_mech.mechanism so the CKA_SIGN, CKA_VERIFY + * attributes are set correctly? + */ + test_mech.mechanism = CKM_ECDH1_DERIVE; + break; +#endif /* NSS_ENABLE_ECC */ default: PORT_SetError( SEC_ERROR_BAD_KEY ); return NULL; @@ -2042,6 +2129,15 @@ PK11_GenerateKeyPair(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, case CKM_DH_PKCS_DERIVE: mechanism_info.flags = CKF_DERIVE; break; +#ifdef NSS_ENABLE_ECC + case CKM_ECDH1_DERIVE: + mechanism_info.flags = CKF_DERIVE; + break; + case CKM_ECDSA: + case CKM_ECDSA_SHA1: + mechanism_info.flags = CKF_SIGN | CKF_VERIFY; + break; +#endif /* NSS_ENABLE_ECC */ default: break; } @@ -2137,6 +2233,11 @@ PK11_GenerateKeyPair(PK11SlotInfo *slot,CK_MECHANISM_TYPE type, case CKM_DH_PKCS_KEY_PAIR_GEN: pubKeyIndex = &(*pubKey)->u.dh.publicValue; break; +#ifdef NSS_ENABLE_ECC + case CKM_EC_KEY_PAIR_GEN: + pubKeyIndex = &(*pubKey)->u.ec.publicValue; + break; +#endif /* NSS_ENABLE_ECC */ } PORT_Assert(pubKeyIndex != NULL); @@ -2695,6 +2796,62 @@ PK11_PubDerive(SECKEYPrivateKey *privKey, SECKEYPublicKey *pubKey, PORT_SetError( PK11_MapError(crv) ); } break; +#ifdef NSS_ENABLE_ECC + case ecKey: + { + CK_BBOOL cktrue = CK_TRUE; + CK_OBJECT_CLASS keyClass = CKO_SECRET_KEY; + CK_KEY_TYPE keyType = CKK_GENERIC_SECRET; + CK_ULONG key_size = 0; + CK_ATTRIBUTE keyTemplate[4]; + int templateCount; + CK_ATTRIBUTE *attrs = keyTemplate; + CK_ECDH1_DERIVE_PARAMS *mechParams = NULL; + + if (pubKey->keyType != ecKey) { + PORT_SetError(SEC_ERROR_BAD_KEY); + break; + } + + PK11_SETATTRS(attrs, CKA_CLASS, &keyClass, sizeof(keyClass)); + attrs++; + PK11_SETATTRS(attrs, CKA_KEY_TYPE, &keyType, sizeof(keyType)); + attrs++; + PK11_SETATTRS(attrs, operation, &cktrue, 1); attrs++; + PK11_SETATTRS(attrs, CKA_VALUE_LEN, &key_size, sizeof(key_size)); + attrs++; + templateCount = attrs - keyTemplate; + PR_ASSERT(templateCount <= sizeof(keyTemplate)/sizeof(CK_ATTRIBUTE)); + + keyType = PK11_GetKeyType(target,keySize); + key_size = keySize; + symKey->size = keySize; + if (key_size == 0) templateCount--; + + mechParams = (CK_ECDH1_DERIVE_PARAMS *) + PORT_ZAlloc(sizeof(CK_ECDH1_DERIVE_PARAMS)); + mechParams->kdf = CKD_SHA1_KDF; + mechParams->ulSharedDataLen = 0; + mechParams->pSharedData = NULL; + mechParams->ulPublicDataLen = pubKey->u.ec.publicValue.len; + mechParams->pPublicData = pubKey->u.ec.publicValue.data; + + mechanism.mechanism = derive; + mechanism.pParameter = mechParams; + mechanism.ulParameterLen = sizeof(CK_ECDH1_DERIVE_PARAMS); + + pk11_EnterKeyMonitor(symKey); + crv = PK11_GETTAB(slot)->C_DeriveKey(symKey->session, + &mechanism, privKey->pkcs11ID, keyTemplate, + templateCount, &symKey->objectID); + pk11_ExitKeyMonitor(symKey); + + PORT_ZFree(mechParams, sizeof(CK_ECDH1_DERIVE_PARAMS)); + + if (crv == CKR_OK) return symKey; + PORT_SetError( PK11_MapError(crv) ); + } +#endif /* NSS_ENABLE_ECC */ } PK11_FreeSymKey(symKey); diff --git a/security/nss/lib/pk11wrap/pk11slot.c b/security/nss/lib/pk11wrap/pk11slot.c index 27fb2f3927ad..bf57cbb9201d 100644 --- a/security/nss/lib/pk11wrap/pk11slot.c +++ b/security/nss/lib/pk11wrap/pk11slot.c @@ -16,8 +16,12 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * - * Contributor(s): + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): * Dr Stephen Henson + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -114,6 +118,7 @@ static PK11SlotList pk11_aesSlotList, pk11_rsaSlotList, pk11_dsaSlotList, pk11_dhSlotList, + pk11_ecSlotList, pk11_ideaSlotList, pk11_sslSlotList, pk11_tlsSlotList, @@ -1250,6 +1255,7 @@ PK11_InitSlotLists(void) pk11_initSlotList(&pk11_rsaSlotList); pk11_initSlotList(&pk11_dsaSlotList); pk11_initSlotList(&pk11_dhSlotList); + pk11_initSlotList(&pk11_ecSlotList); pk11_initSlotList(&pk11_ideaSlotList); pk11_initSlotList(&pk11_sslSlotList); pk11_initSlotList(&pk11_tlsSlotList); @@ -1273,6 +1279,7 @@ PK11_DestroySlotLists(void) pk11_freeSlotList(&pk11_rsaSlotList); pk11_freeSlotList(&pk11_dsaSlotList); pk11_freeSlotList(&pk11_dhSlotList); + pk11_freeSlotList(&pk11_ecSlotList); pk11_freeSlotList(&pk11_ideaSlotList); pk11_freeSlotList(&pk11_sslSlotList); pk11_freeSlotList(&pk11_tlsSlotList); @@ -1327,6 +1334,11 @@ PK11_GetSlotList(CK_MECHANISM_TYPE type) case CKM_DH_PKCS_KEY_PAIR_GEN: case CKM_DH_PKCS_DERIVE: return &pk11_dhSlotList; + case CKM_ECDSA: + case CKM_ECDSA_SHA1: + case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */ + case CKM_ECDH1_DERIVE: + return &pk11_ecSlotList; case CKM_SSL3_PRE_MASTER_KEY_GEN: case CKM_SSL3_MASTER_KEY_DERIVE: case CKM_SSL3_SHA1_MAC: @@ -2946,10 +2958,11 @@ PK11_GetKeyType(CK_MECHANISM_TYPE type,unsigned long len) case CKM_KEA_KEY_DERIVE: case CKM_KEA_KEY_PAIR_GEN: return CKK_KEA; - case CKM_ECDSA_KEY_PAIR_GEN: case CKM_ECDSA: case CKM_ECDSA_SHA1: - return CKK_ECDSA; + case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */ + case CKM_ECDH1_DERIVE: + return CKK_EC; /* CKK_ECDSA is deprecated */ case CKM_SSL3_PRE_MASTER_KEY_GEN: case CKM_GENERIC_SECRET_KEY_GEN: case CKM_SSL3_MASTER_KEY_DERIVE: @@ -3109,8 +3122,10 @@ PK11_GetKeyGen(CK_MECHANISM_TYPE type) case CKM_KEA_KEY_PAIR_GEN: return CKM_KEA_KEY_PAIR_GEN; case CKM_ECDSA: - case CKM_ECDSA_KEY_PAIR_GEN: - return CKM_ECDSA_KEY_PAIR_GEN; + case CKM_ECDSA_SHA1: + case CKM_EC_KEY_PAIR_GEN: /* aka CKM_ECDSA_KEY_PAIR_GEN */ + case CKM_ECDH1_DERIVE: + return CKM_EC_KEY_PAIR_GEN; case CKM_SSL3_PRE_MASTER_KEY_GEN: case CKM_SSL3_MASTER_KEY_DERIVE: case CKM_SSL3_KEY_AND_MAC_DERIVE: diff --git a/security/nss/lib/softoken/ecdecode.c b/security/nss/lib/softoken/ecdecode.c new file mode 100644 index 000000000000..d65b018a404e --- /dev/null +++ b/security/nss/lib/softoken/ecdecode.c @@ -0,0 +1,672 @@ +/* + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is the Elliptic Curve Cryptography library. + * + * The Initial Developer of the Original Code is Sun Microsystems, Inc. + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + */ + +#ifdef NSS_ENABLE_ECC + +#include "blapi.h" +#include "secoid.h" +#include "secitem.h" +#include "secerr.h" +#include "ec.h" + +#define CHECK_OK(func) if (func == NULL) goto cleanup; + +/* Initializes a SECItem from a hexadecimal string */ +static SECItem * +hexString2SECItem(PRArenaPool *arena, SECItem *item, const char *str) +{ + int i = 0; + int byteval = 0; + int tmp = PORT_Strlen(str); + + if ((tmp % 2) != 0) return NULL; + + item->data = (unsigned char *) PORT_ArenaZAlloc(arena, tmp/2); + if (item->data == NULL) return NULL; + item->len = tmp/2; + + while (str[i]) { + if ((str[i] >= '0') && (str[i] <= '9')) + tmp = str[i] - '0'; + else if ((str[i] >= 'a') && (str[i] <= 'f')) + tmp = str[i] - 'a' + 10; + else if ((str[i] >= 'A') && (str[i] <= 'F')) + tmp = str[i] - 'A' + 10; + else + return NULL; + + byteval = byteval * 16 + tmp; + if ((i % 2) != 0) { + item->data[i/2] = byteval; + byteval = 0; + } + i++; + } + + return item; +} + +SECStatus +EC_FillParams(PRArenaPool *arena, const SECItem *encodedParams, + ECParams *params) +{ + SECOidTag tag; + SECItem oid = { siBuffer, NULL, 0}; + +#if EC_DEBUG + int i; + + printf("Encoded params in EC_DecodeParams: "); + for (i = 0; i < encodedParams->len; i++) { + printf("%02x:", encodedParams->data[i]); + } + printf("\n"); +#endif + + if ((encodedParams->len != ANSI_X962_CURVE_OID_TOTAL_LEN) && + (encodedParams->len != SECG_CURVE_OID_TOTAL_LEN)) { + PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); + return SECFailure; + }; + + oid.len = encodedParams->len - 2; + oid.data = encodedParams->data + 2; + if ((encodedParams->data[0] != SEC_ASN1_OBJECT_ID) || + ((tag = SECOID_FindOIDTag(&oid)) == SEC_OID_UNKNOWN)) { + PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); + return SECFailure; + } + + params->arena = arena; + params->cofactor = 0; + params->type = ec_params_named; + + switch (tag) { + case SEC_OID_ANSIX962_EC_PRIME192V1: + /* Populate params for prime192v1 aka secp192r1 + * (the NIST P-192 curve) + */ + params->fieldID.size = 192; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" \ + "FFFFFFFFFFFFFFFF")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" \ + "FFFFFFFFFFFFFFFC")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "64210519E59C80E70FA7E9AB72243049" \ + "FEB8DEECC146B9B1")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "188DA80EB03090F67CBF20EB43A18800" \ + "F4FF0AFD82FF1012" \ + "07192B95FFC8DA78631011ED6B24CDD5" \ + "73F977A11E794811")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836" \ + "146BC9B1B4D22831")); + params->cofactor = 1; + break; + + case SEC_OID_ANSIX962_EC_PRIME192V2: + /* Populate params for prime192v2 */ + params->fieldID.size = 192; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" \ + "FFFFFFFFFFFFFFFF")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" \ + "FFFFFFFFFFFFFFFC")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "CC22D6DFB95C6B25E49C0D6364A4E598" \ + "0C393AA21668D953")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "EEA2BAE7E1497842F2DE7769CFE9C989" \ + "C072AD696F48034A" \ + "6574D11D69B6EC7A672BB82A083DF2F2" \ + "B0847DE970B2DE15")); + + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "FFFFFFFFFFFFFFFFFFFFFFFE5FB1A724" \ + "DC80418648D8DD31")); + params->cofactor = 1; + break; + + case SEC_OID_ANSIX962_EC_PRIME192V3: + /* Populate params for prime192v3 */ + params->fieldID.size = 192; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" \ + "FFFFFFFFFFFFFFFF")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" \ + "FFFFFFFFFFFFFFFC")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "22123DC2395A05CAA7423DAECCC94760" \ + "A7D462256BD56916")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "7D29778100C65A1DA1783716588DCE2B" \ + "8B4AEE8E228F1896" \ + "38A90F22637337334B49DCB66A6DC8F9" \ + "978ACA7648A943B0")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "FFFFFFFFFFFFFFFFFFFFFFFF7A62D031" \ + "C83F4294F640EC13")); + params->cofactor = 1; + break; + + case SEC_OID_ANSIX962_EC_PRIME239V1: + /* Populate params for prime239v1 */ + params->fieldID.size = 239; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF" \ + "FFFF8000000000007FFFFFFFFFFF")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF" \ + "FFFF8000000000007FFFFFFFFFFC")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "6B016C3BDCF18941D0D654921475CA71" \ + "A9DB2FB27D1D37796185C2942C0A")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "0FFA963CDCA8816CCC33B8642BEDF905" \ + "C3D358573D3F27FBBD3B3CB9AAAF" \ + "7DEBE8E4E90A5DAE6E4054CA530BA046" \ + "54B36818CE226B39FCCB7B02F1AE")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF9E" \ + "5E9A9F5D9071FBD1522688909D0B")); + params->cofactor = 1; + break; + + case SEC_OID_ANSIX962_EC_PRIME239V2: + /* Populate params for prime239v2 */ + params->fieldID.size = 239; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF" \ + "FFFF8000000000007FFFFFFFFFFF")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF" \ + "FFFF8000000000007FFFFFFFFFFC")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "617FAB6832576CBBFED50D99F0249C3F" \ + "EE58B94BA0038C7AE84C8C832F2C")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "38AF09D98727705120C921BB5E9E2629" \ + "6A3CDCF2F35757A0EAFD87B830E7" \ + "5B0125E4DBEA0EC7206DA0FC01D9B081" \ + "329FB555DE6EF460237DFF8BE4BA")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "7FFFFFFFFFFFFFFFFFFFFFFF800000CF" \ + "A7E8594377D414C03821BC582063")); + params->cofactor = 1; + break; + + case SEC_OID_ANSIX962_EC_PRIME239V3: + /* Populate params for prime239v3 */ + params->fieldID.size = 239; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF" \ + "FFFF8000000000007FFFFFFFFFFF")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF" \ + "FFFF8000000000007FFFFFFFFFFC")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "255705FA2A306654B1F4CB03D6A750A3" \ + "0C250102D4988717D9BA15AB6D3E")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "6768AE8E18BB92CFCF005C949AA2C6D9" \ + "4853D0E660BBF854B1C9505FE95A" \ + "1607E6898F390C06BC1D552BAD226F3B" \ + "6FCFE48B6E818499AF18E3ED6CF3")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF97" \ + "5DEB41B3A6057C3C432146526551")); + params->cofactor = 1; + break; + + case SEC_OID_ANSIX962_EC_PRIME256V1: + /* Populate params for prime256v1 aka secp256r1 + * (the NIST P-256 curve) + */ + params->fieldID.size = 256; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "FFFFFFFF000000010000000000000000" \ + "00000000FFFFFFFFFFFFFFFFFFFFFFFF")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "FFFFFFFF000000010000000000000000" \ + "00000000FFFFFFFFFFFFFFFFFFFFFFFC")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "5AC635D8AA3A93E7B3EBBD55769886BC" \ + "651D06B0CC53B0F63BCE3C3E27D2604B")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "6B17D1F2E12C4247F8BCE6E563A440F2" \ + "77037D812DEB33A0F4A13945D898C296" \ + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E16" \ + "2BCE33576B315ECECBB6406837BF51F5")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "FFFFFFFF00000000FFFFFFFFFFFFFFFF" \ + "BCE6FAADA7179E84F3B9CAC2FC632551")); + params->cofactor = 1; + break; + + case SEC_OID_SECG_EC_SECP112R1: + /* Populate params for secp112r1 */ + params->fieldID.size = 112; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "DB7C2ABF62E35E668076BEAD208B")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "DB7C2ABF62E35E668076BEAD2088")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "659EF8BA043916EEDE8911702B22")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "09487239995A5EE76B55F9C2F098" \ + "A89CE5AF8724C0A23E0E0FF77500")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "DB7C2ABF62E35E7628DFAC6561C5")); + params->cofactor = 1; + break; + + case SEC_OID_SECG_EC_SECP112R2: + /* Populate params for secp112r2 */ + params->fieldID.size = 112; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "DB7C2ABF62E35E668076BEAD208B")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "6127C24C05F38A0AAAF65C0EF02C")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "51DEF1815DB5ED74FCC34C85D709")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "4BA30AB5E892B4E1649DD0928643" \ + "ADCD46F5882E3747DEF36E956E97")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "36DF0AAFD8B8D7597CA10520D04B")); + params->cofactor = 4; + break; + + case SEC_OID_SECG_EC_SECP128R1: + /* Populate params for secp128r1 */ + params->fieldID.size = 128; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "E87579C11079F43DD824993C2CEE5ED3")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "161FF7528B899B2D0C28607CA52C5B86" \ + "CF5AC8395BAFEB13C02DA292DDED7A83")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "FFFFFFFE0000000075A30D1B9038A115")); + params->cofactor = 1; + break; + + case SEC_OID_SECG_EC_SECP128R2: + /* Populate params for secp128r2 */ + params->fieldID.size = 128; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "D6031998D1B3BBFEBF59CC9BBFF9AEE1")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "5EEEFCA380D02919DC2C6558BB6D8A5D")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "7B6AA5D85E572983E6FB32A7CDEBC140" \ + "27B6916A894D3AEE7106FE805FC34B44")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "3FFFFFFF7FFFFFFFBE0024720613B5A3")); + params->cofactor = 4; + break; + + case SEC_OID_SECG_EC_SECP160K1: + /* Populate params for secp160k1 */ + params->fieldID.size = 160; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" \ + "FFFFAC73")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "00")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "07")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "3B4C382CE37AA192A4019E763036F4F5" \ + "DD4D7EBB" \ + "938CF935318FDCED6BC28286531733C3" \ + "F03C4FEE")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "0100000000000000000001B8FA16DFAB" \ + "9ACA16B6B3")); + params->cofactor = 1; + break; + + case SEC_OID_SECG_EC_SECP160R1: + /* Populate params for secp160r1 */ + params->fieldID.size = 160; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "7FFFFFFF")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "7FFFFFFC")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "1C97BEFC54BD7A8B65ACF89F81D4D4AD" \ + "C565FA45")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "4A96B5688EF573284664698968C38BB9" \ + "13CBFC82" \ + "23A628553168947D59DCC91204235137" \ + "7AC5FB32")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "0100000000000000000001F4C8F927AE" \ + "D3CA752257")); + params->cofactor = 1; + break; + + case SEC_OID_SECG_EC_SECP160R2: + /* Populate params for secp160r1 */ + params->fieldID.size = 160; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" \ + "FFFFAC73")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" \ + "FFFFAC70")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "B4E134D3FB59EB8BAB57274904664D5A" \ + "F50388BA")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "52DCB034293A117E1F4FF11B30F7199D" \ + "3144CE6D" \ + "FEAFFEF2E331F296E071FA0DF9982CFE" \ + "A7D43F2E")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "0100000000000000000000351EE786A8" \ + "18F3A1A16B")); + params->cofactor = 1; + break; + + case SEC_OID_SECG_EC_SECP192K1: + /* Populate params for secp192k1 */ + params->fieldID.size = 192; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "FFFFFFFEFFFFEE37")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "00")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "03")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "DB4FF10EC057E9AE26B07D0280B7F434" \ + "1DA5D1B1EAE06C7D" \ + "9B2F2F6D9C5628A7844163D015BE8634" \ + "4082AA88D95E2F9D")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "FFFFFFFFFFFFFFFFFFFFFFFE26F2FC17" \ + "0F69466A74DEFD8D")); + params->cofactor = 1; + break; + + case SEC_OID_SECG_EC_SECP224K1: + /* Populate params for secp224k1 */ + params->fieldID.size = 224; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "FFFFFFFFFFFFFFFEFFFFE56D")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "00")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "05")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "A1455B334DF099DF30FC28A169A467E9" \ + "E47075A90F7E650EB6B7A45C" \ + "7E089FED7FBA344282CAFBD6F7E319F7" \ + "C0B0BD59E2CA4BDB556D61A5")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "010000000000000000000000000001DC" \ + "E8D2EC6184CAF0A971769FB1F7")); + params->cofactor = 1; + break; + + case SEC_OID_SECG_EC_SECP224R1: + /* Populate params for secp224r1 + * (the NIST P-224 curve) + */ + params->fieldID.size = 224; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "000000000000000000000001")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" \ + "FFFFFFFFFFFFFFFFFFFFFFFE")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "B4050A850C04B3ABF54132565044B0B7" \ + "D7BFD8BA270B39432355FFB4")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "B70E0CBD6BB4BF7F321390B94A03C1D3" \ + "56C21122343280D6115C1D21" \ + "BD376388B5F723FB4C22DFE6CD4375A0" \ + "5A07476444D5819985007E34")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2" \ + "E0B8F03E13DD29455C5C2A3D")); + params->cofactor = 1; + break; + + case SEC_OID_SECG_EC_SECP256K1: + /* Populate params for secp256k1 */ + params->fieldID.size = 256; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "FFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "00")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "07")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "79BE667EF9DCBBAC55A06295CE870B07" \ + "029BFCDB2DCE28D959F2815B16F81798" \ + "483ADA7726A3C4655DA4FBFC0E1108A8" \ + "FD17B448A68554199C47D08FFB10D4B8")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" \ + "BAAEDCE6AF48A03BBFD25E8CD0364141")); + params->cofactor = 1; + break; + + case SEC_OID_SECG_EC_SECP384R1: + /* Populate params for secp384r1 + * (the NIST P-384 curve) + */ + params->fieldID.size = 384; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" \ + "FFFFFFFF0000000000000000FFFFFFFF")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE" \ + "FFFFFFFF0000000000000000FFFFFFFC")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "B3312FA7E23EE7E4988E056BE3F82D19" \ + "181D9C6EFE8141120314088F5013875A" \ + "C656398D8A2ED19D2A85C8EDD3EC2AEF")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "AA87CA22BE8B05378EB1C71EF320AD74" \ + "6E1D3B628BA79B9859F741E082542A38" \ + "5502F25DBF55296C3A545E3872760AB7" \ + "3617DE4A96262C6F5D9E98BF9292DC29" \ + "F8F41DBD289A147CE9DA3113B5F0B8C0" \ + "0A60B1CE1D7E819D7A431D7C90EA0E5F")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "FFFFFFFFFFFFFFFFC7634D81F4372DDF" \ + "581A0DB248B0A77AECEC196ACCC52973")); + params->cofactor = 1; + break; + + case SEC_OID_SECG_EC_SECP521R1: + /* Populate params for secp521r1 + * (the NIST P-521 curve) + */ + params->fieldID.size = 521; + params->fieldID.type = ec_field_GFp; + CHECK_OK(hexString2SECItem(params->arena, ¶ms->fieldID.u.prime, + "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "FFFF")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.a, + "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "FFFC")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->curve.b, + "0051953EB9618E1C9A1F929A21A0B685" \ + "40EEA2DA725B99B315F3B8B489918EF1" \ + "09E156193951EC7E937B1652C0BD3BB1" \ + "BF073573DF883D2C34F1EF451FD46B50" \ + "3F00")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->base, + "04" \ + "00C6858E06B70404E9CD9E3ECB662395" \ + "B4429C648139053FB521F828AF606B4D" \ + "3DBAA14B5E77EFE75928FE1DC127A2FF" \ + "A8DE3348B3C1856A429BF97E7E31C2E5" \ + "BD66" \ + "011839296A789A3BC0045C8A5FB42C7D" \ + "1BD998F54449579B446817AFBD17273E" \ + "662C97EE72995EF42640C550B9013FAD" \ + "0761353C7086A272C24088BE94769FD1" \ + "6650")); + CHECK_OK(hexString2SECItem(params->arena, ¶ms->order, + "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF" \ + "FFFA51868783BF2F966B7FCC0148F709" \ + "A5D03BB5C9B8899C47AEBB6FB71E9138" \ + "6409")); + params->cofactor = 1; + break; + + default: + break; + }; + +cleanup: + if (!params->cofactor) { + PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); +#if EC_DEBUG + printf("Unrecognized curve, returning NULL params\n"); +#endif + return SECFailure; + } + + return SECSuccess; +} + +SECStatus +EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams) +{ + PRArenaPool *arena; + ECParams *params; + SECStatus rv = SECFailure; + + /* Initialize an arena for the ECParams structure */ + if (!(arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE))) + return SECFailure; + + params = (ECParams *)PORT_ArenaZAlloc(arena, sizeof(ECParams)); + if (!params) { + PORT_FreeArena(arena, PR_TRUE); + return SECFailure; + } + + /* Copy the encoded params */ + SECITEM_AllocItem(arena, &(params->DEREncoding), + encodedParams->len); + memcpy(params->DEREncoding.data, encodedParams->data, encodedParams->len); + + /* Fill out the rest of the ECParams structure based on + * the encoded params + */ + rv = EC_FillParams(arena, encodedParams, params); + if (rv == SECFailure) { + PORT_FreeArena(arena, PR_TRUE); + return SECFailure; + } else { + *ecparams = params;; + return SECSuccess; + } +} + +#endif /* NSS_ENABLE_ECC */ diff --git a/security/nss/lib/softoken/lowkeyti.h b/security/nss/lib/softoken/lowkeyti.h index 48b1837f8478..938686a06359 100644 --- a/security/nss/lib/softoken/lowkeyti.h +++ b/security/nss/lib/softoken/lowkeyti.h @@ -16,7 +16,11 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -115,7 +119,8 @@ typedef enum { NSSLOWKEYNullKey = 0, NSSLOWKEYRSAKey = 1, NSSLOWKEYDSAKey = 2, - NSSLOWKEYDHKey = 4 + NSSLOWKEYDHKey = 4, + NSSLOWKEYECKey = 5 } NSSLOWKEYType; /* @@ -128,6 +133,7 @@ struct NSSLOWKEYPublicKeyStr { RSAPublicKey rsa; DSAPublicKey dsa; DHPublicKey dh; + ECPublicKey ec; } u; }; typedef struct NSSLOWKEYPublicKeyStr NSSLOWKEYPublicKey; @@ -144,6 +150,7 @@ struct NSSLOWKEYPrivateKeyStr { RSAPrivateKey rsa; DSAPrivateKey dsa; DHPrivateKey dh; + ECPrivateKey ec; } u; }; typedef struct NSSLOWKEYPrivateKeyStr NSSLOWKEYPrivateKey; diff --git a/security/nss/lib/softoken/manifest.mn b/security/nss/lib/softoken/manifest.mn index 24afb40d4827..baf114426039 100644 --- a/security/nss/lib/softoken/manifest.mn +++ b/security/nss/lib/softoken/manifest.mn @@ -62,6 +62,7 @@ CSRCS = \ alghmac.c \ dbinit.c \ dbmshim.c \ + ecdecode.c \ fipstest.c \ fipstokn.c \ keydb.c \ diff --git a/security/nss/lib/softoken/pkcs11.c b/security/nss/lib/softoken/pkcs11.c index c62d4cbd37c4..6a22d4c98665 100644 --- a/security/nss/lib/softoken/pkcs11.c +++ b/security/nss/lib/softoken/pkcs11.c @@ -16,8 +16,12 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * - * Contributor(s): + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): * Dr Stephen Henson + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -61,7 +65,11 @@ #include "keydbi.h" - +#ifdef NSS_ENABLE_ECC +extern SECStatus EC_FillParams(PRArenaPool *arena, + const SECItem *encodedParams, ECParams *params); +#endif + /* * ******************** Static data ******************************* */ @@ -226,6 +234,8 @@ struct mechanismList { #define CKF_SN_VR_RE CKF_SN_VR | CKF_SN_RE #define CKF_DUZ_IT_ALL CKF_EN_DE_WR_UN | CKF_SN_VR_RE +#define CKF_EC_PNU CKF_EC_FP | CKF_EC_NAMEDCURVE | CKF_EC_UNCOMPRESS + #define CK_MAX 0xffffffff static const struct mechanismList mechanisms[] = { @@ -236,11 +246,11 @@ static const struct mechanismList mechanisms[] = { * The first argument is the PKCS #11 Mechanism we support. * The second argument is Mechanism info structure. It includes: * The minimum key size, - * in bits for RSA, DSA, DH, KEA, RC2 and RC4 * algs. + * in bits for RSA, DSA, DH, EC*, KEA, RC2 and RC4 * algs. * in bytes for RC5, AES, and CAST* * ignored for DES*, IDEA and FORTEZZA based * The maximum key size, - * in bits for RSA, DSA, DH, KEA, RC2 and RC4 * algs. + * in bits for RSA, DSA, DH, EC*, KEA, RC2 and RC4 * algs. * in bytes for RC5, AES, and CAST* * ignored for DES*, IDEA and FORTEZZA based * Flags @@ -272,6 +282,13 @@ static const struct mechanismList mechanisms[] = { /* no diffie hellman yet */ {CKM_DH_PKCS_KEY_PAIR_GEN, {128, 1024, CKF_GENERATE_KEY_PAIR}, PR_TRUE}, {CKM_DH_PKCS_DERIVE, {128, 1024, CKF_DERIVE}, PR_TRUE}, +#ifdef NSS_ENABLE_ECC + /* -------------------- Elliptic Curve Operations --------------------- */ + {CKM_EC_KEY_PAIR_GEN, {112, 571, CKF_GENERATE_KEY_PAIR|CKF_EC_PNU}, PR_TRUE}, + {CKM_ECDH1_DERIVE, {112, 571, CKF_DERIVE|CKF_EC_PNU}, PR_TRUE}, + {CKM_ECDSA, {112, 571, CKF_SN_VR|CKF_EC_PNU}, PR_TRUE}, + {CKM_ECDSA_SHA1, {112, 571, CKF_SN_VR|CKF_EC_PNU}, PR_TRUE}, +#endif /* NSS_ENABLE_ECC */ /* ------------------------- RC2 Operations --------------------------- */ {CKM_RC2_KEY_GEN, {1, 128, CKF_GENERATE}, PR_TRUE}, {CKM_RC2_ECB, {1, 128, CKF_EN_DE_WR_UN}, PR_TRUE}, @@ -1037,6 +1054,21 @@ pk11_handlePublicKeyObject(PK11Session *session, PK11Object *object, recover = CK_FALSE; wrap = CK_FALSE; break; +#ifdef NSS_ENABLE_ECC + case CKK_EC: + if ( !pk11_hasAttribute(object, CKA_EC_PARAMS)) { + return CKR_TEMPLATE_INCOMPLETE; + } + if ( !pk11_hasAttribute(object, CKA_EC_POINT)) { + return CKR_TEMPLATE_INCOMPLETE; + } + derive = CK_TRUE; /* for ECDH */ + verify = CK_TRUE; /* for ECDSA */ + encrypt = CK_FALSE; + recover = CK_FALSE; + wrap = CK_FALSE; + break; +#endif /* NSS_ENABLE_ECC */ default: return CKR_ATTRIBUTE_VALUE_INVALID; } @@ -1111,6 +1143,7 @@ pk11_handlePrivateKeyObject(PK11Session *session,PK11Object *object,CK_KEY_TYPE CK_BBOOL encrypt = CK_TRUE; CK_BBOOL recover = CK_TRUE; CK_BBOOL wrap = CK_TRUE; + CK_BBOOL derive = CK_FALSE; CK_BBOOL ckfalse = CK_FALSE; SECItem mod; CK_RV crv; @@ -1172,6 +1205,20 @@ pk11_handlePrivateKeyObject(PK11Session *session,PK11Object *object,CK_KEY_TYPE recover = CK_FALSE; wrap = CK_FALSE; break; +#ifdef NSS_ENABLE_ECC + case CKK_EC: + if ( !pk11_hasAttribute(object, CKA_EC_PARAMS)) { + return CKR_TEMPLATE_INCOMPLETE; + } + if ( !pk11_hasAttribute(object, CKA_VALUE)) { + return CKR_TEMPLATE_INCOMPLETE; + } + encrypt = CK_FALSE; + recover = CK_FALSE; + wrap = CK_FALSE; + derive = CK_TRUE; + break; +#endif /* NSS_ENABLE_ECC */ default: return CKR_ATTRIBUTE_VALUE_INVALID; } @@ -1190,6 +1237,8 @@ pk11_handlePrivateKeyObject(PK11Session *session,PK11Object *object,CK_KEY_TYPE if (crv != CKR_OK) return crv; crv = pk11_defaultAttribute(object,CKA_UNWRAP,&wrap,sizeof(CK_BBOOL)); if (crv != CKR_OK) return crv; + crv = pk11_defaultAttribute(object,CKA_DERIVE,&derive,sizeof(CK_BBOOL)); + if (crv != CKR_OK) return crv; /* the next two bits get modified only in the key gen and token cases */ crv = pk11_forceAttribute(object,CKA_ALWAYS_SENSITIVE, &ckfalse,sizeof(CK_BBOOL)); @@ -1793,6 +1842,24 @@ NSSLOWKEYPublicKey *pk11_GetPubKey(PK11Object *object,CK_KEY_TYPE key_type, crv = pk11_Attribute2SSecItem(arena,&pubKey->u.dh.publicValue, object,CKA_VALUE); break; +#ifdef NSS_ENABLE_ECC + case CKK_EC: + pubKey->keyType = NSSLOWKEYECKey; + crv = pk11_Attribute2SSecItem(arena, + &pubKey->u.ec.ecParams.DEREncoding, + object,CKA_EC_PARAMS); + if (crv != CKR_OK) break; + + /* Fill out the rest of the ecParams structure + * based on the encoded params + */ + if (EC_FillParams(arena, &pubKey->u.ec.ecParams.DEREncoding, + &pubKey->u.ec.ecParams) != SECSuccess) break; + + crv = pk11_Attribute2SSecItem(arena,&pubKey->u.ec.publicValue, + object,CKA_EC_POINT); + break; +#endif /* NSS_ENABLE_ECC */ default: crv = CKR_KEY_TYPE_INCONSISTENT; break; @@ -1899,6 +1966,30 @@ pk11_mkPrivKey(PK11Object *object, CK_KEY_TYPE key_type, CK_RV *crvp) crv = pk11_Attribute2SSecItem(arena,&privKey->u.dh.publicValue, object,CKA_NETSCAPE_DB); break; + +#ifdef NSS_ENABLE_ECC + case CKK_EC: + privKey->keyType = NSSLOWKEYECKey; + crv = pk11_Attribute2SSecItem(arena, + &privKey->u.ec.ecParams.DEREncoding, + object,CKA_EC_PARAMS); + if (crv != CKR_OK) break; + + /* Fill out the rest of the ecParams structure + * based on the encoded params + */ + if (EC_FillParams(arena, &privKey->u.ec.ecParams.DEREncoding, + &privKey->u.ec.ecParams) != SECSuccess) break; + crv = pk11_Attribute2SSecItem(arena,&privKey->u.ec.privateValue, + object,CKA_VALUE); + if (crv != CKR_OK) break; + /* XXX Why does this break handlePrivateKeyObject ? + crv = pk11_Attribute2SSecItem(arena,&privKey->u.ec.publicValue, + object,CKA_NETSCAPE_DB); + */ + break; +#endif /* NSS_ENABLE_ECC */ + default: crv = CKR_KEY_TYPE_INCONSISTENT; break; diff --git a/security/nss/lib/softoken/pkcs11c.c b/security/nss/lib/softoken/pkcs11c.c index b476e69763ee..82da04d16147 100644 --- a/security/nss/lib/softoken/pkcs11c.c +++ b/security/nss/lib/softoken/pkcs11c.c @@ -16,8 +16,12 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * - * Contributor(s): + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): * Dr Stephen Henson + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -90,6 +94,11 @@ static void pk11_Null(void *data, PRBool freeit) return; } +#ifdef NSS_ENABLE_ECC +extern SECStatus EC_DecodeParams(const SECItem *encodedParams, + ECParams **ecparams); +#endif /* NSS_ENABLE_ECC */ + /* * free routines.... Free local type allocated data, and convert * other free routines to the destroy signature. @@ -1607,6 +1616,41 @@ nsc_DSA_Sign_Stub(void *ctx, void *sigBuf, return rv; } +#ifdef NSS_ENABLE_ECC +static SECStatus +nsc_ECDSAVerifyStub(void *ctx, void *sigBuf, unsigned int sigLen, + void *dataBuf, unsigned int dataLen) +{ + SECItem signature, digest; + NSSLOWKEYPublicKey *key = (NSSLOWKEYPublicKey *)ctx; + + signature.data = (unsigned char *)sigBuf; + signature.len = sigLen; + digest.data = (unsigned char *)dataBuf; + digest.len = dataLen; + return ECDSA_VerifyDigest(&(key->u.ec), &signature, &digest); +} + +static SECStatus +nsc_ECDSASignStub(void *ctx, void *sigBuf, + unsigned int *sigLen, unsigned int maxSigLen, + void *dataBuf, unsigned int dataLen) +{ + SECItem signature = { 0 }, digest; + SECStatus rv; + NSSLOWKEYPrivateKey *key = (NSSLOWKEYPrivateKey *)ctx; + + (void)SECITEM_AllocItem(NULL, &signature, maxSigLen); + digest.data = (unsigned char *)dataBuf; + digest.len = dataLen; + rv = ECDSA_SignDigest(&(key->u.ec), &signature, &digest); + *sigLen = signature.len; + PORT_Memcpy(sigBuf, signature.data, signature.len); + SECITEM_FreeItem(&signature, PR_FALSE); + return rv; +} +#endif /* NSS_ENABLE_ECC */ + /* NSC_SignInit setups up the signing operations. There are three basic * types of signing: * (1) the tradition single part, where "Raw RSA" or "Raw DSA" is applied @@ -1729,6 +1773,31 @@ finish_rsa: break; +#ifdef NSS_ENABLE_ECC + case CKM_ECDSA_SHA1: + context->multi = PR_TRUE; + crv = pk11_doSubSHA1(context); + if (crv != CKR_OK) break; + /* fall through */ + case CKM_ECDSA: + if (key_type != CKK_EC) { + crv = CKR_KEY_TYPE_INCONSISTENT; + break; + } + privKey = pk11_GetPrivKey(key,CKK_EC,&crv); + if (privKey == NULL) { + crv = CKR_HOST_MEMORY; + break; + } + context->cipherInfo = privKey; + context->update = (PK11Cipher) nsc_ECDSASignStub; + context->destroy = (privKey == key->objectInfo) ? + (PK11Destroy) pk11_Null:(PK11Destroy)pk11_FreePrivKey; + context->maxLen = MAX_ECKEY_LEN * 2; + + break; +#endif /* NSS_ENABLE_ECC */ + #define INIT_HMAC_MECH(mmm) \ case CKM_ ## mmm ## _HMAC_GENERAL: \ crv = pk11_doHMACInit(context, HASH_Alg ## mmm ,key, \ @@ -2126,7 +2195,28 @@ finish_rsa: context->verify = (PK11Verify) nsc_DSA_Verify_Stub; context->destroy = pk11_Null; break; - +#ifdef NSS_ENABLE_ECC + case CKM_ECDSA_SHA1: + context->multi = PR_TRUE; + crv = pk11_doSubSHA1(context); + if (crv != CKR_OK) break; + /* fall through */ + case CKM_ECDSA: + if (key_type != CKK_EC) { + crv = CKR_KEY_TYPE_INCONSISTENT; + break; + } + context->multi = PR_FALSE; + pubKey = pk11_GetPubKey(key,CKK_EC,&crv); + if (pubKey == NULL) { + crv = CKR_HOST_MEMORY; + break; + } + context->cipherInfo = pubKey; + context->verify = (PK11Verify) nsc_ECDSAVerifyStub; + context->destroy = pk11_Null; + break; +#endif /* NSS_ENABLE_ECC */ INIT_HMAC_MECH(MD2) INIT_HMAC_MECH(MD5) @@ -2872,6 +2962,13 @@ CK_RV NSC_GenerateKeyPair (CK_SESSION_HANDLE hSession, int private_value_bits = 0; DHPrivateKey * dhPriv; +#ifdef NSS_ENABLE_ECC + /* Elliptic Curve Cryptography */ + SECItem ecEncodedParams; /* DER Encoded parameters */ + ECPrivateKey * ecPriv; + ECParams * ecParams; +#endif /* NSS_ENABLE_ECC */ + /* * now lets create an object to hang the attributes off of */ @@ -3123,6 +3220,51 @@ dhgn_done: PORT_FreeArena(dhPriv->arena, PR_TRUE); break; +#ifdef NSS_ENABLE_ECC + case CKM_EC_KEY_PAIR_GEN: + pk11_DeleteAttributeType(privateKey,CKA_EC_PARAMS); + pk11_DeleteAttributeType(privateKey,CKA_VALUE); + key_type = CKK_EC; + + /* extract the necessary parameters and copy them to private keys */ + crv = pk11_Attribute2SSecItem(NULL, &ecEncodedParams, publicKey, + CKA_EC_PARAMS); + if (crv != CKR_OK) break; + + crv = pk11_AddAttributeType(privateKey, CKA_EC_PARAMS, + pk11_item_expand(&ecEncodedParams)); + if (crv != CKR_OK) { + PORT_Free(ecEncodedParams.data); + break; + } + + /* Decode ec params before calling EC_NewKey */ + rv = EC_DecodeParams(&ecEncodedParams, &ecParams); + PORT_Free(ecEncodedParams.data); + if (rv != SECSuccess) { + crv = CKR_DEVICE_ERROR; + break; + } + rv = EC_NewKey(ecParams, &ecPriv); + PORT_FreeArena(ecParams->arena, PR_TRUE); + if (rv != SECSuccess) { + crv = CKR_DEVICE_ERROR; + break; + } + + crv = pk11_AddAttributeType(publicKey, CKA_EC_POINT, + pk11_item_expand(&ecPriv->publicValue)); + if (crv != CKR_OK) goto ecgn_done; + + crv = pk11_AddAttributeType(privateKey, CKA_VALUE, + pk11_item_expand(&ecPriv->privateValue)); + +ecgn_done: + /* should zeroize, since this function doesn't. */ + PORT_FreeArena(ecPriv->ecParams.arena, PR_TRUE); + break; +#endif /* NSS_ENABLE_ECC */ + default: crv = CKR_MECHANISM_INVALID; } @@ -4778,6 +4920,103 @@ key_and_mac_derive_fail: break; } +#ifdef NSS_ENABLE_ECC + case CKM_ECDH1_DERIVE: + case CKM_ECDH1_COFACTOR_DERIVE: + { + SECItem ecScalar, ecPoint; + SECItem tmp; + ECParams *ecParams; + PRBool withCofactor = PR_FALSE; + unsigned char secret_hash[20]; + unsigned char *secret; + int secretlen; + CK_ECDH1_DERIVE_PARAMS *mechParams; + + /* get params and value attributes */ + crv = pk11_Attribute2SecItem(NULL, &tmp, sourceKey, + CKA_EC_PARAMS); + if (crv != CKR_OK) break; + crv = pk11_Attribute2SecItem(NULL, &ecScalar, sourceKey, CKA_VALUE); + if (crv != CKR_OK) { + PORT_Free(tmp.data); + break; + } + + /* Check elliptic curve parameters */ + rv = EC_DecodeParams(&tmp, &ecParams); + PORT_Free(tmp.data); + if (rv != SECSuccess) { + crv = CKR_TEMPLATE_INCONSISTENT; + PORT_Free(ecScalar.data); + break; + } + + /* Check mechanism parameters */ + mechParams = (CK_ECDH1_DERIVE_PARAMS *) pMechanism->pParameter; + if ((pMechanism->ulParameterLen != sizeof(CK_ECDH1_DERIVE_PARAMS)) || + ((mechParams->kdf == CKD_NULL) && + ((mechParams->ulSharedDataLen != 0) || + (mechParams->pSharedData != NULL)))) { + crv = CKR_MECHANISM_PARAM_INVALID; + PORT_FreeArena(ecParams->arena, PR_TRUE); + PORT_Free(ecScalar.data); + break; + } + + ecPoint.data = mechParams->pPublicData; + ecPoint.len = mechParams->ulPublicDataLen; + + if (pMechanism->mechanism == CKM_ECDH1_COFACTOR_DERIVE) { + withCofactor = PR_TRUE; + } else { + /* When not using cofactor derivation, one should + * validate the public key to avoid small subgroup + * attacks. + */ + if (EC_ValidatePublicKey(ecParams, &ecPoint) != SECSuccess) { + crv = CKR_ARGUMENTS_BAD; + PORT_FreeArena(ecParams->arena, PR_TRUE); + PORT_Free(ecScalar.data); + break; + } + } + + rv = ECDH_Derive(&ecPoint, ecParams, &ecScalar, + withCofactor, &tmp); + PORT_FreeArena(ecParams->arena, PR_TRUE); + PORT_Free(ecScalar.data); + + if (rv != SECSuccess) { + crv = CKR_DEVICE_ERROR; + break; + } + + secret = tmp.data; + secretlen = tmp.len; + if (mechParams->kdf == CKD_SHA1_KDF) { + /* Compute SHA1 hash */ + memset(secret_hash, 0, 20); + rv = SHA1_HashBuf(secret_hash, tmp.data, tmp.len); + if (rv != SECSuccess) { + PORT_ZFree(tmp.data, tmp.len); + } else { + secret = secret_hash; + secretlen = 20; + } + } + + if (rv == SECSuccess) { + pk11_forceAttribute(key, CKA_VALUE, secret, secretlen); + PORT_ZFree(tmp.data, tmp.len); + memset(secret_hash, 0, 20); + } else + crv = CKR_HOST_MEMORY; + + break; + } +#endif /* NSS_ENABLE_ECC */ + default: crv = CKR_MECHANISM_INVALID; } diff --git a/security/nss/lib/softoken/pkcs11t.h b/security/nss/lib/softoken/pkcs11t.h index 8a81a77d64dd..4b16e873def1 100644 --- a/security/nss/lib/softoken/pkcs11t.h +++ b/security/nss/lib/softoken/pkcs11t.h @@ -16,7 +16,11 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -1377,6 +1381,25 @@ typedef struct CK_PKCS5_PBKD2_PARAMS { typedef CK_PKCS5_PBKD2_PARAMS CK_PTR CK_PKCS5_PBKD2_PARAMS_PTR; +/* CK_ECDH1_DERIVE_PARAMS is defined in Section 12.4.4 of + * PKCS#11v2.11. This structure provides parameters for + * the CKM_ECDH1_DERIVE and CKM_ECDH1_COFACTOR_DERIVE key + * derivation mechanisms. + */ +typedef CK_ULONG CK_EC_KDF_TYPE; +#define CKD_NULL 0x00000001 +#define CKD_SHA1_KDF 0x00000002 + +typedef struct CK_ECDH1_DERIVE_PARAMS { + CK_EC_KDF_TYPE kdf; + CK_ULONG ulSharedDataLen; + CK_BYTE_PTR pSharedData; + CK_ULONG ulPublicDataLen; + CK_BYTE_PTR pPublicData; +} CK_ECDH1_DERIVE_PARAMS; + +typedef CK_ECDH1_DERIVE_PARAMS CK_PTR CK_ECDH1_DERIVE_PARAMS_PTR; + /* Netscape Specific defines */ #include "pkcs11n.h" diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c index e23cd55db31a..b5d7dcc86030 100644 --- a/security/nss/lib/ssl/ssl3con.c +++ b/security/nss/lib/ssl/ssl3con.c @@ -18,8 +18,12 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * - * Contributor(s): + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): * Dr Stephen Henson + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -33,7 +37,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: ssl3con.c,v 1.48 2003/02/21 23:00:16 nelsonb%netscape.com Exp $ + * $Id: ssl3con.c,v 1.49 2003/02/27 01:31:29 nelsonb%netscape.com Exp $ */ #include "nssrenam.h" @@ -56,6 +60,7 @@ #include "pk11func.h" #include "secmod.h" #include "nsslocks.h" +#include "ec.h" #include @@ -90,24 +95,43 @@ static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen, /* This list of SSL3 cipher suites is sorted in descending order of * precedence (desirability). It only includes cipher suites we implement. - * This table is modified by SSL3_SetPolicy(). + * This table is modified by SSL3_SetPolicy(). The ordering of cipher suites + * in this table must match the ordering in SSL_ImplementedCiphers (sslenum.c) */ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { /* cipher_suite policy enabled is_present*/ { TLS_DHE_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, { TLS_DHE_DSS_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, +#ifdef NSS_ENABLE_ECC + { TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, + { TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, +#endif /* NSS_ENABLE_ECC */ { TLS_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, { SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, +#ifdef NSS_ENABLE_ECC + { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, + { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, +#endif /* NSS_ENABLE_ECC */ { TLS_DHE_DSS_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, { TLS_DHE_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, { TLS_DHE_DSS_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, +#ifdef NSS_ENABLE_ECC + { TLS_ECDH_RSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, + { TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, + { TLS_ECDH_ECDSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, + { TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, +#endif /* NSS_ENABLE_ECC */ { SSL_RSA_WITH_RC4_128_MD5, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, { SSL_RSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, { TLS_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, { SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, { SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, +#ifdef NSS_ENABLE_ECC + { TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, + { TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, +#endif /* NSS_ENABLE_ECC */ { SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, { SSL_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, @@ -115,16 +139,26 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { { SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, { SSL_DHE_DSS_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, +#ifdef NSS_ENABLE_ECC + { TLS_ECDH_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, + { TLS_ECDH_ECDSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, +#endif /* NSS_ENABLE_ECC */ { SSL_RSA_FIPS_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, { SSL_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, - { TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, { TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, + { SSL_RSA_EXPORT_WITH_RC4_40_MD5, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, { SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, + { SSL_FORTEZZA_DMS_WITH_NULL_SHA, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, +#ifdef NSS_ENABLE_ECC + { TLS_ECDH_RSA_WITH_NULL_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE}, + { TLS_ECDH_ECDSA_WITH_NULL_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE}, +#endif /* NSS_ENABLE_ECC */ { SSL_RSA_WITH_NULL_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, - { SSL_RSA_WITH_NULL_MD5, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE} + { SSL_RSA_WITH_NULL_MD5, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, + }; static const /*SSL3CompressionMethod*/ uint8 compressions [] = { @@ -203,6 +237,12 @@ static const ssl3KEADef kea_defs[] = { /* indexed by SSL3KeyExchangeAlgorithm */ {kea_dh_anon_export, kt_dh, sign_null, PR_TRUE, 512, PR_FALSE}, {kea_fortezza, kt_fortezza, sign_dsa, PR_FALSE, 0, PR_FALSE}, {kea_rsa_fips, kt_rsa, sign_rsa, PR_FALSE, 0, PR_TRUE }, +#ifdef NSS_ENABLE_ECC + {kea_ecdh_ecdsa, kt_ecdh, sign_ecdsa, PR_FALSE, 0, PR_FALSE}, + {kea_ecdhe_ecdsa, kt_ecdh, sign_ecdsa, PR_FALSE, 0, PR_FALSE}, + {kea_ecdh_rsa, kt_ecdh, sign_rsa, PR_FALSE, 0, PR_FALSE}, + {kea_ecdhe_rsa, kt_ecdh, sign_rsa, PR_FALSE, 0, PR_FALSE}, +#endif /* NSS_ENABLE_ECC */ }; /* must use ssl_LookupCipherSuiteDef to access */ @@ -283,13 +323,34 @@ static const ssl3CipherSuiteDef cipher_suite_defs[] = { {SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_rsa_fips}, {SSL_RSA_FIPS_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_rsa_fips}, +#ifdef NSS_ENABLE_ECC + /* Experimental TLS cipher suites using Elliptic Curves */ + {TLS_ECDH_ECDSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdh_ecdsa}, + {TLS_ECDH_ECDSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdh_ecdsa}, + {TLS_ECDH_ECDSA_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_ecdh_ecdsa}, + {TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdh_ecdsa}, + {TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdh_ecdsa}, + {TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdh_ecdsa}, + + {TLS_ECDH_RSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdh_rsa}, + {TLS_ECDH_RSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdh_rsa}, + {TLS_ECDH_RSA_WITH_DES_CBC_SHA, cipher_des, mac_sha, kea_ecdh_rsa}, + {TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdh_rsa}, + {TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdh_rsa}, + {TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdh_rsa}, + + {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdhe_ecdsa}, + + {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdhe_rsa}, +#endif /* NSS_ENABLE_ECC */ }; static const CK_MECHANISM_TYPE kea_alg_defs[] = { 0x80000000L, CKM_RSA_PKCS, CKM_DH_PKCS_DERIVE, - CKM_KEA_KEY_DERIVE + CKM_KEA_KEY_DERIVE, + CKM_ECDH1_DERIVE }; typedef struct SSLCipher2MechStr { @@ -342,6 +403,110 @@ const char * const ssl3_cipherName[] = { "missing" }; +#ifdef NSS_ENABLE_ECC +/* Types and names of elliptic curves used in TLS */ +typedef enum { ec_type_explicitPrime = 1, + ec_type_explicitChar2Curve, + ec_type_named +} ECType; + +typedef enum { ec_noName = 0, + ec_sect163k1, ec_sect163r1, ec_sect163r2, + ec_sect193r1, ec_sect193r2, ec_sect233k1, + ec_sect233r1, ec_sect239k1, ec_sect283k1, + ec_sect283r1, ec_sect409k1, ec_sect409r1, + ec_sect571k1, ec_sect571r1, ec_secp160k1, + ec_secp160r1, ec_secp160r2, ec_secp192k1, + ec_secp192r1, ec_secp224k1, ec_secp224r1, + ec_secp256k1, ec_secp256r1, ec_secp384r1, + ec_secp521r1, + ec_pastLastName +} ECName; + +/* XXX Change this when more curves are supported */ +#define supportedCurve(x) (((x) >= ec_secp160k1) && ((x) <= ec_secp521r1)) + +/* Table containing OID tags for elliptic curves named in the + * ECC-TLS IETF draft. + */ +static const SECOidTag ecName2OIDTag[] = { + 0, + 0, /* SEC_OID_SECG_EC_SECT163K1, */ /* 1 */ + 0, /* SEC_OID_SECG_EC_SECT163R1, */ /* 2 */ + 0, /* SEC_OID_SECG_EC_SECT163R2, */ /* 3 */ + 0, /* SEC_OID_SECG_EC_SECT193R1, */ /* 4 */ + 0, /* SEC_OID_SECG_EC_SECT193R2, */ /* 5 */ + 0, /* SEC_OID_SECG_EC_SECT233K1, */ /* 6 */ + 0, /* SEC_OID_SECG_EC_SECT233R1, */ /* 7 */ + 0, /* SEC_OID_SECG_EC_SECT239K1, */ /* 8 */ + 0, /* SEC_OID_SECG_EC_SECT283K1, */ /* 9 */ + 0, /* SEC_OID_SECG_EC_SECT283R1, */ /* 10 */ + 0, /* SEC_OID_SECG_EC_SECT409K1, */ /* 11 */ + 0, /* SEC_OID_SECG_EC_SECT409R1, */ /* 12 */ + 0, /* SEC_OID_SECG_EC_SECT571K1, */ /* 13 */ + 0, /* SEC_OID_SECG_EC_SECT571R1, */ /* 14 */ + SEC_OID_SECG_EC_SECP160K1, /* 15 */ + SEC_OID_SECG_EC_SECP160R1, /* 16 */ + SEC_OID_SECG_EC_SECP160R2, /* 17 */ + SEC_OID_SECG_EC_SECP192K1, /* 18 */ + SEC_OID_SECG_EC_SECP192R1, /* 19 */ + SEC_OID_SECG_EC_SECP224K1, /* 20 */ + SEC_OID_SECG_EC_SECP224R1, /* 21 */ + SEC_OID_SECG_EC_SECP256K1, /* 22 */ + SEC_OID_SECG_EC_SECP256R1, /* 23 */ + SEC_OID_SECG_EC_SECP384R1, /* 24 */ + SEC_OID_SECG_EC_SECP521R1, /* 25 */ +}; + +static SECStatus +ecName2params(PRArenaPool * arena, ECName curve, SECKEYECParams * params) +{ + SECOidData *oidData = NULL; + + if ((curve <= ec_noName) || (curve >= ec_pastLastName) || + ((oidData = SECOID_FindOIDByTag(ecName2OIDTag[curve])) == NULL)) { + PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); + return SECFailure; + } + + SECITEM_AllocItem(arena, params, (2 + oidData->oid.len)); + /* + * params->data needs to contain the ASN encoding of an object ID (OID) + * representing the named curve. The actual OID is in + * oidData->oid.data so we simply prepend 0x06 and OID length + */ + params->data[0] = SEC_ASN1_OBJECT_ID; + params->data[1] = oidData->oid.len; + memcpy(params->data + 2, oidData->oid.data, oidData->oid.len); + + return SECSuccess; +} + +static ECName +params2ecName(SECKEYECParams * params) +{ + SECItem oid = { siBuffer, NULL, 0}; + SECOidData *oidData = NULL; + ECName i; + + /* + * params->data needs to contain the ASN encoding of an object ID (OID) + * representing a named curve. Here, we strip away everything + * before the actual OID and use the OID to look up a named curve. + */ + if (params->data[0] != SEC_ASN1_OBJECT_ID) return ec_noName; + oid.len = params->len - 2; + oid.data = params->data + 2; + if ((oidData = SECOID_FindOID(&oid)) == NULL) return ec_noName; + for (i = ec_noName + 1; i < ec_pastLastName; i++) { + if (ecName2OIDTag[i] == oidData->offset) + return i; + } + + return ec_noName; +} +#endif /* NSS_ENABLE_ECC */ + #if defined(TRACE) static char * @@ -472,7 +637,24 @@ ssl3_config_match_init(sslSocket *ss) cipher_mech = alg2Mech[cipher_alg].cmech; exchKeyType = kea_defs[cipher_def->key_exchange_alg].exchKeyType; +#ifndef NSS_ENABLE_ECC svrAuth = ss->serverCerts + exchKeyType; +#else + /* XXX SSLKEAType isn't really a good choice for + * indexing certificates. It doesn't work for + * (EC)DHE-* ciphers. Here we use a hack to ensure + * that the server uses an RSA cert for (EC)DHE-RSA. + */ + switch (cipher_def->key_exchange_alg) { + case kea_ecdhe_rsa: + case kea_dhe_rsa: + svrAuth = ss->serverCerts + kt_rsa; + break; + default: + svrAuth = ss->serverCerts + exchKeyType; + break; + } +#endif /* NSS_ENABLE_ECC */ /* Mark the suites that are backed by real tokens, certs and keys */ suite->isPresent = (PRBool) @@ -688,6 +870,9 @@ ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert, SECItem * signature = NULL; SECStatus rv; SECItem hashItem; +#ifdef NSS_ENABLE_ECC + int len; +#endif /* NSS_ENABLE_ECC */ PRINT_BUF(60, (NULL, "check signed hashes", @@ -718,6 +903,44 @@ ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert, buf = signature; } break; + +#ifdef NSS_ENABLE_ECC + case ecKey: + hashItem.data = hash->sha; + hashItem.len = sizeof(hash->sha); + /* + * ECDSA signatures always encode the integers r and s + * using ASN (unlike DSA where ASN encoding is used + * with TLS but not with SSL3) + */ + len = SECKEY_PublicKeyStrength(key) * 2; + if (len == 0) { + SECKEY_DestroyPublicKey(key); + PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); + return SECFailure; + } + signature = SECITEM_AllocItem(NULL, NULL, len); + /* XXX Use a better decoder */ + if ((buf->len < len + 6) || + (buf->data[0] != 0x30) || /* must start with a SEQUENCE */ + (buf->data[1] != buf->len - 2) || + (buf->data[2] != 0x02) || /* 1st INTEGER, r */ + (buf->data[3] < len/2) || + (buf->data[4 + buf->data[3]] != 0x02) || /* 2nd INTEGER, s */ + (buf->data[5 + buf->data[3]] < len/2)) { + PORT_SetError(SSL_ERROR_BAD_HANDSHAKE_HASH_VALUE); + SECITEM_FreeItem(signature, PR_TRUE); + return SECFailure; + } + + PORT_Memcpy(signature->data, + buf->data + 4 + (buf->data[3]-len/2), len/2); + PORT_Memcpy(signature->data + len/2, + buf->data + buf->len - len/2, len/2); + buf = signature; + break; +#endif /* NSS_ENABLE_ECC */ + default: SECKEY_DestroyPublicKey(key); PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); @@ -915,6 +1138,73 @@ done: PORT_Free(hashBuf); return rv; } + +#ifdef NSS_ENABLE_ECC +/* Caller must set hiLevel error code. */ +static SECStatus +ssl3_ComputeECDHKeyHash(SECItem ec_params, SECItem server_ecpoint, + SSL3Random *client_rand, SSL3Random *server_rand, + SSL3Hashes *hashes) +{ + PRUint8 * hashBuf; + PRUint8 * pBuf; + SECStatus rv = SECSuccess; + unsigned int bufLen; + /* + * XXX For now, we only support named curves (the appropriate + * checks are made before this method is called) so ec_params + * takes up only two bytes. ECPoint needs to fit in 256 bytes + * (because the spec says the length must fit in one byte) + */ + PRUint8 buf[2*SSL3_RANDOM_LENGTH + 2 + 1 + 256]; + + bufLen = 2*SSL3_RANDOM_LENGTH + ec_params.len + 1 + server_ecpoint.len; + if (bufLen <= sizeof buf) { + hashBuf = buf; + } else { + hashBuf = PORT_Alloc(bufLen); + if (!hashBuf) { + return SECFailure; + } + } + + memcpy(hashBuf, client_rand, SSL3_RANDOM_LENGTH); + pBuf = hashBuf + SSL3_RANDOM_LENGTH; + memcpy(pBuf, server_rand, SSL3_RANDOM_LENGTH); + pBuf += SSL3_RANDOM_LENGTH; + memcpy(pBuf, ec_params.data, ec_params.len); + pBuf += ec_params.len; + pBuf[0] = (PRUint8)(server_ecpoint.len); + pBuf += 1; + memcpy(pBuf, server_ecpoint.data, server_ecpoint.len); + pBuf += server_ecpoint.len; + PORT_Assert((unsigned int)(pBuf - hashBuf) == bufLen); + + rv = PK11_HashBuf(SEC_OID_MD5, hashes->md5, hashBuf, bufLen); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_MD5_DIGEST_FAILURE); + rv = SECFailure; + goto done; + } + + rv = PK11_HashBuf(SEC_OID_SHA1, hashes->sha, hashBuf, bufLen); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_SHA_DIGEST_FAILURE); + rv = SECFailure; + goto done; + } + + PRINT_BUF(95, (NULL, "ECDHkey hash: ", hashBuf, bufLen)); + PRINT_BUF(95, (NULL, "ECDHkey hash: MD5 result", hashes->md5, MD5_LENGTH)); + PRINT_BUF(95, (NULL, "ECDHkey hash: SHA1 result", hashes->sha, SHA1_LENGTH)); + +done: + if (hashBuf != buf && hashBuf != NULL) + PORT_Free(hashBuf); + return rv; +} +#endif /* NSS_ENABLE_ECC */ + /* Caller must set hiLevel error code. */ static SECStatus ssl3_ComputeFortezzaPublicKeyHash(SECItem publicValue, unsigned char * hash) @@ -2013,7 +2303,13 @@ ssl3_GenerateSessionKeys(sslSocket *ss, const PK11SymKey *pms) PRBool skipKeysAndIVs = (PRBool) ((cipher_def->calg == calg_fortezza) || (cipher_def->calg == calg_null)); - PRBool isDH = (PRBool) (ss->ssl3->hs.kea_def->exchKeyType == kt_dh); + /* + * Whenever isDH is true, we need to use CKM_TLS_MASTER_KEY_DERIVE_DH + * which, unlike CKM_TLS_MASTER_KEY_DERIVE, converts arbitrary size + * data into a 48-byte value. + */ + PRBool isDH = (PRBool) ((ss->ssl3->hs.kea_def->exchKeyType == kt_dh) || + (ss->ssl3->hs.kea_def->exchKeyType == kt_ecdh)); CK_MECHANISM_TYPE master_derive; CK_MECHANISM_TYPE key_derive; CK_MECHANISM_TYPE bulk_mechanism; @@ -3387,6 +3683,84 @@ loser: return rv; } +#ifdef NSS_ENABLE_ECC +/* Called from ssl3_SendClientKeyExchange(). */ +static SECStatus +sendECDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) +{ + PK11SymKey * pms = NULL; + SECStatus rv = SECFailure; + PRBool isTLS; + CK_MECHANISM_TYPE target; + SECKEYPublicKey *pubKey = NULL; /* Ephemeral ECDH key */ + SECKEYPrivateKey *privKey = NULL; /* Ephemeral ECDH key */ + + PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + PORT_Assert( ssl_HaveXmitBufLock(ss)); + + isTLS = (PRBool)(ss->ssl3->pwSpec->version > SSL_LIBRARY_VERSION_3_0); + + /* Generate ephemeral EC keypair */ + privKey = SECKEY_CreateECPrivateKey(&svrPubKey->u.ec.DEREncodedParams, + &pubKey, NULL); + if (!privKey || !pubKey) { + ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); + rv = SECFailure; + goto loser; + } + PRINT_BUF(50, (ss, "ECDH public value:", + pubKey->u.ec.publicValue.data, + pubKey->u.ec.publicValue.len)); + + if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH; + else target = CKM_SSL3_MASTER_KEY_DERIVE_DH; + + /* Determine the PMS */ + pms = PK11_PubDerive(privKey, svrPubKey, PR_FALSE, NULL, NULL, + CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, NULL); + + if (pms == NULL) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto loser; + } + + SECKEY_DestroyPrivateKey(privKey); + privKey = NULL; + + rv = ssl3_InitPendingCipherSpec(ss, pms); + PK11_FreeSymKey(pms); pms = NULL; + + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + goto loser; + } + + rv = ssl3_AppendHandshakeHeader(ss, client_key_exchange, + pubKey->u.ec.publicValue.len + 1); + if (rv != SECSuccess) { + goto loser; /* err set by ssl3_AppendHandshake* */ + } + + rv = ssl3_AppendHandshakeVariable(ss, + pubKey->u.ec.publicValue.data, + pubKey->u.ec.publicValue.len, 1); + SECKEY_DestroyPublicKey(pubKey); + pubKey = NULL; + + if (rv != SECSuccess) { + goto loser; /* err set by ssl3_AppendHandshake* */ + } + + rv = SECSuccess; + +loser: + if(pms) PK11_FreeSymKey(pms); + if(privKey) SECKEY_DestroyPrivateKey(privKey); + if(pubKey) SECKEY_DestroyPublicKey(pubKey); + return rv; +} +#endif /* NSS_ENABLE_ECC */ + /* fortezza client-auth portion of ClientKeyExchange message * This function appends the KEA public key from the client's V3 cert * (empty for a V1 cert) to the outgoing ClientKeyExchange message. @@ -3856,7 +4230,7 @@ ssl3_SendClientKeyExchange(sslSocket *ss) } ss->sec.keaType = ss->ssl3->hs.kea_def->exchKeyType; - ss->sec.keaKeyBits = SECKEY_PublicKeyStrength(serverKey) * BPB; + ss->sec.keaKeyBits = SECKEY_PublicKeyStrengthInBits(serverKey); switch (ss->ssl3->hs.kea_def->exchKeyType) { case kt_rsa: @@ -3871,6 +4245,12 @@ ssl3_SendClientKeyExchange(sslSocket *ss) rv = sendDHClientKeyExchange(ss, serverKey); break; +#ifdef NSS_ENABLE_ECC + case kt_ecdh: + rv = sendECDHClientKeyExchange(ss, serverKey); + break; +#endif /* NSS_ENABLE_ECC */ + default: /* got an unknown or unsupported Key Exchange Algorithm. */ SEND_ALERT @@ -4246,6 +4626,10 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) SECItem dh_g = {siBuffer, NULL, 0}; SECItem dh_Ys = {siBuffer, NULL, 0}; SSL3Hashes hashes; +#ifdef NSS_ENABLE_ECC + SECItem ec_params = {siBuffer, NULL, 0}; + SECItem ec_point = {siBuffer, NULL, 0}; +#endif /* NSS_ENABLE_ECC */ SSL_TRC(3, ("%d: SSL3[%d]: handle server_key_exchange handshake", SSL_GETPID(), ss->fd)); @@ -4427,6 +4811,116 @@ ssl3_HandleServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ss->ssl3->hs.ws = wait_cert_request; return SECSuccess; +#ifdef NSS_ENABLE_ECC + case kt_ecdh: + /* XXX This works only for named curves, revisit this when + * we support generic curves. + */ + ec_params.len = 2; + ec_params.data = (unsigned char*)PORT_Alloc(ec_params.len); + rv = ssl3_ConsumeHandshake(ss, ec_params.data, ec_params.len, &b, &length); + if (rv != SECSuccess) { + goto loser; /* malformed. */ + } + + /* Fail if the curve is not a named curve */ + if ((ec_params.data[0] != ec_type_named) || + !supportedCurve(ec_params.data[1])) { + errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE; + desc = handshake_failure; + goto alert_loser; + } + + rv = ssl3_ConsumeHandshakeVariable(ss, &ec_point, 1, &b, &length); + if (rv != SECSuccess) { + goto loser; /* malformed. */ + } + /* Fail if the ec point uses compressed representation */ + if (ec_point.data[0] != EC_POINT_FORM_UNCOMPRESSED) { + errCode = SEC_ERROR_UNSUPPORTED_EC_POINT_FORM; + desc = handshake_failure; + goto alert_loser; + } + + rv = ssl3_ConsumeHandshakeVariable(ss, &signature, 2, &b, &length); + if (rv != SECSuccess) { + goto loser; /* malformed. */ + } + + if (length != 0) { + if (isTLS) + desc = decode_error; + goto alert_loser; /* malformed. */ + } + + PRINT_BUF(60, (NULL, "Server EC params", ec_params.data, + ec_params.len)); + PRINT_BUF(60, (NULL, "Server EC point", ec_point.data, ec_point.len)); + + /* failures after this point are not malformed handshakes. */ + /* TLS: send decrypt_error if signature failed. */ + desc = isTLS ? decrypt_error : handshake_failure; + + /* + * check to make sure the hash is signed by right guy + */ + rv = ssl3_ComputeECDHKeyHash(ec_params, ec_point, + &ss->ssl3->hs.client_random, + &ss->ssl3->hs.server_random, &hashes); + + if (rv != SECSuccess) { + errCode = + ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); + goto alert_loser; + } + rv = ssl3_VerifySignedHashes(&hashes, ss->sec.peerCert, &signature, + isTLS, ss->pkcs11PinArg); + if (rv != SECSuccess) { + errCode = + ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); + goto alert_loser; + } + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + goto no_memory; + } + + ss->sec.peerKey = peerKey = PORT_ArenaZNew(arena, SECKEYPublicKey); + if (peerKey == NULL) { + goto no_memory; + } + + peerKey->arena = arena; + peerKey->keyType = ecKey; + + /* set up EC parameters in peerKey */ + if (ecName2params(arena, ec_params.data[1], + &peerKey->u.ec.DEREncodedParams) != SECSuccess) { + /* we should never get here since we already + * checked that we are dealing with a supported curve + */ + errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE; + goto alert_loser; + } + + /* copy publicValue in peerKey */ + if (SECITEM_CopyItem(arena, &peerKey->u.ec.publicValue, &ec_point)) + { + PORT_FreeArena(arena, PR_FALSE); + goto no_memory; + } + peerKey->pkcs11Slot = NULL; + peerKey->pkcs11ID = CK_INVALID_HANDLE; + + ss->sec.peerKey = peerKey; + SECITEM_FreeItem(&ec_params, PR_FALSE); + SECITEM_FreeItem(&ec_point, PR_FALSE); + ss->ssl3->hs.ws = wait_cert_request; + + return SECSuccess; +#endif /* NSS_ENABLE_ECC */ + case kt_fortezza: /* Fortezza needs *BOTH* a server cert message @@ -4462,6 +4956,10 @@ loser: if (dh_p.data != NULL) SECITEM_FreeItem(&dh_p, PR_FALSE); if (dh_g.data != NULL) SECITEM_FreeItem(&dh_g, PR_FALSE); if (dh_Ys.data != NULL) SECITEM_FreeItem(&dh_Ys, PR_FALSE); +#ifdef NSS_ENABLE_ECC + if (ec_params.data != NULL) SECITEM_FreeItem(&ec_params, PR_FALSE); + if (ec_point.data != NULL) SECITEM_FreeItem(&ec_point, PR_FALSE); +#endif /* NSS_ENABLE_ECC */ PORT_SetError( errCode ); return SECFailure; @@ -4469,6 +4967,13 @@ no_memory: /* no-memory error has already been set. */ if (modulus.data != NULL) SECITEM_FreeItem(&modulus, PR_FALSE); if (exponent.data != NULL) SECITEM_FreeItem(&exponent, PR_FALSE); if (signature.data != NULL) SECITEM_FreeItem(&signature, PR_FALSE); + if (dh_p.data != NULL) SECITEM_FreeItem(&dh_p, PR_FALSE); + if (dh_g.data != NULL) SECITEM_FreeItem(&dh_g, PR_FALSE); + if (dh_Ys.data != NULL) SECITEM_FreeItem(&dh_Ys, PR_FALSE); +#ifdef NSS_ENABLE_ECC + if (ec_params.data != NULL) SECITEM_FreeItem(&ec_params, PR_FALSE); + if (ec_point.data != NULL) SECITEM_FreeItem(&ec_point, PR_FALSE); +#endif /* NSS_ENABLE_ECC */ ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); return SECFailure; } @@ -4913,6 +5418,14 @@ ssl3_SendServerHelloSequence(sslSocket *ss) return rv; #endif } +#ifdef NSS_ENABLE_ECC + } else if ((kea_def->kea == kea_ecdhe_rsa) || + (kea_def->kea == kea_ecdhe_ecdsa)) { + rv = ssl3_SendServerKeyExchange(ss); + if (rv != SECSuccess) { + return rv; /* err code was set. */ + } +#endif /* NSS_ENABLE_ECC */ } if (ss->requestCertificate) { @@ -5619,6 +6132,11 @@ const ssl3KEADef * kea_def = ss->ssl3->hs.kea_def; SECItem signed_hash = {siBuffer, NULL, 0}; SSL3Hashes hashes; SECKEYPublicKey * sdPub; /* public key for step-down */ +#ifdef NSS_ENABLE_ECC + SECKEYPublicKey * ecdhePub; + SECItem ec_params = {siBuffer, NULL, 0}; + ECName curve; +#endif /* NSS_ENABLE_ECC */ SSL_TRC(3, ("%d: SSL3[%d]: send server_key_exchange handshake", SSL_GETPID(), ss->fd)); @@ -5707,6 +6225,90 @@ const ssl3KEADef * kea_def = ss->ssl3->hs.kea_def; } return SECSuccess; +#ifdef NSS_ENABLE_ECC + case kt_ecdh: + /* Generate ephemeral ECDH key pair and send the public key */ + rv = ssl3_CreateECDHEphemeralKeys(ss); + if (rv != SECSuccess) { + goto loser; /* err set by AppendHandshake. */ + } + ecdhePub = ss->ephemeralECDHKeyPair->pubKey; + PORT_Assert(ecdhePub != NULL); + if (!ecdhePub) { + PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); + return SECFailure; + } + + ec_params.len = 2; + ec_params.data = (unsigned char*)PORT_Alloc(ec_params.len); + curve = params2ecName(&ecdhePub->u.ec.DEREncodedParams); + if (curve != ec_noName) { + ec_params.data[0] = ec_type_named; + ec_params.data[1] = curve; + } else { + PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); + goto loser; + } + + rv = ssl3_ComputeECDHKeyHash(ec_params, ecdhePub->u.ec.publicValue, + &ss->ssl3->hs.client_random, + &ss->ssl3->hs.server_random, + &hashes); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); + goto loser; + } + + isTLS = (PRBool)(ss->ssl3->pwSpec->version > SSL_LIBRARY_VERSION_3_0); + + /* XXX SSLKEAType isn't really a good choice for + * indexing certificates. The following line of + * code will need to change when we support + * (EC)DHE-xxx ciphers on the server side where xxx + * is something other than RSA. + */ + rv = ssl3_SignHashes(&hashes, ss->serverCerts[kt_rsa].serverKey, + &signed_hash, isTLS); + if (rv != SECSuccess) { + goto loser; /* ssl3_SignHashes has set err. */ + } + if (signed_hash.data == NULL) { + /* how can this happen and rv == SECSuccess ?? */ + PORT_SetError(SSL_ERROR_SERVER_KEY_EXCHANGE_FAILURE); + goto loser; + } + + length = ec_params.len + + 1 + ecdhePub->u.ec.publicValue.len + + 2 + signed_hash.len; + + rv = ssl3_AppendHandshakeHeader(ss, server_key_exchange, length); + if (rv != SECSuccess) { + goto loser; /* err set by AppendHandshake. */ + } + + rv = ssl3_AppendHandshake(ss, ec_params.data, ec_params.len); + if (rv != SECSuccess) { + goto loser; /* err set by AppendHandshake. */ + } + + rv = ssl3_AppendHandshakeVariable(ss, ecdhePub->u.ec.publicValue.data, + ecdhePub->u.ec.publicValue.len, 1); + if (rv != SECSuccess) { + goto loser; /* err set by AppendHandshake. */ + } + + rv = ssl3_AppendHandshakeVariable(ss, signed_hash.data, + signed_hash.len, 2); + if (rv != SECSuccess) { + goto loser; /* err set by AppendHandshake. */ + } + + PORT_Free(ec_params.data); + PORT_Free(signed_hash.data); + return SECSuccess; +#endif /* NSS_ENABLE_ECC */ + case kt_dh: case kt_null: default: @@ -5714,6 +6316,10 @@ const ssl3KEADef * kea_def = ss->ssl3->hs.kea_def; break; } loser: +#ifdef NSS_ENABLE_ECC + if (ec_params.data != NULL) + PORT_Free(ec_params.data); +#endif /* NSS_ENABLE_ECC */ if (signed_hash.data != NULL) PORT_Free(signed_hash.data); return SECFailure; @@ -6268,6 +6874,65 @@ ssl3_HandleRSAClientKeyExchange(sslSocket *ss, return SECSuccess; } +#ifdef NSS_ENABLE_ECC +/* +** Called from ssl3_HandleClientKeyExchange() +*/ +static SECStatus +ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b, + PRUint32 length, + SECKEYPublicKey *srvrPubKey, + SECKEYPrivateKey *srvrPrivKey) +{ + PK11SymKey * pms; + SECStatus rv; + SECKEYPublicKey clntPubKey; + CK_MECHANISM_TYPE target; + PRBool isTLS; + + PORT_Assert( ssl_HaveRecvBufLock(ss) ); + PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); + + clntPubKey.keyType = ecKey; + clntPubKey.u.ec.DEREncodedParams.len = + srvrPubKey->u.ec.DEREncodedParams.len; + clntPubKey.u.ec.DEREncodedParams.data = + srvrPubKey->u.ec.DEREncodedParams.data; + + rv = ssl3_ConsumeHandshakeVariable(ss, &clntPubKey.u.ec.publicValue, + 1, &b, &length); + if (rv != SECSuccess) { + SEND_ALERT + return SECFailure; /* XXX Who sets the error code?? */ + } + + isTLS = (PRBool)(ss->ssl3->prSpec->version > SSL_LIBRARY_VERSION_3_0); + + if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH; + else target = CKM_SSL3_MASTER_KEY_DERIVE_DH; + + /* Determine the PMS */ + pms = PK11_PubDerive(srvrPrivKey, &clntPubKey, PR_FALSE, NULL, NULL, + CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, NULL); + + PORT_Free(clntPubKey.u.ec.publicValue.data); + + if (pms == NULL) { + /* last gasp. */ + ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); + return SECFailure; + } + + rv = ssl3_InitPendingCipherSpec(ss, pms); + PK11_FreeSymKey(pms); + if (rv != SECSuccess) { + SEND_ALERT + return SECFailure; /* error code set by ssl3_InitPendingCipherSpec */ + } + return SECSuccess; +} +#endif /* NSS_ENABLE_ECC */ + /* Called from ssl3_HandleHandshakeMessage() when it has deciphered a complete * ssl3 ClientKeyExchange message from the remote client * Caller must hold Handshake and RecvBuf locks. @@ -6293,6 +6958,23 @@ const ssl3KEADef * kea_def; kea_def = ss->ssl3->hs.kea_def; +#ifdef NSS_ENABLE_ECC + /* XXX We'll need additional code here to compute serverKey and + * ss->sec.keaKeyBits appropriately when we add server side + * support for (EC)DHE-xxx cipher suites where xxx is something + * other than rsa. Using SSLKEAType to index server certifiates + * does not work for (EC)DHE ciphers. + */ + if ((kea_def->kea == kea_ecdhe_rsa) || + (kea_def->kea == kea_ecdhe_ecdsa)) { + if (ss->ephemeralECDHKeyPair != NULL) { + serverKey = ss->ephemeralECDHKeyPair->privKey; + ss->sec.keaKeyBits = + SECKEY_PublicKeyStrengthInBits(ss->ephemeralECDHKeyPair->pubKey); + } + } else { +#endif /* NSS_ENABLE_ECC */ + serverKey = (ss->ssl3->hs.usedStepDownKey #ifdef DEBUG && kea_def->is_limited /* XXX OR cert is signing only */ @@ -6317,6 +6999,10 @@ const ssl3KEADef * kea_def; ss->sec.keaKeyBits = sc->serverKeyBits; } +#ifdef NSS_ENABLE_ECC + } +#endif /* NSS_ENABLE_ECC */ + if (serverKey == NULL) { SEND_ALERT PORT_SetError(SSL_ERROR_NO_SERVER_KEY_FOR_ALG); @@ -6341,6 +7027,17 @@ const ssl3KEADef * kea_def; } break; +#ifdef NSS_ENABLE_ECC + case kt_ecdh: + rv = ssl3_HandleECDHClientKeyExchange(ss, b, length, + ss->ephemeralECDHKeyPair->pubKey, + serverKey); + if (rv != SECSuccess) { + return SECFailure; /* error code set */ + } + break; +#endif /* NSS_ENABLE_ECC */ + default: (void) ssl3_HandshakeFailure(ss); PORT_SetError(SEC_ERROR_UNSUPPORTED_KEYALG); @@ -6375,6 +7072,7 @@ ssl3_SendCertificate(sslSocket *ss) CERTCertificateList *certChain; int len = 0; int i; + SSL3KEAType certIndex; SSL_TRC(3, ("%d: SSL3[%d]: send certificate handshake", SSL_GETPID(), ss->fd)); @@ -6385,9 +7083,24 @@ ssl3_SendCertificate(sslSocket *ss) if (ss->sec.localCert) CERT_DestroyCertificate(ss->sec.localCert); if (ss->sec.isServer) { - sslServerCerts * sc = - ss->serverCerts + ss->ssl3->hs.kea_def->exchKeyType; - certChain = sc->serverCertChain; + sslServerCerts * sc = NULL; + + /* XXX SSLKEAType isn't really a good choice for + * indexing certificates (it breaks when we deal + * with (EC)DHE-* cipher suites. This hack ensures + * the RSA cert is picked for (EC)DHE-RSA. + * Revisit this when we add server side support + * for ECDHE-ECDSA or client-side authentication + * using EC certificates. + */ + if ((ss->ssl3->hs.kea_def->kea == kea_ecdhe_rsa) || + (ss->ssl3->hs.kea_def->kea == kea_dhe_rsa)) { + certIndex = kt_rsa; + } else { + certIndex = ss->ssl3->hs.kea_def->exchKeyType; + } + sc = ss->serverCerts + certIndex; + certChain = sc->serverCertChain; ss->sec.authKeyBits = sc->serverKeyBits; ss->sec.authAlgorithm = ss->ssl3->hs.kea_def->signKeyType; ss->sec.localCert = CERT_DupCertificate(sc->serverCert); @@ -6655,7 +7368,34 @@ ssl3_HandleCertificate(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ss->sec.keaType = ssl3->hs.kea_def->exchKeyType; if (pubKey) { ss->sec.keaKeyBits = ss->sec.authKeyBits = - SECKEY_PublicKeyStrength(pubKey) * BPB; + SECKEY_PublicKeyStrengthInBits(pubKey); +#ifdef NSS_ENABLE_ECC + if (ss->sec.keaType == kt_ecdh) { + /* Get authKeyBits from signing key. + * XXX The code below uses a quick approximation of + * key size based on cert->signatureWrap.signature.data + * (which contains the DER encoded signature). The field + * cert->signatureWrap.signature.len contains the + * length of the encoded signature in bits. + */ + if (ss->ssl3->hs.kea_def->kea == kea_ecdh_ecdsa) { + ss->sec.authKeyBits = + cert->signatureWrap.signature.data[3]*8; + if (cert->signatureWrap.signature.data[4] == 0x00) + ss->sec.authKeyBits -= 8; + /* + * XXX: if cert is not signed by ecdsa we should + * destroy pubKey and goto bad_cert + */ + } else if (ss->ssl3->hs.kea_def->kea == kea_ecdh_rsa) { + ss->sec.authKeyBits = cert->signatureWrap.signature.len; + /* + * XXX: if cert is not signed by rsa we should + * destroy pubKey and goto bad_cert + */ + } + } +#endif /* NSS_ENABLE_ECC */ SECKEY_DestroyPublicKey(pubKey); pubKey = NULL; } @@ -6671,6 +7411,10 @@ cert_block: if (ssl3->hs.kea_def->is_limited || /* XXX OR server cert is signing only. */ ssl3->hs.kea_def->kea == kea_fortezza || +#ifdef NSS_ENABLE_ECC + ssl3->hs.kea_def->kea == kea_ecdhe_ecdsa || + ssl3->hs.kea_def->kea == kea_ecdhe_rsa || +#endif /* NSS_ENABLE_ECC */ ssl3->hs.kea_def->exchKeyType == kt_dh) { ssl3->hs.ws = wait_server_key; /* allow server_key_exchange */ } @@ -6906,6 +7650,7 @@ ssl3_HandleFinished(sslSocket *ss, SSL3Opaque *b, PRUint32 length, PRBool isTLS; PRBool doStepUp; CK_MECHANISM_TYPE mechanism; + SSL3KEAType effectiveExchKeyType; PORT_Assert( ssl_HaveRecvBufLock(ss) ); PORT_Assert( ssl_HaveSSL3HandshakeLock(ss) ); @@ -6996,13 +7741,19 @@ xmit_loser: ss->gs.writeOffset = 0; ss->gs.readOffset = 0; + if (ssl3->hs.kea_def->kea == kea_ecdhe_rsa) { + effectiveExchKeyType = kt_rsa; + } else { + effectiveExchKeyType = ssl3->hs.kea_def->exchKeyType; + } + if (sid->cached == never_cached) { /* fill in the sid */ sid->u.ssl3.cipherSuite = ssl3->hs.cipher_suite; sid->u.ssl3.compression = ssl3->hs.compression; sid->u.ssl3.policy = ssl3->policy; - sid->u.ssl3.exchKeyType = ssl3->hs.kea_def->exchKeyType; + sid->u.ssl3.exchKeyType = effectiveExchKeyType; sid->version = ss->version; sid->authAlgorithm = ss->sec.authAlgorithm; sid->authKeyBits = ss->sec.authKeyBits; @@ -7059,7 +7810,7 @@ xmit_loser: mechanism = PK11_GetBestWrapMechanism(symKeySlot); if (mechanism != CKM_INVALID_MECHANISM) { wrappingKey = - getWrappingKey(ss, symKeySlot, ssl3->hs.kea_def->exchKeyType, + getWrappingKey(ss, symKeySlot, effectiveExchKeyType, mechanism, pwArg); if (wrappingKey) { mechanism = PK11_GetMechanism(wrappingKey); /* can't fail. */ @@ -7800,6 +8551,40 @@ ssl3_CreateRSAStepDownKeys(sslSocket *ss) return rv; } +#ifdef NSS_ENABLE_ECC +/* + * Creates the ephemeral public and private ECDH keys used by + * server in ECDHE_RSA and ECDHE_ECDSA handshakes. + * XXX For now, the elliptic curve is hardcoded to NIST P-224. + * We need an API to specify the curve. This won't be a real + * issue until we further develop server-side support for ECC + * cipher suites. + */ +SECStatus +ssl3_CreateECDHEphemeralKeys(sslSocket *ss) +{ + SECStatus rv = SECSuccess; + SECKEYPrivateKey * privKey; + SECKEYPublicKey * pubKey; + SECKEYECParams ecParams = { siBuffer, NULL, 0 }; + + if (ss->ephemeralECDHKeyPair) + ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair); + ss->ephemeralECDHKeyPair = NULL; + + if (ecName2params(NULL, ec_secp224r1, &ecParams) == SECFailure) + return SECFailure; + privKey = SECKEY_CreateECPrivateKey(&ecParams, &pubKey, NULL); + if (!privKey || !pubKey || + !(ss->ephemeralECDHKeyPair = ssl3_NewKeyPair(privKey, pubKey))) { + ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); + rv = SECFailure; + } + + PORT_Free(ecParams.data); + return rv; +} +#endif /* NSS_ENABLE_ECC */ /* record the export policy for this cipher suite */ SECStatus diff --git a/security/nss/lib/ssl/ssl3prot.h b/security/nss/lib/ssl/ssl3prot.h index 46718aa126cc..8a9e3dd67918 100644 --- a/security/nss/lib/ssl/ssl3prot.h +++ b/security/nss/lib/ssl/ssl3prot.h @@ -19,7 +19,11 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -33,7 +37,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: ssl3prot.h,v 1.2 2001/09/18 01:59:19 nelsonb%netscape.com Exp $ + * $Id: ssl3prot.h,v 1.3 2003/02/27 01:31:30 nelsonb%netscape.com Exp $ */ #ifndef __ssl3proto_h_ @@ -203,7 +207,11 @@ typedef enum { kea_dh_anon, kea_dh_anon_export, kea_fortezza, - kea_rsa_fips + kea_rsa_fips, + kea_ecdh_ecdsa, + kea_ecdhe_ecdsa, + kea_ecdh_rsa, + kea_ecdhe_rsa } SSL3KeyExchangeAlgorithm; typedef struct { diff --git a/security/nss/lib/ssl/sslcon.c b/security/nss/lib/ssl/sslcon.c index 2ab1d11b697c..3f879d6993c2 100644 --- a/security/nss/lib/ssl/sslcon.c +++ b/security/nss/lib/ssl/sslcon.c @@ -18,7 +18,11 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -32,7 +36,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: sslcon.c,v 1.19 2002/02/27 04:40:15 nelsonb%netscape.com Exp $ + * $Id: sslcon.c,v 1.20 2003/02/27 01:31:30 nelsonb%netscape.com Exp $ */ #include "nssrenam.h" @@ -2061,7 +2065,7 @@ ssl2_ClientSetupSessionCypher(sslSocket *ss, PRUint8 *cs, int csLen) ss->sec.authAlgorithm = ssl_sign_rsa; ss->sec.keaType = ssl_kea_rsa; ss->sec.keaKeyBits = \ - ss->sec.authKeyBits = SECKEY_PublicKeyStrength(serverKey) * BPB; + ss->sec.authKeyBits = SECKEY_PublicKeyStrengthInBits(serverKey); /* Choose a compatible cipher with the server */ nc = csLen / 3; diff --git a/security/nss/lib/ssl/sslenum.c b/security/nss/lib/ssl/sslenum.c index 73293532628d..86ed6e37e084 100644 --- a/security/nss/lib/ssl/sslenum.c +++ b/security/nss/lib/ssl/sslenum.c @@ -19,8 +19,12 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * - * Contributor(s): + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): * Dr Stephen Henson + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -34,7 +38,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: sslenum.c,v 1.6 2002/08/09 21:53:17 nelsonb%netscape.com Exp $ + * $Id: sslenum.c,v 1.7 2003/02/27 01:31:32 nelsonb%netscape.com Exp $ */ #include "ssl.h" @@ -45,13 +49,27 @@ const PRUint16 SSL_ImplementedCiphers[] = { /* 256-bit */ TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, +#ifdef NSS_ENABLE_ECC + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, +#endif /* NSS_ENABLE_ECC */ TLS_RSA_WITH_AES_256_CBC_SHA, /* 128-bit */ SSL_FORTEZZA_DMS_WITH_RC4_128_SHA, +#ifdef NSS_ENABLE_ECC + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, +#endif /* NSS_ENABLE_ECC */ TLS_DHE_DSS_WITH_RC4_128_SHA, TLS_DHE_RSA_WITH_AES_128_CBC_SHA, TLS_DHE_DSS_WITH_AES_128_CBC_SHA, +#ifdef NSS_ENABLE_ECC + TLS_ECDH_RSA_WITH_RC4_128_SHA, + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, + TLS_ECDH_ECDSA_WITH_RC4_128_SHA, + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, +#endif /* NSS_ENABLE_ECC */ SSL_RSA_WITH_RC4_128_MD5, SSL_RSA_WITH_RC4_128_SHA, TLS_RSA_WITH_AES_128_CBC_SHA, @@ -59,6 +77,10 @@ const PRUint16 SSL_ImplementedCiphers[] = { /* 112-bit 3DES */ SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, +#ifdef NSS_ENABLE_ECC + TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, +#endif /* NSS_ENABLE_ECC */ SSL_RSA_FIPS_WITH_3DES_EDE_CBC_SHA, SSL_RSA_WITH_3DES_EDE_CBC_SHA, @@ -68,6 +90,10 @@ const PRUint16 SSL_ImplementedCiphers[] = { /* 56-bit DES "domestic" cipher suites */ SSL_DHE_RSA_WITH_DES_CBC_SHA, SSL_DHE_DSS_WITH_DES_CBC_SHA, +#ifdef NSS_ENABLE_ECC + TLS_ECDH_RSA_WITH_DES_CBC_SHA, + TLS_ECDH_ECDSA_WITH_DES_CBC_SHA, +#endif /* NSS_ENABLE_ECC */ SSL_RSA_FIPS_WITH_DES_CBC_SHA, SSL_RSA_WITH_DES_CBC_SHA, @@ -81,6 +107,10 @@ const PRUint16 SSL_ImplementedCiphers[] = { /* ciphersuites with no encryption */ SSL_FORTEZZA_DMS_WITH_NULL_SHA, +#ifdef NSS_ENABLE_ECC + TLS_ECDH_RSA_WITH_NULL_SHA, + TLS_ECDH_ECDSA_WITH_NULL_SHA, +#endif /* NSS_ENABLE_ECC */ SSL_RSA_WITH_NULL_SHA, SSL_RSA_WITH_NULL_MD5, diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h index 17f8ada5f5db..6d64bfa3053e 100644 --- a/security/nss/lib/ssl/sslimpl.h +++ b/security/nss/lib/ssl/sslimpl.h @@ -19,8 +19,12 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * - * Contributor(s): + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): * Dr Stephen Henson + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -34,7 +38,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: sslimpl.h,v 1.29 2003/02/15 01:21:24 relyea%netscape.com Exp $ + * $Id: sslimpl.h,v 1.30 2003/02/27 01:31:34 nelsonb%netscape.com Exp $ */ #ifndef __sslimpl_h_ @@ -72,6 +76,7 @@ typedef SSLSignType SSL3SignType; #define sign_null ssl_sign_null #define sign_rsa ssl_sign_rsa #define sign_dsa ssl_sign_dsa +#define sign_ecdsa ssl_sign_ecdsa #define calg_null ssl_calg_null #define calg_rc4 ssl_calg_rc4 @@ -254,7 +259,11 @@ typedef struct { #endif } ssl3CipherSuiteCfg; +#ifdef NSS_ENABLE_ECC +#define ssl_V3_SUITES_IMPLEMENTED 40 +#else #define ssl_V3_SUITES_IMPLEMENTED 26 +#endif /* NSS_ENABLE_ECC */ typedef struct sslOptionsStr { unsigned int useSecurity : 1; /* 1 */ @@ -972,7 +981,7 @@ const unsigned char * preferredCipher; sslHandshakingType handshaking; ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED]; - + ssl3KeyPair * ephemeralECDHKeyPair; /* for ECDHE-* handshake */ }; @@ -1181,6 +1190,10 @@ int ssl3_GatherCompleteHandshake(sslSocket *ss, int flags); */ extern SECStatus ssl3_CreateRSAStepDownKeys(sslSocket *ss); +#ifdef NSS_ENABLE_ECC +extern SECStatus ssl3_CreateECDHEphemeralKeys(sslSocket *ss); +#endif /* NSS_ENABLE_ECC */ + extern SECStatus ssl3_CipherPrefSetDefault(ssl3CipherSuite which, PRBool on); extern SECStatus ssl3_CipherPrefGetDefault(ssl3CipherSuite which, PRBool *on); extern SECStatus ssl2_CipherPrefSetDefault(PRInt32 which, PRBool enabled); diff --git a/security/nss/lib/ssl/sslinfo.c b/security/nss/lib/ssl/sslinfo.c index 858be7f4edf8..cfe058f2c291 100644 --- a/security/nss/lib/ssl/sslinfo.c +++ b/security/nss/lib/ssl/sslinfo.c @@ -16,7 +16,11 @@ * Copyright (C) 2001 Netscape Communications Corporation. All * Rights Reserved. * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -30,7 +34,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: sslinfo.c,v 1.5 2002/08/09 21:53:17 nelsonb%netscape.com Exp $ + * $Id: sslinfo.c,v 1.6 2003/02/27 01:31:34 nelsonb%netscape.com Exp $ */ #include "ssl.h" #include "sslimpl.h" @@ -106,10 +110,13 @@ SSL_GetChannelInfo(PRFileDesc *fd, SSLChannelInfo *info, PRUintn len) #define S_DSA "DSA", ssl_auth_dsa #define S_RSA "RSA", ssl_auth_rsa #define S_KEA "KEA", ssl_auth_kea +#define S_ECDSA "ECDSA", ssl_auth_ecdsa #define K_DHE "DHE", kt_dh #define K_RSA "RSA", kt_rsa #define K_KEA "KEA", kt_kea +#define K_ECDH "ECDH", kt_ecdh +#define K_ECDHE "ECDHE", kt_ecdh #define C_AES "AES", calg_aes #define C_RC4 "RC4", calg_rc4 @@ -164,6 +171,27 @@ static const SSLCipherSuiteInfo suiteInfo[] = { {0,CS(SSL_RSA_WITH_NULL_SHA), S_RSA, K_RSA, C_NULL,B_0, M_SHA, 0, 1, 0, }, {0,CS(SSL_RSA_WITH_NULL_MD5), S_RSA, K_RSA, C_NULL,B_0, M_MD5, 0, 1, 0, }, +#ifdef NSS_ENABLE_ECC +/* ECC cipher suites */ +{0,CS(TLS_ECDH_ECDSA_WITH_NULL_SHA), S_ECDSA, K_ECDH, C_NULL, B_0, M_SHA, 0, 0, 0, }, +{0,CS(TLS_ECDH_ECDSA_WITH_RC4_128_SHA), S_ECDSA, K_ECDH, C_RC4, B_128, M_SHA, 0, 0, 0, }, +{0,CS(TLS_ECDH_ECDSA_WITH_DES_CBC_SHA), S_ECDSA, K_ECDH, C_DES, B_DES, M_SHA, 0, 0, 0, }, +{0,CS(TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDH, C_3DES, B_3DES, M_SHA, 0, 0, 0, }, +{0,CS(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_128, M_SHA, 0, 0, 0, }, +{0,CS(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_256, M_SHA, 0, 0, 0, }, + +{0,CS(TLS_ECDH_RSA_WITH_NULL_SHA), S_RSA, K_ECDH, C_NULL, B_0, M_SHA, 0, 0, 0, }, +{0,CS(TLS_ECDH_RSA_WITH_RC4_128_SHA), S_RSA, K_ECDH, C_RC4, B_128, M_SHA, 0, 0, 0, }, +{0,CS(TLS_ECDH_RSA_WITH_DES_CBC_SHA), S_RSA, K_ECDH, C_DES, B_DES, M_SHA, 0, 0, 0, }, +{0,CS(TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_ECDH, C_3DES, B_3DES, M_SHA, 0, 0, 0, }, +{0,CS(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDH, C_AES, B_128, M_SHA, 0, 0, 0, }, +{0,CS(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_ECDH, C_AES, B_256, M_SHA, 0, 0, 0, }, + +{0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA, 0, 0, 0, }, + +{0,CS(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDHE, C_AES, B_128, M_SHA, 0, 0, 0, }, +#endif /* NSS_ENABLE_ECC */ + /* SSL 2 table */ {0,CK(SSL_CK_RC4_128_WITH_MD5), S_RSA, K_RSA, C_RC4, B_128, M_MD5, 0, 0, 0, }, {0,CK(SSL_CK_RC2_128_CBC_WITH_MD5), S_RSA, K_RSA, C_RC2, B_128, M_MD5, 0, 0, 0, }, diff --git a/security/nss/lib/ssl/sslproto.h b/security/nss/lib/ssl/sslproto.h index 6f60155d2b33..4946d90a175f 100644 --- a/security/nss/lib/ssl/sslproto.h +++ b/security/nss/lib/ssl/sslproto.h @@ -20,7 +20,11 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -34,7 +38,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: sslproto.h,v 1.3 2001/09/21 03:07:35 nelsonb%netscape.com Exp $ + * $Id: sslproto.h,v 1.4 2003/02/27 01:31:35 nelsonb%netscape.com Exp $ */ #ifndef __sslproto_h_ @@ -161,6 +165,29 @@ #define TLS_DHE_DSS_EXPORT1024_WITH_RC4_56_SHA 0x0065 #define TLS_DHE_DSS_WITH_RC4_128_SHA 0x0066 +#ifdef NSS_ENABLE_ECC +/* "Experimental" ECC cipher suites. +** XXX These numbers might change before the current IETF draft +** on ECC cipher suites for TLS becomes an RFC. +*/ +#define TLS_ECDH_ECDSA_WITH_NULL_SHA 0x0047 +#define TLS_ECDH_ECDSA_WITH_RC4_128_SHA 0x0048 +#define TLS_ECDH_ECDSA_WITH_DES_CBC_SHA 0x0049 +#define TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA 0x004A +#define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0x004B +#define TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0x004C + +#define TLS_ECDH_RSA_WITH_NULL_SHA 0x004D +#define TLS_ECDH_RSA_WITH_RC4_128_SHA 0x004E +#define TLS_ECDH_RSA_WITH_DES_CBC_SHA 0x004F +#define TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA 0x0050 +#define TLS_ECDH_RSA_WITH_AES_128_CBC_SHA 0x0051 +#define TLS_ECDH_RSA_WITH_AES_256_CBC_SHA 0x0052 + +#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0x0077 +#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 0x0078 +#endif /* NSS_ENABLE_ECC */ + /* Netscape "experimental" cipher suites. */ #define SSL_RSA_OLDFIPS_WITH_3DES_EDE_CBC_SHA 0xffe0 #define SSL_RSA_OLDFIPS_WITH_DES_CBC_SHA 0xffe1 diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c index adb8c26c7e8c..bee005ba8b7a 100644 --- a/security/nss/lib/ssl/sslsecur.c +++ b/security/nss/lib/ssl/sslsecur.c @@ -18,7 +18,11 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -32,7 +36,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: sslsecur.c,v 1.21 2003/02/15 01:21:25 relyea%netscape.com Exp $ + * $Id: sslsecur.c,v 1.22 2003/02/27 01:31:35 nelsonb%netscape.com Exp $ */ #include "cert.h" #include "secitem.h" @@ -639,7 +643,7 @@ SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert, pubKey = CERT_ExtractPublicKey(cert); if (!pubKey) goto loser; - sc->serverKeyBits = SECKEY_PublicKeyStrength(pubKey) * BPB; + sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(pubKey); SECKEY_DestroyPublicKey(pubKey); pubKey = NULL; } diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c index 3dce0f88be1e..7686b54346dc 100644 --- a/security/nss/lib/ssl/sslsock.c +++ b/security/nss/lib/ssl/sslsock.c @@ -20,8 +20,12 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * - * Contributor(s): + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * + * Contributor(s): * Dr Stephen Henson + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -35,7 +39,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: sslsock.c,v 1.30 2002/08/09 21:53:17 nelsonb%netscape.com Exp $ + * $Id: sslsock.c,v 1.31 2003/02/27 01:31:35 nelsonb%netscape.com Exp $ */ #include "seccomon.h" #include "cert.h" @@ -93,6 +97,22 @@ static cipherPolicy ssl_ciphers[] = { /* Export France */ { TLS_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, { TLS_RSA_EXPORT1024_WITH_DES_CBC_SHA, SSL_ALLOWED, SSL_NOT_ALLOWED }, { TLS_RSA_EXPORT1024_WITH_RC4_56_SHA, SSL_ALLOWED, SSL_NOT_ALLOWED }, +#ifdef NSS_ENABLE_ECC + { TLS_ECDH_ECDSA_WITH_NULL_SHA, SSL_ALLOWED, SSL_ALLOWED }, + { TLS_ECDH_ECDSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, + { TLS_ECDH_ECDSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, + { TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, + { TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, + { TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, + { TLS_ECDH_RSA_WITH_NULL_SHA, SSL_ALLOWED, SSL_ALLOWED }, + { TLS_ECDH_RSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, + { TLS_ECDH_RSA_WITH_DES_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, + { TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, + { TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, + { TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, + { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, + { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, +#endif /* NSS_ENABLE_ECC */ { 0, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED } }; diff --git a/security/nss/lib/ssl/sslt.h b/security/nss/lib/ssl/sslt.h index 0c98a19db4d2..f5b355a28aa8 100644 --- a/security/nss/lib/ssl/sslt.h +++ b/security/nss/lib/ssl/sslt.h @@ -18,7 +18,11 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -32,7 +36,7 @@ * may use your version of this file under either the MPL or the * GPL. * - * $Id: sslt.h,v 1.3 2002/03/22 21:43:43 nelsonb%netscape.com Exp $ + * $Id: sslt.h,v 1.4 2003/02/27 01:31:35 nelsonb%netscape.com Exp $ */ #ifndef __sslt_h_ @@ -63,6 +67,7 @@ typedef enum { ssl_kea_rsa = 1, ssl_kea_dh = 2, ssl_kea_fortezza = 3, + ssl_kea_ecdh = 4, ssl_kea_size /* number of ssl_kea_ algorithms */ } SSLKEAType; @@ -75,19 +80,22 @@ typedef enum { #define kt_rsa ssl_kea_rsa #define kt_dh ssl_kea_dh #define kt_fortezza ssl_kea_fortezza +#define kt_ecdh ssl_kea_ecdh #define kt_kea_size ssl_kea_size typedef enum { ssl_sign_null = 0, ssl_sign_rsa = 1, - ssl_sign_dsa = 2 + ssl_sign_dsa = 2, + ssl_sign_ecdsa = 3 } SSLSignType; typedef enum { ssl_auth_null = 0, ssl_auth_rsa = 1, ssl_auth_dsa = 2, - ssl_auth_kea = 3 + ssl_auth_kea = 3, + ssl_auth_ecdsa = 4 } SSLAuthType; typedef enum { diff --git a/security/nss/lib/util/secerr.h b/security/nss/lib/util/secerr.h index 1387292f24e4..e69449e7f5bb 100644 --- a/security/nss/lib/util/secerr.h +++ b/security/nss/lib/util/secerr.h @@ -185,7 +185,12 @@ SEC_ERROR_BAD_TEMPLATE = (SEC_ERROR_BASE + 136), SEC_ERROR_CRL_NOT_FOUND = (SEC_ERROR_BASE + 137), SEC_ERROR_REUSED_ISSUER_AND_SERIAL = (SEC_ERROR_BASE + 138), SEC_ERROR_BUSY = (SEC_ERROR_BASE + 139), -SEC_ERROR_EXTRA_INPUT = (SEC_ERROR_BASE + 140) +SEC_ERROR_EXTRA_INPUT = (SEC_ERROR_BASE + 140), +/* error codes used by elliptic curve code */ +SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE = (SEC_ERROR_BASE + 141), +SEC_ERROR_UNSUPPORTED_EC_POINT_FORM = (SEC_ERROR_BASE + 142), +SEC_ERROR_UNRECOGNIZED_OID = (SEC_ERROR_BASE + 143) + } SECErrorCodes; #endif /* NO_SECURITY_ERROR_ENUM */ diff --git a/security/nss/lib/util/secoid.c b/security/nss/lib/util/secoid.c index 9d28c484178c..3f36294501e1 100644 --- a/security/nss/lib/util/secoid.c +++ b/security/nss/lib/util/secoid.c @@ -16,7 +16,11 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -153,6 +157,14 @@ /* { 1.3.6.1.4.1.311 } */ #define MICROSOFT_OID 0x2b, 0x6, 0x1, 0x4, 0x1, 0x82, 0x37 +#define CERTICOM_OID 0x2b, 0x81, 0x04 +#define SECG_OID CERTICOM_OID, 0x00 + +#define ANSI_X962_OID 0x2a, 0x86, 0x48, 0xce, 0x3d +#define ANSI_X962_CURVE_OID ANSI_X962_OID, 0x03 +#define ANSI_X962_GF2m_OID ANSI_X962_CURVE_OID, 0x00 +#define ANSI_X962_GFp_OID ANSI_X962_CURVE_OID, 0x01 + #define CONST_OID static const unsigned char CONST_OID md2[] = { DIGEST, 0x02 }; @@ -425,6 +437,36 @@ CONST_OID sha256[] = { SHAXXX, 1 }; CONST_OID sha384[] = { SHAXXX, 2 }; CONST_OID sha512[] = { SHAXXX, 3 }; +CONST_OID ansix962ECPublicKey[] = { ANSI_X962_OID, 0x02, 0x01 }; +CONST_OID ansix962ECDSASignaturewithSHA1Digest[] = { ANSI_X962_OID, 0x04, 0x01 }; + +/* ANSI X9.62 prime curve OIDs */ +/* NOTE: prime192v1 is the same as secp192r1, prime256v1 is the + * same as secp256r1 + */ +CONST_OID ansiX962prime192v1[] = { ANSI_X962_GFp_OID, 0x01 }; +CONST_OID ansiX962prime192v2[] = { ANSI_X962_GFp_OID, 0x02 }; +CONST_OID ansiX962prime192v3[] = { ANSI_X962_GFp_OID, 0x03 }; +CONST_OID ansiX962prime239v1[] = { ANSI_X962_GFp_OID, 0x04 }; +CONST_OID ansiX962prime239v2[] = { ANSI_X962_GFp_OID, 0x05 }; +CONST_OID ansiX962prime239v3[] = { ANSI_X962_GFp_OID, 0x06 }; +CONST_OID ansiX962prime256v1[] = { ANSI_X962_GFp_OID, 0x07 }; + +/* SECG prime curve OIDs */ +CONST_OID secgECsecp112r1[] = { SECG_OID, 0x06 }; +CONST_OID secgECsecp112r2[] = { SECG_OID, 0x07 }; +CONST_OID secgECsecp128r1[] = { SECG_OID, 0x1c }; +CONST_OID secgECsecp128r2[] = { SECG_OID, 0x1d }; +CONST_OID secgECsecp160k1[] = { SECG_OID, 0x09 }; +CONST_OID secgECsecp160r1[] = { SECG_OID, 0x08 }; +CONST_OID secgECsecp160r2[] = { SECG_OID, 0x1e }; +CONST_OID secgECsecp192k1[] = { SECG_OID, 0x1f }; +CONST_OID secgECsecp224k1[] = { SECG_OID, 0x20 }; +CONST_OID secgECsecp224r1[] = { SECG_OID, 0x21 }; +CONST_OID secgECsecp256k1[] = { SECG_OID, 0x0a }; +CONST_OID secgECsecp384r1[] = { SECG_OID, 0x22 }; +CONST_OID secgECsecp521r1[] = { SECG_OID, 0x23 }; + #define OI(x) { siDEROID, (unsigned char *)x, sizeof x } #ifndef SECOID_NO_STRINGS #define OD(oid,tag,desc,mech,ext) { OI(oid), tag, desc, mech, ext } @@ -1046,6 +1088,101 @@ const static SECOidData oids[] = { OD( aes256_KEY_WRAP, SEC_OID_AES_256_KEY_WRAP, "AES-256 Key Wrap", CKM_NETSCAPE_AES_KEY_WRAP, INVALID_CERT_EXTENSION), + /* Elliptic Curve Cryptography (ECC) OIDs */ + OD( ansix962ECPublicKey, SEC_OID_ANSIX962_EC_PUBLIC_KEY, + "X9.62 elliptic curve public key", CKM_ECDH1_DERIVE, + INVALID_CERT_EXTENSION ), + OD( ansix962ECDSASignaturewithSHA1Digest, + SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST, + "X9.62 ECDSA signature with SHA1", CKM_ECDSA_SHA1, + INVALID_CERT_EXTENSION ), + + /* Named curves */ + + /* ANSI X9.62 named elliptic curves (prime field) */ + OD( ansiX962prime192v1, SEC_OID_ANSIX962_EC_PRIME192V1, + "ANSI X9.62 elliptic curve prime192v1 (aka secp192r1, NIST P-192)", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( ansiX962prime192v2, SEC_OID_ANSIX962_EC_PRIME192V2, + "ANSI X9.62 elliptic curve prime192v2", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( ansiX962prime192v3, SEC_OID_ANSIX962_EC_PRIME192V3, + "ANSI X9.62 elliptic curve prime192v3", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( ansiX962prime239v1, SEC_OID_ANSIX962_EC_PRIME239V1, + "ANSI X9.62 elliptic curve prime239v1", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( ansiX962prime239v2, SEC_OID_ANSIX962_EC_PRIME239V2, + "ANSI X9.62 elliptic curve prime239v2", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( ansiX962prime239v3, SEC_OID_ANSIX962_EC_PRIME239V3, + "ANSI X9.62 elliptic curve prime239v3", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( ansiX962prime256v1, SEC_OID_ANSIX962_EC_PRIME256V1, + "ANSI X9.62 elliptic curve prime256v1 (aka secp256r1, NIST P-256)", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + + /* SECG named elliptic curves (prime field) */ + OD( secgECsecp112r1, SEC_OID_SECG_EC_SECP112R1, + "SECG elliptic curve secp112r1", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( secgECsecp112r2, SEC_OID_SECG_EC_SECP112R2, + "SECG elliptic curve secp112r2", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( secgECsecp128r1, SEC_OID_SECG_EC_SECP128R1, + "SECG elliptic curve secp128r1", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( secgECsecp128r2, SEC_OID_SECG_EC_SECP128R2, + "SECG elliptic curve secp128r2", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( secgECsecp160k1, SEC_OID_SECG_EC_SECP160K1, + "SECG elliptic curve secp160k1", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( secgECsecp160r1, SEC_OID_SECG_EC_SECP160R1, + "SECG elliptic curve secp160r1", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( secgECsecp160r2, SEC_OID_SECG_EC_SECP160R2, + "SECG elliptic curve secp160r2", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( secgECsecp192k1, SEC_OID_SECG_EC_SECP192K1, + "SECG elliptic curve secp192k1", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( secgECsecp224k1, SEC_OID_SECG_EC_SECP224K1, + "SECG elliptic curve secp224k1", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( secgECsecp224r1, SEC_OID_SECG_EC_SECP224R1, + "SECG elliptic curve secp224r1 (aka NIST P-224)", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( secgECsecp256k1, SEC_OID_SECG_EC_SECP256K1, + "SECG elliptic curve secp256k1", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( secgECsecp384r1, SEC_OID_SECG_EC_SECP384R1, + "SECG elliptic curve secp384r1 (aka NIST P-384)", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( secgECsecp521r1, SEC_OID_SECG_EC_SECP521R1, + "SECG elliptic curve secp521r1 (aka NIST P-521)", + CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + }; /* diff --git a/security/nss/lib/util/secoidt.h b/security/nss/lib/util/secoidt.h index 0417292c646c..b3655b138db1 100644 --- a/security/nss/lib/util/secoidt.h +++ b/security/nss/lib/util/secoidt.h @@ -16,7 +16,11 @@ * Copyright (C) 1994-2000 Netscape Communications Corporation. All * Rights Reserved. * + * Portions created by Sun Microsystems, Inc. are Copyright (C) 2003 + * Sun Microsystems, Inc. All Rights Reserved. + * * Contributor(s): + * Dr Vipul Gupta , Sun Microsystems Laboratories * * Alternatively, the contents of this file may be used under the * terms of the GNU General Public License Version 2 or later (the @@ -36,7 +40,7 @@ /* * secoidt.h - public data structures for ASN.1 OID functions * - * $Id: secoidt.h,v 1.11 2003/01/22 04:35:54 nelsonb%netscape.com Exp $ + * $Id: secoidt.h,v 1.12 2003/02/27 01:31:38 nelsonb%netscape.com Exp $ */ #include "secitem.h" @@ -308,9 +312,42 @@ typedef enum { SEC_OID_AES_192_KEY_WRAP = 198, SEC_OID_AES_256_KEY_WRAP = 199, + /* Elliptic Curve Cryptography (ECC) OIDs */ + SEC_OID_ANSIX962_EC_PUBLIC_KEY = 200, + SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST = 201, + + /* ANSI X9.62 named elliptic curves (prime field) */ + SEC_OID_ANSIX962_EC_PRIME192V1 = 202, + SEC_OID_ANSIX962_EC_PRIME192V2 = 203, + SEC_OID_ANSIX962_EC_PRIME192V3 = 204, + SEC_OID_ANSIX962_EC_PRIME239V1 = 205, + SEC_OID_ANSIX962_EC_PRIME239V2 = 206, + SEC_OID_ANSIX962_EC_PRIME239V3 = 207, + SEC_OID_ANSIX962_EC_PRIME256V1 = 208, + + /* SECG named elliptic curves (prime field) */ + SEC_OID_SECG_EC_SECP112R1 = 209, + SEC_OID_SECG_EC_SECP112R2 = 210, + SEC_OID_SECG_EC_SECP128R1 = 211, + SEC_OID_SECG_EC_SECP128R2 = 212, + SEC_OID_SECG_EC_SECP160K1 = 213, + SEC_OID_SECG_EC_SECP160R1 = 214, + SEC_OID_SECG_EC_SECP160R2 = 215, + SEC_OID_SECG_EC_SECP192K1 = 216, + /* SEC_OID_SECG_EC_SECP192R1 is SEC_OID_ANSIX962_EC_PRIME192V1 */ + SEC_OID_SECG_EC_SECP224K1 = 217, + SEC_OID_SECG_EC_SECP224R1 = 218, + SEC_OID_SECG_EC_SECP256K1 = 219, + /* SEC_OID_SECG_EC_SECP256R1 is SEC_OID_ANSIX962_EC_PRIME256V1 */ + SEC_OID_SECG_EC_SECP384R1 = 220, + SEC_OID_SECG_EC_SECP521R1 = 221, + SEC_OID_TOTAL } SECOidTag; +#define SEC_OID_SECG_EC_SECP192R1 SEC_OID_ANSIX962_EC_PRIME192V1 +#define SEC_OID_SECG_EC_SECP256R1 SEC_OID_ANSIX962_EC_PRIME256V1 + /* fake OID for DSS sign/verify */ #define SEC_OID_SHA SEC_OID_MISS_DSS