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