Bug 622859 - Reject EV certificates with key sizes below RSA 2048. r=briansmith

This commit is contained in:
Cykesiopka 2014-10-16 05:13:00 +02:00
Родитель b9708b293b
Коммит 01941f880c
10 изменённых файлов: 49 добавлений и 33 удалений

Просмотреть файл

@ -30,6 +30,8 @@ using namespace mozilla::pkix;
extern PRLogModuleInfo* gPIPNSSLog; extern PRLogModuleInfo* gPIPNSSLog;
#endif #endif
static const unsigned int MINIMUM_NON_ECC_BITS = 2048;
namespace mozilla { namespace psm { namespace mozilla { namespace psm {
AppTrustDomain::AppTrustDomain(ScopedCERTCertList& certChain, void* pinArg) AppTrustDomain::AppTrustDomain(ScopedCERTCertList& certChain, void* pinArg)
@ -213,7 +215,7 @@ AppTrustDomain::VerifySignedData(const SignedDataWithSignature& signedData,
Input subjectPublicKeyInfo) Input subjectPublicKeyInfo)
{ {
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo, return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
mPinArg); MINIMUM_NON_ECC_BITS, mPinArg);
} }
Result Result
@ -247,7 +249,8 @@ AppTrustDomain::IsChainValid(const DERArray& certChain, Time time)
Result Result
AppTrustDomain::CheckPublicKey(Input subjectPublicKeyInfo) AppTrustDomain::CheckPublicKey(Input subjectPublicKeyInfo)
{ {
return ::mozilla::pkix::CheckPublicKey(subjectPublicKeyInfo); return ::mozilla::pkix::CheckPublicKey(subjectPublicKeyInfo,
MINIMUM_NON_ECC_BITS);
} }
} } // namespace mozilla::psm } } // namespace mozilla::psm

Просмотреть файл

