Low watch CVSS 4.3 chrome Input Validation 🔧 Commit mapped

Overview

Low
Severity
4.3
CVSS
No
Exploited ITW
Fixed
Fix Status
ImpactImproper input validation in Chromium
DescriptionImproper input validation in Chromium
ComponentChromium
Sub-componentFortify
Bug ClassInput Validation
Action tierwatch — logic/policy bug — security-relevant, no memory-unsafety
Computed by PatchGap's deterministic exploitability ruler from the fixing commit. patch-now = RCE-class & attacker-reachable in a default config, or exploited in the wild; watch = real security signal below that bar; noise = no security relevance.
Tracker513143955
Fix commit530c94950ded (chromium/src) +78/-23
CWECWE-20 (Improper input validation)
CVSS vectorCVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:L/A:N
CISA KEVNot listed
CreditedGoogle
Reported2026-05-14 (per vendor advisory)
Fix landed2026-07-28 (public git)
Disclosed2026-09-08
Patch gapNot computed: several commits cite this bug and it is not yet established which one is the fix.

Background

SPKI (Subject Public Key Info)
the DER-encoded structure inside an X.509 certificate that holds the public key and its algorithm, uniquely identifying the key the certificate binds to.
`KeyUploadClient`
the enterprise client-certificates component that uploads a browser-generated public key to the Device Management (DM) server and receives back a provisioned client certificate.
`PrivateKey`
the local platform key object; its GetSubjectPublicKeyInfo() returns the SPKI of the key that was originally uploaded to the DM server.
`EVP_PKEY_cmp`
a BoringSSL routine that returns 1 when two parsed public keys are cryptographically equal, used here to bind the returned certificate to the uploaded key.

Root Cause Analysis

In KeyUploadClientImpl::OnCertificateResponseReceived, the client parsed the PEM-encoded certificate returned by the DM server and, pre-patch, accepted it whenever !certs.empty() — it performed no check that the certificate’s public key corresponded to the key the browser had just uploaded. This violated the invariant that a provisioned client certificate must attest to the browser’s own key: any certificate the server chose to return, including one embedding an attacker-controlled or unrelated public key, was accepted and installed. The removed comment // Try to parse the client certificate. reflects that parsing success was treated as the only gate.

The fix threads the scoped_refptr<PrivateKey> through CreateCertificate → OnCertificateRequestCreated → OnCertificateResponseReceived so the originally uploaded key is available at response time, and adds the new VerifySPKI helper, extending the acceptance condition to !certs.empty() && VerifySPKI(certs[0].get(), private_key.get()). VerifySPKI extracts the certificate’s SPKI with net::asn1::ExtractSPKIFromDERCert, fetches the expected SPKI from private_key->GetSubjectPublicKeyInfo(), parses both via crypto::evp::PublicKeyFromBytes, and returns true only when EVP_PKEY_cmp reports equality — so a mismatched or unparseable key now causes the certificate to be rejected. This is a tightening of input validation, not a relaxation.

Key insight
The client trusted the DM server’s returned certificate without cryptographically binding it to the public key it had uploaded; the fix adds an SPKI-equality check so only a certificate carrying the browser’s own key is accepted.

Attack Path

  1. Position a spoofed or malicious DM server An attacker who controls or impersonates the Device Management endpoint (or the response path to it) responds to the browser’s public-key upload with an attacker-chosen certificate.
  2. Return an arbitrary certificate The server sets pem_encoded_certificate in the browser_public_key_upload_response to a well-formed X.509 certificate that embeds a public key unrelated to the one the browser uploaded.
  3. Bypass the parse-only gate (pre-patch) OnCertificateResponseReceived parses the PEM via CreateCertificateListFromBytes; because the old code only checked !certs.empty(), the attacker’s certificate is accepted and provisioned as the client certificate.
  4. Injected tracking/identity certificate is installed The browser now holds a client certificate not bound to its own key, enabling the injected “tracking certificate” described in the advisory (inferred beyond this: any downstream authentication or identity abuse of the injected certificate).

Impact Assessment

