Coverage Report

Created: 2018-09-25 14:53

/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