LCOV - code coverage report
Current view: top level - security/pkix/lib - pkixocsp.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 0 355 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 26 0.0 %
Legend: Lines: hit not hit

          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

Generated by: LCOV version 1.13