An attacker able to spoof or man-in-the-middle the DM server can cause an enterprise browser to accept and install an arbitrary client certificate that is not bound to the browser’s uploaded key, per the advisory enabling injection of malicious or spoofed tracking certificates. The affected context is the enterprise client-certificates provisioning flow in the browser process, and the precondition is control over (or interposition on) the DM server’s upload response. The advisory classifies this as improper input validation in Chromium; no exploited-in-the-wild status or terminal escalation is stated, so any further identity or authentication abuse of the injected certificate is (inferred).

Changed Functions

FunctionChangeNotes
if
components/enterprise/client_certificates/core/key_upload_client.cc
modified
KeyUploadClientImpl
components/enterprise/client_certificates/core/key_upload_client.cc
modified
if
components/enterprise/client_certificates/core/key_upload_client_unittest.cc
modified

Files Changed

  • components/enterprise/client_certificates/core/key_upload_client_unittest.cc
  • components/enterprise/client_certificates/core/key_upload_client.cc

Audit Directions

  • Server-returned material accepted after parse-only checks
    Audit other DM-server and remote-response handlers that treat successful parsing (non-empty result) as sufficient without cryptographically binding the returned object to a locally held key or expected identity.
  • Key/certificate binding gaps
    Look for provisioning or enrollment paths that upload a public key and later consume a certificate or credential without comparing SPKI, key fingerprint, or EVP_PKEY_cmp equality against the originating key.
  • State not threaded to the verification point
    Review async callback chains where the value needed to validate a response (here PrivateKey) is not carried through, making the verification impossible and inviting a missing check.
From 530c94950ded75f64ae9910b004d119bb3f02d2f Mon Sep 17 00:00:00 2001
From: Anatoli Hancharou <[email protected]>
Date: Tue, 28 Jul 2026 07:14:27 -0700
Subject: [PATCH] [Fortify] Implement SPKI binding check for client certificates

The client previously accepted any certificate returned by the DM
server. This CL extracts the Subject Public Key Info (SPKI) from the
downloaded certificate and verifies it matches the SPKI of the key that
was originally uploaded, preventing malicious or spoofed servers from
injecting arbitrary tracking certificates.

Bug: 513143955
Change-Id: Ie87b5c1365d9d9942659aefcefec5bc3a3f1ef2f
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/8086416
Commit-Queue: Anatoli Hancharou <[email protected]>
Reviewed-by: Sebastien Lalancette <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1669451}
---
diff --git a/components/enterprise/client_certificates/core/key_upload_client.cc b/components/enterprise/client_certificates/core/key_upload_client.cc
index 3b139b1..7d9e6aa 100644
--- a/components/enterprise/client_certificates/core/key_upload_client.cc
+++ b/components/enterprise/client_certificates/core/key_upload_client.cc
@@ -23,8 +23,12 @@
 #include "components/enterprise/client_certificates/core/private_key_types.h"
 #include "components/policy/core/common/cloud/dmserver_job_configurations.h"
 #include "components/policy/proto/device_management_backend.pb.h"
+#include "crypto/evp.h"
 #include "crypto/signature_verifier.h"
+#include "net/cert/asn1_util.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
+#include "third_party/boringssl/src/include/openssl/evp.h"
 
 using BPKUR = enterprise_management::BrowserPublicKeyUploadRequest;
 
@@ -85,6 +89,28 @@
   return overall_request;
 }
 
+bool VerifySPKI(const net::X509Certificate* cert,
+                const PrivateKey* private_key) {
+  std::string_view extracted_spki;
+  if (!net::asn1::ExtractSPKIFromDERCert(
+          net::x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()),
+          &extracted_spki)) {
+    return false;
+  }
+  std::vector<uint8_t> expected_spki = private_key->GetSubjectPublicKeyInfo();
+
+  bssl::UniquePtr<EVP_PKEY> cert_key =
+      crypto::evp::PublicKeyFromBytes(base::as_byte_span(extracted_spki));
+  bssl::UniquePtr<EVP_PKEY> platform_key =
+      crypto::evp::PublicKeyFromBytes(expected_spki);
+
+  if (!cert_key || !platform_key) {
+    return false;
+  }
+
+  return EVP_PKEY_cmp(cert_key.get(), platform_key.get()) == 1;
+}
+
 }  // namespace
 
 class KeyUploadClientImpl : public KeyUploadClient {
@@ -111,11 +137,13 @@
           callback);
 
   void OnCertificateRequestCreated(
+      scoped_refptr<PrivateKey> private_key,
       CreateCertificateCallback callback,
       UploadClientErrorOr<enterprise_management::DeviceManagementRequest>
           request);
 
