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 #ifndef mozilla_pkix_pkixutil_h
26 #define mozilla_pkix_pkixutil_h
27 
28 #include "mozpkix/pkixder.h"
29 
30 namespace mozilla {
31 namespace pkix {
32 
33 // During path building and verification, we build a linked list of BackCerts
34 // from the current cert toward the end-entity certificate. The linked list
35 // is used to verify properties that aren't local to the current certificate
36 // and/or the direct link between the current certificate and its issuer,
37 // such as name constraints.
38 //
39 // Each BackCert contains pointers to all the given certificate's extensions
40 // so that we can parse the extension block once and then process the
41 // extensions in an order that may be different than they appear in the cert.
42 class BackCert final {
43  public:
44   // certDER and childCert must be valid for the lifetime of BackCert.
BackCert(Input aCertDER,EndEntityOrCA aEndEntityOrCA,const BackCert * aChildCert)45   BackCert(Input aCertDER, EndEntityOrCA aEndEntityOrCA,
46            const BackCert* aChildCert)
47       : der(aCertDER),
48         endEntityOrCA(aEndEntityOrCA),
49         childCert(aChildCert),
50         version(der::Version::Uninitialized) {}
51 
52   Result Init();
53 
GetDER()54   const Input GetDER() const { return der; }
GetSignedData()55   const der::SignedDataWithSignature& GetSignedData() const {
56     return signedData;
57   }
58 
GetVersion()59   der::Version GetVersion() const { return version; }
GetSerialNumber()60   const Input GetSerialNumber() const { return serialNumber; }
GetSignature()61   const Input GetSignature() const { return signature; }
GetIssuer()62   const Input GetIssuer() const { return issuer; }
63   // XXX: "validity" is a horrible name for the structure that holds
64   // notBefore & notAfter, but that is the name used in RFC 5280 and we use the
65   // RFC 5280 names for everything.
GetValidity()66   const Input GetValidity() const { return validity; }
GetSubject()67   const Input GetSubject() const { return subject; }
GetSubjectPublicKeyInfo()68   const Input GetSubjectPublicKeyInfo() const { return subjectPublicKeyInfo; }
GetAuthorityInfoAccess()69   const Input* GetAuthorityInfoAccess() const {
70     return MaybeInput(authorityInfoAccess);
71   }
GetBasicConstraints()72   const Input* GetBasicConstraints() const {
73     return MaybeInput(basicConstraints);
74   }
GetCertificatePolicies()75   const Input* GetCertificatePolicies() const {
76     return MaybeInput(certificatePolicies);
77   }
GetExtKeyUsage()78   const Input* GetExtKeyUsage() const { return MaybeInput(extKeyUsage); }
GetKeyUsage()79   const Input* GetKeyUsage() const { return MaybeInput(keyUsage); }
GetInhibitAnyPolicy()80   const Input* GetInhibitAnyPolicy() const {
81     return MaybeInput(inhibitAnyPolicy);
82   }
GetNameConstraints()83   const Input* GetNameConstraints() const {
84     return MaybeInput(nameConstraints);
85   }
GetSubjectAltName()86   const Input* GetSubjectAltName() const { return MaybeInput(subjectAltName); }
GetRequiredTLSFeatures()87   const Input* GetRequiredTLSFeatures() const {
88     return MaybeInput(requiredTLSFeatures);
89   }
GetSignedCertificateTimestamps()90   const Input* GetSignedCertificateTimestamps() const {
91     return MaybeInput(signedCertificateTimestamps);
92   }
93 
94  private:
95   const Input der;
96 
97  public:
98   const EndEntityOrCA endEntityOrCA;
99   BackCert const* const childCert;
100 
101  private:
102   // When parsing certificates in BackCert::Init, we don't accept empty
103   // extensions. Consequently, we don't have to store a distinction between
104   // empty extensions and extensions that weren't included. However, when
105   // *processing* extensions, we distinguish between whether an extension was
106   // included or not based on whetehr the GetXXX function for the extension
107   // returns nullptr.
MaybeInput(const Input & item)108   static inline const Input* MaybeInput(const Input& item) {
109     return item.GetLength() > 0 ? &item : nullptr;
110   }
111 
112   der::SignedDataWithSignature signedData;
113 
114   der::Version version;
115   Input serialNumber;
116   Input signature;
117   Input issuer;
118   // XXX: "validity" is a horrible name for the structure that holds
119   // notBefore & notAfter, but that is the name used in RFC 5280 and we use the
120   // RFC 5280 names for everything.
121   Input validity;
122   Input subject;
123   Input subjectPublicKeyInfo;
124 
125   Input authorityInfoAccess;
126   Input basicConstraints;
127   Input certificatePolicies;
128   Input extKeyUsage;
129   Input inhibitAnyPolicy;
130   Input keyUsage;
131   Input nameConstraints;
132   Input subjectAltName;
133   Input criticalNetscapeCertificateType;
134   Input requiredTLSFeatures;
135   Input signedCertificateTimestamps;  // RFC 6962 (Certificate Transparency)
136 
137   Result RememberExtension(Reader& extnID, Input extnValue, bool critical,
138                            /*out*/ bool& understood);
139 
140   BackCert(const BackCert&) = delete;
141   void operator=(const BackCert&) = delete;
142 };
143 
144 class NonOwningDERArray final : public DERArray {
145  public:
NonOwningDERArray()146   NonOwningDERArray() : numItems(0) {
147     // we don't need to initialize the items array because we always check
148     // numItems before accessing i.
149   }
150 
GetLength()151   size_t GetLength() const override { return numItems; }
152 
GetDER(size_t i)153   const Input* GetDER(size_t i) const override {
154     return i < numItems ? &items[i] : nullptr;
155   }
156 
Append(Input der)157   Result Append(Input der) {
158     if (numItems >= MAX_LENGTH) {
159       return Result::FATAL_ERROR_INVALID_ARGS;
160     }
161     Result rv = items[numItems].Init(der);  // structure assignment
162     if (rv != Success) {
163       return rv;
164     }
165     ++numItems;
166     return Success;
167   }
168 
169   // Public so we can static_assert on this. Keep in sync with MAX_SUBCA_COUNT.
170   static const size_t MAX_LENGTH = 8;
171 
172  private:
173   Input items[MAX_LENGTH];  // avoids any heap allocations
174   size_t numItems;
175 
176   NonOwningDERArray(const NonOwningDERArray&) = delete;
177   void operator=(const NonOwningDERArray&) = delete;
178 };
179 
180 // Extracts the SignedCertificateTimestampList structure which is encoded as an
181 // OCTET STRING within the X.509v3 / OCSP extensions (see RFC 6962 section 3.3).
182 Result ExtractSignedCertificateTimestampListFromExtension(Input extnValue,
183                                                           Input& sctList);
184 
DaysBeforeYear(unsigned int year)185 inline unsigned int DaysBeforeYear(unsigned int year) {
186   assert(year <= 9999);
187   return ((year - 1u) * 365u) +
188          ((year - 1u) / 4u)       // leap years are every 4 years,
189          - ((year - 1u) / 100u)   // except years divisible by 100,
190          + ((year - 1u) / 400u);  // except years divisible by 400.
191 }
192 
193 static const size_t MAX_DIGEST_SIZE_IN_BYTES = 512 / 8;  // sha-512
194 
195 Result DigestSignedData(TrustDomain& trustDomain,
196                         const der::SignedDataWithSignature& signedData,
197                         /*out*/ uint8_t (&digestBuf)[MAX_DIGEST_SIZE_IN_BYTES],
198                         /*out*/ der::PublicKeyAlgorithm& publicKeyAlg,
199                         /*out*/ SignedDigest& signedDigest);
200 
201 Result VerifySignedDigest(TrustDomain& trustDomain,
202                           der::PublicKeyAlgorithm publicKeyAlg,
203                           const SignedDigest& signedDigest,
204                           Input signerSubjectPublicKeyInfo);
205 
206 // Combines DigestSignedData and VerifySignedDigest
207 Result VerifySignedData(TrustDomain& trustDomain,
208                         const der::SignedDataWithSignature& signedData,
209                         Input signerSubjectPublicKeyInfo);
210 
211 // Extracts the key parameters from |subjectPublicKeyInfo|, invoking
212 // the relevant methods of |trustDomain|.
213 Result CheckSubjectPublicKeyInfo(Input subjectPublicKeyInfo,
214                                  TrustDomain& trustDomain,
215                                  EndEntityOrCA endEntityOrCA);
216 
217 // In a switch over an enum, sometimes some compilers are not satisfied that
218 // all control flow paths have been considered unless there is a default case.
219 // However, in our code, such a default case is almost always unreachable dead
220 // code. That can be particularly problematic when the compiler wants the code
221 // to choose a value, such as a return value, for the default case, but there's
222 // no appropriate "impossible case" value to choose.
223 //
224 // MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM accounts for this. Example:
225 //
226 //     // In xy.cpp
227 //     #include "xt.h"
228 //
229 //     enum class XY { X, Y };
230 //
231 //     int func(XY xy) {
232 //       switch (xy) {
233 //         case XY::X: return 1;
234 //         case XY::Y; return 2;
235 //         MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
236 //       }
237 //     }
238 #if defined(__clang__)
239 // Clang will warn if not all cases are covered (-Wswitch-enum) AND it will
240 // warn if a switch statement that covers every enum label has a default case
241 // (-W-covered-switch-default). Versions prior to 3.5 warned about unreachable
242 // code in such default cases (-Wunreachable-code) even when
243 // -W-covered-switch-default was disabled, but that changed in Clang 3.5.
244 #define MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM  // empty
245 #elif defined(__GNUC__)
246 // GCC will warn if not all cases are covered (-Wswitch-enum). It does not
247 // assume that the default case is unreachable.
248 #define MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM \
249   default:                                    \
250     assert(false);                            \
251     __builtin_unreachable();
252 #elif defined(_MSC_VER)
253 // MSVC will warn if not all cases are covered (C4061, level 4). It does not
254 // assume that the default case is unreachable.
255 #define MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM \
256   default:                                    \
257     assert(false);                            \
258     __assume(0);
259 #else
260 #error Unsupported compiler for MOZILLA_PKIX_UNREACHABLE_DEFAULT.
261 #endif
262 
DigestAlgorithmToSizeInBytes(DigestAlgorithm digestAlgorithm)263 inline size_t DigestAlgorithmToSizeInBytes(DigestAlgorithm digestAlgorithm) {
264   switch (digestAlgorithm) {
265     case DigestAlgorithm::sha1:
266       return 160 / 8;
267     case DigestAlgorithm::sha256:
268       return 256 / 8;
269     case DigestAlgorithm::sha384:
270       return 384 / 8;
271     case DigestAlgorithm::sha512:
272       return 512 / 8;
273       MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
274   }
275 }
276 }
277 }  // namespace mozilla::pkix
278 
279 #endif  // mozilla_pkix_pkixutil_h
280