Line data Source code
1 : #include "source/common/quic/envoy_quic_utils.h" 2 : 3 : #include <memory> 4 : 5 : #include "envoy/common/platform.h" 6 : #include "envoy/config/core/v3/base.pb.h" 7 : 8 : #include "source/common/http/utility.h" 9 : #include "source/common/network/socket_option_factory.h" 10 : #include "source/common/network/utility.h" 11 : 12 : namespace Envoy { 13 : namespace Quic { 14 : 15 : // TODO(danzh): this is called on each write. Consider to return an address instance on the stack if 16 : // the heap allocation is too expensive. 17 : Network::Address::InstanceConstSharedPtr 18 0 : quicAddressToEnvoyAddressInstance(const quic::QuicSocketAddress& quic_address) { 19 0 : return quic_address.IsInitialized() 20 0 : ? Network::Address::addressFromSockAddrOrDie(quic_address.generic_address(), 21 0 : quic_address.host().address_family() == 22 0 : quiche::IpAddressFamily::IP_V4 23 0 : ? sizeof(sockaddr_in) 24 0 : : sizeof(sockaddr_in6), 25 0 : -1, false) 26 0 : : nullptr; 27 0 : } 28 : 29 0 : quic::QuicSocketAddress envoyIpAddressToQuicSocketAddress(const Network::Address::Ip* envoy_ip) { 30 0 : if (envoy_ip == nullptr) { 31 : // Return uninitialized socket addr 32 0 : return {}; 33 0 : } 34 : 35 0 : uint32_t port = envoy_ip->port(); 36 0 : sockaddr_storage ss; 37 : 38 0 : if (envoy_ip->version() == Network::Address::IpVersion::v4) { 39 : // Create and return quic ipv4 address 40 0 : auto ipv4_addr = reinterpret_cast<sockaddr_in*>(&ss); 41 0 : memset(ipv4_addr, 0, sizeof(sockaddr_in)); 42 0 : ipv4_addr->sin_family = AF_INET; 43 0 : ipv4_addr->sin_port = htons(port); 44 0 : ipv4_addr->sin_addr.s_addr = envoy_ip->ipv4()->address(); 45 0 : } else { 46 : // Create and return quic ipv6 address 47 0 : auto ipv6_addr = reinterpret_cast<sockaddr_in6*>(&ss); 48 0 : memset(ipv6_addr, 0, sizeof(sockaddr_in6)); 49 0 : ipv6_addr->sin6_family = AF_INET6; 50 0 : ipv6_addr->sin6_port = htons(port); 51 0 : ASSERT(sizeof(ipv6_addr->sin6_addr.s6_addr) == 16u); 52 0 : *reinterpret_cast<absl::uint128*>(ipv6_addr->sin6_addr.s6_addr) = envoy_ip->ipv6()->address(); 53 0 : } 54 0 : return quic::QuicSocketAddress(ss); 55 0 : } 56 : 57 0 : spdy::Http2HeaderBlock envoyHeadersToHttp2HeaderBlock(const Http::HeaderMap& headers) { 58 0 : spdy::Http2HeaderBlock header_block; 59 0 : headers.iterate([&header_block](const Http::HeaderEntry& header) -> Http::HeaderMap::Iterate { 60 : // The key-value pairs are copied. 61 0 : header_block.AppendValueOrAddHeader(header.key().getStringView(), 62 0 : header.value().getStringView()); 63 0 : return Http::HeaderMap::Iterate::Continue; 64 0 : }); 65 0 : return header_block; 66 0 : } 67 : 68 0 : quic::QuicRstStreamErrorCode envoyResetReasonToQuicRstError(Http::StreamResetReason reason) { 69 0 : switch (reason) { 70 0 : case Http::StreamResetReason::LocalRefusedStreamReset: 71 0 : return quic::QUIC_REFUSED_STREAM; 72 0 : case Http::StreamResetReason::LocalConnectionFailure: 73 0 : case Http::StreamResetReason::RemoteConnectionFailure: 74 0 : case Http::StreamResetReason::ConnectionTimeout: 75 0 : case Http::StreamResetReason::ConnectionTermination: 76 0 : return quic::QUIC_STREAM_CONNECTION_ERROR; 77 0 : case Http::StreamResetReason::LocalReset: 78 0 : case Http::StreamResetReason::OverloadManager: 79 0 : return quic::QUIC_STREAM_CANCELLED; 80 0 : default: 81 0 : return quic::QUIC_BAD_APPLICATION_PAYLOAD; 82 0 : } 83 0 : } 84 : 85 2 : Http::StreamResetReason quicRstErrorToEnvoyLocalResetReason(quic::QuicRstStreamErrorCode rst_err) { 86 2 : switch (rst_err) { 87 0 : case quic::QUIC_REFUSED_STREAM: 88 0 : return Http::StreamResetReason::LocalRefusedStreamReset; 89 0 : case quic::QUIC_STREAM_CONNECTION_ERROR: 90 0 : return Http::StreamResetReason::LocalConnectionFailure; 91 2 : case quic::QUIC_BAD_APPLICATION_PAYLOAD: 92 2 : return Http::StreamResetReason::ProtocolError; 93 0 : default: 94 0 : return Http::StreamResetReason::LocalReset; 95 2 : } 96 2 : } 97 : 98 8 : Http::StreamResetReason quicRstErrorToEnvoyRemoteResetReason(quic::QuicRstStreamErrorCode rst_err) { 99 8 : switch (rst_err) { 100 0 : case quic::QUIC_REFUSED_STREAM: 101 0 : return Http::StreamResetReason::RemoteRefusedStreamReset; 102 0 : case quic::QUIC_STREAM_CONNECTION_ERROR: 103 0 : return Http::StreamResetReason::ConnectError; 104 8 : default: 105 8 : return Http::StreamResetReason::RemoteReset; 106 8 : } 107 8 : } 108 : 109 : Http::StreamResetReason quicErrorCodeToEnvoyLocalResetReason(quic::QuicErrorCode error, 110 229 : bool connected) { 111 229 : switch (error) { 112 0 : case quic::QUIC_HANDSHAKE_FAILED: 113 0 : case quic::QUIC_HANDSHAKE_TIMEOUT: 114 0 : return Http::StreamResetReason::LocalConnectionFailure; 115 0 : case quic::QUIC_PACKET_WRITE_ERROR: 116 0 : case quic::QUIC_NETWORK_IDLE_TIMEOUT: 117 0 : return connected ? Http::StreamResetReason::ConnectionTermination 118 0 : : Http::StreamResetReason::LocalConnectionFailure; 119 171 : case quic::QUIC_HTTP_FRAME_ERROR: 120 171 : return Http::StreamResetReason::ProtocolError; 121 58 : default: 122 58 : return Http::StreamResetReason::ConnectionTermination; 123 229 : } 124 229 : } 125 : 126 1 : Http::StreamResetReason quicErrorCodeToEnvoyRemoteResetReason(quic::QuicErrorCode error) { 127 1 : switch (error) { 128 0 : case quic::QUIC_HANDSHAKE_FAILED: 129 0 : case quic::QUIC_HANDSHAKE_TIMEOUT: 130 0 : return Http::StreamResetReason::RemoteConnectionFailure; 131 1 : default: 132 1 : return Http::StreamResetReason::ConnectionTermination; 133 1 : } 134 1 : } 135 : 136 : Network::ConnectionSocketPtr 137 : createConnectionSocket(const Network::Address::InstanceConstSharedPtr& peer_addr, 138 : Network::Address::InstanceConstSharedPtr& local_addr, 139 515 : const Network::ConnectionSocket::OptionsSharedPtr& options) { 140 515 : if (local_addr == nullptr) { 141 0 : local_addr = Network::Utility::getLocalAddress(peer_addr->ip()->version()); 142 0 : } 143 515 : auto connection_socket = std::make_unique<Network::ConnectionSocketImpl>( 144 515 : Network::Socket::Type::Datagram, local_addr, peer_addr, Network::SocketCreationOptions{}); 145 515 : connection_socket->addOptions(Network::SocketOptionFactory::buildIpPacketInfoOptions()); 146 515 : connection_socket->addOptions(Network::SocketOptionFactory::buildRxQueueOverFlowOptions()); 147 515 : if (options != nullptr) { 148 0 : connection_socket->addOptions(options); 149 0 : } 150 515 : if (!Network::Socket::applyOptions(connection_socket->options(), *connection_socket, 151 515 : envoy::config::core::v3::SocketOption::STATE_PREBIND)) { 152 0 : connection_socket->close(); 153 0 : ENVOY_LOG_MISC(error, "Fail to apply pre-bind options"); 154 0 : return connection_socket; 155 0 : } 156 515 : connection_socket->bind(local_addr); 157 515 : ASSERT(local_addr->ip()); 158 515 : local_addr = connection_socket->connectionInfoProvider().localAddress(); 159 515 : if (!Network::Socket::applyOptions(connection_socket->options(), *connection_socket, 160 515 : envoy::config::core::v3::SocketOption::STATE_BOUND)) { 161 0 : ENVOY_LOG_MISC(error, "Fail to apply post-bind options"); 162 0 : connection_socket->close(); 163 0 : } 164 515 : return connection_socket; 165 515 : } 166 : 167 : bssl::UniquePtr<X509> parseDERCertificate(const std::string& der_bytes, 168 0 : std::string* error_details) { 169 0 : const uint8_t* data; 170 0 : const uint8_t* orig_data; 171 0 : orig_data = data = reinterpret_cast<const uint8_t*>(der_bytes.data()); 172 0 : bssl::UniquePtr<X509> cert(d2i_X509(nullptr, &data, der_bytes.size())); 173 0 : if (!cert.get()) { 174 0 : *error_details = "d2i_X509: fail to parse DER"; 175 0 : return nullptr; 176 0 : } 177 0 : if (data < orig_data || static_cast<size_t>(data - orig_data) != der_bytes.size()) { 178 0 : *error_details = "There is trailing garbage in DER."; 179 0 : return nullptr; 180 0 : } 181 0 : return cert; 182 0 : } 183 : 184 0 : int deduceSignatureAlgorithmFromPublicKey(const EVP_PKEY* public_key, std::string* error_details) { 185 0 : int sign_alg = 0; 186 0 : if (public_key == nullptr) { 187 0 : *error_details = "Invalid leaf cert, bad public key"; 188 0 : return sign_alg; 189 0 : } 190 0 : const int pkey_id = EVP_PKEY_id(public_key); 191 0 : switch (pkey_id) { 192 0 : case EVP_PKEY_EC: { 193 : // We only support P-256 ECDSA today. 194 0 : const EC_KEY* ecdsa_public_key = EVP_PKEY_get0_EC_KEY(public_key); 195 : // Since we checked the key type above, this should be valid. 196 0 : ASSERT(ecdsa_public_key != nullptr); 197 0 : const EC_GROUP* ecdsa_group = EC_KEY_get0_group(ecdsa_public_key); 198 0 : if (ecdsa_group == nullptr || EC_GROUP_get_curve_name(ecdsa_group) != NID_X9_62_prime256v1) { 199 0 : *error_details = "Invalid leaf cert, only P-256 ECDSA certificates are supported"; 200 0 : break; 201 0 : } 202 : // QUICHE uses SHA-256 as hash function in cert signature. 203 0 : sign_alg = SSL_SIGN_ECDSA_SECP256R1_SHA256; 204 0 : } break; 205 0 : case EVP_PKEY_RSA: { 206 : // We require RSA certificates with 2048-bit or larger keys. 207 0 : const RSA* rsa_public_key = EVP_PKEY_get0_RSA(public_key); 208 : // Since we checked the key type above, this should be valid. 209 0 : ASSERT(rsa_public_key != nullptr); 210 0 : const unsigned rsa_key_length = RSA_size(rsa_public_key); 211 : #ifdef BORINGSSL_FIPS 212 : if (rsa_key_length != 2048 / 8 && rsa_key_length != 3072 / 8 && rsa_key_length != 4096 / 8) { 213 : *error_details = "Invalid leaf cert, only RSA certificates with 2048-bit, 3072-bit or " 214 : "4096-bit keys are supported in FIPS mode"; 215 : break; 216 : } 217 : #else 218 0 : if (rsa_key_length < 2048 / 8) { 219 0 : *error_details = 220 0 : "Invalid leaf cert, only RSA certificates with 2048-bit or larger keys are supported"; 221 0 : break; 222 0 : } 223 0 : #endif 224 0 : sign_alg = SSL_SIGN_RSA_PSS_RSAE_SHA256; 225 0 : } break; 226 0 : default: 227 0 : *error_details = "Invalid leaf cert, only RSA and ECDSA certificates are supported"; 228 0 : } 229 0 : return sign_alg; 230 0 : } 231 : 232 : Network::ConnectionSocketPtr 233 : createServerConnectionSocket(Network::IoHandle& io_handle, 234 : const quic::QuicSocketAddress& self_address, 235 : const quic::QuicSocketAddress& peer_address, 236 0 : const std::string& hostname, absl::string_view alpn) { 237 0 : auto connection_socket = std::make_unique<Network::ConnectionSocketImpl>( 238 0 : std::make_unique<QuicIoHandleWrapper>(io_handle), 239 0 : quicAddressToEnvoyAddressInstance(self_address), 240 0 : quicAddressToEnvoyAddressInstance(peer_address)); 241 0 : connection_socket->setDetectedTransportProtocol("quic"); 242 0 : connection_socket->setRequestedServerName(hostname); 243 0 : connection_socket->setRequestedApplicationProtocols({alpn}); 244 0 : return connection_socket; 245 0 : } 246 : 247 : void convertQuicConfig(const envoy::config::core::v3::QuicProtocolOptions& config, 248 0 : quic::QuicConfig& quic_config) { 249 0 : int32_t max_streams = PROTOBUF_GET_WRAPPED_OR_DEFAULT(config, max_concurrent_streams, 100); 250 0 : quic_config.SetMaxBidirectionalStreamsToSend(max_streams); 251 0 : quic_config.SetMaxUnidirectionalStreamsToSend(max_streams); 252 0 : configQuicInitialFlowControlWindow(config, quic_config); 253 0 : quic_config.SetConnectionOptionsToSend(quic::ParseQuicTagVector(config.connection_options())); 254 0 : quic_config.SetClientConnectionOptions( 255 0 : quic::ParseQuicTagVector(config.client_connection_options())); 256 0 : } 257 : 258 : void configQuicInitialFlowControlWindow(const envoy::config::core::v3::QuicProtocolOptions& config, 259 0 : quic::QuicConfig& quic_config) { 260 0 : size_t stream_flow_control_window_to_send = PROTOBUF_GET_WRAPPED_OR_DEFAULT( 261 0 : config, initial_stream_window_size, 262 0 : Http3::Utility::OptionsLimits::DEFAULT_INITIAL_STREAM_WINDOW_SIZE); 263 0 : if (stream_flow_control_window_to_send < quic::kMinimumFlowControlSendWindow) { 264 : // If the configured value is smaller than 16kB, only use it for IETF QUIC, because Google QUIC 265 : // requires minimum 16kB stream flow control window. The QUICHE default 16kB will be used for 266 : // Google QUIC connections. 267 0 : quic_config.SetInitialMaxStreamDataBytesIncomingBidirectionalToSend( 268 0 : stream_flow_control_window_to_send); 269 0 : } else { 270 : // Both Google QUIC and IETF Quic can be configured from this. 271 0 : quic_config.SetInitialStreamFlowControlWindowToSend(stream_flow_control_window_to_send); 272 0 : } 273 : 274 0 : uint32_t session_flow_control_window_to_send = PROTOBUF_GET_WRAPPED_OR_DEFAULT( 275 0 : config, initial_connection_window_size, 276 0 : Http3::Utility::OptionsLimits::DEFAULT_INITIAL_CONNECTION_WINDOW_SIZE); 277 : // Config connection level flow control window shouldn't be smaller than the minimum flow control 278 : // window supported in QUICHE which is 16kB. 279 0 : quic_config.SetInitialSessionFlowControlWindowToSend( 280 0 : std::max(quic::kMinimumFlowControlSendWindow, 281 0 : static_cast<quic::QuicByteCount>(session_flow_control_window_to_send))); 282 0 : } 283 : 284 : void adjustNewConnectionIdForRouting(quic::QuicConnectionId& new_connection_id, 285 0 : const quic::QuicConnectionId& old_connection_id) { 286 0 : char* new_connection_id_data = new_connection_id.mutable_data(); 287 0 : const char* old_connection_id_ptr = old_connection_id.data(); 288 : // Override the first 4 bytes of the new CID to the original CID's first 4 bytes. 289 0 : memcpy(new_connection_id_data, old_connection_id_ptr, 4); // NOLINT(safe-memcpy) 290 0 : } 291 : 292 : } // namespace Quic 293 : } // namespace Envoy