-  void OnCertificateResponseReceived(CreateCertificateCallback callback,
+  void OnCertificateResponseReceived(scoped_refptr<PrivateKey> private_key,
+                                     CreateCertificateCallback callback,
                                      policy::DMServerJobResult result);
 
   void OnSyncRequestCreated(
@@ -153,7 +181,8 @@
     CreateCertificateCallback callback) {
   GetRequest(private_key, /*create_certificate=*/true,
              base::BindOnce(&KeyUploadClientImpl::OnCertificateRequestCreated,
-                            weak_factory_.GetWeakPtr(), std::move(callback)));
+                            weak_factory_.GetWeakPtr(), private_key,
+                            std::move(callback)));
 }
 
 void KeyUploadClientImpl::SyncKey(scoped_refptr<PrivateKey> private_key,
@@ -194,6 +223,7 @@
 }
 
 void KeyUploadClientImpl::OnCertificateRequestCreated(
+    scoped_refptr<PrivateKey> private_key,
     CreateCertificateCallback callback,
     UploadClientErrorOr<enterprise_management::DeviceManagementRequest>
         request) {
@@ -205,10 +235,12 @@
   management_delegate_->UploadBrowserPublicKey(
       std::move(request.value()),
       base::BindOnce(&KeyUploadClientImpl::OnCertificateResponseReceived,
-                     weak_factory_.GetWeakPtr(), std::move(callback)));
+                     weak_factory_.GetWeakPtr(), private_key,
+                     std::move(callback)));
 }
 
 void KeyUploadClientImpl::OnCertificateResponseReceived(
+    scoped_refptr<PrivateKey> private_key,
     CreateCertificateCallback callback,
     policy::DMServerJobResult result) {
   scoped_refptr<net::X509Certificate> certificate = nullptr;
@@ -216,7 +248,6 @@
       result.response.has_browser_public_key_upload_response() &&
       result.response.browser_public_key_upload_response()
           .has_pem_encoded_certificate()) {
-    // Try to parse the client certificate.
     std::string_view pem_encoded_certificate =
         result.response.browser_public_key_upload_response()
             .pem_encoded_certificate();
@@ -224,7 +255,7 @@
         net::X509Certificate::CreateCertificateListFromBytes(
             base::as_byte_span(pem_encoded_certificate),
             net::X509Certificate::FORMAT_AUTO);
-    if (!certs.empty()) {
+    if (!certs.empty() && VerifySPKI(certs[0].get(), private_key.get())) {
       certificate = certs[0];
     }
   }
diff --git a/components/enterprise/client_certificates/core/key_upload_client_unittest.cc b/components/enterprise/client_certificates/core/key_upload_client_unittest.cc
index 2528b8c..0b6084e 100644
--- a/components/enterprise/client_certificates/core/key_upload_client_unittest.cc
+++ b/components/enterprise/client_certificates/core/key_upload_client_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <string_view>
 
+#include "base/check.h"
 #include "base/containers/span.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
@@ -24,7 +25,9 @@
 #include "components/enterprise/client_certificates/core/private_key.h"
 #include "components/enterprise/client_certificates/core/upload_client_error.h"
 #include "crypto/signature_verifier.h"
+#include "net/cert/asn1_util.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -37,6 +40,7 @@
 using base::test::EqualsProto;
 using base::test::RunOnceCallback;
 using testing::_;
+using testing::AtMost;
 using testing::Return;
 using testing::StrictMock;
 
@@ -51,12 +55,23 @@
   return std::vector<uint8_t>(bytes.begin(), bytes.end());
 }
 
