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; }
Result VerifySignedData(const SignedDataWithSignature& sd, Input subjectPublicKeyInfo, void* pkcs11PinArg) { // See bug 921585. if (sd.data.GetLength() > static_cast<unsigned int>(std::numeric_limits<int>::max())) { return Result::FATAL_ERROR_INVALID_ARGS; } SECOidTag pubKeyAlg; SECOidTag digestAlg; switch (sd.algorithm) { case SignatureAlgorithm::ecdsa_with_sha512: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA512; break; case SignatureAlgorithm::ecdsa_with_sha384: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA384; break; case SignatureAlgorithm::ecdsa_with_sha256: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA256; break; case SignatureAlgorithm::ecdsa_with_sha1: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA1; break; case SignatureAlgorithm::rsa_pkcs1_with_sha512: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA512; break; case SignatureAlgorithm::rsa_pkcs1_with_sha384: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA384; break; case SignatureAlgorithm::rsa_pkcs1_with_sha256: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA256; break; case SignatureAlgorithm::rsa_pkcs1_with_sha1: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA1; break; case SignatureAlgorithm::dsa_with_sha256: pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE; digestAlg = SEC_OID_SHA256; break; case SignatureAlgorithm::dsa_with_sha1: pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE; digestAlg = SEC_OID_SHA1; break; default: PR_NOT_REACHED("unknown signature algorithm"); return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED; } Result rv; ScopedSECKeyPublicKey pubKey; rv = CheckPublicKeySize(subjectPublicKeyInfo, pubKey); if (rv != Success) { return rv; } // The static_cast is safe according to the check above that references // bug 921585. SECItem dataSECItem(UnsafeMapInputToSECItem(sd.data)); SECItem signatureSECItem(UnsafeMapInputToSECItem(sd.signature)); SECStatus srv = VFY_VerifyDataDirect(dataSECItem.data, static_cast<int>(dataSECItem.len), pubKey.get(), &signatureSECItem, pubKeyAlg, digestAlg, nullptr, pkcs11PinArg); if (srv != SECSuccess) { return MapPRErrorCodeToResult(PR_GetError()); } return Success; }
SECStatus VerifySignedData(const SignedDataWithSignature& sd, const SECItem& subjectPublicKeyInfo, void* pkcs11PinArg) { if (!sd.data.data || !sd.signature.data) { 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; } SECOidTag pubKeyAlg; SECOidTag digestAlg; switch (sd.algorithm) { case SignatureAlgorithm::ecdsa_with_sha512: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA512; break; case SignatureAlgorithm::ecdsa_with_sha384: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA384; break; case SignatureAlgorithm::ecdsa_with_sha256: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA256; break; case SignatureAlgorithm::ecdsa_with_sha1: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA1; break; case SignatureAlgorithm::rsa_pkcs1_with_sha512: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA512; break; case SignatureAlgorithm::rsa_pkcs1_with_sha384: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA384; break; case SignatureAlgorithm::rsa_pkcs1_with_sha256: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA256; break; case SignatureAlgorithm::rsa_pkcs1_with_sha1: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA1; break; case SignatureAlgorithm::dsa_with_sha256: pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE; digestAlg = SEC_OID_SHA256; break; case SignatureAlgorithm::dsa_with_sha1: pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE; digestAlg = SEC_OID_SHA1; break; default: PR_NOT_REACHED("unknown signature algorithm"); PR_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, 0); return SECFailure; } ScopedSECKeyPublicKey pubKey; if (CheckPublicKeySize(subjectPublicKeyInfo, pubKey) != SECSuccess) { return SECFailure; } // The static_cast is safe according to the check above that references // bug 921585. return VFY_VerifyDataDirect(sd.data.data, static_cast<int>(sd.data.len), pubKey.get(), &sd.signature, pubKeyAlg, digestAlg, nullptr, pkcs11PinArg); }
Result VerifySignedData(const SignedDataWithSignature& sd, Input subjectPublicKeyInfo, void* pkcs11PinArg) { SECOidTag pubKeyAlg; SECOidTag digestAlg; switch (sd.algorithm) { case SignatureAlgorithm::ecdsa_with_sha512: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA512; break; case SignatureAlgorithm::ecdsa_with_sha384: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA384; break; case SignatureAlgorithm::ecdsa_with_sha256: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA256; break; case SignatureAlgorithm::ecdsa_with_sha1: pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY; digestAlg = SEC_OID_SHA1; break; case SignatureAlgorithm::rsa_pkcs1_with_sha512: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA512; break; case SignatureAlgorithm::rsa_pkcs1_with_sha384: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA384; break; case SignatureAlgorithm::rsa_pkcs1_with_sha256: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA256; break; case SignatureAlgorithm::rsa_pkcs1_with_sha1: pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION; digestAlg = SEC_OID_SHA1; break; case SignatureAlgorithm::dsa_with_sha256: pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE; digestAlg = SEC_OID_SHA256; break; case SignatureAlgorithm::dsa_with_sha1: pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE; digestAlg = SEC_OID_SHA1; break; default: PR_NOT_REACHED("unknown signature algorithm"); return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED; } Result rv; ScopedSECKeyPublicKey pubKey; rv = CheckPublicKeySize(subjectPublicKeyInfo, pubKey); if (rv != Success) { return rv; } // The static_cast is safe as long as the length of the data in sd.data can // fit in an int. Right now that length is stored as a uint16_t, so this // works. In the future this may change, hence the assertion. // See also bug 921585. static_assert(sizeof(decltype(sd.data.GetLength())) < sizeof(int), "sd.data.GetLength() must fit in an int"); SECItem dataSECItem(UnsafeMapInputToSECItem(sd.data)); SECItem signatureSECItem(UnsafeMapInputToSECItem(sd.signature)); SECStatus srv = VFY_VerifyDataDirect(dataSECItem.data, static_cast<int>(dataSECItem.len), pubKey.get(), &signatureSECItem, pubKeyAlg, digestAlg, nullptr, pkcs11PinArg); if (srv != SECSuccess) { return MapPRErrorCodeToResult(PR_GetError()); } return Success; }