Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/security/pkix/lib/pkixocsp.cpp
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
#include <limits>
26
27
#include "pkix/pkix.h"
28
#include "pkixcheck.h"
29
#include "pkixutil.h"
30
31
namespace {
32
33
const size_t SHA1_DIGEST_LENGTH = 160 / 8;
34
35
} // namespace
36
37
namespace mozilla { namespace pkix {
38
39
// These values correspond to the tag values in the ASN.1 CertStatus
40
enum class CertStatus : uint8_t {
41
  Good = der::CONTEXT_SPECIFIC | 0,
42
  Revoked = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1,
43
  Unknown = der::CONTEXT_SPECIFIC | 2
44
};
45
46
class Context final
47
{
48
public:
49
  Context(TrustDomain& aTrustDomain, const CertID& aCertID, Time aTime,
50
          uint16_t aMaxLifetimeInDays, /*optional out*/ Time* aThisUpdate,
51
          /*optional out*/ Time* aValidThrough)
52
    : trustDomain(aTrustDomain)
53
    , certID(aCertID)
54
    , time(aTime)
55
    , maxLifetimeInDays(aMaxLifetimeInDays)
56
    , certStatus(CertStatus::Unknown)
57
    , thisUpdate(aThisUpdate)
58
    , validThrough(aValidThrough)
59
    , expired(false)
60
    , matchFound(false)
61
0
  {
62
0
    if (thisUpdate) {
63
0
      *thisUpdate = TimeFromElapsedSecondsAD(0);
64
0
    }
65
0
    if (validThrough) {
66
0
      *validThrough = TimeFromElapsedSecondsAD(0);
67
0
    }
68
0
  }
69
70
  TrustDomain& trustDomain;
71
  const CertID& certID;
72
  const Time time;
73
  const uint16_t maxLifetimeInDays;
74
  CertStatus certStatus;
75
  Time* thisUpdate;
76
  Time* validThrough;
77
  bool expired;
78
79
  Input signedCertificateTimestamps;
80
81
  // Keep track of whether the OCSP response contains the status of the
82
  // certificate we're interested in. Responders might reply without
83
  // including the status of any of the requested certs, we should
84
  // indicate a server failure in those cases.
85
  bool matchFound;
86
87
  Context(const Context&) = delete;
88
  void operator=(const Context&) = delete;
89
};
90
91
// Verify that potentialSigner is a valid delegated OCSP response signing cert
92
// according to RFC 6960 section 4.2.2.2.
93
static Result
94
CheckOCSPResponseSignerCert(TrustDomain& trustDomain,
95
                            BackCert& potentialSigner,
96
                            Input issuerSubject,
97
                            Input issuerSubjectPublicKeyInfo,
98
                            Time time)
99
0
{
100
0
  Result rv;
101
0
102
0
  // We don't need to do a complete verification of the signer (i.e. we don't
103
0
  // have to call BuildCertChain to verify the entire chain) because we
104
0
  // already know that the issuer is valid, since revocation checking is done
105
0
  // from the root to the parent after we've built a complete chain that we
106
0
  // know is otherwise valid. Rather, we just need to do a one-step validation
107
0
  // from potentialSigner to the issuer.
108
0
  //
109
0
  // It seems reasonable to require the KU_DIGITAL_SIGNATURE key usage on the
110
0
  // OCSP responder certificate if the OCSP responder certificate has a
111
0
  // key usage extension. However, according to bug 240456, some OCSP responder
112
0
  // certificates may have only the nonRepudiation bit set. Also, the OCSP
113
0
  // specification (RFC 6960) does not mandate any particular key usage to be
114
0
  // asserted for OCSP responde signers. Oddly, the CABForum Baseline
115
0
  // Requirements v.1.1.5 do say "If the Root CA Private Key is used for
116
0
  // signing OCSP responses, then the digitalSignature bit MUST be set."
117
0
  //
118
0
  // Note that CheckIssuerIndependentProperties processes
119
0
  // SEC_OID_OCSP_RESPONDER in the way that the OCSP specification requires us
120
0
  // to--in particular, it doesn't allow SEC_OID_OCSP_RESPONDER to be implied
121
0
  // by a missing EKU extension, unlike other EKUs.
122
0
  //
123
0
  // TODO(bug 926261): If we're validating for a policy then the policy OID we
124
0
  // are validating for should be passed to CheckIssuerIndependentProperties.
125
0
  TrustLevel unusedTrustLevel;
126
0
  rv = CheckIssuerIndependentProperties(trustDomain, potentialSigner, time,
127
0
                                        KeyUsage::noParticularKeyUsageRequired,
128
0
                                        KeyPurposeId::id_kp_OCSPSigning,
129
0
                                        CertPolicyId::anyPolicy, 0,
130
0
                                        unusedTrustLevel);
131
0
  if (rv != Success) {
132
0
    return rv;
133
0
  }
134
0
135
0
  // It is possible that there exists a certificate with the same key as the
136
0
  // issuer but with a different name, so we need to compare names
137
0
  // XXX(bug 926270) XXX(bug 1008133) XXX(bug 980163): Improve name
138
0
  // comparison.
139
0
  // TODO: needs test
140
0
  if (!InputsAreEqual(potentialSigner.GetIssuer(), issuerSubject)) {
141
0
    return Result::ERROR_OCSP_RESPONDER_CERT_INVALID;
142
0
  }
143
0
144
0
  // TODO(bug 926260): check name constraints
145
0
146
0
  rv = VerifySignedData(trustDomain, potentialSigner.GetSignedData(),
147
0
                        issuerSubjectPublicKeyInfo);
148
0
149
0
  // TODO: check for revocation of the OCSP responder certificate unless no-check
150
0
  // or the caller forcing no-check. To properly support the no-check policy, we'd
151
0
  // need to enforce policy constraints from the issuerChain.
152
0
153
0
  return rv;
154
0
}
155
156
enum class ResponderIDType : uint8_t
157
{
158
  byName = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1,
159
  byKey = der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 2
160
};
161
162
static inline Result OCSPResponse(Reader&, Context&);
163
static inline Result ResponseBytes(Reader&, Context&);
164
static inline Result BasicResponse(Reader&, Context&);
165
static inline Result ResponseData(
166
                       Reader& tbsResponseData,
167
                       Context& context,
168
                       const der::SignedDataWithSignature& signedResponseData,
169
                       const DERArray& certs);
170
static inline Result SingleResponse(Reader& input, Context& context);
171
static Result ExtensionNotUnderstood(Reader& extnID, Input extnValue,
172
                                     bool critical, /*out*/ bool& understood);
173
static Result RememberSingleExtension(Context& context, Reader& extnID,
174
                                      Input extnValue, bool critical,
175
                                      /*out*/ bool& understood);
176
// It is convention to name the function after the part of the data structure
177
// we're parsing from the RFC (e.g. OCSPResponse, ResponseBytes).
178
// But since we also have a C++ type called CertID, this function doesn't
179
// follow the convention to prevent shadowing.
180
static inline Result MatchCertID(Reader& input,
181
                                 const Context& context,
182
                                 /*out*/ bool& match);
183
static Result MatchKeyHash(TrustDomain& trustDomain,
184
                           Input issuerKeyHash,
185
                           Input issuerSubjectPublicKeyInfo,
186
                           /*out*/ bool& match);
187
static Result KeyHash(TrustDomain& trustDomain,
188
                      Input subjectPublicKeyInfo,
189
                      /*out*/ uint8_t* hashBuf, size_t hashBufSize);
190
191
static Result
192
MatchResponderID(TrustDomain& trustDomain,
193
                 ResponderIDType responderIDType,
194
                 Input responderID,
195
                 Input potentialSignerSubject,
196
                 Input potentialSignerSubjectPublicKeyInfo,
197
                 /*out*/ bool& match)
198
0
{
199
0
  match = false;
200
0
201
0
  switch (responderIDType) {
202
0
    case ResponderIDType::byName:
203
0
      // XXX(bug 926270) XXX(bug 1008133) XXX(bug 980163): Improve name
204
0
      // comparison.
205
0
      match = InputsAreEqual(responderID, potentialSignerSubject);
206
0
      return Success;
207
0
208
0
    case ResponderIDType::byKey:
209
0
    {
210
0
      Reader input(responderID);
211
0
      Input keyHash;
212
0
      Result rv = der::ExpectTagAndGetValue(input, der::OCTET_STRING, keyHash);
213
0
      if (rv != Success) {
214
0
        return rv;
215
0
      }
216
0
      return MatchKeyHash(trustDomain, keyHash,
217
0
                          potentialSignerSubjectPublicKeyInfo, match);
218
0
    }
219
0
220
0
    MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
221
0
  }
222
0
}
223
224
static Result
225
VerifyOCSPSignedData(TrustDomain& trustDomain,
226
                     const der::SignedDataWithSignature& signedResponseData,
227
                     Input spki)
228
0
{
229
0
  Result rv = VerifySignedData(trustDomain, signedResponseData, spki);
230
0
  if (rv == Result::ERROR_BAD_SIGNATURE) {
231
0
    rv = Result::ERROR_OCSP_BAD_SIGNATURE;
232
0
  }
233
0
  return rv;
234
0
}
235
236
// RFC 6960 section 4.2.2.2: The OCSP responder must either be the issuer of
237
// the cert or it must be a delegated OCSP response signing cert directly
238
// issued by the issuer. If the OCSP responder is a delegated OCSP response
239
// signer, then its certificate is (probably) embedded within the OCSP
240
// response and we'll need to verify that it is a valid certificate that chains
241
// *directly* to issuerCert.
242
static Result
243
VerifySignature(Context& context, ResponderIDType responderIDType,
244
                Input responderID, const DERArray& certs,
245
                const der::SignedDataWithSignature& signedResponseData)
246
0
{
247
0
  bool match;
248
0
  Result rv = MatchResponderID(context.trustDomain, responderIDType,
249
0
                               responderID, context.certID.issuer,
250
0
                               context.certID.issuerSubjectPublicKeyInfo,
251
0
                               match);
252
0
  if (rv != Success) {
253
0
    return rv;
254
0
  }
255
0
  if (match) {
256
0
    return VerifyOCSPSignedData(context.trustDomain, signedResponseData,
257
0
                                context.certID.issuerSubjectPublicKeyInfo);
258
0
  }
259
0
260
0
  size_t numCerts = certs.GetLength();
261
0
  for (size_t i = 0; i < numCerts; ++i) {
262
0
    BackCert cert(*certs.GetDER(i), EndEntityOrCA::MustBeEndEntity, nullptr);
263
0
    rv = cert.Init();
264
0
    if (rv != Success) {
265
0
      return rv;
266
0
    }
267
0
    rv = MatchResponderID(context.trustDomain, responderIDType, responderID,
268
0
                          cert.GetSubject(), cert.GetSubjectPublicKeyInfo(),
269
0
                          match);
270
0
    if (rv != Success) {
271
0
      if (IsFatalError(rv)) {
272
0
        return rv;
273
0
      }
274
0
      continue;
275
0
    }
276
0
277
0
    if (match) {
278
0
      rv = CheckOCSPResponseSignerCert(context.trustDomain, cert,
279
0
                                       context.certID.issuer,
280
0
                                       context.certID.issuerSubjectPublicKeyInfo,
281
0
                                       context.time);
282
0
      if (rv != Success) {
283
0
        if (IsFatalError(rv)) {
284
0
          return rv;
285
0
        }
286
0
        continue;
287
0
      }
288
0
289
0
      return VerifyOCSPSignedData(context.trustDomain, signedResponseData,
290
0
                                  cert.GetSubjectPublicKeyInfo());
291
0
    }
292
0
  }
293
0
294
0
  return Result::ERROR_OCSP_INVALID_SIGNING_CERT;
295
0
}
296
297
static inline Result
298
MapBadDERToMalformedOCSPResponse(Result rv)
299
0
{
300
0
  if (rv == Result::ERROR_BAD_DER) {
301
0
    return Result::ERROR_OCSP_MALFORMED_RESPONSE;
302
0
  }
303
0
  return rv;
304
0
}
305
306
Result
307
VerifyEncodedOCSPResponse(TrustDomain& trustDomain, const struct CertID& certID,
308
                          Time time, uint16_t maxOCSPLifetimeInDays,
309
                          Input encodedResponse,
310
                          /*out*/ bool& expired,
311
                          /*optional out*/ Time* thisUpdate,
312
                          /*optional out*/ Time* validThrough)
313
0
{
314
0
  // Always initialize this to something reasonable.
315
0
  expired = false;
316
0
317
0
  Context context(trustDomain, certID, time, maxOCSPLifetimeInDays,
318
0
                  thisUpdate, validThrough);
319
0
320
0
  Reader input(encodedResponse);
321
0
  Result rv = der::Nested(input, der::SEQUENCE, [&context](Reader& r) {
322
0
    return OCSPResponse(r, context);
323
0
  });
324
0
  if (rv != Success) {
325
0
    return MapBadDERToMalformedOCSPResponse(rv);
326
0
  }
327
0
  rv = der::End(input);
328
0
  if (rv != Success) {
329
0
    return MapBadDERToMalformedOCSPResponse(rv);
330
0
  }
331
0
  if (!context.matchFound) {
332
0
    return Result::ERROR_OCSP_RESPONSE_FOR_CERT_MISSING;
333
0
  }
334
0
335
0
  expired = context.expired;
336
0
337
0
  switch (context.certStatus) {
338
0
    case CertStatus::Good:
339
0
      if (expired) {
340
0
        return Result::ERROR_OCSP_OLD_RESPONSE;
341
0
      }
342
0
      if (context.signedCertificateTimestamps.GetLength()) {
343
0
        Input sctList;
344
0
        rv = ExtractSignedCertificateTimestampListFromExtension(
345
0
          context.signedCertificateTimestamps, sctList);
346
0
        if (rv != Success) {
347
0
          return MapBadDERToMalformedOCSPResponse(rv);
348
0
        }
349
0
        context.trustDomain.NoteAuxiliaryExtension(
350
0
          AuxiliaryExtension::SCTListFromOCSPResponse, sctList);
351
0
      }
352
0
      return Success;
353
0
    case CertStatus::Revoked:
354
0
      return Result::ERROR_REVOKED_CERTIFICATE;
355
0
    case CertStatus::Unknown:
356
0
      return Result::ERROR_OCSP_UNKNOWN_CERT;
357
0
     MOZILLA_PKIX_UNREACHABLE_DEFAULT_ENUM
358
0
  }
359
0
}
360
361
// OCSPResponse ::= SEQUENCE {
362
//       responseStatus         OCSPResponseStatus,
363
//       responseBytes          [0] EXPLICIT ResponseBytes OPTIONAL }
364
//
365
static inline Result
366
OCSPResponse(Reader& input, Context& context)
367
0
{
368
0
  // OCSPResponseStatus ::= ENUMERATED {
369
0
  //     successful            (0),  -- Response has valid confirmations
370
0
  //     malformedRequest      (1),  -- Illegal confirmation request
371
0
  //     internalError         (2),  -- Internal error in issuer
372
0
  //     tryLater              (3),  -- Try again later
373
0
  //                                 -- (4) is not used
374
0
  //     sigRequired           (5),  -- Must sign the request
375
0
  //     unauthorized          (6)   -- Request unauthorized
376
0
  // }
377
0
  uint8_t responseStatus;
378
0
379
0
  Result rv = der::Enumerated(input, responseStatus);
380
0
  if (rv != Success) {
381
0
    return rv;
382
0
  }
383
0
  switch (responseStatus) {
384
0
    case 0: break; // successful
385
0
    case 1: return Result::ERROR_OCSP_MALFORMED_REQUEST;
386
0
    case 2: return Result::ERROR_OCSP_SERVER_ERROR;
387
0
    case 3: return Result::ERROR_OCSP_TRY_SERVER_LATER;
388
0
    case 5: return Result::ERROR_OCSP_REQUEST_NEEDS_SIG;
389
0
    case 6: return Result::ERROR_OCSP_UNAUTHORIZED_REQUEST;
390
0
    default: return Result::ERROR_OCSP_UNKNOWN_RESPONSE_STATUS;
391
0
  }
392
0
393
0
  return der::Nested(input, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0,
394
0
                     der::SEQUENCE, [&context](Reader& r) {
395
0
    return ResponseBytes(r, context);
396
0
  });
397
0
}
398
399
// ResponseBytes ::=       SEQUENCE {
400
//     responseType   OBJECT IDENTIFIER,
401
//     response       OCTET STRING }
402
static inline Result
403
ResponseBytes(Reader& input, Context& context)
404
0
{
405
0
  static const uint8_t id_pkix_ocsp_basic[] = {
406
0
    0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x01
407
0
  };
408
0
409
0
  Result rv = der::OID(input, id_pkix_ocsp_basic);
410
0
  if (rv != Success) {
411
0
    return rv;
412
0
  }
413
0
414
0
  return der::Nested(input, der::OCTET_STRING, der::SEQUENCE,
415
0
                     [&context](Reader& r) {
416
0
    return BasicResponse(r, context);
417
0
  });
418
0
}
419
420
// BasicOCSPResponse       ::= SEQUENCE {
421
//    tbsResponseData      ResponseData,
422
//    signatureAlgorithm   AlgorithmIdentifier,
423
//    signature            BIT STRING,
424
//    certs            [0] EXPLICIT SEQUENCE OF Certificate OPTIONAL }
425
Result
426
BasicResponse(Reader& input, Context& context)
427
0
{
428
0
  Reader tbsResponseData;
429
0
  der::SignedDataWithSignature signedData;
430
0
  Result rv = der::SignedData(input, tbsResponseData, signedData);
431
0
  if (rv != Success) {
432
0
    if (rv == Result::ERROR_BAD_SIGNATURE) {
433
0
      return Result::ERROR_OCSP_BAD_SIGNATURE;
434
0
    }
435
0
    return rv;
436
0
  }
437
0
438
0
  // Parse certificates, if any
439
0
  NonOwningDERArray certs;
440
0
  if (!input.AtEnd()) {
441
0
    rv = der::Nested(input, der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0,
442
0
                     der::SEQUENCE, [&certs](Reader& certsDER) -> Result {
443
0
      while (!certsDER.AtEnd()) {
444
0
        Input cert;
445
0
        Result nestedRv =
446
0
          der::ExpectTagAndGetTLV(certsDER, der::SEQUENCE, cert);
447
0
        if (nestedRv != Success) {
448
0
          return nestedRv;
449
0
        }
450
0
        nestedRv = certs.Append(cert);
451
0
        if (nestedRv != Success) {
452
0
          return Result::ERROR_BAD_DER; // Too many certs
453
0
        }
454
0
      }
455
0
      return Success;
456
0
    });
457
0
    if (rv != Success) {
458
0
      return rv;
459
0
    }
460
0
  }
461
0
462
0
  return ResponseData(tbsResponseData, context, signedData, certs);
463
0
}
464
465
// ResponseData ::= SEQUENCE {
466
//    version             [0] EXPLICIT Version DEFAULT v1,
467
//    responderID             ResponderID,
468
//    producedAt              GeneralizedTime,
469
//    responses               SEQUENCE OF SingleResponse,
470
//    responseExtensions  [1] EXPLICIT Extensions OPTIONAL }
471
static inline Result
472
ResponseData(Reader& input, Context& context,
473
             const der::SignedDataWithSignature& signedResponseData,
474
             const DERArray& certs)
475
0
{
476
0
  der::Version version;
477
0
  Result rv = der::OptionalVersion(input, version);
478
0
  if (rv != Success) {
479
0
    return rv;
480
0
  }
481
0
  if (version != der::Version::v1) {
482
0
    // TODO: more specific error code for bad version?
483
0
    return Result::ERROR_BAD_DER;
484
0
  }
485
0
486
0
  // ResponderID ::= CHOICE {
487
0
  //    byName              [1] Name,
488
0
  //    byKey               [2] KeyHash }
489
0
  Input responderID;
490
0
  ResponderIDType responderIDType
491
0
    = input.Peek(static_cast<uint8_t>(ResponderIDType::byName))
492
0
    ? ResponderIDType::byName
493
0
    : ResponderIDType::byKey;
494
0
  rv = der::ExpectTagAndGetValue(input, static_cast<uint8_t>(responderIDType),
495
0
                                 responderID);
496
0
  if (rv != Success) {
497
0
    return rv;
498
0
  }
499
0
500
0
  // This is the soonest we can verify the signature. We verify the signature
501
0
  // right away to follow the principal of minimizing the processing of data
502
0
  // before verifying its signature.
503
0
  rv = VerifySignature(context, responderIDType, responderID, certs,
504
0
                       signedResponseData);
505
0
  if (rv != Success) {
506
0
    return rv;
507
0
  }
508
0
509
0
  // TODO: Do we even need to parse this? Should we just skip it?
510
0
  Time producedAt(Time::uninitialized);
511
0
  rv = der::GeneralizedTime(input, producedAt);
512
0
  if (rv != Success) {
513
0
    return rv;
514
0
  }
515
0
516
0
  // We don't accept an empty sequence of responses. In practice, a legit OCSP
517
0
  // responder will never return an empty response, and handling the case of an
518
0
  // empty response makes things unnecessarily complicated.
519
0
  rv = der::NestedOf(input, der::SEQUENCE, der::SEQUENCE,
520
0
                     der::EmptyAllowed::No, [&context](Reader& r) {
521
0
    return SingleResponse(r, context);
522
0
  });
523
0
  if (rv != Success) {
524
0
    return rv;
525
0
  }
526
0
527
0
  return der::OptionalExtensions(input,
528
0
                                 der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1,
529
0
                                 ExtensionNotUnderstood);
530
0
}
531
532
// SingleResponse ::= SEQUENCE {
533
//    certID                       CertID,
534
//    certStatus                   CertStatus,
535
//    thisUpdate                   GeneralizedTime,
536
//    nextUpdate           [0]     EXPLICIT GeneralizedTime OPTIONAL,
537
//    singleExtensions     [1]     EXPLICIT Extensions{{re-ocsp-crl |
538
//                                              re-ocsp-archive-cutoff |
539
//                                              CrlEntryExtensions, ...}
540
//                                              } OPTIONAL }
541
static inline Result
542
SingleResponse(Reader& input, Context& context)
543
0
{
544
0
  bool match = false;
545
0
  Result rv = der::Nested(input, der::SEQUENCE, [&context, &match](Reader& r) {
546
0
    return MatchCertID(r, context, match);
547
0
  });
548
0
  if (rv != Success) {
549
0
    return rv;
550
0
  }
551
0
552
0
  if (!match) {
553
0
    // This response does not reference the certificate we're interested in.
554
0
    // By consuming the rest of our input and returning successfully, we can
555
0
    // continue processing and examine another response that might have what
556
0
    // we want.
557
0
    input.SkipToEnd();
558
0
    return Success;
559
0
  }
560
0
561
0
  // We found a response for the cert we're interested in.
562
0
  context.matchFound = true;
563
0
564
0
  // CertStatus ::= CHOICE {
565
0
  //     good        [0]     IMPLICIT NULL,
566
0
  //     revoked     [1]     IMPLICIT RevokedInfo,
567
0
  //     unknown     [2]     IMPLICIT UnknownInfo }
568
0
  //
569
0
  // In the event of multiple SingleResponses for a cert that have conflicting
570
0
  // statuses, we use the following precedence rules:
571
0
  //
572
0
  // * revoked overrides good and unknown
573
0
  // * good overrides unknown
574
0
  if (input.Peek(static_cast<uint8_t>(CertStatus::Good))) {
575
0
    rv = der::ExpectTagAndEmptyValue(input,
576
0
                                     static_cast<uint8_t>(CertStatus::Good));
577
0
    if (rv != Success) {
578
0
      return rv;
579
0
    }
580
0
    if (context.certStatus != CertStatus::Revoked) {
581
0
      context.certStatus = CertStatus::Good;
582
0
    }
583
0
  } else if (input.Peek(static_cast<uint8_t>(CertStatus::Revoked))) {
584
0
    // We don't need any info from the RevokedInfo structure, so we don't even
585
0
    // parse it. TODO: We should mention issues like this in the explanation of
586
0
    // why we treat invalid OCSP responses equivalently to revoked for OCSP
587
0
    // stapling.
588
0
    rv = der::ExpectTagAndSkipValue(input,
589
0
                                    static_cast<uint8_t>(CertStatus::Revoked));
590
0
    if (rv != Success) {
591
0
      return rv;
592
0
    }
593
0
    context.certStatus = CertStatus::Revoked;
594
0
  } else {
595
0
    rv = der::ExpectTagAndEmptyValue(input,
596
0
                                     static_cast<uint8_t>(CertStatus::Unknown));
597
0
    if (rv != Success) {
598
0
      return rv;
599
0
    }
600
0
  }
601
0
602
0
  // http://tools.ietf.org/html/rfc6960#section-3.2
603
0
  // 5. The time at which the status being indicated is known to be
604
0
  //    correct (thisUpdate) is sufficiently recent;
605
0
  // 6. When available, the time at or before which newer information will
606
0
  //    be available about the status of the certificate (nextUpdate) is
607
0
  //    greater than the current time.
608
0
609
0
  Time thisUpdate(Time::uninitialized);
610
0
  rv = der::GeneralizedTime(input, thisUpdate);
611
0
  if (rv != Success) {
612
0
    return rv;
613
0
  }
614
0
615
0
  static const uint64_t SLOP_SECONDS = Time::ONE_DAY_IN_SECONDS;
616
0
617
0
  Time timePlusSlop(context.time);
618
0
  rv = timePlusSlop.AddSeconds(SLOP_SECONDS);
619
0
  if (rv != Success) {
620
0
    return rv;
621
0
  }
622
0
  if (thisUpdate > timePlusSlop) {
623
0
    return Result::ERROR_OCSP_FUTURE_RESPONSE;
624
0
  }
625
0
626
0
  Time notAfter(Time::uninitialized);
627
0
  static const uint8_t NEXT_UPDATE_TAG =
628
0
    der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0;
629
0
  if (input.Peek(NEXT_UPDATE_TAG)) {
630
0
    Time nextUpdate(Time::uninitialized);
631
0
    rv = der::Nested(input, NEXT_UPDATE_TAG, [&nextUpdate](Reader& r) {
632
0
      return der::GeneralizedTime(r, nextUpdate);
633
0
    });
634
0
    if (rv != Success) {
635
0
      return rv;
636
0
    }
637
0
638
0
    if (nextUpdate < thisUpdate) {
639
0
      return Result::ERROR_OCSP_MALFORMED_RESPONSE;
640
0
    }
641
0
    notAfter = thisUpdate;
642
0
    if (notAfter.AddSeconds(context.maxLifetimeInDays *
643
0
                            Time::ONE_DAY_IN_SECONDS) != Success) {
644
0
      // This could only happen if we're dealing with times beyond the year
645
0
      // 10,000AD.
646
0
      return Result::ERROR_OCSP_FUTURE_RESPONSE;
647
0
    }
648
0
    if (nextUpdate <= notAfter) {
649
0
      notAfter = nextUpdate;
650
0
    }
651
0
  } else {
652
0
    // NSS requires all OCSP responses without a nextUpdate to be recent.
653
0
    // Match that stricter behavior.
654
0
    notAfter = thisUpdate;
655
0
    if (notAfter.AddSeconds(Time::ONE_DAY_IN_SECONDS) != Success) {
656
0
      // This could only happen if we're dealing with times beyond the year
657
0
      // 10,000AD.
658
0
      return Result::ERROR_OCSP_FUTURE_RESPONSE;
659
0
    }
660
0
  }
661
0
662
0
  // Add some slop to hopefully handle clock-skew.
663
0
  Time notAfterPlusSlop(notAfter);
664
0
  rv = notAfterPlusSlop.AddSeconds(SLOP_SECONDS);
665
0
  if (rv != Success) {
666
0
    // This could only happen if we're dealing with times beyond the year
667
0
    // 10,000AD.
668
0
    return Result::ERROR_OCSP_FUTURE_RESPONSE;
669
0
  }
670
0
  if (context.time > notAfterPlusSlop) {
671
0
    context.expired = true;
672
0
  }
673
0
674
0
  rv = der::OptionalExtensions(
675
0
    input,
676
0
    der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1,
677
0
    [&context](Reader& extnID, const Input& extnValue, bool critical,
678
0
               /*out*/ bool& understood) {
679
0
      return RememberSingleExtension(context, extnID, extnValue, critical,
680
0
                                     understood);
681
0
    });
682
0
683
0
  if (rv != Success) {
684
0
    return rv;
685
0
  }
686
0
687
0
  if (context.thisUpdate) {
688
0
    *context.thisUpdate = thisUpdate;
689
0
  }
690
0
  if (context.validThrough) {
691
0
    *context.validThrough = notAfterPlusSlop;
692
0
  }
693
0
694
0
  return Success;
695
0
}
696
697
// CertID          ::=     SEQUENCE {
698
//        hashAlgorithm       AlgorithmIdentifier,
699
//        issuerNameHash      OCTET STRING, -- Hash of issuer's DN
700
//        issuerKeyHash       OCTET STRING, -- Hash of issuer's public key
701
//        serialNumber        CertificateSerialNumber }
702
static inline Result
703
MatchCertID(Reader& input, const Context& context, /*out*/ bool& match)
704
0
{
705
0
  match = false;
706
0
707
0
  DigestAlgorithm hashAlgorithm;
708
0
  Result rv = der::DigestAlgorithmIdentifier(input, hashAlgorithm);
709
0
  if (rv != Success) {
710
0
    if (rv == Result::ERROR_INVALID_ALGORITHM) {
711
0
      // Skip entries that are hashed with algorithms we don't support.
712
0
      input.SkipToEnd();
713
0
      return Success;
714
0
    }
715
0
    return rv;
716
0
  }
717
0
718
0
  Input issuerNameHash;
719
0
  rv = der::ExpectTagAndGetValue(input, der::OCTET_STRING, issuerNameHash);
720
0
  if (rv != Success) {
721
0
    return rv;
722
0
  }
723
0
724
0
  Input issuerKeyHash;
725
0
  rv = der::ExpectTagAndGetValue(input, der::OCTET_STRING, issuerKeyHash);
726
0
  if (rv != Success) {
727
0
    return rv;
728
0
  }
729
0
730
0
  Input serialNumber;
731
0
  rv = der::CertificateSerialNumber(input, serialNumber);
732
0
  if (rv != Success) {
733
0
    return rv;
734
0
  }
735
0
736
0
  if (!InputsAreEqual(serialNumber, context.certID.serialNumber)) {
737
0
    // This does not reference the certificate we're interested in.
738
0
    // Consume the rest of the input and return successfully to
739
0
    // potentially continue processing other responses.
740
0
    input.SkipToEnd();
741
0
    return Success;
742
0
  }
743
0
744
0
  // TODO: support SHA-2 hashes.
745
0
746
0
  if (hashAlgorithm != DigestAlgorithm::sha1) {
747
0
    // Again, not interested in this response. Consume input, return success.
748
0
    input.SkipToEnd();
749
0
    return Success;
750
0
  }
751
0
752
0
  if (issuerNameHash.GetLength() != SHA1_DIGEST_LENGTH) {
753
0
    return Result::ERROR_OCSP_MALFORMED_RESPONSE;
754
0
  }
755
0
756
0
  // From http://tools.ietf.org/html/rfc6960#section-4.1.1:
757
0
  // "The hash shall be calculated over the DER encoding of the
758
0
  // issuer's name field in the certificate being checked."
759
0
  uint8_t hashBuf[SHA1_DIGEST_LENGTH];
760
0
  rv = context.trustDomain.DigestBuf(context.certID.issuer,
761
0
                                     DigestAlgorithm::sha1, hashBuf,
762
0
                                     sizeof(hashBuf));
763
0
  if (rv != Success) {
764
0
    return rv;
765
0
  }
766
0
  Input computed(hashBuf);
767
0
  if (!InputsAreEqual(computed, issuerNameHash)) {
768
0
    // Again, not interested in this response. Consume input, return success.
769
0
    input.SkipToEnd();
770
0
    return Success;
771
0
  }
772
0
773
0
  return MatchKeyHash(context.trustDomain, issuerKeyHash,
774
0
                      context.certID.issuerSubjectPublicKeyInfo, match);
775
0
}
776
777
// From http://tools.ietf.org/html/rfc6960#section-4.1.1:
778
// "The hash shall be calculated over the value (excluding tag and length) of
779
// the subject public key field in the issuer's certificate."
780
//
781
// From http://tools.ietf.org/html/rfc6960#appendix-B.1:
782
// KeyHash ::= OCTET STRING -- SHA-1 hash of responder's public key
783
//                          -- (i.e., the SHA-1 hash of the value of the
784
//                          -- BIT STRING subjectPublicKey [excluding
785
//                          -- the tag, length, and number of unused
786
//                          -- bits] in the responder's certificate)
787
static Result
788
MatchKeyHash(TrustDomain& trustDomain, Input keyHash,
789
             const Input subjectPublicKeyInfo, /*out*/ bool& match)
790
0
{
791
0
  if (keyHash.GetLength() != SHA1_DIGEST_LENGTH)  {
792
0
    return Result::ERROR_OCSP_MALFORMED_RESPONSE;
793
0
  }
794
0
  uint8_t hashBuf[SHA1_DIGEST_LENGTH];
795
0
  Result rv = KeyHash(trustDomain, subjectPublicKeyInfo, hashBuf,
796
0
                      sizeof hashBuf);
797
0
  if (rv != Success) {
798
0
    return rv;
799
0
  }
800
0
  Input computed(hashBuf);
801
0
  match = InputsAreEqual(computed, keyHash);
802
0
  return Success;
803
0
}
804
805
// TODO(bug 966856): support SHA-2 hashes
806
Result
807
KeyHash(TrustDomain& trustDomain, const Input subjectPublicKeyInfo,
808
        /*out*/ uint8_t* hashBuf, size_t hashBufSize)
809
0
{
810
0
  if (!hashBuf || hashBufSize != SHA1_DIGEST_LENGTH) {
811
0
    return Result::FATAL_ERROR_LIBRARY_FAILURE;
812
0
  }
813
0
814
0
  // RFC 5280 Section 4.1
815
0
  //
816
0
  // SubjectPublicKeyInfo  ::=  SEQUENCE  {
817
0
  //    algorithm            AlgorithmIdentifier,
818
0
  //    subjectPublicKey     BIT STRING  }
819
0
820
0
  Reader spki;
821
0
  Result rv = der::ExpectTagAndGetValueAtEnd(subjectPublicKeyInfo,
822
0
                                             der::SEQUENCE, spki);
823
0
  if (rv != Success) {
824
0
    return rv;
825
0
  }
826
0
827
0
  // Skip AlgorithmIdentifier
828
0
  rv = der::ExpectTagAndSkipValue(spki, der::SEQUENCE);
829
0
  if (rv != Success) {
830
0
    return rv;
831
0
  }
832
0
833
0
  Input subjectPublicKey;
834
0
  rv = der::BitStringWithNoUnusedBits(spki, subjectPublicKey);
835
0
  if (rv != Success) {
836
0
    return rv;
837
0
  }
838
0
  rv = der::End(spki);
839
0
  if (rv != Success) {
840
0
    return rv;
841
0
  }
842
0
843
0
  return trustDomain.DigestBuf(subjectPublicKey, DigestAlgorithm::sha1,
844
0
                               hashBuf, hashBufSize);
845
0
}
846
847
Result
848
ExtensionNotUnderstood(Reader& /*extnID*/, Input /*extnValue*/,
849
                       bool /*critical*/, /*out*/ bool& understood)
850
0
{
851
0
  understood = false;
852
0
  return Success;
853
0
}
854
855
Result
856
RememberSingleExtension(Context& context, Reader& extnID, Input extnValue,
857
                        bool /*critical*/, /*out*/ bool& understood)
858
0
{
859
0
  understood = false;
860
0
861
0
  // SingleExtension for Signed Certificate Timestamp List.
862
0
  // See Section 3.3 of RFC 6962.
863
0
  // python DottedOIDToCode.py
864
0
  //   id_ocsp_singleExtensionSctList 1.3.6.1.4.1.11129.2.4.5
865
0
  static const uint8_t id_ocsp_singleExtensionSctList[] = {
866
0
    0x2b, 0x06, 0x01, 0x04, 0x01, 0xd6, 0x79, 0x02, 0x04, 0x05
867
0
  };
868
0
869
0
  if (extnID.MatchRest(id_ocsp_singleExtensionSctList)) {
870
0
    // Empty values are not allowed for this extension. Note that
871
0
    // we assume this later, when checking if the extension was present.
872
0
    if (extnValue.GetLength() == 0) {
873
0
      return Result::ERROR_EXTENSION_VALUE_INVALID;
874
0
    }
875
0
    if (context.signedCertificateTimestamps.Init(extnValue) != Success) {
876
0
      // Duplicate extension.
877
0
      return Result::ERROR_EXTENSION_VALUE_INVALID;
878
0
    }
879
0
    understood = true;
880
0
  }
881
0
882
0
  return Success;
883
0
}
884
885
//   1. The certificate identified in a received response corresponds to
886
//      the certificate that was identified in the corresponding request;
887
//   2. The signature on the response is valid;
888
//   3. The identity of the signer matches the intended recipient of the
889
//      request;
890
//   4. The signer is currently authorized to provide a response for the
891
//      certificate in question;
892
//   5. The time at which the status being indicated is known to be
893
//      correct (thisUpdate) is sufficiently recent;
894
//   6. When available, the time at or before which newer information will
895
//      be available about the status of the certificate (nextUpdate) is
896
//      greater than the current time.
897
//
898
//   Responses whose nextUpdate value is earlier than
899
//   the local system time value SHOULD be considered unreliable.
900
//   Responses whose thisUpdate time is later than the local system time
901
//   SHOULD be considered unreliable.
902
//
903
//   If nextUpdate is not set, the responder is indicating that newer
904
//   revocation information is available all the time.
905
//
906
// http://tools.ietf.org/html/rfc5019#section-4
907
908
Result
909
CreateEncodedOCSPRequest(TrustDomain& trustDomain, const struct CertID& certID,
910
                         /*out*/ uint8_t (&out)[OCSP_REQUEST_MAX_LENGTH],
911
                         /*out*/ size_t& outLen)
912
0
{
913
0
  // We do not add any extensions to the request.
914
0
915
0
  // RFC 6960 says "An OCSP client MAY wish to specify the kinds of response
916
0
  // types it understands. To do so, it SHOULD use an extension with the OID
917
0
  // id-pkix-ocsp-response." This use of MAY and SHOULD is unclear. MSIE11
918
0
  // on Windows 8.1 does not include any extensions, whereas NSS has always
919
0
  // included the id-pkix-ocsp-response extension. Avoiding the sending the
920
0
  // extension is better for OCSP GET because it makes the request smaller,
921
0
  // and thus more likely to fit within the 255 byte limit for OCSP GET that
922
0
  // is specified in RFC 5019 Section 5.
923
0
924
0
  // Bug 966856: Add the id-pkix-ocsp-pref-sig-algs extension.
925
0
926
0
  // Since we don't know whether the OCSP responder supports anything other
927
0
  // than SHA-1, we have no choice but to use SHA-1 for issuerNameHash and
928
0
  // issuerKeyHash.
929
0
  static const uint8_t hashAlgorithm[11] = {
930
0
    0x30, 0x09,                               // SEQUENCE
931
0
    0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, //   OBJECT IDENTIFIER id-sha1
932
0
    0x05, 0x00,                               //   NULL
933
0
  };
934
0
  static const uint8_t hashLen = 160 / 8;
935
0
936
0
  static const unsigned int totalLenWithoutSerialNumberData
937
0
    = 2                             // OCSPRequest
938
0
    + 2                             //   tbsRequest
939
0
    + 2                             //     requestList
940
0
    + 2                             //       Request
941
0
    + 2                             //         reqCert (CertID)
942
0
    + sizeof(hashAlgorithm)         //           hashAlgorithm
943
0
    + 2 + hashLen                   //           issuerNameHash
944
0
    + 2 + hashLen                   //           issuerKeyHash
945
0
    + 2;                            //           serialNumber (header)
946
0
947
0
  // The only way we could have a request this large is if the serialNumber was
948
0
  // ridiculously and unreasonably large. RFC 5280 says "Conforming CAs MUST
949
0
  // NOT use serialNumber values longer than 20 octets." With this restriction,
950
0
  // we allow for some amount of non-conformance with that requirement while
951
0
  // still ensuring we can encode the length values in the ASN.1 TLV structures
952
0
  // in a single byte.
953
0
  static_assert(totalLenWithoutSerialNumberData < OCSP_REQUEST_MAX_LENGTH,
954
0
                "totalLenWithoutSerialNumberData too big");
955
0
  if (certID.serialNumber.GetLength() >
956
0
        OCSP_REQUEST_MAX_LENGTH - totalLenWithoutSerialNumberData) {
957
0
    return Result::ERROR_BAD_DER;
958
0
  }
959
0
960
0
  outLen = totalLenWithoutSerialNumberData + certID.serialNumber.GetLength();
961
0
962
0
  uint8_t totalLen = static_cast<uint8_t>(outLen);
963
0
964
0
  uint8_t* d = out;
965
0
  *d++ = 0x30; *d++ = totalLen - 2u;  // OCSPRequest (SEQUENCE)
966
0
  *d++ = 0x30; *d++ = totalLen - 4u;  //   tbsRequest (SEQUENCE)
967
0
  *d++ = 0x30; *d++ = totalLen - 6u;  //     requestList (SEQUENCE OF)
968
0
  *d++ = 0x30; *d++ = totalLen - 8u;  //       Request (SEQUENCE)
969
0
  *d++ = 0x30; *d++ = totalLen - 10u; //         reqCert (CertID SEQUENCE)
970
0
971
0
  // reqCert.hashAlgorithm
972
0
  for (const uint8_t hashAlgorithmByte : hashAlgorithm) {
973
0
    *d++ = hashAlgorithmByte;
974
0
  }
975
0
976
0
  // reqCert.issuerNameHash (OCTET STRING)
977
0
  *d++ = 0x04;
978
0
  *d++ = hashLen;
979
0
  Result rv = trustDomain.DigestBuf(certID.issuer, DigestAlgorithm::sha1, d,
980
0
                                    hashLen);
981
0
  if (rv != Success) {
982
0
    return rv;
983
0
  }
984
0
  d += hashLen;
985
0
986
0
  // reqCert.issuerKeyHash (OCTET STRING)
987
0
  *d++ = 0x04;
988
0
  *d++ = hashLen;
989
0
  rv = KeyHash(trustDomain, certID.issuerSubjectPublicKeyInfo, d, hashLen);
990
0
  if (rv != Success) {
991
0
    return rv;
992
0
  }
993
0
  d += hashLen;
994
0
995
0
  // reqCert.serialNumber (INTEGER)
996
0
  *d++ = 0x02; // INTEGER
997
0
  *d++ = static_cast<uint8_t>(certID.serialNumber.GetLength());
998
0
  Reader serialNumber(certID.serialNumber);
999
0
  do {
1000
0
    rv = serialNumber.Read(*d);
1001
0
    if (rv != Success) {
1002
0
      return rv;
1003
0
    }
1004
0
    ++d;
1005
0
  } while (!serialNumber.AtEnd());
1006
0
1007
0
  assert(d == out + totalLen);
1008
0
1009
0
  return Success;
1010
0
}
1011
1012
} } // namespace mozilla::pkix