-scoped_refptr<MockPrivateKey> CreateMockedKey() {
+std::vector<uint8_t> GetSpki(const net::X509Certificate* cert) {
+  std::string_view spki;
+  CHECK(net::asn1::ExtractSPKIFromDERCert(
+      net::x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()), &spki));
+  return ToBytes(spki);
+}
+
+scoped_refptr<MockPrivateKey> CreateMockedKey(
+    const net::X509Certificate* cert = nullptr) {
   auto private_key = base::MakeRefCounted<StrictMock<MockPrivateKey>>();
   ON_CALL(*private_key, SignSlowly(_))
       .WillByDefault(Return(ToBytes(kFakeSignature)));
-  ON_CALL(*private_key, GetSubjectPublicKeyInfo())
-      .WillByDefault(Return(ToBytes(kFakeSpki)));
+  std::vector<uint8_t> spki = ToBytes(kFakeSpki);
+  if (cert) {
+    spki = GetSpki(cert);
+  }
+  ON_CALL(*private_key, GetSubjectPublicKeyInfo()).WillByDefault(Return(spki));
   ON_CALL(*private_key, GetAlgorithm())
       .WillByDefault(Return(crypto::SignatureVerifier::RSA_PKCS1_SHA1));
   return private_key;
@@ -64,10 +79,16 @@
 
 enterprise_management::DeviceManagementRequest CreateExpectedRequest(
     bool provision_certificate,
-    BPKUR::KeyTrustLevel trust_level = BPKUR::CHROME_BROWSER_HW_KEY) {
+    BPKUR::KeyTrustLevel trust_level = BPKUR::CHROME_BROWSER_HW_KEY,
+    const net::X509Certificate* cert = nullptr) {
   enterprise_management::DeviceManagementRequest request;
   auto* upload_request = request.mutable_browser_public_key_upload_request();
-  upload_request->set_public_key(std::string(kFakeSpki));
+  std::string spki_string(kFakeSpki);
+  if (cert) {
+    auto spki_bytes = GetSpki(cert);
+    spki_string = std::string(spki_bytes.begin(), spki_bytes.end());
+  }
+  upload_request->set_public_key(spki_string);
   upload_request->set_signature(std::string(kFakeSignature));
   upload_request->set_key_trust_level(trust_level);
   upload_request->set_key_type(BPKUR::RSA_KEY);
@@ -90,10 +111,12 @@
         KeyUploadClient::Create(std::move(mock_management_delegate_));
   }
 
-  scoped_refptr<PrivateKey> SetUpPrivateKey() {
-    auto private_key = CreateMockedKey();
+  scoped_refptr<PrivateKey> SetUpPrivateKey(
+      const net::X509Certificate* cert = nullptr) {
+    auto private_key = CreateMockedKey(cert);
     EXPECT_CALL(*private_key, SignSlowly(_));
-    EXPECT_CALL(*private_key, GetSubjectPublicKeyInfo());
+    EXPECT_CALL(*private_key, GetSubjectPublicKeyInfo())
+        .Times(testing::AtMost(2));
     EXPECT_CALL(*private_key, GetAlgorithm());
     return private_key;
   }
@@ -106,11 +129,12 @@
   void SetUpUploadPublicKey(
       policy::DMServerJobResult result,
       scoped_refptr<net::X509Certificate> fake_cert = nullptr) {
-    EXPECT_CALL(
-        *mock_management_delegate_,
-        UploadBrowserPublicKey(EqualsProto(CreateExpectedRequest(
-                                   /*provision_certificate=*/!!fake_cert)),
-                               _))
+    EXPECT_CALL(*mock_management_delegate_,
+                UploadBrowserPublicKey(
+                    EqualsProto(CreateExpectedRequest(
+                        /*provision_certificate=*/!!fake_cert,
+                        BPKUR::CHROME_BROWSER_HW_KEY, fake_cert.get())),
+                    _))
         .WillOnce(RunOnceCallback<1>(result));
   }
 
@@ -135,7 +159,7 @@
     SetUpDMToken();
     SetUpUploadPublicKey(CreateResult(fake_cert), fake_cert);
     CreateUploadClient();
-    return SetUpPrivateKey();
+    return SetUpPrivateKey(fake_cert.get());
   }
 
   base::test::TaskEnvironment task_environment_;
@@ -208,7 +232,7 @@
 
   CreateUploadClient();
 
-  auto private_key = SetUpPrivateKey();
+  auto private_key = SetUpPrivateKey(test_cert.get());
 
   base::test::TestFuture<HttpCodeOrClientError,
                          scoped_refptr<net::X509Certificate>>
@@ -234,7 +258,7 @@
 
   CreateUploadClient();
 
-  auto private_key = SetUpPrivateKey();
+  auto private_key = SetUpPrivateKey(test_cert.get());
 
   base::test::TestFuture<HttpCodeOrClientError,
                          scoped_refptr<net::X509Certificate>>
@@ -260,7 +284,7 @@
 
   CreateUploadClient();
 
-  auto private_key = SetUpPrivateKey();
+  auto private_key = SetUpPrivateKey(test_cert.get());
 
   base::test::TestFuture<HttpCodeOrClientError,
                          scoped_refptr<net::X509Certificate>>
@@ -346,7 +370,7 @@
   ON_CALL(*key, GetAlgorithm())
       .WillByDefault(Return(crypto::SignatureVerifier::RSA_PKCS1_SHA1));
   EXPECT_CALL(*key, SignSlowly(_));
-  EXPECT_CALL(*key, GetSubjectPublicKeyInfo());
+  EXPECT_CALL(*key, GetSubjectPublicKeyInfo()).Times(testing::AtMost(2));
   EXPECT_CALL(*key, GetAlgorithm());
   return key;
 }
