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