Ejemplo n.º 1
0
// TODO: Remove #include "pkix/pkixnss.h", #include "cert.h",
// #include "ScopedPtr.h", etc. when this is rewritten to be independent of
// NSS.
Result
CheckNameConstraints(Input encodedNameConstraints,
                     const BackCert& firstChild,
                     KeyPurposeId requiredEKUIfPresent)
{
  ScopedPtr<PLArenaPool, PORT_FreeArena_false>
    arena(PORT_NewArena(DER_DEFAULT_CHUNKSIZE));
  if (!arena) {
    return Result::FATAL_ERROR_NO_MEMORY;
  }

  SECItem encodedNameConstraintsSECItem =
    UnsafeMapInputToSECItem(encodedNameConstraints);

  // Owned by arena
  const CERTNameConstraints* constraints =
    CERT_DecodeNameConstraintsExtension(arena.get(),
                                        &encodedNameConstraintsSECItem);
  if (!constraints) {
    return MapPRErrorCodeToResult(PR_GetError());
  }

  for (const BackCert* child = &firstChild; child; child = child->childCert) {
    SECItem childCertDER = UnsafeMapInputToSECItem(child->GetDER());
    ScopedPtr<CERTCertificate, CERT_DestroyCertificate>
      nssCert(CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &childCertDER,
                                      nullptr, false, true));
    if (!nssCert) {
      return MapPRErrorCodeToResult(PR_GetError());
    }

    bool includeCN = child->endEntityOrCA == EndEntityOrCA::MustBeEndEntity &&
                     requiredEKUIfPresent == KeyPurposeId::id_kp_serverAuth;
    // owned by arena
    const CERTGeneralName*
      names(CERT_GetConstrainedCertificateNames(nssCert.get(), arena.get(),
                                                includeCN));
    if (!names) {
      return MapPRErrorCodeToResult(PR_GetError());
    }

    CERTGeneralName* currentName = const_cast<CERTGeneralName*>(names);
    do {
      if (CERT_CheckNameSpace(arena.get(), constraints, currentName)
            != SECSuccess) {
        // XXX: It seems like CERT_CheckNameSpace doesn't always call
        // PR_SetError when it fails, so we ignore what PR_GetError would
        // return. NSS's cert_VerifyCertChainOld does something similar.
        return Result::ERROR_CERT_NOT_IN_NAME_SPACE;
      }
      currentName = CERT_GetNextGeneralName(currentName);
    } while (currentName != names);
  }

  return Success;
}
Ejemplo n.º 2
0
Result
AppTrustDomain::GetCertTrust(EndEntityOrCA endEntityOrCA,
                             const CertPolicyId& policy,
                             Input candidateCertDER,
                     /*out*/ TrustLevel& trustLevel)
{
  MOZ_ASSERT(policy.IsAnyPolicy());
  MOZ_ASSERT(mTrustedRoot);
  if (!policy.IsAnyPolicy()) {
    return Result::FATAL_ERROR_INVALID_ARGS;
  }
  if (!mTrustedRoot) {
    return Result::FATAL_ERROR_INVALID_STATE;
  }

  // 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.
  SECItem candidateCertDERSECItem =
    UnsafeMapInputToSECItem(candidateCertDER);
  UniqueCERTCertificate candidateCert(
    CERT_NewTempCertificate(CERT_GetDefaultCertDB(), &candidateCertDERSECItem,
                            nullptr, false, true));
  if (!candidateCert) {
    return MapPRErrorCodeToResult(PR_GetError());
  }

  CERTCertTrust trust;
  if (CERT_GetCertTrust(candidateCert.get(), &trust) == SECSuccess) {
    uint32_t 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.
    uint32_t relevantTrustBit = endEntityOrCA == EndEntityOrCA::MustBeCA
                              ? CERTDB_TRUSTED_CA
                              : CERTDB_TRUSTED;
    if (((flags & (relevantTrustBit | CERTDB_TERMINAL_RECORD)))
            == CERTDB_TERMINAL_RECORD) {
      trustLevel = TrustLevel::ActivelyDistrusted;
      return Success;
    }
  }

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

  trustLevel = TrustLevel::InheritsTrust;
  return Success;
}
Ejemplo n.º 3
0
Result
OCSPCache::Entry::Init(const CertID& aCertID)
{
  SECStatus srv = CertIDHash(mIDHash, aCertID);
  if (srv != SECSuccess) {
    return MapPRErrorCodeToResult(PR_GetError());
  }
  return Success;
}
Ejemplo n.º 4
0
Result
AppTrustDomain::IsChainValid(const DERArray& certChain, Time time)
{
  SECStatus srv = ConstructCERTCertListFromReversedDERArray(certChain,
                                                            mCertChain);
  if (srv != SECSuccess) {
    return MapPRErrorCodeToResult(PR_GetError());
  }
  return Success;
}
Ejemplo n.º 5
0
Result
CertListContainsExpectedKeys(const CERTCertList* certList,
                             const char* hostname, Time time,
                             CertVerifier::PinningMode pinningMode)
{
  if (pinningMode == CertVerifier::pinningDisabled) {
    PR_LOG(gCertVerifierLog, PR_LOG_DEBUG,
           ("Pinning is disabled; not checking keys."));
    return Success;
  }

  if (!certList) {
    return Result::FATAL_ERROR_INVALID_ARGS;
  }

  CERTCertListNode* rootNode = CERT_LIST_TAIL(certList);
  if (CERT_LIST_END(rootNode, certList)) {
    return Result::FATAL_ERROR_INVALID_ARGS;
  }

  bool isBuiltInRoot = false;
  SECStatus srv = IsCertBuiltInRoot(rootNode->cert, isBuiltInRoot);
  if (srv != SECSuccess) {
    return MapPRErrorCodeToResult(PR_GetError());
  }
  // If desired, the user can enable "allow user CA MITM mode", in which
  // case key pinning is not enforced for certificates that chain to trust
  // anchors that are not in Mozilla's root program
  if (!isBuiltInRoot && pinningMode == CertVerifier::pinningAllowUserCAMITM) {
    return Success;
  }

  bool enforceTestMode = (pinningMode == CertVerifier::pinningEnforceTestMode);
  if (PublicKeyPinningService::ChainHasValidPins(certList, hostname, time,
                                                 enforceTestMode)) {
    return Success;
  }

  return Result::ERROR_KEY_PINNING_FAILURE;
}
Ejemplo n.º 6
0
Result
DigestBuf(Input item, /*out*/ uint8_t* digestBuf, size_t digestBufLen)
{
  static_assert(TrustDomain::DIGEST_LENGTH == SHA1_LENGTH,
                "TrustDomain::DIGEST_LENGTH must be 20 (SHA-1 digest length)");
  if (digestBufLen != TrustDomain::DIGEST_LENGTH) {
    PR_NOT_REACHED("invalid hash length");
    return Result::FATAL_ERROR_INVALID_ARGS;
  }
  SECItem itemSECItem = UnsafeMapInputToSECItem(item);
  if (itemSECItem.len >
        static_cast<decltype(itemSECItem.len)>(
          std::numeric_limits<int32_t>::max())) {
    PR_NOT_REACHED("large items should not be possible here");
    return Result::FATAL_ERROR_INVALID_ARGS;
  }
  SECStatus srv = PK11_HashBuf(SEC_OID_SHA1, digestBuf, itemSECItem.data,
                               static_cast<int32_t>(itemSECItem.len));
  if (srv != SECSuccess) {
    return MapPRErrorCodeToResult(PR_GetError());
  }
  return Success;
}
Ejemplo n.º 7
0
Result
VerifySignedData(const SignedDataWithSignature& sd,
                 Input subjectPublicKeyInfo, void* pkcs11PinArg)
{
  // See bug 921585.
  if (sd.data.GetLength() >
        static_cast<unsigned int>(std::numeric_limits<int>::max())) {
    return Result::FATAL_ERROR_INVALID_ARGS;
  }

  SECOidTag pubKeyAlg;
  SECOidTag digestAlg;
  switch (sd.algorithm) {
    case SignatureAlgorithm::ecdsa_with_sha512:
      pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
      digestAlg = SEC_OID_SHA512;
      break;
    case SignatureAlgorithm::ecdsa_with_sha384:
      pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
      digestAlg = SEC_OID_SHA384;
      break;
    case SignatureAlgorithm::ecdsa_with_sha256:
      pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
      digestAlg = SEC_OID_SHA256;
      break;
    case SignatureAlgorithm::ecdsa_with_sha1:
      pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
      digestAlg = SEC_OID_SHA1;
      break;
    case SignatureAlgorithm::rsa_pkcs1_with_sha512:
      pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
      digestAlg = SEC_OID_SHA512;
      break;
    case SignatureAlgorithm::rsa_pkcs1_with_sha384:
      pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
      digestAlg = SEC_OID_SHA384;
      break;
    case SignatureAlgorithm::rsa_pkcs1_with_sha256:
      pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
      digestAlg = SEC_OID_SHA256;
      break;
    case SignatureAlgorithm::rsa_pkcs1_with_sha1:
      pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
      digestAlg = SEC_OID_SHA1;
      break;
    case SignatureAlgorithm::dsa_with_sha256:
      pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE;
      digestAlg = SEC_OID_SHA256;
      break;
    case SignatureAlgorithm::dsa_with_sha1:
      pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE;
      digestAlg = SEC_OID_SHA1;
      break;
    default:
      PR_NOT_REACHED("unknown signature algorithm");
      return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
  }

  Result rv;
  ScopedSECKeyPublicKey pubKey;
  rv = CheckPublicKeySize(subjectPublicKeyInfo, pubKey);
  if (rv != Success) {
    return rv;
  }

  // The static_cast is safe according to the check above that references
  // bug 921585.
  SECItem dataSECItem(UnsafeMapInputToSECItem(sd.data));
  SECItem signatureSECItem(UnsafeMapInputToSECItem(sd.signature));
  SECStatus srv = VFY_VerifyDataDirect(dataSECItem.data,
                                       static_cast<int>(dataSECItem.len),
                                       pubKey.get(), &signatureSECItem,
                                       pubKeyAlg, digestAlg, nullptr,
                                       pkcs11PinArg);
  if (srv != SECSuccess) {
    return MapPRErrorCodeToResult(PR_GetError());
  }

  return Success;
}
Ejemplo n.º 8
0
Result
VerifySignedData(const SignedDataWithSignature& sd,
                 Input subjectPublicKeyInfo, void* pkcs11PinArg)
{
  SECOidTag pubKeyAlg;
  SECOidTag digestAlg;
  switch (sd.algorithm) {
    case SignatureAlgorithm::ecdsa_with_sha512:
      pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
      digestAlg = SEC_OID_SHA512;
      break;
    case SignatureAlgorithm::ecdsa_with_sha384:
      pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
      digestAlg = SEC_OID_SHA384;
      break;
    case SignatureAlgorithm::ecdsa_with_sha256:
      pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
      digestAlg = SEC_OID_SHA256;
      break;
    case SignatureAlgorithm::ecdsa_with_sha1:
      pubKeyAlg = SEC_OID_ANSIX962_EC_PUBLIC_KEY;
      digestAlg = SEC_OID_SHA1;
      break;
    case SignatureAlgorithm::rsa_pkcs1_with_sha512:
      pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
      digestAlg = SEC_OID_SHA512;
      break;
    case SignatureAlgorithm::rsa_pkcs1_with_sha384:
      pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
      digestAlg = SEC_OID_SHA384;
      break;
    case SignatureAlgorithm::rsa_pkcs1_with_sha256:
      pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
      digestAlg = SEC_OID_SHA256;
      break;
    case SignatureAlgorithm::rsa_pkcs1_with_sha1:
      pubKeyAlg = SEC_OID_PKCS1_RSA_ENCRYPTION;
      digestAlg = SEC_OID_SHA1;
      break;
    case SignatureAlgorithm::dsa_with_sha256:
      pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE;
      digestAlg = SEC_OID_SHA256;
      break;
    case SignatureAlgorithm::dsa_with_sha1:
      pubKeyAlg = SEC_OID_ANSIX9_DSA_SIGNATURE;
      digestAlg = SEC_OID_SHA1;
      break;
    default:
      PR_NOT_REACHED("unknown signature algorithm");
      return Result::ERROR_CERT_SIGNATURE_ALGORITHM_DISABLED;
  }

  Result rv;
  ScopedSECKeyPublicKey pubKey;
  rv = CheckPublicKeySize(subjectPublicKeyInfo, pubKey);
  if (rv != Success) {
    return rv;
  }

  // The static_cast is safe as long as the length of the data in sd.data can
  // fit in an int. Right now that length is stored as a uint16_t, so this
  // works. In the future this may change, hence the assertion.
  // See also bug 921585.
  static_assert(sizeof(decltype(sd.data.GetLength())) < sizeof(int),
                "sd.data.GetLength() must fit in an int");
  SECItem dataSECItem(UnsafeMapInputToSECItem(sd.data));
  SECItem signatureSECItem(UnsafeMapInputToSECItem(sd.signature));
  SECStatus srv = VFY_VerifyDataDirect(dataSECItem.data,
                                       static_cast<int>(dataSECItem.len),
                                       pubKey.get(), &signatureSECItem,
                                       pubKeyAlg, digestAlg, nullptr,
                                       pkcs11PinArg);
  if (srv != SECSuccess) {
    return MapPRErrorCodeToResult(PR_GetError());
  }

  return Success;
}