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