tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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