зеркало из https://github.com/mozilla/gecko-dev.git
bug 1058812 - (3/3) mozilla::pkix: test handling unsupported signature algorithms r=briansmith
This commit is contained in:
Родитель
af214d36f8
Коммит
a052b67f71
|
@ -7,6 +7,7 @@
|
|||
SOURCES += [
|
||||
'pkixbuild_tests.cpp',
|
||||
'pkixcert_extension_tests.cpp',
|
||||
'pkixcert_signature_algorithm_tests.cpp',
|
||||
'pkixcheck_CheckKeyUsage_tests.cpp',
|
||||
'pkixcheck_CheckValidity_tests.cpp',
|
||||
|
||||
|
|
|
@ -0,0 +1,266 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
#include "pkix/pkix.h"
|
||||
#include "pkix/pkixnss.h"
|
||||
#include "pkixgtest.h"
|
||||
#include "pkixtestutil.h"
|
||||
|
||||
using namespace mozilla::pkix;
|
||||
using namespace mozilla::pkix::test;
|
||||
|
||||
static ByteString
|
||||
CreateCert(const char* issuerCN,
|
||||
const char* subjectCN,
|
||||
EndEntityOrCA endEntityOrCA,
|
||||
const ByteString& signatureAlgorithm,
|
||||
/*optional*/ TestKeyPair* issuerKey,
|
||||
/*out*/ ScopedTestKeyPair& subjectKey,
|
||||
/*out*/ ByteString& subjectDER)
|
||||
{
|
||||
static long serialNumberValue = 0;
|
||||
++serialNumberValue;
|
||||
ByteString serialNumber(CreateEncodedSerialNumber(serialNumberValue));
|
||||
EXPECT_FALSE(ENCODING_FAILED(serialNumber));
|
||||
|
||||
ByteString issuerDER(CNToDERName(issuerCN));
|
||||
EXPECT_FALSE(ENCODING_FAILED(issuerDER));
|
||||
subjectDER = CNToDERName(subjectCN);
|
||||
EXPECT_FALSE(ENCODING_FAILED(subjectDER));
|
||||
|
||||
ByteString extensions[2];
|
||||
if (endEntityOrCA == EndEntityOrCA::MustBeCA) {
|
||||
extensions[0] =
|
||||
CreateEncodedBasicConstraints(true, nullptr,
|
||||
ExtensionCriticality::Critical);
|
||||
EXPECT_FALSE(ENCODING_FAILED(extensions[0]));
|
||||
}
|
||||
|
||||
ByteString certDER(CreateEncodedCertificate(v3, signatureAlgorithm,
|
||||
serialNumber,
|
||||
issuerDER, oneDayBeforeNow,
|
||||
oneDayAfterNow, subjectDER,
|
||||
extensions, issuerKey,
|
||||
signatureAlgorithm, subjectKey));
|
||||
EXPECT_FALSE(ENCODING_FAILED(certDER));
|
||||
return certDER;
|
||||
}
|
||||
|
||||
class AlgorithmTestsTrustDomain : public TrustDomain
|
||||
{
|
||||
public:
|
||||
AlgorithmTestsTrustDomain(const ByteString& rootDER,
|
||||
const ByteString& rootSubjectDER,
|
||||
/*optional*/ const ByteString& intDER,
|
||||
/*optional*/ const ByteString& intSubjectDER)
|
||||
: rootDER(rootDER)
|
||||
, rootSubjectDER(rootSubjectDER)
|
||||
, intDER(intDER)
|
||||
, intSubjectDER(intSubjectDER)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
virtual Result GetCertTrust(EndEntityOrCA, const CertPolicyId&,
|
||||
Input candidateCert,
|
||||
/*out*/ TrustLevel& trustLevel)
|
||||
{
|
||||
if (InputEqualsByteString(candidateCert, rootDER)) {
|
||||
trustLevel = TrustLevel::TrustAnchor;
|
||||
} else {
|
||||
trustLevel = TrustLevel::InheritsTrust;
|
||||
}
|
||||
return Success;
|
||||
}
|
||||
|
||||
virtual Result FindIssuer(Input encodedIssuerName, IssuerChecker& checker,
|
||||
Time)
|
||||
{
|
||||
ByteString* issuerDER = nullptr;
|
||||
if (InputEqualsByteString(encodedIssuerName, rootSubjectDER)) {
|
||||
issuerDER = &rootDER;
|
||||
} else if (InputEqualsByteString(encodedIssuerName, intSubjectDER)) {
|
||||
issuerDER = &intDER;
|
||||
} else {
|
||||
// FindIssuer just returns success if it can't find a potential issuer.
|
||||
return Success;
|
||||
}
|
||||
Input issuerCert;
|
||||
Result rv = issuerCert.Init(issuerDER->data(), issuerDER->length());
|
||||
if (rv != Success) {
|
||||
return rv;
|
||||
}
|
||||
bool keepGoing;
|
||||
return checker.Check(issuerCert, nullptr, keepGoing);
|
||||
}
|
||||
|
||||
virtual Result CheckRevocation(EndEntityOrCA, const CertID&, Time,
|
||||
const Input*, const Input*)
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
virtual Result IsChainValid(const DERArray&, Time)
|
||||
{
|
||||
return Success;
|
||||
}
|
||||
|
||||
virtual Result VerifySignedData(const SignedDataWithSignature& signedData,
|
||||
Input subjectPublicKeyInfo)
|
||||
{
|
||||
EXPECT_NE(SignatureAlgorithm::unsupported_algorithm, signedData.algorithm);
|
||||
return ::mozilla::pkix::VerifySignedData(signedData, subjectPublicKeyInfo,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
virtual Result DigestBuf(Input, uint8_t*, size_t)
|
||||
{
|
||||
ADD_FAILURE();
|
||||
return Result::FATAL_ERROR_LIBRARY_FAILURE;
|
||||
}
|
||||
|
||||
virtual Result CheckPublicKey(Input subjectPublicKeyInfo)
|
||||
{
|
||||
return TestCheckPublicKey(subjectPublicKeyInfo);
|
||||
}
|
||||
|
||||
ByteString rootDER;
|
||||
ByteString rootSubjectDER;
|
||||
ByteString intDER;
|
||||
ByteString intSubjectDER;
|
||||
};
|
||||
|
||||
static const ByteString NO_INTERMEDIATE; // empty
|
||||
|
||||
struct ChainValidity
|
||||
{
|
||||
// In general, a certificate is generated for each of these. However, if
|
||||
// optionalIntermediateSignatureAlgorithm is NO_INTERMEDIATE, then only 2
|
||||
// certificates are generated.
|
||||
// The certificate generated for the given rootSignatureAlgorithm is the
|
||||
// trust anchor.
|
||||
ByteString endEntitySignatureAlgorithm;
|
||||
ByteString optionalIntermediateSignatureAlgorithm;
|
||||
ByteString rootSignatureAlgorithm;
|
||||
bool isValid;
|
||||
};
|
||||
|
||||
static const ChainValidity CHAIN_VALIDITY[] =
|
||||
{
|
||||
// The trust anchor may have a signature with an unsupported signature
|
||||
// algorithm.
|
||||
{ sha256WithRSAEncryption,
|
||||
NO_INTERMEDIATE,
|
||||
md5WithRSAEncryption,
|
||||
true
|
||||
},
|
||||
{ sha256WithRSAEncryption,
|
||||
NO_INTERMEDIATE,
|
||||
md2WithRSAEncryption,
|
||||
true
|
||||
},
|
||||
|
||||
// Certificates that are not trust anchors must not have a signature with an
|
||||
// unsupported signature algorithm.
|
||||
{ md5WithRSAEncryption,
|
||||
NO_INTERMEDIATE,
|
||||
sha256WithRSAEncryption,
|
||||
false
|
||||
},
|
||||
{ md2WithRSAEncryption,
|
||||
NO_INTERMEDIATE,
|
||||
sha256WithRSAEncryption,
|
||||
false
|
||||
},
|
||||
{ md2WithRSAEncryption,
|
||||
NO_INTERMEDIATE,
|
||||
md5WithRSAEncryption,
|
||||
false
|
||||
},
|
||||
{ sha256WithRSAEncryption,
|
||||
md5WithRSAEncryption,
|
||||
sha256WithRSAEncryption,
|
||||
false
|
||||
},
|
||||
{ sha256WithRSAEncryption,
|
||||
md2WithRSAEncryption,
|
||||
sha256WithRSAEncryption,
|
||||
false
|
||||
},
|
||||
{ sha256WithRSAEncryption,
|
||||
md2WithRSAEncryption,
|
||||
md5WithRSAEncryption,
|
||||
false
|
||||
},
|
||||
};
|
||||
|
||||
class pkixcert_IsValidChainForAlgorithm
|
||||
: public ::testing::Test
|
||||
, public ::testing::WithParamInterface<ChainValidity>
|
||||
{
|
||||
};
|
||||
|
||||
TEST_P(pkixcert_IsValidChainForAlgorithm, IsValidChainForAlgorithm)
|
||||
{
|
||||
const ChainValidity& chainValidity(GetParam());
|
||||
const char* rootCN = "CN=Root";
|
||||
ScopedTestKeyPair rootKey;
|
||||
ByteString rootSubjectDER;
|
||||
ByteString rootEncoded(
|
||||
CreateCert(rootCN, rootCN, EndEntityOrCA::MustBeCA,
|
||||
chainValidity.rootSignatureAlgorithm,
|
||||
nullptr, rootKey, rootSubjectDER));
|
||||
EXPECT_FALSE(ENCODING_FAILED(rootEncoded));
|
||||
EXPECT_FALSE(ENCODING_FAILED(rootSubjectDER));
|
||||
|
||||
const char* issuerCN = rootCN;
|
||||
TestKeyPair* issuerKey = rootKey.get();
|
||||
|
||||
const char* intermediateCN = "CN=Intermediate";
|
||||
ScopedTestKeyPair intermediateKey;
|
||||
ByteString intermediateSubjectDER;
|
||||
ByteString intermediateEncoded;
|
||||
if (chainValidity.optionalIntermediateSignatureAlgorithm != NO_INTERMEDIATE) {
|
||||
intermediateEncoded =
|
||||
CreateCert(rootCN, intermediateCN, EndEntityOrCA::MustBeCA,
|
||||
chainValidity.optionalIntermediateSignatureAlgorithm,
|
||||
rootKey.get(), intermediateKey, intermediateSubjectDER);
|
||||
EXPECT_FALSE(ENCODING_FAILED(intermediateEncoded));
|
||||
EXPECT_FALSE(ENCODING_FAILED(intermediateSubjectDER));
|
||||
issuerCN = intermediateCN;
|
||||
issuerKey = intermediateKey.get();
|
||||
}
|
||||
|
||||
AlgorithmTestsTrustDomain trustDomain(rootEncoded, rootSubjectDER,
|
||||
intermediateEncoded,
|
||||
intermediateSubjectDER);
|
||||
|
||||
const char* endEntityCN = "CN=End Entity";
|
||||
ScopedTestKeyPair endEntityKey;
|
||||
ByteString endEntitySubjectDER;
|
||||
ByteString endEntityEncoded(
|
||||
CreateCert(issuerCN, endEntityCN, EndEntityOrCA::MustBeEndEntity,
|
||||
chainValidity.endEntitySignatureAlgorithm,
|
||||
issuerKey, endEntityKey, endEntitySubjectDER));
|
||||
EXPECT_FALSE(ENCODING_FAILED(endEntityEncoded));
|
||||
EXPECT_FALSE(ENCODING_FAILED(endEntitySubjectDER));
|
||||
|
||||
Input endEntity;
|
||||
ASSERT_EQ(Success, endEntity.Init(endEntityEncoded.data(),
|
||||
endEntityEncoded.length()));
|
||||
Result expectedResult = chainValidity.isValid
|
||||
? Success
|
||||
: Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
|
||||
ASSERT_EQ(expectedResult,
|
||||
BuildCertChain(trustDomain, endEntity, Now(),
|
||||
EndEntityOrCA::MustBeEndEntity,
|
||||
KeyUsage::noParticularKeyUsageRequired,
|
||||
KeyPurposeId::id_kp_serverAuth,
|
||||
CertPolicyId::anyPolicy, nullptr));
|
||||
}
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(pkixcert_IsValidChainForAlgorithm,
|
||||
pkixcert_IsValidChainForAlgorithm,
|
||||
testing::ValuesIn(CHAIN_VALIDITY));
|
|
@ -416,8 +416,8 @@ TEST_F(pkixder_SignatureAlgorithmIdentifier, Invalid_RSA_With_MD5)
|
|||
Reader reader(input);
|
||||
|
||||
SignatureAlgorithm alg;
|
||||
ASSERT_EQ(Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED,
|
||||
SignatureAlgorithmIdentifier(reader, alg));
|
||||
ASSERT_EQ(Success, SignatureAlgorithmIdentifier(reader, alg));
|
||||
ASSERT_EQ(SignatureAlgorithm::unsupported_algorithm, alg);
|
||||
}
|
||||
|
||||
TEST_F(pkixder_SignatureAlgorithmIdentifier, Invalid_SignatureAlgorithm_SHA256)
|
||||
|
@ -432,8 +432,8 @@ TEST_F(pkixder_SignatureAlgorithmIdentifier, Invalid_SignatureAlgorithm_SHA256)
|
|||
Reader reader(input);
|
||||
|
||||
SignatureAlgorithm alg;
|
||||
ASSERT_EQ(Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED,
|
||||
SignatureAlgorithmIdentifier(reader, alg));
|
||||
ASSERT_EQ(Success, SignatureAlgorithmIdentifier(reader, alg));
|
||||
ASSERT_EQ(SignatureAlgorithm::unsupported_algorithm, alg);
|
||||
}
|
||||
|
||||
} // unnamed namespace
|
||||
|
|
|
@ -239,11 +239,12 @@ public:
|
|||
ByteString CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::CertStatus certStatus,
|
||||
const CertID& certID,
|
||||
/*optional*/ const char* signerName,
|
||||
/*optional*/ const char* signerName,
|
||||
const TestKeyPair& signerKeyPair,
|
||||
time_t producedAt, time_t thisUpdate,
|
||||
/*optional*/ const time_t* nextUpdate,
|
||||
/*optional*/ const ByteString* certs = nullptr)
|
||||
/*optional*/ const time_t* nextUpdate,
|
||||
const ByteString& signatureAlgorithm,
|
||||
/*optional*/ const ByteString* certs = nullptr)
|
||||
{
|
||||
OCSPResponseContext context(certID, producedAt);
|
||||
if (signerName) {
|
||||
|
@ -254,6 +255,7 @@ public:
|
|||
EXPECT_TRUE(context.signerKeyPair);
|
||||
context.responseStatus = OCSPResponseContext::successful;
|
||||
context.producedAt = producedAt;
|
||||
context.signatureAlgorithm = signatureAlgorithm;
|
||||
context.certs = certs;
|
||||
|
||||
context.certStatus = certStatus;
|
||||
|
@ -271,7 +273,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_successful, good_byKey)
|
|||
CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID, byKey,
|
||||
*rootKeyPair, oneDayBeforeNow,
|
||||
oneDayBeforeNow, &oneDayAfterNow));
|
||||
oneDayBeforeNow, &oneDayAfterNow,
|
||||
sha256WithRSAEncryption));
|
||||
Input response;
|
||||
ASSERT_EQ(Success,
|
||||
response.Init(responseString.data(), responseString.length()));
|
||||
|
@ -289,7 +292,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_successful, good_byName)
|
|||
CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID, rootName,
|
||||
*rootKeyPair, oneDayBeforeNow,
|
||||
oneDayBeforeNow, &oneDayAfterNow));
|
||||
oneDayBeforeNow, &oneDayAfterNow,
|
||||
sha256WithRSAEncryption));
|
||||
Input response;
|
||||
ASSERT_EQ(Success,
|
||||
response.Init(responseString.data(), responseString.length()));
|
||||
|
@ -307,7 +311,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_successful, good_byKey_without_nextUpdate)
|
|||
CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID, byKey,
|
||||
*rootKeyPair, oneDayBeforeNow,
|
||||
oneDayBeforeNow, nullptr));
|
||||
oneDayBeforeNow, nullptr,
|
||||
sha256WithRSAEncryption));
|
||||
Input response;
|
||||
ASSERT_EQ(Success,
|
||||
response.Init(responseString.data(), responseString.length()));
|
||||
|
@ -325,7 +330,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_successful, revoked)
|
|||
CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::revoked, *endEntityCertID, byKey,
|
||||
*rootKeyPair, oneDayBeforeNow,
|
||||
oneDayBeforeNow, &oneDayAfterNow));
|
||||
oneDayBeforeNow, &oneDayAfterNow,
|
||||
sha256WithRSAEncryption));
|
||||
Input response;
|
||||
ASSERT_EQ(Success,
|
||||
response.Init(responseString.data(), responseString.length()));
|
||||
|
@ -343,7 +349,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_successful, unknown)
|
|||
CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::unknown, *endEntityCertID, byKey,
|
||||
*rootKeyPair, oneDayBeforeNow,
|
||||
oneDayBeforeNow, &oneDayAfterNow));
|
||||
oneDayBeforeNow, &oneDayAfterNow,
|
||||
sha256WithRSAEncryption));
|
||||
Input response;
|
||||
ASSERT_EQ(Success,
|
||||
response.Init(responseString.data(), responseString.length()));
|
||||
|
@ -355,6 +362,26 @@ TEST_F(pkixocsp_VerifyEncodedResponse_successful, unknown)
|
|||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
TEST_F(pkixocsp_VerifyEncodedResponse_successful,
|
||||
good_unsupportedSignatureAlgorithm)
|
||||
{
|
||||
ByteString responseString(
|
||||
CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID, byKey,
|
||||
*rootKeyPair, oneDayBeforeNow,
|
||||
oneDayBeforeNow, &oneDayAfterNow,
|
||||
md5WithRSAEncryption));
|
||||
Input response;
|
||||
ASSERT_EQ(Success,
|
||||
response.Init(responseString.data(), responseString.length()));
|
||||
bool expired;
|
||||
ASSERT_EQ(Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID,
|
||||
Now(), END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
response, expired));
|
||||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// indirect responses (signed by a delegated OCSP responder cert)
|
||||
|
||||
|
@ -372,6 +399,9 @@ protected:
|
|||
// another value (usually equal to certSubjectName) to use the byName
|
||||
// ResponderID construction.
|
||||
//
|
||||
// certSignatureAlgorithm specifies the signature algorithm that the
|
||||
// certificate will be signed with, not the OCSP response.
|
||||
//
|
||||
// If signerEKU is omitted, then the certificate will have the
|
||||
// id-kp-OCSPSigning EKU. If signerEKU is SEC_OID_UNKNOWN then it will not
|
||||
// have any EKU extension. Otherwise, the certificate will have the given
|
||||
|
@ -380,6 +410,7 @@ protected:
|
|||
const char* certSubjectName,
|
||||
OCSPResponseContext::CertStatus certStatus,
|
||||
const char* signerName,
|
||||
const ByteString& certSignatureAlgorithm,
|
||||
/*optional*/ const Input* signerEKUDER = &OCSPSigningEKUDER,
|
||||
/*optional, out*/ ByteString* signerDEROut = nullptr)
|
||||
{
|
||||
|
@ -396,6 +427,7 @@ protected:
|
|||
ByteString signerDER(CreateEncodedCertificate(
|
||||
++rootIssuedCount, rootName,
|
||||
oneDayBeforeNow, oneDayAfterNow, certSubjectName,
|
||||
certSignatureAlgorithm,
|
||||
signerEKUDER ? extensions : nullptr,
|
||||
rootKeyPair.get(), signerKeyPair));
|
||||
EXPECT_FALSE(ENCODING_FAILED(signerDER));
|
||||
|
@ -413,7 +445,9 @@ protected:
|
|||
signerName, *signerKeyPair,
|
||||
oneDayBeforeNow,
|
||||
oneDayBeforeNow,
|
||||
&oneDayAfterNow, certs);
|
||||
&oneDayAfterNow,
|
||||
sha256WithRSAEncryption,
|
||||
certs);
|
||||
}
|
||||
|
||||
static ByteString CreateEncodedCertificate(uint32_t serialNumber,
|
||||
|
@ -421,6 +455,7 @@ protected:
|
|||
time_t notBefore,
|
||||
time_t notAfter,
|
||||
const char* subject,
|
||||
const ByteString& signatureAlg,
|
||||
/*optional*/ const ByteString* extensions,
|
||||
/*optional*/ TestKeyPair* signerKeyPair,
|
||||
/*out*/ ScopedTestKeyPair& keyPair)
|
||||
|
@ -439,11 +474,11 @@ protected:
|
|||
}
|
||||
return ::mozilla::pkix::test::CreateEncodedCertificate(
|
||||
v3,
|
||||
sha256WithRSAEncryption,
|
||||
signatureAlg,
|
||||
serialNumberDER, issuerDER, notBefore,
|
||||
notAfter, subjectDER, extensions,
|
||||
signerKeyPair,
|
||||
sha256WithRSAEncryption,
|
||||
signatureAlg,
|
||||
keyPair);
|
||||
}
|
||||
|
||||
|
@ -458,7 +493,7 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_byKey)
|
|||
ByteString responseString(
|
||||
CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"good_indirect_byKey", OCSPResponseContext::good,
|
||||
byKey));
|
||||
byKey, sha256WithRSAEncryption));
|
||||
Input response;
|
||||
ASSERT_EQ(Success,
|
||||
response.Init(responseString.data(), responseString.length()));
|
||||
|
@ -475,7 +510,7 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_byName)
|
|||
ByteString responseString(
|
||||
CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"good_indirect_byName", OCSPResponseContext::good,
|
||||
"good_indirect_byName"));
|
||||
"good_indirect_byName", sha256WithRSAEncryption));
|
||||
Input response;
|
||||
ASSERT_EQ(Success,
|
||||
response.Init(responseString.data(), responseString.length()));
|
||||
|
@ -497,7 +532,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
|
|||
CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID, byKey,
|
||||
*missingSignerKeyPair, oneDayBeforeNow,
|
||||
oneDayBeforeNow, nullptr));
|
||||
oneDayBeforeNow, nullptr,
|
||||
sha256WithRSAEncryption));
|
||||
Input response;
|
||||
ASSERT_EQ(Success,
|
||||
response.Init(responseString.data(), responseString.length()));
|
||||
|
@ -518,7 +554,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
|
|||
CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID,
|
||||
"missing", *missingSignerKeyPair,
|
||||
oneDayBeforeNow, oneDayBeforeNow, nullptr));
|
||||
oneDayBeforeNow, oneDayBeforeNow, nullptr,
|
||||
sha256WithRSAEncryption));
|
||||
Input response;
|
||||
ASSERT_EQ(Success,
|
||||
response.Init(responseString.data(), responseString.length()));
|
||||
|
@ -545,8 +582,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_expired)
|
|||
++rootIssuedCount, rootName,
|
||||
now - (10 * Time::ONE_DAY_IN_SECONDS),
|
||||
now - (2 * Time::ONE_DAY_IN_SECONDS),
|
||||
signerName, extensions, rootKeyPair.get(),
|
||||
signerKeyPair));
|
||||
signerName, sha256WithRSAEncryption, extensions,
|
||||
rootKeyPair.get(), signerKeyPair));
|
||||
ASSERT_FALSE(ENCODING_FAILED(signerDER));
|
||||
|
||||
ByteString certs[] = { signerDER, ByteString() };
|
||||
|
@ -554,7 +591,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_expired)
|
|||
CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID,
|
||||
signerName, *signerKeyPair, oneDayBeforeNow,
|
||||
oneDayBeforeNow, &oneDayAfterNow, certs));
|
||||
oneDayBeforeNow, &oneDayAfterNow,
|
||||
sha256WithRSAEncryption, certs));
|
||||
Input response;
|
||||
ASSERT_EQ(Success,
|
||||
response.Init(responseString.data(), responseString.length()));
|
||||
|
@ -580,8 +618,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_future)
|
|||
++rootIssuedCount, rootName,
|
||||
now + (2 * Time::ONE_DAY_IN_SECONDS),
|
||||
now + (10 * Time::ONE_DAY_IN_SECONDS),
|
||||
signerName, extensions, rootKeyPair.get(),
|
||||
signerKeyPair));
|
||||
signerName, sha256WithRSAEncryption, extensions,
|
||||
rootKeyPair.get(), signerKeyPair));
|
||||
ASSERT_FALSE(ENCODING_FAILED(signerDER));
|
||||
|
||||
ByteString certs[] = { signerDER, ByteString() };
|
||||
|
@ -589,7 +627,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_future)
|
|||
CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID,
|
||||
signerName, *signerKeyPair, oneDayBeforeNow,
|
||||
oneDayBeforeNow, &oneDayAfterNow, certs));
|
||||
oneDayBeforeNow, &oneDayAfterNow,
|
||||
sha256WithRSAEncryption, certs));
|
||||
Input response;
|
||||
ASSERT_EQ(Success,
|
||||
response.Init(responseString.data(), responseString.length()));
|
||||
|
@ -606,7 +645,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_no_eku)
|
|||
ByteString responseString(
|
||||
CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"good_indirect_wrong_eku",
|
||||
OCSPResponseContext::good, byKey, nullptr));
|
||||
OCSPResponseContext::good, byKey,
|
||||
sha256WithRSAEncryption, nullptr));
|
||||
Input response;
|
||||
ASSERT_EQ(Success,
|
||||
response.Init(responseString.data(), responseString.length()));
|
||||
|
@ -626,7 +666,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
|
|||
ByteString responseString(
|
||||
CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"good_indirect_wrong_eku",
|
||||
OCSPResponseContext::good, byKey, &serverAuthEKUDER));
|
||||
OCSPResponseContext::good, byKey,
|
||||
sha256WithRSAEncryption, &serverAuthEKUDER));
|
||||
Input response;
|
||||
ASSERT_EQ(Success,
|
||||
response.Init(responseString.data(), responseString.length()));
|
||||
|
@ -644,7 +685,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_tampered_eku)
|
|||
ByteString tamperedResponse(
|
||||
CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"good_indirect_tampered_eku",
|
||||
OCSPResponseContext::good, byKey, &serverAuthEKUDER));
|
||||
OCSPResponseContext::good, byKey,
|
||||
sha256WithRSAEncryption, &serverAuthEKUDER));
|
||||
ASSERT_EQ(Success,
|
||||
TamperOnce(tamperedResponse,
|
||||
ByteString(tlv_id_kp_serverAuth,
|
||||
|
@ -680,8 +722,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_unknown_issuer)
|
|||
ScopedTestKeyPair signerKeyPair;
|
||||
ByteString signerDER(CreateEncodedCertificate(
|
||||
1, subCAName, oneDayBeforeNow, oneDayAfterNow,
|
||||
signerName, extensions, unknownKeyPair.get(),
|
||||
signerKeyPair));
|
||||
signerName, sha256WithRSAEncryption, extensions,
|
||||
unknownKeyPair.get(), signerKeyPair));
|
||||
ASSERT_FALSE(ENCODING_FAILED(signerDER));
|
||||
|
||||
// OCSP response signed by that delegated responder
|
||||
|
@ -690,7 +732,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder, good_unknown_issuer)
|
|||
CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID,
|
||||
signerName, *signerKeyPair, oneDayBeforeNow,
|
||||
oneDayBeforeNow, &oneDayAfterNow, certs));
|
||||
oneDayBeforeNow, &oneDayAfterNow,
|
||||
sha256WithRSAEncryption, certs));
|
||||
Input response;
|
||||
ASSERT_EQ(Success,
|
||||
response.Init(responseString.data(), responseString.length()));
|
||||
|
@ -720,8 +763,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
|
|||
ByteString subCADER(CreateEncodedCertificate(
|
||||
++rootIssuedCount, rootName,
|
||||
oneDayBeforeNow, oneDayAfterNow,
|
||||
subCAName, subCAExtensions, rootKeyPair.get(),
|
||||
subCAKeyPair));
|
||||
subCAName, sha256WithRSAEncryption,
|
||||
subCAExtensions, rootKeyPair.get(), subCAKeyPair));
|
||||
ASSERT_FALSE(ENCODING_FAILED(subCADER));
|
||||
|
||||
// Delegated responder cert signed by that sub-CA
|
||||
|
@ -733,8 +776,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
|
|||
ScopedTestKeyPair signerKeyPair;
|
||||
ByteString signerDER(CreateEncodedCertificate(
|
||||
1, subCAName, oneDayBeforeNow, oneDayAfterNow,
|
||||
signerName, extensions, subCAKeyPair.get(),
|
||||
signerKeyPair));
|
||||
signerName, sha256WithRSAEncryption, extensions,
|
||||
subCAKeyPair.get(), signerKeyPair));
|
||||
ASSERT_FALSE(ENCODING_FAILED(signerDER));
|
||||
|
||||
// OCSP response signed by the delegated responder issued by the sub-CA
|
||||
|
@ -744,7 +787,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
|
|||
CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID,
|
||||
signerName, *signerKeyPair, oneDayBeforeNow,
|
||||
oneDayBeforeNow, &oneDayAfterNow, certs));
|
||||
oneDayBeforeNow, &oneDayAfterNow,
|
||||
sha256WithRSAEncryption, certs));
|
||||
Input response;
|
||||
ASSERT_EQ(Success,
|
||||
response.Init(responseString.data(), responseString.length()));
|
||||
|
@ -773,7 +817,9 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
|
|||
ScopedTestKeyPair subCAKeyPair;
|
||||
ByteString subCADER(CreateEncodedCertificate(++rootIssuedCount, rootName,
|
||||
oneDayBeforeNow, oneDayAfterNow,
|
||||
subCAName, subCAExtensions,
|
||||
subCAName,
|
||||
sha256WithRSAEncryption,
|
||||
subCAExtensions,
|
||||
rootKeyPair.get(),
|
||||
subCAKeyPair));
|
||||
ASSERT_FALSE(ENCODING_FAILED(subCADER));
|
||||
|
@ -787,8 +833,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
|
|||
ScopedTestKeyPair signerKeyPair;
|
||||
ByteString signerDER(CreateEncodedCertificate(
|
||||
1, subCAName, oneDayBeforeNow, oneDayAfterNow,
|
||||
signerName, extensions, subCAKeyPair.get(),
|
||||
signerKeyPair));
|
||||
signerName, sha256WithRSAEncryption, extensions,
|
||||
subCAKeyPair.get(), signerKeyPair));
|
||||
ASSERT_FALSE(ENCODING_FAILED(signerDER));
|
||||
|
||||
// OCSP response signed by the delegated responder issued by the sub-CA
|
||||
|
@ -798,7 +844,8 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
|
|||
CreateEncodedOCSPSuccessfulResponse(
|
||||
OCSPResponseContext::good, *endEntityCertID,
|
||||
signerName, *signerKeyPair, oneDayBeforeNow,
|
||||
oneDayBeforeNow, &oneDayAfterNow, certs));
|
||||
oneDayBeforeNow, &oneDayAfterNow,
|
||||
sha256WithRSAEncryption, certs));
|
||||
Input response;
|
||||
ASSERT_EQ(Success,
|
||||
response.Init(responseString.data(), responseString.length()));
|
||||
|
@ -810,6 +857,27 @@ TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
|
|||
ASSERT_FALSE(expired);
|
||||
}
|
||||
|
||||
TEST_F(pkixocsp_VerifyEncodedResponse_DelegatedResponder,
|
||||
good_unsupportedSignatureAlgorithmOnResponder)
|
||||
{
|
||||
// Note that the algorithm ID (md5WithRSAEncryption) identifies the signature
|
||||
// algorithm that will be used to sign the certificate that issues the OCSP
|
||||
// responses, not the responses themselves.
|
||||
ByteString responseString(
|
||||
CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"good_indirect_unsupportedSignatureAlgorithm",
|
||||
OCSPResponseContext::good, byKey,
|
||||
md5WithRSAEncryption));
|
||||
Input response;
|
||||
ASSERT_EQ(Success,
|
||||
response.Init(responseString.data(), responseString.length()));
|
||||
bool expired;
|
||||
ASSERT_EQ(Result::ERROR_OCSP_INVALID_SIGNING_CERT,
|
||||
VerifyEncodedOCSPResponse(trustDomain, *endEntityCertID, Now(),
|
||||
END_ENTITY_MAX_LIFETIME_IN_DAYS,
|
||||
response, expired));
|
||||
}
|
||||
|
||||
class pkixocsp_VerifyEncodedResponse_GetCertTrust
|
||||
: public pkixocsp_VerifyEncodedResponse_DelegatedResponder {
|
||||
public:
|
||||
|
@ -820,7 +888,8 @@ public:
|
|||
responseString =
|
||||
CreateEncodedIndirectOCSPSuccessfulResponse(
|
||||
"OCSPGetCertTrustTest Signer", OCSPResponseContext::good,
|
||||
byKey, &OCSPSigningEKUDER, &signerCertDER);
|
||||
byKey, sha256WithRSAEncryption, &OCSPSigningEKUDER,
|
||||
&signerCertDER);
|
||||
if (ENCODING_FAILED(responseString)) {
|
||||
abort();
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@
|
|||
#include "nss.h"
|
||||
#include "pk11pub.h"
|
||||
#include "pkix/pkixnss.h"
|
||||
#include "pkixder.h"
|
||||
#include "secerr.h"
|
||||
#include "secitem.h"
|
||||
|
||||
|
@ -76,10 +77,28 @@ public:
|
|||
const ByteString& signatureAlgorithm,
|
||||
/*out*/ ByteString& signature) const
|
||||
{
|
||||
SECOidTag signatureAlgorithmOidTag;
|
||||
if (signatureAlgorithm == sha256WithRSAEncryption) {
|
||||
signatureAlgorithmOidTag = SEC_OID_PKCS1_SHA256_WITH_RSA_ENCRYPTION;
|
||||
} else {
|
||||
// signatureAlgorithm is of the form SEQUENCE { OID { <OID bytes> } },
|
||||
// whereas SECOID_GetAlgorithmTag wants just the OID bytes, so we have to
|
||||
// unwrap it here. As long as signatureAlgorithm is short enough, we don't
|
||||
// have to do full DER decoding here.
|
||||
// Also, this is just for testing purposes - there shouldn't be any
|
||||
// untrusted input given to this function. If we make a mistake, we only
|
||||
// have ourselves to blame.
|
||||
if (signatureAlgorithm.length() > 127 ||
|
||||
signatureAlgorithm.length() < 4 ||
|
||||
signatureAlgorithm.data()[0] != der::SEQUENCE ||
|
||||
signatureAlgorithm.data()[2] != der::OIDTag) {
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
SECAlgorithmID signatureAlgorithmID;
|
||||
signatureAlgorithmID.algorithm.data =
|
||||
const_cast<unsigned char*>(signatureAlgorithm.data() + 4);
|
||||
signatureAlgorithmID.algorithm.len = signatureAlgorithm.length() - 4;
|
||||
signatureAlgorithmID.parameters.data = nullptr;
|
||||
signatureAlgorithmID.parameters.len = 0;
|
||||
SECOidTag signatureAlgorithmOidTag =
|
||||
SECOID_GetAlgorithmTag(&signatureAlgorithmID);
|
||||
if (signatureAlgorithmOidTag == SEC_OID_UNKNOWN) {
|
||||
return Result::FATAL_ERROR_INVALID_ARGS;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,13 +37,6 @@ using namespace std;
|
|||
|
||||
namespace mozilla { namespace pkix { namespace test {
|
||||
|
||||
// python DottedOIDToCode.py --alg sha256WithRSAEncryption 1.2.840.113549.1.1.11
|
||||
static const uint8_t alg_sha256WithRSAEncryption[] = {
|
||||
0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b
|
||||
};
|
||||
const ByteString sha256WithRSAEncryption(alg_sha256WithRSAEncryption,
|
||||
MOZILLA_PKIX_ARRAY_LENGTH(alg_sha256WithRSAEncryption));
|
||||
|
||||
namespace {
|
||||
|
||||
inline void
|
||||
|
@ -77,6 +70,19 @@ OpenFile(const string& dir, const string& filename, const string& mode)
|
|||
|
||||
} // unnamed namespace
|
||||
|
||||
bool
|
||||
InputEqualsByteString(Input input, const ByteString& bs)
|
||||
{
|
||||
Input bsInput;
|
||||
if (bsInput.Init(bs.data(), bs.length()) != Success) {
|
||||
// Init can only fail if it is given a bad pointer or if the input is too
|
||||
// long, which won't ever happen. Plus, if it does, it is ok to call abort
|
||||
// since this is only test code.
|
||||
abort();
|
||||
}
|
||||
return InputsAreEqual(input, bsInput);
|
||||
}
|
||||
|
||||
Result
|
||||
TamperOnce(/*in/out*/ ByteString& item, const ByteString& from,
|
||||
const ByteString& to)
|
||||
|
@ -130,6 +136,7 @@ OCSPResponseContext::OCSPResponseContext(const CertID& certID, time_t time)
|
|||
, producedAt(time)
|
||||
, extensions(nullptr)
|
||||
, includeEmptyExtensions(false)
|
||||
, signatureAlgorithm(sha256WithRSAEncryption)
|
||||
, badSignature(false)
|
||||
, certs(nullptr)
|
||||
|
||||
|
@ -758,7 +765,7 @@ BasicOCSPResponse(OCSPResponseContext& context)
|
|||
|
||||
// TODO(bug 980538): certs
|
||||
return SignedData(tbsResponseData, context.signerKeyPair.get(),
|
||||
sha256WithRSAEncryption,
|
||||
context.signatureAlgorithm,
|
||||
context.badSignature, context.certs);
|
||||
}
|
||||
|
||||
|
|
|
@ -74,13 +74,36 @@ static const uint8_t tlv_id_kp_serverAuth[] = {
|
|||
0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x01
|
||||
};
|
||||
|
||||
extern const ByteString sha256WithRSAEncryption;
|
||||
// python DottedOIDToCode.py --alg sha256WithRSAEncryption 1.2.840.113549.1.1.11
|
||||
const uint8_t alg_sha256WithRSAEncryption[] = {
|
||||
0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b
|
||||
};
|
||||
|
||||
const ByteString sha256WithRSAEncryption(alg_sha256WithRSAEncryption,
|
||||
MOZILLA_PKIX_ARRAY_LENGTH(alg_sha256WithRSAEncryption));
|
||||
|
||||
// python DottedOIDToCode.py --alg md5WithRSAEncryption 1.2.840.113549.1.1.4
|
||||
const uint8_t alg_md5WithRSAEncryption[] = {
|
||||
0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x04
|
||||
};
|
||||
|
||||
const ByteString md5WithRSAEncryption(alg_md5WithRSAEncryption,
|
||||
MOZILLA_PKIX_ARRAY_LENGTH(alg_md5WithRSAEncryption));
|
||||
|
||||
// python DottedOIDToCode.py --alg md2WithRSAEncryption 1.2.840.113549.1.1.2
|
||||
const uint8_t alg_md2WithRSAEncryption[] = {
|
||||
0x30, 0x0b, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x02
|
||||
};
|
||||
|
||||
const ByteString md2WithRSAEncryption(alg_md2WithRSAEncryption,
|
||||
MOZILLA_PKIX_ARRAY_LENGTH(alg_md2WithRSAEncryption));
|
||||
|
||||
// e.g. YMDHMS(2016, 12, 31, 1, 23, 45) => 2016-12-31:01:23:45 (GMT)
|
||||
mozilla::pkix::Time YMDHMS(int16_t year, int16_t month, int16_t day,
|
||||
int16_t hour, int16_t minutes, int16_t seconds);
|
||||
|
||||
ByteString CNToDERName(const char* cn);
|
||||
bool InputEqualsByteString(Input input, const ByteString& bs);
|
||||
|
||||
class TestKeyPair
|
||||
{
|
||||
|
@ -221,6 +244,7 @@ public:
|
|||
// regardless of if there are any actual
|
||||
// extensions.
|
||||
ScopedTestKeyPair signerKeyPair;
|
||||
ByteString signatureAlgorithm; // DER encoding of signature algorithm to use.
|
||||
bool badSignature; // If true, alter the signature to fail verification
|
||||
const ByteString* certs; // optional; array terminated by an empty string
|
||||
|
||||
|
|
Загрузка…
Ссылка в новой задаче