1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* Any copyright is dedicated to the Public Domain.
4 * http://creativecommons.org/publicdomain/zero/1.0/ */
5
6 #include "pkixder.h"
7 #include "pkixgtest.h"
8
9 using namespace mozilla::pkix;
10 using namespace mozilla::pkix::test;
11
12 static ByteString
CreateCert(const char * issuerCN,const char * subjectCN,EndEntityOrCA endEntityOrCA,const TestSignatureAlgorithm & signatureAlgorithm,ByteString & subjectDER)13 CreateCert(const char* issuerCN,
14 const char* subjectCN,
15 EndEntityOrCA endEntityOrCA,
16 const TestSignatureAlgorithm& signatureAlgorithm,
17 /*out*/ ByteString& subjectDER)
18 {
19 static long serialNumberValue = 0;
20 ++serialNumberValue;
21 ByteString serialNumber(CreateEncodedSerialNumber(serialNumberValue));
22 EXPECT_FALSE(ENCODING_FAILED(serialNumber));
23
24 ByteString issuerDER(CNToDERName(issuerCN));
25 EXPECT_FALSE(ENCODING_FAILED(issuerDER));
26 subjectDER = CNToDERName(subjectCN);
27 EXPECT_FALSE(ENCODING_FAILED(subjectDER));
28
29 ByteString extensions[2];
30 if (endEntityOrCA == EndEntityOrCA::MustBeCA) {
31 extensions[0] =
32 CreateEncodedBasicConstraints(true, nullptr, Critical::Yes);
33 EXPECT_FALSE(ENCODING_FAILED(extensions[0]));
34 }
35
36 ScopedTestKeyPair reusedKey(CloneReusedKeyPair());
37 ByteString certDER(CreateEncodedCertificate(v3, signatureAlgorithm,
38 serialNumber, issuerDER,
39 oneDayBeforeNow, oneDayAfterNow,
40 subjectDER, *reusedKey,
41 extensions, *reusedKey,
42 signatureAlgorithm));
43 EXPECT_FALSE(ENCODING_FAILED(certDER));
44 return certDER;
45 }
46
47 class AlgorithmTestsTrustDomain final : public DefaultCryptoTrustDomain
48 {
49 public:
AlgorithmTestsTrustDomain(const ByteString & rootDER,const ByteString & rootSubjectDER,const ByteString & intDER,const ByteString & intSubjectDER)50 AlgorithmTestsTrustDomain(const ByteString& rootDER,
51 const ByteString& rootSubjectDER,
52 /*optional*/ const ByteString& intDER,
53 /*optional*/ const ByteString& intSubjectDER)
54 : rootDER(rootDER)
55 , rootSubjectDER(rootSubjectDER)
56 , intDER(intDER)
57 , intSubjectDER(intSubjectDER)
58 {
59 }
60
61 private:
GetCertTrust(EndEntityOrCA,const CertPolicyId &,Input candidateCert,TrustLevel & trustLevel)62 Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input candidateCert,
63 /*out*/ TrustLevel& trustLevel) override
64 {
65 if (InputEqualsByteString(candidateCert, rootDER)) {
66 trustLevel = TrustLevel::TrustAnchor;
67 } else {
68 trustLevel = TrustLevel::InheritsTrust;
69 }
70 return Success;
71 }
72
FindIssuer(Input encodedIssuerName,IssuerChecker & checker,Time)73 Result FindIssuer(Input encodedIssuerName, IssuerChecker& checker, Time)
74 override
75 {
76 ByteString* issuerDER = nullptr;
77 if (InputEqualsByteString(encodedIssuerName, rootSubjectDER)) {
78 issuerDER = &rootDER;
79 } else if (InputEqualsByteString(encodedIssuerName, intSubjectDER)) {
80 issuerDER = &intDER;
81 } else {
82 // FindIssuer just returns success if it can't find a potential issuer.
83 return Success;
84 }
85 Input issuerCert;
86 Result rv = issuerCert.Init(issuerDER->data(), issuerDER->length());
87 if (rv != Success) {
88 return rv;
89 }
90 bool keepGoing;
91 return checker.Check(issuerCert, nullptr, keepGoing);
92 }
93
CheckRevocation(EndEntityOrCA,const CertID &,Time,Duration,const Input *,const Input *)94 Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
95 const Input*, const Input*) override
96 {
97 return Success;
98 }
99
IsChainValid(const DERArray &,Time)100 Result IsChainValid(const DERArray&, Time) override
101 {
102 return Success;
103 }
104
105 ByteString rootDER;
106 ByteString rootSubjectDER;
107 ByteString intDER;
108 ByteString intSubjectDER;
109 };
110
111 static const TestSignatureAlgorithm NO_INTERMEDIATE
112 {
113 TestPublicKeyAlgorithm(ByteString()),
114 TestDigestAlgorithmID::MD2,
115 ByteString(),
116 false
117 };
118
119 struct ChainValidity final
120 {
ChainValidityChainValidity121 ChainValidity(const TestSignatureAlgorithm& endEntitySignatureAlgorithm,
122 const TestSignatureAlgorithm& optionalIntSignatureAlgorithm,
123 const TestSignatureAlgorithm& rootSignatureAlgorithm,
124 bool isValid)
125 : endEntitySignatureAlgorithm(endEntitySignatureAlgorithm)
126 , optionalIntermediateSignatureAlgorithm(optionalIntSignatureAlgorithm)
127 , rootSignatureAlgorithm(rootSignatureAlgorithm)
128 , isValid(isValid)
129 { }
130
131 // In general, a certificate is generated for each of these. However, if
132 // optionalIntermediateSignatureAlgorithm is NO_INTERMEDIATE, then only 2
133 // certificates are generated.
134 // The certificate generated for the given rootSignatureAlgorithm is the
135 // trust anchor.
136 TestSignatureAlgorithm endEntitySignatureAlgorithm;
137 TestSignatureAlgorithm optionalIntermediateSignatureAlgorithm;
138 TestSignatureAlgorithm rootSignatureAlgorithm;
139 bool isValid;
140 };
141
142 static const ChainValidity CHAIN_VALIDITY[] =
143 {
144 // The trust anchor may have a signature with an unsupported signature
145 // algorithm.
146 ChainValidity(sha256WithRSAEncryption(),
147 NO_INTERMEDIATE,
148 md5WithRSAEncryption(),
149 true),
150 ChainValidity(sha256WithRSAEncryption(),
151 NO_INTERMEDIATE,
152 md2WithRSAEncryption(),
153 true),
154
155 // Certificates that are not trust anchors must not have a signature with an
156 // unsupported signature algorithm.
157 ChainValidity(md5WithRSAEncryption(),
158 NO_INTERMEDIATE,
159 sha256WithRSAEncryption(),
160 false),
161 ChainValidity(md2WithRSAEncryption(),
162 NO_INTERMEDIATE,
163 sha256WithRSAEncryption(),
164 false),
165 ChainValidity(md2WithRSAEncryption(),
166 NO_INTERMEDIATE,
167 md5WithRSAEncryption(),
168 false),
169 ChainValidity(sha256WithRSAEncryption(),
170 md5WithRSAEncryption(),
171 sha256WithRSAEncryption(),
172 false),
173 ChainValidity(sha256WithRSAEncryption(),
174 md2WithRSAEncryption(),
175 sha256WithRSAEncryption(),
176 false),
177 ChainValidity(sha256WithRSAEncryption(),
178 md2WithRSAEncryption(),
179 md5WithRSAEncryption(),
180 false),
181 };
182
183 class pkixcert_IsValidChainForAlgorithm
184 : public ::testing::Test
185 , public ::testing::WithParamInterface<ChainValidity>
186 {
187 };
188
TEST_P(pkixcert_IsValidChainForAlgorithm,IsValidChainForAlgorithm)189 TEST_P(pkixcert_IsValidChainForAlgorithm, IsValidChainForAlgorithm)
190 {
191 const ChainValidity& chainValidity(GetParam());
192 const char* rootCN = "CN=Root";
193 ByteString rootSubjectDER;
194 ByteString rootEncoded(
195 CreateCert(rootCN, rootCN, EndEntityOrCA::MustBeCA,
196 chainValidity.rootSignatureAlgorithm, rootSubjectDER));
197 EXPECT_FALSE(ENCODING_FAILED(rootEncoded));
198 EXPECT_FALSE(ENCODING_FAILED(rootSubjectDER));
199
200 const char* issuerCN = rootCN;
201
202 const char* intermediateCN = "CN=Intermediate";
203 ByteString intermediateSubjectDER;
204 ByteString intermediateEncoded;
205
206 // If the the algorithmIdentifier is empty, then it's NO_INTERMEDIATE.
207 if (!chainValidity.optionalIntermediateSignatureAlgorithm
208 .algorithmIdentifier.empty()) {
209 intermediateEncoded =
210 CreateCert(rootCN, intermediateCN, EndEntityOrCA::MustBeCA,
211 chainValidity.optionalIntermediateSignatureAlgorithm,
212 intermediateSubjectDER);
213 EXPECT_FALSE(ENCODING_FAILED(intermediateEncoded));
214 EXPECT_FALSE(ENCODING_FAILED(intermediateSubjectDER));
215 issuerCN = intermediateCN;
216 }
217
218 AlgorithmTestsTrustDomain trustDomain(rootEncoded, rootSubjectDER,
219 intermediateEncoded,
220 intermediateSubjectDER);
221
222 const char* endEntityCN = "CN=End Entity";
223 ByteString endEntitySubjectDER;
224 ByteString endEntityEncoded(
225 CreateCert(issuerCN, endEntityCN, EndEntityOrCA::MustBeEndEntity,
226 chainValidity.endEntitySignatureAlgorithm,
227 endEntitySubjectDER));
228 EXPECT_FALSE(ENCODING_FAILED(endEntityEncoded));
229 EXPECT_FALSE(ENCODING_FAILED(endEntitySubjectDER));
230
231 Input endEntity;
232 ASSERT_EQ(Success, endEntity.Init(endEntityEncoded.data(),
233 endEntityEncoded.length()));
234 Result expectedResult = chainValidity.isValid
235 ? Success
236 : Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
237 ASSERT_EQ(expectedResult,
238 BuildCertChain(trustDomain, endEntity, Now(),
239 EndEntityOrCA::MustBeEndEntity,
240 KeyUsage::noParticularKeyUsageRequired,
241 KeyPurposeId::id_kp_serverAuth,
242 CertPolicyId::anyPolicy, nullptr));
243 }
244
245 INSTANTIATE_TEST_CASE_P(pkixcert_IsValidChainForAlgorithm,
246 pkixcert_IsValidChainForAlgorithm,
247 testing::ValuesIn(CHAIN_VALIDITY));
248