Loading diff…

Regression Test / PoC

shipped with the fix
diff --git a/components/enterprise/client_certificates/core/key_upload_client_unittest.cc b/components/enterprise/client_certificates/core/key_upload_client_unittest.cc
index 2528b8c..0b6084e 100644
--- a/components/enterprise/client_certificates/core/key_upload_client_unittest.cc
+++ b/components/enterprise/client_certificates/core/key_upload_client_unittest.cc
@@ -6,6 +6,7 @@
 
 #include <string_view>
 
+#include "base/check.h"
 #include "base/containers/span.h"
 #include "base/functional/bind.h"
 #include "base/functional/callback.h"
@@ -24,7 +25,9 @@
 #include "components/enterprise/client_certificates/core/private_key.h"
 #include "components/enterprise/client_certificates/core/upload_client_error.h"
 #include "crypto/signature_verifier.h"
+#include "net/cert/asn1_util.h"
 #include "net/cert/x509_certificate.h"
+#include "net/cert/x509_util.h"
 #include "net/test/cert_test_util.h"
 #include "net/test/test_data_directory.h"
 #include "testing/gmock/include/gmock/gmock.h"
@@ -37,6 +40,7 @@
 using base::test::EqualsProto;
 using base::test::RunOnceCallback;
 using testing::_;
+using testing::AtMost;
 using testing::Return;
 using testing::StrictMock;
 
@@ -51,12 +55,23 @@
   return std::vector<uint8_t>(bytes.begin(), bytes.end());
 }
 
