コード例 #1
0
ファイル: AppTrustDomain.cpp プロジェクト: randombit/hacrypto
SECStatus
AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
                             const CertPolicyId& policy,
                             const SECItem& candidateCertDER,
                     /*out*/ TrustLevel* trustLevel)
{
  MOZ_ASSERT(policy.IsAnyPolicy());
  MOZ_ASSERT(trustLevel);
  MOZ_ASSERT(mTrustedRoot);
  if (!trustLevel || !policy.IsAnyPolicy()) {
    PR_SetError(SEC_ERROR_INVALID_ARGS, 0);
    return SECFailure;
  }
  if (!mTrustedRoot) {
    PR_SetError(PR_INVALID_STATE_ERROR, 0);
    return SECFailure;
  }

  // Handle active distrust of the certificate.

  // XXX: This would be cleaner and more efficient if we could get the trust
  // information without constructing a CERTCertificate here, but NSS doesn't
  // expose it in any other easy-to-use fashion.
  ScopedCERTCertificate candidateCert(
    CERT_NewTempCertificate(CERT_GetDefaultCertDB(),
                            const_cast<SECItem*>(&candidateCertDER), nullptr,
                            false, true));
  if (!candidateCert) {
    return SECFailure;
  }

  CERTCertTrust trust;
  if (CERT_GetCertTrust(candidateCert.get(), &trust) == SECSuccess) {
    PRUint32 flags = SEC_GET_TRUST_FLAGS(&trust, trustObjectSigning);

    // For DISTRUST, we use the CERTDB_TRUSTED or CERTDB_TRUSTED_CA bit,
    // because we can have active distrust for either type of cert. Note that
    // CERTDB_TERMINAL_RECORD means "stop trying to inherit trust" so if the
    // relevant trust bit isn't set then that means the cert must be considered
    // distrusted.
    PRUint32 relevantTrustBit = endEntityOrCA == EndEntityOrCA::MustBeCA
                              ? CERTDB_TRUSTED_CA
                              : CERTDB_TRUSTED;
    if (((flags & (relevantTrustBit | CERTDB_TERMINAL_RECORD)))
            == CERTDB_TERMINAL_RECORD) {
      *trustLevel = TrustLevel::ActivelyDistrusted;
      return SECSuccess;
    }
  }

  // mTrustedRoot is the only trust anchor for this validation.
  if (CERT_CompareCerts(mTrustedRoot.get(), candidateCert.get())) {
    *trustLevel = TrustLevel::TrustAnchor;
    return SECSuccess;
  }

  *trustLevel = TrustLevel::InheritsTrust;
  return SECSuccess;
}
コード例 #2
0
ファイル: pkixcheck.cpp プロジェクト: franzks/gecko-dev
// certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
Result
CheckCertificatePolicies(EndEntityOrCA endEntityOrCA,
                         const SECItem* encodedCertificatePolicies,
                         const SECItem* encodedInhibitAnyPolicy,
                         TrustLevel trustLevel,
                         const CertPolicyId& requiredPolicy)
{
  if (requiredPolicy.numBytes == 0 ||
      requiredPolicy.numBytes > sizeof requiredPolicy.bytes) {
    return Fail(FatalError, SEC_ERROR_INVALID_ARGS);
  }

  // Ignore all policy information if the caller indicates any policy is
  // acceptable. See TrustDomain::GetCertTrust and the policy part of
  // BuildCertChain's documentation.
  if (requiredPolicy.IsAnyPolicy()) {
    return Success;
  }

  // Bug 989051. Until we handle inhibitAnyPolicy we will fail close when
  // inhibitAnyPolicy extension is present and we need to evaluate certificate
  // policies.
  if (encodedInhibitAnyPolicy) {
    return Fail(RecoverableError, SEC_ERROR_POLICY_VALIDATION_FAILED);
  }

  // The root CA certificate may omit the policies that it has been
  // trusted for, so we cannot require the policies to be present in those
  // certificates. Instead, the determination of which roots are trusted for
  // which policies is made by the TrustDomain's GetCertTrust method.
  if (trustLevel == TrustLevel::TrustAnchor &&
      endEntityOrCA == EndEntityOrCA::MustBeCA) {
    return Success;
  }

  if (!encodedCertificatePolicies) {
    return Fail(RecoverableError, SEC_ERROR_POLICY_VALIDATION_FAILED);
  }

  bool found = false;

  der::Input input;
  if (input.Init(encodedCertificatePolicies->data,
                 encodedCertificatePolicies->len) != der::Success) {
    return Fail(RecoverableError, SEC_ERROR_POLICY_VALIDATION_FAILED);
  }
  if (der::NestedOf(input, der::SEQUENCE, der::SEQUENCE, der::EmptyAllowed::No,
                    bind(CheckPolicyInformation, _1, endEntityOrCA,
                         requiredPolicy, ref(found))) != der::Success) {
    return Fail(RecoverableError, SEC_ERROR_POLICY_VALIDATION_FAILED);
  }
  if (der::End(input) != der::Success) {
    return Fail(RecoverableError, SEC_ERROR_POLICY_VALIDATION_FAILED);
  }
  if (!found) {
    return Fail(RecoverableError, SEC_ERROR_POLICY_VALIDATION_FAILED);
  }

  return Success;
}
コード例 #3
0
ファイル: pkixcheck.cpp プロジェクト: L2-D2/gecko-dev
// certificatePolicies ::= SEQUENCE SIZE (1..MAX) OF PolicyInformation
Result
CheckCertificatePolicies(EndEntityOrCA endEntityOrCA,
                         const Input* encodedCertificatePolicies,
                         const Input* encodedInhibitAnyPolicy,
                         TrustLevel trustLevel,
                         const CertPolicyId& requiredPolicy)
{
  if (requiredPolicy.numBytes == 0 ||
      requiredPolicy.numBytes > sizeof requiredPolicy.bytes) {
    return Result::FATAL_ERROR_INVALID_ARGS;
  }

  bool requiredPolicyFound = requiredPolicy.IsAnyPolicy();
  if (requiredPolicyFound) {
    return Success;
  }

  // Bug 989051. Until we handle inhibitAnyPolicy we will fail close when
  // inhibitAnyPolicy extension is present and we are validating for a policy.
  if (!requiredPolicyFound && encodedInhibitAnyPolicy) {
    return Result::ERROR_POLICY_VALIDATION_FAILED;
  }

  // The root CA certificate may omit the policies that it has been
  // trusted for, so we cannot require the policies to be present in those
  // certificates. Instead, the determination of which roots are trusted for
  // which policies is made by the TrustDomain's GetCertTrust method.
  if (trustLevel == TrustLevel::TrustAnchor &&
      endEntityOrCA == EndEntityOrCA::MustBeCA) {
    requiredPolicyFound = true;
  }

  Input requiredPolicyDER;
  if (requiredPolicyDER.Init(requiredPolicy.bytes, requiredPolicy.numBytes)
        != Success) {
    return Result::FATAL_ERROR_INVALID_ARGS;
  }

  if (encodedCertificatePolicies) {
    Reader extension(*encodedCertificatePolicies);
    Reader certificatePolicies;
    Result rv = der::ExpectTagAndGetValue(extension, der::SEQUENCE,
                                          certificatePolicies);
    if (rv != Success) {
      return Result::ERROR_POLICY_VALIDATION_FAILED;
    }
    if (!extension.AtEnd()) {
      return Result::ERROR_POLICY_VALIDATION_FAILED;
    }

    do {
      // PolicyInformation ::= SEQUENCE {
      //         policyIdentifier   CertPolicyId,
      //         policyQualifiers   SEQUENCE SIZE (1..MAX) OF
      //                                 PolicyQualifierInfo OPTIONAL }
      Reader policyInformation;
      rv = der::ExpectTagAndGetValue(certificatePolicies, der::SEQUENCE,
                                     policyInformation);
      if (rv != Success) {
        return Result::ERROR_POLICY_VALIDATION_FAILED;
      }

      Reader policyIdentifier;
      rv = der::ExpectTagAndGetValue(policyInformation, der::OIDTag,
                                     policyIdentifier);
      if (rv != Success) {
        return rv;
      }

      if (policyIdentifier.MatchRest(requiredPolicyDER)) {
        requiredPolicyFound = true;
      } else if (endEntityOrCA == EndEntityOrCA::MustBeCA &&
                 policyIdentifier.MatchRest(anyPolicy)) {
        requiredPolicyFound = true;
      }

      // RFC 5280 Section 4.2.1.4 says "Optional qualifiers, which MAY be
      // present, are not expected to change the definition of the policy." Also,
      // it seems that Section 6, which defines validation, does not require any
      // matching of qualifiers. Thus, doing anything with the policy qualifiers
      // would be a waste of time and a source of potential incompatibilities, so
      // we just ignore them.
    } while (!requiredPolicyFound && !certificatePolicies.AtEnd());
  }

  if (!requiredPolicyFound) {
    return Result::ERROR_POLICY_VALIDATION_FAILED;
  }

  return Success;
}