Bug 1041186, Part 1: Improve buffer overflow protection in mozilla::pkix, r=keeler

--HG--
extra : rebase_source : 0f4a33f2c66594930ba9c79233648c70e33ba27c
This commit is contained in:
Brian Smith 2014-07-18 22:30:51 -07:00
parent d20849c5bf
commit ffe743ee06
35 changed files with 1353 additions and 1413 deletions

View File

@ -542,7 +542,12 @@ VerifyCertificate(CERTCertificate* signerCert, void* voidContext, void* pinArg)
if (trustDomain.SetTrustedRoot(context.trustedRoot) != SECSuccess) {
return MapSECStatus(SECFailure);
}
Result rv = BuildCertChain(trustDomain, signerCert->derCert, PR_Now(),
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,

View File

@ -94,7 +94,7 @@ AppTrustDomain::SetTrustedRoot(AppTrustedRoot trustedRoot)
}
Result
AppTrustDomain::FindIssuer(const SECItem& encodedIssuerName,
AppTrustDomain::FindIssuer(InputBuffer encodedIssuerName,
IssuerChecker& checker, PRTime time)
{
@ -111,15 +111,23 @@ 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*/,
rv = checker.Check(certDER, nullptr/*additionalNameConstraints*/,
keepGoing);
if (rv != Success) {
return rv;
@ -136,7 +144,7 @@ AppTrustDomain::FindIssuer(const SECItem& encodedIssuerName,
Result
AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
const CertPolicyId& policy,
const SECItem& candidateCertDER,
InputBuffer candidateCertDER,
/*out*/ TrustLevel& trustLevel)
{
MOZ_ASSERT(policy.IsAnyPolicy());
@ -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);
}

View File

@ -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:

View File

@ -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);
}

View File

@ -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,
// Owned by arena
const SECItem* responseSECItem =
DoOCSPRequest(arena.get(), url, &ocspRequestItem,
OCSPFetchingTypeToTimeoutTime(mOCSPFetching),
mOCSPGetConfig == CertVerifier::ocsp_get_enabled);
if (!response) {
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);
}

View File

@ -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,
virtual Result CheckRevocation(
mozilla::pkix::EndEntityOrCA endEntityOrCA,
const mozilla::pkix::CertID& certID,
PRTime time,
/*optional*/ const SECItem* stapledOCSPResponse,
/*optional*/ const SECItem* aiaExtension) MOZ_OVERRIDE;
/*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;

View File

@ -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;
}

View File

@ -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;

View File

@ -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);

View File

@ -12,6 +12,7 @@ SOURCES += [
LOCAL_INCLUDES += [
'../../../../certverifier',
'../../../../pkix/include',
'../../../../pkix/test/lib',
'/security/manager/ssl/src',
]

View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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

View File

@ -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,8 +207,8 @@ 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,
virtual Result Check(InputBuffer potentialIssuerDER,
/*optional*/ const InputBuffer* additionalNameConstraints,
/*out*/ bool& keepGoing) = 0;
protected:
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() { }

View File

@ -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,8 +126,8 @@ PathBuildingStep::CheckResult() const
// The code that executes in the inner loop of BuildForward
Result
PathBuildingStep::Check(const SECItem& potentialIssuerDER,
/*optional*/ const SECItem* additionalNameConstraints,
PathBuildingStep::Check(InputBuffer potentialIssuerDER,
/*optional*/ const InputBuffer* additionalNameConstraints,
/*out*/ bool& keepGoing)
{
BackCert potentialIssuer(potentialIssuerDER, EndEntityOrCA::MustBeCA,
@ -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.

View File

@ -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;
}

View File

@ -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)))

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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());
}

View File

@ -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);

View File

