bug 1058812 - (3/3) mozilla::pkix: test handling unsupported signature algorithms r=briansmith

This commit is contained in:
David Keeler 2014-10-08 09:48:15 -07:00
Родитель af214d36f8
Коммит a052b67f71
7 изменённых файлов: 440 добавлений и 54 удалений

Просмотреть файл

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