Line data Source code
1 : #include "source/common/quic/envoy_quic_proof_source.h" 2 : 3 : #include <openssl/bio.h> 4 : 5 : #include "envoy/ssl/tls_certificate_config.h" 6 : 7 : #include "source/common/quic/envoy_quic_utils.h" 8 : #include "source/common/quic/quic_io_handle_wrapper.h" 9 : #include "source/common/stream_info/stream_info_impl.h" 10 : 11 : #include "openssl/bytestring.h" 12 : #include "quiche/quic/core/crypto/certificate_view.h" 13 : 14 : namespace Envoy { 15 : namespace Quic { 16 : 17 : quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain> 18 : EnvoyQuicProofSource::GetCertChain(const quic::QuicSocketAddress& server_address, 19 : const quic::QuicSocketAddress& client_address, 20 0 : const std::string& hostname, bool* cert_matched_sni) { 21 : // TODO(DavidSchinazi) parse the certificate to correctly fill in |cert_matched_sni|. 22 0 : *cert_matched_sni = false; 23 : 24 0 : CertConfigWithFilterChain res = 25 0 : getTlsCertConfigAndFilterChain(server_address, client_address, hostname); 26 0 : absl::optional<std::reference_wrapper<const Envoy::Ssl::TlsCertificateConfig>> cert_config_ref = 27 0 : res.cert_config_; 28 0 : if (!cert_config_ref.has_value()) { 29 0 : return nullptr; 30 0 : } 31 0 : auto& cert_config = cert_config_ref.value().get(); 32 0 : const std::string& chain_str = cert_config.certificateChain(); 33 0 : std::stringstream pem_stream(chain_str); 34 0 : std::vector<std::string> chain = quic::CertificateView::LoadPemFromStream(&pem_stream); 35 : 36 0 : quiche::QuicheReferenceCountedPointer<quic::ProofSource::Chain> cert_chain( 37 0 : new quic::ProofSource::Chain(chain)); 38 0 : std::string error_details; 39 0 : bssl::UniquePtr<X509> cert = parseDERCertificate(cert_chain->certs[0], &error_details); 40 0 : if (cert == nullptr) { 41 0 : ENVOY_LOG(warn, absl::StrCat("Invalid leaf cert: ", error_details)); 42 0 : return nullptr; 43 0 : } 44 : 45 0 : bssl::UniquePtr<EVP_PKEY> pub_key(X509_get_pubkey(cert.get())); 46 0 : int sign_alg = deduceSignatureAlgorithmFromPublicKey(pub_key.get(), &error_details); 47 0 : if (sign_alg == 0) { 48 0 : ENVOY_LOG(warn, absl::StrCat("Failed to deduce signature algorithm from public key: ", 49 0 : error_details)); 50 0 : return nullptr; 51 0 : } 52 0 : return cert_chain; 53 0 : } 54 : 55 : void EnvoyQuicProofSource::signPayload( 56 : const quic::QuicSocketAddress& server_address, const quic::QuicSocketAddress& client_address, 57 : const std::string& hostname, uint16_t signature_algorithm, absl::string_view in, 58 0 : std::unique_ptr<quic::ProofSource::SignatureCallback> callback) { 59 0 : CertConfigWithFilterChain res = 60 0 : getTlsCertConfigAndFilterChain(server_address, client_address, hostname); 61 0 : absl::optional<std::reference_wrapper<const Envoy::Ssl::TlsCertificateConfig>> cert_config_ref = 62 0 : res.cert_config_; 63 0 : if (!cert_config_ref.has_value()) { 64 0 : ENVOY_LOG(warn, "No matching filter chain found for handshake."); 65 0 : callback->Run(false, "", nullptr); 66 0 : return; 67 0 : } 68 0 : auto& cert_config = cert_config_ref.value().get(); 69 : // Load private key. 70 0 : const std::string& pkey = cert_config.privateKey(); 71 0 : std::stringstream pem_str(pkey); 72 0 : std::unique_ptr<quic::CertificatePrivateKey> pem_key = 73 0 : quic::CertificatePrivateKey::LoadPemFromStream(&pem_str); 74 0 : if (pem_key == nullptr) { 75 0 : ENVOY_LOG(warn, "Failed to load private key."); 76 0 : callback->Run(false, "", nullptr); 77 0 : return; 78 0 : } 79 : // Verify the signature algorithm is as expected. 80 0 : std::string error_details; 81 0 : int sign_alg = deduceSignatureAlgorithmFromPublicKey(pem_key->private_key(), &error_details); 82 0 : if (sign_alg != signature_algorithm) { 83 0 : ENVOY_LOG(warn, 84 0 : fmt::format("The signature algorithm {} from the private key is not expected: {}", 85 0 : sign_alg, error_details)); 86 0 : callback->Run(false, "", nullptr); 87 0 : return; 88 0 : } 89 : 90 : // Sign. 91 0 : std::string sig = pem_key->Sign(in, signature_algorithm); 92 0 : bool success = !sig.empty(); 93 0 : ASSERT(res.filter_chain_.has_value()); 94 0 : callback->Run(success, sig, 95 0 : std::make_unique<EnvoyQuicProofSourceDetails>(res.filter_chain_.value().get())); 96 0 : } 97 : 98 : EnvoyQuicProofSource::CertConfigWithFilterChain 99 : EnvoyQuicProofSource::getTlsCertConfigAndFilterChain(const quic::QuicSocketAddress& server_address, 100 : const quic::QuicSocketAddress& client_address, 101 0 : const std::string& hostname) { 102 0 : ENVOY_LOG(trace, "Getting cert chain for {}", hostname); 103 : // TODO(danzh) modify QUICHE to make quic session or ALPN accessible to avoid hard-coded ALPN. 104 0 : Network::ConnectionSocketPtr connection_socket = createServerConnectionSocket( 105 0 : listen_socket_.ioHandle(), server_address, client_address, hostname, "h3"); 106 0 : StreamInfo::StreamInfoImpl info(time_source_, 107 0 : connection_socket->connectionInfoProviderSharedPtr()); 108 0 : const Network::FilterChain* filter_chain = 109 0 : filter_chain_manager_->findFilterChain(*connection_socket, info); 110 : 111 0 : if (filter_chain == nullptr) { 112 0 : listener_stats_.no_filter_chain_match_.inc(); 113 0 : ENVOY_LOG(warn, "No matching filter chain found for handshake."); 114 0 : return {absl::nullopt, absl::nullopt}; 115 0 : } 116 0 : ENVOY_LOG(trace, "Got a matching cert chain {}", filter_chain->name()); 117 : 118 0 : auto& transport_socket_factory = 119 0 : dynamic_cast<const QuicServerTransportSocketFactory&>(filter_chain->transportSocketFactory()); 120 : 121 0 : std::vector<std::reference_wrapper<const Envoy::Ssl::TlsCertificateConfig>> tls_cert_configs = 122 0 : transport_socket_factory.getTlsCertificates(); 123 0 : if (tls_cert_configs.empty()) { 124 0 : ENVOY_LOG(warn, "No certificate is configured in transport socket config."); 125 0 : return {absl::nullopt, absl::nullopt}; 126 0 : } 127 : // Only return the first TLS cert config. 128 : // TODO(danzh) Choose based on supported cipher suites in TLS1.3 CHLO and prefer EC 129 : // certs if supported. 130 0 : return {tls_cert_configs[0].get(), *filter_chain}; 131 0 : } 132 : 133 : void EnvoyQuicProofSource::updateFilterChainManager( 134 0 : Network::FilterChainManager& filter_chain_manager) { 135 0 : filter_chain_manager_ = &filter_chain_manager; 136 0 : } 137 : 138 : } // namespace Quic 139 : } // namespace Envoy