@ -211,7 +211,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
// just use trustEmail as it is the closest alternative. // just use trustEmail as it is the closest alternative.
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache, NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
pinArg, ocspGETConfig, pinningDisabled, pinArg, ocspGETConfig, pinningDisabled,
nullptr, builtChain); false, nullptr, builtChain);
rv = BuildCertChain(trustDomain, certDER, time, rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity, EndEntityOrCA::MustBeEndEntity,
KeyUsage::digitalSignature, KeyUsage::digitalSignature,
@ -236,7 +236,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
ocspFetching == NSSCertDBTrustDomain::NeverFetchOCSP ocspFetching == NSSCertDBTrustDomain::NeverFetchOCSP
? NSSCertDBTrustDomain::LocalOnlyOCSPForEV ? NSSCertDBTrustDomain::LocalOnlyOCSPForEV
: NSSCertDBTrustDomain::FetchOCSPForEV, : NSSCertDBTrustDomain::FetchOCSPForEV,
mOCSPCache, pinArg, ocspGETConfig, mPinningMode, mOCSPCache, pinArg, ocspGETConfig, mPinningMode, true,
hostname, builtChain); hostname, builtChain);
rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time, rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time,
KeyUsage::digitalSignature,// (EC)DHE KeyUsage::digitalSignature,// (EC)DHE
@ -261,7 +261,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
// Now try non-EV. // Now try non-EV.
NSSCertDBTrustDomain trustDomain(trustSSL, ocspFetching, mOCSPCache, NSSCertDBTrustDomain trustDomain(trustSSL, ocspFetching, mOCSPCache,
pinArg, ocspGETConfig, mPinningMode, pinArg, ocspGETConfig, mPinningMode,
hostname, builtChain); false, hostname, builtChain);
rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time, rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time,
KeyUsage::digitalSignature, // (EC)DHE KeyUsage::digitalSignature, // (EC)DHE
KeyUsage::keyEncipherment, // RSA KeyUsage::keyEncipherment, // RSA
@ -275,7 +275,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
case certificateUsageSSLCA: { case certificateUsageSSLCA: {
NSSCertDBTrustDomain trustDomain(trustSSL, ocspFetching, mOCSPCache, NSSCertDBTrustDomain trustDomain(trustSSL, ocspFetching, mOCSPCache,
pinArg, ocspGETConfig, pinningDisabled, pinArg, ocspGETConfig, pinningDisabled,
nullptr, builtChain); false, nullptr, builtChain);
rv = BuildCertChain(trustDomain, certDER, time, rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeCA, KeyUsage::keyCertSign, EndEntityOrCA::MustBeCA, KeyUsage::keyCertSign,
KeyPurposeId::id_kp_serverAuth, KeyPurposeId::id_kp_serverAuth,
@ -286,7 +286,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
case certificateUsageEmailSigner: { case certificateUsageEmailSigner: {
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache, NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
pinArg, ocspGETConfig, pinningDisabled, pinArg, ocspGETConfig, pinningDisabled,
nullptr, builtChain); false, nullptr, builtChain);
rv = BuildCertChain(trustDomain, certDER, time, rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity, EndEntityOrCA::MustBeEndEntity,
KeyUsage::digitalSignature, KeyUsage::digitalSignature,
@ -301,7 +301,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
// based on the result of the verification(s). // based on the result of the verification(s).
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache, NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
pinArg, ocspGETConfig, pinningDisabled, pinArg, ocspGETConfig, pinningDisabled,
nullptr, builtChain); false, nullptr, builtChain);
rv = BuildCertChain(trustDomain, certDER, time, rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity, EndEntityOrCA::MustBeEndEntity,
KeyUsage::keyEncipherment, // RSA KeyUsage::keyEncipherment, // RSA
@ -320,7 +320,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
case certificateUsageObjectSigner: { case certificateUsageObjectSigner: {
NSSCertDBTrustDomain trustDomain(trustObjectSigning, ocspFetching, NSSCertDBTrustDomain trustDomain(trustObjectSigning, ocspFetching,
mOCSPCache, pinArg, ocspGETConfig, mOCSPCache, pinArg, ocspGETConfig,
pinningDisabled, nullptr, builtChain); pinningDisabled, false, nullptr,
builtChain);
rv = BuildCertChain(trustDomain, certDER, time, rv = BuildCertChain(trustDomain, certDER, time,
EndEntityOrCA::MustBeEndEntity, EndEntityOrCA::MustBeEndEntity,
KeyUsage::digitalSignature, KeyUsage::digitalSignature,
@ -348,15 +349,15 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
} }
NSSCertDBTrustDomain sslTrust(trustSSL, ocspFetching, mOCSPCache, pinArg, NSSCertDBTrustDomain sslTrust(trustSSL, ocspFetching, mOCSPCache, pinArg,
ocspGETConfig, pinningDisabled, nullptr, ocspGETConfig, pinningDisabled, false,
builtChain); nullptr, builtChain);
rv = BuildCertChain(sslTrust, certDER, time, endEntityOrCA, rv = BuildCertChain(sslTrust, certDER, time, endEntityOrCA,
keyUsage, eku, CertPolicyId::anyPolicy, keyUsage, eku, CertPolicyId::anyPolicy,
stapledOCSPResponse); stapledOCSPResponse);
if (rv == Result::ERROR_UNKNOWN_ISSUER) { if (rv == Result::ERROR_UNKNOWN_ISSUER) {
NSSCertDBTrustDomain emailTrust(trustEmail, ocspFetching, mOCSPCache, NSSCertDBTrustDomain emailTrust(trustEmail, ocspFetching, mOCSPCache,
pinArg, ocspGETConfig, pinningDisabled, pinArg, ocspGETConfig, pinningDisabled,
nullptr, builtChain); false, nullptr, builtChain);
rv = BuildCertChain(emailTrust, certDER, time, endEntityOrCA, rv = BuildCertChain(emailTrust, certDER, time, endEntityOrCA,
keyUsage, eku, CertPolicyId::anyPolicy, keyUsage, eku, CertPolicyId::anyPolicy,
stapledOCSPResponse); stapledOCSPResponse);
@ -364,8 +365,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
NSSCertDBTrustDomain objectSigningTrust(trustObjectSigning, NSSCertDBTrustDomain objectSigningTrust(trustObjectSigning,
ocspFetching, mOCSPCache, ocspFetching, mOCSPCache,
pinArg, ocspGETConfig, pinArg, ocspGETConfig,
pinningDisabled, nullptr, pinningDisabled, false,
builtChain); nullptr, builtChain);
rv = BuildCertChain(objectSigningTrust, certDER, time, rv = BuildCertChain(objectSigningTrust, certDER, time,
endEntityOrCA, keyUsage, eku, endEntityOrCA, keyUsage, eku,
CertPolicyId::anyPolicy, stapledOCSPResponse); CertPolicyId::anyPolicy, stapledOCSPResponse);

Просмотреть файл

@ -35,6 +35,9 @@ extern PRLogModuleInfo* gCertVerifierLog;
static const uint64_t ServerFailureDelaySeconds = 5 * 60; static const uint64_t ServerFailureDelaySeconds = 5 * 60;
static const unsigned int MINIMUM_NON_ECC_BITS_DV = 1024;
static const unsigned int MINIMUM_NON_ECC_BITS_EV = 2048;
namespace mozilla { namespace psm { namespace mozilla { namespace psm {
const char BUILTIN_ROOTS_MODULE_DEFAULT_NAME[] = "Builtin Roots Module"; const char BUILTIN_ROOTS_MODULE_DEFAULT_NAME[] = "Builtin Roots Module";
@ -53,6 +56,7 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(SECTrustType certDBTrustType,
/*optional but shouldn't be*/ void* pinArg, /*optional but shouldn't be*/ void* pinArg,
CertVerifier::ocsp_get_config ocspGETConfig, CertVerifier::ocsp_get_config ocspGETConfig,
CertVerifier::PinningMode pinningMode, CertVerifier::PinningMode pinningMode,
bool forEV,
/*optional*/ const char* hostname, /*optional*/ const char* hostname,
/*optional*/ ScopedCERTCertList* builtChain) /*optional*/ ScopedCERTCertList* builtChain)
: mCertDBTrustType(certDBTrustType) : mCertDBTrustType(certDBTrustType)
@ -61,6 +65,7 @@ NSSCertDBTrustDomain::NSSCertDBTrustDomain(SECTrustType certDBTrustType,
, mPinArg(pinArg) , mPinArg(pinArg)
, mOCSPGetConfig(ocspGETConfig) , mOCSPGetConfig(ocspGETConfig)
, mPinningMode(pinningMode) , mPinningMode(pinningMode)
, mMinimumNonECCBits(forEV ? MINIMUM_NON_ECC_BITS_EV : MINIMUM_NON_ECC_BITS_DV)
, mHostname(hostname) , mHostname(hostname)
, mBuiltChain(builtChain) , mBuiltChain(builtChain)
{ {
@ -226,7 +231,7 @@ NSSCertDBTrustDomain::VerifySignedData(const SignedDataWithSignature& signedData
Input subjectPublicKeyInfo) Input subjectPublicKeyInfo)
{ {
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo, return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
mPinArg); mMinimumNonECCBits, mPinArg);
} }
Result Result
@ -663,7 +668,8 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray, Time time)
Result Result
NSSCertDBTrustDomain::CheckPublicKey(Input subjectPublicKeyInfo) NSSCertDBTrustDomain::CheckPublicKey(Input subjectPublicKeyInfo)
{ {
return ::mozilla::pkix::CheckPublicKey(subjectPublicKeyInfo); return ::mozilla::pkix::CheckPublicKey(subjectPublicKeyInfo,
mMinimumNonECCBits);
} }
namespace { namespace {

Просмотреть файл

@ -54,6 +54,7 @@ public:
OCSPCache& ocspCache, void* pinArg, OCSPCache& ocspCache, void* pinArg,
CertVerifier::ocsp_get_config ocspGETConfig, CertVerifier::ocsp_get_config ocspGETConfig,
CertVerifier::PinningMode pinningMode, CertVerifier::PinningMode pinningMode,
bool forEV,
/*optional*/ const char* hostname = nullptr, /*optional*/ const char* hostname = nullptr,
/*optional out*/ ScopedCERTCertList* builtChain = nullptr); /*optional out*/ ScopedCERTCertList* builtChain = nullptr);
@ -106,6 +107,7 @@ private:
void* mPinArg; // non-owning! void* mPinArg; // non-owning!
const CertVerifier::ocsp_get_config mOCSPGetConfig; const CertVerifier::ocsp_get_config mOCSPGetConfig;
CertVerifier::PinningMode mPinningMode; CertVerifier::PinningMode mPinningMode;
const unsigned int mMinimumNonECCBits;
const char* mHostname; // non-owning - only used for pinning checks const char* mHostname; // non-owning - only used for pinning checks
ScopedCERTCertList* mBuiltChain; // non-owning ScopedCERTCertList* mBuiltChain; // non-owning
}; };

Просмотреть файл

@ -34,6 +34,7 @@ namespace mozilla { namespace pkix {
// Verify the given signed data using the given public key. // Verify the given signed data using the given public key.
Result VerifySignedData(const SignedDataWithSignature& sd, Result VerifySignedData(const SignedDataWithSignature& sd,
Input subjectPublicKeyInfo, Input subjectPublicKeyInfo,
unsigned int minimumNonECCBits,
void* pkcs11PinArg); void* pkcs11PinArg);
// Computes the SHA-1 hash of the data in the current item. // Computes the SHA-1 hash of the data in the current item.
@ -50,8 +51,10 @@ Result VerifySignedData(const SignedDataWithSignature& sd,
Result DigestBuf(Input item, /*out*/ uint8_t* digestBuf, Result DigestBuf(Input item, /*out*/ uint8_t* digestBuf,
size_t digestBufLen); size_t digestBufLen);
// Checks, for RSA keys and DSA keys, that the modulus is at least 1024 bits. // Checks, for RSA keys and DSA keys, that the modulus is at least the given
Result CheckPublicKey(Input subjectPublicKeyInfo); // number of bits.
Result CheckPublicKey(Input subjectPublicKeyInfo,
unsigned int minimumNonECCBits);
Result MapPRErrorCodeToResult(PRErrorCode errorCode); Result MapPRErrorCodeToResult(PRErrorCode errorCode);
PRErrorCode MapResultToPRErrorCode(Result result); PRErrorCode MapResultToPRErrorCode(Result result);

Просмотреть файл

@ -39,7 +39,7 @@ namespace mozilla { namespace pkix {
typedef ScopedPtr<SECKEYPublicKey, SECKEY_DestroyPublicKey> ScopedSECKeyPublicKey; typedef ScopedPtr<SECKEYPublicKey, SECKEY_DestroyPublicKey> ScopedSECKeyPublicKey;
Result Result
CheckPublicKeySize(Input subjectPublicKeyInfo, CheckPublicKeySize(Input subjectPublicKeyInfo, unsigned int minimumNonECCBits,
/*out*/ ScopedSECKeyPublicKey& publicKey) /*out*/ ScopedSECKeyPublicKey& publicKey)
{ {
SECItem subjectPublicKeyInfoSECItem = SECItem subjectPublicKeyInfoSECItem =
@ -54,16 +54,13 @@ CheckPublicKeySize(Input subjectPublicKeyInfo,
return MapPRErrorCodeToResult(PR_GetError()); return MapPRErrorCodeToResult(PR_GetError());
} }
static const unsigned int MINIMUM_NON_ECC_BITS = 1024;
switch (publicKey.get()->keyType) { switch (publicKey.get()->keyType) {
case ecKey: case ecKey:
// TODO(bug 622859): We should check which curve. // TODO(bug 1077790): We should check which curve.
return Success; return Success;
case dsaKey: // fall through case dsaKey: // fall through
case rsaKey: case rsaKey:
// TODO(bug 622859): Enforce a minimum of 2048 bits for EV certs. if (SECKEY_PublicKeyStrengthInBits(publicKey.get()) < minimumNonECCBits) {
if (SECKEY_PublicKeyStrengthInBits(publicKey.get()) < MINIMUM_NON_ECC_BITS) {
return Result::ERROR_INADEQUATE_KEY_SIZE; return Result::ERROR_INADEQUATE_KEY_SIZE;
} }
break; break;
@ -81,15 +78,16 @@ CheckPublicKeySize(Input subjectPublicKeyInfo,
} }
Result Result
CheckPublicKey(Input subjectPublicKeyInfo) CheckPublicKey(Input subjectPublicKeyInfo, unsigned int minimumNonECCBits)
{ {
ScopedSECKeyPublicKey unused; ScopedSECKeyPublicKey unused;
return CheckPublicKeySize(subjectPublicKeyInfo, unused); return CheckPublicKeySize(subjectPublicKeyInfo, minimumNonECCBits, unused);
} }
Result Result
VerifySignedData(const SignedDataWithSignature& sd, VerifySignedData(const SignedDataWithSignature& sd,
Input subjectPublicKeyInfo, void* pkcs11PinArg) Input subjectPublicKeyInfo, unsigned int minimumNonECCBits,
void* pkcs11PinArg)
{ {
SECOidTag pubKeyAlg; SECOidTag pubKeyAlg;
SECOidTag digestAlg; SECOidTag digestAlg;
@ -142,7 +140,7 @@ VerifySignedData(const SignedDataWithSignature& sd,
Result rv; Result rv;
ScopedSECKeyPublicKey pubKey; ScopedSECKeyPublicKey pubKey;
rv = CheckPublicKeySize(subjectPublicKeyInfo, pubKey); rv = CheckPublicKeySize(subjectPublicKeyInfo, minimumNonECCBits, pubKey);
if (rv != Success) { if (rv != Success) {
return rv; return rv;
} }

Просмотреть файл

@ -169,7 +169,7 @@ private:
Input subjectPublicKeyInfo) Input subjectPublicKeyInfo)
{ {
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo, return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
nullptr); MINIMUM_TEST_KEY_BITS, nullptr);
} }
virtual Result DigestBuf(Input item, /*out*/ uint8_t *digestBuf, virtual Result DigestBuf(Input item, /*out*/ uint8_t *digestBuf,
@ -352,7 +352,7 @@ public:
Input subjectPublicKeyInfo) Input subjectPublicKeyInfo)
{ {
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo, return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
nullptr); MINIMUM_TEST_KEY_BITS, nullptr);
} }
virtual Result DigestBuf(Input, /*out*/uint8_t*, size_t) virtual Result DigestBuf(Input, /*out*/uint8_t*, size_t)

Просмотреть файл

@ -111,7 +111,7 @@ private:
{ {
EXPECT_NE(SignatureAlgorithm::unsupported_algorithm, signedData.algorithm); EXPECT_NE(SignatureAlgorithm::unsupported_algorithm, signedData.algorithm);
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo, return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
nullptr); MINIMUM_TEST_KEY_BITS, nullptr);
} }
virtual Result DigestBuf(Input, uint8_t*, size_t) virtual Result DigestBuf(Input, uint8_t*, size_t)

Просмотреть файл

@ -259,7 +259,7 @@ Result
TestCheckPublicKey(Input subjectPublicKeyInfo) TestCheckPublicKey(Input subjectPublicKeyInfo)
{ {
InitNSSIfNeeded(); InitNSSIfNeeded();
return CheckPublicKey(subjectPublicKeyInfo); return CheckPublicKey(subjectPublicKeyInfo, MINIMUM_TEST_KEY_BITS);
} }
Result Result
@ -267,7 +267,8 @@ TestVerifySignedData(const SignedDataWithSignature& signedData,
Input subjectPublicKeyInfo) Input subjectPublicKeyInfo)
{ {
InitNSSIfNeeded(); InitNSSIfNeeded();
return VerifySignedData(signedData, subjectPublicKeyInfo, nullptr); return VerifySignedData(signedData, subjectPublicKeyInfo,
MINIMUM_TEST_KEY_BITS, nullptr);
} }
Result Result

Просмотреть файл

@ -33,6 +33,8 @@
#include "pkix/pkixtypes.h" #include "pkix/pkixtypes.h"
#include "pkix/ScopedPtr.h" #include "pkix/ScopedPtr.h"
static const unsigned int MINIMUM_TEST_KEY_BITS = 1024;
namespace mozilla { namespace pkix { namespace test { namespace mozilla { namespace pkix { namespace test {
typedef std::basic_string<uint8_t> ByteString; typedef std::basic_string<uint8_t> ByteString;