Add a way to make WebTransportFingerprintProofVerifier reject RSA keys.

This is necessary as <https://github.com/w3c/webtransport/pull/375> will require us rejecting RSA keys for self-signed certificates.

PiperOrigin-RevId: 420822901
diff --git a/quic/core/crypto/certificate_view.cc b/quic/core/crypto/certificate_view.cc
index e920cdb..1286667 100644
--- a/quic/core/crypto/certificate_view.cc
+++ b/quic/core/crypto/certificate_view.cc
@@ -168,6 +168,22 @@
 
 }  // namespace
 
+std::string PublicKeyTypeToString(PublicKeyType type) {
+  switch (type) {
+    case PublicKeyType::kRsa:
+      return "RSA";
+    case PublicKeyType::kP256:
+      return "ECDSA P-256";
+    case PublicKeyType::kP384:
+      return "ECDSA P-384";
+    case PublicKeyType::kEd25519:
+      return "Ed25519";
+    case PublicKeyType::kUnknown:
+      return "unknown";
+  }
+  return "";
+}
+
 absl::optional<quic::QuicWallTime> ParseDerTime(unsigned tag,
                                                 absl::string_view payload) {
   if (tag != CBS_ASN1_GENERALIZEDTIME && tag != CBS_ASN1_UTCTIME) {
@@ -461,7 +477,7 @@
   }
 }
 
-PublicKeyType CertificateView::public_key_type() {
+PublicKeyType CertificateView::public_key_type() const {
   return PublicKeyTypeFromKey(public_key_.get());
 }
 
diff --git a/quic/core/crypto/certificate_view.h b/quic/core/crypto/certificate_view.h
index 4249258..e546bf6 100644
--- a/quic/core/crypto/certificate_view.h
+++ b/quic/core/crypto/certificate_view.h
@@ -42,6 +42,7 @@
   kEd25519,
   kUnknown,
 };
+std::string PublicKeyTypeToString(PublicKeyType type);
 
 // CertificateView represents a parsed version of a single X.509 certificate. As
 // the word "view" implies, it does not take ownership of the underlying strings
@@ -79,7 +80,7 @@
                        uint16_t signature_algorithm) const;
 
   // Returns the type of the key used in the certificate's SPKI.
-  PublicKeyType public_key_type();
+  PublicKeyType public_key_type() const;
 
  private:
   CertificateView() = default;
diff --git a/quic/core/crypto/certificate_view_test.cc b/quic/core/crypto/certificate_view_test.cc
index 33514f2..fbca915 100644
--- a/quic/core/crypto/certificate_view_test.cc
+++ b/quic/core/crypto/certificate_view_test.cc
@@ -59,6 +59,7 @@
       *quiche::QuicheUtcDateTimeToUnixSeconds(2020, 2, 2, 18, 13, 59));
   EXPECT_EQ(view->validity_end(), validity_end);
   EXPECT_EQ(view->public_key_type(), PublicKeyType::kRsa);
+  EXPECT_EQ(PublicKeyTypeToString(view->public_key_type()), "RSA");
 
   EXPECT_EQ("C=US,ST=California,L=Mountain View,O=QUIC Server,CN=127.0.0.1",
             view->GetHumanReadableSubject());
diff --git a/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc b/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc
index ec58386..649406a 100644
--- a/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc
+++ b/quic/quic_transport/web_transport_fingerprint_proof_verifier.cc
@@ -158,6 +158,14 @@
     return QUIC_FAILURE;
   }
 
+  if (!IsKeyTypeAllowedByPolicy(*view)) {
+    *details = std::make_unique<Details>(Status::kDisallowedKeyAlgorithm);
+    *error_details =
+        absl::StrCat("Certificate uses a disallowed public key type (",
+                     PublicKeyTypeToString(view->public_key_type()), ")");
+    return QUIC_FAILURE;
+  }
+
   *details = std::make_unique<Details>(Status::kValidCertificate);
   return QUIC_SUCCESS;
 }
@@ -201,4 +209,21 @@
          now.IsBefore(certificate.validity_end());
 }
 
+bool WebTransportFingerprintProofVerifier::IsKeyTypeAllowedByPolicy(
+    const CertificateView& certificate) {
+  switch (certificate.public_key_type()) {
+    // https://github.com/w3c/webtransport/pull/375 defines P-256 as an MTI
+    // algorithm, and prohibits RSA.  We also allow P-384 and Ed25519.
+    case PublicKeyType::kP256:
+    case PublicKeyType::kP384:
+    case PublicKeyType::kEd25519:
+      return true;
+    case PublicKeyType::kRsa:
+      // TODO(b/213614428): this should be false by default.
+      return true;
+    default:
+      return false;
+  }
+}
+
 }  // namespace quic
diff --git a/quic/quic_transport/web_transport_fingerprint_proof_verifier.h b/quic/quic_transport/web_transport_fingerprint_proof_verifier.h
index 76323d5..9a03c66 100644
--- a/quic/quic_transport/web_transport_fingerprint_proof_verifier.h
+++ b/quic/quic_transport/web_transport_fingerprint_proof_verifier.h
@@ -61,8 +61,9 @@
     kExpiryTooLong = 3,
     kExpired = 4,
     kInternalError = 5,
+    kDisallowedKeyAlgorithm = 6,
 
-    kMaxValue = kInternalError,
+    kMaxValue = kDisallowedKeyAlgorithm,
   };
 
   class QUIC_EXPORT_PRIVATE Details : public ProofVerifyDetails {
@@ -115,6 +116,9 @@
       std::unique_ptr<ProofVerifierCallback> callback) override;
   std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override;
 
+ protected:
+  virtual bool IsKeyTypeAllowedByPolicy(const CertificateView& certificate);
+
  private:
   bool HasKnownFingerprint(absl::string_view der_certificate);
   bool HasValidExpiry(const CertificateView& certificate);