示例#1
0
// ResponseData ::= SEQUENCE {
//    version             [0] EXPLICIT Version DEFAULT v1,
//    responderID             ResponderID,
//    producedAt              GeneralizedTime,
//    responses               SEQUENCE OF SingleResponse,
//    responseExtensions  [1] EXPLICIT Extensions OPTIONAL }
static inline Result
ResponseData(Reader& input, Context& context,
             const SignedDataWithSignature& signedResponseData,
             const DERArray& certs)
{
  der::Version version;
  Result rv = der::OptionalVersion(input, version);
  if (rv != Success) {
    return rv;
  }
  if (version != der::Version::v1) {
    // TODO: more specific error code for bad version?
    return Result::ERROR_BAD_DER;
  }

  // ResponderID ::= CHOICE {
  //    byName              [1] Name,
  //    byKey               [2] KeyHash }
  Input responderID;
  ResponderIDType responderIDType
    = input.Peek(static_cast<uint8_t>(ResponderIDType::byName))
    ? ResponderIDType::byName
    : ResponderIDType::byKey;
  rv = der::ExpectTagAndGetValue(input, static_cast<uint8_t>(responderIDType),
                                 responderID);
  if (rv != Success) {
    return rv;
  }

  // This is the soonest we can verify the signature. We verify the signature
  // right away to follow the principal of minimizing the processing of data
  // before verifying its signature.
  rv = VerifySignature(context, responderIDType, responderID, certs,
                       signedResponseData);
  if (rv != Success) {
    return rv;
  }

  // TODO: Do we even need to parse this? Should we just skip it?
  Time producedAt(Time::uninitialized);
  rv = der::GeneralizedTime(input, producedAt);
  if (rv != Success) {
    return rv;
  }

  // We don't accept an empty sequence of responses. In practice, a legit OCSP
  // responder will never return an empty response, and handling the case of an
  // empty response makes things unnecessarily complicated.
  rv = der::NestedOf(input, der::SEQUENCE, der::SEQUENCE,
                     der::EmptyAllowed::No,
                     bind(SingleResponse, _1, ref(context)));
  if (rv != Success) {
    return rv;
  }

  return der::OptionalExtensions(input,
                                 der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1,
                                 ExtensionNotUnderstood);
}
示例#2
0
static Result
OptionalNull(Reader& input)
{
  if (input.Peek(NULLTag)) {
    return Null(input);
  }
  return Success;
}
示例#3
0
Result
BackCert::Init()
{
  Result rv;

  // Certificate  ::=  SEQUENCE  {
  //         tbsCertificate       TBSCertificate,
  //         signatureAlgorithm   AlgorithmIdentifier,
  //         signatureValue       BIT STRING  }

  Reader tbsCertificate;

  // The scope of |input| and |certificate| are limited to this block so we
  // don't accidentally confuse them for tbsCertificate later.
  {
    Reader certificate;
    rv = der::ExpectTagAndGetValueAtEnd(der, der::SEQUENCE, certificate);
    if (rv != Success) {
      return rv;
    }
    rv = der::SignedData(certificate, tbsCertificate, signedData);
    if (rv != Success) {
      return rv;
    }
    rv = der::End(certificate);
    if (rv != Success) {
      return rv;
    }
  }

  // TBSCertificate  ::=  SEQUENCE  {
  //      version         [0]  EXPLICIT Version DEFAULT v1,
  //      serialNumber         CertificateSerialNumber,
  //      signature            AlgorithmIdentifier,
  //      issuer               Name,
  //      validity             Validity,
  //      subject              Name,
  //      subjectPublicKeyInfo SubjectPublicKeyInfo,
  //      issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
  //                           -- If present, version MUST be v2 or v3
  //      subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
  //                           -- If present, version MUST be v2 or v3
  //      extensions      [3]  EXPLICIT Extensions OPTIONAL
  //                           -- If present, version MUST be v3
  //      }
  rv = der::OptionalVersion(tbsCertificate, version);
  if (rv != Success) {
    return rv;
  }
  rv = der::CertificateSerialNumber(tbsCertificate, serialNumber);
  if (rv != Success) {
    return rv;
  }
  rv = der::ExpectTagAndGetValue(tbsCertificate, der::SEQUENCE, signature);
  if (rv != Success) {
    return rv;
  }
  rv = der::ExpectTagAndGetTLV(tbsCertificate, der::SEQUENCE, issuer);
  if (rv != Success) {
    return rv;
  }
  rv = der::ExpectTagAndGetValue(tbsCertificate, der::SEQUENCE, validity);
  if (rv != Success) {
    return rv;
  }
  // TODO(bug XXXXXXX): We rely on the the caller of mozilla::pkix to validate
  // that the name is syntactically valid, if they care. In Gecko we do this
  // implicitly by parsing the certificate into a CERTCertificate object.
  // Instead of relying on the caller to do this, we should do it ourselves.
  rv = der::ExpectTagAndGetTLV(tbsCertificate, der::SEQUENCE, subject);
  if (rv != Success) {
    return rv;
  }
  rv = der::ExpectTagAndGetTLV(tbsCertificate, der::SEQUENCE,
                               subjectPublicKeyInfo);
  if (rv != Success) {
    return rv;
  }

  static const uint8_t CSC = der::CONTEXT_SPECIFIC | der::CONSTRUCTED;

  // According to RFC 5280, all fields below this line are forbidden for
  // certificate versions less than v3.  However, for compatibility reasons,
  // we parse v1/v2 certificates in the same way as v3 certificates.  So if
  // these fields appear in a v1 certificate, they will be used.

  // Ignore issuerUniqueID if present.
  if (tbsCertificate.Peek(CSC | 1)) {
    rv = der::ExpectTagAndSkipValue(tbsCertificate, CSC | 1);
    if (rv != Success) {
      return rv;
    }
  }

  // Ignore subjectUniqueID if present.
  if (tbsCertificate.Peek(CSC | 2)) {
    rv = der::ExpectTagAndSkipValue(tbsCertificate, CSC | 2);
    if (rv != Success) {
      return rv;
    }
  }

  rv = der::OptionalExtensions(
         tbsCertificate, CSC | 3,
         [this](Reader& extnID, const Input& extnValue, bool critical,
                /*out*/ bool& understood) {
           return RememberExtension(extnID, extnValue, critical, understood);
         });
  if (rv != Success) {
    return rv;
  }

  // The Netscape Certificate Type extension is an obsolete
  // Netscape-proprietary mechanism that we ignore in favor of the standard
  // extensions. However, some CAs have issued certificates with the Netscape
  // Cert Type extension marked critical. Thus, for compatibility reasons, we
  // "understand" this extension by ignoring it when it is not critical, and
  // by ensuring that the equivalent standardized extensions are present when
  // it is marked critical, based on the assumption that the information in
  // the Netscape Cert Type extension is consistent with the information in
  // the standard extensions.
  //
  // Here is a mapping between the Netscape Cert Type extension and the
  // standard extensions:
  //
  // Netscape Cert Type  |  BasicConstraints.cA  |  Extended Key Usage
  // --------------------+-----------------------+----------------------
  // SSL Server          |  false                |  id_kp_serverAuth
  // SSL Client          |  false                |  id_kp_clientAuth
  // S/MIME Client       |  false                |  id_kp_emailProtection
  // Object Signing      |  false                |  id_kp_codeSigning
  // SSL Server CA       |  true                 |  id_pk_serverAuth
  // SSL Client CA       |  true                 |  id_kp_clientAuth
  // S/MIME CA           |  true                 |  id_kp_emailProtection
  // Object Signing CA   |  true                 |  id_kp_codeSigning
  if (criticalNetscapeCertificateType.GetLength() > 0 &&
      (basicConstraints.GetLength() == 0 || extKeyUsage.GetLength() == 0)) {
    return Result::ERROR_UNKNOWN_CRITICAL_EXTENSION;
  }

  return der::End(tbsCertificate);
}
示例#4
0
// SingleResponse ::= SEQUENCE {
//    certID                       CertID,
//    certStatus                   CertStatus,
//    thisUpdate                   GeneralizedTime,
//    nextUpdate           [0]     EXPLICIT GeneralizedTime OPTIONAL,
//    singleExtensions     [1]     EXPLICIT Extensions{{re-ocsp-crl |
//                                              re-ocsp-archive-cutoff |
//                                              CrlEntryExtensions, ...}
//                                              } OPTIONAL }
static inline Result
SingleResponse(Reader& input, Context& context)
{
  bool match = false;
  Result rv = der::Nested(input, der::SEQUENCE,
                          bind(CertID, _1, cref(context), ref(match)));
  if (rv != Success) {
    return rv;
  }

  if (!match) {
    // This response does not reference the certificate we're interested in.
    // By consuming the rest of our input and returning successfully, we can
    // continue processing and examine another response that might have what
    // we want.
    input.SkipToEnd();
    return Success;
  }

  // CertStatus ::= CHOICE {
  //     good        [0]     IMPLICIT NULL,
  //     revoked     [1]     IMPLICIT RevokedInfo,
  //     unknown     [2]     IMPLICIT UnknownInfo }
  //
  // In the event of multiple SingleResponses for a cert that have conflicting
  // statuses, we use the following precedence rules:
  //
  // * revoked overrides good and unknown
  // * good overrides unknown
  if (input.Peek(static_cast<uint8_t>(CertStatus::Good))) {
    rv = der::ExpectTagAndEmptyValue(input,
                                     static_cast<uint8_t>(CertStatus::Good));
    if (rv != Success) {
      return rv;
    }
    if (context.certStatus != CertStatus::Revoked) {
      context.certStatus = CertStatus::Good;
    }
  } else if (input.Peek(static_cast<uint8_t>(CertStatus::Revoked))) {
    // We don't need any info from the RevokedInfo structure, so we don't even
    // parse it. TODO: We should mention issues like this in the explanation of
    // why we treat invalid OCSP responses equivalently to revoked for OCSP
    // stapling.
    rv = der::ExpectTagAndSkipValue(input,
                                    static_cast<uint8_t>(CertStatus::Revoked));
    if (rv != Success) {
      return rv;
    }
    context.certStatus = CertStatus::Revoked;
  } else {
    rv = der::ExpectTagAndEmptyValue(input,
                                     static_cast<uint8_t>(CertStatus::Unknown));
    if (rv != Success) {
      return rv;
    }
  }

  // http://tools.ietf.org/html/rfc6960#section-3.2
  // 5. The time at which the status being indicated is known to be
  //    correct (thisUpdate) is sufficiently recent;
  // 6. When available, the time at or before which newer information will
  //    be available about the status of the certificate (nextUpdate) is
  //    greater than the current time.

  Time thisUpdate(Time::uninitialized);
  rv = der::GeneralizedTime(input, thisUpdate);
  if (rv != Success) {
    return rv;
  }

  static const uint64_t SLOP_SECONDS = Time::ONE_DAY_IN_SECONDS;

  Time timePlusSlop(context.time);
  rv = timePlusSlop.AddSeconds(SLOP_SECONDS);
  if (rv != Success) {
    return rv;
  }
  if (thisUpdate > timePlusSlop) {
    return Result::ERROR_OCSP_FUTURE_RESPONSE;
  }

  Time notAfter(Time::uninitialized);
  static const uint8_t NEXT_UPDATE_TAG =
    der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 0;
  if (input.Peek(NEXT_UPDATE_TAG)) {
    Time nextUpdate(Time::uninitialized);
    rv = der::Nested(input, NEXT_UPDATE_TAG,
                    bind(der::GeneralizedTime, _1, ref(nextUpdate)));
    if (rv != Success) {
      return rv;
    }

    if (nextUpdate < thisUpdate) {
      return Result::ERROR_OCSP_MALFORMED_RESPONSE;
    }
    notAfter = thisUpdate;
    if (notAfter.AddSeconds(context.maxLifetimeInDays *
                            Time::ONE_DAY_IN_SECONDS) != Success) {
      // This could only happen if we're dealing with times beyond the year
      // 10,000AD.
      return Result::ERROR_OCSP_FUTURE_RESPONSE;
    }
    if (nextUpdate <= notAfter) {
      notAfter = nextUpdate;
    }
  } else {
    // NSS requires all OCSP responses without a nextUpdate to be recent.
    // Match that stricter behavior.
    notAfter = thisUpdate;
    if (notAfter.AddSeconds(Time::ONE_DAY_IN_SECONDS) != Success) {
      // This could only happen if we're dealing with times beyond the year
      // 10,000AD.
      return Result::ERROR_OCSP_FUTURE_RESPONSE;
    }
  }

  // Add some slop to hopefully handle clock-skew.
  Time notAfterPlusSlop(notAfter);
  rv = notAfterPlusSlop.AddSeconds(SLOP_SECONDS);
  if (rv != Success) {
    // This could only happen if we're dealing with times beyond the year
    // 10,000AD.
    return Result::ERROR_OCSP_FUTURE_RESPONSE;
  }
  if (context.time > notAfterPlusSlop) {
    context.expired = true;
  }

  rv = der::OptionalExtensions(input,
                               der::CONTEXT_SPECIFIC | der::CONSTRUCTED | 1,
                               ExtensionNotUnderstood);
  if (rv != Success) {
    return rv;
  }

  if (context.thisUpdate) {
    *context.thisUpdate = thisUpdate;
  }
  if (context.validThrough) {
    *context.validThrough = notAfterPlusSlop;
  }

  return Success;
}
示例#5
0
Result
BackCert::Init()
{
  Result rv;

  // Certificate  ::=  SEQUENCE  {
  //         tbsCertificate       TBSCertificate,
  //         signatureAlgorithm   AlgorithmIdentifier,
  //         signatureValue       BIT STRING  }

  Reader tbsCertificate;

  // The scope of |input| and |certificate| are limited to this block so we
  // don't accidentally confuse them for tbsCertificate later.
  {
    Reader input(der);
    Reader certificate;
    rv = der::ExpectTagAndGetValue(input, der::SEQUENCE, certificate);
    if (rv != Success) {
      return rv;
    }
    rv = der::End(input);
    if (rv != Success) {
      return rv;
    }
    rv = der::SignedData(certificate, tbsCertificate, signedData);
    if (rv != Success) {
      return rv;
    }
    rv = der::End(certificate);
    if (rv != Success) {
      return rv;
    }
  }

  // TBSCertificate  ::=  SEQUENCE  {
  //      version         [0]  EXPLICIT Version DEFAULT v1,
  //      serialNumber         CertificateSerialNumber,
  //      signature            AlgorithmIdentifier,
  //      issuer               Name,
  //      validity             Validity,
  //      subject              Name,
  //      subjectPublicKeyInfo SubjectPublicKeyInfo,
  //      issuerUniqueID  [1]  IMPLICIT UniqueIdentifier OPTIONAL,
  //                           -- If present, version MUST be v2 or v3
  //      subjectUniqueID [2]  IMPLICIT UniqueIdentifier OPTIONAL,
  //                           -- If present, version MUST be v2 or v3
  //      extensions      [3]  EXPLICIT Extensions OPTIONAL
  //                           -- If present, version MUST be v3
  //      }
  rv = der::OptionalVersion(tbsCertificate, version);
  if (rv != Success) {
    return rv;
  }
  rv = der::CertificateSerialNumber(tbsCertificate, serialNumber);
  if (rv != Success) {
    return rv;
  }
  // XXX: Ignored. What are we supposed to check? This seems totally redundant
  // with Certificate.signatureAlgorithm. Is it important to check that they
  // are consistent with each other? It doesn't seem to matter!
  SignatureAlgorithm signature;
  rv = der::SignatureAlgorithmIdentifier(tbsCertificate, signature);
  if (rv != Success) {
    return rv;
  }
  rv = der::ExpectTagAndGetTLV(tbsCertificate, der::SEQUENCE, issuer);
  if (rv != Success) {
    return rv;
  }
  rv = der::ExpectTagAndGetValue(tbsCertificate, der::SEQUENCE, validity);
  if (rv != Success) {
    return rv;
  }
  // TODO(bug XXXXXXX): We rely on the the caller of mozilla::pkix to validate
  // that the name is syntactically valid, if they care. In Gecko we do this
  // implicitly by parsing the certificate into a CERTCertificate object.
  // Instead of relying on the caller to do this, we should do it ourselves.
  rv = der::ExpectTagAndGetTLV(tbsCertificate, der::SEQUENCE, subject);
  if (rv != Success) {
    return rv;
  }
  // TODO(bug XXXXXXX): We defer parsing/validating subjectPublicKeyInfo to
  // the point where the public key is needed. For end-entity certificates, we
  // assume that the caller will extract the public key and use it somehow; if
  // they don't do that then we'll never know whether the key is invalid. On
  // the other hand, if the caller never uses the key then in some ways it
  // doesn't matter. Regardless, we should parse and validate
  // subjectPublicKeyKeyInfo internally.
  rv = der::ExpectTagAndGetTLV(tbsCertificate, der::SEQUENCE,
                               subjectPublicKeyInfo);
  if (rv != Success) {
    return rv;
  }

  static const uint8_t CSC = der::CONTEXT_SPECIFIC | der::CONSTRUCTED;

  // RFC 5280 says: "These fields MUST only appear if the version is 2 or 3
  // (Section 4.1.2.1). These fields MUST NOT appear if the version is 1."
  if (version != der::Version::v1) {

    // Ignore issuerUniqueID if present.
    if (tbsCertificate.Peek(CSC | 1)) {
      rv = der::ExpectTagAndSkipValue(tbsCertificate, CSC | 1);
      if (rv != Success) {
        return rv;
      }
    }

    // Ignore subjectUniqueID if present.
    if (tbsCertificate.Peek(CSC | 2)) {
      rv = der::ExpectTagAndSkipValue(tbsCertificate, CSC | 2);
      if (rv != Success) {
        return rv;
      }
    }
  }

  // Extensions were added in v3, so only accept extensions in v3 certificates.
  // v4 certificates are not defined but there are some certificates issued
  // with v4 that expect v3 decoding. For compatibility reasons we handle them
  // as v3 certificates.
  if (version == der::Version::v3 || version == der::Version::v4) {
    rv = der::OptionalExtensions(tbsCertificate, CSC | 3,
                                 bind(&BackCert::RememberExtension, this, _1,
                                      _2, _3, _4));
    if (rv != Success) {
      return rv;
    }
    // The Netscape Certificate Type extension is an obsolete
    // Netscape-proprietary mechanism that we ignore in favor of the standard
    // extensions. However, some CAs have issued certificates with the Netscape
    // Cert Type extension marked critical. Thus, for compatibility reasons, we
    // "understand" this extension by ignoring it when it is not critical, and
    // by ensuring that the equivalent standardized extensions are present when
    // it is marked critical, based on the assumption that the information in
    // the Netscape Cert Type extension is consistent with the information in
    // the standard extensions.
    //
    // Here is a mapping between the Netscape Cert Type extension and the
    // standard extensions:
    //
    // Netscape Cert Type  |  BasicConstraints.cA  |  Extended Key Usage
    // --------------------+-----------------------+----------------------
    // SSL Server          |  false                |  id_kp_serverAuth
    // SSL Client          |  false                |  id_kp_clientAuth
    // S/MIME Client       |  false                |  id_kp_emailProtection
    // Object Signing      |  false                |  id_kp_codeSigning
    // SSL Server CA       |  true                 |  id_pk_serverAuth
    // SSL Client CA       |  true                 |  id_kp_clientAuth
    // S/MIME CA           |  true                 |  id_kp_emailProtection
    // Object Signing CA   |  true                 |  id_kp_codeSigning
    if (criticalNetscapeCertificateType.GetLength() > 0 &&
        (basicConstraints.GetLength() == 0 || extKeyUsage.GetLength() == 0)) {
      return Result::ERROR_UNKNOWN_CRITICAL_EXTENSION;
    }
  }

  return der::End(tbsCertificate);
}