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