1 /* This Source Code Form is subject to the terms of the Mozilla Public
2  * License, v. 2.0. If a copy of the MPL was not distributed with this
3  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
4  */
5 
6 #include "pkixgtest.h"
7 
8 #include "mozpkix/pkixc.h"
9 #include "mozpkix/pkixder.h"
10 #include "mozpkix/pkixnss.h"
11 #include "secerr.h"
12 #include "sslerr.h"
13 
14 using namespace mozilla::pkix;
15 using namespace mozilla::pkix::test;
16 
CreateCert(const char * issuerCN,const char * subjectCN,EndEntityOrCA endEntityOrCA,const ByteString * subjectAlternativeNameExtension=nullptr,const ByteString * extendedKeyUsageExtension=nullptr)17 static ByteString CreateCert(
18     const char* issuerCN, const char* subjectCN, EndEntityOrCA endEntityOrCA,
19     /*optional*/ const ByteString* subjectAlternativeNameExtension = nullptr,
20     /*optional*/ const ByteString* extendedKeyUsageExtension = nullptr) {
21   EXPECT_TRUE(issuerCN);
22   EXPECT_TRUE(subjectCN);
23   static long serialNumberValue = 0;
24   ++serialNumberValue;
25   ByteString serialNumber(CreateEncodedSerialNumber(serialNumberValue));
26   EXPECT_FALSE(ENCODING_FAILED(serialNumber));
27 
28   ByteString issuerDER(CNToDERName(issuerCN));
29   ByteString subjectDER(CNToDERName(subjectCN));
30 
31   std::time_t notBefore = 1620000000;
32   std::time_t notAfter = 1630000000;
33 
34   std::vector<ByteString> extensions;
35   if (endEntityOrCA == EndEntityOrCA::MustBeCA) {
36     ByteString basicConstraints =
37         CreateEncodedBasicConstraints(true, nullptr, Critical::Yes);
38     EXPECT_FALSE(ENCODING_FAILED(basicConstraints));
39     extensions.push_back(basicConstraints);
40   }
41   if (subjectAlternativeNameExtension) {
42     extensions.push_back(*subjectAlternativeNameExtension);
43   }
44   if (extendedKeyUsageExtension) {
45     extensions.push_back(*extendedKeyUsageExtension);
46   }
47   extensions.push_back(ByteString());  // marks the end of the list
48 
49   ScopedTestKeyPair reusedKey(CloneReusedKeyPair());
50   ByteString certDER(CreateEncodedCertificate(
51       v3, sha256WithRSAEncryption(), serialNumber, issuerDER, notBefore,
52       notAfter, subjectDER, *reusedKey, extensions.data(), *reusedKey,
53       sha256WithRSAEncryption()));
54   EXPECT_FALSE(ENCODING_FAILED(certDER));
55 
56   return certDER;
57 }
58 
59 class pkixc_tests : public ::testing::Test {};
60 
TEST_F(pkixc_tests,Valid_VerifyCodeSigningCertificateChain)61 TEST_F(pkixc_tests, Valid_VerifyCodeSigningCertificateChain) {
62   ByteString root(CreateCert("CA", "CA", EndEntityOrCA::MustBeCA));
63   ByteString intermediate(
64       CreateCert("CA", "intermediate", EndEntityOrCA::MustBeCA));
65   ByteString subjectAltNameExtension =
66       CreateEncodedSubjectAltName(DNSName("example.com"));
67   ByteString endEntity(CreateCert("intermediate", "end-entity",
68                                   EndEntityOrCA::MustBeEndEntity,
69                                   &subjectAltNameExtension));
70   const uint8_t* certificates[] = {endEntity.data(), intermediate.data(),
71                                    root.data()};
72   const uint16_t certificateLengths[] = {
73       static_cast<uint16_t>(endEntity.length()),
74       static_cast<uint16_t>(intermediate.length()),
75       static_cast<uint16_t>(root.length())};
76   const size_t numCertificates = 3;
77   const uint64_t secondsSinceEpoch = 1625000000;
78   uint8_t rootSHA256Digest[32] = {0};
79   Input rootInput;
80   Result rv = rootInput.Init(root.data(), root.length());
81   ASSERT_EQ(rv, Success);
82   rv = DigestBufNSS(rootInput, DigestAlgorithm::sha256, rootSHA256Digest,
83                     sizeof(rootSHA256Digest));
84   ASSERT_EQ(rv, Success);
85   const uint8_t hostname[] = {"example.com"};
86   size_t hostnameLength = strlen("example.com");
87   PRErrorCode error = 0;
88   ASSERT_TRUE(VerifyCodeSigningCertificateChain(
89       &certificates[0], &certificateLengths[0], numCertificates,
90       secondsSinceEpoch, &rootSHA256Digest[0], &hostname[0], hostnameLength,
91       &error));
92 
93   // If the extended key usage extension is present, it must have the code
94   // signing usage.
95   ByteString extendedKeyUsageExtension(
96       CreateEKUExtension(BytesToByteString(tlv_id_kp_codeSigning)));
97   ByteString endEntityWithEKU(
98       CreateCert("intermediate", "end-entity", EndEntityOrCA::MustBeEndEntity,
99                  &subjectAltNameExtension, &extendedKeyUsageExtension));
100   const uint8_t* certificatesWithEKU[] = {endEntityWithEKU.data(),
101                                           intermediate.data(), root.data()};
102   const uint16_t certificateLengthsWithEKU[] = {
103       static_cast<uint16_t>(endEntityWithEKU.length()),
104       static_cast<uint16_t>(intermediate.length()),
105       static_cast<uint16_t>(root.length())};
106   ASSERT_TRUE(VerifyCodeSigningCertificateChain(
107       &certificatesWithEKU[0], &certificateLengthsWithEKU[0], numCertificates,
108       secondsSinceEpoch, &rootSHA256Digest[0], &hostname[0], hostnameLength,
109       &error));
110 }
111 
TEST_F(pkixc_tests,Invalid_VerifyCodeSigningCertificateChain)112 TEST_F(pkixc_tests, Invalid_VerifyCodeSigningCertificateChain) {
113   ByteString root(CreateCert("CA", "CA", EndEntityOrCA::MustBeCA));
114   ByteString subjectAltNameExtension =
115       CreateEncodedSubjectAltName(DNSName("example.com"));
116   ByteString endEntity(CreateCert("CA", "end-entity",
117                                   EndEntityOrCA::MustBeEndEntity,
118                                   &subjectAltNameExtension));
119   const uint8_t* certificates[] = {endEntity.data(), root.data()};
120   const uint16_t certificateLengths[] = {
121       static_cast<uint16_t>(endEntity.length()),
122       static_cast<uint16_t>(root.length())};
123   const size_t numCertificates = 2;
124   const uint64_t secondsSinceEpoch = 1625000000;
125   uint8_t rootSHA256Digest[32] = {0};
126   Input rootInput;
127   Result rv = rootInput.Init(root.data(), root.length());
128   ASSERT_EQ(rv, Success);
129   rv = DigestBufNSS(rootInput, DigestAlgorithm::sha256, rootSHA256Digest,
130                     sizeof(rootSHA256Digest));
131   ASSERT_EQ(rv, Success);
132   const uint8_t hostname[] = {"example.com"};
133   size_t hostnameLength = strlen("example.com");
134   PRErrorCode error = 0;
135   // Consistency check first to ensure these tests are meaningful.
136   ASSERT_TRUE(VerifyCodeSigningCertificateChain(
137       &certificates[0], &certificateLengths[0], numCertificates,
138       secondsSinceEpoch, &rootSHA256Digest[0], &hostname[0], hostnameLength,
139       &error));
140   ASSERT_EQ(error, 0);
141 
142   // Test with "now" after the certificates have expired.
143   ASSERT_FALSE(VerifyCodeSigningCertificateChain(
144       &certificates[0], &certificateLengths[0], numCertificates,
145       secondsSinceEpoch + 10000000, &rootSHA256Digest[0], &hostname[0],
146       hostnameLength, &error));
147   ASSERT_EQ(error, SEC_ERROR_EXPIRED_ISSUER_CERTIFICATE);
148 
149   // Test with a different root digest.
150   uint8_t wrongRootSHA256Digest[32] = {1};
151   ASSERT_FALSE(VerifyCodeSigningCertificateChain(
152       &certificates[0], &certificateLengths[0], numCertificates,
153       secondsSinceEpoch, &wrongRootSHA256Digest[0], &hostname[0],
154       hostnameLength, &error));
155   ASSERT_EQ(error, SEC_ERROR_UNKNOWN_ISSUER);
156 
157   // Test with a different host name.
158   const uint8_t wrongHostname[] = "example.org";
159   size_t wrongHostnameLength = strlen("example.org");
160   ASSERT_FALSE(VerifyCodeSigningCertificateChain(
161       &certificates[0], &certificateLengths[0], numCertificates,
162       secondsSinceEpoch, &rootSHA256Digest[0], &wrongHostname[0],
163       wrongHostnameLength, &error));
164   ASSERT_EQ(error, SSL_ERROR_BAD_CERT_DOMAIN);
165 
166   // Test with a certificate with an extended key usage that doesn't include
167   // code signing.
168   ByteString extendedKeyUsageExtension(
169       CreateEKUExtension(BytesToByteString(tlv_id_kp_clientAuth)));
170   ByteString endEntityWithEKU(
171       CreateCert("CA", "end-entity", EndEntityOrCA::MustBeEndEntity,
172                  &subjectAltNameExtension, &extendedKeyUsageExtension));
173   const uint8_t* certificatesWithEKU[] = {endEntityWithEKU.data(), root.data()};
174   const uint16_t certificateLengthsWithEKU[] = {
175       static_cast<uint16_t>(endEntityWithEKU.length()),
176       static_cast<uint16_t>(root.length())};
177   ASSERT_FALSE(VerifyCodeSigningCertificateChain(
178       &certificatesWithEKU[0], &certificateLengthsWithEKU[0], numCertificates,
179       secondsSinceEpoch, &rootSHA256Digest[0], &hostname[0], hostnameLength,
180       &error));
181   ASSERT_EQ(error, SEC_ERROR_INADEQUATE_CERT_TYPE);
182 }
183