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 "pkixder.h"
26 #include "pkixgtest.h"
27 #include "pkixtestutil.h"
28
29 using namespace mozilla::pkix;
30 using namespace mozilla::pkix::test;
31
32 // Creates a self-signed certificate with the given extension.
CreateCertWithExtensions(const char * subjectCN,const ByteString * extensions)33 static ByteString CreateCertWithExtensions(const char* subjectCN,
34 const ByteString* extensions) {
35 static long serialNumberValue = 0;
36 ++serialNumberValue;
37 ByteString serialNumber(CreateEncodedSerialNumber(serialNumberValue));
38 EXPECT_FALSE(ENCODING_FAILED(serialNumber));
39 ByteString issuerDER(CNToDERName(subjectCN));
40 EXPECT_FALSE(ENCODING_FAILED(issuerDER));
41 ByteString subjectDER(CNToDERName(subjectCN));
42 EXPECT_FALSE(ENCODING_FAILED(subjectDER));
43 ScopedTestKeyPair subjectKey(CloneReusedKeyPair());
44 return CreateEncodedCertificate(v3, sha256WithRSAEncryption(), serialNumber,
45 issuerDER, oneDayBeforeNow, oneDayAfterNow,
46 subjectDER, *subjectKey, extensions,
47 *subjectKey, sha256WithRSAEncryption());
48 }
49
50 // Creates a self-signed certificate with the given extension.
CreateCertWithOneExtension(const char * subjectStr,const ByteString & extension)51 static ByteString CreateCertWithOneExtension(const char* subjectStr,
52 const ByteString& extension) {
53 const ByteString extensions[] = {extension, ByteString()};
54 return CreateCertWithExtensions(subjectStr, extensions);
55 }
56
57 class TrustEverythingTrustDomain final : public DefaultCryptoTrustDomain {
58 private:
GetCertTrust(EndEntityOrCA,const CertPolicyId &,Input,TrustLevel & trustLevel)59 Result GetCertTrust(EndEntityOrCA, const CertPolicyId&, Input,
60 /*out*/ TrustLevel& trustLevel) override {
61 trustLevel = TrustLevel::TrustAnchor;
62 return Success;
63 }
64
CheckRevocation(EndEntityOrCA,const CertID &,Time,Duration,const Input *,const Input *)65 Result CheckRevocation(EndEntityOrCA, const CertID&, Time, Duration,
66 /*optional*/ const Input*,
67 /*optional*/ const Input*) override {
68 return Success;
69 }
70
IsChainValid(const DERArray &,Time,const CertPolicyId &)71 Result IsChainValid(const DERArray&, Time, const CertPolicyId&) override {
72 return Success;
73 }
74 };
75
76 // python DottedOIDToCode.py --tlv
77 // unknownExtensionOID 1.3.6.1.4.1.13769.666.666.666.1.500.9.3
78 static const uint8_t tlv_unknownExtensionOID[] = {
79 0x06, 0x12, 0x2b, 0x06, 0x01, 0x04, 0x01, 0xeb, 0x49, 0x85,
80 0x1a, 0x85, 0x1a, 0x85, 0x1a, 0x01, 0x83, 0x74, 0x09, 0x03};
81
82 // python DottedOIDToCode.py --tlv
83 // id-pe-authorityInformationAccess 1.3.6.1.5.5.7.1.1
84 static const uint8_t tlv_id_pe_authorityInformationAccess[] = {
85 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01};
86
87 // python DottedOIDToCode.py --tlv wrongExtensionOID 1.3.6.6.1.5.5.7.1.1
88 // (there is an extra "6" that shouldn't be in this OID)
89 static const uint8_t tlv_wrongExtensionOID[] = {
90 0x06, 0x09, 0x2b, 0x06, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x01};
91
92 // python DottedOIDToCode.py --tlv id-ce-unknown 2.5.29.55
93 // (this is a made-up OID for testing "id-ce"-prefixed OIDs that mozilla::pkix
94 // doesn't handle)
95 static const uint8_t tlv_id_ce_unknown[] = {0x06, 0x03, 0x55, 0x1d, 0x37};
96
97 // python DottedOIDToCode.py --tlv id-ce-inhibitAnyPolicy 2.5.29.54
98 static const uint8_t tlv_id_ce_inhibitAnyPolicy[] = {0x06, 0x03, 0x55, 0x1d,
99 0x36};
100
101 // python DottedOIDToCode.py --tlv id-pkix-ocsp-nocheck 1.3.6.1.5.5.7.48.1.5
102 static const uint8_t tlv_id_pkix_ocsp_nocheck[] = {
103 0x06, 0x09, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x05};
104
105 struct ExtensionTestcase {
106 ByteString extension;
107 Result expectedResult;
108 };
109
operator <<(::std::ostream & os,const ExtensionTestcase &)110 ::std::ostream& operator<<(::std::ostream& os, const ExtensionTestcase&) {
111 return os << "TODO (bug 1318770)";
112 }
113
114 static const ExtensionTestcase EXTENSION_TESTCASES[] = {
115 // Tests that a non-critical extension not in the id-ce or id-pe arcs (which
116 // is thus unknown to us) verifies successfully even if empty (extensions we
117 // know about aren't normally allowed to be empty).
118 {TLV(der::SEQUENCE, BytesToByteString(tlv_unknownExtensionOID) +
119 TLV(der::OCTET_STRING, ByteString())),
120 Success},
121
122 // Tests that a critical extension not in the id-ce or id-pe arcs (which is
123 // thus unknown to us) is detected and that verification fails with the
124 // appropriate error.
125 {TLV(der::SEQUENCE, BytesToByteString(tlv_unknownExtensionOID) +
126 Boolean(true) +
127 TLV(der::OCTET_STRING, ByteString())),
128 Result::ERROR_UNKNOWN_CRITICAL_EXTENSION},
129
130 // Tests that a id-pe-authorityInformationAccess critical extension
131 // is detected and that verification succeeds.
132 // XXX: According to RFC 5280 an AIA that consists of an empty sequence is
133 // not legal, but we accept it and that is not what we're testing here.
134 {TLV(der::SEQUENCE,
135 BytesToByteString(tlv_id_pe_authorityInformationAccess) +
136 Boolean(true) +
137 TLV(der::OCTET_STRING, TLV(der::SEQUENCE, ByteString()))),
138 Success},
139
140 // Tests that an incorrect OID for id-pe-authorityInformationAccess
141 // (when marked critical) is detected and that verification fails.
142 // (Until bug 1020993 was fixed, this wrong value was used for
143 // id-pe-authorityInformationAccess.)
144 {TLV(der::SEQUENCE, BytesToByteString(tlv_wrongExtensionOID) +
145 Boolean(true) +
146 TLV(der::OCTET_STRING, ByteString())),
147 Result::ERROR_UNKNOWN_CRITICAL_EXTENSION},
148
149 // We know about some id-ce extensions (OID arc 2.5.29), but not all of
150 // them. Tests that an unknown id-ce extension is detected and that
151 // verification fails.
152 {TLV(der::SEQUENCE, BytesToByteString(tlv_id_ce_unknown) + Boolean(true) +
153 TLV(der::OCTET_STRING, ByteString())),
154 Result::ERROR_UNKNOWN_CRITICAL_EXTENSION},
155
156 // Tests that a certificate with a known critical id-ce extension (in this
157 // case, OID 2.5.29.54, which is id-ce-inhibitAnyPolicy), verifies
158 // successfully.
159 {TLV(der::SEQUENCE, BytesToByteString(tlv_id_ce_inhibitAnyPolicy) +
160 Boolean(true) + TLV(der::OCTET_STRING, Integer(0))),
161 Success},
162
163 // Tests that a certificate with the id-pkix-ocsp-nocheck extension (marked
164 // critical) verifies successfully.
165 // RFC 6960:
166 // ext-ocsp-nocheck EXTENSION ::= { SYNTAX NULL IDENTIFIED
167 // BY id-pkix-ocsp-nocheck }
168 {TLV(der::SEQUENCE,
169 BytesToByteString(tlv_id_pkix_ocsp_nocheck) + Boolean(true) +
170 TLV(der::OCTET_STRING, TLV(der::NULLTag, ByteString()))),
171 Success},
172
173 // Tests that a certificate with another representation of the
174 // id-pkix-ocsp-nocheck extension (marked critical) verifies successfully.
175 // According to http://comments.gmane.org/gmane.ietf.x509/30947,
176 // some code creates certificates where value of the extension is
177 // an empty OCTET STRING.
178 {TLV(der::SEQUENCE, BytesToByteString(tlv_id_pkix_ocsp_nocheck) +
179 Boolean(true) +
180 TLV(der::OCTET_STRING, ByteString())),
181 Success},
182 };
183
184 class pkixcert_extension
185 : public ::testing::Test,
186 public ::testing::WithParamInterface<ExtensionTestcase> {
187 protected:
188 static TrustEverythingTrustDomain trustDomain;
189 };
190
191 /*static*/ TrustEverythingTrustDomain pkixcert_extension::trustDomain;
192
TEST_P(pkixcert_extension,ExtensionHandledProperly)193 TEST_P(pkixcert_extension, ExtensionHandledProperly) {
194 const ExtensionTestcase& testcase(GetParam());
195 const char* cn = "Cert Extension Test";
196 ByteString cert(CreateCertWithOneExtension(cn, testcase.extension));
197 ASSERT_FALSE(ENCODING_FAILED(cert));
198 Input certInput;
199 ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
200 ASSERT_EQ(testcase.expectedResult,
201 BuildCertChain(
202 trustDomain, certInput, Now(), EndEntityOrCA::MustBeEndEntity,
203 KeyUsage::noParticularKeyUsageRequired,
204 KeyPurposeId::anyExtendedKeyUsage, CertPolicyId::anyPolicy,
205 nullptr /*stapledOCSPResponse*/));
206 }
207
208 INSTANTIATE_TEST_CASE_P(pkixcert_extension, pkixcert_extension,
209 testing::ValuesIn(EXTENSION_TESTCASES));
210
211 // Two subjectAltNames must result in an error.
TEST_F(pkixcert_extension,DuplicateSubjectAltName)212 TEST_F(pkixcert_extension, DuplicateSubjectAltName) {
213 // python DottedOIDToCode.py --tlv id-ce-subjectAltName 2.5.29.17
214 static const uint8_t tlv_id_ce_subjectAltName[] = {0x06, 0x03, 0x55, 0x1d,
215 0x11};
216
217 ByteString subjectAltName(TLV(
218 der::SEQUENCE,
219 BytesToByteString(tlv_id_ce_subjectAltName) +
220 TLV(der::OCTET_STRING, TLV(der::SEQUENCE, DNSName("example.com")))));
221 static const ByteString extensions[] = {subjectAltName, subjectAltName,
222 ByteString()};
223 static const char* certCN = "Cert With Duplicate subjectAltName";
224 ByteString cert(CreateCertWithExtensions(certCN, extensions));
225 ASSERT_FALSE(ENCODING_FAILED(cert));
226 Input certInput;
227 ASSERT_EQ(Success, certInput.Init(cert.data(), cert.length()));
228 ASSERT_EQ(Result::ERROR_EXTENSION_VALUE_INVALID,
229 BuildCertChain(
230 trustDomain, certInput, Now(), EndEntityOrCA::MustBeEndEntity,
231 KeyUsage::noParticularKeyUsageRequired,
232 KeyPurposeId::anyExtendedKeyUsage, CertPolicyId::anyPolicy,
233 nullptr /*stapledOCSPResponse*/));
234 }
235