@ -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,42 +111,31 @@ 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,
Result RememberExtension(Input& extnID, const InputBuffer& extnValue,
/*out*/ bool& understood);
BackCert(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*/;

View File

@ -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;
}
subjectCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certDER,
EXPECT_TRUE(certDER);
if (subjectCert) {
*subjectCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certDER,
nullptr, false, true);
return subjectCert.get() != nullptr;
EXPECT_TRUE(*subjectCert);
}
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],
(void) CreateCert(arena.get(), issuerName, names[i],
EndEntityOrCA::MustBeCA, leafCAKey.get(), leafCAKey,
certChainTail[i])) {
return false;
}
&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,18 +125,26 @@ 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*/,
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*/));
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*/));
}
TEST_F(pkixbuild, BeyondMaxAcceptableCertChainLength)
{
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,
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(), caCert->subjectName,
"CN=End-Entity Too Far",
InputBuffer certDER(CreateCert(arena.get(),
trustDomain.GetLeafCACert()->subjectName,
"CN=Direct End-Entity",
EndEntityOrCA::MustBeEndEntity,
caPrivateKey.get(), privateKey, cert));
ASSERT_EQ(Result::ERROR_UNKNOWN_ISSUER,
BuildCertChain(trustDomain, cert->derCert, now,
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;
// 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*/));
}
}

View File

@ -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,
InputBuffer cert(CreateCert(arena.get(), certCN,
&unknownCriticalExtension, key));
ASSERT_TRUE(cert);
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,
InputBuffer cert(CreateCert(arena.get(), certCN,
&unknownNonCriticalExtension, key));
ASSERT_TRUE(cert);
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,
InputBuffer cert(CreateCert(arena.get(), certCN,
&wrongOIDCriticalExtension, key));
ASSERT_TRUE(cert);
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,
InputBuffer cert(CreateCert(arena.get(), certCN,
&unknownCriticalCEExtension, key));
ASSERT_TRUE(cert);
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,

View File

@ -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,

View File

@ -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));
}

View File

@ -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));

View File

@ -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));

View File

@ -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

View File

@ -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));
}

View File

@ -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(
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::good, *endEntityCertID, byKey,
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
&oneDayAfterNow));
ASSERT_TRUE(response);
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(
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::good, *endEntityCertID, rootName,
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
&oneDayAfterNow));
ASSERT_TRUE(response);
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(
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::good, *endEntityCertID, byKey,
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
nullptr));
ASSERT_TRUE(response);
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(
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::revoked, *endEntityCertID, byKey,
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
&oneDayAfterNow));
ASSERT_TRUE(response);
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(
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::unknown, *endEntityCertID, byKey,
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
&oneDayAfterNow));
ASSERT_TRUE(response);
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(
InputBuffer response(CreateEncodedIndirectOCSPSuccessfulResponse(
"CN=good_indirect_byKey", OCSPResponseContext::good,
byKey));
ASSERT_TRUE(response);
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(
InputBuffer response(CreateEncodedIndirectOCSPSuccessfulResponse(
"CN=good_indirect_byName", OCSPResponseContext::good,
"CN=good_indirect_byName"));
ASSERT_TRUE(response);
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(
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::good, *endEntityCertID, byKey,
missingSignerPrivateKey, oneDayBeforeNow,
oneDayBeforeNow, nullptr));
ASSERT_TRUE(response);
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(
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::good, *endEntityCertID,
signerName, signerPrivateKey, oneDayBeforeNow,
oneDayBeforeNow, &oneDayAfterNow, certs));
ASSERT_TRUE(response);
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(
InputBuffer response(CreateEncodedIndirectOCSPSuccessfulResponse(
"CN=good_indirect_tampered_eku",
OCSPResponseContext::good, byKey,
SEC_OID_EXT_KEY_USAGE_SERVER_AUTH));
ASSERT_TRUE(response);
#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(
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::good, *endEntityCertID,
signerName, signerPrivateKey, oneDayBeforeNow,
oneDayBeforeNow, &oneDayAfterNow, certs));
ASSERT_TRUE(response);
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(
InputBuffer response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::good, *endEntityCertID,
signerName, signerPrivateKey, oneDayBeforeNow,
oneDayBeforeNow, &oneDayAfterNow, certs));
ASSERT_TRUE(response);
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);
}

View File

@ -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;

View File

@ -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