diff options
author | wtchang%redhat.com <devnull@localhost> | 2006-05-15 17:45:58 +0000 |
---|---|---|
committer | wtchang%redhat.com <devnull@localhost> | 2006-05-15 17:45:58 +0000 |
commit | 617436e372f5b4ade30e234767bbf37401ea5e29 (patch) | |
tree | cd0adaa279514e5a56b4e8bbb1f7f6ae5dec35b1 /security/nss/lib | |
parent | 089f031e67a4cb9eb888d5fbf3c06af1e8c7456b (diff) | |
download | nss-hg-617436e372f5b4ade30e234767bbf37401ea5e29.tar.gz |
Bugzilla Bug 337770: upgraded the NSS version on the MOZILLA_1_8_BRANCH to
a stable snapshot of NSS_3_11_BRANCH (NSS_3_11_20050512_TAG, NSS 3.11.2
pre-release). a=wtc for branch-1.8.1.
Tag: MOZILLA_1_8_BRANCH
Diffstat (limited to 'security/nss/lib')
128 files changed, 7381 insertions, 4960 deletions
diff --git a/security/nss/lib/certdb/certdb.c b/security/nss/lib/certdb/certdb.c index 9c5c22f31..f710db899 100644 --- a/security/nss/lib/certdb/certdb.c +++ b/security/nss/lib/certdb/certdb.c @@ -864,8 +864,7 @@ CERT_DecodeDERCertificate(SECItem *derSignedCert, PRBool copyDER, } if (cert_HasUnknownCriticalExten (cert->extensions) == PR_TRUE) { - PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION); - goto loser; + cert->options.bits.hasUnsupportedCriticalExt = PR_TRUE; } /* generate and save the database key for the cert */ diff --git a/security/nss/lib/certdb/certt.h b/security/nss/lib/certdb/certt.h index 8567ebbe4..b50ad6e5c 100644 --- a/security/nss/lib/certdb/certt.h +++ b/security/nss/lib/certdb/certt.h @@ -301,7 +301,13 @@ struct CERTCertificateStr { * XXX - these should be moved into some sort of application specific * data structure. They are only used by the browser right now. */ - struct SECSocketNode *authsocketlist; + union { + void* apointer; /* was struct SECSocketNode* authsocketlist */ + struct { + unsigned int hasUnsupportedCriticalExt :1; + /* add any new option bits needed here */ + } bits; + } options; int series; /* was int authsocketcount; record the series of the pkcs11ID */ /* This is PKCS #11 stuff. */ diff --git a/security/nss/lib/certdb/stanpcertdb.c b/security/nss/lib/certdb/stanpcertdb.c index 18e35b299..ae5c15a11 100644 --- a/security/nss/lib/certdb/stanpcertdb.c +++ b/security/nss/lib/certdb/stanpcertdb.c @@ -155,6 +155,9 @@ __CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname, NSSCryptoContext *context; nssCryptokiObject *permInstance; NSSCertificate *c = STAN_GetNSSCertificate(cert); + nssCertificateStoreTrace lockTrace = {NULL, NULL, PR_FALSE, PR_FALSE}; + nssCertificateStoreTrace unlockTrace = {NULL, NULL, PR_FALSE, PR_FALSE}; + context = c->object.cryptoContext; if (!context) { PORT_SetError(SEC_ERROR_ADDING_CERT); @@ -170,9 +173,10 @@ __CERT_AddTempCertToPerm(CERTCertificate *cert, char *nickname, stanNick = nssUTF8_Duplicate((NSSUTF8 *)nickname, c->object.arena); } /* Delete the temp instance */ - nssCertificateStore_Lock(context->certStore); + nssCertificateStore_Lock(context->certStore, &lockTrace); nssCertificateStore_RemoveCertLOCKED(context->certStore, c); - nssCertificateStore_Unlock(context->certStore); + nssCertificateStore_Unlock(context->certStore, &lockTrace, &unlockTrace); + nssCertificateStore_Check(&lockTrace, &unlockTrace); c->object.cryptoContext = NULL; /* Import the perm instance onto the internal token */ slot = PK11_GetInternalKeySlot(); diff --git a/security/nss/lib/certhigh/certhigh.c b/security/nss/lib/certhigh/certhigh.c index 2c0ffe7cb..a101ca4c8 100644 --- a/security/nss/lib/certhigh/certhigh.c +++ b/security/nss/lib/certhigh/certhigh.c @@ -720,11 +720,9 @@ CERT_FindCertByNameString(CERTCertDBHandle *handle, char *nameStr) if ( name ) { nameItem = SEC_ASN1EncodeItem (arena, NULL, (void *)name, CERT_NameTemplate); - if ( nameItem == NULL ) { - goto loser; + if ( nameItem != NULL ) { + cert = CERT_FindCertByName(handle, nameItem); } - - cert = CERT_FindCertByName(handle, nameItem); CERT_DestroyName(name); } diff --git a/security/nss/lib/certhigh/certvfy.c b/security/nss/lib/certhigh/certvfy.c index 25d0eaf42..e55ede89d 100644 --- a/security/nss/lib/certhigh/certvfy.c +++ b/security/nss/lib/certhigh/certvfy.c @@ -101,7 +101,6 @@ CERT_VerifySignedDataWithPublicKey(CERTSignedData *sd, void *wincx) { SECStatus rv; - SECOidTag algid; SECItem sig; if ( !pubKey || !sd ) { @@ -114,9 +113,8 @@ CERT_VerifySignedDataWithPublicKey(CERTSignedData *sd, /* convert sig->len from bit counts to byte count. */ DER_ConvertBitString(&sig); - algid = SECOID_GetAlgorithmTag(&sd->signatureAlgorithm); - rv = VFY_VerifyData(sd->data.data, sd->data.len, pubKey, &sig, - algid, wincx); + rv = VFY_VerifyDataWithAlgorithmID(sd->data.data, sd->data.len, pubKey, + &sig, &sd->signatureAlgorithm, NULL, wincx); return rv ? SECFailure : SECSuccess; } @@ -362,20 +360,20 @@ loser: chain, 2, NULL, &status, td, cc); nss_ZFreeIf(nssTime); if (status == PR_SUCCESS) { + PORT_Assert(me == chain[0]); /* if it's a root, the chain will only have one cert */ if (!chain[1]) { /* already has a reference from the call to BuildChain */ return cert; - } else { - CERT_DestroyCertificate(cert); /* the first cert in the chain */ - return STAN_GetCERTCertificate(chain[1]); /* return the 2nd */ - } - } else { - if (chain[0]) { - CERT_DestroyCertificate(cert); - } - PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER); - } + } + NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */ + return STAN_GetCERTCertificate(chain[1]); /* return the 2nd */ + } + if (chain[0]) { + PORT_Assert(me == chain[0]); + NSSCertificate_Destroy(chain[0]); /* the first cert in the chain */ + } + PORT_SetError (SEC_ERROR_UNKNOWN_ISSUER); return NULL; #endif } @@ -729,6 +727,13 @@ cert_VerifyCertChain(CERTCertDBHandle *handle, CERTCertificate *cert, namesCount += subjectNameListLen; namesList = cert_CombineNamesLists(namesList, subjectNameList); } + + /* check if the cert has an unsupported critical extension */ + if ( subjectCert->options.bits.hasUnsupportedCriticalExt ) { + PORT_SetError(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION); + LOG_ERROR_OR_EXIT(log,subjectCert,count,0); + } + /* find the certificate of the issuer */ issuerCert = CERT_FindCertIssuer(subjectCert, t, certUsage); if ( ! issuerCert ) { diff --git a/security/nss/lib/certhigh/ocsp.c b/security/nss/lib/certhigh/ocsp.c index 53f2c3e13..c271c1866 100644 --- a/security/nss/lib/certhigh/ocsp.c +++ b/security/nss/lib/certhigh/ocsp.c @@ -2678,9 +2678,9 @@ ocsp_CheckSignature(ocspSignature *signature, void *tbs, */ DER_ConvertBitString(&rawSignature); - rv = VFY_VerifyData(encodedTBS->data, encodedTBS->len, signerKey, - &rawSignature, - SECOID_GetAlgorithmTag(&signature->signatureAlgorithm), + rv = VFY_VerifyDataWithAlgorithmID(encodedTBS->data, encodedTBS->len, + signerKey, &rawSignature, + &signature->signatureAlgorithm, NULL, pwArg); finish: diff --git a/security/nss/lib/ckfw/builtins/constants.c b/security/nss/lib/ckfw/builtins/constants.c index a4a8bc7c7..6cc62c0e8 100644 --- a/security/nss/lib/ckfw/builtins/constants.c +++ b/security/nss/lib/ckfw/builtins/constants.c @@ -62,7 +62,7 @@ nss_builtins_CryptokiVersion = { NSS_BUILTINS_CRYPTOKI_VERSION_MINOR }; NSS_IMPLEMENT_DATA const NSSUTF8 * -nss_builtins_ManufacturerID = (NSSUTF8 *) "Netscape Communications Corp."; +nss_builtins_ManufacturerID = (NSSUTF8 *) "Mozilla Foundation"; NSS_IMPLEMENT_DATA const NSSUTF8 * nss_builtins_LibraryDescription = (NSSUTF8 *) "NSS Builtin Object Cryptoki Module"; diff --git a/security/nss/lib/ckfw/builtins/nssckbi.rc b/security/nss/lib/ckfw/builtins/nssckbi.rc index 1ff4fa9c1..2d30b880c 100644 --- a/security/nss/lib/ckfw/builtins/nssckbi.rc +++ b/security/nss/lib/ckfw/builtins/nssckbi.rc @@ -80,11 +80,10 @@ BEGIN BEGIN BLOCK "040904B0" // Lang=US English, CharSet=Unicode BEGIN - VALUE "CompanyName", "Netscape Communications Corporation\0" + VALUE "CompanyName", "Mozilla Foundation\0" VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0" VALUE "FileVersion", NSS_BUILTINS_LIBRARY_VERSION "\0" VALUE "InternalName", MY_INTERNAL_NAME "\0" - VALUE "LegalCopyright", "Copyright \251 1994-2001 Netscape Communications Corporation\0" VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0" VALUE "ProductName", "Network Security Services\0" VALUE "ProductVersion", NSS_BUILTINS_LIBRARY_VERSION "\0" diff --git a/security/nss/lib/ckfw/capi/nsscapi.rc b/security/nss/lib/ckfw/capi/nsscapi.rc index d5024f7a6..254599f75 100644 --- a/security/nss/lib/ckfw/capi/nsscapi.rc +++ b/security/nss/lib/ckfw/capi/nsscapi.rc @@ -84,7 +84,6 @@ BEGIN VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0" VALUE "FileVersion", NSS_CKCAPI_LIBRARY_VERSION "\0" VALUE "InternalName", MY_INTERNAL_NAME "\0" - VALUE "LegalCopyright", "Copyright \251 1994-2005 Netscape Communications Corporation\0" VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0" VALUE "ProductName", "Network Security Services\0" VALUE "ProductVersion", NSS_CKCAPI_LIBRARY_VERSION "\0" diff --git a/security/nss/lib/ckfw/dbm/instance.c b/security/nss/lib/ckfw/dbm/instance.c index 3afc23efb..f1fced615 100644 --- a/security/nss/lib/ckfw/dbm/instance.c +++ b/security/nss/lib/ckfw/dbm/instance.c @@ -122,7 +122,7 @@ nss_dbm_mdInstance_GetManufacturerID CK_RV *pError ) { - return "Netscape Communications Corp."; + return "Mozilla Foundation"; } static NSSUTF8 * diff --git a/security/nss/lib/ckfw/find.c b/security/nss/lib/ckfw/find.c index fe9345b42..747c79ef9 100644 --- a/security/nss/lib/ckfw/find.c +++ b/security/nss/lib/ckfw/find.c @@ -176,22 +176,24 @@ nssCKFWFindObjects_Create return fwFindObjects; loser: - nss_ZFreeIf(fwFindObjects); - - if( (NSSCKMDFindObjects *)NULL != mdFindObjects1 ) { - if( (void *)NULL != (void *)mdFindObjects1->Final ) { - fwFindObjects->mdFindObjects = mdFindObjects1; - mdFindObjects1->Final(mdFindObjects1, fwFindObjects, mdSession, - fwSession, mdToken, fwToken, mdInstance, fwInstance); + if( fwFindObjects ) { + if( NULL != mdFindObjects1 ) { + if( NULL != mdFindObjects1->Final ) { + fwFindObjects->mdFindObjects = mdFindObjects1; + mdFindObjects1->Final(mdFindObjects1, fwFindObjects, mdSession, + fwSession, mdToken, fwToken, mdInstance, fwInstance); + } } - } - if( (NSSCKMDFindObjects *)NULL != mdFindObjects2 ) { - if( (void *)NULL != (void *)mdFindObjects2->Final ) { - fwFindObjects->mdFindObjects = mdFindObjects2; - mdFindObjects2->Final(mdFindObjects2, fwFindObjects, mdSession, - fwSession, mdToken, fwToken, mdInstance, fwInstance); + if( NULL != mdFindObjects2 ) { + if( NULL != mdFindObjects2->Final ) { + fwFindObjects->mdFindObjects = mdFindObjects2; + mdFindObjects2->Final(mdFindObjects2, fwFindObjects, mdSession, + fwSession, mdToken, fwToken, mdInstance, fwInstance); + } } + + nss_ZFreeIf(fwFindObjects); } if( CKR_OK == *pError ) { diff --git a/security/nss/lib/ckfw/session.c b/security/nss/lib/ckfw/session.c index b2a85d75c..2b020d77e 100644 --- a/security/nss/lib/ckfw/session.c +++ b/security/nss/lib/ckfw/session.c @@ -234,7 +234,7 @@ nssCKFWSession_Create loser: if( (NSSArena *)NULL != arena ) { - if( (nssCKFWHash *)NULL != fwSession->sessionObjectHash ) { + if( fwSession && (nssCKFWHash *)NULL != fwSession->sessionObjectHash ) { (void)nssCKFWHash_Destroy(fwSession->sessionObjectHash); } NSSArena_Destroy(arena); diff --git a/security/nss/lib/crmf/crmf.h b/security/nss/lib/crmf/crmf.h index d09163ae1..315100702 100644 --- a/security/nss/lib/crmf/crmf.h +++ b/security/nss/lib/crmf/crmf.h @@ -208,7 +208,7 @@ extern SECStatus CRMF_CertReqMsgSetCertRequest(CRMFCertReqMsg *inCertReqMsg, * A pointer to the new Certificate Request. A NULL return value * indicates an error in creating the Certificate Request. */ -extern CRMFCertRequest *CRMF_CreateCertRequest (long inRequestID); +extern CRMFCertRequest *CRMF_CreateCertRequest (PRUint32 inRequestID); /* * FUNCTION: CRMF_DestroyCertRequest diff --git a/security/nss/lib/crmf/crmfcont.c b/security/nss/lib/crmf/crmfcont.c index b609e84ea..f2cab57b3 100644 --- a/security/nss/lib/crmf/crmfcont.c +++ b/security/nss/lib/crmf/crmfcont.c @@ -148,21 +148,27 @@ crmf_destroy_encrypted_value(CRMFEncryptedValue *inEncrValue, PRBool freeit) if (inEncrValue != NULL) { if (inEncrValue->intendedAlg) { SECOID_DestroyAlgorithmID(inEncrValue->intendedAlg, PR_TRUE); + inEncrValue->intendedAlg = NULL; } if (inEncrValue->symmAlg) { SECOID_DestroyAlgorithmID(inEncrValue->symmAlg, PR_TRUE); + inEncrValue->symmAlg = NULL; } if (inEncrValue->encSymmKey.data) { PORT_Free(inEncrValue->encSymmKey.data); + inEncrValue->encSymmKey.data = NULL; } if (inEncrValue->keyAlg) { SECOID_DestroyAlgorithmID(inEncrValue->keyAlg, PR_TRUE); + inEncrValue->keyAlg = NULL; } if (inEncrValue->valueHint.data) { PORT_Free(inEncrValue->valueHint.data); + inEncrValue->valueHint.data = NULL; } if (inEncrValue->encValue.data) { PORT_Free(inEncrValue->encValue.data); + inEncrValue->encValue.data = NULL; } if (freeit) { PORT_Free(inEncrValue); @@ -183,15 +189,24 @@ crmf_copy_encryptedvalue_secalg(PRArenaPool *poolp, SECAlgorithmID **destAlgId) { SECAlgorithmID *newAlgId; + SECStatus rv; - *destAlgId = newAlgId = (poolp != NULL) ? - PORT_ArenaZNew(poolp, SECAlgorithmID) : - PORT_ZNew(SECAlgorithmID); + newAlgId = (poolp != NULL) ? PORT_ArenaZNew(poolp, SECAlgorithmID) : + PORT_ZNew(SECAlgorithmID); if (newAlgId == NULL) { return SECFailure; } - return SECOID_CopyAlgorithmID(poolp, newAlgId, srcAlgId); + rv = SECOID_CopyAlgorithmID(poolp, newAlgId, srcAlgId); + if (rv != SECSuccess) { + if (!poolp) { + SECOID_DestroyAlgorithmID(newAlgId, PR_TRUE); + } + return rv; + } + *destAlgId = newAlgId; + + return rv; } SECStatus @@ -252,7 +267,7 @@ crmf_copy_encryptedvalue(PRArenaPool *poolp, return SECSuccess; loser: if (poolp == NULL && destValue != NULL) { - crmf_destroy_encrypted_value(destValue, PR_TRUE); + crmf_destroy_encrypted_value(destValue, PR_FALSE); } return SECFailure; } diff --git a/security/nss/lib/crmf/crmfit.h b/security/nss/lib/crmf/crmfit.h index 1edde840b..2f9be4946 100644 --- a/security/nss/lib/crmf/crmfit.h +++ b/security/nss/lib/crmf/crmfit.h @@ -140,7 +140,7 @@ struct CRMFCertRequestStr { * are not part of the encoding. */ PRArenaPool *poolp; - long requestID; /* This is the value that will be encoded into + PRUint32 requestID; /* This is the value that will be encoded into * the certReqId field. */ }; diff --git a/security/nss/lib/crmf/crmfpop.c b/security/nss/lib/crmf/crmfpop.c index e105a90a8..b5a4883ed 100644 --- a/security/nss/lib/crmf/crmfpop.c +++ b/security/nss/lib/crmf/crmfpop.c @@ -94,35 +94,14 @@ CRMF_CertReqMsgSetRAVerifiedPOP(CRMFCertReqMsg *inCertReqMsg) } SECOidTag -crmf_map_keytag_to_signtag(SECOidTag inTag) -{ - switch (inTag) { - case SEC_OID_PKCS1_RSA_ENCRYPTION: - return SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; - case SEC_OID_ANSIX9_DSA_SIGNATURE: - case SEC_OID_MISSI_KEA_DSS: - case SEC_OID_MISSI_DSS: - return SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; - default: - /* Put this in here to kill warnings. */ - break; - } - return inTag; -} - -SECOidTag crmf_get_key_sign_tag(SECKEYPublicKey *inPubKey) { - CERTSubjectPublicKeyInfo *spki; - SECOidTag tag; - - spki = SECKEY_CreateSubjectPublicKeyInfo(inPubKey); - if (spki == NULL) { - return SEC_OID_UNKNOWN; + /* maintain backward compatibility with older + * implementations */ + if (inPubKey->keyType == rsaKey) { + return SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION; } - tag = SECOID_GetAlgorithmTag(&spki->algorithm); - SECKEY_DestroySubjectPublicKeyInfo(spki); - return crmf_map_keytag_to_signtag(tag); + return SEC_GetSignatureAlgorithmOidTag(inPubKey->keyType, SEC_OID_UNKNOWN); } SECAlgorithmID* diff --git a/security/nss/lib/crmf/crmfreq.c b/security/nss/lib/crmf/crmfreq.c index b4e06bc32..73a0548b9 100644 --- a/security/nss/lib/crmf/crmfreq.c +++ b/security/nss/lib/crmf/crmfreq.c @@ -63,6 +63,20 @@ crmf_encode_integer(PRArenaPool *poolp, SECItem *dest, long value) return SECSuccess; } +SECStatus +crmf_encode_unsigned_integer(PRArenaPool *poolp, SECItem *dest, + unsigned long value) +{ + SECItem *dummy; + + dummy = SEC_ASN1EncodeUnsignedInteger(poolp, dest, value); + PORT_Assert (dummy == dest); + if (dummy != dest) { + return SECFailure; + } + return SECSuccess; +} + static SECStatus crmf_copy_secitem (PRArenaPool *poolp, SECItem *dest, SECItem *src) { @@ -104,7 +118,8 @@ CRMF_DoesRequestHaveField (CRMFCertRequest *inCertReq, } CRMFCertRequest * -CRMF_CreateCertRequest (long inRequestID) { +CRMF_CreateCertRequest (PRUint32 inRequestID) +{ PRArenaPool *poolp; CRMFCertRequest *certReq; SECStatus rv; @@ -122,7 +137,8 @@ CRMF_CreateCertRequest (long inRequestID) { certReq->poolp = poolp; certReq->requestID = inRequestID; - rv = crmf_encode_integer(poolp, &(certReq->certReqId), inRequestID); + rv = crmf_encode_unsigned_integer(poolp, &(certReq->certReqId), + inRequestID); if (rv != SECSuccess) { goto loser; } @@ -177,9 +193,12 @@ crmf_template_copy_secalg (PRArenaPool *poolp, SECAlgorithmID **dest, void *mark = NULL; SECAlgorithmID *mySecAlg; - if (poolp != NULL) { - mark = PORT_ArenaMark(poolp); + if (!poolp) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; } + + mark = PORT_ArenaMark(poolp); *dest = mySecAlg = PORT_ArenaZNew(poolp, SECAlgorithmID); if (mySecAlg == NULL) { goto loser; diff --git a/security/nss/lib/crmf/respcmn.c b/security/nss/lib/crmf/respcmn.c index 153ecee51..54fbb3faf 100644 --- a/security/nss/lib/crmf/respcmn.c +++ b/security/nss/lib/crmf/respcmn.c @@ -46,12 +46,15 @@ cmmf_DestroyPKIStatusInfo (CMMFPKIStatusInfo *info, PRBool freeit) { if (info->status.data != NULL) { PORT_Free(info->status.data); + info->status.data = NULL; } if (info->statusString.data != NULL) { PORT_Free(info->statusString.data); + info->statusString.data = NULL; } if (info->failInfo.data != NULL) { PORT_Free(info->failInfo.data); + info->failInfo.data = NULL; } if (freeit) { PORT_Free(info); @@ -232,6 +235,7 @@ cmmf_DestroyCertOrEncCert(CMMFCertOrEncCert *certOrEncCert, PRBool freeit) case cmmfEncryptedCert: crmf_destroy_encrypted_value(certOrEncCert->cert.encryptedCert, PR_TRUE); + certOrEncCert->cert.encryptedCert = NULL; break; default: break; @@ -292,17 +296,22 @@ cmmf_CopyCertResponse(PRArenaPool *poolp, return rv; } if (src->certifiedKeyPair != NULL) { - dest->certifiedKeyPair = (poolp == NULL) ? - PORT_ZNew(CMMFCertifiedKeyPair) : - PORT_ArenaZNew(poolp, CMMFCertifiedKeyPair); - if (dest->certifiedKeyPair == NULL) { + CMMFCertifiedKeyPair *destKeyPair; + + destKeyPair = (poolp == NULL) ? PORT_ZNew(CMMFCertifiedKeyPair) : + PORT_ArenaZNew(poolp, CMMFCertifiedKeyPair); + if (!destKeyPair) { return SECFailure; } - rv = cmmf_CopyCertifiedKeyPair(poolp, dest->certifiedKeyPair, + rv = cmmf_CopyCertifiedKeyPair(poolp, destKeyPair, src->certifiedKeyPair); if (rv != SECSuccess) { + if (!poolp) { + CMMF_DestroyCertifiedKeyPair(destKeyPair); + } return rv; } + dest->certifiedKeyPair = destKeyPair; } return SECSuccess; } @@ -321,16 +330,19 @@ cmmf_CopyCertOrEncCert(PRArenaPool *poolp, CMMFCertOrEncCert *dest, dest->cert.certificate = CERT_DupCertificate(src->cert.certificate); break; case cmmfEncryptedCert: - dest->cert.encryptedCert = encVal = (poolp == NULL) ? - PORT_ZNew(CRMFEncryptedValue) : - PORT_ArenaZNew(poolp, CRMFEncryptedValue); + encVal = (poolp == NULL) ? PORT_ZNew(CRMFEncryptedValue) : + PORT_ArenaZNew(poolp, CRMFEncryptedValue); if (encVal == NULL) { return SECFailure; } rv = crmf_copy_encryptedvalue(poolp, src->cert.encryptedCert, encVal); if (rv != SECSuccess) { + if (!poolp) { + crmf_destroy_encrypted_value(encVal, PR_TRUE); + } return rv; } + dest->cert.encryptedCert = encVal; break; default: rv = SECFailure; @@ -351,19 +363,22 @@ cmmf_CopyCertifiedKeyPair(PRArenaPool *poolp, CMMFCertifiedKeyPair *dest, } if (src->privateKey != NULL) { - CRMFEncryptedValue *encVal; + CRMFEncryptedValue *encVal; - encVal = dest->privateKey = (poolp == NULL) ? - PORT_ZNew(CRMFEncryptedValue) : - PORT_ArenaZNew(poolp, CRMFEncryptedValue); + encVal = (poolp == NULL) ? PORT_ZNew(CRMFEncryptedValue) : + PORT_ArenaZNew(poolp, CRMFEncryptedValue); if (encVal == NULL) { return SECFailure; } - rv = crmf_copy_encryptedvalue(poolp, src->privateKey, - dest->privateKey); + rv = crmf_copy_encryptedvalue(poolp, src->privateKey, + encVal); if (rv != SECSuccess) { + if (!poolp) { + crmf_destroy_encrypted_value(encVal, PR_TRUE); + } return rv; } + dest->privateKey = encVal; } rv = cmmf_copy_secitem(poolp, &dest->derPublicationInfo, &src->derPublicationInfo); diff --git a/security/nss/lib/cryptohi/cryptohi.h b/security/nss/lib/cryptohi/cryptohi.h index 0cc700703..5897a3a6b 100644 --- a/security/nss/lib/cryptohi/cryptohi.h +++ b/security/nss/lib/cryptohi/cryptohi.h @@ -269,6 +269,25 @@ extern SECStatus VFY_VerifyData(unsigned char *buf, int len, SECKEYPublicKey *key, SECItem *sig, SECOidTag algid, void *wincx); +/* + * NOTE: This function is private in NSS 3.11.x +** Verify the signature on a block of data. +** "buf" the input data +** "len" the length of the input data +** "key" the public key to check the signature with +** "sig" the encrypted signature data +** "algid" specifies the signing algorithm and parameters to use. +** This must match the key type. +** "reserved" must be NULL in this version. +** "wincx" void pointer to the window context +*/ +extern SECStatus VFY_VerifyDataWithAlgorithmID(const unsigned char *buf, + int len, const SECKEYPublicKey *key, + const SECItem *sig, + const SECAlgorithmID *algid, + SECOidTag *reserved, + void *wincx); + SEC_END_PROTOS diff --git a/security/nss/lib/cryptohi/keyhi.h b/security/nss/lib/cryptohi/keyhi.h index 8707c3d1d..9a35bead8 100644 --- a/security/nss/lib/cryptohi/keyhi.h +++ b/security/nss/lib/cryptohi/keyhi.h @@ -283,8 +283,24 @@ SECKEY_AddPublicKeyToListTail( SECKEYPublicKeyList *list, #define PUBKEY_LIST_NEXT(n) ((SECKEYPublicKeyListNode *)n->links.next) #define PUBKEY_LIST_END(n,l) (((void *)n) == ((void *)&l->list)) +/* + * Length in bits of the EC's field size. This is also the length of + * the x and y coordinates of EC points, such as EC public keys and + * base points. + * + * Return 0 on failure (unknown EC domain parameters). + */ extern int SECKEY_ECParamsToKeySize(const SECItem *params); +/* + * Length in bits of the EC base point order, usually denoted n. This + * is also the length of EC private keys and ECDSA signature components + * r and s. + * + * Return 0 on failure (unknown EC domain parameters). + */ +extern int SECKEY_ECParamsToBasePointOrderLen(const SECItem *params); + SEC_END_PROTOS #endif /* _KEYHI_H_ */ diff --git a/security/nss/lib/cryptohi/seckey.c b/security/nss/lib/cryptohi/seckey.c index 97f79d99e..d2bd046e1 100644 --- a/security/nss/lib/cryptohi/seckey.c +++ b/security/nss/lib/cryptohi/seckey.c @@ -1288,6 +1288,152 @@ SECKEY_ECParamsToKeySize(const SECItem *encodedParams) } } +int +SECKEY_ECParamsToBasePointOrderLen(const 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_SECG_EC_SECP112R1: + return 112; + case SEC_OID_SECG_EC_SECP112R2: + return 110; + + case SEC_OID_SECG_EC_SECT113R1: + case SEC_OID_SECG_EC_SECT113R2: + return 113; + + case SEC_OID_SECG_EC_SECP128R1: + return 128; + case SEC_OID_SECG_EC_SECP128R2: + return 126; + + case SEC_OID_SECG_EC_SECT131R1: + case SEC_OID_SECG_EC_SECT131R2: + return 131; + + case SEC_OID_SECG_EC_SECP160K1: + case SEC_OID_SECG_EC_SECP160R1: + case SEC_OID_SECG_EC_SECP160R2: + return 161; + + case SEC_OID_SECG_EC_SECT163K1: + return 163; + case SEC_OID_SECG_EC_SECT163R1: + return 162; + case SEC_OID_SECG_EC_SECT163R2: + case SEC_OID_ANSIX962_EC_C2PNB163V1: + return 163; + case SEC_OID_ANSIX962_EC_C2PNB163V2: + case SEC_OID_ANSIX962_EC_C2PNB163V3: + return 162; + + case SEC_OID_ANSIX962_EC_C2PNB176V1: + return 161; + + case SEC_OID_ANSIX962_EC_C2TNB191V1: + return 191; + case SEC_OID_ANSIX962_EC_C2TNB191V2: + return 190; + case SEC_OID_ANSIX962_EC_C2TNB191V3: + return 189; + case SEC_OID_ANSIX962_EC_C2ONB191V4: + return 191; + case SEC_OID_ANSIX962_EC_C2ONB191V5: + return 188; + + case SEC_OID_SECG_EC_SECP192K1: + case SEC_OID_ANSIX962_EC_PRIME192V1: + case SEC_OID_ANSIX962_EC_PRIME192V2: + case SEC_OID_ANSIX962_EC_PRIME192V3: + return 192; + + case SEC_OID_SECG_EC_SECT193R1: + case SEC_OID_SECG_EC_SECT193R2: + return 193; + + case SEC_OID_ANSIX962_EC_C2PNB208W1: + return 193; + + case SEC_OID_SECG_EC_SECP224K1: + return 225; + case SEC_OID_SECG_EC_SECP224R1: + return 224; + + case SEC_OID_SECG_EC_SECT233K1: + return 232; + case SEC_OID_SECG_EC_SECT233R1: + return 233; + + case SEC_OID_SECG_EC_SECT239K1: + case SEC_OID_ANSIX962_EC_C2TNB239V1: + return 238; + case SEC_OID_ANSIX962_EC_C2TNB239V2: + return 237; + case SEC_OID_ANSIX962_EC_C2TNB239V3: + return 236; + case SEC_OID_ANSIX962_EC_C2ONB239V4: + return 238; + case SEC_OID_ANSIX962_EC_C2ONB239V5: + return 237; + case SEC_OID_ANSIX962_EC_PRIME239V1: + case SEC_OID_ANSIX962_EC_PRIME239V2: + case SEC_OID_ANSIX962_EC_PRIME239V3: + return 239; + + case SEC_OID_SECG_EC_SECP256K1: + case SEC_OID_ANSIX962_EC_PRIME256V1: + return 256; + + case SEC_OID_ANSIX962_EC_C2PNB272W1: + return 257; + + case SEC_OID_SECG_EC_SECT283K1: + return 281; + case SEC_OID_SECG_EC_SECT283R1: + return 282; + + case SEC_OID_ANSIX962_EC_C2PNB304W1: + return 289; + + case SEC_OID_ANSIX962_EC_C2TNB359V1: + return 353; + + case SEC_OID_ANSIX962_EC_C2PNB368W1: + return 353; + + case SEC_OID_SECG_EC_SECP384R1: + return 384; + + case SEC_OID_SECG_EC_SECT409K1: + return 407; + case SEC_OID_SECG_EC_SECT409R1: + return 409; + + case SEC_OID_ANSIX962_EC_C2TNB431R1: + return 418; + + case SEC_OID_SECG_EC_SECP521R1: + return 521; + + case SEC_OID_SECG_EC_SECT571K1: + case SEC_OID_SECG_EC_SECT571R1: + return 570; + + default: + return 0; + } +} + /* returns key strength in bytes (not bits) */ unsigned SECKEY_PublicKeyStrength(SECKEYPublicKey *pubk) @@ -1352,13 +1498,13 @@ SECKEY_CopyPrivateKey(SECKEYPrivateKey *privk) SECKEYPrivateKey *copyk; PRArenaPool *arena; - if (privk == NULL) { + if (!privk || !privk->pkcs11Slot) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) { - PORT_SetError (SEC_ERROR_NO_MEMORY); return NULL; } @@ -1397,7 +1543,8 @@ SECKEY_CopyPublicKey(SECKEYPublicKey *pubk) { SECKEYPublicKey *copyk; PRArenaPool *arena; - + SECStatus rv = SECSuccess; + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (arena == NULL) { PORT_SetError (SEC_ERROR_NO_MEMORY); @@ -1405,119 +1552,117 @@ SECKEY_CopyPublicKey(SECKEYPublicKey *pubk) } copyk = (SECKEYPublicKey *) PORT_ArenaZAlloc (arena, sizeof (SECKEYPublicKey)); - if (copyk != NULL) { - SECStatus rv = SECSuccess; - - copyk->arena = arena; - copyk->keyType = pubk->keyType; - if (pubk->pkcs11Slot && - PK11_IsPermObject(pubk->pkcs11Slot,pubk->pkcs11ID)) { - copyk->pkcs11Slot = PK11_ReferenceSlot(pubk->pkcs11Slot); - copyk->pkcs11ID = pubk->pkcs11ID; - } else { - copyk->pkcs11Slot = NULL; /* go get own reference */ - copyk->pkcs11ID = CK_INVALID_HANDLE; - } - switch (pubk->keyType) { - case rsaKey: - rv = SECITEM_CopyItem(arena, ©k->u.rsa.modulus, - &pubk->u.rsa.modulus); - if (rv == SECSuccess) { - rv = SECITEM_CopyItem (arena, ©k->u.rsa.publicExponent, - &pubk->u.rsa.publicExponent); - if (rv == SECSuccess) - return copyk; - } - break; - case dsaKey: - rv = SECITEM_CopyItem(arena, ©k->u.dsa.publicValue, - &pubk->u.dsa.publicValue); - if (rv != SECSuccess) break; - rv = SECITEM_CopyItem(arena, ©k->u.dsa.params.prime, - &pubk->u.dsa.params.prime); - if (rv != SECSuccess) break; - rv = SECITEM_CopyItem(arena, ©k->u.dsa.params.subPrime, - &pubk->u.dsa.params.subPrime); - if (rv != SECSuccess) break; - rv = SECITEM_CopyItem(arena, ©k->u.dsa.params.base, - &pubk->u.dsa.params.base); - break; - case keaKey: - rv = SECITEM_CopyItem(arena, ©k->u.kea.publicValue, - &pubk->u.kea.publicValue); - if (rv != SECSuccess) break; - rv = SECITEM_CopyItem(arena, ©k->u.kea.params.hash, - &pubk->u.kea.params.hash); - break; - case fortezzaKey: - copyk->u.fortezza.KEAversion = pubk->u.fortezza.KEAversion; - copyk->u.fortezza.DSSversion = pubk->u.fortezza.DSSversion; - PORT_Memcpy(copyk->u.fortezza.KMID, pubk->u.fortezza.KMID, - sizeof(pubk->u.fortezza.KMID)); - rv = SECITEM_CopyItem(arena, ©k->u.fortezza.clearance, - &pubk->u.fortezza.clearance); - if (rv != SECSuccess) break; - rv = SECITEM_CopyItem(arena, ©k->u.fortezza.KEApriviledge, - &pubk->u.fortezza.KEApriviledge); - if (rv != SECSuccess) break; - rv = SECITEM_CopyItem(arena, ©k->u.fortezza.DSSpriviledge, - &pubk->u.fortezza.DSSpriviledge); - if (rv != SECSuccess) break; - rv = SECITEM_CopyItem(arena, ©k->u.fortezza.KEAKey, - &pubk->u.fortezza.KEAKey); - if (rv != SECSuccess) break; - rv = SECITEM_CopyItem(arena, ©k->u.fortezza.DSSKey, - &pubk->u.fortezza.DSSKey); - if (rv != SECSuccess) break; - rv = SECITEM_CopyItem(arena, ©k->u.fortezza.params.prime, - &pubk->u.fortezza.params.prime); - if (rv != SECSuccess) break; - rv = SECITEM_CopyItem(arena, ©k->u.fortezza.params.subPrime, - &pubk->u.fortezza.params.subPrime); - if (rv != SECSuccess) break; - rv = SECITEM_CopyItem(arena, ©k->u.fortezza.params.base, - &pubk->u.fortezza.params.base); - if (rv != SECSuccess) break; - rv = SECITEM_CopyItem(arena, ©k->u.fortezza.keaParams.prime, - &pubk->u.fortezza.keaParams.prime); - if (rv != SECSuccess) break; - rv = SECITEM_CopyItem(arena, ©k->u.fortezza.keaParams.subPrime, - &pubk->u.fortezza.keaParams.subPrime); - if (rv != SECSuccess) break; - rv = SECITEM_CopyItem(arena, ©k->u.fortezza.keaParams.base, - &pubk->u.fortezza.keaParams.base); - break; - case dhKey: - rv = SECITEM_CopyItem(arena,©k->u.dh.prime,&pubk->u.dh.prime); - if (rv != SECSuccess) break; - rv = SECITEM_CopyItem(arena,©k->u.dh.base,&pubk->u.dh.base); - if (rv != SECSuccess) break; - rv = SECITEM_CopyItem(arena, ©k->u.dh.publicValue, - &pubk->u.dh.publicValue); - break; - 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; - case nullKey: - return copyk; - default: - rv = SECFailure; - break; - } - if (rv == SECSuccess) - return copyk; + if (!copyk) { + PORT_SetError (SEC_ERROR_NO_MEMORY); + PORT_FreeArena (arena, PR_FALSE); + return NULL; + } - SECKEY_DestroyPublicKey (copyk); + copyk->arena = arena; + copyk->keyType = pubk->keyType; + if (pubk->pkcs11Slot && + PK11_IsPermObject(pubk->pkcs11Slot,pubk->pkcs11ID)) { + copyk->pkcs11Slot = PK11_ReferenceSlot(pubk->pkcs11Slot); + copyk->pkcs11ID = pubk->pkcs11ID; } else { - PORT_SetError (SEC_ERROR_NO_MEMORY); + copyk->pkcs11Slot = NULL; /* go get own reference */ + copyk->pkcs11ID = CK_INVALID_HANDLE; } + switch (pubk->keyType) { + case rsaKey: + rv = SECITEM_CopyItem(arena, ©k->u.rsa.modulus, + &pubk->u.rsa.modulus); + if (rv == SECSuccess) { + rv = SECITEM_CopyItem (arena, ©k->u.rsa.publicExponent, + &pubk->u.rsa.publicExponent); + if (rv == SECSuccess) + return copyk; + } + break; + case dsaKey: + rv = SECITEM_CopyItem(arena, ©k->u.dsa.publicValue, + &pubk->u.dsa.publicValue); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.dsa.params.prime, + &pubk->u.dsa.params.prime); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.dsa.params.subPrime, + &pubk->u.dsa.params.subPrime); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.dsa.params.base, + &pubk->u.dsa.params.base); + break; + case keaKey: + rv = SECITEM_CopyItem(arena, ©k->u.kea.publicValue, + &pubk->u.kea.publicValue); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.kea.params.hash, + &pubk->u.kea.params.hash); + break; + case fortezzaKey: + copyk->u.fortezza.KEAversion = pubk->u.fortezza.KEAversion; + copyk->u.fortezza.DSSversion = pubk->u.fortezza.DSSversion; + PORT_Memcpy(copyk->u.fortezza.KMID, pubk->u.fortezza.KMID, + sizeof(pubk->u.fortezza.KMID)); + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.clearance, + &pubk->u.fortezza.clearance); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.KEApriviledge, + &pubk->u.fortezza.KEApriviledge); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.DSSpriviledge, + &pubk->u.fortezza.DSSpriviledge); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.KEAKey, + &pubk->u.fortezza.KEAKey); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.DSSKey, + &pubk->u.fortezza.DSSKey); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.params.prime, + &pubk->u.fortezza.params.prime); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.params.subPrime, + &pubk->u.fortezza.params.subPrime); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.params.base, + &pubk->u.fortezza.params.base); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.keaParams.prime, + &pubk->u.fortezza.keaParams.prime); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.keaParams.subPrime, + &pubk->u.fortezza.keaParams.subPrime); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.fortezza.keaParams.base, + &pubk->u.fortezza.keaParams.base); + break; + case dhKey: + rv = SECITEM_CopyItem(arena,©k->u.dh.prime,&pubk->u.dh.prime); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena,©k->u.dh.base,&pubk->u.dh.base); + if (rv != SECSuccess) break; + rv = SECITEM_CopyItem(arena, ©k->u.dh.publicValue, + &pubk->u.dh.publicValue); + break; + 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; + case nullKey: + return copyk; + default: + rv = SECFailure; + break; + } + if (rv == SECSuccess) + return copyk; - PORT_FreeArena (arena, PR_FALSE); + SECKEY_DestroyPublicKey (copyk); return NULL; } @@ -1853,7 +1998,6 @@ SECKEY_DecodeDERSubjectPublicKeyInfo(SECItem *spkider) } if (rv == SECSuccess) return spki; - SECKEY_DestroySubjectPublicKeyInfo(spki); } else { PORT_SetError(SEC_ERROR_NO_MEMORY); } @@ -1944,8 +2088,8 @@ SECKEY_ConvertAndDecodePublicKeyAndChallenge(char *pkacstr, char *challenge, /* check the signature */ sig = sd.signature; DER_ConvertBitString(&sig); - rv = VFY_VerifyData(sd.data.data, sd.data.len, pubKey, &sig, - SECOID_GetAlgorithmTag(&(sd.signatureAlgorithm)), wincx); + rv = VFY_VerifyDataWithAlgorithmID(sd.data.data, sd.data.len, pubKey, &sig, + &sd.signatureAlgorithm, NULL, wincx); if ( rv != SECSuccess ) { goto loser; } diff --git a/security/nss/lib/cryptohi/secsign.c b/security/nss/lib/cryptohi/secsign.c index 12e6ed3ad..270889e6c 100644 --- a/security/nss/lib/cryptohi/secsign.c +++ b/security/nss/lib/cryptohi/secsign.c @@ -121,11 +121,26 @@ SGN_NewContext(SECOidTag alg, SECKEYPrivateKey *key) signalg = SEC_OID_MISSI_DSS; /* XXX Is there a better algid? */ keyType = fortezzaKey; break; - case SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST: + case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: hashalg = SEC_OID_SHA1; signalg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; keyType = ecKey; break; + case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: + hashalg = SEC_OID_SHA256; + signalg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; + keyType = ecKey; + break; + case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: + hashalg = SEC_OID_SHA384; + signalg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; + keyType = ecKey; + break; + case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: + hashalg = SEC_OID_SHA512; + signalg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; + keyType = ecKey; + break; /* we don't implement MD4 hashes. * we *CERTAINLY* don't want to sign one! */ case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: @@ -142,6 +157,13 @@ SGN_NewContext(SECOidTag alg, SECKEYPrivateKey *key) return 0; } +#ifndef NSS_ECC_MORE_THAN_SUITE_B + if (key->keyType == ecKey) { + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + return 0; + } +#endif + cx = (SGNContext*) PORT_ZAlloc(sizeof(SGNContext)); if (cx) { cx->hashalg = hashalg; @@ -200,7 +222,8 @@ SECStatus SGN_End(SGNContext *cx, SECItem *result) { unsigned char digest[HASH_LENGTH_MAX]; - unsigned part1, signatureLen; + unsigned part1; + int signatureLen; SECStatus rv; SECItem digder, sigitem; PRArenaPool *arena = 0; @@ -248,6 +271,11 @@ SGN_End(SGNContext *cx, SECItem *result) ** block */ signatureLen = PK11_SignatureLen(privKey); + if (signatureLen <= 0) { + PORT_SetError(SEC_ERROR_INVALID_KEY); + rv = SECFailure; + goto loser; + } sigitem.len = signatureLen; sigitem.data = (unsigned char*) PORT_Alloc(signatureLen); @@ -266,7 +294,7 @@ SGN_End(SGNContext *cx, SECItem *result) if ((cx->signalg == SEC_OID_ANSIX9_DSA_SIGNATURE) || (cx->signalg == SEC_OID_ANSIX962_EC_PUBLIC_KEY)) { /* DSAU_EncodeDerSigWithLen works for DSA and ECDSA */ - rv = DSAU_EncodeDerSigWithLen(result, &sigitem, signatureLen); + rv = DSAU_EncodeDerSigWithLen(result, &sigitem, sigitem.len); PORT_Free(sigitem.data); if (rv != SECSuccess) goto loser; @@ -373,7 +401,7 @@ SEC_DerSignData(PRArenaPool *arena, SECItem *result, algID = SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST; break; case ecKey: - algID = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST; + algID = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; break; default: PORT_SetError(SEC_ERROR_INVALID_KEY); @@ -407,7 +435,7 @@ SECStatus SGN_Digest(SECKEYPrivateKey *privKey, SECOidTag algtag, SECItem *result, SECItem *digest) { - unsigned modulusLen; + int modulusLen; SECStatus rv; SECItem digder; PRArenaPool *arena = 0; @@ -446,6 +474,11 @@ SGN_Digest(SECKEYPrivateKey *privKey, ** block */ modulusLen = PK11_SignatureLen(privKey); + if (modulusLen <= 0) { + PORT_SetError(SEC_ERROR_INVALID_KEY); + rv = SECFailure; + goto loser; + } result->len = modulusLen; result->data = (unsigned char*) PORT_Alloc(modulusLen); @@ -503,8 +536,19 @@ SEC_GetSignatureAlgorithmOidTag(KeyType keyType, SECOidTag hashAlgTag) } break; case ecKey: - /* XXX For now only ECDSA with SHA1 is supported */ - sigTag = SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST; + switch (hashAlgTag) { + case SEC_OID_UNKNOWN: /* default for ECDSA if hash not specified */ + case SEC_OID_SHA1: /* is ECDSA_SHA1_SIGNTARURE */ + sigTag = SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; break; + case SEC_OID_SHA256: + sigTag = SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; break; + case SEC_OID_SHA384: + sigTag = SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE; break; + case SEC_OID_SHA512: + sigTag = SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE; break; + default: + break; + } break; default: break; diff --git a/security/nss/lib/cryptohi/secvfy.c b/security/nss/lib/cryptohi/secvfy.c index 311bec35e..7a7c6ec98 100644 --- a/security/nss/lib/cryptohi/secvfy.c +++ b/security/nss/lib/cryptohi/secvfy.c @@ -48,6 +48,7 @@ #include "pk11func.h" #include "secdig.h" #include "secerr.h" +#include "secport.h" /* ** Decrypt signature block using public key @@ -57,7 +58,7 @@ */ static SECStatus DecryptSigBlock(SECOidTag *tagp, unsigned char *digest, unsigned int len, - SECKEYPublicKey *key, SECItem *sig, char *wincx) + SECKEYPublicKey *key, const SECItem *sig, char *wincx) { SGNDigestInfo *di = NULL; unsigned char *buf = NULL; @@ -73,7 +74,7 @@ DecryptSigBlock(SECOidTag *tagp, unsigned char *digest, unsigned int len, if (!buf) goto loser; /* decrypt the block */ - rv = PK11_VerifyRecover(key, sig, &it, wincx); + rv = PK11_VerifyRecover(key, (SECItem *)sig, &it, wincx); if (rv != SECSuccess) goto loser; di = SGN_DecodeDigestInfo(&it); @@ -153,19 +154,21 @@ decodeECorDSASignature(SECOidTag algid, SECItem *sig, unsigned char *dsig, SECStatus rv=SECSuccess; switch (algid) { + case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: + case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: + case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: + case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: + case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST: + case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST: + if (len > MAX_ECKEY_LEN * 2) { + PORT_SetError(SEC_ERROR_BAD_DER); + return SECFailure; + } + /* fall through */ case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: case SEC_OID_ANSIX9_DSA_SIGNATURE: - case SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST: - if (algid == SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST) { - if (len > MAX_ECKEY_LEN * 2) { - PORT_SetError(SEC_ERROR_BAD_DER); - return SECFailure; - } - dsasig = DSAU_DecodeDerSigToLen(sig, len); - } else { - dsasig = DSAU_DecodeDerSig(sig); - } + dsasig = DSAU_DecodeDerSigToLen(sig, len); if ((dsasig == NULL) || (dsasig->len != len)) { rv = SECFailure; @@ -187,22 +190,32 @@ decodeECorDSASignature(SECOidTag algid, SECItem *sig, unsigned char *dsig, return rv; } +const static SEC_ASN1Template hashParameterTemplate[] = +{ + { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(SECItem) }, + { SEC_ASN1_OBJECT_ID, 0 }, + { SEC_ASN1_SKIP_REST }, + { 0, } +}; /* * Pulls the hash algorithm, signing algorithm, and key type out of a * composite algorithm. * * alg: the composite algorithm to dissect. * hashalg: address of a SECOidTag which will be set with the hash algorithm. - * signalg: address of a SECOidTag which will be set with the signing alg. - * (not implemented) - * keyType: address of a KeyType which will be set with the key type. - * (not implemented) - * Returns: SECSuccess if the algorithm was acceptable, SECFailure if the + * params: specific signature parameter (from the signature AlgorithmID). + * key: public key to verify against. + * Returns: SECSuccess if the alg algorithm was acceptable, SECFailure if the * algorithm was not found or was not a signing algorithm. */ static SECStatus -decodeSigAlg(SECOidTag alg, SECOidTag *hashalg) +decodeSigAlg(SECOidTag alg, const SECItem *params, const SECKEYPublicKey *key, + SECOidTag *hashalg) { + PRArenaPool *arena; + SECStatus rv; + SECItem oid; + unsigned int len; PR_ASSERT(hashalg!=NULL); switch (alg) { @@ -218,20 +231,67 @@ decodeSigAlg(SECOidTag alg, SECOidTag *hashalg) *hashalg = SEC_OID_SHA1; break; + case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: *hashalg = SEC_OID_SHA256; break; + case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: *hashalg = SEC_OID_SHA384; break; + case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: *hashalg = SEC_OID_SHA512; break; + case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST: + /* This is an EC algorithm. Recommended means the largest + * hash algorithm that is not truncated by the keysize of + * the EC algorithm. Note that key strength is in bytes and + * algorithms are specified in bits. Never use an algorithm + * weaker than sha1. */ + len = SECKEY_PublicKeyStrength((SECKEYPublicKey *)key); + if (len < 28) { /* 28 bytes == 244 bits */ + *hashalg = SEC_OID_SHA1; + } else if (len < 32) { /* 32 bytes == 256 bits */ + /* we don't support 244 bit hash algorithms */ + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + return SECFailure; + } else if (len < 48) { /* 48 bytes == 384 bits */ + *hashalg = SEC_OID_SHA256; + } else if (len < 64) { /* 48 bytes == 512 bits */ + *hashalg = SEC_OID_SHA384; + } else { + /* use the largest in this case */ + *hashalg = SEC_OID_SHA512; + } + break; + case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST: + if (params == NULL) { + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + return SECFailure; + } + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + return SECFailure; + } + rv = SEC_QuickDERDecodeItem(arena, &oid, hashParameterTemplate, params); + if (rv != SECSuccess) { + PORT_FreeArena(arena, PR_FALSE); + return rv; + } + + *hashalg = SECOID_FindOIDTag(&oid); + PORT_FreeArena(arena, PR_FALSE); + if (*hashalg == SEC_OID_UNKNOWN) { + PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); + return SECFailure; + } + break; /* what about normal DSA? */ case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: case SEC_OID_BOGUS_DSA_SIGNATURE_WITH_SHA1_DIGEST: - case SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST: + case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: *hashalg = SEC_OID_SHA1; break; case SEC_OID_MISSI_DSS: @@ -248,9 +308,9 @@ decodeSigAlg(SECOidTag alg, SECOidTag *hashalg) return SECSuccess; } -VFYContext * -VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag algid, - void *wincx) +static VFYContext * +vfy_CreateContextPrivate(const SECKEYPublicKey *key, const SECItem *sig, + SECOidTag algid, const SECItem *params, void *wincx) { VFYContext *cx; SECStatus rv; @@ -265,14 +325,15 @@ VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag algid, switch (key->keyType) { case rsaKey: cx->type = VFY_RSA; - cx->key = SECKEY_CopyPublicKey(key); /* extra safety precautions */ + /* keep our own copy */ + cx->key = SECKEY_CopyPublicKey((SECKEYPublicKey *)key); if (sig) { SECOidTag hashid = SEC_OID_UNKNOWN; rv = DecryptSigBlock(&hashid, cx->u.buffer, HASH_LENGTH_MAX, cx->key, sig, (char*)wincx); cx->alg = hashid; } else { - rv = decodeSigAlg(algid,&cx->alg); + rv = decodeSigAlg(algid, params, key, &cx->alg); } break; case fortezzaKey: @@ -283,13 +344,16 @@ VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag algid, /* Unlike DSA, EDSA does not have a fixed signature length * (it depends on the key size) */ - sigLen = SECKEY_PublicKeyStrength(key) * 2; + sigLen = SECKEY_PublicKeyStrength((SECKEYPublicKey *)key) * 2; } else { cx->type = VFY_DSA; sigLen = DSA_SIGNATURE_LEN; } - cx->alg = SEC_OID_SHA1; - cx->key = SECKEY_CopyPublicKey(key); + rv = decodeSigAlg(algid, params, key, &cx->alg); + if (rv != SECSuccess) { + break; + } + cx->key = SECKEY_CopyPublicKey((SECKEYPublicKey *)key); if (sig) { rv = decodeECorDSASignature(algid,sig,cx->u.buffer,sigLen); } @@ -319,6 +383,13 @@ VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag algid, return 0; } +VFYContext * +VFY_CreateContext(SECKEYPublicKey *key, SECItem *sig, SECOidTag algid, + void *wincx) +{ + return vfy_CreateContextPrivate(key, sig, algid, NULL, wincx); +} + void VFY_DestroyContext(VFYContext *cx, PRBool freeit) { @@ -489,20 +560,21 @@ VFY_VerifyDigest(SECItem *digest, SECKEYPublicKey *key, SECItem *sig, return rv; } -SECStatus -VFY_VerifyData(unsigned char *buf, int len, SECKEYPublicKey *key, - SECItem *sig, SECOidTag algid, void *wincx) +static SECStatus +vfy_VerifyDataPrivate(const unsigned char *buf, int len, + const SECKEYPublicKey *key, const SECItem *sig, + SECOidTag algid, const SECItem *params, void *wincx) { SECStatus rv; VFYContext *cx; - cx = VFY_CreateContext(key, sig, algid, wincx); + cx = vfy_CreateContextPrivate(key, sig, algid, params, wincx); if (cx == NULL) return SECFailure; rv = VFY_Begin(cx); if (rv == SECSuccess) { - rv = VFY_Update(cx, buf, len); + rv = VFY_Update(cx, (unsigned char *)buf, len); if (rv == SECSuccess) rv = VFY_End(cx); } @@ -510,3 +582,34 @@ VFY_VerifyData(unsigned char *buf, int len, SECKEYPublicKey *key, VFY_DestroyContext(cx, PR_TRUE); return rv; } + +SECStatus +VFY_VerifyData(unsigned char *buf, int len, SECKEYPublicKey *key, + SECItem *sig, SECOidTag algid, void *wincx) +{ + return vfy_VerifyDataPrivate(buf, len, key, sig, algid, NULL, wincx); +} + +/* + * this function is private to nss3.dll in NSS 3.11 + */ +SECStatus +VFY_VerifyDataWithAlgorithmID(const unsigned char *buf, int len, + const SECKEYPublicKey *key, + const SECItem *sig, + const SECAlgorithmID *sigAlgorithm, + SECOidTag *reserved, void *wincx) +{ + /* the hash parameter is only provided to match the NSS 3.12 signature */ + PORT_Assert(reserved == NULL); + if (reserved) { + /* shouldn't happen, This function is not exported, and the only + * NSS callers pass 'NULL' */ + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + return vfy_VerifyDataPrivate(buf, len, key, sig, + SECOID_GetAlgorithmTag((SECAlgorithmID *)sigAlgorithm), + &sigAlgorithm->parameters, wincx); +} + diff --git a/security/nss/lib/freebl/GF2m_ecl.c b/security/nss/lib/freebl/GF2m_ecl.c deleted file mode 100644 index 4c0ab88f7..000000000 --- a/security/nss/lib/freebl/GF2m_ecl.c +++ /dev/null @@ -1,540 +0,0 @@ -/* - * ***** BEGIN LICENSE BLOCK ***** - * 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 binary polynomial field curves. - * - * The Initial Developer of the Original Code is - * Sun Microsystems, Inc. - * Portions created by the Initial Developer are Copyright (C) 2003 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Douglas Stebila <douglas@stebila.ca> - * - * 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. - * - * ***** END LICENSE BLOCK ***** */ - -#ifdef NSS_ENABLE_ECC -/* - * GF2m_ecl.c: Contains an implementation of elliptic curve math library - * for curves over GF2m. - * - * XXX Can be moved to a separate subdirectory later. - * - */ - -#include "GF2m_ecl.h" -#include "mpi/mplogic.h" -#include "mpi/mp_gf2m.h" -#include <stdlib.h> - -/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */ -mp_err -GF2m_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 -GF2m_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.2. - * Elliptic curve points P, Q, and R can all be identical. - * Uses affine coordinates. - */ -mp_err -GF2m_ec_pt_add_aff(const mp_int *pp, 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, xtemp, ytemp; - unsigned int *p; - int p_size; - - p_size = mp_bpoly2arr(pp, p, 0) + 1; - p = (unsigned int *) (malloc(sizeof(unsigned int) * p_size)); - if (p == NULL) goto cleanup; - mp_bpoly2arr(pp, p, p_size); - - CHECK_MPI_OK( mp_init(&lambda) ); - CHECK_MPI_OK( mp_init(&xtemp) ); - CHECK_MPI_OK( mp_init(&ytemp) ); - /* if P = inf, then R = Q */ - if (GF2m_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 (GF2m_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), - * xtemp = a + lambda^2 + lambda + px + qx - */ - if (mp_cmp(px, qx) != 0) { - CHECK_MPI_OK( mp_badd(py, qy, &ytemp) ); - CHECK_MPI_OK( mp_badd(px, qx, &xtemp) ); - CHECK_MPI_OK( mp_bdivmod(&ytemp, &xtemp, pp, p, &lambda) ); - CHECK_MPI_OK( mp_bsqrmod(&lambda, p, &xtemp) ); - CHECK_MPI_OK( mp_badd(&xtemp, &lambda, &xtemp) ); - CHECK_MPI_OK( mp_badd(&xtemp, a, &xtemp) ); - CHECK_MPI_OK( mp_badd(&xtemp, px, &xtemp) ); - CHECK_MPI_OK( mp_badd(&xtemp, qx, &xtemp) ); - } else { - /* if py != qy or qx = 0, then R = inf */ - if (((mp_cmp(py, qy) != 0)) || (mp_cmp_z(qx) == 0)) { - mp_zero(rx); - mp_zero(ry); - err = MP_OKAY; - goto cleanup; - } - /* lambda = qx + qy / qx */ - CHECK_MPI_OK( mp_bdivmod(qy, qx, pp, p, &lambda) ); - CHECK_MPI_OK( mp_badd(&lambda, qx, &lambda) ); - /* xtemp = a + lambda^2 + lambda */ - CHECK_MPI_OK( mp_bsqrmod(&lambda, p, &xtemp) ); - CHECK_MPI_OK( mp_badd(&xtemp, &lambda, &xtemp) ); - CHECK_MPI_OK( mp_badd(&xtemp, a, &xtemp) ); - } - /* ry = (qx + xtemp) * lambda + xtemp + qy */ - CHECK_MPI_OK( mp_badd(qx, &xtemp, &ytemp) ); - CHECK_MPI_OK( mp_bmulmod(&ytemp, &lambda, p, &ytemp) ); - CHECK_MPI_OK( mp_badd(&ytemp, &xtemp, &ytemp) ); - CHECK_MPI_OK( mp_badd(&ytemp, qy, ry) ); - /* rx = xtemp */ - CHECK_MPI_OK( mp_copy(&xtemp, rx) ); - -cleanup: - mp_clear(&lambda); - mp_clear(&xtemp); - mp_clear(&ytemp); - free(p); - return err; -} - -/* Computes R = P - Q. - * Elliptic curve points P, Q, and R can all be identical. - * Uses affine coordinates. - */ -mp_err -GF2m_ec_pt_sub_aff(const mp_int *pp, 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 = qx+qy */ - CHECK_MPI_OK( mp_badd(qx, qy, &nqy) ); - err = GF2m_ec_pt_add_aff(pp, 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 -GF2m_ec_pt_dbl_aff(const mp_int *pp, const mp_int *a, const mp_int *px, - const mp_int *py, mp_int *rx, mp_int *ry) -{ - return GF2m_ec_pt_add_aff(pp, 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 -GF2m_ec_pt_mul_aff(const mp_int *pp, 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; - unsigned int *p; - int p_size; - - 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) ); - - p_size = mp_bpoly2arr(pp, p, 0) + 1; - p = (unsigned int *) (malloc(sizeof(unsigned int) * p_size)); - if (p == NULL) goto cleanup; - mp_bpoly2arr(pp, p, p_size); - - /* 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 then Q = -Q, k = -k */ - if (mp_cmp_z(n) < 0) { - CHECK_MPI_OK( mp_badd(&qx, &qy, &qy) ); - CHECK_MPI_OK( mp_neg(&k, &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( GF2m_ec_pt_add_aff(pp, a, &sx, &sy, &qx, &qy, &sx, &sy) ); - } - if (i > 0) { - /* S = 2S */ - CHECK_MPI_OK( GF2m_ec_pt_dbl_aff(pp, 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( GF2m_ec_pt_dbl_aff(pp, 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( GF2m_ec_pt_add_aff(pp, 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( GF2m_ec_pt_sub_aff(pp, 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); - free(p); - return err; -} - -/* Compute the x-coordinate x/z for the point 2*(x/z) in Montgomery projective - * coordinates. - * Uses algorithm Mdouble in appendix of - * Lopez, J. and Dahab, R. "Fast multiplication on elliptic curves over - * GF(2^m) without precomputation". - * modified to not require precomputation of c=b^{2^{m-1}}. - */ -static mp_err -gf2m_Mdouble(const mp_int *pp, const unsigned int p[], const mp_int *a, - const mp_int *b, mp_int *x, mp_int *z) -{ - mp_err err = MP_OKAY; - mp_int t1; - - MP_DIGITS(&t1) = 0; - CHECK_MPI_OK( mp_init(&t1) ); - - CHECK_MPI_OK( mp_bsqrmod(x, p, x) ); - CHECK_MPI_OK( mp_bsqrmod(z, p, &t1) ); - CHECK_MPI_OK( mp_bmulmod(x, &t1, p, z) ); - CHECK_MPI_OK( mp_bsqrmod(x, p, x) ); - CHECK_MPI_OK( mp_bsqrmod(&t1, p, &t1) ); - CHECK_MPI_OK( mp_bmulmod(b, &t1, p, &t1) ); - CHECK_MPI_OK( mp_badd(x, &t1, x) ); - -cleanup: - mp_clear(&t1); - return err; -} - -/* Compute the x-coordinate x1/z1 for the point (x1/z1)+(x2/x2) in Montgomery - * projective coordinates. - * Uses algorithm Madd in appendix of - * Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over - * GF(2^m) without precomputation". - */ -static mp_err -gf2m_Madd(const mp_int *pp, const unsigned int p[], const mp_int *a, - const mp_int *b, const mp_int *x, mp_int *x1, mp_int *z1, mp_int *x2, - mp_int *z2) -{ - mp_err err = MP_OKAY; - mp_int t1, t2; - - MP_DIGITS(&t1) = 0; - MP_DIGITS(&t2) = 0; - CHECK_MPI_OK( mp_init(&t1) ); - CHECK_MPI_OK( mp_init(&t2) ); - - CHECK_MPI_OK( mp_copy(x, &t1) ); - CHECK_MPI_OK( mp_bmulmod(x1, z2, p, x1) ); - CHECK_MPI_OK( mp_bmulmod(z1, x2, p, z1) ); - CHECK_MPI_OK( mp_bmulmod(x1, z1, p, &t2) ); - CHECK_MPI_OK( mp_badd(z1, x1, z1) ); - CHECK_MPI_OK( mp_bsqrmod(z1, p, z1) ); - CHECK_MPI_OK( mp_bmulmod(z1, &t1, p, x1) ); - CHECK_MPI_OK( mp_badd(x1, &t2, x1) ); - -cleanup: - mp_clear(&t1); - mp_clear(&t2); - return err; -} - -/* Compute the x, y affine coordinates from the point (x1, z1) (x2, z2) - * using Montgomery point multiplication algorithm Mxy() in appendix of - * Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over - * GF(2^m) without precomputation". - * Returns: - * 0 on error - * 1 if return value should be the point at infinity - * 2 otherwise - */ -static int -gf2m_Mxy(const mp_int *pp, const unsigned int p[], const mp_int *a, - const mp_int *b, const mp_int *x, const mp_int *y, mp_int *x1, mp_int *z1, - mp_int *x2, mp_int *z2) -{ - mp_err err = MP_OKAY; - int ret; - mp_int t3, t4, t5; - - MP_DIGITS(&t3) = 0; - MP_DIGITS(&t4) = 0; - MP_DIGITS(&t5) = 0; - CHECK_MPI_OK( mp_init(&t3) ); - CHECK_MPI_OK( mp_init(&t4) ); - CHECK_MPI_OK( mp_init(&t5) ); - - if (mp_cmp_z(z1) == 0) { - mp_zero(x2); - mp_zero(z2); - ret = 1; - goto cleanup; - } - - if (mp_cmp_z(z2) == 0) { - CHECK_MPI_OK( mp_copy(x, x2) ); - CHECK_MPI_OK( mp_badd(x, y, z2) ); - ret = 2; - goto cleanup; - } - - mp_set(&t5, 0x1); - - CHECK_MPI_OK( mp_bmulmod(z1, z2, p, &t3) ); - - CHECK_MPI_OK( mp_bmulmod(z1, x, p, z1) ); - CHECK_MPI_OK( mp_badd(z1, x1, z1) ); - CHECK_MPI_OK( mp_bmulmod(z2, x, p, z2) ); - CHECK_MPI_OK( mp_bmulmod(z2, x1, p, x1) ); - CHECK_MPI_OK( mp_badd(z2, x2, z2) ); - - CHECK_MPI_OK( mp_bmulmod(z2, z1, p, z2) ); - CHECK_MPI_OK( mp_bsqrmod(x, p, &t4) ); - CHECK_MPI_OK( mp_badd(&t4, y, &t4) ); - CHECK_MPI_OK( mp_bmulmod(&t4, &t3, p, &t4) ); - CHECK_MPI_OK( mp_badd(&t4, z2, &t4) ); - - CHECK_MPI_OK( mp_bmulmod(&t3, x, p, &t3) ); - CHECK_MPI_OK( mp_bdivmod(&t5, &t3, pp, p, &t3) ); - CHECK_MPI_OK( mp_bmulmod(&t3, &t4, p, &t4) ); - CHECK_MPI_OK( mp_bmulmod(x1, &t3, p, x2) ); - CHECK_MPI_OK( mp_badd(x2, x, z2) ); - - CHECK_MPI_OK( mp_bmulmod(z2, &t4, p, z2) ); - CHECK_MPI_OK( mp_badd(z2, y, z2) ); - - ret = 2; - -cleanup: - mp_clear(&t3); - mp_clear(&t4); - mp_clear(&t5); - if (err == MP_OKAY) { - return ret; - } else { - return 0; - } -} - -/* Computes R = nP based on algorithm 2P of - * Lopex, J. and Dahab, R. "Fast multiplication on elliptic curves over - * GF(2^m) without precomputation". - * Elliptic curve points P and R can be identical. - * Uses Montgomery projective coordinates. - */ -mp_err -GF2m_ec_pt_mul_mont(const mp_int *pp, 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 x1, x2, z1, z2; - int i, j; - mp_digit top_bit, mask; - unsigned int *p; - int p_size; - - MP_DIGITS(&x1) = 0; - MP_DIGITS(&x2) = 0; - MP_DIGITS(&z1) = 0; - MP_DIGITS(&z2) = 0; - CHECK_MPI_OK( mp_init(&x1) ); - CHECK_MPI_OK( mp_init(&x2) ); - CHECK_MPI_OK( mp_init(&z1) ); - CHECK_MPI_OK( mp_init(&z2) ); - - p_size = mp_bpoly2arr(pp, p, 0) + 1; - p = (unsigned int *) (malloc(sizeof(unsigned int) * p_size)); - if (p == NULL) goto cleanup; - mp_bpoly2arr(pp, p, p_size); - - /* if result should be point at infinity */ - if ((mp_cmp_z(n) == 0) || (GF2m_ec_pt_is_inf_aff(px, py) == MP_YES)) { - CHECK_MPI_OK( GF2m_ec_pt_set_inf_aff(rx, ry) ); - goto cleanup; - } - - CHECK_MPI_OK( mp_copy(rx, &x2) ); /* x2 = rx */ - CHECK_MPI_OK( mp_copy(ry, &z2) ); /* z2 = ry */ - - CHECK_MPI_OK( mp_copy(px, &x1) ); /* x1 = px */ - mp_set(&z1, 0x1); /* z1 = 1 */ - CHECK_MPI_OK( mp_bsqrmod(&x1, p, &z2) ); /* z2 = x1^2 = x2^2 */ - CHECK_MPI_OK( mp_bsqrmod(&z2, p, &x2) ); - CHECK_MPI_OK( mp_badd(&x2, b, &x2) ); /* x2 = px^4 + b */ - - /* find top-most bit and go one past it */ - i = MP_USED(n) - 1; - j = MP_DIGIT_BIT - 1; - top_bit = 1; - top_bit <<= MP_DIGIT_BIT - 1; - mask = top_bit; - while (!(MP_DIGITS(n)[i] & mask)) { - mask >>= 1; - j--; - } - mask >>= 1; j--; - - /* if top most bit was at word break, go to next word */ - if (!mask) { - i--; - j = MP_DIGIT_BIT - 1; - mask = top_bit; - } - - for (; i >= 0; i--) { - for (; j >= 0; j--) { - if (MP_DIGITS(n)[i] & mask) { - CHECK_MPI_OK( gf2m_Madd(pp, p, a, b, px, &x1, &z1, &x2, &z2) ); - CHECK_MPI_OK( gf2m_Mdouble(pp, p, a, b, &x2, &z2) ); - } else { - CHECK_MPI_OK( gf2m_Madd(pp, p, a, b, px, &x2, &z2, &x1, &z1) ); - CHECK_MPI_OK( gf2m_Mdouble(pp, p, a, b, &x1, &z1) ); - } - mask >>= 1; - } - j = MP_DIGIT_BIT - 1; - mask = top_bit; - } - - /* convert out of "projective" coordinates */ - i = gf2m_Mxy(pp, p, a, b, px, py, &x1, &z1, &x2, &z2); - if (i == 0) { - err = MP_BADARG; - goto cleanup; - } else if (i == 1) { - CHECK_MPI_OK( GF2m_ec_pt_set_inf_aff(rx, ry) ); - } else { - CHECK_MPI_OK( mp_copy(&x2, rx) ); - CHECK_MPI_OK( mp_copy(&z2, ry) ); - } - -cleanup: - mp_clear(&x1); - mp_clear(&x2); - mp_clear(&z1); - mp_clear(&z2); - free(p); - return err; -} - -#endif /* NSS_ENABLE_ECC */ diff --git a/security/nss/lib/freebl/GF2m_ecl.h b/security/nss/lib/freebl/GF2m_ecl.h deleted file mode 100644 index 3641d63da..000000000 --- a/security/nss/lib/freebl/GF2m_ecl.h +++ /dev/null @@ -1,97 +0,0 @@ -/* - * ***** BEGIN LICENSE BLOCK ***** - * 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 binary polynomial field curves. - * - * The Initial Developer of the Original Code is - * Sun Microsystems, Inc. - * Portions created by the Initial Developer are Copyright (C) 2003 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Douglas Stebila <douglas@stebila.ca> - * - * 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. - * - * ***** END LICENSE BLOCK ***** */ - -#ifndef __gf2m_ecl_h_ -#define __gf2m_ecl_h_ -#ifdef NSS_ENABLE_ECC - -#include "secmpi.h" - -/* Checks if point P(px, py) is at infinity. Uses affine coordinates. */ -mp_err GF2m_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. */ -mp_err GF2m_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. - */ -mp_err GF2m_ec_pt_add_aff(const mp_int *pp, 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. */ -mp_err GF2m_ec_pt_sub_aff(const mp_int *pp, 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. */ -mp_err GF2m_ec_pt_dbl_aff(const mp_int *pp, 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 irreducible that - * determines the field GF2m. Uses affine coordinates. - */ -mp_err GF2m_ec_pt_mul_aff(const mp_int *pp, 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); - -/* 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 irreducible that - * determines the field GF2m. Uses Montgomery projective coordinates. - */ -mp_err GF2m_ec_pt_mul_mont(const mp_int *pp, 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 GF2m_ec_pt_is_inf(px, py) GF2m_ec_pt_is_inf_aff((px), (py)) -#define GF2m_ec_pt_add(p, a, px, py, qx, qy, rx, ry) \ - GF2m_ec_pt_add_aff((p), (a), (px), (py), (qx), (qy), (rx), (ry)) - -#define GF2m_ECL_MONTGOMERY -#ifdef GF2m_ECL_AFFINE -#define GF2m_ec_pt_mul(pp, a, b, px, py, n, rx, ry) \ - GF2m_ec_pt_mul_aff((pp), (a), (b), (px), (py), (n), (rx), (ry)) -#elif defined(GF2m_ECL_MONTGOMERY) -#define GF2m_ec_pt_mul(pp, a, b, px, py, n, rx, ry) \ - GF2m_ec_pt_mul_mont((pp), (a), (b), (px), (py), (n), (rx), (ry)) -#endif /* GF2m_ECL_AFFINE or GF2m_ECL_MONTGOMERY */ - -#endif /* NSS_ENABLE_ECC */ -#endif /* __gf2m_ecl_h_ */ diff --git a/security/nss/lib/freebl/GFp_ecl.c b/security/nss/lib/freebl/GFp_ecl.c deleted file mode 100644 index 7b460cc58..000000000 --- a/security/nss/lib/freebl/GFp_ecl.c +++ /dev/null @@ -1,648 +0,0 @@ -/* - * ***** BEGIN LICENSE BLOCK ***** - * 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 the Initial Developer are Copyright (C) 2003 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Sheueling Chang Shantz <sheueling.chang@sun.com> and - * Douglas Stebila <douglas@stebila.ca>, Sun Microsystems Laboratories - * Bodo Moeller <moeller@cdc.informatik.tu-darmstadt.de>, - * Nils Larsch <nla@trustcenter.de>, and - * Lenka Fibikova <fibikova@exp-math.uni-essen.de>, 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. - * - * ***** END LICENSE BLOCK ***** */ - -#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 deleted file mode 100644 index d920b2e7c..000000000 --- a/security/nss/lib/freebl/GFp_ecl.h +++ /dev/null @@ -1,127 +0,0 @@ -/* - * ***** BEGIN LICENSE BLOCK ***** - * 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 the Initial Developer are Copyright (C) 2003 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * Douglas Stebila <douglas@stebila.ca>, 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. - * - * ***** END LICENSE BLOCK ***** */ - -#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 1805d1c5e..23d3b0277 100644 --- a/security/nss/lib/freebl/Makefile +++ b/security/nss/lib/freebl/Makefile @@ -98,7 +98,7 @@ ifdef NS_USE_GCC ASFILES = DEFINES += -DMP_NO_MP_WORD -DMP_USE_UINT_DIGIT else - ASFILES = mpi_x86.asm + MPI_SRCS += mpi_x86_asm.c DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE DEFINES += -DMP_ASSEMBLY_DIV_2DX1D -DMP_USE_UINT_DIGIT -DMP_NO_MP_WORD ifdef BUILD_OPT @@ -112,12 +112,6 @@ ifeq ($(OS_TARGET),WINCE) DEFINES += -DSHA_NO_LONG_LONG # avoid 64-bit arithmetic in SHA512 endif -ifdef XP_OS2_VACPP - ASFILES = mpi_x86.asm - DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE - DEFINES += -DMP_ASSEMBLY_DIV_2DX1D -DMP_USE_UINT_DIGIT -DMP_NO_MP_WORD -endif - ifeq ($(OS_TARGET),IRIX) ifeq ($(USE_N32),1) ASFILES = mpi_mips.s @@ -137,12 +131,15 @@ ifeq ($(CPU_ARCH),x86_64) ASFLAGS += -march=opteron -m64 -fPIC DEFINES += -DNSS_BEVAND_ARCFOUR -DMPI_AMD64 -DMP_ASSEMBLY_MULTIPLY DEFINES += -DNSS_USE_COMBA + DEFINES += -DMP_CHAR_STORE_SLOW -DMP_IS_LITTLE_ENDIAN +# DEFINES += -DMPI_AMD64_ADD MPI_SRCS += mpi_amd64.c mp_comba.c endif ifeq ($(CPU_ARCH),x86) ASFILES = mpi_x86.s DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE DEFINES += -DMP_ASSEMBLY_DIV_2DX1D + DEFINES += -DMP_CHAR_STORE_SLOW -DMP_IS_LITTLE_ENDIAN # The floating point ECC code doesn't work on Linux x86 (bug 311432). #ECL_USE_FP = 1 endif @@ -171,13 +168,13 @@ ifdef USE_ABI32_INT32 DEFINES += -DSHA_NO_LONG_LONG # avoid 64-bit arithmetic in SHA512 else ifdef USE_64 -# this builds for DA2.0W (HP PA 2.0 Wide), the LP64 ABI, using 32-bit digits +# this builds for DA2.0W (HP PA 2.0 Wide), the LP64 ABI, using 64-bit digits MPI_SRCS += mpi_hp.c ASFILES += hpma512.s hppa20.s DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE else # this builds for DA2.0 (HP PA 2.0 Narrow) ABI32_FPU model -# (the 32-bit ABI with 64-bit registers) using 32-bit digits +# (the 32-bit ABI with 64-bit registers) using 64-bit digits MPI_SRCS += mpi_hp.c ASFILES += hpma512.s hppa20.s DEFINES += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE @@ -238,18 +235,36 @@ ifeq ($(CPU_ARCH),sparc) endif ifdef USE_ABI32_INT64 ARCHFLAG=-mcpu=v9 -Wa,-xarch=v8plus + SOLARIS_AS_FLAGS = -xarch=v8plus -K PIC endif ifdef USE_ABI32_FPU - ARCHFLAG=-mcpu=v9 -Wa,-xarch=v8plus + ARCHFLAG=-mcpu=v9 -Wa,-xarch=v8plusa + SOLARIS_AS_FLAGS = -xarch=v8plusa -K PIC endif # USE_ABI32_FPU ifdef USE_ABI64_INT # this builds for Sparc v9a pure 64-bit architecture + ARCHFLAG += -mcpu=v9 -Wa,-xarch=v9 + SOLARIS_AS_FLAGS = -xarch=v9 -K PIC endif ifdef USE_ABI64_FPU # this builds for Sparc v9a pure 64-bit architecture # It uses floating point, and 32-bit word size + ARCHFLAG += -mcpu=v9 -Wa,-xarch=v9a + SOLARIS_AS_FLAGS = -xarch=v9a -K PIC endif else # NS_USE_GCC + # FPU_TARGET_OPTIMIZER specifies the target processor and cache + # properties of the ABI32_FPU and ABI64_FPU architectures for use + # by the optimizer. + ifeq (,$(findstring Sun WorkShop 6,$(shell $(CC) -V 2>&1))) + # if the compiler is not Forte 6 + FPU_TARGET_OPTIMIZER = -xcache=64/32/4:1024/64/4 -xchip=ultra3 + else + # Forte 6 C compiler generates incorrect code for rijndael.c + # if -xchip=ultra3 is used (Bugzilla bug 333925). So we revert + # to what we used in NSS 3.10. + FPU_TARGET_OPTIMIZER = -xchip=ultra2 + endif ifdef USE_ABI32_INT32 #ARCHFLAG=-xarch=v8 set in coreconf/sunOS5.mk endif @@ -270,7 +285,7 @@ ifeq ($(CPU_ARCH),sparc) # the generated flag settings SOL_CFLAGS += -D__MATHERR_ERRNO_DONTCARE -fns -fsimple=2 -fsingle SOL_CFLAGS += -xalias_level=basic -xbuiltin=%all - SOL_CFLAGS += -xcache=64/32/4:1024/64/4 -xchip=ultra3 -xdepend + SOL_CFLAGS += $(FPU_TARGET_OPTIMIZER) -xdepend SOL_CFLAGS += -xlibmil -xmemalign=8s -xO5 ARCHFLAG = -xarch=v8plusa SOLARIS_AS_FLAGS = -xarch=v8plusa -K PIC @@ -288,14 +303,14 @@ ifeq ($(CPU_ARCH),sparc) # See comment for USE_ABI32_FPU. SOL_CFLAGS += -D__MATHERR_ERRNO_DONTCARE -fns -fsimple=2 -fsingle SOL_CFLAGS += -xalias_level=basic -xbuiltin=%all - SOL_CFLAGS += -xcache=64/32/4:1024/64/4 -xchip=ultra3 -xdepend + SOL_CFLAGS += $(FPU_TARGET_OPTIMIZER) -xdepend SOL_CFLAGS += -xlibmil -xmemalign=8s -xO5 ARCHFLAG = -xarch=v9a SOLARIS_AS_FLAGS = -xarch=v9a -K PIC endif endif # NS_USE_GCC - ### set MP_ flags for both GCC and Sun cc + ### set flags for both GCC and Sun cc ifdef USE_ABI32_INT32 # this builds for Sparc v8 pure 32-bit architecture DEFINES += -DMP_USE_UINT_DIGIT -DMP_ASSEMBLY_MULTIPLY @@ -314,6 +329,7 @@ ifeq ($(CPU_ARCH),sparc) ASFILES = mpv_sparcv8.s montmulfv8.s DEFINES += -DMP_NO_MP_WORD -DMP_USE_UINT_DIGIT -DMP_ASSEMBLY_MULTIPLY DEFINES += -DMP_USING_MONT_MULF -DMP_MONT_USE_MP_MUL + ECL_USE_FP = 1 endif ifdef USE_ABI64_INT # this builds for Sparc v9a pure 64-bit architecture @@ -326,9 +342,9 @@ ifeq ($(CPU_ARCH),sparc) ASFILES = mpv_sparcv9.s montmulfv9.s DEFINES += -DMP_NO_MP_WORD -DMP_USE_UINT_DIGIT -DMP_ASSEMBLY_MULTIPLY DEFINES += -DMP_USING_MONT_MULF -DMP_MONT_USE_MP_MUL + ECL_USE_FP = 1 endif - ECL_USE_FP = 1 else # Solaris for non-sparc family CPUs ifdef NS_USE_GCC @@ -403,7 +419,6 @@ vpath %.h mpi ecl vpath %.c mpi ecl vpath %.S mpi ecl vpath %.s mpi ecl -vpath %.asm mpi ecl INCLUDES += -Impi -Iecl @@ -546,3 +561,17 @@ $(OBJDIR)/alg2268.obj: alg2268.c @$(MAKE_OBJDIR) $(CC) -Fo$@ -c $(filter-out /O+, $(CFLAGS)) $(call abspath,$<) endif + +# Bugzilla Bug 333917: the non-x86 code in desblapi.c seems to violate +# ANSI C's strict aliasing rules. +ifeq ($(OS_TARGET),Linux) +ifneq ($(CPU_ARCH),x86) +$(OBJDIR)/$(PROG_PREFIX)desblapi$(OBJ_SUFFIX): desblapi.c + @$(MAKE_OBJDIR) +ifdef NEED_ABSOLUTE_PATH + $(CC) -o $@ -c $(CFLAGS) -fno-strict-aliasing $(call abspath,$<) +else + $(CC) -o $@ -c $(CFLAGS) -fno-strict-aliasing $< +endif +endif +endif diff --git a/security/nss/lib/freebl/blapi.h b/security/nss/lib/freebl/blapi.h index 899eadd45..5e9c3dcd1 100644 --- a/security/nss/lib/freebl/blapi.h +++ b/security/nss/lib/freebl/blapi.h @@ -984,6 +984,50 @@ extern void RNG_RNGShutdown(void); extern void RNG_SystemInfoForRNG(void); +/* + * FIPS 186-2 Change Notice 1 RNG Algorithm 1, used both to + * generate the DSA X parameter and as a generic purpose RNG. + * + * The following two FIPS186Change functions are needed for + * NIST RNG Validation System. + */ + +/* + * Given the seed-key and the seed, generate the random output. + * + * Parameters: + * XKEY [input/output]: the state of the RNG (seed-key) + * XSEEDj [input]: optional user input (seed) + * x_j [output]: output of the RNG + * + * Return value: + * This function usually returns SECSuccess. The only reason + * this function returns SECFailure is that XSEEDj equals + * XKEY, including the intermediate XKEY value between the two + * iterations. (This test is actually a FIPS 140-2 requirement + * and not required for FIPS algorithm testing, but it is too + * hard to separate from this function.) If this function fails, + * XKEY is not updated, but some data may have been written to + * x_j, which should be ignored. + */ +extern SECStatus +FIPS186Change_GenerateX(unsigned char *XKEY, + const unsigned char *XSEEDj, + unsigned char *x_j); + +/* + * When generating the DSA X parameter, we generate 2*GSIZE bytes + * of random output and reduce it mod q. + * + * Input: w, 2*GSIZE bytes + * q, DSA_SUBPRIME_LEN bytes + * Output: xj, DSA_SUBPRIME_LEN bytes + */ +extern SECStatus +FIPS186Change_ReduceModQForDSA(const unsigned char *w, + const unsigned char *q, + unsigned char *xj); + /* Generate PQGParams and PQGVerify structs. * Length of seed and length of h both equal length of P. * All lengths are specified by "j", according to the table above. diff --git a/security/nss/lib/freebl/des.c b/security/nss/lib/freebl/des.c index 684a466f8..92c84692b 100644 --- a/security/nss/lib/freebl/des.c +++ b/security/nss/lib/freebl/des.c @@ -658,7 +658,7 @@ DES_Do1Block(HALF * ks, const BYTE * inbuf, BYTE * outbuf) HALFPTR(outbuf)[0] = left; HALFPTR(outbuf)[1] = right; #else - if (((ptrdiff_t)inbuf & 0x03) == 0) { + if (((ptrdiff_t)outbuf & 0x03) == 0) { #if defined(IS_LITTLE_ENDIAN) BYTESWAP(left, temp); BYTESWAP(right, temp); diff --git a/security/nss/lib/freebl/ec.c b/security/nss/lib/freebl/ec.c index 53949ab94..196ad7442 100644 --- a/security/nss/lib/freebl/ec.c +++ b/security/nss/lib/freebl/ec.c @@ -42,6 +42,7 @@ #include "secerr.h" #include "secmpi.h" #include "secitem.h" +#include "mplogic.h" #include "ec.h" #include "ecl.h" @@ -53,7 +54,7 @@ PRBool ec_point_at_infinity(SECItem *pointP) { - int i; + unsigned int i; for (i = 1; i < pointP->len; i++) { if (pointP->data[i] != 0x00) return PR_FALSE; @@ -353,28 +354,26 @@ EC_NewKeyFromSeed(ECParams *ecParams, ECPrivateKey **privKey, 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. The random value for the - * private key is generated using the algorithm A.4.1 of ANSI X9.62, +/* Generate a random private key using the algorithm A.4.1 of ANSI X9.62, * modified a la FIPS 186-2 Change Notice 1 to eliminate the bias in the * random number generator. + * + * Parameters + * - order: a buffer that holds the curve's group order + * - len: the length in octets of the order buffer + * + * Return Value + * Returns a buffer of len octets that holds the private key. The caller + * is responsible for freeing the buffer with PORT_ZFree. */ -SECStatus -EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey) +static unsigned char * +ec_GenerateRandomPrivateKey(const unsigned char *order, int len) { - SECStatus rv = SECFailure; -#ifdef NSS_ENABLE_ECC + SECStatus rv = SECSuccess; mp_err err; - int len; unsigned char *privKeyBytes = NULL; mp_int privKeyVal, order_1, one; - if (!ecParams || !privKey) { - PORT_SetError(SEC_ERROR_INVALID_ARGS); - return SECFailure; - } - MP_DIGITS(&privKeyVal) = 0; MP_DIGITS(&order_1) = 0; MP_DIGITS(&one) = 0; @@ -382,36 +381,62 @@ EC_NewKey(ECParams *ecParams, ECPrivateKey **privKey) CHECK_MPI_OK( mp_init(&order_1) ); CHECK_MPI_OK( mp_init(&one) ); - /* Generate random private key. - * Generates 2*len random bytes using the global random bit generator + /* Generates 2*len random bytes using the global random bit generator * (which implements Algorithm 1 of FIPS 186-2 Change Notice 1) then * reduces modulo the group order. */ - len = ecParams->order.len; if ((privKeyBytes = PORT_Alloc(2*len)) == NULL) goto cleanup; CHECK_SEC_OK( RNG_GenerateGlobalRandomBytes(privKeyBytes, 2*len) ); CHECK_MPI_OK( mp_read_unsigned_octets(&privKeyVal, privKeyBytes, 2*len) ); - CHECK_MPI_OK( mp_read_unsigned_octets(&order_1, - ecParams->order.data, len) ); + CHECK_MPI_OK( mp_read_unsigned_octets(&order_1, order, len) ); CHECK_MPI_OK( mp_set_int(&one, 1) ); CHECK_MPI_OK( mp_sub(&order_1, &one, &order_1) ); CHECK_MPI_OK( mp_mod(&privKeyVal, &order_1, &privKeyVal) ); CHECK_MPI_OK( mp_add(&privKeyVal, &one, &privKeyVal) ); CHECK_MPI_OK( mp_to_fixlen_octets(&privKeyVal, privKeyBytes, len) ); - /* generate public key */ - CHECK_SEC_OK( ec_NewKey(ecParams, privKey, privKeyBytes, len) ); - + memset(privKeyBytes+len, 0, len); cleanup: mp_clear(&privKeyVal); mp_clear(&order_1); mp_clear(&one); - if (privKeyBytes) { - PORT_ZFree(privKeyBytes, 2*len); - } if (err < MP_OKAY) { MP_TO_SEC_ERROR(err); rv = SECFailure; } + if (rv != SECSuccess && privKeyBytes) { + PORT_Free(privKeyBytes); + privKeyBytes = NULL; + } + return privKeyBytes; +} + +/* 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 *privKeyBytes = NULL; + + if (!ecParams) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + len = ecParams->order.len; + privKeyBytes = ec_GenerateRandomPrivateKey(ecParams->order.data, len); + if (privKeyBytes == NULL) goto cleanup; + /* generate public key */ + CHECK_SEC_OK( ec_NewKey(ecParams, privKey, privKeyBytes, len) ); + +cleanup: + if (privKeyBytes) { + PORT_ZFree(privKeyBytes, len); + } #if EC_DEBUG printf("EC_NewKey returning %s\n", (rv == SECSuccess) ? "success" : "failure"); @@ -613,33 +638,41 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, mp_err err = MP_OKAY; ECParams *ecParams = NULL; SECItem kGpoint = { siBuffer, NULL, 0}; - int len = 0; + int flen = 0; /* length in bytes of the field size */ + unsigned olen; /* length in bytes of the base point order */ #if EC_DEBUG char mpstr[256]; #endif + /* Initialize MPI integers. */ + /* must happen before the first potential call to cleanup */ + 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 args */ - if (!key || !signature || !digest || !kb || (kblen < 0) || - (digest->len != SHA1_LENGTH)) { + if (!key || !signature || !digest || !kb || (kblen < 0)) { 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); + flen = (ecParams->fieldID.size + 7) >> 3; + olen = ecParams->order.len; + if (signature->data == NULL) { + /* a call to get the signature length only */ + goto finish; + } + if (signature->len < 2*olen) { + PORT_SetError(SEC_ERROR_OUTPUT_LEN); 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) ); @@ -668,8 +701,8 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, ** ** Compute kG */ - kGpoint.len = 2*len + 1; - kGpoint.data = PORT_Alloc(2*len + 1); + kGpoint.len = 2*flen + 1; + kGpoint.data = PORT_Alloc(2*flen + 1); if ((kGpoint.data == NULL) || (ec_points_mul(ecParams, &k, NULL, NULL, &kGpoint) != SECSuccess)) @@ -681,7 +714,7 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, ** Extract the x co-ordinate of kG into x1 */ CHECK_MPI_OK( mp_read_unsigned_octets(&x1, kGpoint.data + 1, - (mp_size) len) ); + (mp_size) flen) ); /* ** ANSI X9.62, Section 5.3.3, Step 2 @@ -703,9 +736,16 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, /* ** ANSI X9.62, Section 5.3.3, Step 4 ** - ** s = (k**-1 * (SHA1(M) + d*r)) mod n + ** s = (k**-1 * (HASH(M) + d*r)) mod n */ - SECITEM_TO_MPINT(*digest, &s); /* s = SHA1(M) */ + SECITEM_TO_MPINT(*digest, &s); /* s = HASH(M) */ + + /* In the definition of EC signing, digests are truncated + * to the length of n in bits. + * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/ + if (digest->len*8 > ecParams->fieldID.size) { + mpl_rsh(&s,&s,digest->len*8 - ecParams->fieldID.size); + } #if EC_DEBUG mp_todecimal(&n, mpstr); @@ -748,9 +788,10 @@ ECDSA_SignDigestWithSeed(ECPrivateKey *key, SECItem *signature, ** ** 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; + CHECK_MPI_OK( mp_to_fixlen_octets(&r, signature->data, olen) ); + CHECK_MPI_OK( mp_to_fixlen_octets(&s, signature->data + olen, olen) ); +finish: + signature->len = 2*olen; rv = SECSuccess; err = MP_OKAY; @@ -763,7 +804,7 @@ cleanup: mp_clear(&n); if (kGpoint.data) { - PORT_ZFree(kGpoint.data, 2*len + 1); + PORT_ZFree(kGpoint.data, 2*flen + 1); } if (err) { @@ -791,47 +832,26 @@ ECDSA_SignDigest(ECPrivateKey *key, SECItem *signature, const SECItem *digest) { SECStatus rv = SECFailure; #ifdef NSS_ENABLE_ECC - int prerr = 0; - int n = key->ecParams.order.len; - unsigned char *kseed = NULL; - unsigned char *mask; - int i; + int len; + unsigned char *kBytes= 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; - /* make sure that kseed is smaller than the curve order */ - mask = key->ecParams.order.data; - for (i = 0; (i < n) && (*mask == 0x00); i++, mask++) { -#if EC_DEBUG - printf("replacing byte %02x in position %d [n=%d] with zero\n", - *(kseed + i), i, n); -#endif - *(kseed + i) = 0x00; - } + if (!key) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } - if (i == n) { - rv = SECFailure; - prerr = SEC_ERROR_NEED_RANDOM; - } else { -#if EC_DEBUG - printf("replacing byte %02x in position %d [n=%d] with %d\n", - *(kseed + i), i, n, (*mask - 1)); -#endif - if (*(kseed + i) >= *mask) - *(kseed + i) = *mask - 1; - rv = ECDSA_SignDigestWithSeed(key, signature, digest, kseed, n); - if (rv) prerr = PORT_GetError(); - } - } while ((rv != SECSuccess) && (prerr == SEC_ERROR_NEED_RANDOM)); + /* Generate random value k */ + len = key->ecParams.order.len; + kBytes = ec_GenerateRandomPrivateKey(key->ecParams.order.data, len); + if (kBytes == NULL) goto cleanup; + + /* Generate ECDSA signature with the specified k value */ + rv = ECDSA_SignDigestWithSeed(key, signature, digest, kBytes, len); cleanup: - if (kseed) PORT_ZFree(kseed, n); + if (kBytes) { + PORT_ZFree(kBytes, len); + } #if EC_DEBUG printf("ECDSA signing %s\n", @@ -855,75 +875,65 @@ ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature, #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 x1; 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; + int slen; /* length in bytes of a half signature (r or s) */ + int flen; /* length in bytes of the field size */ + unsigned olen; /* length in bytes of the base point order */ #if EC_DEBUG char mpstr[256]; printf("ECDSA verification called\n"); #endif + /* Initialize MPI integers. */ + /* must happen before the first potential call to cleanup */ + 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(&v) = 0; + MP_DIGITS(&n) = 0; + /* Check args */ - if (!key || !signature || !digest || - (digest->len != SHA1_LENGTH)) { + if (!key || !signature || !digest) { 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); + flen = (ecParams->fieldID.size + 7) >> 3; + olen = ecParams->order.len; + if (signature->len == 0 || signature->len%2 != 0 || + signature->len > 2*olen) { + PORT_SetError(SEC_ERROR_INPUT_LEN); goto cleanup; } + slen = signature->len/2; - /* Initialize an arena for pointA, pointB and pointC */ - if ((arena = PORT_NewArena(NSS_FREEBL_DEFAULT_CHUNKSIZE)) == NULL) + SECITEM_AllocItem(NULL, &pointC, 2*flen + 1); + if (pointC.data == 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) ); + CHECK_MPI_OK( mp_read_unsigned_octets(&r_, signature->data, slen) ); + CHECK_MPI_OK( mp_read_unsigned_octets(&s_, signature->data + slen, slen) ); /* ** ANSI X9.62, Section 5.4.2, Steps 1 and 2 @@ -932,8 +942,10 @@ ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature, */ 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) + mp_cmp(&r_, &n) >= 0 || mp_cmp(&s_, &n) >= 0) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); goto cleanup; /* will return rv == SECFailure */ + } /* ** ANSI X9.62, Section 5.4.2, Step 3 @@ -945,9 +957,16 @@ ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature, /* ** ANSI X9.62, Section 5.4.2, Step 4 ** - ** u1 = ((SHA1(M')) * c) mod n + ** u1 = ((HASH(M')) * c) mod n */ - SECITEM_TO_MPINT(*digest, &u1); /* u1 = SHA1(M') */ + SECITEM_TO_MPINT(*digest, &u1); /* u1 = HASH(M) */ + + /* In the definition of EC signing, digests are truncated + * to the length of n in bits. + * (see SEC 1 "Elliptic Curve Digit Signature Algorithm" section 4.1.*/ + if (digest->len*8 > ecParams->fieldID.size) { /* u1 = HASH(M') */ + mpl_rsh(&u1,&u1,digest->len*8- ecParams->fieldID.size); + } #if EC_DEBUG mp_todecimal(&r_, mpstr); @@ -976,13 +995,18 @@ ECDSA_VerifyDigest(ECPublicKey *key, const SECItem *signature, ** 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_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC) == SECFailure) || - ec_point_at_infinity(&pointC)) { - rv = SECFailure; - goto cleanup; + if (ec_points_mul(ecParams, &u1, &u2, &key->publicValue, &pointC) + != SECSuccess) { + rv = SECFailure; + goto cleanup; + } + if (ec_point_at_infinity(&pointC)) { + PORT_SetError(SEC_ERROR_BAD_SIGNATURE); + rv = SECFailure; + goto cleanup; } - CHECK_MPI_OK( mp_read_unsigned_octets(&x1, pointC.data + 1, len) ); + CHECK_MPI_OK( mp_read_unsigned_octets(&x1, pointC.data + 1, flen) ); /* ** ANSI X9.62, Section 5.4.4, Step 2 @@ -1028,13 +1052,10 @@ cleanup: 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 (pointC.data) SECITEM_FreeItem(&pointC, PR_FALSE); if (err) { MP_TO_SEC_ERROR(err); rv = SECFailure; diff --git a/security/nss/lib/freebl/ecl/Makefile b/security/nss/lib/freebl/ecl/Makefile index c791531eb..7af8d48e3 100644 --- a/security/nss/lib/freebl/ecl/Makefile +++ b/security/nss/lib/freebl/ecl/Makefile @@ -113,7 +113,7 @@ LIBOBJS = ecl.o ecl_curve.o ecl_mult.o ecl_gf.o \ ec2_163.o ec2_193.o ec2_233.o \ ecp_aff.o ecp_jac.o ecp_mont.o \ ec_naf.o ecp_jm.o \ - ecp_192.o ecp_224.o + ecp_192.o ecp_224.o ecp_256.o ecp_384.o ecp_521.o ifeq ($(ECL_USE_FP),1) LIBOBJS+= ecp_fp160.o ecp_fp192.o ecp_fp224.o ecp_fp.o endif @@ -162,6 +162,9 @@ ecp_jm.o: ecp_jm.c $(LIBHDRS) ecp_mont.o: ecp_mont.c $(LIBHDRS) ecp_192.o: ecp_192.c $(LIBHDRS) ecp_224.o: ecp_224.c $(LIBHDRS) +ecp_256.o: ecp_256.c $(LIBHDRS) +ecp_384.o: ecp_384.c $(LIBHDRS) +ecp_521.o: ecp_521.c $(LIBHDRS) ecp_fp.o: ecp_fp.c $(LIBHDRS) ifeq ($(ECL_USE_FP),1) ecp_fp160.o: ecp_fp160.c ecp_fpinc.c $(LIBHDRS) diff --git a/security/nss/lib/freebl/ecl/ec2_aff.c b/security/nss/lib/freebl/ecl/ec2_aff.c index 45b277001..64bb6fecc 100644 --- a/security/nss/lib/freebl/ecl/ec2_aff.c +++ b/security/nss/lib/freebl/ecl/ec2_aff.c @@ -312,7 +312,6 @@ ec_GF2m_validate_point(const mp_int *px, const mp_int *py, const ECGroup *group) /* left-hand side: y^2 + x*y */ MP_CHECKOK( group->meth->field_sqr(&pyt, &accl, group->meth) ); MP_CHECKOK( group->meth->field_mul(&pxt, &pyt, &tmp, group->meth) ); - MP_CHECKOK( group->meth->field_mul(&pxt, &pyt, &tmp, group->meth) ); MP_CHECKOK( group->meth->field_add(&accl, &tmp, &accl, group->meth) ); /* right-hand side: x^3 + a*x^2 + b */ MP_CHECKOK( group->meth->field_sqr(&pxt, &tmp, group->meth) ); diff --git a/security/nss/lib/freebl/ecl/ecl-curve.h b/security/nss/lib/freebl/ecl/ecl-curve.h index fed21fa52..36651dada 100644 --- a/security/nss/lib/freebl/ecl/ecl-curve.h +++ b/security/nss/lib/freebl/ecl/ecl-curve.h @@ -42,25 +42,6 @@ #ifndef __ecl_curve_h_ #define __ecl_curve_h_ -/* NIST prime curves */ -static const ECCurveParams ecCurve_NIST_P192 = { - "NIST-P192", ECField_GFp, 192, - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", - "64210519E59C80E70FA7E9AB72243049FEB8DEECC146B9B1", - "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012", - "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811", - "FFFFFFFFFFFFFFFFFFFFFFFF99DEF836146BC9B1B4D22831", 1 -}; -static const ECCurveParams ecCurve_NIST_P224 = { - "NIST-P224", ECField_GFp, 224, - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF000000000000000000000001", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFFFFFFFFFE", - "B4050A850C04B3ABF54132565044B0B7D7BFD8BA270B39432355FFB4", - "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21", - "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFF16A2E0B8F03E13DD29455C5C2A3D", 1 -}; static const ECCurveParams ecCurve_NIST_P256 = { "NIST-P256", ECField_GFp, 256, "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF", @@ -70,6 +51,7 @@ static const ECCurveParams ecCurve_NIST_P256 = { "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5", "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551", 1 }; + static const ECCurveParams ecCurve_NIST_P384 = { "NIST-P384", ECField_GFp, 384, "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF", @@ -80,6 +62,7 @@ static const ECCurveParams ecCurve_NIST_P384 = { "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973", 1 }; + static const ECCurveParams ecCurve_NIST_P521 = { "NIST-P521", ECField_GFp, 521, "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF", @@ -91,558 +74,67 @@ static const ECCurveParams ecCurve_NIST_P521 = { 1 }; -/* NIST binary curves */ -static const ECCurveParams ecCurve_NIST_K163 = { - "NIST-K163", ECField_GF2m, 163, - "0800000000000000000000000000000000000000C9", - "000000000000000000000000000000000000000001", - "000000000000000000000000000000000000000001", - "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8", - "0289070FB05D38FF58321F2E800536D538CCDAA3D9", - "04000000000000000000020108A2E0CC0D99F8A5EF", 2 -}; -static const ECCurveParams ecCurve_NIST_B163 = { - "NIST-B163", ECField_GF2m, 163, - "0800000000000000000000000000000000000000C9", - "000000000000000000000000000000000000000001", - "020A601907B8C953CA1481EB10512F78744A3205FD", - "03F0EBA16286A2D57EA0991168D4994637E8343E36", - "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1", - "040000000000000000000292FE77E70C12A4234C33", 2 -}; -static const ECCurveParams ecCurve_NIST_K233 = { - "NIST-K233", ECField_GF2m, 233, - "020000000000000000000000000000000000000004000000000000000001", - "000000000000000000000000000000000000000000000000000000000000", - "000000000000000000000000000000000000000000000000000000000001", - "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126", - "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3", - "8000000000000000000000000000069D5BB915BCD46EFB1AD5F173ABDF", 4 -}; -static const ECCurveParams ecCurve_NIST_B233 = { - "NIST-B233", ECField_GF2m, 233, - "020000000000000000000000000000000000000004000000000000000001", - "000000000000000000000000000000000000000000000000000000000001", - "0066647EDE6C332C7F8C0923BB58213B333B20E9CE4281FE115F7D8F90AD", - "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B", - "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052", - "01000000000000000000000000000013E974E72F8A6922031D2603CFE0D7", 2 -}; -static const ECCurveParams ecCurve_NIST_K283 = { - "NIST-K283", ECField_GF2m, 283, - "0800000000000000000000000000000000000000000000000000000000000000000010A1", - "000000000000000000000000000000000000000000000000000000000000000000000000", - "000000000000000000000000000000000000000000000000000000000000000000000001", - "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836", - "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259", - "01FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE9AE2ED07577265DFF7F94451E061E163C61", - 4 -}; -static const ECCurveParams ecCurve_NIST_B283 = { - "NIST-B283", ECField_GF2m, 283, - "0800000000000000000000000000000000000000000000000000000000000000000010A1", - "000000000000000000000000000000000000000000000000000000000000000000000001", - "027B680AC8B8596DA5A4AF8A19A0303FCA97FD7645309FA2A581485AF6263E313B79A2F5", - "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053", - "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4", - "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEF90399660FC938A90165B042A7CEFADB307", - 2 -}; -static const ECCurveParams ecCurve_NIST_K409 = { - "NIST-K409", ECField_GF2m, 409, - "02000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000001", - "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", - "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746", - "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B", - "7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE5F83B2D4EA20400EC4557D5ED3E3E7CA5B4B5C83B8E01E5FCF", - 4 -}; -static const ECCurveParams ecCurve_NIST_B409 = { - "NIST-B409", ECField_GF2m, 409, - "02000000000000000000000000000000000000000000000000000000000000000000000000000000008000000000000000000001", - "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", - "0021A5C2C8EE9FEB5C4B9A753B7B476B7FD6422EF1F3DD674761FA99D6AC27C8A9A197B272822F6CD57A55AA4F50AE317B13545F", - "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7", - "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706", - "010000000000000000000000000000000000000000000000000001E2AAD6A612F33307BE5FA47C3C9E052F838164CD37D9A21173", - 2 -}; -static const ECCurveParams ecCurve_NIST_K571 = { - "NIST-K571", ECField_GF2m, 571, - "080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425", - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000", - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", - "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972", - "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3", - "020000000000000000000000000000000000000000000000000000000000000000000000131850E1F19A63E4B391A8DB917F4138B630D84BE5D639381E91DEB45CFE778F637C1001", - 4 -}; -static const ECCurveParams ecCurve_NIST_B571 = { - "NIST-B571", ECField_GF2m, 571, - "080000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000425", - "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001", - "02F40E7E2221F295DE297117B7F3D62F5C6A97FFCB8CEFF1CD6BA8CE4A9A18AD84FFABBD8EFA59332BE7AD6756A66E294AFD185A78FF12AA520E4DE739BACA0C7FFEFF7F2955727A", - "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19", - "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B", - "03FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE661CE18FF55987308059B186823851EC7DD9CA1161DE93D5174D66E8382E9BB2FE84E47", - 2 -}; - -/* ANSI X9.62 prime curves */ -static const ECCurveParams ecCurve_X9_62_PRIME_192V2 = { - "X9.62 P-192V2", ECField_GFp, 192, - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", - "CC22D6DFB95C6B25E49C0D6364A4E5980C393AA21668D953", - "EEA2BAE7E1497842F2DE7769CFE9C989C072AD696F48034A", - "6574D11D69B6EC7A672BB82A083DF2F2B0847DE970B2DE15", - "FFFFFFFFFFFFFFFFFFFFFFFE5FB1A724DC80418648D8DD31", 1 -}; -static const ECCurveParams ecCurve_X9_62_PRIME_192V3 = { - "X9.62 P-192V3", ECField_GFp, 192, - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFF", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFFFFFFFFFC", - "22123DC2395A05CAA7423DAECCC94760A7D462256BD56916", - "7D29778100C65A1DA1783716588DCE2B8B4AEE8E228F1896", - "38A90F22637337334B49DCB66A6DC8F9978ACA7648A943B0", - "FFFFFFFFFFFFFFFFFFFFFFFF7A62D031C83F4294F640EC13", 1 -}; -static const ECCurveParams ecCurve_X9_62_PRIME_239V1 = { - "X9.62 P-239V1", ECField_GFp, 239, - "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", - "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", - "6B016C3BDCF18941D0D654921475CA71A9DB2FB27D1D37796185C2942C0A", - "0FFA963CDCA8816CCC33B8642BEDF905C3D358573D3F27FBBD3B3CB9AAAF", - "7DEBE8E4E90A5DAE6E4054CA530BA04654B36818CE226B39FCCB7B02F1AE", - "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF9E5E9A9F5D9071FBD1522688909D0B", 1 -}; -static const ECCurveParams ecCurve_X9_62_PRIME_239V2 = { - "X9.62 P-239V2", ECField_GFp, 239, - "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", - "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", - "617FAB6832576CBBFED50D99F0249C3FEE58B94BA0038C7AE84C8C832F2C", - "38AF09D98727705120C921BB5E9E26296A3CDCF2F35757A0EAFD87B830E7", - "5B0125E4DBEA0EC7206DA0FC01D9B081329FB555DE6EF460237DFF8BE4BA", - "7FFFFFFFFFFFFFFFFFFFFFFF800000CFA7E8594377D414C03821BC582063", 1 -}; -static const ECCurveParams ecCurve_X9_62_PRIME_239V3 = { - "X9.62 P-239V3", ECField_GFp, 239, - "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFF", - "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFFFFFFFF8000000000007FFFFFFFFFFC", - "255705FA2A306654B1F4CB03D6A750A30C250102D4988717D9BA15AB6D3E", - "6768AE8E18BB92CFCF005C949AA2C6D94853D0E660BBF854B1C9505FE95A", - "1607E6898F390C06BC1D552BAD226F3B6FCFE48B6E818499AF18E3ED6CF3", - "7FFFFFFFFFFFFFFFFFFFFFFF7FFFFF975DEB41B3A6057C3C432146526551", 1 -}; - -/* ANSI X9.62 binary curves */ -static const ECCurveParams ecCurve_X9_62_CHAR2_PNB163V1 = { - "X9.62 C2-PNB163V1", ECField_GF2m, 163, - "080000000000000000000000000000000000000107", - "072546B5435234A422E0789675F432C89435DE5242", - "00C9517D06D5240D3CFF38C74B20B6CD4D6F9DD4D9", - "07AF69989546103D79329FCC3D74880F33BBE803CB", - "01EC23211B5966ADEA1D3F87F7EA5848AEF0B7CA9F", - "0400000000000000000001E60FC8821CC74DAEAFC1", 2 -}; -static const ECCurveParams ecCurve_X9_62_CHAR2_PNB163V2 = { - "X9.62 C2-PNB163V2", ECField_GF2m, 163, - "080000000000000000000000000000000000000107", - "0108B39E77C4B108BED981ED0E890E117C511CF072", - "0667ACEB38AF4E488C407433FFAE4F1C811638DF20", - "0024266E4EB5106D0A964D92C4860E2671DB9B6CC5", - "079F684DDF6684C5CD258B3890021B2386DFD19FC5", - "03FFFFFFFFFFFFFFFFFFFDF64DE1151ADBB78F10A7", 2 -}; -static const ECCurveParams ecCurve_X9_62_CHAR2_PNB163V3 = { - "X9.62 C2-PNB163V3", ECField_GF2m, 163, - "080000000000000000000000000000000000000107", - "07A526C63D3E25A256A007699F5447E32AE456B50E", - "03F7061798EB99E238FD6F1BF95B48FEEB4854252B", - "02F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB", - "05B935590C155E17EA48EB3FF3718B893DF59A05D0", - "03FFFFFFFFFFFFFFFFFFFE1AEE140F110AFF961309", 2 -}; -static const ECCurveParams ecCurve_X9_62_CHAR2_PNB176V1 = { - "X9.62 C2-PNB176V1", ECField_GF2m, 176, - "0100000000000000000000000000000000080000000007", - "E4E6DB2995065C407D9D39B8D0967B96704BA8E9C90B", - "5DDA470ABE6414DE8EC133AE28E9BBD7FCEC0AE0FFF2", - "8D16C2866798B600F9F08BB4A8E860F3298CE04A5798", - "6FA4539C2DADDDD6BAB5167D61B436E1D92BB16A562C", - "00010092537397ECA4F6145799D62B0A19CE06FE26AD", 0xFF6E -}; -static const ECCurveParams ecCurve_X9_62_CHAR2_TNB191V1 = { - "X9.62 C2-TNB191V1", ECField_GF2m, 191, - "800000000000000000000000000000000000000000000201", - "2866537B676752636A68F56554E12640276B649EF7526267", - "2E45EF571F00786F67B0081B9495A3D95462F5DE0AA185EC", - "36B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D", - "765BE73433B3F95E332932E70EA245CA2418EA0EF98018FB", - "40000000000000000000000004A20E90C39067C893BBB9A5", 2 -}; -static const ECCurveParams ecCurve_X9_62_CHAR2_TNB191V2 = { - "X9.62 C2-TNB191V2", ECField_GF2m, 191, - "800000000000000000000000000000000000000000000201", - "401028774D7777C7B7666D1366EA432071274F89FF01E718", - "0620048D28BCBD03B6249C99182B7C8CD19700C362C46A01", - "3809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10", - "17434386626D14F3DBF01760D9213A3E1CF37AEC437D668A", - "20000000000000000000000050508CB89F652824E06B8173", 4 -}; -static const ECCurveParams ecCurve_X9_62_CHAR2_TNB191V3 = { - "X9.62 C2-TNB191V3", ECField_GF2m, 191, - "800000000000000000000000000000000000000000000201", - "6C01074756099122221056911C77D77E77A777E7E7E77FCB", - "71FE1AF926CF847989EFEF8DB459F66394D90F32AD3F15E8", - "375D4CE24FDE434489DE8746E71786015009E66E38A926DD", - "545A39176196575D985999366E6AD34CE0A77CD7127B06BE", - "155555555555555555555555610C0B196812BFB6288A3EA3", 6 -}; -static const ECCurveParams ecCurve_X9_62_CHAR2_PNB208W1 = { - "X9.62 C2-PNB208W1", ECField_GF2m, 208, - "010000000000000000000000000000000800000000000000000007", - "0000000000000000000000000000000000000000000000000000", - "C8619ED45A62E6212E1160349E2BFA844439FAFC2A3FD1638F9E", - "89FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A", - "0F55B51A06E78E9AC38A035FF520D8B01781BEB1A6BB08617DE3", - "000101BAF95C9723C57B6C21DA2EFF2D5ED588BDD5717E212F9D", 0xFE48 -}; -static const ECCurveParams ecCurve_X9_62_CHAR2_TNB239V1 = { - "X9.62 C2-TNB239V1", ECField_GF2m, 239, - "800000000000000000000000000000000000000000000000001000000001", - "32010857077C5431123A46B808906756F543423E8D27877578125778AC76", - "790408F2EEDAF392B012EDEFB3392F30F4327C0CA3F31FC383C422AA8C16", - "57927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D", - "61D8EE5077C33FECF6F1A16B268DE469C3C7744EA9A971649FC7A9616305", - "2000000000000000000000000000000F4D42FFE1492A4993F1CAD666E447", 4 -}; -static const ECCurveParams ecCurve_X9_62_CHAR2_TNB239V2 = { - "X9.62 C2-TNB239V2", ECField_GF2m, 239, - "800000000000000000000000000000000000000000000000001000000001", - "4230017757A767FAE42398569B746325D45313AF0766266479B75654E65F", - "5037EA654196CFF0CD82B2C14A2FCF2E3FF8775285B545722F03EACDB74B", - "28F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205", - "5667334C45AFF3B5A03BAD9DD75E2C71A99362567D5453F7FA6E227EC833", - "1555555555555555555555555555553C6F2885259C31E3FCDF154624522D", 6 -}; -static const ECCurveParams ecCurve_X9_62_CHAR2_TNB239V3 = { - "X9.62 C2-TNB239V3", ECField_GF2m, 239, - "800000000000000000000000000000000000000000000000001000000001", - "01238774666A67766D6676F778E676B66999176666E687666D8766C66A9F", - "6A941977BA9F6A435199ACFC51067ED587F519C5ECB541B8E44111DE1D40", - "70F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92", - "2E5A0EAF6E5E1305B9004DCE5C0ED7FE59A35608F33837C816D80B79F461", - "0CCCCCCCCCCCCCCCCCCCCCCCCCCCCCAC4912D2D9DF903EF9888B8A0E4CFF", 0xA -}; -static const ECCurveParams ecCurve_X9_62_CHAR2_PNB272W1 = { - "X9.62 C2-PNB272W1", ECField_GF2m, 272, - "010000000000000000000000000000000000000000000000000000010000000000000B", - "91A091F03B5FBA4AB2CCF49C4EDD220FB028712D42BE752B2C40094DBACDB586FB20", - "7167EFC92BB2E3CE7C8AAAFF34E12A9C557003D7C73A6FAF003F99F6CC8482E540F7", - "6108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D", - "10C7695716851EEF6BA7F6872E6142FBD241B830FF5EFCACECCAB05E02005DDE9D23", - "000100FAF51354E0E39E4892DF6E319C72C8161603FA45AA7B998A167B8F1E629521", - 0xFF06 -}; -static const ECCurveParams ecCurve_X9_62_CHAR2_PNB304W1 = { - "X9.62 C2-PNB304W1", ECField_GF2m, 304, - "010000000000000000000000000000000000000000000000000000000000000000000000000807", - "FD0D693149A118F651E6DCE6802085377E5F882D1B510B44160074C1288078365A0396C8E681", - "BDDB97E555A50A908E43B01C798EA5DAA6788F1EA2794EFCF57166B8C14039601E55827340BE", - "197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614", - "E19FBEB76E0DA171517ECF401B50289BF014103288527A9B416A105E80260B549FDC1B92C03B", - "000101D556572AABAC800101D556572AABAC8001022D5C91DD173F8FB561DA6899164443051D", - 0xFE2E -}; -static const ECCurveParams ecCurve_X9_62_CHAR2_TNB359V1 = { - "X9.62 C2-TNB359V1", ECField_GF2m, 359, - "800000000000000000000000000000000000000000000000000000000000000000000000100000000000000001", - "5667676A654B20754F356EA92017D946567C46675556F19556A04616B567D223A5E05656FB549016A96656A557", - "2472E2D0197C49363F1FE7F5B6DB075D52B6947D135D8CA445805D39BC345626089687742B6329E70680231988", - "3C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097", - "53D7E08529547048121E9C95F3791DD804963948F34FAE7BF44EA82365DC7868FE57E4AE2DE211305A407104BD", - "01AF286BCA1AF286BCA1AF286BCA1AF286BCA1AF286BC9FB8F6B85C556892C20A7EB964FE7719E74F490758D3B", - 0x4C -}; -static const ECCurveParams ecCurve_X9_62_CHAR2_PNB368W1 = { - "X9.62 C2-PNB368W1", ECField_GF2m, 368, - "0100000000000000000000000000000000000000000000000000000000000000000000002000000000000000000007", - "E0D2EE25095206F5E2A4F9ED229F1F256E79A0E2B455970D8D0D865BD94778C576D62F0AB7519CCD2A1A906AE30D", - "FC1217D4320A90452C760A58EDCD30C8DD069B3C34453837A34ED50CB54917E1C2112D84D164F444F8F74786046A", - "1085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F", - "7B3EB1BDDCBA62D5D8B2059B525797FC73822C59059C623A45FF3843CEE8F87CD1855ADAA81E2A0750B80FDA2310", - "00010090512DA9AF72B08349D98A5DD4C7B0532ECA51CE03E2D10F3B7AC579BD87E909AE40A6F131E9CFCE5BD967", - 0xFF70 -}; -static const ECCurveParams ecCurve_X9_62_CHAR2_TNB431R1 = { - "X9.62 C2-TNB431R1", ECField_GF2m, 431, - "800000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000001", - "1A827EF00DD6FC0E234CAF046C6A5D8A85395B236CC4AD2CF32A0CADBDC9DDF620B0EB9906D0957F6C6FEACD615468DF104DE296CD8F", - "10D9B4A3D9047D8B154359ABFB1B7F5485B04CEB868237DDC9DEDA982A679A5A919B626D4E50A8DD731B107A9962381FB5D807BF2618", - "120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7", - "20D0AF8903A96F8D5FA2C255745D3C451B302C9346D9B7E485E7BCE41F6B591F3E8F6ADDCBB0BC4C2F947A7DE1A89B625D6A598B3760", - "0340340340340340340340340340340340340340340340340340340323C313FAB50589703B5EC68D3587FEC60D161CC149C1AD4A91", - 0x2760 -}; - -/* SEC2 prime curves */ -static const ECCurveParams ecCurve_SECG_PRIME_112R1 = { - "SECP-112R1", ECField_GFp, 112, - "DB7C2ABF62E35E668076BEAD208B", - "DB7C2ABF62E35E668076BEAD2088", - "659EF8BA043916EEDE8911702B22", - "09487239995A5EE76B55F9C2F098", - "A89CE5AF8724C0A23E0E0FF77500", - "DB7C2ABF62E35E7628DFAC6561C5", 1 -}; -static const ECCurveParams ecCurve_SECG_PRIME_112R2 = { - "SECP-112R2", ECField_GFp, 112, - "DB7C2ABF62E35E668076BEAD208B", - "6127C24C05F38A0AAAF65C0EF02C", - "51DEF1815DB5ED74FCC34C85D709", - "4BA30AB5E892B4E1649DD0928643", - "adcd46f5882e3747def36e956e97", - "36DF0AAFD8B8D7597CA10520D04B", 4 -}; -static const ECCurveParams ecCurve_SECG_PRIME_128R1 = { - "SECP-128R1", ECField_GFp, 128, - "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", - "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFC", - "E87579C11079F43DD824993C2CEE5ED3", - "161FF7528B899B2D0C28607CA52C5B86", - "CF5AC8395BAFEB13C02DA292DDED7A83", - "FFFFFFFE0000000075A30D1B9038A115", 1 -}; -static const ECCurveParams ecCurve_SECG_PRIME_128R2 = { - "SECP-128R2", ECField_GFp, 128, - "FFFFFFFDFFFFFFFFFFFFFFFFFFFFFFFF", - "D6031998D1B3BBFEBF59CC9BBFF9AEE1", - "5EEEFCA380D02919DC2C6558BB6D8A5D", - "7B6AA5D85E572983E6FB32A7CDEBC140", - "27B6916A894D3AEE7106FE805FC34B44", - "3FFFFFFF7FFFFFFFBE0024720613B5A3", 4 -}; -static const ECCurveParams ecCurve_SECG_PRIME_160K1 = { - "SECP-160K1", ECField_GFp, 160, - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", - "0000000000000000000000000000000000000000", - "0000000000000000000000000000000000000007", - "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB", - "938CF935318FDCED6BC28286531733C3F03C4FEE", - "0100000000000000000001B8FA16DFAB9ACA16B6B3", 1 -}; -static const ECCurveParams ecCurve_SECG_PRIME_160R1 = { - "SECP-160R1", ECField_GFp, 160, - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFF", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF7FFFFFFC", - "1C97BEFC54BD7A8B65ACF89F81D4D4ADC565FA45", - "4A96B5688EF573284664698968C38BB913CBFC82", - "23A628553168947D59DCC912042351377AC5FB32", - "0100000000000000000001F4C8F927AED3CA752257", 1 -}; -static const ECCurveParams ecCurve_SECG_PRIME_160R2 = { - "SECP-160R2", ECField_GFp, 160, - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC73", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFAC70", - "B4E134D3FB59EB8BAB57274904664D5AF50388BA", - "52DCB034293A117E1F4FF11B30F7199D3144CE6D", - "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E", - "0100000000000000000000351EE786A818F3A1A16B", 1 -}; -static const ECCurveParams ecCurve_SECG_PRIME_192K1 = { - "SECP-192K1", ECField_GFp, 192, - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFEE37", - "000000000000000000000000000000000000000000000000", - "000000000000000000000000000000000000000000000003", - "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D", - "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D", - "FFFFFFFFFFFFFFFFFFFFFFFE26F2FC170F69466A74DEFD8D", 1 -}; -static const ECCurveParams ecCurve_SECG_PRIME_224K1 = { - "SECP-224K1", ECField_GFp, 224, - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFE56D", - "00000000000000000000000000000000000000000000000000000000", - "00000000000000000000000000000000000000000000000000000005", - "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C", - "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5", - "010000000000000000000000000001DCE8D2EC6184CAF0A971769FB1F7", 1 -}; -static const ECCurveParams ecCurve_SECG_PRIME_256K1 = { - "SECP-256K1", ECField_GFp, 256, - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F", - "0000000000000000000000000000000000000000000000000000000000000000", - "0000000000000000000000000000000000000000000000000000000000000007", - "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798", - "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8", - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141", 1 -}; - -/* SEC2 binary curves */ -static const ECCurveParams ecCurve_SECG_CHAR2_113R1 = { - "SECT-113R1", ECField_GF2m, 113, - "020000000000000000000000000201", - "003088250CA6E7C7FE649CE85820F7", - "00E8BEE4D3E2260744188BE0E9C723", - "009D73616F35F4AB1407D73562C10F", - "00A52830277958EE84D1315ED31886", - "0100000000000000D9CCEC8A39E56F", 2 -}; -static const ECCurveParams ecCurve_SECG_CHAR2_113R2 = { - "SECT-113R2", ECField_GF2m, 113, - "020000000000000000000000000201", - "00689918DBEC7E5A0DD6DFC0AA55C7", - "0095E9A9EC9B297BD4BF36E059184F", - "01A57A6A7B26CA5EF52FCDB8164797", - "00B3ADC94ED1FE674C06E695BABA1D", - "010000000000000108789B2496AF93", 2 -}; -static const ECCurveParams ecCurve_SECG_CHAR2_131R1 = { - "SECT-131R1", ECField_GF2m, 131, - "080000000000000000000000000000010D", - "07A11B09A76B562144418FF3FF8C2570B8", - "0217C05610884B63B9C6C7291678F9D341", - "0081BAF91FDF9833C40F9C181343638399", - "078C6E7EA38C001F73C8134B1B4EF9E150", - "0400000000000000023123953A9464B54D", 2 -}; -static const ECCurveParams ecCurve_SECG_CHAR2_131R2 = { - "SECT-131R2", ECField_GF2m, 131, - "080000000000000000000000000000010D", - "03E5A88919D7CAFCBF415F07C2176573B2", - "04B8266A46C55657AC734CE38F018F2192", - "0356DCD8F2F95031AD652D23951BB366A8", - "0648F06D867940A5366D9E265DE9EB240F", - "0400000000000000016954A233049BA98F", 2 -}; -static const ECCurveParams ecCurve_SECG_CHAR2_163R1 = { - "SECT-163R1", ECField_GF2m, 163, - "0800000000000000000000000000000000000000C9", - "07B6882CAAEFA84F9554FF8428BD88E246D2782AE2", - "0713612DCDDCB40AAB946BDA29CA91F73AF958AFD9", - "0369979697AB43897789566789567F787A7876A654", - "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883", - "03FFFFFFFFFFFFFFFFFFFF48AAB689C29CA710279B", 2 -}; -static const ECCurveParams ecCurve_SECG_CHAR2_193R1 = { - "SECT-193R1", ECField_GF2m, 193, - "02000000000000000000000000000000000000000000008001", - "0017858FEB7A98975169E171F77B4087DE098AC8A911DF7B01", - "00FDFB49BFE6C3A89FACADAA7A1E5BBC7CC1C2E5D831478814", - "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1", - "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05", - "01000000000000000000000000C7F34A778F443ACC920EBA49", 2 -}; -static const ECCurveParams ecCurve_SECG_CHAR2_193R2 = { - "SECT-193R2", ECField_GF2m, 193, - "02000000000000000000000000000000000000000000008001", - "0163F35A5137C2CE3EA6ED8667190B0BC43ECD69977702709B", - "00C9BB9E8927D4D64C377E2AB2856A5B16E3EFB7F61D4316AE", - "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F", - "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C", - "010000000000000000000000015AAB561B005413CCD4EE99D5", 2 -}; -static const ECCurveParams ecCurve_SECG_CHAR2_239K1 = { - "SECT-239K1", ECField_GF2m, 239, - "800000000000000000004000000000000000000000000000000000000001", - "000000000000000000000000000000000000000000000000000000000000", - "000000000000000000000000000000000000000000000000000000000001", - "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC", - "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA", - "2000000000000000000000000000005A79FEC67CB6E91F1C1DA800E478A5", 4 -}; - -/* WTLS curves */ -static const ECCurveParams ecCurve_WTLS_1 = { - "WTLS-1", ECField_GF2m, 113, - "020000000000000000000000000201", - "000000000000000000000000000001", - "000000000000000000000000000001", - "01667979A40BA497E5D5C270780617", - "00F44B4AF1ECC2630E08785CEBCC15", - "00FFFFFFFFFFFFFFFDBF91AF6DEA73", 2 -}; -static const ECCurveParams ecCurve_WTLS_8 = { - "WTLS-8", ECField_GFp, 112, - "FFFFFFFFFFFFFFFFFFFFFFFFFDE7", - "0000000000000000000000000000", - "0000000000000000000000000003", - "0000000000000000000000000001", - "0000000000000000000000000002", - "0100000000000001ECEA551AD837E9", 1 -}; -static const ECCurveParams ecCurve_WTLS_9 = { - "WTLS-9", ECField_GFp, 160, - "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC808F", - "0000000000000000000000000000000000000000", - "0000000000000000000000000000000000000003", - "0000000000000000000000000000000000000001", - "0000000000000000000000000000000000000002", - "0100000000000000000001CDC98AE0E2DE574ABF33", 1 -}; - /* mapping between ECCurveName enum and pointers to ECCurveParams */ static const ECCurveParams *ecCurve_map[] = { - NULL, /* ECCurve_noName */ - &ecCurve_NIST_P192, /* ECCurve_NIST_P192 */ - &ecCurve_NIST_P224, /* ECCurve_NIST_P224 */ - &ecCurve_NIST_P256, /* ECCurve_NIST_P256 */ - &ecCurve_NIST_P384, /* ECCurve_NIST_P384 */ - &ecCurve_NIST_P521, /* ECCurve_NIST_P521 */ - &ecCurve_NIST_K163, /* ECCurve_NIST_K163 */ - &ecCurve_NIST_B163, /* ECCurve_NIST_B163 */ - &ecCurve_NIST_K233, /* ECCurve_NIST_K233 */ - &ecCurve_NIST_B233, /* ECCurve_NIST_B233 */ - &ecCurve_NIST_K283, /* ECCurve_NIST_K283 */ - &ecCurve_NIST_B283, /* ECCurve_NIST_B283 */ - &ecCurve_NIST_K409, /* ECCurve_NIST_K409 */ - &ecCurve_NIST_B409, /* ECCurve_NIST_B409 */ - &ecCurve_NIST_K571, /* ECCurve_NIST_K571 */ - &ecCurve_NIST_B571, /* ECCurve_NIST_B571 */ - &ecCurve_X9_62_PRIME_192V2, /* ECCurve_X9_62_PRIME_192V2 */ - &ecCurve_X9_62_PRIME_192V3, /* ECCurve_X9_62_PRIME_192V3 */ - &ecCurve_X9_62_PRIME_239V1, /* ECCurve_X9_62_PRIME_239V1 */ - &ecCurve_X9_62_PRIME_239V2, /* ECCurve_X9_62_PRIME_239V2 */ - &ecCurve_X9_62_PRIME_239V3, /* ECCurve_X9_62_PRIME_239V3 */ - &ecCurve_X9_62_CHAR2_PNB163V1, /* ECCurve_X9_62_CHAR2_PNB163V1 */ - &ecCurve_X9_62_CHAR2_PNB163V2, /* ECCurve_X9_62_CHAR2_PNB163V2 */ - &ecCurve_X9_62_CHAR2_PNB163V3, /* ECCurve_X9_62_CHAR2_PNB163V3 */ - &ecCurve_X9_62_CHAR2_PNB176V1, /* ECCurve_X9_62_CHAR2_PNB176V1 */ - &ecCurve_X9_62_CHAR2_TNB191V1, /* ECCurve_X9_62_CHAR2_TNB191V1 */ - &ecCurve_X9_62_CHAR2_TNB191V2, /* ECCurve_X9_62_CHAR2_TNB191V2 */ - &ecCurve_X9_62_CHAR2_TNB191V3, /* ECCurve_X9_62_CHAR2_TNB191V3 */ - &ecCurve_X9_62_CHAR2_PNB208W1, /* ECCurve_X9_62_CHAR2_PNB208W1 */ - &ecCurve_X9_62_CHAR2_TNB239V1, /* ECCurve_X9_62_CHAR2_TNB239V1 */ - &ecCurve_X9_62_CHAR2_TNB239V2, /* ECCurve_X9_62_CHAR2_TNB239V2 */ - &ecCurve_X9_62_CHAR2_TNB239V3, /* ECCurve_X9_62_CHAR2_TNB239V3 */ - &ecCurve_X9_62_CHAR2_PNB272W1, /* ECCurve_X9_62_CHAR2_PNB272W1 */ - &ecCurve_X9_62_CHAR2_PNB304W1, /* ECCurve_X9_62_CHAR2_PNB304W1 */ - &ecCurve_X9_62_CHAR2_TNB359V1, /* ECCurve_X9_62_CHAR2_TNB359V1 */ - &ecCurve_X9_62_CHAR2_PNB368W1, /* ECCurve_X9_62_CHAR2_PNB368W1 */ - &ecCurve_X9_62_CHAR2_TNB431R1, /* ECCurve_X9_62_CHAR2_TNB431R1 */ - &ecCurve_SECG_PRIME_112R1, /* ECCurve_SECG_PRIME_112R1 */ - &ecCurve_SECG_PRIME_112R2, /* ECCurve_SECG_PRIME_112R2 */ - &ecCurve_SECG_PRIME_128R1, /* ECCurve_SECG_PRIME_128R1 */ - &ecCurve_SECG_PRIME_128R2, /* ECCurve_SECG_PRIME_128R2 */ - &ecCurve_SECG_PRIME_160K1, /* ECCurve_SECG_PRIME_160K1 */ - &ecCurve_SECG_PRIME_160R1, /* ECCurve_SECG_PRIME_160R1 */ - &ecCurve_SECG_PRIME_160R2, /* ECCurve_SECG_PRIME_160R2 */ - &ecCurve_SECG_PRIME_192K1, /* ECCurve_SECG_PRIME_192K1 */ - &ecCurve_SECG_PRIME_224K1, /* ECCurve_SECG_PRIME_224K1 */ - &ecCurve_SECG_PRIME_256K1, /* ECCurve_SECG_PRIME_256K1 */ - &ecCurve_SECG_CHAR2_113R1, /* ECCurve_SECG_CHAR2_113R1 */ - &ecCurve_SECG_CHAR2_113R2, /* ECCurve_SECG_CHAR2_113R2 */ - &ecCurve_SECG_CHAR2_131R1, /* ECCurve_SECG_CHAR2_131R1 */ - &ecCurve_SECG_CHAR2_131R2, /* ECCurve_SECG_CHAR2_131R2 */ - &ecCurve_SECG_CHAR2_163R1, /* ECCurve_SECG_CHAR2_163R1 */ - &ecCurve_SECG_CHAR2_193R1, /* ECCurve_SECG_CHAR2_193R1 */ - &ecCurve_SECG_CHAR2_193R2, /* ECCurve_SECG_CHAR2_193R2 */ - &ecCurve_SECG_CHAR2_239K1, /* ECCurve_SECG_CHAR2_239K1 */ - &ecCurve_WTLS_1, /* ECCurve_WTLS_1 */ - &ecCurve_WTLS_8, /* ECCurve_WTLS_8 */ - &ecCurve_WTLS_9, /* ECCurve_WTLS_9 */ - NULL /* ECCurve_pastLastCurve */ + NULL, /* ECCurve_noName */ + NULL, /* ECCurve_NIST_P192 */ + NULL, /* ECCurve_NIST_P224 */ + &ecCurve_NIST_P256, /* ECCurve_NIST_P256 */ + &ecCurve_NIST_P384, /* ECCurve_NIST_P384 */ + &ecCurve_NIST_P521, /* ECCurve_NIST_P521 */ + NULL, /* ECCurve_NIST_K163 */ + NULL, /* ECCurve_NIST_B163 */ + NULL, /* ECCurve_NIST_K233 */ + NULL, /* ECCurve_NIST_B233 */ + NULL, /* ECCurve_NIST_K283 */ + NULL, /* ECCurve_NIST_B283 */ + NULL, /* ECCurve_NIST_K409 */ + NULL, /* ECCurve_NIST_B409 */ + NULL, /* ECCurve_NIST_K571 */ + NULL, /* ECCurve_NIST_B571 */ + NULL, /* ECCurve_X9_62_PRIME_192V2 */ + NULL, /* ECCurve_X9_62_PRIME_192V3 */ + NULL, /* ECCurve_X9_62_PRIME_239V1 */ + NULL, /* ECCurve_X9_62_PRIME_239V2 */ + NULL, /* ECCurve_X9_62_PRIME_239V3 */ + NULL, /* ECCurve_X9_62_CHAR2_PNB163V1 */ + NULL, /* ECCurve_X9_62_CHAR2_PNB163V2 */ + NULL, /* ECCurve_X9_62_CHAR2_PNB163V3 */ + NULL, /* ECCurve_X9_62_CHAR2_PNB176V1 */ + NULL, /* ECCurve_X9_62_CHAR2_TNB191V1 */ + NULL, /* ECCurve_X9_62_CHAR2_TNB191V2 */ + NULL, /* ECCurve_X9_62_CHAR2_TNB191V3 */ + NULL, /* ECCurve_X9_62_CHAR2_PNB208W1 */ + NULL, /* ECCurve_X9_62_CHAR2_TNB239V1 */ + NULL, /* ECCurve_X9_62_CHAR2_TNB239V2 */ + NULL, /* ECCurve_X9_62_CHAR2_TNB239V3 */ + NULL, /* ECCurve_X9_62_CHAR2_PNB272W1 */ + NULL, /* ECCurve_X9_62_CHAR2_PNB304W1 */ + NULL, /* ECCurve_X9_62_CHAR2_TNB359V1 */ + NULL, /* ECCurve_X9_62_CHAR2_PNB368W1 */ + NULL, /* ECCurve_X9_62_CHAR2_TNB431R1 */ + NULL, /* ECCurve_SECG_PRIME_112R1 */ + NULL, /* ECCurve_SECG_PRIME_112R2 */ + NULL, /* ECCurve_SECG_PRIME_128R1 */ + NULL, /* ECCurve_SECG_PRIME_128R2 */ + NULL, /* ECCurve_SECG_PRIME_160K1 */ + NULL, /* ECCurve_SECG_PRIME_160R1 */ + NULL, /* ECCurve_SECG_PRIME_160R2 */ + NULL, /* ECCurve_SECG_PRIME_192K1 */ + NULL, /* ECCurve_SECG_PRIME_224K1 */ + NULL, /* ECCurve_SECG_PRIME_256K1 */ + NULL, /* ECCurve_SECG_CHAR2_113R1 */ + NULL, /* ECCurve_SECG_CHAR2_113R2 */ + NULL, /* ECCurve_SECG_CHAR2_131R1 */ + NULL, /* ECCurve_SECG_CHAR2_131R2 */ + NULL, /* ECCurve_SECG_CHAR2_163R1 */ + NULL, /* ECCurve_SECG_CHAR2_193R1 */ + NULL, /* ECCurve_SECG_CHAR2_193R2 */ + NULL, /* ECCurve_SECG_CHAR2_239K1 */ + NULL, /* ECCurve_WTLS_1 */ + NULL, /* ECCurve_WTLS_8 */ + NULL, /* ECCurve_WTLS_9 */ + NULL /* ECCurve_pastLastCurve */ }; #endif diff --git a/security/nss/lib/freebl/ecl/ecl-priv.h b/security/nss/lib/freebl/ecl/ecl-priv.h index bce7ccf09..05abb4dff 100644 --- a/security/nss/lib/freebl/ecl/ecl-priv.h +++ b/security/nss/lib/freebl/ecl/ecl-priv.h @@ -45,22 +45,62 @@ #include "mplogic.h" /* MAX_FIELD_SIZE_DIGITS is the maximum size of field element supported */ +/* the following needs to go away... */ #if defined(MP_USE_LONG_LONG_DIGIT) || defined(MP_USE_LONG_DIGIT) #define ECL_SIXTY_FOUR_BIT -#define ECL_BITS 64 -#define ECL_MAX_FIELD_SIZE_DIGITS 10 #else #define ECL_THIRTY_TWO_BIT -#define ECL_BITS 32 -#define ECL_MAX_FIELD_SIZE_DIGITS 20 #endif +#define ECL_CURVE_DIGITS(curve_size_in_bits) \ + (((curve_size_in_bits)+(sizeof(mp_digit)*8-1))/(sizeof(mp_digit)*8)) +#define ECL_BITS (sizeof(mp_digit)*8) +#define ECL_MAX_FIELD_SIZE_DIGITS (80/sizeof(mp_digit)) + /* 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)) +#if !defined(MP_NO_MP_WORD) && !defined(MP_NO_ADD_WORD) +#define MP_ADD_CARRY(a1, a2, s, cin, cout) \ + { mp_word w; \ + w = ((mp_word)(cin)) + (a1) + (a2); \ + s = ACCUM(w); \ + cout = CARRYOUT(w); } + +#define MP_SUB_BORROW(a1, a2, s, bin, bout) \ + { mp_word w; \ + w = ((mp_word)(a1)) - (a2) - (bin); \ + s = ACCUM(w); \ + bout = (w >> MP_DIGIT_BIT) & 1; } + +#else +/* NOTE, + * cin and cout could be the same variable. + * bin and bout could be the same variable. + * a1 or a2 and s could be the same variable. + * don't trash those outputs until their respective inputs have + * been read. */ +#define MP_ADD_CARRY(a1, a2, s, cin, cout) \ + { mp_digit tmp,sum; \ + tmp = (a1); \ + sum = tmp + (a2); \ + tmp = (sum < tmp); /* detect overflow */ \ + s = sum += (cin); \ + cout = tmp + (sum < (cin)); } + +#define MP_SUB_BORROW(a1, a2, s, bin, bout) \ + { mp_digit tmp; \ + tmp = (a1); \ + s = tmp - (a2); \ + tmp = (s > tmp); /* detect borrow */ \ + if ((bin) && !s--) tmp++; \ + bout = tmp; } +#endif + + struct GFMethodStr; typedef struct GFMethodStr GFMethod; struct GFMethodStr { @@ -158,6 +198,25 @@ mp_err ec_GFp_add(const mp_int *a, const mp_int *b, mp_int *r, mp_err ec_GFp_neg(const mp_int *a, mp_int *r, const GFMethod *meth); mp_err ec_GFp_sub(const mp_int *a, const mp_int *b, mp_int *r, const GFMethod *meth); + +/* fixed length in-line adds. Count is in words */ +mp_err ec_GFp_add_3(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth); +mp_err ec_GFp_add_4(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth); +mp_err ec_GFp_add_5(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth); +mp_err ec_GFp_add_6(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth); +mp_err ec_GFp_sub_3(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth); +mp_err ec_GFp_sub_4(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth); +mp_err ec_GFp_sub_5(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth); +mp_err ec_GFp_sub_6(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth); + mp_err ec_GFp_mod(const mp_int *a, mp_int *r, const GFMethod *meth); mp_err ec_GFp_mul(const mp_int *a, const mp_int *b, mp_int *r, const GFMethod *meth); @@ -205,6 +264,9 @@ mp_err ec_compute_wNAF(signed char *out, int bitsize, const mp_int *in, /* Optimized field arithmetic */ mp_err ec_group_set_gfp192(ECGroup *group, ECCurveName); mp_err ec_group_set_gfp224(ECGroup *group, ECCurveName); +mp_err ec_group_set_gfp256(ECGroup *group, ECCurveName); +mp_err ec_group_set_gfp384(ECGroup *group, ECCurveName); +mp_err ec_group_set_gfp521(ECGroup *group, ECCurveName); mp_err ec_group_set_gf2m163(ECGroup *group, ECCurveName name); mp_err ec_group_set_gf2m193(ECGroup *group, ECCurveName name); mp_err ec_group_set_gf2m233(ECGroup *group, ECCurveName name); diff --git a/security/nss/lib/freebl/ecl/ecl.c b/security/nss/lib/freebl/ecl/ecl.c index 520755f6a..4521e5b57 100644 --- a/security/nss/lib/freebl/ecl/ecl.c +++ b/security/nss/lib/freebl/ecl/ecl.c @@ -55,23 +55,24 @@ ECGroup_new() if (group == NULL) return NULL; group->constructed = MP_YES; + group->meth = NULL; group->text = NULL; MP_DIGITS(&group->curvea) = 0; MP_DIGITS(&group->curveb) = 0; MP_DIGITS(&group->genx) = 0; MP_DIGITS(&group->geny) = 0; MP_DIGITS(&group->order) = 0; - MP_CHECKOK(mp_init(&group->curvea)); - MP_CHECKOK(mp_init(&group->curveb)); - MP_CHECKOK(mp_init(&group->genx)); - MP_CHECKOK(mp_init(&group->geny)); - MP_CHECKOK(mp_init(&group->order)); group->base_point_mul = NULL; group->points_mul = NULL; group->validate_point = NULL; group->extra1 = NULL; group->extra2 = NULL; group->extra_free = NULL; + MP_CHECKOK(mp_init(&group->curvea)); + MP_CHECKOK(mp_init(&group->curveb)); + MP_CHECKOK(mp_init(&group->genx)); + MP_CHECKOK(mp_init(&group->geny)); + MP_CHECKOK(mp_init(&group->order)); CLEANUP: if (res != MP_OKAY) { @@ -164,6 +165,7 @@ ECGroup_consGFp_mont(const mp_int *irr, const mp_int *curvea, return group; } +#ifdef NSS_ECC_MORE_THAN_SUITE_B /* Construct a generic ECGroup for elliptic curves over binary polynomial * fields. */ ECGroup * @@ -205,13 +207,7 @@ ECGroup_consGF2m(const mp_int *irr, const unsigned int irr_arr[5], } return group; } - -/* Helper macros for ecgroup_fromNameAndHex. */ -#define CHECK_GROUP \ - if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } -#define CONS_GF2M \ - group = ECGroup_consGF2m(&irr, NULL, &curvea, &curveb, &genx, &geny, &order, params->cofactor); \ - CHECK_GROUP +#endif /* Construct ECGroup from hex parameters and name, if any. Called by * ECGroup_fromHex and ECGroup_fromName. */ @@ -253,82 +249,85 @@ ecgroup_fromNameAndHex(const ECCurveName name, /* determine which optimizations (if any) to use */ if (params->field == ECField_GFp) { - if ((name == ECCurve_SECG_PRIME_160K1) - || (name == ECCurve_SECG_PRIME_160R2)) { +#ifdef NSS_ECC_MORE_THAN_SUITE_B + switch (name) { +#ifdef ECL_USE_FP + case ECCurve_SECG_PRIME_160R1: group = - ECGroup_consGFp_mont(&irr, &curvea, &curveb, &genx, &geny, - &order, params->cofactor); - } else if ((name == ECCurve_SECG_PRIME_160R1)) { + ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, + &order, params->cofactor); + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } + MP_CHECKOK(ec_group_set_secp160r1_fp(group)); + break; +#endif + case ECCurve_SECG_PRIME_192R1: #ifdef ECL_USE_FP group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); - CHECK_GROUP MP_CHECKOK(ec_group_set_secp160r1_fp(group)); + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } + MP_CHECKOK(ec_group_set_nistp192_fp(group)); #else group = - ECGroup_consGFp_mont(&irr, &curvea, &curveb, &genx, &geny, - &order, params->cofactor); + ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, + &order, params->cofactor); + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } + MP_CHECKOK(ec_group_set_gfp192(group, name)); #endif - } else if ((name == ECCurve_SECG_PRIME_192K1)) { - group = - ECGroup_consGFp_mont(&irr, &curvea, &curveb, &genx, &geny, - &order, params->cofactor); - CHECK_GROUP MP_CHECKOK(ec_group_set_gfp192(group, name)); - } else if ((name == ECCurve_SECG_PRIME_192R1)) { + break; + case ECCurve_SECG_PRIME_224R1: #ifdef ECL_USE_FP group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); - CHECK_GROUP MP_CHECKOK(ec_group_set_nistp192_fp(group)); + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } + MP_CHECKOK(ec_group_set_nistp224_fp(group)); #else group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); - CHECK_GROUP MP_CHECKOK(ec_group_set_gfp192(group, name)); + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } + MP_CHECKOK(ec_group_set_gfp224(group, name)); #endif - } else if ((name == ECCurve_SECG_PRIME_224K1)) { - group = - ECGroup_consGFp_mont(&irr, &curvea, &curveb, &genx, &geny, - &order, params->cofactor); - CHECK_GROUP MP_CHECKOK(ec_group_set_gfp224(group, name)); - } else if ((name == ECCurve_SECG_PRIME_224R1)) { -#ifdef ECL_USE_FP + break; + case ECCurve_SECG_PRIME_256R1: group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); - CHECK_GROUP MP_CHECKOK(ec_group_set_nistp224_fp(group)); -#else + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } + MP_CHECKOK(ec_group_set_gfp256(group, name)); + break; + case ECCurve_SECG_PRIME_521R1: group = ECGroup_consGFp(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); - CHECK_GROUP MP_CHECKOK(ec_group_set_gfp224(group, name)); + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } + MP_CHECKOK(ec_group_set_gfp521(group, name)); + break; + default: + /* use generic arithmetic */ #endif - } else { group = ECGroup_consGFp_mont(&irr, &curvea, &curveb, &genx, &geny, &order, params->cofactor); - CHECK_GROUP} - /* XXX secp521r1 fails ecp_test with &ec_GFp_pts_mul_jac */ - if (name == ECCurve_SECG_PRIME_521R1) { - group->points_mul = &ec_pts_mul_simul_w2; + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } +#ifdef NSS_ECC_MORE_THAN_SUITE_B } } else if (params->field == ECField_GF2m) { - switch (bits) { - case 163: - CONS_GF2M MP_CHECKOK(ec_group_set_gf2m163(group, name)); - break; - case 193: - CONS_GF2M MP_CHECKOK(ec_group_set_gf2m193(group, name)); - break; - case 233: - CONS_GF2M MP_CHECKOK(ec_group_set_gf2m233(group, name)); - break; - default: - group = - ECGroup_consGF2m(&irr, NULL, &curvea, &curveb, &genx, - &geny, &order, params->cofactor); - CHECK_GROUP break; + group = ECGroup_consGF2m(&irr, NULL, &curvea, &curveb, &genx, &geny, &order, params->cofactor); + if (group == NULL) { res = MP_UNDEF; goto CLEANUP; } + if ((name == ECCurve_NIST_K163) || + (name == ECCurve_NIST_B163) || + (name == ECCurve_SECG_CHAR2_163R1)) { + MP_CHECKOK(ec_group_set_gf2m163(group, name)); + } else if ((name == ECCurve_SECG_CHAR2_193R1) || + (name == ECCurve_SECG_CHAR2_193R2)) { + MP_CHECKOK(ec_group_set_gf2m193(group, name)); + } else if ((name == ECCurve_NIST_K233) || + (name == ECCurve_NIST_B233)) { + MP_CHECKOK(ec_group_set_gf2m233(group, name)); } +#endif } /* set name, if any */ @@ -353,10 +352,6 @@ ecgroup_fromNameAndHex(const ECCurveName name, return group; } -#undef CHECK_GROUP -#undef CONS_GFP -#undef CONS_GF2M - /* Construct ECGroup from hexadecimal representations of parameters. */ ECGroup * ECGroup_fromHex(const ECCurveParams * params) @@ -418,6 +413,11 @@ ECGroup_free(ECGroup *group) GFMethod_free(group->meth); if (group->constructed == MP_NO) return; + mp_clear(&group->curvea); + mp_clear(&group->curveb); + mp_clear(&group->genx); + mp_clear(&group->geny); + mp_clear(&group->order); if (group->text != NULL) free(group->text); if (group->extra_free != NULL) diff --git a/security/nss/lib/freebl/ecl/ecl_curve.c b/security/nss/lib/freebl/ecl/ecl_curve.c index b0a7d5074..a0a7bd316 100644 --- a/security/nss/lib/freebl/ecl/ecl_curve.c +++ b/security/nss/lib/freebl/ecl/ecl_curve.c @@ -51,7 +51,7 @@ ECCurveParams_dup(const ECCurveParams * params) int res = 1; ECCurveParams *ret = NULL; - CHECK(ret = (ECCurveParams *) malloc(sizeof(ECCurveParams))); + CHECK(ret = (ECCurveParams *) calloc(1, sizeof(ECCurveParams))); if (params->text != NULL) { CHECK(ret->text = strdup(params->text)); } @@ -91,7 +91,8 @@ ECCurveParams_dup(const ECCurveParams * params) ECCurveParams * EC_GetNamedCurveParams(const ECCurveName name) { - if ((name <= ECCurve_noName) || (ECCurve_pastLastCurve <= name)) { + if ((name <= ECCurve_noName) || (ECCurve_pastLastCurve <= name) || + (ecCurve_map[name] == NULL)) { return NULL; } else { return ECCurveParams_dup(ecCurve_map[name]); diff --git a/security/nss/lib/freebl/ecl/ecl_gf.c b/security/nss/lib/freebl/ecl/ecl_gf.c index 9ee3bb6ac..08fa0c3e0 100644 --- a/security/nss/lib/freebl/ecl/ecl_gf.c +++ b/security/nss/lib/freebl/ecl/ecl_gf.c @@ -40,6 +40,7 @@ #include "mpi.h" #include "mp_gf2m.h" #include "ecl-priv.h" +#include "mpi-priv.h" #include <stdlib.h> /* Allocate memory for a new GFMethod object. */ @@ -52,8 +53,9 @@ GFMethod_new() if (meth == NULL) return NULL; meth->constructed = MP_YES; - MP_CHECKOK(mp_init(&meth->irr)); + MP_DIGITS(&meth->irr) = 0; meth->extra_free = NULL; + MP_CHECKOK(mp_init(&meth->irr)); CLEANUP: if (res != MP_OKAY) { @@ -79,9 +81,29 @@ GFMethod_consGFp(const mp_int *irr) meth->irr_arr[0] = mpl_significant_bits(irr); meth->irr_arr[1] = meth->irr_arr[2] = meth->irr_arr[3] = meth->irr_arr[4] = 0; - meth->field_add = &ec_GFp_add; + switch(MP_USED(&meth->irr)) { + /* maybe we need 1 and 2 words here as well?*/ + case 3: + meth->field_add = &ec_GFp_add_3; + meth->field_sub = &ec_GFp_sub_3; + break; + case 4: + meth->field_add = &ec_GFp_add_4; + meth->field_sub = &ec_GFp_sub_4; + break; + case 5: + meth->field_add = &ec_GFp_add_5; + meth->field_sub = &ec_GFp_sub_5; + break; + case 6: + meth->field_add = &ec_GFp_add_6; + meth->field_sub = &ec_GFp_sub_6; + break; + default: + meth->field_add = &ec_GFp_add; + meth->field_sub = &ec_GFp_sub; + } meth->field_neg = &ec_GFp_neg; - meth->field_sub = &ec_GFp_sub; meth->field_mod = &ec_GFp_mod; meth->field_mul = &ec_GFp_mul; meth->field_sqr = &ec_GFp_sqr; @@ -164,6 +186,7 @@ GFMethod_free(GFMethod *meth) return; if (meth->constructed == MP_NO) return; + mp_clear(&meth->irr); if (meth->extra_free != NULL) meth->extra_free(meth); free(meth); @@ -223,6 +246,676 @@ ec_GFp_sub(const mp_int *a, const mp_int *b, mp_int *r, CLEANUP: return res; } +/* + * Inline adds for small curve lengths. + */ +/* 3 words */ +mp_err +ec_GFp_add_3(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth) +{ + mp_err res = MP_OKAY; + mp_digit a0 = 0, a1 = 0, a2 = 0; + mp_digit r0 = 0, r1 = 0, r2 = 0; + mp_digit carry; + + switch(MP_USED(a)) { + case 3: + a2 = MP_DIGIT(a,2); + case 2: + a1 = MP_DIGIT(a,1); + case 1: + a0 = MP_DIGIT(a,0); + } + switch(MP_USED(b)) { + case 3: + r2 = MP_DIGIT(b,2); + case 2: + r1 = MP_DIGIT(b,1); + case 1: + r0 = MP_DIGIT(b,0); + } + +#ifndef MPI_AMD64_ADD + MP_ADD_CARRY(a0, r0, r0, 0, carry); + MP_ADD_CARRY(a1, r1, r1, carry, carry); + MP_ADD_CARRY(a2, r2, r2, carry, carry); +#else + __asm__ ( + "xorq %3,%3 \n\t" + "addq %4,%0 \n\t" + "adcq %5,%1 \n\t" + "adcq %6,%2 \n\t" + "adcq $0,%3 \n\t" + : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(carry) + : "r" (a0), "r" (a1), "r" (a2), + "0" (r0), "1" (r1), "2" (r2) + : "%cc" ); +#endif + + MP_CHECKOK(s_mp_pad(r, 3)); + MP_DIGIT(r, 2) = r2; + MP_DIGIT(r, 1) = r1; + MP_DIGIT(r, 0) = r0; + MP_SIGN(r) = MP_ZPOS; + MP_USED(r) = 3; + + /* Do quick 'subract' if we've gone over + * (add the 2's complement of the curve field) */ + a2 = MP_DIGIT(&meth->irr,2); + if (carry || r2 > a2 || + ((r2 == a2) && mp_cmp(r,&meth->irr) != MP_LT)) { + a1 = MP_DIGIT(&meth->irr,1); + a0 = MP_DIGIT(&meth->irr,0); +#ifndef MPI_AMD64_ADD + MP_SUB_BORROW(r0, a0, r0, 0, carry); + MP_SUB_BORROW(r1, a1, r1, carry, carry); + MP_SUB_BORROW(r2, a2, r2, carry, carry); +#else + __asm__ ( + "subq %3,%0 \n\t" + "sbbq %4,%1 \n\t" + "sbbq %5,%2 \n\t" + : "=r"(r0), "=r"(r1), "=r"(r2) + : "r" (a0), "r" (a1), "r" (a2), + "0" (r0), "1" (r1), "2" (r2) + : "%cc" ); +#endif + MP_DIGIT(r, 2) = r2; + MP_DIGIT(r, 1) = r1; + MP_DIGIT(r, 0) = r0; + } + + s_mp_clamp(r); + + CLEANUP: + return res; +} + +/* 4 words */ +mp_err +ec_GFp_add_4(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth) +{ + mp_err res = MP_OKAY; + mp_digit a0 = 0, a1 = 0, a2 = 0, a3 = 0; + mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0; + mp_digit carry; + + switch(MP_USED(a)) { + case 4: + a3 = MP_DIGIT(a,3); + case 3: + a2 = MP_DIGIT(a,2); + case 2: + a1 = MP_DIGIT(a,1); + case 1: + a0 = MP_DIGIT(a,0); + } + switch(MP_USED(b)) { + case 4: + r3 = MP_DIGIT(b,3); + case 3: + r2 = MP_DIGIT(b,2); + case 2: + r1 = MP_DIGIT(b,1); + case 1: + r0 = MP_DIGIT(b,0); + } + +#ifndef MPI_AMD64_ADD + MP_ADD_CARRY(a0, r0, r0, 0, carry); + MP_ADD_CARRY(a1, r1, r1, carry, carry); + MP_ADD_CARRY(a2, r2, r2, carry, carry); + MP_ADD_CARRY(a3, r3, r3, carry, carry); +#else + __asm__ ( + "xorq %4,%4 \n\t" + "addq %5,%0 \n\t" + "adcq %6,%1 \n\t" + "adcq %7,%2 \n\t" + "adcq %8,%3 \n\t" + "adcq $0,%4 \n\t" + : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3), "=r"(carry) + : "r" (a0), "r" (a1), "r" (a2), "r" (a3), + "0" (r0), "1" (r1), "2" (r2), "3" (r3) + : "%cc" ); +#endif + + MP_CHECKOK(s_mp_pad(r, 4)); + MP_DIGIT(r, 3) = r3; + MP_DIGIT(r, 2) = r2; + MP_DIGIT(r, 1) = r1; + MP_DIGIT(r, 0) = r0; + MP_SIGN(r) = MP_ZPOS; + MP_USED(r) = 4; + + /* Do quick 'subract' if we've gone over + * (add the 2's complement of the curve field) */ + a3 = MP_DIGIT(&meth->irr,3); + if (carry || r3 > a3 || + ((r3 == a3) && mp_cmp(r,&meth->irr) != MP_LT)) { + a2 = MP_DIGIT(&meth->irr,2); + a1 = MP_DIGIT(&meth->irr,1); + a0 = MP_DIGIT(&meth->irr,0); +#ifndef MPI_AMD64_ADD + MP_SUB_BORROW(r0, a0, r0, 0, carry); + MP_SUB_BORROW(r1, a1, r1, carry, carry); + MP_SUB_BORROW(r2, a2, r2, carry, carry); + MP_SUB_BORROW(r3, a3, r3, carry, carry); +#else + __asm__ ( + "subq %4,%0 \n\t" + "sbbq %5,%1 \n\t" + "sbbq %6,%2 \n\t" + "sbbq %7,%3 \n\t" + : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3) + : "r" (a0), "r" (a1), "r" (a2), "r" (a3), + "0" (r0), "1" (r1), "2" (r2), "3" (r3) + : "%cc" ); +#endif + MP_DIGIT(r, 3) = r3; + MP_DIGIT(r, 2) = r2; + MP_DIGIT(r, 1) = r1; + MP_DIGIT(r, 0) = r0; + } + + s_mp_clamp(r); + + CLEANUP: + return res; +} + +/* 5 words */ +mp_err +ec_GFp_add_5(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth) +{ + mp_err res = MP_OKAY; + mp_digit a0 = 0, a1 = 0, a2 = 0, a3 = 0, a4 = 0; + mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0; + mp_digit carry; + + switch(MP_USED(a)) { + case 5: + a4 = MP_DIGIT(a,4); + case 4: + a3 = MP_DIGIT(a,3); + case 3: + a2 = MP_DIGIT(a,2); + case 2: + a1 = MP_DIGIT(a,1); + case 1: + a0 = MP_DIGIT(a,0); + } + switch(MP_USED(b)) { + case 5: + r4 = MP_DIGIT(b,4); + case 4: + r3 = MP_DIGIT(b,3); + case 3: + r2 = MP_DIGIT(b,2); + case 2: + r1 = MP_DIGIT(b,1); + case 1: + r0 = MP_DIGIT(b,0); + } + + MP_ADD_CARRY(a0, r0, r0, 0, carry); + MP_ADD_CARRY(a1, r1, r1, carry, carry); + MP_ADD_CARRY(a2, r2, r2, carry, carry); + MP_ADD_CARRY(a3, r3, r3, carry, carry); + MP_ADD_CARRY(a4, r4, r4, carry, carry); + + MP_CHECKOK(s_mp_pad(r, 5)); + MP_DIGIT(r, 4) = r4; + MP_DIGIT(r, 3) = r3; + MP_DIGIT(r, 2) = r2; + MP_DIGIT(r, 1) = r1; + MP_DIGIT(r, 0) = r0; + MP_SIGN(r) = MP_ZPOS; + MP_USED(r) = 5; + + /* Do quick 'subract' if we've gone over + * (add the 2's complement of the curve field) */ + a4 = MP_DIGIT(&meth->irr,4); + if (carry || r4 > a4 || + ((r4 == a4) && mp_cmp(r,&meth->irr) != MP_LT)) { + a3 = MP_DIGIT(&meth->irr,3); + a2 = MP_DIGIT(&meth->irr,2); + a1 = MP_DIGIT(&meth->irr,1); + a0 = MP_DIGIT(&meth->irr,0); + MP_SUB_BORROW(r0, a0, r0, 0, carry); + MP_SUB_BORROW(r1, a1, r1, carry, carry); + MP_SUB_BORROW(r2, a2, r2, carry, carry); + MP_SUB_BORROW(r3, a3, r3, carry, carry); + MP_SUB_BORROW(r4, a4, r4, carry, carry); + MP_DIGIT(r, 4) = r4; + MP_DIGIT(r, 3) = r3; + MP_DIGIT(r, 2) = r2; + MP_DIGIT(r, 1) = r1; + MP_DIGIT(r, 0) = r0; + } + + s_mp_clamp(r); + + CLEANUP: + return res; +} + +/* 6 words */ +mp_err +ec_GFp_add_6(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth) +{ + mp_err res = MP_OKAY; + mp_digit a0 = 0, a1 = 0, a2 = 0, a3 = 0, a4 = 0, a5 = 0; + mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0; + mp_digit carry; + + switch(MP_USED(a)) { + case 6: + a5 = MP_DIGIT(a,5); + case 5: + a4 = MP_DIGIT(a,4); + case 4: + a3 = MP_DIGIT(a,3); + case 3: + a2 = MP_DIGIT(a,2); + case 2: + a1 = MP_DIGIT(a,1); + case 1: + a0 = MP_DIGIT(a,0); + } + switch(MP_USED(b)) { + case 6: + r5 = MP_DIGIT(b,5); + case 5: + r4 = MP_DIGIT(b,4); + case 4: + r3 = MP_DIGIT(b,3); + case 3: + r2 = MP_DIGIT(b,2); + case 2: + r1 = MP_DIGIT(b,1); + case 1: + r0 = MP_DIGIT(b,0); + } + + MP_ADD_CARRY(a0, r0, r0, 0, carry); + MP_ADD_CARRY(a1, r1, r1, carry, carry); + MP_ADD_CARRY(a2, r2, r2, carry, carry); + MP_ADD_CARRY(a3, r3, r3, carry, carry); + MP_ADD_CARRY(a4, r4, r4, carry, carry); + MP_ADD_CARRY(a5, r5, r5, carry, carry); + + MP_CHECKOK(s_mp_pad(r, 6)); + MP_DIGIT(r, 5) = r5; + MP_DIGIT(r, 4) = r4; + MP_DIGIT(r, 3) = r3; + MP_DIGIT(r, 2) = r2; + MP_DIGIT(r, 1) = r1; + MP_DIGIT(r, 0) = r0; + MP_SIGN(r) = MP_ZPOS; + MP_USED(r) = 6; + + /* Do quick 'subract' if we've gone over + * (add the 2's complement of the curve field) */ + a5 = MP_DIGIT(&meth->irr,5); + if (carry || r5 > a5 || + ((r5 == a5) && mp_cmp(r,&meth->irr) != MP_LT)) { + a4 = MP_DIGIT(&meth->irr,4); + a3 = MP_DIGIT(&meth->irr,3); + a2 = MP_DIGIT(&meth->irr,2); + a1 = MP_DIGIT(&meth->irr,1); + a0 = MP_DIGIT(&meth->irr,0); + MP_SUB_BORROW(r0, a0, r0, 0, carry); + MP_SUB_BORROW(r1, a1, r1, carry, carry); + MP_SUB_BORROW(r2, a2, r2, carry, carry); + MP_SUB_BORROW(r3, a3, r3, carry, carry); + MP_SUB_BORROW(r4, a4, r4, carry, carry); + MP_SUB_BORROW(r5, a5, r5, carry, carry); + MP_DIGIT(r, 5) = r5; + MP_DIGIT(r, 4) = r4; + MP_DIGIT(r, 3) = r3; + MP_DIGIT(r, 2) = r2; + MP_DIGIT(r, 1) = r1; + MP_DIGIT(r, 0) = r0; + } + + s_mp_clamp(r); + + CLEANUP: + return res; +} + +/* + * The following subraction functions do in-line subractions based + * on our curve size. + * + * ... 3 words + */ +mp_err +ec_GFp_sub_3(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth) +{ + mp_err res = MP_OKAY; + mp_digit b0 = 0, b1 = 0, b2 = 0; + mp_digit r0 = 0, r1 = 0, r2 = 0; + mp_digit borrow; + + switch(MP_USED(a)) { + case 3: + r2 = MP_DIGIT(a,2); + case 2: + r1 = MP_DIGIT(a,1); + case 1: + r0 = MP_DIGIT(a,0); + } + switch(MP_USED(b)) { + case 3: + b2 = MP_DIGIT(b,2); + case 2: + b1 = MP_DIGIT(b,1); + case 1: + b0 = MP_DIGIT(b,0); + } + +#ifndef MPI_AMD64_ADD + MP_SUB_BORROW(r0, b0, r0, 0, borrow); + MP_SUB_BORROW(r1, b1, r1, borrow, borrow); + MP_SUB_BORROW(r2, b2, r2, borrow, borrow); +#else + __asm__ ( + "xorq %3,%3 \n\t" + "subq %4,%0 \n\t" + "sbbq %5,%1 \n\t" + "sbbq %6,%2 \n\t" + "adcq $0,%3 \n\t" + : "=r"(r0), "=r"(r1), "=r"(r2), "=r" (borrow) + : "r" (b0), "r" (b1), "r" (b2), + "0" (r0), "1" (r1), "2" (r2) + : "%cc" ); +#endif + + /* Do quick 'add' if we've gone under 0 + * (subtract the 2's complement of the curve field) */ + if (borrow) { + b2 = MP_DIGIT(&meth->irr,2); + b1 = MP_DIGIT(&meth->irr,1); + b0 = MP_DIGIT(&meth->irr,0); +#ifndef MPI_AMD64_ADD + MP_ADD_CARRY(b0, r0, r0, 0, borrow); + MP_ADD_CARRY(b1, r1, r1, borrow, borrow); + MP_ADD_CARRY(b2, r2, r2, borrow, borrow); +#else + __asm__ ( + "addq %3,%0 \n\t" + "adcq %4,%1 \n\t" + "adcq %5,%2 \n\t" + : "=r"(r0), "=r"(r1), "=r"(r2) + : "r" (b0), "r" (b1), "r" (b2), + "0" (r0), "1" (r1), "2" (r2) + : "%cc" ); +#endif + } + +#ifdef MPI_AMD64_ADD + /* compiler fakeout? */ + if ((r2 == b0) && (r1 == b0) && (r0 == b0)) { + MP_CHECKOK(s_mp_pad(r, 4)); + } +#endif + MP_CHECKOK(s_mp_pad(r, 3)); + MP_DIGIT(r, 2) = r2; + MP_DIGIT(r, 1) = r1; + MP_DIGIT(r, 0) = r0; + MP_SIGN(r) = MP_ZPOS; + MP_USED(r) = 3; + s_mp_clamp(r); + + CLEANUP: + return res; +} + +/* 4 words */ +mp_err +ec_GFp_sub_4(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth) +{ + mp_err res = MP_OKAY; + mp_digit b0 = 0, b1 = 0, b2 = 0, b3 = 0; + mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0; + mp_digit borrow; + + switch(MP_USED(a)) { + case 4: + r3 = MP_DIGIT(a,3); + case 3: + r2 = MP_DIGIT(a,2); + case 2: + r1 = MP_DIGIT(a,1); + case 1: + r0 = MP_DIGIT(a,0); + } + switch(MP_USED(b)) { + case 4: + b3 = MP_DIGIT(b,3); + case 3: + b2 = MP_DIGIT(b,2); + case 2: + b1 = MP_DIGIT(b,1); + case 1: + b0 = MP_DIGIT(b,0); + } + +#ifndef MPI_AMD64_ADD + MP_SUB_BORROW(r0, b0, r0, 0, borrow); + MP_SUB_BORROW(r1, b1, r1, borrow, borrow); + MP_SUB_BORROW(r2, b2, r2, borrow, borrow); + MP_SUB_BORROW(r3, b3, r3, borrow, borrow); +#else + __asm__ ( + "xorq %4,%4 \n\t" + "subq %5,%0 \n\t" + "sbbq %6,%1 \n\t" + "sbbq %7,%2 \n\t" + "sbbq %8,%3 \n\t" + "adcq $0,%4 \n\t" + : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3), "=r" (borrow) + : "r" (b0), "r" (b1), "r" (b2), "r" (b3), + "0" (r0), "1" (r1), "2" (r2), "3" (r3) + : "%cc" ); +#endif + + /* Do quick 'add' if we've gone under 0 + * (subtract the 2's complement of the curve field) */ + if (borrow) { + b3 = MP_DIGIT(&meth->irr,3); + b2 = MP_DIGIT(&meth->irr,2); + b1 = MP_DIGIT(&meth->irr,1); + b0 = MP_DIGIT(&meth->irr,0); +#ifndef MPI_AMD64_ADD + MP_ADD_CARRY(b0, r0, r0, 0, borrow); + MP_ADD_CARRY(b1, r1, r1, borrow, borrow); + MP_ADD_CARRY(b2, r2, r2, borrow, borrow); + MP_ADD_CARRY(b3, r3, r3, borrow, borrow); +#else + __asm__ ( + "addq %4,%0 \n\t" + "adcq %5,%1 \n\t" + "adcq %6,%2 \n\t" + "adcq %7,%3 \n\t" + : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3) + : "r" (b0), "r" (b1), "r" (b2), "r" (b3), + "0" (r0), "1" (r1), "2" (r2), "3" (r3) + : "%cc" ); +#endif + } +#ifdef MPI_AMD64_ADD + /* compiler fakeout? */ + if ((r3 == b0) && (r1 == b0) && (r0 == b0)) { + MP_CHECKOK(s_mp_pad(r, 4)); + } +#endif + MP_CHECKOK(s_mp_pad(r, 4)); + MP_DIGIT(r, 3) = r3; + MP_DIGIT(r, 2) = r2; + MP_DIGIT(r, 1) = r1; + MP_DIGIT(r, 0) = r0; + MP_SIGN(r) = MP_ZPOS; + MP_USED(r) = 4; + s_mp_clamp(r); + + CLEANUP: + return res; +} + +/* 5 words */ +mp_err +ec_GFp_sub_5(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth) +{ + mp_err res = MP_OKAY; + mp_digit b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0; + mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0; + mp_digit borrow; + + switch(MP_USED(a)) { + case 5: + r4 = MP_DIGIT(a,4); + case 4: + r3 = MP_DIGIT(a,3); + case 3: + r2 = MP_DIGIT(a,2); + case 2: + r1 = MP_DIGIT(a,1); + case 1: + r0 = MP_DIGIT(a,0); + } + switch(MP_USED(b)) { + case 5: + b4 = MP_DIGIT(b,4); + case 4: + b3 = MP_DIGIT(b,3); + case 3: + b2 = MP_DIGIT(b,2); + case 2: + b1 = MP_DIGIT(b,1); + case 1: + b0 = MP_DIGIT(b,0); + } + + MP_SUB_BORROW(r0, b0, r0, 0, borrow); + MP_SUB_BORROW(r1, b1, r1, borrow, borrow); + MP_SUB_BORROW(r2, b2, r2, borrow, borrow); + MP_SUB_BORROW(r3, b3, r3, borrow, borrow); + MP_SUB_BORROW(r4, b4, r4, borrow, borrow); + + /* Do quick 'add' if we've gone under 0 + * (subtract the 2's complement of the curve field) */ + if (borrow) { + b4 = MP_DIGIT(&meth->irr,4); + b3 = MP_DIGIT(&meth->irr,3); + b2 = MP_DIGIT(&meth->irr,2); + b1 = MP_DIGIT(&meth->irr,1); + b0 = MP_DIGIT(&meth->irr,0); + MP_ADD_CARRY(b0, r0, r0, 0, borrow); + MP_ADD_CARRY(b1, r1, r1, borrow, borrow); + MP_ADD_CARRY(b2, r2, r2, borrow, borrow); + MP_ADD_CARRY(b3, r3, r3, borrow, borrow); + } + MP_CHECKOK(s_mp_pad(r, 5)); + MP_DIGIT(r, 4) = r4; + MP_DIGIT(r, 3) = r3; + MP_DIGIT(r, 2) = r2; + MP_DIGIT(r, 1) = r1; + MP_DIGIT(r, 0) = r0; + MP_SIGN(r) = MP_ZPOS; + MP_USED(r) = 5; + s_mp_clamp(r); + + CLEANUP: + return res; +} + +/* 6 words */ +mp_err +ec_GFp_sub_6(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth) +{ + mp_err res = MP_OKAY; + mp_digit b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0; + mp_digit r0 = 0, r1 = 0, r2 = 0, r3 = 0, r4 = 0, r5 = 0; + mp_digit borrow; + + switch(MP_USED(a)) { + case 6: + r5 = MP_DIGIT(a,5); + case 5: + r4 = MP_DIGIT(a,4); + case 4: + r3 = MP_DIGIT(a,3); + case 3: + r2 = MP_DIGIT(a,2); + case 2: + r1 = MP_DIGIT(a,1); + case 1: + r0 = MP_DIGIT(a,0); + } + switch(MP_USED(b)) { + case 6: + b5 = MP_DIGIT(b,5); + case 5: + b4 = MP_DIGIT(b,4); + case 4: + b3 = MP_DIGIT(b,3); + case 3: + b2 = MP_DIGIT(b,2); + case 2: + b1 = MP_DIGIT(b,1); + case 1: + b0 = MP_DIGIT(b,0); + } + + MP_SUB_BORROW(r0, b0, r0, 0, borrow); + MP_SUB_BORROW(r1, b1, r1, borrow, borrow); + MP_SUB_BORROW(r2, b2, r2, borrow, borrow); + MP_SUB_BORROW(r3, b3, r3, borrow, borrow); + MP_SUB_BORROW(r4, b4, r4, borrow, borrow); + MP_SUB_BORROW(r5, b5, r5, borrow, borrow); + + /* Do quick 'add' if we've gone under 0 + * (subtract the 2's complement of the curve field) */ + if (borrow) { + b5 = MP_DIGIT(&meth->irr,5); + b4 = MP_DIGIT(&meth->irr,4); + b3 = MP_DIGIT(&meth->irr,3); + b2 = MP_DIGIT(&meth->irr,2); + b1 = MP_DIGIT(&meth->irr,1); + b0 = MP_DIGIT(&meth->irr,0); + MP_ADD_CARRY(b0, r0, r0, 0, borrow); + MP_ADD_CARRY(b1, r1, r1, borrow, borrow); + MP_ADD_CARRY(b2, r2, r2, borrow, borrow); + MP_ADD_CARRY(b3, r3, r3, borrow, borrow); + MP_ADD_CARRY(b4, r4, r4, borrow, borrow); + } + + MP_CHECKOK(s_mp_pad(r, 6)); + MP_DIGIT(r, 5) = r5; + MP_DIGIT(r, 4) = r4; + MP_DIGIT(r, 3) = r3; + MP_DIGIT(r, 2) = r2; + MP_DIGIT(r, 1) = r1; + MP_DIGIT(r, 0) = r0; + MP_SIGN(r) = MP_ZPOS; + MP_USED(r) = 6; + s_mp_clamp(r); + + CLEANUP: + return res; +} + /* Reduces an integer to a field element. */ mp_err diff --git a/security/nss/lib/freebl/ecl/ecl_mult.c b/security/nss/lib/freebl/ecl/ecl_mult.c index 106c7ee42..050d0a747 100644 --- a/security/nss/lib/freebl/ecl/ecl_mult.c +++ b/security/nss/lib/freebl/ecl/ecl_mult.c @@ -57,7 +57,7 @@ ECPoint_mul(const ECGroup *group, const mp_int *k, const mp_int *px, MP_DIGITS(&kt) = 0; /* want scalar to be less than or equal to group order */ - if (mp_cmp(k, &group->order) >= 0) { + if (mp_cmp(k, &group->order) > 0) { MP_CHECKOK(mp_init(&kt)); MP_CHECKOK(mp_mod(k, &group->order, &kt)); } else { diff --git a/security/nss/lib/freebl/ecl/ecp_192.c b/security/nss/lib/freebl/ecl/ecp_192.c index 26867ae3e..f4cd42bc3 100644 --- a/security/nss/lib/freebl/ecl/ecp_192.c +++ b/security/nss/lib/freebl/ecl/ecp_192.c @@ -42,6 +42,8 @@ #include "mpi-priv.h" #include <stdlib.h> +#define ECP192_DIGITS ECL_CURVE_DIGITS(192) + /* Fast modular reduction for p192 = 2^192 - 2^64 - 1. a can be r. Uses * algorithm 7 from Brown, Hankerson, Lopez, Menezes. Software * Implementation of the NIST Elliptic Curves over Prime Fields. */ @@ -50,101 +52,127 @@ ec_GFp_nistp192_mod(const mp_int *a, mp_int *r, const GFMethod *meth) { mp_err res = MP_OKAY; mp_size a_used = MP_USED(a); - - /* s is a statically-allocated mp_int of exactly the size we need */ - mp_int s; - + mp_digit r3; +#ifndef MPI_AMD64_ADD + mp_digit carry; +#endif #ifdef ECL_THIRTY_TWO_BIT - mp_digit sa[6]; - mp_digit a11 = 0, a10, a9 = 0, a8, a7 = 0, a6; - - MP_SIGN(&s) = MP_ZPOS; - MP_ALLOC(&s) = 6; - MP_USED(&s) = 6; - MP_DIGITS(&s) = sa; + mp_digit a5a = 0, a5b = 0, a4a = 0, a4b = 0, a3a = 0, a3b = 0; + mp_digit r0a, r0b, r1a, r1b, r2a, r2b; #else - mp_digit sa[3]; mp_digit a5 = 0, a4 = 0, a3 = 0; - - MP_SIGN(&s) = MP_ZPOS; - MP_ALLOC(&s) = 3; - MP_USED(&s) = 3; - MP_DIGITS(&s) = sa; + mp_digit r0, r1, r2; #endif /* reduction not needed if a is not larger than field size */ -#ifdef ECL_THIRTY_TWO_BIT - if (a_used < 6) { -#else - if (a_used < 3) { -#endif + if (a_used < ECP192_DIGITS) { + if (a == r) { + return MP_OKAY; + } return mp_copy(a, r); } -#ifdef ECL_THIRTY_TWO_BIT + /* for polynomials larger than twice the field size, use regular * reduction */ - if (a_used > 12) { + if (a_used > ECP192_DIGITS*2) { MP_CHECKOK(mp_mod(a, &meth->irr, r)); } else { /* copy out upper words of a */ + +#ifdef ECL_THIRTY_TWO_BIT + + /* in all the math below, + * nXb is most signifiant, nXa is least significant */ switch (a_used) { case 12: - a11 = MP_DIGIT(a, 11); + a5b = MP_DIGIT(a, 11); case 11: - a10 = MP_DIGIT(a, 10); + a5a = MP_DIGIT(a, 10); case 10: - a9 = MP_DIGIT(a, 9); + a4b = MP_DIGIT(a, 9); case 9: - a8 = MP_DIGIT(a, 8); + a4a = MP_DIGIT(a, 8); case 8: - a7 = MP_DIGIT(a, 7); + a3b = MP_DIGIT(a, 7); case 7: - a6 = MP_DIGIT(a, 6); + a3a = MP_DIGIT(a, 6); } + + + r2b= MP_DIGIT(a, 5); + r2a= MP_DIGIT(a, 4); + r1b = MP_DIGIT(a, 3); + r1a = MP_DIGIT(a, 2); + r0b = MP_DIGIT(a, 1); + r0a = MP_DIGIT(a, 0); + + /* implement r = (a2,a1,a0)+(a5,a5,a5)+(a4,a4,0)+(0,a3,a3) */ + MP_ADD_CARRY(r0a, a3a, r0a, 0, carry); + MP_ADD_CARRY(r0b, a3b, r0b, carry, carry); + MP_ADD_CARRY(r1a, a3a, r1a, carry, carry); + MP_ADD_CARRY(r1b, a3b, r1b, carry, carry); + MP_ADD_CARRY(r2a, a4a, r2a, carry, carry); + MP_ADD_CARRY(r2b, a4b, r2b, carry, carry); + r3 = carry; carry = 0; + MP_ADD_CARRY(r0a, a5a, r0a, 0, carry); + MP_ADD_CARRY(r0b, a5b, r0b, carry, carry); + MP_ADD_CARRY(r1a, a5a, r1a, carry, carry); + MP_ADD_CARRY(r1b, a5b, r1b, carry, carry); + MP_ADD_CARRY(r2a, a5a, r2a, carry, carry); + MP_ADD_CARRY(r2b, a5b, r2b, carry, carry); + r3 += carry; + MP_ADD_CARRY(r1a, a4a, r1a, 0, carry); + MP_ADD_CARRY(r1b, a4b, r1b, carry, carry); + MP_ADD_CARRY(r2a, 0, r2a, carry, carry); + MP_ADD_CARRY(r2b, 0, r2b, carry, carry); + r3 += carry; + + /* reduce out the carry */ + while (r3) { + MP_ADD_CARRY(r0a, r3, r0a, 0, carry); + MP_ADD_CARRY(r0b, 0, r0b, carry, carry); + MP_ADD_CARRY(r1a, r3, r1a, carry, carry); + MP_ADD_CARRY(r1b, 0, r1b, carry, carry); + MP_ADD_CARRY(r2a, 0, r2a, carry, carry); + MP_ADD_CARRY(r2b, 0, r2b, carry, carry); + r3 = carry; + } + + /* check for final reduction */ + /* + * our field is 0xffffffffffffffff, 0xfffffffffffffffe, + * 0xffffffffffffffff. That means we can only be over and need + * one more reduction + * if r2 == 0xffffffffffffffffff (same as r2+1 == 0) + * and + * r1 == 0xffffffffffffffffff or + * r1 == 0xfffffffffffffffffe and r0 = 0xfffffffffffffffff + * In all cases, we subtract the field (or add the 2's + * complement value (1,1,0)). (r0, r1, r2) + */ + if (((r2b == 0xffffffff) && (r2a == 0xffffffff) + && (r1b == 0xffffffff) ) && + ((r1a == 0xffffffff) || + (r1a == 0xfffffffe) && (r0a == 0xffffffff) && + (r0b == 0xffffffff)) ) { + /* do a quick subtract */ + MP_ADD_CARRY(r0a, 1, r0a, 0, carry); + r0b += carry; + r1a = r1b = r2a = r2b = 0; + } + /* set the lower words of r */ if (a != r) { - MP_CHECKOK(s_mp_pad(r, 7)); - MP_DIGIT(r, 5) = MP_DIGIT(a, 5); - MP_DIGIT(r, 4) = MP_DIGIT(a, 4); - MP_DIGIT(r, 3) = MP_DIGIT(a, 3); - MP_DIGIT(r, 2) = MP_DIGIT(a, 2); - MP_DIGIT(r, 1) = MP_DIGIT(a, 1); - MP_DIGIT(r, 0) = MP_DIGIT(a, 0); + MP_CHECKOK(s_mp_pad(r, 6)); } + MP_DIGIT(r, 5) = r2b; + MP_DIGIT(r, 4) = r2a; + MP_DIGIT(r, 3) = r1b; + MP_DIGIT(r, 2) = r1a; + MP_DIGIT(r, 1) = r0b; + MP_DIGIT(r, 0) = r0a; MP_USED(r) = 6; - /* compute r = s1 + s2 + s3 + s4, where s1 = (a2,a1,a0), s2 = - * (0,a3,a3), s3 = (a4,a4,0), and s4 = (a5,a5,a5), for - * sixty-four-bit words */ - switch (a_used) { - case 12: - case 11: - sa[5] = sa[3] = sa[1] = a11; - sa[4] = sa[2] = sa[0] = a10; - MP_CHECKOK(mp_add(r, &s, r)); - case 10: - case 9: - sa[5] = sa[3] = a9; - sa[4] = sa[2] = a8; - sa[1] = sa[0] = 0; - MP_CHECKOK(mp_add(r, &s, r)); - case 8: - case 7: - sa[5] = sa[4] = 0; - sa[3] = sa[1] = a7; - sa[2] = sa[0] = a6; - MP_CHECKOK(mp_add(r, &s, r)); - } - /* there might be 1 or 2 bits left to reduce; use regular - * reduction for this */ - MP_CHECKOK(mp_mod(r, &meth->irr, r)); - } #else - /* for polynomials larger than twice the field size, use regular - * reduction */ - if (a_used > 6) { - MP_CHECKOK(mp_mod(a, &meth->irr, r)); - } else { - /* copy out upper words of a */ switch (a_used) { case 6: a5 = MP_DIGIT(a, 5); @@ -153,39 +181,268 @@ ec_GFp_nistp192_mod(const mp_int *a, mp_int *r, const GFMethod *meth) case 4: a3 = MP_DIGIT(a, 3); } + + r2 = MP_DIGIT(a, 2); + r1 = MP_DIGIT(a, 1); + r0 = MP_DIGIT(a, 0); + + /* implement r = (a2,a1,a0)+(a5,a5,a5)+(a4,a4,0)+(0,a3,a3) */ +#ifndef MPI_AMD64_ADD + MP_ADD_CARRY(r0, a3, r0, 0, carry); + MP_ADD_CARRY(r1, a3, r1, carry, carry); + MP_ADD_CARRY(r2, a4, r2, carry, carry); + r3 = carry; + MP_ADD_CARRY(r0, a5, r0, 0, carry); + MP_ADD_CARRY(r1, a5, r1, carry, carry); + MP_ADD_CARRY(r2, a5, r2, carry, carry); + r3 += carry; + MP_ADD_CARRY(r1, a4, r1, 0, carry); + MP_ADD_CARRY(r2, 0, r2, carry, carry); + r3 += carry; + +#else + r2 = MP_DIGIT(a, 2); + r1 = MP_DIGIT(a, 1); + r0 = MP_DIGIT(a, 0); + + /* set the lower words of r */ + __asm__ ( + "xorq %3,%3 \n\t" + "addq %4,%0 \n\t" + "adcq %4,%1 \n\t" + "adcq %5,%2 \n\t" + "adcq $0,%3 \n\t" + "addq %6,%0 \n\t" + "adcq %6,%1 \n\t" + "adcq %6,%2 \n\t" + "adcq $0,%3 \n\t" + "addq %5,%1 \n\t" + "adcq $0,%2 \n\t" + "adcq $0,%3 \n\t" + : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3), "=r"(a3), + "=r"(a4), "=r"(a5) + : "0" (r0), "1" (r1), "2" (r2), "3" (r3), + "4" (a3), "5" (a4), "6"(a5) + : "%cc" ); +#endif + + /* reduce out the carry */ + while (r3) { +#ifndef MPI_AMD64_ADD + MP_ADD_CARRY(r0, r3, r0, 0, carry); + MP_ADD_CARRY(r1, r3, r1, carry, carry); + MP_ADD_CARRY(r2, 0, r2, carry, carry); + r3 = carry; +#else + a3=r3; + __asm__ ( + "xorq %3,%3 \n\t" + "addq %4,%0 \n\t" + "adcq %4,%1 \n\t" + "adcq $0,%2 \n\t" + "adcq $0,%3 \n\t" + : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(r3), "=r"(a3) + : "0" (r0), "1" (r1), "2" (r2), "3" (r3), "4"(a3) + : "%cc" ); +#endif + } + + /* check for final reduction */ + /* + * our field is 0xffffffffffffffff, 0xfffffffffffffffe, + * 0xffffffffffffffff. That means we can only be over and need + * one more reduction + * if r2 == 0xffffffffffffffffff (same as r2+1 == 0) + * and + * r1 == 0xffffffffffffffffff or + * r1 == 0xfffffffffffffffffe and r0 = 0xfffffffffffffffff + * In all cases, we subtract the field (or add the 2's + * complement value (1,1,0)). (r0, r1, r2) + */ + if (r3 || ((r2 == MP_DIGIT_MAX) && + ((r1 == MP_DIGIT_MAX) || + ((r1 == (MP_DIGIT_MAX-1)) && (r0 == MP_DIGIT_MAX))))) { + /* do a quick subtract */ + r0++; + r1 = r2 = 0; + } /* set the lower words of r */ if (a != r) { - MP_CHECKOK(s_mp_pad(r, 4)); - MP_DIGIT(r, 2) = MP_DIGIT(a, 2); - MP_DIGIT(r, 1) = MP_DIGIT(a, 1); - MP_DIGIT(r, 0) = MP_DIGIT(a, 0); + MP_CHECKOK(s_mp_pad(r, 3)); } + MP_DIGIT(r, 2) = r2; + MP_DIGIT(r, 1) = r1; + MP_DIGIT(r, 0) = r0; MP_USED(r) = 3; - /* compute r = s1 + s2 + s3 + s4, where s1 = (a2,a1,a0), s2 = - * (0,a3,a3), s3 = (a4,a4,0), and s4 = (a5,a5,a5) */ - switch (a_used) { - case 6: - sa[2] = sa[1] = sa[0] = a5; - MP_CHECKOK(mp_add(r, &s, r)); - case 5: - sa[2] = sa[1] = a4; - sa[0] = 0; - MP_CHECKOK(mp_add(r, &s, r)); - case 4: - sa[2] = 0; - sa[1] = sa[0] = a3; - MP_CHECKOK(mp_add(r, &s, r)); - } - /* there might be 1 or 2 bits left to reduce; use regular - * reduction for this */ - MP_CHECKOK(mp_mod(r, &meth->irr, r)); +#endif } + + CLEANUP: + return res; +} + +#ifndef ECL_THIRTY_TWO_BIT +/* Compute the sum of 192 bit curves. Do the work in-line since the + * number of words are so small, we don't want to overhead of mp function + * calls. Uses optimized modular reduction for p192. + */ +mp_err +ec_GFp_nistp192_add(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth) +{ + mp_err res = MP_OKAY; + mp_digit a0 = 0, a1 = 0, a2 = 0; + mp_digit r0 = 0, r1 = 0, r2 = 0; + mp_digit carry; + + switch(MP_USED(a)) { + case 3: + a2 = MP_DIGIT(a,2); + case 2: + a1 = MP_DIGIT(a,1); + case 1: + a0 = MP_DIGIT(a,0); + } + switch(MP_USED(b)) { + case 3: + r2 = MP_DIGIT(b,2); + case 2: + r1 = MP_DIGIT(b,1); + case 1: + r0 = MP_DIGIT(b,0); + } + +#ifndef MPI_AMD64_ADD + MP_ADD_CARRY(a0, r0, r0, 0, carry); + MP_ADD_CARRY(a1, r1, r1, carry, carry); + MP_ADD_CARRY(a2, r2, r2, carry, carry); +#else + __asm__ ( + "xorq %3,%3 \n\t" + "addq %4,%0 \n\t" + "adcq %5,%1 \n\t" + "adcq %6,%2 \n\t" + "adcq $0,%3 \n\t" + : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(carry) + : "r" (a0), "r" (a1), "r" (a2), "0" (r0), + "1" (r1), "2" (r2) + : "%cc" ); +#endif + + /* Do quick 'subract' if we've gone over + * (add the 2's complement of the curve field) */ + if (carry || ((r2 == MP_DIGIT_MAX) && + ((r1 == MP_DIGIT_MAX) || + ((r1 == (MP_DIGIT_MAX-1)) && (r0 == MP_DIGIT_MAX))))) { +#ifndef MPI_AMD64_ADD + MP_ADD_CARRY(r0, 1, r0, 0, carry); + MP_ADD_CARRY(r1, 1, r1, carry, carry); + MP_ADD_CARRY(r2, 0, r2, carry, carry); +#else + __asm__ ( + "addq $1,%0 \n\t" + "adcq $1,%1 \n\t" + "adcq $0,%2 \n\t" + : "=r"(r0), "=r"(r1), "=r"(r2) + : "0" (r0), "1" (r1), "2" (r2) + : "%cc" ); +#endif + } + + + MP_CHECKOK(s_mp_pad(r, 3)); + MP_DIGIT(r, 2) = r2; + MP_DIGIT(r, 1) = r1; + MP_DIGIT(r, 0) = r0; + MP_SIGN(r) = MP_ZPOS; + MP_USED(r) = 3; + s_mp_clamp(r); + + + CLEANUP: + return res; +} + +/* Compute the diff of 192 bit curves. Do the work in-line since the + * number of words are so small, we don't want to overhead of mp function + * calls. Uses optimized modular reduction for p192. + */ +mp_err +ec_GFp_nistp192_sub(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth) +{ + mp_err res = MP_OKAY; + mp_digit b0 = 0, b1 = 0, b2 = 0; + mp_digit r0 = 0, r1 = 0, r2 = 0; + mp_digit borrow; + + switch(MP_USED(a)) { + case 3: + r2 = MP_DIGIT(a,2); + case 2: + r1 = MP_DIGIT(a,1); + case 1: + r0 = MP_DIGIT(a,0); + } + + switch(MP_USED(b)) { + case 3: + b2 = MP_DIGIT(b,2); + case 2: + b1 = MP_DIGIT(b,1); + case 1: + b0 = MP_DIGIT(b,0); + } + +#ifndef MPI_AMD64_ADD + MP_SUB_BORROW(r0, b0, r0, 0, borrow); + MP_SUB_BORROW(r1, b1, r1, borrow, borrow); + MP_SUB_BORROW(r2, b2, r2, borrow, borrow); +#else + __asm__ ( + "xorq %3,%3 \n\t" + "subq %4,%0 \n\t" + "sbbq %5,%1 \n\t" + "sbbq %6,%2 \n\t" + "adcq $0,%3 \n\t" + : "=r"(r0), "=r"(r1), "=r"(r2), "=r"(borrow) + : "r" (b0), "r" (b1), "r" (b2), "0" (r0), + "1" (r1), "2" (r2) + : "%cc" ); +#endif + + /* Do quick 'add' if we've gone under 0 + * (subtract the 2's complement of the curve field) */ + if (borrow) { +#ifndef MPI_AMD64_ADD + MP_SUB_BORROW(r0, 1, r0, 0, borrow); + MP_SUB_BORROW(r1, 1, r1, borrow, borrow); + MP_SUB_BORROW(r2, 0, r2, borrow, borrow); +#else + __asm__ ( + "subq $1,%0 \n\t" + "sbbq $1,%1 \n\t" + "sbbq $0,%2 \n\t" + : "=r"(r0), "=r"(r1), "=r"(r2) + : "0" (r0), "1" (r1), "2" (r2) + : "%cc" ); #endif + } + + MP_CHECKOK(s_mp_pad(r, 3)); + MP_DIGIT(r, 2) = r2; + MP_DIGIT(r, 1) = r1; + MP_DIGIT(r, 0) = r0; + MP_SIGN(r) = MP_ZPOS; + MP_USED(r) = 3; + s_mp_clamp(r); CLEANUP: return res; } +#endif + /* Compute the square of polynomial a, reduce modulo p192. Store the * result in r. r could be a. Uses optimized modular reduction for p192. */ @@ -215,6 +472,31 @@ ec_GFp_nistp192_mul(const mp_int *a, const mp_int *b, mp_int *r, return res; } +/* Divides two field elements. If a is NULL, then returns the inverse of + * b. */ +mp_err +ec_GFp_nistp192_div(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth) +{ + mp_err res = MP_OKAY; + mp_int t; + + /* If a is NULL, then return the inverse of b, otherwise return a/b. */ + if (a == NULL) { + return mp_invmod(b, &meth->irr, r); + } else { + /* MPI doesn't support divmod, so we implement it using invmod and + * mulmod. */ + MP_CHECKOK(mp_init(&t)); + MP_CHECKOK(mp_invmod(b, &meth->irr, &t)); + MP_CHECKOK(mp_mul(a, &t, r)); + MP_CHECKOK(ec_GFp_nistp192_mod(r, r, meth)); + CLEANUP: + mp_clear(&t); + return res; + } +} + /* Wire in fast field arithmetic and precomputation of base point for * named curves. */ mp_err @@ -224,6 +506,11 @@ ec_group_set_gfp192(ECGroup *group, ECCurveName name) group->meth->field_mod = &ec_GFp_nistp192_mod; group->meth->field_mul = &ec_GFp_nistp192_mul; group->meth->field_sqr = &ec_GFp_nistp192_sqr; + group->meth->field_div = &ec_GFp_nistp192_div; +#ifndef ECL_THIRTY_TWO_BIT + group->meth->field_add = &ec_GFp_nistp192_add; + group->meth->field_sub = &ec_GFp_nistp192_sub; +#endif } return MP_OKAY; } diff --git a/security/nss/lib/freebl/ecl/ecp_224.c b/security/nss/lib/freebl/ecl/ecp_224.c index c3d8fa362..56683e9ef 100644 --- a/security/nss/lib/freebl/ecl/ecp_224.c +++ b/security/nss/lib/freebl/ecl/ecp_224.c @@ -42,6 +42,8 @@ #include "mpi-priv.h" #include <stdlib.h> +#define ECP224_DIGITS ECL_CURVE_DIGITS(224) + /* Fast modular reduction for p224 = 2^224 - 2^96 + 1. a can be r. Uses * algorithm 7 from Brown, Hankerson, Lopez, Menezes. Software * Implementation of the NIST Elliptic Curves over Prime Fields. */ @@ -51,213 +53,251 @@ ec_GFp_nistp224_mod(const mp_int *a, mp_int *r, const GFMethod *meth) mp_err res = MP_OKAY; mp_size a_used = MP_USED(a); - /* s is a statically-allocated mp_int of exactly the size we need */ - mp_int s; - + int r3b; + mp_digit carry; #ifdef ECL_THIRTY_TWO_BIT - mp_digit sa[8]; - mp_digit a13 = 0, a12 = 0, a11 = 0, a10, a9 = 0, a8, a7; - - MP_SIGN(&s) = MP_ZPOS; - MP_ALLOC(&s) = 8; - MP_USED(&s) = 7; - MP_DIGITS(&s) = sa; + mp_digit a6a = 0, a6b = 0, + a5a = 0, a5b = 0, a4a = 0, a4b = 0, a3a = 0, a3b = 0; + mp_digit r0a, r0b, r1a, r1b, r2a, r2b, r3a; #else - mp_digit sa[4]; - mp_digit a6 = 0, a5 = 0, a4 = 0, a3 = 0; - - MP_SIGN(&s) = MP_ZPOS; - MP_ALLOC(&s) = 4; - MP_USED(&s) = 4; - MP_DIGITS(&s) = sa; + mp_digit a6 = 0, a5 = 0, a4 = 0, a3b = 0, a5a = 0; + mp_digit a6b = 0, a6a_a5b = 0, a5b = 0, a5a_a4b = 0, a4a_a3b = 0; + mp_digit r0, r1, r2, r3; #endif /* reduction not needed if a is not larger than field size */ -#ifdef ECL_THIRTY_TWO_BIT - if (a_used < 8) { -#else - if (a_used < 4) { -#endif + if (a_used < ECP224_DIGITS) { + if (a == r) return MP_OKAY; return mp_copy(a, r); } -#ifdef ECL_THIRTY_TWO_BIT /* for polynomials larger than twice the field size, use regular * reduction */ - if (a_used > 14) { + if (a_used > ECL_CURVE_DIGITS(224*2)) { MP_CHECKOK(mp_mod(a, &meth->irr, r)); } else { +#ifdef ECL_THIRTY_TWO_BIT /* copy out upper words of a */ switch (a_used) { case 14: - a13 = MP_DIGIT(a, 13); + a6b = MP_DIGIT(a, 13); case 13: - a12 = MP_DIGIT(a, 12); + a6a = MP_DIGIT(a, 12); case 12: - a11 = MP_DIGIT(a, 11); + a5b = MP_DIGIT(a, 11); case 11: - a10 = MP_DIGIT(a, 10); + a5a = MP_DIGIT(a, 10); case 10: - a9 = MP_DIGIT(a, 9); + a4b = MP_DIGIT(a, 9); case 9: - a8 = MP_DIGIT(a, 8); + a4a = MP_DIGIT(a, 8); case 8: - a7 = MP_DIGIT(a, 7); + a3b = MP_DIGIT(a, 7); } - /* set the lower words of r */ - if (a != r) { - MP_CHECKOK(s_mp_pad(r, 8)); - MP_DIGIT(r, 6) = MP_DIGIT(a, 6); - MP_DIGIT(r, 5) = MP_DIGIT(a, 5); - MP_DIGIT(r, 4) = MP_DIGIT(a, 4); - MP_DIGIT(r, 3) = MP_DIGIT(a, 3); - MP_DIGIT(r, 2) = MP_DIGIT(a, 2); - MP_DIGIT(r, 1) = MP_DIGIT(a, 1); - MP_DIGIT(r, 0) = MP_DIGIT(a, 0); + r3a = MP_DIGIT(a, 6); + r2b= MP_DIGIT(a, 5); + r2a= MP_DIGIT(a, 4); + r1b = MP_DIGIT(a, 3); + r1a = MP_DIGIT(a, 2); + r0b = MP_DIGIT(a, 1); + r0a = MP_DIGIT(a, 0); + + + /* implement r = (a3a,a2,a1,a0) + +(a5a, a4,a3b, 0) + +( 0, a6,a5b, 0) + -( 0 0, 0|a6b, a6a|a5b ) + -( a6b, a6a|a5b, a5a|a4b, a4a|a3b ) */ + MP_ADD_CARRY (r1b, a3b, r1b, 0, carry); + MP_ADD_CARRY (r2a, a4a, r2a, carry, carry); + MP_ADD_CARRY (r2b, a4b, r2b, carry, carry); + MP_ADD_CARRY (r3a, a5a, r3a, carry, carry); + r3b = carry; + MP_ADD_CARRY (r1b, a5b, r1b, 0, carry); + MP_ADD_CARRY (r2a, a6a, r2a, carry, carry); + MP_ADD_CARRY (r2b, a6b, r2b, carry, carry); + MP_ADD_CARRY (r3a, 0, r3a, carry, carry); + r3b += carry; + MP_SUB_BORROW(r0a, a3b, r0a, 0, carry); + MP_SUB_BORROW(r0b, a4a, r0b, carry, carry); + MP_SUB_BORROW(r1a, a4b, r1a, carry, carry); + MP_SUB_BORROW(r1b, a5a, r1b, carry, carry); + MP_SUB_BORROW(r2a, a5b, r2a, carry, carry); + MP_SUB_BORROW(r2b, a6a, r2b, carry, carry); + MP_SUB_BORROW(r3a, a6b, r3a, carry, carry); + r3b -= carry; + MP_SUB_BORROW(r0a, a5b, r0a, 0, carry); + MP_SUB_BORROW(r0b, a6a, r0b, carry, carry); + MP_SUB_BORROW(r1a, a6b, r1a, carry, carry); + if (carry) { + MP_SUB_BORROW(r1b, 0, r1b, carry, carry); + MP_SUB_BORROW(r2a, 0, r2a, carry, carry); + MP_SUB_BORROW(r2b, 0, r2b, carry, carry); + MP_SUB_BORROW(r3a, 0, r3a, carry, carry); + r3b -= carry; } - MP_USED(r) = 7; - switch (a_used) { - case 14: - case 13: - case 12: - case 11: - sa[6] = a10; - case 10: - sa[5] = a9; - case 9: - sa[4] = a8; - case 8: - sa[3] = a7; - sa[2] = sa[1] = sa[0] = 0; - MP_USED(&s) = a_used - 4; - if (MP_USED(&s) > 7) - MP_USED(&s) = 7; - MP_CHECKOK(mp_add(r, &s, r)); + + while (r3b > 0) { + int tmp; + MP_ADD_CARRY(r1b, r3b, r1b, 0, carry); + if (carry) { + MP_ADD_CARRY(r2a, 0, r2a, carry, carry); + MP_ADD_CARRY(r2b, 0, r2b, carry, carry); + MP_ADD_CARRY(r3a, 0, r3a, carry, carry); + } + tmp = carry; + MP_SUB_BORROW(r0a, r3b, r0a, 0, carry); + if (carry) { + MP_SUB_BORROW(r0b, 0, r0b, carry, carry); + MP_SUB_BORROW(r1a, 0, r1a, carry, carry); + MP_SUB_BORROW(r1b, 0, r1b, carry, carry); + MP_SUB_BORROW(r2a, 0, r2a, carry, carry); + MP_SUB_BORROW(r2b, 0, r2b, carry, carry); + MP_SUB_BORROW(r3a, 0, r3a, carry, carry); + tmp -= carry; + } + r3b = tmp; } - switch (a_used) { - case 14: - sa[5] = a13; - case 13: - sa[4] = a12; - case 12: - sa[3] = a11; - sa[2] = sa[1] = sa[0] = 0; - MP_USED(&s) = a_used - 8; - MP_CHECKOK(mp_add(r, &s, r)); + + while (r3b < 0) { + mp_digit maxInt = MP_DIGIT_MAX; + MP_ADD_CARRY (r0a, 1, r0a, 0, carry); + MP_ADD_CARRY (r0b, 0, r0b, carry, carry); + MP_ADD_CARRY (r1a, 0, r1a, carry, carry); + MP_ADD_CARRY (r1b, maxInt, r1b, carry, carry); + MP_ADD_CARRY (r2a, maxInt, r2a, carry, carry); + MP_ADD_CARRY (r2b, maxInt, r2b, carry, carry); + MP_ADD_CARRY (r3a, maxInt, r3a, carry, carry); + r3b += carry; } - switch (a_used) { - case 14: - sa[6] = a13; - case 13: - sa[5] = a12; - case 12: - sa[4] = a11; - case 11: - sa[3] = a10; - case 10: - sa[2] = a9; - case 9: - sa[1] = a8; - case 8: - sa[0] = a7; - MP_USED(&s) = a_used - 7; - MP_CHECKOK(mp_sub(r, &s, r)); + /* check for final reduction */ + /* now the only way we are over is if the top 4 words are all ones */ + if ((r3a == MP_DIGIT_MAX) && (r2b == MP_DIGIT_MAX) + && (r2a == MP_DIGIT_MAX) && (r1b == MP_DIGIT_MAX) && + ((r1a != 0) || (r0b != 0) || (r0a != 0)) ) { + /* one last subraction */ + MP_SUB_BORROW(r0a, 1, r0a, 0, carry); + MP_SUB_BORROW(r0b, 0, r0b, carry, carry); + MP_SUB_BORROW(r1a, 0, r1a, carry, carry); + r1b = r2a = r2b = r3a = 0; } - switch (a_used) { - case 14: - sa[2] = a13; - case 13: - sa[1] = a12; - case 12: - sa[0] = a11; - MP_USED(&s) = a_used - 11; - MP_CHECKOK(mp_sub(r, &s, r)); + + + if (a != r) { + MP_CHECKOK(s_mp_pad(r, 7)); } - /* there might be 1 or 2 bits left to reduce; use regular - * reduction for this */ - MP_CHECKOK(mp_mod(r, &meth->irr, r)); - } + /* set the lower words of r */ + MP_SIGN(r) = MP_ZPOS; + MP_USED(r) = 7; + MP_DIGIT(r, 6) = r3a; + MP_DIGIT(r, 5) = r2b; + MP_DIGIT(r, 4) = r2a; + MP_DIGIT(r, 3) = r1b; + MP_DIGIT(r, 2) = r1a; + MP_DIGIT(r, 1) = r0b; + MP_DIGIT(r, 0) = r0a; #else - /* for polynomials larger than twice the field size, use regular - * reduction */ - if (a_used > 7) { - MP_CHECKOK(mp_mod(a, &meth->irr, r)); - } else { /* copy out upper words of a */ switch (a_used) { case 7: a6 = MP_DIGIT(a, 6); + a6b = a6 >> 32; + a6a_a5b = a6 << 32; case 6: a5 = MP_DIGIT(a, 5); + a5b = a5 >> 32; + a6a_a5b |= a5b; + a5b = a5b << 32; + a5a_a4b = a5 << 32; + a5a = a5 & 0xffffffff; case 5: a4 = MP_DIGIT(a, 4); + a5a_a4b |= a4 >> 32; + a4a_a3b = a4 << 32; case 4: - a3 = MP_DIGIT(a, 3) >> 32; + a3b = MP_DIGIT(a, 3) >> 32; + a4a_a3b |= a3b; + a3b = a3b << 32; } - /* set the lower words of r */ - if (a != r) { - MP_CHECKOK(s_mp_pad(r, 5)); - MP_DIGIT(r, 3) = MP_DIGIT(a, 3) & 0xFFFFFFFF; - MP_DIGIT(r, 2) = MP_DIGIT(a, 2); - MP_DIGIT(r, 1) = MP_DIGIT(a, 1); - MP_DIGIT(r, 0) = MP_DIGIT(a, 0); - } else { - MP_DIGIT(r, 3) &= 0xFFFFFFFF; + + r3 = MP_DIGIT(a, 3) & 0xffffffff; + r2 = MP_DIGIT(a, 2); + r1 = MP_DIGIT(a, 1); + r0 = MP_DIGIT(a, 0); + + /* implement r = (a3a,a2,a1,a0) + +(a5a, a4,a3b, 0) + +( 0, a6,a5b, 0) + -( 0 0, 0|a6b, a6a|a5b ) + -( a6b, a6a|a5b, a5a|a4b, a4a|a3b ) */ + MP_ADD_CARRY (r1, a3b, r1, 0, carry); + MP_ADD_CARRY (r2, a4 , r2, carry, carry); + MP_ADD_CARRY (r3, a5a, r3, carry, carry); + MP_ADD_CARRY (r1, a5b, r1, 0, carry); + MP_ADD_CARRY (r2, a6 , r2, carry, carry); + MP_ADD_CARRY (r3, 0, r3, carry, carry); + + MP_SUB_BORROW(r0, a4a_a3b, r0, 0, carry); + MP_SUB_BORROW(r1, a5a_a4b, r1, carry, carry); + MP_SUB_BORROW(r2, a6a_a5b, r2, carry, carry); + MP_SUB_BORROW(r3, a6b , r3, carry, carry); + MP_SUB_BORROW(r0, a6a_a5b, r0, 0, carry); + MP_SUB_BORROW(r1, a6b , r1, carry, carry); + if (carry) { + MP_SUB_BORROW(r2, 0, r2, carry, carry); + MP_SUB_BORROW(r3, 0, r3, carry, carry); } - MP_USED(r) = 4; - switch (a_used) { - case 7: - case 6: - sa[3] = a5 & 0xFFFFFFFF; - case 5: - sa[2] = a4; - case 4: - sa[1] = a3 << 32; - sa[0] = 0; - MP_USED(&s) = a_used - 2; - if (MP_USED(&s) == 5) - MP_USED(&s) = 4; - MP_CHECKOK(mp_add(r, &s, r)); + + + /* if the value is negative, r3 has a 2's complement + * high value */ + r3b = (int)(r3 >>32); + while (r3b > 0) { + r3 &= 0xffffffff; + MP_ADD_CARRY(r1,((mp_digit)r3b) << 32, r1, 0, carry); + if (carry) { + MP_ADD_CARRY(r2, 0, r2, carry, carry); + MP_ADD_CARRY(r3, 0, r3, carry, carry); + } + MP_SUB_BORROW(r0, r3b, r0, 0, carry); + if (carry) { + MP_SUB_BORROW(r1, 0, r1, carry, carry); + MP_SUB_BORROW(r2, 0, r2, carry, carry); + MP_SUB_BORROW(r3, 0, r3, carry, carry); + } + r3b = (int)(r3 >>32); } - switch (a_used) { - case 7: - sa[2] = a6; - case 6: - sa[1] = (a5 >> 32) << 32; - sa[0] = 0; - MP_USED(&s) = a_used - 4; - MP_CHECKOK(mp_add(r, &s, r)); + + while (r3b < 0) { + MP_ADD_CARRY (r0, 1, r0, 0, carry); + MP_ADD_CARRY (r1, MP_DIGIT_MAX <<32, r1, carry, carry); + MP_ADD_CARRY (r2, MP_DIGIT_MAX, r2, carry, carry); + MP_ADD_CARRY (r3, MP_DIGIT_MAX >> 32, r3, carry, carry); + r3b = (int)(r3 >>32); } - sa[2] = sa[1] = sa[0] = 0; - switch (a_used) { - case 7: - sa[3] = a6 >> 32; - sa[2] = a6 << 32; - case 6: - sa[2] |= a5 >> 32; - sa[1] = a5 << 32; - case 5: - sa[1] |= a4 >> 32; - sa[0] = a4 << 32; - case 4: - sa[0] |= a3; - MP_USED(&s) = a_used - 3; - MP_CHECKOK(mp_sub(r, &s, r)); + /* check for final reduction */ + /* now the only way we are over is if the top 4 words are all ones */ + if ((r3 == (MP_DIGIT_MAX >> 32)) && (r2 == MP_DIGIT_MAX) + && ((r1 & MP_DIGIT_MAX << 32)== MP_DIGIT_MAX << 32) && + ((r1 != MP_DIGIT_MAX << 32 ) || (r0 != 0)) ) { + /* one last subraction */ + MP_SUB_BORROW(r0, 1, r0, 0, carry); + MP_SUB_BORROW(r1, 0, r1, carry, carry); + r2 = r3 = 0; } - sa[0] = 0; - switch (a_used) { - case 7: - sa[1] = a6 >> 32; - sa[0] = a6 << 32; - case 6: - sa[0] |= a5 >> 32; - MP_USED(&s) = a_used - 5; - MP_CHECKOK(mp_sub(r, &s, r)); + + + if (a != r) { + MP_CHECKOK(s_mp_pad(r, 4)); } - /* there might be 1 or 2 bits left to reduce; use regular - * reduction for this */ - MP_CHECKOK(mp_mod(r, &meth->irr, r)); - } + /* set the lower words of r */ + MP_SIGN(r) = MP_ZPOS; + MP_USED(r) = 4; + MP_DIGIT(r, 3) = r3; + MP_DIGIT(r, 2) = r2; + MP_DIGIT(r, 1) = r1; + MP_DIGIT(r, 0) = r0; #endif + } CLEANUP: return res; @@ -292,6 +332,31 @@ ec_GFp_nistp224_mul(const mp_int *a, const mp_int *b, mp_int *r, return res; } +/* Divides two field elements. If a is NULL, then returns the inverse of + * b. */ +mp_err +ec_GFp_nistp224_div(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth) +{ + mp_err res = MP_OKAY; + mp_int t; + + /* If a is NULL, then return the inverse of b, otherwise return a/b. */ + if (a == NULL) { + return mp_invmod(b, &meth->irr, r); + } else { + /* MPI doesn't support divmod, so we implement it using invmod and + * mulmod. */ + MP_CHECKOK(mp_init(&t)); + MP_CHECKOK(mp_invmod(b, &meth->irr, &t)); + MP_CHECKOK(mp_mul(a, &t, r)); + MP_CHECKOK(ec_GFp_nistp224_mod(r, r, meth)); + CLEANUP: + mp_clear(&t); + return res; + } +} + /* Wire in fast field arithmetic and precomputation of base point for * named curves. */ mp_err @@ -301,6 +366,7 @@ ec_group_set_gfp224(ECGroup *group, ECCurveName name) group->meth->field_mod = &ec_GFp_nistp224_mod; group->meth->field_mul = &ec_GFp_nistp224_mul; group->meth->field_sqr = &ec_GFp_nistp224_sqr; + group->meth->field_div = &ec_GFp_nistp224_div; } return MP_OKAY; } diff --git a/security/nss/lib/freebl/ecl/ecp_256.c b/security/nss/lib/freebl/ecl/ecp_256.c new file mode 100644 index 000000000..15d29ab6e --- /dev/null +++ b/security/nss/lib/freebl/ecl/ecp_256.c @@ -0,0 +1,429 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * 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 the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Douglas Stebila <douglas@stebila.ca> + * + * 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. + * + * ***** END LICENSE BLOCK ***** */ + +#include "ecp.h" +#include "mpi.h" +#include "mplogic.h" +#include "mpi-priv.h" +#include <stdlib.h> + +/* Fast modular reduction for p256 = 2^256 - 2^224 + 2^192+ 2^96 - 1. a can be r. + * Uses algorithm 2.29 from Hankerson, Menezes, Vanstone. Guide to + * Elliptic Curve Cryptography. */ +mp_err +ec_GFp_nistp256_mod(const mp_int *a, mp_int *r, const GFMethod *meth) +{ + mp_err res = MP_OKAY; + mp_size a_used = MP_USED(a); + int a_bits = mpl_significant_bits(a); + mp_digit carry; + +#ifdef ECL_THIRTY_TWO_BIT + mp_digit a8=0, a9=0, a10=0, a11=0, a12=0, a13=0, a14=0, a15=0; + mp_digit r0, r1, r2, r3, r4, r5, r6, r7; + int r8; /* must be a signed value ! */ +#else + mp_digit a4=0, a5=0, a6=0, a7=0; + mp_digit a4h, a4l, a5h, a5l, a6h, a6l, a7h, a7l; + mp_digit r0, r1, r2, r3; + int r4; /* must be a signed value ! */ +#endif + /* for polynomials larger than twice the field size + * use regular reduction */ + if (a_bits < 256) { + if (a == r) return MP_OKAY; + return mp_copy(a,r); + } + if (a_bits > 512) { + MP_CHECKOK(mp_mod(a, &meth->irr, r)); + } else { + +#ifdef ECL_THIRTY_TWO_BIT + switch (a_used) { + case 16: + a15 = MP_DIGIT(a,15); + case 15: + a14 = MP_DIGIT(a,14); + case 14: + a13 = MP_DIGIT(a,13); + case 13: + a12 = MP_DIGIT(a,12); + case 12: + a11 = MP_DIGIT(a,11); + case 11: + a10 = MP_DIGIT(a,10); + case 10: + a9 = MP_DIGIT(a,9); + case 9: + a8 = MP_DIGIT(a,8); + } + + r0 = MP_DIGIT(a,0); + r1 = MP_DIGIT(a,1); + r2 = MP_DIGIT(a,2); + r3 = MP_DIGIT(a,3); + r4 = MP_DIGIT(a,4); + r5 = MP_DIGIT(a,5); + r6 = MP_DIGIT(a,6); + r7 = MP_DIGIT(a,7); + + /* sum 1 */ + MP_ADD_CARRY(r3, a11, r3, 0, carry); + MP_ADD_CARRY(r4, a12, r4, carry, carry); + MP_ADD_CARRY(r5, a13, r5, carry, carry); + MP_ADD_CARRY(r6, a14, r6, carry, carry); + MP_ADD_CARRY(r7, a15, r7, carry, carry); + r8 = carry; + MP_ADD_CARRY(r3, a11, r3, 0, carry); + MP_ADD_CARRY(r4, a12, r4, carry, carry); + MP_ADD_CARRY(r5, a13, r5, carry, carry); + MP_ADD_CARRY(r6, a14, r6, carry, carry); + MP_ADD_CARRY(r7, a15, r7, carry, carry); + r8 += carry; + /* sum 2 */ + MP_ADD_CARRY(r3, a12, r3, 0, carry); + MP_ADD_CARRY(r4, a13, r4, carry, carry); + MP_ADD_CARRY(r5, a14, r5, carry, carry); + MP_ADD_CARRY(r6, a15, r6, carry, carry); + MP_ADD_CARRY(r7, 0, r7, carry, carry); + r8 += carry; + /* combine last bottom of sum 3 with second sum 2 */ + MP_ADD_CARRY(r0, a8, r0, 0, carry); + MP_ADD_CARRY(r1, a9, r1, carry, carry); + MP_ADD_CARRY(r2, a10, r2, carry, carry); + MP_ADD_CARRY(r3, a12, r3, carry, carry); + MP_ADD_CARRY(r4, a13, r4, carry, carry); + MP_ADD_CARRY(r5, a14, r5, carry, carry); + MP_ADD_CARRY(r6, a15, r6, carry, carry); + MP_ADD_CARRY(r7, a15, r7, carry, carry); /* from sum 3 */ + r8 += carry; + /* sum 3 (rest of it)*/ + MP_ADD_CARRY(r6, a14, r6, 0, carry); + MP_ADD_CARRY(r7, 0, r7, carry, carry); + r8 += carry; + /* sum 4 (rest of it)*/ + MP_ADD_CARRY(r0, a9, r0, 0, carry); + MP_ADD_CARRY(r1, a10, r1, carry, carry); + MP_ADD_CARRY(r2, a11, r2, carry, carry); + MP_ADD_CARRY(r3, a13, r3, carry, carry); + MP_ADD_CARRY(r4, a14, r4, carry, carry); + MP_ADD_CARRY(r5, a15, r5, carry, carry); + MP_ADD_CARRY(r6, a13, r6, carry, carry); + MP_ADD_CARRY(r7, a8, r7, carry, carry); + r8 += carry; + /* diff 5 */ + MP_SUB_BORROW(r0, a11, r0, 0, carry); + MP_SUB_BORROW(r1, a12, r1, carry, carry); + MP_SUB_BORROW(r2, a13, r2, carry, carry); + MP_SUB_BORROW(r3, 0, r3, carry, carry); + MP_SUB_BORROW(r4, 0, r4, carry, carry); + MP_SUB_BORROW(r5, 0, r5, carry, carry); + MP_SUB_BORROW(r6, a8, r6, carry, carry); + MP_SUB_BORROW(r7, a10, r7, carry, carry); + r8 -= carry; + /* diff 6 */ + MP_SUB_BORROW(r0, a12, r0, 0, carry); + MP_SUB_BORROW(r1, a13, r1, carry, carry); + MP_SUB_BORROW(r2, a14, r2, carry, carry); + MP_SUB_BORROW(r3, a15, r3, carry, carry); + MP_SUB_BORROW(r4, 0, r4, carry, carry); + MP_SUB_BORROW(r5, 0, r5, carry, carry); + MP_SUB_BORROW(r6, a9, r6, carry, carry); + MP_SUB_BORROW(r7, a11, r7, carry, carry); + r8 -= carry; + /* diff 7 */ + MP_SUB_BORROW(r0, a13, r0, 0, carry); + MP_SUB_BORROW(r1, a14, r1, carry, carry); + MP_SUB_BORROW(r2, a15, r2, carry, carry); + MP_SUB_BORROW(r3, a8, r3, carry, carry); + MP_SUB_BORROW(r4, a9, r4, carry, carry); + MP_SUB_BORROW(r5, a10, r5, carry, carry); + MP_SUB_BORROW(r6, 0, r6, carry, carry); + MP_SUB_BORROW(r7, a12, r7, carry, carry); + r8 -= carry; + /* diff 8 */ + MP_SUB_BORROW(r0, a14, r0, 0, carry); + MP_SUB_BORROW(r1, a15, r1, carry, carry); + MP_SUB_BORROW(r2, 0, r2, carry, carry); + MP_SUB_BORROW(r3, a9, r3, carry, carry); + MP_SUB_BORROW(r4, a10, r4, carry, carry); + MP_SUB_BORROW(r5, a11, r5, carry, carry); + MP_SUB_BORROW(r6, 0, r6, carry, carry); + MP_SUB_BORROW(r7, a13, r7, carry, carry); + r8 -= carry; + + /* reduce the overflows */ + while (r8 > 0) { + mp_digit r8_d = r8; + MP_ADD_CARRY(r0, r8_d, r0, 0, carry); + MP_ADD_CARRY(r1, 0, r1, carry, carry); + MP_ADD_CARRY(r2, 0, r2, carry, carry); + MP_ADD_CARRY(r3, -r8_d, r3, carry, carry); + MP_ADD_CARRY(r4, MP_DIGIT_MAX, r4, carry, carry); + MP_ADD_CARRY(r5, MP_DIGIT_MAX, r5, carry, carry); + MP_ADD_CARRY(r6, -(r8_d+1), r6, carry, carry); + MP_ADD_CARRY(r7, (r8_d-1), r7, carry, carry); + r8 = carry; + } + + /* reduce the underflows */ + while (r8 < 0) { + mp_digit r8_d = -r8; + MP_SUB_BORROW(r0, r8_d, r0, 0, carry); + MP_SUB_BORROW(r1, 0, r1, carry, carry); + MP_SUB_BORROW(r2, 0, r2, carry, carry); + MP_SUB_BORROW(r3, -r8_d, r3, carry, carry); + MP_SUB_BORROW(r4, MP_DIGIT_MAX, r4, carry, carry); + MP_SUB_BORROW(r5, MP_DIGIT_MAX, r5, carry, carry); + MP_SUB_BORROW(r6, -(r8_d+1), r6, carry, carry); + MP_SUB_BORROW(r7, (r8_d-1), r7, carry, carry); + r8 = -carry; + } + if (a != r) { + MP_CHECKOK(s_mp_pad(r,8)); + } + MP_SIGN(r) = MP_ZPOS; + MP_USED(r) = 8; + + MP_DIGIT(r,7) = r7; + MP_DIGIT(r,6) = r6; + MP_DIGIT(r,5) = r5; + MP_DIGIT(r,4) = r4; + MP_DIGIT(r,3) = r3; + MP_DIGIT(r,2) = r2; + MP_DIGIT(r,1) = r1; + MP_DIGIT(r,0) = r0; + + /* final reduction if necessary */ + if ((r7 == MP_DIGIT_MAX) && + ((r6 > 1) || ((r6 == 1) && + (r5 || r4 || r3 || + ((r2 == MP_DIGIT_MAX) && (r1 == MP_DIGIT_MAX) + && (r0 == MP_DIGIT_MAX)))))) { + MP_CHECKOK(mp_sub(r, &meth->irr, r)); + } +#ifdef notdef + + + /* smooth the negatives */ + while (MP_SIGN(r) != MP_ZPOS) { + MP_CHECKOK(mp_add(r, &meth->irr, r)); + } + while (MP_USED(r) > 8) { + MP_CHECKOK(mp_sub(r, &meth->irr, r)); + } + + /* final reduction if necessary */ + if (MP_DIGIT(r,7) >= MP_DIGIT(&meth->irr,7)) { + if (mp_cmp(r,&meth->irr) != MP_LT) { + MP_CHECKOK(mp_sub(r, &meth->irr, r)); + } + } +#endif + s_mp_clamp(r); +#else + switch (a_used) { + case 8: + a7 = MP_DIGIT(a,7); + case 7: + a6 = MP_DIGIT(a,6); + case 6: + a5 = MP_DIGIT(a,5); + case 5: + a4 = MP_DIGIT(a,4); + } + a7l = a7 << 32; + a7h = a7 >> 32; + a6l = a6 << 32; + a6h = a6 >> 32; + a5l = a5 << 32; + a5h = a5 >> 32; + a4l = a4 << 32; + a4h = a4 >> 32; + r3 = MP_DIGIT(a,3); + r2 = MP_DIGIT(a,2); + r1 = MP_DIGIT(a,1); + r0 = MP_DIGIT(a,0); + + /* sum 1 */ + MP_ADD_CARRY(r1, a5h << 32, r1, 0, carry); + MP_ADD_CARRY(r2, a6, r2, carry, carry); + MP_ADD_CARRY(r3, a7, r3, carry, carry); + r4 = carry; + MP_ADD_CARRY(r1, a5h << 32, r1, 0, carry); + MP_ADD_CARRY(r2, a6, r2, carry, carry); + MP_ADD_CARRY(r3, a7, r3, carry, carry); + r4 += carry; + /* sum 2 */ + MP_ADD_CARRY(r1, a6l, r1, 0, carry); + MP_ADD_CARRY(r2, a6h | a7l, r2, carry, carry); + MP_ADD_CARRY(r3, a7h, r3, carry, carry); + r4 += carry; + MP_ADD_CARRY(r1, a6l, r1, 0, carry); + MP_ADD_CARRY(r2, a6h | a7l, r2, carry, carry); + MP_ADD_CARRY(r3, a7h, r3, carry, carry); + r4 += carry; + + /* sum 3 */ + MP_ADD_CARRY(r0, a4, r0, 0, carry); + MP_ADD_CARRY(r1, a5l >> 32, r1, carry, carry); + MP_ADD_CARRY(r2, 0, r2, carry, carry); + MP_ADD_CARRY(r3, a7, r3, carry, carry); + r4 += carry; + /* sum 4 */ + MP_ADD_CARRY(r0, a4h | a5l, r0, 0, carry); + MP_ADD_CARRY(r1, a5h|(a6h<<32), r1, carry, carry); + MP_ADD_CARRY(r2, a7, r2, carry, carry); + MP_ADD_CARRY(r3, a6h | a4l, r3, carry, carry); + r4 += carry; + /* diff 5 */ + MP_SUB_BORROW(r0, a5h | a6l, r0, 0, carry); + MP_SUB_BORROW(r1, a6h, r1, carry, carry); + MP_SUB_BORROW(r2, 0, r2, carry, carry); + MP_SUB_BORROW(r3, (a4l>>32)|a5l,r3, carry, carry); + r4 -= carry; + /* diff 6 */ + MP_SUB_BORROW(r0, a6, r0, 0, carry); + MP_SUB_BORROW(r1, a7, r1, carry, carry); + MP_SUB_BORROW(r2, 0, r2, carry, carry); + MP_SUB_BORROW(r3, a4h|(a5h<<32),r3, carry, carry); + r4 -= carry; + /* diff 7 */ + MP_SUB_BORROW(r0, a6h|a7l, r0, 0, carry); + MP_SUB_BORROW(r1, a7h|a4l, r1, carry, carry); + MP_SUB_BORROW(r2, a4h|a5l, r2, carry, carry); + MP_SUB_BORROW(r3, a6l, r3, carry, carry); + r4 -= carry; + /* diff 8 */ + MP_SUB_BORROW(r0, a7, r0, 0, carry); + MP_SUB_BORROW(r1, a4h<<32, r1, carry, carry); + MP_SUB_BORROW(r2, a5, r2, carry, carry); + MP_SUB_BORROW(r3, a6h<<32, r3, carry, carry); + r4 -= carry; + + /* reduce the overflows */ + while (r4 > 0) { + mp_digit r4_long = r4; + mp_digit r4l = (r4_long << 32); + MP_ADD_CARRY(r0, r4_long, r0, 0, carry); + MP_ADD_CARRY(r1, -r4l, r1, carry, carry); + MP_ADD_CARRY(r2, MP_DIGIT_MAX, r2, carry, carry); + MP_ADD_CARRY(r3, r4l-r4_long-1,r3, carry, carry); + r4 = carry; + } + + /* reduce the underflows */ + while (r4 < 0) { + mp_digit r4_long = -r4; + mp_digit r4l = (r4_long << 32); + MP_SUB_BORROW(r0, r4_long, r0, 0, carry); + MP_SUB_BORROW(r1, -r4l, r1, carry, carry); + MP_SUB_BORROW(r2, MP_DIGIT_MAX, r2, carry, carry); + MP_SUB_BORROW(r3, r4l-r4_long-1,r3, carry, carry); + r4 = -carry; + } + + if (a != r) { + MP_CHECKOK(s_mp_pad(r,4)); + } + MP_SIGN(r) = MP_ZPOS; + MP_USED(r) = 4; + + MP_DIGIT(r,3) = r3; + MP_DIGIT(r,2) = r2; + MP_DIGIT(r,1) = r1; + MP_DIGIT(r,0) = r0; + + /* final reduction if necessary */ + if ((r3 > 0xFFFFFFFF00000001ULL) || + ((r3 == 0xFFFFFFFF00000001ULL) && + (r2 || (r1 >> 32)|| + (r1 == 0xFFFFFFFFULL && r0 == MP_DIGIT_MAX)))) { + /* very rare, just use mp_sub */ + MP_CHECKOK(mp_sub(r, &meth->irr, r)); + } + + s_mp_clamp(r); +#endif + } + + CLEANUP: + return res; +} + +/* Compute the square of polynomial a, reduce modulo p256. Store the + * result in r. r could be a. Uses optimized modular reduction for p256. + */ +mp_err +ec_GFp_nistp256_sqr(const mp_int *a, mp_int *r, const GFMethod *meth) +{ + mp_err res = MP_OKAY; + + MP_CHECKOK(mp_sqr(a, r)); + MP_CHECKOK(ec_GFp_nistp256_mod(r, r, meth)); + CLEANUP: + return res; +} + +/* Compute the product of two polynomials a and b, reduce modulo p256. + * Store the result in r. r could be a or b; a could be b. Uses + * optimized modular reduction for p256. */ +mp_err +ec_GFp_nistp256_mul(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth) +{ + mp_err res = MP_OKAY; + + MP_CHECKOK(mp_mul(a, b, r)); + MP_CHECKOK(ec_GFp_nistp256_mod(r, r, meth)); + CLEANUP: + return res; +} + +/* Wire in fast field arithmetic and precomputation of base point for + * named curves. */ +mp_err +ec_group_set_gfp256(ECGroup *group, ECCurveName name) +{ + if (name == ECCurve_NIST_P256) { + group->meth->field_mod = &ec_GFp_nistp256_mod; + group->meth->field_mul = &ec_GFp_nistp256_mul; + group->meth->field_sqr = &ec_GFp_nistp256_sqr; + } + return MP_OKAY; +} diff --git a/security/nss/lib/freebl/ecl/ecp_384.c b/security/nss/lib/freebl/ecl/ecp_384.c new file mode 100644 index 000000000..4ad4137d2 --- /dev/null +++ b/security/nss/lib/freebl/ecl/ecp_384.c @@ -0,0 +1,293 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * 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 the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Douglas Stebila <douglas@stebila.ca> + * + * 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. + * + * ***** END LICENSE BLOCK ***** */ + +#include "ecp.h" +#include "mpi.h" +#include "mplogic.h" +#include "mpi-priv.h" +#include <stdlib.h> + +/* Fast modular reduction for p384 = 2^384 - 2^128 - 2^96 + 2^32 - 1. a can be r. + * Uses algorithm 2.30 from Hankerson, Menezes, Vanstone. Guide to + * Elliptic Curve Cryptography. */ +mp_err +ec_GFp_nistp384_mod(const mp_int *a, mp_int *r, const GFMethod *meth) +{ + mp_err res = MP_OKAY; + int a_bits = mpl_significant_bits(a); + int i; + + /* m1, m2 are statically-allocated mp_int of exactly the size we need */ + mp_int m[10]; + +#ifdef ECL_THIRTY_TWO_BIT + mp_digit s[10][12]; + for (i = 0; i < 10; i++) { + MP_SIGN(&m[i]) = MP_ZPOS; + MP_ALLOC(&m[i]) = 12; + MP_USED(&m[i]) = 12; + MP_DIGITS(&m[i]) = s[i]; + } +#else + mp_digit s[10][6]; + for (i = 0; i < 10; i++) { + MP_SIGN(&m[i]) = MP_ZPOS; + MP_ALLOC(&m[i]) = 6; + MP_USED(&m[i]) = 6; + MP_DIGITS(&m[i]) = s[i]; + } +#endif + +#ifdef ECL_THIRTY_TWO_BIT + /* for polynomials larger than twice the field size or polynomials + * not using all words, use regular reduction */ + if ((a_bits > 768) || (a_bits <= 736)) { + MP_CHECKOK(mp_mod(a, &meth->irr, r)); + } else { + for (i = 0; i < 12; i++) { + s[0][i] = MP_DIGIT(a, i); + } + s[1][0] = 0; + s[1][1] = 0; + s[1][2] = 0; + s[1][3] = 0; + s[1][4] = MP_DIGIT(a, 21); + s[1][5] = MP_DIGIT(a, 22); + s[1][6] = MP_DIGIT(a, 23); + s[1][7] = 0; + s[1][8] = 0; + s[1][9] = 0; + s[1][10] = 0; + s[1][11] = 0; + for (i = 0; i < 12; i++) { + s[2][i] = MP_DIGIT(a, i+12); + } + s[3][0] = MP_DIGIT(a, 21); + s[3][1] = MP_DIGIT(a, 22); + s[3][2] = MP_DIGIT(a, 23); + for (i = 3; i < 12; i++) { + s[3][i] = MP_DIGIT(a, i+9); + } + s[4][0] = 0; + s[4][1] = MP_DIGIT(a, 23); + s[4][2] = 0; + s[4][3] = MP_DIGIT(a, 20); + for (i = 4; i < 12; i++) { + s[4][i] = MP_DIGIT(a, i+8); + } + s[5][0] = 0; + s[5][1] = 0; + s[5][2] = 0; + s[5][3] = 0; + s[5][4] = MP_DIGIT(a, 20); + s[5][5] = MP_DIGIT(a, 21); + s[5][6] = MP_DIGIT(a, 22); + s[5][7] = MP_DIGIT(a, 23); + s[5][8] = 0; + s[5][9] = 0; + s[5][10] = 0; + s[5][11] = 0; + s[6][0] = MP_DIGIT(a, 20); + s[6][1] = 0; + s[6][2] = 0; + s[6][3] = MP_DIGIT(a, 21); + s[6][4] = MP_DIGIT(a, 22); + s[6][5] = MP_DIGIT(a, 23); + s[6][6] = 0; + s[6][7] = 0; + s[6][8] = 0; + s[6][9] = 0; + s[6][10] = 0; + s[6][11] = 0; + s[7][0] = MP_DIGIT(a, 23); + for (i = 1; i < 12; i++) { + s[7][i] = MP_DIGIT(a, i+11); + } + s[8][0] = 0; + s[8][1] = MP_DIGIT(a, 20); + s[8][2] = MP_DIGIT(a, 21); + s[8][3] = MP_DIGIT(a, 22); + s[8][4] = MP_DIGIT(a, 23); + s[8][5] = 0; + s[8][6] = 0; + s[8][7] = 0; + s[8][8] = 0; + s[8][9] = 0; + s[8][10] = 0; + s[8][11] = 0; + s[9][0] = 0; + s[9][1] = 0; + s[9][2] = 0; + s[9][3] = MP_DIGIT(a, 23); + s[9][4] = MP_DIGIT(a, 23); + s[9][5] = 0; + s[9][6] = 0; + s[9][7] = 0; + s[9][8] = 0; + s[9][9] = 0; + s[9][10] = 0; + s[9][11] = 0; + + MP_CHECKOK(mp_add(&m[0], &m[1], r)); + MP_CHECKOK(mp_add(r, &m[1], r)); + MP_CHECKOK(mp_add(r, &m[2], r)); + MP_CHECKOK(mp_add(r, &m[3], r)); + MP_CHECKOK(mp_add(r, &m[4], r)); + MP_CHECKOK(mp_add(r, &m[5], r)); + MP_CHECKOK(mp_add(r, &m[6], r)); + MP_CHECKOK(mp_sub(r, &m[7], r)); + MP_CHECKOK(mp_sub(r, &m[8], r)); + MP_CHECKOK(mp_submod(r, &m[9], &meth->irr, r)); + s_mp_clamp(r); + } +#else + /* for polynomials larger than twice the field size or polynomials + * not using all words, use regular reduction */ + if ((a_bits > 768) || (a_bits <= 736)) { + MP_CHECKOK(mp_mod(a, &meth->irr, r)); + } else { + for (i = 0; i < 6; i++) { + s[0][i] = MP_DIGIT(a, i); + } + s[1][0] = 0; + s[1][1] = 0; + s[1][2] = (MP_DIGIT(a, 10) >> 32) | (MP_DIGIT(a, 11) << 32); + s[1][3] = MP_DIGIT(a, 11) >> 32; + s[1][4] = 0; + s[1][5] = 0; + for (i = 0; i < 6; i++) { + s[2][i] = MP_DIGIT(a, i+6); + } + s[3][0] = (MP_DIGIT(a, 10) >> 32) | (MP_DIGIT(a, 11) << 32); + s[3][1] = (MP_DIGIT(a, 11) >> 32) | (MP_DIGIT(a, 6) << 32); + for (i = 2; i < 6; i++) { + s[3][i] = (MP_DIGIT(a, i+4) >> 32) | (MP_DIGIT(a, i+5) << 32); + } + s[4][0] = (MP_DIGIT(a, 11) >> 32) << 32; + s[4][1] = MP_DIGIT(a, 10) << 32; + for (i = 2; i < 6; i++) { + s[4][i] = MP_DIGIT(a, i+4); + } + s[5][0] = 0; + s[5][1] = 0; + s[5][2] = MP_DIGIT(a, 10); + s[5][3] = MP_DIGIT(a, 11); + s[5][4] = 0; + s[5][5] = 0; + s[6][0] = (MP_DIGIT(a, 10) << 32) >> 32; + s[6][1] = (MP_DIGIT(a, 10) >> 32) << 32; + s[6][2] = MP_DIGIT(a, 11); + s[6][3] = 0; + s[6][4] = 0; + s[6][5] = 0; + s[7][0] = (MP_DIGIT(a, 11) >> 32) | (MP_DIGIT(a, 6) << 32); + for (i = 1; i < 6; i++) { + s[7][i] = (MP_DIGIT(a, i+5) >> 32) | (MP_DIGIT(a, i+6) << 32); + } + s[8][0] = MP_DIGIT(a, 10) << 32; + s[8][1] = (MP_DIGIT(a, 10) >> 32) | (MP_DIGIT(a, 11) << 32); + s[8][2] = MP_DIGIT(a, 11) >> 32; + s[8][3] = 0; + s[8][4] = 0; + s[8][5] = 0; + s[9][0] = 0; + s[9][1] = (MP_DIGIT(a, 11) >> 32) << 32; + s[9][2] = MP_DIGIT(a, 11) >> 32; + s[9][3] = 0; + s[9][4] = 0; + s[9][5] = 0; + + MP_CHECKOK(mp_add(&m[0], &m[1], r)); + MP_CHECKOK(mp_add(r, &m[1], r)); + MP_CHECKOK(mp_add(r, &m[2], r)); + MP_CHECKOK(mp_add(r, &m[3], r)); + MP_CHECKOK(mp_add(r, &m[4], r)); + MP_CHECKOK(mp_add(r, &m[5], r)); + MP_CHECKOK(mp_add(r, &m[6], r)); + MP_CHECKOK(mp_sub(r, &m[7], r)); + MP_CHECKOK(mp_sub(r, &m[8], r)); + MP_CHECKOK(mp_submod(r, &m[9], &meth->irr, r)); + s_mp_clamp(r); + } +#endif + + CLEANUP: + return res; +} + +/* Compute the square of polynomial a, reduce modulo p384. Store the + * result in r. r could be a. Uses optimized modular reduction for p384. + */ +mp_err +ec_GFp_nistp384_sqr(const mp_int *a, mp_int *r, const GFMethod *meth) +{ + mp_err res = MP_OKAY; + + MP_CHECKOK(mp_sqr(a, r)); + MP_CHECKOK(ec_GFp_nistp384_mod(r, r, meth)); + CLEANUP: + return res; +} + +/* Compute the product of two polynomials a and b, reduce modulo p384. + * Store the result in r. r could be a or b; a could be b. Uses + * optimized modular reduction for p384. */ +mp_err +ec_GFp_nistp384_mul(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth) +{ + mp_err res = MP_OKAY; + + MP_CHECKOK(mp_mul(a, b, r)); + MP_CHECKOK(ec_GFp_nistp384_mod(r, r, meth)); + CLEANUP: + return res; +} + +/* Wire in fast field arithmetic and precomputation of base point for + * named curves. */ +mp_err +ec_group_set_gfp384(ECGroup *group, ECCurveName name) +{ + if (name == ECCurve_NIST_P384) { + group->meth->field_mod = &ec_GFp_nistp384_mod; + group->meth->field_mul = &ec_GFp_nistp384_mul; + group->meth->field_sqr = &ec_GFp_nistp384_sqr; + } + return MP_OKAY; +} diff --git a/security/nss/lib/freebl/ecl/ecp_521.c b/security/nss/lib/freebl/ecl/ecp_521.c new file mode 100644 index 000000000..685d19b9f --- /dev/null +++ b/security/nss/lib/freebl/ecl/ecp_521.c @@ -0,0 +1,170 @@ +/* + * ***** BEGIN LICENSE BLOCK ***** + * 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 the Initial Developer are Copyright (C) 2003 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Douglas Stebila <douglas@stebila.ca> + * + * 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. + * + * ***** END LICENSE BLOCK ***** */ + +#include "ecp.h" +#include "mpi.h" +#include "mplogic.h" +#include "mpi-priv.h" +#include <stdlib.h> + +#define ECP521_DIGITS ECL_CURVE_DIGITS(521) + +/* Fast modular reduction for p521 = 2^521 - 1. a can be r. Uses + * algorithm 2.31 from Hankerson, Menezes, Vanstone. Guide to + * Elliptic Curve Cryptography. */ +mp_err +ec_GFp_nistp521_mod(const mp_int *a, mp_int *r, const GFMethod *meth) +{ + mp_err res = MP_OKAY; + int a_bits = mpl_significant_bits(a); + int i; + + /* m1, m2 are statically-allocated mp_int of exactly the size we need */ + mp_int m1; + + mp_digit s1[ECP521_DIGITS] = { 0 }; + + MP_SIGN(&m1) = MP_ZPOS; + MP_ALLOC(&m1) = ECP521_DIGITS; + MP_USED(&m1) = ECP521_DIGITS; + MP_DIGITS(&m1) = s1; + + if (a_bits < 521) { + if (a==r) return MP_OKAY; + return mp_copy(a, r); + } + /* for polynomials larger than twice the field size or polynomials + * not using all words, use regular reduction */ + if (a_bits > (521*2)) { + MP_CHECKOK(mp_mod(a, &meth->irr, r)); + } else { +#define FIRST_DIGIT (ECP521_DIGITS-1) + for (i = FIRST_DIGIT; i < MP_USED(a)-1; i++) { + s1[i-FIRST_DIGIT] = (MP_DIGIT(a, i) >> 9) + | (MP_DIGIT(a, 1+i) << (MP_DIGIT_BIT-9)); + } + s1[i-FIRST_DIGIT] = MP_DIGIT(a, i) >> 9; + + if ( a != r ) { + MP_CHECKOK(s_mp_pad(r,ECP521_DIGITS)); + for (i = 0; i < ECP521_DIGITS; i++) { + MP_DIGIT(r,i) = MP_DIGIT(a, i); + } + } + MP_USED(r) = ECP521_DIGITS; + MP_DIGIT(r,FIRST_DIGIT) &= 0x1FF; + + MP_CHECKOK(s_mp_add(r, &m1)); + if (MP_DIGIT(r, FIRST_DIGIT) & 0x200) { + MP_CHECKOK(s_mp_add_d(r,1)); + MP_DIGIT(r,FIRST_DIGIT) &= 0x1FF; + } + s_mp_clamp(r); + } + + CLEANUP: + return res; +} + +/* Compute the square of polynomial a, reduce modulo p521. Store the + * result in r. r could be a. Uses optimized modular reduction for p521. + */ +mp_err +ec_GFp_nistp521_sqr(const mp_int *a, mp_int *r, const GFMethod *meth) +{ + mp_err res = MP_OKAY; + + MP_CHECKOK(mp_sqr(a, r)); + MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth)); + CLEANUP: + return res; +} + +/* Compute the product of two polynomials a and b, reduce modulo p521. + * Store the result in r. r could be a or b; a could be b. Uses + * optimized modular reduction for p521. */ +mp_err +ec_GFp_nistp521_mul(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth) +{ + mp_err res = MP_OKAY; + + MP_CHECKOK(mp_mul(a, b, r)); + MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth)); + CLEANUP: + return res; +} + +/* Divides two field elements. If a is NULL, then returns the inverse of + * b. */ +mp_err +ec_GFp_nistp521_div(const mp_int *a, const mp_int *b, mp_int *r, + const GFMethod *meth) +{ + mp_err res = MP_OKAY; + mp_int t; + + /* If a is NULL, then return the inverse of b, otherwise return a/b. */ + if (a == NULL) { + return mp_invmod(b, &meth->irr, r); + } else { + /* MPI doesn't support divmod, so we implement it using invmod and + * mulmod. */ + MP_CHECKOK(mp_init(&t)); + MP_CHECKOK(mp_invmod(b, &meth->irr, &t)); + MP_CHECKOK(mp_mul(a, &t, r)); + MP_CHECKOK(ec_GFp_nistp521_mod(r, r, meth)); + CLEANUP: + mp_clear(&t); + return res; + } +} + +/* Wire in fast field arithmetic and precomputation of base point for + * named curves. */ +mp_err +ec_group_set_gfp521(ECGroup *group, ECCurveName name) +{ + if (name == ECCurve_NIST_P521) { + group->meth->field_mod = &ec_GFp_nistp521_mod; + group->meth->field_mul = &ec_GFp_nistp521_mul; + group->meth->field_sqr = &ec_GFp_nistp521_sqr; + group->meth->field_div = &ec_GFp_nistp521_div; + } + return MP_OKAY; +} diff --git a/security/nss/lib/freebl/ecl/tests/ec2_test.c b/security/nss/lib/freebl/ecl/tests/ec2_test.c index e82b47da0..cf6540221 100644 --- a/security/nss/lib/freebl/ecl/tests/ec2_test.c +++ b/security/nss/lib/freebl/ecl/tests/ec2_test.c @@ -455,6 +455,36 @@ main(int argv, char **argc) ECTEST_GENERIC_GF2M("SECT-131R1", ECCurve_SECG_CHAR2_131R1); /* specific arithmetic tests */ + ECTEST_NAMED_GF2M("NIST-K163", ECCurve_NIST_K163); + ECTEST_NAMED_GF2M("NIST-B163", ECCurve_NIST_B163); + ECTEST_NAMED_GF2M("NIST-K233", ECCurve_NIST_K233); + ECTEST_NAMED_GF2M("NIST-B233", ECCurve_NIST_B233); + ECTEST_NAMED_GF2M("NIST-K283", ECCurve_NIST_K283); + ECTEST_NAMED_GF2M("NIST-B283", ECCurve_NIST_B283); + ECTEST_NAMED_GF2M("NIST-K409", ECCurve_NIST_K409); + ECTEST_NAMED_GF2M("NIST-B409", ECCurve_NIST_B409); + ECTEST_NAMED_GF2M("NIST-K571", ECCurve_NIST_K571); + ECTEST_NAMED_GF2M("NIST-B571", ECCurve_NIST_B571); + ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB163V1", ECCurve_X9_62_CHAR2_PNB163V1); + ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB163V2", ECCurve_X9_62_CHAR2_PNB163V2); + ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB163V3", ECCurve_X9_62_CHAR2_PNB163V3); + ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB176V1", ECCurve_X9_62_CHAR2_PNB176V1); + ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB191V1", ECCurve_X9_62_CHAR2_TNB191V1); + ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB191V2", ECCurve_X9_62_CHAR2_TNB191V2); + ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB191V3", ECCurve_X9_62_CHAR2_TNB191V3); + ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB208W1", ECCurve_X9_62_CHAR2_PNB208W1); + ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB239V1", ECCurve_X9_62_CHAR2_TNB239V1); + ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB239V2", ECCurve_X9_62_CHAR2_TNB239V2); + ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB239V3", ECCurve_X9_62_CHAR2_TNB239V3); + ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB272W1", ECCurve_X9_62_CHAR2_PNB272W1); + ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB304W1", ECCurve_X9_62_CHAR2_PNB304W1); + ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB359V1", ECCurve_X9_62_CHAR2_TNB359V1); + ECTEST_NAMED_GF2M("ANSI X9.62 C2PNB368W1", ECCurve_X9_62_CHAR2_PNB368W1); + ECTEST_NAMED_GF2M("ANSI X9.62 C2TNB431R1", ECCurve_X9_62_CHAR2_TNB431R1); + ECTEST_NAMED_GF2M("SECT-113R1", ECCurve_SECG_CHAR2_113R1); + ECTEST_NAMED_GF2M("SECT-113R2", ECCurve_SECG_CHAR2_113R2); + ECTEST_NAMED_GF2M("SECT-131R1", ECCurve_SECG_CHAR2_131R1); + ECTEST_NAMED_GF2M("SECT-131R2", ECCurve_SECG_CHAR2_131R2); ECTEST_NAMED_GF2M("SECT-163K1", ECCurve_SECG_CHAR2_163K1); ECTEST_NAMED_GF2M("SECT-163R1", ECCurve_SECG_CHAR2_163R1); ECTEST_NAMED_GF2M("SECT-163R2", ECCurve_SECG_CHAR2_163R2); @@ -462,6 +492,19 @@ main(int argv, char **argc) ECTEST_NAMED_GF2M("SECT-193R2", ECCurve_SECG_CHAR2_193R2); ECTEST_NAMED_GF2M("SECT-233K1", ECCurve_SECG_CHAR2_233K1); ECTEST_NAMED_GF2M("SECT-233R1", ECCurve_SECG_CHAR2_233R1); + ECTEST_NAMED_GF2M("SECT-239K1", ECCurve_SECG_CHAR2_239K1); + ECTEST_NAMED_GF2M("SECT-283K1", ECCurve_SECG_CHAR2_283K1); + ECTEST_NAMED_GF2M("SECT-283R1", ECCurve_SECG_CHAR2_283R1); + ECTEST_NAMED_GF2M("SECT-409K1", ECCurve_SECG_CHAR2_409K1); + ECTEST_NAMED_GF2M("SECT-409R1", ECCurve_SECG_CHAR2_409R1); + ECTEST_NAMED_GF2M("SECT-571K1", ECCurve_SECG_CHAR2_571K1); + ECTEST_NAMED_GF2M("SECT-571R1", ECCurve_SECG_CHAR2_571R1); + ECTEST_NAMED_GF2M("WTLS-1 (113)", ECCurve_WTLS_1); + ECTEST_NAMED_GF2M("WTLS-3 (163)", ECCurve_WTLS_3); + ECTEST_NAMED_GF2M("WTLS-4 (113)", ECCurve_WTLS_4); + ECTEST_NAMED_GF2M("WTLS-5 (163)", ECCurve_WTLS_5); + ECTEST_NAMED_GF2M("WTLS-10 (233)", ECCurve_WTLS_10); + ECTEST_NAMED_GF2M("WTLS-11 (233)", ECCurve_WTLS_11); CLEANUP: EC_FreeCurveParams(params); diff --git a/security/nss/lib/freebl/ecl/tests/ecp_test.c b/security/nss/lib/freebl/ecl/tests/ecp_test.c index d7ce299ec..eb2844fe5 100644 --- a/security/nss/lib/freebl/ecl/tests/ecp_test.c +++ b/security/nss/lib/freebl/ecl/tests/ecp_test.c @@ -417,6 +417,22 @@ main(int argv, char **argc) ECTEST_GENERIC_GFP("SECP-160R1", ECCurve_SECG_PRIME_160R1); /* specific arithmetic tests */ + ECTEST_NAMED_GFP("NIST-P192", ECCurve_NIST_P192); + ECTEST_NAMED_GFP("NIST-P224", ECCurve_NIST_P224); + ECTEST_NAMED_GFP("NIST-P256", ECCurve_NIST_P256); + ECTEST_NAMED_GFP("NIST-P384", ECCurve_NIST_P384); + ECTEST_NAMED_GFP("NIST-P521", ECCurve_NIST_P521); + ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v1", ECCurve_X9_62_PRIME_192V1); + ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v2", ECCurve_X9_62_PRIME_192V2); + ECTEST_NAMED_GFP("ANSI X9.62 PRIME192v3", ECCurve_X9_62_PRIME_192V3); + ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v1", ECCurve_X9_62_PRIME_239V1); + ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v2", ECCurve_X9_62_PRIME_239V2); + ECTEST_NAMED_GFP("ANSI X9.62 PRIME239v3", ECCurve_X9_62_PRIME_239V3); + ECTEST_NAMED_GFP("ANSI X9.62 PRIME256v1", ECCurve_X9_62_PRIME_256V1); + ECTEST_NAMED_GFP("SECP-112R1", ECCurve_SECG_PRIME_112R1); + ECTEST_NAMED_GFP("SECP-112R2", ECCurve_SECG_PRIME_112R2); + ECTEST_NAMED_GFP("SECP-128R1", ECCurve_SECG_PRIME_128R1); + ECTEST_NAMED_GFP("SECP-128R2", ECCurve_SECG_PRIME_128R2); ECTEST_NAMED_GFP("SECP-160K1", ECCurve_SECG_PRIME_160K1); ECTEST_NAMED_GFP("SECP-160R1", ECCurve_SECG_PRIME_160R1); ECTEST_NAMED_GFP("SECP-160R2", ECCurve_SECG_PRIME_160R2); @@ -424,6 +440,15 @@ main(int argv, char **argc) ECTEST_NAMED_GFP("SECP-192R1", ECCurve_SECG_PRIME_192R1); ECTEST_NAMED_GFP("SECP-224K1", ECCurve_SECG_PRIME_224K1); ECTEST_NAMED_GFP("SECP-224R1", ECCurve_SECG_PRIME_224R1); + ECTEST_NAMED_GFP("SECP-256K1", ECCurve_SECG_PRIME_256K1); + ECTEST_NAMED_GFP("SECP-256R1", ECCurve_SECG_PRIME_256R1); + ECTEST_NAMED_GFP("SECP-384R1", ECCurve_SECG_PRIME_384R1); + ECTEST_NAMED_GFP("SECP-521R1", ECCurve_SECG_PRIME_521R1); + ECTEST_NAMED_GFP("WTLS-6 (112)", ECCurve_WTLS_6); + ECTEST_NAMED_GFP("WTLS-7 (160)", ECCurve_WTLS_7); + ECTEST_NAMED_GFP("WTLS-8 (112)", ECCurve_WTLS_8); + ECTEST_NAMED_GFP("WTLS-9 (160)", ECCurve_WTLS_9); + ECTEST_NAMED_GFP("WTLS-12 (224)", ECCurve_WTLS_12); CLEANUP: EC_FreeCurveParams(params); diff --git a/security/nss/lib/freebl/freebl.rc b/security/nss/lib/freebl/freebl.rc index 4f60cba9f..39b0e70bc 100644 --- a/security/nss/lib/freebl/freebl.rc +++ b/security/nss/lib/freebl/freebl.rc @@ -84,11 +84,10 @@ BEGIN BEGIN BLOCK "040904B0" // Lang=US English, CharSet=Unicode BEGIN - VALUE "CompanyName", "Netscape Communications Corporation\0" + VALUE "CompanyName", "Mozilla Foundation\0" VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0" VALUE "FileVersion", NSS_VERSION "\0" VALUE "InternalName", MY_INTERNAL_NAME "\0" - VALUE "LegalCopyright", "Copyright \251 2005 Netscape Communications Corporation\0" VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0" VALUE "ProductName", "Network Security Services\0" VALUE "ProductVersion", NSS_VERSION "\0" diff --git a/security/nss/lib/freebl/ldvector.c b/security/nss/lib/freebl/ldvector.c index 595d7dd8b..70a4eed50 100644 --- a/security/nss/lib/freebl/ldvector.c +++ b/security/nss/lib/freebl/ldvector.c @@ -222,6 +222,11 @@ static const struct FREEBLVectorStr vector = RNG_SystemInfoForRNG, /* End of Version 3.008. */ + + FIPS186Change_GenerateX, + FIPS186Change_ReduceModQForDSA, + + /* End of Version 3.009. */ }; const FREEBLVector * diff --git a/security/nss/lib/freebl/loader.c b/security/nss/lib/freebl/loader.c index 141cc1b7f..0aae0e6ac 100644 --- a/security/nss/lib/freebl/loader.c +++ b/security/nss/lib/freebl/loader.c @@ -1631,3 +1631,22 @@ RNG_SystemInfoForRNG(void) (vector->p_RNG_SystemInfoForRNG)(); } + +SECStatus +FIPS186Change_GenerateX(unsigned char *XKEY, const unsigned char *XSEEDj, + unsigned char *x_j) +{ + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) + return SECFailure; + return (vector->p_FIPS186Change_GenerateX)(XKEY, XSEEDj, x_j); +} + +SECStatus +FIPS186Change_ReduceModQForDSA(const unsigned char *w, + const unsigned char *q, + unsigned char *xj) +{ + if (!vector && PR_SUCCESS != freebl_RunLoaderOnce()) + return SECFailure; + return (vector->p_FIPS186Change_ReduceModQForDSA)(w, q, xj); +} diff --git a/security/nss/lib/freebl/loader.h b/security/nss/lib/freebl/loader.h index 89bab5401..df7c5c99b 100644 --- a/security/nss/lib/freebl/loader.h +++ b/security/nss/lib/freebl/loader.h @@ -44,7 +44,7 @@ #include "blapi.h" -#define FREEBL_VERSION 0x0308 +#define FREEBL_VERSION 0x0309 struct FREEBLVectorStr { @@ -449,6 +449,15 @@ struct FREEBLVectorStr { void (* p_RNG_SystemInfoForRNG)(void); /* Version 3.008 came to here */ + + SECStatus (* p_FIPS186Change_GenerateX)(unsigned char *XKEY, + const unsigned char *XSEEDj, + unsigned char *x_j); + SECStatus (* p_FIPS186Change_ReduceModQForDSA)(const unsigned char *w, + const unsigned char *q, + unsigned char *xj); + + /* Version 3.009 came to here */ }; typedef struct FREEBLVectorStr FREEBLVector; diff --git a/security/nss/lib/freebl/manifest.mn b/security/nss/lib/freebl/manifest.mn index 787c7fbec..00dac226d 100644 --- a/security/nss/lib/freebl/manifest.mn +++ b/security/nss/lib/freebl/manifest.mn @@ -104,11 +104,13 @@ MPI_SRCS = mpprime.c mpmontg.c mplogic.c mpi.c mp_gf2m.c ECL_HDRS = ecl-exp.h ecl.h ec2.h ecp.h ecl-priv.h ifdef NSS_ENABLE_ECC ECL_SRCS = ecl.c ecl_curve.c ecl_mult.c ecl_gf.c \ - ec2_aff.c ec2_mont.c ec2_proj.c \ - ec2_163.c ec2_193.c ec2_233.c \ ecp_aff.c ecp_jac.c ecp_mont.c \ - ecp_192.c ecp_224.c \ ec_naf.c ecp_jm.c +ifdef NSS_ECC_MORE_THAN_SUITE_B +ECL_SRCS += ec2_aff.c ec2_mont.c ec2_proj.c \ + ec2_163.c ec2_193.c ec2_233.c \ + ecp_192.c ecp_224.c ecp_256.c ecp_384.c ecp_521.c +endif else ECL_SRCS = $(NULL) endif diff --git a/security/nss/lib/freebl/mpi/Makefile b/security/nss/lib/freebl/mpi/Makefile index 3c780f5ac..4716f6ac5 100644 --- a/security/nss/lib/freebl/mpi/Makefile +++ b/security/nss/lib/freebl/mpi/Makefile @@ -112,7 +112,7 @@ DOCS=README doc utils/README utils/PRIMES TOOLS=gcd invmod isprime lap dec2hex hex2dec primegen prng \ basecvt fact exptmod pi makeprime identest -LIBOBJS = mpprime.o mpmontg.o mplogic.o mp_gf2m.o mpi.o $(AS_OBJS) +LIBOBJS = mpprime.o mpmontg.o mplogic.o mp_gf2m.o mpi.o mpcpucache.o $(AS_OBJS) LIBHDRS = mpi-config.h mpi-priv.h mpi.h APPHDRS = mpi-config.h mpi.h mplogic.h mp_gf2m.h mpprime.h @@ -154,6 +154,8 @@ mpmontg.o: mpmontg.c mpi-priv.h mplogic.h mpprime.h $(LIBHDRS) mpprime.o: mpprime.c mpi-priv.h mpprime.h mplogic.h primes.c $(LIBHDRS) +mpcpucache.o: mpcpucache.c $(LIBHDRS) + mpi_mips.o: mpi_mips.s $(CC) -o $@ $(ASFLAGS) -c mpi_mips.s diff --git a/security/nss/lib/freebl/mpi/mp_gf2m.c b/security/nss/lib/freebl/mpi/mp_gf2m.c index 962fdb1fb..5ce9fed9e 100644 --- a/security/nss/lib/freebl/mpi/mp_gf2m.c +++ b/security/nss/lib/freebl/mpi/mp_gf2m.c @@ -92,7 +92,7 @@ s_bmul_1x1(mp_digit *rh, mp_digit *rl, const mp_digit a, const mp_digit b) mp_digit tab[16], top3b = a >> 61; register mp_digit a1, a2, a4, a8; - a1 = a & (0x1FFFFFFFFFFFFFFF); a2 = a1 << 1; + a1 = a & (0x1FFFFFFFFFFFFFFFULL); a2 = a1 << 1; a4 = a2 << 1; a8 = a4 << 1; tab[ 0] = 0; tab[ 1] = a1; tab[ 2] = a2; tab[ 3] = a1^a2; tab[ 4] = a4; tab[ 5] = a1^a4; tab[ 6] = a2^a4; tab[ 7] = a1^a2^a4; diff --git a/security/nss/lib/freebl/mpi/mpi_sparc.c b/security/nss/lib/freebl/mpi/mpi_sparc.c index eb2317dd0..f7eb19c19 100644 --- a/security/nss/lib/freebl/mpi/mpi_sparc.c +++ b/security/nss/lib/freebl/mpi/mpi_sparc.c @@ -177,11 +177,11 @@ v8_mpv_mul_d_add_prop(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) #endif } -/* vis versions of these functions run only on v8+vis or v9+vis CPUs. */ +/* These functions run only on v8plus+vis or v9+vis CPUs. */ /* c = a * b */ -static void -vis_mpv_mul_d(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) +void +s_mpv_mul_d(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) { mp_digit d; mp_digit x[258]; @@ -204,8 +204,8 @@ vis_mpv_mul_d(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) } /* c += a * b, where a is a_len words long. */ -static void -vis_mpv_mul_d_add(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) +void +s_mpv_mul_d_add(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) { mp_digit d; mp_digit x[258]; @@ -227,9 +227,8 @@ vis_mpv_mul_d_add(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) } /* c += a * b, where a is y words long. */ -static void -vis_mpv_mul_d_add_prop(const mp_digit *a, mp_size a_len, mp_digit b, - mp_digit *c) +void +s_mpv_mul_d_add_prop(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) { mp_digit d; mp_digit x[258]; @@ -256,106 +255,3 @@ vis_mpv_mul_d_add_prop(const mp_digit *a, mp_size a_len, mp_digit b, v8_mpv_mul_d_add_prop(a, a_len, b, c); } } - -#if defined(SOLARIS2_5) -static int -isSparcV8PlusVis(void) -{ - long buflen; - int rv = 0; /* false */ - char buf[256]; - buflen = sysinfo(SI_MACHINE, buf, sizeof buf); - if (buflen > 0) { - rv = (!strcmp(buf, "sun4u") || !strcmp(buf, "sun4u1")); - } - return rv; -} -#else /* SunOS2.6or higher has SI_ISALIST */ - -static int -isSparcV8PlusVis(void) -{ - long buflen; - int rv = 0; /* false */ - char buf[256]; - buflen = sysinfo(SI_ISALIST, buf, sizeof buf); - if (buflen > 0) { -#if defined(MP_USE_LONG_DIGIT) - char * found = strstr(buf, "sparcv9+vis"); -#else - char * found = strstr(buf, "sparcv8plus+vis"); -#endif - rv = (found != 0); - } - return rv; -} -#endif - -typedef void MPVmpy(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c); - -/* forward static function declarations */ -static MPVmpy sp_mpv_mul_d; -static MPVmpy sp_mpv_mul_d_add; -static MPVmpy sp_mpv_mul_d_add_prop; - -static MPVmpy *p_mpv_mul_d = &sp_mpv_mul_d; -static MPVmpy *p_mpv_mul_d_add = &sp_mpv_mul_d_add; -static MPVmpy *p_mpv_mul_d_add_prop = &sp_mpv_mul_d_add_prop; - -static void -initPtrs(void) -{ - if (isSparcV8PlusVis()) { - p_mpv_mul_d = &vis_mpv_mul_d; - p_mpv_mul_d_add = &vis_mpv_mul_d_add; - p_mpv_mul_d_add_prop = &vis_mpv_mul_d_add_prop; - } else { - p_mpv_mul_d = &v8_mpv_mul_d; - p_mpv_mul_d_add = &v8_mpv_mul_d_add; - p_mpv_mul_d_add_prop = &v8_mpv_mul_d_add_prop; - } -} - -static void -sp_mpv_mul_d(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) -{ - initPtrs(); - (* p_mpv_mul_d)(a, a_len, b, c); -} - -static void -sp_mpv_mul_d_add(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) -{ - initPtrs(); - (* p_mpv_mul_d_add)(a, a_len, b, c); -} - -static void -sp_mpv_mul_d_add_prop(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) -{ - initPtrs(); - (* p_mpv_mul_d_add_prop)(a, a_len, b, c); -} - - -/* This is the external interface */ - -void -s_mpv_mul_d(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) -{ - (* p_mpv_mul_d)(a, a_len, b, c); -} - -void -s_mpv_mul_d_add(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) -{ - (* p_mpv_mul_d_add)(a, a_len, b, c); -} - -void -s_mpv_mul_d_add_prop(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) -{ - (* p_mpv_mul_d_add_prop)(a, a_len, b, c); -} - - diff --git a/security/nss/lib/freebl/mpi/mpi_x86.asm b/security/nss/lib/freebl/mpi/mpi_x86.asm deleted file mode 100644 index 826747c39..000000000 --- a/security/nss/lib/freebl/mpi/mpi_x86.asm +++ /dev/null @@ -1,356 +0,0 @@ -; -; mpi_x86.asm - assembly language implementation of s_mpv_ functions. -; -; ***** BEGIN LICENSE BLOCK ***** -; 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 Netscape security libraries. -; -; The Initial Developer of the Original Code is -; Netscape Communications Corporation. -; Portions created by the Initial Developer are Copyright (C) 2000 -; the Initial Developer. All Rights Reserved. -; -; Contributor(s): -; -; 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. -; -; ***** END LICENSE BLOCK ***** - -; $Id$ - - .386p - .MODEL FLAT - ASSUME CS: FLAT, DS: FLAT, SS: FLAT -_TEXT SEGMENT - -; ebp - 36: caller's esi -; ebp - 32: caller's edi -; ebp - 28: -; ebp - 24: -; ebp - 20: -; ebp - 16: -; ebp - 12: -; ebp - 8: -; ebp - 4: -; ebp + 0: caller's ebp -; ebp + 4: return address -; ebp + 8: a argument -; ebp + 12: a_len argument -; ebp + 16: b argument -; ebp + 20: c argument -; registers: -; eax: -; ebx: carry -; ecx: a_len -; edx: -; esi: a ptr -; edi: c ptr - -public _s_mpv_mul_d -_s_mpv_mul_d PROC NEAR - push ebp - mov ebp,esp - sub esp,28 - push edi - push esi - push ebx - mov ebx,0 ; carry = 0 - mov ecx,[ebp+12] ; ecx = a_len - mov edi,[ebp+20] - cmp ecx,0 - je L_2 ; jmp if a_len == 0 - mov esi,[ebp+8] ; esi = a - cld -L_1: - lodsd ; eax = [ds:esi]; esi += 4 - mov edx,[ebp+16] ; edx = b - mul edx ; edx:eax = Phi:Plo = a_i * b - - add eax,ebx ; add carry (ebx) to edx:eax - adc edx,0 - mov ebx,edx ; high half of product becomes next carry - - stosd ; [es:edi] = ax; edi += 4; - dec ecx ; --a_len - jnz L_1 ; jmp if a_len != 0 -L_2: - mov [edi],ebx ; *c = carry - pop ebx - pop esi - pop edi - leave - ret - nop -_s_mpv_mul_d ENDP - -; ebp - 36: caller's esi -; ebp - 32: caller's edi -; ebp - 28: -; ebp - 24: -; ebp - 20: -; ebp - 16: -; ebp - 12: -; ebp - 8: -; ebp - 4: -; ebp + 0: caller's ebp -; ebp + 4: return address -; ebp + 8: a argument -; ebp + 12: a_len argument -; ebp + 16: b argument -; ebp + 20: c argument -; registers: -; eax: -; ebx: carry -; ecx: a_len -; edx: -; esi: a ptr -; edi: c ptr -public _s_mpv_mul_d_add -_s_mpv_mul_d_add PROC NEAR - push ebp - mov ebp,esp - sub esp,28 - push edi - push esi - push ebx - mov ebx,0 ; carry = 0 - mov ecx,[ebp+12] ; ecx = a_len - mov edi,[ebp+20] - cmp ecx,0 - je L_4 ; jmp if a_len == 0 - mov esi,[ebp+8] ; esi = a - cld -L_3: - lodsd ; eax = [ds:esi]; esi += 4 - mov edx,[ebp+16] ; edx = b - mul edx ; edx:eax = Phi:Plo = a_i * b - - add eax,ebx ; add carry (ebx) to edx:eax - adc edx,0 - mov ebx,[edi] ; add in current word from *c - add eax,ebx - adc edx,0 - mov ebx,edx ; high half of product becomes next carry - - stosd ; [es:edi] = ax; edi += 4; - dec ecx ; --a_len - jnz L_3 ; jmp if a_len != 0 -L_4: - mov [edi],ebx ; *c = carry - pop ebx - pop esi - pop edi - leave - ret - nop -_s_mpv_mul_d_add ENDP - -; ebp - 36: caller's esi -; ebp - 32: caller's edi -; ebp - 28: -; ebp - 24: -; ebp - 20: -; ebp - 16: -; ebp - 12: -; ebp - 8: -; ebp - 4: -; ebp + 0: caller's ebp -; ebp + 4: return address -; ebp + 8: a argument -; ebp + 12: a_len argument -; ebp + 16: b argument -; ebp + 20: c argument -; registers: -; eax: -; ebx: carry -; ecx: a_len -; edx: -; esi: a ptr -; edi: c ptr -public _s_mpv_mul_d_add_prop -_s_mpv_mul_d_add_prop PROC NEAR - push ebp - mov ebp,esp - sub esp,28 - push edi - push esi - push ebx - mov ebx,0 ; carry = 0 - mov ecx,[ebp+12] ; ecx = a_len - mov edi,[ebp+20] - cmp ecx,0 - je L_6 ; jmp if a_len == 0 - cld - mov esi,[ebp+8] ; esi = a -L_5: - lodsd ; eax = [ds:esi]; esi += 4 - mov edx,[ebp+16] ; edx = b - mul edx ; edx:eax = Phi:Plo = a_i * b - - add eax,ebx ; add carry (ebx) to edx:eax - adc edx,0 - mov ebx,[edi] ; add in current word from *c - add eax,ebx - adc edx,0 - mov ebx,edx ; high half of product becomes next carry - - stosd ; [es:edi] = ax; edi += 4; - dec ecx ; --a_len - jnz L_5 ; jmp if a_len != 0 -L_6: - cmp ebx,0 ; is carry zero? - jz L_8 - mov eax,[edi] ; add in current word from *c - add eax,ebx - stosd ; [es:edi] = ax; edi += 4; - jnc L_8 -L_7: - mov eax,[edi] ; add in current word from *c - adc eax,0 - stosd ; [es:edi] = ax; edi += 4; - jc L_7 -L_8: - pop ebx - pop esi - pop edi - leave - ret - nop -_s_mpv_mul_d_add_prop ENDP - -; ebp - 20: caller's esi -; ebp - 16: caller's edi -; ebp - 12: -; ebp - 8: carry -; ebp - 4: a_len local -; ebp + 0: caller's ebp -; ebp + 4: return address -; ebp + 8: pa argument -; ebp + 12: a_len argument -; ebp + 16: ps argument -; ebp + 20: -; registers: -; eax: -; ebx: carry -; ecx: a_len -; edx: -; esi: a ptr -; edi: c ptr - -public _s_mpv_sqr_add_prop -_s_mpv_sqr_add_prop PROC NEAR - push ebp - mov ebp,esp - sub esp,12 - push edi - push esi - push ebx - mov ebx,0 ; carry = 0 - mov ecx,[ebp+12] ; a_len - mov edi,[ebp+16] ; edi = ps - cmp ecx,0 - je L_11 ; jump if a_len == 0 - cld - mov esi,[ebp+8] ; esi = pa -L_10: - lodsd ; eax = [ds:si]; si += 4; - mul eax - - add eax,ebx ; add "carry" - adc edx,0 - mov ebx,[edi] - add eax,ebx ; add low word from result - mov ebx,[edi+4] - stosd ; [es:di] = eax; di += 4; - adc edx,ebx ; add high word from result - mov ebx,0 - mov eax,edx - adc ebx,0 - stosd ; [es:di] = eax; di += 4; - dec ecx ; --a_len - jnz L_10 ; jmp if a_len != 0 -L_11: - cmp ebx,0 ; is carry zero? - jz L_14 - mov eax,[edi] ; add in current word from *c - add eax,ebx - stosd ; [es:edi] = ax; edi += 4; - jnc L_14 -L_12: - mov eax,[edi] ; add in current word from *c - adc eax,0 - stosd ; [es:edi] = ax; edi += 4; - jc L_12 -L_14: - pop ebx - pop esi - pop edi - leave - ret - nop -_s_mpv_sqr_add_prop ENDP - -; -; Divide 64-bit (Nhi,Nlo) by 32-bit divisor, which must be normalized -; so its high bit is 1. This code is from NSPR. -; -; mp_err s_mpv_div_2dx1d(mp_digit Nhi, mp_digit Nlo, mp_digit divisor, -; mp_digit *qp, mp_digit *rp) - -; Dump of assembler code for function s_mpv_div_2dx1d: -; -; esp + 0: Caller's ebx -; esp + 4: return address -; esp + 8: Nhi argument -; esp + 12: Nlo argument -; esp + 16: divisor argument -; esp + 20: qp argument -; esp + 24: rp argument -; registers: -; eax: -; ebx: carry -; ecx: a_len -; edx: -; esi: a ptr -; edi: c ptr -; -public _s_mpv_div_2dx1d -_s_mpv_div_2dx1d PROC NEAR - push ebx - mov edx,[esp+8] - mov eax,[esp+12] - mov ebx,[esp+16] - div ebx - mov ebx,[esp+20] - mov [ebx],eax - mov ebx,[esp+24] - mov [ebx],edx - xor eax,eax ; return zero - pop ebx - ret - nop -_s_mpv_div_2dx1d ENDP - -_TEXT ENDS -END diff --git a/security/nss/lib/freebl/mpi/mpi_x86_asm.c b/security/nss/lib/freebl/mpi/mpi_x86_asm.c new file mode 100644 index 000000000..b8a224f14 --- /dev/null +++ b/security/nss/lib/freebl/mpi/mpi_x86_asm.c @@ -0,0 +1,368 @@ +/* + * mpi_x86.c - MSVC inline assembly implementation of s_mpv_ functions. + * + * ***** BEGIN LICENSE BLOCK ***** + * 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 Netscape security libraries. + * + * The Initial Developer of the Original Code is + * Netscape Communications Corporation. + * Portions created by the Initial Developer are Copyright (C) 2000 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Benjamin Smedberg <benjamin@smedbergs.us> + * + * 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. + * + * ***** END LICENSE BLOCK ***** */ + +#include "mpi-priv.h" + +/* + * ebp - 36: caller's esi + * ebp - 32: caller's edi + * ebp - 28: + * ebp - 24: + * ebp - 20: + * ebp - 16: + * ebp - 12: + * ebp - 8: + * ebp - 4: + * ebp + 0: caller's ebp + * ebp + 4: return address + * ebp + 8: a argument + * ebp + 12: a_len argument + * ebp + 16: b argument + * ebp + 20: c argument + * registers: + * eax: + * ebx: carry + * ecx: a_len + * edx: + * esi: a ptr + * edi: c ptr + */ +__declspec(naked) void +s_mpv_mul_d(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) +{ + __asm { + push ebp + mov ebp,esp + sub esp,28 + push edi + push esi + push ebx + mov ebx,0 ; carry = 0 + mov ecx,[ebp+12] ; ecx = a_len + mov edi,[ebp+20] + cmp ecx,0 + je L_2 ; jmp if a_len == 0 + mov esi,[ebp+8] ; esi = a + cld +L_1: + lodsd ; eax = [ds:esi]; esi += 4 + mov edx,[ebp+16] ; edx = b + mul edx ; edx:eax = Phi:Plo = a_i * b + + add eax,ebx ; add carry (ebx) to edx:eax + adc edx,0 + mov ebx,edx ; high half of product becomes next carry + + stosd ; [es:edi] = ax; edi += 4; + dec ecx ; --a_len + jnz L_1 ; jmp if a_len != 0 +L_2: + mov [edi],ebx ; *c = carry + pop ebx + pop esi + pop edi + leave + ret + nop + } +} + +/* + * ebp - 36: caller's esi + * ebp - 32: caller's edi + * ebp - 28: + * ebp - 24: + * ebp - 20: + * ebp - 16: + * ebp - 12: + * ebp - 8: + * ebp - 4: + * ebp + 0: caller's ebp + * ebp + 4: return address + * ebp + 8: a argument + * ebp + 12: a_len argument + * ebp + 16: b argument + * ebp + 20: c argument + * registers: + * eax: + * ebx: carry + * ecx: a_len + * edx: + * esi: a ptr + * edi: c ptr + */ +__declspec(naked) void +s_mpv_mul_d_add(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) +{ + __asm { + push ebp + mov ebp,esp + sub esp,28 + push edi + push esi + push ebx + mov ebx,0 ; carry = 0 + mov ecx,[ebp+12] ; ecx = a_len + mov edi,[ebp+20] + cmp ecx,0 + je L_4 ; jmp if a_len == 0 + mov esi,[ebp+8] ; esi = a + cld +L_3: + lodsd ; eax = [ds:esi]; esi += 4 + mov edx,[ebp+16] ; edx = b + mul edx ; edx:eax = Phi:Plo = a_i * b + + add eax,ebx ; add carry (ebx) to edx:eax + adc edx,0 + mov ebx,[edi] ; add in current word from *c + add eax,ebx + adc edx,0 + mov ebx,edx ; high half of product becomes next carry + + stosd ; [es:edi] = ax; edi += 4; + dec ecx ; --a_len + jnz L_3 ; jmp if a_len != 0 +L_4: + mov [edi],ebx ; *c = carry + pop ebx + pop esi + pop edi + leave + ret + nop + } +} + +/* + * ebp - 36: caller's esi + * ebp - 32: caller's edi + * ebp - 28: + * ebp - 24: + * ebp - 20: + * ebp - 16: + * ebp - 12: + * ebp - 8: + * ebp - 4: + * ebp + 0: caller's ebp + * ebp + 4: return address + * ebp + 8: a argument + * ebp + 12: a_len argument + * ebp + 16: b argument + * ebp + 20: c argument + * registers: + * eax: + * ebx: carry + * ecx: a_len + * edx: + * esi: a ptr + * edi: c ptr + */ +__declspec(naked) void +s_mpv_mul_d_add_prop(const mp_digit *a, mp_size a_len, mp_digit b, mp_digit *c) +{ + __asm { + push ebp + mov ebp,esp + sub esp,28 + push edi + push esi + push ebx + mov ebx,0 ; carry = 0 + mov ecx,[ebp+12] ; ecx = a_len + mov edi,[ebp+20] + cmp ecx,0 + je L_6 ; jmp if a_len == 0 + cld + mov esi,[ebp+8] ; esi = a +L_5: + lodsd ; eax = [ds:esi]; esi += 4 + mov edx,[ebp+16] ; edx = b + mul edx ; edx:eax = Phi:Plo = a_i * b + + add eax,ebx ; add carry (ebx) to edx:eax + adc edx,0 + mov ebx,[edi] ; add in current word from *c + add eax,ebx + adc edx,0 + mov ebx,edx ; high half of product becomes next carry + + stosd ; [es:edi] = ax; edi += 4; + dec ecx ; --a_len + jnz L_5 ; jmp if a_len != 0 +L_6: + cmp ebx,0 ; is carry zero? + jz L_8 + mov eax,[edi] ; add in current word from *c + add eax,ebx + stosd ; [es:edi] = ax; edi += 4; + jnc L_8 +L_7: + mov eax,[edi] ; add in current word from *c + adc eax,0 + stosd ; [es:edi] = ax; edi += 4; + jc L_7 +L_8: + pop ebx + pop esi + pop edi + leave + ret + nop + } +} + +/* + * ebp - 20: caller's esi + * ebp - 16: caller's edi + * ebp - 12: + * ebp - 8: carry + * ebp - 4: a_len local + * ebp + 0: caller's ebp + * ebp + 4: return address + * ebp + 8: pa argument + * ebp + 12: a_len argument + * ebp + 16: ps argument + * ebp + 20: + * registers: + * eax: + * ebx: carry + * ecx: a_len + * edx: + * esi: a ptr + * edi: c ptr + */ +__declspec(naked) void +s_mpv_sqr_add_prop(const mp_digit *a, mp_size a_len, mp_digit *sqrs) +{ + __asm { + push ebp + mov ebp,esp + sub esp,12 + push edi + push esi + push ebx + mov ebx,0 ; carry = 0 + mov ecx,[ebp+12] ; a_len + mov edi,[ebp+16] ; edi = ps + cmp ecx,0 + je L_11 ; jump if a_len == 0 + cld + mov esi,[ebp+8] ; esi = pa +L_10: + lodsd ; eax = [ds:si]; si += 4; + mul eax + + add eax,ebx ; add "carry" + adc edx,0 + mov ebx,[edi] + add eax,ebx ; add low word from result + mov ebx,[edi+4] + stosd ; [es:di] = eax; di += 4; + adc edx,ebx ; add high word from result + mov ebx,0 + mov eax,edx + adc ebx,0 + stosd ; [es:di] = eax; di += 4; + dec ecx ; --a_len + jnz L_10 ; jmp if a_len != 0 +L_11: + cmp ebx,0 ; is carry zero? + jz L_14 + mov eax,[edi] ; add in current word from *c + add eax,ebx + stosd ; [es:edi] = ax; edi += 4; + jnc L_14 +L_12: + mov eax,[edi] ; add in current word from *c + adc eax,0 + stosd ; [es:edi] = ax; edi += 4; + jc L_12 +L_14: + pop ebx + pop esi + pop edi + leave + ret + nop + } +} + +/* + * Divide 64-bit (Nhi,Nlo) by 32-bit divisor, which must be normalized + * so its high bit is 1. This code is from NSPR. + * + * Dump of assembler code for function s_mpv_div_2dx1d: + * + * esp + 0: Caller's ebx + * esp + 4: return address + * esp + 8: Nhi argument + * esp + 12: Nlo argument + * esp + 16: divisor argument + * esp + 20: qp argument + * esp + 24: rp argument + * registers: + * eax: + * ebx: carry + * ecx: a_len + * edx: + * esi: a ptr + * edi: c ptr + */ +__declspec(naked) mp_err +s_mpv_div_2dx1d(mp_digit Nhi, mp_digit Nlo, mp_digit divisor, + mp_digit *qp, mp_digit *rp) +{ + __asm { + push ebx + mov edx,[esp+8] + mov eax,[esp+12] + mov ebx,[esp+16] + div ebx + mov ebx,[esp+20] + mov [ebx],eax + mov ebx,[esp+24] + mov [ebx],edx + xor eax,eax ; return zero + pop ebx + ret + nop + } +} diff --git a/security/nss/lib/freebl/mpi/mpmontg.c b/security/nss/lib/freebl/mpi/mpmontg.c index 7b0bdd3d3..312e0d089 100644 --- a/security/nss/lib/freebl/mpi/mpmontg.c +++ b/security/nss/lib/freebl/mpi/mpmontg.c @@ -60,8 +60,8 @@ /* if MP_CHAR_STORE_SLOW is defined, we */ /* need to know endianness of this platform. */ #ifdef MP_CHAR_STORE_SLOW -#if !defined(MPI_IS_BIG_ENDIAN) && !defined(MPI_IS_LITTLE_ENDIAN) -#error "You must define MPI_IS_BIG_ENDIAN or MPI_IS_LITTLE_ENDIAN\n" \ +#if !defined(MP_IS_BIG_ENDIAN) && !defined(MP_IS_LITTLE_ENDIAN) +#error "You must define MP_IS_BIG_ENDIAN or MP_IS_LITTLE_ENDIAN\n" \ " if you define MP_CHAR_STORE_SLOW." #endif #endif @@ -703,8 +703,8 @@ mp_err mpi_to_weave(const mp_int *a, unsigned char *b, count = count/sizeof(mp_weave_word); /* this code pretty much depends on this ! */ -#if MP_ARGCHK < 2 - assert(WEAVE_WORD_SIZE == 4); +#if MP_ARGCHK == 2 + assert(WEAVE_WORD_SIZE == 4); assert(sizeof(mp_weave_word) == 4); #endif @@ -754,19 +754,19 @@ mp_err mpi_to_weave(const mp_int *a, unsigned char *b, * NOTE: This code assumes sizeof(mp_weave_word) and MP_WEAVE_WORD_SIZE * is 4. */ -#ifdef IS_LITTLE_ENDIAN +#ifdef MP_IS_LITTLE_ENDIAN #define MPI_WEAVE_ONE_STEP \ - acc = (d0 >> (MP_DIGIT_BITS-8)) & 0x000000ff; d0 <<= 8; /*b0*/ \ - acc |= (d1 >> (MP_DIGIT_BITS-16)) & 0x0000ff00; d1 <<= 8; /*b1*/ \ - acc |= (d2 >> (MP_DIGIT_BITS-24)) & 0x00ff0000; d2 <<= 8; /*b2*/ \ - acc |= (d3 >> (MP_DIGIT_BITS-32)) & 0xff000000; d3 <<= 8; /*b3*/ \ + acc = (d0 >> (MP_DIGIT_BIT-8)) & 0x000000ff; d0 <<= 8; /*b0*/ \ + acc |= (d1 >> (MP_DIGIT_BIT-16)) & 0x0000ff00; d1 <<= 8; /*b1*/ \ + acc |= (d2 >> (MP_DIGIT_BIT-24)) & 0x00ff0000; d2 <<= 8; /*b2*/ \ + acc |= (d3 >> (MP_DIGIT_BIT-32)) & 0xff000000; d3 <<= 8; /*b3*/ \ *weaved = acc; weaved += count; #else #define MPI_WEAVE_ONE_STEP \ - acc = (d0 >> (MP_DIGIT_BITS-32)) & 0xff000000; d0 <<= 8; /*b0*/ \ - acc |= (d1 >> (MP_DIGIT_BITS-24)) & 0x00ff0000; d1 <<= 8; /*b1*/ \ - acc |= (d2 >> (MP_DIGIT_BITS-16)) & 0x0000ff00; d2 <<= 8; /*b2*/ \ - acc |= (d3 >> (MP_DIGIT_BITS-8)) & 0x000000ff; d3 <<= 8; /*b3*/ \ + acc = (d0 >> (MP_DIGIT_BIT-32)) & 0xff000000; d0 <<= 8; /*b0*/ \ + acc |= (d1 >> (MP_DIGIT_BIT-24)) & 0x00ff0000; d1 <<= 8; /*b1*/ \ + acc |= (d2 >> (MP_DIGIT_BIT-16)) & 0x0000ff00; d2 <<= 8; /*b2*/ \ + acc |= (d3 >> (MP_DIGIT_BIT-8)) & 0x000000ff; d3 <<= 8; /*b3*/ \ *weaved = acc; weaved += count; #endif switch (sizeof(mp_digit)) { @@ -921,6 +921,14 @@ mp_err mp_exptmod_safe_i(const mp_int * montBase, unsigned char *powersArray; unsigned char *powers; + MP_DIGITS(&accum1) = 0; + MP_DIGITS(&accum2) = 0; + MP_DIGITS(&accum[0]) = 0; + MP_DIGITS(&accum[1]) = 0; + MP_DIGITS(&accum[2]) = 0; + MP_DIGITS(&accum[3]) = 0; + MP_DIGITS(&tmp) = 0; + powersArray = (unsigned char *)malloc(num_powers*(nLen*sizeof(mp_digit)+1)); if (powersArray == NULL) { res = MP_MEM; @@ -930,13 +938,6 @@ mp_err mp_exptmod_safe_i(const mp_int * montBase, /* powers[i] = base ** (i); */ powers = (unsigned char *)MP_ALIGN(powersArray,num_powers); - MP_DIGITS(&accum1) = 0; - MP_DIGITS(&accum2) = 0; - MP_DIGITS(&accum[0]) = 0; - MP_DIGITS(&accum[1]) = 0; - MP_DIGITS(&accum[2]) = 0; - MP_DIGITS(&accum[3]) = 0; - /* grab the first window value. This allows us to preload accumulator1 * and save a conversion, some squares and a multiple*/ MP_CHECKOK( mpl_get_bits(exponent, @@ -945,7 +946,6 @@ mp_err mp_exptmod_safe_i(const mp_int * montBase, MP_CHECKOK( mp_init_size(&accum1, 3 * nLen + 2) ); MP_CHECKOK( mp_init_size(&accum2, 3 * nLen + 2) ); - MP_DIGITS(&tmp) = 0; MP_CHECKOK( mp_init_size(&tmp, 3 * nLen + 2) ); /* build the first WEAVE_WORD powers inline */ @@ -1070,6 +1070,7 @@ CLEANUP: mp_clear(&accum[1]); mp_clear(&accum[2]); mp_clear(&accum[3]); + mp_clear(&tmp); /* PORT_Memset(powers,0,num_powers*nLen*sizeof(mp_digit)); */ free(powersArray); return res; diff --git a/security/nss/lib/freebl/mpi/mpprime.c b/security/nss/lib/freebl/mpi/mpprime.c index dfe7988f7..32d6f6f70 100644 --- a/security/nss/lib/freebl/mpi/mpprime.c +++ b/security/nss/lib/freebl/mpi/mpprime.c @@ -427,20 +427,10 @@ mp_err mpp_make_prime(mp_int *start, mp_size nBits, mp_size strong, mp_int trial; mp_int q; mp_size num_tests; - /* - * Always make sieve the last variabale allocated so that - * Mac builds don't break by adding an extra variable - * on the stack. -javi - */ -#if defined(macintosh) || defined (XP_OS2) \ - || (defined(HPUX) && defined(__ia64)) unsigned char *sieve; sieve = malloc(SIEVE_SIZE); ARGCHK(sieve != NULL, MP_MEM); -#else - unsigned char sieve[SIEVE_SIZE]; -#endif ARGCHK(start != 0, MP_BADARG); ARGCHK(nBits > 16, MP_RANGE); @@ -575,13 +565,10 @@ CLEANUP: mp_clear(&q); if (nTries) *nTries += i; -#if defined(macintosh) || defined(XP_OS2) \ - || (defined(HPUX) && defined(__ia64)) if (sieve != NULL) { memset(sieve, 0, SIEVE_SIZE); free (sieve); } -#endif return res; } diff --git a/security/nss/lib/freebl/mpi/target.mk b/security/nss/lib/freebl/mpi/target.mk index c17854819..6f71e8053 100644 --- a/security/nss/lib/freebl/mpi/target.mk +++ b/security/nss/lib/freebl/mpi/target.mk @@ -229,3 +229,21 @@ MPICMN += $(MP_CONFIG) mpi_amd64_asm.o: mpi_amd64_sun.s $(AS) -xarch=generic64 -P -D_ASM mpi_amd64_sun.s endif + +ifeq ($(TARGET),WIN32) +AS_OBJS = mpi_x86.obj +MPICMN += -DMP_ASSEMBLY_MULTIPLY -DMP_ASSEMBLY_SQUARE -DMP_ASSEMBLY_DIV_2DX1D +MPICMN += -DMP_USE_UINT_DIGIT -DMP_NO_MP_WORD -DMP_API_COMPATIBLE +MPICMN += -DMP_MONT_USE_MP_MUL +MPICMN += -DMP_CHAR_STORE_SLOW -DMP_IS_LITTLE_ENDIAN +CFLAGS = -Od -Z7 -MDd -W3 -nologo -DDEBUG -D_DEBUG -UNDEBUG -DDEBUG_$(USER) +CFLAGS += -DWIN32 -D_WINDOWS -D_X86_ -DWIN95 -DXP_PC -DNSS_ENABLE_ECC +CFLAGS += $(MPICMN) + +$(AS_OBJS): %.obj : %.asm + ml -Cp -Sn -Zi -coff -nologo -c $< + +$(LIBOBJS): %.obj : %.c + cl $(CFLAGS) -Fo$@ -c $< + +endif diff --git a/security/nss/lib/freebl/mpi/tests/mptest-7.c b/security/nss/lib/freebl/mpi/tests/mptest-7.c index a32be1978..3153133cb 100644 --- a/security/nss/lib/freebl/mpi/tests/mptest-7.c +++ b/security/nss/lib/freebl/mpi/tests/mptest-7.c @@ -47,7 +47,7 @@ #include <limits.h> #include <time.h> -#define MP_IOFUNC +#define MP_IOFUNC 1 #include "mpi.h" #include "mpprime.h" diff --git a/security/nss/lib/freebl/mpi/tests/mptest-8.c b/security/nss/lib/freebl/mpi/tests/mptest-8.c index 7cf95a9b1..8bff49b20 100644 --- a/security/nss/lib/freebl/mpi/tests/mptest-8.c +++ b/security/nss/lib/freebl/mpi/tests/mptest-8.c @@ -47,7 +47,7 @@ #include <limits.h> #include <time.h> -#define MP_IOFUNC +#define MP_IOFUNC 1 #include "mpi.h" #include "mpprime.h" diff --git a/security/nss/lib/freebl/pqg.c b/security/nss/lib/freebl/pqg.c index c3e92c62d..66c535fe9 100644 --- a/security/nss/lib/freebl/pqg.c +++ b/security/nss/lib/freebl/pqg.c @@ -78,6 +78,8 @@ static const unsigned char fips_186_1_a5_pqseed[] = { static SECStatus getPQseed(SECItem *seed, PRArenaPool* arena) { + SECStatus rv; + if (!seed->data) { seed->data = (unsigned char*)PORT_ArenaZAlloc(arena, seed->len); } @@ -89,7 +91,15 @@ getPQseed(SECItem *seed, PRArenaPool* arena) memcpy(seed->data, fips_186_1_a5_pqseed, seed->len); return SECSuccess; #else - return RNG_GenerateGlobalRandomBytes(seed->data, seed->len); + rv = RNG_GenerateGlobalRandomBytes(seed->data, seed->len); + /* + * NIST CMVP disallows a sequence of 20 bytes with the most + * significant byte equal to 0. Perhaps they interpret + * "a sequence of at least 160 bits" as "a number >= 2^159". + * So we always set the most significant bit to 1. (bug 334533) + */ + seed->data[0] |= 0x80; + return rv; #endif } @@ -322,8 +332,8 @@ makeGfromH(const mp_int *P, /* input. */ CHECK_MPI_OK( mp_init(&exp) ); CHECK_MPI_OK( mp_init(&pm1) ); CHECK_MPI_OK( mp_sub_d(P, 1, &pm1) ); /* P - 1 */ - if ( mp_cmp(H, &pm1) > 0) /* H = H mod (P-1) */ - CHECK_MPI_OK( mp_sub(H, &pm1, H) ); + if ( mp_cmp(H, &pm1) >= 0) /* H >= P-1 */ + CHECK_MPI_OK( mp_sub(H, &pm1, H) ); /* H = H mod (P-1) */ /* Let b = 2**n (smallest power of 2 greater than P). ** Since P-1 >= b/2, and H < b, quotient(H/(P-1)) = 0 or 1 ** so the above operation safely computes H mod (P-1) @@ -392,7 +402,7 @@ PQG_ParamGenSeedLen(unsigned int j, unsigned int seedBytes, mp_err err = MP_OKAY; SECStatus rv = SECFailure; int iterations = 0; - if (j > 8 || !pParams || !pVfy) { + if (j > 8 || seedBytes < 20 || !pParams || !pVfy) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return SECFailure; } @@ -538,7 +548,7 @@ step_15: ** in certifying the proper generation of p and q." */ /* Generate h. */ - SECITEM_AllocItem(NULL, &hit, seedBytes); /* h is no longer than p */ + SECITEM_AllocItem(NULL, &hit, L/8); /* h is no longer than p */ if (!hit.data) goto cleanup; do { /* loop generate h until 1<h<p-1 and (h**[(p-1)/q])mod p > 1 */ @@ -628,7 +638,6 @@ PQG_VerifyParams(const PQGParams *params, /* 6. P is prime */ CHECKPARAM( mpp_pprime(&P, PQG_P_PRIMALITY_TESTS) == MP_YES ); /* Steps 7-12 are done only if the optional PQGVerify is supplied. */ - if (!vfy) goto cleanup; /* 7. counter < 4096 */ CHECKPARAM( vfy->counter < 4096 ); /* 8. g >= 160 and g < 2048 (g is length of seed in bits) */ diff --git a/security/nss/lib/freebl/prng_fips1861.c b/security/nss/lib/freebl/prng_fips1861.c index 900b98ab8..c21df3ab0 100644 --- a/security/nss/lib/freebl/prng_fips1861.c +++ b/security/nss/lib/freebl/prng_fips1861.c @@ -106,9 +106,10 @@ * q, DSA_SUBPRIME_LEN bytes * Output: xj, DSA_SUBPRIME_LEN bytes */ -static SECStatus -dsa_reduce_mod_q(const unsigned char *w, const unsigned char *q, - unsigned char *xj) +SECStatus +FIPS186Change_ReduceModQForDSA(const unsigned char *w, + const unsigned char *q, + unsigned char *xj) { mp_int W, Q, Xj; mp_err err; @@ -181,15 +182,28 @@ freeRNGContext() } /* - * Implementation of Algorithm 1 of FIPS 186-2 Change Notice 1, - * hereinafter called alg_cn_1(). It is assumed a lock for the global - * rng context has already been acquired. - * Calling this function with XSEEDj == NULL is equivalent to saying there - * is no optional user input, which is further equivalent to saying that - * the optional user input is 0. + * The core of Algorithm 1 of FIPS 186-2 Change Notice 1, + * separated from alg_fips186_2_cn_1 as a standalone function + * for FIPS algorithm testing. + * + * Parameters: + * XKEY [input/output]: the state of the RNG (seed-key) + * XSEEDj [input]: optional user input (seed) + * x_j [output]: output of the RNG + * + * Return value: + * This function usually returns SECSuccess. The only reason + * this function returns SECFailure is that XSEEDj equals + * XKEY, including the intermediate XKEY value between the two + * iterations. (This test is actually a FIPS 140-2 requirement + * and not required for FIPS algorithm testing, but it is too + * hard to separate from this function.) If this function fails, + * XKEY is not updated, but some data may have been written to + * x_j, which should be ignored. */ -static SECStatus -alg_fips186_2_cn_1(RNGContext *rng, const unsigned char *XSEEDj) +SECStatus +FIPS186Change_GenerateX(unsigned char *XKEY, const unsigned char *XSEEDj, + unsigned char *x_j) { /* SHA1 context for G(t, XVAL) function */ SHA1Context sha1cx; @@ -199,8 +213,6 @@ alg_fips186_2_cn_1(RNGContext *rng, const unsigned char *XSEEDj) PRUint8 *XKEY_new; /* input to hash function */ PRUint8 XVAL[BSIZE]; - /* store a copy of the output to compare with the previous output */ - PRUint8 x_j[2*GSIZE]; /* used by ADD_B_BIT macros */ int k, carry; /* store the output of G(t, XVAL) in the rightmost GSIZE bytes */ @@ -209,11 +221,6 @@ alg_fips186_2_cn_1(RNGContext *rng, const unsigned char *XSEEDj) unsigned int len; SECStatus rv = SECSuccess; - if (!rng->isValid) { - /* RNG has alread entered an invalid state. */ - PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); - return SECFailure; - } #if GSIZE < BSIZE /* zero the leftmost bytes so we can pass it to ADD_B_BIT_PLUS_CARRY */ memset(w_i, 0, BSIZE - GSIZE); @@ -224,15 +231,15 @@ alg_fips186_2_cn_1(RNGContext *rng, const unsigned char *XSEEDj) * <Step 3.1> XSEEDj is optional user input */ for (i = 0; i < 2; i++) { - /* only update rng->XKEY when both iterations have been completed */ + /* only update XKEY when both iterations have been completed */ if (i == 0) { /* for iteration 0 */ - XKEY_old = rng->XKEY; + XKEY_old = XKEY; XKEY_new = XKEY_1; } else { /* for iteration 1 */ XKEY_old = XKEY_1; - XKEY_new = rng->XKEY; + XKEY_new = XKEY; } /* * <Step 3.2a> XVAL = (XKEY + XSEEDj) mod 2^b @@ -270,6 +277,39 @@ alg_fips186_2_cn_1(RNGContext *rng, const unsigned char *XSEEDj) */ memcpy(&x_j[i*GSIZE], &w_i[BSIZE - GSIZE], GSIZE); } + +done: + /* housekeeping */ + memset(&w_i[BSIZE - GSIZE], 0, GSIZE); + memset(XVAL, 0, BSIZE); + memset(XKEY_1, 0, BSIZE); + return rv; +} + +/* + * Implementation of Algorithm 1 of FIPS 186-2 Change Notice 1, + * hereinafter called alg_cn_1(). It is assumed a lock for the global + * rng context has already been acquired. + * Calling this function with XSEEDj == NULL is equivalent to saying there + * is no optional user input, which is further equivalent to saying that + * the optional user input is 0. + */ +static SECStatus +alg_fips186_2_cn_1(RNGContext *rng, const unsigned char *XSEEDj) +{ + /* store a copy of the output to compare with the previous output */ + PRUint8 x_j[2*GSIZE]; + SECStatus rv; + + if (!rng->isValid) { + /* RNG has alread entered an invalid state. */ + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + rv = FIPS186Change_GenerateX(rng->XKEY, XSEEDj, x_j); + if (rv != SECSuccess) { + goto done; + } /* [FIPS 140-2] verify output does not match previous output */ if (memcmp(x_j, rng->Xj, 2*GSIZE) == 0) { /* failed FIPS 140-2 continuous RNG test. RNG now invalid. */ @@ -285,10 +325,7 @@ alg_fips186_2_cn_1(RNGContext *rng, const unsigned char *XSEEDj) done: /* housekeeping */ - memset(&w_i[BSIZE - GSIZE], 0, GSIZE); memset(x_j, 0, 2*GSIZE); - memset(XVAL, 0, BSIZE); - memset(XKEY_1, 0, BSIZE); return rv; } @@ -581,6 +618,6 @@ DSA_GenerateGlobalRandomBytes(void *dest, size_t len, const unsigned char *q) if (rv != SECSuccess) { return rv; } - dsa_reduce_mod_q(w, q, (unsigned char *)dest); + FIPS186Change_ReduceModQForDSA(w, q, (unsigned char *)dest); return rv; } diff --git a/security/nss/lib/freebl/unix_rand.c b/security/nss/lib/freebl/unix_rand.c index f61da8b29..6a4c283bb 100644 --- a/security/nss/lib/freebl/unix_rand.c +++ b/security/nss/lib/freebl/unix_rand.c @@ -959,6 +959,9 @@ size_t RNG_FileUpdate(const char *fileName, size_t limit) unsigned char buffer[BUFSIZ]; static size_t totalFileBytes = 0; + /* suppress valgrind warnings due to holes in struct stat */ + memset(&stat_buf, 0, sizeof(stat_buf)); + if (stat((char *)fileName, &stat_buf) < 0) return fileBytes; RNG_RandomUpdate(&stat_buf, sizeof(stat_buf)); diff --git a/security/nss/lib/nss/nss.def b/security/nss/lib/nss/nss.def index d4f8ff8a1..b9d6971d1 100644 --- a/security/nss/lib/nss/nss.def +++ b/security/nss/lib/nss/nss.def @@ -874,6 +874,9 @@ SECMOD_OpenUserDB; ;+}; ;+NSS_3.11.1 { ;+ global: +NSS_RegisterShutdown; +NSS_UnregisterShutdown; +SEC_ASN1EncodeUnsignedInteger; SEC_RegisterDefaultHttpClient; ;+ local: ;+ *; diff --git a/security/nss/lib/nss/nss.h b/security/nss/lib/nss/nss.h index 9ced4592a..100758dd9 100644 --- a/security/nss/lib/nss/nss.h +++ b/security/nss/lib/nss/nss.h @@ -52,13 +52,16 @@ SEC_BEGIN_PROTOS * The format of the version string should be * "<major version>.<minor version>[.<patch level>] [<Beta>]" */ -#define NSS_VERSION "3.11.1 Beta" +#ifdef NSS_ENABLE_ECC +#define NSS_VERSION "3.11.2 ECC Beta" +#else +#define NSS_VERSION "3.11.2 Beta" +#endif #define NSS_VMAJOR 3 #define NSS_VMINOR 11 -#define NSS_VPATCH 1 +#define NSS_VPATCH 2 #define NSS_BETA PR_TRUE - /* * Return a boolean that indicates whether the underlying library * will perform as the caller expects. @@ -184,6 +187,31 @@ extern SECStatus NSS_Initialize(const char *configdir, */ SECStatus NSS_NoDB_Init(const char *configdir); +/* + * Allow applications and libraries to register with NSS so that they are called + * when NSS shuts down. + * + * void *appData application specific data passed in by the application at + * NSS_RegisterShutdown() time. + * void *nssData is NULL in this release, but is reserved for future versions of + * NSS to pass some future status information * back to the shutdown function. + * + * If the shutdown function returns SECFailure, + * Shutdown will still complete, but NSS_Shutdown() will return SECFailure. + */ +typedef SECStatus (*NSS_ShutdownFunc)(void *appData, void *nssData); + +/* + * Register a shutdown function. + */ +SECStatus NSS_RegisterShutdown(NSS_ShutdownFunc sFunc, void *appData); + +/* + * Remove an existing shutdown function (you may do this if your library is + * complete and going away, but NSS is still running). + */ +SECStatus NSS_UnregisterShutdown(NSS_ShutdownFunc sFunc, void *appData); + /* * Close the Cert, Key databases. */ diff --git a/security/nss/lib/nss/nss.rc b/security/nss/lib/nss/nss.rc index be82dab75..156309e6a 100644 --- a/security/nss/lib/nss/nss.rc +++ b/security/nss/lib/nss/nss.rc @@ -84,11 +84,10 @@ BEGIN BEGIN BLOCK "040904B0" // Lang=US English, CharSet=Unicode BEGIN - VALUE "CompanyName", "Netscape Communications Corporation\0" + VALUE "CompanyName", "Mozilla Foundation\0" VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0" VALUE "FileVersion", NSS_VERSION "\0" VALUE "InternalName", MY_INTERNAL_NAME "\0" - VALUE "LegalCopyright", "Copyright \251 1994-2001 Netscape Communications Corporation\0" VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0" VALUE "ProductName", "Network Security Services\0" VALUE "ProductVersion", NSS_VERSION "\0" diff --git a/security/nss/lib/nss/nssinit.c b/security/nss/lib/nss/nssinit.c index a0a1fafa4..2a7a88c09 100644 --- a/security/nss/lib/nss/nssinit.c +++ b/security/nss/lib/nss/nssinit.c @@ -396,6 +396,11 @@ nss_FindExternalRoot(const char *dbpath, const char* secmodprefix) static PRBool nss_IsInitted = PR_FALSE; extern SECStatus secoid_Init(void); +static SECStatus nss_InitShutdownList(void); + +#ifdef DEBUG +static CERTCertificate dummyCert; +#endif static SECStatus nss_Init(const char *configdir, const char *certPrefix, const char *keyPrefix, @@ -417,6 +422,9 @@ nss_Init(const char *configdir, const char *certPrefix, const char *keyPrefix, return SECSuccess; } + /* New option bits must not change the size of CERTCertificate. */ + PORT_Assert(sizeof(dummyCert.options) == sizeof(void *)); + if (SECSuccess != InitCRLCache()) { return SECFailure; } @@ -484,6 +492,9 @@ loser: if (STAN_LoadDefaultNSS3TrustDomain() != PR_SUCCESS) { return SECFailure; } + if (nss_InitShutdownList() != SECSuccess) { + return SECFailure; + } CERT_SetDefaultCertDB((CERTCertDBHandle *) STAN_GetDefaultTrustDomain()); #ifndef XP_MAC @@ -591,28 +602,201 @@ NSS_NoDB_Init(const char * configdir) PR_FALSE,PR_FALSE,PR_FALSE); } + +#define NSS_SHUTDOWN_STEP 10 + +struct NSSShutdownFuncPair { + NSS_ShutdownFunc func; + void *appData; +}; + +static struct NSSShutdownListStr { + PZLock *lock; + int maxFuncs; + int numFuncs; + struct NSSShutdownFuncPair *funcs; +} nssShutdownList = { 0 }; + +/* + * find and existing shutdown function + */ +static int +nss_GetShutdownEntry(NSS_ShutdownFunc sFunc, void *appData) +{ + int count, i; + count = nssShutdownList.numFuncs; + /* expect the list to be short, just do a linear search */ + for (i=0; i < count; i++) { + if ((nssShutdownList.funcs[i].func == sFunc) && + (nssShutdownList.funcs[i].appData == appData)){ + return i; + } + } + return -1; +} + +/* + * register a callback to be called when NSS shuts down + */ +SECStatus +NSS_RegisterShutdown(NSS_ShutdownFunc sFunc, void *appData) +{ + int i; + + if (!nss_IsInitted) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + if (sFunc == NULL) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + return SECFailure; + } + + PORT_Assert(nssShutdownList.lock); + PZ_Lock(nssShutdownList.lock); + + /* make sure we don't have a duplicate */ + i = nss_GetShutdownEntry(sFunc, appData); + if (i > 0) { + PZ_Unlock(nssShutdownList.lock); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + /* find an empty slot */ + i = nss_GetShutdownEntry(NULL, NULL); + if (i > 0) { + nssShutdownList.funcs[i].func = sFunc; + nssShutdownList.funcs[i].appData = appData; + PZ_Unlock(nssShutdownList.lock); + return SECFailure; + } + if (nssShutdownList.maxFuncs == nssShutdownList.numFuncs) { + struct NSSShutdownFuncPair *funcs = + (struct NSSShutdownFuncPair *)PORT_Realloc + (nssShutdownList.funcs, + (nssShutdownList.maxFuncs + NSS_SHUTDOWN_STEP) + *sizeof(struct NSSShutdownFuncPair)); + if (!funcs) { + return SECFailure; + } + nssShutdownList.funcs = funcs; + nssShutdownList.maxFuncs += NSS_SHUTDOWN_STEP; + } + nssShutdownList.funcs[nssShutdownList.numFuncs++].func = sFunc; + nssShutdownList.funcs[nssShutdownList.numFuncs++].appData = appData; + PZ_Unlock(nssShutdownList.lock); + return SECSuccess; +} + +/* + * unregister a callback so it won't get called on shutdown. + */ +SECStatus +NSS_UnregisterShutdown(NSS_ShutdownFunc sFunc, void *appData) +{ + int i; + if (!nss_IsInitted) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + + PORT_Assert(nssShutdownList.lock); + PZ_Lock(nssShutdownList.lock); + i = nss_GetShutdownEntry(sFunc, appData); + if (i > 0) { + nssShutdownList.funcs[i].func = NULL; + nssShutdownList.funcs[i].appData = NULL; + } + PZ_Unlock(nssShutdownList.lock); + + if (i < 0) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + return SECSuccess; +} + +/* + * bring up and shutdown the shutdown list + */ +static SECStatus +nss_InitShutdownList(void) +{ + nssShutdownList.lock = PZ_NewLock(nssILockOther); + if (nssShutdownList.lock == NULL) { + return SECFailure; + } + nssShutdownList.funcs = PORT_ZNewArray(struct NSSShutdownFuncPair, + NSS_SHUTDOWN_STEP); + if (nssShutdownList.funcs == NULL) { + PZ_DestroyLock(nssShutdownList.lock); + nssShutdownList.lock = NULL; + return SECFailure; + } + nssShutdownList.maxFuncs = NSS_SHUTDOWN_STEP; + nssShutdownList.numFuncs = 0; + + return SECSuccess; +} + +static SECStatus +nss_ShutdownShutdownList(void) +{ + SECStatus rv = SECSuccess; + int i; + + /* call all the registerd functions first */ + for (i=0; i < nssShutdownList.numFuncs; i++) { + struct NSSShutdownFuncPair *funcPair = &nssShutdownList.funcs[i]; + if (funcPair->func) { + if ((*funcPair->func)(funcPair->appData,NULL) != SECSuccess) { + rv = SECFailure; + } + } + } + + nssShutdownList.numFuncs = 0; + nssShutdownList.maxFuncs = 0; + PORT_Free(nssShutdownList.funcs); + nssShutdownList.funcs = NULL; + if (nssShutdownList.lock) { + PZ_DestroyLock(nssShutdownList.lock); + } + nssShutdownList.lock = NULL; + return rv; +} + + extern const NSSError NSS_ERROR_BUSY; SECStatus NSS_Shutdown(void) { + SECStatus shutdownRV = SECSuccess; SECStatus rv; PRStatus status; + rv = nss_ShutdownShutdownList(); + if (rv != SECSuccess) { + shutdownRV = SECFailure; + } ShutdownCRLCache(); SECOID_Shutdown(); status = STAN_Shutdown(); cert_DestroySubjectKeyIDHashTable(); rv = SECMOD_Shutdown(); + if (rv != SECSuccess) { + shutdownRV = SECFailure; + } pk11sdr_Shutdown(); if (status == PR_FAILURE) { if (NSS_GetError() == NSS_ERROR_BUSY) { PORT_SetError(SEC_ERROR_BUSY); } - rv = SECFailure; + shutdownRV = SECFailure; } nss_IsInitted = PR_FALSE; - return rv; + return shutdownRV; } PRBool diff --git a/security/nss/lib/pk11wrap/pk11akey.c b/security/nss/lib/pk11wrap/pk11akey.c index a6189cf43..f63ff3b9f 100644 --- a/security/nss/lib/pk11wrap/pk11akey.c +++ b/security/nss/lib/pk11wrap/pk11akey.c @@ -1313,68 +1313,6 @@ PK11_ExportPrivateKeyInfo(CERTCertificate *cert, void *wincx) return NULL; } -static int -pk11_private_key_encrypt_buffer_length(SECKEYPrivateKey *key) - -{ - CK_ATTRIBUTE rsaTemplate = { CKA_MODULUS, NULL, 0 }; - CK_ATTRIBUTE dsaTemplate = { CKA_PRIME, NULL, 0 }; - /* XXX We should normally choose an attribute such that - * factor times its size is enough to hold the private key. - * For EC keys, we have no choice but to use CKA_EC_PARAMS, - * CKA_VALUE is not available for token keys. But for named - * curves, the number of bytes needed to represent the params - * is quite small so we bump up factor from 10 to 15. - */ - CK_ATTRIBUTE ecTemplate = { CKA_EC_PARAMS, NULL, 0 }; - CK_ATTRIBUTE_PTR pTemplate; - CK_RV crv; - int length; - int factor = 10; - - if(!key) { - return -1; - } - - switch (key->keyType) { - case rsaKey: - pTemplate = &rsaTemplate; - break; - case dsaKey: - case dhKey: - pTemplate = &dsaTemplate; - break; - case ecKey: - pTemplate = &ecTemplate; - factor = 15; - break; - case fortezzaKey: - default: - pTemplate = NULL; - } - - if(!pTemplate) { - return -1; - } - - crv = PK11_GetAttributes(NULL, key->pkcs11Slot, key->pkcs11ID, - pTemplate, 1); - if(crv != CKR_OK) { - PORT_SetError( PK11_MapError(crv) ); - return -1; - } - - length = pTemplate->ulValueLen; - length *= factor; - - - if(pTemplate->pValue != NULL) { - PORT_Free(pTemplate->pValue); - } - - return length; -} - SECKEYEncryptedPrivateKeyInfo * PK11_ExportEncryptedPrivKeyInfo( PK11SlotInfo *slot, /* optional, encrypt key in this slot */ @@ -1390,14 +1328,12 @@ PK11_ExportEncryptedPrivKeyInfo( SECItem *pbe_param = NULL; PK11SymKey *key = NULL; SECStatus rv = SECSuccess; - int encryptBufLen; CK_RV crv; - CK_ULONG encBufLenPtr; + CK_ULONG encBufLen; CK_MECHANISM_TYPE mechanism; CK_MECHANISM pbeMech; CK_MECHANISM cryptoMech; SECItem crypto_param; - SECItem encryptedKey = {siBuffer, NULL, 0}; if (!pwitem || !pk) { PORT_SetError(SEC_ERROR_INVALID_ARGS); @@ -1461,20 +1397,6 @@ PK11_ExportEncryptedPrivKeyInfo( crypto_param.data = (unsigned char *)cryptoMech.pParameter; crypto_param.len = cryptoMech.ulParameterLen; - - encryptBufLen = pk11_private_key_encrypt_buffer_length(pk); - if(encryptBufLen == -1) { - rv = SECFailure; - goto loser; - } - encryptedKey.len = (unsigned int)encryptBufLen; - encBufLenPtr = (CK_ULONG) encryptBufLen; - encryptedKey.data = (unsigned char *)PORT_ZAlloc(encryptedKey.len); - if(!encryptedKey.data) { - rv = SECFailure; - goto loser; - } - /* If the key isn't in the private key slot, move it */ if (key->slot != pk->pkcs11Slot) { PK11SymKey *newkey = pk11_CopyToSlot(pk->pkcs11Slot, @@ -1488,30 +1410,40 @@ PK11_ExportEncryptedPrivKeyInfo( PK11_FreeSymKey(key); key = newkey; } - + /* we are extracting an encrypted privateKey structure. * which needs to be freed along with the buffer into which it is * returned. eventually, we should retrieve an encrypted key using * pkcs8/pkcs5. */ + encBufLen = 0; PK11_EnterSlotMonitor(pk->pkcs11Slot); crv = PK11_GETTAB(pk->pkcs11Slot)->C_WrapKey(pk->pkcs11Slot->session, - &cryptoMech, key->objectID, pk->pkcs11ID, encryptedKey.data, - &encBufLenPtr); + &cryptoMech, key->objectID, pk->pkcs11ID, NULL, + &encBufLen); PK11_ExitSlotMonitor(pk->pkcs11Slot); - encryptedKey.len = (unsigned int) encBufLenPtr; - if(crv != CKR_OK) { + if (crv != CKR_OK) { rv = SECFailure; goto loser; } - - if(!encryptedKey.len) { + epki->encryptedData.data = PORT_ArenaAlloc(arena, encBufLen); + if (!epki->encryptedData.data) { + rv = SECFailure; + goto loser; + } + PK11_EnterSlotMonitor(pk->pkcs11Slot); + crv = PK11_GETTAB(pk->pkcs11Slot)->C_WrapKey(pk->pkcs11Slot->session, + &cryptoMech, key->objectID, pk->pkcs11ID, + epki->encryptedData.data, &encBufLen); + PK11_ExitSlotMonitor(pk->pkcs11Slot); + epki->encryptedData.len = (unsigned int) encBufLen; + if(crv != CKR_OK) { rv = SECFailure; goto loser; } - - rv = SECITEM_CopyItem(arena, &epki->encryptedData, &encryptedKey); - if(rv != SECSuccess) { + + if(!epki->encryptedData.len) { + rv = SECFailure; goto loser; } @@ -2026,6 +1958,7 @@ PK11_ListPublicKeysInSlot(PK11SlotInfo *slot, char *nickname) keys = SECKEY_NewPublicKeyList(); if (keys == NULL) { PORT_Free(key_ids); + return NULL; } for (i=0; i < objCount ; i++) { @@ -2071,6 +2004,7 @@ PK11_ListPrivKeysInSlot(PK11SlotInfo *slot, char *nickname, void *wincx) keys = SECKEY_NewPrivateKeyList(); if (keys == NULL) { PORT_Free(key_ids); + return NULL; } for (i=0; i < objCount ; i++) { diff --git a/security/nss/lib/pk11wrap/pk11cert.c b/security/nss/lib/pk11wrap/pk11cert.c index 08c0af2db..f4d6c9895 100644 --- a/security/nss/lib/pk11wrap/pk11cert.c +++ b/security/nss/lib/pk11wrap/pk11cert.c @@ -796,6 +796,8 @@ PK11_ImportCert(PK11SlotInfo *slot, CERTCertificate *cert, NSSToken *token = PK11Slot_GetNSSToken(slot); SECItem *keyID = pk11_mkcertKeyID(cert); char *emailAddr = NULL; + nssCertificateStoreTrace lockTrace = {NULL, NULL, PR_FALSE, PR_FALSE}; + nssCertificateStoreTrace unlockTrace = {NULL, NULL, PR_FALSE, PR_FALSE}; if (keyID == NULL) { goto loser; @@ -815,9 +817,10 @@ PK11_ImportCert(PK11SlotInfo *slot, CERTCertificate *cert, if (c->object.cryptoContext) { /* Delete the temp instance */ NSSCryptoContext *cc = c->object.cryptoContext; - nssCertificateStore_Lock(cc->certStore); + nssCertificateStore_Lock(cc->certStore, &lockTrace); nssCertificateStore_RemoveCertLOCKED(cc->certStore, c); - nssCertificateStore_Unlock(cc->certStore); + nssCertificateStore_Unlock(cc->certStore, &lockTrace, &unlockTrace); + nssCertificateStore_Check(&lockTrace, &unlockTrace); c->object.cryptoContext = NULL; cert->istemp = PR_FALSE; cert->isperm = PR_TRUE; @@ -935,6 +938,7 @@ PK11_FindPrivateKeyFromCert(PK11SlotInfo *slot, CERTCertificate *cert, CK_OBJECT_HANDLE certh; CK_OBJECT_HANDLE keyh; CK_ATTRIBUTE *attrs = theTemplate; + PRBool needLogin; SECStatus rv; PK11_SETATTRS(attrs, CKA_VALUE, cert->derCert.data, @@ -953,10 +957,18 @@ PK11_FindPrivateKeyFromCert(PK11SlotInfo *slot, CERTCertificate *cert, if (certh == CK_INVALID_HANDLE) { return NULL; } + /* + * prevent a login race condition. If slot is logged in between + * our call to pk11_LoginStillRequired and the + * PK11_MatchItem. The matchItem call will either succeed, or + * we will call it one more time after calling PK11_Authenticate + * (which is a noop on an authenticated token). + */ + needLogin = pk11_LoginStillRequired(slot,wincx); keyh = PK11_MatchItem(slot,certh,CKO_PRIVATE_KEY); if ((keyh == CK_INVALID_HANDLE) && (PORT_GetError() == SSL_ERROR_NO_CERTIFICATE) && - pk11_LoginStillRequired(slot, wincx)) { + needLogin) { /* try it again authenticated */ rv = PK11_Authenticate(slot, PR_TRUE, wincx); if (rv != SECSuccess) { @@ -995,10 +1007,18 @@ PK11_KeyForCertExists(CERTCertificate *cert, CK_OBJECT_HANDLE *keyPtr, /* Look for the slot that holds the Key */ for (le = list->head ; le; le = le->next) { + /* + * prevent a login race condition. If le->slot is logged in between + * our call to pk11_LoginStillRequired and the + * pk11_FindPrivateKeyFromCertID, the find will either succeed, or + * we will call it one more time after calling PK11_Authenticate + * (which is a noop on an authenticated token). + */ + PRBool needLogin = pk11_LoginStillRequired(le->slot,wincx); key = pk11_FindPrivateKeyFromCertID(le->slot,keyID); if ((key == CK_INVALID_HANDLE) && (PORT_GetError() == SSL_ERROR_NO_CERTIFICATE) && - pk11_LoginStillRequired(le->slot,wincx)) { + needLogin) { /* authenticate and try again */ rv = PK11_Authenticate(le->slot, PR_TRUE, wincx); if (rv != SECSuccess) continue; @@ -1553,16 +1573,25 @@ PK11_FindKeyByAnyCert(CERTCertificate *cert, void *wincx) CK_OBJECT_HANDLE keyHandle; PK11SlotInfo *slot = NULL; SECKEYPrivateKey *privKey = NULL; + PRBool needLogin; SECStatus rv; certHandle = PK11_FindObjectForCert(cert, wincx, &slot); if (certHandle == CK_INVALID_HANDLE) { return NULL; } + /* + * prevent a login race condition. If slot is logged in between + * our call to pk11_LoginStillRequired and the + * PK11_MatchItem. The matchItem call will either succeed, or + * we will call it one more time after calling PK11_Authenticate + * (which is a noop on an authenticated token). + */ + needLogin = pk11_LoginStillRequired(slot,wincx); keyHandle = PK11_MatchItem(slot,certHandle,CKO_PRIVATE_KEY); if ((keyHandle == CK_INVALID_HANDLE) && (PORT_GetError() == SSL_ERROR_NO_CERTIFICATE) && - pk11_LoginStillRequired(slot,wincx)) { + needLogin) { /* authenticate and try again */ rv = PK11_Authenticate(slot, PR_TRUE, wincx); if (rv == SECSuccess) { @@ -1947,6 +1976,7 @@ pk11_findKeyObjectByDERCert(PK11SlotInfo *slot, CERTCertificate *cert, SECItem *keyID; CK_OBJECT_HANDLE key; SECStatus rv; + PRBool needLogin; if((slot == NULL) || (cert == NULL)) { return CK_INVALID_HANDLE; @@ -1957,10 +1987,18 @@ pk11_findKeyObjectByDERCert(PK11SlotInfo *slot, CERTCertificate *cert, return CK_INVALID_HANDLE; } + /* + * prevent a login race condition. If slot is logged in between + * our call to pk11_LoginStillRequired and the + * pk11_FindPrivateKeyFromCerID. The matchItem call will either succeed, or + * we will call it one more time after calling PK11_Authenticate + * (which is a noop on an authenticated token). + */ + needLogin = pk11_LoginStillRequired(slot,wincx); key = pk11_FindPrivateKeyFromCertID(slot, keyID); if ((key == CK_INVALID_HANDLE) && (PORT_GetError() == SSL_ERROR_NO_CERTIFICATE) && - pk11_LoginStillRequired(slot,wincx)) { + needLogin) { /* authenticate and try again */ rv = PK11_Authenticate(slot, PR_TRUE, wincx); if (rv != SECSuccess) goto loser; diff --git a/security/nss/lib/pk11wrap/pk11cxt.c b/security/nss/lib/pk11wrap/pk11cxt.c index 4428fda9b..1ce648bf7 100644 --- a/security/nss/lib/pk11wrap/pk11cxt.c +++ b/security/nss/lib/pk11wrap/pk11cxt.c @@ -249,7 +249,7 @@ static PK11Context *pk11_CreateNewContextInSlot(CK_MECHANISM_TYPE type, SECStatus rv; PORT_Assert(slot != NULL); - if (!slot) { + if (!slot || (!symKey && operation != CKA_DIGEST)) { PORT_SetError(SEC_ERROR_INVALID_ARGS); return NULL; } diff --git a/security/nss/lib/pk11wrap/pk11obj.c b/security/nss/lib/pk11wrap/pk11obj.c index 65b47ef96..07536003c 100644 --- a/security/nss/lib/pk11wrap/pk11obj.c +++ b/security/nss/lib/pk11wrap/pk11obj.c @@ -571,11 +571,14 @@ PK11_SignatureLen(SECKEYPrivateKey *key) if (theTemplate.pValue != NULL) { params.len = theTemplate.ulValueLen; params.data = (unsigned char *) theTemplate.pValue; - length = SECKEY_ECParamsToKeySize(¶ms); + length = SECKEY_ECParamsToBasePointOrderLen(¶ms); PORT_Free(theTemplate.pValue); + if (length == 0) { + return pk11_backupGetSignLength(key); + } + length = ((length + 7)/8) * 2; + return length; } - length = ((length + 7)/8) * 2; - return length; } break; default: diff --git a/security/nss/lib/pk11wrap/pk11pbe.c b/security/nss/lib/pk11wrap/pk11pbe.c index 1234af856..4a55b0ba7 100644 --- a/security/nss/lib/pk11wrap/pk11pbe.c +++ b/security/nss/lib/pk11wrap/pk11pbe.c @@ -775,7 +775,8 @@ PK11_RawPBEKeyGen(PK11SlotInfo *slot, CK_MECHANISM_TYPE type, SECItem *mech, return NULL; } - symKey = PK11_KeyGen(slot, type, mech, 0, wincx); + symKey = PK11_TokenKeyGenWithFlags(slot, type, mech, 0, NULL, + CKF_SIGN|CKF_ENCRYPT|CKF_DECRYPT|CKF_UNWRAP|CKF_WRAP, 0, wincx); PORT_ZFree(pbe_params->pPassword, pwitem->len); pbe_params->pPassword = NULL; diff --git a/security/nss/lib/pk11wrap/pk11pub.h b/security/nss/lib/pk11wrap/pk11pub.h index 8a933cc93..4c674d48e 100644 --- a/security/nss/lib/pk11wrap/pk11pub.h +++ b/security/nss/lib/pk11wrap/pk11pub.h @@ -582,6 +582,14 @@ CERTSignedCrl* PK11_ImportCRL(PK11SlotInfo * slot, SECItem *derCRL, char *url, /********************************************************************** * Sign/Verify **********************************************************************/ + +/* + * Return the length in bytes of a signature generated with the + * private key. + * + * Return 0 or -1 on failure. (XXX Should we fix it to always return + * -1 on failure?) + */ int PK11_SignatureLen(SECKEYPrivateKey *key); PK11SlotInfo * PK11_GetSlotFromPrivateKey(SECKEYPrivateKey *key); SECStatus PK11_Sign(SECKEYPrivateKey *key, SECItem *sig, SECItem *hash); diff --git a/security/nss/lib/pk11wrap/pk11slot.c b/security/nss/lib/pk11wrap/pk11slot.c index a92fbf7df..94d4ffaba 100644 --- a/security/nss/lib/pk11wrap/pk11slot.c +++ b/security/nss/lib/pk11wrap/pk11slot.c @@ -354,7 +354,7 @@ PK11_NewSlotInfo(SECMODModule *mod) PZ_NewLock(nssILockSession) : mod->refLock; if (slot->sessionLock == NULL) { PORT_Free(slot); - return slot; + return NULL; } slot->freeListLock = PZ_NewLock(nssILockFreelist); if (slot->freeListLock == NULL) { @@ -362,7 +362,7 @@ PK11_NewSlotInfo(SECMODModule *mod) PZ_DestroyLock(slot->sessionLock); } PORT_Free(slot); - return slot; + return NULL; } slot->freeSymKeysWithSessionHead = NULL; slot->freeSymKeysHead = NULL; diff --git a/security/nss/lib/pk11wrap/secmod.h b/security/nss/lib/pk11wrap/secmod.h index 83545f5e3..68ac59f27 100644 --- a/security/nss/lib/pk11wrap/secmod.h +++ b/security/nss/lib/pk11wrap/secmod.h @@ -55,6 +55,9 @@ #define PUBLIC_MECH_MD2_FLAG 0x00000400ul #define PUBLIC_MECH_SSL_FLAG 0x00000800ul #define PUBLIC_MECH_TLS_FLAG 0x00001000ul +#define PUBLIC_MECH_AES_FLAG 0x00002000ul +#define PUBLIC_MECH_SHA256_FLAG 0x00004000ul +#define PUBLIC_MECH_SHA512_FLAG 0x00008000ul #define PUBLIC_MECH_RANDOM_FLAG 0x08000000ul #define PUBLIC_MECH_FRIENDLY_FLAG 0x10000000ul @@ -62,7 +65,7 @@ #define PUBLIC_DISABLE_FLAG 0x40000000ul /* warning: reserved means reserved */ -#define PUBLIC_MECH_RESERVED_FLAGS 0x87FFE000ul +#define PUBLIC_MECH_RESERVED_FLAGS 0x87FF0000ul /* These cipher flags are visible to all other libraries, */ /* But they must be converted before used in functions */ diff --git a/security/nss/lib/pkcs12/p12d.c b/security/nss/lib/pkcs12/p12d.c index 2d4d29cae..68220e15d 100644 --- a/security/nss/lib/pkcs12/p12d.c +++ b/security/nss/lib/pkcs12/p12d.c @@ -543,15 +543,15 @@ sec_pkcs12_decoder_safe_contents_init_decode(SEC_PKCS12DecoderContext *p12dcx, if(!p12dcx->safeContentsCnt) { p12dcx->safeContentsList = (sec_PKCS12SafeContentsContext**)PORT_ArenaZAlloc(p12dcx->arena, - sizeof(sec_PKCS12SafeContentsContext *)); + 2 * sizeof(sec_PKCS12SafeContentsContext *)); } else { p12dcx->safeContentsList = (sec_PKCS12SafeContentsContext **) PORT_ArenaGrow(p12dcx->arena, p12dcx->safeContentsList, - (p12dcx->safeContentsCnt * - sizeof(sec_PKCS12SafeContentsContext *)), - (1 + p12dcx->safeContentsCnt * - sizeof(sec_PKCS12SafeContentsContext *))); + (1 + p12dcx->safeContentsCnt) * + sizeof(sec_PKCS12SafeContentsContext *), + (2 + p12dcx->safeContentsCnt) * + sizeof(sec_PKCS12SafeContentsContext *)); } if(!p12dcx->safeContentsList) { p12dcx->errorValue = SEC_ERROR_NO_MEMORY; @@ -2721,7 +2721,7 @@ SEC_PKCS12DecoderValidateBags(SEC_PKCS12DecoderContext *p12dcx, { SECStatus rv; int i, noInstallCnt, probCnt, bagCnt, errorVal = 0; - if(!p12dcx || p12dcx->error) { + if(!p12dcx || p12dcx->error || !p12dcx->safeBags) { return SECFailure; } diff --git a/security/nss/lib/pkcs7/p7decode.c b/security/nss/lib/pkcs7/p7decode.c index 37a0c5b40..df3919975 100644 --- a/security/nss/lib/pkcs7/p7decode.c +++ b/security/nss/lib/pkcs7/p7decode.c @@ -1665,7 +1665,9 @@ sec_pkcs7_verify_signature(SEC_PKCS7ContentInfo *cinfo, algiddata = SECOID_FindOID (&(signerinfo->digestEncAlg.algorithm)); if (algiddata == NULL || ((algiddata->offset != SEC_OID_PKCS1_RSA_ENCRYPTION) && +#ifdef NSS_ECC_MORE_THAN_SUITE_B (algiddata->offset != SEC_OID_ANSIX962_EC_PUBLIC_KEY) && +#endif (algiddata->offset != SEC_OID_ANSIX9_DSA_SIGNATURE))) { PORT_SetError (SEC_ERROR_PKCS7_BAD_SIGNATURE); goto done; diff --git a/security/nss/lib/pki/certificate.c b/security/nss/lib/pki/certificate.c index 3abca38c1..a669879e7 100644 --- a/security/nss/lib/pki/certificate.c +++ b/security/nss/lib/pki/certificate.c @@ -120,6 +120,10 @@ nssCertificate_Destroy ( NSSCertificate *c ) { + nssCertificateStoreTrace lockTrace = {NULL, NULL, PR_FALSE, PR_FALSE}; + nssCertificateStoreTrace unlockTrace = {NULL, NULL, PR_FALSE, PR_FALSE}; + PRBool locked = PR_FALSE; + if (c) { PRUint32 i; nssDecodedCert *dc = c->decoding; @@ -130,7 +134,8 @@ nssCertificate_Destroy ( /* --- LOCK storage --- */ if (cc) { - nssCertificateStore_Lock(cc->certStore); + nssCertificateStore_Lock(cc->certStore, &lockTrace); + locked = PR_TRUE; } else { nssTrustDomain_LockCertCache(td); } @@ -138,7 +143,10 @@ nssCertificate_Destroy ( /* --- remove cert and UNLOCK storage --- */ if (cc) { nssCertificateStore_RemoveCertLOCKED(cc->certStore, c); - nssCertificateStore_Unlock(cc->certStore); + nssCertificateStore_Unlock(cc->certStore, &lockTrace, + &unlockTrace); + nssCertificateStore_Check(&lockTrace, &unlockTrace); + } else { nssTrustDomain_RemoveCertFromCacheLOCKED(td, c); nssTrustDomain_UnlockCertCache(td); @@ -153,12 +161,18 @@ nssCertificate_Destroy ( } else { /* --- UNLOCK storage --- */ if (cc) { - nssCertificateStore_Unlock(cc->certStore); + nssCertificateStore_Unlock(cc->certStore, + &lockTrace, + &unlockTrace); + nssCertificateStore_Check(&lockTrace, &unlockTrace); } else { nssTrustDomain_UnlockCertCache(td); } } } + if (locked) { + nssCertificateStore_Check(&lockTrace, &unlockTrace); + } return PR_SUCCESS; } diff --git a/security/nss/lib/pki/cryptocontext.c b/security/nss/lib/pki/cryptocontext.c index 6b8a724c3..68fe20003 100644 --- a/security/nss/lib/pki/cryptocontext.c +++ b/security/nss/lib/pki/cryptocontext.c @@ -84,6 +84,12 @@ nssCryptoContext_Create ( } rvCC->td = td; rvCC->arena = arena; + rvCC->certStore = nssCertificateStore_Create(rvCC->arena); + if (!rvCC->certStore) { + nssArena_Destroy(arena); + return NULL; + } + return rvCC; } @@ -93,11 +99,14 @@ NSSCryptoContext_Destroy ( ) { PRStatus status = PR_SUCCESS; + PORT_Assert(cc->certStore); if (cc->certStore) { status = nssCertificateStore_Destroy(cc->certStore); if (status == PR_FAILURE) { return status; } + } else { + status = PR_FAILURE; } nssArena_Destroy(cc->arena); return status; @@ -140,11 +149,9 @@ NSSCryptoContext_ImportCertificate ( ) { PRStatus nssrv; + PORT_Assert(cc->certStore); if (!cc->certStore) { - cc->certStore = nssCertificateStore_Create(cc->arena); - if (!cc->certStore) { - return PR_FAILURE; - } + return PR_FAILURE; } nssrv = nssCertificateStore_Add(cc->certStore, c); if (nssrv == PR_SUCCESS) { @@ -190,11 +197,9 @@ nssCryptoContext_ImportTrust ( ) { PRStatus nssrv; + PORT_Assert(cc->certStore); if (!cc->certStore) { - cc->certStore = nssCertificateStore_Create(cc->arena); - if (!cc->certStore) { - return PR_FAILURE; - } + return PR_FAILURE; } nssrv = nssCertificateStore_AddTrust(cc->certStore, trust); #if 0 @@ -212,11 +217,9 @@ nssCryptoContext_ImportSMIMEProfile ( ) { PRStatus nssrv; + PORT_Assert(cc->certStore); if (!cc->certStore) { - cc->certStore = nssCertificateStore_Create(cc->arena); - if (!cc->certStore) { - return PR_FAILURE; - } + return PR_FAILURE; } nssrv = nssCertificateStore_AddSMIMEProfile(cc->certStore, profile); #if 0 @@ -238,6 +241,7 @@ NSSCryptoContext_FindBestCertificateByNickname ( { NSSCertificate **certs; NSSCertificate *rvCert = NULL; + PORT_Assert(cc->certStore); if (!cc->certStore) { return NULL; } @@ -264,6 +268,7 @@ NSSCryptoContext_FindCertificatesByNickname ( ) { NSSCertificate **rvCerts; + PORT_Assert(cc->certStore); if (!cc->certStore) { return NULL; } @@ -282,6 +287,7 @@ NSSCryptoContext_FindCertificateByIssuerAndSerialNumber ( NSSDER *serialNumber ) { + PORT_Assert(cc->certStore); if (!cc->certStore) { return NULL; } @@ -302,6 +308,7 @@ NSSCryptoContext_FindBestCertificateBySubject ( { NSSCertificate **certs; NSSCertificate *rvCert = NULL; + PORT_Assert(cc->certStore); if (!cc->certStore) { return NULL; } @@ -328,6 +335,7 @@ nssCryptoContext_FindCertificatesBySubject ( ) { NSSCertificate **rvCerts; + PORT_Assert(cc->certStore); if (!cc->certStore) { return NULL; } @@ -385,6 +393,7 @@ NSSCryptoContext_FindCertificateByEncodedCertificate ( NSSBER *encodedCertificate ) { + PORT_Assert(cc->certStore); if (!cc->certStore) { return NULL; } @@ -404,6 +413,8 @@ NSSCryptoContext_FindBestCertificateByEmail ( { NSSCertificate **certs; NSSCertificate *rvCert = NULL; + + PORT_Assert(cc->certStore); if (!cc->certStore) { return NULL; } @@ -430,6 +441,7 @@ NSSCryptoContext_FindCertificatesByEmail ( ) { NSSCertificate **rvCerts; + PORT_Assert(cc->certStore); if (!cc->certStore) { return NULL; } @@ -546,6 +558,7 @@ nssCryptoContext_FindTrustForCertificate ( NSSCertificate *cert ) { + PORT_Assert(cc->certStore); if (!cc->certStore) { return NULL; } @@ -558,6 +571,7 @@ nssCryptoContext_FindSMIMEProfileForCertificate ( NSSCertificate *cert ) { + PORT_Assert(cc->certStore); if (!cc->certStore) { return NULL; } diff --git a/security/nss/lib/pki/pkistore.c b/security/nss/lib/pki/pkistore.c index ed35c9749..b575d24d9 100644 --- a/security/nss/lib/pki/pkistore.c +++ b/security/nss/lib/pki/pkistore.c @@ -313,18 +313,41 @@ nssCertificateStore_RemoveCertLOCKED ( NSS_IMPLEMENT void nssCertificateStore_Lock ( - nssCertificateStore *store + nssCertificateStore *store, nssCertificateStoreTrace* out ) { +#ifdef DEBUG + PORT_Assert(out); + out->store = store; + out->lock = store->lock; + out->locked = PR_TRUE; + PZ_Lock(out->lock); +#else PZ_Lock(store->lock); +#endif } NSS_IMPLEMENT void nssCertificateStore_Unlock ( - nssCertificateStore *store + nssCertificateStore *store, nssCertificateStoreTrace* in, + nssCertificateStoreTrace* out ) { +#ifdef DEBUG + PORT_Assert(in); + PORT_Assert(out); + out->store = store; + out->lock = store->lock; + out->unlocked = PR_TRUE; + + PORT_Assert(in->store == out->store); + PORT_Assert(in->lock == out->lock); + PORT_Assert(in->locked); + + PZ_Unlock(out->lock); +#else PZ_Unlock(store->lock); +#endif } static NSSCertificate ** diff --git a/security/nss/lib/pki/pkistore.h b/security/nss/lib/pki/pkistore.h index d2f222a1c..a89ebbfac 100644 --- a/security/nss/lib/pki/pkistore.h +++ b/security/nss/lib/pki/pkistore.h @@ -95,14 +95,36 @@ nssCertificateStore_RemoveCertLOCKED NSSCertificate *cert ); +struct nssCertificateStoreTraceStr { + nssCertificateStore* store; + PZLock* lock; + PRBool locked; + PRBool unlocked; +}; + +typedef struct nssCertificateStoreTraceStr nssCertificateStoreTrace; + +static void nssCertificateStore_Check(nssCertificateStoreTrace* a, + nssCertificateStoreTrace* b) { + PORT_Assert(a->locked); + PORT_Assert(b->unlocked); + + PORT_Assert(!a->unlocked); + PORT_Assert(!b->locked); + + PORT_Assert(a->lock == b->lock); + PORT_Assert(a->store == b->store); +}; + NSS_EXTERN void nssCertificateStore_Lock ( - nssCertificateStore *store + nssCertificateStore *store, nssCertificateStoreTrace* out ); NSS_EXTERN void nssCertificateStore_Unlock ( - nssCertificateStore *store + nssCertificateStore *store, nssCertificateStoreTrace* in, + nssCertificateStoreTrace* out ); NSS_EXTERN NSSCertificate ** diff --git a/security/nss/lib/smime/cmsrecinfo.c b/security/nss/lib/smime/cmsrecinfo.c index 07236adc1..e7dadac5b 100644 --- a/security/nss/lib/smime/cmsrecinfo.c +++ b/security/nss/lib/smime/cmsrecinfo.c @@ -295,6 +295,9 @@ done: return ri; loser: + if (ri && ri->cert) { + CERT_DestroyCertificate(ri->cert); + } if (freeSpki) { SECKEY_DestroySubjectPublicKeyInfo(freeSpki); } diff --git a/security/nss/lib/smime/cmssiginfo.c b/security/nss/lib/smime/cmssiginfo.c index 675040b66..508632f69 100644 --- a/security/nss/lib/smime/cmssiginfo.c +++ b/security/nss/lib/smime/cmssiginfo.c @@ -386,7 +386,9 @@ NSS_CMSSignerInfo_Verify(NSSCMSSignerInfo *signerinfo, case SEC_OID_ANSIX9_DSA_SIGNATURE_WITH_SHA1_DIGEST: case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: +#ifdef NSS_ECC_MORE_THAN_SUITE_B case SEC_OID_ANSIX962_EC_PUBLIC_KEY: +#endif /* ok */ break; case SEC_OID_UNKNOWN: diff --git a/security/nss/lib/smime/cmsutil.c b/security/nss/lib/smime/cmsutil.c index 1765655bb..710a749c6 100644 --- a/security/nss/lib/smime/cmsutil.c +++ b/security/nss/lib/smime/cmsutil.c @@ -259,7 +259,13 @@ NSS_CMSUtil_MakeSignatureAlgorithm(SECOidTag hashalg, SECOidTag encalg) case SEC_OID_ANSIX962_EC_PUBLIC_KEY: switch (hashalg) { case SEC_OID_SHA1: - return SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST; + return SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE; + case SEC_OID_SHA256: + return SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE; + case SEC_OID_SHA384: + return SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE; + case SEC_OID_SHA512: + return SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE; default: return SEC_OID_UNKNOWN; } diff --git a/security/nss/lib/smime/smime.rc b/security/nss/lib/smime/smime.rc index 05fb11bfa..7fd7298d1 100644 --- a/security/nss/lib/smime/smime.rc +++ b/security/nss/lib/smime/smime.rc @@ -84,11 +84,10 @@ BEGIN BEGIN BLOCK "040904B0" // Lang=US English, CharSet=Unicode BEGIN - VALUE "CompanyName", "Netscape Communications Corporation\0" + VALUE "CompanyName", "Mozilla Foundation\0" VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0" VALUE "FileVersion", NSS_VERSION "\0" VALUE "InternalName", MY_INTERNAL_NAME "\0" - VALUE "LegalCopyright", "Copyright \251 1994-2001 Netscape Communications Corporation\0" VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0" VALUE "ProductName", "Network Security Services\0" VALUE "ProductVersion", NSS_VERSION "\0" diff --git a/security/nss/lib/smime/smimeutil.c b/security/nss/lib/smime/smimeutil.c index 6fb10ec07..b632b1a0d 100644 --- a/security/nss/lib/smime/smimeutil.c +++ b/security/nss/lib/smime/smimeutil.c @@ -738,7 +738,7 @@ NSS_SMIMEUtil_GetCertFromEncryptionKeyPreference(CERTCertDBHandle *certdb, SECIt return NULL; /* decode DERekp */ - if (SEC_QuickDERDecodeItem(tmppoolp, &ekp, smime_encryptionkeypref_template, + if (SEC_ASN1DecodeItem(tmppoolp, &ekp, smime_encryptionkeypref_template, DERekp) != SECSuccess) goto loser; diff --git a/security/nss/lib/softoken/ecdecode.c b/security/nss/lib/softoken/ecdecode.c index e649ff899..dbf1cb3f8 100644 --- a/security/nss/lib/softoken/ecdecode.c +++ b/security/nss/lib/softoken/ecdecode.c @@ -49,7 +49,12 @@ #define CHECK_OK(func) if (func == NULL) goto cleanup #define CHECK_SEC_OK(func) if (SECSuccess != (rv = func)) goto cleanup -/* Initializes a SECItem from a hexadecimal string */ +/* + * Initializes a SECItem from a hexadecimal string + * + * Warning: This function ignores leading 00's, so any leading 00's + * in the hexadecimal string must be optional. + */ static SECItem * hexString2SECItem(PRArenaPool *arena, SECItem *item, const char *str) { @@ -59,6 +64,12 @@ hexString2SECItem(PRArenaPool *arena, SECItem *item, const char *str) if ((tmp % 2) != 0) return NULL; + /* skip leading 00's unless the hex string is "00" */ + while ((tmp > 2) && (str[0] == '0') && (str[1] == '0')) { + str += 2; + tmp -= 2; + } + item->data = (unsigned char *) PORT_ArenaAlloc(arena, tmp/2); if (item->data == NULL) return NULL; item->len = tmp/2; @@ -136,7 +147,8 @@ EC_FillParams(PRArenaPool *arena, const SECItem *encodedParams, SECOidTag tag; SECItem oid = { siBuffer, NULL, 0}; const ECCurveParams *curveParams; - char genenc[2 + 2 * 2 * MAX_ECKEY_LEN]; + /* 2 ['0'+'4'] + MAX_ECKEY_LEN * 2 [x,y] * 2 [hex string] + 1 ['\0'] */ + char genenc[3 + 2 * 2 * MAX_ECKEY_LEN]; #if EC_DEBUG int i; diff --git a/security/nss/lib/softoken/fipstest.c b/security/nss/lib/softoken/fipstest.c index acee77676..efc2c278b 100644 --- a/security/nss/lib/softoken/fipstest.c +++ b/security/nss/lib/softoken/fipstest.c @@ -42,10 +42,21 @@ /* DES-CBC, DES3-ECB, DES3-CBC, RSA */ /* and DSA. */ #include "seccomon.h" /* Required for RSA and DSA. */ -#include "lowkeyi.h" /* Required for RSA and DSA. */ +#include "lowkeyi.h" /* Required for RSA and DSA. */ #include "pkcs11.h" /* Required for PKCS #11. */ #include "secerr.h" +#ifdef NSS_ENABLE_ECC +#include "secdert.h" /* Required for ECDSA */ +#include "ec.h" /* Required for ECDSA */ +extern SECStatus +EC_DecodeParams(const SECItem *encodedParams, ECParams **ecparams); +extern SECStatus +EC_CopyParams(PRArenaPool *arena, ECParams *dstParams, + const ECParams *srcParams); +#endif + + /* FIPS preprocessor directives for RC2-ECB and RC2-CBC. */ #define FIPS_RC2_KEY_LENGTH 5 /* 40-bits */ #define FIPS_RC2_ENCRYPT_LENGTH 8 /* 64-bits */ @@ -81,22 +92,21 @@ #define FIPS_KNOWN_HASH_MESSAGE_LENGTH 64 /* 512-bits */ -/* FIPS preprocessor directives for RSA. */ +/* FIPS preprocessor directives for RSA. */ #define FIPS_RSA_TYPE siBuffer -#define FIPS_RSA_PUBLIC_EXPONENT_LENGTH 1 /* 8-bits */ -#define FIPS_RSA_PRIVATE_VERSION_LENGTH 1 /* 8-bits */ -#define FIPS_RSA_MESSAGE_LENGTH 16 /* 128-bits */ -#define FIPS_RSA_COEFFICIENT_LENGTH 32 /* 256-bits */ -#define FIPS_RSA_PRIME0_LENGTH 33 /* 264-bits */ -#define FIPS_RSA_PRIME1_LENGTH 33 /* 264-bits */ -#define FIPS_RSA_EXPONENT0_LENGTH 33 /* 264-bits */ -#define FIPS_RSA_EXPONENT1_LENGTH 33 /* 264-bits */ -#define FIPS_RSA_PRIVATE_EXPONENT_LENGTH 64 /* 512-bits */ -#define FIPS_RSA_ENCRYPT_LENGTH 64 /* 512-bits */ -#define FIPS_RSA_DECRYPT_LENGTH 64 /* 512-bits */ -#define FIPS_RSA_CRYPTO_LENGTH 64 /* 512-bits */ -#define FIPS_RSA_SIGNATURE_LENGTH 64 /* 512-bits */ -#define FIPS_RSA_MODULUS_LENGTH 65 /* 520-bits */ +#define FIPS_RSA_PUBLIC_EXPONENT_LENGTH 3 /* 24-bits */ +#define FIPS_RSA_PRIVATE_VERSION_LENGTH 1 /* 8-bits */ +#define FIPS_RSA_MESSAGE_LENGTH 128 /* 1024-bits */ +#define FIPS_RSA_COEFFICIENT_LENGTH 64 /* 512-bits */ +#define FIPS_RSA_PRIME0_LENGTH 64 /* 512-bits */ +#define FIPS_RSA_PRIME1_LENGTH 64 /* 512-bits */ +#define FIPS_RSA_EXPONENT0_LENGTH 64 /* 512-bits */ +#define FIPS_RSA_EXPONENT1_LENGTH 64 /* 512-bits */ +#define FIPS_RSA_PRIVATE_EXPONENT_LENGTH 128 /* 1024-bits */ +#define FIPS_RSA_ENCRYPT_LENGTH 128 /* 1024-bits */ +#define FIPS_RSA_DECRYPT_LENGTH 128 /* 1024-bits */ +#define FIPS_RSA_SIGNATURE_LENGTH 128 /* 1024-bits */ +#define FIPS_RSA_MODULUS_LENGTH 128 /* 1024-bits */ /* FIPS preprocessor directives for DSA. */ @@ -1046,121 +1056,324 @@ sftk_fips_SHA_PowerUpSelfTest( void ) return( CKR_OK ); } +/* +* Single round RSA Signature Known Answer Test +*/ +static SECStatus +sftk_fips_RSA_PowerUpSigSelfTest (HASH_HashType shaAlg, + NSSLOWKEYPublicKey *rsa_public_key, + NSSLOWKEYPrivateKey *rsa_private_key, + const unsigned char *rsa_known_msg, + const unsigned int rsa_kmsg_length, + const unsigned char *rsa_known_signature) +{ + SECOidTag shaOid; /* SHA OID */ + unsigned char sha[HASH_LENGTH_MAX]; /* SHA digest */ + unsigned int shaLength = 0; /* length of SHA */ + unsigned int rsa_bytes_signed; + unsigned char rsa_computed_signature[FIPS_RSA_SIGNATURE_LENGTH]; + SECStatus rv; + + if (shaAlg == HASH_AlgSHA1) { + if (SHA1_HashBuf(sha, rsa_known_msg, rsa_kmsg_length) + != SECSuccess) { + goto loser; + } + shaLength = SHA1_LENGTH; + shaOid = SEC_OID_SHA1; + } else if (shaAlg == HASH_AlgSHA256) { + if (SHA256_HashBuf(sha, rsa_known_msg, rsa_kmsg_length) + != SECSuccess) { + goto loser; + } + shaLength = SHA256_LENGTH; + shaOid = SEC_OID_SHA256; + } else if (shaAlg == HASH_AlgSHA384) { + if (SHA384_HashBuf(sha, rsa_known_msg, rsa_kmsg_length) + != SECSuccess) { + goto loser; + } + shaLength = SHA384_LENGTH; + shaOid = SEC_OID_SHA384; + } else if (shaAlg == HASH_AlgSHA512) { + if (SHA512_HashBuf(sha, rsa_known_msg, rsa_kmsg_length) + != SECSuccess) { + goto loser; + } + shaLength = SHA512_LENGTH; + shaOid = SEC_OID_SHA512; + } else { + goto loser; + } + + /*************************************************/ + /* RSA Single-Round Known Answer Signature Test. */ + /*************************************************/ + + /* Perform RSA signature with the RSA private key. */ + rv = RSA_HashSign( shaOid, + rsa_private_key, + rsa_computed_signature, + &rsa_bytes_signed, + FIPS_RSA_SIGNATURE_LENGTH, + sha, + shaLength); + + if( ( rv != SECSuccess ) || + ( rsa_bytes_signed != FIPS_RSA_SIGNATURE_LENGTH ) || + ( PORT_Memcmp( rsa_computed_signature, rsa_known_signature, + FIPS_RSA_SIGNATURE_LENGTH ) != 0 ) ) { + goto loser; + } + + /****************************************************/ + /* RSA Single-Round Known Answer Verification Test. */ + /****************************************************/ + + /* Perform RSA verification with the RSA public key. */ + rv = RSA_HashCheckSign( shaOid, + rsa_public_key, + rsa_computed_signature, + rsa_bytes_signed, + sha, + shaLength); + + if( rv != SECSuccess ) { + goto loser; + } + return( SECSuccess ); + +loser: + + return( SECFailure ); + +} static CK_RV sftk_fips_RSA_PowerUpSelfTest( void ) { - /* RSA Known Modulus used in both Public/Private Key Values (520-bits). */ + /* RSA Known Modulus used in both Public/Private Key Values (1024-bits). */ static const PRUint8 rsa_modulus[FIPS_RSA_MODULUS_LENGTH] = { - 0x00,0xa1,0xe9,0x5e,0x66,0x88,0xe2,0xf2, - 0x2b,0xe7,0x70,0x36,0x33,0xbc,0xeb,0x55, - 0x55,0xf1,0x60,0x18,0x3c,0xfb,0xd2,0x79, - 0xf6,0xc4,0xb8,0x09,0xe3,0x12,0xf6,0x63, - 0x6d,0xc7,0x8e,0x19,0xc0,0x0e,0x10,0x78, - 0xc1,0xfe,0x2a,0x41,0x74,0x2d,0xf7,0xc4, - 0x69,0xa7,0x3c,0xbc,0x8a,0xc8,0x31,0x2b, - 0x4f,0x60,0xf0,0xf1,0xec,0x5a,0x29,0xec, - 0x6b}; - - /* RSA Known Public Key Values (8-bits). */ - static const PRUint8 rsa_public_exponent[] = { 0x03 }; - - /* RSA Known Private Key Values (version is 8-bits), */ - /* (private exponent is 512-bits), */ - /* (private prime0 is 264-bits), */ - /* (private prime1 is 264-bits), */ - /* (private prime exponent0 is 264-bits), */ - /* (private prime exponent1 is 264-bits), */ - /* and (private coefficient is 256-bits). */ + 0xd5, 0x84, 0x95, 0x07, 0xf4, 0xd0, 0x1f, 0x82, + 0xf3, 0x79, 0xf4, 0x99, 0x48, 0x10, 0xe1, 0x71, + 0xa5, 0x62, 0x22, 0xa3, 0x4b, 0x00, 0xe3, 0x5b, + 0x3a, 0xcc, 0x10, 0x83, 0xe0, 0xaf, 0x61, 0x13, + 0x54, 0x6a, 0xa2, 0x6a, 0x2c, 0x5e, 0xb3, 0xcc, + 0xa3, 0x71, 0x9a, 0xb2, 0x3e, 0x78, 0xec, 0xb5, + 0x0e, 0x6e, 0x31, 0x3b, 0x77, 0x1f, 0x6e, 0x94, + 0x41, 0x60, 0xd5, 0x6e, 0xd9, 0xc6, 0xf9, 0x29, + 0xc3, 0x40, 0x36, 0x25, 0xdb, 0xea, 0x0b, 0x07, + 0xae, 0x76, 0xfd, 0x99, 0x29, 0xf4, 0x22, 0xc1, + 0x1a, 0x8f, 0x05, 0xfe, 0x98, 0x09, 0x07, 0x05, + 0xc2, 0x0f, 0x0b, 0x11, 0x83, 0x39, 0xca, 0xc7, + 0x43, 0x63, 0xff, 0x33, 0x80, 0xe7, 0xc3, 0x78, + 0xae, 0xf1, 0x73, 0x52, 0x98, 0x1d, 0xde, 0x5c, + 0x53, 0x6e, 0x01, 0x73, 0x0d, 0x12, 0x7e, 0x77, + 0x03, 0xf1, 0xef, 0x1b, 0xc8, 0xa8, 0x0f, 0x97}; + + /* RSA Known Public Key Values (24-bits). */ + static const PRUint8 rsa_public_exponent[FIPS_RSA_PUBLIC_EXPONENT_LENGTH] + = { 0x01, 0x00, 0x01 }; + /* RSA Known Private Key Values (version is 8-bits), */ + /* (private exponent is 1024-bits), */ + /* (private prime0 is 512-bits), */ + /* (private prime1 is 512-bits), */ + /* (private prime exponent0 is 512-bits), */ + /* (private prime exponent1 is 512-bits), */ + /* and (private coefficient is 512-bits). */ static const PRUint8 rsa_version[] = { 0x00 }; - static const PRUint8 rsa_private_exponent[FIPS_RSA_PRIVATE_EXPONENT_LENGTH] = { - 0x6b,0xf0,0xe9,0x99,0xb0,0x97,0x4c,0x1d, - 0x44,0xf5,0x79,0x77,0xd3,0x47,0x8e,0x39, - 0x4b,0x95,0x65,0x7d,0xfd,0x36,0xfb,0xf9, - 0xd8,0x7a,0xb1,0x42,0x0c,0xa4,0x42,0x48, - 0x20,0x1c,0x6b,0x7d,0x5d,0xa3,0x58,0xd6, - 0x95,0xd6,0x41,0xe3,0xd6,0x73,0xad,0xdb, - 0x3b,0x89,0x00,0x8a,0xcd,0x1d,0xb9,0x06, - 0xac,0xac,0x0e,0x02,0x72,0x1c,0xf8,0xab }; + + static const PRUint8 rsa_private_exponent[FIPS_RSA_PRIVATE_EXPONENT_LENGTH] + = { 0x85, 0x27, 0x47, 0x61, 0x4c, 0xd4, 0xb5, 0xb2, + 0x0e, 0x70, 0x91, 0x8f, 0x3d, 0x97, 0xf9, 0x5f, + 0xcc, 0x09, 0x65, 0x1c, 0x7c, 0x5b, 0xb3, 0x6d, + 0x63, 0x3f, 0x7b, 0x55, 0x22, 0xbb, 0x7c, 0x48, + 0x77, 0xae, 0x80, 0x56, 0xc2, 0x10, 0xd5, 0x03, + 0xdb, 0x31, 0xaf, 0x8d, 0x54, 0xd4, 0x48, 0x99, + 0xa8, 0xc4, 0x23, 0x43, 0xb8, 0x48, 0x0b, 0xc7, + 0xbc, 0xf5, 0xcc, 0x64, 0x72, 0xbf, 0x59, 0x06, + 0x04, 0x1c, 0x32, 0xf5, 0x14, 0x2e, 0x6e, 0xe2, + 0x0f, 0x5c, 0xde, 0x36, 0x3c, 0x6e, 0x7c, 0x4d, + 0xcc, 0xd3, 0x00, 0x6e, 0xe5, 0x45, 0x46, 0xef, + 0x4d, 0x25, 0x46, 0x6d, 0x7f, 0xed, 0xbb, 0x4f, + 0x4d, 0x9f, 0xda, 0x87, 0x47, 0x8f, 0x74, 0x44, + 0xb7, 0xbe, 0x9d, 0xf5, 0xdd, 0xd2, 0x4c, 0xa5, + 0xab, 0x74, 0xe5, 0x29, 0xa1, 0xd2, 0x45, 0x3b, + 0x33, 0xde, 0xd5, 0xae, 0xf7, 0x03, 0x10, 0x21}; + static const PRUint8 rsa_prime0[FIPS_RSA_PRIME0_LENGTH] = { - 0x00,0xd2,0x2c,0x9d,0xef,0x7c,0x8f,0x58, - 0x93,0x19,0xa1,0x77,0x0e,0x38,0x3e,0x85, - 0xb4,0xaf,0xcc,0x99,0xa5,0x43,0xbf,0x97, - 0xdc,0x46,0xb8,0x3f,0x6e,0x85,0x18,0x00, - 0x81}; + 0xf9, 0x74, 0x8f, 0x16, 0x02, 0x6b, 0xa0, 0xee, + 0x7f, 0x28, 0x97, 0x91, 0xdc, 0xec, 0xc0, 0x7c, + 0x49, 0xc2, 0x85, 0x76, 0xee, 0x66, 0x74, 0x2d, + 0x1a, 0xb8, 0xf7, 0x2f, 0x11, 0x5b, 0x36, 0xd8, + 0x46, 0x33, 0x3b, 0xd8, 0xf3, 0x2d, 0xa1, 0x03, + 0x83, 0x2b, 0xec, 0x35, 0x43, 0x32, 0xff, 0xdd, + 0x81, 0x7c, 0xfd, 0x65, 0x13, 0x04, 0x7c, 0xfc, + 0x03, 0x97, 0xf0, 0xd5, 0x62, 0xdc, 0x0d, 0xbf}; static const PRUint8 rsa_prime1[FIPS_RSA_PRIME1_LENGTH] = { - 0x00,0xc5,0x36,0xda,0x94,0x85,0x0c,0x1a, - 0xed,0x03,0xc7,0x67,0x90,0x34,0x0b,0xb9, - 0xec,0x1e,0x22,0xa2,0x15,0x50,0xc4,0xfd, - 0xe9,0x17,0x36,0x9d,0x7a,0x29,0xe6,0x76, - 0xeb}; + 0xdb, 0x1e, 0xa7, 0x3d, 0xe7, 0xfa, 0x8b, 0x04, + 0x83, 0x48, 0xf3, 0xa5, 0x31, 0x9d, 0x35, 0x5e, + 0x4d, 0x54, 0x77, 0xcc, 0x84, 0x09, 0xf3, 0x11, + 0x0d, 0x54, 0xed, 0x85, 0x39, 0xa9, 0xca, 0xa8, + 0xea, 0xae, 0x19, 0x9c, 0x75, 0xdb, 0x88, 0xb8, + 0x04, 0x8d, 0x54, 0xc6, 0xa4, 0x80, 0xf8, 0x93, + 0xf0, 0xdb, 0x19, 0xef, 0xd7, 0x87, 0x8a, 0x8f, + 0x5a, 0x09, 0x2e, 0x54, 0xf3, 0x45, 0x24, 0x29}; static const PRUint8 rsa_exponent0[FIPS_RSA_EXPONENT0_LENGTH] = { - 0x00,0x8c,0x1d,0xbe,0x9f,0xa8, - 0x5f,0x90,0x62,0x11,0x16,0x4f, - 0x5e,0xd0,0x29,0xae,0x78,0x75, - 0x33,0x11,0x18,0xd7,0xd5,0x0f, - 0xe8,0x2f,0x25,0x7f,0x9f,0x03, - 0x65,0x55,0xab}; + 0x6a, 0xd1, 0x25, 0x80, 0x18, 0x33, 0x3c, 0x2b, + 0x44, 0x19, 0xfe, 0xa5, 0x40, 0x03, 0xc4, 0xfc, + 0xb3, 0x9c, 0xef, 0x07, 0x99, 0x58, 0x17, 0xc1, + 0x44, 0xa3, 0x15, 0x7d, 0x7b, 0x22, 0x22, 0xdf, + 0x03, 0x58, 0x66, 0xf5, 0x24, 0x54, 0x52, 0x91, + 0x2d, 0x76, 0xfe, 0x63, 0x64, 0x4e, 0x0f, 0x50, + 0x2b, 0x65, 0x79, 0x1f, 0xf1, 0xbf, 0xc7, 0x41, + 0x26, 0xcc, 0xc6, 0x1c, 0xa9, 0x83, 0x6f, 0x03}; static const PRUint8 rsa_exponent1[FIPS_RSA_EXPONENT1_LENGTH] = { - 0x00,0x83,0x79,0xe7,0x0d,0xae, - 0x08,0x11,0xf3,0x57,0xda,0x45, - 0x0a,0xcd,0x5d,0x26,0x9d,0x69, - 0x6c,0x6c,0x0e,0x35,0xd8,0xa9, - 0x46,0x0f,0x79,0xbe,0x51,0x71, - 0x44,0x4f,0x47}; + 0x12, 0x84, 0x1a, 0x99, 0xce, 0x9a, 0x8b, 0x58, + 0xcc, 0x47, 0x43, 0xdf, 0x77, 0xbb, 0xd3, 0x20, + 0xae, 0xe4, 0x2e, 0x63, 0x67, 0xdc, 0xf7, 0x5f, + 0x3f, 0x83, 0x27, 0xb7, 0x14, 0x52, 0x56, 0xbf, + 0xc3, 0x65, 0x06, 0xe1, 0x03, 0xcc, 0x93, 0x57, + 0x09, 0x7b, 0x6f, 0xe8, 0x81, 0x4a, 0x2c, 0xb7, + 0x43, 0xa9, 0x20, 0x1d, 0xf6, 0x56, 0x8b, 0xcc, + 0xe5, 0x4c, 0xd5, 0x4f, 0x74, 0x67, 0x29, 0x51}; static const PRUint8 rsa_coefficient[FIPS_RSA_COEFFICIENT_LENGTH] = { - 0x54,0x8d,0xb8,0xdc,0x8b,0xde,0xbb, - 0x08,0xc9,0x67,0xb7,0xa9,0x5f,0xa5, - 0xc4,0x5e,0x67,0xaa,0xfe,0x1a,0x08, - 0xeb,0x48,0x43,0xcb,0xb0,0xb9,0x38, - 0x3a,0x31,0x39,0xde}; - - - /* RSA Known Plaintext (512-bits). */ - static const PRUint8 rsa_known_plaintext[] = { - "Known plaintext utilized for RSA" - " Encryption and Decryption test." }; - - /* RSA Known Ciphertext (512-bits). */ + 0x23, 0xab, 0xf4, 0x03, 0x2f, 0x29, 0x95, 0x74, + 0xac, 0x1a, 0x33, 0x96, 0x62, 0xed, 0xf7, 0xf6, + 0xae, 0x07, 0x2a, 0x2e, 0xe8, 0xab, 0xfb, 0x1e, + 0xb9, 0xb2, 0x88, 0x1e, 0x85, 0x05, 0x42, 0x64, + 0x03, 0xb2, 0x8b, 0xc1, 0x81, 0x75, 0xd7, 0xba, + 0xaa, 0xd4, 0x31, 0x3c, 0x8a, 0x96, 0x23, 0x9d, + 0x3f, 0x06, 0x3e, 0x44, 0xa9, 0x62, 0x2f, 0x61, + 0x5a, 0x51, 0x82, 0x2c, 0x04, 0x85, 0x73, 0xd1}; + + /* RSA Known Plaintext Message (1024-bits). */ + static const PRUint8 rsa_known_plaintext_msg[FIPS_RSA_MESSAGE_LENGTH] = { + "Known plaintext message utilized" + "for RSA Encryption & Decryption" + "block, SHA1, SHA256, SHA384 and" + "SHA512 RSA Signature KAT tests."}; + + /* RSA Known Ciphertext (1024-bits). */ static const PRUint8 rsa_known_ciphertext[] = { - 0x12,0x80,0x3a,0x53,0xee,0x93,0x81,0xa5, - 0xf7,0x40,0xc5,0xb1,0xef,0xd9,0x27,0xaf, - 0xef,0x4b,0x87,0x44,0x00,0xd0,0xda,0xcf, - 0x10,0x57,0x4c,0xd5,0xc3,0xed,0x84,0xdc, - 0x74,0x03,0x19,0x69,0x2c,0xd6,0x54,0x3e, - 0xd2,0xe3,0x90,0xb6,0x67,0x91,0x2f,0x1f, - 0x54,0x13,0x99,0x00,0x0b,0xfd,0x52,0x7f, - 0xd8,0xc6,0xdb,0x8a,0xfe,0x06,0xf3,0xb1}; - - /* RSA Known Message (128-bits). */ - static const PRUint8 rsa_known_message[] = { "Netscape Forever" }; - - /* RSA Known Signed Hash (512-bits). */ - static const PRUint8 rsa_known_signature[] = { - 0x27,0x23,0xa6,0x71,0x57,0xc8,0x70,0x5f, - 0x70,0x0e,0x06,0x7b,0x96,0x6a,0xaa,0x41, - 0x6e,0xab,0x67,0x4b,0x5f,0x76,0xc4,0x53, - 0x23,0xd7,0x57,0x7a,0x3a,0xbc,0x4c,0x27, - 0x65,0xca,0xde,0x9f,0xd3,0x1d,0xa4,0x5a, - 0xf9,0x8f,0xb2,0x05,0xa3,0x86,0xf9,0x66, - 0x55,0x4c,0x68,0x50,0x66,0xa4,0xe9,0x17, - 0x45,0x11,0xb8,0x1a,0xfc,0xbc,0x79,0x3b}; - - - static const RSAPublicKey bl_public_key = { NULL, - { FIPS_RSA_TYPE, (unsigned char *)rsa_modulus, FIPS_RSA_MODULUS_LENGTH }, - { FIPS_RSA_TYPE, (unsigned char *)rsa_public_exponent, FIPS_RSA_PUBLIC_EXPONENT_LENGTH } + 0x1e, 0x7e, 0x12, 0xbb, 0x15, 0x62, 0xd0, 0x23, + 0x53, 0x4c, 0x51, 0x97, 0x77, 0x06, 0xa0, 0xbb, + 0x26, 0x99, 0x9a, 0x8f, 0x39, 0xad, 0x88, 0x5c, + 0xc4, 0xce, 0x33, 0x40, 0x94, 0x92, 0xb4, 0x0e, + 0xab, 0x71, 0xa9, 0x5d, 0x9a, 0x37, 0xe3, 0x9a, + 0x24, 0x95, 0x13, 0xea, 0x0f, 0xbb, 0xf7, 0xff, + 0xdf, 0x31, 0x33, 0x23, 0x1d, 0xce, 0x26, 0x9e, + 0xd1, 0xde, 0x98, 0x40, 0xde, 0x57, 0x86, 0x12, + 0xf1, 0xe6, 0x5a, 0x3f, 0x08, 0x02, 0x81, 0x85, + 0xe0, 0xd9, 0xad, 0x3c, 0x8c, 0x71, 0xf8, 0xcf, + 0x0a, 0x98, 0xc5, 0x08, 0xdc, 0xc4, 0xca, 0x8c, + 0x23, 0x1b, 0x4d, 0x9b, 0xb5, 0x13, 0x44, 0xe1, + 0x5f, 0xf9, 0x30, 0x80, 0x25, 0xe0, 0x1e, 0x94, + 0xa3, 0x0c, 0xdc, 0x82, 0x2e, 0xfb, 0x30, 0xbe, + 0x89, 0xba, 0x76, 0xb6, 0x23, 0xf7, 0xda, 0x7c, + 0xca, 0xe6, 0x02, 0xbd, 0x92, 0xce, 0x64, 0xfc}; + + /* RSA Known Signed Hash (1024-bits). */ + static const PRUint8 rsa_known_sha1_signature[] = { + 0xd2, 0xa4, 0xe0, 0x2b, 0xc7, 0x03, 0x7f, 0xc6, + 0x06, 0x9e, 0xa2, 0x82, 0x19, 0xe9, 0x2b, 0xaf, + 0xe3, 0x48, 0x88, 0xc1, 0xf3, 0xb5, 0x0d, 0xe4, + 0x52, 0x9e, 0xad, 0xd5, 0x58, 0xb5, 0x9f, 0xe8, + 0x40, 0xe9, 0xb7, 0x2e, 0xc6, 0x71, 0x58, 0x56, + 0x04, 0xac, 0xb0, 0xf3, 0x3a, 0x42, 0x38, 0x08, + 0xc4, 0x43, 0x39, 0xba, 0x19, 0xce, 0xb1, 0x99, + 0xf1, 0x8d, 0x89, 0xd8, 0x50, 0x07, 0x14, 0x3d, + 0xcf, 0xd0, 0xb6, 0x79, 0xde, 0x9c, 0x89, 0x32, + 0xb0, 0x73, 0x3f, 0xed, 0x03, 0x0b, 0xdf, 0x6d, + 0x7e, 0xc9, 0x1c, 0x39, 0xe8, 0x2b, 0x16, 0x09, + 0xbb, 0x5f, 0x99, 0x2f, 0xeb, 0xf3, 0x37, 0x73, + 0x0d, 0x0e, 0xcc, 0x95, 0xad, 0x90, 0x80, 0x03, + 0x1d, 0x80, 0x55, 0x37, 0xa1, 0x2a, 0x71, 0x76, + 0x23, 0x87, 0x8c, 0x9b, 0x41, 0x07, 0xc6, 0x3d, + 0xc6, 0xa3, 0x7d, 0x1b, 0xff, 0x4e, 0x11, 0x19}; + + /* RSA Known Signed Hash (1024-bits). */ + static const PRUint8 rsa_known_sha256_signature[] = { + 0x27, 0x35, 0xdd, 0xc4, 0xf8, 0xe2, 0x0b, 0xa3, + 0xef, 0x63, 0x57, 0x3b, 0xe1, 0x58, 0x9a, 0xbc, + 0x20, 0x9c, 0x25, 0x12, 0x01, 0xbf, 0xbb, 0x29, + 0x80, 0x1a, 0xb1, 0x37, 0x9c, 0xcd, 0x67, 0xc7, + 0x0d, 0xf8, 0x64, 0x10, 0x9f, 0xe2, 0xa1, 0x9b, + 0x21, 0x90, 0xcc, 0xda, 0x8b, 0x76, 0x5e, 0x79, + 0x00, 0x9d, 0x58, 0x8b, 0x8a, 0xb3, 0xc3, 0xb5, + 0xf1, 0x54, 0xc5, 0x8c, 0x72, 0xba, 0xde, 0x51, + 0x3c, 0x6b, 0x94, 0xd6, 0xf3, 0x1b, 0xa2, 0x53, + 0xe6, 0x1a, 0x46, 0x1d, 0x7f, 0x14, 0x86, 0xcc, + 0xa6, 0x30, 0x92, 0x96, 0xc0, 0x96, 0x24, 0xf0, + 0x42, 0x53, 0x4c, 0xdd, 0x27, 0xdf, 0x1d, 0x2e, + 0x8b, 0x83, 0xbe, 0xed, 0x85, 0x1d, 0x50, 0x46, + 0xa3, 0x7d, 0x20, 0xea, 0x3e, 0x91, 0xfb, 0xf6, + 0x86, 0x51, 0xfd, 0x8c, 0xe5, 0x31, 0xe6, 0x7e, + 0x60, 0x08, 0x0e, 0xec, 0xa6, 0xea, 0x24, 0x8d}; + + /* RSA Known Signed Hash (1024-bits). */ + static const PRUint8 rsa_known_sha384_signature[] = { + 0x0b, 0x03, 0x94, 0x4f, 0x94, 0x78, 0x9b, 0x96, + 0x76, 0xeb, 0x72, 0x58, 0xe1, 0xc5, 0xc7, 0x5f, + 0x85, 0x01, 0xa8, 0xc4, 0xf6, 0x1a, 0xb5, 0x2c, + 0xd1, 0xd8, 0x87, 0xde, 0x3a, 0x9c, 0x9f, 0x57, + 0x81, 0x2a, 0x1e, 0x23, 0x07, 0x70, 0xb0, 0xf9, + 0x28, 0x3d, 0xfa, 0xe5, 0x2e, 0x1b, 0x9a, 0x72, + 0xc3, 0x74, 0xb3, 0x42, 0x1c, 0x9a, 0x13, 0xdc, + 0xc9, 0xd6, 0xd5, 0x88, 0xc9, 0x9c, 0x46, 0xf1, + 0x0c, 0xa6, 0xf7, 0xd8, 0x06, 0xa3, 0x1b, 0xdf, + 0x55, 0xb3, 0x1b, 0x7b, 0x58, 0x1d, 0xff, 0x19, + 0xc7, 0xe0, 0xdd, 0x59, 0xac, 0x2f, 0x78, 0x71, + 0xe7, 0xe0, 0x17, 0xa3, 0x1c, 0x5c, 0x92, 0xef, + 0xb6, 0x75, 0xed, 0xbe, 0x18, 0x39, 0x6b, 0xd7, + 0xc9, 0x08, 0x62, 0x55, 0x62, 0xac, 0x5d, 0xa1, + 0x9b, 0xd5, 0xb8, 0x98, 0x15, 0xc0, 0xf5, 0x41, + 0x85, 0x44, 0x96, 0xca, 0x10, 0xdc, 0x57, 0x21}; + + /* RSA Known Signed Hash (1024-bits). */ + static const PRUint8 rsa_known_sha512_signature[] = { + 0xa5, 0xd0, 0x80, 0x04, 0x22, 0xfc, 0x80, 0x73, + 0x7d, 0x46, 0xc8, 0x7b, 0xac, 0x44, 0x7b, 0xe6, + 0x07, 0xe5, 0x61, 0x4c, 0x33, 0x7f, 0x6f, 0x46, + 0x7c, 0x30, 0xe3, 0x75, 0x59, 0x4b, 0x42, 0xf3, + 0x9f, 0x35, 0x3c, 0x10, 0x56, 0xdb, 0xd2, 0x69, + 0x43, 0xcb, 0x77, 0xe9, 0x7d, 0xcd, 0x07, 0x43, + 0xc5, 0xd4, 0x0c, 0x9d, 0xf5, 0x92, 0xbd, 0x0e, + 0x3b, 0xb7, 0x68, 0x88, 0x84, 0xca, 0xae, 0x0d, + 0xab, 0x71, 0x10, 0xad, 0xab, 0x27, 0xe4, 0xa3, + 0x24, 0x41, 0xeb, 0x1c, 0xa6, 0x5f, 0xf1, 0x85, + 0xd0, 0xf6, 0x22, 0x74, 0x3d, 0x81, 0xbe, 0xdd, + 0x1b, 0x2a, 0x4c, 0xd1, 0x6c, 0xb5, 0x6d, 0x7a, + 0xbb, 0x99, 0x69, 0x01, 0xa6, 0xc0, 0x98, 0xfa, + 0x97, 0xa3, 0xd1, 0xb0, 0xdf, 0x09, 0xe3, 0x3d, + 0x88, 0xee, 0x90, 0xf3, 0x10, 0x41, 0x0f, 0x06, + 0x31, 0xe9, 0x60, 0x2d, 0xbf, 0x63, 0x7b, 0xf8}; + + static const RSAPublicKey bl_public_key = { NULL, + { FIPS_RSA_TYPE, (unsigned char *)rsa_modulus, + FIPS_RSA_MODULUS_LENGTH }, + { FIPS_RSA_TYPE, (unsigned char *)rsa_public_exponent, + FIPS_RSA_PUBLIC_EXPONENT_LENGTH } }; static const RSAPrivateKey bl_private_key = { NULL, - { FIPS_RSA_TYPE, (unsigned char *)rsa_version, FIPS_RSA_PRIVATE_VERSION_LENGTH }, - { FIPS_RSA_TYPE, (unsigned char *)rsa_modulus, FIPS_RSA_MODULUS_LENGTH }, - { FIPS_RSA_TYPE, (unsigned char *)rsa_public_exponent, FIPS_RSA_PUBLIC_EXPONENT_LENGTH }, - { FIPS_RSA_TYPE, (unsigned char *)rsa_private_exponent, FIPS_RSA_PRIVATE_EXPONENT_LENGTH }, - { FIPS_RSA_TYPE, (unsigned char *)rsa_prime0, FIPS_RSA_PRIME0_LENGTH }, - { FIPS_RSA_TYPE, (unsigned char *)rsa_prime1, FIPS_RSA_PRIME1_LENGTH }, - { FIPS_RSA_TYPE, (unsigned char *)rsa_exponent0, FIPS_RSA_EXPONENT0_LENGTH }, - { FIPS_RSA_TYPE, (unsigned char *)rsa_exponent1, FIPS_RSA_EXPONENT1_LENGTH }, - { FIPS_RSA_TYPE, (unsigned char *)rsa_coefficient, FIPS_RSA_COEFFICIENT_LENGTH } + { FIPS_RSA_TYPE, (unsigned char *)rsa_version, + FIPS_RSA_PRIVATE_VERSION_LENGTH }, + { FIPS_RSA_TYPE, (unsigned char *)rsa_modulus, + FIPS_RSA_MODULUS_LENGTH }, + { FIPS_RSA_TYPE, (unsigned char *)rsa_public_exponent, + FIPS_RSA_PUBLIC_EXPONENT_LENGTH }, + { FIPS_RSA_TYPE, (unsigned char *)rsa_private_exponent, + FIPS_RSA_PRIVATE_EXPONENT_LENGTH }, + { FIPS_RSA_TYPE, (unsigned char *)rsa_prime0, + FIPS_RSA_PRIME0_LENGTH }, + { FIPS_RSA_TYPE, (unsigned char *)rsa_prime1, + FIPS_RSA_PRIME1_LENGTH }, + { FIPS_RSA_TYPE, (unsigned char *)rsa_exponent0, + FIPS_RSA_EXPONENT0_LENGTH }, + { FIPS_RSA_TYPE, (unsigned char *)rsa_exponent1, + FIPS_RSA_EXPONENT1_LENGTH }, + { FIPS_RSA_TYPE, (unsigned char *)rsa_coefficient, + FIPS_RSA_COEFFICIENT_LENGTH } }; /* RSA variables. */ @@ -1170,14 +1383,12 @@ sftk_fips_RSA_PowerUpSelfTest( void ) #endif NSSLOWKEYPublicKey * rsa_public_key; NSSLOWKEYPrivateKey * rsa_private_key; - unsigned int rsa_bytes_signed; SECStatus rsa_status; NSSLOWKEYPublicKey low_public_key = { NULL, NSSLOWKEYRSAKey, }; NSSLOWKEYPrivateKey low_private_key = { NULL, NSSLOWKEYRSAKey, }; PRUint8 rsa_computed_ciphertext[FIPS_RSA_ENCRYPT_LENGTH]; PRUint8 rsa_computed_plaintext[FIPS_RSA_DECRYPT_LENGTH]; - PRUint8 rsa_computed_signature[FIPS_RSA_SIGNATURE_LENGTH]; /****************************************/ /* Compose RSA Public/Private Key Pair. */ @@ -1216,8 +1427,9 @@ sftk_fips_RSA_PowerUpSelfTest( void ) /**************************************************/ /* Perform RSA Public Key Encryption. */ - rsa_status = RSA_PublicKeyOp(&rsa_public_key->u.rsa, - rsa_computed_ciphertext, rsa_known_plaintext); + rsa_status = RSA_PublicKeyOp(&rsa_public_key->u.rsa, + rsa_computed_ciphertext, + rsa_known_plaintext_msg); if( ( rsa_status != SECSuccess ) || ( PORT_Memcmp( rsa_computed_ciphertext, rsa_known_ciphertext, @@ -1229,44 +1441,40 @@ sftk_fips_RSA_PowerUpSelfTest( void ) /**************************************************/ /* Perform RSA Private Key Decryption. */ - rsa_status = RSA_PrivateKeyOp(&rsa_private_key->u.rsa, - rsa_computed_plaintext, rsa_known_ciphertext); + rsa_status = RSA_PrivateKeyOp(&rsa_private_key->u.rsa, + rsa_computed_plaintext, + rsa_known_ciphertext); if( ( rsa_status != SECSuccess ) || - ( PORT_Memcmp( rsa_computed_plaintext, rsa_known_plaintext, + ( PORT_Memcmp( rsa_computed_plaintext, rsa_known_plaintext_msg, FIPS_RSA_DECRYPT_LENGTH ) != 0 ) ) goto rsa_loser; - - /*************************************************/ - /* RSA Single-Round Known Answer Signature Test. */ - /*************************************************/ - - /* Perform RSA signature with the RSA private key. */ - rsa_status = RSA_Sign( rsa_private_key, rsa_computed_signature, - &rsa_bytes_signed, - FIPS_RSA_SIGNATURE_LENGTH, - (unsigned char *)rsa_known_message, - FIPS_RSA_MESSAGE_LENGTH ); - - if( ( rsa_status != SECSuccess ) || - ( rsa_bytes_signed != FIPS_RSA_SIGNATURE_LENGTH ) || - ( PORT_Memcmp( rsa_computed_signature, rsa_known_signature, - FIPS_RSA_SIGNATURE_LENGTH ) != 0 ) ) + rsa_status = sftk_fips_RSA_PowerUpSigSelfTest (HASH_AlgSHA1, + rsa_public_key, rsa_private_key, + rsa_known_plaintext_msg, FIPS_RSA_MESSAGE_LENGTH, + rsa_known_sha1_signature); + if( rsa_status != SECSuccess ) goto rsa_loser; + rsa_status = sftk_fips_RSA_PowerUpSigSelfTest (HASH_AlgSHA256, + rsa_public_key, rsa_private_key, + rsa_known_plaintext_msg, FIPS_RSA_MESSAGE_LENGTH, + rsa_known_sha256_signature); + if( rsa_status != SECSuccess ) + goto rsa_loser; - /****************************************************/ - /* RSA Single-Round Known Answer Verification Test. */ - /****************************************************/ - - /* Perform RSA verification with the RSA public key. */ - rsa_status = RSA_CheckSign( rsa_public_key, - rsa_computed_signature, - FIPS_RSA_SIGNATURE_LENGTH, - (unsigned char *)rsa_known_message, - FIPS_RSA_MESSAGE_LENGTH ); + rsa_status = sftk_fips_RSA_PowerUpSigSelfTest (HASH_AlgSHA384, + rsa_public_key, rsa_private_key, + rsa_known_plaintext_msg, FIPS_RSA_MESSAGE_LENGTH, + rsa_known_sha384_signature); + if( rsa_status != SECSuccess ) + goto rsa_loser; + rsa_status = sftk_fips_RSA_PowerUpSigSelfTest (HASH_AlgSHA512, + rsa_public_key, rsa_private_key, + rsa_known_plaintext_msg, FIPS_RSA_MESSAGE_LENGTH, + rsa_known_sha512_signature); if( rsa_status != SECSuccess ) goto rsa_loser; @@ -1276,7 +1484,6 @@ sftk_fips_RSA_PowerUpSelfTest( void ) return( CKR_OK ); - rsa_loser: nsslowkey_DestroyPublicKey( rsa_public_key ); @@ -1285,6 +1492,162 @@ rsa_loser: return( CKR_DEVICE_ERROR ); } +#ifdef NSS_ENABLE_ECC +static CK_RV +sftk_fips_ECDSA_PowerUpSelfTest() { + + /* ECDSA Known info for curve nistp256 */ + static const PRUint8 ecdsa_publicValue[] = { + EC_POINT_FORM_UNCOMPRESSED, + 0x07, 0xb1, 0xcb, 0x57, 0x20, 0xa7, 0x10, 0xd6, + 0x9d, 0x37, 0x4b, 0x1c, 0xdc, 0x35, 0x90, 0xff, + 0x1a, 0x2d, 0x98, 0x95, 0x1b, 0x2f, 0xeb, 0x7f, + 0xbb, 0x81, 0xca, 0xc0, 0x69, 0x75, 0xea, 0xc5, + 0xb8, 0x03, 0xe6, 0x89, 0xe5, 0x06, 0x55, 0x22, + 0x21, 0x0e, 0xcd, 0x1a, 0xf8, 0xc0, 0xd4, 0xa7, + 0x8f, 0x47, 0x81, 0x1e, 0x4a, 0x81, 0xb5, 0x41, + 0x3d, 0xa1, 0xf0, 0x4b, 0x65, 0xb4, 0x26, 0xe9}; + + static const PRUint8 ecdsa_privateValue[] = { + 0x6a, 0x9b, 0xf6, 0xf7, 0xce, 0xed, 0x79, 0x11, + 0xf0, 0xc7, 0xc8, 0x9a, 0xa5, 0xd1, 0x57, 0xb1, + 0x7b, 0x5a, 0x3b, 0x76, 0x4e, 0x7b, 0x7c, 0xbc, + 0xf2, 0x76, 0x1c, 0x1c, 0x7f, 0xc5, 0x53, 0x2f}; + + static const PRUint8 ecdsa_version[] = { 0x01 }; + + static const PRUint8 ecdsa_known_P256_signature[] = { + 0xa8, 0x6f, 0x0a, 0x04, 0x6b, 0x6c, 0x47, 0x0c, + 0x5a, 0xfd, 0xc6, 0x9f, 0xab, 0x65, 0x1d, 0x21, + 0xa5, 0x8f, 0x0d, 0xe6, 0xac, 0xaa, 0x63, 0xb6, + 0x7a, 0x39, 0x62, 0x4c, 0xae, 0xa1, 0x50, 0xb7, + 0x30, 0xa9, 0x88, 0xeb, 0x44, 0x94, 0xb7, 0x1f, + 0x23, 0x35, 0xe3, 0x52, 0x13, 0xd3, 0x46, 0xd0, + 0x54, 0xfd, 0x43, 0xdc, 0x3b, 0x7f, 0xf5, 0x60, + 0x92, 0xcc, 0x43, 0x67, 0x8c, 0xc5, 0xea, 0x75}; + + /* ECDSA Known curve nistp256 params */ + static const PRUint8 knownEncodedParams[] = { + 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, + 0x01, 0x07}; + + static const PRUint8 ecdsa_Known_Seed[] = { + 0xe3, 0x2f, 0x50, 0x8d, 0xde, 0xd3, 0x55, 0x74, + 0xe7, 0x71, 0x86, 0x76, 0x3b, 0xeb, 0x84, 0x15, + 0x1b, 0x49, 0xf5, 0x18, 0xe5, 0x5f, 0x84, 0x7e, + 0x76, 0x16, 0x14, 0x4f, 0x79, 0x4f, 0xbb, 0xd6}; + + static const PRUint8 msg[] = { + "Firefox and ThunderBird are awesome!"}; + + unsigned char sha1[SHA1_LENGTH]; /* SHA-1 hash (160 bits) */ + unsigned char sig[2*MAX_ECKEY_LEN]; + SECItem signature, digest; + SECItem encodedparams; + ECParams *ecparams; + ECPrivateKey ecdsa_private_key; + ECPublicKey ecdsa_public_key; + SECStatus ecdsaStatus = SECSuccess; + + /* construct the ECDSA private/public key pair */ + encodedparams.type = siBuffer; + encodedparams.data = (unsigned char *) knownEncodedParams; + encodedparams.len = sizeof knownEncodedParams; + if (EC_DecodeParams(&encodedparams, &ecparams) != SECSuccess) { + return( CKR_DEVICE_ERROR ); + } + + ecdsa_private_key.ecParams.arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (ecdsa_private_key.ecParams.arena == NULL) { + PORT_FreeArena(ecparams->arena, PR_FALSE); + return CKR_HOST_MEMORY; + } + + ecdsaStatus = EC_CopyParams(ecdsa_private_key.ecParams.arena, + &ecdsa_private_key.ecParams, ecparams); + PORT_FreeArena(ecparams->arena, PR_FALSE); + + if (ecdsaStatus != SECSuccess) { + goto loser; + } + + ecdsa_private_key.publicValue.type = siBuffer; + ecdsa_private_key.publicValue.data = (unsigned char *)ecdsa_publicValue; + ecdsa_private_key.publicValue.len = sizeof ecdsa_publicValue; + + ecdsa_private_key.privateValue.type = siBuffer; + ecdsa_private_key.privateValue.data = (unsigned char *)ecdsa_privateValue; + ecdsa_private_key.privateValue.len = sizeof ecdsa_privateValue; + + ecdsa_private_key.version.type = siBuffer; + ecdsa_private_key.version.data = (unsigned char *)ecdsa_version; + ecdsa_private_key.version.len = sizeof ecdsa_version; + + /* validate public key value */ + ecdsaStatus = EC_ValidatePublicKey(&ecdsa_private_key.ecParams, + &ecdsa_private_key.publicValue); + if (ecdsaStatus != SECSuccess) { + goto loser; + } + + /***************************************************/ + /* ECDSA Single-Round Known Answer Signature Test. */ + /***************************************************/ + + ecdsaStatus = SHA1_HashBuf(sha1, msg, sizeof msg); + if (ecdsaStatus != SECSuccess) { + goto loser; + } + digest.type = siBuffer; + digest.data = sha1; + digest.len = SHA1_LENGTH; + + memset(sig, 0, sizeof sig); + signature.type = siBuffer; + signature.data = sig; + signature.len = sizeof sig; + + ecdsaStatus = ECDSA_SignDigestWithSeed(&ecdsa_private_key, &signature, + &digest, ecdsa_Known_Seed, sizeof ecdsa_Known_Seed); + if (ecdsaStatus != SECSuccess) { + goto loser; + } + + if( ( signature.len != sizeof ecdsa_known_P256_signature ) || + ( PORT_Memcmp( signature.data, ecdsa_known_P256_signature, + sizeof ecdsa_known_P256_signature ) != 0 ) ) { + ecdsaStatus = SECFailure; + goto loser; + } + + /* construct public key from private key. */ + ecdsaStatus = EC_CopyParams(ecdsa_private_key.ecParams.arena, + &ecdsa_public_key.ecParams, + &ecdsa_private_key.ecParams); + if (ecdsaStatus != SECSuccess) { + goto loser; + } + ecdsa_public_key.publicValue = ecdsa_private_key.publicValue; + + /******************************************************/ + /* ECDSA Single-Round Known Answer Verification Test. */ + /******************************************************/ + + /* Perform ECDSA verification process. */ + ecdsaStatus = ECDSA_VerifyDigest(&ecdsa_public_key, &signature, &digest); + +loser: + /* free the memory for the private */ + if (ecdsa_private_key.ecParams.arena != NULL) { + PORT_FreeArena(ecdsa_private_key.ecParams.arena, PR_FALSE); + } + + if (ecdsaStatus != SECSuccess) { + return CKR_DEVICE_ERROR ; + } + return( CKR_OK ); +} +#endif /* NSS_ENABLE_ECC */ static CK_RV sftk_fips_DSA_PowerUpSelfTest( void ) @@ -1487,6 +1850,14 @@ sftk_fipsPowerUpSelfTest( void ) if( rv != CKR_OK ) return rv; + +#ifdef NSS_ENABLE_ECC + /* ECDSA Power-Up SelfTest(s). */ + rv = sftk_fips_ECDSA_PowerUpSelfTest(); + + if( rv != CKR_OK ) + return rv; +#endif /* Passed Power-Up SelfTest(s). */ return( CKR_OK ); diff --git a/security/nss/lib/softoken/fipstokn.c b/security/nss/lib/softoken/fipstokn.c index 9ef144cb8..472b3cad0 100644 --- a/security/nss/lib/softoken/fipstokn.c +++ b/security/nss/lib/softoken/fipstokn.c @@ -55,9 +55,47 @@ #include "pcert.h" #include "pkcs11.h" #include "pkcs11i.h" +#include "prenv.h" +#include "prprf.h" #include <ctype.h> +#ifdef XP_UNIX +#define NSS_AUDIT_WITH_SYSLOG 1 +#include <syslog.h> +#include <unistd.h> +#endif + +#ifdef LINUX +#include <pthread.h> +#include <dlfcn.h> +#define LIBAUDIT_NAME "libaudit.so.0" +#ifndef AUDIT_USER +#define AUDIT_USER 1005 /* message type: message from userspace */ +#endif +static void *libaudit_handle; +static int (*audit_open_func)(void); +static void (*audit_close_func)(int fd); +static int (*audit_log_user_message_func)(int audit_fd, int type, + const char *message, const char *hostname, const char *addr, + const char *tty, int result); + +static pthread_once_t libaudit_once_control = PTHREAD_ONCE_INIT; + +static void +libaudit_init(void) +{ + libaudit_handle = dlopen(LIBAUDIT_NAME, RTLD_LAZY); + if (!libaudit_handle) { + return; + } + audit_open_func = dlsym(libaudit_handle, "audit_open"); + audit_close_func = dlsym(libaudit_handle, "audit_close"); + audit_log_user_message_func = dlsym(libaudit_handle, + "audit_log_user_message"); +} +#endif /* LINUX */ + /* * ******************** Password Utilities ******************************* @@ -251,6 +289,76 @@ fips_login_if_key_object(CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) return rv; } +/********************************************************************** + * + * FIPS 140 auditable event logging + * + **********************************************************************/ + +PRBool sftk_audit_enabled = PR_FALSE; + +/* + * Each audit record must have the following information: + * - Date and time of the event + * - Type of event + * - user (subject) identity + * - outcome (success or failure) of the event + * - process ID + * - name (ID) of the object + * - for changes to data (except for authentication data and CSPs), the new + * and old values of the data + * - for authentication attempts, the origin of the attempt (e.g., terminal + * identifier) + * - for assuming a role, the type of role, and the location of the request + */ +void +sftk_LogAuditMessage(NSSAuditSeverity severity, const char *msg) +{ +#ifdef NSS_AUDIT_WITH_SYSLOG + int level; + + switch (severity) { + case NSS_AUDIT_ERROR: + level = LOG_ERR; + break; + case NSS_AUDIT_WARNING: + level = LOG_WARNING; + break; + default: + level = LOG_INFO; + break; + } + /* timestamp is provided by syslog in the message header */ + syslog(level | LOG_USER /* facility */, + "NSS " SOFTOKEN_LIB_NAME "[pid=%d uid=%d]: %s", + (int)getpid(), (int)getuid(), msg); +#ifdef LINUX + if (pthread_once(&libaudit_once_control, libaudit_init) != 0) { + return; + } + if (libaudit_handle) { + int audit_fd; + int result = (severity != NSS_AUDIT_ERROR); /* 1=success; 0=failed */ + char *message = PR_smprintf("NSS " SOFTOKEN_LIB_NAME ": %s", msg); + if (!message) { + return; + } + audit_fd = audit_open_func(); + if (audit_fd < 0) { + PR_smprintf_free(message); + return; + } + audit_log_user_message_func(audit_fd, AUDIT_USER, message, + NULL, NULL, NULL, result); + audit_close_func(audit_fd); + PR_smprintf_free(message); + } +#endif /* LINUX */ +#else + /* do nothing */ +#endif +} + /********************************************************************** * @@ -268,12 +376,17 @@ PRBool nsf_init = PR_FALSE; /* FC_Initialize initializes the PKCS #11 library. */ CK_RV FC_Initialize(CK_VOID_PTR pReserved) { + const char *envp; CK_RV crv; if (nsf_init) { return CKR_CRYPTOKI_ALREADY_INITIALIZED; } + if ((envp = PR_GetEnv("NSS_ENABLE_AUDIT")) != NULL) { + sftk_audit_enabled = (atoi(envp) == 1); + } + crv = nsc_CommonInitialize(pReserved, PR_TRUE); /* not an 'else' rv can be set by either SFTK_LowInit or SFTK_SlotInit*/ @@ -288,6 +401,14 @@ CK_RV FC_Initialize(CK_VOID_PTR pReserved) { if (crv != CKR_OK) { nsc_CommonFinalize(NULL, PR_TRUE); fatalError = PR_TRUE; + if (sftk_audit_enabled) { + char msg[128]; + PR_snprintf(msg,sizeof msg, + "C_Initialize()=0x%08lX " + "self-test: cryptographic algorithm test failed", + (PRUint32)crv); + sftk_LogAuditMessage(NSS_AUDIT_ERROR, msg); + } return crv; } nsf_init = PR_TRUE; @@ -321,15 +442,7 @@ CK_RV FC_GetSlotList(CK_BBOOL tokenPresent, /* FC_GetSlotInfo obtains information about a particular slot in the system. */ CK_RV FC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { - - CK_RV crv; - - crv = NSC_GetSlotInfo(slotID,pInfo); - if (crv != CKR_OK) { - return crv; - } - - return CKR_OK; + return NSC_GetSlotInfo(slotID,pInfo); } @@ -369,7 +482,20 @@ CK_RV FC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { /* FC_InitToken initializes a token. */ CK_RV FC_InitToken(CK_SLOT_ID slotID,CK_CHAR_PTR pPin, CK_ULONG usPinLen,CK_CHAR_PTR pLabel) { - return NSC_InitToken(slotID,pPin,usPinLen,pLabel); + CK_RV crv; + + crv = NSC_InitToken(slotID,pPin,usPinLen,pLabel); + if (sftk_audit_enabled) { + char msg[128]; + NSSAuditSeverity severity = (crv == CKR_OK) ? + NSS_AUDIT_INFO : NSS_AUDIT_ERROR; + /* pLabel points to a 32-byte label, which is not null-terminated */ + PR_snprintf(msg,sizeof msg, + "C_InitToken(slotID=%lu, pLabel=\"%.32s\")=0x%08lX", + (PRUint32)slotID,pLabel,(PRUint32)crv); + sftk_LogAuditMessage(severity, msg); + } + return crv; } @@ -377,9 +503,20 @@ CK_RV FC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { CK_RV FC_InitPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pPin, CK_ULONG ulPinLen) { CK_RV rv; - SFTK_FIPSFATALCHECK(); - if ((rv = sftk_newPinCheck(pPin,ulPinLen)) != CKR_OK) return rv; - return NSC_InitPIN(hSession,pPin,ulPinLen); + if (fatalError) return CKR_DEVICE_ERROR; + if ((rv = sftk_newPinCheck(pPin,ulPinLen)) == CKR_OK) { + rv = NSC_InitPIN(hSession,pPin,ulPinLen); + } + if (sftk_audit_enabled) { + char msg[128]; + NSSAuditSeverity severity = (rv == CKR_OK) ? + NSS_AUDIT_INFO : NSS_AUDIT_ERROR; + PR_snprintf(msg,sizeof msg, + "C_InitPIN(hSession=%lu)=0x%08lX", + (PRUint32)hSession,(PRUint32)rv); + sftk_LogAuditMessage(severity, msg); + } + return rv; } @@ -388,9 +525,20 @@ CK_RV FC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { CK_RV FC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin, CK_ULONG usOldLen, CK_CHAR_PTR pNewPin, CK_ULONG usNewLen) { CK_RV rv; - if ((rv = sftk_fipsCheck()) != CKR_OK) return rv; - if ((rv = sftk_newPinCheck(pNewPin,usNewLen)) != CKR_OK) return rv; - return NSC_SetPIN(hSession,pOldPin,usOldLen,pNewPin,usNewLen); + if ((rv = sftk_fipsCheck()) == CKR_OK && + (rv = sftk_newPinCheck(pNewPin,usNewLen)) == CKR_OK) { + rv = NSC_SetPIN(hSession,pOldPin,usOldLen,pNewPin,usNewLen); + } + if (sftk_audit_enabled) { + char msg[128]; + NSSAuditSeverity severity = (rv == CKR_OK) ? + NSS_AUDIT_INFO : NSS_AUDIT_ERROR; + PR_snprintf(msg,sizeof msg, + "C_SetPIN(hSession=%lu)=0x%08lX", + (PRUint32)hSession,(PRUint32)rv); + sftk_LogAuditMessage(severity, msg); + } + return rv; } /* FC_OpenSession opens a session between an application and a token. */ @@ -435,7 +583,7 @@ CK_RV FC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { CK_RV FC_Login(CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_CHAR_PTR pPin, CK_ULONG usPinLen) { CK_RV rv; - SFTK_FIPSFATALCHECK(); + if (fatalError) return CKR_DEVICE_ERROR; rv = NSC_Login(hSession,userType,pPin,usPinLen); if (rv == CKR_OK) isLoggedIn = PR_TRUE; @@ -443,22 +591,50 @@ CK_RV FC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { { isLoggedIn = PR_TRUE; - /* Provide FIPS PUB 140-1 power-up self-tests on demand. */ + /* Provide FIPS PUB 140-2 power-up self-tests on demand. */ rv = sftk_fipsPowerUpSelfTest(); if (rv == CKR_OK) - return CKR_USER_ALREADY_LOGGED_IN; + rv = CKR_USER_ALREADY_LOGGED_IN; else fatalError = PR_TRUE; } + if (sftk_audit_enabled) { + char msg[128]; + NSSAuditSeverity severity; + if (fatalError) { + severity = NSS_AUDIT_ERROR; + PR_snprintf(msg,sizeof msg, + "C_Login(hSession=%lu, userType=%lu)=0x%08lX ", + "self-test: cryptographic algorithm test failed", + (PRUint32)hSession,(PRUint32)userType,(PRUint32)rv); + } else { + severity = (rv == CKR_OK || rv == CKR_USER_ALREADY_LOGGED_IN) ? + NSS_AUDIT_INFO : NSS_AUDIT_ERROR; + PR_snprintf(msg,sizeof msg, + "C_Login(hSession=%lu, userType=%lu)=0x%08lX", + (PRUint32)hSession,(PRUint32)userType,(PRUint32)rv); + } + sftk_LogAuditMessage(severity, msg); + } return rv; } /* FC_Logout logs a user out from a token. */ CK_RV FC_Logout(CK_SESSION_HANDLE hSession) { - SFTK_FIPSCHECK(); - - rv = NSC_Logout(hSession); - isLoggedIn = PR_FALSE; + CK_RV rv; + if ((rv = sftk_fipsCheck()) == CKR_OK) { + rv = NSC_Logout(hSession); + isLoggedIn = PR_FALSE; + } + if (sftk_audit_enabled) { + char msg[128]; + NSSAuditSeverity severity = (rv == CKR_OK) ? + NSS_AUDIT_INFO : NSS_AUDIT_ERROR; + PR_snprintf(msg,sizeof msg, + "C_Logout(hSession=%lu)=0x%08lX", + (PRUint32)hSession,(PRUint32)rv); + sftk_LogAuditMessage(severity, msg); + } return rv; } @@ -982,13 +1158,23 @@ CK_RV FC_GetSlotInfo(CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { /* FC_GenerateRandom generates random data. */ CK_RV FC_GenerateRandom(CK_SESSION_HANDLE hSession, - CK_BYTE_PTR pRandomData, CK_ULONG usRandomLen) { + CK_BYTE_PTR pRandomData, CK_ULONG ulRandomLen) { CK_RV crv; SFTK_FIPSFATALCHECK(); - crv = NSC_GenerateRandom(hSession,pRandomData,usRandomLen); + crv = NSC_GenerateRandom(hSession,pRandomData,ulRandomLen); if (crv != CKR_OK) { fatalError = PR_TRUE; + if (sftk_audit_enabled) { + char msg[128]; + PR_snprintf(msg,sizeof msg, + "C_GenerateRandom(hSession=%lu, pRandomData=%p, " + "ulRandomLen=%lu)=0x%08lX " + "self-test: continuous RNG test failed", + (PRUint32)hSession,pRandomData, + (PRUint32)ulRandomLen,(PRUint32)crv); + sftk_LogAuditMessage(NSS_AUDIT_ERROR, msg); + } } return crv; } diff --git a/security/nss/lib/softoken/keydb.c b/security/nss/lib/softoken/keydb.c index 2f685a5a6..5dca43f40 100644 --- a/security/nss/lib/softoken/keydb.c +++ b/security/nss/lib/softoken/keydb.c @@ -52,12 +52,8 @@ #include "nsslocks.h" #include "keydbi.h" +#include "softoken.h" -#ifdef NSS_ENABLE_ECC -extern SECStatus EC_FillParams(PRArenaPool *arena, - const SECItem *encodedParams, - ECParams *params); -#endif /* * Record keys for keydb @@ -2046,6 +2042,9 @@ seckey_decrypt_private_key(NSSLOWKEYEncryptedPrivateKeyInfo *epki, rv = EC_FillParams(permarena, &pk->u.ec.ecParams.DEREncoding, &pk->u.ec.ecParams); + if (rv != SECSuccess) + goto loser; + /* * NOTE: Encoding of the publicValue is optional * so we need to be able to regenerate the publicValue diff --git a/security/nss/lib/softoken/lowcert.c b/security/nss/lib/softoken/lowcert.c index cb048307d..008687e52 100644 --- a/security/nss/lib/softoken/lowcert.c +++ b/security/nss/lib/softoken/lowcert.c @@ -51,12 +51,8 @@ #include "secasn1.h" #include "secoid.h" #include "secerr.h" +#include "softoken.h" -#ifdef NSS_ENABLE_ECC -extern SECStatus EC_FillParams(PRArenaPool *arena, - const SECItem *encodedParams, - ECParams *params); -#endif static const SEC_ASN1Template nsslowcert_SubjectPublicKeyInfoTemplate[] = { { SEC_ASN1_SEQUENCE, 0, NULL, sizeof(NSSLOWCERTSubjectPublicKeyInfo) }, diff --git a/security/nss/lib/softoken/lowkey.c b/security/nss/lib/softoken/lowkey.c index fb6e30fdc..9c984b4d3 100644 --- a/security/nss/lib/softoken/lowkey.c +++ b/security/nss/lib/softoken/lowkey.c @@ -295,7 +295,6 @@ nsslowkey_ConvertToPublicKey(NSSLOWKEYPrivateKey *privk) if (rv == SECSuccess) return pubk; } - nsslowkey_DestroyPublicKey (pubk); } else { PORT_SetError (SEC_ERROR_NO_MEMORY); } diff --git a/security/nss/lib/softoken/lowpbe.c b/security/nss/lib/softoken/lowpbe.c index 81a0cb06b..b73485948 100644 --- a/security/nss/lib/softoken/lowpbe.c +++ b/security/nss/lib/softoken/lowpbe.c @@ -546,13 +546,15 @@ loser: PORT_FreeArena(arena, PR_TRUE); } - /* if i != c, then we didn't complete the loop above and must of failed - * somwhere along the way */ - if (i != c) { - SECITEM_ZfreeItem(A,PR_TRUE); - A = NULL; - } else { - A->len = bytesNeeded; + if (A) { + /* if i != c, then we didn't complete the loop above and must of failed + * somwhere along the way */ + if (i != c) { + SECITEM_ZfreeItem(A,PR_TRUE); + A = NULL; + } else { + A->len = bytesNeeded; + } } return A; @@ -634,7 +636,7 @@ nsspkcs5_ComputeKeyAndIV(NSSPKCS5PBEParameter *pbe_param, SECItem *pwitem, PORT_Memcpy(key->data, hash->data, key->len); } - SECITEM_FreeItem(hash, PR_TRUE); + SECITEM_ZfreeItem(hash, PR_TRUE); return key; loser: diff --git a/security/nss/lib/softoken/manifest.mn b/security/nss/lib/softoken/manifest.mn index 52d1f75cd..294bd0b49 100644 --- a/security/nss/lib/softoken/manifest.mn +++ b/security/nss/lib/softoken/manifest.mn @@ -59,6 +59,11 @@ EXPORTS = \ PRIVATE_EXPORTS = \ pk11pars.h \ pkcs11ni.h \ + lowkeyi.h \ + lowkeyti.h \ + pcertt.h \ + softoken.h \ + softoknt.h \ $(NULL) CSRCS = \ diff --git a/security/nss/lib/softoken/pcert.h b/security/nss/lib/softoken/pcert.h index a808373d8..d4314f634 100644 --- a/security/nss/lib/softoken/pcert.h +++ b/security/nss/lib/softoken/pcert.h @@ -41,9 +41,16 @@ #include "prlong.h" #include "pcertt.h" +#include "lowkeyti.h" /* for struct NSSLOWKEYPublicKeyStr */ + SEC_BEGIN_PROTOS /* + * initialize any global certificate locks + */ +SECStatus nsslowcert_InitLocks(void); + +/* ** Add a DER encoded certificate to the permanent database. ** "derCert" is the DER encoded certificate. ** "nickname" is the nickname to use for the cert @@ -244,6 +251,11 @@ pkcs11_copyStaticData(unsigned char *data, int datalen, unsigned char *space, int spaceLen); NSSLOWCERTCertificate * nsslowcert_CreateCert(void); + +certDBEntry * +nsslowcert_DecodeAnyDBEntry(SECItem *dbData, SECItem *dbKey, + certDBEntryType entryType, void *pdata); + SEC_END_PROTOS #endif /* _PCERTDB_H_ */ diff --git a/security/nss/lib/softoken/pcertdb.c b/security/nss/lib/softoken/pcertdb.c index 4a7706378..7455602a1 100644 --- a/security/nss/lib/softoken/pcertdb.c +++ b/security/nss/lib/softoken/pcertdb.c @@ -91,6 +91,9 @@ static int entryListCount = 0; * a global lock to make the database thread safe. */ static PZLock *dbLock = NULL; +static PZLock *certRefCountLock = NULL; +static PZLock *certTrustLock = NULL; +static PZLock *freeListLock = NULL; void certdb_InitDBLock(NSSLOWCERTCertDBHandle *handle) @@ -99,8 +102,31 @@ certdb_InitDBLock(NSSLOWCERTCertDBHandle *handle) nss_InitLock(&dbLock, nssILockCertDB); PORT_Assert(dbLock != NULL); } +} - return; +SECStatus +nsslowcert_InitLocks(void) +{ + if (freeListLock == NULL) { + nss_InitLock(&freeListLock, nssILockRefLock); + if (freeListLock == NULL) { + return SECFailure; + } + } + if (certRefCountLock == NULL) { + nss_InitLock(&certRefCountLock, nssILockRefLock); + if (certRefCountLock == NULL) { + return SECFailure; + } + } + if (certTrustLock == NULL ) { + nss_InitLock(&certTrustLock, nssILockCertDB); + if (certTrustLock == NULL) { + return SECFailure; + } + } + + return SECSuccess; } /* @@ -133,7 +159,6 @@ nsslowcert_UnlockDB(NSSLOWCERTCertDBHandle *handle) return; } -static PZLock *certRefCountLock = NULL; /* * Acquire the cert reference count lock @@ -144,10 +169,7 @@ static PZLock *certRefCountLock = NULL; static void nsslowcert_LockCertRefCount(NSSLOWCERTCertificate *cert) { - if ( certRefCountLock == NULL ) { - nss_InitLock(&certRefCountLock, nssILockRefLock); - PORT_Assert(certRefCountLock != NULL); - } + PORT_Assert(certRefCountLock != NULL); PZ_Lock(certRefCountLock); return; @@ -170,8 +192,6 @@ nsslowcert_UnlockCertRefCount(NSSLOWCERTCertificate *cert) return; } -static PZLock *certTrustLock = NULL; - /* * Acquire the cert trust lock * There is currently one global lock for all certs, but I'm putting a cert @@ -181,11 +201,8 @@ static PZLock *certTrustLock = NULL; void nsslowcert_LockCertTrust(NSSLOWCERTCertificate *cert) { - if ( certTrustLock == NULL ) { - nss_InitLock(&certTrustLock, nssILockCertDB); - PORT_Assert(certTrustLock != NULL); - } - + PORT_Assert(certTrustLock != NULL); + PZ_Lock(certTrustLock); return; } @@ -207,7 +224,6 @@ nsslowcert_UnlockCertTrust(NSSLOWCERTCertificate *cert) return; } -static PZLock *freeListLock = NULL; /* * Acquire the cert reference count lock @@ -218,10 +234,7 @@ static PZLock *freeListLock = NULL; static void nsslowcert_LockFreeList(void) { - if ( freeListLock == NULL ) { - nss_InitLock(&freeListLock, nssILockRefLock); - PORT_Assert(freeListLock != NULL); - } + PORT_Assert(freeListLock != NULL); PZ_Lock(freeListLock); return; @@ -825,8 +838,7 @@ NewDBCertEntry(SECItem *derCert, char *nickname, goto loser; } - entry = (certDBEntryCert *)PORT_ArenaZAlloc(arena, sizeof(certDBEntryCert)); - + entry = PORT_ArenaZNew(arena, certDBEntryCert); if ( entry == NULL ) { goto loser; } @@ -917,21 +929,6 @@ DecodeV4DBCertEntry(unsigned char *buf, int len) goto loser; } - entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, certlen); - if ( !entry->derCert.data ) { - goto loser; - } - entry->derCert.len = certlen; - - if ( nnlen ) { - entry->nickname = (char *) PORT_ArenaAlloc(arena, nnlen); - if ( !entry->nickname ) { - goto loser; - } - } else { - entry->nickname = 0; - } - entry->common.arena = arena; entry->common.version = CERT_DB_FILE_VERSION; entry->common.type = certDBEntryTypeCert; @@ -940,11 +937,25 @@ DecodeV4DBCertEntry(unsigned char *buf, int len) entry->trust.emailFlags = buf[1]; entry->trust.objectSigningFlags = buf[2]; + entry->derCert.data = (unsigned char *)PORT_ArenaAlloc(arena, certlen); + if ( !entry->derCert.data ) { + goto loser; + } + entry->derCert.len = certlen; PORT_Memcpy(entry->derCert.data, &buf[DBCERT_V4_HEADER_LEN], certlen); - PORT_Memcpy(entry->nickname, &buf[DBCERT_V4_HEADER_LEN + certlen], nnlen); - if (PORT_Strcmp(entry->nickname,"Server-Cert") == 0) { - entry->trust.sslFlags |= CERTDB_USER; + if ( nnlen ) { + entry->nickname = (char *) PORT_ArenaAlloc(arena, nnlen); + if ( !entry->nickname ) { + goto loser; + } + PORT_Memcpy(entry->nickname, &buf[DBCERT_V4_HEADER_LEN + certlen], nnlen); + + if (PORT_Strcmp(entry->nickname, "Server-Cert") == 0) { + entry->trust.sslFlags |= CERTDB_USER; + } + } else { + entry->nickname = 0; } return(entry); @@ -1056,7 +1067,7 @@ CreateCertEntry(void) return entry; } - return PORT_ZAlloc(sizeof(certDBEntryCert)); + return PORT_ZNew(certDBEntryCert); } static void @@ -1121,9 +1132,8 @@ loser: pkcs11_freeStaticData(dbkey.data,buf); dbkey.data = NULL; if ( entry ) { - + DestroyDBEntry((certDBEntry *)entry); } - DestroyDBEntry((certDBEntry *)entry); return(NULL); } @@ -1245,9 +1255,7 @@ NewDBCrlEntry(SECItem *derCrl, char * url, certDBEntryType crlType, int flags) goto loser; } - entry = (certDBEntryRevocation*) - PORT_ArenaZAlloc(arena, sizeof(certDBEntryRevocation)); - + entry = PORT_ArenaZNew(arena, certDBEntryRevocation); if ( entry == NULL ) { goto loser; } @@ -1457,7 +1465,6 @@ EncodeDBNicknameEntry(certDBEntryNickname *entry, PRArenaPool *arena, dbitem->data = (unsigned char *)PORT_ArenaAlloc(arena, dbitem->len); if ( dbitem->data == NULL) { - PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; } @@ -2709,11 +2716,9 @@ nsslowcert_UpdateSubjectEmailAddr(NSSLOWCERTCertDBHandle *dbhandle, goto loser; } - if ( entry->emailAddrs ) { - for (i=0; i < (int)(entry->nemailAddrs); i++) { - if (PORT_Strcmp(entry->emailAddrs[i],emailAddr) == 0) { - index = i; - } + for (i=0; i < (int)(entry->nemailAddrs); i++) { + if (PORT_Strcmp(entry->emailAddrs[i],emailAddr) == 0) { + index = i; } } @@ -2755,7 +2760,7 @@ nsslowcert_UpdateSubjectEmailAddr(NSSLOWCERTCertDBHandle *dbhandle, /* write the new one */ rv = WriteDBSubjectEntry(dbhandle, entry); if ( rv != SECSuccess ) { - goto loser; + goto loser; } DestroyDBEntry((certDBEntry *)entry); @@ -2794,8 +2799,7 @@ AddNicknameToSubject(NSSLOWCERTCertDBHandle *dbhandle, goto loser; } - entry->nickname = (nickname) ? - PORT_ArenaStrdup(entry->common.arena, nickname) : NULL; + entry->nickname = PORT_ArenaStrdup(entry->common.arena, nickname); if ( entry->nickname == NULL ) { goto loser; @@ -2876,8 +2880,7 @@ ReadDBVersionEntry(NSSLOWCERTCertDBHandle *handle) goto loser; } - entry = (certDBEntryVersion *)PORT_ArenaAlloc(arena, - sizeof(certDBEntryVersion)); + entry = PORT_ArenaZNew(arena, certDBEntryVersion); if ( entry == NULL ) { PORT_SetError(SEC_ERROR_NO_MEMORY); goto loser; @@ -3070,6 +3073,7 @@ AddPermSubjectNode(certDBEntrySubject *entry, NSSLOWCERTCertificate *cert, } if ( nsslowcert_IsNewer(cert, cmpcert) ) { + nsslowcert_DestroyCertificate(cmpcert); /* insert before cmpcert */ rv = SECITEM_CopyItem(entry->common.arena, &newCertKeys[new_i], &cert->certKey); @@ -3097,6 +3101,7 @@ AddPermSubjectNode(certDBEntrySubject *entry, NSSLOWCERTCertificate *cert, added = PR_TRUE; break; } + nsslowcert_DestroyCertificate(cmpcert); /* copy this cert entry */ newCertKeys[new_i] = entry->certKeys[i]; newKeyIDs[new_i] = entry->keyIDs[i]; @@ -3849,6 +3854,8 @@ UpdateV5DB(NSSLOWCERTCertDBHandle *handle, DB *updatedb) updatehandle.permCertDB = updatedb; updatehandle.dbMon = PZ_NewMonitor(nssILockCertDB); + updatehandle.dbVerify = 0; + updatehandle.ref = 1; /* prevent premature close */ rv = nsslowcert_TraversePermCerts(&updatehandle, updateV5Callback, (void *)handle); @@ -4298,7 +4305,8 @@ nsslowcert_TraverseDBEntries(NSSLOWCERTCertDBHandle *handle, keybuf = (unsigned char *)key.data; keyitem.data = &keybuf[SEC_DB_KEY_HEADER_LEN]; keyitem.type = siBuffer; - + /* type should equal keybuf[0]. */ + rv = (* callback)(&dataitem, &keyitem, type, udata); if ( rv != SECSuccess ) { return(rv); @@ -4352,7 +4360,7 @@ CreateTrust(void) return trust; } - return PORT_ZAlloc(sizeof(NSSLOWCERTTrust)); + return PORT_ZNew(NSSLOWCERTTrust); } static void @@ -5079,7 +5087,7 @@ nsslowcert_CreateCert(void) if (cert) { return cert; } - return (NSSLOWCERTCertificate *) PORT_ZAlloc(sizeof(NSSLOWCERTCertificate)); + return PORT_ZNew(NSSLOWCERTCertificate); } static void @@ -5106,6 +5114,9 @@ nsslowcert_DestroyTrust(NSSLOWCERTTrust *trust) if ( entry ) { DestroyDBEntry((certDBEntry *)entry); } + if (trust->dbhandle) { + sftk_freeCertDB(trust->dbhandle); + } pkcs11_freeStaticData(trust->dbKey.data,trust->dbKeySpace); PORT_Memset(trust, 0, sizeof(*trust)); @@ -5338,9 +5349,6 @@ nsslowcert_SaveSMimeProfile(NSSLOWCERTCertDBHandle *dbhandle, char *emailAddr, return(rv); } -/* If the freeListLock doesn't exist when this function is called, -** this function will create it, use it 3 times, and delete it. -*/ void nsslowcert_DestroyFreeLists(void) { @@ -5368,3 +5376,77 @@ nsslowcert_DestroyGlobalLocks(void) } } +certDBEntry * +nsslowcert_DecodeAnyDBEntry(SECItem *dbData, SECItem *dbKey, + certDBEntryType entryType, void *pdata) +{ + PLArenaPool *arena = NULL; + certDBEntry *entry; + SECStatus rv; + SECItem dbEntry; + + + if ((dbData->len < SEC_DB_ENTRY_HEADER_LEN) || (dbKey->len == 0)) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + goto loser; + } + dbEntry.data = &dbData->data[SEC_DB_ENTRY_HEADER_LEN]; + dbEntry.len = dbData->len - SEC_DB_ENTRY_HEADER_LEN; + + arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); + if (arena == NULL) { + goto loser; + } + entry = PORT_ArenaZNew(arena, certDBEntry); + if (!entry) + goto loser; + + entry->common.version = (unsigned int)dbData->data[0]; + entry->common.flags = (unsigned int)dbData->data[2]; + entry->common.type = entryType; + entry->common.arena = arena; + + switch (entryType) { + case certDBEntryTypeContentVersion: /* This type appears to be unused */ + case certDBEntryTypeVersion: /* This type has only the common hdr */ + rv = SECSuccess; + break; + + case certDBEntryTypeSubject: + rv = DecodeDBSubjectEntry(&entry->subject, &dbEntry, dbKey); + break; + + case certDBEntryTypeNickname: + rv = DecodeDBNicknameEntry(&entry->nickname, &dbEntry, + (char *)dbKey->data); + break; + + /* smime profiles need entries created after the certs have + * been imported, loop over them in a second run */ + case certDBEntryTypeSMimeProfile: + rv = DecodeDBSMimeEntry(&entry->smime, &dbEntry, (char *)dbKey->data); + break; + + case certDBEntryTypeCert: + rv = DecodeDBCertEntry(&entry->cert, &dbEntry); + break; + + case certDBEntryTypeKeyRevocation: + case certDBEntryTypeRevocation: + rv = DecodeDBCrlEntry(&entry->revocation, &dbEntry); + break; + + default: + PORT_SetError(SEC_ERROR_INVALID_ARGS); + rv = SECFailure; + } + + if (rv == SECSuccess) + return entry; + +loser: + if (arena) + PORT_FreeArena(arena, PR_FALSE); + return NULL; +} + diff --git a/security/nss/lib/softoken/pcertt.h b/security/nss/lib/softoken/pcertt.h index e805950e1..848fe69e9 100644 --- a/security/nss/lib/softoken/pcertt.h +++ b/security/nss/lib/softoken/pcertt.h @@ -410,12 +410,14 @@ typedef struct { #define SEC_DB_CONTENT_VERSION_KEY_LEN sizeof(SEC_DB_CONTENT_VERSION_KEY) typedef union { - certDBEntryCommon common; - certDBEntryVersion version; - certDBEntryCert cert; - certDBEntryNickname nickname; - certDBEntrySubject subject; - certDBEntryRevocation revocation; + certDBEntryCommon common; + certDBEntryCert cert; + certDBEntryContentVersion content; + certDBEntryNickname nickname; + certDBEntryRevocation revocation; + certDBEntrySMime smime; + certDBEntrySubject subject; + certDBEntryVersion version; } certDBEntry; /* length of the fixed part of a database entry */ diff --git a/security/nss/lib/softoken/pk11db.c b/security/nss/lib/softoken/pk11db.c index c1d649b35..30584c91e 100644 --- a/security/nss/lib/softoken/pk11db.c +++ b/security/nss/lib/softoken/pk11db.c @@ -891,7 +891,7 @@ secmod_ReadPermDB(const char *appName, const char *filename, newModuleList = (char **)PORT_Realloc(moduleList,useCount*sizeof(char *)); if (newModuleList == NULL) goto done; - moduleList = newModuleList; + moduleList = newModuleList; PORT_Memset(&moduleList[moduleCount+1],0, sizeof(char *)*SECMOD_STEP); } diff --git a/security/nss/lib/softoken/pkcs11.c b/security/nss/lib/softoken/pkcs11.c index 10a7bcfb7..39ef7de02 100644 --- a/security/nss/lib/softoken/pkcs11.c +++ b/security/nss/lib/softoken/pkcs11.c @@ -67,9 +67,8 @@ #include "keydbi.h" -#ifdef NSS_ENABLE_ECC -extern SECStatus EC_FillParams(PRArenaPool *arena, - const SECItem *encodedParams, ECParams *params); +#ifdef DEBUG +#include "cdbhdl.h" #endif /* @@ -77,7 +76,7 @@ extern SECStatus EC_FillParams(PRArenaPool *arena, */ /* The next three strings must be exactly 32 characters long */ -static char *manufacturerID = "mozilla.org "; +static char *manufacturerID = "Mozilla Foundation "; static char manufacturerID_space[33]; static char *libraryDescription = "NSS Internal Crypto Services "; static char libraryDescription_space[33]; @@ -1228,6 +1227,7 @@ sftk_handlePrivateKeyObject(SFTKSession *session,SFTKObject *object,CK_KEY_TYPE { CK_BBOOL cktrue = CK_TRUE; CK_BBOOL encrypt = CK_TRUE; + CK_BBOOL sign = CK_FALSE; CK_BBOOL recover = CK_TRUE; CK_BBOOL wrap = CK_TRUE; CK_BBOOL derive = CK_FALSE; @@ -1268,15 +1268,18 @@ sftk_handlePrivateKeyObject(SFTKSession *session,SFTKObject *object,CK_KEY_TYPE sftk_item_expand(&mod)); if (mod.data) PORT_Free(mod.data); if (crv != CKR_OK) return crv; - + + sign = CK_TRUE; break; case CKK_DSA: if ( !sftk_hasAttribute(object, CKA_SUBPRIME)) { return CKR_TEMPLATE_INCOMPLETE; } - if ( !sftk_hasAttribute(object, CKA_NETSCAPE_DB)) { + if (sftk_isTrue(object,CKA_TOKEN) && + !sftk_hasAttribute(object, CKA_NETSCAPE_DB)) { return CKR_TEMPLATE_INCOMPLETE; } + sign = CK_TRUE; /* fall through */ case CKK_DH: if ( !sftk_hasAttribute(object, CKA_PRIME)) { @@ -1300,10 +1303,12 @@ sftk_handlePrivateKeyObject(SFTKSession *session,SFTKObject *object,CK_KEY_TYPE if ( !sftk_hasAttribute(object, CKA_VALUE)) { return CKR_TEMPLATE_INCOMPLETE; } - if ( !sftk_hasAttribute(object, CKA_NETSCAPE_DB)) { + if (sftk_isTrue(object,CKA_TOKEN) && + !sftk_hasAttribute(object, CKA_NETSCAPE_DB)) { return CKR_TEMPLATE_INCOMPLETE; } encrypt = CK_FALSE; + sign = CK_TRUE; recover = CK_FALSE; wrap = CK_FALSE; derive = CK_TRUE; @@ -1320,7 +1325,7 @@ sftk_handlePrivateKeyObject(SFTKSession *session,SFTKObject *object,CK_KEY_TYPE if (crv != CKR_OK) return crv; crv = sftk_defaultAttribute(object,CKA_DECRYPT,&encrypt,sizeof(CK_BBOOL)); if (crv != CKR_OK) return crv; - crv = sftk_defaultAttribute(object,CKA_SIGN,&cktrue,sizeof(CK_BBOOL)); + crv = sftk_defaultAttribute(object,CKA_SIGN,&sign,sizeof(CK_BBOOL)); if (crv != CKR_OK) return crv; crv = sftk_defaultAttribute(object,CKA_SIGN_RECOVER,&recover, sizeof(CK_BBOOL)); @@ -1952,7 +1957,10 @@ NSSLOWKEYPublicKey *sftk_GetPubKey(SFTKObject *object,CK_KEY_TYPE key_type, * based on the encoded params */ if (EC_FillParams(arena, &pubKey->u.ec.ecParams.DEREncoding, - &pubKey->u.ec.ecParams) != SECSuccess) break; + &pubKey->u.ec.ecParams) != SECSuccess) { + crv = CKR_DOMAIN_PARAMS_INVALID; + break; + } crv = sftk_Attribute2SSecItem(arena,&pubKey->u.ec.publicValue, object,CKA_EC_POINT); @@ -2045,9 +2053,12 @@ sftk_mkPrivKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp) crv = sftk_Attribute2SSecItem(arena,&privKey->u.dsa.privateValue, object,CKA_VALUE); if (crv != CKR_OK) break; - crv = sftk_Attribute2SSecItem(arena,&privKey->u.dsa.publicValue, - object,CKA_NETSCAPE_DB); - /* can't set the public value.... */ + if (sftk_hasAttribute(object,CKA_NETSCAPE_DB)) { + crv = sftk_Attribute2SSecItem(arena, &privKey->u.dsa.publicValue, + object,CKA_NETSCAPE_DB); + /* privKey was zero'd so public value is already set to NULL, 0 + * if we don't set it explicitly */ + } break; case CKK_DH: @@ -2061,8 +2072,12 @@ sftk_mkPrivKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp) crv = sftk_Attribute2SSecItem(arena,&privKey->u.dh.privateValue, object,CKA_VALUE); if (crv != CKR_OK) break; - crv = sftk_Attribute2SSecItem(arena,&privKey->u.dh.publicValue, - object,CKA_NETSCAPE_DB); + if (sftk_hasAttribute(object,CKA_NETSCAPE_DB)) { + crv = sftk_Attribute2SSecItem(arena, &privKey->u.dh.publicValue, + object,CKA_NETSCAPE_DB); + /* privKey was zero'd so public value is already set to NULL, 0 + * if we don't set it explicitly */ + } break; #ifdef NSS_ENABLE_ECC @@ -2077,13 +2092,20 @@ sftk_mkPrivKey(SFTKObject *object, CK_KEY_TYPE key_type, CK_RV *crvp) * based on the encoded params */ if (EC_FillParams(arena, &privKey->u.ec.ecParams.DEREncoding, - &privKey->u.ec.ecParams) != SECSuccess) break; + &privKey->u.ec.ecParams) != SECSuccess) { + crv = CKR_DOMAIN_PARAMS_INVALID; + break; + } crv = sftk_Attribute2SSecItem(arena,&privKey->u.ec.privateValue, object,CKA_VALUE); if (crv != CKR_OK) break; - crv = sftk_Attribute2SSecItem(arena, &privKey->u.ec.publicValue, + if (sftk_hasAttribute(object,CKA_NETSCAPE_DB)) { + crv = sftk_Attribute2SSecItem(arena, &privKey->u.ec.publicValue, object,CKA_NETSCAPE_DB); - if (crv != CKR_OK) break; + if (crv != CKR_OK) break; + /* privKey was zero'd so public value is already set to NULL, 0 + * if we don't set it explicitly */ + } rv = DER_SetUInteger(privKey->arena, &privKey->u.ec.version, NSSLOWKEY_EC_PRIVATE_KEY_VERSION); if (rv != SECSuccess) crv = CKR_HOST_MEMORY; @@ -2333,7 +2355,7 @@ sftk_getDefTokName(CK_SLOT_ID slotID) case PRIVATE_KEY_SLOT_ID: return "NSS Certificate DB "; case FIPS_SLOT_ID: - return "NSS FIPS-140-1 Certificate DB "; + return "NSS FIPS 140-2 Certificate DB "; default: break; } @@ -2355,7 +2377,7 @@ sftk_getDefSlotName(CK_SLOT_ID slotID) "NSS User Private Key and Certificate Services "; case FIPS_SLOT_ID: return - "Netscape FIPS-140-1 User Private Key Services "; + "NSS FIPS 140-2 User Private Key Services "; default: break; } @@ -2756,9 +2778,11 @@ sftk_DBShutdown(SFTKSlot *slot) slot->keyDB = NULL; PZ_Unlock(slot->slotLock); if (certHandle) { + PORT_Assert(certHandle->ref == 1 || slot->slotID > FIPS_SLOT_ID); sftk_freeCertDB(certHandle); } if (keyHandle) { + PORT_Assert(keyHandle->ref == 1 || slot->slotID > FIPS_SLOT_ID); sftk_freeKeyDB(keyHandle); } } @@ -2957,6 +2981,14 @@ CK_RV nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS) if (!BLAPI_VerifySelf(NULL) || !BLAPI_SHVerify(SOFTOKEN_LIB_NAME, (PRFuncPtr) sftk_closePeer)) { crv = CKR_DEVICE_ERROR; /* better error code? checksum error? */ + if (sftk_audit_enabled) { + char msg[128]; + PR_snprintf(msg,sizeof msg, + "C_Initialize()=0x%08lX " + "self-test: software/firmware integrity test failed", + (PRUint32)crv); + sftk_LogAuditMessage(NSS_AUDIT_ERROR, msg); + } return crv; } @@ -2976,6 +3008,12 @@ CK_RV nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS) } RNG_SystemInfoForRNG(); + rv = nsslowcert_InitLocks(); + if (rv != SECSuccess) { + crv = CKR_DEVICE_ERROR; + return crv; + } + /* NOTE: * we should be getting out mutexes from this list, not statically binding @@ -3022,6 +3060,13 @@ CK_RV nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS) * don't clobber each other. */ if ((isFIPS && nsc_init) || (!isFIPS && nsf_init)) { sftk_closePeer(isFIPS); + if (sftk_audit_enabled) { + if (isFIPS && nsc_init) { + sftk_LogAuditMessage(NSS_AUDIT_INFO, "enabled FIPS mode"); + } else { + sftk_LogAuditMessage(NSS_AUDIT_INFO, "disabled FIPS mode"); + } + } } for (i=0; i < paramStrings.token_count; i++) { @@ -3551,7 +3596,7 @@ CK_RV NSC_SetPIN(CK_SESSION_HANDLE hSession, CK_CHAR_PTR pOldPin, handle = sftk_getKeyDB(slot); if (handle == NULL) { sftk_FreeSession(sp); - return CKR_PIN_LEN_RANGE; + return CKR_PIN_LEN_RANGE; /* XXX FIXME wrong return value */ } if (slot->needLogin && sp->info.state != CKS_RW_USER_FUNCTIONS) { @@ -3927,7 +3972,7 @@ static CK_RV sftk_CreateNewSlot(SFTKSlot *slot, CK_OBJECT_CLASS class, if (attribute == NULL) { return CKR_TEMPLATE_INCOMPLETE; } - paramString = (unsigned char *)attribute->attrib.pValue; + paramString = (char *)attribute->attrib.pValue; crv = secmod_parseParameters(paramString, ¶mStrings, isFIPS); if (crv != CKR_OK) { goto loser; @@ -3990,7 +4035,9 @@ CK_RV NSC_CreateObject(CK_SESSION_HANDLE hSession, SFTKSlot *slot = sftk_SlotFromSessionHandle(hSession); SFTKSession *session; SFTKObject *object; - CK_OBJECT_CLASS class; + /* make sure class isn't randomly CKO_NETSCAPE_NEWSLOT or + * CKO_NETSCPE_DELSLOT. */ + CK_OBJECT_CLASS class = CKO_VENDOR_DEFINED; CK_RV crv; int i; diff --git a/security/nss/lib/softoken/pkcs11c.c b/security/nss/lib/softoken/pkcs11c.c index 56eb1814c..477b2ab2a 100644 --- a/security/nss/lib/softoken/pkcs11c.c +++ b/security/nss/lib/softoken/pkcs11c.c @@ -73,6 +73,7 @@ #include "pcert.h" #include "ssl3prot.h" /* for SSL3_RANDOM_LENGTH */ +#include "prprf.h" #define __PASTE(x,y) x##y @@ -441,17 +442,23 @@ sftk_CryptInit(CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, break; } context->multi = PR_FALSE; - context->cipherInfo = isEncrypt ? - (void *)sftk_GetPubKey(key,CKK_RSA,&crv) : - (void *)sftk_GetPrivKey(key,CKK_RSA,&crv); - if (context->cipherInfo == NULL) { - break; - } if (isEncrypt) { + NSSLOWKEYPublicKey *pubKey = sftk_GetPubKey(key,CKK_RSA,&crv); + if (pubKey == NULL) { + break; + } + context->maxLen = nsslowkey_PublicModulusLen(pubKey); + context->cipherInfo = (void *)pubKey; context->update = (SFTKCipher) (pMechanism->mechanism == CKM_RSA_X_509 ? RSA_EncryptRaw : RSA_EncryptBlock); } else { + NSSLOWKEYPrivateKey *privKey = sftk_GetPrivKey(key,CKK_RSA,&crv); + if (privKey == NULL) { + break; + } + context->maxLen = nsslowkey_PrivateModulusLen(privKey); + context->cipherInfo = (void *)privKey; context->update = (SFTKCipher) (pMechanism->mechanism == CKM_RSA_X_509 ? RSA_DecryptRaw : RSA_DecryptBlock); @@ -717,6 +724,18 @@ CK_RV NSC_EncryptUpdate(CK_SESSION_HANDLE hSession, crv = sftk_GetContext(hSession,&context,SFTK_ENCRYPT,PR_TRUE,NULL); if (crv != CKR_OK) return crv; + if (!pEncryptedPart) { + if (context->doPad) { + CK_ULONG totalDataAvailable = ulPartLen + context->padDataLength; + CK_ULONG blocksToSend = totalDataAvailable/context->blockSize; + + *pulEncryptedPartLen = blocksToSend * context->blockSize; + return CKR_OK; + } + *pulEncryptedPartLen = ulPartLen; + return CKR_OK; + } + /* do padding */ if (context->doPad) { /* deal with previous buffered data */ @@ -837,7 +856,8 @@ CK_RV NSC_Encrypt (CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, if (crv != CKR_OK) return crv; if (!pEncryptedData) { - *pulEncryptedDataLen = ulDataLen + 2 * context->blockSize; + *pulEncryptedDataLen = context->multi ? + ulDataLen + 2 * context->blockSize : context->maxLen; goto finish; } @@ -923,6 +943,35 @@ CK_RV NSC_DecryptUpdate(CK_SESSION_HANDLE hSession, crv = sftk_GetContext(hSession,&context,SFTK_DECRYPT,PR_TRUE,NULL); if (crv != CKR_OK) return crv; + /* this can only happen on an NSS programming error */ + PORT_Assert((context->padDataLength == 0) + || context->padDataLength == context->blockSize); + + + if (!pPart) { + if (context->doPad) { + /* we can check the data length here because if we are padding, + * then we must be using a block cipher. In the non-padding case + * the error will be returned by the underlying decryption + * function when do do the actual decrypt. We need to do the + * check here to avoid returning a negative length to the caller. + */ + if ((ulEncryptedPartLen == 0) || + (ulEncryptedPartLen % context->blockSize) != 0) { + return CKR_ENCRYPTED_DATA_LEN_RANGE; + } + *pulPartLen = + ulEncryptedPartLen + context->padDataLength - context->blockSize; + return CKR_OK; + } + /* for stream ciphers there is are no constraints on ulEncryptedPartLen. + * for block ciphers, it must be a multiple of blockSize. The error is + * detected when this function is called again do decrypt the output. + */ + *pulPartLen = ulEncryptedPartLen; + return CKR_OK; + } + if (context->doPad) { /* first decrypt our saved buffer */ if (context->padDataLength != 0) { @@ -957,7 +1006,6 @@ CK_RV NSC_DecryptFinal(CK_SESSION_HANDLE hSession, unsigned int maxout = *pulLastPartLen; CK_RV crv; SECStatus rv = SECSuccess; - PRBool contextFinished = PR_TRUE; /* make sure we're legal */ crv = sftk_GetContext(hSession,&context,SFTK_DECRYPT,PR_TRUE,&session); @@ -967,9 +1015,9 @@ CK_RV NSC_DecryptFinal(CK_SESSION_HANDLE hSession, if (!pLastPart) { /* caller is checking the amount of remaining data */ if (context->padDataLength > 0) { - *pulLastPartLen = 2 * context->blockSize; - contextFinished = PR_FALSE; /* still have padding to go */ + *pulLastPartLen = context->padDataLength; } + rv = SECSuccess; goto finish; } @@ -992,11 +1040,9 @@ CK_RV NSC_DecryptFinal(CK_SESSION_HANDLE hSession, } } + sftk_SetContextByType(session, SFTK_DECRYPT, NULL); + sftk_FreeContext(context); finish: - if (contextFinished) { - sftk_SetContextByType(session, SFTK_DECRYPT, NULL); - sftk_FreeContext(context); - } sftk_FreeSession(session); return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; } @@ -1548,6 +1594,15 @@ static SECStatus sftk_HashSign(SFTKHashSignInfo *info,unsigned char *sig,unsigned int *sigLen, unsigned int maxLen,unsigned char *hash, unsigned int hashLen) { + return RSA_HashSign(info->hashOid,info->key,sig,sigLen,maxLen, + hash,hashLen); +} + +SECStatus +RSA_HashSign(SECOidTag hashOid, NSSLOWKEYPrivateKey *key, + unsigned char *sig, unsigned int *sigLen, unsigned int maxLen, + unsigned char *hash, unsigned int hashLen) +{ SECStatus rv = SECFailure; SECItem digder; @@ -1560,7 +1615,7 @@ sftk_HashSign(SFTKHashSignInfo *info,unsigned char *sig,unsigned int *sigLen, if ( !arena ) { goto loser; } /* Construct digest info */ - di = SGN_CreateDigestInfo(info->hashOid, hash, hashLen); + di = SGN_CreateDigestInfo(hashOid, hash, hashLen); if (!di) { goto loser; } /* Der encode the digest as a DigestInfo */ @@ -1573,7 +1628,7 @@ sftk_HashSign(SFTKHashSignInfo *info,unsigned char *sig,unsigned int *sigLen, ** Encrypt signature after constructing appropriate PKCS#1 signature ** block */ - rv = RSA_Sign(info->key,sig,sigLen,maxLen,digder.data,digder.len); + rv = RSA_Sign(key,sig,sigLen,maxLen,digder.data,digder.len); loser: SGN_DestroyDigestInfo(di); @@ -2055,11 +2110,20 @@ CK_RV NSC_SignRecover(CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, ************** Crypto Functions: verify ************************ */ -/* Handle RSA Signature formating */ +/* Handle RSA Signature formatting */ static SECStatus sftk_hashCheckSign(SFTKHashVerifyInfo *info, unsigned char *sig, unsigned int sigLen, unsigned char *digest, unsigned int digestLen) { + return RSA_HashCheckSign(info->hashOid, info->key, sig, sigLen, + digest, digestLen); +} + +SECStatus +RSA_HashCheckSign(SECOidTag hashOid, NSSLOWKEYPublicKey *key, + unsigned char *sig, unsigned int sigLen, + unsigned char *digest, unsigned int digestLen) +{ SECItem it; SGNDigestInfo *di = NULL; @@ -2067,16 +2131,16 @@ sftk_hashCheckSign(SFTKHashVerifyInfo *info, unsigned char *sig, it.data = NULL; - if (info->key == NULL) goto loser; + if (key == NULL) goto loser; - it.len = nsslowkey_PublicModulusLen(info->key); + it.len = nsslowkey_PublicModulusLen(key); if (!it.len) goto loser; it.data = (unsigned char *) PORT_Alloc(it.len); if (it.data == NULL) goto loser; /* decrypt the block */ - rv = RSA_CheckSignRecover(info->key, it.data, &it.len, it.len, sig, sigLen); + rv = RSA_CheckSignRecover(key, it.data, &it.len, it.len, sig, sigLen); if (rv != SECSuccess) goto loser; di = SGN_DecodeDigestInfo(&it); @@ -2084,7 +2148,7 @@ sftk_hashCheckSign(SFTKHashVerifyInfo *info, unsigned char *sig, if (di->digest.len != digestLen) goto loser; /* make sure the tag is OK */ - if (SECOID_GetAlgorithmTag(&di->digestAlgorithm) != info->hashOid) { + if (SECOID_GetAlgorithmTag(&di->digestAlgorithm) != hashOid) { goto loser; } /* Now check the signature */ @@ -2202,7 +2266,6 @@ finish_rsa: crv = CKR_KEY_TYPE_INCONSISTENT; break; } - context->multi = PR_FALSE; pubKey = sftk_GetPubKey(key,CKK_EC,&crv); if (pubKey == NULL) { crv = CKR_HOST_MEMORY; @@ -2414,14 +2477,23 @@ CK_RV NSC_VerifyRecover(CK_SESSION_HANDLE hSession, crv = sftk_GetContext(hSession,&context,SFTK_VERIFY_RECOVER, PR_FALSE,&session); if (crv != CKR_OK) return crv; + if (pData == NULL) { + /* to return the actual size, we need to do the decrypt, just return + * the max size, which is the size of the input signature. */ + *pulDataLen = ulSignatureLen; + rv = SECSuccess; + goto finish; + } rv = (*context->update)(context->cipherInfo, pData, &outlen, maxoutlen, pSignature, ulSignatureLen); *pulDataLen = (CK_ULONG) outlen; + sftk_FreeContext(context); sftk_SetContextByType(session, SFTK_VERIFY_RECOVER, NULL); +finish: sftk_FreeSession(session); - return (rv == SECSuccess) ? CKR_OK : CKR_DEVICE_ERROR; + return (rv == SECSuccess) ? CKR_OK : CKR_SIGNATURE_INVALID; } /* @@ -2482,9 +2554,13 @@ nsc_pbe_key_gen(NSSPKCS5PBEParameter *pkcs5_pbe, CK_MECHANISM_PTR pMechanism, SECITEM_ZfreeItem(pbe_key, PR_TRUE); pbe_key = NULL; - if (iv.data && pbe_params->pInitVector != NULL) { - PORT_Memcpy(pbe_params->pInitVector, iv.data, iv.len); + if (iv.data) { + if (pbe_params->pInitVector != NULL) { + PORT_Memcpy(pbe_params->pInitVector, iv.data, iv.len); + } + PORT_Free(iv.data); } + return CKR_OK; } static CK_RV @@ -3695,6 +3771,16 @@ ecgn_done: sftk_FreeObject(publicKey); NSC_DestroyObject(hSession,privateKey->handle); sftk_FreeObject(privateKey); + if (sftk_audit_enabled) { + char msg[128]; + PR_snprintf(msg,sizeof msg, + "C_GenerateKeyPair(hSession=%lu, " + "pMechanism->mechanism=0x%08lX)=0x%08lX " + "self-test: pair-wise consistency test failed", + (PRUint32)hSession,(PRUint32)pMechanism->mechanism, + (PRUint32)crv); + sftk_LogAuditMessage(NSS_AUDIT_ERROR, msg); + } return crv; } @@ -3937,6 +4023,17 @@ CK_RV NSC_WrapKey(CK_SESSION_HANDLE hSession, crv = NSC_Encrypt(hSession, (CK_BYTE_PTR)pText.data, pText.len, pWrappedKey, pulWrappedKeyLen); + /* always force a finalize, both on errors and when + * we are just getting the size */ + if (crv != CKR_OK || pWrappedKey == NULL) { + CK_RV lcrv ; + lcrv = sftk_GetContext(hSession,&context, + SFTK_ENCRYPT,PR_FALSE,NULL); + sftk_SetContextByType(session, SFTK_ENCRYPT, NULL); + if (lcrv == CKR_OK && context) { + sftk_FreeContext(context); + } + } if (pText.data != (unsigned char *)attribute->attrib.pValue) PORT_ZFree(pText.data, pText.len); @@ -3947,6 +4044,7 @@ CK_RV NSC_WrapKey(CK_SESSION_HANDLE hSession, case CKO_PRIVATE_KEY: { SECItem *bpki = sftk_PackagePrivateKey(key, &crv); + SFTKSessionContext *context = NULL; if(!bpki) { break; @@ -3962,6 +4060,16 @@ CK_RV NSC_WrapKey(CK_SESSION_HANDLE hSession, crv = NSC_Encrypt(hSession, bpki->data, bpki->len, pWrappedKey, pulWrappedKeyLen); + /* always force a finalize */ + if (crv != CKR_OK || pWrappedKey == NULL) { + CK_RV lcrv ; + lcrv = sftk_GetContext(hSession,&context, + SFTK_ENCRYPT,PR_FALSE,NULL); + sftk_SetContextByType(session, SFTK_ENCRYPT, NULL); + if (lcrv == CKR_OK && context) { + sftk_FreeContext(context); + } + } SECITEM_ZfreeItem(bpki, PR_TRUE); break; } @@ -3989,7 +4097,6 @@ sftk_unwrapPrivateKey(SFTKObject *key, SECItem *bpki) PLArenaPool *arena; NSSLOWKEYPrivateKey *lpk = NULL; NSSLOWKEYPrivateKeyInfo *pki = NULL; - SECItem *ck_id = NULL; CK_RV crv = CKR_KEY_TYPE_INCONSISTENT; arena = PORT_NewArena(2048); @@ -4197,10 +4304,6 @@ sftk_unwrapPrivateKey(SFTKObject *key, SECItem *bpki) } loser: - if(ck_id) { - SECITEM_ZfreeItem(ck_id, PR_TRUE); - } - if(lpk) { nsslowkey_DestroyPrivateKey(lpk); } @@ -4605,14 +4708,6 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, return CKR_KEY_HANDLE_INVALID; } - /* don't use key derive to expose sensitive keys */ - crv = sftk_DeriveSensitiveCheck(sourceKey,key); - if (crv != CKR_OK) { - sftk_FreeObject(key); - sftk_FreeObject(sourceKey); - return crv; - } - /* get the value of the base key */ att = sftk_FindAttribute(sourceKey,CKA_VALUE); if (att == NULL) { @@ -4633,7 +4728,9 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, case CKM_SSL3_MASTER_KEY_DERIVE_DH: { CK_SSL3_MASTER_KEY_DERIVE_PARAMS *ssl3_master; - SSL3RSAPreMasterSecret *rsa_pms; + SSL3RSAPreMasterSecret * rsa_pms; + unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2]; + if ((pMechanism->mechanism == CKM_SSL3_MASTER_KEY_DERIVE_DH) || (pMechanism->mechanism == CKM_TLS_MASTER_KEY_DERIVE_DH)) isDH = PR_TRUE; @@ -4660,10 +4757,15 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, break; } - /* finally do the key gen */ ssl3_master = (CK_SSL3_MASTER_KEY_DERIVE_PARAMS *) pMechanism->pParameter; + + PORT_Memcpy(crsrdata, + ssl3_master->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH); + PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, + ssl3_master->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH); + if (ssl3_master->pVersion) { SFTKSessionObject *sessKey = sftk_narrowToSessionObject(key); rsa_pms = (SSL3RSAPreMasterSecret *) att->attrib.pValue; @@ -4686,23 +4788,16 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, } if (isTLS) { - unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2]; - SECItem crsr = { siBuffer, NULL, 0 }; - SECItem master = { siBuffer, NULL, 0 }; - SECItem pms = { siBuffer, NULL, 0 }; SECStatus status; + SECItem crsr = { siBuffer, crsrdata, sizeof crsrdata }; + SECItem master = { siBuffer, key_block, SSL3_MASTER_SECRET_LENGTH}; + SECItem pms = { siBuffer }; - pms.data = (unsigned char*)att->attrib.pValue; - pms.len = att->attrib.ulValueLen; - master.data = key_block; - master.len = SSL3_MASTER_SECRET_LENGTH; - crsr.data = crsrdata; - crsr.len = sizeof(crsrdata); - - PORT_Memcpy(crsrdata, ssl3_master->RandomInfo.pClientRandom, - SSL3_RANDOM_LENGTH); - PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, - ssl3_master->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH); + /* HPUX won't let a structure member be initialized with the + * value of a variable, but the address of a local variable. :-/ + */ + pms.data = (unsigned char*)att->attrib.pValue; + pms.len = att->attrib.ulValueLen; status = TLS_PRF(&pms, "master secret", &crsr, &master, isFIPS); if (status != SECSuccess) { @@ -4727,12 +4822,10 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, SHA1_Update(sha, (unsigned char*) mixers[i], strlen(mixers[i])); SHA1_Update(sha, (const unsigned char*)att->attrib.pValue, att->attrib.ulValueLen); - SHA1_Update(sha, ssl3_master->RandomInfo.pClientRandom, - ssl3_master->RandomInfo.ulClientRandomLen); - SHA1_Update(sha, ssl3_master->RandomInfo.pServerRandom, - ssl3_master->RandomInfo.ulServerRandomLen); + SHA1_Update(sha, crsrdata, sizeof crsrdata); SHA1_End(sha, sha_out, &outLen, SHA1_LENGTH); PORT_Assert(outLen == SHA1_LENGTH); + MD5_Begin(md5); MD5_Update(md5, (const unsigned char*)att->attrib.pValue, att->attrib.ulValueLen); @@ -4773,6 +4866,9 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, CK_SSL3_KEY_MAT_PARAMS *ssl3_keys; CK_SSL3_KEY_MAT_OUT * ssl3_keys_out; CK_ULONG effKeySize; + unsigned int block_needed; + unsigned char srcrdata[SSL3_RANDOM_LENGTH * 2]; + unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2]; crv = sftk_DeriveSensitiveCheck(sourceKey,key); if (crv != CKR_OK) break; @@ -4801,6 +4897,17 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, break; } ssl3_keys = (CK_SSL3_KEY_MAT_PARAMS *) pMechanism->pParameter; + + PORT_Memcpy(srcrdata, + ssl3_keys->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH); + PORT_Memcpy(srcrdata + SSL3_RANDOM_LENGTH, + ssl3_keys->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH); + + PORT_Memcpy(crsrdata, + ssl3_keys->RandomInfo.pClientRandom, SSL3_RANDOM_LENGTH); + PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, + ssl3_keys->RandomInfo.pServerRandom, SSL3_RANDOM_LENGTH); + /* * clear out our returned keys so we can recover on failure */ @@ -4811,29 +4918,33 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, ssl3_keys_out->hServerKey = CK_INVALID_HANDLE; /* + * How much key material do we need? + */ + macSize = ssl3_keys->ulMacSizeInBits/8; + effKeySize = ssl3_keys->ulKeySizeInBits/8; + IVSize = ssl3_keys->ulIVSizeInBits/8; + if (keySize == 0) { + effKeySize = keySize; + } + block_needed = 2 * (macSize + effKeySize + + ((!ssl3_keys->bIsExport) * IVSize)); + PORT_Assert(block_needed <= sizeof key_block); + if (block_needed > sizeof key_block) + block_needed = sizeof key_block; + + /* * generate the key material: This looks amazingly similar to the * PMS code, and is clearly crying out for a function to provide it. */ if (isTLS) { SECStatus status; - SECItem master = { siBuffer, NULL, 0 }; - SECItem srcr = { siBuffer, NULL, 0 }; - SECItem keyblk = { siBuffer, NULL, 0 }; - unsigned char srcrdata[SSL3_RANDOM_LENGTH * 2]; + SECItem srcr = { siBuffer, srcrdata, sizeof srcrdata }; + SECItem keyblk = { siBuffer, key_block }; + SECItem master = { siBuffer }; + keyblk.len = block_needed; master.data = (unsigned char*)att->attrib.pValue; - master.len = att->attrib.ulValueLen; - srcr.data = srcrdata; - srcr.len = sizeof srcrdata; - keyblk.data = key_block; - keyblk.len = sizeof key_block; - - PORT_Memcpy(srcrdata, - ssl3_keys->RandomInfo.pServerRandom, - SSL3_RANDOM_LENGTH); - PORT_Memcpy(srcrdata + SSL3_RANDOM_LENGTH, - ssl3_keys->RandomInfo.pClientRandom, - SSL3_RANDOM_LENGTH); + master.len = att->attrib.ulValueLen; status = TLS_PRF(&master, "key expansion", &srcr, &keyblk, isFIPS); @@ -4841,6 +4952,7 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, goto key_and_mac_derive_fail; } } else { + unsigned int block_bytes = 0; /* key_block = * MD5(master_secret + SHA('A' + master_secret + * ServerHello.random + ClientHello.random)) + @@ -4850,15 +4962,12 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, * ServerHello.random + ClientHello.random)) + * [...]; */ - for (i = 0; i < NUM_MIXERS; i++) { + for (i = 0; i < NUM_MIXERS && block_bytes < block_needed; i++) { SHA1_Begin(sha); SHA1_Update(sha, (unsigned char*) mixers[i], strlen(mixers[i])); SHA1_Update(sha, (const unsigned char*)att->attrib.pValue, att->attrib.ulValueLen); - SHA1_Update(sha, ssl3_keys->RandomInfo.pServerRandom, - ssl3_keys->RandomInfo.ulServerRandomLen); - SHA1_Update(sha, ssl3_keys->RandomInfo.pClientRandom, - ssl3_keys->RandomInfo.ulClientRandomLen); + SHA1_Update(sha, srcrdata, sizeof srcrdata); SHA1_End(sha, sha_out, &outLen, SHA1_LENGTH); PORT_Assert(outLen == SHA1_LENGTH); MD5_Begin(md5); @@ -4867,6 +4976,7 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, MD5_Update(md5, sha_out, outLen); MD5_End(md5, &key_block[i*MD5_LENGTH], &outLen, MD5_LENGTH); PORT_Assert(outLen == MD5_LENGTH); + block_bytes += outLen; } } @@ -4874,12 +4984,6 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, * Put the key material where it goes. */ i = 0; /* now shows how much consumed */ - macSize = ssl3_keys->ulMacSizeInBits/8; - effKeySize = ssl3_keys->ulKeySizeInBits/8; - IVSize = ssl3_keys->ulIVSizeInBits/8; - if (keySize == 0) { - effKeySize = keySize; - } /* * The key_block is partitioned as follows: @@ -4954,10 +5058,7 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, */ MD5_Begin(md5); MD5_Update(md5, &key_block[i], effKeySize); - MD5_Update(md5, ssl3_keys->RandomInfo.pClientRandom, - ssl3_keys->RandomInfo.ulClientRandomLen); - MD5_Update(md5, ssl3_keys->RandomInfo.pServerRandom, - ssl3_keys->RandomInfo.ulServerRandomLen); + MD5_Update(md5, crsrdata, sizeof crsrdata); MD5_End(md5, key_block2, &outLen, MD5_LENGTH); i += effKeySize; crv = sftk_buildSSLKey(hSession,key,PR_FALSE,key_block2, @@ -4973,10 +5074,7 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, */ MD5_Begin(md5); MD5_Update(md5, &key_block[i], effKeySize); - MD5_Update(md5, ssl3_keys->RandomInfo.pServerRandom, - ssl3_keys->RandomInfo.ulServerRandomLen); - MD5_Update(md5, ssl3_keys->RandomInfo.pClientRandom, - ssl3_keys->RandomInfo.ulClientRandomLen); + MD5_Update(md5, srcrdata, sizeof srcrdata); MD5_End(md5, key_block2, &outLen, MD5_LENGTH); i += effKeySize; crv = sftk_buildSSLKey(hSession,key,PR_FALSE,key_block2, @@ -4990,10 +5088,7 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, ** MD5(ClientHello.random + ServerHello.random); */ MD5_Begin(md5); - MD5_Update(md5, ssl3_keys->RandomInfo.pClientRandom, - ssl3_keys->RandomInfo.ulClientRandomLen); - MD5_Update(md5, ssl3_keys->RandomInfo.pServerRandom, - ssl3_keys->RandomInfo.ulServerRandomLen); + MD5_Update(md5, crsrdata, sizeof crsrdata); MD5_End(md5, key_block2, &outLen, MD5_LENGTH); PORT_Memcpy(ssl3_keys_out->pIVClient, key_block2, IVSize); @@ -5002,10 +5097,7 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, ** MD5(ServerHello.random + ClientHello.random); */ MD5_Begin(md5); - MD5_Update(md5, ssl3_keys->RandomInfo.pServerRandom, - ssl3_keys->RandomInfo.ulServerRandomLen); - MD5_Update(md5, ssl3_keys->RandomInfo.pClientRandom, - ssl3_keys->RandomInfo.ulClientRandomLen); + MD5_Update(md5, srcrdata, sizeof srcrdata); MD5_End(md5, key_block2, &outLen, MD5_LENGTH); PORT_Memcpy(ssl3_keys_out->pIVServer, key_block2, IVSize); @@ -5016,20 +5108,8 @@ CK_RV NSC_DeriveKey( CK_SESSION_HANDLE hSession, */ SECStatus status; SECItem secret = { siBuffer, NULL, 0 }; - SECItem crsr = { siBuffer, NULL, 0 }; + SECItem crsr = { siBuffer, crsrdata, sizeof crsrdata }; SECItem keyblk = { siBuffer, NULL, 0 }; - unsigned char crsrdata[SSL3_RANDOM_LENGTH * 2]; - - crsr.data = crsrdata; - crsr.len = sizeof crsrdata; - - PORT_Memcpy(crsrdata, - ssl3_keys->RandomInfo.pClientRandom, - SSL3_RANDOM_LENGTH); - PORT_Memcpy(crsrdata + SSL3_RANDOM_LENGTH, - ssl3_keys->RandomInfo.pServerRandom, - SSL3_RANDOM_LENGTH); - /* ** client_write_key[CipherSpec.key_material] @@ -5177,6 +5257,9 @@ key_and_mac_derive_fail: } case CKM_CONCATENATE_BASE_AND_DATA: + crv = sftk_DeriveSensitiveCheck(sourceKey,key); + if (crv != CKR_OK) break; + stringPtr = (CK_KEY_DERIVATION_STRING_DATA *) pMechanism->pParameter; tmpKeySize = att->attrib.ulValueLen+stringPtr->ulLen; if (keySize == 0) keySize = tmpKeySize; @@ -5198,6 +5281,9 @@ key_and_mac_derive_fail: PORT_ZFree(buf,tmpKeySize); break; case CKM_CONCATENATE_DATA_AND_BASE: + crv = sftk_DeriveSensitiveCheck(sourceKey,key); + if (crv != CKR_OK) break; + stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter; tmpKeySize = att->attrib.ulValueLen+stringPtr->ulLen; if (keySize == 0) keySize = tmpKeySize; @@ -5219,6 +5305,9 @@ key_and_mac_derive_fail: PORT_ZFree(buf,tmpKeySize); break; case CKM_XOR_BASE_AND_DATA: + crv = sftk_DeriveSensitiveCheck(sourceKey,key); + if (crv != CKR_OK) break; + stringPtr = (CK_KEY_DERIVATION_STRING_DATA *)pMechanism->pParameter; tmpKeySize = PR_MIN(att->attrib.ulValueLen,stringPtr->ulLen); if (keySize == 0) keySize = tmpKeySize; @@ -5249,6 +5338,9 @@ key_and_mac_derive_fail: CK_ULONG shift = extract & 0x7; /* extract mod 8 the fast way */ CK_ULONG offset = extract >> 3; /* extract div 8 the fast way */ + crv = sftk_DeriveSensitiveCheck(sourceKey,key); + if (crv != CKR_OK) break; + if (keySize == 0) { crv = CKR_TEMPLATE_INCOMPLETE; break; @@ -5382,6 +5474,7 @@ key_and_mac_derive_fail: PRBool withCofactor = PR_FALSE; unsigned char secret_hash[20]; unsigned char *secret; + unsigned char *keyData = NULL; int secretlen; CK_ECDH1_DERIVE_PARAMS *mechParams; NSSLOWKEYPrivateKey *privKey; @@ -5435,26 +5528,59 @@ key_and_mac_derive_fail: break; } + /* + * tmp is the raw data created by ECDH_Derive, + * secret and secretlen are the values we will eventually pass as our + * generated key. + */ secret = tmp.data; secretlen = tmp.len; + + /* + * apply the kdf function. + */ if (mechParams->kdf == CKD_SHA1_KDF) { /* Compute SHA1 hash */ - memset(secret_hash, 0, 20); + PORT_Memset(secret_hash, 0, 20); rv = SHA1_HashBuf(secret_hash, tmp.data, tmp.len); if (rv != SECSuccess) { PORT_ZFree(tmp.data, tmp.len); + crv = CKR_HOST_MEMORY; + break; + } + secret = secret_hash; + secretlen = 20; + } + + /* + * if keySize is supplied, then we are generating a key of a specific + * length. This is done by taking the least significant 'keySize' + * bytes from the unsigned value calculated by ECDH. Note: this may + * mean padding temp with extra leading zeros from what ECDH_Derive + * already returned (which itself may contain leading zeros). + */ + if (keySize) { + if (secretlen < keySize) { + keyData = PORT_ZAlloc(keySize); + if (!keyData) { + PORT_ZFree(tmp.data, tmp.len); + crv = CKR_HOST_MEMORY; + break; + } + PORT_Memcpy(&keyData[keySize-secretlen],secret,secretlen); + secret = keyData; } else { - secret = secret_hash; - secretlen = 20; + secret += (secretlen - keySize); } + secretlen = keySize; } - if (rv == SECSuccess) { - sftk_forceAttribute(key, CKA_VALUE, secret, secretlen); - PORT_ZFree(tmp.data, tmp.len); - memset(secret_hash, 0, 20); - } else - crv = CKR_HOST_MEMORY; + sftk_forceAttribute(key, CKA_VALUE, secret, secretlen); + PORT_ZFree(tmp.data, tmp.len); + if (keyData) { + PORT_ZFree(keyData, keySize); + } + PORT_Memset(secret_hash, 0, 20); break; } diff --git a/security/nss/lib/softoken/pkcs11i.h b/security/nss/lib/softoken/pkcs11i.h index 0eaf5bf37..fd5ff6423 100644 --- a/security/nss/lib/softoken/pkcs11i.h +++ b/security/nss/lib/softoken/pkcs11i.h @@ -555,7 +555,7 @@ typedef struct sftk_parametersStr { SEC_BEGIN_PROTOS -/* shared functions between PKCS11.c and SFTKFIPS.c */ +/* shared functions between pkcs11.c and fipstokn.c */ extern int nsf_init; extern CK_RV nsc_CommonInitialize(CK_VOID_PTR pReserved, PRBool isFIPS); extern CK_RV nsc_CommonFinalize(CK_VOID_PTR pReserved, PRBool isFIPS); diff --git a/security/nss/lib/softoken/pkcs11u.c b/security/nss/lib/softoken/pkcs11u.c index 8e68587ce..9790f0ca3 100644 --- a/security/nss/lib/softoken/pkcs11u.c +++ b/security/nss/lib/softoken/pkcs11u.c @@ -67,6 +67,7 @@ sftk_NewAttribute(SFTKObject *object, if (so == NULL) { /* allocate new attribute in a buffer */ PORT_Assert(0); + return NULL; } /* * We attempt to keep down contention on Malloc and Arena locks by @@ -891,6 +892,11 @@ sftk_FindDSAPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, case CKA_BASE: return sftk_NewTokenAttributeSigned(type,key->u.dsa.params.base.data, key->u.dsa.params.base.len, PR_FALSE); + case CKA_NETSCAPE_DB: + return sftk_NewTokenAttributeSigned(type, + key->u.dsa.publicValue.data, + key->u.dsa.publicValue.len, + PR_FALSE); default: break; } @@ -925,6 +931,11 @@ sftk_FindDHPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type) case CKA_BASE: return sftk_NewTokenAttributeSigned(type,key->u.dh.base.data, key->u.dh.base.len, PR_FALSE); + case CKA_NETSCAPE_DB: + return sftk_NewTokenAttributeSigned(type, + key->u.dh.publicValue.data, + key->u.dh.publicValue.len, + PR_FALSE); default: break; } @@ -960,6 +971,11 @@ sftk_FindECPrivateKeyAttribute(NSSLOWKEYPrivateKey *key, CK_ATTRIBUTE_TYPE type) key->u.ec.ecParams.DEREncoding.data, key->u.ec.ecParams.DEREncoding.len, PR_FALSE); + case CKA_NETSCAPE_DB: + return sftk_NewTokenAttributeSigned(type, + key->u.ec.publicValue.data, + key->u.ec.publicValue.len, + PR_FALSE); default: break; } @@ -1502,7 +1518,6 @@ sftk_DeleteAttribute(SFTKObject *object, SFTKAttribute *attribute) sessObject->head, sessObject->hashSize); } PZ_Unlock(sessObject->attributeLock); - sftk_FreeAttribute(attribute); } /* @@ -2749,7 +2764,7 @@ stfk_CopyTokenPrivateKey(SFTKObject *destObject,SFTKTokenObject *src_to) } /* copy the common attributes for all private keys next */ crv = stfk_CopyTokenAttributes(destObject, src_to, commonPrivKeyAttrs, - commonKeyAttrsCount); + commonPrivKeyAttrsCount); if (crv != CKR_OK) { goto fail; } diff --git a/security/nss/lib/softoken/rsawrapr.c b/security/nss/lib/softoken/rsawrapr.c index b40a30d80..2ae3039e7 100644 --- a/security/nss/lib/softoken/rsawrapr.c +++ b/security/nss/lib/softoken/rsawrapr.c @@ -489,7 +489,13 @@ RSA_CheckSign(NSSLOWKEYPublicKey *key, modulus_len = nsslowkey_PublicModulusLen(key); if (sign_len != modulus_len) goto failure; - if (hash_len > modulus_len - 8) + /* + * 0x00 || BT || Pad || 0x00 || ActualData + * + * The "3" below is the first octet + the second octet + the 0x00 + * octet that always comes just before the ActualData. + */ + if (hash_len > modulus_len - (3 + RSA_BLOCK_MIN_PAD_LEN)) goto failure; PORT_Assert(key->keyType == NSSLOWKEYRSAKey); if (key->keyType != NSSLOWKEYRSAKey) @@ -509,11 +515,11 @@ RSA_CheckSign(NSSLOWKEYPublicKey *key, if (buffer[0] != 0 || buffer[1] != 1) goto loser; for (i = 2; i < modulus_len - hash_len - 1; i++) { - if (buffer[i] == 0) - break; if (buffer[i] != 0xff) goto loser; } + if (buffer[i] != 0) + goto loser; /* * make sure we get the same results diff --git a/security/nss/lib/softoken/softoken.h b/security/nss/lib/softoken/softoken.h index b89546e53..9a06be831 100644 --- a/security/nss/lib/softoken/softoken.h +++ b/security/nss/lib/softoken/softoken.h @@ -81,7 +81,7 @@ extern unsigned char *RSA_FormatOneBlock(unsigned int modulusLen, /* * convenience wrappers for doing single RSA operations. They create the * RSA context internally and take care of the formatting - * requirements. Blinding happens automagically within RSA_SignHash and + * requirements. Blinding happens automagically within RSA_Sign and * RSA_DecryptBlock. */ extern @@ -89,10 +89,20 @@ SECStatus RSA_Sign(NSSLOWKEYPrivateKey *key, unsigned char *output, unsigned int *outputLen, unsigned int maxOutputLen, unsigned char *input, unsigned int inputLen); extern +SECStatus RSA_HashSign(SECOidTag hashOid, + NSSLOWKEYPrivateKey *key, unsigned char *sig, + unsigned int *sigLen, unsigned int maxLen, + unsigned char *hash, unsigned int hashLen); +extern SECStatus RSA_CheckSign(NSSLOWKEYPublicKey *key, unsigned char *sign, unsigned int signLength, unsigned char *hash, unsigned int hashLength); extern +SECStatus RSA_HashCheckSign(SECOidTag hashOid, + NSSLOWKEYPublicKey *key, unsigned char *sig, + unsigned int sigLen, unsigned char *digest, + unsigned int digestLen); +extern SECStatus RSA_CheckSignRecover(NSSLOWKEYPublicKey *key, unsigned char *data, unsigned int *data_len,unsigned int max_output_len, unsigned char *sign, unsigned int sign_len); @@ -131,6 +141,14 @@ SECStatus RSA_DecryptRaw(NSSLOWKEYPrivateKey *key, unsigned char *output, unsigned int *output_len, unsigned int max_output_len, unsigned char *input, unsigned int input_len); +#ifdef NSS_ENABLE_ECC +/* +** pepare an ECParam structure from DEREncoded params + */ +extern SECStatus EC_FillParams(PRArenaPool *arena, + const SECItem *encodedParams, ECParams *params); +#endif + /* ** Prepare a buffer for DES encryption, growing to the appropriate boundary, @@ -159,6 +177,13 @@ extern CK_RV sftk_fipsPowerUpSelfTest( void ); */ unsigned long sftk_MapKeySize(CK_KEY_TYPE keyType); +/* +** FIPS 140-2 auditing +*/ +extern PRBool sftk_audit_enabled; + +extern void sftk_LogAuditMessage(NSSAuditSeverity severity, const char *msg); + SEC_END_PROTOS #endif /* _SOFTOKEN_H_ */ diff --git a/security/nss/lib/softoken/softokn.rc b/security/nss/lib/softoken/softokn.rc index 0fcaa1219..bbf8905a0 100644 --- a/security/nss/lib/softoken/softokn.rc +++ b/security/nss/lib/softoken/softokn.rc @@ -84,11 +84,10 @@ BEGIN BEGIN BLOCK "040904B0" // Lang=US English, CharSet=Unicode BEGIN - VALUE "CompanyName", "Netscape Communications Corporation\0" + VALUE "CompanyName", "Mozilla Foundation\0" VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0" VALUE "FileVersion", NSS_VERSION "\0" VALUE "InternalName", MY_INTERNAL_NAME "\0" - VALUE "LegalCopyright", "Copyright \251 1994-2001 Netscape Communications Corporation\0" VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0" VALUE "ProductName", "Network Security Services\0" VALUE "ProductVersion", NSS_VERSION "\0" diff --git a/security/nss/lib/softoken/softoknt.h b/security/nss/lib/softoken/softoknt.h index b499eb6b0..3af94e286 100644 --- a/security/nss/lib/softoken/softoknt.h +++ b/security/nss/lib/softoken/softoknt.h @@ -61,4 +61,13 @@ typedef enum { #define NSS_SOFTOKEN_DEFAULT_CHUNKSIZE 2048 +/* + * FIPS 140-2 auditing + */ +typedef enum { + NSS_AUDIT_ERROR = 3, /* errors */ + NSS_AUDIT_WARNING = 2, /* warning messages */ + NSS_AUDIT_INFO = 1 /* informational messages */ +} NSSAuditSeverity; + #endif /* _SOFTOKNT_H_ */ diff --git a/security/nss/lib/ssl/emulate.c b/security/nss/lib/ssl/emulate.c deleted file mode 100644 index a381cd7d2..000000000 --- a/security/nss/lib/ssl/emulate.c +++ /dev/null @@ -1,636 +0,0 @@ -/* - * Functions that emulate PR_AcceptRead and PR_TransmitFile for SSL sockets. - * Each Layered NSPR protocol (like SSL) must unfortunately contain its - * own implementation of these functions. This code was taken from NSPR. - * - * ***** BEGIN LICENSE BLOCK ***** - * 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 Netscape security libraries. - * - * The Initial Developer of the Original Code is - * Netscape Communications Corporation. - * Portions created by the Initial Developer are Copyright (C) 1994-2000 - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * 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. - * - * ***** END LICENSE BLOCK ***** */ -/* $Id$ */ - -#include "nspr.h" - -#if defined( XP_UNIX ) || defined( XP_BEOS ) -#include <fcntl.h> -#endif -#if defined(WIN32) -#include <windef.h> -#include <winbase.h> -#endif -#include <string.h> - -#define AMASK 7 /* mask for alignment of PRNetAddr */ - -/* - * _PR_EmulateAcceptRead - * - * Accept an incoming connection on sd, set *nd to point to the - * newly accepted socket, read 'amount' bytes from the accepted - * socket. - * - * buf is a buffer of length = amount + (2 * sizeof(PRNetAddr)) + 32 - * *raddr points to the PRNetAddr of the accepted connection upon - * return - * - * return number of bytes read or -1 on error - * - */ -PRInt32 -ssl_EmulateAcceptRead( PRFileDesc * sd, - PRFileDesc ** nd, - PRNetAddr ** raddr, - void * buf, - PRInt32 amount, - PRIntervalTime timeout) -{ - PRFileDesc * newsockfd; - PRInt32 rv; - PRNetAddr remote; - - if (!(newsockfd = PR_Accept(sd, &remote, PR_INTERVAL_NO_TIMEOUT))) { - return -1; - } - - rv = PR_Recv(newsockfd, buf, amount, 0, timeout); - if (rv >= 0) { - ptrdiff_t pNetAddr = (((ptrdiff_t)buf) + amount + AMASK) & ~AMASK; - - *nd = newsockfd; - *raddr = (PRNetAddr *)pNetAddr; - memcpy((void *)pNetAddr, &remote, sizeof(PRNetAddr)); - return rv; - } - - PR_Close(newsockfd); - return -1; -} - - -#if !defined( XP_UNIX ) && !defined( WIN32 ) && !defined( XP_BEOS ) -/* - * _PR_EmulateTransmitFile - * - * Send file fd across socket sd. If headers is non-NULL, 'hlen' - * bytes of headers is sent before sending the file. - * - * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file - * - * return number of bytes sent or -1 on error - * - */ -#define _TRANSMITFILE_BUFSIZE (16 * 1024) - -PRInt32 -ssl_EmulateTransmitFile( PRFileDesc * sd, - PRFileDesc * fd, - const void * headers, - PRInt32 hlen, - PRTransmitFileFlags flags, - PRIntervalTime timeout) -{ - char * buf = NULL; - PRInt32 count = 0; - PRInt32 rlen; - PRInt32 rv; - - buf = PR_MALLOC(_TRANSMITFILE_BUFSIZE); - if (buf == NULL) { - PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); - return -1; - } - - /* - * send headers, first - */ - while (hlen) { - rv = PR_Send(sd, headers, hlen, 0, timeout); - if (rv < 0) { - /* PR_Send() has invoked PR_SetError(). */ - rv = -1; - goto done; - } - count += rv; - headers = (const void*) ((const char*)headers + rv); - hlen -= rv; - } - /* - * send file, next - */ - while ((rlen = PR_Read(fd, buf, _TRANSMITFILE_BUFSIZE)) > 0) { - while (rlen) { - char *bufptr = buf; - - rv = PR_Send(sd, bufptr, rlen,0,PR_INTERVAL_NO_TIMEOUT); - if (rv < 0) { - /* PR_Send() has invoked PR_SetError(). */ - rv = -1; - goto done; - } - count += rv; - bufptr = ((char*)bufptr + rv); - rlen -= rv; - } - } - if (rlen == 0) { - /* - * end-of-file - */ - if (flags & PR_TRANSMITFILE_CLOSE_SOCKET) - PR_Close(sd); - rv = count; - } else { - PR_ASSERT(rlen < 0); - /* PR_Read() has invoked PR_SetError(). */ - rv = -1; - } - -done: - if (buf) - PR_DELETE(buf); - return rv; -} -#else - -#define TRANSMITFILE_MMAP_CHUNK (256 * 1024) - -/* - * _PR_UnixTransmitFile - * - * Send file fd across socket sd. If headers is non-NULL, 'hlen' - * bytes of headers is sent before sending the file. - * - * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file - * - * return number of bytes sent or -1 on error - * - */ - -PRInt32 -ssl_EmulateTransmitFile( PRFileDesc * sd, - PRFileDesc * fd, - const void * headers, - PRInt32 hlen, - PRTransmitFileFlags flags, - PRIntervalTime timeout) -{ - void * addr = NULL; - PRFileMap * mapHandle = NULL; - PRInt32 count = 0; - PRInt32 index = 0; - PRInt32 len = 0; - PRInt32 rv; - struct PRFileInfo info; - struct PRIOVec iov[2]; - - /* Get file size */ - if (PR_SUCCESS != PR_GetOpenFileInfo(fd, &info)) { - count = -1; - goto done; - } - if (hlen) { - iov[index].iov_base = (char *) headers; - iov[index].iov_len = hlen; - index++; - } - if (info.size > 0) { - mapHandle = PR_CreateFileMap(fd, info.size, PR_PROT_READONLY); - if (mapHandle == NULL) { - count = -1; - goto done; - } - /* - * If the file is large, mmap and send the file in chunks so as - * to not consume too much virtual address space - */ - len = PR_MIN(info.size , TRANSMITFILE_MMAP_CHUNK ); - /* - * Map in (part of) file. Take care of zero-length files. - */ - if (len) { - addr = PR_MemMap(mapHandle, 0, len); - if (addr == NULL) { - count = -1; - goto done; - } - } - iov[index].iov_base = (char*)addr; - iov[index].iov_len = len; - index++; - } - if (!index) - goto done; - rv = PR_Writev(sd, iov, index, timeout); - if (len) { - PR_MemUnmap(addr, len); - } - if (rv >= 0) { - PR_ASSERT(rv == hlen + len); - info.size -= len; - count += rv; - } else { - count = -1; - goto done; - } - /* - * send remaining bytes of the file, if any - */ - len = PR_MIN(info.size , TRANSMITFILE_MMAP_CHUNK ); - while (len > 0) { - /* - * Map in (part of) file - */ - PR_ASSERT((count - hlen) % TRANSMITFILE_MMAP_CHUNK == 0); - addr = PR_MemMap(mapHandle, count - hlen, len); - if (addr == NULL) { - count = -1; - goto done; - } - rv = PR_Send(sd, addr, len, 0, timeout); - PR_MemUnmap(addr, len); - if (rv >= 0) { - PR_ASSERT(rv == len); - info.size -= rv; - count += rv; - len = PR_MIN(info.size , TRANSMITFILE_MMAP_CHUNK ); - } else { - count = -1; - goto done; - } - } -done: - if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) - PR_Close(sd); - if (mapHandle != NULL) - PR_CloseFileMap(mapHandle); - return count; -} -#endif /* XP_UNIX || WIN32 || XP_BEOS */ - - - - -#if !defined( XP_UNIX ) && !defined( WIN32 ) && !defined( XP_BEOS ) -/* - * _PR_EmulateSendFile - * - * Send file sfd->fd across socket sd. The header and trailer buffers - * specified in the 'sfd' argument are sent before and after the file, - * respectively. - * - * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file - * - * return number of bytes sent or -1 on error - * - */ - -PRInt32 -ssl_EmulateSendFile(PRFileDesc *sd, PRSendFileData *sfd, - PRTransmitFileFlags flags, PRIntervalTime timeout) -{ - char * buf = NULL; - const void * buffer; - PRInt32 rv; - PRInt32 count = 0; - PRInt32 rlen; - PRInt32 buflen; - PRInt32 sendbytes; - PRInt32 readbytes; - -#define _SENDFILE_BUFSIZE (16 * 1024) - - buf = (char*)PR_MALLOC(_SENDFILE_BUFSIZE); - if (buf == NULL) { - PR_SetError(PR_OUT_OF_MEMORY_ERROR, 0); - return -1; - } - - /* - * send header, first - */ - buflen = sfd->hlen; - buffer = sfd->header; - while (buflen) { - rv = PR_Send(sd, buffer, buflen, 0, timeout); - if (rv < 0) { - /* PR_Send() has invoked PR_SetError(). */ - rv = -1; - goto done; - } else { - count += rv; - buffer = (const void*) ((const char*)buffer + rv); - buflen -= rv; - } - } - /* - * send file, next - */ - - if (PR_Seek(sfd->fd, sfd->file_offset, PR_SEEK_SET) < 0) { - rv = -1; - goto done; - } - sendbytes = sfd->file_nbytes; - if (sendbytes == 0) { - /* send entire file */ - while ((rlen = PR_Read(sfd->fd, buf, _SENDFILE_BUFSIZE)) > 0) { - while (rlen) { - char *bufptr = buf; - - rv = PR_Send(sd, bufptr, rlen, 0, timeout); - if (rv < 0) { - /* PR_Send() has invoked PR_SetError(). */ - rv = -1; - goto done; - } else { - count += rv; - bufptr = ((char*)bufptr + rv); - rlen -= rv; - } - } - } - if (rlen < 0) { - /* PR_Read() has invoked PR_SetError(). */ - rv = -1; - goto done; - } - } else { - readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE); - while (readbytes && ((rlen = PR_Read(sfd->fd, buf, readbytes)) > 0)) { - while (rlen) { - char *bufptr = buf; - - rv = PR_Send(sd, bufptr, rlen, 0, timeout); - if (rv < 0) { - /* PR_Send() has invoked PR_SetError(). */ - rv = -1; - goto done; - } else { - count += rv; - sendbytes -= rv; - bufptr = ((char*)bufptr + rv); - rlen -= rv; - } - } - readbytes = PR_MIN(sendbytes, _SENDFILE_BUFSIZE); - } - if (rlen < 0) { - /* PR_Read() has invoked PR_SetError(). */ - rv = -1; - goto done; - } else if (sendbytes != 0) { - /* - * there are fewer bytes in file to send than specified - */ - PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); - rv = -1; - goto done; - } - } - /* - * send trailer, last - */ - buflen = sfd->tlen; - buffer = sfd->trailer; - while (buflen) { - rv = PR_Send(sd, buffer, buflen, 0, timeout); - if (rv < 0) { - /* PR_Send() has invoked PR_SetError(). */ - rv = -1; - goto done; - } else { - count += rv; - buffer = (const void*) ((const char*)buffer + rv); - buflen -= rv; - } - } - rv = count; - -done: - if (buf) - PR_DELETE(buf); - if ((rv >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) - PR_Close(sd); - return rv; -} - -#else /* UNIX, NT, and BEOS handled below */ - -/* - * _PR_UnixSendFile - * - * Send file sfd->fd across socket sd. If header/trailer are specified - * they are sent before and after the file, respectively. - * - * PR_TRANSMITFILE_CLOSE_SOCKET flag - close socket after sending file - * - * return number of bytes sent or -1 on error - * - */ -#define SENDFILE_MMAP_CHUNK (256 * 1024) - -PRInt32 -ssl_EmulateSendFile(PRFileDesc *sd, PRSendFileData *sfd, - PRTransmitFileFlags flags, PRIntervalTime timeout) -{ - void * addr = NULL; - PRFileMap * mapHandle = NULL; - PRInt32 count = 0; - PRInt32 file_bytes; - PRInt32 index = 0; - PRInt32 len; - PRInt32 rv; - PRUint32 addr_offset; - PRUint32 file_mmap_offset; - PRUint32 mmap_len; - PRUint32 pagesize; - struct PRFileInfo info; - struct PRIOVec iov[3]; - - /* Get file size */ - if (PR_SUCCESS != PR_GetOpenFileInfo(sfd->fd, &info)) { - count = -1; - goto done; - } - if (sfd->file_nbytes && - (info.size < (sfd->file_offset + sfd->file_nbytes))) { - /* - * there are fewer bytes in file to send than specified - */ - PR_SetError(PR_INVALID_ARGUMENT_ERROR, 0); - count = -1; - goto done; - } - if (sfd->file_nbytes) - file_bytes = sfd->file_nbytes; - else - file_bytes = info.size - sfd->file_offset; - -#if defined(WIN32) - { - SYSTEM_INFO sysinfo; - GetSystemInfo(&sysinfo); - pagesize = sysinfo.dwAllocationGranularity; - } -#else - pagesize = PR_GetPageSize(); -#endif - /* - * If the file is large, mmap and send the file in chunks so as - * to not consume too much virtual address space - */ - if (!sfd->file_offset || !(sfd->file_offset & (pagesize - 1))) { - /* - * case 1: page-aligned file offset - */ - mmap_len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK); - len = mmap_len; - file_mmap_offset = sfd->file_offset; - addr_offset = 0; - } else { - /* - * case 2: non page-aligned file offset - */ - /* find previous page boundary */ - file_mmap_offset = (sfd->file_offset & ~(pagesize - 1)); - - /* number of initial bytes to skip in mmap'd segment */ - addr_offset = sfd->file_offset - file_mmap_offset; - PR_ASSERT(addr_offset > 0); - mmap_len = PR_MIN(file_bytes + addr_offset, SENDFILE_MMAP_CHUNK); - len = mmap_len - addr_offset; - } - /* - * OK I've convinced myself that length has to be possitive (file_bytes is - * negative or SENDFILE_MMAP_CHUNK is less than pagesize). Just assert - * that this is the case so we catch problems in debug builds. - */ - PR_ASSERT(len >= 0); - - /* - * Map in (part of) file. Take care of zero-length files. - */ - if (len > 0) { - mapHandle = PR_CreateFileMap(sfd->fd, info.size, PR_PROT_READONLY); - if (!mapHandle) { - count = -1; - goto done; - } - addr = PR_MemMap(mapHandle, file_mmap_offset, mmap_len); - if (!addr) { - count = -1; - goto done; - } - } - /* - * send headers, first, followed by the file - */ - if (sfd->hlen) { - iov[index].iov_base = (char *) sfd->header; - iov[index].iov_len = sfd->hlen; - index++; - } - if (len) { - iov[index].iov_base = (char*)addr + addr_offset; - iov[index].iov_len = len; - index++; - } - if ((file_bytes == len) && (sfd->tlen)) { - /* - * all file data is mapped in; send the trailer too - */ - iov[index].iov_base = (char *) sfd->trailer; - iov[index].iov_len = sfd->tlen; - index++; - } - rv = PR_Writev(sd, iov, index, timeout); - if (len) - PR_MemUnmap(addr, mmap_len); - if (rv < 0) { - count = -1; - goto done; - } - - PR_ASSERT(rv == sfd->hlen + len + ((len == file_bytes) ? sfd->tlen : 0)); - - file_bytes -= len; - count += rv; - if (!file_bytes) /* header, file and trailer are sent */ - goto done; - - /* - * send remaining bytes of the file, if any - */ - len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK); - while (len > 0) { - /* - * Map in (part of) file - */ - file_mmap_offset = sfd->file_offset + count - sfd->hlen; - PR_ASSERT((file_mmap_offset % pagesize) == 0); - - addr = PR_MemMap(mapHandle, file_mmap_offset, len); - if (!addr) { - count = -1; - goto done; - } - rv = PR_Send(sd, addr, len, 0, timeout); - PR_MemUnmap(addr, len); - if (rv < 0) { - count = -1; - goto done; - } - - PR_ASSERT(rv == len); - file_bytes -= rv; - count += rv; - len = PR_MIN(file_bytes, SENDFILE_MMAP_CHUNK); - } - PR_ASSERT(0 == file_bytes); - if (sfd->tlen) { - rv = PR_Send(sd, sfd->trailer, sfd->tlen, 0, timeout); - if (rv >= 0) { - PR_ASSERT(rv == sfd->tlen); - count += rv; - } else - count = -1; - } -done: - if (mapHandle) - PR_CloseFileMap(mapHandle); - if ((count >= 0) && (flags & PR_TRANSMITFILE_CLOSE_SOCKET)) - PR_Close(sd); - return count; -} -#endif /* UNIX, NT, and BEOS */ diff --git a/security/nss/lib/ssl/manifest.mn b/security/nss/lib/ssl/manifest.mn index 6428ce5c7..06e2eb118 100644 --- a/security/nss/lib/ssl/manifest.mn +++ b/security/nss/lib/ssl/manifest.mn @@ -56,7 +56,6 @@ MAPFILE = $(OBJDIR)/ssl.def CSRCS = \ derive.c \ - emulate.c \ prelib.c \ ssl3con.c \ ssl3gthr.c \ diff --git a/security/nss/lib/ssl/ssl.rc b/security/nss/lib/ssl/ssl.rc index b20493219..b7d827de7 100644 --- a/security/nss/lib/ssl/ssl.rc +++ b/security/nss/lib/ssl/ssl.rc @@ -84,11 +84,10 @@ BEGIN BEGIN BLOCK "040904B0" // Lang=US English, CharSet=Unicode BEGIN - VALUE "CompanyName", "Netscape Communications Corporation\0" + VALUE "CompanyName", "Mozilla Foundation\0" VALUE "FileDescription", MY_FILEDESCRIPTION MY_DEBUG_STR "\0" VALUE "FileVersion", NSS_VERSION "\0" VALUE "InternalName", MY_INTERNAL_NAME "\0" - VALUE "LegalCopyright", "Copyright \251 1994-2001 Netscape Communications Corporation\0" VALUE "OriginalFilename", MY_INTERNAL_NAME ".dll\0" VALUE "ProductName", "Network Security Services\0" VALUE "ProductVersion", NSS_VERSION "\0" diff --git a/security/nss/lib/ssl/ssl3con.c b/security/nss/lib/ssl/ssl3con.c index 2b34b9519..217060b95 100644 --- a/security/nss/lib/ssl/ssl3con.c +++ b/security/nss/lib/ssl/ssl3con.c @@ -103,6 +103,10 @@ static SECStatus Null_Cipher(void *ctx, unsigned char *output, int *outputLen, */ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { /* cipher_suite policy enabled is_present*/ +#ifdef NSS_ENABLE_ECC + { TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, + { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, +#endif /* NSS_ENABLE_ECC */ { 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 @@ -112,7 +116,9 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { { TLS_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, #ifdef NSS_ENABLE_ECC + { TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, + { TLS_ECDHE_RSA_WITH_RC4_128_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}, @@ -128,6 +134,10 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { { 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}, +#ifdef NSS_ENABLE_ECC + { TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, + { TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, PR_FALSE,PR_FALSE}, +#endif /* NSS_ENABLE_ECC */ { 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 @@ -140,10 +150,6 @@ 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}, @@ -153,6 +159,8 @@ static ssl3CipherSuiteCfg cipherSuites[ssl_V3_SUITES_IMPLEMENTED] = { { SSL_RSA_EXPORT_WITH_RC2_CBC_40_MD5, SSL_NOT_ALLOWED, PR_TRUE, PR_FALSE}, #ifdef NSS_ENABLE_ECC + { TLS_ECDHE_ECDSA_WITH_NULL_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE}, + { TLS_ECDHE_RSA_WITH_NULL_SHA, SSL_NOT_ALLOWED, PR_FALSE, PR_FALSE}, { 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 */ @@ -236,6 +244,7 @@ static const ssl3KEADef kea_defs[] = {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}, + {kea_ecdh_anon, kt_ecdh, sign_null, PR_FALSE, 0, PR_FALSE}, #endif /* NSS_ENABLE_ECC */ }; @@ -315,24 +324,37 @@ static const ssl3CipherSuiteDef cipher_suite_defs[] = {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_ECDHE_ECDSA_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdhe_ecdsa}, + {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdhe_ecdsa}, + {TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdhe_ecdsa}, + {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdhe_ecdsa}, + {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdhe_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_NULL_SHA, cipher_null, mac_sha, kea_ecdhe_rsa}, + {TLS_ECDHE_RSA_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdhe_rsa}, + {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdhe_rsa}, + {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdhe_rsa}, + {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdhe_rsa}, - {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdhe_rsa}, +#if 0 + {TLS_ECDH_anon_WITH_NULL_SHA, cipher_null, mac_sha, kea_ecdh_anon}, + {TLS_ECDH_anon_WITH_RC4_128_SHA, cipher_rc4, mac_sha, kea_ecdh_anon}, + {TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA, cipher_3des, mac_sha, kea_ecdh_anon}, + {TLS_ECDH_anon_WITH_AES_128_CBC_SHA, cipher_aes_128, mac_sha, kea_ecdh_anon}, + {TLS_ECDH_anon_WITH_AES_256_CBC_SHA, cipher_aes_256, mac_sha, kea_ecdh_anon}, +#endif #endif /* NSS_ENABLE_ECC */ }; @@ -395,6 +417,29 @@ const char * const ssl3_cipherName[] = { "missing" }; +#ifdef NSS_ENABLE_ECC +/* The ECCWrappedKeyInfo structure defines how various pieces of + * information are laid out within wrappedSymmetricWrappingkey + * for ECDH key exchange. Since wrappedSymmetricWrappingkey is + * a 512-byte buffer (see sslimpl.h), the variable length field + * in ECCWrappedKeyInfo can be at most (512 - 8) = 504 bytes. + * + * XXX For now, NSS only supports named elliptic curves of size 571 bits + * or smaller. The public value will fit within 145 bytes and EC params + * will fit within 12 bytes. We'll need to revisit this when NSS + * supports arbitrary curves. + */ +#define MAX_EC_WRAPPED_KEY_BUFLEN 504 + +typedef struct ECCWrappedKeyInfoStr { + PRUint16 size; /* EC public key size in bits */ + PRUint16 encodedParamLen; /* length (in bytes) of DER encoded EC params */ + PRUint16 pubValueLen; /* length (in bytes) of EC public value */ + PRUint16 wrappedKeyLen; /* length (in bytes) of the wrapped key */ + PRUint8 var[MAX_EC_WRAPPED_KEY_BUFLEN]; /* this buffer contains the */ + /* EC public-key params, the EC public value and the wrapped key */ +} ECCWrappedKeyInfo; +#endif /* NSS_ENABLE_ECC */ #if defined(TRACE) @@ -450,6 +495,26 @@ SSL_GetStatistics(void) return &ssl3stats; } +typedef struct tooLongStr { +#if defined(IS_LITTLE_ENDIAN) + PRInt32 low; + PRInt32 high; +#else + PRInt32 high; + PRInt32 low; +#endif +} tooLong; + +static void SSL_AtomicIncrementLong(long * x) +{ + if ((sizeof *x) == sizeof(PRInt32)) { + PR_AtomicIncrement((PRInt32 *)x); + } else { + tooLong * tl = (tooLong *)x; + PR_AtomicIncrement(&tl->low) || PR_AtomicIncrement(&tl->high); + } +} + /* return pointer to ssl3CipherSuiteDef for suite, or NULL */ /* XXX This does a linear search. A binary search would be better. */ static const ssl3CipherSuiteDef * @@ -536,7 +601,15 @@ ssl3_config_match_init(sslSocket *ss) */ switch (cipher_def->key_exchange_alg) { case kea_ecdhe_rsa: +#if NSS_SERVER_DHE_IMPLEMENTED + /* XXX NSS does not yet implement the server side of _DHE_ + * cipher suites. Correcting the computation for svrAuth, + * as the case below does, causes NSS SSL servers to begin to + * negotiate cipher suites they do not implement. So, until + * server side _DHE_ is implemented, keep this disabled. + */ case kea_dhe_rsa: +#endif svrAuth = ss->serverCerts + kt_rsa; break; case kea_ecdh_ecdsa: @@ -715,7 +788,7 @@ ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, SECItem *buf, } buf->len = (unsigned)signatureLen; - buf->data = (unsigned char *)PORT_Alloc(signatureLen + 1); + buf->data = (unsigned char *)PORT_Alloc(signatureLen); if (!buf->data) goto done; /* error code was set. */ @@ -749,7 +822,7 @@ ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, SECItem *buf, SECItem derSig = {siBuffer, NULL, 0}; /* This also works for an ECDSA signature */ - rv = DSAU_EncodeDerSigWithLen(&derSig, buf, (unsigned) signatureLen); + rv = DSAU_EncodeDerSigWithLen(&derSig, buf, buf->len); if (rv == SECSuccess) { PORT_Free(buf->data); /* discard unencoded signature. */ *buf = derSig; /* give caller encoded signature. */ @@ -1693,32 +1766,166 @@ ssl3_ClientAuthTokenPresent(sslSessionID *sid) { return isPresent; } +static SECStatus +ssl3_CompressMACEncryptRecord(sslSocket * ss, + SSL3ContentType type, + const SSL3Opaque * pIn, + PRUint32 contentLen) +{ + ssl3CipherSpec * cwSpec; + const ssl3BulkCipherDef * cipher_def; + sslBuffer * wrBuf = &ss->sec.writeBuf; + SECStatus rv; + PRUint32 macLen = 0; + PRUint32 fragLen; + PRUint32 p1Len, p2Len, oddLen = 0; + PRInt32 cipherBytes = 0; + + /* + * null compression is easy to do + PORT_Memcpy(wrBuf->buf + SSL3_RECORD_HEADER_LENGTH, pIn, contentLen); + */ + + ssl_GetSpecReadLock(ss); /********************************/ + + cwSpec = ss->ssl3.cwSpec; + cipher_def = cwSpec->cipher_def; + /* + * Add the MAC + */ + rv = ssl3_ComputeRecordMAC( cwSpec, (PRBool)(ss->sec.isServer), + type, cwSpec->version, cwSpec->write_seq_num, pIn, contentLen, + wrBuf->buf + contentLen + SSL3_RECORD_HEADER_LENGTH, &macLen); + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE); + goto spec_locked_loser; + } + p1Len = contentLen; + p2Len = macLen; + fragLen = contentLen + macLen; /* needs to be encrypted */ + PORT_Assert(fragLen <= MAX_FRAGMENT_LENGTH + 1024); + + /* + * Pad the text (if we're doing a block cipher) + * then Encrypt it + */ + if (cipher_def->type == type_block) { + unsigned char * pBuf; + int padding_length; + int i; + + oddLen = contentLen % cipher_def->block_size; + /* Assume blockSize is a power of two */ + padding_length = cipher_def->block_size - 1 - + ((fragLen) & (cipher_def->block_size - 1)); + fragLen += padding_length + 1; + PORT_Assert((fragLen % cipher_def->block_size) == 0); + + /* Pad according to TLS rules (also acceptable to SSL3). */ + pBuf = &wrBuf->buf[fragLen + SSL3_RECORD_HEADER_LENGTH - 1]; + for (i = padding_length + 1; i > 0; --i) { + *pBuf-- = padding_length; + } + /* now, if contentLen is not a multiple of block size, fix it */ + p2Len = fragLen - p1Len; + } + if (p1Len < 256) { + oddLen = p1Len; + p1Len = 0; + } else { + p1Len -= oddLen; + } + if (oddLen) { + p2Len += oddLen; + PORT_Assert( (cipher_def->block_size < 2) || \ + (p2Len % cipher_def->block_size) == 0); + memcpy(wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + p1Len, + pIn + p1Len, oddLen); + } + if (p1Len > 0) { + rv = cwSpec->encode( cwSpec->encodeContext, + wrBuf->buf + SSL3_RECORD_HEADER_LENGTH, /* output */ + &cipherBytes, /* actual outlen */ + p1Len, /* max outlen */ + pIn, p1Len); /* input, and inputlen */ + PORT_Assert(rv == SECSuccess && cipherBytes == p1Len); + if (rv != SECSuccess || cipherBytes != p1Len) { + PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); + goto spec_locked_loser; + } + } + if (p2Len > 0) { + PRInt32 cipherBytesPart2 = -1; + rv = cwSpec->encode( cwSpec->encodeContext, + wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + p1Len, + &cipherBytesPart2, /* output and actual outLen */ + p2Len, /* max outlen */ + wrBuf->buf + SSL3_RECORD_HEADER_LENGTH + p1Len, + p2Len); /* input and inputLen*/ + PORT_Assert(rv == SECSuccess && cipherBytesPart2 == p2Len); + if (rv != SECSuccess || cipherBytesPart2 != p2Len) { + PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); + goto spec_locked_loser; + } + cipherBytes += cipherBytesPart2; + } + if (rv != SECSuccess) { + ssl_MapLowLevelError(SSL_ERROR_ENCRYPTION_FAILURE); +spec_locked_loser: + ssl_ReleaseSpecReadLock(ss); + return SECFailure; + } + PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 1024); + + ssl3_BumpSequenceNumber(&cwSpec->write_seq_num); + + wrBuf->len = cipherBytes + SSL3_RECORD_HEADER_LENGTH; + wrBuf->buf[0] = type; + wrBuf->buf[1] = MSB(cwSpec->version); + wrBuf->buf[2] = LSB(cwSpec->version); + wrBuf->buf[3] = MSB(cipherBytes); + wrBuf->buf[4] = LSB(cipherBytes); + + ssl_ReleaseSpecReadLock(ss); /************************************/ + + return SECSuccess; +} + /* Process the plain text before sending it. * Returns the number of bytes of plaintext that were succesfully sent * plus the number of bytes of plaintext that were copied into the * output (write) buffer. * Returns SECFailure on a hard IO error, memory error, or crypto error. * Does NOT return SECWouldBlock. + * + * Notes on the use of the private ssl flags: + * (no private SSL flags) + * Attempt to make and send SSL records for all plaintext + * If non-blocking and a send gets WOULD_BLOCK, + * or if the pending (ciphertext) buffer is not empty, + * then buffer remaining bytes of ciphertext into pending buf, + * and continue to do that for all succssive records until all + * bytes are used. + * ssl_SEND_FLAG_FORCE_INTO_BUFFER + * As above, except this suppresses all write attempts, and forces + * all ciphertext into the pending ciphertext buffer. + * */ static PRInt32 ssl3_SendRecord( sslSocket * ss, SSL3ContentType type, - const SSL3Opaque * buf, - PRInt32 bytes, + const SSL3Opaque * pIn, /* input buffer */ + PRInt32 nIn, /* bytes of input */ PRInt32 flags) { - ssl3CipherSpec * cwSpec; - sslBuffer * write = &ss->sec.writeBuf; - const ssl3BulkCipherDef * cipher_def; + sslBuffer * wrBuf = &ss->sec.writeBuf; SECStatus rv; - PRUint32 bufSize = 0; - PRInt32 sent = 0; - PRBool isBlocking = ssl_SocketIsBlocking(ss); + PRInt32 totalSent = 0; - SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s bytes=%d", + SSL_TRC(3, ("%d: SSL3[%d] SendRecord type: %s nIn=%d", SSL_GETPID(), ss->fd, ssl3_DecodeContentType(type), - bytes)); - PRINT_BUF(3, (ss, "Send record (plain text)", buf, bytes)); + nIn)); + PRINT_BUF(3, (ss, "Send record (plain text)", pIn, nIn)); PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); @@ -1740,149 +1947,30 @@ ssl3_SendRecord( sslSocket * ss, return SECFailure; } - while (bytes > 0) { - PRInt32 count; - PRUint32 contentLen; - PRUint32 fragLen; - PRUint32 macLen; - PRInt32 cipherBytes = 0; - PRUint32 p1Len, p2Len, oddLen = 0; + while (nIn > 0) { + PRUint32 contentLen = PR_MIN(nIn, MAX_FRAGMENT_LENGTH); - contentLen = PR_MIN(bytes, MAX_FRAGMENT_LENGTH); - if (write->space < contentLen + SSL3_BUFFER_FUDGE) { - rv = sslBuffer_Grow(write, contentLen + SSL3_BUFFER_FUDGE); + if (wrBuf->space < contentLen + SSL3_BUFFER_FUDGE) { + PRInt32 newSpace = PR_MAX(wrBuf->space * 2, contentLen); + newSpace = PR_MIN(newSpace, MAX_FRAGMENT_LENGTH); + newSpace += SSL3_BUFFER_FUDGE; + rv = sslBuffer_Grow(wrBuf, newSpace); if (rv != SECSuccess) { SSL_DBG(("%d: SSL3[%d]: SendRecord, tried to get %d bytes", - SSL_GETPID(), ss->fd, contentLen + SSL3_BUFFER_FUDGE)); + SSL_GETPID(), ss->fd, newSpace)); return SECFailure; /* sslBuffer_Grow set a memory error code. */ } } - /* This variable records the actual size of the buffer allocated above. - * Some algorithms may expand the number of bytes needed to send data. - * If we only supply the output buffer with the same number - * of bytes as the input buffer, we will fail. - */ - bufSize = contentLen + SSL3_BUFFER_FUDGE; - - /* - * null compression is easy to do - PORT_Memcpy(write->buf + SSL3_RECORD_HEADER_LENGTH, buf, contentLen); - */ - - ssl_GetSpecReadLock(ss); /********************************/ - - cwSpec = ss->ssl3.cwSpec; - cipher_def = cwSpec->cipher_def; - /* - * Add the MAC - */ - rv = ssl3_ComputeRecordMAC( cwSpec, (PRBool)(ss->sec.isServer), - type, cwSpec->version, cwSpec->write_seq_num, buf, contentLen, - write->buf + contentLen + SSL3_RECORD_HEADER_LENGTH, &macLen); - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_MAC_COMPUTATION_FAILURE); - goto spec_locked_loser; - } - p1Len = contentLen; - p2Len = macLen; - fragLen = contentLen + macLen; /* needs to be encrypted */ - PORT_Assert(fragLen <= MAX_FRAGMENT_LENGTH + 1024); - - /* - * Pad the text (if we're doing a block cipher) - * then Encrypt it - */ - if (cipher_def->type == type_block) { - unsigned char * pBuf; - int padding_length; - int i; - - oddLen = contentLen % cipher_def->block_size; - /* Assume blockSize is a power of two */ - padding_length = cipher_def->block_size - 1 - - ((fragLen) & (cipher_def->block_size - 1)); - fragLen += padding_length + 1; - PORT_Assert((fragLen % cipher_def->block_size) == 0); - - /* Pad according to TLS rules (also acceptable to SSL3). */ - pBuf = &write->buf[fragLen + SSL3_RECORD_HEADER_LENGTH - 1]; - for (i = padding_length + 1; i > 0; --i) { - *pBuf-- = padding_length; - } - /* now, if contentLen is not a multiple of block size, fix it */ - p2Len = fragLen - p1Len; - } - if (p1Len < 256) { - oddLen = p1Len; - p1Len = 0; - } else { - p1Len -= oddLen; - } - if (oddLen) { - p2Len += oddLen; - PORT_Assert( (cipher_def->block_size < 2) || \ - (p2Len % cipher_def->block_size) == 0); - memcpy(write->buf + SSL3_RECORD_HEADER_LENGTH + p1Len, - buf + p1Len, oddLen); - } - if (p1Len > 0) { - rv = cwSpec->encode( cwSpec->encodeContext, - write->buf + SSL3_RECORD_HEADER_LENGTH, /* output */ - &cipherBytes, /* actual outlen */ - p1Len, /* max outlen */ - buf, p1Len); /* input, and inputlen */ - PORT_Assert(rv == SECSuccess && cipherBytes == p1Len); - if (rv != SECSuccess || cipherBytes != p1Len) { - PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); - goto spec_locked_loser; - } - } - if (p2Len > 0) { - PRInt32 cipherBytesPart2 = -1; - rv = cwSpec->encode( cwSpec->encodeContext, - write->buf + SSL3_RECORD_HEADER_LENGTH + p1Len, - &cipherBytesPart2, /* output and actual outLen */ - p2Len, /* max outlen */ - write->buf + SSL3_RECORD_HEADER_LENGTH + p1Len, - p2Len); /* input and inputLen*/ - PORT_Assert(rv == SECSuccess && cipherBytesPart2 == p2Len); - if (rv != SECSuccess || cipherBytesPart2 != p2Len) { - PORT_SetError(SSL_ERROR_ENCRYPTION_FAILURE); - goto spec_locked_loser; - } - cipherBytes += cipherBytesPart2; - } - if (rv != SECSuccess) { - ssl_MapLowLevelError(SSL_ERROR_ENCRYPTION_FAILURE); -spec_locked_loser: - ssl_ReleaseSpecReadLock(ss); + rv = ssl3_CompressMACEncryptRecord( ss, type, pIn, contentLen); + if (rv != SECSuccess) return SECFailure; - } - PORT_Assert(cipherBytes <= MAX_FRAGMENT_LENGTH + 1024); - - /* - * XXX should we zero out our copy of the buffer after compressing - * and encryption ?? - */ - ssl3_BumpSequenceNumber(&cwSpec->write_seq_num); + pIn += contentLen; + nIn -= contentLen; + PORT_Assert( nIn >= 0 ); - ssl_ReleaseSpecReadLock(ss); /************************************/ - - buf += contentLen; - bytes -= contentLen; - PORT_Assert( bytes >= 0 ); - - /* PORT_Assert(fragLen == cipherBytes); */ - write->len = cipherBytes + SSL3_RECORD_HEADER_LENGTH; - write->buf[0] = type; - write->buf[1] = MSB(cwSpec->version); - write->buf[2] = LSB(cwSpec->version); - write->buf[3] = MSB(cipherBytes); - write->buf[4] = LSB(cipherBytes); - - PRINT_BUF(50, (ss, "send (encrypted) record data:", write->buf, write->len)); + PRINT_BUF(50, (ss, "send (encrypted) record data:", wrBuf->buf, wrBuf->len)); /* If there's still some previously saved ciphertext, * or the caller doesn't want us to send the data yet, @@ -1891,59 +1979,57 @@ spec_locked_loser: if ((ss->pendingBuf.len > 0) || (flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) { - rv = ssl_SaveWriteData(ss, &ss->pendingBuf, - write->buf, write->len); + rv = ssl_SaveWriteData(ss, wrBuf->buf, wrBuf->len); if (rv != SECSuccess) { /* presumably a memory error, SEC_ERROR_NO_MEMORY */ return SECFailure; } - write->len = 0; /* All cipher text is saved away. */ + wrBuf->len = 0; /* All cipher text is saved away. */ if (!(flags & ssl_SEND_FLAG_FORCE_INTO_BUFFER)) { - + PRInt32 sent; ss->handshakeBegun = 1; - count = ssl_SendSavedWriteData(ss, &ss->pendingBuf, - &ssl_DefSend); - if (count < 0 && PR_GetError() != PR_WOULD_BLOCK_ERROR) { + sent = ssl_SendSavedWriteData(ss); + if (sent < 0 && PR_GetError() != PR_WOULD_BLOCK_ERROR) { ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE); return SECFailure; } + if (ss->pendingBuf.len) { + flags |= ssl_SEND_FLAG_FORCE_INTO_BUFFER; + } } - } else if (write->len > 0) { + } else if (wrBuf->len > 0) { + PRInt32 sent; ss->handshakeBegun = 1; - count = ssl_DefSend(ss, write->buf, write->len, - flags & ~ssl_SEND_FLAG_MASK); - if (count < 0) { + sent = ssl_DefSend(ss, wrBuf->buf, wrBuf->len, + flags & ~ssl_SEND_FLAG_MASK); + if (sent < 0) { if (PR_GetError() != PR_WOULD_BLOCK_ERROR) { ssl_MapLowLevelError(SSL_ERROR_SOCKET_WRITE_FAILURE); - return (sent > 0) ? sent : SECFailure; + return SECFailure; } /* we got PR_WOULD_BLOCK_ERROR, which means none was sent. */ - count = 0; + sent = 0; } - /* now take all the remaining unsent newly-generated ciphertext and - * append it to the buffer of previously unsent ciphertext. - */ - if ((unsigned)count < write->len) { - rv = ssl_SaveWriteData(ss, &ss->pendingBuf, - write->buf + (unsigned)count, - write->len - (unsigned)count); + wrBuf->len -= sent; + if (wrBuf->len) { + /* now take all the remaining unsent new ciphertext and + * append it to the buffer of previously unsent ciphertext. + */ + rv = ssl_SaveWriteData(ss, wrBuf->buf + sent, wrBuf->len); if (rv != SECSuccess) { /* presumably a memory error, SEC_ERROR_NO_MEMORY */ return SECFailure; } } - write->len = 0; - } - sent += contentLen; - if ((flags & ssl_SEND_FLAG_NO_BUFFER) && - (isBlocking || (ss->pendingBuf.len > 0))) { - break; } + totalSent += contentLen; } - return sent; + return totalSent; } +#define SSL3_PENDING_HIGH_WATER 1024 + /* Attempt to send the content of "in" in an SSL application_data record. * Returns "len" or SECFailure, never SECWouldBlock, nor SECSuccess. */ @@ -1951,14 +2037,36 @@ int ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in, PRInt32 len, PRInt32 flags) { - PRInt32 sent = 0; + PRInt32 totalSent = 0; + PRInt32 discarded = 0; PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); + if (len < 0 || !in) { + PORT_SetError(PR_INVALID_ARGUMENT_ERROR); + return SECFailure; + } + + if (ss->pendingBuf.len > SSL3_PENDING_HIGH_WATER && + !ssl_SocketIsBlocking(ss)) { + PORT_Assert(!ssl_SocketIsBlocking(ss)); + PORT_SetError(PR_WOULD_BLOCK_ERROR); + return SECFailure; + } - while (len > 0) { - PRInt32 count; + if (ss->appDataBuffered && len) { + PORT_Assert (in[0] == (unsigned char)(ss->appDataBuffered)); + if (in[0] != (unsigned char)(ss->appDataBuffered)) { + PORT_SetError(PR_INVALID_ARGUMENT_ERROR); + return SECFailure; + } + in++; + len--; + discarded = 1; + } + while (len > totalSent) { + PRInt32 sent, toSend; - if (sent > 0) { + if (totalSent > 0) { /* * The thread yield is intended to give the reader thread a * chance to get some cycles while the writer thread is in @@ -1969,23 +2077,45 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in, PR_Sleep(PR_INTERVAL_NO_WAIT); /* PR_Yield(); */ ssl_GetXmitBufLock(ss); } - count = ssl3_SendRecord(ss, content_application_data, in, len, - flags | ssl_SEND_FLAG_NO_BUFFER); - if (count < 0) { - return (sent > 0) ? sent : count; - /* error code set by ssl3_SendRecord */ + toSend = PR_MIN(len - totalSent, MAX_FRAGMENT_LENGTH); + sent = ssl3_SendRecord(ss, content_application_data, + in + totalSent, toSend, flags); + if (sent < 0) { + if (totalSent > 0 && PR_GetError() == PR_WOULD_BLOCK_ERROR) { + PORT_Assert(ss->lastWriteBlocked); + break; + } + return SECFailure; /* error code set by ssl3_SendRecord */ + } + totalSent += sent; + if (ss->pendingBuf.len) { + /* must be a non-blocking socket */ + PORT_Assert(!ssl_SocketIsBlocking(ss)); + PORT_Assert(ss->lastWriteBlocked); + break; } - sent += count; - len -= count; - in += count; } - return sent; + if (ss->pendingBuf.len) { + /* Must be non-blocking. */ + PORT_Assert(!ssl_SocketIsBlocking(ss)); + if (totalSent > 0) { + ss->appDataBuffered = 0x100 | in[totalSent - 1]; + } + + totalSent = totalSent + discarded - 1; + if (totalSent <= 0) { + PORT_SetError(PR_WOULD_BLOCK_ERROR); + totalSent = SECFailure; + } + return totalSent; + } + ss->appDataBuffered = 0; + return totalSent + discarded; } /* Attempt to send the content of sendBuf buffer in an SSL handshake record. * This function returns SECSuccess or SECFailure, never SECWouldBlock. - * It used to always set sendBuf.len to 0, even when returning SECFailure. - * Now it does not. + * Always set sendBuf.len to 0, even when returning SECFailure. * * Called from SSL3_SendAlert(), ssl3_SendChangeCipherSpecs(), * ssl3_AppendHandshake(), ssl3_SendClientHello(), @@ -1995,21 +2125,41 @@ ssl3_SendApplicationData(sslSocket *ss, const unsigned char *in, static SECStatus ssl3_FlushHandshake(sslSocket *ss, PRInt32 flags) { - PRInt32 rv; + PRInt32 rv = SECSuccess; PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss)); PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); if (!ss->sec.ci.sendBuf.buf || !ss->sec.ci.sendBuf.len) - return SECSuccess; + return rv; - rv = ssl3_SendRecord(ss, content_handshake, ss->sec.ci.sendBuf.buf, - ss->sec.ci.sendBuf.len, flags); - if (rv < 0) { - return (SECStatus)rv; /* error code set by ssl3_SendRecord */ + /* only this flag is allowed */ + PORT_Assert(!(flags & ~ssl_SEND_FLAG_FORCE_INTO_BUFFER)); + if ((flags & ~ssl_SEND_FLAG_FORCE_INTO_BUFFER) != 0) { + PORT_SetError(SEC_ERROR_INVALID_ARGS); + rv = SECFailure; + } else { + rv = ssl3_SendRecord(ss, content_handshake, ss->sec.ci.sendBuf.buf, + ss->sec.ci.sendBuf.len, flags); + } + if (rv < 0) { + int err = PORT_GetError(); + PORT_Assert(err != PR_WOULD_BLOCK_ERROR); + if (err == PR_WOULD_BLOCK_ERROR) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + } + } else if (rv < ss->sec.ci.sendBuf.len) { + /* short write should never happen */ + PORT_Assert(rv >= ss->sec.ci.sendBuf.len); + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + rv = SECFailure; + } else { + rv = SECSuccess; } + + /* Whether we succeeded or failed, toss the old handshake data. */ ss->sec.ci.sendBuf.len = 0; - return SECSuccess; + return rv; } /* @@ -2218,7 +2368,19 @@ ssl3_HandleAlert(sslSocket *ss, sslBuffer *buf) case internal_error: error = SSL_ERROR_INTERNAL_ERROR_ALERT; break; case user_canceled: error = SSL_ERROR_USER_CANCELED_ALERT; break; case no_renegotiation: error = SSL_ERROR_NO_RENEGOTIATION_ALERT; break; - default: error = SSL_ERROR_RX_UNKNOWN_ALERT; break; + + /* Alerts for TLS client hello extensions */ + case unsupported_extension: + error = SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT; break; + case certificate_unobtainable: + error = SSL_ERROR_CERTIFICATE_UNOBTAINABLE_ALERT; break; + case unrecognized_name: + error = SSL_ERROR_UNRECOGNIZED_NAME_ALERT; break; + case bad_certificate_status_response: + error = SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT; break; + case bad_certificate_hash_value: + error = SSL_ERROR_BAD_CERT_HASH_VALUE_ALERT; break; + default: error = SSL_ERROR_RX_UNKNOWN_ALERT; break; } if (level == alert_fatal) { ss->sec.uncache(ss->sec.ci.sid); @@ -2348,7 +2510,7 @@ ssl3_HandleChangeCipherSpecs(sslSocket *ss, sslBuffer *buf) ss->ssl3.prSpec = ss->ssl3.crSpec; ss->ssl3.crSpec = prSpec; - ss->ssl3.hs.ws = wait_finished; + ss->ssl3.hs.ws = wait_finished; SSL_TRC(3, ("%d: SSL3[%d] Set Current Read Cipher Suite to Pending", SSL_GETPID(), ss->fd )); @@ -2715,7 +2877,7 @@ ssl3_AppendHandshake(sslSocket *ss, const void *void_src, PRInt32 bytes) return SECSuccess; } -static SECStatus +SECStatus ssl3_AppendHandshakeNumber(sslSocket *ss, PRInt32 num, PRInt32 lenSize) { SECStatus rv; @@ -2820,7 +2982,7 @@ ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes, SSL3Opaque **b, * Thus, the largest value that may be sent this way is 0x7fffffff. * On error, an alert has been sent, and a generic error code has been set. */ -static PRInt32 +PRInt32 ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes, SSL3Opaque **b, PRUint32 *length) { @@ -3192,6 +3354,7 @@ ssl3_SendClientHello(sslSocket *ss) int length; int num_suites; int actual_count = 0; + PRInt32 total_exten_len = 0; SSL_TRC(3, ("%d: SSL3[%d]: send client_hello handshake", SSL_GETPID(), ss->fd)); @@ -3269,7 +3432,7 @@ ssl3_SendClientHello(sslSocket *ss) } if (!sidOK) { - ++ssl3stats.sch_sid_cache_not_ok; + SSL_AtomicIncrementLong(& ssl3stats.sch_sid_cache_not_ok ); (*ss->sec.uncache)(sid); ssl_FreeSID(sid); sid = NULL; @@ -3277,7 +3440,7 @@ ssl3_SendClientHello(sslSocket *ss) } if (sid) { - ++ssl3stats.sch_sid_cache_hits; + SSL_AtomicIncrementLong(& ssl3stats.sch_sid_cache_hits ); rv = ssl3_NegotiateVersion(ss, sid->version); if (rv != SECSuccess) @@ -3288,7 +3451,7 @@ ssl3_SendClientHello(sslSocket *ss) ss->ssl3.policy = sid->u.ssl3.policy; } else { - ++ssl3stats.sch_sid_cache_misses; + SSL_AtomicIncrementLong(& ssl3stats.sch_sid_cache_misses ); rv = ssl3_NegotiateVersion(ss, SSL_LIBRARY_VERSION_3_1_TLS); if (rv != SECSuccess) @@ -3327,6 +3490,21 @@ ssl3_SendClientHello(sslSocket *ss) if (!num_suites) return SECFailure; /* ssl3_config_match_init has set error code. */ + if (ss->opt.enableTLS) { + PRUint32 maxBytes = 65535; /* 2^16 - 1 */ + PRInt32 extLen; + + extLen = ssl3_CallHelloExtensionSenders(ss, PR_FALSE, maxBytes, NULL); + if (extLen < 0) { + return SECFailure; + } + maxBytes -= extLen; + total_exten_len += extLen; + + if (total_exten_len > 0) + total_exten_len += 2; + } + /* how many suites are permitted by policy and user preference? */ num_suites = count_cipher_suites(ss, ss->ssl3.policy, PR_TRUE); if (!num_suites) @@ -3335,7 +3513,7 @@ ssl3_SendClientHello(sslSocket *ss) length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH + 1 + ((sid == NULL) ? 0 : sid->u.ssl3.sessionIDLength) + 2 + num_suites*sizeof(ssl3CipherSuite) + - 1 + compressionMethodsCount; + 1 + compressionMethodsCount + total_exten_len; rv = ssl3_AppendHandshakeHeader(ss, client_hello, length); if (rv != SECSuccess) { @@ -3409,6 +3587,24 @@ ssl3_SendClientHello(sslSocket *ss) } } + if (total_exten_len) { + PRUint32 maxBytes = total_exten_len - 2; + PRInt32 extLen; + + rv = ssl3_AppendHandshakeNumber(ss, maxBytes, 2); + if (rv != SECSuccess) { + return rv; /* err set by AppendHandshake. */ + } + + extLen = ssl3_CallHelloExtensionSenders(ss, PR_TRUE, maxBytes, NULL); + if (extLen < 0) { + return SECFailure; + } + maxBytes -= extLen; + PORT_Assert(!maxBytes); + } + + rv = ssl3_FlushHandshake(ss, 0); if (rv != SECSuccess) { return rv; /* error code set by ssl3_FlushHandshake */ @@ -3470,6 +3666,7 @@ static const CK_MECHANISM_TYPE wrapMechanismList[SSL_NUM_WRAP_MECHS] = { CKM_CDMF_ECB, CKM_SKIPJACK_WRAP, CKM_SKIPJACK_CBC64, + CKM_AES_ECB, UNKNOWN_WRAP_MECHANISM }; @@ -3495,6 +3692,11 @@ ssl_UnwrapSymWrappingKey( { PK11SymKey * unwrappedWrappingKey = NULL; SECItem wrappedKey; +#ifdef NSS_ENABLE_ECC + PK11SymKey * Ks; + SECKEYPublicKey pubWrapKey; + ECCWrappedKeyInfo *ecWrapped; +#endif /* NSS_ENABLE_ECC */ /* found the wrapping key on disk. */ PORT_Assert(pWswk->symWrapMechanism == masterWrapMech); @@ -3515,6 +3717,60 @@ ssl_UnwrapSymWrappingKey( PK11_PubUnwrapSymKey(svrPrivKey, &wrappedKey, masterWrapMech, CKA_UNWRAP, 0); break; + +#ifdef NSS_ENABLE_ECC + case kt_ecdh: + /* + * For kt_ecdh, we first create an EC public key based on + * data stored with the wrappedSymmetricWrappingkey. Next, + * we do an ECDH computation involving this public key and + * the SSL server's (long-term) EC private key. The resulting + * shared secret is treated the same way as Fortezza's Ks, i.e., + * it is used to recover the symmetric wrapping key. + * + * The data in wrappedSymmetricWrappingkey is laid out as defined + * in the ECCWrappedKeyInfo structure. + */ + ecWrapped = (ECCWrappedKeyInfo *) pWswk->wrappedSymmetricWrappingkey; + + PORT_Assert(ecWrapped->encodedParamLen + ecWrapped->pubValueLen + + ecWrapped->wrappedKeyLen <= MAX_EC_WRAPPED_KEY_BUFLEN); + + if (ecWrapped->encodedParamLen + ecWrapped->pubValueLen + + ecWrapped->wrappedKeyLen > MAX_EC_WRAPPED_KEY_BUFLEN) { + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + goto loser; + } + + pubWrapKey.keyType = ecKey; + pubWrapKey.u.ec.size = ecWrapped->size; + pubWrapKey.u.ec.DEREncodedParams.len = ecWrapped->encodedParamLen; + pubWrapKey.u.ec.DEREncodedParams.data = ecWrapped->var; + pubWrapKey.u.ec.publicValue.len = ecWrapped->pubValueLen; + pubWrapKey.u.ec.publicValue.data = ecWrapped->var + + ecWrapped->encodedParamLen; + + wrappedKey.len = ecWrapped->wrappedKeyLen; + wrappedKey.data = ecWrapped->var + ecWrapped->encodedParamLen + + ecWrapped->pubValueLen; + + /* Derive Ks using ECDH */ + Ks = PK11_PubDeriveWithKDF(svrPrivKey, &pubWrapKey, PR_FALSE, NULL, + NULL, CKM_ECDH1_DERIVE, masterWrapMech, + CKA_DERIVE, 0, CKD_NULL, NULL, NULL); + if (Ks == NULL) { + goto loser; + } + + /* Use Ks to unwrap the wrapping key */ + unwrappedWrappingKey = PK11_UnwrapSymKey(Ks, masterWrapMech, NULL, + &wrappedKey, masterWrapMech, + CKA_UNWRAP, 0); + PK11_FreeSymKey(Ks); + + break; +#endif + default: /* Assert? */ SET_ERROR_CODE @@ -3580,7 +3836,6 @@ getWrappingKey( sslSocket * ss, CK_MECHANISM_TYPE masterWrapMech, void * pwArg) { - CERTCertificate * svrCert; SECKEYPrivateKey * svrPrivKey; SECKEYPublicKey * svrPubKey = NULL; PK11SymKey * unwrappedWrappingKey = NULL; @@ -3650,12 +3905,12 @@ getWrappingKey( sslSocket * ss, */ PORT_Memset(&wswk, 0, sizeof wswk); /* eliminate UMRs. */ - svrCert = ss->serverCerts[exchKeyType].serverCert; - svrPubKey = CERT_ExtractPublicKey(svrCert); + if (ss->serverCerts[exchKeyType].serverKeyPair) { + svrPubKey = ss->serverCerts[exchKeyType].serverKeyPair->pubKey; + } if (svrPubKey == NULL) { - /* CERT_ExtractPublicKey doesn't set error code */ - PORT_SetError(SSL_ERROR_EXTRACT_PUBLIC_KEY_FAILURE); - goto loser; + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + goto loser; } wrappedKey.type = siBuffer; wrappedKey.len = SECKEY_PublicKeyStrength(svrPubKey); @@ -3667,6 +3922,12 @@ getWrappingKey( sslSocket * ss, /* wrap symmetric wrapping key in server's public key. */ switch (exchKeyType) { +#ifdef NSS_ENABLE_ECC + PK11SymKey * Ks; + SECKEYPublicKey *pubWrapKey = NULL; + SECKEYPrivateKey *privWrapKey = NULL; + ECCWrappedKeyInfo *ecWrapped; +#endif /* NSS_ENABLE_ECC */ case kt_rsa: asymWrapMechanism = CKM_RSA_PKCS; @@ -3674,6 +3935,94 @@ getWrappingKey( sslSocket * ss, unwrappedWrappingKey, &wrappedKey); break; +#ifdef NSS_ENABLE_ECC + case kt_ecdh: + /* + * We generate an ephemeral EC key pair. Perform an ECDH + * computation involving this ephemeral EC public key and + * the SSL server's (long-term) EC private key. The resulting + * shared secret is treated in the same way as Fortezza's Ks, + * i.e., it is used to wrap the wrapping key. To facilitate + * unwrapping in ssl_UnwrapWrappingKey, we also store all + * relevant info about the ephemeral EC public key in + * wswk.wrappedSymmetricWrappingkey and lay it out as + * described in the ECCWrappedKeyInfo structure. + */ + PORT_Assert(svrPubKey->keyType == ecKey); + if (svrPubKey->keyType != ecKey) { + /* something is wrong in sslsecur.c if this isn't an ecKey */ + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + rv = SECFailure; + goto ec_cleanup; + } + + privWrapKey = SECKEY_CreateECPrivateKey( + &svrPubKey->u.ec.DEREncodedParams, &pubWrapKey, NULL); + if ((privWrapKey == NULL) || (pubWrapKey == NULL)) { + rv = SECFailure; + goto ec_cleanup; + } + + /* Set the key size in bits */ + if (pubWrapKey->u.ec.size == 0) { + pubWrapKey->u.ec.size = SECKEY_PublicKeyStrengthInBits(svrPubKey); + } + + PORT_Assert(pubWrapKey->u.ec.DEREncodedParams.len + + pubWrapKey->u.ec.publicValue.len < MAX_EC_WRAPPED_KEY_BUFLEN); + if (pubWrapKey->u.ec.DEREncodedParams.len + + pubWrapKey->u.ec.publicValue.len >= MAX_EC_WRAPPED_KEY_BUFLEN) { + PORT_SetError(SEC_ERROR_INVALID_KEY); + rv = SECFailure; + goto ec_cleanup; + } + + /* Derive Ks using ECDH */ + Ks = PK11_PubDeriveWithKDF(svrPrivKey, pubWrapKey, PR_FALSE, NULL, + NULL, CKM_ECDH1_DERIVE, masterWrapMech, + CKA_DERIVE, 0, CKD_NULL, NULL, NULL); + if (Ks == NULL) { + rv = SECFailure; + goto ec_cleanup; + } + + ecWrapped = (ECCWrappedKeyInfo *) (wswk.wrappedSymmetricWrappingkey); + ecWrapped->size = pubWrapKey->u.ec.size; + ecWrapped->encodedParamLen = pubWrapKey->u.ec.DEREncodedParams.len; + PORT_Memcpy(ecWrapped->var, pubWrapKey->u.ec.DEREncodedParams.data, + pubWrapKey->u.ec.DEREncodedParams.len); + + ecWrapped->pubValueLen = pubWrapKey->u.ec.publicValue.len; + PORT_Memcpy(ecWrapped->var + ecWrapped->encodedParamLen, + pubWrapKey->u.ec.publicValue.data, + pubWrapKey->u.ec.publicValue.len); + + wrappedKey.len = MAX_EC_WRAPPED_KEY_BUFLEN - + (ecWrapped->encodedParamLen + ecWrapped->pubValueLen); + wrappedKey.data = ecWrapped->var + ecWrapped->encodedParamLen + + ecWrapped->pubValueLen; + + /* wrap symmetricWrapping key with the local Ks */ + rv = PK11_WrapSymKey(masterWrapMech, NULL, Ks, + unwrappedWrappingKey, &wrappedKey); + + if (rv != SECSuccess) { + goto ec_cleanup; + } + + /* Write down the length of wrapped key in the buffer + * wswk.wrappedSymmetricWrappingkey at the appropriate offset + */ + ecWrapped->wrappedKeyLen = wrappedKey.len; + +ec_cleanup: + if (privWrapKey) SECKEY_DestroyPrivateKey(privWrapKey); + if (pubWrapKey) SECKEY_DestroyPublicKey(pubWrapKey); + if (Ks) PK11_FreeSymKey(Ks); + asymWrapMechanism = masterWrapMech; + break; +#endif /* NSS_ENABLE_ECC */ + default: rv = SECFailure; break; @@ -3716,10 +4065,6 @@ install: loser: done: - if (svrPubKey) { - SECKEY_DestroyPublicKey(svrPubKey); - svrPubKey = NULL; - } PZ_Unlock(symWrapKeysLock); return unwrappedWrappingKey; } @@ -4260,7 +4605,7 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } /* Got a Match */ - ++ssl3stats.hsh_sid_cache_hits; + SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_cache_hits ); ss->ssl3.hs.ws = wait_change_cipher; ss->ssl3.hs.isResuming = PR_TRUE; @@ -4279,9 +4624,9 @@ ssl3_HandleServerHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } while (0); if (sid_match) - ++ssl3stats.hsh_sid_cache_not_ok; + SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_cache_not_ok ); else - ++ssl3stats.hsh_sid_cache_misses; + SSL_AtomicIncrementLong(& ssl3stats.hsh_sid_cache_misses ); /* throw the old one away */ sid->u.ssl3.keys.resumable = PR_FALSE; @@ -4576,6 +4921,14 @@ ssl3_HandleCertificateRequest(sslSocket *ss, SSL3Opaque *b, PRUint32 length) CERT_DestroyCertificateList(ss->ssl3.clientCertChain); ss->ssl3.clientCertChain = NULL; } + if (ss->ssl3.clientCertificate != NULL) { + CERT_DestroyCertificate(ss->ssl3.clientCertificate); + ss->ssl3.clientCertificate = NULL; + } + if (ss->ssl3.clientPrivateKey != NULL) { + SECKEY_DestroyPrivateKey(ss->ssl3.clientPrivateKey); + ss->ssl3.clientPrivateKey = NULL; + } isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); rv = ssl3_ConsumeHandshakeVariable(ss, &cert_types, 1, &b, &length); @@ -5101,11 +5454,6 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) goto loser; /* malformed */ } - /* It's OK for length to be non-zero here. - * Non-zero length means that some new protocol revision has extended - * the client hello message. - */ - desc = handshake_failure; if (sid != NULL) { @@ -5121,33 +5469,54 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) ((ss->opt.requireCertificate == SSL_REQUIRE_FIRST_HANDSHAKE) && !ss->firstHsDone))) { - ++ssl3stats.hch_sid_cache_not_ok; + SSL_AtomicIncrementLong(& ssl3stats.hch_sid_cache_not_ok ); ss->sec.uncache(sid); ssl_FreeSID(sid); sid = NULL; } } +#ifdef NSS_ENABLE_ECC + /* Disable any ECC cipher suites for which we have no cert. */ + ssl3_FilterECCipherSuitesByServerCerts(ss); +#endif + +#ifdef PARANOID /* Look for a matching cipher suite. */ j = ssl3_config_match_init(ss); if (j <= 0) { /* no ciphers are working/supported by PK11 */ errCode = PORT_GetError(); /* error code is already set. */ goto alert_loser; } +#endif + /* If we already have a session for this client, be sure to pick the ** same cipher suite we picked before. ** This is not a loop, despite appearances. */ if (sid) do { ssl3CipherSuiteCfg *suite = ss->cipherSuites; + /* Find the entry for the cipher suite used in the cached session. */ for (j = ssl_V3_SUITES_IMPLEMENTED; j > 0; --j, ++suite) { if (suite->cipher_suite == sid->u.ssl3.cipherSuite) break; } - if (!j) + PORT_Assert(j > 0); + if (j <= 0) break; +#ifdef PARANOID + /* Double check that the cached cipher suite is still enabled, + * implemented, and allowed by policy. Might have been disabled. + * The product policy won't change during the process lifetime. + * Implemented ("isPresent") shouldn't change for servers. + */ if (!config_match(suite, ss->ssl3.policy, PR_TRUE)) break; +#else + if (!suite->enabled) + break; +#endif + /* Double check that the cached cipher suite is in the client's list */ for (i = 0; i < suites.len; i += 2) { if ((suites.data[i] == MSB(suite->cipher_suite)) && (suites.data[i + 1] == LSB(suite->cipher_suite))) { @@ -5160,6 +5529,37 @@ ssl3_HandleClientHello(sslSocket *ss, SSL3Opaque *b, PRUint32 length) } } while (0); + /* START A NEW SESSION */ + + /* Handle TLS hello extensions, for SSL3 & TLS, + * only if we're not restarting a previous session. + */ + if (length) { + /* Get length of hello extensions */ + PRInt32 extension_length; + extension_length = ssl3_ConsumeHandshakeNumber(ss, 2, &b, &length); + if (extension_length < 0) { + goto loser; /* alert already sent */ + } + if (extension_length != length) { + ssl3_DecodeError(ss); /* send alert */ + goto loser; + } + rv = ssl3_HandleClientHelloExtensions(ss, &b, &length); + if (rv != SECSuccess) { + goto loser; /* malformed */ + } + } + +#ifndef PARANOID + /* Look for a matching cipher suite. */ + j = ssl3_config_match_init(ss); + if (j <= 0) { /* no ciphers are working/supported by PK11 */ + errCode = PORT_GetError(); /* error code is already set. */ + goto alert_loser; + } +#endif + /* Select a cipher suite. ** NOTE: This suite selection algorithm should be the same as the one in ** ssl3_HandleV2ClientHello(). @@ -5294,7 +5694,7 @@ compression_found: * * XXX make sure compression still matches */ - ++ssl3stats.hch_sid_cache_hits; + SSL_AtomicIncrementLong(& ssl3stats.hch_sid_cache_hits ); ss->ssl3.hs.isResuming = PR_TRUE; ss->sec.authAlgorithm = sid->authAlgorithm; @@ -5356,12 +5756,12 @@ compression_found: } if (sid) { /* we had a sid, but it's no longer valid, free it */ - ++ssl3stats.hch_sid_cache_not_ok; + SSL_AtomicIncrementLong(& ssl3stats.hch_sid_cache_not_ok ); ss->sec.uncache(sid); ssl_FreeSID(sid); sid = NULL; } - ++ssl3stats.hch_sid_cache_misses; + SSL_AtomicIncrementLong(& ssl3stats.hch_sid_cache_misses ); sid = ssl3_NewSessionID(ss, PR_TRUE); if (sid == NULL) { @@ -5488,7 +5888,10 @@ ssl3_HandleV2ClientHello(sslSocket *ss, unsigned char *buffer, int length) PRINT_BUF(60, (ss, "client random:", &ss->ssl3.hs.client_random.rand[0], SSL3_RANDOM_LENGTH)); - +#ifdef NSS_ENABLE_ECC + /* Disable any ECC cipher suites for which we have no cert. */ + ssl3_FilterECCipherSuitesByServerCerts(ss); +#endif i = ssl3_config_match_init(ss); if (i <= 0) { errCode = PORT_GetError(); /* error code is already set. */ @@ -5524,7 +5927,7 @@ suite_found: ss->sec.send = ssl3_SendApplicationData; /* we don't even search for a cache hit here. It's just a miss. */ - ++ssl3stats.hch_sid_cache_misses; + SSL_AtomicIncrementLong(& ssl3stats.hch_sid_cache_misses ); sid = ssl3_NewSessionID(ss, PR_TRUE); if (sid == NULL) { errCode = PORT_GetError(); @@ -5577,7 +5980,9 @@ ssl3_SendServerHello(sslSocket *ss) { sslSessionID *sid; SECStatus rv; + PRUint32 maxBytes = 65535; PRUint32 length; + PRInt32 extensions_len = 0; SSL_TRC(3, ("%d: SSL3[%d]: send server_hello handshake", SSL_GETPID(), ss->fd)); @@ -5592,9 +5997,15 @@ ssl3_SendServerHello(sslSocket *ss) } sid = ss->sec.ci.sid; + + extensions_len = ssl3_CallHelloExtensionSenders(ss, PR_FALSE, maxBytes, + &ss->serverExtensionSenders[0]); + if (extensions_len > 0) + extensions_len += 2; /* Add sizeof total extension length */ + length = sizeof(SSL3ProtocolVersion) + SSL3_RANDOM_LENGTH + 1 + ((sid == NULL) ? 0: SSL3_SESSIONID_BYTES) + - sizeof(ssl3CipherSuite) + 1; + sizeof(ssl3CipherSuite) + 1 + extensions_len; rv = ssl3_AppendHandshakeHeader(ss, server_hello, length); if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ @@ -5632,6 +6043,22 @@ ssl3_SendServerHello(sslSocket *ss) if (rv != SECSuccess) { return rv; /* err set by AppendHandshake. */ } + if (extensions_len) { + PRInt32 sent_len; + + extensions_len -= 2; + rv = ssl3_AppendHandshakeNumber(ss, extensions_len, 2); + if (rv != SECSuccess) + return rv; /* err set by ssl3_SetupPendingCipherSpec */ + sent_len = ssl3_CallHelloExtensionSenders(ss, PR_TRUE, extensions_len, + &ss->serverExtensionSenders[0]); + PORT_Assert(sent_len == extensions_len); + if (sent_len != extensions_len) { + if (sent_len >= 0) + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; + } + } rv = ssl3_SetupPendingCipherSpec(ss); if (rv != SECSuccess) { return rv; /* err set by ssl3_SetupPendingCipherSpec */ @@ -6085,6 +6512,7 @@ ssl3_HandleClientKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) SECKEYPrivateKey *serverKey = NULL; SECStatus rv; const ssl3KEADef * kea_def; + ssl3KeyPair *serverKeyPair = NULL; #ifdef NSS_ENABLE_ECC SECKEYPublicKey *serverPubKey = NULL; #endif /* NSS_ENABLE_ECC */ @@ -6103,6 +6531,20 @@ const ssl3KEADef * kea_def; kea_def = ss->ssl3.hs.kea_def; + if (ss->ssl3.hs.usedStepDownKey) { + PORT_Assert(kea_def->is_limited /* XXX OR cert is signing only */ + && kea_def->exchKeyType == kt_rsa + && ss->stepDownKeyPair != NULL); + if (!kea_def->is_limited || + kea_def->exchKeyType != kt_rsa || + ss->stepDownKeyPair == NULL) { + /* shouldn't happen, don't use step down if it does */ + goto skip; + } + serverKeyPair = ss->stepDownKeyPair; + ss->sec.keaKeyBits = EXPORT_RSA_KEY_LENGTH * BPB; + } else +skip: #ifdef NSS_ENABLE_ECC /* XXX Using SSLKEAType to index server certifiates * does not work for (EC)DHE ciphers. Until we have @@ -6111,42 +6553,25 @@ const ssl3KEADef * kea_def; * one seprately. */ 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 */ - && kea_def->exchKeyType == kt_rsa - && ss->stepDownKeyPair != NULL -#endif - ) ? ss->stepDownKeyPair->privKey - : ss->serverCerts[kea_def->exchKeyType].SERVERKEY; - - if (ss->ssl3.hs.usedStepDownKey -#ifdef DEBUG - && kea_def->is_limited /* XXX OR cert is signing only */ - && kea_def->exchKeyType == kt_rsa - && ss->stepDownKeyPair != NULL + (kea_def->kea == kea_ecdhe_ecdsa)) { + if (ss->ephemeralECDHKeyPair != NULL) { + serverKeyPair = ss->ephemeralECDHKeyPair; + if (serverKeyPair->pubKey) { + ss->sec.keaKeyBits = + SECKEY_PublicKeyStrengthInBits(serverKeyPair->pubKey); + } + } + } else #endif - ) { - serverKey = ss->stepDownKeyPair->privKey; - ss->sec.keaKeyBits = EXPORT_RSA_KEY_LENGTH * BPB; - } else { + { sslServerCerts * sc = ss->serverCerts + kea_def->exchKeyType; - serverKey = sc->SERVERKEY; + serverKeyPair = sc->serverKeyPair; ss->sec.keaKeyBits = sc->serverKeyBits; } -#ifdef NSS_ENABLE_ECC + if (serverKeyPair) { + serverKey = serverKeyPair->privKey; } -#endif /* NSS_ENABLE_ECC */ if (serverKey == NULL) { SEND_ALERT @@ -6168,19 +6593,14 @@ const ssl3KEADef * kea_def; #ifdef NSS_ENABLE_ECC case kt_ecdh: - /* XXX We really ought to be able to store multiple + /* XXX We really ought to be able to store multiple * EC certs (a requirement if we wish to support both * ECDH-RSA and ECDH-ECDSA key exchanges concurrently). * When we make that change, we'll need an index other * than kt_ecdh to pick the right EC certificate. */ - if (((kea_def->kea == kea_ecdhe_ecdsa) || - (kea_def->kea == kea_ecdhe_rsa)) && - (ss->ephemeralECDHKeyPair != NULL)) { - serverPubKey = ss->ephemeralECDHKeyPair->pubKey; - } else { - serverPubKey = CERT_ExtractPublicKey( - ss->serverCerts[kt_ecdh].serverCert); + if (serverKeyPair) { + serverPubKey = serverKeyPair->pubKey; } if (serverPubKey == NULL) { /* XXX Is this the right error code? */ @@ -7066,6 +7486,9 @@ xmit_loser: sid->u.ssl3.cipherSuite = ss->ssl3.hs.cipher_suite; sid->u.ssl3.compression = ss->ssl3.hs.compression; sid->u.ssl3.policy = ss->ssl3.policy; +#ifdef NSS_ENABLE_ECC + sid->u.ssl3.negotiatedECCurves = ss->ssl3.hs.negotiatedECCurves; +#endif sid->u.ssl3.exchKeyType = effectiveExchKeyType; sid->version = ss->version; sid->authAlgorithm = ss->sec.authAlgorithm; @@ -7688,6 +8111,9 @@ ssl3_InitState(sslSocket *ss) ssl3_InitCipherSpec(ss, ss->ssl3.prSpec); ss->ssl3.hs.ws = (ss->sec.isServer) ? wait_client_hello : wait_server_hello; +#ifdef NSS_ENABLE_ECC + ss->ssl3.hs.negotiatedECCurves = SSL3_SUPPORTED_CURVES_MASK; +#endif ssl_ReleaseSpecWriteLock(ss); /* @@ -7742,8 +8168,7 @@ ssl3_NewKeyPair( SECKEYPrivateKey * privKey, SECKEYPublicKey * pubKey) { ssl3KeyPair * pair; - if (!privKey && !pubKey) { - /* one or the other may be NULL, but not both. */ + if (!privKey || !pubKey) { PORT_SetError(PR_INVALID_ARGUMENT_ERROR); return NULL; } diff --git a/security/nss/lib/ssl/ssl3ecc.c b/security/nss/lib/ssl/ssl3ecc.c index af7cdb30f..1195189cb 100644 --- a/security/nss/lib/ssl/ssl3ecc.c +++ b/security/nss/lib/ssl/ssl3ecc.c @@ -42,9 +42,8 @@ /* ECC code moved here from ssl3con.c */ /* $Id$ */ -#ifdef NSS_ENABLE_ECC - #include "nssrenam.h" +#include "nss.h" #include "cert.h" #include "ssl.h" #include "cryptohi.h" /* for DSAU_ stuff */ @@ -60,6 +59,7 @@ #include "prerror.h" #include "pratom.h" #include "prthread.h" +#include "prinit.h" #include "pk11func.h" #include "secmod.h" @@ -69,38 +69,59 @@ #include <stdio.h> -/* - line 297: implicit function declaration: ssl3_InitPendingCipherSpec - line 305: implicit function declaration: ssl3_AppendHandshakeHeader - line 311: implicit function declaration: ssl3_AppendHandshakeVariable - line 356: implicit function declaration: ssl3_ConsumeHandshakeVariable -*/ - +#ifdef NSS_ENABLE_ECC #ifndef PK11_SETATTRS #define PK11_SETATTRS(x,id,v,l) (x)->type = (id); \ (x)->pValue=(v); (x)->ulValueLen = (l); #endif +#define SSL_GET_SERVER_PUBLIC_KEY(sock, type) \ + (ss->serverCerts[type].serverKeyPair ? \ + ss->serverCerts[type].serverKeyPair->pubKey : NULL) + +#define SSL_IS_CURVE_NEGOTIATED(ss, curveName) \ + ((curveName > ec_noName) && \ + (curveName < ec_pastLastName) && \ + ((1UL << curveName) & ss->ssl3.hs.negotiatedECCurves) != 0) + /* Types and names of elliptic curves used in TLS */ -typedef enum { ec_type_explicitPrime = 1, - ec_type_explicitChar2Curve, +typedef enum { ec_type_explicitPrime = 1, + ec_type_explicitChar2Curve = 2, 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, +typedef enum { ec_noName = 0, + ec_sect163k1 = 1, + ec_sect163r1 = 2, + ec_sect163r2 = 3, + ec_sect193r1 = 4, + ec_sect193r2 = 5, + ec_sect233k1 = 6, + ec_sect233r1 = 7, + ec_sect239k1 = 8, + ec_sect283k1 = 9, + ec_sect283r1 = 10, + ec_sect409k1 = 11, + ec_sect409r1 = 12, + ec_sect571k1 = 13, + ec_sect571r1 = 14, + ec_secp160k1 = 15, + ec_secp160r1 = 16, + ec_secp160r2 = 17, + ec_secp192k1 = 18, + ec_secp192r1 = 19, + ec_secp224k1 = 20, + ec_secp224r1 = 21, + ec_secp256k1 = 22, + ec_secp256r1 = 23, + ec_secp384r1 = 24, + ec_secp521r1 = 25, ec_pastLastName } ECName; +static SECStatus ssl3_CreateECDHEphemeralKeys(sslSocket *ss, ECName ec_curve); + #define supportedCurve(x) (((x) > ec_noName) && ((x) < ec_pastLastName)) /* Table containing OID tags for elliptic curves named in the @@ -135,6 +156,79 @@ static const SECOidTag ecName2OIDTag[] = { SEC_OID_SECG_EC_SECP521R1, /* 25 */ }; +static const PRUint16 curve2bits[] = { + 0, /* ec_noName = 0, */ + 163, /* ec_sect163k1 = 1, */ + 163, /* ec_sect163r1 = 2, */ + 163, /* ec_sect163r2 = 3, */ + 193, /* ec_sect193r1 = 4, */ + 193, /* ec_sect193r2 = 5, */ + 233, /* ec_sect233k1 = 6, */ + 233, /* ec_sect233r1 = 7, */ + 239, /* ec_sect239k1 = 8, */ + 283, /* ec_sect283k1 = 9, */ + 283, /* ec_sect283r1 = 10, */ + 409, /* ec_sect409k1 = 11, */ + 409, /* ec_sect409r1 = 12, */ + 571, /* ec_sect571k1 = 13, */ + 571, /* ec_sect571r1 = 14, */ + 160, /* ec_secp160k1 = 15, */ + 160, /* ec_secp160r1 = 16, */ + 160, /* ec_secp160r2 = 17, */ + 192, /* ec_secp192k1 = 18, */ + 192, /* ec_secp192r1 = 19, */ + 224, /* ec_secp224k1 = 20, */ + 224, /* ec_secp224r1 = 21, */ + 256, /* ec_secp256k1 = 22, */ + 256, /* ec_secp256r1 = 23, */ + 384, /* ec_secp384r1 = 24, */ + 521, /* ec_secp521r1 = 25, */ + 65535 /* ec_pastLastName */ +}; + +typedef struct Bits2CurveStr { + PRUint16 bits; + ECName curve; +} Bits2Curve; + +static const Bits2Curve bits2curve [] = { + { 160, ec_secp160r2 /* = 17, fast */ }, + { 160, ec_secp160k1 /* = 15, */ }, + { 160, ec_secp160r1 /* = 16, */ }, + { 163, ec_sect163k1 /* = 1, */ }, + { 163, ec_sect163r1 /* = 2, */ }, + { 163, ec_sect163r2 /* = 3, */ }, + { 192, ec_secp192k1 /* = 18, */ }, + { 192, ec_secp192r1 /* = 19, */ }, + { 193, ec_sect193r1 /* = 4, */ }, + { 193, ec_sect193r2 /* = 5, */ }, + { 224, ec_secp224r1 /* = 21, fast */ }, + { 224, ec_secp224k1 /* = 20, */ }, + { 233, ec_sect233k1 /* = 6, */ }, + { 233, ec_sect233r1 /* = 7, */ }, + { 239, ec_sect239k1 /* = 8, */ }, + { 256, ec_secp256r1 /* = 23, fast */ }, + { 256, ec_secp256k1 /* = 22, */ }, + { 283, ec_sect283k1 /* = 9, */ }, + { 283, ec_sect283r1 /* = 10, */ }, + { 384, ec_secp384r1 /* = 24, fast */ }, + { 409, ec_sect409k1 /* = 11, */ }, + { 409, ec_sect409r1 /* = 12, */ }, + { 521, ec_secp521r1 /* = 25, fast */ }, + { 571, ec_sect571k1 /* = 13, */ }, + { 571, ec_sect571r1 /* = 14, */ }, + { 65535, ec_noName } +}; + +typedef struct ECDHEKeyPairStr { + ssl3KeyPair * pair; + PRInt32 flag; + PRCallOnceType once; +} ECDHEKeyPair; + +/* arrays of ECDHE KeyPairs */ +static ECDHEKeyPair gECDHEKeyPairs[ec_pastLastName]; + static SECStatus ecName2params(PRArenaPool * arena, ECName curve, SECKEYECParams * params) { @@ -229,7 +323,6 @@ ssl3_ComputeECDHKeyHash(SECItem ec_params, SECItem server_ecpoint, 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; @@ -246,7 +339,6 @@ ssl3_SendECDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) CK_MECHANISM_TYPE target; SECKEYPublicKey *pubKey = NULL; /* Ephemeral ECDH key */ SECKEYPrivateKey *privKey = NULL; /* Ephemeral ECDH key */ - CK_EC_KDF_TYPE kdf; PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss)); @@ -254,6 +346,7 @@ ssl3_SendECDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) isTLS = (PRBool)(ss->ssl3.pwSpec->version > SSL_LIBRARY_VERSION_3_0); /* Generate ephemeral EC keypair */ + /* XXX SHOULD CALL ssl3_CreateECDHEphemeralKeys here, instead! */ privKey = SECKEY_CreateECPrivateKey(&svrPubKey->u.ec.DEREncodedParams, &pubKey, NULL); if (!privKey || !pubKey) { @@ -268,19 +361,10 @@ ssl3_SendECDHClientKeyExchange(sslSocket * ss, SECKEYPublicKey * svrPubKey) if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH; else target = CKM_SSL3_MASTER_KEY_DERIVE_DH; - /* If field size is not more than 24 octets, then use SHA-1 hash of result; - * otherwise, use result (see section 4.8 of draft-ietf-tls-ecc-03.txt). - */ - if ((pubKey->u.ec.publicValue.len - 1) / 2 <= 24) { - kdf = CKD_SHA1_KDF; - } else { - kdf = CKD_NULL; - } - /* Determine the PMS */ pms = PK11_PubDeriveWithKDF(privKey, svrPubKey, PR_FALSE, NULL, NULL, CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, - kdf, NULL, NULL); + CKD_NULL, NULL, NULL); if (pms == NULL) { ssl_MapLowLevelError(SSL_ERROR_CLIENT_KEY_EXCHANGE_FAILURE); @@ -338,7 +422,6 @@ ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b, SECKEYPublicKey clntPubKey; CK_MECHANISM_TYPE target; PRBool isTLS; - CK_EC_KDF_TYPE kdf; PORT_Assert( ss->opt.noLocks || ssl_HaveRecvBufLock(ss) ); PORT_Assert( ss->opt.noLocks || ssl_HaveSSL3HandshakeLock(ss) ); @@ -361,19 +444,10 @@ ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b, if (isTLS) target = CKM_TLS_MASTER_KEY_DERIVE_DH; else target = CKM_SSL3_MASTER_KEY_DERIVE_DH; - /* If field size is not more than 24 octets, then use SHA-1 hash of result; - * otherwise, use result (see section 4.8 of draft-ietf-tls-ecc-03.txt). - */ - if (srvrPubKey->u.ec.size <= 24 * 8) { - kdf = CKD_SHA1_KDF; - } else { - kdf = CKD_NULL; - } - /* Determine the PMS */ pms = PK11_PubDeriveWithKDF(srvrPrivKey, &clntPubKey, PR_FALSE, NULL, NULL, CKM_ECDH1_DERIVE, target, CKA_DERIVE, 0, - kdf, NULL, NULL); + CKD_NULL, NULL, NULL); if (pms == NULL) { /* last gasp. */ @@ -390,38 +464,167 @@ ssl3_HandleECDHClientKeyExchange(sslSocket *ss, SSL3Opaque *b, return SECSuccess; } +/* find the "weakest link". Get strength of signature key and of sym key. + * choose curve for the weakest of those two. + */ +ECName +ssl3_GetCurveNameForServerSocket(sslSocket *ss) +{ + SECKEYPublicKey * svrPublicKey = NULL; + ECName ec_curve = ec_noName; + int signatureKeyStrength = 521; + int requiredECCbits = ss->sec.secretKeyBits * 2; + int i; + + if (ss->ssl3.hs.kea_def->kea == kea_ecdhe_ecdsa) { + svrPublicKey = SSL_GET_SERVER_PUBLIC_KEY(ss, kt_ecdh); + if (svrPublicKey) + ec_curve = params2ecName(&svrPublicKey->u.ec.DEREncodedParams); + if (!SSL_IS_CURVE_NEGOTIATED(ss, ec_curve)) { + PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); + return ec_noName; + } + signatureKeyStrength = curve2bits[ ec_curve ]; + } else { + /* RSA is our signing cert */ + int serverKeyStrengthInBits; + + svrPublicKey = SSL_GET_SERVER_PUBLIC_KEY(ss, kt_rsa); + if (!svrPublicKey) { + PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); + return ec_noName; + } + + /* currently strength in bytes */ + serverKeyStrengthInBits = svrPublicKey->u.rsa.modulus.len; + if (svrPublicKey->u.rsa.modulus.data[0] == 0) { + serverKeyStrengthInBits--; + } + /* convert to strength in bits */ + serverKeyStrengthInBits *= BPB; + + if (serverKeyStrengthInBits <= 1024) { + signatureKeyStrength = 160; + } else if (serverKeyStrengthInBits <= 2048) { + signatureKeyStrength = 224; + } else if (serverKeyStrengthInBits <= 3072) { + signatureKeyStrength = 256; + } else if (serverKeyStrengthInBits <= 7168) { + signatureKeyStrength = 384; + } else { + signatureKeyStrength = 521; + } + } + if ( requiredECCbits > signatureKeyStrength ) + requiredECCbits = signatureKeyStrength; + + for ( i = 0; bits2curve[i].curve != ec_noName; i++) { + if (bits2curve[i].bits < requiredECCbits) + continue; + if (SSL_IS_CURVE_NEGOTIATED(ss, bits2curve[i].curve)) { + return bits2curve[i].curve; + } + } + PORT_SetError(SSL_ERROR_NO_CYPHER_OVERLAP); + return ec_noName; +} + +/* function to clear out the lists */ +static SECStatus +ssl3_ShutdownECDHECurves(void *appData, void *nssData) +{ + int i; + ECDHEKeyPair *keyPair = &gECDHEKeyPairs[0]; + + for (i=0; i < ec_pastLastName; i++, keyPair++) { + if (keyPair->pair) { + ssl3_FreeKeyPair(keyPair->pair); + } + } + memset(gECDHEKeyPairs, 0, sizeof gECDHEKeyPairs); + return SECSuccess; +} + +static PRStatus +ssl3_ECRegister(void) +{ + SECStatus rv; + rv = NSS_RegisterShutdown(ssl3_ShutdownECDHECurves, gECDHEKeyPairs); + return (PRStatus)rv; +} + +/* CallOnce function, called once for each named curve. */ +static PRStatus +ssl3_CreateECDHEphemeralKeyPair(void * arg) +{ + SECKEYPrivateKey * privKey = NULL; + SECKEYPublicKey * pubKey = NULL; + ssl3KeyPair * keyPair = NULL; + ECName ec_curve = (ECName)arg; + SECKEYECParams ecParams = { siBuffer, NULL, 0 }; + + PORT_Assert(gECDHEKeyPairs[ec_curve].pair == NULL); + + /* ok, no one has generated a global key for this curve yet, do so */ + if (ecName2params(NULL, ec_curve, &ecParams) != SECSuccess) { + return PR_FAILURE; + } + + privKey = SECKEY_CreateECPrivateKey(&ecParams, &pubKey, NULL); + SECITEM_FreeItem(&ecParams, PR_FALSE); + + if (!privKey || !pubKey || !(keyPair = ssl3_NewKeyPair(privKey, pubKey))) { + if (privKey) { + SECKEY_DestroyPrivateKey(privKey); + } + if (pubKey) { + SECKEY_DestroyPublicKey(pubKey); + } + ssl_MapLowLevelError(SEC_ERROR_KEYGEN_FAIL); + return PR_FAILURE; + } + + gECDHEKeyPairs[ec_curve].pair = keyPair; + return PR_SUCCESS; +} /* * 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. + * For now, the elliptic curve is chosen to be the same + * strength as the signing certificate (ECC or RSA). * 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) +static SECStatus +ssl3_CreateECDHEphemeralKeys(sslSocket *ss, ECName ec_curve) { - SECStatus rv = SECSuccess; - SECKEYPrivateKey * privKey; - SECKEYPublicKey * pubKey; - SECKEYECParams ecParams = { siBuffer, NULL, 0 }; + ssl3KeyPair * keyPair = NULL; - if (ss->ephemeralECDHKeyPair) - ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair); - ss->ephemeralECDHKeyPair = NULL; + /* if there's no global key for this curve, make one. */ + if (gECDHEKeyPairs[ec_curve].pair == NULL) { + PRStatus status; - 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; + status = PR_CallOnce(&gECDHEKeyPairs[ec_noName].once, ssl3_ECRegister); + if (status != PR_SUCCESS) { + return SECFailure; + } + status = PR_CallOnceWithArg(&gECDHEKeyPairs[ec_curve].once, + ssl3_CreateECDHEphemeralKeyPair, + (void *)ec_curve); + if (status != PR_SUCCESS) { + return SECFailure; + } } - PORT_Free(ecParams.data); - return rv; + keyPair = gECDHEKeyPairs[ec_curve].pair; + PORT_Assert(keyPair != NULL); + if (!keyPair) + return SECFailure; + ss->ephemeralECDHKeyPair = ssl3_GetKeyPairRef(keyPair); + + return SECSuccess; } SECStatus @@ -438,24 +641,24 @@ ssl3_HandleECDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) SECItem ec_params = {siBuffer, NULL, 0}; SECItem ec_point = {siBuffer, NULL, 0}; - unsigned char paramBuf[2]; + unsigned char paramBuf[3]; /* only for curve_type == named_curve */ isTLS = (PRBool)(ss->ssl3.prSpec->version > SSL_LIBRARY_VERSION_3_0); /* XXX This works only for named curves, revisit this when * we support generic curves. */ - ec_params.len = 2; + ec_params.len = sizeof paramBuf; ec_params.data = paramBuf; - rv = ssl3_ConsumeHandshake(ss, ec_params.data, ec_params.len, - &b, &length); + 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])) { + (ec_params.data[1] != 0) || + !supportedCurve(ec_params.data[2])) { errCode = SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE; desc = handshake_failure; goto alert_loser; @@ -526,7 +729,7 @@ ssl3_HandleECDHServerKeyExchange(sslSocket *ss, SSL3Opaque *b, PRUint32 length) peerKey->keyType = ecKey; /* set up EC parameters in peerKey */ - if (ecName2params(arena, ec_params.data[1], + if (ecName2params(arena, ec_params.data[2], &peerKey->u.ec.DEREncodedParams) != SECSuccess) { /* we should never get here since we already * checked that we are dealing with a supported curve @@ -572,12 +775,17 @@ const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def; SECKEYPublicKey * ecdhePub; SECItem ec_params = {siBuffer, NULL, 0}; + unsigned char paramBuf[3]; ECName curve; SSL3KEAType certIndex; /* Generate ephemeral ECDH key pair and send the public key */ - rv = ssl3_CreateECDHEphemeralKeys(ss); + curve = ssl3_GetCurveNameForServerSocket(ss); + if (curve == ec_noName) { + goto loser; + } + rv = ssl3_CreateECDHEphemeralKeys(ss, curve); if (rv != SECSuccess) { goto loser; /* err set by AppendHandshake. */ } @@ -588,12 +796,13 @@ const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def; return SECFailure; } - ec_params.len = 2; - ec_params.data = (unsigned char*)PORT_Alloc(ec_params.len); + ec_params.len = sizeof paramBuf; + ec_params.data = paramBuf; curve = params2ecName(&ecdhePub->u.ec.DEREncodedParams); if (curve != ec_noName) { ec_params.data[0] = ec_type_named; - ec_params.data[1] = curve; + ec_params.data[1] = 0x00; + ec_params.data[2] = curve; } else { PORT_SetError(SEC_ERROR_UNSUPPORTED_ELLIPTIC_CURVE); goto loser; @@ -656,18 +865,510 @@ const ssl3KEADef * kea_def = ss->ssl3.hs.kea_def; goto loser; /* err set by AppendHandshake. */ } - PORT_Free(ec_params.data); PORT_Free(signed_hash.data); return SECSuccess; loser: - if (ec_params.data != NULL) - PORT_Free(ec_params.data); if (signed_hash.data != NULL) PORT_Free(signed_hash.data); return SECFailure; } +/* Lists of ECC cipher suites for searching and disabling. */ + +static const ssl3CipherSuite ecdh_suites[] = { + TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + TLS_ECDH_ECDSA_WITH_NULL_SHA, + TLS_ECDH_ECDSA_WITH_RC4_128_SHA, + TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, + TLS_ECDH_RSA_WITH_NULL_SHA, + TLS_ECDH_RSA_WITH_RC4_128_SHA, + 0 /* end of list marker */ +}; + +static const ssl3CipherSuite ecdh_ecdsa_suites[] = { + TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + TLS_ECDH_ECDSA_WITH_NULL_SHA, + TLS_ECDH_ECDSA_WITH_RC4_128_SHA, + 0 /* end of list marker */ +}; + +static const ssl3CipherSuite ecdh_rsa_suites[] = { + TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, + TLS_ECDH_RSA_WITH_NULL_SHA, + TLS_ECDH_RSA_WITH_RC4_128_SHA, + 0 /* end of list marker */ +}; + +static const ssl3CipherSuite ecdhe_ecdsa_suites[] = { + TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + TLS_ECDHE_ECDSA_WITH_NULL_SHA, + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, + 0 /* end of list marker */ +}; + +static const ssl3CipherSuite ecdhe_rsa_suites[] = { + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + TLS_ECDHE_RSA_WITH_NULL_SHA, + TLS_ECDHE_RSA_WITH_RC4_128_SHA, + 0 /* end of list marker */ +}; + +/* List of all ECC cipher suites */ +static const ssl3CipherSuite ecSuites[] = { + TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + TLS_ECDHE_ECDSA_WITH_NULL_SHA, + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, + TLS_ECDHE_RSA_WITH_NULL_SHA, + TLS_ECDHE_RSA_WITH_RC4_128_SHA, + TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA, + TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA, + TLS_ECDH_ECDSA_WITH_NULL_SHA, + TLS_ECDH_ECDSA_WITH_RC4_128_SHA, + TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDH_RSA_WITH_AES_128_CBC_SHA, + TLS_ECDH_RSA_WITH_AES_256_CBC_SHA, + TLS_ECDH_RSA_WITH_NULL_SHA, + TLS_ECDH_RSA_WITH_RC4_128_SHA, + 0 /* end of list marker */ +}; + +/* On this socket, Disable the ECC cipher suites in the argument's list */ +SECStatus +ssl3_DisableECCSuites(sslSocket * ss, const ssl3CipherSuite * suite) +{ + for (; *suite; ++suite) { + SECStatus rv = ssl3_CipherPrefSet(ss, *suite, PR_FALSE); + + PORT_Assert(rv == SECSuccess); /* else is coding error */ + } + return SECSuccess; +} + +/* Look at the server certs configured on this socket, and disable any + * ECC cipher suites that are not supported by those certs. + */ +void +ssl3_FilterECCipherSuitesByServerCerts(sslSocket * ss) +{ + CERTCertificate * svrCert; + + svrCert = ss->serverCerts[kt_rsa].serverCert; + if (!svrCert) { + ssl3_DisableECCSuites(ss, ecdhe_rsa_suites); + } + + svrCert = ss->serverCerts[kt_ecdh].serverCert; + if (!svrCert) { + ssl3_DisableECCSuites(ss, ecdh_suites); + ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites); + } else { + SECOidTag sigTag = SECOID_GetAlgorithmTag(&svrCert->signature); + + switch (sigTag) { + case SEC_OID_PKCS1_RSA_ENCRYPTION: + case SEC_OID_PKCS1_MD2_WITH_RSA_ENCRYPTION: + case SEC_OID_PKCS1_MD4_WITH_RSA_ENCRYPTION: + case SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION: + case SEC_OID_PKCS1_SHA1_WITH_RSA_ENCRYPTION: + case SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION: + case SEC_OID_PKCS1_SHA384_WITH_RSA_ENCRYPTION: + case SEC_OID_PKCS1_SHA512_WITH_RSA_ENCRYPTION: + ssl3_DisableECCSuites(ss, ecdh_ecdsa_suites); + break; + case SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE: + case SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE: + case SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE: + case SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE: + case SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE: + case SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST: + case SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST: + ssl3_DisableECCSuites(ss, ecdh_rsa_suites); + break; + default: + ssl3_DisableECCSuites(ss, ecdh_suites); + break; + } + } +} + +/* Ask: is ANY ECC cipher suite enabled on this socket? */ +/* Order(N^2). Yuk. Also, this ignores export policy. */ +PRBool +ssl3_IsECCEnabled(sslSocket * ss) +{ + const ssl3CipherSuite * suite; + + for (suite = ecSuites; *suite; ++suite) { + PRBool enabled = PR_FALSE; + SECStatus rv = ssl3_CipherPrefGet(ss, *suite, &enabled); + + PORT_Assert(rv == SECSuccess); /* else is coding error */ + if (rv == SECSuccess && enabled) + return PR_TRUE; + } + return PR_FALSE; +} + +#define BE(n) 0, n + +#ifndef NSS_ECC_MORE_THAN_SUITE_B +/* Prefabricated TLS client hello extension, Elliptic Curves List, + * offers only 3 curves, the Suite B curves, 23-25 + */ +static const PRUint8 EClist[12] = { + BE(10), /* Extension type */ + BE( 8), /* octets that follow ( 3 pairs + 1 length pair) */ + BE( 6), /* octets that follow ( 3 pairs) */ + BE(23), BE(24), BE(25) +}; +#else +/* Prefabricated TLS client hello extension, Elliptic Curves List, + * offers curves 1-25. + */ +static const PRUint8 EClist[56] = { + BE(10), /* Extension type */ + BE(52), /* octets that follow (25 pairs + 1 length pair) */ + BE(50), /* octets that follow (25 pairs) */ + BE( 1), BE( 2), BE( 3), BE( 4), BE( 5), BE( 6), BE( 7), + BE( 8), BE( 9), BE(10), BE(11), BE(12), BE(13), BE(14), BE(15), + BE(16), BE(17), BE(18), BE(19), BE(20), BE(21), BE(22), BE(23), + BE(24), BE(25) +}; +#endif + +static const PRUint8 ECPtFmt[6] = { + BE(11), /* Extension type */ + BE( 2), /* octets that follow */ + 1, /* octets that follow */ + 0 /* uncompressed type only */ +}; + +/* Send our "canned" (precompiled) Supported Elliptic Curves extension, + * which says that we support all TLS-defined named curves. + */ +PRInt32 +ssl3_SendSupportedEllipticCurvesExtension( + sslSocket * ss, + PRBool append, + PRUint32 maxBytes) +{ + if (!ss || !ssl3_IsECCEnabled(ss)) + return 0; + if (append && maxBytes >= (sizeof EClist)) { + SECStatus rv = ssl3_AppendHandshake(ss, EClist, (sizeof EClist)); + } + return (sizeof EClist); +} + +/* Send our "canned" (precompiled) Supported Point Formats extension, + * which says that we only support uncompressed points. + */ +PRInt32 +ssl3_SendSupportedPointFormatsExtension( + sslSocket * ss, + PRBool append, + PRUint32 maxBytes) +{ + if (!ss || !ssl3_IsECCEnabled(ss)) + return 0; + if (append && maxBytes >= (sizeof ECPtFmt)) { + SECStatus rv = ssl3_AppendHandshake(ss, ECPtFmt, (sizeof ECPtFmt)); + } + return (sizeof ECPtFmt); +} + +/* Just make sure that the remote client supports uncompressed points, + * Since that is all we support. Disable ECC cipher suites if it doesn't. + */ +static SECStatus +ssl3_HandleSupportedPointFormatsExtension(sslSocket * ss, PRUint16 ex_type, + SECItem *data) +{ + int i; + + if (data->len < 2 || data->len > 255 || !data->data || + data->len != (unsigned int)data->data[0] + 1) { + /* malformed */ + goto loser; + } + for (i = data->len; --i > 0; ) { + if (data->data[i] == 0) { + /* indicate that we should send a reply */ + SECStatus rv; + rv = ssl3_RegisterServerHelloExtensionSender(ss, ex_type, + &ssl3_SendSupportedPointFormatsExtension); + return rv; + } + } +loser: + /* evil client doesn't support uncompressed */ + ssl3_DisableECCSuites(ss, ecSuites); + return SECFailure; +} + + +#define SSL3_GET_SERVER_PUBLICKEY(sock, type) \ + (ss->serverCerts[type].serverKeyPair ? \ + ss->serverCerts[type].serverKeyPair->pubKey : NULL) + +/* Extract the TLS curve name for the public key in our EC server cert. */ +ECName ssl3_GetSvrCertCurveName(sslSocket *ss) +{ + SECKEYPublicKey *srvPublicKey; + ECName ec_curve = ec_noName; + + srvPublicKey = SSL3_GET_SERVER_PUBLICKEY(ss, kt_ecdh); + if (srvPublicKey) { + ec_curve = params2ecName(&srvPublicKey->u.ec.DEREncodedParams); + } + return ec_curve; +} + +/* Ensure that the curve in our server cert is one of the ones suppored + * by the remote client, and disable all ECC cipher suites if not. + */ +static SECStatus +ssl3_HandleSupportedEllipticCurvesExtension(sslSocket * ss, PRUint16 ex_type, + SECItem *data) +{ + PRInt32 list_len; + PRUint32 peerCurves = 0; + PRUint32 mutualCurves = 0; + PRUint16 svrCertCurveName; + + if (!data->data || data->len < 4 || data->len > 65535) + goto loser; + /* get the length of elliptic_curve_list */ + list_len = ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len); + if (list_len < 0 || data->len != list_len || (data->len % 2) != 0) { + /* malformed */ + goto loser; + } + /* build bit vector of peer's supported curve names */ + while (data->len) { + PRInt32 curve_name = + ssl3_ConsumeHandshakeNumber(ss, 2, &data->data, &data->len); + if (curve_name > ec_noName && curve_name < ec_pastLastName) { + peerCurves |= (1U << curve_name); + } + } + /* What curves do we support in common? */ + mutualCurves = ss->ssl3.hs.negotiatedECCurves &= peerCurves; + if (!mutualCurves) { /* no mutually supported EC Curves */ + goto loser; + } + + /* if our ECC cert doesn't use one of these supported curves, + * disable ECC cipher suites that require an ECC cert. + */ + svrCertCurveName = ssl3_GetSvrCertCurveName(ss); + if (svrCertCurveName != ec_noName && + (mutualCurves & (1U << svrCertCurveName)) != 0) { + return SECSuccess; + } + /* Our EC cert doesn't contain a mutually supported curve. + * Disable all ECC cipher suites that require an EC cert + */ + ssl3_DisableECCSuites(ss, ecdh_ecdsa_suites); + ssl3_DisableECCSuites(ss, ecdhe_ecdsa_suites); + return SECFailure; + +loser: + /* no common curve supported */ + ssl3_DisableECCSuites(ss, ecSuites); + return SECFailure; +} #endif /* NSS_ENABLE_ECC */ +/* Format an SNI extension, using the name from the socket's URL, + * unless that name is a dotted decimal string. + */ +PRInt32 +ssl3_SendServerNameIndicationExtension( + sslSocket * ss, + PRBool append, + PRUint32 maxBytes) +{ + PRUint32 len, span; + /* must have a hostname */ + if (!ss || !ss->url || !ss->url[0]) + return 0; + /* must have at lest one character other than [0-9\.] */ + len = PORT_Strlen(ss->url); + span = strspn(ss->url, "0123456789."); + if (len == span) { + /* is a dotted decimal IP address */ + return 0; + } + if (append && maxBytes >= len + 9) { + SECStatus rv; + /* extension_type */ + rv = ssl3_AppendHandshakeNumber(ss, 0, 2); + if (rv != SECSuccess) return 0; + /* length of extension_data */ + rv = ssl3_AppendHandshakeNumber(ss, len + 5, 2); + if (rv != SECSuccess) return 0; + /* length of server_name_list */ + rv = ssl3_AppendHandshakeNumber(ss, len + 3, 2); + if (rv != SECSuccess) return 0; + /* Name Type (host_name) */ + rv = ssl3_AppendHandshake(ss, "\0", 1); + if (rv != SECSuccess) return 0; + /* HostName (length and value) */ + rv = ssl3_AppendHandshakeVariable(ss, ss->url, len, 2); + if (rv != SECSuccess) return 0; + } + return len + 9; +} + +/* handle an incoming SNI extension, by ignoring it. */ +SECStatus +ssl3_HandleServerNameIndicationExtension(sslSocket * ss, PRUint16 ex_type, + SECItem *data) +{ + /* For now, we ignore this, as if we didn't understand it. :-) */ + return SECSuccess; +} + +/* Table of handlers for received TLS hello extensions, one per extension. + * In the second generation, this table will be dynamic, and functions + * will be registered here. + */ +static const ssl3HelloExtensionHandler handlers[] = { + { 0, &ssl3_HandleServerNameIndicationExtension }, +#ifdef NSS_ENABLE_ECC + { 10, &ssl3_HandleSupportedEllipticCurvesExtension }, + { 11, &ssl3_HandleSupportedPointFormatsExtension }, +#endif + { -1, NULL } +}; + +/* Table of functions to format TLS hello extensions, one per extension. + * This static table is for the formatting of client hello extensions. + * The server's table of hello senders is dynamic, in the socket struct, + * and sender functions are registered there. + */ +static const +ssl3HelloExtensionSender clientHelloSenders[MAX_EXTENSION_SENDERS] = { + { 0, &ssl3_SendServerNameIndicationExtension }, +#ifdef NSS_ENABLE_ECC + { 10, &ssl3_SendSupportedEllipticCurvesExtension }, + { 11, &ssl3_SendSupportedPointFormatsExtension }, +#else + { -1, NULL } +#endif +}; + +/* go through hello extensions in buffer "b". + * For each one, find the extension handler in the table above, and + * if present, invoke that handler. + * ignore any extensions with unknown extension types. + */ +SECStatus +ssl3_HandleClientHelloExtensions(sslSocket *ss, + SSL3Opaque **b, + PRUint32 *length) +{ + while (*length) { + const ssl3HelloExtensionHandler * handler; + SECStatus rv; + PRInt32 extension_type; + SECItem extension_data; + + /* Get the extension's type field */ + extension_type = ssl3_ConsumeHandshakeNumber(ss, 2, b, length); + if (extension_type < 0) /* failure to decode extension_type */ + return SECFailure; /* alert already sent */ + + /* get the data for this extension, so we can pass it or skip it. */ + rv = ssl3_ConsumeHandshakeVariable(ss, &extension_data, 2, b, length); + if (rv != SECSuccess) + return rv; + + /* find extension_type in table of Client Hello Extension Handlers */ + for (handler = handlers; handler->ex_type >= 0; handler++) { + if (handler->ex_type == extension_type) + break; + } + + /* if found, Call this handler */ + if (handler->ex_type == extension_type) { + rv = (*handler->ex_handler)(ss, (PRUint16)extension_type, + &extension_data); + /* Ignore this result */ + /* Essentially, treat all bad extensions as unrecognized types. */ + } + } + return SECSuccess; +} + +/* Add a callback function to the table of senders of server hello extensions. + */ +SECStatus +ssl3_RegisterServerHelloExtensionSender(sslSocket *ss, PRUint16 ex_type, + ssl3HelloExtensionSenderFunc cb) +{ + int i; + ssl3HelloExtensionSender *sender = &ss->serverExtensionSenders[0]; + + for (i = 0; i < MAX_EXTENSION_SENDERS; ++i, ++sender) { + if (!sender->ex_sender) { + sender->ex_type = ex_type; + sender->ex_sender = cb; + return SECSuccess; + } + /* detect duplicate senders */ + PORT_Assert(sender->ex_type != ex_type); + if (sender->ex_type == ex_type) { + /* duplicate */ + break; + } + } + PORT_Assert(i < MAX_EXTENSION_SENDERS); /* table needs to grow */ + PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); + return SECFailure; +} + +/* call each of the extension senders and return the accumulated length */ +PRInt32 +ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes, + const ssl3HelloExtensionSender *sender) +{ + PRInt32 total_exten_len = 0; + int i; + + if (!sender) + sender = &clientHelloSenders[0]; + + for (i = 0; i < MAX_EXTENSION_SENDERS; ++i, ++sender) { + if (sender->ex_sender) { + PRInt32 extLen = (*sender->ex_sender)(ss, append, maxBytes); + if (extLen < 0) + return -1; + maxBytes -= extLen; + total_exten_len += extLen; + } + } + return total_exten_len; +} + diff --git a/security/nss/lib/ssl/ssl3prot.h b/security/nss/lib/ssl/ssl3prot.h index d466c614d..b57314005 100644 --- a/security/nss/lib/ssl/ssl3prot.h +++ b/security/nss/lib/ssl/ssl3prot.h @@ -130,7 +130,14 @@ typedef enum { insufficient_security = 71, internal_error = 80, user_canceled = 90, - no_renegotiation = 100 + no_renegotiation = 100, + +/* Alerts for client hello extensions */ + unsupported_extension = 110, + certificate_unobtainable = 111, + unrecognized_name = 112, + bad_certificate_status_response = 113, + bad_certificate_hash_value = 114 } SSL3AlertDescription; @@ -210,7 +217,8 @@ typedef enum { kea_ecdh_ecdsa, kea_ecdhe_ecdsa, kea_ecdh_rsa, - kea_ecdhe_rsa + kea_ecdhe_rsa, + kea_ecdh_anon } SSL3KeyExchangeAlgorithm; typedef struct { @@ -250,13 +258,9 @@ typedef enum { ct_DSS_fixed_DH = 4, ct_RSA_ephemeral_DH = 5, ct_DSS_ephemeral_DH = 6, - /* XXX The numbers assigned to the following EC-based - * certificate types might change before the ECC in TLS - * draft becomes an IETF RFC. - */ - ct_ECDSA_sign = 7, - ct_RSA_fixed_ECDH = 8, - ct_ECDSA_fixed_ECDH = 9 + ct_ECDSA_sign = 64, + ct_RSA_fixed_ECDH = 65, + ct_ECDSA_fixed_ECDH = 66 } SSL3ClientCertificateType; diff --git a/security/nss/lib/ssl/sslauth.c b/security/nss/lib/ssl/sslauth.c index 848f5aa63..45108afd7 100644 --- a/security/nss/lib/ssl/sslauth.c +++ b/security/nss/lib/ssl/sslauth.c @@ -116,11 +116,14 @@ SSL_SecurityStatus(PRFileDesc *fd, int *op, char **cp, int *kp0, int *kp1, } else { cipherName = ssl3_cipherName[ss->sec.cipherType]; } - if (cipherName && PORT_Strstr(cipherName, "DES")) isDes = PR_TRUE; - - if (cp) { - *cp = PORT_Strdup(cipherName); - } + PORT_Assert(cipherName); + if (cipherName) { + if (PORT_Strstr(cipherName, "DES")) isDes = PR_TRUE; + + if (cp) { + *cp = PORT_Strdup(cipherName); + } + } if (kp0) { *kp0 = ss->sec.keyBits; diff --git a/security/nss/lib/ssl/sslcon.c b/security/nss/lib/ssl/sslcon.c index 06ec09813..e72d1ff3a 100644 --- a/security/nss/lib/ssl/sslcon.c +++ b/security/nss/lib/ssl/sslcon.c @@ -926,8 +926,8 @@ ssl2_SendClear(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags) if ((unsigned)rv < (amount + 2)) { /* Short write. Save the data and return. */ - if (ssl_SaveWriteData(ss, &ss->pendingBuf, out + rv, - amount + 2 - rv) == SECFailure) { + if (ssl_SaveWriteData(ss, out + rv, amount + 2 - rv) + == SECFailure) { count = SECFailure; } else { count += amount; @@ -1023,8 +1023,7 @@ ssl2_SendStream(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags) if ((unsigned)rv < buflen) { /* Short write. Save the data and return. */ - if (ssl_SaveWriteData(ss, &ss->pendingBuf, out + rv, - buflen - rv) == SECFailure) { + if (ssl_SaveWriteData(ss, out + rv, buflen - rv) == SECFailure) { count = SECFailure; } else { count += amount; @@ -1152,8 +1151,7 @@ ssl2_SendBlock(sslSocket *ss, const PRUint8 *in, PRInt32 len, PRInt32 flags) if (rv < (op - out)) { /* Short write. Save the data and return. */ - if (ssl_SaveWriteData(ss, &ss->pendingBuf, out + rv, - op - out - rv) == SECFailure) { + if (ssl_SaveWriteData(ss, out + rv, op - out - rv) == SECFailure) { count = SECFailure; } else { count += amount; @@ -3742,7 +3740,8 @@ ssl2_BeginServerHandshake(sslSocket *ss) ss->sec.rcvSequence = 0; /* don't turn on SSL2 if we don't have an RSA key and cert */ - if (!rsaAuth->SERVERKEY || !rsaAuth->serverCert) { + if (!rsaAuth->serverKeyPair || !rsaAuth->SERVERKEY || + !rsaAuth->serverCert) { ss->opt.enableSSL2 = PR_FALSE; } diff --git a/security/nss/lib/ssl/ssldef.c b/security/nss/lib/ssl/ssldef.c index 23ef9cafe..9a473380e 100644 --- a/security/nss/lib/ssl/ssldef.c +++ b/security/nss/lib/ssl/ssldef.c @@ -104,14 +104,15 @@ int ssl_DefRecv(sslSocket *ss, unsigned char *buf, int len, int flags) } /* Default (unencrypted) send. - * Returns SECSuccess or SECFailure, NOT SECWouldBlock. - * Returns positive count if any data was written. - * ALWAYS check for a short write after calling ssl_DefSend. + * For blocking sockets, always returns len or SECFailure, no short writes. + * For non-blocking sockets: + * Returns positive count if any data was written, else returns SECFailure. + * Short writes may occur. Does not return SECWouldBlock. */ int ssl_DefSend(sslSocket *ss, const unsigned char *buf, int len, int flags) { PRFileDesc *lower = ss->fd->lower; - int rv, count; + int sent = 0; #if NSS_DISABLE_NAGLE_DELAYS /* Although this is overkill, we disable Nagle delays completely for @@ -122,32 +123,24 @@ int ssl_DefSend(sslSocket *ss, const unsigned char *buf, int len, int flags) ss->delayDisabled = 1; } #endif - count = 0; - for (;;) { - rv = lower->methods->send(lower, (const void *)buf, len, - flags, ss->wTimeout); + do { + int rv = lower->methods->send(lower, (const void *)(buf + sent), + len - sent, flags, ss->wTimeout); if (rv < 0) { PRErrorCode err = PR_GetError(); if (err == PR_WOULD_BLOCK_ERROR) { ss->lastWriteBlocked = 1; - return count ? count : rv; + return sent ? sent : SECFailure; } ss->lastWriteBlocked = 0; MAP_ERROR(PR_CONNECT_ABORTED_ERROR, PR_CONNECT_RESET_ERROR) /* Loser */ return rv; } - count += rv; - if (rv < len) { - /* Short send. Send the rest in the next call */ - buf += rv; - len -= rv; - continue; - } - break; - } + sent += rv; + } while (len > sent); ss->lastWriteBlocked = 0; - return count; + return sent; } int ssl_DefRead(sslSocket *ss, unsigned char *buf, int len) @@ -166,33 +159,26 @@ int ssl_DefRead(sslSocket *ss, unsigned char *buf, int len) int ssl_DefWrite(sslSocket *ss, const unsigned char *buf, int len) { PRFileDesc *lower = ss->fd->lower; - int rv, count; + int sent = 0; - count = 0; - for (;;) { - rv = lower->methods->write(lower, (void *)buf, len); + do { + int rv = lower->methods->write(lower, (const void *)(buf + sent), + len - sent); if (rv < 0) { PRErrorCode err = PR_GetError(); if (err == PR_WOULD_BLOCK_ERROR) { ss->lastWriteBlocked = 1; - return count ? count : rv; + return sent ? sent : SECFailure; } ss->lastWriteBlocked = 0; MAP_ERROR(PR_CONNECT_ABORTED_ERROR, PR_CONNECT_RESET_ERROR) /* Loser */ return rv; } - count += rv; - if (rv != len) { - /* Short write. Send the rest in the next call */ - buf += rv; - len -= rv; - continue; - } - break; - } + sent += rv; + } while (len > sent); ss->lastWriteBlocked = 0; - return count; + return sent; } int ssl_DefGetpeername(sslSocket *ss, PRNetAddr *name) diff --git a/security/nss/lib/ssl/sslenum.c b/security/nss/lib/ssl/sslenum.c index d28d689b7..f53bd2268 100644 --- a/security/nss/lib/ssl/sslenum.c +++ b/security/nss/lib/ssl/sslenum.c @@ -47,6 +47,10 @@ const PRUint16 SSL_ImplementedCiphers[] = { /* 256-bit */ +#ifdef NSS_ENABLE_ECC + TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, + TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, +#endif /* NSS_ENABLE_ECC */ TLS_DHE_RSA_WITH_AES_256_CBC_SHA, TLS_DHE_DSS_WITH_AES_256_CBC_SHA, #ifdef NSS_ENABLE_ECC @@ -57,7 +61,9 @@ const PRUint16 SSL_ImplementedCiphers[] = { /* 128-bit */ #ifdef NSS_ENABLE_ECC + TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, + TLS_ECDHE_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, #endif /* NSS_ENABLE_ECC */ TLS_DHE_DSS_WITH_RC4_128_SHA, @@ -74,6 +80,10 @@ const PRUint16 SSL_ImplementedCiphers[] = { TLS_RSA_WITH_AES_128_CBC_SHA, /* 112-bit 3DES */ +#ifdef NSS_ENABLE_ECC + TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, + TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, +#endif /* NSS_ENABLE_ECC */ SSL_DHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA, #ifdef NSS_ENABLE_ECC @@ -86,10 +96,6 @@ 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, @@ -103,6 +109,8 @@ const PRUint16 SSL_ImplementedCiphers[] = { /* ciphersuites with no encryption */ #ifdef NSS_ENABLE_ECC + TLS_ECDHE_ECDSA_WITH_NULL_SHA, + TLS_ECDHE_RSA_WITH_NULL_SHA, TLS_ECDH_RSA_WITH_NULL_SHA, TLS_ECDH_ECDSA_WITH_NULL_SHA, #endif /* NSS_ENABLE_ECC */ diff --git a/security/nss/lib/ssl/sslerr.h b/security/nss/lib/ssl/sslerr.h index be808b8bc..c17014c24 100644 --- a/security/nss/lib/ssl/sslerr.h +++ b/security/nss/lib/ssl/sslerr.h @@ -186,6 +186,12 @@ SSL_ERROR_NO_RENEGOTIATION_ALERT = (SSL_ERROR_BASE + 102), SSL_ERROR_SERVER_CACHE_NOT_CONFIGURED = (SSL_ERROR_BASE + 103), +SSL_ERROR_UNSUPPORTED_EXTENSION_ALERT = (SSL_ERROR_BASE + 104), +SSL_ERROR_CERTIFICATE_UNOBTAINABLE_ALERT = (SSL_ERROR_BASE + 105), +SSL_ERROR_UNRECOGNIZED_NAME_ALERT = (SSL_ERROR_BASE + 106), +SSL_ERROR_BAD_CERT_STATUS_RESPONSE_ALERT = (SSL_ERROR_BASE + 107), +SSL_ERROR_BAD_CERT_HASH_VALUE_ALERT = (SSL_ERROR_BASE + 108), + SSL_ERROR_END_OF_LIST /* let the c compiler determine the value of this. */ } SSLErrorCodes; #endif /* NO_SECURITY_ERROR_ENUM */ diff --git a/security/nss/lib/ssl/sslimpl.h b/security/nss/lib/ssl/sslimpl.h index 1da55d59b..6da5801cb 100644 --- a/security/nss/lib/ssl/sslimpl.h +++ b/security/nss/lib/ssl/sslimpl.h @@ -170,13 +170,22 @@ typedef enum { SSLAppOpRead = 0, #define SSL3_MASTER_SECRET_LENGTH 48 /* number of wrap mechanisms potentially used to wrap master secrets. */ -#define SSL_NUM_WRAP_MECHS 13 +#define SSL_NUM_WRAP_MECHS 14 /* This makes the cert cache entry exactly 4k. */ #define SSL_MAX_CACHED_CERT_LEN 4060 +#define MAX_EXTENSION_SENDERS 3 + #define NUM_MIXERS 9 +/* Mask of the 25 named curves we support. */ +#ifndef NSS_ECC_MORE_THAN_SUITE_B +#define SSL3_SUPPORTED_CURVES_MASK 0x3800000 /* only 3 curves, suite B*/ +#else +#define SSL3_SUPPORTED_CURVES_MASK 0x3fffffe +#endif + #ifndef BPB #define BPB 8 /* Bits Per Byte */ #endif @@ -217,6 +226,38 @@ typedef sslSessionID *(*sslSessionIDLookupFunc)(const PRIPv6Addr *addr, unsigned int sidLen, CERTCertDBHandle * dbHandle); +/* registerable callback function that either appends extension to buffer + * or returns length of data that it would have appended. + */ +typedef PRInt32 (*ssl3HelloExtensionSenderFunc)(sslSocket *ss, PRBool append, + PRUint32 maxBytes); + +/* registerable callback function that handles a received extension, + * of the given type. + */ +typedef SECStatus (* ssl3HelloExtensionHandlerFunc)(sslSocket *ss, + PRUint16 ex_type, + SECItem * data); + +/* row in a table of hello extension senders */ +typedef struct { + PRInt32 ex_type; + ssl3HelloExtensionSenderFunc ex_sender; +} ssl3HelloExtensionSender; + +/* row in a table of hello extension handlers */ +typedef struct { + PRInt32 ex_type; + ssl3HelloExtensionHandlerFunc ex_handler; +} ssl3HelloExtensionHandler; + +extern SECStatus +ssl3_RegisterServerHelloExtensionSender(sslSocket *ss, PRUint16 ex_type, + ssl3HelloExtensionSenderFunc cb); + +extern PRInt32 +ssl3_CallHelloExtensionSenders(sslSocket *ss, PRBool append, PRUint32 maxBytes, + const ssl3HelloExtensionSender *sender); /* Socket ops */ struct sslSocketOpsStr { @@ -270,7 +311,7 @@ typedef struct { } ssl3CipherSuiteCfg; #ifdef NSS_ENABLE_ECC -#define ssl_V3_SUITES_IMPLEMENTED 37 +#define ssl_V3_SUITES_IMPLEMENTED 43 #else #define ssl_V3_SUITES_IMPLEMENTED 23 #endif /* NSS_ENABLE_ECC */ @@ -552,6 +593,9 @@ struct sslSessionIDStr { SSL3KEAType exchKeyType; /* key type used in exchange algorithm, * and to wrap the sym wrapping key. */ +#ifdef NSS_ENABLE_ECC + PRUint32 negotiatedECCurves; +#endif /* NSS_ENABLE_ECC */ /* The following values are NOT restored from the server's on-disk * session cache, but are restored from the client's cache. @@ -677,6 +721,9 @@ const ssl3CipherSuiteDef *suite_def; PRBool usedStepDownKey; /* we did a server key exchange. */ sslBuffer msgState; /* current state for handshake messages*/ /* protected by recvBufLock */ +#ifdef NSS_ENABLE_ECC + PRUint32 negotiatedECCurves; /* bit mask */ +#endif /* NSS_ENABLE_ECC */ } SSL3HandshakeState; @@ -727,8 +774,8 @@ typedef struct { } SSL3Ciphertext; struct ssl3KeyPairStr { - SECKEYPrivateKey * privKey; /* RSA step down key */ - SECKEYPublicKey * pubKey; /* RSA step down key */ + SECKEYPrivateKey * privKey; + SECKEYPublicKey * pubKey; PRInt32 refCount; /* use PR_Atomic calls for this. */ }; @@ -897,6 +944,7 @@ struct sslSocketStr { unsigned long lastWriteBlocked; unsigned long recvdCloseNotify; /* received SSL EOF. */ unsigned long TCPconnected; + unsigned long appDataBuffered; /* version of the protocol to use */ SSL3ProtocolVersion version; @@ -911,6 +959,9 @@ struct sslSocketStr { sslHandshakeFunc nextHandshake; /*firstHandshakeLock*/ sslHandshakeFunc securityHandshake; /*firstHandshakeLock*/ + /* registered callbacks that send server hello extensions */ + ssl3HelloExtensionSender serverExtensionSenders[MAX_EXTENSION_SENDERS]; + /* the following variable is only used with socks or other proxies. */ char * peerID; /* String uniquely identifies target server. */ @@ -1084,9 +1135,8 @@ extern sslSocket * ssl_DupSocket(sslSocket *old); extern void ssl_PrintBuf(sslSocket *ss, const char *msg, const void *cp, int len); extern void ssl_DumpMsg(sslSocket *ss, unsigned char *bp, unsigned len); -extern int ssl_SendSavedWriteData(sslSocket *ss, sslBuffer *buf, - sslSendFunc fp); -extern SECStatus ssl_SaveWriteData(sslSocket *ss, sslBuffer *buf, +extern int ssl_SendSavedWriteData(sslSocket *ss); +extern SECStatus ssl_SaveWriteData(sslSocket *ss, const void* p, unsigned int l); extern SECStatus ssl2_BeginClientHandshake(sslSocket *ss); extern SECStatus ssl2_BeginServerHandshake(sslSocket *ss); @@ -1222,7 +1272,8 @@ int ssl3_GatherCompleteHandshake(sslSocket *ss, int flags); extern SECStatus ssl3_CreateRSAStepDownKeys(sslSocket *ss); #ifdef NSS_ENABLE_ECC -extern SECStatus ssl3_CreateECDHEphemeralKeys(sslSocket *ss); +extern void ssl3_FilterECCipherSuitesByServerCerts(sslSocket *ss); +extern PRBool ssl3_IsECCEnabled(sslSocket *ss); #endif /* NSS_ENABLE_ECC */ extern SECStatus ssl3_CipherPrefSetDefault(ssl3CipherSuite which, PRBool on); @@ -1276,10 +1327,14 @@ extern SECStatus ssl3_AppendHandshake(sslSocket *ss, const void *void_src, PRInt32 bytes); extern SECStatus ssl3_AppendHandshakeHeader(sslSocket *ss, SSL3HandshakeType t, PRUint32 length); +extern SECStatus ssl3_AppendHandshakeNumber(sslSocket *ss, PRInt32 num, + PRInt32 lenSize); extern SECStatus ssl3_AppendHandshakeVariable( sslSocket *ss, const SSL3Opaque *src, PRInt32 bytes, PRInt32 lenSize); extern SECStatus ssl3_ConsumeHandshake(sslSocket *ss, void *v, PRInt32 bytes, SSL3Opaque **b, PRUint32 *length); +extern PRInt32 ssl3_ConsumeHandshakeNumber(sslSocket *ss, PRInt32 bytes, + SSL3Opaque **b, PRUint32 *length); extern SECStatus ssl3_ConsumeHandshakeVariable(sslSocket *ss, SECItem *i, PRInt32 bytes, SSL3Opaque **b, PRUint32 *length); extern SECStatus ssl3_SignHashes(SSL3Hashes *hash, SECKEYPrivateKey *key, @@ -1288,6 +1343,14 @@ extern SECStatus ssl3_VerifySignedHashes(SSL3Hashes *hash, CERTCertificate *cert, SECItem *buf, PRBool isTLS, void *pwArg); +/* functions that append extensions to hello messages. */ +extern PRInt32 ssl3_SendServerNameIndicationExtension( sslSocket * ss, + PRBool append, PRUint32 maxBytes); + +/* call the registered extension handlers. */ +extern SECStatus ssl3_HandleClientHelloExtensions(sslSocket *ss, + SSL3Opaque **b, PRUint32 *length); + /* Construct a new NSPR socket for the app to use */ extern PRFileDesc *ssl_NewPRSocket(sslSocket *ss, PRFileDesc *fd); extern void ssl_FreePRSocket(PRFileDesc *fd); @@ -1338,27 +1401,6 @@ extern int ssl_MapLowLevelError(int hiLevelError); extern PRUint32 ssl_Time(void); -/* emulation of NSPR routines. */ -extern PRInt32 -ssl_EmulateAcceptRead( PRFileDesc * sd, - PRFileDesc ** nd, - PRNetAddr ** raddr, - void * buf, - PRInt32 amount, - PRIntervalTime timeout); -extern PRInt32 -ssl_EmulateTransmitFile( PRFileDesc * sd, - PRFileDesc * fd, - const void * headers, - PRInt32 hlen, - PRTransmitFileFlags flags, - PRIntervalTime timeout); -extern PRInt32 -ssl_EmulateSendFile( PRFileDesc * sd, - PRSendFileData * sfd, - PRTransmitFileFlags flags, - PRIntervalTime timeout); - SECStatus SSL_DisableDefaultExportCipherSuites(void); SECStatus SSL_DisableExportCipherSuites(PRFileDesc * fd); diff --git a/security/nss/lib/ssl/sslinfo.c b/security/nss/lib/ssl/sslinfo.c index d3a9735f0..020c892e9 100644 --- a/security/nss/lib/ssl/sslinfo.c +++ b/security/nss/lib/ssl/sslinfo.c @@ -163,21 +163,27 @@ static const SSLCipherSuiteInfo suiteInfo[] = { /* 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, 1, 0, 0, }, {0,CS(TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_128, M_SHA, 1, 0, 0, }, {0,CS(TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA), S_ECDSA, K_ECDH, C_AES, B_256, M_SHA, 1, 0, 0, }, +{0,CS(TLS_ECDHE_ECDSA_WITH_NULL_SHA), S_ECDSA, K_ECDHE, C_NULL, B_0, M_SHA, 0, 0, 0, }, +{0,CS(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA), S_ECDSA, K_ECDHE, C_RC4, B_128, M_SHA, 0, 0, 0, }, +{0,CS(TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA), S_ECDSA, K_ECDHE, C_3DES, B_3DES, M_SHA, 1, 0, 0, }, +{0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA, 1, 0, 0, }, +{0,CS(TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA), S_ECDSA, K_ECDHE, C_AES, B_256, M_SHA, 1, 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, 1, 0, 0, }, {0,CS(TLS_ECDH_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDH, C_AES, B_128, M_SHA, 1, 0, 0, }, {0,CS(TLS_ECDH_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_ECDH, C_AES, B_256, M_SHA, 1, 0, 0, }, -{0,CS(TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA), S_ECDSA, K_ECDHE, C_AES, B_128, M_SHA, 1, 0, 0, }, - +{0,CS(TLS_ECDHE_RSA_WITH_NULL_SHA), S_RSA, K_ECDHE, C_NULL, B_0, M_SHA, 0, 0, 0, }, +{0,CS(TLS_ECDHE_RSA_WITH_RC4_128_SHA), S_RSA, K_ECDHE, C_RC4, B_128, M_SHA, 0, 0, 0, }, +{0,CS(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA), S_RSA, K_ECDHE, C_3DES, B_3DES, M_SHA, 1, 0, 0, }, {0,CS(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA), S_RSA, K_ECDHE, C_AES, B_128, M_SHA, 1, 0, 0, }, +{0,CS(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA), S_RSA, K_ECDHE, C_AES, B_256, M_SHA, 1, 0, 0, }, #endif /* NSS_ENABLE_ECC */ /* SSL 2 table */ diff --git a/security/nss/lib/ssl/sslproto.h b/security/nss/lib/ssl/sslproto.h index e7a998126..f96bb8da3 100644 --- a/security/nss/lib/ssl/sslproto.h +++ b/security/nss/lib/ssl/sslproto.h @@ -166,26 +166,35 @@ #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 +#define TLS_ECDH_ECDSA_WITH_NULL_SHA 0xC001 +#define TLS_ECDH_ECDSA_WITH_RC4_128_SHA 0xC002 +#define TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC003 +#define TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0xC004 +#define TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0xC005 + +#define TLS_ECDHE_ECDSA_WITH_NULL_SHA 0xC006 +#define TLS_ECDHE_ECDSA_WITH_RC4_128_SHA 0xC007 +#define TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC008 +#define TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0xC009 +#define TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0xC00A + +#define TLS_ECDH_RSA_WITH_NULL_SHA 0xC00B +#define TLS_ECDH_RSA_WITH_RC4_128_SHA 0xC00C +#define TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA 0xC00D +#define TLS_ECDH_RSA_WITH_AES_128_CBC_SHA 0xC00E +#define TLS_ECDH_RSA_WITH_AES_256_CBC_SHA 0xC00F + +#define TLS_ECDHE_RSA_WITH_NULL_SHA 0xC010 +#define TLS_ECDHE_RSA_WITH_RC4_128_SHA 0xC011 +#define TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA 0xC012 +#define TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 0xC013 +#define TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 0xC014 + +#define TLS_ECDH_anon_WITH_NULL_SHA 0xC015 +#define TLS_ECDH_anon_WITH_RC4_128_SHA 0xC016 +#define TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA 0xC017 +#define TLS_ECDH_anon_WITH_AES_128_CBC_SHA 0xC018 +#define TLS_ECDH_anon_WITH_AES_256_CBC_SHA 0xC019 #endif /* NSS_ENABLE_ECC */ /* Netscape "experimental" cipher suites. */ diff --git a/security/nss/lib/ssl/sslsecur.c b/security/nss/lib/ssl/sslsecur.c index a30b062df..0d395f64e 100644 --- a/security/nss/lib/ssl/sslsecur.c +++ b/security/nss/lib/ssl/sslsecur.c @@ -440,24 +440,23 @@ sslBuffer_Grow(sslBuffer *b, unsigned int newLen) ** Caller must hold xmitBufLock */ SECStatus -ssl_SaveWriteData(sslSocket *ss, sslBuffer *buf, const void *data, - unsigned int len) +ssl_SaveWriteData(sslSocket *ss, const void *data, unsigned int len) { unsigned int newlen; SECStatus rv; PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); - newlen = buf->len + len; - if (newlen > buf->space) { - rv = sslBuffer_Grow(buf, newlen); + newlen = ss->pendingBuf.len + len; + if (newlen > ss->pendingBuf.space) { + rv = sslBuffer_Grow(&ss->pendingBuf, newlen); if (rv) { return rv; } } SSL_TRC(5, ("%d: SSL[%d]: saving %d bytes of data (%d total saved so far)", SSL_GETPID(), ss->fd, len, newlen)); - PORT_Memcpy(buf->buf + buf->len, data, len); - buf->len = newlen; + PORT_Memcpy(ss->pendingBuf.buf + ss->pendingBuf.len, data, len); + ss->pendingBuf.len = newlen; return SECSuccess; } @@ -468,28 +467,23 @@ ssl_SaveWriteData(sslSocket *ss, sslBuffer *buf, const void *data, ** Caller must hold xmitBufLock */ int -ssl_SendSavedWriteData(sslSocket *ss, sslBuffer *buf, sslSendFunc send) +ssl_SendSavedWriteData(sslSocket *ss) { int rv = 0; - int len = buf->len; PORT_Assert( ss->opt.noLocks || ssl_HaveXmitBufLock(ss) ); - if (len != 0) { + if (ss->pendingBuf.len != 0) { SSL_TRC(5, ("%d: SSL[%d]: sending %d bytes of saved data", - SSL_GETPID(), ss->fd, len)); - rv = (*send)(ss, buf->buf, len, 0); + SSL_GETPID(), ss->fd, ss->pendingBuf.len)); + rv = ssl_DefSend(ss, ss->pendingBuf.buf, ss->pendingBuf.len, 0); if (rv < 0) { return rv; } - if (rv < len) { - /* UGH !! This shifts the whole buffer down by copying it, and - ** it depends on PORT_Memmove doing overlapping moves correctly! - ** It should advance the pointer offset instead !! - */ - PORT_Memmove(buf->buf, buf->buf + rv, len - rv); - buf->len = len - rv; - } else { - buf->len = 0; + ss->pendingBuf.len -= rv; + if (ss->pendingBuf.len > 0 && rv > 0) { + /* UGH !! This shifts the whole buffer down by copying it */ + PORT_Memmove(ss->pendingBuf.buf, ss->pendingBuf.buf + rv, + ss->pendingBuf.len); } } return rv; @@ -632,6 +626,7 @@ SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert, SECStatus rv; sslSocket *ss; sslServerCerts *sc; + SECKEYPublicKey * pubKey = NULL; ss = ssl_FindSocket(fd); if (!ss) { @@ -664,7 +659,6 @@ SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert, sc->serverCert = NULL; } if (cert) { - SECKEYPublicKey * pubKey; sc->serverCert = CERT_DupCertificate(cert); if (!sc->serverCert) goto loser; @@ -673,8 +667,6 @@ SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert, if (!pubKey) goto loser; sc->serverKeyBits = SECKEY_PublicKeyStrengthInBits(pubKey); - SECKEY_DestroyPublicKey(pubKey); - pubKey = NULL; } @@ -723,11 +715,12 @@ SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert, if (keyCopy == NULL) goto loser; SECKEY_CacheStaticFlags(keyCopy); - sc->serverKeyPair = ssl3_NewKeyPair(keyCopy, NULL); + sc->serverKeyPair = ssl3_NewKeyPair(keyCopy, pubKey); if (sc->serverKeyPair == NULL) { SECKEY_DestroyPrivateKey(keyCopy); goto loser; } + pubKey = NULL; /* adopted by serverKeyPair */ } if (kea == kt_rsa && cert && sc->serverKeyBits > 512) { @@ -748,6 +741,10 @@ SSL_ConfigSecureServer(PRFileDesc *fd, CERTCertificate *cert, return SECSuccess; loser: + if (pubKey) { + SECKEY_DestroyPublicKey(pubKey); + pubKey = NULL; + } if (sc->serverCert != NULL) { CERT_DestroyCertificate(sc->serverCert); sc->serverCert = NULL; @@ -1017,7 +1014,7 @@ ssl_SecureRecv(sslSocket *ss, unsigned char *buf, int len, int flags) if (!ssl_SocketIsBlocking(ss) && !ss->opt.fdx) { ssl_GetXmitBufLock(ss); if (ss->pendingBuf.len != 0) { - rv = ssl_SendSavedWriteData(ss, &ss->pendingBuf, ssl_DefSend); + rv = ssl_SendSavedWriteData(ss); if ((rv < 0) && (PORT_GetError() != PR_WOULD_BLOCK_ERROR)) { ssl_ReleaseXmitBufLock(ss); return SECFailure; @@ -1072,7 +1069,7 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) ssl_GetXmitBufLock(ss); if (ss->pendingBuf.len != 0) { PORT_Assert(ss->pendingBuf.len > 0); - rv = ssl_SendSavedWriteData(ss, &ss->pendingBuf, ssl_DefSend); + rv = ssl_SendSavedWriteData(ss); if (rv >= 0 && ss->pendingBuf.len != 0) { PORT_Assert(ss->pendingBuf.len > 0); PORT_SetError(PR_WOULD_BLOCK_ERROR); @@ -1106,6 +1103,10 @@ ssl_SecureSend(sslSocket *ss, const unsigned char *buf, int len, int flags) return 0; } PORT_Assert(buf != NULL); + if (!buf) { + PORT_SetError(PR_INVALID_ARGUMENT_ERROR); + return PR_FAILURE; + } SSL_TRC(2, ("%d: SSL[%d]: SecureSend: sending %d bytes", SSL_GETPID(), ss->fd, len)); diff --git a/security/nss/lib/ssl/sslsnce.c b/security/nss/lib/ssl/sslsnce.c index 877a5a995..b0e386e2e 100644 --- a/security/nss/lib/ssl/sslsnce.c +++ b/security/nss/lib/ssl/sslsnce.c @@ -750,12 +750,14 @@ ServerSessionIDCache(sslSessionID *sid) if (sid->cached == never_cached || sid->cached == invalid_cache) { PRUint32 set; - PORT_Assert(sid->creationTime != 0 && sid->expirationTime != 0); + PORT_Assert(sid->creationTime != 0); if (!sid->creationTime) sid->lastAccessTime = sid->creationTime = ssl_Time(); if (version < SSL_LIBRARY_VERSION_3_0) { - if (!sid->expirationTime) - sid->expirationTime = sid->creationTime + ssl_sid_timeout; + /* override caller's expiration time, which uses client timeout + * duration, not server timeout duration. + */ + sid->expirationTime = sid->creationTime + cache->ssl2Timeout; SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x " "cipher=%d", myPid, sid->cached, sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], @@ -769,8 +771,10 @@ ServerSessionIDCache(sslSessionID *sid) sid->u.ssl2.cipherArg.len)); } else { - if (!sid->expirationTime) - sid->expirationTime = sid->creationTime + ssl3_sid_timeout; + /* override caller's expiration time, which uses client timeout + * duration, not server timeout duration. + */ + sid->expirationTime = sid->creationTime + cache->ssl3Timeout; SSL_TRC(8, ("%d: SSL: CacheMT: cached=%d addr=0x%08x%08x%08x%08x time=%x " "cipherSuite=%d", myPid, sid->cached, sid->addr.pr_s6_addr32[0], sid->addr.pr_s6_addr32[1], diff --git a/security/nss/lib/ssl/sslsock.c b/security/nss/lib/ssl/sslsock.c index 6344c99c5..97069b14e 100644 --- a/security/nss/lib/ssl/sslsock.c +++ b/security/nss/lib/ssl/sslsock.c @@ -48,6 +48,7 @@ #include "sslimpl.h" #include "sslproto.h" #include "nspr.h" +#include "private/pprio.h" #define SET_ERROR_CODE /* reminder */ @@ -97,18 +98,24 @@ static cipherPolicy ssl_ciphers[] = { /* Export France */ #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_ECDHE_ECDSA_WITH_NULL_SHA, SSL_ALLOWED, SSL_ALLOWED }, + { TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, + { TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, + { TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, + { TLS_ECDHE_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_NULL_SHA, SSL_ALLOWED, SSL_ALLOWED }, + { TLS_ECDHE_RSA_WITH_RC4_128_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, + { TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, { TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, + { TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED }, #endif /* NSS_ENABLE_ECC */ { 0, SSL_NOT_ALLOWED, SSL_NOT_ALLOWED } }; @@ -291,6 +298,8 @@ ssl_DupSocket(sslSocket *os) } ss->stepDownKeyPair = !os->stepDownKeyPair ? NULL : ssl3_GetKeyPairRef(os->stepDownKeyPair); + ss->ephemeralECDHKeyPair = !os->ephemeralECDHKeyPair ? NULL : + ssl3_GetKeyPairRef(os->ephemeralECDHKeyPair); /* * XXX the preceeding CERT_ and SECKEY_ functions can fail and return NULL. * XXX We should detect this, and not just march on with NULL pointers. @@ -396,6 +405,10 @@ ssl_DestroySocketContents(sslSocket *ss) ssl3_FreeKeyPair(ss->stepDownKeyPair); ss->stepDownKeyPair = NULL; } + if (ss->ephemeralECDHKeyPair) { + ssl3_FreeKeyPair(ss->ephemeralECDHKeyPair); + ss->ephemeralECDHKeyPair = NULL; + } } /* @@ -1586,6 +1599,24 @@ ssl_Poll(PRFileDesc *fd, PRInt16 how_flags, PRInt16 *p_out_flags) return new_flags; } +static PRInt32 PR_CALLBACK +ssl_TransmitFile(PRFileDesc *sd, PRFileDesc *fd, + const void *headers, PRInt32 hlen, + PRTransmitFileFlags flags, PRIntervalTime timeout) +{ + PRSendFileData sfd; + + sfd.fd = fd; + sfd.file_offset = 0; + sfd.file_nbytes = 0; + sfd.header = headers; + sfd.hlen = hlen; + sfd.trailer = NULL; + sfd.tlen = 0; + + return sd->methods->sendfile(sd, &sfd, flags, timeout); +} + PRBool ssl_FdIsBlocking(PRFileDesc *fd) @@ -1842,15 +1873,15 @@ static const PRIOMethods ssl_methods = { ssl_RecvFrom, /* recvfrom */ ssl_SendTo, /* sendto */ ssl_Poll, /* poll */ - ssl_EmulateAcceptRead, /* acceptread */ - ssl_EmulateTransmitFile, /* transmitfile */ + PR_EmulateAcceptRead, /* acceptread */ + ssl_TransmitFile, /* transmitfile */ ssl_GetSockName, /* getsockname */ ssl_GetPeerName, /* getpeername */ NULL, /* getsockopt OBSOLETE */ NULL, /* setsockopt OBSOLETE */ NULL, /* getsocketoption */ NULL, /* setsocketoption */ - ssl_EmulateSendFile, /* Send a (partial) file with header/trailer*/ + PR_EmulateSendFile, /* Send a (partial) file with header/trailer*/ NULL, /* reserved for future use */ NULL, /* reserved for future use */ NULL, /* reserved for future use */ diff --git a/security/nss/lib/util/secasn1e.c b/security/nss/lib/util/secasn1e.c index db7792cb1..2300060df 100644 --- a/security/nss/lib/util/secasn1e.c +++ b/security/nss/lib/util/secasn1e.c @@ -1639,7 +1639,7 @@ SEC_ASN1EncodeInteger(PRArenaPool *poolp, SECItem *dest, long value) } -extern SECItem * +SECItem * SEC_ASN1EncodeUnsignedInteger(PRArenaPool *poolp, SECItem *dest, unsigned long value) { diff --git a/security/nss/lib/util/secitem.h b/security/nss/lib/util/secitem.h index b73083f2b..fee905c2f 100644 --- a/security/nss/lib/util/secitem.h +++ b/security/nss/lib/util/secitem.h @@ -53,7 +53,8 @@ SEC_BEGIN_PROTOS ** Allocate an item. If "arena" is not NULL, then allocate from there, ** otherwise allocate from the heap. If "item" is not NULL, allocate ** only the data for the item, not the item itself. The item structure -** is allocated zero-filled; the data buffer is not zeroed. +** is allocated zero-filled; the data buffer is not zeroed. The caller +** is responsible for initializing the type field of the item. ** ** The resulting item is returned; NULL if any error occurs. ** diff --git a/security/nss/lib/util/secoid.c b/security/nss/lib/util/secoid.c index 550f09b4f..79536ad11 100644 --- a/security/nss/lib/util/secoid.c +++ b/security/nss/lib/util/secoid.c @@ -166,6 +166,8 @@ #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 ANSI_X962_SIGNATURE_OID ANSI_X962_OID, 0x04 +#define ANSI_X962_SPECIFY_OID ANSI_X962_SIGNATURE_OID, 0x03 #define CONST_OID static const unsigned char @@ -453,8 +455,14 @@ 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 }; +CONST_OID ansix962ECPublicKey[] = { ANSI_X962_OID, 0x02, 0x01 }; +CONST_OID ansix962SignaturewithSHA1Digest[] = { ANSI_X962_SIGNATURE_OID, 0x01 }; +CONST_OID ansix962SignatureRecommended[] = { ANSI_X962_SIGNATURE_OID, 0x02 }; +CONST_OID ansix962SignatureSpecified[] = { ANSI_X962_SPECIFY_OID }; +CONST_OID ansix962SignaturewithSHA224Digest[] = { ANSI_X962_SPECIFY_OID, 0x01 }; +CONST_OID ansix962SignaturewithSHA256Digest[] = { ANSI_X962_SPECIFY_OID, 0x02 }; +CONST_OID ansix962SignaturewithSHA384Digest[] = { ANSI_X962_SPECIFY_OID, 0x03 }; +CONST_OID ansix962SignaturewithSHA512Digest[] = { ANSI_X962_SPECIFY_OID, 0x04 }; /* ANSI X9.62 prime curve OIDs */ /* NOTE: prime192v1 is the same as secp192r1, prime256v1 is the @@ -1150,8 +1158,8 @@ const static SECOidData 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, + OD( ansix962SignaturewithSHA1Digest, + SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE, "X9.62 ECDSA signature with SHA1", CKM_ECDSA_SHA1, INVALID_CERT_EXTENSION ), @@ -1435,6 +1443,32 @@ const static SECOidData oids[] = { OD( pkcs9ExtensionRequest, SEC_OID_PKCS9_EXTENSION_REQUEST, "PKCS #9 Extension Request", CKM_INVALID_MECHANISM, INVALID_CERT_EXTENSION ), + + /* more ECC Signature Oids */ + OD( ansix962SignatureRecommended, + SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST, + "X9.62 ECDSA signature with recommended digest", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( ansix962SignatureSpecified, + SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST, + "X9.62 ECDSA signature with specified digest", CKM_ECDSA, + INVALID_CERT_EXTENSION ), + OD( ansix962SignaturewithSHA224Digest, + SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE, + "X9.62 ECDSA signature with SHA224", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( ansix962SignaturewithSHA256Digest, + SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE, + "X9.62 ECDSA signature with SHA256", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( ansix962SignaturewithSHA384Digest, + SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE, + "X9.62 ECDSA signature with SHA384", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), + OD( ansix962SignaturewithSHA512Digest, + SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE, + "X9.62 ECDSA signature with SHA512", CKM_INVALID_MECHANISM, + INVALID_CERT_EXTENSION ), }; /* diff --git a/security/nss/lib/util/secoidt.h b/security/nss/lib/util/secoidt.h index e1072c5bb..64e75c720 100644 --- a/security/nss/lib/util/secoidt.h +++ b/security/nss/lib/util/secoidt.h @@ -314,7 +314,10 @@ typedef enum { /* Elliptic Curve Cryptography (ECC) OIDs */ SEC_OID_ANSIX962_EC_PUBLIC_KEY = 200, - SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST = 201, + SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE = 201, + +#define SEC_OID_ANSIX962_ECDSA_SIGNATURE_WITH_SHA1_DIGEST \ + SEC_OID_ANSIX962_ECDSA_SHA1_SIGNATURE /* ANSI X9.62 named elliptic curves (prime field) */ SEC_OID_ANSIX962_EC_PRIME192V1 = 202, @@ -403,6 +406,13 @@ typedef enum { SEC_OID_PKIX_CA_ISSUERS = 273, SEC_OID_PKCS9_EXTENSION_REQUEST = 274, + /* new EC Signature oids */ + SEC_OID_ANSIX962_ECDSA_SIGNATURE_RECOMMENDED_DIGEST = 275, + SEC_OID_ANSIX962_ECDSA_SIGNATURE_SPECIFIED_DIGEST = 276, + SEC_OID_ANSIX962_ECDSA_SHA224_SIGNATURE = 277, + SEC_OID_ANSIX962_ECDSA_SHA256_SIGNATURE = 278, + SEC_OID_ANSIX962_ECDSA_SHA384_SIGNATURE = 279, + SEC_OID_ANSIX962_ECDSA_SHA512_SIGNATURE = 280, SEC_OID_TOTAL } SECOidTag; |