1 // Copyright 2020 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef QUICHE_QUIC_CORE_CRYPTO_WEB_TRANSPORT_FINGERPRINT_PROOF_VERIFIER_H_
6 #define QUICHE_QUIC_CORE_CRYPTO_WEB_TRANSPORT_FINGERPRINT_PROOF_VERIFIER_H_
7 
8 #include <vector>
9 
10 #include "absl/strings/string_view.h"
11 #include "quiche/quic/core/crypto/certificate_view.h"
12 #include "quiche/quic/core/crypto/proof_verifier.h"
13 #include "quiche/quic/core/quic_clock.h"
14 #include "quiche/quic/platform/api/quic_export.h"
15 
16 namespace quic {
17 
18 // Represents a fingerprint of an X.509 certificate in a format based on
19 // https://w3c.github.io/webrtc-pc/#dom-rtcdtlsfingerprint.
20 // TODO(vasilvv): remove this once all consumers of this API use
21 // WebTransportHash.
22 struct QUICHE_EXPORT CertificateFingerprint {
23   static constexpr char kSha256[] = "sha-256";
24 
25   // An algorithm described by one of the names in
26   // https://www.iana.org/assignments/hash-function-text-names/hash-function-text-names.xhtml
27   std::string algorithm;
28   // Hex-encoded, colon-separated fingerprint of the certificate.  For example,
29   // "12:3d:5b:71:8c:54:df:85:7e:bd:e3:7c:66:da:f9:db:6a:94:8f:85:cb:6e:44:7f:09:3e:05:f2:dd:d4:f7:86"
30   std::string fingerprint;
31 };
32 
33 // Represents a fingerprint of an X.509 certificate in a format based on
34 // https://w3c.github.io/webtransport/#dictdef-webtransporthash.
35 struct QUICHE_EXPORT WebTransportHash {
36   static constexpr char kSha256[] = "sha-256";
37 
38   // An algorithm described by one of the names in
39   // https://www.iana.org/assignments/hash-function-text-names/hash-function-text-names.xhtml
40   std::string algorithm;
41   // Raw bytes of the hash.
42   std::string value;
43 };
44 
45 // WebTransportFingerprintProofVerifier verifies the server leaf certificate
46 // against a supplied list of certificate fingerprints following the procedure
47 // described in the WebTransport specification.  The certificate is deemed
48 // trusted if it matches a fingerprint in the list, has expiry dates that are
49 // not too long and has not expired.  Only the leaf is checked, the rest of the
50 // chain is ignored. Reference specification:
51 // https://wicg.github.io/web-transport/#dom-quictransportconfiguration-server_certificate_fingerprints
52 class QUICHE_EXPORT WebTransportFingerprintProofVerifier
53     : public ProofVerifier {
54  public:
55   // Note: the entries in this list may be logged into a UMA histogram, and thus
56   // should not be renumbered.
57   enum class Status {
58     kValidCertificate = 0,
59     kUnknownFingerprint = 1,
60     kCertificateParseFailure = 2,
61     kExpiryTooLong = 3,
62     kExpired = 4,
63     kInternalError = 5,
64     kDisallowedKeyAlgorithm = 6,
65 
66     kMaxValue = kDisallowedKeyAlgorithm,
67   };
68 
69   class QUICHE_EXPORT Details : public ProofVerifyDetails {
70    public:
Details(Status status)71     explicit Details(Status status) : status_(status) {}
status()72     Status status() const { return status_; }
73 
74     ProofVerifyDetails* Clone() const override;
75 
76    private:
77     const Status status_;
78   };
79 
80   // |clock| is used to check if the certificate has expired.  It is not owned
81   // and must outlive the object.  |max_validity_days| is the maximum time for
82   // which the certificate is allowed to be valid.
83   WebTransportFingerprintProofVerifier(const QuicClock* clock,
84                                        int max_validity_days);
85 
86   // Adds a certificate fingerprint to be trusted.  The fingerprints are
87   // case-insensitive and are validated internally; the function returns true if
88   // the validation passes.
89   bool AddFingerprint(CertificateFingerprint fingerprint);
90   bool AddFingerprint(WebTransportHash hash);
91 
92   // ProofVerifier implementation.
93   QuicAsyncStatus VerifyProof(
94       const std::string& hostname, const uint16_t port,
95       const std::string& server_config, QuicTransportVersion transport_version,
96       absl::string_view chlo_hash, const std::vector<std::string>& certs,
97       const std::string& cert_sct, const std::string& signature,
98       const ProofVerifyContext* context, std::string* error_details,
99       std::unique_ptr<ProofVerifyDetails>* details,
100       std::unique_ptr<ProofVerifierCallback> callback) override;
101   QuicAsyncStatus VerifyCertChain(
102       const std::string& hostname, const uint16_t port,
103       const std::vector<std::string>& certs, const std::string& ocsp_response,
104       const std::string& cert_sct, const ProofVerifyContext* context,
105       std::string* error_details, std::unique_ptr<ProofVerifyDetails>* details,
106       uint8_t* out_alert,
107       std::unique_ptr<ProofVerifierCallback> callback) override;
108   std::unique_ptr<ProofVerifyContext> CreateDefaultContext() override;
109 
110  protected:
111   virtual bool IsKeyTypeAllowedByPolicy(const CertificateView& certificate);
112 
113  private:
114   bool HasKnownFingerprint(absl::string_view der_certificate);
115   bool HasValidExpiry(const CertificateView& certificate);
116   bool IsWithinValidityPeriod(const CertificateView& certificate);
117 
118   const QuicClock* clock_;  // Unowned.
119   const int max_validity_days_;
120   const QuicTime::Delta max_validity_;
121   std::vector<WebTransportHash> hashes_;
122 };
123 
124 }  // namespace quic
125 
126 #endif  // QUICHE_QUIC_CORE_CRYPTO_WEB_TRANSPORT_FINGERPRINT_PROOF_VERIFIER_H_
127