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