--- a/security/apps/AppSignatureVerification.cpp
+++ b/security/apps/AppSignatureVerification.cpp
@@ -6,16 +6,17 @@
#ifdef MOZ_LOGGING
#define FORCE_PR_LOG 1
#endif
#include "nsNSSCertificateDB.h"
#include "pkix/pkix.h"
+#include "pkix/pkixnss.h"
#include "mozilla/RefPtr.h"
#include "CryptoTask.h"
#include "AppTrustDomain.h"
#include "nsComponentManagerUtils.h"
#include "nsCOMPtr.h"
#include "nsDataSignatureVerifier.h"
#include "nsHashKeys.h"
#include "nsIFile.h"
@@ -536,23 +537,24 @@ VerifyCertificate(CERTCertificate* signe
}
const VerifyCertificateContext& context =
*reinterpret_cast<const VerifyCertificateContext*>(voidContext);
AppTrustDomain trustDomain(context.builtChain, pinArg);
if (trustDomain.SetTrustedRoot(context.trustedRoot) != SECSuccess) {
return MapSECStatus(SECFailure);
}
- if (BuildCertChain(trustDomain, signerCert->derCert, PR_Now(),
- EndEntityOrCA::MustBeEndEntity,
- KeyUsage::digitalSignature,
- KeyPurposeId::id_kp_codeSigning,
- CertPolicyId::anyPolicy,
- nullptr/*stapledOCSPResponse*/) != SECSuccess) {
- return MapSECStatus(SECFailure);
+ Result rv = BuildCertChain(trustDomain, signerCert->derCert, PR_Now(),
+ EndEntityOrCA::MustBeEndEntity,
+ KeyUsage::digitalSignature,
+ KeyPurposeId::id_kp_codeSigning,
+ CertPolicyId::anyPolicy,
+ nullptr/*stapledOCSPResponse*/);
+ if (rv != Success) {
+ return mozilla::psm::GetXPCOMFromNSSError(MapResultToPRErrorCode(rv));
}
return NS_OK;
}
nsresult
VerifySignature(AppTrustedRoot trustedRoot, const SECItem& buffer,
const SECItem& detachedDigest,
--- a/security/apps/AppTrustDomain.cpp
+++ b/security/apps/AppTrustDomain.cpp
@@ -5,17 +5,17 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifdef MOZ_LOGGING
#define FORCE_PR_LOG 1
#endif
#include "AppTrustDomain.h"
#include "certdb.h"
-#include "pkix/pkix.h"
+#include "pkix/pkixnss.h"
#include "mozilla/ArrayUtils.h"
#include "nsIX509CertDB.h"
#include "nsNSSCertificate.h"
#include "prerror.h"
#include "secerr.h"
// Generated in Makefile.in
#include "marketplace-prod-public.inc"
@@ -82,25 +82,24 @@ AppTrustDomain::SetTrustedRoot(AppTruste
&trustedDER, nullptr, false, true);
if (!mTrustedRoot) {
return SECFailure;
}
return SECSuccess;
}
-SECStatus
+Result
AppTrustDomain::FindIssuer(const SECItem& encodedIssuerName,
IssuerChecker& checker, PRTime time)
{
MOZ_ASSERT(mTrustedRoot);
if (!mTrustedRoot) {
- PR_SetError(PR_INVALID_STATE_ERROR, 0);
- return SECFailure;
+ return Result::FATAL_ERROR_INVALID_STATE;
}
// TODO(bug 1035418): If/when mozilla::pkix relaxes the restriction that
// FindIssuer must only pass certificates with a matching subject name to
// checker.Check, we can stop using CERT_CreateSubjectCertList and instead
// use logic like this:
//
// 1. First, try the trusted trust anchor.
@@ -108,60 +107,58 @@ AppTrustDomain::FindIssuer(const SECItem
// message, passing each one to checker.Check.
ScopedCERTCertList
candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
&encodedIssuerName, time, true));
if (candidates) {
for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
!CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
bool keepGoing;
- SECStatus srv = checker.Check(n->cert->derCert,
- nullptr/*additionalNameConstraints*/,
- keepGoing);
- if (srv != SECSuccess) {
- return SECFailure;
+ Result rv = checker.Check(n->cert->derCert,
+ nullptr/*additionalNameConstraints*/,
+ keepGoing);
+ if (rv != Success) {
+ return rv;
}
if (!keepGoing) {
break;
}
}
}
- return SECSuccess;
+ return Success;
}
-SECStatus
+Result
AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
const CertPolicyId& policy,
const SECItem& candidateCertDER,
/*out*/ TrustLevel* trustLevel)
{
MOZ_ASSERT(policy.IsAnyPolicy());
MOZ_ASSERT(trustLevel);
MOZ_ASSERT(mTrustedRoot);
if (!trustLevel || !policy.IsAnyPolicy()) {
- PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
- return SECFailure;
+ return Result::FATAL_ERROR_INVALID_ARGS;
}
if (!mTrustedRoot) {
- PR_SetError(PR_INVALID_STATE_ERROR, 0);
- return SECFailure;
+ return Result::FATAL_ERROR_INVALID_STATE;
}
// Handle active distrust of the certificate.
// 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.
ScopedCERTCertificate candidateCert(
CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
const_cast<SECItem*>(&candidateCertDER), nullptr,
false, true));
if (!candidateCert) {
- return SECFailure;
+ return MapPRErrorCodeToResult(PR_GetError());
}
CERTCertTrust trust;
if (CERT_GetCertTrust(candidateCert.get(), &trust) == SECSuccess) {
PRUint32 flags = SEC_GET_TRUST_FLAGS(&trust, trustObjectSigning);
// For DISTRUST, we use the CERTDB_TRUSTED or CERTDB_TRUSTED_CA bit,
// because we can have active distrust for either type of cert. Note that
@@ -169,60 +166,65 @@ AppTrustDomain::GetCertTrust(EndEntityOr
// relevant trust bit isn't set then that means the cert must be considered
// distrusted.
PRUint32 relevantTrustBit = endEntityOrCA == EndEntityOrCA::MustBeCA
? CERTDB_TRUSTED_CA
: CERTDB_TRUSTED;
if (((flags & (relevantTrustBit | CERTDB_TERMINAL_RECORD)))
== CERTDB_TERMINAL_RECORD) {
*trustLevel = TrustLevel::ActivelyDistrusted;
- return SECSuccess;
+ return Success;
}
}
// mTrustedRoot is the only trust anchor for this validation.
if (CERT_CompareCerts(mTrustedRoot.get(), candidateCert.get())) {
*trustLevel = TrustLevel::TrustAnchor;
- return SECSuccess;
+ return Success;
}
*trustLevel = TrustLevel::InheritsTrust;
- return SECSuccess;
+ return Success;
}
-SECStatus
+Result
AppTrustDomain::VerifySignedData(const SignedDataWithSignature& signedData,
const SECItem& subjectPublicKeyInfo)
{
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
mPinArg);
}
-SECStatus
+Result
AppTrustDomain::DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
size_t digestBufLen)
{
return ::mozilla::pkix::DigestBuf(item, digestBuf, digestBufLen);
}
-SECStatus
+Result
AppTrustDomain::CheckRevocation(EndEntityOrCA, const CertID&, PRTime time,
/*optional*/ const SECItem*,
/*optional*/ const SECItem*)
{
// We don't currently do revocation checking. If we need to distrust an Apps
// certificate, we will use the active distrust mechanism.
- return SECSuccess;
+ return Success;
}
-SECStatus
+Result
AppTrustDomain::IsChainValid(const DERArray& certChain)
{
- return ConstructCERTCertListFromReversedDERArray(certChain, mCertChain);
+ SECStatus srv = ConstructCERTCertListFromReversedDERArray(certChain,
+ mCertChain);
+ if (srv != SECSuccess) {
+ return MapPRErrorCodeToResult(PR_GetError());
+ }
+ return Success;
}
-SECStatus
+Result
AppTrustDomain::CheckPublicKey(const SECItem& subjectPublicKeyInfo)
{
return ::mozilla::pkix::CheckPublicKey(subjectPublicKeyInfo);
}
} } // namespace mozilla::psm
--- a/security/apps/AppTrustDomain.h
+++ b/security/apps/AppTrustDomain.h
@@ -12,38 +12,43 @@
#include "nsIX509CertDB.h"
#include "ScopedNSSTypes.h"
namespace mozilla { namespace psm {
class AppTrustDomain MOZ_FINAL : public mozilla::pkix::TrustDomain
{
public:
+ typedef mozilla::pkix::Result Result;
+
AppTrustDomain(ScopedCERTCertList&, void* pinArg);
SECStatus SetTrustedRoot(AppTrustedRoot trustedRoot);
- SECStatus GetCertTrust(mozilla::pkix::EndEntityOrCA endEntityOrCA,
- const mozilla::pkix::CertPolicyId& policy,
- const SECItem& candidateCertDER,
- /*out*/ mozilla::pkix::TrustLevel* trustLevel) MOZ_OVERRIDE;
- SECStatus FindIssuer(const SECItem& encodedIssuerName,
- IssuerChecker& checker, PRTime time) MOZ_OVERRIDE;
- SECStatus CheckRevocation(mozilla::pkix::EndEntityOrCA endEntityOrCA,
- const mozilla::pkix::CertID& certID, PRTime time,
- /*optional*/ const SECItem* stapledOCSPresponse,
- /*optional*/ const SECItem* aiaExtension);
- SECStatus IsChainValid(const mozilla::pkix::DERArray& certChain);
-
- SECStatus VerifySignedData(
- const mozilla::pkix::SignedDataWithSignature& signedData,
- const SECItem& subjectPublicKeyInfo) MOZ_OVERRIDE;
- SECStatus DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
- size_t digestBufLen) MOZ_OVERRIDE;
- SECStatus CheckPublicKey(const SECItem& subjectPublicKeyInfo) MOZ_OVERRIDE;
+ virtual Result GetCertTrust(mozilla::pkix::EndEntityOrCA endEntityOrCA,
+ const mozilla::pkix::CertPolicyId& policy,
+ const SECItem& candidateCertDER,
+ /*out*/ mozilla::pkix::TrustLevel* trustLevel)
+ MOZ_OVERRIDE;
+ virtual Result FindIssuer(const SECItem& 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);
+ virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain)
+ MOZ_OVERRIDE;
+ virtual Result CheckPublicKey(const SECItem& 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,
+ size_t digestBufLen) MOZ_OVERRIDE;
private:
/*out*/ ScopedCERTCertList& mCertChain;
void* mPinArg; // non-owning!
ScopedCERTCertificate mTrustedRoot;
};
} } // namespace mozilla::psm
--- a/security/certverifier/CertVerifier.cpp
+++ b/security/certverifier/CertVerifier.cpp
@@ -10,16 +10,17 @@
#include "ExtendedValidation.h"
#include "NSSCertDBTrustDomain.h"
#include "NSSErrorsService.h"
#include "PublicKeyPinningService.h"
#include "cert.h"
#include "pk11pub.h"
#include "pkix/pkix.h"
+#include "pkix/pkixnss.h"
#include "prerror.h"
#include "secerr.h"
#include "sslerr.h"
using namespace mozilla::pkix;
using namespace mozilla::psm;
#ifdef PR_LOGGING
@@ -149,36 +150,36 @@ SECStatus chainValidationCallback(void*
CertVerifier::pinningEnforceTestMode);
*chainOK = PublicKeyPinningService::
ChainHasValidPins(certList, callbackState->hostname, callbackState->time,
enforceTestMode);
return SECSuccess;
}
-static SECStatus
+static Result
BuildCertChainForOneKeyUsage(TrustDomain& trustDomain, CERTCertificate* cert,
PRTime time, KeyUsage ku1, KeyUsage ku2,
KeyUsage ku3, KeyPurposeId eku,
const CertPolicyId& requiredPolicy,
const SECItem* stapledOCSPResponse)
{
- SECStatus rv = BuildCertChain(trustDomain, cert->derCert, time,
- EndEntityOrCA::MustBeEndEntity, ku1,
- eku, requiredPolicy, stapledOCSPResponse);
- if (rv != SECSuccess && PR_GetError() == SEC_ERROR_INADEQUATE_KEY_USAGE) {
+ Result rv = BuildCertChain(trustDomain, cert->derCert, time,
+ EndEntityOrCA::MustBeEndEntity, ku1,
+ eku, requiredPolicy, stapledOCSPResponse);
+ if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
rv = BuildCertChain(trustDomain, cert->derCert, time,
EndEntityOrCA::MustBeEndEntity, ku2,
eku, requiredPolicy, stapledOCSPResponse);
- if (rv != SECSuccess && PR_GetError() == SEC_ERROR_INADEQUATE_KEY_USAGE) {
+ if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
rv = BuildCertChain(trustDomain, cert->derCert, time,
EndEntityOrCA::MustBeEndEntity, ku3,
eku, requiredPolicy, stapledOCSPResponse);
- if (rv != SECSuccess) {
- PR_SetError(SEC_ERROR_INADEQUATE_KEY_USAGE, 0);
+ if (rv != Success) {
+ rv = Result::ERROR_INADEQUATE_KEY_USAGE;
}
}
}
return rv;
}
SECStatus
CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
@@ -217,17 +218,17 @@ CertVerifier::VerifyCert(CERTCertificate
= !mOCSPDownloadEnabled ||
(flags & FLAG_LOCAL_ONLY) ? NSSCertDBTrustDomain::NeverFetchOCSP
: !mOCSPStrict ? NSSCertDBTrustDomain::FetchOCSPForDVSoftFail
: NSSCertDBTrustDomain::FetchOCSPForDVHardFail;
ocsp_get_config ocspGETConfig = mOCSPGETEnabled ? ocsp_get_enabled
: ocsp_get_disabled;
- SECStatus rv;
+ Result rv;
switch (usage) {
case certificateUsageSSLClient: {
// XXX: We don't really have a trust bit for SSL client authentication so
// just use trustEmail as it is the closest alternative.
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
pinArg, ocspGETConfig, nullptr,
builtChain);
@@ -243,43 +244,42 @@ CertVerifier::VerifyCert(CERTCertificate
// TODO: When verifying a certificate in an SSL handshake, we should
// restrict the acceptable key usage based on the key exchange method
// chosen by the server.
#ifndef MOZ_NO_EV_CERTS
// Try to validate for EV first.
CertPolicyId evPolicy;
SECOidTag evPolicyOidTag;
- rv = GetFirstEVPolicy(cert, evPolicy, evPolicyOidTag);
- if (rv == SECSuccess) {
+ SECStatus srv = GetFirstEVPolicy(cert, evPolicy, evPolicyOidTag);
+ if (srv == SECSuccess) {
NSSCertDBTrustDomain
trustDomain(trustSSL,
ocspFetching == NSSCertDBTrustDomain::NeverFetchOCSP
? NSSCertDBTrustDomain::LocalOnlyOCSPForEV
: NSSCertDBTrustDomain::FetchOCSPForEV,
mOCSPCache, pinArg, ocspGETConfig,
&callbackContainer, builtChain);
rv = BuildCertChainForOneKeyUsage(trustDomain, cert, time,
KeyUsage::digitalSignature,// (EC)DHE
KeyUsage::keyEncipherment, // RSA
KeyUsage::keyAgreement, // (EC)DH
KeyPurposeId::id_kp_serverAuth,
evPolicy, stapledOCSPResponse);
- if (rv == SECSuccess) {
+ if (rv == Success) {
if (evOidPolicy) {
*evOidPolicy = evPolicyOidTag;
}
break;
}
}
#endif
if (flags & FLAG_MUST_BE_EV) {
- PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0);
- rv = SECFailure;
+ rv = Result::ERROR_POLICY_VALIDATION_FAILED;
break;
}
// Now try non-EV.
NSSCertDBTrustDomain trustDomain(trustSSL, ocspFetching, mOCSPCache,
pinArg, ocspGETConfig, &callbackContainer,
builtChain);
rv = BuildCertChainForOneKeyUsage(trustDomain, cert, time,
@@ -322,17 +322,17 @@ CertVerifier::VerifyCert(CERTCertificate
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
pinArg, ocspGETConfig, nullptr,
builtChain);
rv = BuildCertChain(trustDomain, cert->derCert, time,
EndEntityOrCA::MustBeEndEntity,
KeyUsage::keyEncipherment, // RSA
KeyPurposeId::id_kp_emailProtection,
CertPolicyId::anyPolicy, stapledOCSPResponse);
- if (rv != SECSuccess && PR_GetError() == SEC_ERROR_INADEQUATE_KEY_USAGE) {
+ if (rv == Result::ERROR_INADEQUATE_KEY_USAGE) {
rv = BuildCertChain(trustDomain, cert->derCert, time,
EndEntityOrCA::MustBeEndEntity,
KeyUsage::keyAgreement, // ECDH/DH
KeyPurposeId::id_kp_emailProtection,
CertPolicyId::anyPolicy, stapledOCSPResponse);
}
break;
}
@@ -368,43 +368,47 @@ CertVerifier::VerifyCert(CERTCertificate
eku = KeyPurposeId::id_kp_OCSPSigning;
}
NSSCertDBTrustDomain sslTrust(trustSSL, ocspFetching, mOCSPCache, pinArg,
ocspGETConfig, nullptr, builtChain);
rv = BuildCertChain(sslTrust, cert->derCert, time, endEntityOrCA,
keyUsage, eku, CertPolicyId::anyPolicy,
stapledOCSPResponse);
- if (rv == SECFailure && PR_GetError() == SEC_ERROR_UNKNOWN_ISSUER) {
+ if (rv == Result::ERROR_UNKNOWN_ISSUER) {
NSSCertDBTrustDomain emailTrust(trustEmail, ocspFetching, mOCSPCache,
pinArg, ocspGETConfig, nullptr,
builtChain);
rv = BuildCertChain(emailTrust, cert->derCert, time, endEntityOrCA,
keyUsage, eku, CertPolicyId::anyPolicy,
stapledOCSPResponse);
- if (rv == SECFailure && PR_GetError() == SEC_ERROR_UNKNOWN_ISSUER) {
+ if (rv == Result::ERROR_UNKNOWN_ISSUER) {
NSSCertDBTrustDomain objectSigningTrust(trustObjectSigning,
ocspFetching, mOCSPCache,
pinArg, ocspGETConfig,
nullptr, builtChain);
rv = BuildCertChain(objectSigningTrust, cert->derCert, time,
endEntityOrCA, keyUsage, eku,
CertPolicyId::anyPolicy, stapledOCSPResponse);
}
}
break;
}
default:
- PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
- return SECFailure;
+ rv = Result::FATAL_ERROR_INVALID_ARGS;
}
- return rv;
+ if (rv != Success) {
+ PR_SetError(MapResultToPRErrorCode(rv), 0);
+ return SECFailure;
+ }
+
+ return SECSuccess;
}
SECStatus
CertVerifier::VerifySSLServerCert(CERTCertificate* peerCert,
/*optional*/ const SECItem* stapledOCSPResponse,
PRTime time,
/*optional*/ void* pinarg,
const char* hostname,
--- a/security/certverifier/NSSCertDBTrustDomain.cpp
+++ b/security/certverifier/NSSCertDBTrustDomain.cpp
@@ -12,16 +12,17 @@
#include "nsNSSCertificate.h"
#include "NSSErrorsService.h"
#include "OCSPRequestor.h"
#include "certdb.h"
#include "mozilla/Telemetry.h"
#include "nss.h"
#include "pk11pub.h"
#include "pkix/pkix.h"
+#include "pkix/pkixnss.h"
#include "pkix/ScopedPtr.h"
#include "prerror.h"
#include "prmem.h"
#include "prprf.h"
#include "ScopedNSSTypes.h"
#include "secerr.h"
#include "secmod.h"
@@ -101,17 +102,17 @@ static const uint8_t PERMIT_FRANCE_GOV_N
"\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
};
-SECStatus
+Result
NSSCertDBTrustDomain::FindIssuer(const SECItem& 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."
ScopedCERTCertList
candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
&encodedIssuerName, time, true));
@@ -119,62 +120,59 @@ NSSCertDBTrustDomain::FindIssuer(const S
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;
}
bool keepGoing;
- SECStatus srv = checker.Check(n->cert->derCert,
- additionalNameConstraints, keepGoing);
- if (srv != SECSuccess) {
- return SECFailure;
+ Result rv = checker.Check(n->cert->derCert,
+ additionalNameConstraints, keepGoing);
+ if (rv != Success) {
+ return rv;
}
if (!keepGoing) {
break;
}
}
}
- return SECSuccess;
+ return Success;
}
-SECStatus
+Result
NSSCertDBTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
const CertPolicyId& policy,
const SECItem& candidateCertDER,
/*out*/ TrustLevel* trustLevel)
{
PR_ASSERT(trustLevel);
-
if (!trustLevel) {
- PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
- return SECFailure;
+ return Result::FATAL_ERROR_INVALID_ARGS;
}
#ifdef MOZ_NO_EV_CERTS
if (!policy.IsAnyPolicy()) {
- PR_SetError(SEC_ERROR_POLICY_VALIDATION_FAILED, 0);
- return SECFailure;
+ return Result::ERROR_POLICY_VALIDATION_FAILED;
}
#endif
// 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. The use of
// 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.
ScopedCERTCertificate candidateCert(
CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
const_cast<SECItem*>(&candidateCertDER), nullptr,
false, true));
if (!candidateCert) {
- return SECFailure;
+ return MapPRErrorCodeToResult(PR_GetError());
}
// XXX: CERT_GetCertTrust seems to be abusing SECStatus as a boolean, where
// SECSuccess means that there is a trust record and SECFailure means there
// is not a trust record. I looked at NSS's internal uses of
// CERT_GetCertTrust, and all that code uses the result as a boolean meaning
// "We have a trust record."
CERTCertTrust trust;
@@ -187,49 +185,49 @@ NSSCertDBTrustDomain::GetCertTrust(EndEn
// relevant trust bit isn't set then that means the cert must be considered
// distrusted.
PRUint32 relevantTrustBit =
endEntityOrCA == EndEntityOrCA::MustBeCA ? CERTDB_TRUSTED_CA
: CERTDB_TRUSTED;
if (((flags & (relevantTrustBit|CERTDB_TERMINAL_RECORD)))
== CERTDB_TERMINAL_RECORD) {
*trustLevel = TrustLevel::ActivelyDistrusted;
- return SECSuccess;
+ return Success;
}
// For TRUST, we only use the CERTDB_TRUSTED_CA bit, because Gecko hasn't
// needed to consider end-entity certs to be their own trust anchors since
// Gecko implemented nsICertOverrideService.
if (flags & CERTDB_TRUSTED_CA) {
if (policy.IsAnyPolicy()) {
*trustLevel = TrustLevel::TrustAnchor;
- return SECSuccess;
+ return Success;
}
#ifndef MOZ_NO_EV_CERTS
if (CertIsAuthoritativeForEVPolicy(candidateCert.get(), policy)) {
*trustLevel = TrustLevel::TrustAnchor;
- return SECSuccess;
+ return Success;
}
#endif
}
}
*trustLevel = TrustLevel::InheritsTrust;
- return SECSuccess;
+ return Success;
}
-SECStatus
+Result
NSSCertDBTrustDomain::VerifySignedData(const SignedDataWithSignature& signedData,
const SECItem& subjectPublicKeyInfo)
{
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
mPinArg);
}
-SECStatus
+Result
NSSCertDBTrustDomain::DigestBuf(const SECItem& item,
/*out*/ uint8_t* digestBuf, size_t digestBufLen)
{
return ::mozilla::pkix::DigestBuf(item, digestBuf, digestBufLen);
}
static PRIntervalTime
@@ -252,68 +250,66 @@ OCSPFetchingTypeToTimeoutTime(NSSCertDBT
return PR_SecondsToInterval(2);
}
// Copied and modified from CERT_GetOCSPAuthorityInfoAccessLocation and
// CERT_GetGeneralNameByType. Returns SECFailure on error, SECSuccess
// with url == nullptr when an OCSP URI was not found, and SECSuccess with
// url != nullptr when an OCSP URI was found. The output url will be owned
// by the arena.
-static SECStatus
+static Result
GetOCSPAuthorityInfoAccessLocation(PLArenaPool* arena,
const SECItem& aiaExtension,
/*out*/ char const*& url)
{
url = nullptr;
// TODO(bug 1028380): Remove the const_cast.
CERTAuthInfoAccess** aia = CERT_DecodeAuthInfoAccessExtension(
arena,
const_cast<SECItem*>(&aiaExtension));
if (!aia) {
- PR_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION, 0);
- return SECFailure;
+ return Result::ERROR_CERT_BAD_ACCESS_LOCATION;
}
for (size_t i = 0; aia[i]; ++i) {
if (SECOID_FindOIDTag(&aia[i]->method) == SEC_OID_PKIX_OCSP) {
// NSS chooses the **last** OCSP URL; we choose the **first**
CERTGeneralName* current = aia[i]->location;
if (!current) {
continue;
}
do {
if (current->type == certURI) {
const SECItem& location = current->name.other;
// (location.len + 1) must be small enough to fit into a uint32_t,
// but we limit it to a smaller bound to reduce OOM risk.
if (location.len > 1024 || memchr(location.data, 0, location.len)) {
// Reject embedded nulls. (NSS doesn't do this)
- PR_SetError(SEC_ERROR_CERT_BAD_ACCESS_LOCATION, 0);
- return SECFailure;
+ return Result::ERROR_CERT_BAD_ACCESS_LOCATION;
}
// Copy the non-null-terminated SECItem into a null-terminated string.
char* nullTerminatedURL(static_cast<char*>(
PORT_ArenaAlloc(arena, location.len + 1)));
if (!nullTerminatedURL) {
- return SECFailure;
+ return Result::FATAL_ERROR_NO_MEMORY;
}
memcpy(nullTerminatedURL, location.data, location.len);
nullTerminatedURL[location.len] = 0;
url = nullTerminatedURL;
- return SECSuccess;
+ return Success;
}
current = CERT_GetNextGeneralName(current);
} while (current != aia[i]->location);
}
}
- return SECSuccess;
+ return Success;
}
-SECStatus
+Result
NSSCertDBTrustDomain::CheckRevocation(EndEntityOrCA endEntityOrCA,
const CertID& certID, PRTime time,
/*optional*/ const SECItem* stapledOCSPResponse,
/*optional*/ const SECItem* aiaExtension)
{
// Actively distrusted certificates will have already been blocked by
// GetCertTrust.
@@ -333,363 +329,345 @@ NSSCertDBTrustDomain::CheckRevocation(En
}
// If we have a stapled OCSP response then the verification of that response
// determines the result unless the OCSP response is expired. We make an
// exception for expired responses because some servers, nginx in particular,
// are known to serve expired responses due to bugs.
// We keep track of the result of verifying the stapled response but don't
// immediately return failure if the response has expired.
- PRErrorCode stapledOCSPResponseErrorCode = 0;
+ Result stapledOCSPResponseResult = Success;
if (stapledOCSPResponse) {
PR_ASSERT(endEntityOrCA == EndEntityOrCA::MustBeEndEntity);
bool expired;
- SECStatus rv = VerifyAndMaybeCacheEncodedOCSPResponse(certID, time,
- maxOCSPLifetimeInDays,
- *stapledOCSPResponse,
- ResponseWasStapled,
- expired);
- if (rv == SECSuccess) {
+ stapledOCSPResponseResult =
+ VerifyAndMaybeCacheEncodedOCSPResponse(certID, time,
+ maxOCSPLifetimeInDays,
+ *stapledOCSPResponse,
+ ResponseWasStapled, expired);
+ if (stapledOCSPResponseResult == Success) {
// stapled OCSP response present and good
Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 1);
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: stapled OCSP response: good"));
- return rv;
+ return Success;
}
- stapledOCSPResponseErrorCode = PR_GetError();
- if (stapledOCSPResponseErrorCode == SEC_ERROR_OCSP_OLD_RESPONSE ||
+ if (stapledOCSPResponseResult == Result::ERROR_OCSP_OLD_RESPONSE ||
expired) {
// stapled OCSP response present but expired
Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 3);
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: expired stapled OCSP response"));
} else {
// stapled OCSP response present but invalid for some reason
Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 4);
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: stapled OCSP response: failure"));
- return rv;
+ return stapledOCSPResponseResult;
}
} else {
// no stapled OCSP response
Telemetry::Accumulate(Telemetry::SSL_OCSP_STAPLING, 2);
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: no stapled OCSP response"));
}
- PRErrorCode cachedResponseErrorCode = 0;
+ Result cachedResponseResult = Success;
PRTime cachedResponseValidThrough = 0;
bool cachedResponsePresent = mOCSPCache.Get(certID,
- cachedResponseErrorCode,
+ cachedResponseResult,
cachedResponseValidThrough);
if (cachedResponsePresent) {
- if (cachedResponseErrorCode == 0 && cachedResponseValidThrough >= time) {
+ if (cachedResponseResult == Success && cachedResponseValidThrough >= time) {
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: cached OCSP response: good"));
- return SECSuccess;
+ return Success;
}
// If we have a cached revoked response, use it.
- if (cachedResponseErrorCode == SEC_ERROR_REVOKED_CERTIFICATE) {
+ if (cachedResponseResult == Result::ERROR_REVOKED_CERTIFICATE) {
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: cached OCSP response: revoked"));
- PR_SetError(SEC_ERROR_REVOKED_CERTIFICATE, 0);
- return SECFailure;
+ return Result::ERROR_REVOKED_CERTIFICATE;
}
// The cached response may indicate an unknown certificate or it may be
// expired. Don't return with either of these statuses yet - we may be
// able to fetch a more recent one.
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: cached OCSP response: error %ld valid "
- "until %lld", cachedResponseErrorCode, cachedResponseValidThrough));
+ "until %lld", cachedResponseResult, cachedResponseValidThrough));
// When a good cached response has expired, it is more convenient
// to convert that to an error code and just deal with
- // cachedResponseErrorCode from here on out.
- if (cachedResponseErrorCode == 0 && cachedResponseValidThrough < time) {
- cachedResponseErrorCode = SEC_ERROR_OCSP_OLD_RESPONSE;
+ // cachedResponseResult from here on out.
+ if (cachedResponseResult == Success && cachedResponseValidThrough < time) {
+ cachedResponseResult = Result::ERROR_OCSP_OLD_RESPONSE;
}
// We may have a cached indication of server failure. Ignore it if
// it has expired.
- if (cachedResponseErrorCode != 0 &&
- cachedResponseErrorCode != SEC_ERROR_OCSP_UNKNOWN_CERT &&
- cachedResponseErrorCode != SEC_ERROR_OCSP_OLD_RESPONSE &&
+ if (cachedResponseResult != Success &&
+ cachedResponseResult != Result::ERROR_OCSP_UNKNOWN_CERT &&
+ cachedResponseResult != Result::ERROR_OCSP_OLD_RESPONSE &&
cachedResponseValidThrough < time) {
- cachedResponseErrorCode = 0;
+ cachedResponseResult = Success;
cachedResponsePresent = false;
}
} else {
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: no cached OCSP response"));
}
- // At this point, if and only if cachedErrorResponseCode is 0, there was no
+ // At this point, if and only if cachedErrorResult is Success, there was no
// cached response.
- PR_ASSERT((!cachedResponsePresent && cachedResponseErrorCode == 0) ||
- (cachedResponsePresent && cachedResponseErrorCode != 0));
+ PR_ASSERT((!cachedResponsePresent && cachedResponseResult == Success) ||
+ (cachedResponsePresent && cachedResponseResult != Success));
// TODO: We still need to handle the fallback for expired responses. But,
// if/when we disable OCSP fetching by default, it would be ambiguous whether
// security.OCSP.enable==0 means "I want the default" or "I really never want
// you to ever fetch OCSP."
if ((mOCSPFetching == NeverFetchOCSP) ||
(endEntityOrCA == EndEntityOrCA::MustBeCA &&
(mOCSPFetching == FetchOCSPForDVHardFail ||
mOCSPFetching == FetchOCSPForDVSoftFail))) {
// We're not going to be doing any fetching, so if there was a cached
// "unknown" response, say so.
- if (cachedResponseErrorCode == SEC_ERROR_OCSP_UNKNOWN_CERT) {
- PR_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT, 0);
- return SECFailure;
+ if (cachedResponseResult == Result::ERROR_OCSP_UNKNOWN_CERT) {
+ return Result::ERROR_OCSP_UNKNOWN_CERT;
}
// If we're doing hard-fail, we want to know if we have a cached response
// that has expired.
if (mOCSPFetching == FetchOCSPForDVHardFail &&
- cachedResponseErrorCode == SEC_ERROR_OCSP_OLD_RESPONSE) {
- PR_SetError(SEC_ERROR_OCSP_OLD_RESPONSE, 0);
- return SECFailure;
+ cachedResponseResult == Result::ERROR_OCSP_OLD_RESPONSE) {
+ return Result::ERROR_OCSP_OLD_RESPONSE;
}
- return SECSuccess;
+ return Success;
}
if (mOCSPFetching == LocalOnlyOCSPForEV) {
- PR_SetError(cachedResponseErrorCode != 0 ? cachedResponseErrorCode
- : SEC_ERROR_OCSP_UNKNOWN_CERT, 0);
- return SECFailure;
+ if (cachedResponseResult != Success) {
+ return cachedResponseResult;
+ }
+ return Result::ERROR_OCSP_UNKNOWN_CERT;
}
ScopedPLArenaPool arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
if (!arena) {
- return SECFailure;
+ return Result::FATAL_ERROR_NO_MEMORY;
}
+ Result rv;
const char* url = nullptr; // owned by the arena
if (aiaExtension) {
- if (GetOCSPAuthorityInfoAccessLocation(arena.get(), *aiaExtension, url)
- != SECSuccess) {
- return SECFailure;
+ rv = GetOCSPAuthorityInfoAccessLocation(arena.get(), *aiaExtension, url);
+ if (rv != Success) {
+ return rv;
}
}
if (!url) {
if (mOCSPFetching == FetchOCSPForEV ||
- cachedResponseErrorCode == SEC_ERROR_OCSP_UNKNOWN_CERT) {
- PR_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT, 0);
- return SECFailure;
+ cachedResponseResult == Result::ERROR_OCSP_UNKNOWN_CERT) {
+ return Result::ERROR_OCSP_UNKNOWN_CERT;
}
- if (cachedResponseErrorCode == SEC_ERROR_OCSP_OLD_RESPONSE) {
- PR_SetError(SEC_ERROR_OCSP_OLD_RESPONSE, 0);
- return SECFailure;
+ if (cachedResponseResult == Result::ERROR_OCSP_OLD_RESPONSE) {
+ return Result::ERROR_OCSP_OLD_RESPONSE;
}
- if (stapledOCSPResponseErrorCode != 0) {
- PR_SetError(stapledOCSPResponseErrorCode, 0);
- return SECFailure;
+ if (stapledOCSPResponseResult != Success) {
+ return stapledOCSPResponseResult;
}
// Nothing to do if we don't have an OCSP responder URI for the cert; just
// assume it is good. Note that this is the confusing, but intended,
// interpretation of "strict" revocation checking in the face of a
// certificate that lacks an OCSP responder URI.
- return SECSuccess;
+ return Success;
}
// 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;
bool attemptedRequest;
- // Initialize error here to a value we check that it isn't later, because
- // the compiler on windows isn't smart enough to figure out that it's
- // always initialized before it gets used.
- PRErrorCode error = 0;
- if (cachedResponseErrorCode == 0 ||
- cachedResponseErrorCode == SEC_ERROR_OCSP_UNKNOWN_CERT ||
- cachedResponseErrorCode == SEC_ERROR_OCSP_OLD_RESPONSE) {
- const SECItem* request(CreateEncodedOCSPRequest(*this, arena.get(),
- certID));
- if (!request) {
- return SECFailure;
+ if (cachedResponseResult == Success ||
+ cachedResponseResult == Result::ERROR_OCSP_UNKNOWN_CERT ||
+ cachedResponseResult == Result::ERROR_OCSP_OLD_RESPONSE) {
+ uint8_t ocspRequest[OCSP_REQUEST_MAX_LENGTH];
+ size_t ocspRequestLength;
+ rv = CreateEncodedOCSPRequest(*this, certID, ocspRequest,
+ ocspRequestLength);
+ if (rv != Success) {
+ return rv;
}
-
- response = DoOCSPRequest(arena.get(), url, request,
+ SECItem ocspRequestItem = {
+ siBuffer,
+ ocspRequest,
+ static_cast<unsigned int>(ocspRequestLength)
+ };
+ response = DoOCSPRequest(arena.get(), url, &ocspRequestItem,
OCSPFetchingTypeToTimeoutTime(mOCSPFetching),
mOCSPGetConfig == CertVerifier::ocsp_get_enabled);
if (!response) {
- error = PR_GetError();
+ rv = MapPRErrorCodeToResult(PR_GetError());
}
attemptedRequest = true;
} else {
- error = cachedResponseErrorCode;
+ 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) {
- MOZ_ASSERT(error != 0);
- // If we haven't actually attempted to fetch a response, we have nothing
- // new to tell the cache. Otherwise, we do.
+ Result error = rv;
if (attemptedRequest) {
PRTime timeout = time + ServerFailureDelay;
- SECStatus rv = mOCSPCache.Put(certID, error, time, timeout);
- if (rv != SECSuccess) {
- return SECFailure;
+ rv = mOCSPCache.Put(certID, error, time, timeout);
+ if (rv != Success) {
+ return rv;
}
}
- PR_SetError(error, 0);
if (mOCSPFetching != FetchOCSPForDVSoftFail) {
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: returning SECFailure after "
"OCSP request failure"));
- return SECFailure;
+ return error;
}
- if (cachedResponseErrorCode == SEC_ERROR_OCSP_UNKNOWN_CERT) {
+ if (cachedResponseResult == Result::ERROR_OCSP_UNKNOWN_CERT) {
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: returning SECFailure from cached "
"response after OCSP request failure"));
- PR_SetError(cachedResponseErrorCode, 0);
- return SECFailure;
+ return cachedResponseResult;
}
- if (stapledOCSPResponseErrorCode != 0) {
+ if (stapledOCSPResponseResult != Success) {
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: returning SECFailure from expired "
"stapled response after OCSP request failure"));
- PR_SetError(stapledOCSPResponseErrorCode, 0);
- return SECFailure;
+ return stapledOCSPResponseResult;
}
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: returning SECSuccess after "
"OCSP request failure"));
- return SECSuccess; // Soft fail -> success :(
+ return Success; // Soft fail -> success :(
}
// If the response from the network has expired but indicates a revoked
// or unknown certificate, PR_GetError() will return the appropriate error.
// We actually ignore expired here.
bool expired;
- SECStatus rv = VerifyAndMaybeCacheEncodedOCSPResponse(certID, time,
- maxOCSPLifetimeInDays,
- *response,
- ResponseIsFromNetwork,
- expired);
- if (rv == SECSuccess || mOCSPFetching != FetchOCSPForDVSoftFail) {
+ rv = VerifyAndMaybeCacheEncodedOCSPResponse(certID, time,
+ maxOCSPLifetimeInDays,
+ *response, ResponseIsFromNetwork,
+ expired);
+ if (rv == Success || mOCSPFetching != FetchOCSPForDVSoftFail) {
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: returning after VerifyEncodedOCSPResponse"));
return rv;
}
- error = PR_GetError();
- if (error == SEC_ERROR_OCSP_UNKNOWN_CERT ||
- error == SEC_ERROR_REVOKED_CERTIFICATE) {
+ if (rv == Result::ERROR_OCSP_UNKNOWN_CERT ||
+ rv == Result::ERROR_REVOKED_CERTIFICATE) {
return rv;
}
-
- if (stapledOCSPResponseErrorCode != 0) {
+ if (stapledOCSPResponseResult != Success) {
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: returning SECFailure from expired stapled "
"response after OCSP request verification failure"));
- PR_SetError(stapledOCSPResponseErrorCode, 0);
- return SECFailure;
+ return stapledOCSPResponseResult;
}
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: end of CheckRevocation"));
- return SECSuccess; // Soft fail -> success :(
+ return Success; // Soft fail -> success :(
}
-SECStatus
+Result
NSSCertDBTrustDomain::VerifyAndMaybeCacheEncodedOCSPResponse(
const CertID& certID, PRTime time, uint16_t maxLifetimeInDays,
const SECItem& encodedResponse, EncodedResponseSource responseSource,
/*out*/ bool& expired)
{
PRTime thisUpdate = 0;
PRTime validThrough = 0;
- SECStatus rv = VerifyEncodedOCSPResponse(*this, certID, time,
- maxLifetimeInDays, encodedResponse,
- expired, &thisUpdate, &validThrough);
- PRErrorCode error = (rv == SECSuccess ? 0 : PR_GetError());
+ Result rv = VerifyEncodedOCSPResponse(*this, certID, time,
+ maxLifetimeInDays, encodedResponse,
+ expired, &thisUpdate, &validThrough);
// If a response was stapled and expired, we don't want to cache it. Return
// early to simplify the logic here.
if (responseSource == ResponseWasStapled && expired) {
- PR_ASSERT(rv != SECSuccess);
+ PR_ASSERT(rv != Success);
return rv;
}
// validThrough is only trustworthy if the response successfully verifies
// or it indicates a revoked or unknown certificate.
// If this isn't the case, store an indication of failure (to prevent
// repeatedly requesting a response from a failing server).
- if (rv != SECSuccess && error != SEC_ERROR_REVOKED_CERTIFICATE &&
- error != SEC_ERROR_OCSP_UNKNOWN_CERT) {
+ if (rv != Success && rv != Result::ERROR_REVOKED_CERTIFICATE &&
+ rv != Result::ERROR_OCSP_UNKNOWN_CERT) {
validThrough = time + ServerFailureDelay;
}
if (responseSource == ResponseIsFromNetwork ||
- rv == SECSuccess ||
- error == SEC_ERROR_REVOKED_CERTIFICATE ||
- error == SEC_ERROR_OCSP_UNKNOWN_CERT) {
+ rv == Success ||
+ rv == Result::ERROR_REVOKED_CERTIFICATE ||
+ rv == Result::ERROR_OCSP_UNKNOWN_CERT) {
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: caching OCSP response"));
- if (mOCSPCache.Put(certID, error, thisUpdate, validThrough) != SECSuccess) {
- return SECFailure;
+ Result putRV = mOCSPCache.Put(certID, rv, thisUpdate, validThrough);
+ if (putRV != Success) {
+ return putRV;
}
}
- // If the verification failed, re-set to that original error
- // (the call to Put may have un-set it).
- if (rv != SECSuccess) {
- PR_SetError(error, 0);
- }
return rv;
}
-SECStatus
+Result
NSSCertDBTrustDomain::IsChainValid(const DERArray& certArray)
{
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
("NSSCertDBTrustDomain: Top of IsChainValid mCheckChainCallback=%p",
mCheckChainCallback));
if (!mBuiltChain && !mCheckChainCallback) {
// No need to create a CERTCertList, and nothing else to do.
- return SECSuccess;
+ return Success;
}
ScopedCERTCertList certList;
- SECStatus rv = ConstructCERTCertListFromReversedDERArray(certArray, certList);
- if (rv != SECSuccess) {
- return rv;
+ SECStatus srv = ConstructCERTCertListFromReversedDERArray(certArray,
+ certList);
+ if (srv != SECSuccess) {
+ return MapPRErrorCodeToResult(PR_GetError());
}
if (mCheckChainCallback) {
if (!mCheckChainCallback->isChainValid) {
- PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
- return SECFailure;
+ return Result::FATAL_ERROR_INVALID_ARGS;
}
PRBool chainOK;
- rv = (mCheckChainCallback->isChainValid)(
+ srv = (mCheckChainCallback->isChainValid)(
mCheckChainCallback->isChainValidArg, certList.get(), &chainOK);
- if (rv != SECSuccess) {
- return rv;
+ if (srv != SECSuccess) {
+ return MapPRErrorCodeToResult(PR_GetError());
}
if (!chainOK) {
- PR_SetError(PSM_ERROR_KEY_PINNING_FAILURE, 0);
- return SECFailure;
+ return Result::ERROR_KEY_PINNING_FAILURE;
}
}
if (mBuiltChain) {
*mBuiltChain = certList.forget();
}
- return SECSuccess;
+ return Success;
}
-SECStatus
+Result
NSSCertDBTrustDomain::CheckPublicKey(const SECItem& subjectPublicKeyInfo)
{
return ::mozilla::pkix::CheckPublicKey(subjectPublicKeyInfo);
}
namespace {
static char*
--- a/security/certverifier/NSSCertDBTrustDomain.h
+++ b/security/certverifier/NSSCertDBTrustDomain.h
@@ -36,61 +36,67 @@ void UnloadLoadableRoots(const char* mod
char* DefaultServerNicknameForCert(CERTCertificate* cert);
void SaveIntermediateCerts(const ScopedCERTCertList& certList);
class NSSCertDBTrustDomain : public mozilla::pkix::TrustDomain
{
public:
+ typedef mozilla::pkix::Result Result;
+
enum OCSPFetching {
NeverFetchOCSP = 0,
FetchOCSPForDVSoftFail = 1,
FetchOCSPForDVHardFail = 2,
FetchOCSPForEV = 3,
LocalOnlyOCSPForEV = 4,
};
NSSCertDBTrustDomain(SECTrustType certDBTrustType, OCSPFetching ocspFetching,
OCSPCache& ocspCache, void* pinArg,
CertVerifier::ocsp_get_config ocspGETConfig,
/*optional*/ CERTChainVerifyCallback* checkChainCallback = nullptr,
/*optional*/ ScopedCERTCertList* builtChain = nullptr);
- virtual SECStatus FindIssuer(const SECItem& encodedIssuerName,
- IssuerChecker& checker, PRTime time);
+ virtual Result FindIssuer(const SECItem& encodedIssuerName,
+ IssuerChecker& checker,
+ PRTime time) MOZ_OVERRIDE;
- virtual SECStatus GetCertTrust(mozilla::pkix::EndEntityOrCA endEntityOrCA,
- const mozilla::pkix::CertPolicyId& policy,
- const SECItem& candidateCertDER,
- /*out*/ mozilla::pkix::TrustLevel* trustLevel);
+ virtual Result GetCertTrust(mozilla::pkix::EndEntityOrCA endEntityOrCA,
+ const mozilla::pkix::CertPolicyId& policy,
+ const SECItem& candidateCertDER,
+ /*out*/ mozilla::pkix::TrustLevel* trustLevel)
+ MOZ_OVERRIDE;
- virtual SECStatus VerifySignedData(
- const mozilla::pkix::SignedDataWithSignature& signedData,
- const SECItem& subjectPublicKeyInfo);
+ virtual Result CheckPublicKey(const SECItem& subjectPublicKeyInfo)
+ MOZ_OVERRIDE;
- virtual SECStatus DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
- size_t digestBufLen);
+ virtual Result VerifySignedData(
+ const mozilla::pkix::SignedDataWithSignature& signedData,
+ const SECItem& subjectPublicKeyInfo) MOZ_OVERRIDE;
+
+ virtual Result DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
+ size_t digestBufLen) MOZ_OVERRIDE;
- virtual SECStatus CheckRevocation(mozilla::pkix::EndEntityOrCA endEntityOrCA,
- const mozilla::pkix::CertID& certID,
- PRTime time,
- /*optional*/ const SECItem* stapledOCSPResponse,
- /*optional*/ const SECItem* aiaExtension);
+ virtual Result CheckRevocation(mozilla::pkix::EndEntityOrCA endEntityOrCA,
+ const mozilla::pkix::CertID& certID,
+ PRTime time,
+ /*optional*/ const SECItem* stapledOCSPResponse,
+ /*optional*/ const SECItem* aiaExtension) MOZ_OVERRIDE;
- virtual SECStatus IsChainValid(const mozilla::pkix::DERArray& certChain);
-
- virtual SECStatus CheckPublicKey(const SECItem& subjectPublicKeyInfo);
+ virtual Result IsChainValid(const mozilla::pkix::DERArray& certChain)
+ MOZ_OVERRIDE;
private:
enum EncodedResponseSource {
ResponseIsFromNetwork = 1,
ResponseWasStapled = 2
};
static const PRTime ServerFailureDelay = 5 * 60 * PR_USEC_PER_SEC;
- SECStatus VerifyAndMaybeCacheEncodedOCSPResponse(
+ Result VerifyAndMaybeCacheEncodedOCSPResponse(
const mozilla::pkix::CertID& certID, PRTime time,
uint16_t maxLifetimeInDays, const SECItem& encodedResponse,
EncodedResponseSource responseSource, /*out*/ bool& expired);
const SECTrustType mCertDBTrustType;
const OCSPFetching mOCSPFetching;
OCSPCache& mOCSPCache; // non-owning!
void* mPinArg; // non-owning!
--- a/security/certverifier/OCSPCache.cpp
+++ b/security/certverifier/OCSPCache.cpp
@@ -23,17 +23,17 @@
*/
#include "OCSPCache.h"
#include <limits>
#include "NSSCertDBTrustDomain.h"
#include "pk11pub.h"
-#include "pkix/pkixtypes.h"
+#include "pkix/pkixnss.h"
#include "ScopedNSSTypes.h"
#include "secerr.h"
#ifdef PR_LOGGING
extern PRLogModuleInfo* gCertVerifierLog;
#endif
using namespace mozilla::pkix;
@@ -79,24 +79,28 @@ CertIDHash(SHA384Buffer& buf, const Cert
uint32_t outLen = 0;
rv = PK11_DigestFinal(context.get(), buf, &outLen, SHA384_LENGTH);
if (outLen != SHA384_LENGTH) {
return SECFailure;
}
return rv;
}
-SECStatus
-OCSPCache::Entry::Init(const CertID& aCertID, PRErrorCode aErrorCode,
+Result
+OCSPCache::Entry::Init(const CertID& aCertID, Result aResult,
PRTime aThisUpdate, PRTime aValidThrough)
{
- mErrorCode = aErrorCode;
+ mResult = aResult;
mThisUpdate = aThisUpdate;
mValidThrough = aValidThrough;
- return CertIDHash(mIDHash, aCertID);
+ SECStatus srv = CertIDHash(mIDHash, aCertID);
+ if (srv != SECSuccess) {
+ return MapPRErrorCodeToResult(PR_GetError());
+ }
+ return Success;
}
OCSPCache::OCSPCache()
: mMutex("OCSPCache-mutex")
{
}
OCSPCache::~OCSPCache()
@@ -145,123 +149,117 @@ OCSPCache::MakeMostRecentlyUsed(size_t a
Entry* entry = mEntries[aIndex];
// Since mEntries is sorted with the most-recently-used entry at the end,
// aIndex is likely to be near the end, so this is likely to be fast.
mEntries.erase(mEntries.begin() + aIndex);
mEntries.append(entry);
}
bool
-OCSPCache::Get(const CertID& aCertID, PRErrorCode& aErrorCode,
- PRTime& aValidThrough)
+OCSPCache::Get(const CertID& aCertID, Result& aResult, PRTime& aValidThrough)
{
MutexAutoLock lock(mMutex);
size_t index;
if (!FindInternal(aCertID, index, lock)) {
LogWithCertID("OCSPCache::Get(%p) not in cache", aCertID);
return false;
}
LogWithCertID("OCSPCache::Get(%p) in cache", aCertID);
- aErrorCode = mEntries[index]->mErrorCode;
+ aResult = mEntries[index]->mResult;
aValidThrough = mEntries[index]->mValidThrough;
MakeMostRecentlyUsed(index, lock);
return true;
}
-SECStatus
-OCSPCache::Put(const CertID& aCertID, PRErrorCode aErrorCode,
+Result
+OCSPCache::Put(const CertID& aCertID, Result aResult,
PRTime aThisUpdate, PRTime aValidThrough)
{
MutexAutoLock lock(mMutex);
size_t index;
if (FindInternal(aCertID, index, lock)) {
// Never replace an entry indicating a revoked certificate.
- if (mEntries[index]->mErrorCode == SEC_ERROR_REVOKED_CERTIFICATE) {
+ if (mEntries[index]->mResult == Result::ERROR_REVOKED_CERTIFICATE) {
LogWithCertID("OCSPCache::Put(%p) already in cache as revoked - "
"not replacing", aCertID);
MakeMostRecentlyUsed(index, lock);
- return SECSuccess;
+ return Success;
}
// Never replace a newer entry with an older one unless the older entry
// indicates a revoked certificate, which we want to remember.
if (mEntries[index]->mThisUpdate > aThisUpdate &&
- aErrorCode != SEC_ERROR_REVOKED_CERTIFICATE) {
+ aResult != Result::ERROR_REVOKED_CERTIFICATE) {
LogWithCertID("OCSPCache::Put(%p) already in cache with more recent "
"validity - not replacing", aCertID);
MakeMostRecentlyUsed(index, lock);
- return SECSuccess;
+ return Success;
}
// Only known good responses or responses indicating an unknown
// or revoked certificate should replace previously known responses.
- if (aErrorCode != 0 && aErrorCode != SEC_ERROR_OCSP_UNKNOWN_CERT &&
- aErrorCode != SEC_ERROR_REVOKED_CERTIFICATE) {
+ if (aResult != Success &&
+ aResult != Result::ERROR_OCSP_UNKNOWN_CERT &&
+ aResult != Result::ERROR_REVOKED_CERTIFICATE) {
LogWithCertID("OCSPCache::Put(%p) already in cache - not replacing "
"with less important status", aCertID);
MakeMostRecentlyUsed(index, lock);
- return SECSuccess;
+ return Success;
}
LogWithCertID("OCSPCache::Put(%p) already in cache - replacing", aCertID);
- mEntries[index]->mErrorCode = aErrorCode;
+ mEntries[index]->mResult = aResult;
mEntries[index]->mThisUpdate = aThisUpdate;
mEntries[index]->mValidThrough = aValidThrough;
MakeMostRecentlyUsed(index, lock);
- return SECSuccess;
+ return Success;
}
if (mEntries.length() == MaxEntries) {
LogWithCertID("OCSPCache::Put(%p) too full - evicting an entry", aCertID);
for (Entry** toEvict = mEntries.begin(); toEvict != mEntries.end();
toEvict++) {
// Never evict an entry that indicates a revoked or unknokwn certificate,
// because revoked responses are more security-critical to remember.
- if ((*toEvict)->mErrorCode != SEC_ERROR_REVOKED_CERTIFICATE &&
- (*toEvict)->mErrorCode != SEC_ERROR_OCSP_UNKNOWN_CERT) {
+ if ((*toEvict)->mResult != Result::ERROR_REVOKED_CERTIFICATE &&
+ (*toEvict)->mResult != Result::ERROR_OCSP_UNKNOWN_CERT) {
delete *toEvict;
mEntries.erase(toEvict);
break;
}
}
// Well, we tried, but apparently everything is revoked or unknown.
// We don't want to remove a cached revoked or unknown response. If we're
// trying to insert a good response, we can just return "successfully"
// without doing so. This means we'll lose some speed, but it's not a
// security issue. If we're trying to insert a revoked or unknown response,
// we can't. We should return with an error that causes the current
// verification to fail.
if (mEntries.length() == MaxEntries) {
- if (aErrorCode != 0) {
- PR_SetError(aErrorCode, 0);
- return SECFailure;
- }
- return SECSuccess;
+ return aResult;
}
}
- Entry* newEntry = new Entry();
+ Entry* newEntry = new (std::nothrow) Entry();
// Normally we don't have to do this in Gecko, because OOM is fatal.
// However, if we want to embed this in another project, OOM might not
// be fatal, so handle this case.
if (!newEntry) {
- PR_SetError(SEC_ERROR_NO_MEMORY, 0);
- return SECFailure;
+ return Result::FATAL_ERROR_NO_MEMORY;
}
- SECStatus rv = newEntry->Init(aCertID, aErrorCode, aThisUpdate,
- aValidThrough);
- if (rv != SECSuccess) {
+ Result rv = newEntry->Init(aCertID, aResult, aThisUpdate, aValidThrough);
+ if (rv != Success) {
delete newEntry;
return rv;
}
mEntries.append(newEntry);
LogWithCertID("OCSPCache::Put(%p) added to cache", aCertID);
- return SECSuccess;
+ return Success;
}
void
OCSPCache::Clear()
{
MutexAutoLock lock(mMutex);
PR_LOG(gCertVerifierLog, PR_LOG_DEBUG, ("OCSPCache::Clear: clearing cache"));
// First go through and delete the memory being pointed to by the pointers
--- a/security/certverifier/OCSPCache.h
+++ b/security/certverifier/OCSPCache.h
@@ -23,16 +23,17 @@
*/
#ifndef mozilla_psm_OCSPCache_h
#define mozilla_psm_OCSPCache_h
#include "hasht.h"
#include "mozilla/Mutex.h"
#include "mozilla/Vector.h"
+#include "pkix/Result.h"
#include "prerror.h"
#include "prtime.h"
#include "seccomon.h"
namespace mozilla { namespace pkix {
struct CertID;
} } // namespace mozilla::pkix
@@ -53,41 +54,44 @@ public:
OCSPCache();
~OCSPCache();
// Returns true if the status of the given certificate (issued by the given
// issuer) is in the cache, and false otherwise.
// If it is in the cache, returns by reference the error code of the cached
// status and the time through which the status is considered trustworthy.
bool Get(const mozilla::pkix::CertID& aCertID,
- /* out */ PRErrorCode& aErrorCode, /* out */ PRTime& aValidThrough);
+ /*out*/ mozilla::pkix::Result& aResult,
+ /*out*/ PRTime& aValidThrough);
// Caches the status of the given certificate (issued by the given issuer).
// The status is considered trustworthy through the given time.
// A status with an error code of SEC_ERROR_REVOKED_CERTIFICATE will not
// be replaced or evicted.
// A status with an error code of SEC_ERROR_OCSP_UNKNOWN_CERT will not
// be evicted when the cache is full.
// A status with a more recent thisUpdate will not be replaced with a
// status with a less recent thisUpdate unless the less recent status
// indicates the certificate is revoked.
- SECStatus Put(const mozilla::pkix::CertID& aCertID, PRErrorCode aErrorCode,
- PRTime aThisUpdate, PRTime aValidThrough);
+ mozilla::pkix::Result Put(const mozilla::pkix::CertID& aCertID,
+ mozilla::pkix::Result aResult, PRTime aThisUpdate,
+ PRTime aValidThrough);
// Removes everything from the cache.
void Clear();
private:
class Entry
{
public:
- SECStatus Init(const mozilla::pkix::CertID& aCertID, PRErrorCode aErrorCode,
- PRTime aThisUpdate, PRTime aValidThrough);
+ mozilla::pkix::Result Init(const mozilla::pkix::CertID& aCertID,
+ mozilla::pkix::Result aResult,
+ PRTime aThisUpdate, PRTime aValidThrough);
- PRErrorCode mErrorCode;
+ mozilla::pkix::Result mResult;
PRTime mThisUpdate;
PRTime mValidThrough;
// The SHA-384 hash of the concatenation of the DER encodings of the
// issuer name and issuer key, followed by the serial number.
// See the documentation for CertIDHash in OCSPCache.cpp.
SHA384Buffer mIDHash;
};
--- a/security/certverifier/moz.build
+++ b/security/certverifier/moz.build
@@ -27,16 +27,17 @@ DIRS += [
]
CXXFLAGS += ['-Wall']
if CONFIG['_MSC_VER']:
# -Wall with Visual C++ enables too many problematic warnings
CXXFLAGS += [
'-wd4480', # nonstandard extension used: specifying underlying type for
# enum 'enum'
+ '-wd4481', # nonstandard extension used: override specifier 'keyword'
'-wd4510', # default constructor could not be generated
'-wd4512', # assignment operator could not be generated
'-wd4514', # 'function': unreferenced inline function has been removed
'-wd4610', # struct 'symbol' can never be instantiated - user defined
# constructor required
'-wd4619', # pragma warning: there is no warning 'warning'
'-wd4625', # copy constructor could not be generated because a base
# class copy constructor is inaccessible or deleted
--- a/security/manager/ssl/src/NSSErrorsService.cpp
+++ b/security/manager/ssl/src/NSSErrorsService.cpp
@@ -1,50 +1,40 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "NSSErrorsService.h"
#include "nsNSSComponent.h"
#include "nsServiceManagerUtils.h"
+#include "pkix/pkixnss.h"
#include "secerr.h"
#include "sslerr.h"
#define PIPNSS_STRBUNDLE_URL "chrome://pipnss/locale/pipnss.properties"
#define NSSERR_STRBUNDLE_URL "chrome://pipnss/locale/nsserrors.properties"
namespace mozilla {
namespace psm {
-static const struct PRErrorMessage PSMErrorTableText[] = {
- { "PSM_ERROR_KEY_PINNING_FAILURE",
- "The server uses key pinning (HPKP) but no trusted certificate chain "
- "could be constructed that matches the pinset. Key pinning violations "
- "cannot be overridden." }
-};
-
-static const struct PRErrorTable PSMErrorTable = {
- PSMErrorTableText,
- "psmerrors",
- nsINSSErrorsService::PSM_ERROR_BASE,
- PR_ARRAY_SIZE(PSMErrorTableText)
-};
-
-void
-RegisterPSMErrorTable()
-{
- PR_ErrorInstallTable(&PSMErrorTable);
-}
+static_assert(mozilla::pkix::ERROR_BASE ==
+ nsINSSErrorsService::PSM_ERROR_BASE,
+ "mozilla::pkix::ERROR_BASE and "
+ "nsINSSErrorsService::PSM_ERROR_BASE do not match.");
+static_assert(mozilla::pkix::ERROR_LIMIT ==
+ nsINSSErrorsService::PSM_ERROR_LIMIT,
+ "PSM_ERROR_LIMIT and "
+ "nsINSSErrorsService::PSM_ERROR_LIMIT do not match.");
static bool
IsPSMError(PRErrorCode error)
{
- return (error >= nsINSSErrorsService::PSM_ERROR_BASE &&
- error < nsINSSErrorsService::PSM_ERROR_LIMIT);
+ return (error >= mozilla::pkix::ERROR_BASE &&
+ error < mozilla::pkix::ERROR_LIMIT);
}
NS_IMPL_ISUPPORTS(NSSErrorsService, nsINSSErrorsService)
NSSErrorsService::~NSSErrorsService() { }
nsresult
NSSErrorsService::Init()
--- a/security/manager/ssl/src/NSSErrorsService.h
+++ b/security/manager/ssl/src/NSSErrorsService.h
@@ -1,31 +1,24 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef NSSErrorsService_h
#define NSSErrorsService_h
#include "nsINSSErrorsService.h"
-
#include "mozilla/Attributes.h"
#include "nsCOMPtr.h"
#include "nsIStringBundle.h"
#include "prerror.h"
namespace mozilla {
namespace psm {
-enum PSMErrorCodes {
- PSM_ERROR_KEY_PINNING_FAILURE = (nsINSSErrorsService::PSM_ERROR_BASE + 0)
-};
-
-void RegisterPSMErrorTable();
-
class NSSErrorsService MOZ_FINAL : public nsINSSErrorsService
{
NS_DECL_ISUPPORTS
NS_DECL_NSINSSERRORSSERVICE
public:
nsresult Init();
--- a/security/manager/ssl/src/nsNSSComponent.cpp
+++ b/security/manager/ssl/src/nsNSSComponent.cpp
@@ -46,16 +46,17 @@
#include "nsIBufEntropyCollector.h"
#include "nsITokenPasswordDialogs.h"
#include "nsServiceManagerUtils.h"
#include "nsNSSShutDown.h"
#include "SharedSSLState.h"
#include "NSSErrorsService.h"
#include "nss.h"
+#include "pkix/pkixnss.h"
#include "ssl.h"
#include "sslproto.h"
#include "secmod.h"
#include "secerr.h"
#include "sslerr.h"
#include "nsXULAppAPI.h"
@@ -1204,17 +1205,17 @@ nsNSSComponent::InitializeNSS()
setValidationOptions(true, lock);
mHttpForNSS.initTable();
#ifndef MOZ_DISABLE_CRYPTOLEGACY
LaunchSmartCardThreads();
#endif
- RegisterPSMErrorTable();
+ mozilla::pkix::RegisterErrorTable();
PR_LOG(gPIPNSSLog, PR_LOG_DEBUG, ("NSS Initialization done\n"));
return NS_OK;
}
void
nsNSSComponent::ShutdownNSS()
{
--- a/security/manager/ssl/tests/gtest/OCSPCacheTest.cpp
+++ b/security/manager/ssl/tests/gtest/OCSPCacheTest.cpp
@@ -26,30 +26,31 @@ class OCSPCacheTest : public ::testing::
NSS_NoDB_Init(nullptr);
mozilla::psm::InitCertVerifierLog();
}
mozilla::psm::OCSPCache cache;
};
static void
-PutAndGet(OCSPCache& cache, const CertID& certID, PRErrorCode error,
+PutAndGet(OCSPCache& cache, const CertID& certID, Result result,
PRTime time)
{
// The first time is thisUpdate. The second is validUntil.
// The caller is expecting the validUntil returned with Get
// to be equal to the passed-in time. Since these values will
// be different in practice, make thisUpdate less than validUntil.
ASSERT_TRUE(time >= 10);
- SECStatus rv = cache.Put(certID, error, time - 10, time);
- ASSERT_TRUE(rv == SECSuccess);
- PRErrorCode errorOut;
+ Result rv = cache.Put(certID, result, time - 10, time);
+ ASSERT_TRUE(rv == Success);
+ Result resultOut;
PRTime timeOut;
- ASSERT_TRUE(cache.Get(certID, errorOut, timeOut));
- ASSERT_TRUE(error == errorOut && time == timeOut);
+ ASSERT_TRUE(cache.Get(certID, resultOut, timeOut));
+ ASSERT_EQ(result, resultOut);
+ 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 = {
@@ -77,69 +78,75 @@ TEST_F(OCSPCacheTest, TestPutAndGet)
};
static const SECItem fakeSerial001 = {
siBuffer,
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("001")),
3
};
SCOPED_TRACE("");
- PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial001), 0, PR_Now());
- PRErrorCode errorOut;
+ PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial001),
+ Success, PR_Now());
+ Result resultOut;
PRTime timeOut;
ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey001, fakeSerial000),
- errorOut, timeOut));
+ resultOut, timeOut));
}
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
};
- PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial), 0, timeIn + i);
+ PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial),
+ Success, timeIn + i);
}
- PRErrorCode errorOut;
+ Result resultOut;
PRTime timeOut;
// This will be at the end of the list in the cache
CertID cert0000(fakeIssuer1, fakeKey000, fakeSerial0000);
- ASSERT_TRUE(cache.Get(cert0000, errorOut, timeOut));
- ASSERT_TRUE(errorOut == 0 && timeOut == timeIn);
+ ASSERT_TRUE(cache.Get(cert0000, resultOut, timeOut));
+ ASSERT_EQ(Success, resultOut);
+ ASSERT_EQ(timeIn, timeOut);
// Once we access it, it goes to the front
- ASSERT_TRUE(cache.Get(cert0000, errorOut, timeOut));
- ASSERT_TRUE(errorOut == 0 && timeOut == timeIn);
+ ASSERT_TRUE(cache.Get(cert0000, resultOut, timeOut));
+ ASSERT_EQ(Success, resultOut);
+ 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
};
CertID cert0512(fakeIssuer1, fakeKey000, fakeSerial0512);
- ASSERT_TRUE(cache.Get(cert0512, errorOut, timeOut));
- ASSERT_TRUE(errorOut == 0 && timeOut == timeIn + 512);
- ASSERT_TRUE(cache.Get(cert0512, errorOut, timeOut));
- ASSERT_TRUE(errorOut == 0 && timeOut == timeIn + 512);
+ ASSERT_TRUE(cache.Get(cert0512, resultOut, timeOut));
+ ASSERT_EQ(Success, resultOut);
+ ASSERT_EQ(timeIn + 512, timeOut);
+ ASSERT_TRUE(cache.Get(cert0512, resultOut, timeOut));
+ ASSERT_EQ(Success, resultOut);
+ 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
};
ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey000, fakeSerial1111),
- errorOut, timeOut));
+ resultOut, timeOut));
}
TEST_F(OCSPCacheTest, TestEviction)
{
SCOPED_TRACE("");
PRTime timeIn = PR_Now();
// By putting more distinct entries in the cache than it can hold,
@@ -147,99 +154,100 @@ TEST_F(OCSPCacheTest, TestEviction)
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
};
- PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial), 0, timeIn + i);
+ PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial),
+ Success, timeIn + i);
}
- PRErrorCode errorOut;
+ Result resultOut;
PRTime timeOut;
ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey001, fakeSerial0000),
- errorOut, timeOut));
+ resultOut, timeOut));
}
TEST_F(OCSPCacheTest, TestNoEvictionForRevokedResponses)
{
SCOPED_TRACE("");
PRTime timeIn = PR_Now();
CertID notEvicted(fakeIssuer1, fakeKey000, fakeSerial0000);
- PutAndGet(cache, notEvicted, SEC_ERROR_REVOKED_CERTIFICATE, timeIn);
+ PutAndGet(cache, notEvicted, Result::ERROR_REVOKED_CERTIFICATE, timeIn);
// 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
};
- PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial), 0, timeIn + i);
+ PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial),
+ Success, timeIn + i);
}
- PRErrorCode errorOut;
+ Result resultOut;
PRTime timeOut;
- ASSERT_TRUE(cache.Get(notEvicted, errorOut, timeOut));
- ASSERT_TRUE(errorOut == SEC_ERROR_REVOKED_CERTIFICATE && timeOut == timeIn);
+ ASSERT_TRUE(cache.Get(notEvicted, resultOut, timeOut));
+ 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
};
CertID evicted(fakeIssuer1, fakeKey000, fakeSerial0001);
- ASSERT_FALSE(cache.Get(evicted, errorOut, timeOut));
+ ASSERT_FALSE(cache.Get(evicted, resultOut, timeOut));
}
TEST_F(OCSPCacheTest, TestEverythingIsRevoked)
{
SCOPED_TRACE("");
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
};
PutAndGet(cache, CertID(fakeIssuer1, fakeKey000, fakeSerial),
- SEC_ERROR_REVOKED_CERTIFICATE, timeIn + i);
+ Result::ERROR_REVOKED_CERTIFICATE, timeIn + i);
}
const SECItem fakeSerial1025 = {
siBuffer,
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("1025")),
4
};
CertID good(fakeIssuer1, fakeKey000, fakeSerial1025);
// This will "succeed", allowing verification to continue. However,
// nothing was actually put in the cache.
- SECStatus result = cache.Put(good, 0, timeIn + 1025 - 50, timeIn + 1025);
- ASSERT_TRUE(result == SECSuccess);
- PRErrorCode errorOut;
+ Result result = cache.Put(good, Success, timeIn + 1025 - 50, timeIn + 1025);
+ ASSERT_EQ(Success, result);
+ Result resultOut;
PRTime timeOut;
- ASSERT_FALSE(cache.Get(good, errorOut, timeOut));
+ ASSERT_FALSE(cache.Get(good, resultOut, timeOut));
const SECItem fakeSerial1026 = {
siBuffer,
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("1026")),
4
};
CertID revoked(fakeIssuer1, fakeKey000, fakeSerial1026);
// This will fail, causing verification to fail.
- result = cache.Put(revoked, SEC_ERROR_REVOKED_CERTIFICATE,
+ result = cache.Put(revoked, Result::ERROR_REVOKED_CERTIFICATE,
timeIn + 1026 - 50, timeIn + 1026);
- PRErrorCode error = PR_GetError();
- ASSERT_TRUE(result == SECFailure);
- ASSERT_TRUE(error == SEC_ERROR_REVOKED_CERTIFICATE);
+ ASSERT_EQ(Result::ERROR_REVOKED_CERTIFICATE, result);
}
TEST_F(OCSPCacheTest, VariousIssuers)
{
SCOPED_TRACE("");
static const SECItem fakeIssuer2 = {
siBuffer,
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("CN=issuer2")),
@@ -248,68 +256,73 @@ TEST_F(OCSPCacheTest, VariousIssuers)
static const SECItem fakeSerial001 = {
siBuffer,
const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>("001")),
3
};
PRTime timeIn = PR_Now();
CertID subject(fakeIssuer1, fakeKey000, fakeSerial001);
- PutAndGet(cache, subject, 0, timeIn);
- PRErrorCode errorOut;
+ PutAndGet(cache, subject, Success, timeIn);
+ Result resultOut;
PRTime timeOut;
- ASSERT_TRUE(cache.Get(subject, errorOut, timeOut));
- ASSERT_TRUE(errorOut == 0 && timeOut == timeIn);
+ ASSERT_TRUE(cache.Get(subject, resultOut, timeOut));
+ ASSERT_EQ(Success, resultOut);
+ ASSERT_EQ(timeIn, timeOut);
// Test that we don't match a different issuer DN
ASSERT_FALSE(cache.Get(CertID(fakeIssuer2, fakeKey000, fakeSerial001),
- errorOut, timeOut));
+ resultOut, timeOut));
// Test that we don't match a different issuer key
ASSERT_FALSE(cache.Get(CertID(fakeIssuer1, fakeKey001, fakeSerial001),
- errorOut, timeOut));
+ resultOut, timeOut));
}
TEST_F(OCSPCacheTest, Times)
{
SCOPED_TRACE("");
CertID certID(fakeIssuer1, fakeKey000, fakeSerial0000);
- PutAndGet(cache, certID, SEC_ERROR_OCSP_UNKNOWN_CERT, 100);
- PutAndGet(cache, certID, 0, 200);
+ PutAndGet(cache, certID, Result::ERROR_OCSP_UNKNOWN_CERT, 100);
+ PutAndGet(cache, certID, Success, 200);
// This should not override the more recent entry.
- ASSERT_EQ(SECSuccess, cache.Put(certID, SEC_ERROR_OCSP_UNKNOWN_CERT, 100,
- 100));
- PRErrorCode errorOut;
+ ASSERT_EQ(Success,
+ cache.Put(certID, Result::ERROR_OCSP_UNKNOWN_CERT, 100, 100));
+ Result resultOut;
PRTime timeOut;
- ASSERT_TRUE(cache.Get(certID, errorOut, timeOut));
+ ASSERT_TRUE(cache.Get(certID, resultOut, timeOut));
// Here we see the more recent time.
- ASSERT_TRUE(errorOut == 0 && timeOut == 200);
+ ASSERT_EQ(Success, resultOut);
+ ASSERT_EQ(200, timeOut);
- // SEC_ERROR_REVOKED_CERTIFICATE overrides everything
- PutAndGet(cache, certID, SEC_ERROR_REVOKED_CERTIFICATE, 50);
+ // Result::ERROR_REVOKED_CERTIFICATE overrides everything
+ PutAndGet(cache, certID, Result::ERROR_REVOKED_CERTIFICATE, 50);
}
TEST_F(OCSPCacheTest, NetworkFailure)
{
SCOPED_TRACE("");
CertID certID(fakeIssuer1, fakeKey000, fakeSerial0000);
- PutAndGet(cache, certID, PR_CONNECT_REFUSED_ERROR, 100);
- PutAndGet(cache, certID, 0, 200);
+ PutAndGet(cache, certID, Result::ERROR_CONNECT_REFUSED, 100);
+ PutAndGet(cache, certID, Success, 200);
// This should not override the already present entry.
- SECStatus rv = cache.Put(certID, PR_CONNECT_REFUSED_ERROR, 300, 350);
- ASSERT_TRUE(rv == SECSuccess);
- PRErrorCode errorOut;
+ ASSERT_EQ(Success,
+ cache.Put(certID, Result::ERROR_CONNECT_REFUSED, 300, 350));
+ Result resultOut;
PRTime timeOut;
- ASSERT_TRUE(cache.Get(certID, errorOut, timeOut));
- ASSERT_TRUE(errorOut == 0 && timeOut == 200);
+ ASSERT_TRUE(cache.Get(certID, resultOut, timeOut));
+ ASSERT_EQ(Success, resultOut);
+ ASSERT_EQ(200, timeOut);
- PutAndGet(cache, certID, SEC_ERROR_OCSP_UNKNOWN_CERT, 400);
+ PutAndGet(cache, certID, Result::ERROR_OCSP_UNKNOWN_CERT, 400);
// This should not override the already present entry.
- rv = cache.Put(certID, PR_CONNECT_REFUSED_ERROR, 500, 550);
- ASSERT_TRUE(rv == SECSuccess);
- ASSERT_TRUE(cache.Get(certID, errorOut, timeOut));
- ASSERT_TRUE(errorOut == SEC_ERROR_OCSP_UNKNOWN_CERT && timeOut == 400);
+ ASSERT_EQ(Success,
+ cache.Put(certID, Result::ERROR_CONNECT_REFUSED, 500, 550));
+ ASSERT_TRUE(cache.Get(certID, resultOut, timeOut));
+ ASSERT_EQ(Result::ERROR_OCSP_UNKNOWN_CERT, resultOut);
+ ASSERT_EQ(400, timeOut);
- PutAndGet(cache, certID, SEC_ERROR_REVOKED_CERTIFICATE, 600);
+ PutAndGet(cache, certID, Result::ERROR_REVOKED_CERTIFICATE, 600);
// This should not override the already present entry.
- rv = cache.Put(certID, PR_CONNECT_REFUSED_ERROR, 700, 750);
- ASSERT_TRUE(rv == SECSuccess);
- ASSERT_TRUE(cache.Get(certID, errorOut, timeOut));
- ASSERT_TRUE(errorOut == SEC_ERROR_REVOKED_CERTIFICATE && timeOut == 600);
+ ASSERT_EQ(Success,
+ cache.Put(certID, Result::ERROR_CONNECT_REFUSED, 700, 750));
+ ASSERT_TRUE(cache.Get(certID, resultOut, timeOut));
+ ASSERT_EQ(Result::ERROR_REVOKED_CERTIFICATE, resultOut);
+ ASSERT_EQ(600, timeOut);
}
--- a/security/manager/ssl/tests/unit/head_psm.js
+++ b/security/manager/ssl/tests/unit/head_psm.js
@@ -15,17 +15,17 @@ let { ctypes } = Cu.import("resource://g
let gIsWindows = ("@mozilla.org/windows-registry-key;1" in Cc);
const isDebugBuild = Cc["@mozilla.org/xpcom/debug;1"]
.getService(Ci.nsIDebug2).isDebugBuild;
const SEC_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SEC_ERROR_BASE;
const SSL_ERROR_BASE = Ci.nsINSSErrorsService.NSS_SSL_ERROR_BASE;
-const PSM_ERROR_BASE = Ci.nsINSSErrorsService.PSM_ERROR_BASE;
+const MOZILLA_PKIX_ERROR_BASE = Ci.nsINSSErrorsService.PSM_ERROR_BASE;
// Sort in numerical order
const SEC_ERROR_INVALID_ARGS = SEC_ERROR_BASE + 5; // -8187
const SEC_ERROR_BAD_DER = SEC_ERROR_BASE + 9;
const SEC_ERROR_EXPIRED_CERTIFICATE = SEC_ERROR_BASE + 11;
const SEC_ERROR_REVOKED_CERTIFICATE = SEC_ERROR_BASE + 12; // -8180
const SEC_ERROR_UNKNOWN_ISSUER = SEC_ERROR_BASE + 13;
const SEC_ERROR_BAD_DATABASE = SEC_ERROR_BASE + 18;
@@ -53,17 +53,17 @@ const SEC_ERROR_OCSP_OLD_RESPONSE
const SEC_ERROR_OCSP_INVALID_SIGNING_CERT = SEC_ERROR_BASE + 144;
const SEC_ERROR_POLICY_VALIDATION_FAILED = SEC_ERROR_BASE + 160; // -8032
const SEC_ERROR_OCSP_BAD_SIGNATURE = SEC_ERROR_BASE + 157;
const SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED = SEC_ERROR_BASE + 176;
const SEC_ERROR_APPLICATION_CALLBACK_ERROR = SEC_ERROR_BASE + 178;
const SSL_ERROR_BAD_CERT_DOMAIN = SSL_ERROR_BASE + 12;
-const PSM_ERROR_KEY_PINNING_FAILURE = PSM_ERROR_BASE + 0;
+const MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE = MOZILLA_PKIX_ERROR_BASE + 0;
// Supported Certificate Usages
const certificateUsageSSLClient = 0x0001;
const certificateUsageSSLServer = 0x0002;
const certificateUsageSSLCA = 0x0008;
const certificateUsageEmailSigner = 0x0010;
const certificateUsageEmailRecipient = 0x0020;
const certificateUsageObjectSigner = 0x0040;
--- a/security/manager/ssl/tests/unit/test_pinning.js
+++ b/security/manager/ssl/tests/unit/test_pinning.js
@@ -34,17 +34,17 @@ function test_strict() {
// test mode.
add_test(function() {
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 2);
run_next_test();
});
// Issued by otherCA, which is not in the pinset for pinning.example.com.
add_connection_test("bad.include-subdomains.pinning.example.com",
- getXPCOMStatusFromNSS(PSM_ERROR_KEY_PINNING_FAILURE));
+ getXPCOMStatusFromNSS(MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE));
// These domains serve certs that match the pinset.
add_connection_test("include-subdomains.pinning.example.com", Cr.NS_OK);
add_connection_test("good.include-subdomains.pinning.example.com", Cr.NS_OK);
add_connection_test("exclude-subdomains.pinning.example.com", Cr.NS_OK);
// This domain serves a cert that doesn't match the pinset, but subdomains
// are excluded.
@@ -96,33 +96,33 @@ function test_enforce_test_mode() {
// In enforce test mode, we always enforce all pins, even test pins.
add_test(function() {
Services.prefs.setIntPref("security.cert_pinning.enforcement_level", 3);
run_next_test();
});
// Issued by otherCA, which is not in the pinset for pinning.example.com.
add_connection_test("bad.include-subdomains.pinning.example.com",
- getXPCOMStatusFromNSS(PSM_ERROR_KEY_PINNING_FAILURE));
+ getXPCOMStatusFromNSS(MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE));
// These domains serve certs that match the pinset.
add_connection_test("include-subdomains.pinning.example.com", Cr.NS_OK);
add_connection_test("good.include-subdomains.pinning.example.com", Cr.NS_OK);
add_connection_test("exclude-subdomains.pinning.example.com", Cr.NS_OK);
// This domain serves a cert that doesn't match the pinset, but subdomains
// are excluded.
add_connection_test("sub.exclude-subdomains.pinning.example.com", Cr.NS_OK);
// This domain's pinset is exactly the same as
// include-subdomains.pinning.example.com, serves the same cert as
// bad.include-subdomains.pinning.example.com, is in test-mode, but we are
// enforcing test mode pins.
add_connection_test("test-mode.pinning.example.com",
- getXPCOMStatusFromNSS(PSM_ERROR_KEY_PINNING_FAILURE));
+ getXPCOMStatusFromNSS(MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE));
}
function check_pinning_telemetry() {
let service = Cc["@mozilla.org/base/telemetry;1"].getService(Ci.nsITelemetry);
let prod_histogram = service.getHistogramById("CERT_PINNING_RESULTS")
.snapshot();
let test_histogram = service.getHistogramById("CERT_PINNING_TEST_RESULTS")
.snapshot();
--- a/security/pkix/include/pkix/Input.h
+++ b/security/pkix/include/pkix/Input.h
@@ -22,16 +22,17 @@
* limitations under the License.
*/
#ifndef mozilla_pkix__Input_h
#define mozilla_pkix__Input_h
#include "pkix/nullptr.h"
#include "pkix/Result.h"
+#include "seccomon.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.
//
@@ -50,21 +51,21 @@ public:
, end(nullptr)
{
}
Result Init(const uint8_t* data, size_t len)
{
if (input) {
// already initialized
- return Fail(SEC_ERROR_INVALID_ARGS);
+ return Result::FATAL_ERROR_INVALID_ARGS;
}
if (!data || len > 0xffffu) {
// input too large
- return Fail(SEC_ERROR_BAD_DER);
+ 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;
@@ -72,17 +73,17 @@ public:
Result Expect(const uint8_t* expected, uint16_t expectedLen)
{
Result rv = EnsureLength(expectedLen);
if (rv != Success) {
return rv;
}
if (memcmp(input, expected, expectedLen)) {
- return Fail(SEC_ERROR_BAD_DER);
+ return Result::ERROR_BAD_DER;
}
input += expectedLen;
return Success;
}
bool Peek(uint8_t expectedByte) const
{
return input < end && *input == expectedByte;
@@ -191,17 +192,17 @@ public:
void SkipToEnd()
{
input = end;
}
Result EnsureLength(uint16_t len)
{
if (static_cast<size_t>(end - input) < len) {
- return Fail(SEC_ERROR_BAD_DER);
+ return Result::ERROR_BAD_DER;
}
return Success;
}
bool AtEnd() const { return input == end; }
class Mark
{
@@ -214,17 +215,17 @@ public:
};
Mark GetMark() const { return Mark(*this, input); }
Result GetSECItem(SECItemType type, const Mark& mark, /*out*/ SECItem& item)
{
if (&mark.input != this || mark.mark > input) {
PR_NOT_REACHED("invalid mark");
- return Fail(SEC_ERROR_INVALID_ARGS);
+ 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;
}
private:
--- a/security/pkix/include/pkix/Result.h
+++ b/security/pkix/include/pkix/Result.h
@@ -20,70 +20,89 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef mozilla_pkix__Result_h
#define mozilla_pkix__Result_h
-#include "prerror.h"
-#include "seccomon.h"
-#include "secerr.h"
+#include "pkix/enumclass.h"
namespace mozilla { namespace pkix {
-enum Result
+static const unsigned int FATAL_ERROR_FLAG = 0x800;
+
+MOZILLA_PKIX_ENUM_CLASS Result
{
Success = 0,
- FatalError = -1, // An error was encountered that caused path building
- // to stop immediately. example: out-of-memory.
- RecoverableError = -2 // an error that will cause path building to continue
- // searching for alternative paths. example: expired
- // certificate.
+
+ ERROR_BAD_DER = 1,
+ ERROR_CA_CERT_INVALID = 2,
+ ERROR_BAD_SIGNATURE = 3,
+ ERROR_CERT_BAD_ACCESS_LOCATION = 4,
+ ERROR_CERT_NOT_IN_NAME_SPACE = 5,
+ ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED = 6,
+ ERROR_CONNECT_REFUSED = 7,
+ ERROR_EXPIRED_CERTIFICATE = 8,
+ ERROR_EXTENSION_VALUE_INVALID = 9,
+ ERROR_INADEQUATE_CERT_TYPE = 10,
+ ERROR_INADEQUATE_KEY_USAGE = 11,
+ ERROR_INVALID_ALGORITHM = 12,
+ ERROR_INVALID_TIME = 13,
+ ERROR_KEY_PINNING_FAILURE = 14,
+ ERROR_PATH_LEN_CONSTRAINT_INVALID = 15,
+ ERROR_POLICY_VALIDATION_FAILED = 16,
+ ERROR_REVOKED_CERTIFICATE = 17,
+ ERROR_UNKNOWN_CRITICAL_EXTENSION = 18,
+ ERROR_UNKNOWN_ISSUER = 19,
+ ERROR_UNTRUSTED_CERT = 20,
+ ERROR_UNTRUSTED_ISSUER = 21,
+
+ ERROR_OCSP_BAD_SIGNATURE = 22,
+ ERROR_OCSP_INVALID_SIGNING_CERT = 23,
+ ERROR_OCSP_MALFORMED_REQUEST = 24,
+ ERROR_OCSP_MALFORMED_RESPONSE = 25,
+ ERROR_OCSP_OLD_RESPONSE = 26,
+ ERROR_OCSP_REQUEST_NEEDS_SIG = 27,
+ ERROR_OCSP_RESPONDER_CERT_INVALID = 28,
+ ERROR_OCSP_SERVER_ERROR = 29,
+ ERROR_OCSP_TRY_SERVER_LATER = 30,
+ ERROR_OCSP_UNAUTHORIZED_REQUEST = 31,
+ ERROR_OCSP_UNKNOWN_RESPONSE_STATUS = 32,
+ ERROR_OCSP_UNKNOWN_CERT = 33,
+ ERROR_OCSP_FUTURE_RESPONSE = 34,
+
+ ERROR_UNKNOWN_ERROR = 35,
+
+ ERROR_INVALID_KEY = 36,
+ ERROR_UNSUPPORTED_KEYALG = 37,
+
+ // Keep this in sync with MAP_LIST in pkixnss.cpp
+
+ FATAL_ERROR_INVALID_ARGS = FATAL_ERROR_FLAG | 1,
+ FATAL_ERROR_INVALID_STATE = FATAL_ERROR_FLAG | 2,
+ FATAL_ERROR_LIBRARY_FAILURE = FATAL_ERROR_FLAG | 3,
+ FATAL_ERROR_NO_MEMORY = FATAL_ERROR_FLAG | 4,
+
+ // Keep this in sync with MAP_LIST in pkixnss.cpp
};
-// When returning errors, use this function instead of calling PR_SetError
-// directly. This helps ensure that we always call PR_SetError when we return
-// an error code. This is a useful place to set a breakpoint when a debugging
-// a certificate verification failure.
-inline Result
-Fail(Result result, PRErrorCode errorCode)
-{
- PR_ASSERT(result != Success);
- PR_SetError(errorCode, 0);
- return result;
-}
-
-inline Result
-MapSECStatus(SECStatus srv)
-{
- if (srv == SECSuccess) {
- return Success;
- }
+// We write many comparisons as (x != Success), and this shortened name makes
+// those comparisons clearer, especially because the shortened name often
+// results in less line wrapping.
+//
+// Visual Studio before VS2013 does not support "enum class," so
+// Result::Success will already be visible in this scope, and compilation will
+// fail if we try to define a variable with that name here.
+#if !defined(_MSC_VER) || (_MSC_VER >= 1700)
+static const Result Success = Result::Success;
+#endif
- PRErrorCode error = PORT_GetError();
- switch (error) {
- case SEC_ERROR_EXTENSION_NOT_FOUND:
- return RecoverableError;
-
- case PR_INVALID_STATE_ERROR:
- case SEC_ERROR_INVALID_ARGS:
- case SEC_ERROR_LIBRARY_FAILURE:
- case SEC_ERROR_NO_MEMORY:
- return FatalError;
- }
-
- // TODO: PORT_Assert(false); // we haven't classified the error yet
- return RecoverableError;
-}
-
-inline Result
-Fail(PRErrorCode errorCode)
+inline bool
+IsFatalError(Result rv)
{
- PR_ASSERT(errorCode != 0);
- PR_SetError(errorCode, 0);
- return mozilla::pkix::MapSECStatus(SECFailure);
+ return static_cast<unsigned int>(rv) & FATAL_ERROR_FLAG;
}
} } // namespace mozilla::pkix
#endif // mozilla_pkix__Result_h
--- a/security/pkix/include/pkix/pkix.h
+++ b/security/pkix/include/pkix/pkix.h
@@ -20,19 +20,17 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef mozilla_pkix__pkix_h
#define mozilla_pkix__pkix_h
-#include "pkix/nullptr.h"
#include "pkixtypes.h"
-#include "prtime.h"
namespace mozilla { namespace pkix {
// ----------------------------------------------------------------------------
// LIMITED SUPPORT FOR CERTIFICATE POLICIES
//
// If SEC_OID_X509_ANY_POLICY is passed as the value of the requiredPolicy
// parameter then all policy validation will be skipped. Otherwise, path
@@ -55,93 +53,74 @@ namespace mozilla { namespace pkix {
//
// BuildCertChain prioritizes certain checks ahead of others so that when a
// certificate chain has multiple errors, the "most serious" error is
// returned. In practice, this ranking of seriousness is tied directly to how
// Firefox's certificate error override mechanism.
//
// The ranking is:
//
-// 1. Active distrust (SEC_ERROR_UNTRUSTED_CERT).
+// 1. Active distrust (Result::ERROR_UNTRUSTED_CERT).
// 2. Problems with issuer-independent properties for CA certificates.
-// 3. Unknown issuer (SEC_ERROR_UNKNOWN_ISSUER).
+// 3. Unknown issuer (Result::ERROR_UNKNOWN_ISSUER).
// 4. Problems with issuer-independent properties for EE certificates.
// 5. Revocation.
//
-// In particular, if BuildCertChain returns SEC_ERROR_UNKNOWN_ISSUER then the
-// caller can call CERT_CheckCertValidTimes to determine if the certificate is
-// ALSO expired.
+// In particular, if BuildCertChain returns Result::ERROR_UNKNOWN_ISSUER then
+// the caller can call CERT_CheckCertValidTimes to determine if the certificate
+// is ALSO expired.
//
// It would be better if revocation were prioritized above expiration and
// unknown issuer. However, it is impossible to do revocation checking without
// knowing the issuer, since the issuer information is needed to validate the
// revocation information. Also, generally revocation checking only works
// during the validity period of the certificate.
//
// In general, when path building fails, BuildCertChain will return
-// SEC_ERROR_UNKNOWN_ISSUER. However, if all attempted paths resulted in the
-// same error (which is trivially true when there is only one potential path),
-// more specific errors will be returned.
+// Result::ERROR_UNKNOWN_ISSUER. However, if all attempted paths resulted in
+// the same error (which is trivially true when there is only one potential
+// path), more specific errors will be returned.
//
// ----------------------------------------------------------------------------
// Meaning of specific error codes
//
-// SEC_ERROR_UNTRUSTED_CERT means that the end-entity certificate was actively
-// distrusted.
-// SEC_ERROR_UNTRUSTED_ISSUER means that path building failed because of active
-// distrust.
+// Result::ERROR_UNTRUSTED_CERT means that the end-entity certificate was
+// actively distrusted.
+// Result::SEC_ERROR_UNTRUSTED_ISSUER means that path building failed because
+// of active distrust.
// TODO(bug 968451): Document more of these.
-SECStatus BuildCertChain(TrustDomain& trustDomain, const SECItem& cert,
- PRTime time, EndEntityOrCA endEntityOrCA,
- KeyUsage requiredKeyUsageIfPresent,
- KeyPurposeId requiredEKUIfPresent,
- const CertPolicyId& requiredPolicy,
- /*optional*/ const SECItem* stapledOCSPResponse);
+Result BuildCertChain(TrustDomain& trustDomain, const SECItem& cert,
+ PRTime time, EndEntityOrCA endEntityOrCA,
+ KeyUsage requiredKeyUsageIfPresent,
+ KeyPurposeId requiredEKUIfPresent,
+ const CertPolicyId& requiredPolicy,
+ /*optional*/ const SECItem* stapledOCSPResponse);
-// Verify the given signed data using the given public key.
-SECStatus VerifySignedData(const SignedDataWithSignature& sd,
- const SECItem& subjectPublicKeyInfo,
- void* pkcs11PinArg);
-
-// The return value, if non-null, is owned by the arena and MUST NOT be freed.
-SECItem* CreateEncodedOCSPRequest(TrustDomain& trustDomain, PLArenaPool* arena,
- const CertID& certID);
+static const size_t OCSP_REQUEST_MAX_LENGTH = 127;
+Result CreateEncodedOCSPRequest(TrustDomain& trustDomain,
+ const struct CertID& certID,
+ /*out*/ uint8_t (&out)[OCSP_REQUEST_MAX_LENGTH],
+ /*out*/ size_t& outLen);
// The out parameter expired will be true if the response has expired. If the
// response also indicates a revoked or unknown certificate, that error
-// will be returned by PR_GetError(). Otherwise, SEC_ERROR_OCSP_OLD_RESPONSE
-// will be returned by PR_GetError() for an expired response.
+// will be returned. Otherwise, REsult::ERROR_OCSP_OLD_RESPONSE will be
+// returned for an expired response.
+//
// The optional parameter thisUpdate will be the thisUpdate value of
// the encoded response if it is considered trustworthy. Only
// good, unknown, or revoked responses that verify correctly are considered
// trustworthy. If the response is not trustworthy, thisUpdate will be 0.
// Similarly, the optional parameter validThrough will be the time through
// which the encoded response is considered trustworthy (that is, if a response had a
// thisUpdate time of validThrough, it would be considered trustworthy).
-SECStatus VerifyEncodedOCSPResponse(TrustDomain& trustDomain,
- const CertID& certID, PRTime time,
- uint16_t maxLifetimeInDays,
- const SECItem& encodedResponse,
- /* out */ bool& expired,
- /* optional out */ PRTime* thisUpdate = nullptr,
- /* optional out */ PRTime* validThrough = nullptr);
-
-// Computes the SHA-1 hash of the data in the current item.
-//
-// item contains the data to hash.
-// digestBuf must point to a buffer to where the SHA-1 hash will be written.
-// digestBufLen must be 20 (the length of a SHA-1 hash,
-// TrustDomain::DIGEST_LENGTH).
-//
-// TODO(bug 966856): Add SHA-2 support
-// 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.
-SECStatus DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
- size_t digestBufLen);
-
-// Checks, for RSA keys and DSA keys, that the modulus is at least 1024 bits.
-SECStatus CheckPublicKey(const SECItem& subjectPublicKeyInfo);
+Result VerifyEncodedOCSPResponse(TrustDomain& trustDomain,
+ const CertID& certID, PRTime time,
+ uint16_t maxLifetimeInDays,
+ const SECItem& encodedResponse,
+ /* out */ bool& expired,
+ /* optional out */ PRTime* thisUpdate = nullptr,
+ /* optional out */ PRTime* validThrough = nullptr);
} } // namespace mozilla::pkix
#endif // mozilla_pkix__pkix_h
new file mode 100644
--- /dev/null
+++ b/security/pkix/include/pkix/pkixnss.h
@@ -0,0 +1,81 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef mozilla_pkix__pkixnss_h
+#define mozilla_pkix__pkixnss_h
+
+#include "pkixtypes.h"
+#include "prerror.h"
+#include "seccomon.h"
+
+namespace mozilla { namespace pkix {
+
+// Verify the given signed data using the given public key.
+Result VerifySignedData(const SignedDataWithSignature& sd,
+ const SECItem& subjectPublicKeyInfo,
+ void* pkcs11PinArg);
+
+// Computes the SHA-1 hash of the data in the current item.
+//
+// item contains the data to hash.
+// digestBuf must point to a buffer to where the SHA-1 hash will be written.
+// digestBufLen must be 20 (the length of a SHA-1 hash,
+// TrustDomain::DIGEST_LENGTH).
+//
+// TODO(bug 966856): Add SHA-2 support
+// 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,
+ size_t digestBufLen);
+
+// Checks, for RSA keys and DSA keys, that the modulus is at least 1024 bits.
+Result CheckPublicKey(const SECItem& subjectPublicKeyInfo);
+
+Result MapPRErrorCodeToResult(PRErrorCode errorCode);
+PRErrorCode MapResultToPRErrorCode(Result result);
+
+// Returns the stringified name of the given result, e.g. "Result::Success",
+// or nullptr if result is unknown (invalid).
+const char* MapResultToName(Result result);
+
+// The error codes within each module must fit in 16 bits. We want these
+// errors to fit in the same module as the NSS errors but not overlap with
+// any of them. Converting an NSS SEC, NSS SSL, or PSM error to an NS error
+// involves negating the value of the error and then synthesizing an error
+// in the NS_ERROR_MODULE_SECURITY module. Hence, PSM errors will start at
+// a negative value that both doesn't overlap with the current value
+// ranges for NSS errors and that will fit in 16 bits when negated.
+static const PRErrorCode ERROR_BASE = -0x4000;
+static const PRErrorCode ERROR_LIMIT = ERROR_BASE + 1000;
+
+enum ErrorCode {
+ MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE = ERROR_BASE + 0
+};
+
+void RegisterErrorTable();
+
+} } // namespace mozilla::pkix
+
+#endif // mozilla_pkix__pkixnss_h
--- a/security/pkix/include/pkix/pkixtypes.h
+++ b/security/pkix/include/pkix/pkixtypes.h
@@ -20,17 +20,17 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef mozilla_pkix__pkixtypes_h
#define mozilla_pkix__pkixtypes_h
-#include "pkix/enumclass.h"
+#include "pkix/Result.h"
#include "pkix/nullptr.h"
#include "prtime.h"
#include "seccomon.h"
#include "stdint.h"
namespace mozilla { namespace pkix {
MOZILLA_PKIX_ENUM_CLASS DigestAlgorithm
@@ -193,34 +193,34 @@ public:
// When policy.IsAnyPolicy(), then no policy-related checking should be done.
// When !policy.IsAnyPolicy(), then GetCertTrust MUST NOT return with
// *trustLevel == TrustAnchor unless the given cert is considered a trust
// anchor *for that policy*. In particular, if the user has marked an
// intermediate certificate as trusted, but that intermediate isn't in the
// list of EV roots, then GetCertTrust must result in
// *trustLevel == InheritsTrust instead of *trustLevel == TrustAnchor
// (assuming the candidate cert is not actively distrusted).
- virtual SECStatus GetCertTrust(EndEntityOrCA endEntityOrCA,
- const CertPolicyId& policy,
- const SECItem& candidateCertDER,
- /*out*/ TrustLevel* trustLevel) = 0;
+ virtual Result GetCertTrust(EndEntityOrCA endEntityOrCA,
+ const CertPolicyId& policy,
+ const SECItem& candidateCertDER,
+ /*out*/ TrustLevel* trustLevel) = 0;
class IssuerChecker
{
public:
// potentialIssuerDER is the complete DER encoding of the certificate to
// be checked as a potential issuer.
//
// If additionalNameConstraints is not nullptr then it must point to an
// encoded NameConstraints extension value; in that case, those name
// constraints will be checked in addition to any any name constraints
// contained in potentialIssuerDER.
- virtual SECStatus Check(const SECItem& potentialIssuerDER,
- /*optional*/ const SECItem* additionalNameConstraints,
- /*out*/ bool& keepGoing) = 0;
+ virtual Result Check(const SECItem& potentialIssuerDER,
+ /*optional*/ const SECItem* additionalNameConstraints,
+ /*out*/ bool& keepGoing) = 0;
protected:
IssuerChecker();
virtual ~IssuerChecker();
private:
IssuerChecker(const IssuerChecker&) /*= delete*/;
void operator=(const IssuerChecker&) /*= delete*/;
};
@@ -260,18 +260,18 @@ public:
// [...]
// TrustDomain::FindIssuer
// [...]
// IssuerChecker::Check
// [...]
//
// checker.Check is responsible for limiting the recursion to a reasonable
// limit.
- virtual SECStatus FindIssuer(const SECItem& encodedIssuerName,
- IssuerChecker& checker, PRTime time) = 0;
+ virtual Result FindIssuer(const SECItem& encodedIssuerName,
+ IssuerChecker& checker, PRTime time) = 0;
// Called as soon as we think we have a valid chain but before revocation
// checks are done. This function can be used to compute additional checks,
// especilaly checks that require the entire certificate chain. This callback
// can also be used to save a copy of the built certificate chain for later
// use.
//
// This function may be called multiple times, regardless of whether it
@@ -284,57 +284,56 @@ public:
// Keep in mind, in particular, that if the application saves a copy of the
// certificate chain the last invocation of IsChainValid during a validation,
// it is still possible for BuildCertChain to fail (return SECFailure), in
// which case the application must not assume anything about the validity of
// the last certificate chain passed to IsChainValid; especially, it would be
// very wrong to assume that the certificate chain is valid.
//
// certChain.GetDER(0) is the trust anchor.
- virtual SECStatus IsChainValid(const DERArray& certChain) = 0;
+ virtual Result IsChainValid(const DERArray& certChain) = 0;
// issuerCertToDup is only non-const so CERT_DupCertificate can be called on
// it.
- virtual SECStatus CheckRevocation(EndEntityOrCA endEntityOrCA,
- const CertID& certID, PRTime time,
- /*optional*/ const SECItem* stapledOCSPresponse,
- /*optional*/ const SECItem* aiaExtension) = 0;
+ virtual Result CheckRevocation(EndEntityOrCA endEntityOrCA,
+ const CertID& certID, PRTime time,
+ /*optional*/ const SECItem* stapledOCSPresponse,
+ /*optional*/ const SECItem* aiaExtension) = 0;
+
+ // Check that the key size, algorithm, and parameters of the given public key
+ // are acceptable.
+ //
+ // 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;
// Verify the given signature using the given public key.
//
// Most implementations of this function should probably forward the call
// directly to mozilla::pkix::VerifySignedData.
//
// In any case, the implementation must perform checks on the public key
// similar to how mozilla::pkix::CheckPublicKey() does.
- virtual SECStatus VerifySignedData(const SignedDataWithSignature& signedData,
- const SECItem& subjectPublicKeyInfo) = 0;
+ virtual Result VerifySignedData(const SignedDataWithSignature& signedData,
+ const SECItem& subjectPublicKeyInfo) = 0;
// Compute the SHA-1 hash of the data in the current item.
//
// item contains the data to hash.
// digestBuf must point to a buffer to where the SHA-1 hash will be written.
// digestBufLen must be DIGEST_LENGTH (20, the length of a SHA-1 hash).
//
// TODO(bug 966856): Add SHA-2 support
// 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.
static const size_t DIGEST_LENGTH = 20; // length of SHA-1 digest
- virtual SECStatus DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
- size_t digestBufLen) = 0;
-
- // Check that the key size, algorithm, and parameters of the given public key
- // are acceptable.
- //
- // 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 SECStatus CheckPublicKey(const SECItem& subjectPublicKeyInfo) = 0;
-
+ virtual Result DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
+ size_t digestBufLen) = 0;
protected:
TrustDomain() { }
private:
TrustDomain(const TrustDomain&) /* = delete */;
void operator=(const TrustDomain&) /* = delete */;
};
--- a/security/pkix/lib/pkixbuild.cpp
+++ b/security/pkix/lib/pkixbuild.cpp
@@ -54,158 +54,152 @@ public:
unsigned int subCACount)
: trustDomain(trustDomain)
, subject(subject)
, time(time)
, requiredEKUIfPresent(requiredEKUIfPresent)
, requiredPolicy(requiredPolicy)
, stapledOCSPResponse(stapledOCSPResponse)
, subCACount(subCACount)
- , result(SEC_ERROR_LIBRARY_FAILURE)
+ , result(Result::FATAL_ERROR_LIBRARY_FAILURE)
, resultWasSet(false)
{
}
- SECStatus Check(const SECItem& potentialIssuerDER,
- /*optional*/ const SECItem* additionalNameConstraints,
- /*out*/ bool& keepGoing);
+ Result Check(const SECItem& potentialIssuerDER,
+ /*optional*/ const SECItem* additionalNameConstraints,
+ /*out*/ bool& keepGoing);
Result CheckResult() const;
private:
TrustDomain& trustDomain;
const BackCert& subject;
const PRTime time;
const KeyPurposeId requiredEKUIfPresent;
const CertPolicyId& requiredPolicy;
/*optional*/ SECItem const* const stapledOCSPResponse;
const unsigned int subCACount;
- SECStatus RecordResult(PRErrorCode currentResult, /*out*/ bool& keepGoing);
- PRErrorCode result;
+ Result RecordResult(Result currentResult, /*out*/ bool& keepGoing);
+ Result result;
bool resultWasSet;
PathBuildingStep(const PathBuildingStep&) /*= delete*/;
void operator=(const PathBuildingStep&) /*= delete*/;
};
-SECStatus
-PathBuildingStep::RecordResult(PRErrorCode newResult,
- /*out*/ bool& keepGoing)
+Result
+PathBuildingStep::RecordResult(Result newResult, /*out*/ bool& keepGoing)
{
- if (newResult == SEC_ERROR_UNTRUSTED_CERT) {
- newResult = SEC_ERROR_UNTRUSTED_ISSUER;
+ if (newResult == Result::ERROR_UNTRUSTED_CERT) {
+ newResult = Result::ERROR_UNTRUSTED_ISSUER;
}
+
if (resultWasSet) {
- if (result == 0) {
+ if (result == Success) {
PR_NOT_REACHED("RecordResult called after finding a chain");
- PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
- return SECFailure;
+ return Result::FATAL_ERROR_INVALID_STATE;
}
// If every potential issuer has the same problem (e.g. expired) and/or if
// there is only one bad potential issuer, then return a more specific
// error. Otherwise, punt on trying to decide which error should be
- // returned by returning the generic SEC_ERROR_UNKNOWN_ISSUER error.
- if (newResult != 0 && newResult != result) {
- newResult = SEC_ERROR_UNKNOWN_ISSUER;
+ // returned by returning the generic Result::ERROR_UNKNOWN_ISSUER error.
+ if (newResult != Success && newResult != result) {
+ newResult = Result::ERROR_UNKNOWN_ISSUER;
}
}
result = newResult;
resultWasSet = true;
- keepGoing = result != 0;
- return SECSuccess;
+ keepGoing = result != Success;
+ return Success;
}
Result
PathBuildingStep::CheckResult() const
{
if (!resultWasSet) {
- return Fail(RecoverableError, SEC_ERROR_UNKNOWN_ISSUER);
+ return Result::ERROR_UNKNOWN_ISSUER;
}
- if (result == 0) {
- return Success;
- }
- PR_SetError(result, 0);
- return MapSECStatus(SECFailure);
+ return result;
}
// The code that executes in the inner loop of BuildForward
-SECStatus
+Result
PathBuildingStep::Check(const SECItem& potentialIssuerDER,
/*optional*/ const SECItem* additionalNameConstraints,
/*out*/ bool& keepGoing)
{
BackCert potentialIssuer(potentialIssuerDER, EndEntityOrCA::MustBeCA,
&subject);
Result rv = potentialIssuer.Init();
if (rv != Success) {
- return RecordResult(PR_GetError(), keepGoing);
+ return RecordResult(rv, keepGoing);
}
// RFC5280 4.2.1.1. Authority Key Identifier
// RFC5280 4.2.1.2. Subject Key Identifier
// Loop prevention, done as recommended by RFC4158 Section 5.2
// TODO: this doesn't account for subjectAltNames!
// TODO(perf): This probably can and should be optimized in some way.
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())) {
// XXX: error code
- return RecordResult(SEC_ERROR_UNKNOWN_ISSUER, keepGoing);
+ return RecordResult(Result::ERROR_UNKNOWN_ISSUER, keepGoing);
}
}
if (potentialIssuer.GetNameConstraints()) {
rv = CheckNameConstraints(*potentialIssuer.GetNameConstraints(),
subject, requiredEKUIfPresent);
if (rv != Success) {
- return RecordResult(PR_GetError(), keepGoing);
+ return RecordResult(rv, keepGoing);
}
}
if (additionalNameConstraints) {
rv = CheckNameConstraints(*additionalNameConstraints, subject,
requiredEKUIfPresent);
if (rv != Success) {
- return RecordResult(PR_GetError(), keepGoing);
+ return RecordResult(rv, keepGoing);
}
}
// RFC 5280, Section 4.2.1.3: "If the keyUsage extension is present, then the
// subject public key MUST NOT be used to verify signatures on certificates
// or CRLs unless the corresponding keyCertSign or cRLSign bit is set."
rv = BuildForward(trustDomain, potentialIssuer, time, KeyUsage::keyCertSign,
requiredEKUIfPresent, requiredPolicy, nullptr, subCACount);
if (rv != Success) {
- return RecordResult(PR_GetError(), keepGoing);
+ return RecordResult(rv, keepGoing);
}
- SECStatus srv = trustDomain.VerifySignedData(
- subject.GetSignedData(),
- potentialIssuer.GetSubjectPublicKeyInfo());
- if (srv != SECSuccess) {
- return RecordResult(PR_GetError(), keepGoing);
+ rv = trustDomain.VerifySignedData(subject.GetSignedData(),
+ potentialIssuer.GetSubjectPublicKeyInfo());
+ if (rv != Success) {
+ return RecordResult(rv, keepGoing);
}
CertID certID(subject.GetIssuer(), potentialIssuer.GetSubjectPublicKeyInfo(),
subject.GetSerialNumber());
- srv = trustDomain.CheckRevocation(subject.endEntityOrCA, certID, time,
- stapledOCSPResponse,
- subject.GetAuthorityInfoAccess());
- if (srv != SECSuccess) {
- return RecordResult(PR_GetError(), keepGoing);
+ rv = trustDomain.CheckRevocation(subject.endEntityOrCA, certID, time,
+ stapledOCSPResponse,
+ subject.GetAuthorityInfoAccess());
+ if (rv != Success) {
+ return RecordResult(rv, keepGoing);
}
- return RecordResult(0/*PRErrorCode::success*/, keepGoing);
+ return RecordResult(Success, keepGoing);
}
// Recursively build the path from the given subject certificate to the root.
//
// Be very careful about changing the order of checks. The order is significant
// because it affects which error we return when a certificate or certificate
// chain has multiple problems. See the error ranking documentation in
// pkix/pkix.h.
@@ -224,116 +218,107 @@ BuildForward(TrustDomain& trustDomain,
TrustLevel trustLevel;
// If this is an end-entity and not a trust anchor, we defer reporting
// any error found here until after attempting to find a valid chain.
// See the explanation of error prioritization in pkix.h.
rv = CheckIssuerIndependentProperties(trustDomain, subject, time,
requiredKeyUsageIfPresent,
requiredEKUIfPresent, requiredPolicy,
subCACount, &trustLevel);
- PRErrorCode deferredEndEntityError = 0;
+ Result deferredEndEntityError = Success;
if (rv != Success) {
if (subject.endEntityOrCA == EndEntityOrCA::MustBeEndEntity &&
trustLevel != TrustLevel::TrustAnchor) {
- deferredEndEntityError = PR_GetError();
+ deferredEndEntityError = rv;
} else {
return rv;
}
}
if (trustLevel == TrustLevel::TrustAnchor) {
// End of the recursion.
NonOwningDERArray chain;
for (const BackCert* cert = &subject; cert; cert = cert->childCert) {
- Result rv = chain.Append(cert->GetDER());
+ rv = chain.Append(cert->GetDER());
if (rv != Success) {
PR_NOT_REACHED("NonOwningDERArray::SetItem failed.");
return rv;
}
}
// This must be done here, after the chain is built but before any
// revocation checks have been done.
- SECStatus srv = trustDomain.IsChainValid(chain);
- if (srv != SECSuccess) {
- return MapSECStatus(srv);
- }
-
- return Success;
+ return trustDomain.IsChainValid(chain);
}
if (subject.endEntityOrCA == EndEntityOrCA::MustBeCA) {
// Avoid stack overflows and poor performance by limiting cert chain
// length.
static const unsigned int MAX_SUBCA_COUNT = 6;
static_assert(1/*end-entity*/ + MAX_SUBCA_COUNT + 1/*root*/ ==
NonOwningDERArray::MAX_LENGTH,
"MAX_SUBCA_COUNT and NonOwningDERArray::MAX_LENGTH mismatch.");
if (subCACount >= MAX_SUBCA_COUNT) {
- return Fail(RecoverableError, SEC_ERROR_UNKNOWN_ISSUER);
+ return Result::ERROR_UNKNOWN_ISSUER;
}
++subCACount;
} else {
PR_ASSERT(subCACount == 0);
}
// Find a trusted issuer.
PathBuildingStep pathBuilder(trustDomain, subject, time,
requiredEKUIfPresent, requiredPolicy,
stapledOCSPResponse, subCACount);
// TODO(bug 965136): Add SKI/AKI matching optimizations
- if (trustDomain.FindIssuer(subject.GetIssuer(), pathBuilder, time)
- != SECSuccess) {
- return MapSECStatus(SECFailure);
+ rv = trustDomain.FindIssuer(subject.GetIssuer(), pathBuilder, time);
+ if (rv != Success) {
+ return rv;
}
rv = pathBuilder.CheckResult();
if (rv != Success) {
return rv;
}
// If we found a valid chain but deferred reporting an error with the
// end-entity certificate, report it now.
- if (deferredEndEntityError != 0) {
- return Fail(RecoverableError, deferredEndEntityError);
+ if (deferredEndEntityError != Success) {
+ return deferredEndEntityError;
}
// We've built a valid chain from the subject cert up to a trusted root.
return Success;
}
-SECStatus
+Result
BuildCertChain(TrustDomain& trustDomain, const SECItem& certDER,
PRTime time, EndEntityOrCA endEntityOrCA,
KeyUsage requiredKeyUsageIfPresent,
KeyPurposeId requiredEKUIfPresent,
const CertPolicyId& requiredPolicy,
/*optional*/ const SECItem* stapledOCSPResponse)
{
// XXX: Support the legacy use of the subject CN field for indicating the
// domain name the certificate is valid for.
BackCert cert(certDER, endEntityOrCA, nullptr);
Result rv = cert.Init();
if (rv != Success) {
- return SECFailure;
+ return rv;
}
// See documentation for CheckPublicKey() in pkixtypes.h for why the public
// key also needs to be checked here when trustDomain.VerifySignedData()
// should already be doing it.
- if (trustDomain.CheckPublicKey(cert.GetSubjectPublicKeyInfo()) != SECSuccess) {
- return SECFailure;
+ rv = trustDomain.CheckPublicKey(cert.GetSubjectPublicKeyInfo());
+ if (rv != Success) {
+ return rv;
}
- rv = BuildForward(trustDomain, cert, time, requiredKeyUsageIfPresent,
- requiredEKUIfPresent, requiredPolicy, stapledOCSPResponse,
- 0/*subCACount*/);
- if (rv != Success) {
- return SECFailure;
- }
-
- return SECSuccess;
+ return BuildForward(trustDomain, cert, time, requiredKeyUsageIfPresent,
+ requiredEKUIfPresent, requiredPolicy, stapledOCSPResponse,
+ 0/*subCACount*/);
}
} } // namespace mozilla::pkix
--- a/security/pkix/lib/pkixcert.cpp
+++ b/security/pkix/lib/pkixcert.cpp
@@ -180,17 +180,17 @@ BackCert::Init()
// S/MIME Client | false | id_kp_emailProtection
// Object Signing | false | id_kp_codeSigning
// SSL Server CA | true | id_pk_serverAuth
// SSL Client CA | true | id_kp_clientAuth
// S/MIME CA | true | id_kp_emailProtection
// Object Signing CA | true | id_kp_codeSigning
if (criticalNetscapeCertificateType.len > 0 &&
(basicConstraints.len == 0 || extKeyUsage.len == 0)) {
- return Fail(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
+ return Result::ERROR_UNKNOWN_CRITICAL_EXTENSION;
}
}
return der::End(tbsCertificate);
}
Result
BackCert::RememberExtension(Input& extnID, const SECItem& extnValue,
@@ -274,21 +274,21 @@ BackCert::RememberExtension(Input& extnI
} else if (extnID.MatchRest(Netscape_certificate_type) && critical) {
out = &criticalNetscapeCertificateType;
}
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) {
- return Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
+ return Result::ERROR_EXTENSION_VALUE_INVALID;
}
if (out->len != 0) {
// Duplicate extension
- return Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
+ return Result::ERROR_EXTENSION_VALUE_INVALID;
}
*out = extnValue;
understood = true;
}
return Success;
}
--- a/security/pkix/lib/pkixcheck.cpp
+++ b/security/pkix/lib/pkixcheck.cpp
@@ -23,41 +23,42 @@
*/
#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"
namespace mozilla { namespace pkix {
Result
CheckValidity(const SECItem& encodedValidity, PRTime time)
{
Input validity;
if (validity.Init(encodedValidity.data, encodedValidity.len) != Success) {
- return Fail(RecoverableError, SEC_ERROR_EXPIRED_CERTIFICATE);
+ return Result::ERROR_EXPIRED_CERTIFICATE;
}
PRTime notBefore;
if (der::TimeChoice(validity, notBefore) != Success) {
- return Fail(RecoverableError, SEC_ERROR_EXPIRED_CERTIFICATE);
+ return Result::ERROR_EXPIRED_CERTIFICATE;
}
if (time < notBefore) {
- return Fail(RecoverableError, SEC_ERROR_EXPIRED_CERTIFICATE);
+ return Result::ERROR_EXPIRED_CERTIFICATE;
}
PRTime notAfter;
if (der::TimeChoice(validity, notAfter) != Success) {
- return Fail(RecoverableError, SEC_ERROR_EXPIRED_CERTIFICATE);
+ return Result::ERROR_EXPIRED_CERTIFICATE;
}
if (time > notAfter) {
- return Fail(RecoverableError, SEC_ERROR_EXPIRED_CERTIFICATE);
+ return Result::ERROR_EXPIRED_CERTIFICATE;
}
return der::End(validity);
}
// 4.2.1.3. Key Usage (id-ce-keyUsage)
// As explained in the comment in CheckKeyUsage, bit 0 is the most significant
@@ -73,46 +74,46 @@ CheckKeyUsage(EndEntityOrCA endEntityOrC
KeyUsage requiredKeyUsageIfPresent)
{
if (!encodedKeyUsage) {
// TODO(bug 970196): Reject certificates that are being used to verify
// certificate signatures unless the certificate is a trust anchor, to
// reduce the chances of an end-entity certificate being abused as a CA
// certificate.
// if (endEntityOrCA == EndEntityOrCA::MustBeCA && !isTrustAnchor) {
- // return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
+ // return Result::ERROR_INADEQUATE_KEY_USAGE;
// }
//
// TODO: Users may configure arbitrary certificates as trust anchors, not
// just roots. We should only allow a certificate without a key usage to be
// used as a CA when it is self-issued and self-signed.
return Success;
}
Input input;
if (input.Init(encodedKeyUsage->data, encodedKeyUsage->len) != Success) {
- return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
+ return Result::ERROR_INADEQUATE_KEY_USAGE;
}
Input value;
if (der::ExpectTagAndGetValue(input, der::BIT_STRING, value) != Success) {
- return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
+ return Result::ERROR_INADEQUATE_KEY_USAGE;
}
uint8_t numberOfPaddingBits;
if (value.Read(numberOfPaddingBits) != Success) {
- return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
+ return Result::ERROR_INADEQUATE_KEY_USAGE;
}
if (numberOfPaddingBits > 7) {
- return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
+ return Result::ERROR_INADEQUATE_KEY_USAGE;
}
uint8_t bits;
if (value.Read(bits) != Success) {
// Reject empty bit masks.
- return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
+ return Result::ERROR_INADEQUATE_KEY_USAGE;
}
// The most significant bit is numbered 0 (digitalSignature) and the least
// significant bit is numbered 7 (encipherOnly), and the padding is in the
// least significant bits of the last byte. The numbering of bits in a byte
// is backwards from how we usually interpret them.
//
// For example, let's say bits is encoded in one byte with of value 0xB0 and
@@ -143,41 +144,41 @@ CheckKeyUsage(EndEntityOrCA endEntityOrC
//
// Note that since the KeyUsage enumeration is limited to values 0-7, we
// only ever need to examine the first byte test for
// requiredKeyUsageIfPresent.
if (requiredKeyUsageIfPresent != KeyUsage::noParticularKeyUsageRequired) {
// Check that the required key usage bit is set.
if ((bits & KeyUsageToBitMask(requiredKeyUsageIfPresent)) == 0) {
- return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
+ return Result::ERROR_INADEQUATE_KEY_USAGE;
}
}
if (endEntityOrCA != EndEntityOrCA::MustBeCA) {
// RFC 5280 says "The keyCertSign bit is asserted when the subject public
// key is used for verifying signatures on public key certificates. If the
// keyCertSign bit is asserted, then the cA bit in the basic constraints
// extension (Section 4.2.1.9) MUST also be asserted."
if ((bits & KeyUsageToBitMask(KeyUsage::keyCertSign)) != 0) {
- return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
+ return Result::ERROR_INADEQUATE_KEY_USAGE;
}
}
// The padding applies to the last byte, so skip to the last byte.
while (!value.AtEnd()) {
if (value.Read(bits) != Success) {
- return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
+ return Result::ERROR_INADEQUATE_KEY_USAGE;
}
}
// All of the padding bits must be zero, according to DER rules.
uint8_t paddingMask = static_cast<uint8_t>((1 << numberOfPaddingBits) - 1);
if ((bits & paddingMask) != 0) {
- return Fail(RecoverableError, SEC_ERROR_INADEQUATE_KEY_USAGE);
+ return Result::ERROR_INADEQUATE_KEY_USAGE;
}
return Success;
}
// RFC5820 4.2.1.4. Certificate Policies
// "The user-initial-policy-set contains the special value any-policy if the
@@ -234,63 +235,63 @@ Result
CheckCertificatePolicies(EndEntityOrCA endEntityOrCA,
const SECItem* encodedCertificatePolicies,
const SECItem* encodedInhibitAnyPolicy,
TrustLevel trustLevel,
const CertPolicyId& requiredPolicy)
{
if (requiredPolicy.numBytes == 0 ||
requiredPolicy.numBytes > sizeof requiredPolicy.bytes) {
- return Fail(FatalError, SEC_ERROR_INVALID_ARGS);
+ return Result::FATAL_ERROR_INVALID_ARGS;
}
// Ignore all policy information if the caller indicates any policy is
// acceptable. See TrustDomain::GetCertTrust and the policy part of
// BuildCertChain's documentation.
if (requiredPolicy.IsAnyPolicy()) {
return Success;
}
// Bug 989051. Until we handle inhibitAnyPolicy we will fail close when
// inhibitAnyPolicy extension is present and we need to evaluate certificate
// policies.
if (encodedInhibitAnyPolicy) {
- return Fail(RecoverableError, SEC_ERROR_POLICY_VALIDATION_FAILED);
+ return Result::ERROR_POLICY_VALIDATION_FAILED;
}
// The root CA certificate may omit the policies that it has been
// trusted for, so we cannot require the policies to be present in those
// certificates. Instead, the determination of which roots are trusted for
// which policies is made by the TrustDomain's GetCertTrust method.
if (trustLevel == TrustLevel::TrustAnchor &&
endEntityOrCA == EndEntityOrCA::MustBeCA) {
return Success;
}
if (!encodedCertificatePolicies) {
- return Fail(RecoverableError, SEC_ERROR_POLICY_VALIDATION_FAILED);
+ return Result::ERROR_POLICY_VALIDATION_FAILED;
}
bool found = false;
Input input;
if (input.Init(encodedCertificatePolicies->data,
encodedCertificatePolicies->len) != Success) {
- return Fail(RecoverableError, SEC_ERROR_POLICY_VALIDATION_FAILED);
+ return Result::ERROR_POLICY_VALIDATION_FAILED;
}
if (der::NestedOf(input, der::SEQUENCE, der::SEQUENCE, der::EmptyAllowed::No,
bind(CheckPolicyInformation, _1, endEntityOrCA,
requiredPolicy, ref(found))) != Success) {
- return Fail(RecoverableError, SEC_ERROR_POLICY_VALIDATION_FAILED);
+ return Result::ERROR_POLICY_VALIDATION_FAILED;
}
if (der::End(input) != Success) {
- return Fail(RecoverableError, SEC_ERROR_POLICY_VALIDATION_FAILED);
+ return Result::ERROR_POLICY_VALIDATION_FAILED;
}
if (!found) {
- return Fail(RecoverableError, SEC_ERROR_POLICY_VALIDATION_FAILED);
+ return Result::ERROR_POLICY_VALIDATION_FAILED;
}
return Success;
}
static const long UNLIMITED_PATH_LEN = -1; // must be less than zero
// BasicConstraints ::= SEQUENCE {
@@ -302,25 +303,25 @@ DecodeBasicConstraints(Input& input, /*o
{
// TODO(bug 989518): cA is by default false. According to DER, default
// values must not be explicitly encoded in a SEQUENCE. So, if this
// value is present and false, it is an encoding error. However, Go Daddy
// has issued many certificates with this improper encoding, so we can't
// enforce this yet (hence passing true for allowInvalidExplicitEncoding
// to der::OptionalBoolean).
if (der::OptionalBoolean(input, true, isCA) != Success) {
- return Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
+ return Result::ERROR_EXTENSION_VALUE_INVALID;
}
// TODO(bug 985025): If isCA is false, pathLenConstraint MUST NOT
// be included (as per RFC 5280 section 4.2.1.9), but for compatibility
// reasons, we don't check this for now.
if (der::OptionalInteger(input, UNLIMITED_PATH_LEN, pathLenConstraint)
!= Success) {
- return Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
+ return Result::ERROR_EXTENSION_VALUE_INVALID;
}
return Success;
}
// RFC5280 4.2.1.9. Basic Constraints (id-ce-basicConstraints)
Result
CheckBasicConstraints(EndEntityOrCA endEntityOrCA,
@@ -330,25 +331,25 @@ CheckBasicConstraints(EndEntityOrCA endE
{
bool isCA = false;
long pathLenConstraint = UNLIMITED_PATH_LEN;
if (encodedBasicConstraints) {
Input input;
if (input.Init(encodedBasicConstraints->data,
encodedBasicConstraints->len) != Success) {
- return Fail(RecoverableError, SEC_ERROR_EXTENSION_VALUE_INVALID);
+ return Result::ERROR_EXTENSION_VALUE_INVALID;
}
if (der::Nested(input, der::SEQUENCE,
bind(DecodeBasicConstraints, _1, ref(isCA),
ref(pathLenConstraint))) != Success) {
- return Fail(RecoverableError, SEC_ERROR_EXTENSION_VALUE_INVALID);
+ return Result::ERROR_EXTENSION_VALUE_INVALID;
}
if (der::End(input) != Success) {
- return Fail(RecoverableError, SEC_ERROR_EXTENSION_VALUE_INVALID);
+ return Result::ERROR_EXTENSION_VALUE_INVALID;
}
} else {
// "If the basic constraints extension is not present in a version 3
// certificate, or the extension is present but the cA boolean is not
// asserted, then the certified public key MUST NOT be used to verify
// certificate signatures."
//
// For compatibility, we must accept v1 trust anchors without basic
@@ -360,102 +361,103 @@ CheckBasicConstraints(EndEntityOrCA endE
isCA = true;
}
}
if (endEntityOrCA == EndEntityOrCA::MustBeEndEntity) {
// CA certificates are not trusted as EE certs.
if (isCA) {
- // XXX: We use SEC_ERROR_CA_CERT_INVALID here so we can distinguish
- // this error from other errors, given that NSS does not have a "CA cert
- // used as end-entity" error code since it doesn't have such a
+ // TODO(bug 1040446): We use Result::ERROR_CA_CERT_INVALID here so we can
+ // distinguish this error from other errors, given that NSS does not have
+ // a "CA cert used as end-entity" error code since it doesn't have such a
// prohibition. We should add such an error code and stop abusing
- // SEC_ERROR_CA_CERT_INVALID this way.
+ // Result::ERROR_CA_CERT_INVALID this way.
//
// Note, in particular, that this check prevents a delegated OCSP
// response signing certificate with the CA bit from successfully
// validating when we check it from pkixocsp.cpp, which is a good thing.
//
- return Fail(RecoverableError, SEC_ERROR_CA_CERT_INVALID);
+ return Result::ERROR_CA_CERT_INVALID;
}
return Success;
}
PORT_Assert(endEntityOrCA == EndEntityOrCA::MustBeCA);
// End-entity certificates are not allowed to act as CA certs.
if (!isCA) {
- return Fail(RecoverableError, SEC_ERROR_CA_CERT_INVALID);
+ return Result::ERROR_CA_CERT_INVALID;
}
if (pathLenConstraint >= 0 &&
static_cast<long>(subCACount) > pathLenConstraint) {
- return Fail(RecoverableError, SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID);
+ return Result::ERROR_PATH_LEN_CONSTRAINT_INVALID;
}
return Success;
}
// 4.2.1.10. Name Constraints
inline void
PORT_FreeArena_false(PLArenaPool* arena) {
// PL_FreeArenaPool can't be used because it doesn't actually free the
// memory, which doesn't work well with memory analysis tools
return PORT_FreeArena(arena, PR_FALSE);
}
+// TODO: remove #include "pkix/pkixnss.h" when this is rewritten to be
+// independent of NSS.
Result
CheckNameConstraints(const SECItem& encodedNameConstraints,
const BackCert& firstChild,
KeyPurposeId requiredEKUIfPresent)
{
ScopedPtr<PLArenaPool, PORT_FreeArena_false>
arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
if (!arena) {
- return MapSECStatus(SECFailure);
+ return Result::FATAL_ERROR_NO_MEMORY;
}
// Owned by arena
const CERTNameConstraints* constraints =
CERT_DecodeNameConstraintsExtension(arena.get(), &encodedNameConstraints);
if (!constraints) {
- return MapSECStatus(SECFailure);
+ return MapPRErrorCodeToResult(PR_GetError());
}
for (const BackCert* child = &firstChild; child; child = child->childCert) {
ScopedPtr<CERTCertificate, CERT_DestroyCertificate>
nssCert(CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
const_cast<SECItem*>(&child->GetDER()),
nullptr, false, true));
if (!nssCert) {
- return MapSECStatus(SECFailure);
+ return MapPRErrorCodeToResult(PR_GetError());
}
bool includeCN = child->endEntityOrCA == EndEntityOrCA::MustBeEndEntity &&
requiredEKUIfPresent == KeyPurposeId::id_kp_serverAuth;
// owned by arena
const CERTGeneralName*
names(CERT_GetConstrainedCertificateNames(nssCert.get(), arena.get(),
includeCN));
if (!names) {
- return MapSECStatus(SECFailure);
+ return MapPRErrorCodeToResult(PR_GetError());
}
CERTGeneralName* currentName = const_cast<CERTGeneralName*>(names);
do {
if (CERT_CheckNameSpace(arena.get(), constraints, currentName)
!= SECSuccess) {
// XXX: It seems like CERT_CheckNameSpace doesn't always call
- // PR_SetError when it fails. We set the error code here, though this
- // may be papering over some fatal errors. NSS's
- // cert_VerifyCertChainOld does something similar.
- return Fail(RecoverableError, SEC_ERROR_CERT_NOT_IN_NAME_SPACE);
+ // PR_SetError when it fails, so we ignore what PR_GetError would
+ // return. NSS's cert_VerifyCertChainOld does something similar.
+ return Result::ERROR_CERT_NOT_IN_NAME_SPACE;
}
currentName = CERT_GetNextGeneralName(currentName);
} while (currentName != names);
}
return Success;
}
@@ -517,21 +519,21 @@ MatchEKU(Input& value, KeyPurposeId requ
break;
case KeyPurposeId::id_kp_OCSPSigning:
match = value.MatchRest(ocsp);
break;
case KeyPurposeId::anyExtendedKeyUsage:
PR_NOT_REACHED("anyExtendedKeyUsage should start with found==true");
- return Fail(SEC_ERROR_LIBRARY_FAILURE);
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
default:
PR_NOT_REACHED("unrecognized EKU");
- return Fail(SEC_ERROR_LIBRARY_FAILURE);
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
}
if (match) {
found = true;
if (requiredEKU == KeyPurposeId::id_kp_OCSPSigning) {
foundOCSPSigning = true;
}
@@ -544,45 +546,45 @@ MatchEKU(Input& value, KeyPurposeId requ
return Success;
}
Result
CheckExtendedKeyUsage(EndEntityOrCA endEntityOrCA,
const SECItem* encodedExtendedKeyUsage,
KeyPurposeId requiredEKU)
{
- // XXX: We're using SEC_ERROR_INADEQUATE_CERT_TYPE here so that callers can
- // distinguish EKU mismatch from KU mismatch from basic constraints mismatch.
- // We should probably add a new error code that is more clear for this type
- // of problem.
+ // XXX: We're using Result::ERROR_INADEQUATE_CERT_TYPE here so that callers
+ // can distinguish EKU mismatch from KU mismatch from basic constraints
+ // mismatch. We should probably add a new error code that is more clear for
+ // this type of problem.
bool foundOCSPSigning = false;
if (encodedExtendedKeyUsage) {
bool found = requiredEKU == KeyPurposeId::anyExtendedKeyUsage;
Input input;
if (input.Init(encodedExtendedKeyUsage->data,
encodedExtendedKeyUsage->len) != Success) {
- return Fail(RecoverableError, SEC_ERROR_INADEQUATE_CERT_TYPE);
+ return Result::ERROR_INADEQUATE_CERT_TYPE;
}
if (der::NestedOf(input, der::SEQUENCE, der::OIDTag, der::EmptyAllowed::No,
bind(MatchEKU, _1, requiredEKU, endEntityOrCA,
ref(found), ref(foundOCSPSigning)))
!= Success) {
- return Fail(RecoverableError, SEC_ERROR_INADEQUATE_CERT_TYPE);
+ return Result::ERROR_INADEQUATE_CERT_TYPE;
}
if (der::End(input) != Success) {
- return Fail(RecoverableError, SEC_ERROR_INADEQUATE_CERT_TYPE);
+ return Result::ERROR_INADEQUATE_CERT_TYPE;
}
// If the EKU extension was included, then the required EKU must be in the
// list.
if (!found) {
- return Fail(RecoverableError, SEC_ERROR_INADEQUATE_CERT_TYPE);
+ return Result::ERROR_INADEQUATE_CERT_TYPE;
}
}
// pkixocsp.cpp depends on the following additional checks.
if (endEntityOrCA == EndEntityOrCA::MustBeEndEntity) {
// When validating anything other than an delegated OCSP signing cert,
// reject any cert that also claims to be an OCSP responder, because such
@@ -592,29 +594,29 @@ CheckExtendedKeyUsage(EndEntityOrCA endE
// That said, we accept CA certificates with id-kp-OCSPSigning because
// some CAs in Mozilla's CA program have issued such intermediate
// certificates, and because some CAs have reported some Microsoft server
// software wrongly requires CA certificates to have id-kp-OCSPSigning.
// Allowing this exception does not cause any security issues because we
// require delegated OCSP response signing certificates to be end-entity
// certificates.
if (foundOCSPSigning && requiredEKU != KeyPurposeId::id_kp_OCSPSigning) {
- return Fail(RecoverableError, SEC_ERROR_INADEQUATE_CERT_TYPE);
+ return Result::ERROR_INADEQUATE_CERT_TYPE;
}
// http://tools.ietf.org/html/rfc6960#section-4.2.2.2:
// "OCSP signing delegation SHALL be designated by the inclusion of
// id-kp-OCSPSigning in an extended key usage certificate extension
// included in the OCSP response signer's certificate."
//
// id-kp-OCSPSigning is the only EKU that isn't implicitly assumed when the
// EKU extension is missing from an end-entity certificate. However, any CA
// certificate can issue a delegated OCSP response signing certificate, so
// we can't require the EKU be explicitly included for CA certificates.
if (!foundOCSPSigning && requiredEKU == KeyPurposeId::id_kp_OCSPSigning) {
- return Fail(RecoverableError, SEC_ERROR_INADEQUATE_CERT_TYPE);
+ return Result::ERROR_INADEQUATE_CERT_TYPE;
}
}
return Success;
}
Result
CheckIssuerIndependentProperties(TrustDomain& trustDomain,
@@ -626,29 +628,28 @@ CheckIssuerIndependentProperties(TrustDo
unsigned int subCACount,
/*optional out*/ TrustLevel* trustLevelOut)
{
Result rv;
const EndEntityOrCA endEntityOrCA = cert.endEntityOrCA;
TrustLevel trustLevel;
- rv = MapSECStatus(trustDomain.GetCertTrust(endEntityOrCA, requiredPolicy,
- cert.GetDER(), &trustLevel));
+ rv = trustDomain.GetCertTrust(endEntityOrCA, requiredPolicy, cert.GetDER(),
+ &trustLevel);
if (rv != Success) {
return rv;
}
if (trustLevel == TrustLevel::ActivelyDistrusted) {
- return Fail(RecoverableError, SEC_ERROR_UNTRUSTED_CERT);
+ return Result::ERROR_UNTRUSTED_CERT;
}
if (trustLevel != TrustLevel::TrustAnchor &&
trustLevel != TrustLevel::InheritsTrust) {
// The TrustDomain returned a trust level that we weren't expecting.
- PORT_SetError(PR_INVALID_STATE_ERROR);
- return FatalError;
+ return Result::FATAL_ERROR_INVALID_STATE;
}
if (trustLevelOut) {
*trustLevelOut = trustLevel;
}
// 4.2.1.1. Authority Key Identifier is ignored (see bug 965136).
// 4.2.1.2. Subject Key Identifier is ignored (see bug 965136).
--- a/security/pkix/lib/pkixder.cpp
+++ b/security/pkix/lib/pkixder.cpp
@@ -39,17 +39,17 @@ ExpectTagAndGetLength(Input& input, uint
uint8_t tag;
Result rv;
rv = input.Read(tag);
if (rv != Success) {
return rv;
}
if (tag != expectedTag) {
- return Fail(SEC_ERROR_BAD_DER);
+ return Result::ERROR_BAD_DER;
}
// The short form of length is a single byte with the high order bit set
// to zero. The long form of length is one byte with the high order bit
// set, followed by N bytes, where N is encoded in the lowest 7 bits of
// the first byte.
uint8_t length1;
rv = input.Read(length1);
@@ -61,31 +61,31 @@ ExpectTagAndGetLength(Input& input, uint
} else if (length1 == 0x81) {
uint8_t length2;
rv = input.Read(length2);
if (rv != Success) {
return rv;
}
if (length2 < 128) {
// Not shortest possible encoding
- return Fail(SEC_ERROR_BAD_DER);
+ return Result::ERROR_BAD_DER;
}
length = length2;
} else if (length1 == 0x82) {
rv = input.Read(length);
if (rv != Success) {
return rv;
}
if (length < 256) {
// Not shortest possible encoding
- return Fail(SEC_ERROR_BAD_DER);
+ return Result::ERROR_BAD_DER;
}
} else {
// We don't support lengths larger than 2^16 - 1.
- return Fail(SEC_ERROR_BAD_DER);
+ return Result::ERROR_BAD_DER;
}
// Ensure the input is long enough for the length it says it has.
return input.EnsureLength(length);
}
} // namespace internal
@@ -127,17 +127,17 @@ DigestAlgorithmOIDValue(Input& algorithm
algorithm = DigestAlgorithm::sha1;
} else if (algorithmID.MatchRest(id_sha256)) {
algorithm = DigestAlgorithm::sha256;
} else if (algorithmID.MatchRest(id_sha384)) {
algorithm = DigestAlgorithm::sha384;
} else if (algorithmID.MatchRest(id_sha512)) {
algorithm = DigestAlgorithm::sha512;
} else {
- return Fail(SEC_ERROR_INVALID_ALGORITHM);
+ return Result::ERROR_INVALID_ALGORITHM;
}
return Success;
}
Result
SignatureAlgorithmOIDValue(Input& algorithmID,
/*out*/ SignatureAlgorithm& algorithm)
@@ -234,17 +234,17 @@ SignatureAlgorithmOIDValue(Input& algori
algorithm = SignatureAlgorithm::dsa_with_sha1;
} else if (algorithmID.MatchRest(id_dsa_with_sha256)) {
algorithm = SignatureAlgorithm::dsa_with_sha256;
} else if (algorithmID.MatchRest(sha1WithRSASignature)) {
// XXX(bug 1042479): recognize this old OID for compatibility.
algorithm = SignatureAlgorithm::rsa_pkcs1_with_sha1;
} else {
// Any MD5-based signature algorithm, or any unknown signature algorithm.
- return Fail(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED);
+ return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
}
return Success;
}
template <typename OidValueParser, typename Algorithm>
Result
AlgorithmIdentifier(OidValueParser oidValueParser, Input& input,
@@ -311,43 +311,43 @@ SignedData(Input& input, /*out*/ Input&
return rv;
}
rv = ExpectTagAndGetValue(input, BIT_STRING, signedData.signature);
if (rv != Success) {
return rv;
}
if (signedData.signature.len == 0) {
- return Fail(SEC_ERROR_BAD_SIGNATURE);
+ 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 Fail(SEC_ERROR_BAD_SIGNATURE);
+ return Result::ERROR_BAD_SIGNATURE;
}
++signedData.signature.data;
--signedData.signature.len;
return Success;
}
static inline Result
ReadDigit(Input& input, /*out*/ int& value)
{
uint8_t b;
if (input.Read(b) != Success) {
- return Fail(SEC_ERROR_INVALID_TIME);
+ return Result::ERROR_INVALID_TIME;
}
if (b < '0' || b > '9') {
- return Fail(SEC_ERROR_INVALID_TIME);
+ return Result::ERROR_INVALID_TIME;
}
value = b - '0';
return Success;
}
static inline Result
ReadTwoDigits(Input& input, int minValue, int maxValue, /*out*/ int& value)
{
@@ -358,17 +358,17 @@ ReadTwoDigits(Input& input, int minValue
}
int lo;
rv = ReadDigit(input, lo);
if (rv != Success) {
return rv;
}
value = (hi * 10) + lo;
if (value < minValue || value > maxValue) {
- return Fail(SEC_ERROR_INVALID_TIME);
+ return Result::ERROR_INVALID_TIME;
}
return Success;
}
inline int
daysBeforeYear(int year)
{
return (365 * (year - 1))
@@ -409,22 +409,22 @@ TimeChoice(Input& tagged, uint8_t expect
} else if (expectedTag == UTCTime) {
rv = ReadTwoDigits(input, 0, 99, yearLo);
if (rv != Success) {
return rv;
}
yearHi = yearLo >= 50 ? 19 : 20;
} else {
PR_NOT_REACHED("invalid tag given to TimeChoice");
- return Fail(SEC_ERROR_INVALID_TIME);
+ return Result::ERROR_INVALID_TIME;
}
int year = (yearHi * 100) + yearLo;
if (year < 1970) {
// We don't support dates before January 1, 1970 because that is the epoch.
- return Fail(SEC_ERROR_INVALID_TIME); // TODO: better error code
+ return Result::ERROR_INVALID_TIME;
}
if (year > 1970) {
// This is NOT equivalent to daysBeforeYear(year - 1970) because the
// leap year calculations in daysBeforeYear only works on absolute years.
days = daysBeforeYear(year) - daysBeforeYear(1970);
// We subtract 1 because we're interested in knowing how many days there
// were *before* the given year, relative to 1970.
} else {
@@ -473,17 +473,17 @@ TimeChoice(Input& tagged, uint8_t expect
case 11: daysInMonth = nov; days += jan + feb + mar + apr + may + jun +
jul + aug + sep + oct;
break;
case 12: daysInMonth = dec; days += jan + feb + mar + apr + may + jun +
jul + aug + sep + oct + nov;
break;
default:
PR_NOT_REACHED("month already bounds-checked by ReadTwoDigits");
- return Fail(PR_INVALID_STATE_ERROR);
+ return Result::FATAL_ERROR_INVALID_STATE;
}
int dayOfMonth;
rv = ReadTwoDigits(input, 1, daysInMonth, dayOfMonth);
if (rv != Success) {
return rv;
}
days += dayOfMonth - 1;
@@ -501,23 +501,23 @@ TimeChoice(Input& tagged, uint8_t expect
int seconds;
rv = ReadTwoDigits(input, 0, 59, seconds);
if (rv != Success) {
return rv;
}
uint8_t b;
if (input.Read(b) != Success) {
- return Fail(SEC_ERROR_INVALID_TIME);
+ return Result::ERROR_INVALID_TIME;
}
if (b != 'Z') {
- return Fail(SEC_ERROR_INVALID_TIME); // TODO: better error code?
+ return Result::ERROR_INVALID_TIME;
}
if (End(input) != Success) {
- return Fail(SEC_ERROR_INVALID_TIME);
+ return Result::ERROR_INVALID_TIME;
}
int64_t totalSeconds = (static_cast<int64_t>(days) * 24 * 60 * 60) +
(static_cast<int64_t>(hours) * 60 * 60) +
(static_cast<int64_t>(minutes) * 60) +
seconds;
time = totalSeconds * PR_USEC_PER_SEC;
--- a/security/pkix/lib/pkixder.h
+++ b/security/pkix/lib/pkixder.h
@@ -87,17 +87,17 @@ ExpectTagAndLength(Input& input, uint8_t
if (rv != Success) {
return rv;
}
uint16_t expectedTagAndLength = static_cast<uint16_t>(expectedTag << 8);
expectedTagAndLength |= expectedLength;
if (tagAndLength != expectedTagAndLength) {
- return Fail(SEC_ERROR_BAD_DER);
+ return Result::ERROR_BAD_DER;
}
return Success;
}
namespace internal {
Result
@@ -162,17 +162,17 @@ ExpectTagAndGetTLV(Input& input, uint8_t
}
return input.GetSECItem(siBuffer, mark, tlv);
}
inline Result
End(Input& input)
{
if (!input.AtEnd()) {
- return Fail(SEC_ERROR_BAD_DER);
+ return Result::ERROR_BAD_DER;
}
return Success;
}
template <typename Decoder>
inline Result
Nested(Input& input, uint8_t tag, Decoder decoder)
@@ -233,17 +233,17 @@ NestedOf(Input& input, uint8_t outerTag,
Input inner;
Result rv = ExpectTagAndGetValue(input, outerTag, inner);
if (rv != Success) {
return rv;
}
if (inner.AtEnd()) {
if (mayBeEmpty != EmptyAllowed::Yes) {
- return Fail(SEC_ERROR_BAD_DER);
+ return Result::ERROR_BAD_DER;
}
return Success;
}
do {
rv = Nested(inner, innerTag, decoder);
if (rv != Success) {
return rv;
@@ -270,17 +270,17 @@ IntegralValue(Input& input, uint8_t tag,
return rv;
}
uint8_t valueByte;
rv = input.Read(valueByte);
if (rv != Success) {
return rv;
}
if (valueByte & 0x80) { // negative
- return Fail(SEC_ERROR_BAD_DER);
+ return Result::ERROR_BAD_DER;
}
value = valueByte;
return Success;
}
} // namespace internal
inline Result
@@ -295,17 +295,17 @@ Boolean(Input& input, /*out*/ bool& valu
rv = input.Read(intValue);
if (rv != Success) {
return rv;
}
switch (intValue) {
case 0: value = false; return Success;
case 0xFF: value = true; return Success;
default:
- return Fail(SEC_ERROR_BAD_DER);
+ return Result::ERROR_BAD_DER;
}
}
// This is for any BOOLEAN DEFAULT FALSE.
// (If it is present and false, this is a bad encoding.)
// TODO(bug 989518): For compatibility reasons, in some places we allow
// invalid encodings with the explicit default value.
inline Result
@@ -314,17 +314,17 @@ OptionalBoolean(Input& input, bool allow
{
value = false;
if (input.Peek(BOOLEAN)) {
Result rv = Boolean(input, value);
if (rv != Success) {
return rv;
}
if (!allowInvalidExplicitEncoding && !value) {
- return Fail(SEC_ERROR_BAD_DER);
+ return Result::ERROR_BAD_DER;
}
}
return Success;
}
// This parser will only parse values between 0..127. If this range is
// increased then callers will need to be changed.
inline Result
@@ -377,17 +377,17 @@ Integer(Input& input, /*out*/ uint8_t& v
// -1; defaultValue is only a parameter to make it clear in the calling code
// what the default value is.
inline Result
OptionalInteger(Input& input, long defaultValue, /*out*/ long& value)
{
// If we need to support a different default value in the future, we need to
// test that parsedValue != defaultValue.
if (defaultValue != -1) {
- return Fail(SEC_ERROR_INVALID_ARGS);
+ return Result::FATAL_ERROR_INVALID_ARGS;
}
if (!input.Peek(INTEGER)) {
value = defaultValue;
return Success;
}
uint8_t parsedValue;
@@ -434,28 +434,28 @@ CertificateSerialNumber(Input& input, /*
// gracefully handle such certificates."
Result rv = ExpectTagAndGetValue(input, INTEGER, value);
if (rv != Success) {
return rv;
}
if (value.len == 0) {
- return Fail(SEC_ERROR_BAD_DER);
+ return Result::ERROR_BAD_DER;
}
// Check for overly-long encodings. If the first byte is 0x00 then the high
// bit on the second byte must be 1; otherwise the same *positive* 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)) {
- return Fail(SEC_ERROR_BAD_DER);
+ return Result::ERROR_BAD_DER;
}
}
return Success;
}
// x.509 and OCSP both use this same version numbering scheme, though OCSP
// only supports v1.
@@ -489,17 +489,17 @@ OptionalVersion(Input& input, /*out*/ Ve
switch (integerValue) {
case static_cast<uint8_t>(Version::v3): version = Version::v3; break;
case static_cast<uint8_t>(Version::v2): version = Version::v2; break;
// XXX(bug 1031093): We shouldn't accept an explicit encoding of v1, but we
// do here for compatibility reasons.
case static_cast<uint8_t>(Version::v1): version = Version::v1; break;
case static_cast<uint8_t>(Version::v4): version = Version::v4; break;
default:
- return Fail(SEC_ERROR_BAD_DER);
+ return Result::ERROR_BAD_DER;
}
return Success;
}
template <typename ExtensionHandler>
inline Result
OptionalExtensions(Input& input, uint8_t tag, ExtensionHandler extensionHandler)
{
@@ -564,17 +564,17 @@ OptionalExtensions(Input& input, uint8_t
}
bool understood = false;
rv = extensionHandler(extnID, extnValue, critical, understood);
if (rv != Success) {
return rv;
}
if (critical && !understood) {
- return Fail(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
+ return Result::ERROR_UNKNOWN_CRITICAL_EXTENSION;
}
}
return Success;
}
Result DigestAlgorithmIdentifier(Input& input,
/*out*/ DigestAlgorithm& algorithm);
deleted file mode 100644
--- a/security/pkix/lib/pkixkey.cpp
+++ /dev/null
@@ -1,188 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This code is made available to you under your choice of the following sets
- * of licensing terms:
- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-/* Copyright 2013 Mozilla Contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <limits>
-#include <stdint.h>
-
-#include "cert.h"
-#include "cryptohi.h"
-#include "keyhi.h"
-#include "pk11pub.h"
-#include "pkix/pkix.h"
-#include "pkix/ScopedPtr.h"
-#include "prerror.h"
-#include "secerr.h"
-
-namespace mozilla { namespace pkix {
-
-typedef ScopedPtr<SECKEYPublicKey, SECKEY_DestroyPublicKey> ScopedSECKeyPublicKey;
-
-SECStatus
-CheckPublicKeySize(const SECItem& subjectPublicKeyInfo,
- /*out*/ ScopedSECKeyPublicKey& publicKey)
-{
- ScopedPtr<CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo>
- spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&subjectPublicKeyInfo));
- if (!spki) {
- return SECFailure;
- }
- publicKey = SECKEY_ExtractPublicKey(spki.get());
- if (!publicKey) {
- return SECFailure;
- }
-
- static const unsigned int MINIMUM_NON_ECC_BITS = 1024;
-
- switch (publicKey.get()->keyType) {
- case ecKey:
- // TODO(bug 622859): We should check which curve.
- return SECSuccess;
- case dsaKey: // fall through
- case rsaKey:
- // TODO(bug 622859): Enforce a minimum of 2048 bits for EV certs.
- if (SECKEY_PublicKeyStrengthInBits(publicKey.get()) < MINIMUM_NON_ECC_BITS) {
- // TODO(bug 1031946): Create a new error code.
- PR_SetError(SEC_ERROR_INVALID_KEY, 0);
- return SECFailure;
- }
- break;
- case nullKey:
- case fortezzaKey:
- case dhKey:
- case keaKey:
- case rsaPssKey:
- case rsaOaepKey:
- default:
- PR_SetError(SEC_ERROR_UNSUPPORTED_KEYALG, 0);
- return SECFailure;
- }
-
- return SECSuccess;
-}
-
-SECStatus
-CheckPublicKey(const SECItem& subjectPublicKeyInfo)
-{
- ScopedSECKeyPublicKey unused;
- return CheckPublicKeySize(subjectPublicKeyInfo, unused);
-}
-
-SECStatus
-VerifySignedData(const SignedDataWithSignature& sd,
- const SECItem& subjectPublicKeyInfo, void* pkcs11PinArg)
-{
- if (!sd.data.data || !sd.signature.data) {
- PR_NOT_REACHED("invalid args to VerifySignedData");
- PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
- return SECFailure;
- }
-
- // See bug 921585.
- if (sd.data.len > static_cast<unsigned int>(std::numeric_limits<int>::max())) {
- PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
- return SECFailure;
- }
-
- SECOidTag pubKeyAlg;
- SECOidTag digestAlg;
- switch (sd.algorithm) {
- case SignatureAlgorithm::ecdsa_with_sha512:
- pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
- digestAlg = SEC_OID_SHA512;
- break;
- case SignatureAlgorithm::ecdsa_with_sha384:
- pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
- digestAlg = SEC_OID_SHA384;
- break;
- case SignatureAlgorithm::ecdsa_with_sha256:
- pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
- digestAlg = SEC_OID_SHA256;
- break;
- case SignatureAlgorithm::ecdsa_with_sha1:
- pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
- digestAlg = SEC_OID_SHA1;
- break;
- case SignatureAlgorithm::rsa_pkcs1_with_sha512:
- pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
- digestAlg = SEC_OID_SHA512;
- break;
- case SignatureAlgorithm::rsa_pkcs1_with_sha384:
- pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
- digestAlg = SEC_OID_SHA384;
- break;
- case SignatureAlgorithm::rsa_pkcs1_with_sha256:
- pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
- digestAlg = SEC_OID_SHA256;
- break;
- case SignatureAlgorithm::rsa_pkcs1_with_sha1:
- pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
- digestAlg = SEC_OID_SHA1;
- break;
- case SignatureAlgorithm::dsa_with_sha256:
- pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE;
- digestAlg = SEC_OID_SHA256;
- break;
- case SignatureAlgorithm::dsa_with_sha1:
- pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE;
- digestAlg = SEC_OID_SHA1;
- break;
- default:
- PR_NOT_REACHED("unknown signature algorithm");
- PR_SetError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, 0);
- return SECFailure;
- }
-
- ScopedSECKeyPublicKey pubKey;
- if (CheckPublicKeySize(subjectPublicKeyInfo, pubKey) != SECSuccess) {
- return SECFailure;
- }
-
- // The static_cast is safe according to the check above that references
- // bug 921585.
- return VFY_VerifyDataDirect(sd.data.data, static_cast<int>(sd.data.len),
- pubKey.get(), &sd.signature, pubKeyAlg,
- digestAlg, nullptr, pkcs11PinArg);
-}
-
-SECStatus
-DigestBuf(const SECItem& 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)");
- if (digestBufLen != TrustDomain::DIGEST_LENGTH) {
- PR_NOT_REACHED("invalid hash length");
- PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
- return SECFailure;
- }
- 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");
- PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
- return SECFailure;
- }
- return PK11_HashBuf(SEC_OID_SHA1, digestBuf, item.data,
- static_cast<int32_t>(item.len));
-}
-
-} } // namespace mozilla::pkix
new file mode 100644
--- /dev/null
+++ b/security/pkix/lib/pkixnss.cpp
@@ -0,0 +1,312 @@
+/*- *- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This code is made available to you under your choice of the following sets
+ * of licensing terms:
+ */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+/* Copyright 2013 Mozilla Contributors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "pkix/pkixnss.h"
+
+#include <limits>
+#include <stdint.h>
+
+#include "cert.h"
+#include "cryptohi.h"
+#include "keyhi.h"
+#include "pk11pub.h"
+#include "pkix/pkix.h"
+#include "pkix/ScopedPtr.h"
+#include "secerr.h"
+
+namespace mozilla { namespace pkix {
+
+typedef ScopedPtr<SECKEYPublicKey, SECKEY_DestroyPublicKey> ScopedSECKeyPublicKey;
+
+Result
+CheckPublicKeySize(const SECItem& subjectPublicKeyInfo,
+ /*out*/ ScopedSECKeyPublicKey& publicKey)
+{
+ ScopedPtr<CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo>
+ spki(SECKEY_DecodeDERSubjectPublicKeyInfo(&subjectPublicKeyInfo));
+ if (!spki) {
+ return MapPRErrorCodeToResult(PR_GetError());
+ }
+ publicKey = SECKEY_ExtractPublicKey(spki.get());
+ if (!publicKey) {
+ return MapPRErrorCodeToResult(PR_GetError());
+ }
+
+ static const unsigned int MINIMUM_NON_ECC_BITS = 1024;
+
+ switch (publicKey.get()->keyType) {
+ case ecKey:
+ // TODO(bug 622859): We should check which curve.
+ return Success;
+ case dsaKey: // fall through
+ case rsaKey:
+ // TODO(bug 622859): Enforce a minimum of 2048 bits for EV certs.
+ if (SECKEY_PublicKeyStrengthInBits(publicKey.get()) < MINIMUM_NON_ECC_BITS) {
+ // TODO(bug 1031946): Create a new error code.
+ return Result::ERROR_INVALID_KEY;
+ }
+ break;
+ case nullKey:
+ case fortezzaKey:
+ case dhKey:
+ case keaKey:
+ case rsaPssKey:
+ case rsaOaepKey:
+ default:
+ return Result::ERROR_UNSUPPORTED_KEYALG;
+ }
+
+ return Success;
+}
+
+Result
+CheckPublicKey(const SECItem& subjectPublicKeyInfo)
+{
+ ScopedSECKeyPublicKey unused;
+ return CheckPublicKeySize(subjectPublicKeyInfo, unused);
+}
+
+Result
+VerifySignedData(const SignedDataWithSignature& sd,
+ const SECItem& 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())) {
+ return Result::FATAL_ERROR_INVALID_ARGS;
+ }
+
+ SECOidTag pubKeyAlg;
+ SECOidTag digestAlg;
+ switch (sd.algorithm) {
+ case SignatureAlgorithm::ecdsa_with_sha512:
+ pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
+ digestAlg = SEC_OID_SHA512;
+ break;
+ case SignatureAlgorithm::ecdsa_with_sha384:
+ pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
+ digestAlg = SEC_OID_SHA384;
+ break;
+ case SignatureAlgorithm::ecdsa_with_sha256:
+ pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
+ digestAlg = SEC_OID_SHA256;
+ break;
+ case SignatureAlgorithm::ecdsa_with_sha1:
+ pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
+ digestAlg = SEC_OID_SHA1;
+ break;
+ case SignatureAlgorithm::rsa_pkcs1_with_sha512:
+ pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
+ digestAlg = SEC_OID_SHA512;
+ break;
+ case SignatureAlgorithm::rsa_pkcs1_with_sha384:
+ pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
+ digestAlg = SEC_OID_SHA384;
+ break;
+ case SignatureAlgorithm::rsa_pkcs1_with_sha256:
+ pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
+ digestAlg = SEC_OID_SHA256;
+ break;
+ case SignatureAlgorithm::rsa_pkcs1_with_sha1:
+ pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
+ digestAlg = SEC_OID_SHA1;
+ break;
+ case SignatureAlgorithm::dsa_with_sha256:
+ pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE;
+ digestAlg = SEC_OID_SHA256;
+ break;
+ case SignatureAlgorithm::dsa_with_sha1:
+ pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE;
+ digestAlg = SEC_OID_SHA1;
+ break;
+ default:
+ PR_NOT_REACHED("unknown signature algorithm");
+ return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
+ }
+
+ Result rv;
+ ScopedSECKeyPublicKey pubKey;
+ rv = CheckPublicKeySize(subjectPublicKeyInfo, pubKey);
+ if (rv != Success) {
+ return rv;
+ }
+
+ // The static_cast is safe according to the check above that references
+ // bug 921585.
+ SECStatus srv = VFY_VerifyDataDirect(sd.data.data,
+ static_cast<int>(sd.data.len),
+ pubKey.get(), &sd.signature, pubKeyAlg,
+ digestAlg, nullptr, pkcs11PinArg);
+ if (srv != SECSuccess) {
+ return MapPRErrorCodeToResult(PR_GetError());
+ }
+
+ return Success;
+}
+
+Result
+DigestBuf(const SECItem& 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)");
+ if (digestBufLen != TrustDomain::DIGEST_LENGTH) {
+ 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");
+ return Result::FATAL_ERROR_INVALID_ARGS;
+ }
+ SECStatus srv = PK11_HashBuf(SEC_OID_SHA1, digestBuf, item.data,
+ static_cast<int32_t>(item.len));
+ if (srv != SECSuccess) {
+ return MapPRErrorCodeToResult(PR_GetError());
+ }
+ return Success;
+}
+
+#define MAP_LIST \
+ MAP(Result::Success, 0) \
+ MAP(Result::ERROR_BAD_DER, SEC_ERROR_BAD_DER) \
+ MAP(Result::ERROR_CA_CERT_INVALID, SEC_ERROR_CA_CERT_INVALID) \
+ MAP(Result::ERROR_BAD_SIGNATURE, SEC_ERROR_BAD_SIGNATURE) \
+ MAP(Result::ERROR_CERT_BAD_ACCESS_LOCATION, SEC_ERROR_CERT_BAD_ACCESS_LOCATION) \
+ MAP(Result::ERROR_CERT_NOT_IN_NAME_SPACE, SEC_ERROR_CERT_NOT_IN_NAME_SPACE) \
+ MAP(Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED, SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED) \
+ MAP(Result::ERROR_CONNECT_REFUSED, PR_CONNECT_REFUSED_ERROR) \
+ MAP(Result::ERROR_EXPIRED_CERTIFICATE, SEC_ERROR_EXPIRED_CERTIFICATE) \
+ MAP(Result::ERROR_EXTENSION_VALUE_INVALID, SEC_ERROR_EXTENSION_VALUE_INVALID) \
+ MAP(Result::ERROR_INADEQUATE_CERT_TYPE, SEC_ERROR_INADEQUATE_CERT_TYPE) \
+ MAP(Result::ERROR_INADEQUATE_KEY_USAGE, SEC_ERROR_INADEQUATE_KEY_USAGE) \
+ MAP(Result::ERROR_INVALID_ALGORITHM, SEC_ERROR_INVALID_ALGORITHM) \
+ MAP(Result::ERROR_INVALID_TIME, SEC_ERROR_INVALID_TIME) \
+ MAP(Result::ERROR_KEY_PINNING_FAILURE, MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE) \
+ MAP(Result::ERROR_PATH_LEN_CONSTRAINT_INVALID, SEC_ERROR_PATH_LEN_CONSTRAINT_INVALID) \
+ MAP(Result::ERROR_POLICY_VALIDATION_FAILED, SEC_ERROR_POLICY_VALIDATION_FAILED) \
+ MAP(Result::ERROR_REVOKED_CERTIFICATE, SEC_ERROR_REVOKED_CERTIFICATE) \
+ MAP(Result::ERROR_UNKNOWN_CRITICAL_EXTENSION, SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION) \
+ MAP(Result::ERROR_UNKNOWN_ERROR, PR_UNKNOWN_ERROR) \
+ MAP(Result::ERROR_UNKNOWN_ISSUER, SEC_ERROR_UNKNOWN_ISSUER) \
+ MAP(Result::ERROR_UNTRUSTED_CERT, SEC_ERROR_UNTRUSTED_CERT) \
+ MAP(Result::ERROR_UNTRUSTED_ISSUER, SEC_ERROR_UNTRUSTED_ISSUER) \
+ MAP(Result::ERROR_OCSP_BAD_SIGNATURE, SEC_ERROR_OCSP_BAD_SIGNATURE) \
+ MAP(Result::ERROR_OCSP_INVALID_SIGNING_CERT, SEC_ERROR_OCSP_INVALID_SIGNING_CERT) \
+ MAP(Result::ERROR_OCSP_MALFORMED_REQUEST, SEC_ERROR_OCSP_MALFORMED_REQUEST) \
+ MAP(Result::ERROR_OCSP_MALFORMED_RESPONSE, SEC_ERROR_OCSP_MALFORMED_RESPONSE) \
+ MAP(Result::ERROR_OCSP_OLD_RESPONSE, SEC_ERROR_OCSP_OLD_RESPONSE) \
+ MAP(Result::ERROR_OCSP_REQUEST_NEEDS_SIG, SEC_ERROR_OCSP_REQUEST_NEEDS_SIG) \
+ MAP(Result::ERROR_OCSP_RESPONDER_CERT_INVALID, SEC_ERROR_OCSP_RESPONDER_CERT_INVALID) \
+ MAP(Result::ERROR_OCSP_SERVER_ERROR, SEC_ERROR_OCSP_SERVER_ERROR) \
+ MAP(Result::ERROR_OCSP_TRY_SERVER_LATER, SEC_ERROR_OCSP_TRY_SERVER_LATER) \
+ MAP(Result::ERROR_OCSP_UNAUTHORIZED_REQUEST, SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST) \
+ MAP(Result::ERROR_OCSP_UNKNOWN_RESPONSE_STATUS, SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS) \
+ MAP(Result::ERROR_OCSP_UNKNOWN_CERT, SEC_ERROR_OCSP_UNKNOWN_CERT) \
+ MAP(Result::ERROR_OCSP_FUTURE_RESPONSE, SEC_ERROR_OCSP_FUTURE_RESPONSE) \
+ MAP(Result::ERROR_INVALID_KEY, SEC_ERROR_INVALID_KEY) \
+ MAP(Result::ERROR_UNSUPPORTED_KEYALG, SEC_ERROR_UNSUPPORTED_KEYALG) \
+ MAP(Result::FATAL_ERROR_INVALID_ARGS, SEC_ERROR_INVALID_ARGS) \
+ MAP(Result::FATAL_ERROR_INVALID_STATE, PR_INVALID_STATE_ERROR) \
+ MAP(Result::FATAL_ERROR_LIBRARY_FAILURE, SEC_ERROR_LIBRARY_FAILURE) \
+ MAP(Result::FATAL_ERROR_NO_MEMORY, SEC_ERROR_NO_MEMORY) \
+ /* nothing here */
+
+Result
+MapPRErrorCodeToResult(PRErrorCode error)
+{
+ switch (error)
+ {
+#define MAP(mozilla_pkix_result, nss_result) \
+ case nss_result: return mozilla_pkix_result;
+
+ MAP_LIST
+
+#undef MAP
+
+ default:
+ return Result::ERROR_UNKNOWN_ERROR;
+ }
+}
+
+PRErrorCode
+MapResultToPRErrorCode(Result result)
+{
+ switch (result)
+ {
+#define MAP(mozilla_pkix_result, nss_result) \
+ case mozilla_pkix_result: return nss_result;
+
+ MAP_LIST
+
+#undef MAP
+
+ default:
+ PR_NOT_REACHED("Unknown error code in MapResultToPRErrorCode");
+ return SEC_ERROR_LIBRARY_FAILURE;
+ }
+}
+
+const char*
+MapResultToName(Result result)
+{
+ switch (result)
+ {
+#define MAP(mozilla_pkix_result, nss_result) \
+ case mozilla_pkix_result: return #mozilla_pkix_result;
+
+ MAP_LIST
+
+#undef MAP
+
+ default:
+ PR_NOT_REACHED("Unknown error code in MapResultToName");
+ return nullptr;
+ }
+}
+
+void
+RegisterErrorTable()
+{
+ static const struct PRErrorMessage ErrorTableText[] = {
+ { "MOZILLA_PKIX_ERROR_KEY_PINNING_FAILURE",
+ "The server uses key pinning (HPKP) but no trusted certificate chain "
+ "could be constructed that matches the pinset. Key pinning violations "
+ "cannot be overridden." }
+ };
+
+ static const struct PRErrorTable ErrorTable = {
+ ErrorTableText,
+ "pkixerrors",
+ ERROR_BASE,
+ PR_ARRAY_SIZE(ErrorTableText)
+ };
+
+ (void) PR_ErrorInstallTable(&ErrorTable);
+}
+
+} } // namespace mozilla::pkix
--- a/security/pkix/lib/pkixocsp.cpp
+++ b/security/pkix/lib/pkixocsp.cpp
@@ -24,19 +24,16 @@
#include <limits>
#include "pkix/bind.h"
#include "pkix/pkix.h"
#include "pkixcheck.h"
#include "pkixder.h"
-// TODO: use typed/qualified typedefs everywhere?
-// TODO: When should we return SEC_ERROR_OCSP_UNAUTHORIZED_RESPONSE?
-
namespace mozilla { namespace pkix {
static const PRTime ONE_DAY
= INT64_C(24) * INT64_C(60) * INT64_C(60) * PR_USEC_PER_SEC;
static const PRTime SLOP = ONE_DAY;
// These values correspond to the tag values in the ASN.1 CertStatus
MOZILLA_PKIX_ENUM_CLASS CertStatus : uint8_t {
@@ -125,31 +122,28 @@ CheckOCSPResponseSignerCert(TrustDomain&
}
// It is possible that there exists a certificate with the same key as the
// issuer but with a different name, so we need to compare names
// XXX(bug 926270) XXX(bug 1008133) XXX(bug 980163): Improve name
// comparison.
// TODO: needs test
if (!SECITEM_ItemsAreEqual(&potentialSigner.GetIssuer(), &issuerSubject)) {
- return Fail(RecoverableError, SEC_ERROR_OCSP_RESPONDER_CERT_INVALID);
+ return Result::ERROR_OCSP_RESPONDER_CERT_INVALID;
}
// TODO(bug 926260): check name constraints
- SECStatus srv = trustDomain.VerifySignedData(potentialSigner.GetSignedData(),
- issuerSubjectPublicKeyInfo);
- if (srv != SECSuccess) {
- return MapSECStatus(srv);
- }
+ rv = trustDomain.VerifySignedData(potentialSigner.GetSignedData(),
+ issuerSubjectPublicKeyInfo);
// TODO: check for revocation of the OCSP responder certificate unless no-check
// or the caller forcing no-check. To properly support the no-check policy, we'd
// need to enforce policy constraints from the issuerChain.
- return Success;
+ return rv;
}
MOZILLA_PKIX_ENUM_CLASS ResponderIDType : uint8_t
{
byName = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1,
byKey = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 2
};
@@ -205,32 +199,30 @@ MatchResponderID(TrustDomain& trustDomai
if (rv != Success) {
return rv;
}
return MatchKeyHash(trustDomain, keyHash,
potentialSignerSubjectPublicKeyInfo, match);
}
default:
- return Fail(RecoverableError, SEC_ERROR_OCSP_MALFORMED_RESPONSE);
+ return Result::ERROR_OCSP_MALFORMED_RESPONSE;
}
}
static Result
VerifyOCSPSignedData(TrustDomain& trustDomain,
const SignedDataWithSignature& signedResponseData,
const SECItem& spki)
{
- SECStatus srv = trustDomain.VerifySignedData(signedResponseData, spki);
- if (srv != SECSuccess) {
- if (PR_GetError() == SEC_ERROR_BAD_SIGNATURE) {
- PR_SetError(SEC_ERROR_OCSP_BAD_SIGNATURE, 0);
- }
+ Result rv = trustDomain.VerifySignedData(signedResponseData, spki);
+ if (rv == Result::ERROR_BAD_SIGNATURE) {
+ rv = Result::ERROR_OCSP_BAD_SIGNATURE;
}
- return MapSECStatus(srv);
+ return rv;
}
// RFC 6960 section 4.2.2.2: The OCSP responder must either be the issuer of
// the cert or it must be a delegated OCSP response signing cert directly
// issued by the issuer. If the OCSP responder is a delegated OCSP response
// signer, then its certificate is (probably) embedded within the OCSP
// response and we'll need to verify that it is a valid certificate that chains
// *directly* to issuerCert.
@@ -257,101 +249,98 @@ VerifySignature(Context& context, Respon
BackCert cert(certs[i], EndEntityOrCA::MustBeEndEntity, nullptr);
rv = cert.Init();
if (rv != Success) {
return rv;
}
rv = MatchResponderID(context.trustDomain, responderIDType, responderID,
cert.GetSubject(), cert.GetSubjectPublicKeyInfo(),
match);
- if (rv == FatalError) {
- return rv;
- }
- if (rv == RecoverableError) {
+ if (rv != Success) {
+ if (IsFatalError(rv)) {
+ return rv;
+ }
continue;
}
if (match) {
rv = CheckOCSPResponseSignerCert(context.trustDomain, cert,
context.certID.issuer,
context.certID.issuerSubjectPublicKeyInfo,
context.time);
- if (rv == FatalError) {
- return rv;
- }
- if (rv == RecoverableError) {
+ if (rv != Success) {
+ if (IsFatalError(rv)) {
+ return rv;
+ }
continue;
}
return VerifyOCSPSignedData(context.trustDomain, signedResponseData,
cert.GetSubjectPublicKeyInfo());
}
}
- return Fail(RecoverableError, SEC_ERROR_OCSP_INVALID_SIGNING_CERT);
+ return Result::ERROR_OCSP_INVALID_SIGNING_CERT;
}
-static inline void
-SetErrorToMalformedResponseOnBadDERError()
+static inline Result
+MapBadDERToMalformedOCSPResponse(Result rv)
{
- if (PR_GetError() == SEC_ERROR_BAD_DER) {
- PR_SetError(SEC_ERROR_OCSP_MALFORMED_RESPONSE, 0);
+ if (rv == Result::ERROR_BAD_DER) {
+ return Result::ERROR_OCSP_MALFORMED_RESPONSE;
}
+ return rv;
}
-SECStatus
+Result
VerifyEncodedOCSPResponse(TrustDomain& trustDomain, const struct CertID& certID,
PRTime time, uint16_t maxOCSPLifetimeInDays,
const SECItem& encodedResponse,
/*out*/ bool& expired,
/*optional out*/ PRTime* thisUpdate,
/*optional out*/ PRTime* validThrough)
{
// Always initialize this to something reasonable.
expired = false;
Input input;
- if (input.Init(encodedResponse.data, encodedResponse.len) != Success) {
- SetErrorToMalformedResponseOnBadDERError();
- return SECFailure;
+ Result rv = input.Init(encodedResponse.data, encodedResponse.len);
+ if (rv != Success) {
+ return MapBadDERToMalformedOCSPResponse(rv);
}
+
Context context(trustDomain, certID, time, maxOCSPLifetimeInDays,
thisUpdate, validThrough);
- if (der::Nested(input, der::SEQUENCE,
- bind(OCSPResponse, _1, ref(context))) != Success) {
- SetErrorToMalformedResponseOnBadDERError();
- return SECFailure;
+ rv = der::Nested(input, der::SEQUENCE, bind(OCSPResponse, _1, ref(context)));
+ if (rv != Success) {
+ return MapBadDERToMalformedOCSPResponse(rv);
}
- if (der::End(input) != Success) {
- SetErrorToMalformedResponseOnBadDERError();
- return SECFailure;
+ rv = der::End(input);
+ if (rv != Success) {
+ return MapBadDERToMalformedOCSPResponse(rv);
}
expired = context.expired;
switch (context.certStatus) {
case CertStatus::Good:
if (expired) {
- PR_SetError(SEC_ERROR_OCSP_OLD_RESPONSE, 0);
- return SECFailure;
+ return Result::ERROR_OCSP_OLD_RESPONSE;
}
- return SECSuccess;
+ return Success;
case CertStatus::Revoked:
- PR_SetError(SEC_ERROR_REVOKED_CERTIFICATE, 0);
- return SECFailure;
+ return Result::ERROR_REVOKED_CERTIFICATE;
case CertStatus::Unknown:
- PR_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT, 0);
- return SECFailure;
+ return Result::ERROR_OCSP_UNKNOWN_CERT;
}
PR_NOT_REACHED("unknown CertStatus");
- PR_SetError(SEC_ERROR_OCSP_UNKNOWN_CERT, 0);
- return SECFailure;
+ return Result::ERROR_OCSP_UNKNOWN_CERT;
}
// OCSPResponse ::= SEQUENCE {
// responseStatus OCSPResponseStatus,
// responseBytes [0] EXPLICIT ResponseBytes OPTIONAL }
//
static inline Result
OCSPResponse(Input& input, Context& context)
@@ -368,22 +357,22 @@ OCSPResponse(Input& input, Context& cont
uint8_t responseStatus;
Result rv = der::Enumerated(input, responseStatus);
if (rv != Success) {
return rv;
}
switch (responseStatus) {
case 0: break; // successful
- case 1: return Fail(SEC_ERROR_OCSP_MALFORMED_REQUEST);
- case 2: return Fail(SEC_ERROR_OCSP_SERVER_ERROR);
- case 3: return Fail(SEC_ERROR_OCSP_TRY_SERVER_LATER);
- case 5: return Fail(SEC_ERROR_OCSP_REQUEST_NEEDS_SIG);
- case 6: return Fail(SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST);
- default: return Fail(SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS);
+ case 1: return Result::ERROR_OCSP_MALFORMED_REQUEST;
+ case 2: return Result::ERROR_OCSP_SERVER_ERROR;
+ case 3: return Result::ERROR_OCSP_TRY_SERVER_LATER;
+ case 5: return Result::ERROR_OCSP_REQUEST_NEEDS_SIG;
+ case 6: return Result::ERROR_OCSP_UNAUTHORIZED_REQUEST;
+ default: return Result::ERROR_OCSP_UNKNOWN_RESPONSE_STATUS;
}
return der::Nested(input, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0,
der::SEQUENCE, bind(ResponseBytes, _1, ref(context)));
}
// ResponseBytes ::= SEQUENCE {
// responseType OBJECT IDENTIFIER,
@@ -411,18 +400,18 @@ ResponseBytes(Input& input, Context& con
// certs [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
Result
BasicResponse(Input& input, Context& context)
{
Input tbsResponseData;
SignedDataWithSignature signedData;
Result rv = der::SignedData(input, tbsResponseData, signedData);
if (rv != Success) {
- if (PR_GetError() == SEC_ERROR_BAD_SIGNATURE) {
- return Fail(RecoverableError, SEC_ERROR_OCSP_BAD_SIGNATURE);
+ if (rv == Result::ERROR_BAD_SIGNATURE) {
+ return Result::ERROR_OCSP_BAD_SIGNATURE;
}
return rv;
}
// Parse certificates, if any
SECItem certs[8];
size_t numCerts = 0;
@@ -443,17 +432,17 @@ BasicResponse(Input& input, Context& con
rv = der::ExpectTagAndSkipLength(input, der::SEQUENCE);
if (rv != Success) {
return rv;
}
// sequence of certificates
while (!input.AtEnd()) {
if (numCerts == PR_ARRAY_SIZE(certs)) {
- return Fail(SEC_ERROR_BAD_DER);
+ return Result::ERROR_BAD_DER;
}
rv = der::ExpectTagAndGetTLV(input, der::SEQUENCE, certs[numCerts]);
if (rv != Success) {
return rv;
}
++numCerts;
}
@@ -475,17 +464,17 @@ ResponseData(Input& input, Context& cont
{
der::Version version;
Result rv = der::OptionalVersion(input, version);
if (rv != Success) {
return rv;
}
if (version != der::Version::v1) {
// TODO: more specific error code for bad version?
- return Fail(SEC_ERROR_BAD_DER);
+ return Result::ERROR_BAD_DER;
}
// ResponderID ::= CHOICE {
// byName [1] Name,
// byKey [2] KeyHash }
SECItem responderID;
ResponderIDType responderIDType
= input.Peek(static_cast<uint8_t>(ResponderIDType::byName))
@@ -606,46 +595,46 @@ SingleResponse(Input& input, Context& co
PRTime thisUpdate;
rv = der::GeneralizedTime(input, thisUpdate);
if (rv != Success) {
return rv;
}
if (thisUpdate > context.time + SLOP) {
- return Fail(SEC_ERROR_OCSP_FUTURE_RESPONSE);
+ return Result::ERROR_OCSP_FUTURE_RESPONSE;
}
PRTime notAfter;
static const uint8_t NEXT_UPDATE_TAG =
der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0;
if (input.Peek(NEXT_UPDATE_TAG)) {
PRTime nextUpdate;
rv = der::Nested(input, NEXT_UPDATE_TAG,
bind(der::GeneralizedTime, _1, ref(nextUpdate)));
if (rv != Success) {
return rv;
}
if (nextUpdate < thisUpdate) {
- return Fail(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
+ return Result::ERROR_OCSP_MALFORMED_RESPONSE;
}
if (nextUpdate - thisUpdate <= maxLifetime) {
notAfter = nextUpdate;
} else {
notAfter = thisUpdate + maxLifetime;
}
} else {
// NSS requires all OCSP responses without a nextUpdate to be recent.
// Match that stricter behavior.
notAfter = thisUpdate + ONE_DAY;
}
if (context.time < SLOP) { // prevent underflow
- return Fail(SEC_ERROR_INVALID_ARGS);
+ return Result::FATAL_ERROR_INVALID_ARGS;
}
if (context.time - SLOP > notAfter) {
context.expired = true;
}
rv = der::OptionalExtensions(input,
der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1,
@@ -672,17 +661,17 @@ SingleResponse(Input& input, Context& co
static inline Result
CertID(Input& input, const Context& context, /*out*/ bool& match)
{
match = false;
DigestAlgorithm hashAlgorithm;
Result rv = der::DigestAlgorithmIdentifier(input, hashAlgorithm);
if (rv != Success) {
- if (PR_GetError() == SEC_ERROR_INVALID_ALGORITHM) {
+ if (rv == Result::ERROR_INVALID_ALGORITHM) {
// Skip entries that are hashed with algorithms we don't support.
input.SkipToEnd();
return Success;
}
return rv;
}
SECItem issuerNameHash;
@@ -715,26 +704,27 @@ CertID(Input& input, const Context& cont
if (hashAlgorithm != DigestAlgorithm::sha1) {
// Again, not interested in this response. Consume input, return success.
input.SkipToEnd();
return Success;
}
if (issuerNameHash.len != TrustDomain::DIGEST_LENGTH) {
- return Fail(SEC_ERROR_OCSP_MALFORMED_RESPONSE);
+ return Result::ERROR_OCSP_MALFORMED_RESPONSE;
}
// From http://tools.ietf.org/html/rfc6960#section-4.1.1:
// "The hash shall be calculated over the DER encoding of the
// issuer's name field in the certificate being checked."
uint8_t hashBuf[TrustDomain::DIGEST_LENGTH];
- if (context.trustDomain.DigestBuf(context.certID.issuer, hashBuf,
- sizeof(hashBuf)) != SECSuccess) {
- return MapSECStatus(SECFailure);
+ rv = context.trustDomain.DigestBuf(context.certID.issuer, hashBuf,
+ sizeof(hashBuf));
+ if (rv != Success) {
+ return rv;
}
if (memcmp(hashBuf, issuerNameHash.data, issuerNameHash.len)) {
// Again, not interested in this response. Consume input, return success.
input.SkipToEnd();
return Success;
}
return MatchKeyHash(context.trustDomain, issuerKeyHash,
@@ -751,17 +741,17 @@ CertID(Input& input, const Context& cont
// -- BIT STRING subjectPublicKey [excluding
// -- 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)
{
if (keyHash.len != TrustDomain::DIGEST_LENGTH) {
- return Fail(RecoverableError, SEC_ERROR_OCSP_MALFORMED_RESPONSE);
+ return Result::ERROR_OCSP_MALFORMED_RESPONSE;
}
static uint8_t hashBuf[TrustDomain::DIGEST_LENGTH];
Result rv = KeyHash(trustDomain, subjectPublicKeyInfo, hashBuf,
sizeof hashBuf);
if (rv != Success) {
return rv;
}
match = !memcmp(hashBuf, keyHash.data, keyHash.len);
@@ -769,71 +759,72 @@ MatchKeyHash(TrustDomain& trustDomain, c
}
// TODO(bug 966856): support SHA-2 hashes
Result
KeyHash(TrustDomain& trustDomain, const SECItem& subjectPublicKeyInfo,
/*out*/ uint8_t* hashBuf, size_t hashBufSize)
{
if (!hashBuf || hashBufSize != TrustDomain::DIGEST_LENGTH) {
- return Fail(FatalError, SEC_ERROR_LIBRARY_FAILURE);
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
// RFC 5280 Section 4.1
//
// SubjectPublicKeyInfo ::= SEQUENCE {
// algorithm AlgorithmIdentifier,
// subjectPublicKey BIT STRING }
Input spki;
+ Result rv;
{
// 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;
- if (input.Init(subjectPublicKeyInfo.data, subjectPublicKeyInfo.len)
- != Success) {
- return MapSECStatus(SECFailure);
+ rv = input.Init(subjectPublicKeyInfo.data, subjectPublicKeyInfo.len);
+ if (rv != Success) {
+ return rv;
}
- if (der::ExpectTagAndGetValue(input, der::SEQUENCE, spki) != Success) {
- return MapSECStatus(SECFailure);
+ rv = der::ExpectTagAndGetValue(input, der::SEQUENCE, spki);
+ if (rv != Success) {
+ return rv;
}
- if (der::End(input) != Success) {
- return MapSECStatus(SECFailure);
+ rv = der::End(input);
+ if (rv != Success) {
+ return rv;
}
}
// Skip AlgorithmIdentifier
- if (der::ExpectTagAndSkipValue(spki, der::SEQUENCE) != Success) {
- return MapSECStatus(SECFailure);
+ rv = der::ExpectTagAndSkipValue(spki, der::SEQUENCE);
+ if (rv != Success) {
+ return rv;
}
SECItem subjectPublicKey;
- if (der::ExpectTagAndGetValue(spki, der::BIT_STRING, subjectPublicKey)
- != Success) {
- return MapSECStatus(SECFailure);
+ rv = der::ExpectTagAndGetValue(spki, der::BIT_STRING, subjectPublicKey);
+ if (rv != Success) {
+ return rv;
}
- if (der::End(spki) != Success) {
- return MapSECStatus(SECFailure);
+ 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 Fail(RecoverableError, SEC_ERROR_BAD_DER);
+ return Result::ERROR_BAD_DER;
}
++subjectPublicKey.data;
--subjectPublicKey.len;
- if (trustDomain.DigestBuf(subjectPublicKey, hashBuf, hashBufSize)
- != SECSuccess) {
- return MapSECStatus(SECFailure);
- }
- return Success;
+ return trustDomain.DigestBuf(subjectPublicKey, hashBuf, hashBufSize);
}
Result
ExtensionNotUnderstood(Input& /*extnID*/, const SECItem& /*extnValue*/,
bool /*critical*/, /*out*/ bool& understood)
{
understood = false;
return Success;
@@ -857,25 +848,21 @@ ExtensionNotUnderstood(Input& /*extnID*/
// Responses whose thisUpdate time is later than the local system time
// SHOULD be considered unreliable.
//
// If nextUpdate is not set, the responder is indicating that newer
// revocation information is available all the time.
//
// http://tools.ietf.org/html/rfc5019#section-4
-SECItem*
-CreateEncodedOCSPRequest(TrustDomain& trustDomain, PLArenaPool* arena,
- const struct CertID& certID)
+Result
+CreateEncodedOCSPRequest(TrustDomain& trustDomain, const struct CertID& certID,
+ /*out*/ uint8_t (&out)[OCSP_REQUEST_MAX_LENGTH],
+ /*out*/ size_t& outLen)
{
- if (!arena) {
- PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
- return nullptr;
- }
-
// We do not add any extensions to the request.
// RFC 6960 says "An OCSP client MAY wish to specify the kinds of response
// types it understands. To do so, it SHOULD use an extension with the OID
// id-pkix-ocsp-response." This use of MAY and SHOULD is unclear. MSIE11
// on Windows 8.1 does not include any extensions, whereas NSS has always
// included the id-pkix-ocsp-response extension. Avoiding the sending the
// extension is better for OCSP GET because it makes the request smaller,
@@ -906,63 +893,62 @@ CreateEncodedOCSPRequest(TrustDomain& tr
+ 2; // serialNumber (header)
// The only way we could have a request this large is if the serialNumber was
// ridiculously and unreasonably large. RFC 5280 says "Conforming CAs MUST
// NOT use serialNumber values longer than 20 octets." With this restriction,
// we allow for some amount of non-conformance with that requirement while
// still ensuring we can encode the length values in the ASN.1 TLV structures
// in a single byte.
- if (certID.serialNumber.len > 127u - totalLenWithoutSerialNumberData) {
- PR_SetError(SEC_ERROR_BAD_DATA, 0);
- return nullptr;
+ static_assert(totalLenWithoutSerialNumberData < OCSP_REQUEST_MAX_LENGTH,
+ "totalLenWithoutSerialNumberData too big");
+ if (certID.serialNumber.len >
+ OCSP_REQUEST_MAX_LENGTH - totalLenWithoutSerialNumberData) {
+ return Result::ERROR_BAD_DER;
}
- uint8_t totalLen = static_cast<uint8_t>(totalLenWithoutSerialNumberData +
- certID.serialNumber.len);
+ outLen = totalLenWithoutSerialNumberData + certID.serialNumber.len;
- SECItem* encodedRequest = SECITEM_AllocItem(arena, nullptr, totalLen);
- if (!encodedRequest) {
- return nullptr;
- }
+ uint8_t totalLen = static_cast<uint8_t>(outLen);
- uint8_t* d = encodedRequest->data;
+ uint8_t* d = out;
*d++ = 0x30; *d++ = totalLen - 2u; // OCSPRequest (SEQUENCE)
*d++ = 0x30; *d++ = totalLen - 4u; // tbsRequest (SEQUENCE)
*d++ = 0x30; *d++ = totalLen - 6u; // requestList (SEQUENCE OF)
*d++ = 0x30; *d++ = totalLen - 8u; // Request (SEQUENCE)
*d++ = 0x30; *d++ = totalLen - 10u; // reqCert (CertID SEQUENCE)
// reqCert.hashAlgorithm
for (size_t i = 0; i < PR_ARRAY_SIZE(hashAlgorithm); ++i) {
*d++ = hashAlgorithm[i];
}
// reqCert.issuerNameHash (OCTET STRING)
*d++ = 0x04;
*d++ = hashLen;
- if (trustDomain.DigestBuf(certID.issuer, d, hashLen) != SECSuccess) {
- return nullptr;
+ Result rv = trustDomain.DigestBuf(certID.issuer, d, hashLen);
+ if (rv != Success) {
+ return rv;
}
d += hashLen;
// reqCert.issuerKeyHash (OCTET STRING)
*d++ = 0x04;
*d++ = hashLen;
- if (KeyHash(trustDomain, certID.issuerSubjectPublicKeyInfo, d, hashLen)
- != Success) {
- return nullptr;
+ rv = KeyHash(trustDomain, certID.issuerSubjectPublicKeyInfo, d, hashLen);
+ if (rv != Success) {
+ return rv;
}
d += hashLen;
// 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];
}
- PR_ASSERT(d == encodedRequest->data + totalLen);
+ PR_ASSERT(d == out + totalLen);
- return encodedRequest;
+ return Success;
}
} } // namespace mozilla::pkix
--- a/security/pkix/lib/pkixutil.h
+++ b/security/pkix/lib/pkixutil.h
@@ -21,19 +21,16 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef mozilla_pkix__pkixutil_h
#define mozilla_pkix__pkixutil_h
#include "pkixder.h"
-#include "prerror.h"
-#include "seccomon.h"
-#include "secerr.h"
namespace mozilla { namespace pkix {
// During path building and verification, we build a linked list of BackCerts
// from the current cert toward the end-entity certificate. The linked list
// is used to verify properties that aren't local to the current certificate
// and/or the direct link between the current certificate and its issuer,
// such as name constraints.
@@ -166,17 +163,17 @@ public:
virtual const SECItem* GetDER(size_t i) const
{
return i < numItems ? items[i] : nullptr;
}
Result Append(const SECItem& der)
{
if (numItems >= MAX_LENGTH) {
- return Fail(SEC_ERROR_INVALID_ARGS);
+ return Result::FATAL_ERROR_INVALID_ARGS;
}
items[numItems] = &der;
++numItems;
return Success;
}
// Public so we can static_assert on this. Keep in sync with MAX_SUBCA_COUNT.
static const size_t MAX_LENGTH = 8;
--- a/security/pkix/moz.build
+++ b/security/pkix/moz.build
@@ -5,17 +5,17 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
SOURCES += [
'lib/pkixbind.cpp',
'lib/pkixbuild.cpp',
'lib/pkixcert.cpp',
'lib/pkixcheck.cpp',
'lib/pkixder.cpp',
- 'lib/pkixkey.cpp',
+ 'lib/pkixnss.cpp',
'lib/pkixocsp.cpp',
]
LOCAL_INCLUDES += [
'include',
]
TEST_DIRS += [
--- a/security/pkix/test/gtest/moz.build
+++ b/security/pkix/test/gtest/moz.build
@@ -13,17 +13,16 @@ SOURCES += [
'pkixcheck_CheckKeyUsage_tests.cpp',
'pkixcheck_CheckValidity_tests.cpp',
# The naming conventions are described in ./README.txt.
'pkixder_input_tests.cpp',
'pkixder_pki_types_tests.cpp',
'pkixder_universal_types_tests.cpp',
- 'pkixgtest.cpp',
'pkixocsp_CreateEncodedOCSPRequest_tests.cpp',
'pkixocsp_VerifyEncodedOCSPResponse.cpp',
]
LOCAL_INCLUDES += [
'../../include',
'../../lib',
'../lib',
--- a/security/pkix/test/gtest/pkixbuild_tests.cpp
+++ b/security/pkix/test/gtest/pkixbuild_tests.cpp
@@ -19,16 +19,19 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nssgtest.h"
#include "pkix/pkix.h"
+#include "pkix/pkixnss.h"
+#include "pkixgtest.h"
+#include "pkixtestutil.h"
#include "prinit.h"
#include "secerr.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
static bool
CreateCert(PLArenaPool* arena, const char* issuerStr,
@@ -107,82 +110,80 @@ public:
return false;
}
}
return true;
}
private:
- SECStatus GetCertTrust(EndEntityOrCA,
- const CertPolicyId&,
- const SECItem& candidateCert,
- /*out*/ TrustLevel* trustLevel)
+ virtual Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
+ const SECItem& candidateCert,
+ /*out*/ TrustLevel* trustLevel)
{
if (SECITEM_ItemsAreEqual(&candidateCert, &certChainTail[0]->derCert)) {
*trustLevel = TrustLevel::TrustAnchor;
} else {
*trustLevel = TrustLevel::InheritsTrust;
}
- return SECSuccess;
+ return Success;
}
- SECStatus FindIssuer(const SECItem& encodedIssuerName,
- IssuerChecker& checker, PRTime time)
+ virtual Result FindIssuer(const SECItem& encodedIssuerName,
+ IssuerChecker& checker, PRTime time)
{
ScopedCERTCertList
candidates(CERT_CreateSubjectCertList(nullptr, CERT_GetDefaultCertDB(),
&encodedIssuerName, time, true));
if (candidates) {
for (CERTCertListNode* n = CERT_LIST_HEAD(candidates);
!CERT_LIST_END(n, candidates); n = CERT_LIST_NEXT(n)) {
bool keepGoing;
- SECStatus srv = checker.Check(n->cert->derCert,
- nullptr/*additionalNameConstraints*/,
- keepGoing);
- if (srv != SECSuccess) {
- return SECFailure;
+ Result rv = checker.Check(n->cert->derCert,
+ nullptr/*additionalNameConstraints*/,
+ keepGoing);
+ if (rv != Success) {
+ return rv;
}
if (!keepGoing) {
break;
}
}
}
- return SECSuccess;
+ return Success;
}
- SECStatus CheckRevocation(EndEntityOrCA, const CertID&, PRTime,
- /*optional*/ const SECItem*,
- /*optional*/ const SECItem*)
+ virtual Result CheckRevocation(EndEntityOrCA, const CertID&, PRTime,
+ /*optional*/ const SECItem*,
+ /*optional*/ const SECItem*)
{
- return SECSuccess;
+ return Success;
}
- virtual SECStatus IsChainValid(const DERArray&)
+ virtual Result IsChainValid(const DERArray&)
{
- return SECSuccess;
+ return Success;
}
- SECStatus VerifySignedData(const SignedDataWithSignature& signedData,
- const SECItem& subjectPublicKeyInfo)
+ virtual Result VerifySignedData(const SignedDataWithSignature& signedData,
+ const SECItem& subjectPublicKeyInfo)
{
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
nullptr);
}
- virtual SECStatus DigestBuf(const SECItem& item, /*out*/ uint8_t *digestBuf,
- size_t digestBufLen)
+ virtual Result DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
+ size_t digestBufLen)
{
ADD_FAILURE();
- PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
- return SECFailure;
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
- SECStatus CheckPublicKey(const SECItem& subjectPublicKeyInfo)
+ virtual Result CheckPublicKey(const SECItem& subjectPublicKeyInfo)
{
return ::mozilla::pkix::CheckPublicKey(subjectPublicKeyInfo);
}
// We hold references to CERTCertificates in the cert chain tail so that we
// CERT_CreateSubjectCertList can find them.
ScopedCERTCertificate certChainTail[7];
@@ -210,64 +211,63 @@ public:
protected:
static TestTrustDomain trustDomain;
};
/*static*/ TestTrustDomain pkixbuild::trustDomain;
TEST_F(pkixbuild, MaxAcceptableCertChainLength)
{
- ASSERT_SECSuccess(BuildCertChain(trustDomain,
- trustDomain.GetLeafCACert()->derCert,
- now, EndEntityOrCA::MustBeCA,
- KeyUsage::noParticularKeyUsageRequired,
- KeyPurposeId::id_kp_serverAuth,
- CertPolicyId::anyPolicy,
- nullptr/*stapledOCSPResponse*/));
+ 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_SECSuccess(BuildCertChain(trustDomain, cert->derCert, now,
- EndEntityOrCA::MustBeEndEntity,
- KeyUsage::noParticularKeyUsageRequired,
- KeyPurposeId::id_kp_serverAuth,
- CertPolicyId::anyPolicy,
- nullptr/*stapledOCSPResponse*/));
+ 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));
- PR_SetError(0, 0);
- ASSERT_SECFailure(SEC_ERROR_UNKNOWN_ISSUER,
- BuildCertChain(trustDomain, caCert->derCert, now,
- EndEntityOrCA::MustBeCA,
- KeyUsage::noParticularKeyUsageRequired,
- KeyPurposeId::id_kp_serverAuth,
- CertPolicyId::anyPolicy,
- nullptr/*stapledOCSPResponse*/));
+ ASSERT_EQ(Result::ERROR_UNKNOWN_ISSUER,
+ BuildCertChain(trustDomain, caCert->derCert, now,
+ EndEntityOrCA::MustBeCA,
+ KeyUsage::noParticularKeyUsageRequired,
+ KeyPurposeId::id_kp_serverAuth,
+ CertPolicyId::anyPolicy,
+ nullptr/*stapledOCSPResponse*/));
ScopedSECKEYPrivateKey privateKey;
ScopedCERTCertificate cert;
ASSERT_TRUE(CreateCert(arena.get(), caCert->subjectName,
"CN=End-Entity Too Far",
EndEntityOrCA::MustBeEndEntity,
caPrivateKey.get(), privateKey, cert));
- PR_SetError(0, 0);
- ASSERT_SECFailure(SEC_ERROR_UNKNOWN_ISSUER,
- BuildCertChain(trustDomain, cert->derCert, now,
- EndEntityOrCA::MustBeEndEntity,
- KeyUsage::noParticularKeyUsageRequired,
- KeyPurposeId::id_kp_serverAuth,
- CertPolicyId::anyPolicy,
- nullptr/*stapledOCSPResponse*/));
+ ASSERT_EQ(Result::ERROR_UNKNOWN_ISSUER,
+ BuildCertChain(trustDomain, cert->derCert, now,
+ EndEntityOrCA::MustBeEndEntity,
+ KeyUsage::noParticularKeyUsageRequired,
+ KeyPurposeId::id_kp_serverAuth,
+ CertPolicyId::anyPolicy,
+ nullptr/*stapledOCSPResponse*/));
}
--- a/security/pkix/test/gtest/pkixcert_extension_tests.cpp
+++ b/security/pkix/test/gtest/pkixcert_extension_tests.cpp
@@ -19,16 +19,18 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nssgtest.h"
#include "pkix/pkix.h"
+#include "pkix/pkixnss.h"
+#include "pkixtestutil.h"
#include "secerr.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
// Creates a self-signed certificate with the given extension.
static const SECItem*
CreateCert(PLArenaPool* arena, const char* subjectStr,
@@ -68,60 +70,57 @@ CreateCert(PLArenaPool* arena, const cha
{
const SECItem * extensions[] = { extension, nullptr };
return CreateCert(arena, subjectStr, extensions, subjectKey);
}
class TrustEverythingTrustDomain : public TrustDomain
{
private:
- SECStatus GetCertTrust(EndEntityOrCA,
- const CertPolicyId&,
- const SECItem& candidateCert,
- /*out*/ TrustLevel* trustLevel)
+ virtual Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
+ const SECItem& candidateCert,
+ /*out*/ TrustLevel* trustLevel)
{
*trustLevel = TrustLevel::TrustAnchor;
- return SECSuccess;
+ return Success;
}
- SECStatus FindIssuer(const SECItem& /*encodedIssuerName*/,
- IssuerChecker& /*checker*/, PRTime /*time*/)
+ virtual Result FindIssuer(const SECItem& /*encodedIssuerName*/,
+ IssuerChecker& /*checker*/, PRTime /*time*/)
{
ADD_FAILURE();
- PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
- return SECFailure;
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
- SECStatus CheckRevocation(EndEntityOrCA, const CertID&, PRTime,
- /*optional*/ const SECItem*,
- /*optional*/ const SECItem*)
+ virtual Result CheckRevocation(EndEntityOrCA, const CertID&, PRTime,
+ /*optional*/ const SECItem*,
+ /*optional*/ const SECItem*)
{
- return SECSuccess;
+ return Success;
}
- virtual SECStatus IsChainValid(const DERArray&)
+ virtual Result IsChainValid(const DERArray&)
{
- return SECSuccess;
+ return Success;
}
- SECStatus VerifySignedData(const SignedDataWithSignature& signedData,
- const SECItem& subjectPublicKeyInfo)
+ virtual Result VerifySignedData(const SignedDataWithSignature& signedData,
+ const SECItem& subjectPublicKeyInfo)
{
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
nullptr);
}
- SECStatus DigestBuf(const SECItem&, /*out*/ uint8_t *, size_t)
+ virtual Result DigestBuf(const SECItem&, /*out*/ uint8_t*, size_t)
{
ADD_FAILURE();
- PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
- return SECFailure;
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
- SECStatus CheckPublicKey(const SECItem& subjectPublicKeyInfo)
+ virtual Result CheckPublicKey(const SECItem& subjectPublicKeyInfo)
{
return ::mozilla::pkix::CheckPublicKey(subjectPublicKeyInfo);
}
};
class pkixcert_extension: public NSSTest
{
public:
@@ -156,23 +155,23 @@ TEST_F(pkixcert_extension, UnknownCritic
sizeof(unknownCriticalExtensionBytes)
};
const char* certCN = "CN=Cert With Unknown Critical Extension";
ScopedSECKEYPrivateKey key;
// cert is owned by the arena
const SECItem* cert(CreateCert(arena.get(), certCN,
&unknownCriticalExtension, key));
ASSERT_TRUE(cert);
- ASSERT_SECFailure(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION,
- BuildCertChain(trustDomain, *cert, now,
- EndEntityOrCA::MustBeEndEntity,
- KeyUsage::noParticularKeyUsageRequired,
- KeyPurposeId::anyExtendedKeyUsage,
- CertPolicyId::anyPolicy,
- nullptr/*stapledOCSPResponse*/));
+ ASSERT_EQ(Result::ERROR_UNKNOWN_CRITICAL_EXTENSION,
+ BuildCertChain(trustDomain, *cert, now,
+ EndEntityOrCA::MustBeEndEntity,
+ KeyUsage::noParticularKeyUsageRequired,
+ KeyPurposeId::anyExtendedKeyUsage,
+ CertPolicyId::anyPolicy,
+ nullptr/*stapledOCSPResponse*/));
}
// Tests that a non-critical extension not in the id-ce or id-pe arcs (which is
// thus unknown to us) verifies successfully.
TEST_F(pkixcert_extension, UnknownNonCriticalExtension)
{
static const uint8_t unknownNonCriticalExtensionBytes[] = {
0x30, 0x16, // SEQUENCE (length = 22)
@@ -188,22 +187,23 @@ TEST_F(pkixcert_extension, UnknownNonCri
sizeof(unknownNonCriticalExtensionBytes)
};
const char* certCN = "CN=Cert With Unknown NonCritical Extension";
ScopedSECKEYPrivateKey key;
// cert is owned by the arena
const SECItem* cert(CreateCert(arena.get(), certCN,
&unknownNonCriticalExtension, key));
ASSERT_TRUE(cert);
- ASSERT_SECSuccess(BuildCertChain(trustDomain, *cert, now,
- EndEntityOrCA::MustBeEndEntity,
- KeyUsage::noParticularKeyUsageRequired,
- KeyPurposeId::anyExtendedKeyUsage,
- CertPolicyId::anyPolicy,
- nullptr/*stapledOCSPResponse*/));
+ ASSERT_EQ(Success,
+ BuildCertChain(trustDomain, *cert, now,
+ EndEntityOrCA::MustBeEndEntity,
+ KeyUsage::noParticularKeyUsageRequired,
+ KeyPurposeId::anyExtendedKeyUsage,
+ CertPolicyId::anyPolicy,
+ nullptr/*stapledOCSPResponse*/));
}
// Tests that an incorrect OID for id-pe-authorityInformationAccess
// (when marked critical) is detected and that verification fails.
// (Until bug 1020993 was fixed, the code checked for this OID.)
TEST_F(pkixcert_extension, WrongOIDCriticalExtension)
{
static const uint8_t wrongOIDCriticalExtensionBytes[] = {
@@ -220,23 +220,23 @@ TEST_F(pkixcert_extension, WrongOIDCriti
sizeof(wrongOIDCriticalExtensionBytes)
};
const char* certCN = "CN=Cert With Critical Wrong OID Extension";
ScopedSECKEYPrivateKey key;
// cert is owned by the arena
const SECItem* cert(CreateCert(arena.get(), certCN,
&wrongOIDCriticalExtension, key));
ASSERT_TRUE(cert);
- ASSERT_SECFailure(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION,
- BuildCertChain(trustDomain, *cert, now,
- EndEntityOrCA::MustBeEndEntity,
- KeyUsage::noParticularKeyUsageRequired,
- KeyPurposeId::anyExtendedKeyUsage,
- CertPolicyId::anyPolicy,
- nullptr/*stapledOCSPResponse*/));
+ ASSERT_EQ(Result::ERROR_UNKNOWN_CRITICAL_EXTENSION,
+ BuildCertChain(trustDomain, *cert, now,
+ EndEntityOrCA::MustBeEndEntity,
+ KeyUsage::noParticularKeyUsageRequired,
+ KeyPurposeId::anyExtendedKeyUsage,
+ CertPolicyId::anyPolicy,
+ nullptr/*stapledOCSPResponse*/));
}
// Tests that a id-pe-authorityInformationAccess critical extension
// is detected and that verification succeeds.
TEST_F(pkixcert_extension, CriticalAIAExtension)
{
// XXX: According to RFC 5280 an AIA that consists of an empty sequence is
// not legal, but we accept it and that is not what we're testing here.
@@ -255,22 +255,23 @@ TEST_F(pkixcert_extension, CriticalAIAEx
sizeof(criticalAIAExtensionBytes)
};
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);
- ASSERT_SECSuccess(BuildCertChain(trustDomain, *cert, now,
- EndEntityOrCA::MustBeEndEntity,
- KeyUsage::noParticularKeyUsageRequired,
- KeyPurposeId::anyExtendedKeyUsage,
- CertPolicyId::anyPolicy,
- nullptr/*stapledOCSPResponse*/));
+ ASSERT_EQ(Success,
+ BuildCertChain(trustDomain, *cert, now,
+ EndEntityOrCA::MustBeEndEntity,
+ KeyUsage::noParticularKeyUsageRequired,
+ KeyPurposeId::anyExtendedKeyUsage,
+ CertPolicyId::anyPolicy,
+ nullptr/*stapledOCSPResponse*/));
}
// We know about some id-ce extensions (OID arc 2.5.29), but not all of them.
// Tests that an unknown id-ce extension is detected and that verification
// fails.
TEST_F(pkixcert_extension, UnknownCriticalCEExtension)
{
static const uint8_t unknownCriticalCEExtensionBytes[] = {
@@ -286,23 +287,23 @@ TEST_F(pkixcert_extension, UnknownCritic
sizeof(unknownCriticalCEExtensionBytes)
};
const char* certCN = "CN=Cert With Unknown Critical id-ce Extension";
ScopedSECKEYPrivateKey key;
// cert is owned by the arena
const SECItem* cert(CreateCert(arena.get(), certCN,
&unknownCriticalCEExtension, key));
ASSERT_TRUE(cert);
- ASSERT_SECFailure(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION,
- BuildCertChain(trustDomain, *cert, now,
- EndEntityOrCA::MustBeEndEntity,
- KeyUsage::noParticularKeyUsageRequired,
- KeyPurposeId::anyExtendedKeyUsage,
- CertPolicyId::anyPolicy,
- nullptr/*stapledOCSPResponse*/));
+ ASSERT_EQ(Result::ERROR_UNKNOWN_CRITICAL_EXTENSION,
+ BuildCertChain(trustDomain, *cert, now,
+ EndEntityOrCA::MustBeEndEntity,
+ KeyUsage::noParticularKeyUsageRequired,
+ KeyPurposeId::anyExtendedKeyUsage,
+ CertPolicyId::anyPolicy,
+ nullptr/*stapledOCSPResponse*/));
}
// Tests that a certificate with a known critical id-ce extension (in this case,
// OID 2.5.29.54, which is id-ce-inhibitAnyPolicy), verifies successfully.
TEST_F(pkixcert_extension, KnownCriticalCEExtension)
{
static const uint8_t criticalCEExtensionBytes[] = {
0x30, 0x0d, // SEQUENCE (length = 13)
@@ -318,22 +319,23 @@ TEST_F(pkixcert_extension, KnownCritical
sizeof(criticalCEExtensionBytes)
};
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);
- ASSERT_SECSuccess(BuildCertChain(trustDomain, *cert,
- now, EndEntityOrCA::MustBeEndEntity,
- KeyUsage::noParticularKeyUsageRequired,
- KeyPurposeId::anyExtendedKeyUsage,
- CertPolicyId::anyPolicy,
- nullptr/*stapledOCSPResponse*/));
+ ASSERT_EQ(Success,
+ BuildCertChain(trustDomain, *cert, now,
+ EndEntityOrCA::MustBeEndEntity,
+ KeyUsage::noParticularKeyUsageRequired,
+ KeyPurposeId::anyExtendedKeyUsage,
+ CertPolicyId::anyPolicy,
+ nullptr/*stapledOCSPResponse*/));
}
// Two subjectAltNames must result in an error.
TEST_F(pkixcert_extension, DuplicateSubjectAltName)
{
static const uint8_t DER_BYTES[] = {
0x30, 22, // SEQUENCE (length = 22)
0x06, 3, // OID (length = 3)
@@ -349,16 +351,16 @@ TEST_F(pkixcert_extension, DuplicateSubj
sizeof(DER_BYTES)
};
static SECItem const* const extensions[] = { &DER, &DER, nullptr };
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);
- ASSERT_SECFailure(SEC_ERROR_EXTENSION_VALUE_INVALID,
- BuildCertChain(trustDomain, *cert,
- now, EndEntityOrCA::MustBeEndEntity,
- KeyUsage::noParticularKeyUsageRequired,
- KeyPurposeId::anyExtendedKeyUsage,
- CertPolicyId::anyPolicy,
- nullptr/*stapledOCSPResponse*/));
+ ASSERT_EQ(Result::ERROR_EXTENSION_VALUE_INVALID,
+ BuildCertChain(trustDomain, *cert, now,
+ EndEntityOrCA::MustBeEndEntity,
+ KeyUsage::noParticularKeyUsageRequired,
+ KeyPurposeId::anyExtendedKeyUsage,
+ CertPolicyId::anyPolicy,
+ nullptr/*stapledOCSPResponse*/));
}
--- a/security/pkix/test/gtest/pkixcheck_CheckKeyUsage_tests.cpp
+++ b/security/pkix/test/gtest/pkixcheck_CheckKeyUsage_tests.cpp
@@ -17,40 +17,32 @@
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "pkixgtest.h"
+#include "gtest/gtest.h"
+#include "pkix/pkixtypes.h"
using namespace mozilla::pkix;
-using namespace mozilla::pkix::test;
namespace mozilla { namespace pkix {
extern Result CheckKeyUsage(EndEntityOrCA endEntityOrCA,
const SECItem* encodedKeyUsage,
KeyUsage requiredKeyUsageIfPresent);
} } // namespace mozilla::pkix
-class pkixcheck_CheckKeyUsage : public ::testing::Test
-{
-public:
- pkixcheck_CheckKeyUsage()
- {
- PR_SetError(0, 0);
- }
-};
+class pkixcheck_CheckKeyUsage : public ::testing::Test { };
-#define ASSERT_BAD(x) \
- ASSERT_RecoverableError(SEC_ERROR_INADEQUATE_KEY_USAGE, x)
+#define ASSERT_BAD(x) ASSERT_EQ(Result::ERROR_INADEQUATE_KEY_USAGE, x)
// Make it easy to define test data for the common, simplest cases.
#define NAMED_SIMPLE_KU(name, unusedBits, bits) \
const uint8_t name##_bytes[4] = { \
0x03/*BIT STRING*/, 0x02/*LENGTH=2*/, unusedBits, bits \
}; \
const SECItem name = { \
siBuffer, \
@@ -66,61 +58,61 @@ static const SECItem empty_nonnull = { s
// 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
// extension. This is always valid because no key usage in an end-entity
// means that there are no key usage restrictions.
- ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
- KeyUsage::noParticularKeyUsageRequired));
- ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
- KeyUsage::digitalSignature));
- ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
- KeyUsage::nonRepudiation));
- ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
- KeyUsage::keyEncipherment));
- ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
- KeyUsage::dataEncipherment));
- ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
- KeyUsage::keyAgreement));
+ ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
+ KeyUsage::noParticularKeyUsageRequired));
+ ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
+ KeyUsage::digitalSignature));
+ ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
+ KeyUsage::nonRepudiation));
+ ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
+ KeyUsage::keyEncipherment));
+ ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
+ KeyUsage::dataEncipherment));
+ ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, nullptr,
+ KeyUsage::keyAgreement));
}
TEST_F(pkixcheck_CheckKeyUsage, EE_empty)
{
// The input SECItem is empty. The cert had an empty keyUsage extension,
// which is syntactically invalid.
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &empty_null,
KeyUsage::digitalSignature));
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &empty_nonnull,
KeyUsage::digitalSignature));
}
TEST_F(pkixcheck_CheckKeyUsage, CA_none)
{
// A CA certificate does not have a KU extension.
- ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeCA, nullptr,
- KeyUsage::keyCertSign));
+ ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeCA, nullptr,
+ KeyUsage::keyCertSign));
}
TEST_F(pkixcheck_CheckKeyUsage, CA_empty)
{
// A CA certificate has an empty KU extension.
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &empty_null,
KeyUsage::keyCertSign));
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, &empty_nonnull,
KeyUsage::keyCertSign));
}
TEST_F(pkixcheck_CheckKeyUsage, maxUnusedBits)
{
NAMED_SIMPLE_KU(encoded, 7, 0x80);
- ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &encoded,
- KeyUsage::digitalSignature));
+ ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &encoded,
+ KeyUsage::digitalSignature));
}
TEST_F(pkixcheck_CheckKeyUsage, tooManyUnusedBits)
{
static uint8_t oneValueByteData[] = {
0x03/*BIT STRING*/, 0x02/*LENGTH=2*/, 8/*unused bits*/, 0x80
};
const SECItem oneValueByte = {
@@ -177,18 +169,19 @@ TEST_F(pkixcheck_CheckKeyUsage, NoValueB
KeyUsage::keyCertSign));
}
void ASSERT_SimpleCase(uint8_t unusedBits, uint8_t bits, KeyUsage usage)
{
// Test that only the right bit is accepted for the usage for both EE and CA
// certs.
NAMED_SIMPLE_KU(good, unusedBits, bits);
- ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &good, usage));
- ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeCA, &good, usage));
+ ASSERT_EQ(Success,
+ CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &good, usage));
+ ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeCA, &good, usage));
// We use (~bits >> unusedBits) << unusedBits) instead of using the same
// calculation that is in CheckKeyUsage to validate that the calculation in
// CheckKeyUsage is correct.
// Test that none of the other non-padding bits are mistaken for the given
// key usage in the single-byte value case.
NAMED_SIMPLE_KU(notGood, unusedBits,
@@ -221,18 +214,18 @@ TEST_F(pkixcheck_CheckKeyUsage, simpleCa
}
// Only CAs are allowed to assert keyCertSign
TEST_F(pkixcheck_CheckKeyUsage, keyCertSign)
{
NAMED_SIMPLE_KU(good, 2, 0x04);
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, &good,
KeyUsage::keyCertSign));
- ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeCA, &good,
- KeyUsage::keyCertSign));
+ ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeCA, &good,
+ KeyUsage::keyCertSign));
// Test that none of the other non-padding bits are mistaken for the given
// key usage in the one-byte value case.
NAMED_SIMPLE_KU(notGood, 2, 0xFB);
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity, ¬Good,
KeyUsage::keyCertSign));
ASSERT_BAD(CheckKeyUsage(EndEntityOrCA::MustBeCA, ¬Good,
KeyUsage::keyCertSign));
@@ -257,21 +250,22 @@ TEST_F(pkixcheck_CheckKeyUsage, unusedBi
static uint8_t controlOneValueByteData[] = {
0x03/*BIT STRING*/, 0x02/*LENGTH=2*/, 7/*unused bits*/, 0x80
};
const SECItem controlOneValueByte = {
siBuffer,
controlOneValueByteData,
sizeof(controlOneValueByteData)
};
- ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity,
- &controlOneValueByte,
- KeyUsage::digitalSignature));
- ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeCA, &controlOneValueByte,
- KeyUsage::digitalSignature));
+ ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity,
+ &controlOneValueByte,
+ KeyUsage::digitalSignature));
+ ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeCA,
+ &controlOneValueByte,
+ KeyUsage::digitalSignature));
// single-byte test case
static uint8_t oneValueByteData[] = {
0x03/*BIT STRING*/, 0x02/*LENGTH=2*/, 7/*unused bits*/, 0x80 | 0x01
};
const SECItem oneValueByte = {
siBuffer,
oneValueByteData,
@@ -287,21 +281,22 @@ TEST_F(pkixcheck_CheckKeyUsage, unusedBi
0x03/*BIT STRING*/, 0x03/*LENGTH=3*/, 7/*unused bits*/,
0x80 | 0x01, 0x80
};
const SECItem controlTwoValueBytes = {
siBuffer,
controlTwoValueBytesData,
sizeof(controlTwoValueBytesData)
};
- ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeEndEntity,
- &controlTwoValueBytes,
- KeyUsage::digitalSignature));
- ASSERT_Success(CheckKeyUsage(EndEntityOrCA::MustBeCA, &controlTwoValueBytes,
- KeyUsage::digitalSignature));
+ ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeEndEntity,
+ &controlTwoValueBytes,
+ KeyUsage::digitalSignature));
+ ASSERT_EQ(Success, CheckKeyUsage(EndEntityOrCA::MustBeCA,
+ &controlTwoValueBytes,
+ KeyUsage::digitalSignature));
// two-byte test case
static uint8_t twoValueBytesData[] = {
0x03/*BIT STRING*/, 0x03/*LENGTH=3*/, 7/*unused bits*/,
0x80 | 0x01, 0x80 | 0x01
};
const SECItem twoValueBytes = {
siBuffer,
--- a/security/pkix/test/gtest/pkixcheck_CheckValidity_tests.cpp
+++ b/security/pkix/test/gtest/pkixcheck_CheckValidity_tests.cpp
@@ -17,17 +17,18 @@
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-#include "pkixgtest.h"
+#include "gtest/gtest.h"
+#include "pkix/pkixtypes.h"
#include "pkixtestutil.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
namespace mozilla { namespace pkix {
Result CheckValidity(const SECItem& encodedValidity, PRTime time);
@@ -55,147 +56,134 @@ static const PRTime NOW(YMDHMS(2016, 12,
#define NEWER_UTCTIME \
0x17, 13, /* tag, length */ \
'2', '1', '0', '1', '0', '1', /* 2021-01-01 */ \
'0', '0', '0', '0', '0', '0', 'Z' /* 00:00:00Z */
static const PRTime FUTURE_TIME(YMDHMS(2025, 12, 31, 12, 23, 56));
-class pkixcheck_CheckValidity : public ::testing::Test
-{
-public:
- virtual void SetUp()
- {
- PR_SetError(0, 0);
- }
-};
+class pkixcheck_CheckValidity : public ::testing::Test { };
TEST_F(pkixcheck_CheckValidity, BothEmptyNull)
{
static const uint8_t DER[] = {
0x17/*UTCTime*/, 0/*length*/,
0x17/*UTCTime*/, 0/*length*/,
};
static const SECItem validity = {
siBuffer,
const_cast<uint8_t*>(DER),
sizeof(DER)
};
- ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
- CheckValidity(validity, NOW));
+ ASSERT_EQ(Result::ERROR_EXPIRED_CERTIFICATE, CheckValidity(validity, NOW));
}
TEST_F(pkixcheck_CheckValidity, NotBeforeEmptyNull)
{
static const uint8_t DER[] = {
0x17/*UTCTime*/, 0x00/*length*/,
NEWER_UTCTIME
};
static const SECItem validity = {
siBuffer,
const_cast<uint8_t*>(DER),
sizeof(DER)
};
- ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
- CheckValidity(validity, NOW));
+ ASSERT_EQ(Result::ERROR_EXPIRED_CERTIFICATE, CheckValidity(validity, NOW));
}
TEST_F(pkixcheck_CheckValidity, NotAfterEmptyNull)
{
static const uint8_t DER[] = {
NEWER_UTCTIME,
0x17/*UTCTime*/, 0x00/*length*/,
};
static const SECItem validity = {
siBuffer,
const_cast<uint8_t*>(DER),
sizeof(DER)
};
- ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
- CheckValidity(validity, NOW));
+ ASSERT_EQ(Result::ERROR_EXPIRED_CERTIFICATE, CheckValidity(validity, NOW));
}
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)
};
TEST_F(pkixcheck_CheckValidity, Valid_UTCTIME_UTCTIME)
{
- ASSERT_Success(CheckValidity(OLDER_UTCTIME_NEWER_UTCTIME, NOW));
+ ASSERT_EQ(Success, CheckValidity(OLDER_UTCTIME_NEWER_UTCTIME, NOW));
}
TEST_F(pkixcheck_CheckValidity, Valid_GENERALIZEDTIME_GENERALIZEDTIME)
{
static const uint8_t DER[] = {
OLDER_GENERALIZEDTIME,
NEWER_GENERALIZEDTIME,
};
static const SECItem validity = {
siBuffer,
const_cast<uint8_t*>(DER),
sizeof(DER)
};
- ASSERT_Success(CheckValidity(validity, NOW));
+ ASSERT_EQ(Success, CheckValidity(validity, NOW));
}
TEST_F(pkixcheck_CheckValidity, Valid_GENERALIZEDTIME_UTCTIME)
{
static const uint8_t DER[] = {
OLDER_GENERALIZEDTIME,
NEWER_UTCTIME,
};
static const SECItem validity = {
siBuffer,
const_cast<uint8_t*>(DER),
sizeof(DER)
};
- ASSERT_Success(CheckValidity(validity, NOW));
+ ASSERT_EQ(Success, CheckValidity(validity, NOW));
}
TEST_F(pkixcheck_CheckValidity, Valid_UTCTIME_GENERALIZEDTIME)
{
static const uint8_t DER[] = {
OLDER_UTCTIME,
NEWER_GENERALIZEDTIME,
};
static const SECItem validity = {
siBuffer,
const_cast<uint8_t*>(DER),
sizeof(DER)
};
- ASSERT_Success(CheckValidity(validity, NOW));
+ ASSERT_EQ(Success, CheckValidity(validity, NOW));
}
TEST_F(pkixcheck_CheckValidity, InvalidBeforeNotBefore)
{
- ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
- CheckValidity(OLDER_UTCTIME_NEWER_UTCTIME,
- PAST_TIME));
+ ASSERT_EQ(Result::ERROR_EXPIRED_CERTIFICATE,
+ CheckValidity(OLDER_UTCTIME_NEWER_UTCTIME, PAST_TIME));
}
TEST_F(pkixcheck_CheckValidity, InvalidAfterNotAfter)
{
- ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
- CheckValidity(OLDER_UTCTIME_NEWER_UTCTIME,
- FUTURE_TIME));
+ ASSERT_EQ(Result::ERROR_EXPIRED_CERTIFICATE,
+ CheckValidity(OLDER_UTCTIME_NEWER_UTCTIME, FUTURE_TIME));
}
TEST_F(pkixcheck_CheckValidity, InvalidNotAfterBeforeNotBefore)
{
static const uint8_t DER[] = {
NEWER_UTCTIME,
OLDER_UTCTIME,
};
static const SECItem validity = {
siBuffer,
const_cast<uint8_t*>(DER),
sizeof(DER)
};
- ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
- CheckValidity(validity, NOW));
+ ASSERT_EQ(Result::ERROR_EXPIRED_CERTIFICATE, CheckValidity(validity, NOW));
}
--- a/security/pkix/test/gtest/pkixder_input_tests.cpp
+++ b/security/pkix/test/gtest/pkixder_input_tests.cpp
@@ -21,34 +21,25 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <functional>
#include <vector>
#include <gtest/gtest.h>
-#include "pkixgtest.h"
#include "pkix/bind.h"
#include "pkixder.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::der;
-using namespace mozilla::pkix::test;
namespace {
-class pkixder_input_tests : public ::testing::Test
-{
-protected:
- virtual void SetUp()
- {
- PR_SetError(0, 0);
- }
-};
+class pkixder_input_tests : public ::testing::Test { };
static const uint8_t DER_SEQUENCE_EMPTY[] = {
0x30, // SEQUENCE
0x00, // length
};
static const uint8_t DER_SEQUENCE_NOT_EMPTY[] = {
0x30, // SEQUENCE
@@ -90,65 +81,57 @@ const uint8_t DER_OVERRUN_SEQUENCE_OF_IN
};
const uint8_t DER_INT16[] = {
0x02, // INTEGER
0x02, // length
0x12, 0x34 // 0x1234
};
-TEST_F(pkixder_input_tests, FailWithError)
-{
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, Fail(SEC_ERROR_BAD_DER));
- ASSERT_FatalError(SEC_ERROR_INVALID_ARGS, Fail(SEC_ERROR_INVALID_ARGS));
-}
-
TEST_F(pkixder_input_tests, InputInit)
{
Input input;
ASSERT_EQ(Success,
input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
}
TEST_F(pkixder_input_tests, InputInitWithNullPointerOrZeroLength)
{
Input input;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, input.Init(nullptr, 0));
+ ASSERT_EQ(Result::ERROR_BAD_DER, input.Init(nullptr, 0));
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, input.Init(nullptr, 100));
+ ASSERT_EQ(Result::ERROR_BAD_DER, input.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());
}
TEST_F(pkixder_input_tests, InputInitWithLargeData)
{
Input input;
// Data argument length does not matter, it is not touched, just
// needs to be non-null
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- input.Init((const uint8_t*) "", 0xffff+1));
+ ASSERT_EQ(Result::ERROR_BAD_DER, input.Init((const uint8_t*) "", 0xffff+1));
ASSERT_EQ(Success, input.Init((const uint8_t*) "", 0xffff));
}
TEST_F(pkixder_input_tests, InputInitMultipleTimes)
{
Input input;
ASSERT_EQ(Success,
input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
- ASSERT_FatalError(SEC_ERROR_INVALID_ARGS,
- input.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));
@@ -160,30 +143,28 @@ TEST_F(pkixder_input_tests, ExpectSucces
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_RecoverableError(SEC_ERROR_BAD_DER,
- input.Expect(expected, sizeof expected));
+ 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_RecoverableError(SEC_ERROR_BAD_DER,
- input.Expect(expected, sizeof expected));
+ ASSERT_EQ(Result::ERROR_BAD_DER, input.Expect(expected, sizeof expected));
}
TEST_F(pkixder_input_tests, PeekWithinBounds)
{
Input input;
const uint8_t der[] = { 0x11, 0x11 };
ASSERT_EQ(Success, input.Init(der, sizeof der));
ASSERT_TRUE(input.Peek(0x11));
@@ -224,34 +205,34 @@ TEST_F(pkixder_input_tests, ReadBytePast
// Initialize with too-short length
ASSERT_EQ(Success, input.Init(der, 1));
uint8_t readByte1 = 0;
ASSERT_EQ(Success, input.Read(readByte1));
ASSERT_EQ(0x11, readByte1);
uint8_t readByte2 = 0;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, input.Read(readByte2));
+ ASSERT_EQ(Result::ERROR_BAD_DER, input.Read(readByte2));
ASSERT_NE(0x22, readByte2);
}
TEST_F(pkixder_input_tests, ReadByteWrapAroundPointer)
{
// The original implementation of our buffer read overflow checks was
// susceptible to integer overflows which could make the checks ineffective.
// This attempts to verify that we've fixed that. Unfortunately, decrementing
// a null pointer is undefined behavior according to the C++ language spec.,
// but this should catch the problem on at least some compilers, if not all of
// them.
const uint8_t* der = nullptr;
--der;
Input input;
ASSERT_EQ(Success, input.Init(der, 0));
uint8_t b;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, input.Read(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));
@@ -271,45 +252,45 @@ TEST_F(pkixder_input_tests, ReadWordPast
// Initialize with too-short length
ASSERT_EQ(Success, input.Init(der, 2));
uint16_t readWord1 = 0;
ASSERT_EQ(Success, input.Read(readWord1));
ASSERT_EQ(0x1122, readWord1);
uint16_t readWord2 = 0;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, input.Read(readWord2));
+ ASSERT_EQ(Result::ERROR_BAD_DER, input.Read(readWord2));
ASSERT_NE(0x3344, readWord2);
}
TEST_F(pkixder_input_tests, ReadWordWithInsufficentData)
{
Input input;
const uint8_t der[] = { 0x11, 0x22 };
ASSERT_EQ(Success, input.Init(der, 1));
uint16_t readWord1 = 0;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, input.Read(readWord1));
+ ASSERT_EQ(Result::ERROR_BAD_DER, input.Read(readWord1));
ASSERT_NE(0x1122, readWord1);
}
TEST_F(pkixder_input_tests, ReadWordWrapAroundPointer)
{
// The original implementation of our buffer read overflow checks was
// susceptible to integer overflows which could make the checks ineffective.
// This attempts to verify that we've fixed that. Unfortunately, decrementing
// a null pointer is undefined behavior according to the C++ language spec.,
// but this should catch the problem on at least some compilers, if not all of
// them.
const uint8_t* der = nullptr;
--der;
Input input;
ASSERT_EQ(Success, input.Init(der, 0));
uint16_t b;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, input.Read(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));
@@ -336,17 +317,17 @@ TEST_F(pkixder_input_tests, InputSkipToE
}
TEST_F(pkixder_input_tests, InputSkipPastEnd)
{
Input input;
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
ASSERT_EQ(Success, input.Init(der, sizeof der));
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, input.Skip(sizeof der + 1));
+ 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));
@@ -373,18 +354,17 @@ TEST_F(pkixder_input_tests, InputSkipToN
TEST_F(pkixder_input_tests, InputSkipToNewInputPastEnd)
{
Input input;
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
ASSERT_EQ(Success, input.Init(der, sizeof der));
Input skippedInput;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- input.Skip(sizeof der * 2, skippedInput));
+ ASSERT_EQ(Result::ERROR_BAD_DER, input.Skip(sizeof der * 2, skippedInput));
}
TEST_F(pkixder_input_tests, InputSkipToSECItem)
{
Input input;
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
ASSERT_EQ(Success, input.Init(der, sizeof der));
@@ -405,28 +385,27 @@ TEST_F(pkixder_input_tests, SkipWrapArou
// This attempts to verify that we've fixed that. Unfortunately, decrementing
// a null pointer is undefined behavior according to the C++ language spec.,
// but this should catch the problem on at least some compilers, if not all of
// them.
const uint8_t* der = nullptr;
--der;
Input input;
ASSERT_EQ(Success, input.Init(der, 0));
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, input.Skip(1));
+ ASSERT_EQ(Result::ERROR_BAD_DER, input.Skip(1));
}
TEST_F(pkixder_input_tests, SkipToSECItemPastEnd)
{
Input input;
const uint8_t der[] = { 0x11, 0x22, 0x33, 0x44 };
ASSERT_EQ(Success, input.Init(der, sizeof der));
SECItem skippedSECItem;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- input.Skip(sizeof der + 1, skippedSECItem));
+ ASSERT_EQ(Result::ERROR_BAD_DER, input.Skip(sizeof der + 1, skippedSECItem));
}
TEST_F(pkixder_input_tests, ExpectTagAndSkipValue)
{
Input input;
ASSERT_EQ(Success,
input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
@@ -435,27 +414,26 @@ TEST_F(pkixder_input_tests, ExpectTagAnd
}
TEST_F(pkixder_input_tests, ExpectTagAndSkipValueWithTruncatedData)
{
Input input;
ASSERT_EQ(Success, input.Init(DER_TRUNCATED_SEQUENCE_OF_INT8,
sizeof DER_TRUNCATED_SEQUENCE_OF_INT8));
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- ExpectTagAndSkipValue(input, SEQUENCE));
+ 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));
ASSERT_EQ(Success, ExpectTagAndSkipValue(input, SEQUENCE));
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, End(input));
+ ASSERT_EQ(Result::ERROR_BAD_DER, End(input));
}
TEST_F(pkixder_input_tests, AtEndOnUnInitializedInput)
{
Input input;
ASSERT_TRUE(input.AtEnd());
}
@@ -507,18 +485,18 @@ TEST_F(pkixder_input_tests, MarkAndGetSE
ASSERT_EQ(Success, input.Init(der, sizeof der));
Input another;
Input::Mark mark = another.GetMark();
ASSERT_EQ(Success, input.Skip(3));
SECItem item;
- ASSERT_FatalError(SEC_ERROR_INVALID_ARGS,
- input.GetSECItem(siBuffer, mark, item));
+ ASSERT_EQ(Result::FATAL_ERROR_INVALID_ARGS,
+ input.GetSECItem(siBuffer, 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));
@@ -528,28 +506,26 @@ TEST_F(pkixder_input_tests, ExpectTagAnd
}
TEST_F(pkixder_input_tests, ExpectTagAndLengthWithWrongLength)
{
Input input;
ASSERT_EQ(Success, input.Init(DER_INT16, sizeof DER_INT16));
// Wrong length
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- ExpectTagAndLength(input, INTEGER, 4));
+ ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndLength(input, INTEGER, 4));
}
TEST_F(pkixder_input_tests, ExpectTagAndLengthWithWrongTag)
{
Input input;
ASSERT_EQ(Success, input.Init(DER_INT16, sizeof DER_INT16));
// Wrong type
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- ExpectTagAndLength(input, OCTET_STRING, 2));
+ ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndLength(input, OCTET_STRING, 2));
}
TEST_F(pkixder_input_tests, ExpectTagAndGetLength)
{
Input input;
ASSERT_EQ(Success,
input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
@@ -563,31 +539,29 @@ TEST_F(pkixder_input_tests, ExpectTagAnd
TEST_F(pkixder_input_tests, ExpectTagAndGetLengthWithWrongTag)
{
Input input;
ASSERT_EQ(Success,
input.Init(DER_SEQUENCE_OF_INT8, sizeof DER_SEQUENCE_OF_INT8));
uint16_t length = 0;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- der::internal::ExpectTagAndGetLength(input, INTEGER,
- length));
+ ASSERT_EQ(Result::ERROR_BAD_DER,
+ der::internal::ExpectTagAndGetLength(input, INTEGER, length));
}
TEST_F(pkixder_input_tests, ExpectTagAndGetLengthWithWrongLength)
{
Input input;
ASSERT_EQ(Success, input.Init(DER_TRUNCATED_SEQUENCE_OF_INT8,
sizeof DER_TRUNCATED_SEQUENCE_OF_INT8));
uint16_t length = 0;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- der::internal::ExpectTagAndGetLength(input, SEQUENCE,
- length));
+ ASSERT_EQ(Result::ERROR_BAD_DER,
+ der::internal::ExpectTagAndGetLength(input, SEQUENCE, length));
}
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_Input_ValidEmpty)
{
Input input;
ASSERT_EQ(Success,
input.Init(DER_SEQUENCE_EMPTY, sizeof DER_SEQUENCE_EMPTY));
Input value;
@@ -610,38 +584,38 @@ TEST_F(pkixder_input_tests, ExpectTagAnd
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));
Input value;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- ExpectTagAndGetValue(input, SEQUENCE, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER,
+ ExpectTagAndGetValue(input, SEQUENCE, value));
}
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));
Input value;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- ExpectTagAndGetValue(input, SEQUENCE, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER,
+ ExpectTagAndGetValue(input, SEQUENCE, value));
}
TEST_F(pkixder_input_tests, ExpectTagAndGetLength_Input_InvalidWrongTag)
{
Input input;
ASSERT_EQ(Success,
input.Init(DER_SEQUENCE_NOT_EMPTY, sizeof DER_SEQUENCE_NOT_EMPTY));
Input value;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- ExpectTagAndGetValue(input, INTEGER, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER,
+ ExpectTagAndGetValue(input, INTEGER, value));
}
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_SECItem_ValidEmpty)
{
Input input;
ASSERT_EQ(Success,
input.Init(DER_SEQUENCE_EMPTY, sizeof DER_SEQUENCE_EMPTY));
SECItem value = { siBuffer, nullptr, 5 };
@@ -667,38 +641,38 @@ TEST_F(pkixder_input_tests, ExpectTagAnd
TEST_F(pkixder_input_tests,
ExpectTagAndGetValue_SECItem_InvalidNotEmptyValueTruncated)
{
Input input;
ASSERT_EQ(Success,
input.Init(DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED,
sizeof DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED));
SECItem value;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- ExpectTagAndGetValue(input, SEQUENCE, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER,
+ ExpectTagAndGetValue(input, SEQUENCE, value));
}
TEST_F(pkixder_input_tests, ExpectTagAndGetValue_SECItem_InvalidWrongLength)
{
Input input;
ASSERT_EQ(Success, input.Init(DER_TRUNCATED_SEQUENCE_OF_INT8,
sizeof DER_TRUNCATED_SEQUENCE_OF_INT8));
SECItem value;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- ExpectTagAndGetValue(input, SEQUENCE, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER,
+ ExpectTagAndGetValue(input, SEQUENCE, value));
}
TEST_F(pkixder_input_tests, ExpectTagAndGetLength_SECItem_InvalidWrongTag)
{
Input input;
ASSERT_EQ(Success,
input.Init(DER_SEQUENCE_NOT_EMPTY, sizeof DER_SEQUENCE_NOT_EMPTY));
SECItem value;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- ExpectTagAndGetValue(input, INTEGER, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER,
+ ExpectTagAndGetValue(input, INTEGER, value));
}
TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_SECItem_ValidEmpty)
{
Input input;
ASSERT_EQ(Success,
input.Init(DER_SEQUENCE_EMPTY, sizeof DER_SEQUENCE_EMPTY));
SECItem tlv = { siBuffer, nullptr, 5 };
@@ -727,77 +701,74 @@ TEST_F(pkixder_input_tests, ExpectTagAnd
TEST_F(pkixder_input_tests,
ExpectTagAndGetTLV_SECItem_InvalidNotEmptyValueTruncated)
{
Input input;
ASSERT_EQ(Success,
input.Init(DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED,
sizeof DER_SEQUENCE_NOT_EMPTY_VALUE_TRUNCATED));
SECItem tlv;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- ExpectTagAndGetTLV(input, SEQUENCE, tlv));
+ ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndGetTLV(input, SEQUENCE, tlv));
}
TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_SECItem_InvalidWrongLength)
{
Input input;
ASSERT_EQ(Success, input.Init(DER_TRUNCATED_SEQUENCE_OF_INT8,
sizeof DER_TRUNCATED_SEQUENCE_OF_INT8));
SECItem tlv;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- ExpectTagAndGetTLV(input, SEQUENCE, tlv));
+ ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndGetTLV(input, SEQUENCE, tlv));
}
TEST_F(pkixder_input_tests, ExpectTagAndGetTLV_SECItem_InvalidWrongTag)
{
Input input;
ASSERT_EQ(Success,
input.Init(DER_SEQUENCE_NOT_EMPTY, sizeof DER_SEQUENCE_NOT_EMPTY));
SECItem tlv;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- ExpectTagAndGetTLV(input, INTEGER, tlv));
+ ASSERT_EQ(Result::ERROR_BAD_DER, ExpectTagAndGetTLV(input, INTEGER, tlv));
}
TEST_F(pkixder_input_tests, ExpectTagAndSkipLength)
{
Input input;
ASSERT_EQ(Success, input.Init(DER_INT16, sizeof DER_INT16));
ASSERT_EQ(Success, ExpectTagAndSkipLength(input, INTEGER));
}
TEST_F(pkixder_input_tests, ExpectTagAndSkipLengthWithWrongTag)
{
Input input;
ASSERT_EQ(Success, input.Init(DER_INT16, sizeof DER_INT16));
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- ExpectTagAndSkipLength(input, OCTET_STRING));
+ ASSERT_EQ(Result::ERROR_BAD_DER,
+ ExpectTagAndSkipLength(input, OCTET_STRING));
}
TEST_F(pkixder_input_tests, EndAtEnd)
{
Input input;
ASSERT_EQ(Success, input.Init(DER_INT16, sizeof DER_INT16));
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));
ASSERT_EQ(Success, input.Skip(2));
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, End(input));
+ 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));
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, End(input));
+ ASSERT_EQ(Result::ERROR_BAD_DER, End(input));
}
// TODO: Need tests for Nested too?
Result NestedOfHelper(Input& input, std::vector<uint8_t>& readValues)
{
uint8_t value = 0;
Result rv = input.Read(value);
@@ -829,21 +800,20 @@ 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));
std::vector<uint8_t> readValues;
- ASSERT_RecoverableError(
- SEC_ERROR_BAD_DER,
- NestedOf(input, SEQUENCE, INTEGER, EmptyAllowed::No,
- mozilla::pkix::bind(NestedOfHelper, mozilla::pkix::_1,
- mozilla::pkix::ref(readValues))));
+ ASSERT_EQ(Result::ERROR_BAD_DER,
+ NestedOf(input, SEQUENCE, INTEGER, EmptyAllowed::No,
+ mozilla::pkix::bind(NestedOfHelper, mozilla::pkix::_1,
+ mozilla::pkix::ref(readValues))));
ASSERT_EQ((size_t) 0, readValues.size());
}
TEST_F(pkixder_input_tests, MatchRestAtEnd)
{
Input input;
static const uint8_t der[1] = { };
ASSERT_EQ(Success, input.Init(der, 0));
--- a/security/pkix/test/gtest/pkixder_pki_types_tests.cpp
+++ b/security/pkix/test/gtest/pkixder_pki_types_tests.cpp
@@ -23,32 +23,24 @@
*/
#include <functional>
#include <vector>
#include "nssgtest.h"
#include "pkix/pkixtypes.h"
#include "pkixder.h"
-#include "pkixgtest.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::der;
using namespace mozilla::pkix::test;
namespace {
-class pkixder_pki_types_tests : public ::testing::Test
-{
-protected:
- virtual void SetUp()
- {
- PR_SetError(0, 0);
- }
-};
+class pkixder_pki_types_tests : public ::testing::Test { };
TEST_F(pkixder_pki_types_tests, CertificateSerialNumber)
{
const uint8_t DER_CERT_SERIAL[] = {
0x02, // INTEGER
8, // length
0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef
};
@@ -108,36 +100,34 @@ TEST_F(pkixder_pki_types_tests, Certific
0x00 // length
};
Input input;
ASSERT_EQ(Success, input.Init(DER_CERT_SERIAL_ZERO_LENGTH,
sizeof DER_CERT_SERIAL_ZERO_LENGTH));
SECItem item;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- CertificateSerialNumber(input, item));
+ ASSERT_EQ(Result::ERROR_BAD_DER, CertificateSerialNumber(input, item));
}
TEST_F(pkixder_pki_types_tests, OptionalVersionV1ExplicitEncodingAllowed)
{
const uint8_t DER_OPTIONAL_VERSION_V1[] = {
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));
// XXX(bug 1031093): We shouldn't accept an explicit encoding of v1, but we
// do here for compatibility reasons.
// Version version;
- // ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- // OptionalVersion(input, version));
+ // ASSERT_EQ(Result::ERROR_BAD_DER, OptionalVersion(input, version));
der::Version version = der::Version::v3;
ASSERT_EQ(Success, OptionalVersion(input, version));
ASSERT_EQ(der::Version::v1, version);
}
TEST_F(pkixder_pki_types_tests, OptionalVersionV2)
{
const uint8_t DER_OPTIONAL_VERSION_V2[] = {
@@ -177,32 +167,32 @@ TEST_F(pkixder_pki_types_tests, Optional
0x02, 0x01, 0x42 // INTEGER(0x42)
};
Input input;
ASSERT_EQ(Success, input.Init(DER_OPTIONAL_VERSION_INVALID,
sizeof DER_OPTIONAL_VERSION_INVALID));
der::Version version = der::Version::v1;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, OptionalVersion(input, version));
+ ASSERT_EQ(Result::ERROR_BAD_DER, OptionalVersion(input, version));
}
TEST_F(pkixder_pki_types_tests, OptionalVersionInvalidTooLong)
{
const uint8_t DER_OPTIONAL_VERSION_INVALID_TOO_LONG[] = {
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));
der::Version version;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, OptionalVersion(input, version));
+ ASSERT_EQ(Result::ERROR_BAD_DER, OptionalVersion(input, version));
}
TEST_F(pkixder_pki_types_tests, OptionalVersionMissing)
{
const uint8_t DER_OPTIONAL_VERSION_MISSING[] = {
0x02, 0x11, 0x22 // INTEGER
};
@@ -296,34 +286,34 @@ TEST_F(pkixder_DigestAlgorithmIdentifier
static const uint8_t DER[] = {
0x30, 0x0a, 0x06, 0x08,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05
};
Input input;
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
DigestAlgorithm alg;
- ASSERT_RecoverableError(SEC_ERROR_INVALID_ALGORITHM,
- DigestAlgorithmIdentifier(input, alg));
+ ASSERT_EQ(Result::ERROR_INVALID_ALGORITHM,
+ DigestAlgorithmIdentifier(input, alg));
}
TEST_F(pkixder_DigestAlgorithmIdentifier, Invalid_Digest_ECDSA_WITH_SHA256)
{
// The OID identifies ecdsa-with-SHA256 (1.2.840.10045.4.3.2). It is invalid
// because ECDSA-with-SHA256 is not a hash algorithm.
static const uint8_t DER[] = {
0x30, 0x0a, 0x06, 0x08,
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, //
};
Input input;
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
DigestAlgorithm alg;
- ASSERT_RecoverableError(SEC_ERROR_INVALID_ALGORITHM,
- DigestAlgorithmIdentifier(input, alg));
+ ASSERT_EQ(Result::ERROR_INVALID_ALGORITHM,
+ DigestAlgorithmIdentifier(input, alg));
}
static const AlgorithmIdentifierTestInfo<SignatureAlgorithm>
SIGNATURE_ALGORITHM_TEST_INFO[] =
{
{ SignatureAlgorithm::ecdsa_with_sha512,
{ 0x30, 0x0a, 0x06, 0x08,
0x2a, 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x04 },
@@ -434,29 +424,29 @@ TEST_F(pkixder_SignatureAlgorithmIdentif
static const uint8_t DER[] = {
0x30, 0x0b, 0x06, 0x09,
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04
};
Input input;
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
SignatureAlgorithm alg;
- ASSERT_RecoverableError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED,
- SignatureAlgorithmIdentifier(input, alg));
+ ASSERT_EQ(Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED,
+ SignatureAlgorithmIdentifier(input, alg));
}
TEST_F(pkixder_SignatureAlgorithmIdentifier, Invalid_SignatureAlgorithm_SHA256)
{
// The OID identifies id-sha256 (2.16.840.1.101.3.4.2.1). It is invalid
// because SHA-256 is not a signature algorithm.
static const uint8_t DER[] = {
0x30, 0x0b, 0x06, 0x09,
0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
};
Input input;
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
SignatureAlgorithm alg;
- ASSERT_RecoverableError(SEC_ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED,
- SignatureAlgorithmIdentifier(input, alg));
+ ASSERT_EQ(Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED,
+ SignatureAlgorithmIdentifier(input, alg));
}
} // unnamed namespace
--- a/security/pkix/test/gtest/pkixder_universal_types_tests.cpp
+++ b/security/pkix/test/gtest/pkixder_universal_types_tests.cpp
@@ -23,66 +23,58 @@
*/
#include <limits>
#include <vector>
#include <gtest/gtest.h>
#include "pkix/bind.h"
#include "pkixder.h"
-#include "pkixgtest.h"
#include "pkixtestutil.h"
#include "stdint.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::der;
using namespace mozilla::pkix::test;
using namespace std;
namespace {
-class pkixder_universal_types_tests : public ::testing::Test
-{
-protected:
- virtual void SetUp()
- {
- PR_SetError(0, 0);
- }
-};
+class pkixder_universal_types_tests : public ::testing::Test { };
TEST_F(pkixder_universal_types_tests, BooleanTrue01)
{
const uint8_t DER_BOOLEAN_TRUE_01[] = {
0x01, // BOOLEAN
0x01, // length
0x01 // invalid
};
Input input;
ASSERT_EQ(Success,
input.Init(DER_BOOLEAN_TRUE_01, sizeof DER_BOOLEAN_TRUE_01));
bool value = false;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, Boolean(input, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER, Boolean(input, value));
}
TEST_F(pkixder_universal_types_tests, BooleanTrue42)
{
const uint8_t DER_BOOLEAN_TRUE_42[] = {
0x01, // BOOLEAN
0x01, // length
0x42 // invalid
};
Input input;
ASSERT_EQ(Success,
input.Init(DER_BOOLEAN_TRUE_42, sizeof DER_BOOLEAN_TRUE_42));
bool value = false;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, Boolean(input, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER, Boolean(input, value));
}
static const uint8_t DER_BOOLEAN_TRUE[] = {
0x01, // BOOLEAN
0x01, // length
0xff // true
};
@@ -121,32 +113,32 @@ TEST_F(pkixder_universal_types_tests, Bo
0x42, 0x42 // invalid
};
Input input;
ASSERT_EQ(Success, input.Init(DER_BOOLEAN_INVALID_LENGTH,
sizeof DER_BOOLEAN_INVALID_LENGTH));
bool value = true;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, Boolean(input, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER, Boolean(input, value));
}
TEST_F(pkixder_universal_types_tests, BooleanInvalidZeroLength)
{
const uint8_t DER_BOOLEAN_INVALID_ZERO_LENGTH[] = {
0x01, // BOOLEAN
0x00 // length
};
Input input;
ASSERT_EQ(Success, input.Init(DER_BOOLEAN_INVALID_ZERO_LENGTH,
sizeof DER_BOOLEAN_INVALID_ZERO_LENGTH));
bool value = true;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, Boolean(input, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER, Boolean(input, value));
}
// OptionalBoolean implements decoding of OPTIONAL BOOLEAN DEFAULT FALSE.
// If the field is present, it must be a valid encoding of a BOOLEAN with
// value TRUE. If the field is not present, it defaults to FALSE. For
// compatibility reasons, OptionalBoolean can be told to accept an encoding
// where the field is present with value FALSE (this is technically not a
// valid DER encoding).
@@ -201,19 +193,18 @@ TEST_F(pkixder_universal_types_tests, Op
Input input1;
ASSERT_EQ(Success, input1.Init(DER_OPTIONAL_BOOLEAN_PRESENT_FALSE,
sizeof DER_OPTIONAL_BOOLEAN_PRESENT_FALSE));
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.
bool allowInvalidEncodings = false;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- OptionalBoolean(input1, allowInvalidEncodings,
- value)) <<
+ ASSERT_EQ(Result::ERROR_BAD_DER,
+ 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));
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.
@@ -229,19 +220,18 @@ TEST_F(pkixder_universal_types_tests, Op
0x42 // (invalid value for a BOOLEAN)
};
Input input3;
ASSERT_EQ(Success, input3.Init(DER_OPTIONAL_BOOLEAN_PRESENT_42,
sizeof DER_OPTIONAL_BOOLEAN_PRESENT_42));
// Even with the second parameter to OptionalBoolean as true, encodings
// of BOOLEAN that are invalid altogether are rejected.
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER,
- OptionalBoolean(input3, allowInvalidEncodings,
- value)) <<
+ ASSERT_EQ(Result::ERROR_BAD_DER,
+ OptionalBoolean(input3, allowInvalidEncodings, value)) <<
"Should reject another invalid encoding of present OPTIONAL BOOLEAN";
}
TEST_F(pkixder_universal_types_tests, Enumerated)
{
const uint8_t DER_ENUMERATED[] = {
0x0a, // ENUMERATED
0x01, // length
@@ -262,17 +252,17 @@ TEST_F(pkixder_universal_types_tests, En
0x0a, // ENUMERATED
0x02, // length
0x00, 0x01 // value
};
Input input;
ASSERT_EQ(Success, input.Init(DER_ENUMERATED, sizeof DER_ENUMERATED));
uint8_t value = 0;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, Enumerated(input, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER, Enumerated(input, value));
}
TEST_F(pkixder_universal_types_tests, EnumeratedOutOfAcceptedRange)
{
// Although this is a valid ENUMERATED value according to ASN.1, we
// intentionally don't support these large values because there are no
// ENUMERATED values in X.509 certs or OCSP this large, and we're trying to
// keep the parser simple and fast.
@@ -282,32 +272,32 @@ TEST_F(pkixder_universal_types_tests, En
0x12, 0x34 // value
};
Input input;
ASSERT_EQ(Success, input.Init(DER_ENUMERATED_INVALID_LENGTH,
sizeof DER_ENUMERATED_INVALID_LENGTH));
uint8_t value = 0;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, Enumerated(input, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER, Enumerated(input, value));
}
TEST_F(pkixder_universal_types_tests, EnumeratedInvalidZeroLength)
{
const uint8_t DER_ENUMERATED_INVALID_ZERO_LENGTH[] = {
0x0a, // ENUMERATED
0x00 // length
};
Input input;
ASSERT_EQ(Success, input.Init(DER_ENUMERATED_INVALID_ZERO_LENGTH,
sizeof DER_ENUMERATED_INVALID_ZERO_LENGTH));
uint8_t value = 0;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, Enumerated(input, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER, Enumerated(input, value));
}
////////////////////////////////////////
// GeneralizedTime and TimeChoice
//
// From RFC 5280 section 4.1.2.5.2
//
// For the purposes of this profile, GeneralizedTime values MUST be
@@ -391,34 +381,32 @@ template <uint16_t LENGTH>
void
ExpectBadTime(const uint8_t (&generalizedTimeDER)[LENGTH])
{
// GeneralizedTime
{
Input input;
ASSERT_EQ(Success, input.Init(generalizedTimeDER, LENGTH));
PRTime value;
- ASSERT_RecoverableError(SEC_ERROR_INVALID_TIME,
- GeneralizedTime(input, value));
+ ASSERT_EQ(Result::ERROR_INVALID_TIME, GeneralizedTime(input, value));
}
// TimeChoice: GeneralizedTime
{
Input input;
ASSERT_EQ(Success, input.Init(generalizedTimeDER, LENGTH));
PRTime value;
- ASSERT_RecoverableError(SEC_ERROR_INVALID_TIME, TimeChoice(input, value));
+ ASSERT_EQ(Result::ERROR_INVALID_TIME, TimeChoice(input, value));
}
// TimeChoice: UTCTime
{
PRTime value;
- ASSERT_RecoverableError(
- SEC_ERROR_INVALID_TIME,
- TimeChoiceForEquivalentUTCTime(generalizedTimeDER, value));
+ ASSERT_EQ(Result::ERROR_INVALID_TIME,
+ TimeChoiceForEquivalentUTCTime(generalizedTimeDER, value));
}
}
// Control value: a valid time
TEST_F(pkixder_universal_types_tests, ValidControl)
{
const uint8_t GT_DER[] = {
0x18, // Generalized Time
@@ -448,34 +436,34 @@ TEST_F(pkixder_universal_types_tests, Ti
PRTime value;
// GeneralizedTime
Input gt;
ASSERT_EQ(Success,
gt.Init(DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH,
sizeof DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH));
- ASSERT_RecoverableError(SEC_ERROR_INVALID_TIME, GeneralizedTime(gt, value));
+ 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));
- ASSERT_RecoverableError(SEC_ERROR_INVALID_TIME, TimeChoice(tc_gt, value));
+ ASSERT_EQ(Result::ERROR_INVALID_TIME, TimeChoice(tc_gt, value));
// TimeChoice: UTCTime
const uint8_t DER_UTCTIME_INVALID_ZERO_LENGTH[] = {
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));
- ASSERT_RecoverableError(SEC_ERROR_INVALID_TIME, TimeChoice(tc_utc, value));
+ ASSERT_EQ(Result::ERROR_INVALID_TIME, TimeChoice(tc_utc, value));
}
// A non zulu time should fail
TEST_F(pkixder_universal_types_tests, TimeInvalidLocal)
{
const uint8_t DER_GENERALIZED_TIME_INVALID_LOCAL[] = {
0x18, // Generalized Time
14, // Length = 14
@@ -745,26 +733,25 @@ TEST_F(pkixder_universal_types_tests, Ti
// We don't use ExpectBadTime here because UTCTime can't represent 2100.
// GeneralizedTime
{
Input input;
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
PRTime value;
- ASSERT_RecoverableError(SEC_ERROR_INVALID_TIME,
- GeneralizedTime(input, value));
+ ASSERT_EQ(Result::ERROR_INVALID_TIME, GeneralizedTime(input, value));
}
// TimeChoice: GeneralizedTime
{
Input input;
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
PRTime value;
- ASSERT_RecoverableError(SEC_ERROR_INVALID_TIME, TimeChoice(input, value));
+ ASSERT_EQ(Result::ERROR_INVALID_TIME, TimeChoice(input, value));
}
}
TEST_F(pkixder_universal_types_tests, TimeHoursValidRange)
{
for (uint8_t i = 0; i <= 23; ++i) {
const uint8_t DER[] = {
0x18, // Generalized Time
@@ -886,28 +873,27 @@ TEST_F(pkixder_universal_types_tests, Ti
// GeneralizedTime
{
Input input;
ASSERT_EQ(Success,
input.Init(DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR,
sizeof DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR));
PRTime value = 0;
- ASSERT_RecoverableError(SEC_ERROR_INVALID_TIME,
- GeneralizedTime(input, value));
+ 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));
PRTime value = 0;
- ASSERT_RecoverableError(SEC_ERROR_INVALID_TIME, TimeChoice(input, value));
+ ASSERT_EQ(Result::ERROR_INVALID_TIME, TimeChoice(input, value));
}
// This test is not applicable to TimeChoice: UTCTime
}
TEST_F(pkixder_universal_types_tests, TimeInvalidYearChar)
{
const uint8_t DER_GENERALIZED_TIME_INVALID_YEAR_CHAR[] = {
@@ -980,17 +966,17 @@ TEST_F(pkixder_universal_types_tests, In
0x01, // length
0xff, // -1 (two's complement)
};
Input input;
ASSERT_EQ(Success, input.Init(DER, sizeof DER));
uint8_t value;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, Integer(input, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER, Integer(input, value));
}
TEST_F(pkixder_universal_types_tests, Integer_Negative128)
{
// This is a valid integer value but our integer parser cannot parse
// negative values.
static const uint8_t DER[] = {
@@ -998,17 +984,17 @@ TEST_F(pkixder_universal_types_tests, In
0x01, // length
0x80, // -128 (two's complement)
};
Input input;
ASSERT_EQ(Success, input.Init(DER, sizeof DER));
uint8_t value;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, Integer(input, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER, Integer(input, value));
}
TEST_F(pkixder_universal_types_tests, Integer_128)
{
// This is a valid integer value but our integer parser cannot parse
// values that require more than one byte to encode.
static const uint8_t DER[] = {
@@ -1016,17 +1002,17 @@ TEST_F(pkixder_universal_types_tests, In
0x02, // length
0x00, 0x80 // 128
};
Input input;
ASSERT_EQ(Success, input.Init(DER, sizeof DER));
uint8_t value;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, Integer(input, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER, Integer(input, value));
}
TEST_F(pkixder_universal_types_tests, Integer11223344)
{
// This is a valid integer value but our integer parser cannot parse
// values that require more than one byte to be encoded.
static const uint8_t DER[] = {
@@ -1034,94 +1020,94 @@ TEST_F(pkixder_universal_types_tests, In
0x04, // length
0x11, 0x22, 0x33, 0x44 // 0x11223344
};
Input input;
ASSERT_EQ(Success, input.Init(DER, sizeof DER));
uint8_t value;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, Integer(input, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER, Integer(input, value));
}
TEST_F(pkixder_universal_types_tests, IntegerTruncatedOneByte)
{
const uint8_t DER_INTEGER_TRUNCATED[] = {
0x02, // INTEGER
0x01, // length
// MISSING DATA HERE
};
Input input;
ASSERT_EQ(Success,
input.Init(DER_INTEGER_TRUNCATED, sizeof DER_INTEGER_TRUNCATED));
uint8_t value;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, Integer(input, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER, Integer(input, value));
}
TEST_F(pkixder_universal_types_tests, IntegerTruncatedLarge)
{
const uint8_t DER_INTEGER_TRUNCATED[] = {
0x02, // INTEGER
0x04, // length
0x11, 0x22 // 0x1122
// MISSING DATA HERE
};
Input input;
ASSERT_EQ(Success,
input.Init(DER_INTEGER_TRUNCATED, sizeof DER_INTEGER_TRUNCATED));
uint8_t value;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, Integer(input, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER, Integer(input, value));
}
TEST_F(pkixder_universal_types_tests, IntegerZeroLength)
{
const uint8_t DER_INTEGER_ZERO_LENGTH[] = {
0x02, // INTEGER
0x00 // length
};
Input input;
ASSERT_EQ(Success, input.Init(DER_INTEGER_ZERO_LENGTH,
sizeof DER_INTEGER_ZERO_LENGTH));
uint8_t value;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, Integer(input, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER, Integer(input, value));
}
TEST_F(pkixder_universal_types_tests, IntegerOverlyLong1)
{
const uint8_t DER_INTEGER_OVERLY_LONG1[] = {
0x02, // INTEGER
0x02, // length
0x00, 0x01 //
};
Input input;
ASSERT_EQ(Success, input.Init(DER_INTEGER_OVERLY_LONG1,
sizeof DER_INTEGER_OVERLY_LONG1));
uint8_t value;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, Integer(input, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER, Integer(input, value));
}
TEST_F(pkixder_universal_types_tests, IntegerOverlyLong2)
{
const uint8_t DER_INTEGER_OVERLY_LONG2[] = {
0x02, // INTEGER
0x02, // length
0xff, 0x80 //
};
Input input;
ASSERT_EQ(Success, input.Init(DER_INTEGER_OVERLY_LONG2,
sizeof DER_INTEGER_OVERLY_LONG2));
uint8_t value;
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, Integer(input, value));
+ ASSERT_EQ(Result::ERROR_BAD_DER, Integer(input, value));
}
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));
@@ -1134,17 +1120,17 @@ TEST_F(pkixder_universal_types_tests, Op
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));
long value;
- ASSERT_FatalError(SEC_ERROR_INVALID_ARGS, OptionalInteger(input, 0, value));
+ ASSERT_EQ(Result::FATAL_ERROR_INVALID_ARGS, OptionalInteger(input, 0, value));
}
TEST_F(pkixder_universal_types_tests, OptionalIntegerSupportedDefaultAtEnd)
{
static const uint8_t dummy = 1;
Input input;
ASSERT_EQ(Success, input.Init(&dummy, 0));
@@ -1188,17 +1174,17 @@ TEST_F(pkixder_universal_types_tests, Nu
0x01,
0x00
};
Input input;
ASSERT_EQ(Success,
input.Init(DER_NULL_BAD_LENGTH, sizeof DER_NULL_BAD_LENGTH));
- ASSERT_RecoverableError(SEC_ERROR_BAD_DER, Null(input));
+ ASSERT_EQ(Result::ERROR_BAD_DER, Null(input));
}
TEST_F(pkixder_universal_types_tests, OID)
{
const uint8_t DER_VALID_OID[] = {
0x06,
0x09,
0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
deleted file mode 100644
--- a/security/pkix/test/gtest/pkixgtest.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
-/* vim: set ts=8 sts=2 et sw=2 tw=80: */
-/* This code is made available to you under your choice of the following sets
- * of licensing terms:
- */
-/* This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
-/* Copyright 2014 Mozilla Contributors
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include "pkixgtest.h"
-
-namespace mozilla { namespace pkix { namespace test {
-
-std::ostream&
-operator<<(std::ostream& os, const ResultWithPRErrorCode& value)
-{
- switch (value.mRv)
- {
- case Success:
- os << "Success";
- break;
- case RecoverableError:
- os << "RecoverableError";
- break;
- case SECFailure:
- os << "FatalError";
- break;
- default:
- os << "[Invalid Result: " << static_cast<int64_t>(value.mRv) << ']';
- break;
- }
-
- if (value.mRv != Success) {
- os << '(';
- const char* name = PR_ErrorToName(value.mErrorCode);
- if (name) {
- os << name;
- } else {
- os << value.mErrorCode;
- }
- os << ')';
- }
-
- return os;
-}
-
-} } } // namespace mozilla::pkix::test
--- a/security/pkix/test/gtest/pkixgtest.h
+++ b/security/pkix/test/gtest/pkixgtest.h
@@ -22,76 +22,27 @@
* limitations under the License.
*/
#ifndef mozilla_pkix__pkixgtest_h
#define mozilla_pkix__pkixgtest_h
#include <ostream>
#include "gtest/gtest.h"
-#include "pkixutil.h"
-#include "prerror.h"
-#include "stdint.h"
-
-namespace mozilla { namespace pkix { namespace test {
-
-class ResultWithPRErrorCode
-{
-public:
- ResultWithPRErrorCode(Result rv, PRErrorCode errorCode)
- : mRv(rv)
- , mErrorCode(errorCode)
- {
- }
+#include "pkix/pkixnss.h"
- explicit ResultWithPRErrorCode(Result rv)
- : mRv(rv)
- , mErrorCode(rv == Success ? 0 : PR_GetError())
- {
- }
-
- bool operator==(const ResultWithPRErrorCode& other) const
- {
- return mRv == other.mRv && mErrorCode == other.mErrorCode;
- }
-
-private:
- const Result mRv;
- const PRErrorCode mErrorCode;
-
- friend std::ostream& operator<<(std::ostream& os,
- const ResultWithPRErrorCode & value);
+// PrintTo must be in the same namespace as the type we're overloading it for.
+namespace mozilla { namespace pkix {
- void operator=(const ResultWithPRErrorCode&) /*= delete*/;
-};
-
-::std::ostream& operator<<(::std::ostream&, const ResultWithPRErrorCode &);
-
-#define ASSERT_Success(rv) \
- ASSERT_EQ(::mozilla::pkix::test::ResultWithPRErrorCode( \
- ::mozilla::pkix::Success, 0), \
- ::mozilla::pkix::test::ResultWithPRErrorCode(rv))
-#define EXPECT_Success(rv) \
- EXPECT_EQ(::mozilla::pkix::test::ResultWithPRErrorCode( \
- ::mozilla::pkix::Success, 0), \
- ::mozilla::pkix::test::ResultWithPRErrorCode(rv))
+inline void
+PrintTo(const Result& result, ::std::ostream* os)
+{
+ const char* stringified = MapResultToName(result);
+ if (stringified) {
+ *os << stringified;
+ } else {
+ *os << "mozilla::pkix::Result(" << static_cast<unsigned int>(result) << ")";
+ }
+}
-#define ASSERT_RecoverableError(expectedError, rv) \
- ASSERT_EQ(::mozilla::pkix::test::ResultWithPRErrorCode( \
- ::mozilla::pkix::RecoverableError, expectedError), \
- ::mozilla::pkix::test::ResultWithPRErrorCode(rv))
-#define EXPECT_RecoverableError(expectedError, rv) \
- EXPECT_EQ(::mozilla::pkix::test::ResultWithPRErrorCode( \
- ::mozilla::pkix::RecoverableError, expectedError), \
- ::mozilla::pkix::test::ResultWithPRErrorCode(rv))
-
-#define ASSERT_FatalError(expectedError, rv) \
- ASSERT_EQ(::mozilla::pkix::test::ResultWithPRErrorCode( \
- ::mozilla::pkix::FatalError, expectedError), \
- ::mozilla::pkix::test::ResultWithPRErrorCode(rv))
-#define EXPECT_FatalError(expectedError, rv) \
- EXPECT_EQ(::mozilla::pkix::test::ResultWithPRErrorCode( \
- ::mozilla::pkix::FatalError, expectedError), \
- ::mozilla::pkix::test::ResultWithPRErrorCode(rv))
-
-} } } // namespace mozilla::pkix::test
+} } // namespace mozilla::pkix
#endif // mozilla_pkix__pkixgtest_h
--- a/security/pkix/test/gtest/pkixocsp_CreateEncodedOCSPRequest_tests.cpp
+++ b/security/pkix/test/gtest/pkixocsp_CreateEncodedOCSPRequest_tests.cpp
@@ -19,71 +19,67 @@
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nssgtest.h"
#include "pkix/pkix.h"
+#include "pkix/pkixnss.h"
#include "pkixder.h"
-#include "prerror.h"
+#include "pkixtestutil.h"
#include "secerr.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
class CreateEncodedOCSPRequestTrustDomain : public TrustDomain
{
private:
- virtual SECStatus GetCertTrust(EndEntityOrCA, const CertPolicyId&,
- const SECItem&, /*out*/ TrustLevel*)
+ virtual Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
+ const SECItem&, /*out*/ TrustLevel*)
{
ADD_FAILURE();
- PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
- return SECFailure;
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
- virtual SECStatus FindIssuer(const SECItem&, IssuerChecker&, PRTime)
+ virtual Result FindIssuer(const SECItem&, IssuerChecker&, PRTime)
{
ADD_FAILURE();
- PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
- return SECFailure;
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
- virtual SECStatus CheckRevocation(EndEntityOrCA, const CertID&, PRTime,
- const SECItem*, const SECItem*)
+ virtual Result CheckRevocation(EndEntityOrCA, const CertID&, PRTime,
+ const SECItem*, const SECItem*)
{
ADD_FAILURE();
- PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
- return SECFailure;
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
- virtual SECStatus IsChainValid(const DERArray&)
+ virtual Result IsChainValid(const DERArray&)
{
ADD_FAILURE();
- PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
- return SECFailure;
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
- virtual SECStatus VerifySignedData(const SignedDataWithSignature&,
- const SECItem&)
+ virtual Result VerifySignedData(const SignedDataWithSignature&,
+ const SECItem&)
{
ADD_FAILURE();
- PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
- return SECFailure;
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
- virtual SECStatus DigestBuf(const SECItem& item, /*out*/ uint8_t *digestBuf,
- size_t digestBufLen)
+ virtual Result DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
+ size_t digestBufLen)
{
return ::mozilla::pkix::DigestBuf(item, digestBuf, digestBufLen);
}
- virtual SECStatus CheckPublicKey(const SECItem& subjectPublicKeyInfo)
+ virtual Result CheckPublicKey(const SECItem& subjectPublicKeyInfo)
{
return ::mozilla::pkix::CheckPublicKey(subjectPublicKeyInfo);
}
};
class pkixocsp_CreateEncodedOCSPRequest : public NSSTest
{
protected:
@@ -145,26 +141,33 @@ protected:
// Test that the large length of the child serial number causes
// CreateEncodedOCSPRequest to fail.
TEST_F(pkixocsp_CreateEncodedOCSPRequest, ChildCertLongSerialNumberTest)
{
const SECItem* issuerDER;
ScopedSECItem issuerSPKI;
ASSERT_EQ(SECSuccess,
MakeIssuerCertIDComponents("CN=CA", issuerDER, issuerSPKI));
- ASSERT_FALSE(CreateEncodedOCSPRequest(trustDomain, arena.get(),
- CertID(*issuerDER, *issuerSPKI,
- *unsupportedLongSerialNumber)));
- ASSERT_EQ(SEC_ERROR_BAD_DATA, PR_GetError());
+ uint8_t ocspRequest[OCSP_REQUEST_MAX_LENGTH];
+ size_t ocspRequestLength;
+ ASSERT_EQ(Result::ERROR_BAD_DER,
+ CreateEncodedOCSPRequest(trustDomain,
+ CertID(*issuerDER, *issuerSPKI,
+ *unsupportedLongSerialNumber),
+ ocspRequest, ocspRequestLength));
}
// Test that CreateEncodedOCSPRequest handles the longest serial number that
// it's required to support (i.e. 20 octets).
TEST_F(pkixocsp_CreateEncodedOCSPRequest, LongestSupportedSerialNumberTest)
{
const SECItem* issuerDER;
ScopedSECItem issuerSPKI;
ASSERT_EQ(SECSuccess,
MakeIssuerCertIDComponents("CN=CA", issuerDER, issuerSPKI));
- ASSERT_TRUE(CreateEncodedOCSPRequest(trustDomain, arena.get(),
- CertID(*issuerDER, *issuerSPKI,
- *longestRequiredSerialNumber)));
+ uint8_t ocspRequest[OCSP_REQUEST_MAX_LENGTH];
+ size_t ocspRequestLength;
+ ASSERT_EQ(Success,
+ CreateEncodedOCSPRequest(trustDomain,
+ CertID(*issuerDER, *issuerSPKI,
+ *longestRequiredSerialNumber),
+ ocspRequest, ocspRequestLength));
}
--- a/security/pkix/test/gtest/pkixocsp_VerifyEncodedOCSPResponse.cpp
+++ b/security/pkix/test/gtest/pkixocsp_VerifyEncodedOCSPResponse.cpp
@@ -20,84 +20,81 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "nss.h"
#include "nssgtest.h"
#include "pkix/pkix.h"
+#include "pkix/pkixnss.h"
+#include "pkixgtest.h"
#include "pkixtestutil.h"
#include "prinit.h"
#include "secerr.h"
using namespace mozilla::pkix;
using namespace mozilla::pkix::test;
const uint16_t END_ENTITY_MAX_LIFETIME_IN_DAYS = 10;
class OCSPTestTrustDomain : public TrustDomain
{
public:
OCSPTestTrustDomain()
{
}
- virtual SECStatus GetCertTrust(EndEntityOrCA endEntityOrCA,
- const CertPolicyId&,
- const SECItem& candidateCert,
- /*out*/ TrustLevel* trustLevel)
+ virtual Result GetCertTrust(EndEntityOrCA endEntityOrCA, const CertPolicyId&,
+ const SECItem& candidateCert,
+ /*out*/ TrustLevel* trustLevel)
{
EXPECT_EQ(endEntityOrCA, EndEntityOrCA::MustBeEndEntity);
EXPECT_TRUE(trustLevel);
*trustLevel = TrustLevel::InheritsTrust;
- return SECSuccess;
+ return Success;
}
- virtual SECStatus FindIssuer(const SECItem&, IssuerChecker&, PRTime)
+ virtual Result FindIssuer(const SECItem&, IssuerChecker&, PRTime)
{
ADD_FAILURE();
- PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
- return SECFailure;
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
- virtual SECStatus CheckRevocation(EndEntityOrCA endEntityOrCA, const CertID&,
- PRTime time,
- /*optional*/ const SECItem*,
- /*optional*/ const SECItem*)
+ virtual Result CheckRevocation(EndEntityOrCA endEntityOrCA, const CertID&,
+ PRTime time, /*optional*/ const SECItem*,
+ /*optional*/ const SECItem*)
{
// TODO: I guess mozilla::pkix should support revocation of designated
// OCSP responder eventually, but we don't now, so this function should
// never get called.
ADD_FAILURE();
- PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
- return SECFailure;
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
- virtual SECStatus IsChainValid(const DERArray&)
+ virtual Result IsChainValid(const DERArray&)
{
ADD_FAILURE();
- PR_SetError(SEC_ERROR_LIBRARY_FAILURE, 0);
- return SECFailure;
+ return Result::FATAL_ERROR_LIBRARY_FAILURE;
}
- virtual SECStatus VerifySignedData(const SignedDataWithSignature& signedData,
- const SECItem& subjectPublicKeyInfo)
+ virtual Result VerifySignedData(const SignedDataWithSignature& signedData,
+ const SECItem& subjectPublicKeyInfo)
{
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
nullptr);
}
- virtual SECStatus DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
- size_t digestBufLen)
+ virtual Result DigestBuf(const SECItem& item, /*out*/ uint8_t* digestBuf,
+ size_t digestBufLen)
{
return ::mozilla::pkix::DigestBuf(item, digestBuf, digestBufLen);
}
- virtual SECStatus CheckPublicKey(const SECItem& subjectPublicKeyInfo)
+ virtual Result CheckPublicKey(const SECItem& subjectPublicKeyInfo)
{
return ::mozilla::pkix::CheckPublicKey(subjectPublicKeyInfo);
}
private:
OCSPTestTrustDomain(const OCSPTestTrustDomain&) /*delete*/;
void operator=(const OCSPTestTrustDomain&) /*delete*/;
};
@@ -168,29 +165,29 @@ public:
/*static*/ long pkixocsp_VerifyEncodedResponse::rootIssuedCount = 0;
///////////////////////////////////////////////////////////////////////////////
// responseStatus
struct WithoutResponseBytes
{
uint8_t responseStatus;
- PRErrorCode expectedError;
+ Result expectedError;
};
static const WithoutResponseBytes WITHOUT_RESPONSEBYTES[] = {
- { OCSPResponseContext::successful, SEC_ERROR_OCSP_MALFORMED_RESPONSE },
- { OCSPResponseContext::malformedRequest, SEC_ERROR_OCSP_MALFORMED_REQUEST },
- { OCSPResponseContext::internalError, SEC_ERROR_OCSP_SERVER_ERROR },
- { OCSPResponseContext::tryLater, SEC_ERROR_OCSP_TRY_SERVER_LATER },
- { 4/*unused*/, SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS },
- { OCSPResponseContext::sigRequired, SEC_ERROR_OCSP_REQUEST_NEEDS_SIG },
- { OCSPResponseContext::unauthorized, SEC_ERROR_OCSP_UNAUTHORIZED_REQUEST },
+ { OCSPResponseContext::successful, Result::ERROR_OCSP_MALFORMED_RESPONSE },
+ { OCSPResponseContext::malformedRequest, Result::ERROR_OCSP_MALFORMED_REQUEST },
+ { OCSPResponseContext::internalError, Result::ERROR_OCSP_SERVER_ERROR },
+ { OCSPResponseContext::tryLater, Result::ERROR_OCSP_TRY_SERVER_LATER },
+ { 4/*unused*/, Result::ERROR_OCSP_UNKNOWN_RESPONSE_STATUS },
+ { OCSPResponseContext::sigRequired, Result::ERROR_OCSP_REQUEST_NEEDS_SIG },
+ { OCSPResponseContext::unauthorized, Result::ERROR_OCSP_UNAUTHORIZED_REQUEST },
{ OCSPResponseContext::unauthorized + 1,
- SEC_ERROR_OCSP_UNKNOWN_RESPONSE_STATUS
+ Result::ERROR_OCSP_UNKNOWN_RESPONSE_STATUS
},
};
class pkixocsp_VerifyEncodedResponse_WithoutResponseBytes
: public pkixocsp_VerifyEncodedResponse
, public ::testing::WithParamInterface<WithoutResponseBytes>
{
protected:
@@ -207,20 +204,20 @@ protected:
};
TEST_P(pkixocsp_VerifyEncodedResponse_WithoutResponseBytes, CorrectErrorCode)
{
SECItem* response(CreateEncodedOCSPErrorResponse(
GetParam().responseStatus));
ASSERT_TRUE(response);
bool expired;
- ASSERT_SECFailure(GetParam().expectedError,
- VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(GetParam().expectedError,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
}
INSTANTIATE_TEST_CASE_P(pkixocsp_VerifyEncodedResponse_WithoutResponseBytes,
pkixocsp_VerifyEncodedResponse_WithoutResponseBytes,
testing::ValuesIn(WITHOUT_RESPONSEBYTES));
///////////////////////////////////////////////////////////////////////////////
// "successful" responses
@@ -283,77 +280,80 @@ public:
TEST_F(pkixocsp_VerifyEncodedResponse_successful, good_byKey)
{
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::good, *endEntityCertID, byKey,
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
&oneDayAfterNow));
ASSERT_TRUE(response);
bool expired;
- ASSERT_SECSuccess(VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Success,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID,
+ now, END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
ASSERT_FALSE(expired);
}
TEST_F(pkixocsp_VerifyEncodedResponse_successful, good_byName)
{
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::good, *endEntityCertID, rootName,
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
&oneDayAfterNow));
ASSERT_TRUE(response);
bool expired;
- ASSERT_SECSuccess(VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Success,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
ASSERT_FALSE(expired);
}
TEST_F(pkixocsp_VerifyEncodedResponse_successful, good_byKey_without_nextUpdate)
{
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::good, *endEntityCertID, byKey,
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
nullptr));
ASSERT_TRUE(response);
bool expired;
- ASSERT_SECSuccess(VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Success,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
ASSERT_FALSE(expired);
}
TEST_F(pkixocsp_VerifyEncodedResponse_successful, revoked)
{
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::revoked, *endEntityCertID, byKey,
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
&oneDayAfterNow));
ASSERT_TRUE(response);
bool expired;
- ASSERT_SECFailure(SEC_ERROR_REVOKED_CERTIFICATE,
- VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Result::ERROR_REVOKED_CERTIFICATE,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
ASSERT_FALSE(expired);
}
TEST_F(pkixocsp_VerifyEncodedResponse_successful, unknown)
{
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::unknown, *endEntityCertID, byKey,
rootPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
&oneDayAfterNow));
ASSERT_TRUE(response);
bool expired;
- ASSERT_SECFailure(SEC_ERROR_OCSP_UNKNOWN_CERT,
- VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Result::ERROR_OCSP_UNKNOWN_CERT,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
ASSERT_FALSE(expired);
}
///////////////////////////////////////////////////////////////////////////////
// indirect responses (signed by a delegated OCSP responder cert)
class pkixocsp_VerifyEncodedResponse_DelegatedResponder
: public pkixocsp_VerifyEncodedResponse_successful
@@ -453,72 +453,74 @@ protected:
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_byKey)
{
SECItem* response(CreateEncodedIndirectOCSPSuccessfulResponse(
"CN=good_indirect_byKey", OCSPResponseContext::good,
byKey));
ASSERT_TRUE(response);
bool expired;
- ASSERT_SECSuccess(VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Success,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
ASSERT_FALSE(expired);
}
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_byName)
{
SECItem* response(CreateEncodedIndirectOCSPSuccessfulResponse(
"CN=good_indirect_byName", OCSPResponseContext::good,
"CN=good_indirect_byName"));
ASSERT_TRUE(response);
bool expired;
- ASSERT_SECSuccess(VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Success,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
ASSERT_FALSE(expired);
}
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
good_byKey_missing_signer)
{
ScopedSECKEYPublicKey missingSignerPublicKey;
ScopedSECKEYPrivateKey missingSignerPrivateKey;
ASSERT_SECSuccess(GenerateKeyPair(missingSignerPublicKey,
missingSignerPrivateKey));
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::good, *endEntityCertID, byKey,
missingSignerPrivateKey, oneDayBeforeNow,
oneDayBeforeNow, nullptr));
ASSERT_TRUE(response);
bool expired;
- ASSERT_SECFailure(SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
- VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
ASSERT_FALSE(expired);
}
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
good_byName_missing_signer)
{
ScopedSECKEYPublicKey missingSignerPublicKey;
ScopedSECKEYPrivateKey missingSignerPrivateKey;
ASSERT_SECSuccess(GenerateKeyPair(missingSignerPublicKey,
missingSignerPrivateKey));
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::good, *endEntityCertID, "CN=missing",
missingSignerPrivateKey, oneDayBeforeNow,
oneDayBeforeNow, nullptr));
ASSERT_TRUE(response);
bool expired;
- ASSERT_SECFailure(SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
- VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
ASSERT_FALSE(expired);
}
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_expired)
{
static const SECOidTag signerEKU = SEC_OID_OCSP_RESPONDER;
static const char* signerName = "CN=good_indirect_expired";
@@ -541,20 +543,20 @@ TEST_F(pkixocsp_VerifyEncodedResponse_De
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::good, *endEntityCertID, signerName,
signerPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
&oneDayAfterNow,
certs));
ASSERT_TRUE(response);
bool expired;
- ASSERT_SECFailure(SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
- VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
}
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_future)
{
static const SECOidTag signerEKU = SEC_OID_OCSP_RESPONDER;
static const char* signerName = "CN=good_indirect_future";
const SECItem* extensions[] = {
@@ -575,49 +577,49 @@ TEST_F(pkixocsp_VerifyEncodedResponse_De
SECItem const* const certs[] = { signerDER, nullptr };
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::good, *endEntityCertID,
signerName, signerPrivateKey, oneDayBeforeNow,
oneDayBeforeNow, &oneDayAfterNow, certs));
ASSERT_TRUE(response);
bool expired;
- ASSERT_SECFailure(SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
- VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *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);
bool expired;
- ASSERT_SECFailure(SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
- VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *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);
bool expired;
- ASSERT_SECFailure(SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
- VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
ASSERT_FALSE(expired);
}
// Test that signature of OCSP response signer cert is verified
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_tampered_eku)
{
SECItem* response(CreateEncodedIndirectOCSPSuccessfulResponse(
"CN=good_indirect_tampered_eku",
@@ -632,20 +634,20 @@ TEST_F(pkixocsp_VerifyEncodedResponse_De
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,
EKU_SERVER_AUTH, PR_ARRAY_SIZE(EKU_SERVER_AUTH),
EKU_OCSP_SIGNER, PR_ARRAY_SIZE(EKU_OCSP_SIGNER)));
bool expired;
- ASSERT_SECFailure(SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
- VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
ASSERT_FALSE(expired);
}
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_unknown_issuer)
{
static const char* subCAName = "CN=good_indirect_unknown_issuer sub-CA";
static const char* signerName = "CN=good_indirect_unknown_issuer OCSP signer";
@@ -672,20 +674,20 @@ TEST_F(pkixocsp_VerifyEncodedResponse_De
SECItem const* const certs[] = { signerDER, nullptr };
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::good, *endEntityCertID,
signerName, signerPrivateKey, oneDayBeforeNow,
oneDayBeforeNow, &oneDayAfterNow, certs));
ASSERT_TRUE(response);
bool expired;
- ASSERT_SECFailure(SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
- VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
ASSERT_FALSE(expired);
}
// The CA that issued the OCSP responder cert is a sub-CA of the issuer of
// the certificate that the OCSP response is for. That sub-CA cert is included
// in the OCSP response before the OCSP responder cert.
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
good_indirect_subca_1_first)
@@ -729,20 +731,20 @@ TEST_F(pkixocsp_VerifyEncodedResponse_De
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::good, *endEntityCertID, signerName,
signerPrivateKey, oneDayBeforeNow, oneDayBeforeNow,
&oneDayAfterNow,
certs));
ASSERT_TRUE(response);
bool expired;
- ASSERT_SECFailure(SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
- VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
ASSERT_FALSE(expired);
}
// The CA that issued the OCSP responder cert is a sub-CA of the issuer of
// the certificate that the OCSP response is for. That sub-CA cert is included
// in the OCSP response after the OCSP responder cert.
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
good_indirect_subca_1_second)
@@ -785,20 +787,20 @@ TEST_F(pkixocsp_VerifyEncodedResponse_De
SECItem const* const certs[] = { signerDER, subCADER, nullptr };
SECItem* response(CreateEncodedOCSPSuccessfulResponse(
OCSPResponseContext::good, *endEntityCertID,
signerName, signerPrivateKey, oneDayBeforeNow,
oneDayBeforeNow, &oneDayAfterNow, certs));
ASSERT_TRUE(response);
bool expired;
- ASSERT_SECFailure(SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
- VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
ASSERT_FALSE(expired);
}
class pkixocsp_VerifyEncodedResponse_GetCertTrust
: public pkixocsp_VerifyEncodedResponse_DelegatedResponder {
public:
pkixocsp_VerifyEncodedResponse_GetCertTrust()
: signerCertDER(nullptr)
@@ -828,63 +830,65 @@ public:
bool SetCertTrust(const SECItem* certDER, TrustLevel certTrustLevel)
{
this->certDER = certDER;
this->certTrustLevel = certTrustLevel;
return true;
}
private:
- virtual SECStatus GetCertTrust(EndEntityOrCA endEntityOrCA,
- const CertPolicyId&,
- const SECItem& candidateCert,
- /*out*/ TrustLevel* trustLevel)
+ virtual Result GetCertTrust(EndEntityOrCA endEntityOrCA,
+ const CertPolicyId&,
+ const SECItem& candidateCert,
+ /*out*/ TrustLevel* trustLevel)
{
EXPECT_EQ(endEntityOrCA, EndEntityOrCA::MustBeEndEntity);
EXPECT_TRUE(trustLevel);
EXPECT_TRUE(certDER);
EXPECT_TRUE(SECITEM_ItemsAreEqual(certDER, &candidateCert));
*trustLevel = certTrustLevel;
- return SECSuccess;
+ return Success;
}
const SECItem* certDER; // weak pointer
TrustLevel certTrustLevel;
};
TrustDomain trustDomain;
const SECItem* signerCertDER; // owned by arena
SECItem* response; // owned by arena
};
TEST_F(pkixocsp_VerifyEncodedResponse_GetCertTrust, InheritTrust)
{
ASSERT_TRUE(trustDomain.SetCertTrust(signerCertDER,
TrustLevel::InheritsTrust));
bool expired;
- ASSERT_SECSuccess(VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Success,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
ASSERT_FALSE(expired);
}
TEST_F(pkixocsp_VerifyEncodedResponse_GetCertTrust, TrustAnchor)
{
ASSERT_TRUE(trustDomain.SetCertTrust(signerCertDER,
TrustLevel::TrustAnchor));
bool expired;
- ASSERT_SECSuccess(VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Success,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
ASSERT_FALSE(expired);
}
TEST_F(pkixocsp_VerifyEncodedResponse_GetCertTrust, ActivelyDistrusted)
{
ASSERT_TRUE(trustDomain.SetCertTrust(signerCertDER,
TrustLevel::ActivelyDistrusted));
bool expired;
- ASSERT_SECFailure(SEC_ERROR_OCSP_INVALID_SIGNING_CERT,
- VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
- END_ENTITY_MAX_LIFETIME_IN_DAYS,
- *response, expired));
+ ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
+ VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, now,
+ END_ENTITY_MAX_LIFETIME_IN_DAYS,
+ *response, expired));
ASSERT_FALSE(expired);
}
--- a/security/pkix/test/lib/pkixtestutil.cpp
+++ b/security/pkix/test/lib/pkixtestutil.cpp
@@ -28,19 +28,21 @@
#include <limits>
#include <new>
#include "cryptohi.h"
#include "hasht.h"
#include "pk11pub.h"
#include "pkixcheck.h"
#include "pkixder.h"
+#include "prerror.h"
#include "prinit.h"
#include "prprf.h"
#include "secder.h"
+#include "secerr.h"
using namespace std;
namespace mozilla { namespace pkix { namespace test {
const PRTime ONE_DAY = PRTime(24) * PRTime(60) * PRTime(60) * PR_USEC_PER_SEC;
namespace {
@@ -159,20 +161,20 @@ public:
// Makes a shallow copy of the input item. All input items must have a
// lifetime that extends at least to where Squash is called.
Result Add(const SECItem* item)
{
PR_ASSERT(item);
PR_ASSERT(item->data);
if (numItems >= MaxSequenceItems) {
- return Fail(SEC_ERROR_INVALID_ARGS);
+ return Result::FATAL_ERROR_INVALID_ARGS;
}
if (length + item->len > 65535) {
- return Fail(SEC_ERROR_INVALID_ARGS);
+ return Result::FATAL_ERROR_INVALID_ARGS;
}
contents[numItems] = item;
numItems++;
length += item->len;
return Success;
}