pkixcert_extension_tests.cpp (11474B)
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 /* This code is made available to you under your choice of the following sets 4 * of licensing terms: 5 */ 6 /* This Source Code Form is subject to the terms of the Mozilla Public 7 * License, v. 2.0. If a copy of the MPL was not distributed with this 8 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 9 */ 10 /* Copyright 2013 Mozilla Contributors 11 * 12 * Licensed under the Apache License, Version 2.0 (the "License"); 13 * you may not use this file except in compliance with the License. 14 * You may obtain a copy of the License at 15 * 16 * http://www.apache.org/licenses/LICENSE-2.0 17 * 18 * Unless required by applicable law or agreed to in writing, software 19 * distributed under the License is distributed on an "AS IS" BASIS, 20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 21 * See the License for the specific language governing permissions and 22 * limitations under the License. 23 */ 24 25 #include "pkixgtest.h" 26 27 #include "mozpkix/pkixder.h" 28 #include "mozpkix/pkixutil.h" 29 #include "mozpkix/test/pkixtestutil.h" 30 31 using namespace mozilla::pkix; 32 using namespace mozilla::pkix::test; 33 34 // Creates a self-signed certificate with the given extension. 35 static ByteString 36 CreateCertWithExtensions(const char* subjectCN, 37 const ByteString* extensions) 38 { 39 static long serialNumberValue = 0; 40 ++serialNumberValue; 41 ByteString serialNumber(CreateEncodedSerialNumber(serialNumberValue)); 42 EXPECT_FALSE(ENCODING_FAILED(serialNumber)); 43 ByteString issuerDER(CNToDERName(subjectCN)); 44 EXPECT_FALSE(ENCODING_FAILED(issuerDER)); 45 ByteString subjectDER(CNToDERName(subjectCN)); 46 EXPECT_FALSE(ENCODING_FAILED(subjectDER)); 47 ScopedTestKeyPair subjectKey(CloneReusedKeyPair()); 48 return CreateEncodedCertificate(v3, sha256WithRSAEncryption(), 49 serialNumber, issuerDER, 50 oneDayBeforeNow, oneDayAfterNow, 51 subjectDER, *subjectKey, extensions, 52 *subjectKey, 53 sha256WithRSAEncryption()); 54 } 55 56 // Creates a self-signed certificate with the given extension. 57 static ByteString 58 CreateCertWithOneExtension(const char* subjectStr, const ByteString& extension) 59 { 60 const ByteString extensions[] = { extension, ByteString() }; 61 return CreateCertWithExtensions(subjectStr, extensions); 62 } 63 64 class TrustEverythingTrustDomain final : public DefaultCryptoTrustDomain 65 { 66 private: 67 Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input, 68 /*out*/ TrustLevel& trustLevel) override 69 { 70 trustLevel = TrustLevel::TrustAnchor; 71 return Success; 72 } 73 74 Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration, 75 /*optional*/ const Input*, /*optional*/ const Input*) 76 override 77 { 78 return Success; 79 } 80 81 Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override 82 { 83 return Success; 84 } 85 }; 86 87 // python DottedOIDToCode.py --tlv unknownExtensionOID 1.3.6.1.4.1.13769.666.666.666.1.500.9.3 88 static const uint8_t tlv_unknownExtensionOID[] = { 89 0x06, 0x12, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xeb, 0x49, 0x85, 0x1a, 0x85, 0x1a, 90 0x85, 0x1a, 0x01, 0x83, 0x74, 0x09, 0x03 91 }; 92 93 // python DottedOIDToCode.py --tlv id-pe-authorityInformationAccess 1.3.6.1.5.5.7.1.1 94 static const uint8_t tlv_id_pe_authorityInformationAccess[] = { 95 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01 96 }; 97 98 // python DottedOIDToCode.py --tlv wrongExtensionOID 1.3.6.6.1.5.5.7.1.1 99 // (there is an extra "6" that shouldn't be in this OID) 100 static const uint8_t tlv_wrongExtensionOID[] = { 101 0x06, 0x09, 0x2b, 0x06, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01 102 }; 103 104 // python DottedOIDToCode.py --tlv id-ce-unknown 2.5.29.55 105 // (this is a made-up OID for testing "id-ce"-prefixed OIDs that mozilla::pkix 106 // doesn't handle) 107 static const uint8_t tlv_id_ce_unknown[] = { 108 0x06, 0x03, 0x55, 0x1d, 0x37 109 }; 110 111 // python DottedOIDToCode.py --tlv id-ce-inhibitAnyPolicy 2.5.29.54 112 static const uint8_t tlv_id_ce_inhibitAnyPolicy[] = { 113 0x06, 0x03, 0x55, 0x1d, 0x36 114 }; 115 116 // python DottedOIDToCode.py --tlv id-pkix-ocsp-nocheck 1.3.6.1.5.5.7.48.1.5 117 static const uint8_t tlv_id_pkix_ocsp_nocheck[] = { 118 0x06, 0x09, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x05 119 }; 120 121 struct ExtensionTestcase 122 { 123 ByteString extension; 124 Result expectedResult; 125 }; 126 127 ::std::ostream& operator<<(::std::ostream& os, const ExtensionTestcase&) 128 { 129 return os << "TODO (bug 1318770)"; 130 } 131 132 static const ExtensionTestcase EXTENSION_TESTCASES[] = 133 { 134 // Tests that a non-critical extension not in the id-ce or id-pe arcs (which 135 // is thus unknown to us) verifies successfully even if empty (extensions we 136 // know about aren't normally allowed to be empty). 137 { TLV(der::SEQUENCE, 138 BytesToByteString(tlv_unknownExtensionOID) + 139 TLV(der::OCTET_STRING, ByteString())), 140 Success 141 }, 142 143 // Tests that a critical extension not in the id-ce or id-pe arcs (which is 144 // thus unknown to us) is detected and that verification fails with the 145 // appropriate error. 146 { TLV(der::SEQUENCE, 147 BytesToByteString(tlv_unknownExtensionOID) + 148 Boolean(true) + 149 TLV(der::OCTET_STRING, ByteString())), 150 Result::ERROR_UNKNOWN_CRITICAL_EXTENSION 151 }, 152 153 // Tests that a id-pe-authorityInformationAccess critical extension 154 // is detected and that verification succeeds. 155 // XXX: According to RFC 5280 an AIA that consists of an empty sequence is 156 // not legal, but we accept it and that is not what we're testing here. 157 { TLV(der::SEQUENCE, 158 BytesToByteString(tlv_id_pe_authorityInformationAccess) + 159 Boolean(true) + 160 TLV(der::OCTET_STRING, TLV(der::SEQUENCE, ByteString()))), 161 Success 162 }, 163 164 // Tests that an incorrect OID for id-pe-authorityInformationAccess 165 // (when marked critical) is detected and that verification fails. 166 // (Until bug 1020993 was fixed, this wrong value was used for 167 // id-pe-authorityInformationAccess.) 168 { TLV(der::SEQUENCE, 169 BytesToByteString(tlv_wrongExtensionOID) + 170 Boolean(true) + 171 TLV(der::OCTET_STRING, ByteString())), 172 Result::ERROR_UNKNOWN_CRITICAL_EXTENSION 173 }, 174 175 // We know about some id-ce extensions (OID arc 2.5.29), but not all of them. 176 // Tests that an unknown id-ce extension is detected and that verification 177 // fails. 178 { TLV(der::SEQUENCE, 179 BytesToByteString(tlv_id_ce_unknown) + 180 Boolean(true) + 181 TLV(der::OCTET_STRING, ByteString())), 182 Result::ERROR_UNKNOWN_CRITICAL_EXTENSION 183 }, 184 185 // Tests that a certificate with a known critical id-ce extension (in this 186 // case, OID 2.5.29.54, which is id-ce-inhibitAnyPolicy), verifies 187 // successfully. 188 { TLV(der::SEQUENCE, 189 BytesToByteString(tlv_id_ce_inhibitAnyPolicy) + 190 Boolean(true) + 191 TLV(der::OCTET_STRING, Integer(0))), 192 Success 193 }, 194 195 // Tests that a certificate with the id-pkix-ocsp-nocheck extension (marked 196 // critical) verifies successfully. 197 // RFC 6960: 198 // ext-ocsp-nocheck EXTENSION ::= { SYNTAX NULL IDENTIFIED 199 // BY id-pkix-ocsp-nocheck } 200 { TLV(der::SEQUENCE, 201 BytesToByteString(tlv_id_pkix_ocsp_nocheck) + 202 Boolean(true) + 203 TLV(der::OCTET_STRING, TLV(der::NULLTag, ByteString()))), 204 Success 205 }, 206 207 // Tests that a certificate with another representation of the 208 // id-pkix-ocsp-nocheck extension (marked critical) verifies successfully. 209 // According to http://comments.gmane.org/gmane.ietf.x509/30947, 210 // some code creates certificates where value of the extension is 211 // an empty OCTET STRING. 212 { TLV(der::SEQUENCE, 213 BytesToByteString(tlv_id_pkix_ocsp_nocheck) + 214 Boolean(true) + 215 TLV(der::OCTET_STRING, ByteString())), 216 Success 217 }, 218 }; 219 220 class pkixcert_extension 221 : public ::testing::Test 222 , public ::testing::WithParamInterface<ExtensionTestcase> 223 { 224 protected: 225 static TrustEverythingTrustDomain trustDomain; 226 }; 227 228 /*static*/ TrustEverythingTrustDomain pkixcert_extension::trustDomain; 229 230 TEST_P(pkixcert_extension, ExtensionHandledProperly) 231 { 232 const ExtensionTestcase& testcase(GetParam()); 233 const char* cn = "Cert Extension Test"; 234 ByteString cert(CreateCertWithOneExtension(cn, testcase.extension)); 235 ASSERT_FALSE(ENCODING_FAILED(cert)); 236 Input certInput; 237 ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length())); 238 ASSERT_EQ(testcase.expectedResult, 239 BuildCertChain(trustDomain, certInput, Now(), 240 EndEntityOrCA::MustBeEndEntity, 241 KeyUsage::noParticularKeyUsageRequired, 242 KeyPurposeId::anyExtendedKeyUsage, 243 CertPolicyId::anyPolicy, 244 nullptr/*stapledOCSPResponse*/)); 245 } 246 247 INSTANTIATE_TEST_SUITE_P(pkixcert_extension, 248 pkixcert_extension, 249 testing::ValuesIn(EXTENSION_TESTCASES)); 250 251 // Two subjectAltNames must result in an error. 252 TEST_F(pkixcert_extension, DuplicateSubjectAltName) 253 { 254 // python DottedOIDToCode.py --tlv id-ce-subjectAltName 2.5.29.17 255 static const uint8_t tlv_id_ce_subjectAltName[] = { 256 0x06, 0x03, 0x55, 0x1d, 0x11 257 }; 258 259 ByteString subjectAltName( 260 TLV(der::SEQUENCE, 261 BytesToByteString(tlv_id_ce_subjectAltName) + 262 TLV(der::OCTET_STRING, TLV(der::SEQUENCE, DNSName("example.com"))))); 263 static const ByteString extensions[] = { subjectAltName, subjectAltName, 264 ByteString() }; 265 static const char* certCN = "Cert With Duplicate subjectAltName"; 266 ByteString cert(CreateCertWithExtensions(certCN, extensions)); 267 ASSERT_FALSE(ENCODING_FAILED(cert)); 268 Input certInput; 269 ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length())); 270 ASSERT_EQ(Result::ERROR_EXTENSION_VALUE_INVALID, 271 BuildCertChain(trustDomain, certInput, Now(), 272 EndEntityOrCA::MustBeEndEntity, 273 KeyUsage::noParticularKeyUsageRequired, 274 KeyPurposeId::anyExtendedKeyUsage, 275 CertPolicyId::anyPolicy, 276 nullptr/*stapledOCSPResponse*/)); 277 } 278 279 TEST_F(pkixcert_extension, QCStatements) 280 { 281 // python DottedOIDToCode.py --tlv id-pe-qcStatements 1.3.6.1.5.5.7.1.3 282 const uint8_t tlv_id_pe_qcStatements[] = { 283 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x03 284 }; 285 286 ByteString qcStatementsBytes( 287 TLV(der::SEQUENCE, 288 BytesToByteString(tlv_id_pe_qcStatements) + 289 TLV(der::OCTET_STRING, ByteString(reinterpret_cast<const uint8_t*>("qcStatements contents"))))); 290 const ByteString extensions[] = { qcStatementsBytes, ByteString() }; 291 const char* certCN = "Cert With qcStatements"; 292 ByteString cert(CreateCertWithExtensions(certCN, extensions)); 293 ASSERT_FALSE(ENCODING_FAILED(cert)); 294 Input certInput; 295 ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length())); 296 BackCert backCert(certInput, EndEntityOrCA::MustBeEndEntity, nullptr); 297 ASSERT_EQ(Success, backCert.Init()); 298 const Input *qcStatements(backCert.GetQCStatements()); 299 ASSERT_TRUE(qcStatements); 300 ByteString qcStatementsContents(qcStatements->UnsafeGetData(), qcStatements->GetLength()); 301 ASSERT_EQ(ByteString(reinterpret_cast<const uint8_t*>("qcStatements contents")), qcStatementsContents); 302 }