mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-29 07:42:04 +00:00
Bug 1041186, Part 1: Improve buffer overflow protection in mozilla::pkix, r=keeler
--HG-- extra : rebase_source : 0f4a33f2c66594930ba9c79233648c70e33ba27c
This commit is contained in:
parent
d20849c5bf
commit
ffe743ee06
@ -542,12 +542,17 @@ VerifyCertificate(CERTCertificate* signerCert, void* voidContext, void* pinArg)
|
||||
if (trustDomain.SetTrustedRoot(context.trustedRoot) != SECSuccess) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
Result rv = BuildCertChain(trustDomain, signerCert->derCert, PR_Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::digitalSignature,
|
||||
KeyPurposeId::id_kp_codeSigning,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/);
|
||||
InputBuffer certDER;
|
||||
Result rv = certDER.Init(signerCert->derCert.data, signerCert->derCert.len);
|
||||
if (rv != Success) {
|
||||
return mozilla::psm::GetXPCOMFromNSSError(MapResultToPRErrorCode(rv));
|
||||
}
|
||||
rv = BuildCertChain(trustDomain, certDER, PR_Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::digitalSignature,
|
||||
KeyPurposeId::id_kp_codeSigning,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/);
|
||||
if (rv != Success) {
|
||||
return mozilla::psm::GetXPCOMFromNSSError(MapResultToPRErrorCode(rv));
|
||||
}
|
||||
|
@ -94,7 +94,7 @@ AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot)
|
||||
}
|
||||
|
||||
Result
|
||||
AppTrustDomain::FindIssuer(const SECItem& encodedIssuerName,
|
||||
AppTrustDomain::FindIssuer(InputBuffer encodedIssuerName,
|
||||
IssuerChecker& checker, PRTime time)
|
||||
|
||||
{
|
||||
@ -111,16 +111,24 @@ AppTrustDomain::FindIssuer(const SECItem& encodedIssuerName,
|
||||
// 1. First, try the trusted trust anchor.
|
||||
// 2. Secondly, iterate through the certificates that were stored in the CMS
|
||||
// message, passing each one to checker.Check.
|
||||
SECItem encodedIssuerNameSECItem =
|
||||
UnsafeMapInputBufferToSECItem(encodedIssuerName);
|
||||
ScopedCERTCertList
|
||||
candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
|
||||
&encodedIssuerName, time, true));
|
||||
&encodedIssuerNameSECItem, time,
|
||||
true));
|
||||
if (candidates) {
|
||||
for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
|
||||
!CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
|
||||
InputBuffer certDER;
|
||||
Result rv = certDER.Init(n->cert->derCert.data, n->cert->derCert.len);
|
||||
if (rv != Success) {
|
||||
continue; // probably too big
|
||||
}
|
||||
|
||||
bool keepGoing;
|
||||
Result rv = checker.Check(n->cert->derCert,
|
||||
nullptr/*additionalNameConstraints*/,
|
||||
keepGoing);
|
||||
rv = checker.Check(certDER, nullptr/*additionalNameConstraints*/,
|
||||
keepGoing);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
@ -136,8 +144,8 @@ AppTrustDomain::FindIssuer(const SECItem& encodedIssuerName,
|
||||
Result
|
||||
AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
|
||||
const CertPolicyId& policy,
|
||||
const SECItem& candidateCertDER,
|
||||
/*out*/ TrustLevel& trustLevel)
|
||||
InputBuffer candidateCertDER,
|
||||
/*out*/ TrustLevel& trustLevel)
|
||||
{
|
||||
MOZ_ASSERT(policy.IsAnyPolicy());
|
||||
MOZ_ASSERT(mTrustedRoot);
|
||||
@ -153,10 +161,11 @@ AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
|
||||
// XXX: This would be cleaner and more efficient if we could get the trust
|
||||
// information without constructing a CERTCertificate here, but NSS doesn't
|
||||
// expose it in any other easy-to-use fashion.
|
||||
SECItem candidateCertDERSECItem =
|
||||
UnsafeMapInputBufferToSECItem(candidateCertDER);
|
||||
ScopedCERTCertificate candidateCert(
|
||||
CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
|
||||
const_cast<SECItem*>(&candidateCertDER), nullptr,
|
||||
false, true));
|
||||
CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &candidateCertDERSECItem,
|
||||
nullptr, false, true));
|
||||
if (!candidateCert) {
|
||||
return MapPRErrorCodeToResult(PR_GetError());
|
||||
}
|
||||
@ -192,14 +201,14 @@ AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
|
||||
|
||||
Result
|
||||
AppTrustDomain::VerifySignedData(const SignedDataWithSignature& signedData,
|
||||
const SECItem& subjectPublicKeyInfo)
|
||||
InputBuffer subjectPublicKeyInfo)
|
||||
{
|
||||
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
|
||||
mPinArg);
|
||||
}
|
||||
|
||||
Result
|
||||
AppTrustDomain::DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
|
||||
AppTrustDomain::DigestBuf(InputBuffer item, /*out*/ uint8_t* digestBuf,
|
||||
size_t digestBufLen)
|
||||
{
|
||||
return ::mozilla::pkix::DigestBuf(item, digestBuf, digestBufLen);
|
||||
@ -207,8 +216,8 @@ AppTrustDomain::DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
|
||||
|
||||
Result
|
||||
AppTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&, PRTime time,
|
||||
/*optional*/ const SECItem*,
|
||||
/*optional*/ const SECItem*)
|
||||
/*optional*/ const InputBuffer*,
|
||||
/*optional*/ const InputBuffer*)
|
||||
{
|
||||
// We don't currently do revocation checking. If we need to distrust an Apps
|
||||
// certificate, we will use the active distrust mechanism.
|
||||
@ -227,7 +236,7 @@ AppTrustDomain::IsChainValid(const DERArray& certChain)
|
||||
}
|
||||
|
||||
Result
|
||||
AppTrustDomain::CheckPublicKey(const SECItem& subjectPublicKeyInfo)
|
||||
AppTrustDomain::CheckPublicKey(InputBuffer subjectPublicKeyInfo)
|
||||
{
|
||||
return ::mozilla::pkix::CheckPublicKey(subjectPublicKeyInfo);
|
||||
}
|
||||
|
@ -25,24 +25,25 @@ public:
|
||||
|
||||
virtual Result GetCertTrust(mozilla::pkix::EndEntityOrCA endEntityOrCA,
|
||||
const mozilla::pkix::CertPolicyId& policy,
|
||||
const SECItem& candidateCertDER,
|
||||
mozilla::pkix::InputBuffer candidateCertDER,
|
||||
/*out*/ mozilla::pkix::TrustLevel& trustLevel)
|
||||
MOZ_OVERRIDE;
|
||||
virtual Result FindIssuer(const SECItem& encodedIssuerName,
|
||||
virtual Result FindIssuer(mozilla::pkix::InputBuffer encodedIssuerName,
|
||||
IssuerChecker& checker,
|
||||
PRTime time) MOZ_OVERRIDE;
|
||||
virtual Result CheckRevocation(mozilla::pkix::EndEntityOrCA endEntityOrCA,
|
||||
const mozilla::pkix::CertID& certID, PRTime time,
|
||||
/*optional*/ const SECItem* stapledOCSPresponse,
|
||||
/*optional*/ const SECItem* aiaExtension);
|
||||
/*optional*/ const mozilla::pkix::InputBuffer* stapledOCSPresponse,
|
||||
/*optional*/ const mozilla::pkix::InputBuffer* aiaExtension);
|
||||
virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain)
|
||||
MOZ_OVERRIDE;
|
||||
virtual Result CheckPublicKey(const SECItem& subjectPublicKeyInfo)
|
||||
virtual Result CheckPublicKey(mozilla::pkix::InputBuffer subjectPublicKeyInfo)
|
||||
MOZ_OVERRIDE;
|
||||
virtual Result VerifySignedData(
|
||||
const mozilla::pkix::SignedDataWithSignature& signedData,
|
||||
const SECItem& subjectPublicKeyInfo) MOZ_OVERRIDE;
|
||||
virtual Result DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
|
||||
mozilla::pkix::InputBuffer subjectPublicKeyInfo) MOZ_OVERRIDE;
|
||||
virtual Result DigestBuf(mozilla::pkix::InputBuffer item,
|
||||
/*out*/ uint8_t* digestBuf,
|
||||
size_t digestBufLen) MOZ_OVERRIDE;
|
||||
|
||||
private:
|
||||
|
@ -156,21 +156,21 @@ SECStatus chainValidationCallback(void* state, const CERTCertList* certList,
|
||||
}
|
||||
|
||||
static Result
|
||||
BuildCertChainForOneKeyUsage(TrustDomain& trustDomain, CERTCertificate* cert,
|
||||
BuildCertChainForOneKeyUsage(TrustDomain& trustDomain, InputBuffer certDER,
|
||||
PRTime time, KeyUsage ku1, KeyUsage ku2,
|
||||
KeyUsage ku3, KeyPurposeId eku,
|
||||
const CertPolicyId& requiredPolicy,
|
||||
const SECItem* stapledOCSPResponse)
|
||||
const InputBuffer* stapledOCSPResponse)
|
||||
{
|
||||
Result rv = BuildCertChain(trustDomain, cert->derCert, time,
|
||||
Result rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeEndEntity, ku1,
|
||||
eku, requiredPolicy, stapledOCSPResponse);
|
||||
if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
|
||||
rv = BuildCertChain(trustDomain, cert->derCert, time,
|
||||
rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeEndEntity, ku2,
|
||||
eku, requiredPolicy, stapledOCSPResponse);
|
||||
if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
|
||||
rv = BuildCertChain(trustDomain, cert->derCert, time,
|
||||
rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeEndEntity, ku3,
|
||||
eku, requiredPolicy, stapledOCSPResponse);
|
||||
if (rv != Success) {
|
||||
@ -185,7 +185,7 @@ SECStatus
|
||||
CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
PRTime time, void* pinArg, const char* hostname,
|
||||
const Flags flags,
|
||||
/*optional*/ const SECItem* stapledOCSPResponse,
|
||||
/*optional*/ const SECItem* stapledOCSPResponseSECItem,
|
||||
/*optional out*/ ScopedCERTCertList* builtChain,
|
||||
/*optional out*/ SECOidTag* evOidPolicy)
|
||||
{
|
||||
@ -207,6 +207,15 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
Result rv;
|
||||
|
||||
InputBuffer certDER;
|
||||
rv = certDER.Init(cert->derCert.data, cert->derCert.len);
|
||||
if (rv != Success) {
|
||||
PR_SetError(MapResultToPRErrorCode(rv), 0);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
ChainValidationCallbackState callbackState = {
|
||||
hostname, mPinningEnforcementLevel, usage, time
|
||||
};
|
||||
@ -223,7 +232,18 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
ocsp_get_config ocspGETConfig = mOCSPGETEnabled ? ocsp_get_enabled
|
||||
: ocsp_get_disabled;
|
||||
|
||||
Result rv;
|
||||
InputBuffer stapledOCSPResponseInputBuffer;
|
||||
const InputBuffer* stapledOCSPResponse = nullptr;
|
||||
if (stapledOCSPResponseSECItem) {
|
||||
rv = stapledOCSPResponseInputBuffer.Init(stapledOCSPResponseSECItem->data,
|
||||
stapledOCSPResponseSECItem->len);
|
||||
if (rv != Success) {
|
||||
// The stapled OCSP response was too big.
|
||||
PR_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE, 0);
|
||||
return SECFailure;
|
||||
}
|
||||
stapledOCSPResponse = &stapledOCSPResponseInputBuffer;
|
||||
}
|
||||
|
||||
switch (usage) {
|
||||
case certificateUsageSSLClient: {
|
||||
@ -232,7 +252,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig, nullptr,
|
||||
builtChain);
|
||||
rv = BuildCertChain(trustDomain, cert->derCert, time,
|
||||
rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::digitalSignature,
|
||||
KeyPurposeId::id_kp_clientAuth,
|
||||
@ -258,7 +278,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
: NSSCertDBTrustDomain::FetchOCSPForEV,
|
||||
mOCSPCache, pinArg, ocspGETConfig,
|
||||
&callbackContainer, builtChain);
|
||||
rv = BuildCertChainForOneKeyUsage(trustDomain, cert, time,
|
||||
rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time,
|
||||
KeyUsage::digitalSignature,// (EC)DHE
|
||||
KeyUsage::keyEncipherment, // RSA
|
||||
KeyUsage::keyAgreement, // (EC)DH
|
||||
@ -282,7 +302,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
NSSCertDBTrustDomain trustDomain(trustSSL, ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig, &callbackContainer,
|
||||
builtChain);
|
||||
rv = BuildCertChainForOneKeyUsage(trustDomain, cert, time,
|
||||
rv = BuildCertChainForOneKeyUsage(trustDomain, certDER, time,
|
||||
KeyUsage::digitalSignature, // (EC)DHE
|
||||
KeyUsage::keyEncipherment, // RSA
|
||||
KeyUsage::keyAgreement, // (EC)DH
|
||||
@ -296,7 +316,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
NSSCertDBTrustDomain trustDomain(trustSSL, ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig, nullptr,
|
||||
builtChain);
|
||||
rv = BuildCertChain(trustDomain, cert->derCert, time,
|
||||
rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeCA, KeyUsage::keyCertSign,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy, stapledOCSPResponse);
|
||||
@ -307,7 +327,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig, nullptr,
|
||||
builtChain);
|
||||
rv = BuildCertChain(trustDomain, cert->derCert, time,
|
||||
rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::digitalSignature,
|
||||
KeyPurposeId::id_kp_emailProtection,
|
||||
@ -322,13 +342,13 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig, nullptr,
|
||||
builtChain);
|
||||
rv = BuildCertChain(trustDomain, cert->derCert, time,
|
||||
rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::keyEncipherment, // RSA
|
||||
KeyPurposeId::id_kp_emailProtection,
|
||||
CertPolicyId::anyPolicy, stapledOCSPResponse);
|
||||
if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
|
||||
rv = BuildCertChain(trustDomain, cert->derCert, time,
|
||||
rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::keyAgreement, // ECDH/DH
|
||||
KeyPurposeId::id_kp_emailProtection,
|
||||
@ -341,7 +361,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
NSSCertDBTrustDomain trustDomain(trustObjectSigning, ocspFetching,
|
||||
mOCSPCache, pinArg, ocspGETConfig,
|
||||
nullptr, builtChain);
|
||||
rv = BuildCertChain(trustDomain, cert->derCert, time,
|
||||
rv = BuildCertChain(trustDomain, certDER, time,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::digitalSignature,
|
||||
KeyPurposeId::id_kp_codeSigning,
|
||||
@ -370,14 +390,14 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
|
||||
NSSCertDBTrustDomain sslTrust(trustSSL, ocspFetching, mOCSPCache, pinArg,
|
||||
ocspGETConfig, nullptr, builtChain);
|
||||
rv = BuildCertChain(sslTrust, cert->derCert, time, endEntityOrCA,
|
||||
rv = BuildCertChain(sslTrust, certDER, time, endEntityOrCA,
|
||||
keyUsage, eku, CertPolicyId::anyPolicy,
|
||||
stapledOCSPResponse);
|
||||
if (rv == Result::ERROR_UNKNOWN_ISSUER) {
|
||||
NSSCertDBTrustDomain emailTrust(trustEmail, ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig, nullptr,
|
||||
builtChain);
|
||||
rv = BuildCertChain(emailTrust, cert->derCert, time, endEntityOrCA,
|
||||
rv = BuildCertChain(emailTrust, certDER, time, endEntityOrCA,
|
||||
keyUsage, eku, CertPolicyId::anyPolicy,
|
||||
stapledOCSPResponse);
|
||||
if (rv == Result::ERROR_UNKNOWN_ISSUER) {
|
||||
@ -385,7 +405,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig,
|
||||
nullptr, builtChain);
|
||||
rv = BuildCertChain(objectSigningTrust, cert->derCert, time,
|
||||
rv = BuildCertChain(objectSigningTrust, certDER, time,
|
||||
endEntityOrCA, keyUsage, eku,
|
||||
CertPolicyId::anyPolicy, stapledOCSPResponse);
|
||||
}
|
||||
|
@ -78,12 +78,6 @@ static const uint8_t ANSSI_SUBJECT_DATA[] =
|
||||
"\x73\x67\x64\x6E\x2E\x70\x6D\x2E\x67\x6F\x75"
|
||||
"\x76\x2E\x66\x72";
|
||||
|
||||
static const SECItem ANSSI_SUBJECT = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(ANSSI_SUBJECT_DATA),
|
||||
sizeof(ANSSI_SUBJECT_DATA) - 1
|
||||
};
|
||||
|
||||
static const uint8_t PERMIT_FRANCE_GOV_NAME_CONSTRAINTS_DATA[] =
|
||||
"\x30\x5D" // SEQUENCE (length=93)
|
||||
"\xA0\x5B" // permittedSubtrees (length=91)
|
||||
@ -101,32 +95,47 @@ static const uint8_t PERMIT_FRANCE_GOV_NAME_CONSTRAINTS_DATA[] =
|
||||
"\x30\x05\x82\x03" ".nc"
|
||||
"\x30\x05\x82\x03" ".tf";
|
||||
|
||||
static const SECItem PERMIT_FRANCE_GOV_NAME_CONSTRAINTS = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(PERMIT_FRANCE_GOV_NAME_CONSTRAINTS_DATA),
|
||||
sizeof(PERMIT_FRANCE_GOV_NAME_CONSTRAINTS_DATA) - 1
|
||||
};
|
||||
|
||||
Result
|
||||
NSSCertDBTrustDomain::FindIssuer(const SECItem& encodedIssuerName,
|
||||
NSSCertDBTrustDomain::FindIssuer(InputBuffer encodedIssuerName,
|
||||
IssuerChecker& checker, PRTime time)
|
||||
{
|
||||
// TODO: NSS seems to be ambiguous between "no potential issuers found" and
|
||||
// "there was an error trying to retrieve the potential issuers."
|
||||
SECItem encodedIssuerNameSECItem =
|
||||
UnsafeMapInputBufferToSECItem(encodedIssuerName);
|
||||
ScopedCERTCertList
|
||||
candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
|
||||
&encodedIssuerName, time, true));
|
||||
&encodedIssuerNameSECItem, time,
|
||||
true));
|
||||
if (candidates) {
|
||||
for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
|
||||
!CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
|
||||
const SECItem* additionalNameConstraints = nullptr;
|
||||
// TODO: Use CERT_CompareName or equivalent
|
||||
if (SECITEM_ItemsAreEqual(&encodedIssuerName, &ANSSI_SUBJECT)) {
|
||||
additionalNameConstraints = &PERMIT_FRANCE_GOV_NAME_CONSTRAINTS;
|
||||
InputBuffer certDER;
|
||||
Result rv = certDER.Init(n->cert->derCert.data, n->cert->derCert.len);
|
||||
if (rv != Success) {
|
||||
continue; // probably too big
|
||||
}
|
||||
|
||||
bool keepGoing;
|
||||
Result rv = checker.Check(n->cert->derCert,
|
||||
additionalNameConstraints, keepGoing);
|
||||
InputBuffer anssiSubject;
|
||||
rv = anssiSubject.Init(ANSSI_SUBJECT_DATA,
|
||||
sizeof(ANSSI_SUBJECT_DATA) - 1);
|
||||
if (rv != Success) {
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
}
|
||||
// TODO: Use CERT_CompareName or equivalent
|
||||
if (InputBuffersAreEqual(encodedIssuerName, anssiSubject)) {
|
||||
InputBuffer anssiNameConstraints;
|
||||
if (anssiNameConstraints.Init(
|
||||
PERMIT_FRANCE_GOV_NAME_CONSTRAINTS_DATA,
|
||||
sizeof(PERMIT_FRANCE_GOV_NAME_CONSTRAINTS_DATA) - 1)
|
||||
!= Success) {
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
}
|
||||
rv = checker.Check(certDER, &anssiNameConstraints, keepGoing);
|
||||
} else {
|
||||
rv = checker.Check(certDER, nullptr, keepGoing);
|
||||
}
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
@ -142,7 +151,7 @@ NSSCertDBTrustDomain::FindIssuer(const SECItem& encodedIssuerName,
|
||||
Result
|
||||
NSSCertDBTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
|
||||
const CertPolicyId& policy,
|
||||
const SECItem& candidateCertDER,
|
||||
InputBuffer candidateCertDER,
|
||||
/*out*/ TrustLevel& trustLevel)
|
||||
{
|
||||
#ifdef MOZ_NO_EV_CERTS
|
||||
@ -157,10 +166,11 @@ NSSCertDBTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
|
||||
// CERT_NewTempCertificate to get a CERTCertificate shouldn't be a
|
||||
// performance problem because NSS will just find the existing
|
||||
// CERTCertificate in its in-memory cache and return it.
|
||||
SECItem candidateCertDERSECItem =
|
||||
UnsafeMapInputBufferToSECItem(candidateCertDER);
|
||||
ScopedCERTCertificate candidateCert(
|
||||
CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
|
||||
const_cast<SECItem*>(&candidateCertDER), nullptr,
|
||||
false, true));
|
||||
CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &candidateCertDERSECItem,
|
||||
nullptr, false, true));
|
||||
if (!candidateCert) {
|
||||
return MapPRErrorCodeToResult(PR_GetError());
|
||||
}
|
||||
@ -211,14 +221,14 @@ NSSCertDBTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
|
||||
|
||||
Result
|
||||
NSSCertDBTrustDomain::VerifySignedData(const SignedDataWithSignature& signedData,
|
||||
const SECItem& subjectPublicKeyInfo)
|
||||
InputBuffer subjectPublicKeyInfo)
|
||||
{
|
||||
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
|
||||
mPinArg);
|
||||
}
|
||||
|
||||
Result
|
||||
NSSCertDBTrustDomain::DigestBuf(const SECItem& item,
|
||||
NSSCertDBTrustDomain::DigestBuf(InputBuffer item,
|
||||
/*out*/ uint8_t* digestBuf, size_t digestBufLen)
|
||||
{
|
||||
return ::mozilla::pkix::DigestBuf(item, digestBuf, digestBufLen);
|
||||
@ -252,15 +262,13 @@ OCSPFetchingTypeToTimeoutTime(NSSCertDBTrustDomain::OCSPFetching ocspFetching)
|
||||
// by the arena.
|
||||
static Result
|
||||
GetOCSPAuthorityInfoAccessLocation(PLArenaPool* arena,
|
||||
const SECItem& aiaExtension,
|
||||
InputBuffer aiaExtension,
|
||||
/*out*/ char const*& url)
|
||||
{
|
||||
url = nullptr;
|
||||
|
||||
// TODO(bug 1028380): Remove the const_cast.
|
||||
CERTAuthInfoAccess** aia = CERT_DecodeAuthInfoAccessExtension(
|
||||
arena,
|
||||
const_cast<SECItem*>(&aiaExtension));
|
||||
SECItem aiaExtensionSECItem = UnsafeMapInputBufferToSECItem(aiaExtension);
|
||||
CERTAuthInfoAccess** aia =
|
||||
CERT_DecodeAuthInfoAccessExtension(arena, &aiaExtensionSECItem);
|
||||
if (!aia) {
|
||||
return Result::ERROR_CERT_BAD_ACCESS_LOCATION;
|
||||
}
|
||||
@ -302,8 +310,8 @@ GetOCSPAuthorityInfoAccessLocation(PLArenaPool* arena,
|
||||
Result
|
||||
NSSCertDBTrustDomain::CheckRevocation(EndEntityOrCA endEntityOrCA,
|
||||
const CertID& certID, PRTime time,
|
||||
/*optional*/ const SECItem* stapledOCSPResponse,
|
||||
/*optional*/ const SECItem* aiaExtension)
|
||||
/*optional*/ const InputBuffer* stapledOCSPResponse,
|
||||
/*optional*/ const InputBuffer* aiaExtension)
|
||||
{
|
||||
// Actively distrusted certificates will have already been blocked by
|
||||
// GetCertTrust.
|
||||
@ -479,7 +487,7 @@ NSSCertDBTrustDomain::CheckRevocation(EndEntityOrCA endEntityOrCA,
|
||||
|
||||
// Only request a response if we didn't have a cached indication of failure
|
||||
// (don't keep requesting responses from a failing server).
|
||||
const SECItem* response;
|
||||
InputBuffer response;
|
||||
bool attemptedRequest;
|
||||
if (cachedResponseResult == Success ||
|
||||
cachedResponseResult == Result::ERROR_OCSP_UNKNOWN_CERT ||
|
||||
@ -496,22 +504,24 @@ NSSCertDBTrustDomain::CheckRevocation(EndEntityOrCA endEntityOrCA,
|
||||
ocspRequest,
|
||||
static_cast<unsigned int>(ocspRequestLength)
|
||||
};
|
||||
response = DoOCSPRequest(arena.get(), url, &ocspRequestItem,
|
||||
OCSPFetchingTypeToTimeoutTime(mOCSPFetching),
|
||||
mOCSPGetConfig == CertVerifier::ocsp_get_enabled);
|
||||
if (!response) {
|
||||
// Owned by arena
|
||||
const SECItem* responseSECItem =
|
||||
DoOCSPRequest(arena.get(), url, &ocspRequestItem,
|
||||
OCSPFetchingTypeToTimeoutTime(mOCSPFetching),
|
||||
mOCSPGetConfig == CertVerifier::ocsp_get_enabled);
|
||||
if (!responseSECItem) {
|
||||
rv = MapPRErrorCodeToResult(PR_GetError());
|
||||
} else if (response.Init(responseSECItem->data, responseSECItem->len)
|
||||
!= Success) {
|
||||
rv = Result::ERROR_OCSP_MALFORMED_RESPONSE; // too big
|
||||
}
|
||||
attemptedRequest = true;
|
||||
} else {
|
||||
rv = cachedResponseResult;
|
||||
response = nullptr;
|
||||
attemptedRequest = false;
|
||||
}
|
||||
|
||||
// If we don't have a response, either something went wrong when fetching it
|
||||
// or we didn't attempt to fetch a response because of a failing responder.
|
||||
if (!response) {
|
||||
if (response.GetLength() == 0) {
|
||||
Result error = rv;
|
||||
if (attemptedRequest) {
|
||||
PRTime timeout = time + ServerFailureDelay;
|
||||
@ -551,7 +561,7 @@ NSSCertDBTrustDomain::CheckRevocation(EndEntityOrCA endEntityOrCA,
|
||||
bool expired;
|
||||
rv = VerifyAndMaybeCacheEncodedOCSPResponse(certID, time,
|
||||
maxOCSPLifetimeInDays,
|
||||
*response, ResponseIsFromNetwork,
|
||||
response, ResponseIsFromNetwork,
|
||||
expired);
|
||||
if (rv == Success || mOCSPFetching != FetchOCSPForDVSoftFail) {
|
||||
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
|
||||
@ -579,7 +589,7 @@ NSSCertDBTrustDomain::CheckRevocation(EndEntityOrCA endEntityOrCA,
|
||||
Result
|
||||
NSSCertDBTrustDomain::VerifyAndMaybeCacheEncodedOCSPResponse(
|
||||
const CertID& certID, PRTime time, uint16_t maxLifetimeInDays,
|
||||
const SECItem& encodedResponse, EncodedResponseSource responseSource,
|
||||
InputBuffer encodedResponse, EncodedResponseSource responseSource,
|
||||
/*out*/ bool& expired)
|
||||
{
|
||||
PRTime thisUpdate = 0;
|
||||
@ -658,7 +668,7 @@ NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray)
|
||||
}
|
||||
|
||||
Result
|
||||
NSSCertDBTrustDomain::CheckPublicKey(const SECItem& subjectPublicKeyInfo)
|
||||
NSSCertDBTrustDomain::CheckPublicKey(InputBuffer subjectPublicKeyInfo)
|
||||
{
|
||||
return ::mozilla::pkix::CheckPublicKey(subjectPublicKeyInfo);
|
||||
}
|
||||
|
@ -56,31 +56,35 @@ public:
|
||||
/*optional*/ CERTChainVerifyCallback* checkChainCallback = nullptr,
|
||||
/*optional*/ ScopedCERTCertList* builtChain = nullptr);
|
||||
|
||||
virtual Result FindIssuer(const SECItem& encodedIssuerName,
|
||||
virtual Result FindIssuer(mozilla::pkix::InputBuffer encodedIssuerName,
|
||||
IssuerChecker& checker,
|
||||
PRTime time) MOZ_OVERRIDE;
|
||||
|
||||
virtual Result GetCertTrust(mozilla::pkix::EndEntityOrCA endEntityOrCA,
|
||||
const mozilla::pkix::CertPolicyId& policy,
|
||||
const SECItem& candidateCertDER,
|
||||
mozilla::pkix::InputBuffer candidateCertDER,
|
||||
/*out*/ mozilla::pkix::TrustLevel& trustLevel)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual Result CheckPublicKey(const SECItem& subjectPublicKeyInfo)
|
||||
virtual Result CheckPublicKey(mozilla::pkix::InputBuffer subjectPublicKeyInfo)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual Result VerifySignedData(
|
||||
const mozilla::pkix::SignedDataWithSignature& signedData,
|
||||
const SECItem& subjectPublicKeyInfo) MOZ_OVERRIDE;
|
||||
mozilla::pkix::InputBuffer subjectPublicKeyInfo)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual Result DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
|
||||
virtual Result DigestBuf(mozilla::pkix::InputBuffer item,
|
||||
/*out*/ uint8_t* digestBuf,
|
||||
size_t digestBufLen) MOZ_OVERRIDE;
|
||||
|
||||
virtual Result CheckRevocation(mozilla::pkix::EndEntityOrCA endEntityOrCA,
|
||||
const mozilla::pkix::CertID& certID,
|
||||
PRTime time,
|
||||
/*optional*/ const SECItem* stapledOCSPResponse,
|
||||
/*optional*/ const SECItem* aiaExtension) MOZ_OVERRIDE;
|
||||
virtual Result CheckRevocation(
|
||||
mozilla::pkix::EndEntityOrCA endEntityOrCA,
|
||||
const mozilla::pkix::CertID& certID,
|
||||
PRTime time,
|
||||
/*optional*/ const mozilla::pkix::InputBuffer* stapledOCSPResponse,
|
||||
/*optional*/ const mozilla::pkix::InputBuffer* aiaExtension)
|
||||
MOZ_OVERRIDE;
|
||||
|
||||
virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain)
|
||||
MOZ_OVERRIDE;
|
||||
@ -93,7 +97,7 @@ private:
|
||||
static const PRTime ServerFailureDelay = 5 * 60 * PR_USEC_PER_SEC;
|
||||
Result VerifyAndMaybeCacheEncodedOCSPResponse(
|
||||
const mozilla::pkix::CertID& certID, PRTime time,
|
||||
uint16_t maxLifetimeInDays, const SECItem& encodedResponse,
|
||||
uint16_t maxLifetimeInDays, mozilla::pkix::InputBuffer encodedResponse,
|
||||
EncodedResponseSource responseSource, /*out*/ bool& expired);
|
||||
|
||||
const SECTrustType mCertDBTrustType;
|
||||
|
@ -62,17 +62,22 @@ CertIDHash(SHA384Buffer& buf, const CertID& certID)
|
||||
if (rv != SECSuccess) {
|
||||
return rv;
|
||||
}
|
||||
rv = PK11_DigestOp(context.get(), certID.issuer.data, certID.issuer.len);
|
||||
SECItem certIDIssuer = UnsafeMapInputBufferToSECItem(certID.issuer);
|
||||
rv = PK11_DigestOp(context.get(), certIDIssuer.data, certIDIssuer.len);
|
||||
if (rv != SECSuccess) {
|
||||
return rv;
|
||||
}
|
||||
rv = PK11_DigestOp(context.get(), certID.issuerSubjectPublicKeyInfo.data,
|
||||
certID.issuerSubjectPublicKeyInfo.len);
|
||||
SECItem certIDIssuerSubjectPublicKeyInfo =
|
||||
UnsafeMapInputBufferToSECItem(certID.issuerSubjectPublicKeyInfo);
|
||||
rv = PK11_DigestOp(context.get(), certIDIssuerSubjectPublicKeyInfo.data,
|
||||
certIDIssuerSubjectPublicKeyInfo.len);
|
||||
if (rv != SECSuccess) {
|
||||
return rv;
|
||||
}
|
||||
rv = PK11_DigestOp(context.get(), certID.serialNumber.data,
|
||||
certID.serialNumber.len);
|
||||
SECItem certIDSerialNumber =
|
||||
UnsafeMapInputBufferToSECItem(certID.serialNumber);
|
||||
rv = PK11_DigestOp(context.get(), certIDSerialNumber.data,
|
||||
certIDSerialNumber.len);
|
||||
if (rv != SECSuccess) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include "prprf.h"
|
||||
#include "CertVerifier.h"
|
||||
#include "ExtendedValidation.h"
|
||||
#include "pkix/pkixnss.h"
|
||||
#include "pkix/pkixtypes.h"
|
||||
#include "pkix/ScopedPtr.h"
|
||||
#include "nsNSSComponent.h" // for PIPNSS string bundle calls.
|
||||
@ -1525,8 +1526,8 @@ ConstructCERTCertListFromReversedDERArray(
|
||||
|
||||
size_t numCerts = certArray.GetLength();
|
||||
for (size_t i = 0; i < numCerts; ++i) {
|
||||
SECItem* certDER(const_cast<SECItem*>(certArray.GetDER(i)));
|
||||
ScopedCERTCertificate cert(CERT_NewTempCertificate(certDB, certDER,
|
||||
SECItem certDER(UnsafeMapInputBufferToSECItem(*certArray.GetDER(i)));
|
||||
ScopedCERTCertificate cert(CERT_NewTempCertificate(certDB, &certDER,
|
||||
nullptr, false, true));
|
||||
if (!cert) {
|
||||
return SECFailure;
|
||||
|
@ -9,11 +9,13 @@
|
||||
#include "gtest/gtest.h"
|
||||
#include "nss.h"
|
||||
#include "pkix/pkixtypes.h"
|
||||
#include "pkixtestutil.h"
|
||||
#include "prerr.h"
|
||||
#include "prprf.h"
|
||||
#include "secerr.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
using namespace mozilla::psm;
|
||||
|
||||
const int MaxCacheEntries = 1024;
|
||||
@ -48,39 +50,15 @@ PutAndGet(OCSPCache& cache, const CertID& certID, Result result,
|
||||
ASSERT_EQ(time, timeOut);
|
||||
}
|
||||
|
||||
static const SECItem fakeIssuer1 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("CN=issuer1")),
|
||||
10
|
||||
};
|
||||
static const SECItem fakeKey000 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("key000")),
|
||||
6
|
||||
};
|
||||
static const SECItem fakeKey001 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("key001")),
|
||||
6
|
||||
};
|
||||
static const SECItem fakeSerial0000 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("0000")),
|
||||
4
|
||||
};
|
||||
TestInputBuffer fakeIssuer1("CN=issuer1");
|
||||
TestInputBuffer fakeKey000("key000");
|
||||
TestInputBuffer fakeKey001("key001");
|
||||
TestInputBuffer fakeSerial0000("0000");
|
||||
|
||||
TEST_F(OCSPCacheTest, TestPutAndGet)
|
||||
{
|
||||
static const SECItem fakeSerial000 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("000")),
|
||||
3
|
||||
};
|
||||
static const SECItem fakeSerial001 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("001")),
|
||||
3
|
||||
};
|
||||
TestInputBuffer fakeSerial000("000");
|
||||
TestInputBuffer fakeSerial001("001");
|
||||
|
||||
SCOPED_TRACE("");
|
||||
PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial001),
|
||||
@ -96,13 +74,10 @@ TEST_F(OCSPCacheTest, TestVariousGets)
|
||||
SCOPED_TRACE("");
|
||||
PRTime timeIn = PR_Now();
|
||||
for (int i = 0; i < MaxCacheEntries; i++) {
|
||||
char serialBuf[8];
|
||||
PR_snprintf(serialBuf, sizeof(serialBuf), "%04d", i);
|
||||
const SECItem fakeSerial = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(serialBuf)),
|
||||
4
|
||||
};
|
||||
uint8_t serialBuf[8];
|
||||
PR_snprintf(reinterpret_cast<char*>(serialBuf), sizeof(serialBuf), "%04d", i);
|
||||
InputBuffer fakeSerial;
|
||||
ASSERT_EQ(Success, fakeSerial.Init(serialBuf, 4));
|
||||
PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial),
|
||||
Success, timeIn + i);
|
||||
}
|
||||
@ -121,11 +96,7 @@ TEST_F(OCSPCacheTest, TestVariousGets)
|
||||
ASSERT_EQ(timeIn, timeOut);
|
||||
|
||||
// This will be in the middle
|
||||
static const SECItem fakeSerial0512 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("0512")),
|
||||
4
|
||||
};
|
||||
static const TestInputBuffer fakeSerial0512("0512");
|
||||
CertID cert0512(fakeIssuer1, fakeKey000, fakeSerial0512);
|
||||
ASSERT_TRUE(cache.Get(cert0512, resultOut, timeOut));
|
||||
ASSERT_EQ(Success, resultOut);
|
||||
@ -135,11 +106,7 @@ TEST_F(OCSPCacheTest, TestVariousGets)
|
||||
ASSERT_EQ(timeIn + 512, timeOut);
|
||||
|
||||
// We've never seen this certificate
|
||||
static const SECItem fakeSerial1111 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("1111")),
|
||||
4
|
||||
};
|
||||
static const TestInputBuffer fakeSerial1111("1111");
|
||||
ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey000, fakeSerial1111),
|
||||
resultOut, timeOut));
|
||||
}
|
||||
@ -152,13 +119,10 @@ TEST_F(OCSPCacheTest, TestEviction)
|
||||
// By putting more distinct entries in the cache than it can hold,
|
||||
// we cause the least recently used entry to be evicted.
|
||||
for (int i = 0; i < MaxCacheEntries + 1; i++) {
|
||||
char serialBuf[8];
|
||||
PR_snprintf(serialBuf, sizeof(serialBuf), "%04d", i);
|
||||
const SECItem fakeSerial = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(serialBuf)),
|
||||
4
|
||||
};
|
||||
uint8_t serialBuf[8];
|
||||
PR_snprintf(reinterpret_cast<char*>(serialBuf), sizeof(serialBuf), "%04d", i);
|
||||
InputBuffer fakeSerial;
|
||||
ASSERT_EQ(Success, fakeSerial.Init(serialBuf, 4));
|
||||
PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial),
|
||||
Success, timeIn + i);
|
||||
}
|
||||
@ -178,13 +142,10 @@ TEST_F(OCSPCacheTest, TestNoEvictionForRevokedResponses)
|
||||
// By putting more distinct entries in the cache than it can hold,
|
||||
// we cause the least recently used entry that isn't revoked to be evicted.
|
||||
for (int i = 1; i < MaxCacheEntries + 1; i++) {
|
||||
char serialBuf[8];
|
||||
PR_snprintf(serialBuf, sizeof(serialBuf), "%04d", i);
|
||||
const SECItem fakeSerial = {
|
||||
siBuffer,
|
||||
reinterpret_cast<uint8_t*>(serialBuf),
|
||||
4
|
||||
};
|
||||
uint8_t serialBuf[8];
|
||||
PR_snprintf(reinterpret_cast<char*>(serialBuf), sizeof(serialBuf), "%04d", i);
|
||||
InputBuffer fakeSerial;
|
||||
ASSERT_EQ(Success, fakeSerial.Init(serialBuf, 4));
|
||||
PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial),
|
||||
Success, timeIn + i);
|
||||
}
|
||||
@ -194,11 +155,7 @@ TEST_F(OCSPCacheTest, TestNoEvictionForRevokedResponses)
|
||||
ASSERT_EQ(Result::ERROR_REVOKED_CERTIFICATE, resultOut);
|
||||
ASSERT_EQ(timeIn, timeOut);
|
||||
|
||||
const SECItem fakeSerial0001 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("0001")),
|
||||
4
|
||||
};
|
||||
TestInputBuffer fakeSerial0001("0001");
|
||||
CertID evicted(fakeIssuer1, fakeKey000, fakeSerial0001);
|
||||
ASSERT_FALSE(cache.Get(evicted, resultOut, timeOut));
|
||||
}
|
||||
@ -209,21 +166,14 @@ TEST_F(OCSPCacheTest, TestEverythingIsRevoked)
|
||||
PRTime timeIn = PR_Now();
|
||||
// Fill up the cache with revoked responses.
|
||||
for (int i = 0; i < MaxCacheEntries; i++) {
|
||||
char serialBuf[8];
|
||||
PR_snprintf(serialBuf, sizeof(serialBuf), "%04d", i);
|
||||
const SECItem fakeSerial = {
|
||||
siBuffer,
|
||||
reinterpret_cast<uint8_t*>(serialBuf),
|
||||
4
|
||||
};
|
||||
uint8_t serialBuf[8];
|
||||
PR_snprintf(reinterpret_cast<char*>(serialBuf), sizeof(serialBuf), "%04d", i);
|
||||
InputBuffer fakeSerial;
|
||||
ASSERT_EQ(Success, fakeSerial.Init(serialBuf, 4));
|
||||
PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial),
|
||||
Result::ERROR_REVOKED_CERTIFICATE, timeIn + i);
|
||||
}
|
||||
const SECItem fakeSerial1025 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("1025")),
|
||||
4
|
||||
};
|
||||
static const TestInputBuffer fakeSerial1025("1025");
|
||||
CertID good(fakeIssuer1, fakeKey000, fakeSerial1025);
|
||||
// This will "succeed", allowing verification to continue. However,
|
||||
// nothing was actually put in the cache.
|
||||
@ -233,11 +183,7 @@ TEST_F(OCSPCacheTest, TestEverythingIsRevoked)
|
||||
PRTime timeOut;
|
||||
ASSERT_FALSE(cache.Get(good, resultOut, timeOut));
|
||||
|
||||
const SECItem fakeSerial1026 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("1026")),
|
||||
4
|
||||
};
|
||||
static const TestInputBuffer fakeSerial1026("1026");
|
||||
CertID revoked(fakeIssuer1, fakeKey000, fakeSerial1026);
|
||||
// This will fail, causing verification to fail.
|
||||
result = cache.Put(revoked, Result::ERROR_REVOKED_CERTIFICATE,
|
||||
@ -248,17 +194,8 @@ TEST_F(OCSPCacheTest, TestEverythingIsRevoked)
|
||||
TEST_F(OCSPCacheTest, VariousIssuers)
|
||||
{
|
||||
SCOPED_TRACE("");
|
||||
static const SECItem fakeIssuer2 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("CN=issuer2")),
|
||||
10
|
||||
};
|
||||
static const SECItem fakeSerial001 = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("001")),
|
||||
3
|
||||
};
|
||||
|
||||
static const TestInputBuffer fakeIssuer2("CN=issuer2");
|
||||
static const TestInputBuffer fakeSerial001("001");
|
||||
PRTime timeIn = PR_Now();
|
||||
CertID subject(fakeIssuer1, fakeKey000, fakeSerial001);
|
||||
PutAndGet(cache, subject, Success, timeIn);
|
||||
|
@ -12,6 +12,7 @@ SOURCES += [
|
||||
LOCAL_INCLUDES += [
|
||||
'../../../../certverifier',
|
||||
'../../../../pkix/include',
|
||||
'../../../../pkix/test/lib',
|
||||
'/security/manager/ssl/src',
|
||||
]
|
||||
|
||||
|
@ -56,7 +56,21 @@ GetOCSPResponseForType(OCSPResponseType aORT, CERTCertificate *aCert,
|
||||
PrintPRError("CERT_FindCertIssuer failed");
|
||||
return nullptr;
|
||||
}
|
||||
CertID certID(cert->derIssuer, issuerCert->derPublicKey, cert->serialNumber);
|
||||
InputBuffer issuer;
|
||||
if (issuer.Init(cert->derIssuer.data, cert->derIssuer.len) != Success) {
|
||||
return nullptr;
|
||||
}
|
||||
InputBuffer issuerPublicKey;
|
||||
if (issuerPublicKey.Init(issuerCert->derPublicKey.data,
|
||||
issuerCert->derPublicKey.len) != Success) {
|
||||
return nullptr;
|
||||
}
|
||||
InputBuffer serialNumber;
|
||||
if (serialNumber.Init(cert->serialNumber.data,
|
||||
cert->serialNumber.len) != Success) {
|
||||
return nullptr;
|
||||
}
|
||||
CertID certID(issuer, issuerPublicKey, serialNumber);
|
||||
OCSPResponseContext context(aArena, certID, now);
|
||||
|
||||
mozilla::ScopedCERTCertificate signerCert;
|
||||
|
@ -25,24 +25,122 @@
|
||||
#ifndef mozilla_pkix__Input_h
|
||||
#define mozilla_pkix__Input_h
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "pkix/nullptr.h"
|
||||
#include "pkix/Result.h"
|
||||
#include "seccomon.h"
|
||||
#include "prlog.h"
|
||||
#include "stdint.h"
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
|
||||
// Expect* functions advance the input mark and return Success if the input
|
||||
// matches the given criteria; they fail with the input mark in an undefined
|
||||
// state if the input does not match the criteria.
|
||||
class Input;
|
||||
|
||||
// An InputBuffer is a safety-oriented immutable weak reference to a array of
|
||||
// bytes of a known size. The data can only be legally accessed by constructing
|
||||
// an Input object, which guarantees all accesses to the data are memory safe.
|
||||
// Neither InputBuffer not Input provide any facilities for modifying the data
|
||||
// they reference.
|
||||
//
|
||||
// Match* functions advance the input mark and return true if the input matches
|
||||
// the given criteria; they return false without changing the input mark if the
|
||||
// input does not match the criteria.
|
||||
// InputBuffers are small and should usually be passed by value, not by
|
||||
// reference, though for inline functions the distinction doesn't matter.
|
||||
//
|
||||
// Skip* functions unconditionally advance the input mark and return Success if
|
||||
// they are able to do so; otherwise they fail with the input mark in an
|
||||
// undefined state.
|
||||
// Result GoodExample(InputBuffer input);
|
||||
// Result BadExample(const InputBuffer& input);
|
||||
// Result WorseExample(const uint8_t* input, size_t len);
|
||||
//
|
||||
// Note that in the example, GoodExample has the same performance
|
||||
// characteristics as WorseExample, but with much better safety guarantees.
|
||||
class InputBuffer
|
||||
{
|
||||
public:
|
||||
// This constructor is useful for input buffers that are statically known to
|
||||
// be of a fixed size, e.g.:
|
||||
//
|
||||
// static const uint8_t EXPECTED_BYTES[] = { 0x00, 0x01, 0x02 };
|
||||
// const InputBuffer expected(EXPECTED_BYTES);
|
||||
//
|
||||
// This is equivalent to (and preferred over):
|
||||
//
|
||||
// static const uint8_t EXPECTED_BYTES[] = { 0x00, 0x01, 0x02 };
|
||||
// InputBuffer expected;
|
||||
// Result rv = expected.Init(EXPECTED_BYTES, sizeof EXPECTED_BYTES);
|
||||
template <uint16_t N>
|
||||
explicit InputBuffer(const uint8_t (&data)[N])
|
||||
: data(data)
|
||||
, len(N)
|
||||
{
|
||||
}
|
||||
|
||||
// Construct a valid, empty, Init-able InputBuffer.
|
||||
InputBuffer()
|
||||
: data(nullptr)
|
||||
, len(0u)
|
||||
{
|
||||
}
|
||||
|
||||
// Initialize the input buffer. data must be non-null and len must be less
|
||||
// than 65536. Init may not be called more than once.
|
||||
Result Init(const uint8_t* data, size_t len)
|
||||
{
|
||||
if (this->data) {
|
||||
// already initialized
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
if (!data || len > 0xffffu) {
|
||||
// input too large
|
||||
return Result::ERROR_BAD_DER;
|
||||
}
|
||||
|
||||
this->data = data;
|
||||
this->len = len;
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
// Initialize the input buffer to be equivalent to the given input buffer.
|
||||
// Init may not be called more than once.
|
||||
//
|
||||
// This is basically operator=, but it wasn't given that name because
|
||||
// normally callers do not check the result of operator=, and normally
|
||||
// operator= can be used multiple times.
|
||||
Result Init(InputBuffer other)
|
||||
{
|
||||
return Init(other.data, other.len);
|
||||
}
|
||||
|
||||
// Returns the length of the buffer.
|
||||
//
|
||||
// Having the return type be uint16_t instead of size_t avoids the need for
|
||||
// callers to ensure that the result is small enough.
|
||||
uint16_t GetLength() const { return static_cast<uint16_t>(len); }
|
||||
|
||||
// Don't use this. It is here because we have some "friend" functions that we
|
||||
// don't want to declare in this header file.
|
||||
const uint8_t* UnsafeGetData() const { return data; }
|
||||
|
||||
private:
|
||||
const uint8_t* data;
|
||||
size_t len;
|
||||
|
||||
void operator=(const InputBuffer&) /* = delete */; // Use Init instead.
|
||||
};
|
||||
|
||||
inline bool
|
||||
InputBuffersAreEqual(const InputBuffer& a, const InputBuffer& b)
|
||||
{
|
||||
return a.GetLength() == b.GetLength() &&
|
||||
!std::memcmp(a.UnsafeGetData(), b.UnsafeGetData(), a.GetLength());
|
||||
}
|
||||
|
||||
// An Input is a cursor/iterator through the contents of an InputBuffer,
|
||||
// designed to maximize safety during parsing while minimizing the performance
|
||||
// cost of that safety. In particular, all methods do strict bounds checking to
|
||||
// ensure buffer overflows are impossible, and they are all inline so that the
|
||||
// compiler can coalesce as many of those checks together as possible.
|
||||
//
|
||||
// In general, Input allows for one byte of lookahead and no backtracking.
|
||||
// However, the Match* functions internally may have more lookahead.
|
||||
class Input
|
||||
{
|
||||
public:
|
||||
@ -52,36 +150,10 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
Result Init(const uint8_t* data, size_t len)
|
||||
explicit Input(InputBuffer buffer)
|
||||
: input(buffer.UnsafeGetData())
|
||||
, end(buffer.UnsafeGetData() + buffer.GetLength())
|
||||
{
|
||||
if (input) {
|
||||
// already initialized
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
if (!data || len > 0xffffu) {
|
||||
// input too large
|
||||
return Result::ERROR_BAD_DER;
|
||||
}
|
||||
|
||||
// XXX: this->input = input bug was not caught by tests! Why not?
|
||||
// this->end = end bug was not caught by tests! Why not?
|
||||
this->input = data;
|
||||
this->end = data + len;
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result Expect(const uint8_t* expected, uint16_t expectedLen)
|
||||
{
|
||||
Result rv = EnsureLength(expectedLen);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
if (memcmp(input, expected, expectedLen)) {
|
||||
return Result::ERROR_BAD_DER;
|
||||
}
|
||||
input += expectedLen;
|
||||
return Success;
|
||||
}
|
||||
|
||||
bool Peek(uint8_t expectedByte) const
|
||||
@ -176,15 +248,16 @@ public:
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result Skip(uint16_t len, SECItem& skippedItem)
|
||||
Result Skip(uint16_t len, InputBuffer& skippedItem)
|
||||
{
|
||||
Result rv = EnsureLength(len);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
skippedItem.type = siBuffer;
|
||||
skippedItem.data = const_cast<uint8_t*>(input);
|
||||
skippedItem.len = len;
|
||||
rv = skippedItem.Init(input, len);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
input += len;
|
||||
return Success;
|
||||
}
|
||||
@ -216,19 +289,27 @@ public:
|
||||
|
||||
Mark GetMark() const { return Mark(*this, input); }
|
||||
|
||||
Result GetSECItem(SECItemType type, const Mark& mark, /*out*/ SECItem& item)
|
||||
Result GetInputBuffer(const Mark& mark, /*out*/ InputBuffer& item)
|
||||
{
|
||||
if (&mark.input != this || mark.mark > input) {
|
||||
PR_NOT_REACHED("invalid mark");
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
item.type = type;
|
||||
item.data = const_cast<uint8_t*>(mark.mark);
|
||||
item.len = static_cast<decltype(item.len)>(input - mark.mark);
|
||||
return Success;
|
||||
return item.Init(mark.mark, static_cast<uint16_t>(input - mark.mark));
|
||||
}
|
||||
|
||||
private:
|
||||
Result Init(const uint8_t* data, uint16_t len)
|
||||
{
|
||||
if (input) {
|
||||
// already initialized
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
input = data;
|
||||
end = data + len;
|
||||
return Success;
|
||||
}
|
||||
|
||||
const uint8_t* input;
|
||||
const uint8_t* end;
|
||||
|
||||
|
@ -88,12 +88,12 @@ namespace mozilla { namespace pkix {
|
||||
// of active distrust.
|
||||
// TODO(bug 968451): Document more of these.
|
||||
|
||||
Result BuildCertChain(TrustDomain& trustDomain, const SECItem& cert,
|
||||
Result BuildCertChain(TrustDomain& trustDomain, InputBuffer cert,
|
||||
PRTime time, EndEntityOrCA endEntityOrCA,
|
||||
KeyUsage requiredKeyUsageIfPresent,
|
||||
KeyPurposeId requiredEKUIfPresent,
|
||||
const CertPolicyId& requiredPolicy,
|
||||
/*optional*/ const SECItem* stapledOCSPResponse);
|
||||
/*optional*/ const InputBuffer* stapledOCSPResponse);
|
||||
|
||||
static const size_t OCSP_REQUEST_MAX_LENGTH = 127;
|
||||
Result CreateEncodedOCSPRequest(TrustDomain& trustDomain,
|
||||
@ -116,7 +116,7 @@ Result CreateEncodedOCSPRequest(TrustDomain& trustDomain,
|
||||
Result VerifyEncodedOCSPResponse(TrustDomain& trustDomain,
|
||||
const CertID& certID, PRTime time,
|
||||
uint16_t maxLifetimeInDays,
|
||||
const SECItem& encodedResponse,
|
||||
InputBuffer encodedResponse,
|
||||
/* out */ bool& expired,
|
||||
/* optional out */ PRTime* thisUpdate = nullptr,
|
||||
/* optional out */ PRTime* validThrough = nullptr);
|
||||
|
@ -33,7 +33,7 @@ namespace mozilla { namespace pkix {
|
||||
|
||||
// Verify the given signed data using the given public key.
|
||||
Result VerifySignedData(const SignedDataWithSignature& sd,
|
||||
const SECItem& subjectPublicKeyInfo,
|
||||
InputBuffer subjectPublicKeyInfo,
|
||||
void* pkcs11PinArg);
|
||||
|
||||
// Computes the SHA-1 hash of the data in the current item.
|
||||
@ -47,11 +47,11 @@ Result VerifySignedData(const SignedDataWithSignature& sd,
|
||||
// TODO: Taking the output buffer as (uint8_t*, size_t) is counter to our
|
||||
// other, extensive, memory safety efforts in mozilla::pkix, and we should find
|
||||
// a way to provide a more-obviously-safe interface.
|
||||
Result DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
|
||||
Result DigestBuf(InputBuffer item, /*out*/ uint8_t* digestBuf,
|
||||
size_t digestBufLen);
|
||||
|
||||
// Checks, for RSA keys and DSA keys, that the modulus is at least 1024 bits.
|
||||
Result CheckPublicKey(const SECItem& subjectPublicKeyInfo);
|
||||
Result CheckPublicKey(InputBuffer subjectPublicKeyInfo);
|
||||
|
||||
Result MapPRErrorCodeToResult(PRErrorCode errorCode);
|
||||
PRErrorCode MapResultToPRErrorCode(Result result);
|
||||
@ -76,6 +76,16 @@ enum ErrorCode {
|
||||
|
||||
void RegisterErrorTable();
|
||||
|
||||
inline SECItem UnsafeMapInputBufferToSECItem(InputBuffer ib)
|
||||
{
|
||||
SECItem result = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(ib.UnsafeGetData()),
|
||||
ib.GetLength()
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
} } // namespace mozilla::pkix
|
||||
|
||||
#endif // mozilla_pkix__pkixnss_h
|
||||
|
@ -25,10 +25,8 @@
|
||||
#ifndef mozilla_pkix__pkixtypes_h
|
||||
#define mozilla_pkix__pkixtypes_h
|
||||
|
||||
#include "pkix/Result.h"
|
||||
#include "pkix/nullptr.h"
|
||||
#include "pkix/Input.h"
|
||||
#include "prtime.h"
|
||||
#include "seccomon.h"
|
||||
#include "stdint.h"
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
@ -81,16 +79,12 @@ MOZILLA_PKIX_ENUM_CLASS SignatureAlgorithm
|
||||
struct SignedDataWithSignature
|
||||
{
|
||||
public:
|
||||
SignedDataWithSignature()
|
||||
{
|
||||
data.data = nullptr;
|
||||
data.len = 0;
|
||||
signature.data = nullptr;
|
||||
signature.len = 0;
|
||||
}
|
||||
SECItem data; // non-owning
|
||||
InputBuffer data;
|
||||
SignatureAlgorithm algorithm;
|
||||
SECItem signature; // non-owning
|
||||
InputBuffer signature;
|
||||
|
||||
private:
|
||||
void operator=(const SignedDataWithSignature&) /*= delete*/;
|
||||
};
|
||||
|
||||
MOZILLA_PKIX_ENUM_CLASS EndEntityOrCA { MustBeEndEntity = 0, MustBeCA = 1 };
|
||||
@ -148,16 +142,16 @@ MOZILLA_PKIX_ENUM_CLASS TrustLevel {
|
||||
struct CertID
|
||||
{
|
||||
public:
|
||||
CertID(const SECItem& issuer, const SECItem& issuerSubjectPublicKeyInfo,
|
||||
const SECItem& serialNumber)
|
||||
CertID(InputBuffer issuer, InputBuffer issuerSubjectPublicKeyInfo,
|
||||
InputBuffer serialNumber)
|
||||
: issuer(issuer)
|
||||
, issuerSubjectPublicKeyInfo(issuerSubjectPublicKeyInfo)
|
||||
, serialNumber(serialNumber)
|
||||
{
|
||||
}
|
||||
const SECItem& issuer;
|
||||
const SECItem& issuerSubjectPublicKeyInfo;
|
||||
const SECItem& serialNumber;
|
||||
const InputBuffer issuer;
|
||||
const InputBuffer issuerSubjectPublicKeyInfo;
|
||||
const InputBuffer serialNumber;
|
||||
private:
|
||||
void operator=(const CertID&) /*= delete*/;
|
||||
};
|
||||
@ -171,7 +165,7 @@ public:
|
||||
// Returns a weak (non-owning) pointer the ith DER-encoded item in the array
|
||||
// (0-indexed). The result is guaranteed to be non-null if i < GetLength(),
|
||||
// and the result is guaranteed to be nullptr if i >= GetLength().
|
||||
virtual const SECItem* GetDER(size_t i) const = 0;
|
||||
virtual const InputBuffer* GetDER(size_t i) const = 0;
|
||||
protected:
|
||||
DERArray() { }
|
||||
virtual ~DERArray() { }
|
||||
@ -200,7 +194,7 @@ public:
|
||||
// (assuming the candidate cert is not actively distrusted).
|
||||
virtual Result GetCertTrust(EndEntityOrCA endEntityOrCA,
|
||||
const CertPolicyId& policy,
|
||||
const SECItem& candidateCertDER,
|
||||
InputBuffer candidateCertDER,
|
||||
/*out*/ TrustLevel& trustLevel) = 0;
|
||||
|
||||
class IssuerChecker
|
||||
@ -213,9 +207,9 @@ public:
|
||||
// encoded NameConstraints extension value; in that case, those name
|
||||
// constraints will be checked in addition to any any name constraints
|
||||
// contained in potentialIssuerDER.
|
||||
virtual Result Check(const SECItem& potentialIssuerDER,
|
||||
/*optional*/ const SECItem* additionalNameConstraints,
|
||||
/*out*/ bool& keepGoing) = 0;
|
||||
virtual Result Check(InputBuffer potentialIssuerDER,
|
||||
/*optional*/ const InputBuffer* additionalNameConstraints,
|
||||
/*out*/ bool& keepGoing) = 0;
|
||||
protected:
|
||||
IssuerChecker();
|
||||
virtual ~IssuerChecker();
|
||||
@ -265,7 +259,7 @@ public:
|
||||
//
|
||||
// checker.Check is responsible for limiting the recursion to a reasonable
|
||||
// limit.
|
||||
virtual Result FindIssuer(const SECItem& encodedIssuerName,
|
||||
virtual Result FindIssuer(InputBuffer encodedIssuerName,
|
||||
IssuerChecker& checker, PRTime time) = 0;
|
||||
|
||||
// Called as soon as we think we have a valid chain but before revocation
|
||||
@ -295,8 +289,8 @@ public:
|
||||
// it.
|
||||
virtual Result CheckRevocation(EndEntityOrCA endEntityOrCA,
|
||||
const CertID& certID, PRTime time,
|
||||
/*optional*/ const SECItem* stapledOCSPresponse,
|
||||
/*optional*/ const SECItem* aiaExtension) = 0;
|
||||
/*optional*/ const InputBuffer* stapledOCSPresponse,
|
||||
/*optional*/ const InputBuffer* aiaExtension) = 0;
|
||||
|
||||
// Check that the key size, algorithm, and parameters of the given public key
|
||||
// are acceptable.
|
||||
@ -304,7 +298,7 @@ public:
|
||||
// VerifySignedData() should do the same checks that this function does, but
|
||||
// mainly for efficiency, some keys are not passed to VerifySignedData().
|
||||
// This function is called instead for those keys.
|
||||
virtual Result CheckPublicKey(const SECItem& subjectPublicKeyInfo) = 0;
|
||||
virtual Result CheckPublicKey(InputBuffer subjectPublicKeyInfo) = 0;
|
||||
|
||||
// Verify the given signature using the given public key.
|
||||
//
|
||||
@ -314,7 +308,7 @@ public:
|
||||
// In any case, the implementation must perform checks on the public key
|
||||
// similar to how mozilla::pkix::CheckPublicKey() does.
|
||||
virtual Result VerifySignedData(const SignedDataWithSignature& signedData,
|
||||
const SECItem& subjectPublicKeyInfo) = 0;
|
||||
InputBuffer subjectPublicKeyInfo) = 0;
|
||||
|
||||
// Compute the SHA-1 hash of the data in the current item.
|
||||
//
|
||||
@ -327,7 +321,7 @@ public:
|
||||
// other, extensive, memory safety efforts in mozilla::pkix, and we should
|
||||
// find a way to provide a more-obviously-safe interface.
|
||||
static const size_t DIGEST_LENGTH = 20; // length of SHA-1 digest
|
||||
virtual Result DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
|
||||
virtual Result DigestBuf(InputBuffer item, /*out*/ uint8_t* digestBuf,
|
||||
size_t digestBufLen) = 0;
|
||||
protected:
|
||||
TrustDomain() { }
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <limits>
|
||||
|
||||
#include "pkixcheck.h"
|
||||
#include "pkixutil.h"
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
|
||||
@ -36,7 +37,7 @@ static Result BuildForward(TrustDomain& trustDomain,
|
||||
KeyUsage requiredKeyUsageIfPresent,
|
||||
KeyPurposeId requiredEKUIfPresent,
|
||||
const CertPolicyId& requiredPolicy,
|
||||
/*optional*/ const SECItem* stapledOCSPResponse,
|
||||
/*optional*/ const InputBuffer* stapledOCSPResponse,
|
||||
unsigned int subCACount);
|
||||
|
||||
TrustDomain::IssuerChecker::IssuerChecker() { }
|
||||
@ -50,7 +51,7 @@ public:
|
||||
PathBuildingStep(TrustDomain& trustDomain, const BackCert& subject,
|
||||
PRTime time, KeyPurposeId requiredEKUIfPresent,
|
||||
const CertPolicyId& requiredPolicy,
|
||||
/*optional*/ const SECItem* stapledOCSPResponse,
|
||||
/*optional*/ const InputBuffer* stapledOCSPResponse,
|
||||
unsigned int subCACount)
|
||||
: trustDomain(trustDomain)
|
||||
, subject(subject)
|
||||
@ -64,8 +65,8 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
Result Check(const SECItem& potentialIssuerDER,
|
||||
/*optional*/ const SECItem* additionalNameConstraints,
|
||||
Result Check(InputBuffer potentialIssuerDER,
|
||||
/*optional*/ const InputBuffer* additionalNameConstraints,
|
||||
/*out*/ bool& keepGoing);
|
||||
|
||||
Result CheckResult() const;
|
||||
@ -76,7 +77,7 @@ private:
|
||||
const PRTime time;
|
||||
const KeyPurposeId requiredEKUIfPresent;
|
||||
const CertPolicyId& requiredPolicy;
|
||||
/*optional*/ SECItem const* const stapledOCSPResponse;
|
||||
/*optional*/ InputBuffer const* const stapledOCSPResponse;
|
||||
const unsigned int subCACount;
|
||||
|
||||
Result RecordResult(Result currentResult, /*out*/ bool& keepGoing);
|
||||
@ -125,9 +126,9 @@ PathBuildingStep::CheckResult() const
|
||||
|
||||
// The code that executes in the inner loop of BuildForward
|
||||
Result
|
||||
PathBuildingStep::Check(const SECItem& potentialIssuerDER,
|
||||
/*optional*/ const SECItem* additionalNameConstraints,
|
||||
/*out*/ bool& keepGoing)
|
||||
PathBuildingStep::Check(InputBuffer potentialIssuerDER,
|
||||
/*optional*/ const InputBuffer* additionalNameConstraints,
|
||||
/*out*/ bool& keepGoing)
|
||||
{
|
||||
BackCert potentialIssuer(potentialIssuerDER, EndEntityOrCA::MustBeCA,
|
||||
&subject);
|
||||
@ -145,10 +146,10 @@ PathBuildingStep::Check(const SECItem& potentialIssuerDER,
|
||||
bool loopDetected = false;
|
||||
for (const BackCert* prev = potentialIssuer.childCert;
|
||||
!loopDetected && prev != nullptr; prev = prev->childCert) {
|
||||
if (SECITEM_ItemsAreEqual(&potentialIssuer.GetSubjectPublicKeyInfo(),
|
||||
&prev->GetSubjectPublicKeyInfo()) &&
|
||||
SECITEM_ItemsAreEqual(&potentialIssuer.GetSubject(),
|
||||
&prev->GetSubject())) {
|
||||
if (InputBuffersAreEqual(potentialIssuer.GetSubjectPublicKeyInfo(),
|
||||
prev->GetSubjectPublicKeyInfo()) &&
|
||||
InputBuffersAreEqual(potentialIssuer.GetSubject(),
|
||||
prev->GetSubject())) {
|
||||
// XXX: error code
|
||||
return RecordResult(Result::ERROR_UNKNOWN_ISSUER, keepGoing);
|
||||
}
|
||||
@ -210,7 +211,7 @@ BuildForward(TrustDomain& trustDomain,
|
||||
KeyUsage requiredKeyUsageIfPresent,
|
||||
KeyPurposeId requiredEKUIfPresent,
|
||||
const CertPolicyId& requiredPolicy,
|
||||
/*optional*/ const SECItem* stapledOCSPResponse,
|
||||
/*optional*/ const InputBuffer* stapledOCSPResponse,
|
||||
unsigned int subCACount)
|
||||
{
|
||||
Result rv;
|
||||
@ -293,12 +294,12 @@ BuildForward(TrustDomain& trustDomain,
|
||||
}
|
||||
|
||||
Result
|
||||
BuildCertChain(TrustDomain& trustDomain, const SECItem& certDER,
|
||||
BuildCertChain(TrustDomain& trustDomain, InputBuffer certDER,
|
||||
PRTime time, EndEntityOrCA endEntityOrCA,
|
||||
KeyUsage requiredKeyUsageIfPresent,
|
||||
KeyPurposeId requiredEKUIfPresent,
|
||||
const CertPolicyId& requiredPolicy,
|
||||
/*optional*/ const SECItem* stapledOCSPResponse)
|
||||
/*optional*/ const InputBuffer* stapledOCSPResponse)
|
||||
{
|
||||
// XXX: Support the legacy use of the subject CN field for indicating the
|
||||
// domain name the certificate is valid for.
|
||||
|
@ -42,11 +42,7 @@ BackCert::Init()
|
||||
// The scope of |input| and |certificate| are limited to this block so we
|
||||
// don't accidentally confuse them for tbsCertificate later.
|
||||
{
|
||||
Input input;
|
||||
rv = input.Init(der.data, der.len);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
Input input(der);
|
||||
Input certificate;
|
||||
rv = der::ExpectTagAndGetValue(input, der::SEQUENCE, certificate);
|
||||
if (rv != Success) {
|
||||
@ -162,8 +158,10 @@ BackCert::Init()
|
||||
return der::End(tbsCertificate);
|
||||
}
|
||||
|
||||
// XXX: The second value is of type |const InputBupkffer&| instead of type
|
||||
// |InputBuffer| due to limitations in our std::bind polyfill.
|
||||
Result
|
||||
BackCert::RememberExtension(Input& extnID, const SECItem& extnValue,
|
||||
BackCert::RememberExtension(Input& extnID, const InputBuffer& extnValue,
|
||||
/*out*/ bool& understood)
|
||||
{
|
||||
understood = false;
|
||||
@ -205,7 +203,7 @@ BackCert::RememberExtension(Input& extnID, const SECItem& extnValue,
|
||||
0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01
|
||||
};
|
||||
|
||||
SECItem* out = nullptr;
|
||||
InputBuffer* out = nullptr;
|
||||
|
||||
// We already enforce the maximum possible constraints for policies so we
|
||||
// can safely ignore even critical policy constraint extensions.
|
||||
@ -213,7 +211,7 @@ BackCert::RememberExtension(Input& extnID, const SECItem& extnValue,
|
||||
// XXX: Doing it this way won't allow us to detect duplicate
|
||||
// policyConstraints extensions, but that's OK because (and only because) we
|
||||
// ignore the extension.
|
||||
SECItem dummyPolicyConstraints = { siBuffer, nullptr, 0 };
|
||||
InputBuffer dummyPolicyConstraints;
|
||||
|
||||
// RFC says "Conforming CAs MUST mark this extension as non-critical" for
|
||||
// both authorityKeyIdentifier and subjectKeyIdentifier, and we do not use
|
||||
@ -241,15 +239,14 @@ BackCert::RememberExtension(Input& extnID, const SECItem& extnValue,
|
||||
|
||||
if (out) {
|
||||
// Don't allow an empty value for any extension we understand. This way, we
|
||||
// can test out->len to check for duplicates.
|
||||
if (extnValue.len == 0) {
|
||||
// can test out->GetLength() != 0 or out->Init() to check for duplicates.
|
||||
if (extnValue.GetLength() == 0) {
|
||||
return Result::ERROR_EXTENSION_VALUE_INVALID;
|
||||
}
|
||||
if (out->len != 0) {
|
||||
if (out->Init(extnValue) != Success) {
|
||||
// Duplicate extension
|
||||
return Result::ERROR_EXTENSION_VALUE_INVALID;
|
||||
}
|
||||
*out = extnValue;
|
||||
understood = true;
|
||||
}
|
||||
|
||||
|
@ -22,11 +22,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
#include "pkixcheck.h"
|
||||
|
||||
#include "cert.h"
|
||||
#include "pkix/bind.h"
|
||||
#include "pkix/pkix.h"
|
||||
#include "pkix/ScopedPtr.h"
|
||||
#include "pkixcheck.h"
|
||||
#include "pkixder.h"
|
||||
#include "pkix/pkixnss.h"
|
||||
#include "pkixutil.h"
|
||||
@ -34,12 +35,9 @@
|
||||
namespace mozilla { namespace pkix {
|
||||
|
||||
Result
|
||||
CheckValidity(const SECItem& encodedValidity, PRTime time)
|
||||
CheckValidity(InputBuffer encodedValidity, PRTime time)
|
||||
{
|
||||
Input validity;
|
||||
if (validity.Init(encodedValidity.data, encodedValidity.len) != Success) {
|
||||
return Result::ERROR_EXPIRED_CERTIFICATE;
|
||||
}
|
||||
Input validity(encodedValidity);
|
||||
PRTime notBefore;
|
||||
if (der::TimeChoice(validity, notBefore) != Success) {
|
||||
return Result::ERROR_EXPIRED_CERTIFICATE;
|
||||
@ -70,7 +68,7 @@ inline uint8_t KeyUsageToBitMask(KeyUsage keyUsage)
|
||||
}
|
||||
|
||||
Result
|
||||
CheckKeyUsage(EndEntityOrCA endEntityOrCA, const SECItem* encodedKeyUsage,
|
||||
CheckKeyUsage(EndEntityOrCA endEntityOrCA, const InputBuffer* encodedKeyUsage,
|
||||
KeyUsage requiredKeyUsageIfPresent)
|
||||
{
|
||||
if (!encodedKeyUsage) {
|
||||
@ -88,10 +86,7 @@ CheckKeyUsage(EndEntityOrCA endEntityOrCA, const SECItem* encodedKeyUsage,
|
||||
return Success;
|
||||
}
|
||||
|
||||
Input input;
|
||||
if (input.Init(encodedKeyUsage->data, encodedKeyUsage->len) != Success) {
|
||||
return Result::ERROR_INADEQUATE_KEY_USAGE;
|
||||
}
|
||||
Input input(*encodedKeyUsage);
|
||||
Input value;
|
||||
if (der::ExpectTagAndGetValue(input, der::BIT_STRING, value) != Success) {
|
||||
return Result::ERROR_INADEQUATE_KEY_USAGE;
|
||||
@ -233,8 +228,8 @@ CheckPolicyInformation(Input& input, EndEntityOrCA endEntityOrCA,
|
||||
// certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
|
||||
Result
|
||||
CheckCertificatePolicies(EndEntityOrCA endEntityOrCA,
|
||||
const SECItem* encodedCertificatePolicies,
|
||||
const SECItem* encodedInhibitAnyPolicy,
|
||||
const InputBuffer* encodedCertificatePolicies,
|
||||
const InputBuffer* encodedInhibitAnyPolicy,
|
||||
TrustLevel trustLevel,
|
||||
const CertPolicyId& requiredPolicy)
|
||||
{
|
||||
@ -272,11 +267,7 @@ CheckCertificatePolicies(EndEntityOrCA endEntityOrCA,
|
||||
|
||||
bool found = false;
|
||||
|
||||
Input input;
|
||||
if (input.Init(encodedCertificatePolicies->data,
|
||||
encodedCertificatePolicies->len) != Success) {
|
||||
return Result::ERROR_POLICY_VALIDATION_FAILED;
|
||||
}
|
||||
Input input(*encodedCertificatePolicies);
|
||||
if (der::NestedOf(input, der::SEQUENCE, der::SEQUENCE, der::EmptyAllowed::No,
|
||||
bind(CheckPolicyInformation, _1, endEntityOrCA,
|
||||
requiredPolicy, ref(found))) != Success) {
|
||||
@ -325,7 +316,7 @@ DecodeBasicConstraints(Input& input, /*out*/ bool& isCA,
|
||||
// RFC5280 4.2.1.9. Basic Constraints (id-ce-basicConstraints)
|
||||
Result
|
||||
CheckBasicConstraints(EndEntityOrCA endEntityOrCA,
|
||||
const SECItem* encodedBasicConstraints,
|
||||
const InputBuffer* encodedBasicConstraints,
|
||||
const der::Version version, TrustLevel trustLevel,
|
||||
unsigned int subCACount)
|
||||
{
|
||||
@ -333,11 +324,7 @@ CheckBasicConstraints(EndEntityOrCA endEntityOrCA,
|
||||
long pathLenConstraint = UNLIMITED_PATH_LEN;
|
||||
|
||||
if (encodedBasicConstraints) {
|
||||
Input input;
|
||||
if (input.Init(encodedBasicConstraints->data,
|
||||
encodedBasicConstraints->len) != Success) {
|
||||
return Result::ERROR_EXTENSION_VALUE_INVALID;
|
||||
}
|
||||
Input input(*encodedBasicConstraints);
|
||||
if (der::Nested(input, der::SEQUENCE,
|
||||
bind(DecodeBasicConstraints, _1, ref(isCA),
|
||||
ref(pathLenConstraint))) != Success) {
|
||||
@ -406,10 +393,11 @@ PORT_FreeArena_false(PLArenaPool* arena) {
|
||||
return PORT_FreeArena(arena, PR_FALSE);
|
||||
}
|
||||
|
||||
// TODO: remove #include "pkix/pkixnss.h" when this is rewritten to be
|
||||
// independent of NSS.
|
||||
// TODO: Remove #include "pkix/pkixnss.h", #include "cert.h",
|
||||
// #include "ScopedPtr.h", etc. when this is rewritten to be independent of
|
||||
// NSS.
|
||||
Result
|
||||
CheckNameConstraints(const SECItem& encodedNameConstraints,
|
||||
CheckNameConstraints(InputBuffer encodedNameConstraints,
|
||||
const BackCert& firstChild,
|
||||
KeyPurposeId requiredEKUIfPresent)
|
||||
{
|
||||
@ -419,17 +407,21 @@ CheckNameConstraints(const SECItem& encodedNameConstraints,
|
||||
return Result::FATAL_ERROR_NO_MEMORY;
|
||||
}
|
||||
|
||||
SECItem encodedNameConstraintsSECItem =
|
||||
UnsafeMapInputBufferToSECItem(encodedNameConstraints);
|
||||
|
||||
// Owned by arena
|
||||
const CERTNameConstraints* constraints =
|
||||
CERT_DecodeNameConstraintsExtension(arena.get(), &encodedNameConstraints);
|
||||
CERT_DecodeNameConstraintsExtension(arena.get(),
|
||||
&encodedNameConstraintsSECItem);
|
||||
if (!constraints) {
|
||||
return MapPRErrorCodeToResult(PR_GetError());
|
||||
}
|
||||
|
||||
for (const BackCert* child = &firstChild; child; child = child->childCert) {
|
||||
SECItem childCertDER = UnsafeMapInputBufferToSECItem(child->GetDER());
|
||||
ScopedPtr<CERTCertificate, CERT_DestroyCertificate>
|
||||
nssCert(CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
|
||||
const_cast<SECItem*>(&child->GetDER()),
|
||||
nssCert(CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &childCertDER,
|
||||
nullptr, false, true));
|
||||
if (!nssCert) {
|
||||
return MapPRErrorCodeToResult(PR_GetError());
|
||||
@ -548,7 +540,7 @@ MatchEKU(Input& value, KeyPurposeId requiredEKU,
|
||||
|
||||
Result
|
||||
CheckExtendedKeyUsage(EndEntityOrCA endEntityOrCA,
|
||||
const SECItem* encodedExtendedKeyUsage,
|
||||
const InputBuffer* encodedExtendedKeyUsage,
|
||||
KeyPurposeId requiredEKU)
|
||||
{
|
||||
// XXX: We're using Result::ERROR_INADEQUATE_CERT_TYPE here so that callers
|
||||
@ -561,11 +553,7 @@ CheckExtendedKeyUsage(EndEntityOrCA endEntityOrCA,
|
||||
if (encodedExtendedKeyUsage) {
|
||||
bool found = requiredEKU == KeyPurposeId::anyExtendedKeyUsage;
|
||||
|
||||
Input input;
|
||||
if (input.Init(encodedExtendedKeyUsage->data,
|
||||
encodedExtendedKeyUsage->len) != Success) {
|
||||
return Result::ERROR_INADEQUATE_CERT_TYPE;
|
||||
}
|
||||
Input input(*encodedExtendedKeyUsage);
|
||||
if (der::NestedOf(input, der::SEQUENCE, der::OIDTag, der::EmptyAllowed::No,
|
||||
bind(MatchEKU, _1, requiredEKU, endEntityOrCA,
|
||||
ref(found), ref(foundOCSPSigning)))
|
||||
|
@ -26,11 +26,11 @@
|
||||
#define mozilla_pkix__pkixcheck_h
|
||||
|
||||
#include "pkix/pkixtypes.h"
|
||||
#include "pkixutil.h"
|
||||
#include "certt.h"
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
|
||||
class BackCert;
|
||||
|
||||
Result CheckIssuerIndependentProperties(
|
||||
TrustDomain& trustDomain,
|
||||
const BackCert& cert,
|
||||
@ -41,7 +41,7 @@ Result CheckIssuerIndependentProperties(
|
||||
unsigned int subCACount,
|
||||
/*out*/ TrustLevel& trustLevel);
|
||||
|
||||
Result CheckNameConstraints(const SECItem& encodedNameConstraints,
|
||||
Result CheckNameConstraints(InputBuffer encodedNameConstraints,
|
||||
const BackCert& firstChild,
|
||||
KeyPurposeId requiredEKUIfPresent);
|
||||
|
||||
|
@ -289,7 +289,7 @@ SignedData(Input& input, /*out*/ Input& tbs,
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = input.GetSECItem(siBuffer, mark, signedData.data);
|
||||
rv = input.GetInputBuffer(mark, signedData.data);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
@ -299,27 +299,38 @@ SignedData(Input& input, /*out*/ Input& tbs,
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = ExpectTagAndGetValue(input, BIT_STRING, signedData.signature);
|
||||
rv = BitStringWithNoUnusedBits(input, signedData.signature);
|
||||
if (rv == Result::ERROR_BAD_DER) {
|
||||
rv = Result::ERROR_BAD_SIGNATURE;
|
||||
}
|
||||
return rv;
|
||||
}
|
||||
|
||||
Result
|
||||
BitStringWithNoUnusedBits(Input& input, /*out*/ InputBuffer& value)
|
||||
{
|
||||
Input valueWithUnusedBits;
|
||||
Result rv = ExpectTagAndGetValue(input, BIT_STRING, valueWithUnusedBits);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
if (signedData.signature.len == 0) {
|
||||
return Result::ERROR_BAD_SIGNATURE;
|
||||
}
|
||||
unsigned int unusedBitsAtEnd = signedData.signature.data[0];
|
||||
// XXX: Really the constraint should be that unusedBitsAtEnd must be less
|
||||
// than 7. But, we suspect there are no real-world OCSP responses or X.509
|
||||
// certificates with non-zero unused bits. It seems like NSS assumes this in
|
||||
// various places, so we enforce it too in order to simplify this code. If we
|
||||
// find compatibility issues, we'll know we're wrong and we'll have to figure
|
||||
// out how to shift the bits around.
|
||||
if (unusedBitsAtEnd != 0) {
|
||||
return Result::ERROR_BAD_SIGNATURE;
|
||||
}
|
||||
++signedData.signature.data;
|
||||
--signedData.signature.len;
|
||||
|
||||
return Success;
|
||||
uint8_t unusedBitsAtEnd;
|
||||
if (valueWithUnusedBits.Read(unusedBitsAtEnd) != Success) {
|
||||
return Result::ERROR_BAD_DER;
|
||||
}
|
||||
// XXX: Really the constraint should be that unusedBitsAtEnd must be less
|
||||
// than 7. But, we suspect there are no real-world values in OCSP responses
|
||||
// or certificates with non-zero unused bits. It seems like NSS assumes this
|
||||
// in various places, so we enforce it too in order to simplify this code. If
|
||||
// we find compatibility issues, we'll know we're wrong and we'll have to
|
||||
// figure out how to shift the bits around.
|
||||
if (unusedBitsAtEnd != 0) {
|
||||
return Result::ERROR_BAD_DER;
|
||||
}
|
||||
Input::Mark mark(valueWithUnusedBits.GetMark());
|
||||
valueWithUnusedBits.SkipToEnd();
|
||||
return valueWithUnusedBits.GetInputBuffer(mark, value);
|
||||
}
|
||||
|
||||
static inline Result
|
||||
|
@ -37,13 +37,9 @@
|
||||
// they are able to do so; otherwise they fail with the input mark in an
|
||||
// undefined state.
|
||||
|
||||
#include "pkix/enumclass.h"
|
||||
#include "pkix/Input.h"
|
||||
#include "pkix/pkixtypes.h"
|
||||
#include "prtime.h"
|
||||
#include "secoidt.h"
|
||||
|
||||
typedef struct CERTSignedDataStr CERTSignedData;
|
||||
|
||||
namespace mozilla { namespace pkix { namespace der {
|
||||
|
||||
@ -117,7 +113,7 @@ ExpectTagAndSkipValue(Input& input, uint8_t tag)
|
||||
}
|
||||
|
||||
inline Result
|
||||
ExpectTagAndGetValue(Input& input, uint8_t tag, /*out*/ SECItem& value)
|
||||
ExpectTagAndGetValue(Input& input, uint8_t tag, /*out*/ InputBuffer& value)
|
||||
{
|
||||
uint16_t length;
|
||||
Result rv = internal::ExpectTagAndGetLength(input, tag, length);
|
||||
@ -138,10 +134,10 @@ ExpectTagAndGetValue(Input& input, uint8_t tag, /*out*/ Input& value)
|
||||
return input.Skip(length, value);
|
||||
}
|
||||
|
||||
// Like ExpectTagAndGetValue, except the output SECItem will contain the
|
||||
// Like ExpectTagAndGetValue, except the output InputBuffer will contain the
|
||||
// encoded tag and length along with the value.
|
||||
inline Result
|
||||
ExpectTagAndGetTLV(Input& input, uint8_t tag, /*out*/ SECItem& tlv)
|
||||
ExpectTagAndGetTLV(Input& input, uint8_t tag, /*out*/ InputBuffer& tlv)
|
||||
{
|
||||
Input::Mark mark(input.GetMark());
|
||||
uint16_t length;
|
||||
@ -153,7 +149,7 @@ ExpectTagAndGetTLV(Input& input, uint8_t tag, /*out*/ SECItem& tlv)
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
return input.GetSECItem(siBuffer, mark, tlv);
|
||||
return input.GetInputBuffer(mark, tlv);
|
||||
}
|
||||
|
||||
inline Result
|
||||
@ -276,6 +272,9 @@ IntegralValue(Input& input, uint8_t tag, T& value)
|
||||
|
||||
} // namespace internal
|
||||
|
||||
Result
|
||||
BitStringWithNoUnusedBits(Input& input, /*out*/ InputBuffer& value);
|
||||
|
||||
inline Result
|
||||
Boolean(Input& input, /*out*/ bool& value)
|
||||
{
|
||||
@ -402,18 +401,21 @@ template <uint8_t Len>
|
||||
Result
|
||||
OID(Input& input, const uint8_t (&expectedOid)[Len])
|
||||
{
|
||||
Result rv = ExpectTagAndLength(input, OIDTag, Len);
|
||||
Input value;
|
||||
Result rv = ExpectTagAndGetValue(input, OIDTag, value);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
return input.Expect(expectedOid, Len);
|
||||
if (!value.MatchRest(expectedOid)) {
|
||||
return Result::ERROR_BAD_DER;
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
|
||||
// PKI-specific types
|
||||
|
||||
inline Result
|
||||
CertificateSerialNumber(Input& input, /*out*/ SECItem& value)
|
||||
CertificateSerialNumber(Input& input, /*out*/ InputBuffer& value)
|
||||
{
|
||||
// http://tools.ietf.org/html/rfc5280#section-4.1.2.2:
|
||||
//
|
||||
@ -431,7 +433,7 @@ CertificateSerialNumber(Input& input, /*out*/ SECItem& value)
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (value.len == 0) {
|
||||
if (value.GetLength() == 0) {
|
||||
return Result::ERROR_BAD_DER;
|
||||
}
|
||||
|
||||
@ -440,9 +442,20 @@ CertificateSerialNumber(Input& input, /*out*/ SECItem& value)
|
||||
// could be encoded without the leading 0x00 byte. If the first byte is 0xFF
|
||||
// then the second byte must NOT have its high bit set; otherwise the same
|
||||
// *negative* value could be encoded without the leading 0xFF byte.
|
||||
if (value.len > 1) {
|
||||
if ((value.data[0] == 0x00 && (value.data[1] & 0x80) == 0) ||
|
||||
(value.data[0] == 0xff && (value.data[1] & 0x80) != 0)) {
|
||||
if (value.GetLength() > 1) {
|
||||
Input valueInput(value);
|
||||
uint8_t firstByte;
|
||||
rv = valueInput.Read(firstByte);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
uint8_t secondByte;
|
||||
rv = valueInput.Read(secondByte);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
if ((firstByte == 0x00 && (secondByte & 0x80) == 0) ||
|
||||
(firstByte == 0xff && (secondByte & 0x80) != 0)) {
|
||||
return Result::ERROR_BAD_DER;
|
||||
}
|
||||
}
|
||||
@ -545,7 +558,7 @@ OptionalExtensions(Input& input, uint8_t tag, ExtensionHandler extensionHandler)
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
SECItem extnValue;
|
||||
InputBuffer extnValue;
|
||||
rv = ExpectTagAndGetValue(extension, OCTET_STRING, extnValue);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
|
@ -25,7 +25,6 @@
|
||||
#include "pkix/pkixnss.h"
|
||||
|
||||
#include <limits>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "cert.h"
|
||||
#include "cryptohi.h"
|
||||
@ -40,11 +39,13 @@ namespace mozilla { namespace pkix {
|
||||
typedef ScopedPtr<SECKEYPublicKey, SECKEY_DestroyPublicKey> ScopedSECKeyPublicKey;
|
||||
|
||||
Result
|
||||
CheckPublicKeySize(const SECItem& subjectPublicKeyInfo,
|
||||
CheckPublicKeySize(InputBuffer subjectPublicKeyInfo,
|
||||
/*out*/ ScopedSECKeyPublicKey& publicKey)
|
||||
{
|
||||
SECItem subjectPublicKeyInfoSECItem =
|
||||
UnsafeMapInputBufferToSECItem(subjectPublicKeyInfo);
|
||||
ScopedPtr<CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo>
|
||||
spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&subjectPublicKeyInfo));
|
||||
spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&subjectPublicKeyInfoSECItem));
|
||||
if (!spki) {
|
||||
return MapPRErrorCodeToResult(PR_GetError());
|
||||
}
|
||||
@ -81,7 +82,7 @@ CheckPublicKeySize(const SECItem& subjectPublicKeyInfo,
|
||||
}
|
||||
|
||||
Result
|
||||
CheckPublicKey(const SECItem& subjectPublicKeyInfo)
|
||||
CheckPublicKey(InputBuffer subjectPublicKeyInfo)
|
||||
{
|
||||
ScopedSECKeyPublicKey unused;
|
||||
return CheckPublicKeySize(subjectPublicKeyInfo, unused);
|
||||
@ -89,15 +90,11 @@ CheckPublicKey(const SECItem& subjectPublicKeyInfo)
|
||||
|
||||
Result
|
||||
VerifySignedData(const SignedDataWithSignature& sd,
|
||||
const SECItem& subjectPublicKeyInfo, void* pkcs11PinArg)
|
||||
InputBuffer subjectPublicKeyInfo, void* pkcs11PinArg)
|
||||
{
|
||||
if (!sd.data.data || !sd.signature.data) {
|
||||
PR_NOT_REACHED("invalid args to VerifySignedData");
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
// See bug 921585.
|
||||
if (sd.data.len > static_cast<unsigned int>(std::numeric_limits<int>::max())) {
|
||||
if (sd.data.GetLength() >
|
||||
static_cast<unsigned int>(std::numeric_limits<int>::max())) {
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
@ -158,10 +155,13 @@ VerifySignedData(const SignedDataWithSignature& sd,
|
||||
|
||||
// The static_cast is safe according to the check above that references
|
||||
// bug 921585.
|
||||
SECStatus srv = VFY_VerifyDataDirect(sd.data.data,
|
||||
static_cast<int>(sd.data.len),
|
||||
pubKey.get(), &sd.signature, pubKeyAlg,
|
||||
digestAlg, nullptr, pkcs11PinArg);
|
||||
SECItem dataSECItem(UnsafeMapInputBufferToSECItem(sd.data));
|
||||
SECItem signatureSECItem(UnsafeMapInputBufferToSECItem(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());
|
||||
}
|
||||
@ -170,7 +170,7 @@ VerifySignedData(const SignedDataWithSignature& sd,
|
||||
}
|
||||
|
||||
Result
|
||||
DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf, size_t digestBufLen)
|
||||
DigestBuf(InputBuffer item, /*out*/ uint8_t* digestBuf, size_t digestBufLen)
|
||||
{
|
||||
static_assert(TrustDomain::DIGEST_LENGTH == SHA1_LENGTH,
|
||||
"TrustDomain::DIGEST_LENGTH must be 20 (SHA-1 digest length)");
|
||||
@ -178,13 +178,15 @@ DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf, size_t digestBufLen)
|
||||
PR_NOT_REACHED("invalid hash length");
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
if (item.len >
|
||||
static_cast<decltype(item.len)>(std::numeric_limits<int32_t>::max())) {
|
||||
PR_NOT_REACHED("large OCSP responses should have already been rejected");
|
||||
SECItem itemSECItem = UnsafeMapInputBufferToSECItem(item);
|
||||
if (itemSECItem.len >
|
||||
static_cast<decltype(itemSECItem.len)>(
|
||||
std::numeric_limits<int32_t>::max())) {
|
||||
PR_NOT_REACHED("large items should not be possible here");
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
SECStatus srv = PK11_HashBuf(SEC_OID_SHA1, digestBuf, item.data,
|
||||
static_cast<int32_t>(item.len));
|
||||
SECStatus srv = PK11_HashBuf(SEC_OID_SHA1, digestBuf, itemSECItem.data,
|
||||
static_cast<int32_t>(itemSECItem.len));
|
||||
if (srv != SECSuccess) {
|
||||
return MapPRErrorCodeToResult(PR_GetError());
|
||||
}
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include "pkix/bind.h"
|
||||
#include "pkix/pkix.h"
|
||||
#include "pkixcheck.h"
|
||||
#include "pkixutil.h"
|
||||
#include "pkixder.h"
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
@ -84,8 +85,8 @@ private:
|
||||
static Result
|
||||
CheckOCSPResponseSignerCert(TrustDomain& trustDomain,
|
||||
BackCert& potentialSigner,
|
||||
const SECItem& issuerSubject,
|
||||
const SECItem& issuerSubjectPublicKeyInfo,
|
||||
InputBuffer issuerSubject,
|
||||
InputBuffer issuerSubjectPublicKeyInfo,
|
||||
PRTime time)
|
||||
{
|
||||
Result rv;
|
||||
@ -128,7 +129,7 @@ CheckOCSPResponseSignerCert(TrustDomain& trustDomain,
|
||||
// XXX(bug 926270) XXX(bug 1008133) XXX(bug 980163): Improve name
|
||||
// comparison.
|
||||
// TODO: needs test
|
||||
if (!SECITEM_ItemsAreEqual(&potentialSigner.GetIssuer(), &issuerSubject)) {
|
||||
if (!InputBuffersAreEqual(potentialSigner.GetIssuer(), issuerSubject)) {
|
||||
return Result::ERROR_OCSP_RESPONDER_CERT_INVALID;
|
||||
}
|
||||
|
||||
@ -158,26 +159,25 @@ static inline Result ResponseData(
|
||||
const SignedDataWithSignature& signedResponseData,
|
||||
const DERArray& certs);
|
||||
static inline Result SingleResponse(Input& input, Context& context);
|
||||
static Result ExtensionNotUnderstood(Input& extnID,
|
||||
const SECItem& extnValue,
|
||||
static Result ExtensionNotUnderstood(Input& extnID, InputBuffer extnValue,
|
||||
/*out*/ bool& understood);
|
||||
static inline Result CertID(Input& input,
|
||||
const Context& context,
|
||||
/*out*/ bool& match);
|
||||
static Result MatchKeyHash(TrustDomain& trustDomain,
|
||||
const SECItem& issuerKeyHash,
|
||||
const SECItem& issuerSubjectPublicKeyInfo,
|
||||
InputBuffer issuerKeyHash,
|
||||
InputBuffer issuerSubjectPublicKeyInfo,
|
||||
/*out*/ bool& match);
|
||||
static Result KeyHash(TrustDomain& trustDomain,
|
||||
const SECItem& subjectPublicKeyInfo,
|
||||
InputBuffer subjectPublicKeyInfo,
|
||||
/*out*/ uint8_t* hashBuf, size_t hashBufSize);
|
||||
|
||||
static Result
|
||||
MatchResponderID(TrustDomain& trustDomain,
|
||||
ResponderIDType responderIDType,
|
||||
const SECItem& responderIDItem,
|
||||
const SECItem& potentialSignerSubject,
|
||||
const SECItem& potentialSignerSubjectPublicKeyInfo,
|
||||
InputBuffer responderID,
|
||||
InputBuffer potentialSignerSubject,
|
||||
InputBuffer potentialSignerSubjectPublicKeyInfo,
|
||||
/*out*/ bool& match)
|
||||
{
|
||||
match = false;
|
||||
@ -186,18 +186,14 @@ MatchResponderID(TrustDomain& trustDomain,
|
||||
case ResponderIDType::byName:
|
||||
// XXX(bug 926270) XXX(bug 1008133) XXX(bug 980163): Improve name
|
||||
// comparison.
|
||||
match = SECITEM_ItemsAreEqual(&responderIDItem, &potentialSignerSubject);
|
||||
match = InputBuffersAreEqual(responderID, potentialSignerSubject);
|
||||
return Success;
|
||||
|
||||
case ResponderIDType::byKey:
|
||||
{
|
||||
Input responderID;
|
||||
Result rv = responderID.Init(responderIDItem.data, responderIDItem.len);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
SECItem keyHash;
|
||||
rv = der::ExpectTagAndGetValue(responderID, der::OCTET_STRING, keyHash);
|
||||
Input input(responderID);
|
||||
InputBuffer keyHash;
|
||||
Result rv = der::ExpectTagAndGetValue(input, der::OCTET_STRING, keyHash);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
@ -213,7 +209,7 @@ MatchResponderID(TrustDomain& trustDomain,
|
||||
static Result
|
||||
VerifyOCSPSignedData(TrustDomain& trustDomain,
|
||||
const SignedDataWithSignature& signedResponseData,
|
||||
const SECItem& spki)
|
||||
InputBuffer spki)
|
||||
{
|
||||
Result rv = trustDomain.VerifySignedData(signedResponseData, spki);
|
||||
if (rv == Result::ERROR_BAD_SIGNATURE) {
|
||||
@ -230,7 +226,7 @@ VerifyOCSPSignedData(TrustDomain& trustDomain,
|
||||
// *directly* to issuerCert.
|
||||
static Result
|
||||
VerifySignature(Context& context, ResponderIDType responderIDType,
|
||||
const SECItem& responderID, const DERArray& certs,
|
||||
InputBuffer responderID, const DERArray& certs,
|
||||
const SignedDataWithSignature& signedResponseData)
|
||||
{
|
||||
bool match;
|
||||
@ -295,7 +291,7 @@ MapBadDERToMalformedOCSPResponse(Result rv)
|
||||
Result
|
||||
VerifyEncodedOCSPResponse(TrustDomain& trustDomain, const struct CertID& certID,
|
||||
PRTime time, uint16_t maxOCSPLifetimeInDays,
|
||||
const SECItem& encodedResponse,
|
||||
InputBuffer encodedResponse,
|
||||
/*out*/ bool& expired,
|
||||
/*optional out*/ PRTime* thisUpdate,
|
||||
/*optional out*/ PRTime* validThrough)
|
||||
@ -303,20 +299,15 @@ VerifyEncodedOCSPResponse(TrustDomain& trustDomain, const struct CertID& certID,
|
||||
// Always initialize this to something reasonable.
|
||||
expired = false;
|
||||
|
||||
Input input;
|
||||
Result rv = input.Init(encodedResponse.data, encodedResponse.len);
|
||||
if (rv != Success) {
|
||||
return MapBadDERToMalformedOCSPResponse(rv);
|
||||
}
|
||||
|
||||
Context context(trustDomain, certID, time, maxOCSPLifetimeInDays,
|
||||
thisUpdate, validThrough);
|
||||
|
||||
rv = der::Nested(input, der::SEQUENCE, bind(OCSPResponse, _1, ref(context)));
|
||||
Input input(encodedResponse);
|
||||
Result rv = der::Nested(input, der::SEQUENCE,
|
||||
bind(OCSPResponse, _1, ref(context)));
|
||||
if (rv != Success) {
|
||||
return MapBadDERToMalformedOCSPResponse(rv);
|
||||
}
|
||||
|
||||
rv = der::End(input);
|
||||
if (rv != Success) {
|
||||
return MapBadDERToMalformedOCSPResponse(rv);
|
||||
@ -446,7 +437,7 @@ BasicResponse(Input& input, Context& context)
|
||||
|
||||
// sequence of certificates
|
||||
while (!certsSequence.AtEnd()) {
|
||||
SECItem cert;
|
||||
InputBuffer cert;
|
||||
rv = der::ExpectTagAndGetTLV(certsSequence, der::SEQUENCE, cert);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
@ -485,7 +476,7 @@ ResponseData(Input& input, Context& context,
|
||||
// ResponderID ::= CHOICE {
|
||||
// byName [1] Name,
|
||||
// byKey [2] KeyHash }
|
||||
SECItem responderID;
|
||||
InputBuffer responderID;
|
||||
ResponderIDType responderIDType
|
||||
= input.Peek(static_cast<uint8_t>(ResponderIDType::byName))
|
||||
? ResponderIDType::byName
|
||||
@ -684,25 +675,25 @@ CertID(Input& input, const Context& context, /*out*/ bool& match)
|
||||
return rv;
|
||||
}
|
||||
|
||||
SECItem issuerNameHash;
|
||||
InputBuffer issuerNameHash;
|
||||
rv = der::ExpectTagAndGetValue(input, der::OCTET_STRING, issuerNameHash);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
SECItem issuerKeyHash;
|
||||
InputBuffer issuerKeyHash;
|
||||
rv = der::ExpectTagAndGetValue(input, der::OCTET_STRING, issuerKeyHash);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
SECItem serialNumber;
|
||||
InputBuffer serialNumber;
|
||||
rv = der::CertificateSerialNumber(input, serialNumber);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
if (!SECITEM_ItemsAreEqual(&serialNumber, &context.certID.serialNumber)) {
|
||||
if (!InputBuffersAreEqual(serialNumber, context.certID.serialNumber)) {
|
||||
// This does not reference the certificate we're interested in.
|
||||
// Consume the rest of the input and return successfully to
|
||||
// potentially continue processing other responses.
|
||||
@ -718,7 +709,7 @@ CertID(Input& input, const Context& context, /*out*/ bool& match)
|
||||
return Success;
|
||||
}
|
||||
|
||||
if (issuerNameHash.len != TrustDomain::DIGEST_LENGTH) {
|
||||
if (issuerNameHash.GetLength() != TrustDomain::DIGEST_LENGTH) {
|
||||
return Result::ERROR_OCSP_MALFORMED_RESPONSE;
|
||||
}
|
||||
|
||||
@ -731,7 +722,8 @@ CertID(Input& input, const Context& context, /*out*/ bool& match)
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
if (memcmp(hashBuf, issuerNameHash.data, issuerNameHash.len)) {
|
||||
InputBuffer computed(hashBuf);
|
||||
if (!InputBuffersAreEqual(computed, issuerNameHash)) {
|
||||
// Again, not interested in this response. Consume input, return success.
|
||||
input.SkipToEnd();
|
||||
return Success;
|
||||
@ -752,10 +744,10 @@ CertID(Input& input, const Context& context, /*out*/ bool& match)
|
||||
// -- the tag, length, and number of unused
|
||||
// -- bits] in the responder's certificate)
|
||||
static Result
|
||||
MatchKeyHash(TrustDomain& trustDomain, const SECItem& keyHash,
|
||||
const SECItem& subjectPublicKeyInfo, /*out*/ bool& match)
|
||||
MatchKeyHash(TrustDomain& trustDomain, InputBuffer keyHash,
|
||||
const InputBuffer subjectPublicKeyInfo, /*out*/ bool& match)
|
||||
{
|
||||
if (keyHash.len != TrustDomain::DIGEST_LENGTH) {
|
||||
if (keyHash.GetLength() != TrustDomain::DIGEST_LENGTH) {
|
||||
return Result::ERROR_OCSP_MALFORMED_RESPONSE;
|
||||
}
|
||||
static uint8_t hashBuf[TrustDomain::DIGEST_LENGTH];
|
||||
@ -764,13 +756,14 @@ MatchKeyHash(TrustDomain& trustDomain, const SECItem& keyHash,
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
match = !memcmp(hashBuf, keyHash.data, keyHash.len);
|
||||
InputBuffer computed(hashBuf);
|
||||
match = InputBuffersAreEqual(computed, keyHash);
|
||||
return Success;
|
||||
}
|
||||
|
||||
// TODO(bug 966856): support SHA-2 hashes
|
||||
Result
|
||||
KeyHash(TrustDomain& trustDomain, const SECItem& subjectPublicKeyInfo,
|
||||
KeyHash(TrustDomain& trustDomain, const InputBuffer subjectPublicKeyInfo,
|
||||
/*out*/ uint8_t* hashBuf, size_t hashBufSize)
|
||||
{
|
||||
if (!hashBuf || hashBufSize != TrustDomain::DIGEST_LENGTH) {
|
||||
@ -789,11 +782,7 @@ KeyHash(TrustDomain& trustDomain, const SECItem& subjectPublicKeyInfo,
|
||||
{
|
||||
// The scope of input is limited to reduce the possibility of confusing it
|
||||
// with spki in places we need to be using spki below.
|
||||
Input input;
|
||||
rv = input.Init(subjectPublicKeyInfo.data, subjectPublicKeyInfo.len);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
Input input(subjectPublicKeyInfo);
|
||||
rv = der::ExpectTagAndGetValue(input, der::SEQUENCE, spki);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
@ -810,29 +799,21 @@ KeyHash(TrustDomain& trustDomain, const SECItem& subjectPublicKeyInfo,
|
||||
return rv;
|
||||
}
|
||||
|
||||
SECItem subjectPublicKey;
|
||||
rv = der::ExpectTagAndGetValue(spki, der::BIT_STRING, subjectPublicKey);
|
||||
InputBuffer subjectPublicKey;
|
||||
rv = der::BitStringWithNoUnusedBits(spki, subjectPublicKey);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
rv = der::End(spki);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// Assume/require that the number of unused bits in the public key is zero.
|
||||
if (subjectPublicKey.len == 0 || subjectPublicKey.data[0] != 0) {
|
||||
return Result::ERROR_BAD_DER;
|
||||
}
|
||||
++subjectPublicKey.data;
|
||||
--subjectPublicKey.len;
|
||||
|
||||
return trustDomain.DigestBuf(subjectPublicKey, hashBuf, hashBufSize);
|
||||
}
|
||||
|
||||
Result
|
||||
ExtensionNotUnderstood(Input& /*extnID*/, const SECItem& /*extnValue*/,
|
||||
ExtensionNotUnderstood(Input& /*extnID*/, InputBuffer /*extnValue*/,
|
||||
/*out*/ bool& understood)
|
||||
{
|
||||
understood = false;
|
||||
@ -909,12 +890,12 @@ CreateEncodedOCSPRequest(TrustDomain& trustDomain, const struct CertID& certID,
|
||||
// in a single byte.
|
||||
static_assert(totalLenWithoutSerialNumberData < OCSP_REQUEST_MAX_LENGTH,
|
||||
"totalLenWithoutSerialNumberData too big");
|
||||
if (certID.serialNumber.len >
|
||||
if (certID.serialNumber.GetLength() >
|
||||
OCSP_REQUEST_MAX_LENGTH - totalLenWithoutSerialNumberData) {
|
||||
return Result::ERROR_BAD_DER;
|
||||
}
|
||||
|
||||
outLen = totalLenWithoutSerialNumberData + certID.serialNumber.len;
|
||||
outLen = totalLenWithoutSerialNumberData + certID.serialNumber.GetLength();
|
||||
|
||||
uint8_t totalLen = static_cast<uint8_t>(outLen);
|
||||
|
||||
@ -950,10 +931,15 @@ CreateEncodedOCSPRequest(TrustDomain& trustDomain, const struct CertID& certID,
|
||||
|
||||
// reqCert.serialNumber (INTEGER)
|
||||
*d++ = 0x02; // INTEGER
|
||||
*d++ = static_cast<uint8_t>(certID.serialNumber.len);
|
||||
for (size_t i = 0; i < certID.serialNumber.len; ++i) {
|
||||
*d++ = certID.serialNumber.data[i];
|
||||
}
|
||||
*d++ = static_cast<uint8_t>(certID.serialNumber.GetLength());
|
||||
Input serialNumber(certID.serialNumber);
|
||||
do {
|
||||
rv = serialNumber.Read(*d);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
++d;
|
||||
} while (!serialNumber.AtEnd());
|
||||
|
||||
PR_ASSERT(d == out + totalLen);
|
||||
|
||||
|
@ -42,7 +42,7 @@ class BackCert
|
||||
{
|
||||
public:
|
||||
// certDER and childCert must be valid for the lifetime of BackCert.
|
||||
BackCert(const SECItem& certDER, EndEntityOrCA endEntityOrCA,
|
||||
BackCert(InputBuffer certDER, EndEntityOrCA endEntityOrCA,
|
||||
const BackCert* childCert)
|
||||
: der(certDER)
|
||||
, endEntityOrCA(endEntityOrCA)
|
||||
@ -52,45 +52,51 @@ public:
|
||||
|
||||
Result Init();
|
||||
|
||||
const SECItem& GetDER() const { return der; }
|
||||
const InputBuffer GetDER() const { return der; }
|
||||
const der::Version GetVersion() const { return version; }
|
||||
const SignedDataWithSignature& GetSignedData() const { return signedData; }
|
||||
const SECItem& GetIssuer() const { return issuer; }
|
||||
const InputBuffer GetIssuer() const { return issuer; }
|
||||
// XXX: "validity" is a horrible name for the structure that holds
|
||||
// notBefore & notAfter, but that is the name used in RFC 5280 and we use the
|
||||
// RFC 5280 names for everything.
|
||||
const SECItem& GetValidity() const { return validity; }
|
||||
const SECItem& GetSerialNumber() const { return serialNumber; }
|
||||
const SECItem& GetSubject() const { return subject; }
|
||||
const SECItem& GetSubjectPublicKeyInfo() const
|
||||
const InputBuffer GetValidity() const { return validity; }
|
||||
const InputBuffer GetSerialNumber() const { return serialNumber; }
|
||||
const InputBuffer GetSubject() const { return subject; }
|
||||
const InputBuffer GetSubjectPublicKeyInfo() const
|
||||
{
|
||||
return subjectPublicKeyInfo;
|
||||
}
|
||||
const SECItem* GetAuthorityInfoAccess() const
|
||||
const InputBuffer* GetAuthorityInfoAccess() const
|
||||
{
|
||||
return MaybeSECItem(authorityInfoAccess);
|
||||
return MaybeInputBuffer(authorityInfoAccess);
|
||||
}
|
||||
const SECItem* GetBasicConstraints() const
|
||||
const InputBuffer* GetBasicConstraints() const
|
||||
{
|
||||
return MaybeSECItem(basicConstraints);
|
||||
return MaybeInputBuffer(basicConstraints);
|
||||
}
|
||||
const SECItem* GetCertificatePolicies() const
|
||||
const InputBuffer* GetCertificatePolicies() const
|
||||
{
|
||||
return MaybeSECItem(certificatePolicies);
|
||||
return MaybeInputBuffer(certificatePolicies);
|
||||
}
|
||||
const SECItem* GetExtKeyUsage() const { return MaybeSECItem(extKeyUsage); }
|
||||
const SECItem* GetKeyUsage() const { return MaybeSECItem(keyUsage); }
|
||||
const SECItem* GetInhibitAnyPolicy() const
|
||||
const InputBuffer* GetExtKeyUsage() const
|
||||
{
|
||||
return MaybeSECItem(inhibitAnyPolicy);
|
||||
return MaybeInputBuffer(extKeyUsage);
|
||||
}
|
||||
const SECItem* GetNameConstraints() const
|
||||
const InputBuffer* GetKeyUsage() const
|
||||
{
|
||||
return MaybeSECItem(nameConstraints);
|
||||
return MaybeInputBuffer(keyUsage);
|
||||
}
|
||||
const InputBuffer* GetInhibitAnyPolicy() const
|
||||
{
|
||||
return MaybeInputBuffer(inhibitAnyPolicy);
|
||||
}
|
||||
const InputBuffer* GetNameConstraints() const
|
||||
{
|
||||
return MaybeInputBuffer(nameConstraints);
|
||||
}
|
||||
|
||||
private:
|
||||
const SECItem& der;
|
||||
const InputBuffer der;
|
||||
|
||||
public:
|
||||
const EndEntityOrCA endEntityOrCA;
|
||||
@ -105,43 +111,32 @@ private:
|
||||
// *processing* extensions, we distinguish between whether an extension was
|
||||
// included or not based on whetehr the GetXXX function for the extension
|
||||
// returns nullptr.
|
||||
static inline const SECItem* MaybeSECItem(const SECItem& item)
|
||||
static inline const InputBuffer* MaybeInputBuffer(const InputBuffer& item)
|
||||
{
|
||||
return item.len > 0 ? &item : nullptr;
|
||||
return item.GetLength() > 0 ? &item : nullptr;
|
||||
}
|
||||
|
||||
// Helper classes to zero-initialize these fields on construction and to
|
||||
// document that they contain non-owning pointers to the data they point
|
||||
// to.
|
||||
struct NonOwningSECItem : public SECItemStr {
|
||||
NonOwningSECItem()
|
||||
{
|
||||
data = nullptr;
|
||||
len = 0;
|
||||
}
|
||||
};
|
||||
|
||||
SignedDataWithSignature signedData;
|
||||
NonOwningSECItem issuer;
|
||||
InputBuffer issuer;
|
||||
// XXX: "validity" is a horrible name for the structure that holds
|
||||
// notBefore & notAfter, but that is the name used in RFC 5280 and we use the
|
||||
// RFC 5280 names for everything.
|
||||
NonOwningSECItem validity;
|
||||
NonOwningSECItem serialNumber;
|
||||
NonOwningSECItem subject;
|
||||
NonOwningSECItem subjectPublicKeyInfo;
|
||||
InputBuffer validity;
|
||||
InputBuffer serialNumber;
|
||||
InputBuffer subject;
|
||||
InputBuffer subjectPublicKeyInfo;
|
||||
|
||||
NonOwningSECItem authorityInfoAccess;
|
||||
NonOwningSECItem basicConstraints;
|
||||
NonOwningSECItem certificatePolicies;
|
||||
NonOwningSECItem extKeyUsage;
|
||||
NonOwningSECItem inhibitAnyPolicy;
|
||||
NonOwningSECItem keyUsage;
|
||||
NonOwningSECItem nameConstraints;
|
||||
NonOwningSECItem subjectAltName;
|
||||
InputBuffer authorityInfoAccess;
|
||||
InputBuffer basicConstraints;
|
||||
InputBuffer certificatePolicies;
|
||||
InputBuffer extKeyUsage;
|
||||
InputBuffer inhibitAnyPolicy;
|
||||
InputBuffer keyUsage;
|
||||
InputBuffer nameConstraints;
|
||||
InputBuffer subjectAltName;
|
||||
|
||||
Result RememberExtension(Input& extnID, const SECItem& extnValue,
|
||||
/*out*/ bool& understood);
|
||||
Result RememberExtension(Input& extnID, const InputBuffer& extnValue,
|
||||
/*out*/ bool& understood);
|
||||
|
||||
BackCert(const BackCert&) /* = delete */;
|
||||
void operator=(const BackCert&); /* = delete */;
|
||||
@ -159,17 +154,20 @@ public:
|
||||
|
||||
virtual size_t GetLength() const { return numItems; }
|
||||
|
||||
virtual const SECItem* GetDER(size_t i) const
|
||||
virtual const InputBuffer* GetDER(size_t i) const
|
||||
{
|
||||
return i < numItems ? &items[i] : nullptr;
|
||||
}
|
||||
|
||||
Result Append(const SECItem& der)
|
||||
Result Append(InputBuffer der)
|
||||
{
|
||||
if (numItems >= MAX_LENGTH) {
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
items[numItems] = der; // structure assignment
|
||||
Result rv = items[numItems].Init(der); // structure assignment
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
++numItems;
|
||||
return Success;
|
||||
}
|
||||
@ -177,7 +175,7 @@ public:
|
||||
// Public so we can static_assert on this. Keep in sync with MAX_SUBCA_COUNT.
|
||||
static const size_t MAX_LENGTH = 8;
|
||||
private:
|
||||
SECItem items[MAX_LENGTH]; // avoids any heap allocations
|
||||
InputBuffer items[MAX_LENGTH]; // avoids any heap allocations
|
||||
size_t numItems;
|
||||
|
||||
NonOwningDERArray(const NonOwningDERArray&) /* = delete*/;
|
||||
|
@ -33,37 +33,30 @@
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
static bool
|
||||
// The result is owned by the arena
|
||||
static InputBuffer
|
||||
CreateCert(PLArenaPool* arena, const char* issuerStr,
|
||||
const char* subjectStr, EndEntityOrCA endEntityOrCA,
|
||||
/*optional*/ SECKEYPrivateKey* issuerKey,
|
||||
/*out*/ ScopedSECKEYPrivateKey& subjectKey,
|
||||
/*out*/ ScopedCERTCertificate& subjectCert)
|
||||
/*out*/ ScopedCERTCertificate* subjectCert = nullptr)
|
||||
{
|
||||
static long serialNumberValue = 0;
|
||||
++serialNumberValue;
|
||||
const SECItem* serialNumber(CreateEncodedSerialNumber(arena,
|
||||
serialNumberValue));
|
||||
if (!serialNumber) {
|
||||
return false;
|
||||
}
|
||||
EXPECT_TRUE(serialNumber);
|
||||
const SECItem* issuerDER(ASCIIToDERName(arena, issuerStr));
|
||||
if (!issuerDER) {
|
||||
return false;
|
||||
}
|
||||
EXPECT_TRUE(issuerDER);
|
||||
const SECItem* subjectDER(ASCIIToDERName(arena, subjectStr));
|
||||
if (!subjectDER) {
|
||||
return false;
|
||||
}
|
||||
EXPECT_TRUE(subjectDER);
|
||||
|
||||
const SECItem* extensions[2] = { nullptr, nullptr };
|
||||
if (endEntityOrCA == EndEntityOrCA::MustBeCA) {
|
||||
extensions[0] =
|
||||
CreateEncodedBasicConstraints(arena, true, nullptr,
|
||||
ExtensionCriticality::Critical);
|
||||
if (!extensions[0]) {
|
||||
return false;
|
||||
}
|
||||
EXPECT_TRUE(extensions[0]);
|
||||
}
|
||||
|
||||
SECItem* certDER(CreateEncodedCertificate(
|
||||
@ -72,12 +65,15 @@ CreateCert(PLArenaPool* arena, const char* issuerStr,
|
||||
PR_Now() - ONE_DAY, PR_Now() + ONE_DAY,
|
||||
subjectDER, extensions, issuerKey, SEC_OID_SHA256,
|
||||
subjectKey));
|
||||
if (!certDER) {
|
||||
return false;
|
||||
EXPECT_TRUE(certDER);
|
||||
if (subjectCert) {
|
||||
*subjectCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certDER,
|
||||
nullptr, false, true);
|
||||
EXPECT_TRUE(*subjectCert);
|
||||
}
|
||||
subjectCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certDER,
|
||||
nullptr, false, true);
|
||||
return subjectCert.get() != nullptr;
|
||||
InputBuffer result;
|
||||
EXPECT_EQ(Success, result.Init(certDER->data, certDER->len));
|
||||
return result;
|
||||
}
|
||||
|
||||
class TestTrustDomain : public TrustDomain
|
||||
@ -104,11 +100,9 @@ public:
|
||||
for (size_t i = 0; i < PR_ARRAY_SIZE(names); ++i) {
|
||||
const char* issuerName = i == 0 ? names[0]
|
||||
: certChainTail[i - 1]->subjectName;
|
||||
if (!CreateCert(arena.get(), issuerName, names[i],
|
||||
EndEntityOrCA::MustBeCA, leafCAKey.get(), leafCAKey,
|
||||
certChainTail[i])) {
|
||||
return false;
|
||||
}
|
||||
(void) CreateCert(arena.get(), issuerName, names[i],
|
||||
EndEntityOrCA::MustBeCA, leafCAKey.get(), leafCAKey,
|
||||
&certChainTail[i]);
|
||||
}
|
||||
|
||||
return true;
|
||||
@ -116,10 +110,14 @@ public:
|
||||
|
||||
private:
|
||||
virtual Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
|
||||
const SECItem& candidateCert,
|
||||
InputBuffer candidateCert,
|
||||
/*out*/ TrustLevel& trustLevel)
|
||||
{
|
||||
if (SECITEM_ItemsAreEqual(&candidateCert, &certChainTail[0]->derCert)) {
|
||||
InputBuffer rootDER;
|
||||
Result rv = rootDER.Init(certChainTail[0]->derCert.data,
|
||||
certChainTail[0]->derCert.len);
|
||||
EXPECT_EQ(Success, rv);
|
||||
if (InputBuffersAreEqual(candidateCert, rootDER)) {
|
||||
trustLevel = TrustLevel::TrustAnchor;
|
||||
} else {
|
||||
trustLevel = TrustLevel::InheritsTrust;
|
||||
@ -127,19 +125,27 @@ private:
|
||||
return Success;
|
||||
}
|
||||
|
||||
virtual Result FindIssuer(const SECItem& encodedIssuerName,
|
||||
virtual Result FindIssuer(InputBuffer encodedIssuerName,
|
||||
IssuerChecker& checker, PRTime time)
|
||||
{
|
||||
SECItem encodedIssuerNameSECItem =
|
||||
UnsafeMapInputBufferToSECItem(encodedIssuerName);
|
||||
ScopedCERTCertList
|
||||
candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
|
||||
&encodedIssuerName, time, true));
|
||||
&encodedIssuerNameSECItem, time,
|
||||
true));
|
||||
if (candidates) {
|
||||
for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
|
||||
!CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
|
||||
bool keepGoing;
|
||||
Result rv = checker.Check(n->cert->derCert,
|
||||
nullptr/*additionalNameConstraints*/,
|
||||
keepGoing);
|
||||
InputBuffer derCert;
|
||||
Result rv = derCert.Init(n->cert->derCert.data, n->cert->derCert.len);
|
||||
EXPECT_EQ(Success, rv);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
rv = checker.Check(derCert, nullptr/*additionalNameConstraints*/,
|
||||
keepGoing);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
@ -153,8 +159,8 @@ private:
|
||||
}
|
||||
|
||||
virtual Result CheckRevocation(EndEntityOrCA, const CertID&, PRTime,
|
||||
/*optional*/ const SECItem*,
|
||||
/*optional*/ const SECItem*)
|
||||
/*optional*/ const InputBuffer*,
|
||||
/*optional*/ const InputBuffer*)
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
@ -165,20 +171,20 @@ private:
|
||||
}
|
||||
|
||||
virtual Result VerifySignedData(const SignedDataWithSignature& signedData,
|
||||
const SECItem& subjectPublicKeyInfo)
|
||||
InputBuffer subjectPublicKeyInfo)
|
||||
{
|
||||
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
virtual Result DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
|
||||
virtual Result DigestBuf(InputBuffer item, /*out*/ uint8_t* digestBuf,
|
||||
size_t digestBufLen)
|
||||
{
|
||||
ADD_FAILURE();
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
}
|
||||
|
||||
virtual Result CheckPublicKey(const SECItem& subjectPublicKeyInfo)
|
||||
virtual Result CheckPublicKey(InputBuffer subjectPublicKeyInfo)
|
||||
{
|
||||
return ::mozilla::pkix::CheckPublicKey(subjectPublicKeyInfo);
|
||||
}
|
||||
@ -216,58 +222,73 @@ protected:
|
||||
|
||||
TEST_F(pkixbuild, MaxAcceptableCertChainLength)
|
||||
{
|
||||
ASSERT_EQ(Success,
|
||||
BuildCertChain(trustDomain, trustDomain.GetLeafCACert()->derCert,
|
||||
now, EndEntityOrCA::MustBeCA,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
{
|
||||
InputBuffer certDER;
|
||||
ASSERT_EQ(Success, certDER.Init(trustDomain.GetLeafCACert()->derCert.data,
|
||||
trustDomain.GetLeafCACert()->derCert.len));
|
||||
ASSERT_EQ(Success,
|
||||
BuildCertChain(trustDomain, certDER, now,
|
||||
EndEntityOrCA::MustBeCA,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
}
|
||||
|
||||
ScopedSECKEYPrivateKey privateKey;
|
||||
ScopedCERTCertificate cert;
|
||||
ASSERT_TRUE(CreateCert(arena.get(),
|
||||
trustDomain.GetLeafCACert()->subjectName,
|
||||
"CN=Direct End-Entity",
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
trustDomain.leafCAKey.get(), privateKey, cert));
|
||||
ASSERT_EQ(Success,
|
||||
BuildCertChain(trustDomain, cert->derCert, now,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
{
|
||||
ScopedSECKEYPrivateKey privateKey;
|
||||
ScopedCERTCertificate cert;
|
||||
InputBuffer certDER(CreateCert(arena.get(),
|
||||
trustDomain.GetLeafCACert()->subjectName,
|
||||
"CN=Direct End-Entity",
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
trustDomain.leafCAKey.get(), privateKey));
|
||||
ASSERT_EQ(Success,
|
||||
BuildCertChain(trustDomain, certDER, now,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_F(pkixbuild, BeyondMaxAcceptableCertChainLength)
|
||||
{
|
||||
static char const* const caCertName = "CN=CA Too Far";
|
||||
ScopedSECKEYPrivateKey caPrivateKey;
|
||||
ScopedCERTCertificate caCert;
|
||||
ASSERT_TRUE(CreateCert(arena.get(),
|
||||
trustDomain.GetLeafCACert()->subjectName,
|
||||
"CN=CA Too Far", EndEntityOrCA::MustBeCA,
|
||||
trustDomain.leafCAKey.get(),
|
||||
caPrivateKey, caCert));
|
||||
ASSERT_EQ(Result::ERROR_UNKNOWN_ISSUER,
|
||||
BuildCertChain(trustDomain, caCert->derCert, now,
|
||||
EndEntityOrCA::MustBeCA,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
|
||||
ScopedSECKEYPrivateKey privateKey;
|
||||
ScopedCERTCertificate cert;
|
||||
ASSERT_TRUE(CreateCert(arena.get(), caCert->subjectName,
|
||||
"CN=End-Entity Too Far",
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
caPrivateKey.get(), privateKey, cert));
|
||||
ASSERT_EQ(Result::ERROR_UNKNOWN_ISSUER,
|
||||
BuildCertChain(trustDomain, cert->derCert, now,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
// We need a CERTCertificate for caCert so that the trustdomain's FindIssuer
|
||||
// method can find it through the NSS cert DB.
|
||||
ScopedCERTCertificate caCert;
|
||||
|
||||
{
|
||||
InputBuffer cert(CreateCert(arena.get(),
|
||||
trustDomain.GetLeafCACert()->subjectName,
|
||||
caCertName, EndEntityOrCA::MustBeCA,
|
||||
trustDomain.leafCAKey.get(), caPrivateKey,
|
||||
&caCert));
|
||||
ASSERT_EQ(Result::ERROR_UNKNOWN_ISSUER,
|
||||
BuildCertChain(trustDomain, cert, now,
|
||||
EndEntityOrCA::MustBeCA,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
}
|
||||
|
||||
{
|
||||
ScopedSECKEYPrivateKey privateKey;
|
||||
InputBuffer cert(CreateCert(arena.get(), caCertName,
|
||||
"CN=End-Entity Too Far",
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
caPrivateKey.get(), privateKey));
|
||||
ASSERT_EQ(Result::ERROR_UNKNOWN_ISSUER,
|
||||
BuildCertChain(trustDomain, cert, now,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr/*stapledOCSPResponse*/));
|
||||
}
|
||||
}
|
||||
|
@ -32,7 +32,7 @@ using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
// Creates a self-signed certificate with the given extension.
|
||||
static const SECItem*
|
||||
static InputBuffer
|
||||
CreateCert(PLArenaPool* arena, const char* subjectStr,
|
||||
SECItem const* const* extensions, // null-terminated array
|
||||
/*out*/ ScopedSECKEYPrivateKey& subjectKey)
|
||||
@ -41,29 +41,27 @@ CreateCert(PLArenaPool* arena, const char* subjectStr,
|
||||
++serialNumberValue;
|
||||
const SECItem* serialNumber(CreateEncodedSerialNumber(arena,
|
||||
serialNumberValue));
|
||||
if (!serialNumber) {
|
||||
return nullptr;
|
||||
}
|
||||
EXPECT_TRUE(serialNumber);
|
||||
const SECItem* issuerDER(ASCIIToDERName(arena, subjectStr));
|
||||
if (!issuerDER) {
|
||||
return nullptr;
|
||||
}
|
||||
EXPECT_TRUE(issuerDER);
|
||||
const SECItem* subjectDER(ASCIIToDERName(arena, subjectStr));
|
||||
if (!subjectDER) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return CreateEncodedCertificate(arena, v3,
|
||||
EXPECT_TRUE(subjectDER);
|
||||
SECItem* cert = CreateEncodedCertificate(
|
||||
arena, v3,
|
||||
SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION,
|
||||
serialNumber, issuerDER,
|
||||
PR_Now() - ONE_DAY,
|
||||
PR_Now() + ONE_DAY,
|
||||
subjectDER, extensions,
|
||||
nullptr, SEC_OID_SHA256, subjectKey);
|
||||
EXPECT_TRUE(cert);
|
||||
InputBuffer result;
|
||||
EXPECT_EQ(Success, result.Init(cert->data, cert->len));
|
||||
return result;
|
||||
}
|
||||
|
||||
// Creates a self-signed certificate with the given extension.
|
||||
static const SECItem*
|
||||
static InputBuffer
|
||||
CreateCert(PLArenaPool* arena, const char* subjectStr,
|
||||
const SECItem* extension,
|
||||
/*out*/ ScopedSECKEYPrivateKey& subjectKey)
|
||||
@ -76,14 +74,14 @@ class TrustEverythingTrustDomain : public TrustDomain
|
||||
{
|
||||
private:
|
||||
virtual Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
|
||||
const SECItem& candidateCert,
|
||||
InputBuffer candidateCert,
|
||||
/*out*/ TrustLevel& trustLevel)
|
||||
{
|
||||
trustLevel = TrustLevel::TrustAnchor;
|
||||
return Success;
|
||||
}
|
||||
|
||||
virtual Result FindIssuer(const SECItem& /*encodedIssuerName*/,
|
||||
virtual Result FindIssuer(InputBuffer /*encodedIssuerName*/,
|
||||
IssuerChecker& /*checker*/, PRTime /*time*/)
|
||||
{
|
||||
ADD_FAILURE();
|
||||
@ -91,8 +89,8 @@ private:
|
||||
}
|
||||
|
||||
virtual Result CheckRevocation(EndEntityOrCA, const CertID&, PRTime,
|
||||
/*optional*/ const SECItem*,
|
||||
/*optional*/ const SECItem*)
|
||||
/*optional*/ const InputBuffer*,
|
||||
/*optional*/ const InputBuffer*)
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
@ -103,19 +101,19 @@ private:
|
||||
}
|
||||
|
||||
virtual Result VerifySignedData(const SignedDataWithSignature& signedData,
|
||||
const SECItem& subjectPublicKeyInfo)
|
||||
InputBuffer subjectPublicKeyInfo)
|
||||
{
|
||||
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
virtual Result DigestBuf(const SECItem&, /*out*/ uint8_t*, size_t)
|
||||
virtual Result DigestBuf(InputBuffer, /*out*/ uint8_t*, size_t)
|
||||
{
|
||||
ADD_FAILURE();
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
}
|
||||
|
||||
virtual Result CheckPublicKey(const SECItem& subjectPublicKeyInfo)
|
||||
virtual Result CheckPublicKey(InputBuffer subjectPublicKeyInfo)
|
||||
{
|
||||
return ::mozilla::pkix::CheckPublicKey(subjectPublicKeyInfo);
|
||||
}
|
||||
@ -157,11 +155,10 @@ TEST_F(pkixcert_extension, UnknownCriticalExtension)
|
||||
const char* certCN = "CN=Cert With Unknown Critical Extension";
|
||||
ScopedSECKEYPrivateKey key;
|
||||
// cert is owned by the arena
|
||||
const SECItem* cert(CreateCert(arena.get(), certCN,
|
||||
&unknownCriticalExtension, key));
|
||||
ASSERT_TRUE(cert);
|
||||
InputBuffer cert(CreateCert(arena.get(), certCN,
|
||||
&unknownCriticalExtension, key));
|
||||
ASSERT_EQ(Result::ERROR_UNKNOWN_CRITICAL_EXTENSION,
|
||||
BuildCertChain(trustDomain, *cert, now,
|
||||
BuildCertChain(trustDomain, cert, now,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
@ -189,11 +186,10 @@ TEST_F(pkixcert_extension, UnknownNonCriticalExtension)
|
||||
const char* certCN = "CN=Cert With Unknown NonCritical Extension";
|
||||
ScopedSECKEYPrivateKey key;
|
||||
// cert is owned by the arena
|
||||
const SECItem* cert(CreateCert(arena.get(), certCN,
|
||||
&unknownNonCriticalExtension, key));
|
||||
ASSERT_TRUE(cert);
|
||||
InputBuffer cert(CreateCert(arena.get(), certCN,
|
||||
&unknownNonCriticalExtension, key));
|
||||
ASSERT_EQ(Success,
|
||||
BuildCertChain(trustDomain, *cert, now,
|
||||
BuildCertChain(trustDomain, cert, now,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
@ -222,11 +218,10 @@ TEST_F(pkixcert_extension, WrongOIDCriticalExtension)
|
||||
const char* certCN = "CN=Cert With Critical Wrong OID Extension";
|
||||
ScopedSECKEYPrivateKey key;
|
||||
// cert is owned by the arena
|
||||
const SECItem* cert(CreateCert(arena.get(), certCN,
|
||||
&wrongOIDCriticalExtension, key));
|
||||
ASSERT_TRUE(cert);
|
||||
InputBuffer cert(CreateCert(arena.get(), certCN,
|
||||
&wrongOIDCriticalExtension, key));
|
||||
ASSERT_EQ(Result::ERROR_UNKNOWN_CRITICAL_EXTENSION,
|
||||
BuildCertChain(trustDomain, *cert, now,
|
||||
BuildCertChain(trustDomain, cert, now,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
@ -257,11 +252,9 @@ TEST_F(pkixcert_extension, CriticalAIAExtension)
|
||||
const char* certCN = "CN=Cert With Critical AIA Extension";
|
||||
ScopedSECKEYPrivateKey key;
|
||||
// cert is owned by the arena
|
||||
const SECItem* cert(CreateCert(arena.get(), certCN, &criticalAIAExtension,
|
||||
key));
|
||||
ASSERT_TRUE(cert);
|
||||
InputBuffer cert(CreateCert(arena.get(), certCN, &criticalAIAExtension, key));
|
||||
ASSERT_EQ(Success,
|
||||
BuildCertChain(trustDomain, *cert, now,
|
||||
BuildCertChain(trustDomain, cert, now,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
@ -289,11 +282,10 @@ TEST_F(pkixcert_extension, UnknownCriticalCEExtension)
|
||||
const char* certCN = "CN=Cert With Unknown Critical id-ce Extension";
|
||||
ScopedSECKEYPrivateKey key;
|
||||
// cert is owned by the arena
|
||||
const SECItem* cert(CreateCert(arena.get(), certCN,
|
||||
&unknownCriticalCEExtension, key));
|
||||
ASSERT_TRUE(cert);
|
||||
InputBuffer cert(CreateCert(arena.get(), certCN,
|
||||
&unknownCriticalCEExtension, key));
|
||||
ASSERT_EQ(Result::ERROR_UNKNOWN_CRITICAL_EXTENSION,
|
||||
BuildCertChain(trustDomain, *cert, now,
|
||||
BuildCertChain(trustDomain, cert, now,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
@ -321,11 +313,9 @@ TEST_F(pkixcert_extension, KnownCriticalCEExtension)
|
||||
const char* certCN = "CN=Cert With Known Critical id-ce Extension";
|
||||
ScopedSECKEYPrivateKey key;
|
||||
// cert is owned by the arena
|
||||
const SECItem* cert(CreateCert(arena.get(), certCN, &criticalCEExtension,
|
||||
key));
|
||||
ASSERT_TRUE(cert);
|
||||
InputBuffer cert(CreateCert(arena.get(), certCN, &criticalCEExtension, key));
|
||||
ASSERT_EQ(Success,
|
||||
BuildCertChain(trustDomain, *cert, now,
|
||||
BuildCertChain(trustDomain, cert, now,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
@ -354,10 +344,9 @@ TEST_F(pkixcert_extension, DuplicateSubjectAltName)
|
||||
static const char* certCN = "CN=Cert With Duplicate subjectAltName";
|
||||
ScopedSECKEYPrivateKey key;
|
||||
// cert is owned by the arena
|
||||
const SECItem* cert(CreateCert(arena.get(), certCN, extensions, key));
|
||||
ASSERT_TRUE(cert);
|
||||
InputBuffer cert(CreateCert(arena.get(), certCN, extensions, key));
|
||||
ASSERT_EQ(Result::ERROR_EXTENSION_VALUE_INVALID,
|
||||
BuildCertChain(trustDomain, *cert, now,
|
||||
BuildCertChain(trustDomain, cert, now,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
|
@ -24,13 +24,15 @@
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "pkix/pkixtypes.h"
|
||||
#include "pkixtestutil.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
|
||||
extern Result CheckKeyUsage(EndEntityOrCA endEntityOrCA,
|
||||
const SECItem* encodedKeyUsage,
|
||||
const InputBuffer* encodedKeyUsage,
|
||||
KeyUsage requiredKeyUsageIfPresent);
|
||||
|
||||
} } // namespace mozilla::pkix
|
||||
@ -44,22 +46,16 @@ class pkixcheck_CheckKeyUsage : public ::testing::Test { };
|
||||
const uint8_t name##_bytes[4] = { \
|
||||
0x03/*BIT STRING*/, 0x02/*LENGTH=2*/, unusedBits, bits \
|
||||
}; \
|
||||
const SECItem name = { \
|
||||
siBuffer, \
|
||||
const_cast<uint8_t*>(name##_bytes), \
|
||||
4 \
|
||||
}
|
||||
const InputBuffer name(name##_bytes);
|
||||
|
||||
static uint8_t dummy;
|
||||
static const SECItem empty_null = { siBuffer, nullptr, 0 };
|
||||
static const SECItem empty_nonnull = { siBuffer, &dummy, 0 };
|
||||
static const InputBuffer empty_null;
|
||||
|
||||
// Note that keyCertSign is really the only interesting case for CA
|
||||
// certificates since we don't support cRLSign.
|
||||
|
||||
TEST_F(pkixcheck_CheckKeyUsage, EE_none)
|
||||
{
|
||||
// The input SECItem is nullptr. This means the cert had no keyUsage
|
||||
// The input InputBuffer is nullptr. This means the cert had no keyUsage
|
||||
// extension. This is always valid because no key usage in an end-entity
|
||||
// means that there are no key usage restrictions.
|
||||
|
||||
@ -79,10 +75,13 @@ TEST_F(pkixcheck_CheckKeyUsage, EE_none)
|
||||
|
||||
TEST_F(pkixcheck_CheckKeyUsage, EE_empty)
|
||||
{
|
||||
// The input SECItem is empty. The cert had an empty keyUsage extension,
|
||||
// The input InputBuffer is empty. The cert had an empty keyUsage extension,
|
||||
// which is syntactically invalid.
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &empty_null,
|
||||
KeyUsage::digitalSignature));
|
||||
static const uint8_t dummy = 0x00;
|
||||
InputBuffer empty_nonnull;
|
||||
ASSERT_EQ(Success, empty_nonnull.Init(&dummy, 0));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &empty_nonnull,
|
||||
KeyUsage::digitalSignature));
|
||||
}
|
||||
@ -99,6 +98,9 @@ TEST_F(pkixcheck_CheckKeyUsage, CA_empty)
|
||||
// A CA certificate has an empty KU extension.
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &empty_null,
|
||||
KeyUsage::keyCertSign));
|
||||
static const uint8_t dummy = 0x00;
|
||||
InputBuffer empty_nonnull;
|
||||
ASSERT_EQ(Success, empty_nonnull.Init(&dummy, 0));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &empty_nonnull,
|
||||
KeyUsage::keyCertSign));
|
||||
}
|
||||
@ -115,22 +117,14 @@ TEST_F(pkixcheck_CheckKeyUsage, tooManyUnusedBits)
|
||||
static uint8_t oneValueByteData[] = {
|
||||
0x03/*BIT STRING*/, 0x02/*LENGTH=2*/, 8/*unused bits*/, 0x80
|
||||
};
|
||||
const SECItem oneValueByte = {
|
||||
siBuffer,
|
||||
oneValueByteData,
|
||||
sizeof(oneValueByteData)
|
||||
};
|
||||
static const InputBuffer oneValueByte(oneValueByteData);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &oneValueByte,
|
||||
KeyUsage::digitalSignature));
|
||||
|
||||
static uint8_t twoValueBytesData[] = {
|
||||
0x03/*BIT STRING*/, 0x03/*LENGTH=3*/, 8/*unused bits*/, 0x01, 0x00
|
||||
};
|
||||
const SECItem twoValueBytes = {
|
||||
siBuffer,
|
||||
twoValueBytesData,
|
||||
sizeof(twoValueBytesData)
|
||||
};
|
||||
static const InputBuffer twoValueBytes(twoValueBytesData);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &twoValueBytes,
|
||||
KeyUsage::digitalSignature));
|
||||
}
|
||||
@ -140,12 +134,7 @@ TEST_F(pkixcheck_CheckKeyUsage, NoValueBytes_NoPaddingBits)
|
||||
static const uint8_t DER_BYTES[] = {
|
||||
0x03/*BIT STRING*/, 0x01/*LENGTH=1*/, 0/*unused bits*/
|
||||
};
|
||||
static const SECItem DER = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(DER_BYTES),
|
||||
sizeof(DER_BYTES)
|
||||
};
|
||||
|
||||
static const InputBuffer DER(DER_BYTES);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &DER,
|
||||
KeyUsage::digitalSignature));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &DER,
|
||||
@ -157,12 +146,7 @@ TEST_F(pkixcheck_CheckKeyUsage, NoValueBytes_7PaddingBits)
|
||||
static const uint8_t DER_BYTES[] = {
|
||||
0x03/*BIT STRING*/, 0x01/*LENGTH=1*/, 7/*unused bits*/
|
||||
};
|
||||
static const SECItem DER = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(DER_BYTES),
|
||||
sizeof(DER_BYTES)
|
||||
};
|
||||
|
||||
static const InputBuffer DER(DER_BYTES);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &DER,
|
||||
KeyUsage::digitalSignature));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &DER,
|
||||
@ -191,14 +175,12 @@ void ASSERT_SimpleCase(uint8_t unusedBits, uint8_t bits, KeyUsage usage)
|
||||
|
||||
// Test that none of the other non-padding bits are mistaken for the given
|
||||
// key usage in the two-byte value case.
|
||||
uint8_t twoByteNotGoodData[] = {
|
||||
const uint8_t twoByteNotGoodData[] = {
|
||||
0x03/*BIT STRING*/, 0x03/*LENGTH=3*/, unusedBits,
|
||||
static_cast<uint8_t>(~bits),
|
||||
static_cast<uint8_t>((0xFFu >> unusedBits) << unusedBits)
|
||||
};
|
||||
const SECItem twoByteNotGood = {
|
||||
siBuffer, twoByteNotGoodData, sizeof(twoByteNotGoodData)
|
||||
};
|
||||
InputBuffer twoByteNotGood(twoByteNotGoodData);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &twoByteNotGood,
|
||||
usage));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &twoByteNotGood, usage));
|
||||
@ -235,9 +217,7 @@ TEST_F(pkixcheck_CheckKeyUsage, keyCertSign)
|
||||
static uint8_t twoByteNotGoodData[] = {
|
||||
0x03/*BIT STRING*/, 0x03/*LENGTH=3*/, 2/*unused bits*/, 0xFBu, 0xFCu
|
||||
};
|
||||
static const SECItem twoByteNotGood = {
|
||||
siBuffer, twoByteNotGoodData, sizeof(twoByteNotGoodData)
|
||||
};
|
||||
static const InputBuffer twoByteNotGood(twoByteNotGoodData);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &twoByteNotGood,
|
||||
KeyUsage::keyCertSign));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &twoByteNotGood,
|
||||
@ -250,11 +230,7 @@ TEST_F(pkixcheck_CheckKeyUsage, unusedBitNotZero)
|
||||
static uint8_t controlOneValueByteData[] = {
|
||||
0x03/*BIT STRING*/, 0x02/*LENGTH=2*/, 7/*unused bits*/, 0x80
|
||||
};
|
||||
const SECItem controlOneValueByte = {
|
||||
siBuffer,
|
||||
controlOneValueByteData,
|
||||
sizeof(controlOneValueByteData)
|
||||
};
|
||||
static const InputBuffer controlOneValueByte(controlOneValueByteData);
|
||||
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity,
|
||||
&controlOneValueByte,
|
||||
KeyUsage::digitalSignature));
|
||||
@ -266,11 +242,7 @@ TEST_F(pkixcheck_CheckKeyUsage, unusedBitNotZero)
|
||||
static uint8_t oneValueByteData[] = {
|
||||
0x03/*BIT STRING*/, 0x02/*LENGTH=2*/, 7/*unused bits*/, 0x80 | 0x01
|
||||
};
|
||||
const SECItem oneValueByte = {
|
||||
siBuffer,
|
||||
oneValueByteData,
|
||||
sizeof(oneValueByteData)
|
||||
};
|
||||
static const InputBuffer oneValueByte(oneValueByteData);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &oneValueByte,
|
||||
KeyUsage::digitalSignature));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &oneValueByte,
|
||||
@ -281,11 +253,7 @@ TEST_F(pkixcheck_CheckKeyUsage, unusedBitNotZero)
|
||||
0x03/*BIT STRING*/, 0x03/*LENGTH=3*/, 7/*unused bits*/,
|
||||
0x80 | 0x01, 0x80
|
||||
};
|
||||
const SECItem controlTwoValueBytes = {
|
||||
siBuffer,
|
||||
controlTwoValueBytesData,
|
||||
sizeof(controlTwoValueBytesData)
|
||||
};
|
||||
static const InputBuffer controlTwoValueBytes(controlTwoValueBytesData);
|
||||
ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity,
|
||||
&controlTwoValueBytes,
|
||||
KeyUsage::digitalSignature));
|
||||
@ -298,11 +266,7 @@ TEST_F(pkixcheck_CheckKeyUsage, unusedBitNotZero)
|
||||
0x03/*BIT STRING*/, 0x03/*LENGTH=3*/, 7/*unused bits*/,
|
||||
0x80 | 0x01, 0x80 | 0x01
|
||||
};
|
||||
const SECItem twoValueBytes = {
|
||||
siBuffer,
|
||||
twoValueBytesData,
|
||||
sizeof(twoValueBytesData)
|
||||
};
|
||||
static const InputBuffer twoValueBytes(twoValueBytesData);
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &twoValueBytes,
|
||||
KeyUsage::digitalSignature));
|
||||
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &twoValueBytes,
|
||||
|
@ -31,7 +31,7 @@ using namespace mozilla::pkix::test;
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
|
||||
Result CheckValidity(const SECItem& encodedValidity, PRTime time);
|
||||
Result CheckValidity(const InputBuffer encodedValidity, PRTime time);
|
||||
|
||||
} } // namespace mozilla::pkix
|
||||
|
||||
@ -69,11 +69,7 @@ TEST_F(pkixcheck_CheckValidity, BothEmptyNull)
|
||||
0x17/*UTCTime*/, 0/*length*/,
|
||||
0x17/*UTCTime*/, 0/*length*/,
|
||||
};
|
||||
static const SECItem validity = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(DER),
|
||||
sizeof(DER)
|
||||
};
|
||||
static const InputBuffer validity(DER);
|
||||
ASSERT_EQ(Result::ERROR_EXPIRED_CERTIFICATE, CheckValidity(validity, NOW));
|
||||
}
|
||||
|
||||
@ -83,11 +79,7 @@ TEST_F(pkixcheck_CheckValidity, NotBeforeEmptyNull)
|
||||
0x17/*UTCTime*/, 0x00/*length*/,
|
||||
NEWER_UTCTIME
|
||||
};
|
||||
static const SECItem validity = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(DER),
|
||||
sizeof(DER)
|
||||
};
|
||||
static const InputBuffer validity(DER);
|
||||
ASSERT_EQ(Result::ERROR_EXPIRED_CERTIFICATE, CheckValidity(validity, NOW));
|
||||
}
|
||||
|
||||
@ -97,11 +89,7 @@ TEST_F(pkixcheck_CheckValidity, NotAfterEmptyNull)
|
||||
NEWER_UTCTIME,
|
||||
0x17/*UTCTime*/, 0x00/*length*/,
|
||||
};
|
||||
static const SECItem validity = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(DER),
|
||||
sizeof(DER)
|
||||
};
|
||||
static const InputBuffer validity(DER);
|
||||
ASSERT_EQ(Result::ERROR_EXPIRED_CERTIFICATE, CheckValidity(validity, NOW));
|
||||
}
|
||||
|
||||
@ -109,11 +97,8 @@ static const uint8_t OLDER_UTCTIME_NEWER_UTCTIME_DATA[] = {
|
||||
OLDER_UTCTIME,
|
||||
NEWER_UTCTIME,
|
||||
};
|
||||
static const SECItem OLDER_UTCTIME_NEWER_UTCTIME = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(OLDER_UTCTIME_NEWER_UTCTIME_DATA),
|
||||
sizeof(OLDER_UTCTIME_NEWER_UTCTIME_DATA)
|
||||
};
|
||||
static const InputBuffer
|
||||
OLDER_UTCTIME_NEWER_UTCTIME(OLDER_UTCTIME_NEWER_UTCTIME_DATA);
|
||||
|
||||
TEST_F(pkixcheck_CheckValidity, Valid_UTCTIME_UTCTIME)
|
||||
{
|
||||
@ -126,11 +111,7 @@ TEST_F(pkixcheck_CheckValidity, Valid_GENERALIZEDTIME_GENERALIZEDTIME)
|
||||
OLDER_GENERALIZEDTIME,
|
||||
NEWER_GENERALIZEDTIME,
|
||||
};
|
||||
static const SECItem validity = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(DER),
|
||||
sizeof(DER)
|
||||
};
|
||||
static const InputBuffer validity(DER);
|
||||
ASSERT_EQ(Success, CheckValidity(validity, NOW));
|
||||
}
|
||||
|
||||
@ -140,11 +121,7 @@ TEST_F(pkixcheck_CheckValidity, Valid_GENERALIZEDTIME_UTCTIME)
|
||||
OLDER_GENERALIZEDTIME,
|
||||
NEWER_UTCTIME,
|
||||
};
|
||||
static const SECItem validity = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(DER),
|
||||
sizeof(DER)
|
||||
};
|
||||
static const InputBuffer validity(DER);
|
||||
ASSERT_EQ(Success, CheckValidity(validity, NOW));
|
||||
}
|
||||
|
||||
@ -154,11 +131,7 @@ TEST_F(pkixcheck_CheckValidity, Valid_UTCTIME_GENERALIZEDTIME)
|
||||
OLDER_UTCTIME,
|
||||
NEWER_GENERALIZEDTIME,
|
||||
};
|
||||
static const SECItem validity = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(DER),
|
||||
sizeof(DER)
|
||||
};
|
||||
static const InputBuffer validity(DER);
|
||||
ASSERT_EQ(Success, CheckValidity(validity, NOW));
|
||||
}
|
||||
|
||||
@ -180,10 +153,6 @@ TEST_F(pkixcheck_CheckValidity, InvalidNotAfterBeforeNotBefore)
|
||||
NEWER_UTCTIME,
|
||||
OLDER_UTCTIME,
|
||||
};
|
||||
static const SECItem validity = {
|
||||
siBuffer,
|
||||
const_cast<uint8_t*>(DER),
|
||||
sizeof(DER)
|
||||
};
|
||||
static const InputBuffer validity(DER);
|
||||
ASSERT_EQ(Result::ERROR_EXPIRED_CERTIFICATE, CheckValidity(validity, NOW));
|
||||
}
|
||||
|
@ -86,96 +86,64 @@ const uint8_t DER_INT16[] = {
|
||||
0x12, 0x34 // 0x1234
|
||||
};
|
||||
|
||||
TEST_F(pkixder_input_tests, InputInit)
|
||||
TEST_F(pkixder_input_tests, InputBufferInit)
|
||||
{
|
||||
Input input;
|
||||
InputBuffer buf;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
|
||||
buf.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, InputInitWithNullPointerOrZeroLength)
|
||||
TEST_F(pkixder_input_tests, InputBufferInitWithNullPointerOrZeroLength)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Init(nullptr, 0));
|
||||
InputBuffer buf;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, buf.Init(nullptr, 0));
|
||||
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Init(nullptr, 100));
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, buf.Init(nullptr, 100));
|
||||
|
||||
// Though it seems odd to initialize with zero-length and non-null ptr, this
|
||||
// is working as intended. The Input class was intended to protect against
|
||||
// buffer overflows, and there's no risk with the current behavior. See bug
|
||||
// 1000354.
|
||||
ASSERT_EQ(Success, input.Init((const uint8_t*) "hello", 0));
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
ASSERT_EQ(Success, buf.Init((const uint8_t*) "hello", 0));
|
||||
ASSERT_TRUE(buf.GetLength() == 0);
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, InputInitWithLargeData)
|
||||
TEST_F(pkixder_input_tests, InputBufferInitWithLargeData)
|
||||
{
|
||||
Input input;
|
||||
InputBuffer buf;
|
||||
// Data argument length does not matter, it is not touched, just
|
||||
// needs to be non-null
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Init((const uint8_t*) "", 0xffff+1));
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, buf.Init((const uint8_t*) "", 0xffff+1));
|
||||
|
||||
ASSERT_EQ(Success, input.Init((const uint8_t*) "", 0xffff));
|
||||
ASSERT_EQ(Success, buf.Init((const uint8_t*) "", 0xffff));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, InputInitMultipleTimes)
|
||||
TEST_F(pkixder_input_tests, InputBufferInitMultipleTimes)
|
||||
{
|
||||
Input input;
|
||||
InputBuffer buf;
|
||||
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
|
||||
buf.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
|
||||
|
||||
ASSERT_EQ(Result::FATAL_ERROR_INVALID_ARGS,
|
||||
input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectSuccess)
|
||||
{
|
||||
Input input;
|
||||
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
|
||||
ASSERT_EQ(Success,
|
||||
input.Expect(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectMismatch)
|
||||
{
|
||||
Input input;
|
||||
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
|
||||
|
||||
const uint8_t expected[] = { 0x11, 0x22 };
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Expect(expected, sizeof expected));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTooMuch)
|
||||
{
|
||||
Input input;
|
||||
|
||||
const uint8_t der[] = { 0x11, 0x22 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
|
||||
const uint8_t expected[] = { 0x11, 0x22, 0x33 };
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Expect(expected, sizeof expected));
|
||||
buf.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, PeekWithinBounds)
|
||||
{
|
||||
Input input;
|
||||
const uint8_t der[] = { 0x11, 0x11 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
InputBuffer buf(der);
|
||||
Input input(buf);
|
||||
ASSERT_TRUE(input.Peek(0x11));
|
||||
ASSERT_FALSE(input.Peek(0x22));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, PeekPastBounds)
|
||||
{
|
||||
Input input;
|
||||
const uint8_t der[] = { 0x11, 0x22 };
|
||||
ASSERT_EQ(Success, input.Init(der, 1));
|
||||
InputBuffer buf;
|
||||
ASSERT_EQ(Success, buf.Init(der, 1));
|
||||
Input input(buf);
|
||||
|
||||
uint8_t readByte;
|
||||
ASSERT_EQ(Success, input.Read(readByte));
|
||||
@ -185,9 +153,9 @@ TEST_F(pkixder_input_tests, PeekPastBounds)
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadByte)
|
||||
{
|
||||
Input input;
|
||||
const uint8_t der[] = { 0x11, 0x22 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
InputBuffer buf(der);
|
||||
Input input(buf);
|
||||
|
||||
uint8_t readByte1;
|
||||
ASSERT_EQ(Success, input.Read(readByte1));
|
||||
@ -200,10 +168,10 @@ TEST_F(pkixder_input_tests, ReadByte)
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadBytePastEnd)
|
||||
{
|
||||
Input input;
|
||||
const uint8_t der[] = { 0x11, 0x22 };
|
||||
// Initialize with too-short length
|
||||
ASSERT_EQ(Success, input.Init(der, 1));
|
||||
InputBuffer buf;
|
||||
ASSERT_EQ(Success, buf.Init(der, 1));
|
||||
Input input(buf);
|
||||
|
||||
uint8_t readByte1 = 0;
|
||||
ASSERT_EQ(Success, input.Read(readByte1));
|
||||
@ -224,17 +192,19 @@ TEST_F(pkixder_input_tests, ReadByteWrapAroundPointer)
|
||||
// them.
|
||||
const uint8_t* der = nullptr;
|
||||
--der;
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(der, 0));
|
||||
InputBuffer buf;
|
||||
ASSERT_EQ(Success, buf.Init(der, 0));
|
||||
Input input(buf);
|
||||
|
||||
uint8_t b;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Read(b));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadWord)
|
||||
{
|
||||
Input input;
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
InputBuffer buf(der);
|
||||
Input input(buf);
|
||||
|
||||
uint16_t readWord1 = 0;
|
||||
ASSERT_EQ(Success, input.Read(readWord1));
|
||||
@ -247,10 +217,10 @@ TEST_F(pkixder_input_tests, ReadWord)
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadWordPastEnd)
|
||||
{
|
||||
Input input;
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
// Initialize with too-short length
|
||||
ASSERT_EQ(Success, input.Init(der, 2));
|
||||
InputBuffer buf;
|
||||
ASSERT_EQ(Success, buf.Init(der, 2)); // Initialize with too-short length
|
||||
Input input(buf);
|
||||
|
||||
uint16_t readWord1 = 0;
|
||||
ASSERT_EQ(Success, input.Read(readWord1));
|
||||
@ -263,9 +233,10 @@ TEST_F(pkixder_input_tests, ReadWordPastEnd)
|
||||
|
||||
TEST_F(pkixder_input_tests, ReadWordWithInsufficentData)
|
||||
{
|
||||
Input input;
|
||||
const uint8_t der[] = { 0x11, 0x22 };
|
||||
ASSERT_EQ(Success, input.Init(der, 1));
|
||||
InputBuffer buf;
|
||||
ASSERT_EQ(Success, buf.Init(der, 1));
|
||||
Input input(buf);
|
||||
|
||||
uint16_t readWord1 = 0;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Read(readWord1));
|
||||
@ -282,17 +253,18 @@ TEST_F(pkixder_input_tests, ReadWordWrapAroundPointer)
|
||||
// them.
|
||||
const uint8_t* der = nullptr;
|
||||
--der;
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(der, 0));
|
||||
InputBuffer buf;
|
||||
ASSERT_EQ(Success, buf.Init(der, 0));
|
||||
Input input(buf);
|
||||
uint16_t b;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Read(b));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, InputSkip)
|
||||
{
|
||||
Input input;
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
InputBuffer buf(der);
|
||||
Input input(buf);
|
||||
|
||||
ASSERT_EQ(Success, input.Skip(1));
|
||||
|
||||
@ -309,27 +281,27 @@ TEST_F(pkixder_input_tests, InputSkip)
|
||||
|
||||
TEST_F(pkixder_input_tests, InputSkipToEnd)
|
||||
{
|
||||
Input input;
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
InputBuffer buf(der);
|
||||
Input input(buf);
|
||||
ASSERT_EQ(Success, input.Skip(sizeof der));
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, InputSkipPastEnd)
|
||||
{
|
||||
Input input;
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
InputBuffer buf(der);
|
||||
Input input(buf);
|
||||
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Skip(sizeof der + 1));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, InputSkipToNewInput)
|
||||
{
|
||||
Input input;
|
||||
const uint8_t der[] = { 0x01, 0x02, 0x03, 0x04 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
InputBuffer buf(der);
|
||||
Input input(buf);
|
||||
|
||||
Input skippedInput;
|
||||
ASSERT_EQ(Success, input.Skip(3, skippedInput));
|
||||
@ -354,28 +326,27 @@ TEST_F(pkixder_input_tests, InputSkipToNewInput)
|
||||
|
||||
TEST_F(pkixder_input_tests, InputSkipToNewInputPastEnd)
|
||||
{
|
||||
Input input;
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
InputBuffer buf(der);
|
||||
Input input(buf);
|
||||
|
||||
Input skippedInput;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Skip(sizeof der * 2, skippedInput));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, InputSkipToSECItem)
|
||||
TEST_F(pkixder_input_tests, InputSkipToInputBuffer)
|
||||
{
|
||||
Input input;
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
InputBuffer buf(der);
|
||||
Input input(buf);
|
||||
|
||||
const uint8_t expectedItemData[] = { 0x11, 0x22, 0x33 };
|
||||
|
||||
SECItem item;
|
||||
InputBuffer item;
|
||||
ASSERT_EQ(Success, input.Skip(sizeof expectedItemData, item));
|
||||
ASSERT_EQ(siBuffer, item.type);
|
||||
ASSERT_EQ(sizeof expectedItemData, item.len);
|
||||
ASSERT_EQ(der, item.data);
|
||||
ASSERT_EQ(0, memcmp(item.data, expectedItemData, sizeof expectedItemData));
|
||||
|
||||
InputBuffer expected(expectedItemData);
|
||||
ASSERT_TRUE(InputBuffersAreEqual(expected, item));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, SkipWrapAroundPointer)
|
||||
@ -388,26 +359,26 @@ TEST_F(pkixder_input_tests, SkipWrapAroundPointer)
|
||||
// them.
|
||||
const uint8_t* der = nullptr;
|
||||
--der;
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(der, 0));
|
||||
InputBuffer buf;
|
||||
ASSERT_EQ(Success, buf.Init(der, 0));
|
||||
Input input(buf);
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Skip(1));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, SkipToSECItemPastEnd)
|
||||
TEST_F(pkixder_input_tests, SkipToInputBufferPastEnd)
|
||||
{
|
||||
Input input;
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
InputBuffer buf(der);
|
||||
Input input(buf);
|
||||
|
||||
SECItem skippedSECItem;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Skip(sizeof der + 1, skippedSECItem));
|
||||
InputBuffer skipped;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, input.Skip(sizeof der + 1, skipped));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndSkipValue)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
|
||||
InputBuffer buf(DER_SEQUENCE_OF_INT8);
|
||||
Input input(buf);
|
||||
|
||||
ASSERT_EQ(Success, ExpectTagAndSkipValue(input, SEQUENCE));
|
||||
ASSERT_EQ(Success, End(input));
|
||||
@ -415,18 +386,16 @@ TEST_F(pkixder_input_tests, ExpectTagAndSkipValue)
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndSkipValueWithTruncatedData)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_TRUNCATED_SEQUENCE_OF_INT8,
|
||||
sizeof DER_TRUNCATED_SEQUENCE_OF_INT8));
|
||||
InputBuffer buf(DER_TRUNCATED_SEQUENCE_OF_INT8);
|
||||
Input input(buf);
|
||||
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndSkipValue(input, SEQUENCE));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndSkipValueWithOverrunData)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_OVERRUN_SEQUENCE_OF_INT8,
|
||||
sizeof DER_OVERRUN_SEQUENCE_OF_INT8));
|
||||
InputBuffer buf(DER_OVERRUN_SEQUENCE_OF_INT8);
|
||||
Input input(buf);
|
||||
ASSERT_EQ(Success, ExpectTagAndSkipValue(input, SEQUENCE));
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, End(input));
|
||||
}
|
||||
@ -439,26 +408,26 @@ TEST_F(pkixder_input_tests, AtEndOnUnInitializedInput)
|
||||
|
||||
TEST_F(pkixder_input_tests, AtEndAtBeginning)
|
||||
{
|
||||
Input input;
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
InputBuffer buf(der);
|
||||
Input input(buf);
|
||||
ASSERT_FALSE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, AtEndAtEnd)
|
||||
{
|
||||
Input input;
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
InputBuffer buf(der);
|
||||
Input input(buf);
|
||||
ASSERT_EQ(Success, input.Skip(sizeof der));
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, MarkAndGetSECItem)
|
||||
TEST_F(pkixder_input_tests, MarkAndGetInputBuffer)
|
||||
{
|
||||
Input input;
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
InputBuffer buf(der);
|
||||
Input input(buf);
|
||||
|
||||
Input::Mark mark = input.GetMark();
|
||||
|
||||
@ -466,40 +435,35 @@ TEST_F(pkixder_input_tests, MarkAndGetSECItem)
|
||||
|
||||
ASSERT_EQ(Success, input.Skip(sizeof expectedItemData));
|
||||
|
||||
SECItem item;
|
||||
memset(&item, 0x00, sizeof item);
|
||||
|
||||
ASSERT_EQ(Success, input.GetSECItem(siBuffer, mark, item));
|
||||
ASSERT_EQ(siBuffer, item.type);
|
||||
ASSERT_EQ(sizeof expectedItemData, item.len);
|
||||
ASSERT_TRUE(item.data);
|
||||
ASSERT_EQ(0, memcmp(item.data, expectedItemData, sizeof expectedItemData));
|
||||
InputBuffer item;
|
||||
ASSERT_EQ(Success, input.GetInputBuffer(mark, item));
|
||||
InputBuffer expected(expectedItemData);
|
||||
ASSERT_TRUE(InputBuffersAreEqual(expected, item));
|
||||
}
|
||||
|
||||
// Cannot run this test on debug builds because of the PR_NOT_REACHED
|
||||
#ifndef DEBUG
|
||||
TEST_F(pkixder_input_tests, MarkAndGetSECItemDifferentInput)
|
||||
TEST_F(pkixder_input_tests, MarkAndGetInputBufferDifferentInput)
|
||||
{
|
||||
Input input;
|
||||
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
InputBuffer buf(der);
|
||||
Input input(buf);
|
||||
|
||||
Input another;
|
||||
Input::Mark mark = another.GetMark();
|
||||
|
||||
ASSERT_EQ(Success, input.Skip(3));
|
||||
|
||||
SECItem item;
|
||||
InputBuffer item;
|
||||
ASSERT_EQ(Result::FATAL_ERROR_INVALID_ARGS,
|
||||
input.GetSECItem(siBuffer, mark, item));
|
||||
input.GetInputBuffer(mark, item));
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndLength)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
|
||||
InputBuffer buf(DER_SEQUENCE_OF_INT8);
|
||||
Input input(buf);
|
||||
|
||||
ASSERT_EQ(Success, ExpectTagAndLength(input, SEQUENCE,
|
||||
sizeof DER_SEQUENCE_OF_INT8 - 2));
|
||||
@ -507,8 +471,8 @@ TEST_F(pkixder_input_tests, ExpectTagAndLength)
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndLengthWithWrongLength)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_INT16, sizeof DER_INT16));
|
||||
InputBuffer buf(DER_INT16);
|
||||
Input input(buf);
|
||||
|
||||
// Wrong length
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndLength(input, INTEGER, 4));
|
||||
@ -516,8 +480,8 @@ TEST_F(pkixder_input_tests, ExpectTagAndLengthWithWrongLength)
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndLengthWithWrongTag)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_INT16, sizeof DER_INT16));
|
||||
InputBuffer buf(DER_INT16);
|
||||
Input input(buf);
|
||||
|
||||
// Wrong type
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndLength(input, OCTET_STRING, 2));
|
||||
@ -525,9 +489,8 @@ TEST_F(pkixder_input_tests, ExpectTagAndLengthWithWrongTag)
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetLength)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
|
||||
InputBuffer buf(DER_SEQUENCE_OF_INT8);
|
||||
Input input(buf);
|
||||
|
||||
uint16_t length = 0;
|
||||
ASSERT_EQ(Success,
|
||||
@ -539,9 +502,8 @@ TEST_F(pkixder_input_tests, ExpectTagAndGetLength)
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetLengthWithWrongTag)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
|
||||
InputBuffer buf(DER_SEQUENCE_OF_INT8);
|
||||
Input input(buf);
|
||||
|
||||
uint16_t length = 0;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
@ -550,9 +512,8 @@ TEST_F(pkixder_input_tests, ExpectTagAndGetLengthWithWrongTag)
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetLengthWithWrongLength)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_TRUNCATED_SEQUENCE_OF_INT8,
|
||||
sizeof DER_TRUNCATED_SEQUENCE_OF_INT8));
|
||||
InputBuffer buf(DER_TRUNCATED_SEQUENCE_OF_INT8);
|
||||
Input input(buf);
|
||||
|
||||
uint16_t length = 0;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
@ -561,9 +522,8 @@ TEST_F(pkixder_input_tests, ExpectTagAndGetLengthWithWrongLength)
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Input_ValidEmpty)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_EMPTY, sizeof DER_SEQUENCE_EMPTY));
|
||||
InputBuffer buf(DER_SEQUENCE_EMPTY);
|
||||
Input input(buf);
|
||||
Input value;
|
||||
ASSERT_EQ(Success, ExpectTagAndGetValue(input, SEQUENCE, value));
|
||||
ASSERT_TRUE(value.AtEnd());
|
||||
@ -572,9 +532,8 @@ TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Input_ValidEmpty)
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Input_ValidNotEmpty)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_NOT_EMPTY, sizeof DER_SEQUENCE_NOT_EMPTY));
|
||||
InputBuffer buf(DER_SEQUENCE_NOT_EMPTY);
|
||||
Input input(buf);
|
||||
Input value;
|
||||
ASSERT_EQ(Success, ExpectTagAndGetValue(input, SEQUENCE, value));
|
||||
ASSERT_TRUE(value.MatchRest(DER_SEQUENCE_NOT_EMPTY_VALUE));
|
||||
@ -584,10 +543,8 @@ TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Input_ValidNotEmpty)
|
||||
TEST_F(pkixder_input_tests,
|
||||
ExpectTagAndGetValue_Input_InvalidNotEmptyValueTruncated)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED,
|
||||
sizeof DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED));
|
||||
InputBuffer buf(DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED);
|
||||
Input input(buf);
|
||||
Input value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
ExpectTagAndGetValue(input, SEQUENCE, value));
|
||||
@ -595,9 +552,8 @@ TEST_F(pkixder_input_tests,
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Input_InvalidWrongLength)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_TRUNCATED_SEQUENCE_OF_INT8,
|
||||
sizeof DER_TRUNCATED_SEQUENCE_OF_INT8));
|
||||
InputBuffer buf(DER_TRUNCATED_SEQUENCE_OF_INT8);
|
||||
Input input(buf);
|
||||
Input value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
ExpectTagAndGetValue(input, SEQUENCE, value));
|
||||
@ -605,148 +561,129 @@ TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Input_InvalidWrongLength)
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetLength_Input_InvalidWrongTag)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_NOT_EMPTY, sizeof DER_SEQUENCE_NOT_EMPTY));
|
||||
InputBuffer buf(DER_SEQUENCE_NOT_EMPTY);
|
||||
Input input(buf);
|
||||
Input value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
ExpectTagAndGetValue(input, INTEGER, value));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_SECItem_ValidEmpty)
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_InputBuffer_ValidEmpty)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_EMPTY, sizeof DER_SEQUENCE_EMPTY));
|
||||
SECItem value = { siBuffer, nullptr, 5 };
|
||||
InputBuffer buf(DER_SEQUENCE_EMPTY);
|
||||
Input input(buf);
|
||||
InputBuffer value;
|
||||
ASSERT_EQ(Success, ExpectTagAndGetValue(input, SEQUENCE, value));
|
||||
ASSERT_EQ(0u, value.len);
|
||||
ASSERT_EQ(0u, value.GetLength());
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_SECItem_ValidNotEmpty)
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_InputBuffer_ValidNotEmpty)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_NOT_EMPTY, sizeof DER_SEQUENCE_NOT_EMPTY));
|
||||
SECItem value;
|
||||
InputBuffer buf(DER_SEQUENCE_NOT_EMPTY);
|
||||
Input input(buf);
|
||||
InputBuffer value;
|
||||
ASSERT_EQ(Success, ExpectTagAndGetValue(input, SEQUENCE, value));
|
||||
ASSERT_EQ(sizeof(DER_SEQUENCE_NOT_EMPTY_VALUE), value.len);
|
||||
ASSERT_TRUE(value.data);
|
||||
ASSERT_FALSE(memcmp(value.data, DER_SEQUENCE_NOT_EMPTY_VALUE,
|
||||
sizeof(DER_SEQUENCE_NOT_EMPTY_VALUE)));
|
||||
InputBuffer expected(DER_SEQUENCE_NOT_EMPTY_VALUE);
|
||||
ASSERT_TRUE(InputBuffersAreEqual(expected, value));
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests,
|
||||
ExpectTagAndGetValue_SECItem_InvalidNotEmptyValueTruncated)
|
||||
ExpectTagAndGetValue_InputBuffer_InvalidNotEmptyValueTruncated)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED,
|
||||
sizeof DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED));
|
||||
SECItem value;
|
||||
InputBuffer buf(DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED);
|
||||
Input input(buf);
|
||||
InputBuffer value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
ExpectTagAndGetValue(input, SEQUENCE, value));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_SECItem_InvalidWrongLength)
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_InputBuffer_InvalidWrongLength)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_TRUNCATED_SEQUENCE_OF_INT8,
|
||||
sizeof DER_TRUNCATED_SEQUENCE_OF_INT8));
|
||||
SECItem value;
|
||||
InputBuffer buf(DER_TRUNCATED_SEQUENCE_OF_INT8);
|
||||
Input input(buf);
|
||||
InputBuffer value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
ExpectTagAndGetValue(input, SEQUENCE, value));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetLength_SECItem_InvalidWrongTag)
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetLength_InputBuffer_InvalidWrongTag)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_NOT_EMPTY, sizeof DER_SEQUENCE_NOT_EMPTY));
|
||||
SECItem value;
|
||||
InputBuffer buf(DER_SEQUENCE_NOT_EMPTY);
|
||||
Input input(buf);
|
||||
InputBuffer value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
ExpectTagAndGetValue(input, INTEGER, value));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_SECItem_ValidEmpty)
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_InputBuffer_ValidEmpty)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_EMPTY, sizeof DER_SEQUENCE_EMPTY));
|
||||
SECItem tlv = { siBuffer, nullptr, 5 };
|
||||
InputBuffer buf(DER_SEQUENCE_EMPTY);
|
||||
Input input(buf);
|
||||
InputBuffer tlv;
|
||||
ASSERT_EQ(Success, ExpectTagAndGetTLV(input, SEQUENCE, tlv));
|
||||
ASSERT_EQ(sizeof DER_SEQUENCE_EMPTY, tlv.len);
|
||||
ASSERT_TRUE(tlv.data);
|
||||
ASSERT_FALSE(memcmp(tlv.data, DER_SEQUENCE_EMPTY,
|
||||
sizeof DER_SEQUENCE_EMPTY));
|
||||
InputBuffer expected(DER_SEQUENCE_EMPTY);
|
||||
ASSERT_TRUE(InputBuffersAreEqual(expected, tlv));
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_SECItem_ValidNotEmpty)
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_InputBuffer_ValidNotEmpty)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_NOT_EMPTY, sizeof DER_SEQUENCE_NOT_EMPTY));
|
||||
SECItem tlv;
|
||||
InputBuffer buf(DER_SEQUENCE_NOT_EMPTY);
|
||||
Input input(buf);
|
||||
InputBuffer tlv;
|
||||
ASSERT_EQ(Success, ExpectTagAndGetTLV(input, SEQUENCE, tlv));
|
||||
ASSERT_EQ(sizeof(DER_SEQUENCE_NOT_EMPTY), tlv.len);
|
||||
ASSERT_TRUE(tlv.data);
|
||||
ASSERT_FALSE(memcmp(tlv.data, DER_SEQUENCE_NOT_EMPTY,
|
||||
sizeof(DER_SEQUENCE_NOT_EMPTY)));
|
||||
InputBuffer expected(DER_SEQUENCE_NOT_EMPTY);
|
||||
ASSERT_TRUE(InputBuffersAreEqual(expected, tlv));
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests,
|
||||
ExpectTagAndGetTLV_SECItem_InvalidNotEmptyValueTruncated)
|
||||
ExpectTagAndGetTLV_InputBuffer_InvalidNotEmptyValueTruncated)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED,
|
||||
sizeof DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED));
|
||||
SECItem tlv;
|
||||
InputBuffer buf(DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED);
|
||||
Input input(buf);
|
||||
InputBuffer tlv;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndGetTLV(input, SEQUENCE, tlv));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_SECItem_InvalidWrongLength)
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_InputBuffer_InvalidWrongLength)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_TRUNCATED_SEQUENCE_OF_INT8,
|
||||
sizeof DER_TRUNCATED_SEQUENCE_OF_INT8));
|
||||
SECItem tlv;
|
||||
InputBuffer buf(DER_TRUNCATED_SEQUENCE_OF_INT8);
|
||||
Input input(buf);
|
||||
InputBuffer tlv;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndGetTLV(input, SEQUENCE, tlv));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_SECItem_InvalidWrongTag)
|
||||
TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_InputBuffer_InvalidWrongTag)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_NOT_EMPTY, sizeof DER_SEQUENCE_NOT_EMPTY));
|
||||
SECItem tlv;
|
||||
InputBuffer buf(DER_SEQUENCE_NOT_EMPTY);
|
||||
Input input(buf);
|
||||
InputBuffer tlv;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndGetTLV(input, INTEGER, tlv));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, EndAtEnd)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_INT16, sizeof DER_INT16));
|
||||
InputBuffer buf(DER_INT16);
|
||||
Input input(buf);
|
||||
ASSERT_EQ(Success, input.Skip(4));
|
||||
ASSERT_EQ(Success, End(input));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, EndBeforeEnd)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_INT16, sizeof DER_INT16));
|
||||
InputBuffer buf(DER_INT16);
|
||||
Input input(buf);
|
||||
ASSERT_EQ(Success, input.Skip(2));
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, End(input));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, EndAtBeginning)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_INT16, sizeof DER_INT16));
|
||||
InputBuffer buf(DER_INT16);
|
||||
Input input(buf);
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, End(input));
|
||||
}
|
||||
|
||||
@ -766,9 +703,8 @@ Result NestedOfHelper(Input& input, std::vector<uint8_t>& readValues)
|
||||
|
||||
TEST_F(pkixder_input_tests, NestedOf)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
|
||||
InputBuffer buf(DER_SEQUENCE_OF_INT8);
|
||||
Input input(buf);
|
||||
|
||||
std::vector<uint8_t> readValues;
|
||||
ASSERT_EQ(Success,
|
||||
@ -784,9 +720,8 @@ TEST_F(pkixder_input_tests, NestedOf)
|
||||
|
||||
TEST_F(pkixder_input_tests, NestedOfWithTruncatedData)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_TRUNCATED_SEQUENCE_OF_INT8,
|
||||
sizeof DER_TRUNCATED_SEQUENCE_OF_INT8));
|
||||
InputBuffer buf(DER_TRUNCATED_SEQUENCE_OF_INT8);
|
||||
Input input(buf);
|
||||
|
||||
std::vector<uint8_t> readValues;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
@ -798,9 +733,10 @@ TEST_F(pkixder_input_tests, NestedOfWithTruncatedData)
|
||||
|
||||
TEST_F(pkixder_input_tests, MatchRestAtEnd)
|
||||
{
|
||||
Input input;
|
||||
static const uint8_t der[1] = { };
|
||||
ASSERT_EQ(Success, input.Init(der, 0));
|
||||
InputBuffer buf;
|
||||
ASSERT_EQ(Success, buf.Init(der, 0));
|
||||
Input input(buf);
|
||||
ASSERT_TRUE(input.AtEnd());
|
||||
static const uint8_t toMatch[] = { 1 };
|
||||
ASSERT_FALSE(input.MatchRest(toMatch));
|
||||
@ -808,18 +744,18 @@ TEST_F(pkixder_input_tests, MatchRestAtEnd)
|
||||
|
||||
TEST_F(pkixder_input_tests, MatchRest1Match)
|
||||
{
|
||||
Input input;
|
||||
static const uint8_t der[] = { 1 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
InputBuffer buf(der);
|
||||
Input input(buf);
|
||||
ASSERT_FALSE(input.AtEnd());
|
||||
ASSERT_TRUE(input.MatchRest(der));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, MatchRest1Mismatch)
|
||||
{
|
||||
Input input;
|
||||
static const uint8_t der[] = { 1 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
InputBuffer buf(der);
|
||||
Input input(buf);
|
||||
static const uint8_t toMatch[] = { 2 };
|
||||
ASSERT_FALSE(input.MatchRest(toMatch));
|
||||
ASSERT_FALSE(input.AtEnd());
|
||||
@ -827,18 +763,18 @@ TEST_F(pkixder_input_tests, MatchRest1Mismatch)
|
||||
|
||||
TEST_F(pkixder_input_tests, MatchRest2WithTrailingByte)
|
||||
{
|
||||
Input input;
|
||||
static const uint8_t der[] = { 1, 2, 3 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
InputBuffer buf(der);
|
||||
Input input(buf);
|
||||
static const uint8_t toMatch[] = { 1, 2 };
|
||||
ASSERT_FALSE(input.MatchRest(toMatch));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_input_tests, MatchRest2Mismatch)
|
||||
{
|
||||
Input input;
|
||||
static const uint8_t der[] = { 1, 2, 3 };
|
||||
ASSERT_EQ(Success, input.Init(der, sizeof der));
|
||||
InputBuffer buf(der);
|
||||
Input input(buf);
|
||||
static const uint8_t toMatchMismatch[] = { 1, 3 };
|
||||
ASSERT_FALSE(input.MatchRest(toMatchMismatch));
|
||||
ASSERT_TRUE(input.MatchRest(der));
|
||||
|
@ -44,16 +44,16 @@ TEST_F(pkixder_pki_types_tests, CertificateSerialNumber)
|
||||
8, // length
|
||||
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef
|
||||
};
|
||||
InputBuffer buf(DER_CERT_SERIAL);
|
||||
Input input(buf);
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_CERT_SERIAL, sizeof DER_CERT_SERIAL));
|
||||
|
||||
SECItem item;
|
||||
InputBuffer item;
|
||||
ASSERT_EQ(Success, CertificateSerialNumber(input, item));
|
||||
|
||||
ASSERT_EQ(sizeof DER_CERT_SERIAL - 2, item.len);
|
||||
ASSERT_TRUE(memcmp(item.data, DER_CERT_SERIAL + 2,
|
||||
sizeof DER_CERT_SERIAL - 2) == 0);
|
||||
InputBuffer expected;
|
||||
ASSERT_EQ(Success,
|
||||
expected.Init(DER_CERT_SERIAL + 2, sizeof DER_CERT_SERIAL - 2));
|
||||
ASSERT_TRUE(InputBuffersAreEqual(expected, item));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_pki_types_tests, CertificateSerialNumberLongest)
|
||||
@ -63,17 +63,17 @@ TEST_F(pkixder_pki_types_tests, CertificateSerialNumberLongest)
|
||||
20, // length
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
|
||||
};
|
||||
InputBuffer buf(DER_CERT_SERIAL_LONGEST);
|
||||
Input input(buf);
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_CERT_SERIAL_LONGEST,
|
||||
sizeof DER_CERT_SERIAL_LONGEST));
|
||||
|
||||
SECItem item;
|
||||
InputBuffer item;
|
||||
ASSERT_EQ(Success, CertificateSerialNumber(input, item));
|
||||
|
||||
ASSERT_EQ(sizeof DER_CERT_SERIAL_LONGEST - 2, item.len);
|
||||
ASSERT_TRUE(memcmp(item.data, DER_CERT_SERIAL_LONGEST + 2,
|
||||
sizeof DER_CERT_SERIAL_LONGEST - 2) == 0);
|
||||
InputBuffer expected;
|
||||
ASSERT_EQ(Success,
|
||||
expected.Init(DER_CERT_SERIAL_LONGEST + 2,
|
||||
sizeof DER_CERT_SERIAL_LONGEST - 2));
|
||||
ASSERT_TRUE(InputBuffersAreEqual(expected, item));
|
||||
}
|
||||
|
||||
TEST_F(pkixder_pki_types_tests, CertificateSerialNumberCrazyLong)
|
||||
@ -84,12 +84,10 @@ TEST_F(pkixder_pki_types_tests, CertificateSerialNumberCrazyLong)
|
||||
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
|
||||
};
|
||||
InputBuffer buf(DER_CERT_SERIAL_CRAZY_LONG);
|
||||
Input input(buf);
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_CERT_SERIAL_CRAZY_LONG,
|
||||
sizeof DER_CERT_SERIAL_CRAZY_LONG));
|
||||
|
||||
SECItem item;
|
||||
InputBuffer item;
|
||||
ASSERT_EQ(Success, CertificateSerialNumber(input, item));
|
||||
}
|
||||
|
||||
@ -99,12 +97,10 @@ TEST_F(pkixder_pki_types_tests, CertificateSerialNumberZeroLength)
|
||||
0x02, // INTEGER
|
||||
0x00 // length
|
||||
};
|
||||
InputBuffer buf(DER_CERT_SERIAL_ZERO_LENGTH);
|
||||
Input input(buf);
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_CERT_SERIAL_ZERO_LENGTH,
|
||||
sizeof DER_CERT_SERIAL_ZERO_LENGTH));
|
||||
|
||||
SECItem item;
|
||||
InputBuffer item;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, CertificateSerialNumber(input, item));
|
||||
}
|
||||
|
||||
@ -114,10 +110,8 @@ TEST_F(pkixder_pki_types_tests, OptionalVersionV1ExplicitEncodingAllowed)
|
||||
0xa0, 0x03, // context specific 0
|
||||
0x02, 0x01, 0x00 // INTEGER(0)
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_OPTIONAL_VERSION_V1,
|
||||
sizeof DER_OPTIONAL_VERSION_V1));
|
||||
InputBuffer buf(DER_OPTIONAL_VERSION_V1);
|
||||
Input input(buf);
|
||||
|
||||
// XXX(bug 1031093): We shouldn't accept an explicit encoding of v1, but we
|
||||
// do here for compatibility reasons.
|
||||
@ -134,10 +128,8 @@ TEST_F(pkixder_pki_types_tests, OptionalVersionV2)
|
||||
0xa0, 0x03, // context specific 0
|
||||
0x02, 0x01, 0x01 // INTEGER(1)
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_OPTIONAL_VERSION_V2,
|
||||
sizeof DER_OPTIONAL_VERSION_V2));
|
||||
InputBuffer buf(DER_OPTIONAL_VERSION_V2);
|
||||
Input input(buf);
|
||||
|
||||
der::Version version = der::Version::v1;
|
||||
ASSERT_EQ(Success, OptionalVersion(input, version));
|
||||
@ -150,10 +142,8 @@ TEST_F(pkixder_pki_types_tests, OptionalVersionV3)
|
||||
0xa0, 0x03, // context specific 0
|
||||
0x02, 0x01, 0x02 // INTEGER(2)
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_OPTIONAL_VERSION_V3,
|
||||
sizeof DER_OPTIONAL_VERSION_V3));
|
||||
InputBuffer buf(DER_OPTIONAL_VERSION_V3);
|
||||
Input input(buf);
|
||||
|
||||
der::Version version = der::Version::v1;
|
||||
ASSERT_EQ(Success, OptionalVersion(input, version));
|
||||
@ -166,10 +156,8 @@ TEST_F(pkixder_pki_types_tests, OptionalVersionUnknown)
|
||||
0xa0, 0x03, // context specific 0
|
||||
0x02, 0x01, 0x42 // INTEGER(0x42)
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_OPTIONAL_VERSION_INVALID,
|
||||
sizeof DER_OPTIONAL_VERSION_INVALID));
|
||||
InputBuffer buf(DER_OPTIONAL_VERSION_INVALID);
|
||||
Input input(buf);
|
||||
|
||||
der::Version version = der::Version::v1;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, OptionalVersion(input, version));
|
||||
@ -181,10 +169,8 @@ TEST_F(pkixder_pki_types_tests, OptionalVersionInvalidTooLong)
|
||||
0xa0, 0x03, // context specific 0
|
||||
0x02, 0x02, 0x12, 0x34 // INTEGER(0x1234)
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_OPTIONAL_VERSION_INVALID_TOO_LONG,
|
||||
sizeof DER_OPTIONAL_VERSION_INVALID_TOO_LONG));
|
||||
InputBuffer buf(DER_OPTIONAL_VERSION_INVALID_TOO_LONG);
|
||||
Input input(buf);
|
||||
|
||||
der::Version version;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, OptionalVersion(input, version));
|
||||
@ -195,10 +181,8 @@ TEST_F(pkixder_pki_types_tests, OptionalVersionMissing)
|
||||
const uint8_t DER_OPTIONAL_VERSION_MISSING[] = {
|
||||
0x02, 0x11, 0x22 // INTEGER
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_OPTIONAL_VERSION_MISSING,
|
||||
sizeof DER_OPTIONAL_VERSION_MISSING));
|
||||
InputBuffer buf(DER_OPTIONAL_VERSION_MISSING);
|
||||
Input input(buf);
|
||||
|
||||
der::Version version = der::Version::v3;
|
||||
ASSERT_EQ(Success, OptionalVersion(input, version));
|
||||
@ -251,8 +235,9 @@ TEST_P(pkixder_DigestAlgorithmIdentifier, Valid)
|
||||
const AlgorithmIdentifierTestInfo<DigestAlgorithm>& param(GetParam());
|
||||
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(param.der, param.derLength));
|
||||
InputBuffer buf;
|
||||
ASSERT_EQ(Success, buf.Init(param.der, param.derLength));
|
||||
Input input(buf);
|
||||
DigestAlgorithm alg;
|
||||
ASSERT_EQ(Success, DigestAlgorithmIdentifier(input, alg));
|
||||
ASSERT_EQ(param.algorithm, alg);
|
||||
@ -266,8 +251,9 @@ TEST_P(pkixder_DigestAlgorithmIdentifier, Valid)
|
||||
derWithNullParam[param.derLength] = 0x05; // NULL tag
|
||||
derWithNullParam[param.derLength + 1] = 0x00; // length zero
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(derWithNullParam, param.derLength + 2));
|
||||
InputBuffer buf;
|
||||
ASSERT_EQ(Success, buf.Init(derWithNullParam, param.derLength + 2));
|
||||
Input input(buf);
|
||||
DigestAlgorithm alg;
|
||||
ASSERT_EQ(Success, DigestAlgorithmIdentifier(input, alg));
|
||||
ASSERT_EQ(param.algorithm, alg);
|
||||
@ -287,9 +273,9 @@ TEST_F(pkixder_DigestAlgorithmIdentifier, Invalid_MD5)
|
||||
0x30, 0x0a, 0x06, 0x08,
|
||||
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05
|
||||
};
|
||||
InputBuffer buf(DER);
|
||||
Input input(buf);
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
|
||||
DigestAlgorithm alg;
|
||||
ASSERT_EQ(Result::ERROR_INVALID_ALGORITHM,
|
||||
DigestAlgorithmIdentifier(input, alg));
|
||||
@ -303,9 +289,9 @@ TEST_F(pkixder_DigestAlgorithmIdentifier, Invalid_Digest_ECDSA_WITH_SHA256)
|
||||
0x30, 0x0a, 0x06, 0x08,
|
||||
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, //
|
||||
};
|
||||
InputBuffer buf(DER);
|
||||
Input input(buf);
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
|
||||
DigestAlgorithm alg;
|
||||
ASSERT_EQ(Result::ERROR_INVALID_ALGORITHM,
|
||||
DigestAlgorithmIdentifier(input, alg));
|
||||
@ -382,8 +368,9 @@ TEST_P(pkixder_SignatureAlgorithmIdentifier, Valid)
|
||||
const AlgorithmIdentifierTestInfo<SignatureAlgorithm>& param(GetParam());
|
||||
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(param.der, param.derLength));
|
||||
InputBuffer buf;
|
||||
ASSERT_EQ(Success, buf.Init(param.der, param.derLength));
|
||||
Input input(buf);
|
||||
SignatureAlgorithm alg;
|
||||
ASSERT_EQ(Success, SignatureAlgorithmIdentifier(input, alg));
|
||||
ASSERT_EQ(param.algorithm, alg);
|
||||
@ -397,8 +384,9 @@ TEST_P(pkixder_SignatureAlgorithmIdentifier, Valid)
|
||||
derWithNullParam[param.derLength] = 0x05; // NULL tag
|
||||
derWithNullParam[param.derLength + 1] = 0x00; // length zero
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(derWithNullParam, param.derLength + 2));
|
||||
InputBuffer buf;
|
||||
ASSERT_EQ(Success, buf.Init(derWithNullParam, param.derLength + 2));
|
||||
Input input(buf);
|
||||
SignatureAlgorithm alg;
|
||||
ASSERT_EQ(Success, SignatureAlgorithmIdentifier(input, alg));
|
||||
ASSERT_EQ(param.algorithm, alg);
|
||||
@ -418,9 +406,9 @@ TEST_F(pkixder_SignatureAlgorithmIdentifier, Invalid_RSA_With_MD5)
|
||||
0x30, 0x0b, 0x06, 0x09,
|
||||
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04
|
||||
};
|
||||
InputBuffer buf(DER);
|
||||
Input input(buf);
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
|
||||
SignatureAlgorithm alg;
|
||||
ASSERT_EQ(Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED,
|
||||
SignatureAlgorithmIdentifier(input, alg));
|
||||
@ -434,9 +422,9 @@ TEST_F(pkixder_SignatureAlgorithmIdentifier, Invalid_SignatureAlgorithm_SHA256)
|
||||
0x30, 0x0b, 0x06, 0x09,
|
||||
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
|
||||
};
|
||||
InputBuffer buf(DER);
|
||||
Input input(buf);
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
|
||||
SignatureAlgorithm alg;
|
||||
ASSERT_EQ(Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED,
|
||||
SignatureAlgorithmIdentifier(input, alg));
|
||||
|
@ -47,11 +47,8 @@ TEST_F(pkixder_universal_types_tests, BooleanTrue01)
|
||||
0x01, // length
|
||||
0x01 // invalid
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_BOOLEAN_TRUE_01, sizeof DER_BOOLEAN_TRUE_01));
|
||||
|
||||
InputBuffer buf(DER_BOOLEAN_TRUE_01);
|
||||
Input input(buf);
|
||||
bool value = false;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, Boolean(input, value));
|
||||
}
|
||||
@ -63,11 +60,8 @@ TEST_F(pkixder_universal_types_tests, BooleanTrue42)
|
||||
0x01, // length
|
||||
0x42 // invalid
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_BOOLEAN_TRUE_42, sizeof DER_BOOLEAN_TRUE_42));
|
||||
|
||||
InputBuffer buf(DER_BOOLEAN_TRUE_42);
|
||||
Input input(buf);
|
||||
bool value = false;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, Boolean(input, value));
|
||||
}
|
||||
@ -80,10 +74,8 @@ static const uint8_t DER_BOOLEAN_TRUE[] = {
|
||||
|
||||
TEST_F(pkixder_universal_types_tests, BooleanTrueFF)
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_BOOLEAN_TRUE, sizeof DER_BOOLEAN_TRUE));
|
||||
|
||||
InputBuffer buf(DER_BOOLEAN_TRUE);
|
||||
Input input(buf);
|
||||
bool value = false;
|
||||
ASSERT_EQ(Success, Boolean(input, value));
|
||||
ASSERT_TRUE(value);
|
||||
@ -96,9 +88,8 @@ TEST_F(pkixder_universal_types_tests, BooleanFalse)
|
||||
0x01, // length
|
||||
0x00 // false
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_BOOLEAN_FALSE, sizeof DER_BOOLEAN_FALSE));
|
||||
InputBuffer buf(DER_BOOLEAN_FALSE);
|
||||
Input input(buf);
|
||||
|
||||
bool value = true;
|
||||
ASSERT_EQ(Success, Boolean(input, value));
|
||||
@ -112,10 +103,8 @@ TEST_F(pkixder_universal_types_tests, BooleanInvalidLength)
|
||||
0x02, // length
|
||||
0x42, 0x42 // invalid
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_BOOLEAN_INVALID_LENGTH,
|
||||
sizeof DER_BOOLEAN_INVALID_LENGTH));
|
||||
InputBuffer buf(DER_BOOLEAN_INVALID_LENGTH);
|
||||
Input input(buf);
|
||||
|
||||
bool value = true;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, Boolean(input, value));
|
||||
@ -127,10 +116,8 @@ TEST_F(pkixder_universal_types_tests, BooleanInvalidZeroLength)
|
||||
0x01, // BOOLEAN
|
||||
0x00 // length
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_BOOLEAN_INVALID_ZERO_LENGTH,
|
||||
sizeof DER_BOOLEAN_INVALID_ZERO_LENGTH));
|
||||
InputBuffer buf(DER_BOOLEAN_INVALID_ZERO_LENGTH);
|
||||
Input input(buf);
|
||||
|
||||
bool value = true;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, Boolean(input, value));
|
||||
@ -149,10 +136,8 @@ TEST_F(pkixder_universal_types_tests, OptionalBooleanValidEncodings)
|
||||
0x01, // length
|
||||
0xff // true
|
||||
};
|
||||
|
||||
Input input1;
|
||||
ASSERT_EQ(Success, input1.Init(DER_OPTIONAL_BOOLEAN_PRESENT_TRUE,
|
||||
sizeof DER_OPTIONAL_BOOLEAN_PRESENT_TRUE));
|
||||
InputBuffer buf1(DER_OPTIONAL_BOOLEAN_PRESENT_TRUE);
|
||||
Input input1(buf1);
|
||||
bool value = false;
|
||||
ASSERT_EQ(Success, OptionalBoolean(input1, false, value)) <<
|
||||
"Should accept the only valid encoding of a present OPTIONAL BOOLEAN";
|
||||
@ -165,17 +150,17 @@ TEST_F(pkixder_universal_types_tests, OptionalBooleanValidEncodings)
|
||||
0x01, // length
|
||||
0x05
|
||||
};
|
||||
|
||||
Input input2;
|
||||
ASSERT_EQ(Success, input2.Init(DER_INTEGER_05, sizeof DER_INTEGER_05));
|
||||
InputBuffer buf2(DER_INTEGER_05);
|
||||
Input input2(buf2);
|
||||
value = true;
|
||||
ASSERT_EQ(Success, OptionalBoolean(input2, false, value)) <<
|
||||
"Should accept a valid encoding of an omitted OPTIONAL BOOLEAN";
|
||||
ASSERT_FALSE(value);
|
||||
ASSERT_FALSE(input2.AtEnd());
|
||||
|
||||
Input input3;
|
||||
ASSERT_EQ(Success, input3.Init(reinterpret_cast<const uint8_t*>(""), 0));
|
||||
InputBuffer buf3;
|
||||
ASSERT_EQ(Success, buf3.Init(reinterpret_cast<const uint8_t*>(""), 0));
|
||||
Input input3(buf3);
|
||||
value = true;
|
||||
ASSERT_EQ(Success, OptionalBoolean(input3, false, value)) <<
|
||||
"Should accept another valid encoding of an omitted OPTIONAL BOOLEAN";
|
||||
@ -191,9 +176,8 @@ TEST_F(pkixder_universal_types_tests, OptionalBooleanInvalidEncodings)
|
||||
0x00 // false
|
||||
};
|
||||
|
||||
Input input1;
|
||||
ASSERT_EQ(Success, input1.Init(DER_OPTIONAL_BOOLEAN_PRESENT_FALSE,
|
||||
sizeof DER_OPTIONAL_BOOLEAN_PRESENT_FALSE));
|
||||
InputBuffer buf1(DER_OPTIONAL_BOOLEAN_PRESENT_FALSE);
|
||||
Input input1(buf1);
|
||||
bool value;
|
||||
// If the second parameter to OptionalBoolean is false, invalid encodings
|
||||
// that include the field even when it is the DEFAULT FALSE are rejected.
|
||||
@ -202,9 +186,8 @@ TEST_F(pkixder_universal_types_tests, OptionalBooleanInvalidEncodings)
|
||||
OptionalBoolean(input1, allowInvalidEncodings, value)) <<
|
||||
"Should reject an invalid encoding of present OPTIONAL BOOLEAN";
|
||||
|
||||
Input input2;
|
||||
ASSERT_EQ(Success, input2.Init(DER_OPTIONAL_BOOLEAN_PRESENT_FALSE,
|
||||
sizeof DER_OPTIONAL_BOOLEAN_PRESENT_FALSE));
|
||||
InputBuffer buf2(DER_OPTIONAL_BOOLEAN_PRESENT_FALSE);
|
||||
Input input2(buf2);
|
||||
value = true;
|
||||
// If the second parameter to OptionalBoolean is true, invalid encodings
|
||||
// that include the field even when it is the DEFAULT FALSE are accepted.
|
||||
@ -219,10 +202,8 @@ TEST_F(pkixder_universal_types_tests, OptionalBooleanInvalidEncodings)
|
||||
0x01, // length
|
||||
0x42 // (invalid value for a BOOLEAN)
|
||||
};
|
||||
|
||||
Input input3;
|
||||
ASSERT_EQ(Success, input3.Init(DER_OPTIONAL_BOOLEAN_PRESENT_42,
|
||||
sizeof DER_OPTIONAL_BOOLEAN_PRESENT_42));
|
||||
InputBuffer buf3(DER_OPTIONAL_BOOLEAN_PRESENT_42);
|
||||
Input input3(buf3);
|
||||
// Even with the second parameter to OptionalBoolean as true, encodings
|
||||
// of BOOLEAN that are invalid altogether are rejected.
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
@ -237,9 +218,8 @@ TEST_F(pkixder_universal_types_tests, Enumerated)
|
||||
0x01, // length
|
||||
0x42 // value
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_ENUMERATED, sizeof DER_ENUMERATED));
|
||||
InputBuffer buf(DER_ENUMERATED);
|
||||
Input input(buf);
|
||||
|
||||
uint8_t value = 0;
|
||||
ASSERT_EQ(Success, Enumerated(input, value));
|
||||
@ -253,9 +233,9 @@ TEST_F(pkixder_universal_types_tests, EnumeratedNotShortestPossibleDER)
|
||||
0x02, // length
|
||||
0x00, 0x01 // value
|
||||
};
|
||||
InputBuffer buf(DER_ENUMERATED);
|
||||
Input input(buf);
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_ENUMERATED, sizeof DER_ENUMERATED));
|
||||
uint8_t value = 0;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, Enumerated(input, value));
|
||||
}
|
||||
@ -271,10 +251,8 @@ TEST_F(pkixder_universal_types_tests, EnumeratedOutOfAcceptedRange)
|
||||
0x02, // length
|
||||
0x12, 0x34 // value
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_ENUMERATED_INVALID_LENGTH,
|
||||
sizeof DER_ENUMERATED_INVALID_LENGTH));
|
||||
InputBuffer buf(DER_ENUMERATED_INVALID_LENGTH);
|
||||
Input input(buf);
|
||||
|
||||
uint8_t value = 0;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, Enumerated(input, value));
|
||||
@ -286,10 +264,8 @@ TEST_F(pkixder_universal_types_tests, EnumeratedInvalidZeroLength)
|
||||
0x0a, // ENUMERATED
|
||||
0x00 // length
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_ENUMERATED_INVALID_ZERO_LENGTH,
|
||||
sizeof DER_ENUMERATED_INVALID_ZERO_LENGTH));
|
||||
InputBuffer buf(DER_ENUMERATED_INVALID_ZERO_LENGTH);
|
||||
Input input(buf);
|
||||
|
||||
uint8_t value = 0;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, Enumerated(input, value));
|
||||
@ -336,12 +312,8 @@ TimeChoiceForEquivalentUTCTime(const uint8_t (&generalizedTimeDER)[LENGTH],
|
||||
utcTimeDER[i] = generalizedTimeDER[i + 2];
|
||||
}
|
||||
|
||||
Input input;
|
||||
Result rv = input.Init(utcTimeDER, sizeof utcTimeDER);
|
||||
EXPECT_EQ(Success, rv);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
InputBuffer buf(utcTimeDER);
|
||||
Input input(buf);
|
||||
return TimeChoice(input, value);
|
||||
}
|
||||
|
||||
@ -352,8 +324,8 @@ ExpectGoodTime(PRTime expectedValue,
|
||||
{
|
||||
// GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(generalizedTimeDER, LENGTH));
|
||||
InputBuffer buf(generalizedTimeDER);
|
||||
Input input(buf);
|
||||
PRTime value = 0;
|
||||
ASSERT_EQ(Success, GeneralizedTime(input, value));
|
||||
EXPECT_EQ(expectedValue, value);
|
||||
@ -361,8 +333,8 @@ ExpectGoodTime(PRTime expectedValue,
|
||||
|
||||
// TimeChoice: GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(generalizedTimeDER, LENGTH));
|
||||
InputBuffer buf(generalizedTimeDER);
|
||||
Input input(buf);
|
||||
PRTime value = 0;
|
||||
ASSERT_EQ(Success, TimeChoice(input, value));
|
||||
EXPECT_EQ(expectedValue, value);
|
||||
@ -383,16 +355,16 @@ ExpectBadTime(const uint8_t (&generalizedTimeDER)[LENGTH])
|
||||
{
|
||||
// GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(generalizedTimeDER, LENGTH));
|
||||
InputBuffer buf(generalizedTimeDER);
|
||||
Input input(buf);
|
||||
PRTime value;
|
||||
ASSERT_EQ(Result::ERROR_INVALID_TIME, GeneralizedTime(input, value));
|
||||
}
|
||||
|
||||
// TimeChoice: GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(generalizedTimeDER, LENGTH));
|
||||
InputBuffer buf(generalizedTimeDER);
|
||||
Input input(buf);
|
||||
PRTime value;
|
||||
ASSERT_EQ(Result::ERROR_INVALID_TIME, TimeChoice(input, value));
|
||||
}
|
||||
@ -437,17 +409,13 @@ TEST_F(pkixder_universal_types_tests, TimeInvalidZeroLength)
|
||||
PRTime value;
|
||||
|
||||
// GeneralizedTime
|
||||
Input gt;
|
||||
ASSERT_EQ(Success,
|
||||
gt.Init(DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH,
|
||||
sizeof DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH));
|
||||
InputBuffer gtBuf(DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH);
|
||||
Input gt(gtBuf);
|
||||
ASSERT_EQ(Result::ERROR_INVALID_TIME, GeneralizedTime(gt, value));
|
||||
|
||||
// TimeChoice: GeneralizedTime
|
||||
Input tc_gt;
|
||||
ASSERT_EQ(Success,
|
||||
tc_gt.Init(DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH,
|
||||
sizeof DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH));
|
||||
InputBuffer tc_gt_buf(DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH);
|
||||
Input tc_gt(tc_gt_buf);
|
||||
ASSERT_EQ(Result::ERROR_INVALID_TIME, TimeChoice(tc_gt, value));
|
||||
|
||||
// TimeChoice: UTCTime
|
||||
@ -455,9 +423,8 @@ TEST_F(pkixder_universal_types_tests, TimeInvalidZeroLength)
|
||||
0x17, // UTCTime
|
||||
0x00 // Length = 0
|
||||
};
|
||||
Input tc_utc;
|
||||
ASSERT_EQ(Success, tc_utc.Init(DER_UTCTIME_INVALID_ZERO_LENGTH,
|
||||
sizeof DER_UTCTIME_INVALID_ZERO_LENGTH));
|
||||
InputBuffer tc_utc_buf(DER_UTCTIME_INVALID_ZERO_LENGTH);
|
||||
Input tc_utc(tc_utc_buf);
|
||||
ASSERT_EQ(Result::ERROR_INVALID_TIME, TimeChoice(tc_utc, value));
|
||||
}
|
||||
|
||||
@ -538,8 +505,8 @@ TEST_F(pkixder_universal_types_tests, GeneralizedTimeYearValidRange)
|
||||
|
||||
// GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
|
||||
InputBuffer buf(DER);
|
||||
Input input(buf);
|
||||
PRTime value = 0;
|
||||
ASSERT_EQ(Success, GeneralizedTime(input, value));
|
||||
EXPECT_EQ(expectedValue, value);
|
||||
@ -547,8 +514,8 @@ TEST_F(pkixder_universal_types_tests, GeneralizedTimeYearValidRange)
|
||||
|
||||
// TimeChoice: GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
|
||||
InputBuffer buf(DER);
|
||||
Input input(buf);
|
||||
PRTime value = 0;
|
||||
ASSERT_EQ(Success, TimeChoice(input, value));
|
||||
EXPECT_EQ(expectedValue, value);
|
||||
@ -556,7 +523,6 @@ TEST_F(pkixder_universal_types_tests, GeneralizedTimeYearValidRange)
|
||||
|
||||
// TimeChoice: UTCTime, which is limited to years less than 2049.
|
||||
if (i <= 2049) {
|
||||
Input input;
|
||||
PRTime value = 0;
|
||||
ASSERT_EQ(Success, TimeChoiceForEquivalentUTCTime(DER, value));
|
||||
EXPECT_EQ(expectedValue, value);
|
||||
@ -694,8 +660,8 @@ TEST_F(pkixder_universal_types_tests, TimeMonthFebLeapYear2400)
|
||||
|
||||
// GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
|
||||
InputBuffer buf(DER);
|
||||
Input input(buf);
|
||||
PRTime value = 0;
|
||||
ASSERT_EQ(Success, GeneralizedTime(input, value));
|
||||
EXPECT_EQ(expectedValue, value);
|
||||
@ -703,8 +669,8 @@ TEST_F(pkixder_universal_types_tests, TimeMonthFebLeapYear2400)
|
||||
|
||||
// TimeChoice: GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
|
||||
InputBuffer buf(DER);
|
||||
Input input(buf);
|
||||
PRTime value = 0;
|
||||
ASSERT_EQ(Success, TimeChoice(input, value));
|
||||
EXPECT_EQ(expectedValue, value);
|
||||
@ -735,16 +701,16 @@ TEST_F(pkixder_universal_types_tests, TimeMonthFebNotLeapYear2100)
|
||||
|
||||
// GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
|
||||
InputBuffer buf(DER);
|
||||
Input input(buf);
|
||||
PRTime value;
|
||||
ASSERT_EQ(Result::ERROR_INVALID_TIME, GeneralizedTime(input, value));
|
||||
}
|
||||
|
||||
// TimeChoice: GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
|
||||
InputBuffer buf(DER);
|
||||
Input input(buf);
|
||||
PRTime value;
|
||||
ASSERT_EQ(Result::ERROR_INVALID_TIME, TimeChoice(input, value));
|
||||
}
|
||||
@ -873,20 +839,16 @@ TEST_F(pkixder_universal_types_tests, TimeInvalidCenturyChar)
|
||||
|
||||
// GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR,
|
||||
sizeof DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR));
|
||||
InputBuffer buf(DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR);
|
||||
Input input(buf);
|
||||
PRTime value = 0;
|
||||
ASSERT_EQ(Result::ERROR_INVALID_TIME, GeneralizedTime(input, value));
|
||||
}
|
||||
|
||||
// TimeChoice: GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR,
|
||||
sizeof DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR));
|
||||
InputBuffer buf(DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR);
|
||||
Input input(buf);
|
||||
PRTime value = 0;
|
||||
ASSERT_EQ(Result::ERROR_INVALID_TIME, TimeChoice(input, value));
|
||||
}
|
||||
@ -946,9 +908,8 @@ TEST_F(pkixder_universal_types_tests, Integer_0_127)
|
||||
0x01, // length
|
||||
i, // value
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof DER));
|
||||
InputBuffer buf(DER);
|
||||
Input input(buf);
|
||||
|
||||
uint8_t value = i + 1; // initialize with a value that is NOT i.
|
||||
ASSERT_EQ(Success, Integer(input, value));
|
||||
@ -966,9 +927,8 @@ TEST_F(pkixder_universal_types_tests, Integer_Negative1)
|
||||
0x01, // length
|
||||
0xff, // -1 (two's complement)
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof DER));
|
||||
InputBuffer buf(DER);
|
||||
Input input(buf);
|
||||
|
||||
uint8_t value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, Integer(input, value));
|
||||
@ -984,9 +944,8 @@ TEST_F(pkixder_universal_types_tests, Integer_Negative128)
|
||||
0x01, // length
|
||||
0x80, // -128 (two's complement)
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof DER));
|
||||
InputBuffer buf(DER);
|
||||
Input input(buf);
|
||||
|
||||
uint8_t value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, Integer(input, value));
|
||||
@ -1002,9 +961,8 @@ TEST_F(pkixder_universal_types_tests, Integer_128)
|
||||
0x02, // length
|
||||
0x00, 0x80 // 128
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof DER));
|
||||
InputBuffer buf(DER);
|
||||
Input input(buf);
|
||||
|
||||
uint8_t value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, Integer(input, value));
|
||||
@ -1020,9 +978,8 @@ TEST_F(pkixder_universal_types_tests, Integer11223344)
|
||||
0x04, // length
|
||||
0x11, 0x22, 0x33, 0x44 // 0x11223344
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof DER));
|
||||
InputBuffer buf(DER);
|
||||
Input input(buf);
|
||||
|
||||
uint8_t value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, Integer(input, value));
|
||||
@ -1035,10 +992,8 @@ TEST_F(pkixder_universal_types_tests, IntegerTruncatedOneByte)
|
||||
0x01, // length
|
||||
// MISSING DATA HERE
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_INTEGER_TRUNCATED, sizeof DER_INTEGER_TRUNCATED));
|
||||
InputBuffer buf(DER_INTEGER_TRUNCATED);
|
||||
Input input(buf);
|
||||
|
||||
uint8_t value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, Integer(input, value));
|
||||
@ -1052,10 +1007,8 @@ TEST_F(pkixder_universal_types_tests, IntegerTruncatedLarge)
|
||||
0x11, 0x22 // 0x1122
|
||||
// MISSING DATA HERE
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_INTEGER_TRUNCATED, sizeof DER_INTEGER_TRUNCATED));
|
||||
InputBuffer buf(DER_INTEGER_TRUNCATED);
|
||||
Input input(buf);
|
||||
|
||||
uint8_t value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, Integer(input, value));
|
||||
@ -1067,10 +1020,9 @@ TEST_F(pkixder_universal_types_tests, IntegerZeroLength)
|
||||
0x02, // INTEGER
|
||||
0x00 // length
|
||||
};
|
||||
InputBuffer buf(DER_INTEGER_ZERO_LENGTH);
|
||||
Input input(buf);
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_INTEGER_ZERO_LENGTH,
|
||||
sizeof DER_INTEGER_ZERO_LENGTH));
|
||||
uint8_t value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, Integer(input, value));
|
||||
}
|
||||
@ -1082,10 +1034,9 @@ TEST_F(pkixder_universal_types_tests, IntegerOverlyLong1)
|
||||
0x02, // length
|
||||
0x00, 0x01 //
|
||||
};
|
||||
InputBuffer buf(DER_INTEGER_OVERLY_LONG1);
|
||||
Input input(buf);
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_INTEGER_OVERLY_LONG1,
|
||||
sizeof DER_INTEGER_OVERLY_LONG1));
|
||||
uint8_t value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, Integer(input, value));
|
||||
}
|
||||
@ -1097,10 +1048,9 @@ TEST_F(pkixder_universal_types_tests, IntegerOverlyLong2)
|
||||
0x02, // length
|
||||
0xff, 0x80 //
|
||||
};
|
||||
InputBuffer buf(DER_INTEGER_OVERLY_LONG2);
|
||||
Input input(buf);
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_INTEGER_OVERLY_LONG2,
|
||||
sizeof DER_INTEGER_OVERLY_LONG2));
|
||||
uint8_t value;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, Integer(input, value));
|
||||
}
|
||||
@ -1109,8 +1059,9 @@ TEST_F(pkixder_universal_types_tests, OptionalIntegerSupportedDefault)
|
||||
{
|
||||
// The input is a BOOLEAN and not INTEGER for the input so we'll not parse
|
||||
// anything and instead use the default value.
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_BOOLEAN_TRUE, sizeof DER_BOOLEAN_TRUE));
|
||||
InputBuffer buf(DER_BOOLEAN_TRUE);
|
||||
Input input(buf);
|
||||
|
||||
long value = 1;
|
||||
ASSERT_EQ(Success, OptionalInteger(input, -1, value));
|
||||
ASSERT_EQ(-1, value);
|
||||
@ -1122,8 +1073,9 @@ TEST_F(pkixder_universal_types_tests, OptionalIntegerUnsupportedDefault)
|
||||
{
|
||||
// The same as the previous test, except with an unsupported default value
|
||||
// passed in.
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_BOOLEAN_TRUE, sizeof DER_BOOLEAN_TRUE));
|
||||
InputBuffer buf(DER_BOOLEAN_TRUE);
|
||||
Input input(buf);
|
||||
|
||||
long value;
|
||||
ASSERT_EQ(Result::FATAL_ERROR_INVALID_ARGS, OptionalInteger(input, 0, value));
|
||||
}
|
||||
@ -1131,9 +1083,10 @@ TEST_F(pkixder_universal_types_tests, OptionalIntegerUnsupportedDefault)
|
||||
TEST_F(pkixder_universal_types_tests, OptionalIntegerSupportedDefaultAtEnd)
|
||||
{
|
||||
static const uint8_t dummy = 1;
|
||||
InputBuffer buf;
|
||||
ASSERT_EQ(Success, buf.Init(&dummy, 0));
|
||||
Input input(buf);
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(&dummy, 0));
|
||||
long value = 1;
|
||||
ASSERT_EQ(Success, OptionalInteger(input, -1, value));
|
||||
ASSERT_EQ(-1, value);
|
||||
@ -1146,9 +1099,9 @@ TEST_F(pkixder_universal_types_tests, OptionalIntegerNonDefaultValue)
|
||||
0x01, // length
|
||||
0x00
|
||||
};
|
||||
InputBuffer buf(DER);
|
||||
Input input(buf);
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof DER));
|
||||
long value = 2;
|
||||
ASSERT_EQ(Success, OptionalInteger(input, -1, value));
|
||||
ASSERT_EQ(0, value);
|
||||
@ -1161,9 +1114,9 @@ TEST_F(pkixder_universal_types_tests, Null)
|
||||
0x05,
|
||||
0x00
|
||||
};
|
||||
InputBuffer buf(DER_NUL);
|
||||
Input input(buf);
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_NUL, sizeof DER_NUL));
|
||||
ASSERT_EQ(Success, Null(input));
|
||||
}
|
||||
|
||||
@ -1174,10 +1127,8 @@ TEST_F(pkixder_universal_types_tests, NullWithBadLength)
|
||||
0x01,
|
||||
0x00
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER_NULL_BAD_LENGTH, sizeof DER_NULL_BAD_LENGTH));
|
||||
InputBuffer buf(DER_NULL_BAD_LENGTH);
|
||||
Input input(buf);
|
||||
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER, Null(input));
|
||||
}
|
||||
@ -1189,9 +1140,8 @@ TEST_F(pkixder_universal_types_tests, OID)
|
||||
0x09,
|
||||
0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
|
||||
};
|
||||
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER_VALID_OID, sizeof DER_VALID_OID));
|
||||
InputBuffer buf(DER_VALID_OID);
|
||||
Input input(buf);
|
||||
|
||||
const uint8_t expectedOID[] = {
|
||||
0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
|
||||
|
@ -36,20 +36,20 @@ class CreateEncodedOCSPRequestTrustDomain : public TrustDomain
|
||||
{
|
||||
private:
|
||||
virtual Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
|
||||
const SECItem&, /*out*/ TrustLevel&)
|
||||
InputBuffer, /*out*/ TrustLevel&)
|
||||
{
|
||||
ADD_FAILURE();
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
}
|
||||
|
||||
virtual Result FindIssuer(const SECItem&, IssuerChecker&, PRTime)
|
||||
virtual Result FindIssuer(InputBuffer, IssuerChecker&, PRTime)
|
||||
{
|
||||
ADD_FAILURE();
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
}
|
||||
|
||||
virtual Result CheckRevocation(EndEntityOrCA, const CertID&, PRTime,
|
||||
const SECItem*, const SECItem*)
|
||||
const InputBuffer*, const InputBuffer*)
|
||||
{
|
||||
ADD_FAILURE();
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
@ -62,19 +62,19 @@ private:
|
||||
}
|
||||
|
||||
virtual Result VerifySignedData(const SignedDataWithSignature&,
|
||||
const SECItem&)
|
||||
InputBuffer)
|
||||
{
|
||||
ADD_FAILURE();
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
}
|
||||
|
||||
virtual Result DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
|
||||
virtual Result DigestBuf(InputBuffer item, /*out*/ uint8_t* digestBuf,
|
||||
size_t digestBufLen)
|
||||
{
|
||||
return ::mozilla::pkix::DigestBuf(item, digestBuf, digestBufLen);
|
||||
}
|
||||
|
||||
virtual Result CheckPublicKey(const SECItem& subjectPublicKeyInfo)
|
||||
virtual Result CheckPublicKey(InputBuffer subjectPublicKeyInfo)
|
||||
{
|
||||
return ::mozilla::pkix::CheckPublicKey(subjectPublicKeyInfo);
|
||||
}
|
||||
@ -113,22 +113,36 @@ protected:
|
||||
longestRequiredSerialNumber->data[2] = 0x01; // value is 0x010000...00
|
||||
}
|
||||
|
||||
// The resultant issuerDER is owned by the arena.
|
||||
// The resultant issuerDER and issuerSPKI are owned by the arena.
|
||||
SECStatus MakeIssuerCertIDComponents(const char* issuerASCII,
|
||||
/*out*/ const SECItem*& issuerDER,
|
||||
/*out*/ ScopedSECItem& issuerSPKI)
|
||||
/*out*/ InputBuffer& issuerDER,
|
||||
/*out*/ InputBuffer& issuerSPKI)
|
||||
{
|
||||
issuerDER = ASCIIToDERName(arena.get(), issuerASCII);
|
||||
if (!issuerDER) {
|
||||
const SECItem* issuerDERSECItem = ASCIIToDERName(arena.get(), issuerASCII);
|
||||
if (!issuerDERSECItem) {
|
||||
return SECFailure;
|
||||
}
|
||||
if (issuerDER.Init(issuerDERSECItem->data, issuerDERSECItem->len)
|
||||
!= Success) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
ScopedSECKEYPublicKey issuerPublicKey;
|
||||
ScopedSECKEYPrivateKey issuerPrivateKey;
|
||||
if (GenerateKeyPair(issuerPublicKey, issuerPrivateKey) != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
issuerSPKI = SECKEY_EncodeDERSubjectPublicKeyInfo(issuerPublicKey.get());
|
||||
if (!issuerSPKI) {
|
||||
ScopedSECItem issuerSPKIOriginal(
|
||||
SECKEY_EncodeDERSubjectPublicKeyInfo(issuerPublicKey.get()));
|
||||
if (!issuerSPKIOriginal) {
|
||||
return SECFailure;
|
||||
}
|
||||
SECItem issuerSPKICopy;
|
||||
if (SECITEM_CopyItem(arena.get(), &issuerSPKICopy,
|
||||
issuerSPKIOriginal.get()) != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
if (issuerSPKI.Init(issuerSPKICopy.data, issuerSPKICopy.len) != Success) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
@ -142,16 +156,19 @@ protected:
|
||||
// CreateEncodedOCSPRequest to fail.
|
||||
TEST_F(pkixocsp_CreateEncodedOCSPRequest, ChildCertLongSerialNumberTest)
|
||||
{
|
||||
const SECItem* issuerDER;
|
||||
ScopedSECItem issuerSPKI;
|
||||
InputBuffer issuerDER;
|
||||
InputBuffer issuerSPKI;
|
||||
ASSERT_EQ(SECSuccess,
|
||||
MakeIssuerCertIDComponents("CN=CA", issuerDER, issuerSPKI));
|
||||
InputBuffer serialNumber;
|
||||
ASSERT_EQ(Success, serialNumber.Init(unsupportedLongSerialNumber->data,
|
||||
unsupportedLongSerialNumber->len));
|
||||
uint8_t ocspRequest[OCSP_REQUEST_MAX_LENGTH];
|
||||
size_t ocspRequestLength;
|
||||
ASSERT_EQ(Result::ERROR_BAD_DER,
|
||||
CreateEncodedOCSPRequest(trustDomain,
|
||||
CertID(*issuerDER, *issuerSPKI,
|
||||
*unsupportedLongSerialNumber),
|
||||
CertID(issuerDER, issuerSPKI,
|
||||
serialNumber),
|
||||
ocspRequest, ocspRequestLength));
|
||||
}
|
||||
|
||||
@ -159,15 +176,18 @@ TEST_F(pkixocsp_CreateEncodedOCSPRequest, ChildCertLongSerialNumberTest)
|
||||
// it's required to support (i.e. 20 octets).
|
||||
TEST_F(pkixocsp_CreateEncodedOCSPRequest, LongestSupportedSerialNumberTest)
|
||||
{
|
||||
const SECItem* issuerDER;
|
||||
ScopedSECItem issuerSPKI;
|
||||
InputBuffer issuerDER;
|
||||
InputBuffer issuerSPKI;
|
||||
ASSERT_EQ(SECSuccess,
|
||||
MakeIssuerCertIDComponents("CN=CA", issuerDER, issuerSPKI));
|
||||
InputBuffer serialNumber;
|
||||
ASSERT_EQ(Success, serialNumber.Init(longestRequiredSerialNumber->data,
|
||||
longestRequiredSerialNumber->len));
|
||||
uint8_t ocspRequest[OCSP_REQUEST_MAX_LENGTH];
|
||||
size_t ocspRequestLength;
|
||||
ASSERT_EQ(Success,
|
||||
CreateEncodedOCSPRequest(trustDomain,
|
||||
CertID(*issuerDER, *issuerSPKI,
|
||||
*longestRequiredSerialNumber),
|
||||
CertID(issuerDER, issuerSPKI,
|
||||
serialNumber),
|
||||
ocspRequest, ocspRequestLength));
|
||||
}
|
||||
|
@ -43,24 +43,23 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
virtual Result GetCertTrust(EndEntityOrCA endEntityOrCA, const CertPolicyId&,
|
||||
const SECItem& candidateCert,
|
||||
/*out*/ TrustLevel& trustLevel)
|
||||
Result GetCertTrust(EndEntityOrCA endEntityOrCA, const CertPolicyId&,
|
||||
InputBuffer, /*out*/ TrustLevel& trustLevel)
|
||||
{
|
||||
EXPECT_EQ(endEntityOrCA, EndEntityOrCA::MustBeEndEntity);
|
||||
trustLevel = TrustLevel::InheritsTrust;
|
||||
return Success;
|
||||
}
|
||||
|
||||
virtual Result FindIssuer(const SECItem&, IssuerChecker&, PRTime)
|
||||
Result FindIssuer(InputBuffer, IssuerChecker&, PRTime)
|
||||
{
|
||||
ADD_FAILURE();
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
}
|
||||
|
||||
virtual Result CheckRevocation(EndEntityOrCA endEntityOrCA, const CertID&,
|
||||
PRTime time, /*optional*/ const SECItem*,
|
||||
/*optional*/ const SECItem*)
|
||||
PRTime time, /*optional*/ const InputBuffer*,
|
||||
/*optional*/ const InputBuffer*)
|
||||
{
|
||||
// TODO: I guess mozilla::pkix should support revocation of designated
|
||||
// OCSP responder eventually, but we don't now, so this function should
|
||||
@ -76,19 +75,19 @@ public:
|
||||
}
|
||||
|
||||
virtual Result VerifySignedData(const SignedDataWithSignature& signedData,
|
||||
const SECItem& subjectPublicKeyInfo)
|
||||
InputBuffer subjectPublicKeyInfo)
|
||||
{
|
||||
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
virtual Result DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
|
||||
virtual Result DigestBuf(InputBuffer item, /*out*/ uint8_t* digestBuf,
|
||||
size_t digestBufLen)
|
||||
{
|
||||
return ::mozilla::pkix::DigestBuf(item, digestBuf, digestBufLen);
|
||||
}
|
||||
|
||||
virtual Result CheckPublicKey(const SECItem& subjectPublicKeyInfo)
|
||||
virtual Result CheckPublicKey(InputBuffer subjectPublicKeyInfo)
|
||||
{
|
||||
return ::mozilla::pkix::CheckPublicKey(subjectPublicKeyInfo);
|
||||
}
|
||||
@ -132,18 +131,27 @@ public:
|
||||
{
|
||||
NSSTest::SetUp();
|
||||
|
||||
const SECItem* rootNameDER = ASCIIToDERName(arena.get(), rootName);
|
||||
if (!rootNameDER) {
|
||||
InputBuffer rootNameDER;
|
||||
// The result of ASCIIToDERName is owned by the arena
|
||||
if (InitInputBufferFromSECItem(ASCIIToDERName(arena.get(), rootName),
|
||||
rootNameDER) != Success) {
|
||||
PR_Abort();
|
||||
}
|
||||
const SECItem*
|
||||
endEntitySerialNumber(CreateEncodedSerialNumber(arena.get(),
|
||||
++rootIssuedCount));
|
||||
if (!endEntitySerialNumber) {
|
||||
|
||||
InputBuffer serialNumberDER;
|
||||
// The result of CreateEncodedSerialNumber is owned by the arena
|
||||
if (InitInputBufferFromSECItem(
|
||||
CreateEncodedSerialNumber(arena.get(), ++rootIssuedCount),
|
||||
serialNumberDER) != Success) {
|
||||
PR_Abort();
|
||||
}
|
||||
endEntityCertID = new (std::nothrow) CertID(*rootNameDER, *rootSPKI,
|
||||
*endEntitySerialNumber);
|
||||
|
||||
InputBuffer rootSPKIDER;
|
||||
if (InitInputBufferFromSECItem(rootSPKI.get(), rootSPKIDER) != Success) {
|
||||
PR_Abort();
|
||||
}
|
||||
endEntityCertID = new (std::nothrow) CertID(rootNameDER, rootSPKIDER,
|
||||
serialNumberDER);
|
||||
if (!endEntityCertID) {
|
||||
PR_Abort();
|
||||
}
|
||||
@ -190,28 +198,33 @@ class pkixocsp_VerifyEncodedResponse_WithoutResponseBytes
|
||||
, public ::testing::WithParamInterface<WithoutResponseBytes>
|
||||
{
|
||||
protected:
|
||||
SECItem* CreateEncodedOCSPErrorResponse(uint8_t status)
|
||||
// The result is owned by the arena
|
||||
InputBuffer CreateEncodedOCSPErrorResponse(uint8_t status)
|
||||
{
|
||||
static const SECItem EMPTY = { siBuffer, nullptr, 0 };
|
||||
static const InputBuffer EMPTY;
|
||||
OCSPResponseContext context(arena.get(),
|
||||
CertID(EMPTY, EMPTY, EMPTY),
|
||||
oneDayBeforeNow);
|
||||
context.responseStatus = status;
|
||||
context.skipResponseBytes = true;
|
||||
return CreateEncodedOCSPResponse(context);
|
||||
SECItem* response = CreateEncodedOCSPResponse(context);
|
||||
EXPECT_TRUE(response);
|
||||
InputBuffer result;
|
||||
EXPECT_EQ(Success, result.Init(response->data, response->len));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_P(pkixocsp_VerifyEncodedResponse_WithoutResponseBytes, CorrectErrorCode)
|
||||
{
|
||||
SECItem* response(CreateEncodedOCSPErrorResponse(
|
||||
GetParam().responseStatus));
|
||||
ASSERT_TRUE(response);
|
||||
InputBuffer
|
||||
response(CreateEncodedOCSPErrorResponse(GetParam().responseStatus));
|
||||
|
||||
bool expired;
|
||||
ASSERT_EQ(GetParam().expectedError,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(pkixocsp_VerifyEncodedResponse_WithoutResponseBytes,
|
||||
@ -242,7 +255,8 @@ public:
|
||||
pkixocsp_VerifyEncodedResponse::SetUpTestCase();
|
||||
}
|
||||
|
||||
SECItem* CreateEncodedOCSPSuccessfulResponse(
|
||||
// The result is owned by the arena
|
||||
InputBuffer CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::CertStatus certStatus,
|
||||
const CertID& certID,
|
||||
/*optional*/ const char* signerName,
|
||||
@ -254,14 +268,10 @@ public:
|
||||
OCSPResponseContext context(arena.get(), certID, producedAt);
|
||||
if (signerName) {
|
||||
context.signerNameDER = ASCIIToDERName(arena.get(), signerName);
|
||||
if (!context.signerNameDER) {
|
||||
return nullptr;
|
||||
}
|
||||
EXPECT_TRUE(context.signerNameDER);
|
||||
}
|
||||
context.signerPrivateKey = SECKEY_CopyPrivateKey(signerPrivateKey.get());
|
||||
if (!context.signerPrivateKey) {
|
||||
return nullptr;
|
||||
}
|
||||
EXPECT_TRUE(context.signerPrivateKey);
|
||||
context.responseStatus = OCSPResponseContext::successful;
|
||||
context.producedAt = producedAt;
|
||||
context.certs = certs;
|
||||
@ -272,82 +282,81 @@ public:
|
||||
context.nextUpdate = nextUpdate ? *nextUpdate : 0;
|
||||
context.includeNextUpdate = nextUpdate != nullptr;
|
||||
|
||||
return CreateEncodedOCSPResponse(context);
|
||||
SECItem* response = CreateEncodedOCSPResponse(context);
|
||||
EXPECT_TRUE(response);
|
||||
InputBuffer result;
|
||||
EXPECT_EQ(Success, result.Init(response->data, response->len));
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(pkixocsp_VerifyEncodedResponse_successful, good_byKey)
|
||||
{
|
||||
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID, byKey,
|
||||
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
|
||||
&oneDayAfterNow));
|
||||
ASSERT_TRUE(response);
|
||||
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID, byKey,
|
||||
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
|
||||
&oneDayAfterNow));
|
||||
bool expired;
|
||||
ASSERT_EQ(Success,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID,
|
||||
now, END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
TEST_F(pkixocsp_VerifyEncodedResponse_successful, good_byName)
|
||||
{
|
||||
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID, rootName,
|
||||
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
|
||||
&oneDayAfterNow));
|
||||
ASSERT_TRUE(response);
|
||||
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID, rootName,
|
||||
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
|
||||
&oneDayAfterNow));
|
||||
bool expired;
|
||||
ASSERT_EQ(Success,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
TEST_F(pkixocsp_VerifyEncodedResponse_successful, good_byKey_without_nextUpdate)
|
||||
{
|
||||
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID, byKey,
|
||||
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
|
||||
nullptr));
|
||||
ASSERT_TRUE(response);
|
||||
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID, byKey,
|
||||
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
|
||||
nullptr));
|
||||
bool expired;
|
||||
ASSERT_EQ(Success,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
TEST_F(pkixocsp_VerifyEncodedResponse_successful, revoked)
|
||||
{
|
||||
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::revoked, *endEntityCertID, byKey,
|
||||
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
|
||||
&oneDayAfterNow));
|
||||
ASSERT_TRUE(response);
|
||||
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::revoked, *endEntityCertID, byKey,
|
||||
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
|
||||
&oneDayAfterNow));
|
||||
bool expired;
|
||||
ASSERT_EQ(Result::ERROR_REVOKED_CERTIFICATE,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
TEST_F(pkixocsp_VerifyEncodedResponse_successful, unknown)
|
||||
{
|
||||
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::unknown, *endEntityCertID, byKey,
|
||||
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
|
||||
&oneDayAfterNow));
|
||||
ASSERT_TRUE(response);
|
||||
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::unknown, *endEntityCertID, byKey,
|
||||
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
|
||||
&oneDayAfterNow));
|
||||
bool expired;
|
||||
ASSERT_EQ(Result::ERROR_OCSP_UNKNOWN_CERT,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
@ -374,12 +383,12 @@ protected:
|
||||
// EKU.
|
||||
//
|
||||
// signerDEROut is owned by the arena
|
||||
SECItem* CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
InputBuffer CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
const char* certSubjectName,
|
||||
OCSPResponseContext::CertStatus certStatus,
|
||||
const char* signerName,
|
||||
SECOidTag signerEKU = SEC_OID_OCSP_RESPONDER,
|
||||
/*optional, out*/ const SECItem** signerDEROut = nullptr)
|
||||
/*optional, out*/ InputBuffer* signerDEROut = nullptr)
|
||||
{
|
||||
PR_ASSERT(certSubjectName);
|
||||
|
||||
@ -397,19 +406,15 @@ protected:
|
||||
signerEKU != SEC_OID_UNKNOWN ? extensions : nullptr,
|
||||
rootPrivateKey.get(), signerPrivateKey));
|
||||
EXPECT_TRUE(signerDER);
|
||||
if (!signerDER) {
|
||||
return nullptr;
|
||||
if (signerDEROut) {
|
||||
EXPECT_EQ(Success,
|
||||
signerDEROut->Init(signerDER->data, signerDER->len));
|
||||
}
|
||||
|
||||
const SECItem* signerNameDER = nullptr;
|
||||
if (signerName) {
|
||||
signerNameDER = ASCIIToDERName(arena.get(), signerName);
|
||||
if (!signerNameDER) {
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
if (signerDEROut) {
|
||||
*signerDEROut = signerDER;
|
||||
EXPECT_TRUE(signerNameDER);
|
||||
}
|
||||
SECItem const* const certs[] = { signerDER, nullptr };
|
||||
return CreateEncodedOCSPSuccessfulResponse(certStatus, *endEntityCertID,
|
||||
@ -452,29 +457,27 @@ protected:
|
||||
|
||||
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_byKey)
|
||||
{
|
||||
SECItem* response(CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"CN=good_indirect_byKey", OCSPResponseContext::good,
|
||||
byKey));
|
||||
ASSERT_TRUE(response);
|
||||
InputBuffer response(CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"CN=good_indirect_byKey", OCSPResponseContext::good,
|
||||
byKey));
|
||||
bool expired;
|
||||
ASSERT_EQ(Success,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_byName)
|
||||
{
|
||||
SECItem* response(CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"CN=good_indirect_byName", OCSPResponseContext::good,
|
||||
"CN=good_indirect_byName"));
|
||||
ASSERT_TRUE(response);
|
||||
InputBuffer response(CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"CN=good_indirect_byName", OCSPResponseContext::good,
|
||||
"CN=good_indirect_byName"));
|
||||
bool expired;
|
||||
ASSERT_EQ(Success,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
@ -485,16 +488,15 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
|
||||
ScopedSECKEYPrivateKey missingSignerPrivateKey;
|
||||
ASSERT_SECSuccess(GenerateKeyPair(missingSignerPublicKey,
|
||||
missingSignerPrivateKey));
|
||||
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID, byKey,
|
||||
missingSignerPrivateKey, oneDayBeforeNow,
|
||||
oneDayBeforeNow, nullptr));
|
||||
ASSERT_TRUE(response);
|
||||
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID, byKey,
|
||||
missingSignerPrivateKey, oneDayBeforeNow,
|
||||
oneDayBeforeNow, nullptr));
|
||||
bool expired;
|
||||
ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
@ -505,16 +507,15 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
|
||||
ScopedSECKEYPrivateKey missingSignerPrivateKey;
|
||||
ASSERT_SECSuccess(GenerateKeyPair(missingSignerPublicKey,
|
||||
missingSignerPrivateKey));
|
||||
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID, "CN=missing",
|
||||
missingSignerPrivateKey, oneDayBeforeNow,
|
||||
oneDayBeforeNow, nullptr));
|
||||
ASSERT_TRUE(response);
|
||||
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID,
|
||||
"CN=missing", missingSignerPrivateKey,
|
||||
oneDayBeforeNow, oneDayBeforeNow, nullptr));
|
||||
bool expired;
|
||||
ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
@ -539,18 +540,15 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_expired)
|
||||
ASSERT_TRUE(signerDER);
|
||||
|
||||
SECItem const* const certs[] = { signerDER, nullptr };
|
||||
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID, signerName,
|
||||
signerPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
|
||||
&oneDayAfterNow,
|
||||
certs));
|
||||
ASSERT_TRUE(response);
|
||||
|
||||
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID,
|
||||
signerName, signerPrivateKey, oneDayBeforeNow,
|
||||
oneDayBeforeNow, &oneDayAfterNow, certs));
|
||||
bool expired;
|
||||
ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
}
|
||||
|
||||
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_future)
|
||||
@ -574,57 +572,53 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_future)
|
||||
ASSERT_TRUE(signerDER);
|
||||
|
||||
SECItem const* const certs[] = { signerDER, nullptr };
|
||||
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID,
|
||||
signerName, signerPrivateKey, oneDayBeforeNow,
|
||||
oneDayBeforeNow, &oneDayAfterNow, certs));
|
||||
ASSERT_TRUE(response);
|
||||
|
||||
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID,
|
||||
signerName, signerPrivateKey, oneDayBeforeNow,
|
||||
oneDayBeforeNow, &oneDayAfterNow, certs));
|
||||
bool expired;
|
||||
ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_no_eku)
|
||||
{
|
||||
SECItem* response(CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"CN=good_indirect_wrong_eku", OCSPResponseContext::good,
|
||||
byKey, SEC_OID_UNKNOWN));
|
||||
ASSERT_TRUE(response);
|
||||
InputBuffer response(CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"CN=good_indirect_wrong_eku",
|
||||
OCSPResponseContext::good, byKey, SEC_OID_UNKNOWN));
|
||||
bool expired;
|
||||
ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
|
||||
good_indirect_wrong_eku)
|
||||
{
|
||||
SECItem* response(CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"CN=good_indirect_wrong_eku", OCSPResponseContext::good,
|
||||
byKey, SEC_OID_EXT_KEY_USAGE_SERVER_AUTH));
|
||||
ASSERT_TRUE(response);
|
||||
InputBuffer response(CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"CN=good_indirect_wrong_eku",
|
||||
OCSPResponseContext::good, byKey,
|
||||
SEC_OID_EXT_KEY_USAGE_SERVER_AUTH));
|
||||
bool expired;
|
||||
ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
// Test that signature of OCSP response signer cert is verified
|
||||
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_tampered_eku)
|
||||
{
|
||||
SECItem* response(CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"CN=good_indirect_tampered_eku",
|
||||
OCSPResponseContext::good, byKey,
|
||||
SEC_OID_EXT_KEY_USAGE_SERVER_AUTH));
|
||||
ASSERT_TRUE(response);
|
||||
InputBuffer response(CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"CN=good_indirect_tampered_eku",
|
||||
OCSPResponseContext::good, byKey,
|
||||
SEC_OID_EXT_KEY_USAGE_SERVER_AUTH));
|
||||
|
||||
#define EKU_PREFIX \
|
||||
0x06, 8, /* OBJECT IDENTIFIER, 8 bytes */ \
|
||||
@ -633,7 +627,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_tampered_eku)
|
||||
static const uint8_t EKU_SERVER_AUTH[] = { EKU_PREFIX, 0x01 }; // serverAuth
|
||||
static const uint8_t EKU_OCSP_SIGNER[] = { EKU_PREFIX, 0x09 }; // OCSPSigning
|
||||
#undef EKU_PREFIX
|
||||
ASSERT_SECSuccess(TamperOnce(*response,
|
||||
SECItem responseSECItem = UnsafeMapInputBufferToSECItem(response);
|
||||
ASSERT_SECSuccess(TamperOnce(responseSECItem,
|
||||
EKU_SERVER_AUTH, PR_ARRAY_SIZE(EKU_SERVER_AUTH),
|
||||
EKU_OCSP_SIGNER, PR_ARRAY_SIZE(EKU_OCSP_SIGNER)));
|
||||
|
||||
@ -641,7 +636,7 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_tampered_eku)
|
||||
ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
@ -671,17 +666,15 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_unknown_issuer)
|
||||
|
||||
// OCSP response signed by that delegated responder
|
||||
SECItem const* const certs[] = { signerDER, nullptr };
|
||||
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID,
|
||||
signerName, signerPrivateKey, oneDayBeforeNow,
|
||||
oneDayBeforeNow, &oneDayAfterNow, certs));
|
||||
ASSERT_TRUE(response);
|
||||
|
||||
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID,
|
||||
signerName, signerPrivateKey, oneDayBeforeNow,
|
||||
oneDayBeforeNow, &oneDayAfterNow, certs));
|
||||
bool expired;
|
||||
ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
@ -727,18 +720,15 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
|
||||
// OCSP response signed by the delegated responder issued by the sub-CA
|
||||
// that is trying to impersonate the root.
|
||||
SECItem const* const certs[] = { subCADER, signerDER, nullptr };
|
||||
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID, signerName,
|
||||
signerPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
|
||||
&oneDayAfterNow,
|
||||
certs));
|
||||
ASSERT_TRUE(response);
|
||||
|
||||
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID,
|
||||
signerName, signerPrivateKey, oneDayBeforeNow,
|
||||
oneDayBeforeNow, &oneDayAfterNow, certs));
|
||||
bool expired;
|
||||
ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
@ -784,37 +774,35 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
|
||||
// OCSP response signed by the delegated responder issued by the sub-CA
|
||||
// that is trying to impersonate the root.
|
||||
SECItem const* const certs[] = { signerDER, subCADER, nullptr };
|
||||
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID,
|
||||
signerName, signerPrivateKey, oneDayBeforeNow,
|
||||
oneDayBeforeNow, &oneDayAfterNow, certs));
|
||||
ASSERT_TRUE(response);
|
||||
|
||||
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID,
|
||||
signerName, signerPrivateKey, oneDayBeforeNow,
|
||||
oneDayBeforeNow, &oneDayAfterNow, certs));
|
||||
bool expired;
|
||||
ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
class pkixocsp_VerifyEncodedResponse_GetCertTrust
|
||||
: public pkixocsp_VerifyEncodedResponse_DelegatedResponder {
|
||||
public:
|
||||
pkixocsp_VerifyEncodedResponse_GetCertTrust()
|
||||
: signerCertDER(nullptr)
|
||||
, response(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void SetUp()
|
||||
{
|
||||
pkixocsp_VerifyEncodedResponse_DelegatedResponder::SetUp();
|
||||
response = CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"CN=OCSPGetCertTrustTest Signer",
|
||||
OCSPResponseContext::good, byKey,
|
||||
SEC_OID_OCSP_RESPONDER, &signerCertDER);
|
||||
if (!response || !signerCertDER) {
|
||||
|
||||
InputBuffer
|
||||
createdResponse(
|
||||
CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"CN=OCSPGetCertTrustTest Signer", OCSPResponseContext::good,
|
||||
byKey, SEC_OID_OCSP_RESPONDER, &signerCertDER));
|
||||
if (response.Init(createdResponse) != Success) {
|
||||
PR_Abort();
|
||||
}
|
||||
|
||||
if (response.GetLength() == 0 || signerCertDER.GetLength() == 0) {
|
||||
PR_Abort();
|
||||
}
|
||||
}
|
||||
@ -827,32 +815,32 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
bool SetCertTrust(const SECItem* certDER, TrustLevel certTrustLevel)
|
||||
bool SetCertTrust(InputBuffer certDER, TrustLevel certTrustLevel)
|
||||
{
|
||||
this->certDER = certDER;
|
||||
EXPECT_EQ(Success, this->certDER.Init(certDER));
|
||||
this->certTrustLevel = certTrustLevel;
|
||||
return true;
|
||||
}
|
||||
private:
|
||||
virtual Result GetCertTrust(EndEntityOrCA endEntityOrCA,
|
||||
const CertPolicyId&,
|
||||
const SECItem& candidateCert,
|
||||
InputBuffer candidateCert,
|
||||
/*out*/ TrustLevel& trustLevel)
|
||||
{
|
||||
EXPECT_EQ(endEntityOrCA, EndEntityOrCA::MustBeEndEntity);
|
||||
EXPECT_TRUE(certDER);
|
||||
EXPECT_TRUE(SECITEM_ItemsAreEqual(certDER, &candidateCert));
|
||||
EXPECT_NE(0, certDER.GetLength());
|
||||
EXPECT_TRUE(InputBuffersAreEqual(certDER, candidateCert));
|
||||
trustLevel = certTrustLevel;
|
||||
return Success;
|
||||
}
|
||||
|
||||
const SECItem* certDER; // weak pointer
|
||||
InputBuffer certDER;
|
||||
TrustLevel certTrustLevel;
|
||||
};
|
||||
|
||||
TrustDomain trustDomain;
|
||||
const SECItem* signerCertDER; // owned by arena
|
||||
SECItem* response; // owned by arena
|
||||
InputBuffer signerCertDER; // owned by arena
|
||||
InputBuffer response; // owned by arena
|
||||
};
|
||||
|
||||
TEST_F(pkixocsp_VerifyEncodedResponse_GetCertTrust, InheritTrust)
|
||||
@ -863,7 +851,7 @@ TEST_F(pkixocsp_VerifyEncodedResponse_GetCertTrust, InheritTrust)
|
||||
ASSERT_EQ(Success,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
@ -875,7 +863,7 @@ TEST_F(pkixocsp_VerifyEncodedResponse_GetCertTrust, TrustAnchor)
|
||||
ASSERT_EQ(Success,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
@ -887,6 +875,6 @@ TEST_F(pkixocsp_VerifyEncodedResponse_GetCertTrust, ActivelyDistrusted)
|
||||
ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
*response, expired));
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
@ -31,7 +31,7 @@
|
||||
#include "cryptohi.h"
|
||||
#include "hasht.h"
|
||||
#include "pk11pub.h"
|
||||
#include "pkixcheck.h"
|
||||
#include "pkix/pkixnss.h"
|
||||
#include "pkixder.h"
|
||||
#include "prerror.h"
|
||||
#include "prinit.h"
|
||||
@ -148,6 +148,16 @@ TamperOnce(SECItem& item,
|
||||
}
|
||||
}
|
||||
|
||||
Result
|
||||
InitInputBufferFromSECItem(const SECItem* secItem,
|
||||
/*out*/ InputBuffer& inputBuffer)
|
||||
{
|
||||
if (!secItem) {
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
return inputBuffer.Init(secItem->data, secItem->len);
|
||||
}
|
||||
|
||||
class Output
|
||||
{
|
||||
public:
|
||||
@ -1327,16 +1337,18 @@ CertID(OCSPResponseContext& context)
|
||||
if (!hashAlgorithm) {
|
||||
return nullptr;
|
||||
}
|
||||
SECItem* issuerNameHash = HashedOctetString(context.arena,
|
||||
context.certID.issuer,
|
||||
SECItem issuerSECItem = UnsafeMapInputBufferToSECItem(context.certID.issuer);
|
||||
SECItem* issuerNameHash = HashedOctetString(context.arena, issuerSECItem,
|
||||
context.certIDHashAlg);
|
||||
if (!issuerNameHash) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SECItem issuerSubjectPublicKeyInfoSECItem =
|
||||
UnsafeMapInputBufferToSECItem(context.certID.issuerSubjectPublicKeyInfo);
|
||||
ScopedPtr<CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo>
|
||||
spki(SECKEY_DecodeDERSubjectPublicKeyInfo(
|
||||
&context.certID.issuerSubjectPublicKeyInfo));
|
||||
&issuerSubjectPublicKeyInfoSECItem));
|
||||
if (!spki) {
|
||||
return nullptr;
|
||||
}
|
||||
@ -1349,8 +1361,10 @@ CertID(OCSPResponseContext& context)
|
||||
{ SEC_ASN1_INTEGER, 0 },
|
||||
{ 0 }
|
||||
};
|
||||
SECItem serialNumberSECItem =
|
||||
UnsafeMapInputBufferToSECItem(context.certID.serialNumber);
|
||||
SECItem* serialNumber = SEC_ASN1EncodeItem(context.arena, nullptr,
|
||||
&context.certID.serialNumber,
|
||||
&serialNumberSECItem,
|
||||
serialTemplate);
|
||||
if (!serialNumber) {
|
||||
return nullptr;
|
||||
|
@ -37,6 +37,16 @@
|
||||
|
||||
namespace mozilla { namespace pkix { namespace test {
|
||||
|
||||
class TestInputBuffer : public InputBuffer
|
||||
{
|
||||
public:
|
||||
template <size_t N>
|
||||
explicit TestInputBuffer(const char (&valueString)[N])
|
||||
: InputBuffer(reinterpret_cast<const uint8_t(&)[N-1]>(valueString))
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
namespace {
|
||||
|
||||
inline void
|
||||
@ -85,6 +95,9 @@ const SECItem* ASCIIToDERName(PLArenaPool* arena, const char* cn);
|
||||
SECStatus TamperOnce(SECItem& item, const uint8_t* from, size_t fromLen,
|
||||
const uint8_t* to, size_t toLen);
|
||||
|
||||
Result InitInputBufferFromSECItem(const SECItem* secItem,
|
||||
/*out*/ InputBuffer& inputBuffer);
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Encode Certificates
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user