pkixc_tests.cpp (7901B)
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 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 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 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 }