-scoped_refptr<MockPrivateKey> CreateMockedKey() {
+std::vector<uint8_t> GetSpki(const net::X509Certificate* cert) {
+  std::string_view spki;
+  CHECK(net::asn1::ExtractSPKIFromDERCert(
+      net::x509_util::CryptoBufferAsStringPiece(cert->cert_buffer()), &spki));
+  return ToBytes(spki);
+}
+
+scoped_refptr<MockPrivateKey> CreateMockedKey(
+    const net::X509Certificate* cert = nullptr) {
   auto private_key = base::MakeRefCounted<StrictMock<MockPrivateKey>>();
   ON_CALL(*private_key, SignSlowly(_))
       .WillByDefault(Return(ToBytes(kFakeSignature)));
-  ON_CALL(*private_key, GetSubjectPublicKeyInfo())
-      .WillByDefault(Return(ToBytes(kFakeSpki)));
+  std::vector<uint8_t> spki = ToBytes(kFakeSpki);
+  if (cert) {
+    spki = GetSpki(cert);
+  }
+  ON_CALL(*private_key, GetSubjectPublicKeyInfo()).WillByDefault(Return(spki));
   ON_CALL(*private_key, GetAlgorithm())
       .WillByDefault(Return(crypto::SignatureVerifier::RSA_PKCS1_SHA1));
   return private_key;
@@ -64,10 +79,16 @@
 
 enterprise_management::DeviceManagementRequest CreateExpectedRequest(
     bool provision_certificate,
-    BPKUR::KeyTrustLevel trust_level = BPKUR::CHROME_BROWSER_HW_KEY) {
+    BPKUR::KeyTrustLevel trust_level = BPKUR::CHROME_BROWSER_HW_KEY,
+    const net::X509Certificate* cert = nullptr) {
   enterprise_management::DeviceManagementRequest request;
   auto* upload_request = request.mutable_browser_public_key_upload_request();
-  upload_request->set_public_key(std::string(kFakeSpki));
+  std::string spki_string(kFakeSpki);
+  if (cert) {
+    auto spki_bytes = GetSpki(cert);
+    spki_string = std::string(spki_bytes.begin(), spki_bytes.end());
+  }
+  upload_request->set_public_key(spki_string);
   upload_request->set_signature(std::string(kFakeSignature));
   upload_request->set_key_trust_level(trust_level);
   upload_request->set_key_type(BPKUR::RSA_KEY);
@@ -90,10 +111,12 @@
         KeyUploadClient::Create(std::move(mock_management_delegate_));
   }
 
-  scoped_refptr<PrivateKey> SetUpPrivateKey() {
-    auto private_key = CreateMockedKey();
+  scoped_refptr<PrivateKey> SetUpPrivateKey(
+      const net::X509Certificate* cert = nullptr) {
+    auto private_key = CreateMockedKey(cert);
     EXPECT_CALL(*private_key, SignSlowly(_));
-    EXPECT_CALL(*private_key, GetSubjectPublicKeyInfo());
+    EXPECT_CALL(*private_key, GetSubjectPublicKeyInfo())
+        .Times(testing::AtMost(2));
     EXPECT_CALL(*private_key, GetAlgorithm());
     return private_key;
   }
@@ -106,11 +129,12 @@
   void SetUpUploadPublicKey(
       policy::DMServerJobResult result,
       scoped_refptr<net::X509Certificate> fake_cert = nullptr) {
-    EXPECT_CALL(
-        *mock_management_delegate_,
-        UploadBrowserPublicKey(EqualsProto(CreateExpectedRequest(
-                                   /*provision_certificate=*/!!fake_cert)),
-                               _))
+    EXPECT_CALL(*mock_management_delegate_,
+                UploadBrowserPublicKey(
+                    EqualsProto(CreateExpectedRequest(
+                        /*provision_certificate=*/!!fake_cert,
+                        BPKUR::CHROME_BROWSER_HW_KEY, fake_cert.get())),
+                    _))
         .WillOnce(RunOnceCallback<1>(result));
   }
 
@@ -135,7 +159,7 @@
     SetUpDMToken();
     SetUpUploadPublicKey(CreateResult(fake_cert), fake_cert);
     CreateUploadClient();
-    return SetUpPrivateKey();
+    return SetUpPrivateKey(fake_cert.get());
   }
 
   base::test::TaskEnvironment task_environment_;
@@ -208,7 +232,7 @@
 
   CreateUploadClient();
 
-  auto private_key = SetUpPrivateKey();
+  auto private_key = SetUpPrivateKey(test_cert.get());
 
   base::test::TestFuture<HttpCodeOrClientError,
                          scoped_refptr<net::X509Certificate>>
@@ -234,7 +258,7 @@
 
   CreateUploadClient();
 
-  auto private_key = SetUpPrivateKey();
+  auto private_key = SetUpPrivateKey(test_cert.get());
 
   base::test::TestFuture<HttpCodeOrClientError,
                          scoped_refptr<net::X509Certificate>>
@@ -260,7 +284,7 @@
 
   CreateUploadClient();
 
-  auto private_key = SetUpPrivateKey();
+  auto private_key = SetUpPrivateKey(test_cert.get());
 
   base::test::TestFuture<HttpCodeOrClientError,
                          scoped_refptr<net::X509Certificate>>
@@ -346,7 +370,7 @@
   ON_CALL(*key, GetAlgorithm())
       .WillByDefault(Return(crypto::SignatureVerifier::RSA_PKCS1_SHA1));
   EXPECT_CALL(*key, SignSlowly(_));
-  EXPECT_CALL(*key, GetSubjectPublicKeyInfo());
+  EXPECT_CALL(*key, GetSubjectPublicKeyInfo()).Times(testing::AtMost(2));
   EXPECT_CALL(*key, GetAlgorithm());
   return key;
 }
Loading diff…

Original Bug Report

The reporter's bug is still restricted on the tracker. Chrome de-restricts security bugs ~30–90 days after the fix ships; a later run will backfill it here.