Line data Source code
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/extensions/transport_sockets/tls/utility.h" 11 : 12 : #include "quiche/quic/core/crypto/certificate_view.h" 13 : 14 : namespace Envoy { 15 : namespace Quic { 16 : 17 : using ValidationResults = Envoy::Extensions::TransportSockets::Tls::ValidationResults; 18 : 19 : namespace { 20 : 21 : // Returns true if hostname matches one of the Subject Alt Names in cert_view. Returns false and 22 : // sets error_details otherwise 23 : bool verifyLeafCertMatchesHostname(quic::CertificateView& cert_view, const std::string& hostname, 24 0 : std::string* error_details) { 25 0 : for (const absl::string_view& config_san : cert_view.subject_alt_name_domains()) { 26 0 : if (Extensions::TransportSockets::Tls::Utility::dnsNameMatch(hostname, config_san)) { 27 0 : return true; 28 0 : } 29 0 : } 30 0 : *error_details = absl::StrCat("Leaf certificate doesn't match hostname: ", hostname); 31 0 : return false; 32 0 : } 33 : 34 : class QuicValidateResultCallback : public Ssl::ValidateResultCallback { 35 : public: 36 : QuicValidateResultCallback(Event::Dispatcher& dispatcher, 37 : std::unique_ptr<quic::ProofVerifierCallback>&& quic_callback, 38 : const std::string& hostname, const std::string& leaf_cert) 39 : : dispatcher_(dispatcher), quic_callback_(std::move(quic_callback)), hostname_(hostname), 40 0 : leaf_cert_(leaf_cert) {} 41 : 42 0 : Event::Dispatcher& dispatcher() override { return dispatcher_; } 43 : 44 : void onCertValidationResult(bool succeeded, Ssl::ClientValidationStatus /*detailed_status*/, 45 0 : const std::string& error_details, uint8_t /*tls_alert*/) override { 46 0 : std::string error; 47 0 : if (!succeeded) { 48 0 : error = error_details; 49 0 : } else { 50 0 : std::unique_ptr<quic::CertificateView> cert_view = 51 0 : quic::CertificateView::ParseSingleCertificate(leaf_cert_); 52 0 : succeeded = verifyLeafCertMatchesHostname(*cert_view, hostname_, &error); 53 0 : } 54 0 : std::unique_ptr<quic::ProofVerifyDetails> details = 55 0 : std::make_unique<CertVerifyResult>(succeeded); 56 0 : quic_callback_->Run(succeeded, error, &details); 57 0 : } 58 : 59 : private: 60 : Event::Dispatcher& dispatcher_; 61 : std::unique_ptr<quic::ProofVerifierCallback> quic_callback_; 62 : const std::string hostname_; 63 : // Leaf cert needs to be retained in case of asynchronous validation. 64 : std::string leaf_cert_; 65 : }; 66 : 67 : } // namespace 68 : 69 : quic::QuicAsyncStatus EnvoyQuicProofVerifier::VerifyCertChain( 70 : const std::string& hostname, const uint16_t /*port*/, const std::vector<std::string>& certs, 71 : const std::string& /*ocsp_response*/, const std::string& /*cert_sct*/, 72 : const quic::ProofVerifyContext* context, std::string* error_details, 73 : std::unique_ptr<quic::ProofVerifyDetails>* details, uint8_t* out_alert, 74 0 : std::unique_ptr<quic::ProofVerifierCallback> callback) { 75 0 : ASSERT(details != nullptr); 76 0 : ASSERT(!certs.empty()); 77 0 : auto* verify_context = dynamic_cast<const EnvoyQuicProofVerifyContext*>(context); 78 0 : if (verify_context == nullptr) { 79 0 : IS_ENVOY_BUG("QUIC proof verify context was not setup correctly."); 80 0 : return quic::QUIC_FAILURE; 81 0 : } 82 0 : ENVOY_BUG(!verify_context->isServer(), "Client certificates are not supported in QUIC yet."); 83 : 84 0 : bssl::UniquePtr<STACK_OF(X509)> cert_chain(sk_X509_new_null()); 85 0 : for (const auto& cert_str : certs) { 86 0 : bssl::UniquePtr<X509> cert = parseDERCertificate(cert_str, error_details); 87 0 : if (!cert || !bssl::PushToStack(cert_chain.get(), std::move(cert))) { 88 0 : return quic::QUIC_FAILURE; 89 0 : } 90 0 : } 91 0 : std::unique_ptr<quic::CertificateView> cert_view = 92 0 : quic::CertificateView::ParseSingleCertificate(certs[0]); 93 0 : ASSERT(cert_view != nullptr); 94 0 : int sign_alg = deduceSignatureAlgorithmFromPublicKey(cert_view->public_key(), error_details); 95 0 : if (sign_alg == 0) { 96 0 : return quic::QUIC_FAILURE; 97 0 : } 98 : 99 0 : auto envoy_callback = std::make_unique<QuicValidateResultCallback>( 100 0 : verify_context->dispatcher(), std::move(callback), hostname, certs[0]); 101 0 : ASSERT(dynamic_cast<Extensions::TransportSockets::Tls::ClientContextImpl*>(context_.get()) != 102 0 : nullptr); 103 : // We down cast rather than add customVerifyCertChainForQuic to Envoy::Ssl::Context because 104 : // verifyCertChain uses a bunch of SSL-specific structs which we want to keep out of the interface 105 : // definition. 106 0 : ValidationResults result = 107 0 : static_cast<Extensions::TransportSockets::Tls::ClientContextImpl*>(context_.get()) 108 0 : ->customVerifyCertChainForQuic(*cert_chain, std::move(envoy_callback), 109 0 : verify_context->isServer(), 110 0 : verify_context->transportSocketOptions(), 111 0 : verify_context->extraValidationContext(), hostname); 112 0 : if (result.status == ValidationResults::ValidationStatus::Pending) { 113 0 : return quic::QUIC_PENDING; 114 0 : } 115 0 : if (result.status == ValidationResults::ValidationStatus::Successful) { 116 0 : if (verifyLeafCertMatchesHostname(*cert_view, hostname, error_details)) { 117 0 : *details = std::make_unique<CertVerifyResult>(true); 118 0 : return quic::QUIC_SUCCESS; 119 0 : } 120 0 : } else { 121 0 : ASSERT(result.status == ValidationResults::ValidationStatus::Failed); 122 0 : if (result.error_details.has_value() && error_details) { 123 0 : *error_details = std::move(result.error_details.value()); 124 0 : } 125 0 : if (result.tls_alert.has_value() && out_alert) { 126 0 : *out_alert = result.tls_alert.value(); 127 0 : } 128 0 : } 129 : 130 0 : *details = std::make_unique<CertVerifyResult>(false); 131 0 : return quic::QUIC_FAILURE; 132 0 : } 133 : 134 : } // namespace Quic 135 : } // namespace Envoy