1
#include "source/common/quic/envoy_quic_proof_verifier.h"
2

            
3
#include <openssl/ssl.h>
4

            
5
#include <cstdint>
6
#include <memory>
7

            
8
#include "source/common/quic/envoy_quic_utils.h"
9
#include "source/common/runtime/runtime_features.h"
10
#include "source/common/tls/client_context_impl.h"
11
#include "source/common/tls/utility.h"
12

            
13
#include "quiche/quic/core/crypto/certificate_view.h"
14

            
15
namespace Envoy {
16
namespace Quic {
17

            
18
using ValidationResults = Envoy::Extensions::TransportSockets::Tls::ValidationResults;
19

            
20
namespace {
21

            
22
// Returns true if hostname matches one of the Subject Alt Names in cert_view. Returns false and
23
// sets error_details otherwise
24
bool verifyLeafCertMatchesHostname(quic::CertificateView& cert_view, const std::string& hostname,
25
2951
                                   std::string* error_details) {
26
2966
  for (const absl::string_view& config_san : cert_view.subject_alt_name_domains()) {
27
2966
    if (Extensions::TransportSockets::Tls::Utility::dnsNameMatch(hostname, config_san)) {
28
2940
      return true;
29
2940
    }
30
2966
  }
31
11
  *error_details = absl::StrCat("Leaf certificate doesn't match hostname: ", hostname);
32
11
  return false;
33
2951
}
34

            
35
class QuicValidateResultCallback : public Ssl::ValidateResultCallback {
36
public:
37
  QuicValidateResultCallback(Event::Dispatcher& dispatcher,
38
                             std::unique_ptr<quic::ProofVerifierCallback>&& quic_callback,
39
                             const std::string& hostname, const std::string& leaf_cert,
40
                             bool accept_untrusted)
41
2955
      : dispatcher_(dispatcher), quic_callback_(std::move(quic_callback)), hostname_(hostname),
42
2955
        leaf_cert_(leaf_cert), accept_untrusted_(accept_untrusted) {}
43

            
44
5
  Event::Dispatcher& dispatcher() override { return dispatcher_; }
45

            
46
  void onCertValidationResult(bool succeeded, Ssl::ClientValidationStatus /*detailed_status*/,
47
5
                              const std::string& error_details, uint8_t /*tls_alert*/) override {
48
5
    std::string error;
49
5
    if (!succeeded) {
50
      error = error_details;
51
5
    } else if (!accept_untrusted_) {
52
5
      std::unique_ptr<quic::CertificateView> cert_view =
53
5
          quic::CertificateView::ParseSingleCertificate(leaf_cert_);
54
5
      succeeded = verifyLeafCertMatchesHostname(*cert_view, hostname_, &error);
55
5
    }
56
5
    std::unique_ptr<quic::ProofVerifyDetails> details =
57
5
        std::make_unique<CertVerifyResult>(succeeded);
58
5
    quic_callback_->Run(succeeded, error, &details);
59
5
  }
60

            
61
private:
62
  Event::Dispatcher& dispatcher_;
63
  std::unique_ptr<quic::ProofVerifierCallback> quic_callback_;
64
  const std::string hostname_;
65
  // Leaf cert needs to be retained in case of asynchronous validation.
66
  std::string leaf_cert_;
67
  const bool accept_untrusted_;
68
};
69

            
70
} // namespace
71

            
72
quic::QuicAsyncStatus EnvoyQuicProofVerifier::VerifyCertChain(
73
    const std::string& hostname, const uint16_t /*port*/, const std::vector<std::string>& certs,
74
    const std::string& /*ocsp_response*/, const std::string& /*cert_sct*/,
75
    const quic::ProofVerifyContext* context, std::string* error_details,
76
    std::unique_ptr<quic::ProofVerifyDetails>* details, uint8_t* out_alert,
77
2959
    std::unique_ptr<quic::ProofVerifierCallback> callback) {
78
2959
  ASSERT(details != nullptr);
79
2959
  ASSERT(!certs.empty());
80
2959
  auto* verify_context = dynamic_cast<const EnvoyQuicProofVerifyContext*>(context);
81
2959
  if (verify_context == nullptr) {
82
    IS_ENVOY_BUG("QUIC proof verify context was not setup correctly.");
83
    return quic::QUIC_FAILURE;
84
  }
85
2959
  ENVOY_BUG(!verify_context->isServer(), "Client certificates are not supported in QUIC yet.");
86

            
87
2959
  bssl::UniquePtr<STACK_OF(X509)> cert_chain(sk_X509_new_null());
88
2960
  for (const auto& cert_str : certs) {
89
2960
    bssl::UniquePtr<X509> cert = parseDERCertificate(cert_str, error_details);
90
2960
    if (!cert || !bssl::PushToStack(cert_chain.get(), std::move(cert))) {
91
2
      return quic::QUIC_FAILURE;
92
2
    }
93
2960
  }
94
2957
  std::unique_ptr<quic::CertificateView> cert_view =
95
2957
      quic::CertificateView::ParseSingleCertificate(certs[0]);
96
2957
  if (cert_view == nullptr) {
97
1
    *error_details = "unable to parse certificate";
98
1
    return quic::QUIC_FAILURE;
99
1
  }
100
2956
  int sign_alg = deduceSignatureAlgorithmFromPublicKey(cert_view->public_key(), error_details);
101
2956
  if (sign_alg == 0) {
102
1
    return quic::QUIC_FAILURE;
103
1
  }
104

            
105
2955
  auto envoy_callback = std::make_unique<QuicValidateResultCallback>(
106
2955
      verify_context->dispatcher(), std::move(callback), hostname, certs[0], accept_untrusted_);
107
2955
  ASSERT(dynamic_cast<Extensions::TransportSockets::Tls::ClientContextImpl*>(context_.get()) !=
108
2955
         nullptr);
109
  // We down cast rather than add customVerifyCertChainForQuic to Envoy::Ssl::Context because
110
  // verifyCertChain uses a bunch of SSL-specific structs which we want to keep out of the interface
111
  // definition.
112
2955
  ValidationResults result =
113
2955
      static_cast<Extensions::TransportSockets::Tls::ClientContextImpl*>(context_.get())
114
2955
          ->customVerifyCertChainForQuic(*cert_chain, std::move(envoy_callback),
115
2955
                                         verify_context->isServer(),
116
2955
                                         verify_context->transportSocketOptions(),
117
2955
                                         verify_context->extraValidationContext(), hostname);
118
2955
  if (result.status == ValidationResults::ValidationStatus::Pending) {
119
5
    return quic::QUIC_PENDING;
120
5
  }
121
2950
  if (result.status == ValidationResults::ValidationStatus::Successful) {
122
2946
    if (verifyLeafCertMatchesHostname(*cert_view, hostname, error_details)) {
123
2936
      *details = std::make_unique<CertVerifyResult>(true);
124
2936
      return quic::QUIC_SUCCESS;
125
2936
    }
126
2947
  } else {
127
4
    ASSERT(result.status == ValidationResults::ValidationStatus::Failed);
128
4
    if (result.error_details.has_value() && error_details) {
129
4
      *error_details = std::move(result.error_details.value());
130
4
    }
131
4
    if (result.tls_alert.has_value() && out_alert) {
132
1
      *out_alert = result.tls_alert.value();
133
1
    }
134
4
  }
135

            
136
14
  *details = std::make_unique<CertVerifyResult>(false);
137
14
  return quic::QUIC_FAILURE;
138
2950
}
139

            
140
} // namespace Quic
141
} // namespace Envoy