#include "net/cert/cert_verify_proc_android.h"
#include <set>
#include <string>
#include <string_view>
#include <vector>
#include "base/check_op.h"
#include "base/containers/adapters.h"
#include "base/containers/span.h"
#include "base/metrics/histogram_functions.h"
#include "base/metrics/histogram_macros.h"
#include "base/notreached.h"
#include "base/strings/string_view_util.h"
#include "crypto/hash.h"
#include "net/android/cert_verify_result_android.h"
#include "net/android/network_library.h"
#include "net/base/hash_value.h"
#include "net/base/net_errors.h"
#include "net/cert/asn1_util.h"
#include "net/cert/cert_net_fetcher.h"
#include "net/cert/cert_status_flags.h"
#include "net/cert/cert_verify_proc.h"
#include "net/cert/cert_verify_result.h"
#include "net/cert/crl_set.h"
#include "net/cert/known_roots.h"
#include "net/cert/test_root_certs.h"
#include "net/cert/x509_certificate.h"
#include "net/cert/x509_util.h"
#include "third_party/boringssl/src/pki/cert_errors.h"
#include "third_party/boringssl/src/pki/parsed_certificate.h"
#include "url/gurl.h"
namespace net {
namespace {
const char kAuthType[] = "RSA";
const unsigned int kMaxAIAFetches = 5;
std::shared_ptr<const bssl::ParsedCertificate> FindLastCertWithUnknownIssuer(
const bssl::ParsedCertificateList& certs,
const std::shared_ptr<const bssl::ParsedCertificate>& start) {
DCHECK_GE(certs.size(), 1u);
std::set<std::shared_ptr<const bssl::ParsedCertificate>> used_in_path;
std::shared_ptr<const bssl::ParsedCertificate> last = start;
while (true) {
used_in_path.insert(last);
std::shared_ptr<const bssl::ParsedCertificate> last_issuer;
for (const auto& cert : certs) {
if (cert->normalized_subject() == last->normalized_issuer()) {
last_issuer = cert;
break;
}
}
if (!last_issuer) {
return last;
}
if (last_issuer->normalized_subject() == last_issuer->normalized_issuer()) {
return nullptr;
}
if (used_in_path.find(last_issuer) != used_in_path.end()) {
return nullptr;
}
last = last_issuer;
}
NOTREACHED();
}
bool PerformAIAFetchAndAddResultToVector(
scoped_refptr<CertNetFetcher> fetcher,
std::string_view uri,
bssl::ParsedCertificateList* cert_list) {
GURL url(uri);
if (!url.is_valid())
return false;
std::unique_ptr<CertNetFetcher::Request> request(fetcher->FetchCaIssuers(
url, CertNetFetcher::DEFAULT, CertNetFetcher::DEFAULT));
Error error;
std::vector<uint8_t> aia_fetch_bytes;
request->WaitForResult(&error, &aia_fetch_bytes);
if (error != OK)
return false;
bssl::CertErrors errors;
return bssl::ParsedCertificate::CreateAndAddToVector(
x509_util::CreateCryptoBuffer(aia_fetch_bytes),
x509_util::DefaultParseCertificateOptions(), cert_list, &errors);
}
android::CertVerifyStatusAndroid AttemptVerificationAfterAIAFetch(
const bssl::ParsedCertificateList& certs,
const std::string& hostname,
const std::string& ocsp_response,
const std::string& sct_list,
CertVerifyResult* verify_result,
std::vector<std::string>* verified_chain) {
std::vector<std::string> cert_bytes;
for (const auto& cert : certs) {
cert_bytes.emplace_back(base::as_string_view(cert->der_cert()));
}
bool is_issued_by_known_root;
std::vector<std::string> candidate_verified_chain;
android::CertVerifyStatusAndroid status;
android::VerifyX509CertChain(cert_bytes, kAuthType, hostname, ocsp_response,
sct_list, &status, &is_issued_by_known_root,
&candidate_verified_chain);
if (status == android::CERT_VERIFY_STATUS_ANDROID_OK) {
verify_result->is_issued_by_known_root = is_issued_by_known_root;
*verified_chain = candidate_verified_chain;
}
return status;
}
android::CertVerifyStatusAndroid TryVerifyWithAIAFetching(
const std::vector<std::string>& cert_bytes,
const std::string& hostname,
const std::string& ocsp_response,
const std::string& sct_list,
scoped_refptr<CertNetFetcher> cert_net_fetcher,
CertVerifyResult* verify_result,
std::vector<std::string>* verified_chain) {
if (!cert_net_fetcher)
return android::CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT;
bssl::CertErrors errors;
bssl::ParsedCertificateList certs;
for (const auto& cert : cert_bytes) {
if (!bssl::ParsedCertificate::CreateAndAddToVector(
x509_util::CreateCryptoBuffer(cert),
x509_util::DefaultParseCertificateOptions(), &certs, &errors)) {
return android::CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT;
}
}
std::shared_ptr<const bssl::ParsedCertificate> last_cert_with_unknown_issuer =
FindLastCertWithUnknownIssuer(certs, certs[0]);
if (!last_cert_with_unknown_issuer) {
return android::CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT;
}
unsigned int num_aia_fetches = 0;
while (true) {
if (!last_cert_with_unknown_issuer->has_authority_info_access())
return android::CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT;
for (const auto& uri : last_cert_with_unknown_issuer->ca_issuers_uris()) {
num_aia_fetches++;
if (num_aia_fetches > kMaxAIAFetches)
return android::CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT;
if (!PerformAIAFetchAndAddResultToVector(cert_net_fetcher, uri, &certs))
continue;
android::CertVerifyStatusAndroid status =
AttemptVerificationAfterAIAFetch(certs, hostname, ocsp_response,
sct_list, verify_result,
verified_chain);
if (status == android::CERT_VERIFY_STATUS_ANDROID_OK)
return status;
}
std::shared_ptr<const bssl::ParsedCertificate>
new_last_cert_with_unknown_issuer =
FindLastCertWithUnknownIssuer(certs, last_cert_with_unknown_issuer);
if (!new_last_cert_with_unknown_issuer ||
new_last_cert_with_unknown_issuer == last_cert_with_unknown_issuer) {
return android::CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT;
}
last_cert_with_unknown_issuer = new_last_cert_with_unknown_issuer;
}
NOTREACHED();
}
bool VerifyFromAndroidTrustManager(
const std::vector<std::string>& cert_bytes,
const std::string& hostname,
const std::string& ocsp_response,
const std::string& sct_list,
int flags,
scoped_refptr<CertNetFetcher> cert_net_fetcher,
CertVerifyResult* verify_result) {
android::CertVerifyStatusAndroid status =
android::CERT_VERIFY_STATUS_ANDROID_FAILED;
std::vector<std::string> verified_chain;
android::VerifyX509CertChain(
cert_bytes, kAuthType, hostname, ocsp_response, sct_list, &status,
&verify_result->is_issued_by_known_root, &verified_chain);
if (status == android::CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT &&
!(flags & CertVerifyProc::VERIFY_DISABLE_NETWORK_FETCHES)) {
status = TryVerifyWithAIAFetching(cert_bytes, hostname, ocsp_response,
sct_list, std::move(cert_net_fetcher),
verify_result, &verified_chain);
}
switch (status) {
case android::CERT_VERIFY_STATUS_ANDROID_FAILED:
return false;
case android::CERT_VERIFY_STATUS_ANDROID_OK:
break;
case android::CERT_VERIFY_STATUS_ANDROID_NO_TRUSTED_ROOT:
verify_result->cert_status |= CERT_STATUS_AUTHORITY_INVALID;
break;
case android::CERT_VERIFY_STATUS_ANDROID_EXPIRED:
case android::CERT_VERIFY_STATUS_ANDROID_NOT_YET_VALID:
verify_result->cert_status |= CERT_STATUS_DATE_INVALID;
break;
case android::CERT_VERIFY_STATUS_ANDROID_UNABLE_TO_PARSE:
verify_result->cert_status |= CERT_STATUS_INVALID;
break;
case android::CERT_VERIFY_STATUS_ANDROID_INCORRECT_KEY_USAGE:
verify_result->cert_status |= CERT_STATUS_INVALID;
break;
default:
NOTREACHED();
}
if (!verified_chain.empty()) {
std::vector<std::string_view> verified_chain_pieces(verified_chain.size());
for (size_t i = 0; i < verified_chain.size(); i++) {
verified_chain_pieces[i] = std::string_view(verified_chain[i]);
}
scoped_refptr<X509Certificate> verified_cert =
X509Certificate::CreateFromDERCertChain(verified_chain_pieces);
if (verified_cert.get())
verify_result->verified_cert = std::move(verified_cert);
else
verify_result->cert_status |= CERT_STATUS_INVALID;
} else if (!IsCertStatusError(verify_result->cert_status)) {
verify_result->cert_status |= CERT_STATUS_INVALID;
}
for (const auto& cert : base::Reversed(verified_chain)) {
std::string_view spki_bytes;
if (!asn1::ExtractSPKIFromDERCert(cert, &spki_bytes)) {
verify_result->cert_status |= CERT_STATUS_INVALID;
continue;
}
SHA256HashValue sha256(
crypto::hash::Sha256(base::as_byte_span(spki_bytes)));
verify_result->public_key_hashes.push_back(sha256);
if (!verify_result->is_issued_by_known_root) {
verify_result->is_issued_by_known_root =
GetNetTrustAnchorHistogramIdForSPKI(sha256) != 0;
}
}
std::ranges::reverse(verify_result->public_key_hashes);
return true;
}
void GetChainDEREncodedBytes(X509Certificate* cert,
std::vector<std::string>* chain_bytes) {
chain_bytes->reserve(cert->cert_buffers().size());
for (const auto& handle : cert->cert_buffers()) {
chain_bytes->emplace_back(
net::x509_util::CryptoBufferAsStringPiece(handle.get()));
}
}
}
CertVerifyProcAndroid::CertVerifyProcAndroid(
scoped_refptr<CertNetFetcher> cert_net_fetcher,
scoped_refptr<CRLSet> crl_set)
: CertVerifyProc(std::move(crl_set)),
cert_net_fetcher_(std::move(cert_net_fetcher)) {}
CertVerifyProcAndroid::~CertVerifyProcAndroid() = default;
int CertVerifyProcAndroid::VerifyInternal(X509Certificate* cert,
const std::string& hostname,
const std::string& ocsp_response,
const std::string& sct_list,
int flags,
CertVerifyResult* verify_result,
const NetLogWithSource& net_log) {
std::vector<std::string> cert_bytes;
GetChainDEREncodedBytes(cert, &cert_bytes);
if (!VerifyFromAndroidTrustManager(cert_bytes, hostname, ocsp_response,
sct_list, flags, cert_net_fetcher_,
verify_result)) {
return ERR_FAILED;
}
if (IsCertStatusError(verify_result->cert_status))
return MapCertStatusToNetError(verify_result->cert_status);
if (TestRootCerts::HasInstance() &&
!verify_result->verified_cert->intermediate_buffers().empty() &&
TestRootCerts::GetInstance()->IsKnownRoot(x509_util::CryptoBufferAsSpan(
verify_result->verified_cert->intermediate_buffers().back().get()))) {
verify_result->is_issued_by_known_root = true;
}
LogNameNormalizationMetrics(".Android", verify_result->verified_cert.get(),
verify_result->is_issued_by_known_root);
return OK;
}
}