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