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