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