gecko-dev/security/pkix/test/gtest/pkixcert_signature_algorith...

267 строки
8.3 KiB
C++

/* -*- 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 "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,
/*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, Critical::Yes);
EXPECT_FALSE(ENCODING_FAILED(extensions[0]));
}
ScopedTestKeyPair reusedKey(CloneReusedKeyPair());
ByteString certDER(CreateEncodedCertificate(v3, signatureAlgorithm,
serialNumber, issuerDER,
oneDayBeforeNow, oneDayAfterNow,
subjectDER, *reusedKey,
extensions, *reusedKey,
signatureAlgorithm));
EXPECT_FALSE(ENCODING_FAILED(certDER));
return certDER;
}
class AlgorithmTestsTrustDomain final : 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:
Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input candidateCert,
/*out*/ TrustLevel& trustLevel) override
{
if (InputEqualsByteString(candidateCert, rootDER)) {
trustLevel = TrustLevel::TrustAnchor;
} else {
trustLevel = TrustLevel::InheritsTrust;
}
return Success;
}
Result FindIssuer(Input encodedIssuerName, IssuerChecker& checker, Time)
override
{
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);
}
Result CheckRevocation(EndEntityOrCA, const CertID&, Time, const Input*,
const Input*) override
{
return Success;
}
Result IsChainValid(const DERArray&, Time) override
{
return Success;
}
Result DigestBuf(Input input, DigestAlgorithm digestAlg,
/*out*/ uint8_t* digestBuf, size_t digestLen) override
{
return TestDigestBuf(input, digestAlg, digestBuf, digestLen);
}
Result CheckRSAPublicKeyModulusSizeInBits(EndEntityOrCA, unsigned int)
override
{
return Success;
}
Result VerifyRSAPKCS1SignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyRSAPKCS1SignedDigest(signedDigest, subjectPublicKeyInfo);
}
Result CheckECDSACurveIsAcceptable(EndEntityOrCA, NamedCurve) override
{
return Success;
}
Result VerifyECDSASignedDigest(const SignedDigest& signedDigest,
Input subjectPublicKeyInfo) override
{
return TestVerifyECDSASignedDigest(signedDigest, subjectPublicKeyInfo);
}
ByteString rootDER;
ByteString rootSubjectDER;
ByteString intDER;
ByteString intSubjectDER;
};
static const ByteString NO_INTERMEDIATE; // empty
struct ChainValidity final
{
// 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";
ByteString rootSubjectDER;
ByteString rootEncoded(
CreateCert(rootCN, rootCN, EndEntityOrCA::MustBeCA,
chainValidity.rootSignatureAlgorithm, rootSubjectDER));
EXPECT_FALSE(ENCODING_FAILED(rootEncoded));
EXPECT_FALSE(ENCODING_FAILED(rootSubjectDER));
const char* issuerCN = rootCN;
const char* intermediateCN = "CN=Intermediate";
ByteString intermediateSubjectDER;
ByteString intermediateEncoded;
if (chainValidity.optionalIntermediateSignatureAlgorithm != NO_INTERMEDIATE) {
intermediateEncoded =
CreateCert(rootCN, intermediateCN, EndEntityOrCA::MustBeCA,
chainValidity.optionalIntermediateSignatureAlgorithm,
intermediateSubjectDER);
EXPECT_FALSE(ENCODING_FAILED(intermediateEncoded));
EXPECT_FALSE(ENCODING_FAILED(intermediateSubjectDER));
issuerCN = intermediateCN;
}
AlgorithmTestsTrustDomain trustDomain(rootEncoded, rootSubjectDER,
intermediateEncoded,
intermediateSubjectDER);
const char* endEntityCN = "CN=End Entity";
ByteString endEntitySubjectDER;
ByteString endEntityEncoded(
CreateCert(issuerCN, endEntityCN, EndEntityOrCA::MustBeEndEntity,
chainValidity.endEntitySignatureAlgorithm,
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));