mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 1029247, Part 2: Parse certificates using mozilla::pkix::der, r=keeler
--HG-- extra : rebase_source : e093922497d005734c590a59f175993a7715bce8
This commit is contained in:
parent
03a7a82015
commit
3fbb0b3f6f
@ -542,7 +542,7 @@ VerifyCertificate(CERTCertificate* signerCert, void* voidContext, void* pinArg)
|
||||
if (trustDomain.SetTrustedRoot(context.trustedRoot) != SECSuccess) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
if (BuildCertChain(trustDomain, signerCert, PR_Now(),
|
||||
if (BuildCertChain(trustDomain, signerCert->derCert, PR_Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::digitalSignature,
|
||||
KeyPurposeId::id_kp_codeSigning,
|
||||
|
@ -162,7 +162,7 @@ AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
|
||||
}
|
||||
|
||||
SECStatus
|
||||
AppTrustDomain::VerifySignedData(const CERTSignedData* signedData,
|
||||
AppTrustDomain::VerifySignedData(const CERTSignedData& signedData,
|
||||
const SECItem& subjectPublicKeyInfo)
|
||||
{
|
||||
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
|
||||
|
@ -28,7 +28,7 @@ public:
|
||||
PRTime time,
|
||||
/*out*/ mozilla::pkix::ScopedCERTCertList& results)
|
||||
MOZ_OVERRIDE;
|
||||
SECStatus VerifySignedData(const CERTSignedData* signedData,
|
||||
SECStatus VerifySignedData(const CERTSignedData& signedData,
|
||||
const SECItem& subjectPublicKeyInfo) MOZ_OVERRIDE;
|
||||
SECStatus CheckRevocation(mozilla::pkix::EndEntityOrCA endEntityOrCA,
|
||||
const mozilla::pkix::CertID& certID, PRTime time,
|
||||
|
@ -164,17 +164,17 @@ BuildCertChainForOneKeyUsage(TrustDomain& trustDomain, CERTCertificate* cert,
|
||||
const SECItem* stapledOCSPResponse,
|
||||
ScopedCERTCertList& builtChain)
|
||||
{
|
||||
SECStatus rv = BuildCertChain(trustDomain, cert, time,
|
||||
SECStatus rv = BuildCertChain(trustDomain, cert->derCert, time,
|
||||
EndEntityOrCA::MustBeEndEntity, ku1,
|
||||
eku, requiredPolicy,
|
||||
stapledOCSPResponse, builtChain);
|
||||
if (rv != SECSuccess && PR_GetError() == SEC_ERROR_INADEQUATE_KEY_USAGE) {
|
||||
rv = BuildCertChain(trustDomain, cert, time,
|
||||
rv = BuildCertChain(trustDomain, cert->derCert, time,
|
||||
EndEntityOrCA::MustBeEndEntity, ku2,
|
||||
eku, requiredPolicy,
|
||||
stapledOCSPResponse, builtChain);
|
||||
if (rv != SECSuccess && PR_GetError() == SEC_ERROR_INADEQUATE_KEY_USAGE) {
|
||||
rv = BuildCertChain(trustDomain, cert, time,
|
||||
rv = BuildCertChain(trustDomain, cert->derCert, time,
|
||||
EndEntityOrCA::MustBeEndEntity, ku3,
|
||||
eku, requiredPolicy,
|
||||
stapledOCSPResponse, builtChain);
|
||||
@ -237,7 +237,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
// just use trustEmail as it is the closest alternative.
|
||||
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig);
|
||||
rv = BuildCertChain(trustDomain, cert, time,
|
||||
rv = BuildCertChain(trustDomain, cert->derCert, time,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::digitalSignature,
|
||||
KeyPurposeId::id_kp_clientAuth,
|
||||
@ -303,7 +303,8 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
case certificateUsageSSLCA: {
|
||||
NSSCertDBTrustDomain trustDomain(trustSSL, ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig);
|
||||
rv = BuildCertChain(trustDomain, cert, time, EndEntityOrCA::MustBeCA,
|
||||
rv = BuildCertChain(trustDomain, cert->derCert, time,
|
||||
EndEntityOrCA::MustBeCA,
|
||||
KeyUsage::keyCertSign,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy,
|
||||
@ -314,7 +315,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
case certificateUsageEmailSigner: {
|
||||
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig);
|
||||
rv = BuildCertChain(trustDomain, cert, time,
|
||||
rv = BuildCertChain(trustDomain, cert->derCert, time,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::digitalSignature,
|
||||
KeyPurposeId::id_kp_emailProtection,
|
||||
@ -329,14 +330,14 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
// based on the result of the verification(s).
|
||||
NSSCertDBTrustDomain trustDomain(trustEmail, ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig);
|
||||
rv = BuildCertChain(trustDomain, cert, time,
|
||||
rv = BuildCertChain(trustDomain, cert->derCert, time,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::keyEncipherment, // RSA
|
||||
KeyPurposeId::id_kp_emailProtection,
|
||||
CertPolicyId::anyPolicy,
|
||||
stapledOCSPResponse, builtChain);
|
||||
if (rv != SECSuccess && PR_GetError() == SEC_ERROR_INADEQUATE_KEY_USAGE) {
|
||||
rv = BuildCertChain(trustDomain, cert, time,
|
||||
rv = BuildCertChain(trustDomain, cert->derCert, time,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::keyAgreement, // ECDH/DH
|
||||
KeyPurposeId::id_kp_emailProtection,
|
||||
@ -349,7 +350,7 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
case certificateUsageObjectSigner: {
|
||||
NSSCertDBTrustDomain trustDomain(trustObjectSigning, ocspFetching,
|
||||
mOCSPCache, pinArg, ocspGETConfig);
|
||||
rv = BuildCertChain(trustDomain, cert, time,
|
||||
rv = BuildCertChain(trustDomain, cert->derCert, time,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::digitalSignature,
|
||||
KeyPurposeId::id_kp_codeSigning,
|
||||
@ -379,22 +380,23 @@ CertVerifier::VerifyCert(CERTCertificate* cert, SECCertificateUsage usage,
|
||||
|
||||
NSSCertDBTrustDomain sslTrust(trustSSL, ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig);
|
||||
rv = BuildCertChain(sslTrust, cert, time, endEntityOrCA,
|
||||
rv = BuildCertChain(sslTrust, cert->derCert, time, endEntityOrCA,
|
||||
keyUsage, eku, CertPolicyId::anyPolicy,
|
||||
stapledOCSPResponse, builtChain);
|
||||
if (rv == SECFailure && PR_GetError() == SEC_ERROR_UNKNOWN_ISSUER) {
|
||||
NSSCertDBTrustDomain emailTrust(trustEmail, ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig);
|
||||
rv = BuildCertChain(emailTrust, cert, time, endEntityOrCA, keyUsage,
|
||||
eku, CertPolicyId::anyPolicy,
|
||||
rv = BuildCertChain(emailTrust, cert->derCert, time, endEntityOrCA,
|
||||
keyUsage, eku, CertPolicyId::anyPolicy,
|
||||
stapledOCSPResponse, builtChain);
|
||||
if (rv == SECFailure && PR_GetError() == SEC_ERROR_UNKNOWN_ISSUER) {
|
||||
NSSCertDBTrustDomain objectSigningTrust(trustObjectSigning,
|
||||
ocspFetching, mOCSPCache,
|
||||
pinArg, ocspGETConfig);
|
||||
rv = BuildCertChain(objectSigningTrust, cert, time, endEntityOrCA,
|
||||
keyUsage, eku, CertPolicyId::anyPolicy,
|
||||
stapledOCSPResponse, builtChain);
|
||||
rv = BuildCertChain(objectSigningTrust, cert->derCert, time,
|
||||
endEntityOrCA, keyUsage, eku,
|
||||
CertPolicyId::anyPolicy, stapledOCSPResponse,
|
||||
builtChain);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -147,7 +147,7 @@ NSSCertDBTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
|
||||
}
|
||||
|
||||
SECStatus
|
||||
NSSCertDBTrustDomain::VerifySignedData(const CERTSignedData* signedData,
|
||||
NSSCertDBTrustDomain::VerifySignedData(const CERTSignedData& signedData,
|
||||
const SECItem& subjectPublicKeyInfo)
|
||||
{
|
||||
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
|
||||
|
@ -63,7 +63,7 @@ public:
|
||||
const SECItem& candidateCertDER,
|
||||
/*out*/ mozilla::pkix::TrustLevel* trustLevel);
|
||||
|
||||
virtual SECStatus VerifySignedData(const CERTSignedData* signedData,
|
||||
virtual SECStatus VerifySignedData(const CERTSignedData& signedData,
|
||||
const SECItem& subjectPublicKeyInfo);
|
||||
|
||||
virtual SECStatus CheckRevocation(mozilla::pkix::EndEntityOrCA endEntityOrCA,
|
||||
|
@ -53,9 +53,9 @@ function run_test() {
|
||||
load_cert("v3_ca_missing_bc", "CTu,CTu,CTu");
|
||||
|
||||
check_ok_ca(cert_from_file('v1_ca.der'));
|
||||
check_ca_err(cert_from_file('v1_ca_bc.der'), SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||
check_ca_err(cert_from_file('v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_ca_err(cert_from_file('v2_ca.der'), SEC_ERROR_CA_CERT_INVALID);
|
||||
check_ca_err(cert_from_file('v2_ca_bc.der'), SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||
check_ca_err(cert_from_file('v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_ok_ca(cert_from_file('v3_ca.der'));
|
||||
check_ca_err(cert_from_file('v3_ca_missing_bc.der'), SEC_ERROR_CA_CERT_INVALID);
|
||||
|
||||
@ -82,21 +82,18 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v1_int-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v1_int-v1_ca.der'), ee_error);
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v1_int-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// v1 intermediate with v3 extensions. CA is invalid.
|
||||
ca_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_ca_err(cert_from_file('v1_int_bc-v1_ca.der'), ca_error);
|
||||
check_cert_err(cert_from_file('v1_ee-v1_int_bc-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int_bc-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_ee-v1_int_bc-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int_bc-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int_bc-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v1_int_bc-v1_ca.der'), ee_error);
|
||||
check_ca_err(cert_from_file('v1_int_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_ee-v1_int_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_ee-v1_int_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v1_int_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v1_int_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// A v2 intermediate with a v1 CA
|
||||
@ -107,21 +104,18 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v2_int-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v2_int-v1_ca.der'), ee_error);
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v2_int-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// A v2 intermediate with basic constraints (not allowed in insanity)
|
||||
ca_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_ca_err(cert_from_file('v2_int_bc-v1_ca.der'), ca_error);
|
||||
check_cert_err(cert_from_file('v1_ee-v2_int_bc-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int_bc-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_ee-v2_int_bc-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int_bc-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int_bc-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v2_int_bc-v1_ca.der'), ee_error);
|
||||
// A v2 intermediate with basic constraints (not allowed in mozilla::pkix)
|
||||
check_ca_err(cert_from_file('v2_int_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_ee-v2_int_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_ee-v2_int_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v2_int_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v2_int_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// Section is OK. A x509 v3 CA MUST have bc
|
||||
@ -133,9 +127,8 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v3_int_missing_bc-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int_missing_bc-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v3_int_missing_bc-v1_ca.der'), ee_error);
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v3_int_missing_bc-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// It is valid for a v1 ca to sign a v3 intemediate.
|
||||
@ -144,10 +137,8 @@ function run_test() {
|
||||
check_ok(cert_from_file('v2_ee-v3_int-v1_ca.der'));
|
||||
check_ok(cert_from_file('v3_missing_bc_ee-v3_int-v1_ca.der'));
|
||||
check_ok(cert_from_file('v3_bc_ee-v3_int-v1_ca.der'));
|
||||
ca_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int-v1_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v3_int-v1_ca.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// The next groups change the v1 ca for a v1 ca with base constraints
|
||||
@ -162,21 +153,18 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v1_int-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v1_int-v1_ca_bc.der'), ee_error);
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v1_int-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// Using a v1 intermediate with v3 extenstions (invalid).
|
||||
ca_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_ca_err(cert_from_file('v1_int_bc-v1_ca_bc.der'), ca_error);
|
||||
check_cert_err(cert_from_file('v1_ee-v1_int_bc-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int_bc-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_ee-v1_int_bc-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int_bc-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int_bc-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v1_int_bc-v1_ca_bc.der'), ee_error);
|
||||
check_ca_err(cert_from_file('v1_int_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_ee-v1_int_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_ee-v1_int_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v1_int_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v1_int_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// Using v2 intermediate
|
||||
@ -187,21 +175,18 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v2_int-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v2_int-v1_ca_bc.der'), ee_error);
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v2_int-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// Using a v2 intermediate with basic constraints (invalid)
|
||||
ca_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_ca_err(cert_from_file('v2_int_bc-v1_ca_bc.der'), ca_error);
|
||||
check_cert_err(cert_from_file('v1_ee-v2_int_bc-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int_bc-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_ee-v2_int_bc-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int_bc-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int_bc-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v2_int_bc-v1_ca_bc.der'), ee_error);
|
||||
check_ca_err(cert_from_file('v2_int_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_ee-v2_int_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_ee-v2_int_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v2_int_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v2_int_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// Using a v3 intermediate that is missing basic constraints (invalid)
|
||||
@ -212,21 +197,20 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v3_int_missing_bc-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int_missing_bc-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v3_int_missing_bc-v1_ca_bc.der'), ee_error);
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v3_int_missing_bc-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// these should pass assuming we are OK with v1 ca signing v3 intermediates
|
||||
ca_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_ca_err(cert_from_file('v3_int-v1_ca_bc.der'), ca_error);
|
||||
check_cert_err(cert_from_file('v1_ee-v3_int-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_ee-v3_int-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int-v1_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v3_int-v1_ca_bc.der'), ee_error);
|
||||
check_ca_err(cert_from_file('v3_int-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_ee-v3_int-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_ee-v3_int-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v3_int-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v3_int-v1_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
|
||||
@ -242,21 +226,18 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v1_int-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v1_int-v2_ca.der'), ee_error);
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int-v2_ca.der'), ee_error)
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v1_int-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// v2 ca, v1 intermediate with basic constraints (invalid)
|
||||
ca_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_ca_err(cert_from_file('v1_int_bc-v2_ca.der'), ca_error);
|
||||
check_cert_err(cert_from_file('v1_ee-v1_int_bc-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int_bc-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_ee-v1_int_bc-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int_bc-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int_bc-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v1_int_bc-v2_ca.der'), ee_error);
|
||||
check_ca_err(cert_from_file('v1_int_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_ee-v1_int_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_ee-v1_int_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v1_int_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v1_int_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// v2 ca, v2 intermediate
|
||||
@ -267,21 +248,18 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v2_int-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v2_int-v2_ca.der'), ee_error);
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v2_int-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// v2 ca, v2 intermediate with basic constraints (invalid)
|
||||
ca_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_ca_err(cert_from_file('v2_int_bc-v2_ca.der'), ca_error);
|
||||
check_cert_err(cert_from_file('v1_ee-v2_int_bc-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int_bc-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_ee-v2_int_bc-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int_bc-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int_bc-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v2_int_bc-v2_ca.der'), ee_error);
|
||||
check_ca_err(cert_from_file('v2_int_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_ee-v2_int_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_ee-v2_int_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v2_int_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v2_int_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// v2 ca, v3 intermediate missing basic constraints
|
||||
@ -292,9 +270,8 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v3_int_missing_bc-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int_missing_bc-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v3_int_missing_bc-v2_ca.der'), ee_error);
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v3_int_missing_bc-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// v2 ca, v3 intermediate
|
||||
@ -305,10 +282,8 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v3_int-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v3_int-v2_ca.der'), ee_error);
|
||||
ca_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int-v2_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v3_int-v2_ca.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// v2 ca, v1 intermediate
|
||||
@ -319,21 +294,18 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v1_int-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v1_int-v2_ca_bc.der'), ee_error);
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v1_int-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// v2 ca, v1 intermediate with bc (invalid)
|
||||
ca_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_ca_err(cert_from_file('v1_int_bc-v2_ca_bc.der'), ca_error);
|
||||
check_cert_err(cert_from_file('v1_ee-v1_int_bc-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int_bc-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_ee-v1_int_bc-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int_bc-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int_bc-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v1_int_bc-v2_ca_bc.der'), ee_error);
|
||||
check_ca_err(cert_from_file('v1_int_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_ee-v1_int_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_ee-v1_int_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v1_int_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v1_int_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// v2 ca, v2 intermediate
|
||||
@ -344,21 +316,18 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v2_int-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v2_int-v2_ca_bc.der'), ee_error);
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v2_int-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// v2 ca, v2 intermediate with bc (invalid)
|
||||
ca_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_ca_err(cert_from_file('v2_int_bc-v2_ca_bc.der'), ca_error);
|
||||
check_cert_err(cert_from_file('v1_ee-v2_int_bc-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int_bc-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_ee-v2_int_bc-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int_bc-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int_bc-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v2_int_bc-v2_ca_bc.der'), ee_error);
|
||||
check_ca_err(cert_from_file('v2_int_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_ee-v2_int_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_ee-v2_int_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v2_int_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v2_int_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// v2 ca, invalid v3 intermediate
|
||||
@ -369,21 +338,18 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v3_int_missing_bc-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int_missing_bc-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v3_int_missing_bc-v2_ca_bc.der'), ee_error);
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v2_ca_bc.der'), ee_error)
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v3_int_missing_bc-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// v2 ca, valid v3 intermediate (is OK if we use 'classic' semantics)
|
||||
ca_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_ca_err(cert_from_file('v3_int-v2_ca_bc.der'), ca_error);
|
||||
check_cert_err(cert_from_file('v1_ee-v3_int-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_ee-v3_int-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int-v2_ca_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v3_int-v2_ca_bc.der'), ee_error);
|
||||
check_ca_err(cert_from_file('v3_int-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_ee-v3_int-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_ee-v3_int-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v3_int-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v3_int-v2_ca_bc.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
//////////////
|
||||
@ -398,21 +364,18 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v1_int-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v1_int-v3_ca.der'), ee_error);
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v1_int-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// A v1 intermediate with v3 extensions
|
||||
ca_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_ca_err(cert_from_file('v1_int_bc-v3_ca.der'), ca_error);
|
||||
check_cert_err(cert_from_file('v1_ee-v1_int_bc-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int_bc-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_ee-v1_int_bc-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int_bc-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int_bc-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v1_int_bc-v3_ca.der'), ee_error);
|
||||
check_ca_err(cert_from_file('v1_int_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_ee-v1_int_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_ee-v1_int_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v1_int_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v1_int_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// reject a v2 cert as intermediate
|
||||
@ -423,21 +386,18 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v2_int-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v2_int-v3_ca.der'), ee_error);
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v2_int-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// v2 intermediate with bc (invalid)
|
||||
ca_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_ca_err(cert_from_file('v2_int_bc-v3_ca.der'), ca_error);
|
||||
check_cert_err(cert_from_file('v1_ee-v2_int_bc-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int_bc-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_ee-v2_int_bc-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int_bc-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int_bc-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v2_int_bc-v3_ca.der'), ee_error);
|
||||
check_ca_err(cert_from_file('v2_int_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_ee-v2_int_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_ee-v2_int_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v2_int_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v2_int_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// invalid v3 intermediate
|
||||
@ -448,9 +408,8 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v3_int_missing_bc-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int_missing_bc-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v3_int_missing_bc-v3_ca.der'), ee_error);
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v3_int_missing_bc-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// I dont think that v3 intermediates should be allowed to sign v1 or v2
|
||||
@ -460,10 +419,8 @@ function run_test() {
|
||||
check_ok(cert_from_file('v2_ee-v3_int-v3_ca.der'));
|
||||
check_ok(cert_from_file('v3_missing_bc_ee-v3_int-v3_ca.der'));
|
||||
check_ok(cert_from_file('v3_bc_ee-v3_int-v3_ca.der'));
|
||||
ca_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int-v3_ca.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v3_int-v3_ca.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// v3 CA, invalid v3 intermediate
|
||||
@ -474,21 +431,18 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v1_int-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v1_int-v3_ca_missing_bc.der'), ee_error);
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v1_int-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// Int v1 with BC that is just invalid (classic fail insanity OK)
|
||||
ca_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_ca_err(cert_from_file('v1_int_bc-v3_ca_missing_bc.der'), ca_error);
|
||||
check_cert_err(cert_from_file('v1_ee-v1_int_bc-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_ee-v1_int_bc-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), ee_error);
|
||||
check_ca_err(cert_from_file('v1_int_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_ee-v1_int_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_ee-v1_int_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v1_int_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// Good section (all fail)
|
||||
@ -499,21 +453,18 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v2_int-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v2_int-v3_ca_missing_bc.der'), ee_error);
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v2_int-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// v2 intermediate (even with basic constraints) is invalid
|
||||
ca_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_ca_err(cert_from_file('v2_int_bc-v3_ca_missing_bc.der'), ca_error);
|
||||
check_cert_err(cert_from_file('v1_ee-v2_int_bc-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_ee-v2_int_bc-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), ee_error);
|
||||
check_ca_err(cert_from_file('v2_int_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_ee-v2_int_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_ee-v2_int_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v2_int_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// v3 intermediate missing basic constraints is invalid
|
||||
@ -524,9 +475,8 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), ee_error);
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v3_int_missing_bc-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
|
||||
// With a v3 root missing bc and valid v3 intermediate
|
||||
@ -537,9 +487,7 @@ function run_test() {
|
||||
check_cert_err(cert_from_file('v2_ee-v3_int-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_missing_bc_ee-v3_int-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v3_bc_ee-v3_int-v3_ca_missing_bc.der'), ee_error);
|
||||
ca_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
ee_error = SEC_ERROR_EXTENSION_VALUE_INVALID;
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int-v3_ca_missing_bc.der'), ee_error);
|
||||
check_cert_err(cert_from_file('v1_bc_ee-v3_int-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v2_bc_ee-v3_int-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
check_cert_err(cert_from_file('v4_bc_ee-v3_int-v3_ca_missing_bc.der'), SEC_ERROR_BAD_DER);
|
||||
}
|
||||
|
@ -89,10 +89,8 @@ namespace mozilla { namespace pkix {
|
||||
// distrust.
|
||||
// TODO(bug 968451): Document more of these.
|
||||
|
||||
SECStatus BuildCertChain(TrustDomain& trustDomain,
|
||||
const CERTCertificate* cert,
|
||||
PRTime time,
|
||||
EndEntityOrCA endEntityOrCA,
|
||||
SECStatus BuildCertChain(TrustDomain& trustDomain, const SECItem& cert,
|
||||
PRTime time, EndEntityOrCA endEntityOrCA,
|
||||
KeyUsage requiredKeyUsageIfPresent,
|
||||
KeyPurposeId requiredEKUIfPresent,
|
||||
const CertPolicyId& requiredPolicy,
|
||||
@ -100,7 +98,7 @@ SECStatus BuildCertChain(TrustDomain& trustDomain,
|
||||
/*out*/ ScopedCERTCertList& results);
|
||||
|
||||
// Verify the given signed data using the given public key.
|
||||
SECStatus VerifySignedData(const CERTSignedData* sd,
|
||||
SECStatus VerifySignedData(const CERTSignedData& sd,
|
||||
const SECItem& subjectPublicKeyInfo,
|
||||
void* pkcs11PinArg);
|
||||
|
||||
|
@ -158,7 +158,7 @@ public:
|
||||
//
|
||||
// Most implementations of this function should probably forward the call
|
||||
// directly to mozilla::pkix::VerifySignedData.
|
||||
virtual SECStatus VerifySignedData(const CERTSignedData* signedData,
|
||||
virtual SECStatus VerifySignedData(const CERTSignedData& signedData,
|
||||
const SECItem& subjectPublicKeyInfo) = 0;
|
||||
|
||||
// issuerCertToDup is only non-const so CERT_DupCertificate can be called on
|
||||
|
@ -27,135 +27,11 @@
|
||||
#include <limits>
|
||||
|
||||
#include "pkixcheck.h"
|
||||
#include "pkixder.h"
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
|
||||
// We assume ext has been zero-initialized by its constructor and otherwise
|
||||
// not modified.
|
||||
//
|
||||
// TODO(perf): This sorting of extensions should be be moved into the
|
||||
// certificate decoder so that the results are cached with the certificate, so
|
||||
// that the decoding doesn't have to happen more than once per cert.
|
||||
Result
|
||||
BackCert::Init(const SECItem& certDER)
|
||||
{
|
||||
// XXX: Currently-known uses of mozilla::pkix create CERTCertificate objects
|
||||
// for all certs anyway, so the overhead of CERT_NewTempCertificate will be
|
||||
// reduced to a lookup in NSS's SECItem* -> CERTCertificate cache and
|
||||
// a CERT_DupCertificate. Eventually, we should parse the certificate using
|
||||
// mozilla::pkix::der and avoid the need to create a CERTCertificate at all.
|
||||
nssCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
|
||||
const_cast<SECItem*>(&certDER),
|
||||
nullptr, false, true);
|
||||
if (!nssCert) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
|
||||
if (nssCert->version.len == 1 &&
|
||||
nssCert->version.data[0] == static_cast<uint8_t>(der::Version::v3)) {
|
||||
version = der::Version::v3;
|
||||
} else if (nssCert->version.len == 1 &&
|
||||
nssCert->version.data[0] == static_cast<uint8_t>(der::Version::v2)) {
|
||||
version = der::Version::v2;
|
||||
} else if (nssCert->version.len == 1 &&
|
||||
nssCert->version.data[0] == static_cast<uint8_t>(der::Version::v2)) {
|
||||
// XXX(bug 1031093): We shouldn't accept an explicit encoding of v1, but we
|
||||
// do here for compatibility reasons.
|
||||
version = der::Version::v1;
|
||||
} else if (nssCert->version.len == 0) {
|
||||
version = der::Version::v1;
|
||||
} else {
|
||||
// Explicit encoding of v1 is not allowed. We do not support any other
|
||||
// version except v3.
|
||||
return Fail(RecoverableError, SEC_ERROR_BAD_DER);
|
||||
}
|
||||
|
||||
const CERTCertExtension* const* exts = nssCert->extensions;
|
||||
if (!exts) {
|
||||
return Success;
|
||||
}
|
||||
|
||||
// Extensions are only allowed in v3 certificates, not v1 or v2. Also, we
|
||||
// use presence of the basic constraints extension with isCA==true to decide
|
||||
// whether to treat a certificate as a CA certificate, and we don't want to
|
||||
// allow v1 or v2 intermediate CA certificates; this check is part of that
|
||||
// enforcement as well.
|
||||
if (version != der::Version::v3) {
|
||||
return Fail(RecoverableError, SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||
}
|
||||
|
||||
const SECItem* dummyEncodedSubjectKeyIdentifier = nullptr;
|
||||
const SECItem* dummyEncodedAuthorityKeyIdentifier = nullptr;
|
||||
const SECItem* dummyEncodedSubjectAltName = nullptr;
|
||||
|
||||
for (const CERTCertExtension* ext = *exts; ext; ext = *++exts) {
|
||||
const SECItem** out = nullptr;
|
||||
|
||||
// python DottedOIDToCode.py id-ce 2.5.29
|
||||
static const uint8_t id_ce[] = {
|
||||
0x55, 0x1d
|
||||
};
|
||||
|
||||
// python DottedOIDToCode.py id-pe-authorityInfoAccess 1.3.6.1.5.5.7.1.1
|
||||
static const uint8_t id_pe_authorityInfoAccess[] = {
|
||||
0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01
|
||||
};
|
||||
|
||||
if (ext->id.len == PR_ARRAY_SIZE(id_ce) + 1 &&
|
||||
!memcmp(ext->id.data, id_ce, PR_ARRAY_SIZE(id_ce))) {
|
||||
switch (ext->id.data[ext->id.len - 1]) {
|
||||
case 14: out = &dummyEncodedSubjectKeyIdentifier; break; // bug 965136
|
||||
case 15: out = &encodedKeyUsage; break;
|
||||
case 17: out = &dummyEncodedSubjectAltName; break; // bug 970542
|
||||
case 19: out = &encodedBasicConstraints; break;
|
||||
case 30: out = &encodedNameConstraints; break;
|
||||
case 32: out = &encodedCertificatePolicies; break;
|
||||
case 35: out = &dummyEncodedAuthorityKeyIdentifier; break; // bug 965136
|
||||
case 37: out = &encodedExtendedKeyUsage; break;
|
||||
case 54: out = &encodedInhibitAnyPolicy; break; // Bug 989051
|
||||
}
|
||||
} else if (ext->id.len == PR_ARRAY_SIZE(id_pe_authorityInfoAccess) &&
|
||||
!memcmp(ext->id.data, id_pe_authorityInfoAccess,
|
||||
PR_ARRAY_SIZE(id_pe_authorityInfoAccess))) {
|
||||
// We should remember the value of the encoded AIA extension here, but
|
||||
// since our TrustDomain implementations get the OCSP URI using
|
||||
// CERT_GetOCSPAuthorityInfoAccessLocation, we currently don't need to.
|
||||
out = &encodedAuthorityInfoAccess;
|
||||
}
|
||||
|
||||
// If this is an extension we don't understand and it's marked critical,
|
||||
// we must reject this certificate.
|
||||
// (The only valid explicit value of the critical flag is TRUE because
|
||||
// it is defined as BOOLEAN DEFAULT FALSE, so we just assume it is true.)
|
||||
if (!out && ext->critical.data && ext->critical.len > 0) {
|
||||
return Fail(RecoverableError, SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION);
|
||||
}
|
||||
|
||||
if (out) {
|
||||
// This is an extension we understand. Save it in results unless we've
|
||||
// already found the extension previously.
|
||||
if (*out) {
|
||||
// Duplicate extension
|
||||
return Fail(RecoverableError, SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||
}
|
||||
*out = &ext->value;
|
||||
}
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
Result
|
||||
BackCert::VerifyOwnSignatureWithKey(TrustDomain& trustDomain,
|
||||
const SECItem& subjectPublicKeyInfo) const
|
||||
{
|
||||
return MapSECStatus(trustDomain.VerifySignedData(&nssCert->signatureWrap,
|
||||
subjectPublicKeyInfo));
|
||||
}
|
||||
|
||||
static Result BuildForward(TrustDomain& trustDomain,
|
||||
BackCert& subject,
|
||||
const BackCert& subject,
|
||||
PRTime time,
|
||||
EndEntityOrCA endEntityOrCA,
|
||||
KeyUsage requiredKeyUsageIfPresent,
|
||||
@ -168,7 +44,7 @@ static Result BuildForward(TrustDomain& trustDomain,
|
||||
// The code that executes in the inner loop of BuildForward
|
||||
static Result
|
||||
BuildForwardInner(TrustDomain& trustDomain,
|
||||
BackCert& subject,
|
||||
const BackCert& subject,
|
||||
PRTime time,
|
||||
KeyPurposeId requiredEKUIfPresent,
|
||||
const CertPolicyId& requiredPolicy,
|
||||
@ -176,8 +52,9 @@ BuildForwardInner(TrustDomain& trustDomain,
|
||||
unsigned int subCACount,
|
||||
/*out*/ ScopedCERTCertList& results)
|
||||
{
|
||||
BackCert potentialIssuer(&subject, BackCert::IncludeCN::No);
|
||||
Result rv = potentialIssuer.Init(potentialIssuerDER);
|
||||
BackCert potentialIssuer(potentialIssuerDER, &subject,
|
||||
BackCert::IncludeCN::No);
|
||||
Result rv = potentialIssuer.Init();
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
@ -189,7 +66,7 @@ BuildForwardInner(TrustDomain& trustDomain,
|
||||
// TODO: this doesn't account for subjectAltNames!
|
||||
// TODO(perf): This probably can and should be optimized in some way.
|
||||
bool loopDetected = false;
|
||||
for (BackCert* prev = potentialIssuer.childCert;
|
||||
for (const BackCert* prev = potentialIssuer.childCert;
|
||||
!loopDetected && prev != nullptr; prev = prev->childCert) {
|
||||
if (SECITEM_ItemsAreEqual(&potentialIssuer.GetSubjectPublicKeyInfo(),
|
||||
&prev->GetSubjectPublicKeyInfo()) &&
|
||||
@ -214,8 +91,14 @@ BuildForwardInner(TrustDomain& trustDomain,
|
||||
return rv;
|
||||
}
|
||||
|
||||
return subject.VerifyOwnSignatureWithKey(
|
||||
trustDomain, potentialIssuer.GetSubjectPublicKeyInfo());
|
||||
SECStatus srv = trustDomain.VerifySignedData(
|
||||
subject.GetSignedData(),
|
||||
potentialIssuer.GetSubjectPublicKeyInfo());
|
||||
if (srv != SECSuccess) {
|
||||
return MapSECStatus(srv);
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
// Recursively build the path from the given subject certificate to the root.
|
||||
@ -226,7 +109,7 @@ BuildForwardInner(TrustDomain& trustDomain,
|
||||
// pkix/pkix.h.
|
||||
static Result
|
||||
BuildForward(TrustDomain& trustDomain,
|
||||
BackCert& subject,
|
||||
const BackCert& subject,
|
||||
PRTime time,
|
||||
EndEntityOrCA endEntityOrCA,
|
||||
KeyUsage requiredKeyUsageIfPresent,
|
||||
@ -265,13 +148,15 @@ BuildForward(TrustDomain& trustDomain,
|
||||
if (!results) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
for (BackCert* cert = &subject; cert; cert = cert->childCert) {
|
||||
CERTCertificate* dup = CERT_DupCertificate(cert->GetNSSCert());
|
||||
if (CERT_AddCertToListHead(results.get(), dup) != SECSuccess) {
|
||||
CERT_DestroyCertificate(dup);
|
||||
for (const BackCert* cert = &subject; cert; cert = cert->childCert) {
|
||||
ScopedCERTCertificate
|
||||
nssCert(CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
|
||||
const_cast<SECItem*>(&cert->GetDER()),
|
||||
nullptr, false, true));
|
||||
if (CERT_AddCertToListHead(results.get(), nssCert.get()) != SECSuccess) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
// dup is now owned by results.
|
||||
nssCert.release(); // nssCert is now owned by results.
|
||||
}
|
||||
|
||||
// This must be done here, after the chain is built but before any
|
||||
@ -326,7 +211,7 @@ BuildForward(TrustDomain& trustDomain,
|
||||
SECStatus srv = trustDomain.CheckRevocation(
|
||||
endEntityOrCA, certID, time,
|
||||
stapledOCSPResponse,
|
||||
subject.encodedAuthorityInfoAccess);
|
||||
subject.GetAuthorityInfoAccess());
|
||||
if (srv != SECSuccess) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
@ -365,22 +250,14 @@ BuildForward(TrustDomain& trustDomain,
|
||||
}
|
||||
|
||||
SECStatus
|
||||
BuildCertChain(TrustDomain& trustDomain,
|
||||
const CERTCertificate* nssCert,
|
||||
PRTime time,
|
||||
EndEntityOrCA endEntityOrCA,
|
||||
BuildCertChain(TrustDomain& trustDomain, const SECItem& certDER,
|
||||
PRTime time, EndEntityOrCA endEntityOrCA,
|
||||
KeyUsage requiredKeyUsageIfPresent,
|
||||
KeyPurposeId requiredEKUIfPresent,
|
||||
const CertPolicyId& requiredPolicy,
|
||||
/*optional*/ const SECItem* stapledOCSPResponse,
|
||||
/*out*/ ScopedCERTCertList& results)
|
||||
{
|
||||
if (!nssCert) {
|
||||
PR_NOT_REACHED("null cert passed to BuildCertChain");
|
||||
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
// XXX: Support the legacy use of the subject CN field for indicating the
|
||||
// domain name the certificate is valid for.
|
||||
BackCert::IncludeCN includeCN
|
||||
@ -389,8 +266,8 @@ BuildCertChain(TrustDomain& trustDomain,
|
||||
? BackCert::IncludeCN::Yes
|
||||
: BackCert::IncludeCN::No;
|
||||
|
||||
BackCert cert(nullptr, includeCN);
|
||||
Result rv = cert.Init(nssCert->derCert);
|
||||
BackCert cert(certDER, nullptr, includeCN);
|
||||
Result rv = cert.Init();
|
||||
if (rv != Success) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
252
security/pkix/lib/pkixcert.cpp
Normal file
252
security/pkix/lib/pkixcert.cpp
Normal file
@ -0,0 +1,252 @@
|
||||
/* -*- 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 "pkix/bind.h"
|
||||
#include "pkixutil.h"
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
|
||||
Result
|
||||
BackCert::Init()
|
||||
{
|
||||
// Certificate ::= SEQUENCE {
|
||||
// tbsCertificate TBSCertificate,
|
||||
// signatureAlgorithm AlgorithmIdentifier,
|
||||
// signatureValue BIT STRING }
|
||||
|
||||
der::Input tbsCertificate;
|
||||
|
||||
// The scope of |input| and |certificate| are limited to this block so we
|
||||
// don't accidentally confuse them for tbsCertificate later.
|
||||
{
|
||||
der::Input input;
|
||||
if (input.Init(der.data, der.len) != der::Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
der::Input certificate;
|
||||
if (der::ExpectTagAndGetValue(input, der::SEQUENCE, certificate)
|
||||
!= der::Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
if (der::End(input) != der::Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
if (der::SignedData(certificate, tbsCertificate, signedData)
|
||||
!= der::Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
if (der::End(certificate) != der::Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
}
|
||||
|
||||
// TBSCertificate ::= SEQUENCE {
|
||||
// version [0] EXPLICIT Version DEFAULT v1,
|
||||
// serialNumber CertificateSerialNumber,
|
||||
// signature AlgorithmIdentifier,
|
||||
// issuer Name,
|
||||
// validity Validity,
|
||||
// subject Name,
|
||||
// subjectPublicKeyInfo SubjectPublicKeyInfo,
|
||||
// issuerUniqueID [1] IMPLICIT UniqueIdentifier OPTIONAL,
|
||||
// -- If present, version MUST be v2 or v3
|
||||
// subjectUniqueID [2] IMPLICIT UniqueIdentifier OPTIONAL,
|
||||
// -- If present, version MUST be v2 or v3
|
||||
// extensions [3] EXPLICIT Extensions OPTIONAL
|
||||
// -- If present, version MUST be v3
|
||||
// }
|
||||
if (der::OptionalVersion(tbsCertificate, version) != der::Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
if (der::CertificateSerialNumber(tbsCertificate, serialNumber)
|
||||
!= der::Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
// XXX: Ignored. What are we supposed to check? This seems totally redundant
|
||||
// with Certificate.signatureAlgorithm. Is it important to check that they
|
||||
// are consistent with each other? It doesn't seem to matter!
|
||||
SECAlgorithmID signature;
|
||||
if (der::AlgorithmIdentifier(tbsCertificate, signature) != der::Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
if (der::ExpectTagAndGetTLV(tbsCertificate, der::SEQUENCE, issuer)
|
||||
!= der::Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
if (der::ExpectTagAndGetValue(tbsCertificate, der::SEQUENCE, validity)
|
||||
!= der::Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
// TODO(bug XXXXXXX): We rely on the the caller of mozilla::pkix to validate
|
||||
// that the name is syntactically valid, if they care. In Gecko we do this
|
||||
// implicitly by parsing the certificate into a CERTCertificate object.
|
||||
// Instead of relying on the caller to do this, we should do it ourselves.
|
||||
if (der::ExpectTagAndGetTLV(tbsCertificate, der::SEQUENCE, subject)
|
||||
!= der::Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
// TODO(bug XXXXXXX): We defer parsing/validating subjectPublicKeyInfo to
|
||||
// the point where the public key is needed. For end-entity certificates, we
|
||||
// assume that the caller will extract the public key and use it somehow; if
|
||||
// they don't do that then we'll never know whether the key is invalid. On
|
||||
// the other hand, if the caller never uses the key then in some ways it
|
||||
// doesn't matter. Regardless, we should parse and validate
|
||||
// subjectPublicKeyKeyInfo internally.
|
||||
if (der::ExpectTagAndGetTLV(tbsCertificate, der::SEQUENCE,
|
||||
subjectPublicKeyInfo) != der::Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
|
||||
static const uint8_t CSC = der::CONTEXT_SPECIFIC | der::CONSTRUCTED;
|
||||
|
||||
// RFC 5280 says: "These fields MUST only appear if the version is 2 or 3
|
||||
// (Section 4.1.2.1). These fields MUST NOT appear if the version is 1."
|
||||
if (version != der::Version::v1) {
|
||||
|
||||
// Ignore issuerUniqueID if present.
|
||||
if (tbsCertificate.Peek(CSC | 1)) {
|
||||
if (der::ExpectTagAndSkipValue(tbsCertificate, CSC | 1) != der::Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
}
|
||||
|
||||
// Ignore subjectUniqueID if present.
|
||||
if (tbsCertificate.Peek(CSC | 2)) {
|
||||
if (der::ExpectTagAndSkipValue(tbsCertificate, CSC | 2) != der::Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Extensions were added in v3, so only accept extensions in v3 certificates.
|
||||
if (version == der::Version::v3) {
|
||||
if (der::OptionalExtensions(tbsCertificate, CSC | 3,
|
||||
bind(&BackCert::RememberExtension, this, _1, _2,
|
||||
_3)) != der::Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
}
|
||||
|
||||
if (der::End(tbsCertificate) != der::Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
der::Result
|
||||
BackCert::RememberExtension(der::Input& extnID, const SECItem& extnValue,
|
||||
/*out*/ bool& understood)
|
||||
{
|
||||
understood = false;
|
||||
|
||||
// python DottedOIDToCode.py id-ce-keyUsage 2.5.29.15
|
||||
static const uint8_t id_ce_keyUsage[] = {
|
||||
0x55, 0x1d, 0x0f
|
||||
};
|
||||
// python DottedOIDToCode.py id-ce-subjectAltName 2.5.29.17
|
||||
static const uint8_t id_ce_subjectAltName[] = {
|
||||
0x55, 0x1d, 0x11
|
||||
};
|
||||
// python DottedOIDToCode.py id-ce-basicConstraints 2.5.29.19
|
||||
static const uint8_t id_ce_basicConstraints[] = {
|
||||
0x55, 0x1d, 0x13
|
||||
};
|
||||
// python DottedOIDToCode.py id-ce-nameConstraints 2.5.29.30
|
||||
static const uint8_t id_ce_nameConstraints[] = {
|
||||
0x55, 0x1d, 0x1e
|
||||
};
|
||||
// python DottedOIDToCode.py id-ce-certificatePolicies 2.5.29.32
|
||||
static const uint8_t id_ce_certificatePolicies[] = {
|
||||
0x55, 0x1d, 0x20
|
||||
};
|
||||
// python DottedOIDToCode.py id-ce-policyConstraints 2.5.29.36
|
||||
static const uint8_t id_ce_policyConstraints[] = {
|
||||
0x55, 0x1d, 0x24
|
||||
};
|
||||
// python DottedOIDToCode.py id-ce-extKeyUsage 2.5.29.37
|
||||
static const uint8_t id_ce_extKeyUsage[] = {
|
||||
0x55, 0x1d, 0x25
|
||||
};
|
||||
// python DottedOIDToCode.py id-ce-inhibitAnyPolicy 2.5.29.54
|
||||
static const uint8_t id_ce_inhibitAnyPolicy[] = {
|
||||
0x55, 0x1d, 0x36
|
||||
};
|
||||
// python DottedOIDToCode.py id-pe-authorityInfoAccess 1.3.6.1.5.5.7.1.1
|
||||
static const uint8_t id_pe_authorityInfoAccess[] = {
|
||||
0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01
|
||||
};
|
||||
|
||||
SECItem* out = nullptr;
|
||||
|
||||
// We already enforce the maximum possible constraints for policies so we
|
||||
// can safely ignore even critical policy constraint extensions.
|
||||
//
|
||||
// XXX: Doing it this way won't allow us to detect duplicate
|
||||
// policyConstraints extensions, but that's OK because (and only because) we
|
||||
// ignore the extension.
|
||||
SECItem dummyPolicyConstraints = { siBuffer, nullptr, 0 };
|
||||
|
||||
// RFC says "Conforming CAs MUST mark this extension as non-critical" for
|
||||
// both authorityKeyIdentifier and subjectKeyIdentifier, and we do not use
|
||||
// them for anything, so we totally ignore them here.
|
||||
|
||||
if (extnID.MatchRest(id_ce_keyUsage)) {
|
||||
out = &keyUsage;
|
||||
} else if (extnID.MatchRest(id_ce_subjectAltName)) {
|
||||
out = &subjectAltName;
|
||||
} else if (extnID.MatchRest(id_ce_basicConstraints)) {
|
||||
out = &basicConstraints;
|
||||
} else if (extnID.MatchRest(id_ce_nameConstraints)) {
|
||||
out = &nameConstraints;
|
||||
} else if (extnID.MatchRest(id_ce_certificatePolicies)) {
|
||||
out = &certificatePolicies;
|
||||
} else if (extnID.MatchRest(id_ce_policyConstraints)) {
|
||||
out = &dummyPolicyConstraints;
|
||||
} else if (extnID.MatchRest(id_ce_extKeyUsage)) {
|
||||
out = &extKeyUsage;
|
||||
} else if (extnID.MatchRest(id_ce_inhibitAnyPolicy)) {
|
||||
out = &inhibitAnyPolicy;
|
||||
} else if (extnID.MatchRest(id_pe_authorityInfoAccess)) {
|
||||
out = &authorityInfoAccess;
|
||||
}
|
||||
|
||||
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 der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||
}
|
||||
if (out->len != 0) {
|
||||
// Duplicate extension
|
||||
return der::Fail(SEC_ERROR_EXTENSION_VALUE_INVALID);
|
||||
}
|
||||
*out = extnValue;
|
||||
understood = true;
|
||||
}
|
||||
|
||||
return der::Success;
|
||||
}
|
||||
|
||||
} } // namespace mozilla::pkix
|
@ -33,36 +33,33 @@
|
||||
namespace mozilla { namespace pkix {
|
||||
|
||||
Result
|
||||
CheckTimes(const CERTValidity& validity, PRTime time)
|
||||
CheckValidity(const SECItem& encodedValidity, PRTime time)
|
||||
{
|
||||
der::Input notBeforeInput;
|
||||
if (notBeforeInput.Init(validity.notBefore.data, validity.notBefore.len)
|
||||
der::Input validity;
|
||||
if (validity.Init(encodedValidity.data, encodedValidity.len)
|
||||
!= der::Success) {
|
||||
return Fail(RecoverableError, SEC_ERROR_EXPIRED_CERTIFICATE);
|
||||
}
|
||||
PRTime notBefore;
|
||||
if (der::TimeChoice(validity.notBefore.type, notBeforeInput, notBefore)
|
||||
!= der::Success) {
|
||||
if (der::TimeChoice(validity, notBefore) != der::Success) {
|
||||
return Fail(RecoverableError, SEC_ERROR_EXPIRED_CERTIFICATE);
|
||||
}
|
||||
if (time < notBefore) {
|
||||
return Fail(RecoverableError, SEC_ERROR_EXPIRED_CERTIFICATE);
|
||||
}
|
||||
|
||||
der::Input notAfterInput;
|
||||
if (notAfterInput.Init(validity.notAfter.data, validity.notAfter.len)
|
||||
!= der::Success) {
|
||||
return Fail(RecoverableError, SEC_ERROR_EXPIRED_CERTIFICATE);
|
||||
}
|
||||
PRTime notAfter;
|
||||
if (der::TimeChoice(validity.notAfter.type, notAfterInput, notAfter)
|
||||
!= der::Success) {
|
||||
if (der::TimeChoice(validity, notAfter) != der::Success) {
|
||||
return Fail(RecoverableError, SEC_ERROR_EXPIRED_CERTIFICATE);
|
||||
}
|
||||
if (time > notAfter) {
|
||||
return Fail(RecoverableError, SEC_ERROR_EXPIRED_CERTIFICATE);
|
||||
}
|
||||
|
||||
if (der::End(validity) != der::Success) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
|
||||
return Success;
|
||||
}
|
||||
|
||||
@ -408,7 +405,7 @@ CheckBasicConstraints(EndEntityOrCA endEntityOrCA,
|
||||
Result
|
||||
CheckNameConstraints(const BackCert& cert)
|
||||
{
|
||||
if (!cert.encodedNameConstraints) {
|
||||
if (!cert.GetNameConstraints()) {
|
||||
return Success;
|
||||
}
|
||||
|
||||
@ -419,7 +416,7 @@ CheckNameConstraints(const BackCert& cert)
|
||||
|
||||
// Owned by arena
|
||||
const CERTNameConstraints* constraints =
|
||||
CERT_DecodeNameConstraintsExtension(arena.get(), cert.encodedNameConstraints);
|
||||
CERT_DecodeNameConstraintsExtension(arena.get(), cert.GetNameConstraints());
|
||||
if (!constraints) {
|
||||
return MapSECStatus(SECFailure);
|
||||
}
|
||||
@ -619,7 +616,7 @@ CheckExtendedKeyUsage(EndEntityOrCA endEntityOrCA,
|
||||
|
||||
Result
|
||||
CheckIssuerIndependentProperties(TrustDomain& trustDomain,
|
||||
BackCert& cert,
|
||||
const BackCert& cert,
|
||||
PRTime time,
|
||||
EndEntityOrCA endEntityOrCA,
|
||||
KeyUsage requiredKeyUsageIfPresent,
|
||||
@ -654,15 +651,15 @@ CheckIssuerIndependentProperties(TrustDomain& trustDomain,
|
||||
// 4.2.1.2. Subject Key Identifier is ignored (see bug 965136).
|
||||
|
||||
// 4.2.1.3. Key Usage
|
||||
rv = CheckKeyUsage(endEntityOrCA, cert.encodedKeyUsage,
|
||||
rv = CheckKeyUsage(endEntityOrCA, cert.GetKeyUsage(),
|
||||
requiredKeyUsageIfPresent);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
||||
// 4.2.1.4. Certificate Policies
|
||||
rv = CheckCertificatePolicies(endEntityOrCA, cert.encodedCertificatePolicies,
|
||||
cert.encodedInhibitAnyPolicy, trustLevel,
|
||||
rv = CheckCertificatePolicies(endEntityOrCA, cert.GetCertificatePolicies(),
|
||||
cert.GetInhibitAnyPolicy(), trustLevel,
|
||||
requiredPolicy);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
@ -680,8 +677,8 @@ CheckIssuerIndependentProperties(TrustDomain& trustDomain,
|
||||
// checking.
|
||||
|
||||
// 4.2.1.9. Basic Constraints.
|
||||
rv = CheckBasicConstraints(endEntityOrCA, cert.encodedBasicConstraints,
|
||||
cert.version, trustLevel, subCACount);
|
||||
rv = CheckBasicConstraints(endEntityOrCA, cert.GetBasicConstraints(),
|
||||
cert.GetVersion(), trustLevel, subCACount);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
@ -692,7 +689,7 @@ CheckIssuerIndependentProperties(TrustDomain& trustDomain,
|
||||
// documentation about policy enforcement in pkix.h.
|
||||
|
||||
// 4.2.1.12. Extended Key Usage
|
||||
rv = CheckExtendedKeyUsage(endEntityOrCA, cert.encodedExtendedKeyUsage,
|
||||
rv = CheckExtendedKeyUsage(endEntityOrCA, cert.GetExtKeyUsage(),
|
||||
requiredEKUIfPresent);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
@ -707,7 +704,7 @@ CheckIssuerIndependentProperties(TrustDomain& trustDomain,
|
||||
|
||||
// IMPORTANT: This check must come after the other checks in order for error
|
||||
// ranking to work correctly.
|
||||
rv = CheckTimes(cert.GetNSSCert()->validity, time);
|
||||
rv = CheckValidity(cert.GetValidity(), time);
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
|
@ -33,7 +33,7 @@ namespace mozilla { namespace pkix {
|
||||
|
||||
Result CheckIssuerIndependentProperties(
|
||||
TrustDomain& trustDomain,
|
||||
BackCert& cert,
|
||||
const BackCert& cert,
|
||||
PRTime time,
|
||||
EndEntityOrCA endEntityOrCA,
|
||||
KeyUsage requiredKeyUsageIfPresent,
|
||||
|
@ -174,26 +174,33 @@ daysBeforeYear(int year)
|
||||
+ ((year - 1) / 400); // except years divisible by 400.
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
// We parse GeneralizedTime and UTCTime according to RFC 5280 and we do not
|
||||
// accept all time formats allowed in the ASN.1 spec. That is,
|
||||
// GeneralizedTime must always be in the format YYYYMMDDHHMMSSZ and UTCTime
|
||||
// must always be in the format YYMMDDHHMMSSZ. Timezone formats of the form
|
||||
// +HH:MM or -HH:MM or NOT accepted.
|
||||
Result
|
||||
TimeChoice(SECItemType type, Input& input, /*out*/ PRTime& time)
|
||||
TimeChoice(Input& tagged, uint8_t expectedTag, /*out*/ PRTime& time)
|
||||
{
|
||||
int days;
|
||||
|
||||
Input input;
|
||||
if (ExpectTagAndGetValue(tagged, expectedTag, input) != Success) {
|
||||
return Failure;
|
||||
}
|
||||
|
||||
int yearHi;
|
||||
int yearLo;
|
||||
if (type == siGeneralizedTime) {
|
||||
if (expectedTag == GENERALIZED_TIME) {
|
||||
if (ReadTwoDigits(input, 0, 99, yearHi) != Success) {
|
||||
return Failure;
|
||||
}
|
||||
if (ReadTwoDigits(input, 0, 99, yearLo) != Success) {
|
||||
return Failure;
|
||||
}
|
||||
} else if (type == siUTCTime) {
|
||||
} else if (expectedTag == UTCTime) {
|
||||
if (ReadTwoDigits(input, 0, 99, yearLo) != Success) {
|
||||
return Failure;
|
||||
}
|
||||
@ -305,4 +312,6 @@ TimeChoice(SECItemType type, Input& input, /*out*/ PRTime& time)
|
||||
return Success;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
|
||||
} } } // namespace mozilla::pkix::der
|
||||
|
@ -513,33 +513,35 @@ Enumerated(Input& input, uint8_t& value)
|
||||
return internal::IntegralValue(input, ENUMERATED | 0, value);
|
||||
}
|
||||
|
||||
// XXX: This function should have the signature:
|
||||
//
|
||||
// Result TimeChoice(Input& input, /*out*/ PRTime& time);
|
||||
//
|
||||
// and parse the tag (and length and value) from the input like the other
|
||||
// functions here. However, currently we get TimeChoices already partially
|
||||
// decoded by NSS, so for now we'll have this signature, where the input
|
||||
// parameter contains the value of the time choice.
|
||||
//
|
||||
// type must be either siGeneralizedTime or siUTCTime.
|
||||
namespace internal {
|
||||
|
||||
// internal::TimeChoice implements the shared functionality of GeneralizedTime
|
||||
// and TimeChoice. tag must be either UTCTime or GENERALIZED_TIME.
|
||||
//
|
||||
// Only times from 1970-01-01-00:00:00 onward are accepted, in order to
|
||||
// eliminate the chance for complications in converting times to traditional
|
||||
// time formats that start at 1970.
|
||||
Result TimeChoice(SECItemType type, Input& input, /*out*/ PRTime& time);
|
||||
Result TimeChoice(Input& input, uint8_t tag, /*out*/ PRTime& time);
|
||||
|
||||
} // namespace internal
|
||||
|
||||
// Only times from 1970-01-01-00:00:00 onward are accepted, in order to
|
||||
// eliminate the chance for complications in converting times to traditional
|
||||
// time formats that start at 1970.
|
||||
inline Result
|
||||
GeneralizedTime(Input& input, PRTime& time)
|
||||
GeneralizedTime(Input& input, /*out*/ PRTime& time)
|
||||
{
|
||||
Input value;
|
||||
if (ExpectTagAndGetValue(input, GENERALIZED_TIME, value) != Success) {
|
||||
return Failure;
|
||||
}
|
||||
return TimeChoice(siGeneralizedTime, value, time);
|
||||
return internal::TimeChoice(input, GENERALIZED_TIME, time);
|
||||
}
|
||||
|
||||
// Only times from 1970-01-01-00:00:00 onward are accepted, in order to
|
||||
// eliminate the chance for complications in converting times to traditional
|
||||
// time formats that start at 1970.
|
||||
inline Result
|
||||
TimeChoice(Input& input, /*out*/ PRTime& time)
|
||||
{
|
||||
uint8_t expectedTag = input.Peek(UTCTime) ? UTCTime : GENERALIZED_TIME;
|
||||
return internal::TimeChoice(input, expectedTag, time);
|
||||
}
|
||||
|
||||
// This parser will only parse values between 0..127. If this range is
|
||||
|
@ -35,24 +35,24 @@
|
||||
namespace mozilla { namespace pkix {
|
||||
|
||||
SECStatus
|
||||
VerifySignedData(const CERTSignedData* sd, const SECItem& subjectPublicKeyInfo,
|
||||
VerifySignedData(const CERTSignedData& sd, const SECItem& subjectPublicKeyInfo,
|
||||
void* pkcs11PinArg)
|
||||
{
|
||||
if (!sd || !sd->data.data || !sd->signatureAlgorithm.algorithm.data ||
|
||||
!sd->signature.data) {
|
||||
if (!sd.data.data || !sd.signatureAlgorithm.algorithm.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())) {
|
||||
if (sd.data.len > static_cast<unsigned int>(std::numeric_limits<int>::max())) {
|
||||
PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
|
||||
return SECFailure;
|
||||
}
|
||||
|
||||
// convert sig->len from bit counts to byte count.
|
||||
SECItem sig = sd->signature;
|
||||
SECItem sig = sd.signature;
|
||||
DER_ConvertBitString(&sig);
|
||||
|
||||
ScopedPtr<CERTSubjectPublicKeyInfo, SECKEY_DestroySubjectPublicKeyInfo>
|
||||
@ -67,8 +67,8 @@ VerifySignedData(const CERTSignedData* sd, const SECItem& subjectPublicKeyInfo,
|
||||
}
|
||||
|
||||
SECOidTag hashAlg;
|
||||
if (VFY_VerifyDataWithAlgorithmID(sd->data.data, static_cast<int>(sd->data.len),
|
||||
pubKey.get(), &sig, &sd->signatureAlgorithm,
|
||||
if (VFY_VerifyDataWithAlgorithmID(sd.data.data, static_cast<int>(sd.data.len),
|
||||
pubKey.get(), &sig, &sd.signatureAlgorithm,
|
||||
&hashAlg, pkcs11PinArg) != SECSuccess) {
|
||||
return SECFailure;
|
||||
}
|
||||
|
@ -156,12 +156,17 @@ CheckOCSPResponseSignerCert(TrustDomain& trustDomain,
|
||||
}
|
||||
|
||||
// TODO(bug 926260): check name constraints
|
||||
return potentialSigner.VerifyOwnSignatureWithKey(trustDomain,
|
||||
issuerSubjectPublicKeyInfo);
|
||||
SECStatus srv = trustDomain.VerifySignedData(potentialSigner.GetSignedData(),
|
||||
issuerSubjectPublicKeyInfo);
|
||||
if (srv != SECSuccess) {
|
||||
return MapSECStatus(srv);
|
||||
}
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
MOZILLA_PKIX_ENUM_CLASS ResponderIDType : uint8_t
|
||||
@ -233,7 +238,7 @@ VerifyOCSPSignedData(TrustDomain& trustDomain,
|
||||
const CERTSignedData& signedResponseData,
|
||||
const SECItem& spki)
|
||||
{
|
||||
SECStatus srv(trustDomain.VerifySignedData(&signedResponseData, 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);
|
||||
@ -267,8 +272,8 @@ VerifySignature(Context& context, ResponderIDType responderIDType,
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < numCerts; ++i) {
|
||||
BackCert cert(nullptr, BackCert::IncludeCN::No);
|
||||
rv = cert.Init(certs[i]);
|
||||
BackCert cert(certs[i], nullptr, BackCert::IncludeCN::No);
|
||||
rv = cert.Init();
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
@ -314,7 +319,7 @@ SECStatus
|
||||
VerifyEncodedOCSPResponse(TrustDomain& trustDomain, const struct CertID& certID,
|
||||
PRTime time, uint16_t maxOCSPLifetimeInDays,
|
||||
const SECItem& encodedResponse,
|
||||
bool& expired,
|
||||
/*out*/ bool& expired,
|
||||
/*optional out*/ PRTime* thisUpdate,
|
||||
/*optional out*/ PRTime* validThrough)
|
||||
{
|
||||
@ -444,7 +449,7 @@ BasicResponse(der::Input& input, Context& context)
|
||||
|
||||
// [0] wrapper
|
||||
if (der::ExpectTagAndSkipLength(
|
||||
input, der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 0)
|
||||
input, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0)
|
||||
!= der::Success) {
|
||||
return der::Failure;
|
||||
}
|
||||
|
@ -95,56 +95,110 @@ public:
|
||||
// constraint enforcement will consider the subject CN as a possible dNSName.
|
||||
MOZILLA_PKIX_ENUM_CLASS IncludeCN { No = 0, Yes = 1 };
|
||||
|
||||
// nssCert and childCert must be valid for the lifetime of BackCert
|
||||
BackCert(BackCert* childCert, IncludeCN includeCN)
|
||||
: encodedAuthorityInfoAccess(nullptr)
|
||||
, encodedBasicConstraints(nullptr)
|
||||
, encodedCertificatePolicies(nullptr)
|
||||
, encodedExtendedKeyUsage(nullptr)
|
||||
, encodedKeyUsage(nullptr)
|
||||
, encodedNameConstraints(nullptr)
|
||||
, encodedInhibitAnyPolicy(nullptr)
|
||||
// certDER and childCert must be valid for the lifetime of BackCert.
|
||||
BackCert(const SECItem& certDER, const BackCert* childCert,
|
||||
IncludeCN includeCN)
|
||||
: der(certDER)
|
||||
, childCert(childCert)
|
||||
, includeCN(includeCN)
|
||||
{
|
||||
}
|
||||
|
||||
Result Init(const SECItem& certDER);
|
||||
Result Init();
|
||||
|
||||
const SECItem& GetDER() const { return nssCert->derCert; }
|
||||
const SECItem& GetIssuer() const { return nssCert->derIssuer; }
|
||||
const SECItem& GetSerialNumber() const { return nssCert->serialNumber; }
|
||||
const SECItem& GetSubject() const { return nssCert->derSubject; }
|
||||
const SECItem& GetDER() const { return der; }
|
||||
const der::Version GetVersion() const { return version; }
|
||||
const CERTSignedData& GetSignedData() const { return signedData; }
|
||||
const SECItem& GetIssuer() const { return issuer; }
|
||||
// XXX: "validity" is a horrible name for the structure that holds
|
||||
// notBefore & notAfter, but that is the name used in RFC 5280 and we use the
|
||||
// RFC 5280 names for everything.
|
||||
const SECItem& GetValidity() const { return validity; }
|
||||
const SECItem& GetSerialNumber() const { return serialNumber; }
|
||||
const SECItem& GetSubject() const { return subject; }
|
||||
const SECItem& GetSubjectPublicKeyInfo() const
|
||||
{
|
||||
return nssCert->derPublicKey;
|
||||
return subjectPublicKeyInfo;
|
||||
}
|
||||
const SECItem* GetAuthorityInfoAccess() const
|
||||
{
|
||||
return MaybeSECItem(authorityInfoAccess);
|
||||
}
|
||||
const SECItem* GetBasicConstraints() const
|
||||
{
|
||||
return MaybeSECItem(basicConstraints);
|
||||
}
|
||||
const SECItem* GetCertificatePolicies() const
|
||||
{
|
||||
return MaybeSECItem(certificatePolicies);
|
||||
}
|
||||
const SECItem* GetExtKeyUsage() const { return MaybeSECItem(extKeyUsage); }
|
||||
const SECItem* GetKeyUsage() const { return MaybeSECItem(keyUsage); }
|
||||
const SECItem* GetInhibitAnyPolicy() const
|
||||
{
|
||||
return MaybeSECItem(inhibitAnyPolicy);
|
||||
}
|
||||
const SECItem* GetNameConstraints() const
|
||||
{
|
||||
return MaybeSECItem(nameConstraints);
|
||||
}
|
||||
|
||||
Result VerifyOwnSignatureWithKey(TrustDomain& trustDomain,
|
||||
const SECItem& subjectPublicKeyInfo) const;
|
||||
private:
|
||||
const SECItem& der;
|
||||
|
||||
der::Version version;
|
||||
|
||||
const SECItem* encodedAuthorityInfoAccess;
|
||||
const SECItem* encodedBasicConstraints;
|
||||
const SECItem* encodedCertificatePolicies;
|
||||
const SECItem* encodedExtendedKeyUsage;
|
||||
const SECItem* encodedKeyUsage;
|
||||
const SECItem* encodedNameConstraints;
|
||||
const SECItem* encodedInhibitAnyPolicy;
|
||||
|
||||
BackCert* const childCert;
|
||||
public:
|
||||
BackCert const* const childCert;
|
||||
const IncludeCN includeCN;
|
||||
|
||||
// Only non-const so that we can pass this to TrustDomain::IsRevoked,
|
||||
// which only takes a non-const pointer because VerifyEncodedOCSPResponse
|
||||
// requires it, and that is only because the implementation of
|
||||
// VerifyEncodedOCSPResponse does a CERT_DupCertificate. TODO: get rid
|
||||
// of that CERT_DupCertificate so that we can make all these things const.
|
||||
/*const*/ CERTCertificate* GetNSSCert() const { return nssCert.get(); }
|
||||
|
||||
private:
|
||||
ScopedCERTCertificate nssCert;
|
||||
der::Version version;
|
||||
|
||||
// When parsing certificates in BackCert::Init, we don't accept empty
|
||||
// extensions. Consequently, we don't have to store a distinction between
|
||||
// empty extensions and extensions that weren't included. However, when
|
||||
// *processing* extensions, we distinguish between whether an extension was
|
||||
// included or not based on whetehr the GetXXX function for the extension
|
||||
// returns nullptr.
|
||||
static inline const SECItem* MaybeSECItem(const SECItem& item)
|
||||
{
|
||||
return item.len > 0 ? &item : nullptr;
|
||||
}
|
||||
|
||||
// Helper classes to zero-initialize these fields on construction and to
|
||||
// document that they contain non-owning pointers to the data they point
|
||||
// to.
|
||||
struct NonOwningSECItem : public SECItemStr {
|
||||
NonOwningSECItem()
|
||||
{
|
||||
data = nullptr;
|
||||
len = 0;
|
||||
}
|
||||
};
|
||||
struct NonOwningCERTSignedData : public CERTSignedDataStr {
|
||||
NonOwningCERTSignedData() { memset(this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
NonOwningCERTSignedData signedData;
|
||||
NonOwningSECItem issuer;
|
||||
// XXX: "validity" is a horrible name for the structure that holds
|
||||
// notBefore & notAfter, but that is the name used in RFC 5280 and we use the
|
||||
// RFC 5280 names for everything.
|
||||
NonOwningSECItem validity;
|
||||
NonOwningSECItem serialNumber;
|
||||
NonOwningSECItem subject;
|
||||
NonOwningSECItem subjectPublicKeyInfo;
|
||||
|
||||
NonOwningSECItem authorityInfoAccess;
|
||||
NonOwningSECItem basicConstraints;
|
||||
NonOwningSECItem certificatePolicies;
|
||||
NonOwningSECItem extKeyUsage;
|
||||
NonOwningSECItem inhibitAnyPolicy;
|
||||
NonOwningSECItem keyUsage;
|
||||
NonOwningSECItem nameConstraints;
|
||||
NonOwningSECItem subjectAltName;
|
||||
|
||||
der::Result RememberExtension(der::Input& extnID, const SECItem& extnValue,
|
||||
/*out*/ bool& understood);
|
||||
|
||||
BackCert(const BackCert&) /* = delete */;
|
||||
void operator=(const BackCert&); /* = delete */;
|
||||
|
@ -7,6 +7,7 @@
|
||||
SOURCES += [
|
||||
'lib/pkixbind.cpp',
|
||||
'lib/pkixbuild.cpp',
|
||||
'lib/pkixcert.cpp',
|
||||
'lib/pkixcheck.cpp',
|
||||
'lib/pkixder.cpp',
|
||||
'lib/pkixkey.cpp',
|
||||
|
@ -12,7 +12,7 @@ SOURCES += [
|
||||
'pkix_cert_extension_tests.cpp',
|
||||
'pkix_ocsp_request_tests.cpp',
|
||||
'pkixcheck_CheckKeyUsage_tests.cpp',
|
||||
'pkixcheck_CheckTimes_tests.cpp',
|
||||
'pkixcheck_CheckValidity_tests.cpp',
|
||||
'pkixder_input_tests.cpp',
|
||||
'pkixder_pki_types_tests.cpp',
|
||||
'pkixder_universal_types_tests.cpp',
|
||||
|
@ -135,7 +135,7 @@ private:
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus VerifySignedData(const CERTSignedData* signedData,
|
||||
SECStatus VerifySignedData(const CERTSignedData& signedData,
|
||||
const SECItem& subjectPublicKeyInfo)
|
||||
{
|
||||
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
|
||||
@ -188,7 +188,8 @@ protected:
|
||||
TEST_F(pkix_cert_chain_length, MaxAcceptableCertChainLength)
|
||||
{
|
||||
ScopedCERTCertList results;
|
||||
ASSERT_SECSuccess(BuildCertChain(trustDomain, trustDomain.GetLeafeCACert(),
|
||||
ASSERT_SECSuccess(BuildCertChain(trustDomain,
|
||||
trustDomain.GetLeafeCACert()->derCert,
|
||||
now, EndEntityOrCA::MustBeCA,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
@ -203,7 +204,7 @@ TEST_F(pkix_cert_chain_length, MaxAcceptableCertChainLength)
|
||||
"CN=Direct End-Entity",
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
trustDomain.leafCAKey.get(), privateKey, cert));
|
||||
ASSERT_SECSuccess(BuildCertChain(trustDomain, cert.get(), now,
|
||||
ASSERT_SECSuccess(BuildCertChain(trustDomain, cert->derCert, now,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
@ -225,7 +226,7 @@ TEST_F(pkix_cert_chain_length, BeyondMaxAcceptableCertChainLength)
|
||||
caPrivateKey, caCert));
|
||||
PR_SetError(0, 0);
|
||||
ASSERT_SECFailure(SEC_ERROR_UNKNOWN_ISSUER,
|
||||
BuildCertChain(trustDomain, caCert.get(), now,
|
||||
BuildCertChain(trustDomain, caCert->derCert, now,
|
||||
EndEntityOrCA::MustBeCA,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
@ -241,7 +242,7 @@ TEST_F(pkix_cert_chain_length, BeyondMaxAcceptableCertChainLength)
|
||||
caPrivateKey.get(), privateKey, cert));
|
||||
PR_SetError(0, 0);
|
||||
ASSERT_SECFailure(SEC_ERROR_UNKNOWN_ISSUER,
|
||||
BuildCertChain(trustDomain, cert.get(), now,
|
||||
BuildCertChain(trustDomain, cert->derCert, now,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
|
@ -30,43 +30,43 @@ using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
// Creates a self-signed certificate with the given extension.
|
||||
static bool
|
||||
static const SECItem*
|
||||
CreateCert(PLArenaPool* arena, const char* subjectStr,
|
||||
const SECItem* extension,
|
||||
/*out*/ ScopedSECKEYPrivateKey& subjectKey,
|
||||
/*out*/ ScopedCERTCertificate& subjectCert)
|
||||
SECItem const* const* extensions, // null-terminated array
|
||||
/*out*/ ScopedSECKEYPrivateKey& subjectKey)
|
||||
{
|
||||
static long serialNumberValue = 0;
|
||||
++serialNumberValue;
|
||||
const SECItem* serialNumber(CreateEncodedSerialNumber(arena,
|
||||
serialNumberValue));
|
||||
if (!serialNumber) {
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
const SECItem* issuerDER(ASCIIToDERName(arena, subjectStr));
|
||||
if (!issuerDER) {
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
const SECItem* subjectDER(ASCIIToDERName(arena, subjectStr));
|
||||
if (!subjectDER) {
|
||||
return false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const SECItem* extensions[2] = { extension, nullptr };
|
||||
return CreateEncodedCertificate(arena, v3, SEC_OID_SHA256,
|
||||
serialNumber, issuerDER,
|
||||
PR_Now() - ONE_DAY,
|
||||
PR_Now() + ONE_DAY,
|
||||
subjectDER, extensions,
|
||||
nullptr, SEC_OID_SHA256, subjectKey);
|
||||
}
|
||||
|
||||
SECItem* certDER(CreateEncodedCertificate(arena, v3, SEC_OID_SHA256,
|
||||
serialNumber, issuerDER,
|
||||
PR_Now() - ONE_DAY,
|
||||
PR_Now() + ONE_DAY,
|
||||
subjectDER, extensions,
|
||||
nullptr, SEC_OID_SHA256,
|
||||
subjectKey));
|
||||
if (!certDER) {
|
||||
return false;
|
||||
}
|
||||
subjectCert = CERT_NewTempCertificate(CERT_GetDefaultCertDB(), certDER,
|
||||
nullptr, false, true);
|
||||
return subjectCert.get() != nullptr;
|
||||
// Creates a self-signed certificate with the given extension.
|
||||
static const SECItem*
|
||||
CreateCert(PLArenaPool* arena, const char* subjectStr,
|
||||
const SECItem* extension,
|
||||
/*out*/ ScopedSECKEYPrivateKey& subjectKey)
|
||||
{
|
||||
const SECItem * extensions[] = { extension, nullptr };
|
||||
return CreateCert(arena, subjectStr, extensions, subjectKey);
|
||||
}
|
||||
|
||||
class TrustEverythingTrustDomain : public TrustDomain
|
||||
@ -88,7 +88,7 @@ private:
|
||||
return SECSuccess;
|
||||
}
|
||||
|
||||
SECStatus VerifySignedData(const CERTSignedData* signedData,
|
||||
SECStatus VerifySignedData(const CERTSignedData& signedData,
|
||||
const SECItem& subjectPublicKeyInfo)
|
||||
{
|
||||
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
|
||||
@ -143,13 +143,14 @@ TEST_F(pkix_cert_extensions, UnknownCriticalExtension)
|
||||
};
|
||||
const char* certCN = "CN=Cert With Unknown Critical Extension";
|
||||
ScopedSECKEYPrivateKey key;
|
||||
ScopedCERTCertificate cert;
|
||||
ASSERT_TRUE(CreateCert(arena.get(), certCN, &unknownCriticalExtension, key,
|
||||
cert));
|
||||
// cert is owned by the arena
|
||||
const SECItem* cert(CreateCert(arena.get(), certCN,
|
||||
&unknownCriticalExtension, key));
|
||||
ASSERT_TRUE(cert);
|
||||
ScopedCERTCertList results;
|
||||
ASSERT_SECFailure(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION,
|
||||
BuildCertChain(trustDomain, cert.get(),
|
||||
now, EndEntityOrCA::MustBeEndEntity,
|
||||
BuildCertChain(trustDomain, *cert, now,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
CertPolicyId::anyPolicy,
|
||||
@ -176,12 +177,13 @@ TEST_F(pkix_cert_extensions, UnknownNonCriticalExtension)
|
||||
};
|
||||
const char* certCN = "CN=Cert With Unknown NonCritical Extension";
|
||||
ScopedSECKEYPrivateKey key;
|
||||
ScopedCERTCertificate cert;
|
||||
ASSERT_TRUE(CreateCert(arena.get(), certCN, &unknownNonCriticalExtension, key,
|
||||
cert));
|
||||
// cert is owned by the arena
|
||||
const SECItem* cert(CreateCert(arena.get(), certCN,
|
||||
&unknownNonCriticalExtension, key));
|
||||
ASSERT_TRUE(cert);
|
||||
ScopedCERTCertList results;
|
||||
ASSERT_SECSuccess(BuildCertChain(trustDomain, cert.get(),
|
||||
now, EndEntityOrCA::MustBeEndEntity,
|
||||
ASSERT_SECSuccess(BuildCertChain(trustDomain, *cert, now,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
CertPolicyId::anyPolicy,
|
||||
@ -209,13 +211,14 @@ TEST_F(pkix_cert_extensions, WrongOIDCriticalExtension)
|
||||
};
|
||||
const char* certCN = "CN=Cert With Critical Wrong OID Extension";
|
||||
ScopedSECKEYPrivateKey key;
|
||||
ScopedCERTCertificate cert;
|
||||
ASSERT_TRUE(CreateCert(arena.get(), certCN, &wrongOIDCriticalExtension, key,
|
||||
cert));
|
||||
// cert is owned by the arena
|
||||
const SECItem* cert(CreateCert(arena.get(), certCN,
|
||||
&wrongOIDCriticalExtension, key));
|
||||
ASSERT_TRUE(cert);
|
||||
ScopedCERTCertList results;
|
||||
ASSERT_SECFailure(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION,
|
||||
BuildCertChain(trustDomain, cert.get(),
|
||||
now, EndEntityOrCA::MustBeEndEntity,
|
||||
BuildCertChain(trustDomain, *cert, now,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
CertPolicyId::anyPolicy,
|
||||
@ -245,12 +248,13 @@ TEST_F(pkix_cert_extensions, CriticalAIAExtension)
|
||||
};
|
||||
const char* certCN = "CN=Cert With Critical AIA Extension";
|
||||
ScopedSECKEYPrivateKey key;
|
||||
ScopedCERTCertificate cert;
|
||||
ASSERT_TRUE(CreateCert(arena.get(), certCN, &criticalAIAExtension, key,
|
||||
cert));
|
||||
// cert is owned by the arena
|
||||
const SECItem* cert(CreateCert(arena.get(), certCN, &criticalAIAExtension,
|
||||
key));
|
||||
ASSERT_TRUE(cert);
|
||||
ScopedCERTCertList results;
|
||||
ASSERT_SECSuccess(BuildCertChain(trustDomain, cert.get(),
|
||||
now, EndEntityOrCA::MustBeEndEntity,
|
||||
ASSERT_SECSuccess(BuildCertChain(trustDomain, *cert, now,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
CertPolicyId::anyPolicy,
|
||||
@ -277,13 +281,14 @@ TEST_F(pkix_cert_extensions, UnknownCriticalCEExtension)
|
||||
};
|
||||
const char* certCN = "CN=Cert With Unknown Critical id-ce Extension";
|
||||
ScopedSECKEYPrivateKey key;
|
||||
ScopedCERTCertificate cert;
|
||||
ASSERT_TRUE(CreateCert(arena.get(), certCN, &unknownCriticalCEExtension, key,
|
||||
cert));
|
||||
// cert is owned by the arena
|
||||
const SECItem* cert(CreateCert(arena.get(), certCN,
|
||||
&unknownCriticalCEExtension, key));
|
||||
ASSERT_TRUE(cert);
|
||||
ScopedCERTCertList results;
|
||||
ASSERT_SECFailure(SEC_ERROR_UNKNOWN_CRITICAL_EXTENSION,
|
||||
BuildCertChain(trustDomain, cert.get(),
|
||||
now, EndEntityOrCA::MustBeEndEntity,
|
||||
BuildCertChain(trustDomain, *cert, now,
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
CertPolicyId::anyPolicy,
|
||||
@ -310,10 +315,46 @@ TEST_F(pkix_cert_extensions, KnownCriticalCEExtension)
|
||||
};
|
||||
const char* certCN = "CN=Cert With Known Critical id-ce Extension";
|
||||
ScopedSECKEYPrivateKey key;
|
||||
ScopedCERTCertificate cert;
|
||||
ASSERT_TRUE(CreateCert(arena.get(), certCN, &criticalCEExtension, key, cert));
|
||||
// cert is owned by the arena
|
||||
const SECItem* cert(CreateCert(arena.get(), certCN, &criticalCEExtension,
|
||||
key));
|
||||
ASSERT_TRUE(cert);
|
||||
ScopedCERTCertList results;
|
||||
ASSERT_SECSuccess(BuildCertChain(trustDomain, cert.get(),
|
||||
ASSERT_SECSuccess(BuildCertChain(trustDomain, *cert,
|
||||
now, EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
CertPolicyId::anyPolicy,
|
||||
nullptr, // stapled OCSP response
|
||||
results));
|
||||
}
|
||||
|
||||
// Two subjectAltNames must result in an error.
|
||||
TEST_F(pkix_cert_extensions, DuplicateSubjectAltName)
|
||||
{
|
||||
static const uint8_t DER_BYTES[] = {
|
||||
0x30, 22, // SEQUENCE (length = 22)
|
||||
0x06, 3, // OID (length = 3)
|
||||
0x55, 0x1d, 0x11, // 2.5.29.17
|
||||
0x04, 15, // OCTET STRING (length = 15)
|
||||
0x30, 13, // GeneralNames (SEQUENCE) (length = 13)
|
||||
0x82, 11, // [2] (dNSName) (length = 11)
|
||||
'e', 'x', 'a', 'm', 'p', 'l', 'e', '.', 'c', 'o', 'm'
|
||||
};
|
||||
static const SECItem DER = {
|
||||
siBuffer,
|
||||
const_cast<unsigned char*>(DER_BYTES),
|
||||
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);
|
||||
ScopedCERTCertList results;
|
||||
ASSERT_SECFailure(SEC_ERROR_EXTENSION_VALUE_INVALID,
|
||||
BuildCertChain(trustDomain, *cert,
|
||||
now, EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::anyExtendedKeyUsage,
|
||||
|
@ -1,174 +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"
|
||||
#include "pkixtestutil.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
|
||||
extern Result CheckTimes(const CERTValidity& validity, PRTime time);
|
||||
|
||||
} } // namespace mozilla::pkix
|
||||
|
||||
static const SECItem empty_null = { siBuffer, nullptr, 0 };
|
||||
|
||||
static const PRTime PAST_TIME(YMDHMS(1998, 12, 31, 12, 23, 56));
|
||||
|
||||
static const uint8_t OLDER_GENERALIZEDTIME_DATA[] = {
|
||||
'1', '9', '9', '9', '0', '1', '0', '1', // 1999-01-01
|
||||
'0', '0', '0', '0', '0', '0', 'Z' // 00:00:00Z
|
||||
};
|
||||
static const SECItem OLDER_GENERALIZEDTIME = {
|
||||
siGeneralizedTime,
|
||||
const_cast<uint8_t*>(OLDER_GENERALIZEDTIME_DATA),
|
||||
sizeof(OLDER_GENERALIZEDTIME_DATA)
|
||||
};
|
||||
|
||||
static const uint8_t OLDER_UTCTIME_DATA[] = {
|
||||
'9', '9', '0', '1', '0', '1', // (19)99-01-01
|
||||
'0', '0', '0', '0', '0', '0', 'Z' // 00:00:00Z
|
||||
};
|
||||
static const SECItem OLDER_UTCTIME = {
|
||||
siUTCTime,
|
||||
const_cast<uint8_t*>(OLDER_UTCTIME_DATA),
|
||||
sizeof(OLDER_UTCTIME_DATA)
|
||||
};
|
||||
|
||||
static const PRTime NOW(YMDHMS(2016, 12, 31, 12, 23, 56));
|
||||
|
||||
static const uint8_t NEWER_GENERALIZEDTIME_DATA[] = {
|
||||
'2', '0', '2', '1', '0', '1', '0', '1', // 2021-01-01
|
||||
'0', '0', '0', '0', '0', '0', 'Z' // 00:00:00Z
|
||||
};
|
||||
static const SECItem NEWER_GENERALIZEDTIME = {
|
||||
siGeneralizedTime,
|
||||
const_cast<uint8_t*>(NEWER_GENERALIZEDTIME_DATA),
|
||||
sizeof(NEWER_GENERALIZEDTIME_DATA)
|
||||
};
|
||||
|
||||
static const uint8_t NEWER_UTCTIME_DATA[] = {
|
||||
'2', '1', '0', '1', '0', '1', // 2021-01-01
|
||||
'0', '0', '0', '0', '0', '0', 'Z' // 00:00:00Z
|
||||
};
|
||||
static const SECItem NEWER_UTCTIME = {
|
||||
siUTCTime,
|
||||
const_cast<uint8_t*>(NEWER_UTCTIME_DATA),
|
||||
sizeof(NEWER_UTCTIME_DATA)
|
||||
};
|
||||
|
||||
static const PRTime FUTURE_TIME(YMDHMS(2025, 12, 31, 12, 23, 56));
|
||||
|
||||
|
||||
|
||||
class pkixcheck_CheckTimes : public ::testing::Test
|
||||
{
|
||||
public:
|
||||
virtual void SetUp()
|
||||
{
|
||||
PR_SetError(0, 0);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(pkixcheck_CheckTimes, BothEmptyNull)
|
||||
{
|
||||
static const CERTValidity validity = { nullptr, empty_null, empty_null };
|
||||
ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
|
||||
CheckTimes(validity, NOW));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckTimes, NotBeforeEmptyNull)
|
||||
{
|
||||
static const CERTValidity validity = { nullptr, empty_null, NEWER_UTCTIME };
|
||||
ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
|
||||
CheckTimes(validity, NOW));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckTimes, NotAfterEmptyNull)
|
||||
{
|
||||
static const CERTValidity validity = { nullptr, OLDER_UTCTIME, empty_null };
|
||||
ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
|
||||
CheckTimes(validity, NOW));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckTimes, Valid_UTCTIME_UTCTIME)
|
||||
{
|
||||
static const CERTValidity validity = {
|
||||
nullptr, OLDER_UTCTIME, NEWER_UTCTIME
|
||||
};
|
||||
ASSERT_Success(CheckTimes(validity, NOW));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckTimes, Valid_GENERALIZEDTIME_GENERALIZEDTIME)
|
||||
{
|
||||
static const CERTValidity validity = {
|
||||
nullptr, OLDER_GENERALIZEDTIME, NEWER_GENERALIZEDTIME
|
||||
};
|
||||
ASSERT_Success(CheckTimes(validity, NOW));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckTimes, Valid_GENERALIZEDTIME_UTCTIME)
|
||||
{
|
||||
static const CERTValidity validity = {
|
||||
nullptr, OLDER_GENERALIZEDTIME, NEWER_UTCTIME
|
||||
};
|
||||
ASSERT_Success(CheckTimes(validity, NOW));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckTimes, Valid_UTCTIME_GENERALIZEDTIME)
|
||||
{
|
||||
static const CERTValidity validity = {
|
||||
nullptr, OLDER_UTCTIME, NEWER_GENERALIZEDTIME
|
||||
};
|
||||
ASSERT_Success(CheckTimes(validity, NOW));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckTimes, InvalidBeforeNotBefore)
|
||||
{
|
||||
static const CERTValidity validity = {
|
||||
nullptr, OLDER_UTCTIME, NEWER_UTCTIME
|
||||
};
|
||||
ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
|
||||
CheckTimes(validity, PAST_TIME));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckTimes, InvalidAfterNotAfter)
|
||||
{
|
||||
static const CERTValidity validity = {
|
||||
nullptr, OLDER_UTCTIME, NEWER_UTCTIME
|
||||
};
|
||||
ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
|
||||
CheckTimes(validity, FUTURE_TIME));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckTimes, InvalidNotAfterBeforeNotBefore)
|
||||
{
|
||||
static const CERTValidity validity = {
|
||||
nullptr, NEWER_UTCTIME, OLDER_UTCTIME
|
||||
};
|
||||
ASSERT_RecoverableError(SEC_ERROR_EXPIRED_CERTIFICATE,
|
||||
CheckTimes(validity, NOW));
|
||||
}
|
203
security/pkix/test/gtest/pkixcheck_CheckValidity_tests.cpp
Normal file
203
security/pkix/test/gtest/pkixcheck_CheckValidity_tests.cpp
Normal file
@ -0,0 +1,203 @@
|
||||
/* -*- 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"
|
||||
#include "pkixtestutil.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
namespace mozilla { namespace pkix {
|
||||
|
||||
Result CheckValidity(const SECItem& encodedValidity, PRTime time);
|
||||
|
||||
} } // namespace mozilla::pkix
|
||||
|
||||
static const SECItem empty_null = { siBuffer, nullptr, 0 };
|
||||
|
||||
static const PRTime PAST_TIME(YMDHMS(1998, 12, 31, 12, 23, 56));
|
||||
|
||||
#define OLDER_GENERALIZEDTIME \
|
||||
0x18, 15, /* tag, length */ \
|
||||
'1', '9', '9', '9', '0', '1', '0', '1', /* 1999-01-01 */ \
|
||||
'0', '0', '0', '0', '0', '0', 'Z' /* 00:00:00Z */
|
||||
|
||||
#define OLDER_UTCTIME \
|
||||
0x17, 13, /* tag, length */ \
|
||||
'9', '9', '0', '1', '0', '1', /* (19)99-01-01 */ \
|
||||
'0', '0', '0', '0', '0', '0', 'Z' /* 00:00:00Z */
|
||||
|
||||
static const PRTime NOW(YMDHMS(2016, 12, 31, 12, 23, 56));
|
||||
|
||||
#define NEWER_GENERALIZEDTIME \
|
||||
0x18, 15, /* tag, length */ \
|
||||
'2', '0', '2', '1', '0', '1', '0', '1', /* 2021-01-01 */ \
|
||||
'0', '0', '0', '0', '0', '0', 'Z' /* 00:00:00Z */
|
||||
|
||||
#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);
|
||||
}
|
||||
};
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
TEST_F(pkixcheck_CheckValidity, InvalidBeforeNotBefore)
|
||||
{
|
||||
ASSERT_RecoverableError(SEC_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));
|
||||
}
|
||||
|
||||
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));
|
||||
}
|
@ -332,23 +332,34 @@ TEST_F(pkixder_universal_types_tests, EnumeratedInvalidZeroLength)
|
||||
#define TWO_CHARS(t) static_cast<uint8_t>('0' + ((t) / 10u)), \
|
||||
static_cast<uint8_t>('0' + ((t) % 10u))
|
||||
|
||||
// Given a DER-encoded GeneralizedTime where we want to extract the value, we
|
||||
// need to skip two bytes: the tag and the length.
|
||||
static const uint16_t GT_VALUE_OFFSET = 2;
|
||||
// Calls TimeChoice on the UTCTime variant of the given generalized time.
|
||||
template <uint16_t LENGTH>
|
||||
Result
|
||||
TimeChoiceForEquivalentUTCTime(const uint8_t (&generalizedTimeDER)[LENGTH],
|
||||
/*out*/ PRTime& value)
|
||||
{
|
||||
static_assert(LENGTH >= 4,
|
||||
"TimeChoiceForEquivalentUTCTime input too small");
|
||||
uint8_t utcTimeDER[LENGTH - 2];
|
||||
utcTimeDER[0] = 0x17; // tag UTCTime
|
||||
utcTimeDER[1] = LENGTH - 1/*tag*/ - 1/*value*/ - 2/*century*/;
|
||||
// Copy the value except for the first two digits of the year
|
||||
for (size_t i = 2; i < LENGTH - 2; ++i) {
|
||||
utcTimeDER[i] = generalizedTimeDER[i + 2];
|
||||
}
|
||||
|
||||
// Given a DER-encoded GeneralizedTime where we want to extract the value as
|
||||
// though it were a UTC time, we need to skip four bytes: the tag, the length
|
||||
// and the first two digits of the year.
|
||||
static const uint16_t UTC_VALUE_OFFSET = 4;
|
||||
Input input;
|
||||
if (input.Init(utcTimeDER, sizeof utcTimeDER) != Success) {
|
||||
return Failure;
|
||||
}
|
||||
return TimeChoice(input, value);
|
||||
}
|
||||
|
||||
template <uint16_t LENGTH>
|
||||
void
|
||||
ExpectGoodTime(PRTime expectedValue,
|
||||
const uint8_t (&generalizedTimeDER)[LENGTH])
|
||||
{
|
||||
static_assert(LENGTH >= UTC_VALUE_OFFSET,
|
||||
"ExpectGoodTime requires input at least UTC_VALUE_OFFSET bytes");
|
||||
|
||||
// GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
@ -361,20 +372,17 @@ ExpectGoodTime(PRTime expectedValue,
|
||||
// TimeChoice: GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(generalizedTimeDER + GT_VALUE_OFFSET,
|
||||
LENGTH - GT_VALUE_OFFSET));
|
||||
ASSERT_EQ(Success, input.Init(generalizedTimeDER, LENGTH));
|
||||
PRTime value = 0;
|
||||
ASSERT_EQ(Success, TimeChoice(siGeneralizedTime, input, value));
|
||||
ASSERT_EQ(Success, TimeChoice(input, value));
|
||||
EXPECT_EQ(expectedValue, value);
|
||||
}
|
||||
|
||||
// TimeChoice: UTCTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(generalizedTimeDER + UTC_VALUE_OFFSET,
|
||||
LENGTH - UTC_VALUE_OFFSET));
|
||||
PRTime value = 0;
|
||||
ASSERT_EQ(Success, TimeChoice(siUTCTime, input, value));
|
||||
ASSERT_EQ(Success,
|
||||
TimeChoiceForEquivalentUTCTime(generalizedTimeDER, value));
|
||||
EXPECT_EQ(expectedValue, value);
|
||||
}
|
||||
}
|
||||
@ -383,9 +391,6 @@ template <uint16_t LENGTH>
|
||||
void
|
||||
ExpectBadTime(const uint8_t (&generalizedTimeDER)[LENGTH])
|
||||
{
|
||||
static_assert(LENGTH >= UTC_VALUE_OFFSET,
|
||||
"ExpectBadTime requires input at least UTC_VALUE_OFFSET bytes");
|
||||
|
||||
// GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
@ -398,23 +403,17 @@ ExpectBadTime(const uint8_t (&generalizedTimeDER)[LENGTH])
|
||||
// TimeChoice: GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(generalizedTimeDER + GT_VALUE_OFFSET,
|
||||
LENGTH - GT_VALUE_OFFSET));
|
||||
ASSERT_EQ(Success, input.Init(generalizedTimeDER, LENGTH));
|
||||
PRTime value;
|
||||
ASSERT_EQ(Failure, TimeChoice(siGeneralizedTime, input, value));
|
||||
ASSERT_EQ(Failure, TimeChoice(input, value));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
|
||||
}
|
||||
|
||||
// TimeChoice: UTCTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(generalizedTimeDER + UTC_VALUE_OFFSET,
|
||||
LENGTH - UTC_VALUE_OFFSET));
|
||||
PRTime value;
|
||||
ASSERT_EQ(Failure, TimeChoice(siUTCTime, input, value));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
|
||||
ASSERT_EQ(Failure,
|
||||
TimeChoiceForEquivalentUTCTime(generalizedTimeDER, value));
|
||||
}
|
||||
}
|
||||
|
||||
@ -457,18 +456,23 @@ TEST_F(pkixder_universal_types_tests, TimeInvalidZeroLength)
|
||||
ASSERT_EQ(Failure, GeneralizedTime(gt, value));
|
||||
ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
|
||||
|
||||
static const uint8_t dummy[1] = { 'X' };
|
||||
|
||||
// TimeChoice: GeneralizedTime
|
||||
Input tc_gt;
|
||||
ASSERT_EQ(Success, tc_gt.Init(dummy, 0));
|
||||
ASSERT_EQ(Failure, TimeChoice(siGeneralizedTime, tc_gt, value));
|
||||
ASSERT_EQ(Success,
|
||||
tc_gt.Init(DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH,
|
||||
sizeof DER_GENERALIZED_TIME_INVALID_ZERO_LENGTH));
|
||||
ASSERT_EQ(Failure, TimeChoice(tc_gt, value));
|
||||
ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
|
||||
|
||||
// TimeChoice: UTCTime
|
||||
const uint8_t DER_UTCTIME_INVALID_ZERO_LENGTH[] = {
|
||||
0x17, // UTCTime
|
||||
0x00 // Length = 0
|
||||
};
|
||||
Input tc_utc;
|
||||
ASSERT_EQ(Success, tc_utc.Init(dummy, 0));
|
||||
ASSERT_EQ(Failure, TimeChoice(siUTCTime, tc_utc, value));
|
||||
ASSERT_EQ(Success, tc_utc.Init(DER_UTCTIME_INVALID_ZERO_LENGTH,
|
||||
sizeof DER_UTCTIME_INVALID_ZERO_LENGTH));
|
||||
ASSERT_EQ(Failure, TimeChoice(tc_utc, value));
|
||||
ASSERT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
|
||||
}
|
||||
|
||||
@ -494,7 +498,7 @@ TEST_F(pkixder_universal_types_tests, TimeInvalidTruncated)
|
||||
ExpectBadTime(DER_GENERALIZED_TIME_INVALID_TRUNCATED);
|
||||
}
|
||||
|
||||
TEST_F(pkixder_universal_types_tests, GeneralizedTimeNoSeconds)
|
||||
TEST_F(pkixder_universal_types_tests, TimeNoSeconds)
|
||||
{
|
||||
const uint8_t DER_GENERALIZED_TIME_NO_SECONDS[] = {
|
||||
0x18, // Generalized Time
|
||||
@ -559,20 +563,17 @@ TEST_F(pkixder_universal_types_tests, GeneralizedTimeYearValidRange)
|
||||
// TimeChoice: GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER + GT_VALUE_OFFSET,
|
||||
sizeof(DER) - GT_VALUE_OFFSET));
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
|
||||
PRTime value = 0;
|
||||
ASSERT_EQ(Success, TimeChoice(siGeneralizedTime, input, value));
|
||||
ASSERT_EQ(Success, TimeChoice(input, value));
|
||||
EXPECT_EQ(expectedValue, value);
|
||||
}
|
||||
|
||||
// TimeChoice: UTCTime, which is limited to years less than 2049.
|
||||
if (i <= 2049) {
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER + UTC_VALUE_OFFSET,
|
||||
sizeof(DER) - UTC_VALUE_OFFSET));
|
||||
PRTime value = 0;
|
||||
ASSERT_EQ(Success, TimeChoice(siUTCTime, input, value));
|
||||
ASSERT_EQ(Success, TimeChoiceForEquivalentUTCTime(DER, value));
|
||||
EXPECT_EQ(expectedValue, value);
|
||||
}
|
||||
}
|
||||
@ -718,10 +719,9 @@ TEST_F(pkixder_universal_types_tests, TimeMonthFebLeapYear2400)
|
||||
// TimeChoice: GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success, input.Init(DER + GT_VALUE_OFFSET,
|
||||
sizeof(DER) - GT_VALUE_OFFSET));
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
|
||||
PRTime value = 0;
|
||||
ASSERT_EQ(Success, TimeChoice(siGeneralizedTime, input, value));
|
||||
ASSERT_EQ(Success, TimeChoice(input, value));
|
||||
EXPECT_EQ(expectedValue, value);
|
||||
}
|
||||
}
|
||||
@ -760,11 +760,9 @@ TEST_F(pkixder_universal_types_tests, TimeMonthFebNotLeapYear2100)
|
||||
// TimeChoice: GeneralizedTime
|
||||
{
|
||||
Input input;
|
||||
ASSERT_EQ(Success,
|
||||
input.Init(DER + GT_VALUE_OFFSET,
|
||||
sizeof(DER) - GT_VALUE_OFFSET));
|
||||
ASSERT_EQ(Success, input.Init(DER, sizeof(DER)));
|
||||
PRTime value;
|
||||
ASSERT_EQ(Failure, TimeChoice(siGeneralizedTime, input, value));
|
||||
ASSERT_EQ(Failure, TimeChoice(input, value));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
|
||||
}
|
||||
}
|
||||
@ -908,7 +906,7 @@ TEST_F(pkixder_universal_types_tests, TimeInvalidCenturyChar)
|
||||
input.Init(DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR,
|
||||
sizeof DER_GENERALIZED_TIME_INVALID_CENTURY_CHAR));
|
||||
PRTime value = 0;
|
||||
ASSERT_EQ(Failure, TimeChoice(siGeneralizedTime, input, value));
|
||||
ASSERT_EQ(Failure, TimeChoice(input, value));
|
||||
EXPECT_EQ(SEC_ERROR_INVALID_TIME, PR_GetError());
|
||||
}
|
||||
|
||||
|
@ -496,7 +496,7 @@ SignedData(PLArenaPool* arena, const SECItem* tbsData,
|
||||
return nullptr;
|
||||
}
|
||||
certsNested = EncodeNested(arena,
|
||||
der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 0,
|
||||
der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0,
|
||||
certsSequence);
|
||||
if (!certsNested) {
|
||||
return nullptr;
|
||||
@ -745,7 +745,7 @@ TBSCertificate(PLArenaPool* arena, long versionValue,
|
||||
return nullptr;
|
||||
}
|
||||
SECItem* version(EncodeNested(arena,
|
||||
der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 0,
|
||||
der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0,
|
||||
versionInteger));
|
||||
if (!version) {
|
||||
return nullptr;
|
||||
@ -829,7 +829,7 @@ TBSCertificate(PLArenaPool* arena, long versionValue,
|
||||
return nullptr;
|
||||
}
|
||||
SECItem* extensionsWrapped(
|
||||
EncodeNested(arena, der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 3,
|
||||
EncodeNested(arena, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 3,
|
||||
allExtensions));
|
||||
if (!extensions) {
|
||||
return nullptr;
|
||||
@ -1354,7 +1354,7 @@ CertStatus(OCSPResponseContext& context)
|
||||
}
|
||||
// TODO(bug 980536): add support for revocationReason
|
||||
return EncodeNested(context.arena,
|
||||
der::CONSTRUCTED | der::CONTEXT_SPECIFIC | 1,
|
||||
der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1,
|
||||
revocationTime);
|
||||
}
|
||||
default:
|
||||
|
Loading…
Reference in New Issue
Block a user