Index: chrome/browser/chromeos/attestation/attestation_policy_observer.cc |
diff --git a/chrome/browser/chromeos/attestation/attestation_policy_observer.cc b/chrome/browser/chromeos/attestation/attestation_policy_observer.cc |
index 371c0be964b756751f10fc51e160c6125097f3bd..08decb54812305f22ed9255a216d33cc8150f84b 100644 |
--- a/chrome/browser/chromeos/attestation/attestation_policy_observer.cc |
+++ b/chrome/browser/chromeos/attestation/attestation_policy_observer.cc |
@@ -23,6 +23,7 @@ |
#include "components/policy/core/common/cloud/cloud_policy_manager.h" |
#include "content/public/browser/browser_thread.h" |
#include "content/public/browser/notification_details.h" |
+#include "net/cert/pem_tokenizer.h" |
#include "net/cert/x509_certificate.h" |
namespace { |
@@ -210,13 +211,25 @@ void AttestationPolicyObserver::GetExistingCertificate() { |
} |
void AttestationPolicyObserver::CheckCertificateExpiry( |
- const std::string& certificate) { |
- scoped_refptr<net::X509Certificate> x509( |
- net::X509Certificate::CreateFromBytes(certificate.data(), |
- certificate.length())); |
- if (!x509.get() || x509->valid_expiry().is_null()) { |
- LOG(WARNING) << "Failed to parse certificate, cannot check expiry."; |
- } else { |
+ const std::string& pem_certificate_chain) { |
+ int num_certificates = 0; |
+ net::PEMTokenizer pem_tokenizer(pem_certificate_chain, {"CERTIFICATE"}); |
+ while (pem_tokenizer.GetNext()) { |
+ ++num_certificates; |
+ scoped_refptr<net::X509Certificate> x509 = |
+ net::X509Certificate::CreateFromBytes(pem_tokenizer.data().data(), |
+ pem_tokenizer.data().length()); |
+ if (!x509.get() || x509->valid_expiry().is_null()) { |
+ // This logic intentionally fails open. In theory this should not happen |
+ // but in practice parsing X.509 can be brittle and there are a lot of |
+ // factors including which underlying module is parsing the certificate, |
+ // whether that module performs more checks than just ASN.1/DER format, |
+ // and the server module that generated the certificate(s). Renewal is |
+ // expensive so we only renew certificates with good evidence that they |
+ // have expired or will soon expire; if we don't know, we don't renew. |
+ LOG(WARNING) << "Failed to parse certificate, cannot check expiry."; |
+ continue; |
+ } |
const base::TimeDelta threshold = |
base::TimeDelta::FromDays(kExpiryThresholdInDays); |
if ((base::Time::Now() + threshold) > x509->valid_expiry()) { |
@@ -225,23 +238,25 @@ void AttestationPolicyObserver::CheckCertificateExpiry( |
return; |
} |
} |
- |
+ if (num_certificates == 0) { |
+ LOG(WARNING) << "Failed to parse certificate chain, cannot check expiry."; |
+ } |
// Get the payload and check if the certificate has already been uploaded. |
GetKeyPayload(base::Bind(&AttestationPolicyObserver::CheckIfUploaded, |
weak_factory_.GetWeakPtr(), |
- certificate)); |
+ pem_certificate_chain)); |
} |
void AttestationPolicyObserver::UploadCertificate( |
- const std::string& certificate) { |
+ const std::string& pem_certificate_chain) { |
policy_client_->UploadCertificate( |
- certificate, |
+ pem_certificate_chain, |
base::Bind(&AttestationPolicyObserver::OnUploadComplete, |
weak_factory_.GetWeakPtr())); |
} |
void AttestationPolicyObserver::CheckIfUploaded( |
- const std::string& certificate, |
+ const std::string& pem_certificate_chain, |
const std::string& key_payload) { |
AttestationKeyPayload payload_pb; |
if (!key_payload.empty() && |
@@ -250,7 +265,7 @@ void AttestationPolicyObserver::CheckIfUploaded( |
// Already uploaded... nothing more to do. |
return; |
} |
- UploadCertificate(certificate); |
+ UploadCertificate(pem_certificate_chain); |
} |
void AttestationPolicyObserver::GetKeyPayload( |