SECKEYPublicKey* CryptoKey::PublicKeyFromSpki(CryptoBuffer& aKeyData, const nsNSSShutDownPreventionLock& /*proofOfLock*/) { ScopedSECItem spkiItem(aKeyData.ToSECItem()); if (!spkiItem) { return nullptr; } ScopedCERTSubjectPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(spkiItem.get())); if (!spki) { return nullptr; } // Check for id-ecDH. Per the WebCrypto spec we must support it but NSS // does unfortunately not know about it. Let's change the algorithm to // id-ecPublicKey to make NSS happy. if (SECITEM_ItemsAreEqual(&SEC_OID_DATA_EC_DH, &spki->algorithm.algorithm)) { // Retrieve OID data for id-ecPublicKey (1.2.840.10045.2.1). SECOidData* oidData = SECOID_FindOIDByTag(SEC_OID_ANSIX962_EC_PUBLIC_KEY); if (!oidData) { return nullptr; } SECStatus rv = SECITEM_CopyItem(spki->arena, &spki->algorithm.algorithm, &oidData->oid); if (rv != SECSuccess) { return nullptr; } } return SECKEY_ExtractPublicKey(spki.get()); }
SECStatus VerifySignedData(const CERTSignedData* sd, const CERTCertificate* cert, void* pkcs11PinArg) { if (!sd || !sd->data.data || !sd->signatureAlgorithm.algorithm.data || !sd->signature.data || !cert) { PR_NOT_REACHED("invalid args to VerifySignedData"); PR_SetError(SEC_ERROR_INVALID_ARGS, 0); return SECFailure; } // See bug 921585. if (sd->data.len > static_cast<unsigned int>(std::numeric_limits<int>::max())) { PR_SetError(SEC_ERROR_INVALID_ARGS, 0); return SECFailure; } // convert sig->len from bit counts to byte count. SECItem sig = sd->signature; DER_ConvertBitString(&sig); // Use SECKEY_ExtractPublicKey instead of CERT_ExtractPublicKey because // CERT_ExtractPublicKey would try to do (EC)DSA parameter inheritance, using // the classic (wrong) NSS path building logic. We intentionally do not // support parameter inheritance. ScopedSECKEYPublicKey pubKey(SECKEY_ExtractPublicKey(&cert->subjectPublicKeyInfo)); if (!pubKey) { return SECFailure; } SECOidTag hashAlg; if (VFY_VerifyDataWithAlgorithmID(sd->data.data, static_cast<int>(sd->data.len), pubKey.get(), &sig, &sd->signatureAlgorithm, &hashAlg, pkcs11PinArg) != SECSuccess) { return SECFailure; } // TODO: Ideally, we would do this check before we call // VFY_VerifyDataWithAlgorithmID. But, VFY_VerifyDataWithAlgorithmID gives us // the hash algorithm so it is more convenient to do things in this order. uint32_t policy; if (NSS_GetAlgorithmPolicy(hashAlg, &policy) != SECSuccess) { return SECFailure; } // XXX: I'm not sure why there isn't NSS_USE_ALG_IN_SSL_SIGNATURE, but there // isn't. Since we don't know the context in which we're being called, be as // strict as we can be given the NSS API that is available. static const uint32_t requiredPolicy = NSS_USE_ALG_IN_CERT_SIGNATURE | NSS_USE_ALG_IN_CMS_SIGNATURE; if ((policy & requiredPolicy) != requiredPolicy) { PR_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, 0); return SECFailure; } return SECSuccess; }
UniqueSECKEYPublicKey CryptoKey::PublicKeyFromSpki(CryptoBuffer& aKeyData, const nsNSSShutDownPreventionLock& /*proofOfLock*/) { UniquePLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE)); if (!arena) { return nullptr; } SECItem spkiItem = { siBuffer, nullptr, 0 }; if (!aKeyData.ToSECItem(arena.get(), &spkiItem)) { return nullptr; } UniqueCERTSubjectPublicKeyInfo spki( SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem)); if (!spki) { return nullptr; } bool isECDHAlgorithm = SECITEM_ItemsAreEqual(&SEC_OID_DATA_EC_DH, &spki->algorithm.algorithm); bool isDHAlgorithm = SECITEM_ItemsAreEqual(&SEC_OID_DATA_DH_KEY_AGREEMENT, &spki->algorithm.algorithm); // Check for |id-ecDH| and |dhKeyAgreement|. Per the WebCrypto spec we must // support these OIDs but NSS does unfortunately not know about them. Let's // change the algorithm to |id-ecPublicKey| or |dhPublicKey| to make NSS happy. if (isECDHAlgorithm || isDHAlgorithm) { SECOidTag oid = SEC_OID_UNKNOWN; if (isECDHAlgorithm) { oid = SEC_OID_ANSIX962_EC_PUBLIC_KEY; } else if (isDHAlgorithm) { oid = SEC_OID_X942_DIFFIE_HELMAN_KEY; } else { MOZ_ASSERT(false); } SECOidData* oidData = SECOID_FindOIDByTag(oid); if (!oidData) { return nullptr; } SECStatus rv = SECITEM_CopyItem(spki->arena, &spki->algorithm.algorithm, &oidData->oid); if (rv != SECSuccess) { return nullptr; } } UniqueSECKEYPublicKey tmp(SECKEY_ExtractPublicKey(spki.get())); if (!tmp.get() || !PublicKeyValid(tmp.get())) { return nullptr; } return UniqueSECKEYPublicKey(SECKEY_CopyPublicKey(tmp.get())); }
int crypto_cert_get_pub_exp_mod(CryptoCert cert, uint32 * key_len, uint8 * exponent, uint32 exp_len, uint8 * modulus, uint32 mod_len) { SECKEYPublicKey * pubkey; SECOidTag tag = SECOID_GetAlgorithmTag(&cert->cert->subjectPublicKeyInfo.algorithm); if ((tag == SEC_OID_PKCS1_MD5_WITH_RSA_ENCRYPTION) || (tag == SEC_OID_ISO_SHA_WITH_RSA_SIGNATURE)) { /* For some reason, Microsoft sets the OID of the Public RSA key to the oid for "MD5 with RSA Encryption" instead of "RSA Encryption". */ SECAlgorithmID org = cert->cert->subjectPublicKeyInfo.algorithm; SECStatus s = SECOID_SetAlgorithmID(cert->cert->subjectPublicKeyInfo.arena, &cert->cert->subjectPublicKeyInfo.algorithm, SEC_OID_PKCS1_RSA_ENCRYPTION, NULL); check(s, "Error setting temp algo oid"); pubkey = SECKEY_ExtractPublicKey(&cert->cert->subjectPublicKeyInfo); SECOID_DestroyAlgorithmID(&cert->cert->subjectPublicKeyInfo.algorithm, False); cert->cert->subjectPublicKeyInfo.algorithm = org; } else { pubkey = SECKEY_ExtractPublicKey(&cert->cert->subjectPublicKeyInfo); } ASSERT(pubkey); ASSERT(pubkey->keyType == rsaKey); *key_len = SECKEY_PublicKeyStrength(pubkey); size_t l = pubkey->u.rsa.publicExponent.len; ASSERT(l <= exp_len); memset(exponent, 0, exp_len - l); memcpy(exponent + exp_len - l, pubkey->u.rsa.publicExponent.data, l); l = pubkey->u.rsa.modulus.len; ASSERT(l <= mod_len); ASSERT(*key_len <= mod_len); memset(modulus, 0, *key_len - l); memcpy(modulus + *key_len - l, pubkey->u.rsa.modulus.data, l); SECKEY_DestroyPublicKey(pubkey); return 0; }
bool cert_key_is_rsa(CERTCertificate *cert) { bool ret = FALSE; SECKEYPublicKey *pk = SECKEY_ExtractPublicKey( &cert->subjectPublicKeyInfo); if (pk != NULL) { ret = SECKEY_GetPublicKeyType(pk) == rsaKey; SECKEY_DestroyPublicKey(pk); } return ret; }
static SECKEYPublicKey* getPublicKeyFromBytes(uint8_t *publicKeyBytes) { uint8_t spkiBytes[TACK_PUBKEY_LENGTH + sizeof(SPKI_P256)]; memcpy(spkiBytes, SPKI_P256, sizeof(SPKI_P256)); memcpy(spkiBytes + sizeof(SPKI_P256), publicKeyBytes, TACK_PUBKEY_LENGTH); SECItem spkiItem; spkiItem.data = spkiBytes; spkiItem.len = sizeof(spkiBytes); CERTSubjectPublicKeyInfo *spki = SECKEY_DecodeDERSubjectPublicKeyInfo(&spkiItem); SECKEYPublicKey *publicKey = SECKEY_ExtractPublicKey(spki); SECKEY_DestroySubjectPublicKeyInfo(spki); return publicKey; }
SECKEYPublicKey* CryptoKey::PublicKeyFromSpki(CryptoBuffer& aKeyData, const nsNSSShutDownPreventionLock& /*proofOfLock*/) { ScopedSECItem spkiItem(aKeyData.ToSECItem()); if (!spkiItem) { return nullptr; } ScopedCERTSubjectPublicKeyInfo spki(SECKEY_DecodeDERSubjectPublicKeyInfo(spkiItem.get())); if (!spki) { return nullptr; } return SECKEY_ExtractPublicKey(spki.get()); }
SECStatus CheckPublicKeySize(const SECItem& subjectPublicKeyInfo, /*out*/ ScopedSECKeyPublicKey& publicKey) { ScopedPtr<CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo> spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&subjectPublicKeyInfo)); if (!spki) { return SECFailure; } publicKey = SECKEY_ExtractPublicKey(spki.get()); if (!publicKey) { return SECFailure; } static const unsigned int MINIMUM_NON_ECC_BITS = 1024; switch (publicKey.get()->keyType) { case ecKey: // TODO(bug 622859): We should check which curve. return SECSuccess; case dsaKey: // fall through case rsaKey: // TODO(bug 622859): Enforce a minimum of 2048 bits for EV certs. if (SECKEY_PublicKeyStrengthInBits(publicKey.get()) < MINIMUM_NON_ECC_BITS) { // TODO(bug 1031946): Create a new error code. PR_SetError(SEC_ERROR_INVALID_KEY, 0); return SECFailure; } break; case nullKey: case fortezzaKey: case dhKey: case keaKey: case rsaPssKey: case rsaOaepKey: default: PR_SetError(SEC_ERROR_UNSUPPORTED_KEYALG, 0); return SECFailure; } return SECSuccess; }
/* * FUNCTION: PKIX_PL_CRL_VerifySignature (see comments in pkix_pl_pki.h) */ PKIX_Error * PKIX_PL_CRL_VerifySignature( PKIX_PL_CRL *crl, PKIX_PL_PublicKey *pubKey, void *plContext) { PKIX_PL_CRL *cachedCrl = NULL; PKIX_Error *verifySig = NULL; PKIX_Error *cachedSig = NULL; PKIX_Boolean crlEqual = PKIX_FALSE; PKIX_Boolean crlInHash= PKIX_FALSE; CERTSignedCrl *nssSignedCrl = NULL; SECKEYPublicKey *nssPubKey = NULL; CERTSignedData *tbsCrl = NULL; void* wincx = NULL; SECStatus status; PKIX_ENTER(CRL, "PKIX_PL_CRL_VerifySignature"); PKIX_NULLCHECK_THREE(crl, crl->nssSignedCrl, pubKey); /* Can call this function only with der been adopted. */ PORT_Assert(crl->adoptedDerCrl); verifySig = PKIX_PL_HashTable_Lookup (cachedCrlSigTable, (PKIX_PL_Object *) pubKey, (PKIX_PL_Object **) &cachedCrl, plContext); if (cachedCrl != NULL && verifySig == NULL) { /* Cached Signature Table lookup succeed */ PKIX_EQUALS(crl, cachedCrl, &crlEqual, plContext, PKIX_OBJECTEQUALSFAILED); if (crlEqual == PKIX_TRUE) { goto cleanup; } /* Different PubKey may hash to same value, skip add */ crlInHash = PKIX_TRUE; } nssSignedCrl = crl->nssSignedCrl; tbsCrl = &nssSignedCrl->signatureWrap; PKIX_CRL_DEBUG("\t\tCalling SECKEY_ExtractPublicKey\n"); nssPubKey = SECKEY_ExtractPublicKey(pubKey->nssSPKI); if (!nssPubKey){ PKIX_ERROR(PKIX_SECKEYEXTRACTPUBLICKEYFAILED); } PKIX_CHECK(pkix_pl_NssContext_GetWincx ((PKIX_PL_NssContext *)plContext, &wincx), PKIX_NSSCONTEXTGETWINCXFAILED); PKIX_CRL_DEBUG("\t\tCalling CERT_VerifySignedDataWithPublicKey\n"); status = CERT_VerifySignedDataWithPublicKey(tbsCrl, nssPubKey, wincx); if (status != SECSuccess) { PKIX_ERROR(PKIX_SIGNATUREDIDNOTVERIFYWITHTHEPUBLICKEY); } if (crlInHash == PKIX_FALSE) { cachedSig = PKIX_PL_HashTable_Add (cachedCrlSigTable, (PKIX_PL_Object *) pubKey, (PKIX_PL_Object *) crl, plContext); if (cachedSig != NULL) { PKIX_DEBUG("PKIX_PL_HashTable_Add skipped: entry existed\n"); } } cleanup: if (nssPubKey){ PKIX_CRL_DEBUG("\t\tCalling SECKEY_DestroyPublicKey\n"); SECKEY_DestroyPublicKey(nssPubKey); nssPubKey = NULL; } PKIX_DECREF(cachedCrl); PKIX_DECREF(verifySig); PKIX_DECREF(cachedSig); PKIX_RETURN(CRL); }
NS_IMETHODIMP nsDataSignatureVerifier::VerifyData(const nsACString & aData, const nsACString & aSignature, const nsACString & aPublicKey, bool *_retval) { // Allocate an arena to handle the majority of the allocations PRArenaPool *arena; arena = PORT_NewArena(DER_DEFAULT_CHUNKSIZE); if (!arena) return NS_ERROR_OUT_OF_MEMORY; // Base 64 decode the key SECItem keyItem; PORT_Memset(&keyItem, 0, sizeof(SECItem)); if (!NSSBase64_DecodeBuffer(arena, &keyItem, nsPromiseFlatCString(aPublicKey).get(), aPublicKey.Length())) { PORT_FreeArena(arena, false); return NS_ERROR_FAILURE; } // Extract the public key from the data CERTSubjectPublicKeyInfo *pki = SECKEY_DecodeDERSubjectPublicKeyInfo(&keyItem); if (!pki) { PORT_FreeArena(arena, false); return NS_ERROR_FAILURE; } SECKEYPublicKey *publicKey = SECKEY_ExtractPublicKey(pki); SECKEY_DestroySubjectPublicKeyInfo(pki); pki = nullptr; if (!publicKey) { PORT_FreeArena(arena, false); return NS_ERROR_FAILURE; } // Base 64 decode the signature SECItem signatureItem; PORT_Memset(&signatureItem, 0, sizeof(SECItem)); if (!NSSBase64_DecodeBuffer(arena, &signatureItem, nsPromiseFlatCString(aSignature).get(), aSignature.Length())) { SECKEY_DestroyPublicKey(publicKey); PORT_FreeArena(arena, false); return NS_ERROR_FAILURE; } // Decode the signature and algorithm CERTSignedData sigData; PORT_Memset(&sigData, 0, sizeof(CERTSignedData)); SECStatus ss = SEC_QuickDERDecodeItem(arena, &sigData, CERT_SignatureDataTemplate, &signatureItem); if (ss != SECSuccess) { SECKEY_DestroyPublicKey(publicKey); PORT_FreeArena(arena, false); return NS_ERROR_FAILURE; } // Perform the final verification DER_ConvertBitString(&(sigData.signature)); ss = VFY_VerifyDataWithAlgorithmID((const unsigned char*)nsPromiseFlatCString(aData).get(), aData.Length(), publicKey, &(sigData.signature), &(sigData.signatureAlgorithm), NULL, NULL); // Clean up remaining objects SECKEY_DestroyPublicKey(publicKey); PORT_FreeArena(arena, false); *_retval = (ss == SECSuccess); return NS_OK; }