1 /* 2 * nghttp2 - HTTP/2 C Library 3 * 4 * Copyright (c) 2021 Tatsuhiro Tsujikawa 5 * 6 * Permission is hereby granted, free of charge, to any person obtaining 7 * a copy of this software and associated documentation files (the 8 * "Software"), to deal in the Software without restriction, including 9 * without limitation the rights to use, copy, modify, merge, publish, 10 * distribute, sublicense, and/or sell copies of the Software, and to 11 * permit persons to whom the Software is furnished to do so, subject to 12 * the following conditions: 13 * 14 * The above copyright notice and this permission notice shall be 15 * included in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 21 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 22 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 23 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 24 */ 25 #ifndef SHRPX_QUIC_H 26 #define SHRPX_QUIC_H 27 28 #include "shrpx.h" 29 30 #include <stdint.h> 31 32 #include <functional> 33 #include <optional> 34 #include <span> 35 36 #include "ssl_compat.h" 37 38 #ifdef NGHTTP2_OPENSSL_IS_WOLFSSL 39 # include <wolfssl/options.h> 40 # include <wolfssl/openssl/evp.h> 41 #else // !NGHTTP2_OPENSSL_IS_WOLFSSL 42 # include <openssl/evp.h> 43 #endif // !NGHTTP2_OPENSSL_IS_WOLFSSL 44 45 #include <ngtcp2/ngtcp2.h> 46 47 #include "network.h" 48 49 using namespace nghttp2; 50 51 namespace std { 52 template <> struct hash<ngtcp2_cid> { 53 std::size_t operator()(const ngtcp2_cid &cid) const noexcept { 54 // FNV-1a 64bits variant 55 constexpr uint64_t basis = 0xCBF29CE484222325ULL; 56 const uint8_t *p = cid.data, *end = cid.data + cid.datalen; 57 uint64_t h = basis; 58 59 for (; p != end;) { 60 h ^= *p++; 61 h *= basis; 62 } 63 64 return static_cast<size_t>(h); 65 } 66 }; 67 } // namespace std 68 69 bool operator==(const ngtcp2_cid &lhs, const ngtcp2_cid &rhs); 70 71 namespace shrpx { 72 73 struct UpstreamAddr; 74 struct QUICKeyingMaterials; 75 struct QUICKeyingMaterial; 76 77 constexpr size_t SHRPX_QUIC_CID_WORKER_ID_OFFSET = 1; 78 constexpr size_t SHRPX_QUIC_SERVER_IDLEN = 4; 79 constexpr size_t SHRPX_QUIC_SOCK_IDLEN = 4; 80 constexpr size_t SHRPX_QUIC_WORKER_IDLEN = 81 SHRPX_QUIC_SERVER_IDLEN + SHRPX_QUIC_SOCK_IDLEN; 82 constexpr size_t SHRPX_QUIC_CLIENT_IDLEN = 8; 83 constexpr size_t SHRPX_QUIC_DECRYPTED_DCIDLEN = 84 SHRPX_QUIC_WORKER_IDLEN + SHRPX_QUIC_CLIENT_IDLEN; 85 constexpr size_t SHRPX_QUIC_SCIDLEN = 86 SHRPX_QUIC_CID_WORKER_ID_OFFSET + SHRPX_QUIC_DECRYPTED_DCIDLEN; 87 constexpr size_t SHRPX_QUIC_CID_ENCRYPTION_KEYLEN = 16; 88 constexpr size_t SHRPX_QUIC_CONN_CLOSE_PKTLEN = 256; 89 constexpr size_t SHRPX_QUIC_STATELESS_RESET_BURST = 100; 90 constexpr size_t SHRPX_QUIC_SECRET_RESERVEDLEN = 4; 91 constexpr size_t SHRPX_QUIC_SECRETLEN = 32; 92 constexpr size_t SHRPX_QUIC_SALTLEN = 32; 93 constexpr uint8_t SHRPX_QUIC_DCID_KM_ID_MASK = 0xe0; 94 95 struct WorkerID { 96 union { 97 struct { 98 uint32_t server; 99 uint16_t worker_process; 100 uint16_t thread; 101 }; 102 uint64_t worker; 103 }; 104 }; 105 106 static_assert(sizeof(WorkerID) == SHRPX_QUIC_WORKER_IDLEN, 107 "WorkerID length assertion failure"); 108 109 inline bool operator==(const WorkerID &lhd, const WorkerID &rhd) { 110 return lhd.worker == rhd.worker; 111 } 112 113 inline bool operator!=(const WorkerID &lhd, const WorkerID &rhd) { 114 return lhd.worker != rhd.worker; 115 } 116 117 struct ConnectionID { 118 WorkerID worker; 119 uint64_t client; 120 }; 121 122 ngtcp2_tstamp quic_timestamp(); 123 124 int quic_send_packet(const UpstreamAddr *faddr, const sockaddr *remote_sa, 125 size_t remote_salen, const sockaddr *local_sa, 126 size_t local_salen, const ngtcp2_pkt_info &pi, 127 std::span<const uint8_t> data, size_t gso_size); 128 129 int generate_quic_retry_connection_id(ngtcp2_cid &cid, uint32_t server_id, 130 uint8_t km_id, EVP_CIPHER_CTX *ctx); 131 132 int generate_quic_connection_id(ngtcp2_cid &cid, const WorkerID &wid, 133 uint8_t km_id, EVP_CIPHER_CTX *ctx); 134 135 int encrypt_quic_connection_id(uint8_t *dest, const uint8_t *src, 136 EVP_CIPHER_CTX *ctx); 137 138 int decrypt_quic_connection_id(ConnectionID &dest, const uint8_t *src, 139 EVP_CIPHER_CTX *ctx); 140 141 int generate_quic_hashed_connection_id(ngtcp2_cid &dest, 142 const Address &remote_addr, 143 const Address &local_addr, 144 const ngtcp2_cid &cid); 145 146 int generate_quic_stateless_reset_token(uint8_t *token, const ngtcp2_cid &cid, 147 const uint8_t *secret, 148 size_t secretlen); 149 150 std::optional<std::span<const uint8_t>> 151 generate_retry_token(std::span<uint8_t> token, uint32_t version, 152 const sockaddr *sa, socklen_t salen, 153 const ngtcp2_cid &retry_scid, const ngtcp2_cid &odcid, 154 std::span<const uint8_t> secret); 155 156 int verify_retry_token(ngtcp2_cid &odcid, std::span<const uint8_t> token, 157 uint32_t version, const ngtcp2_cid &dcid, 158 const sockaddr *sa, socklen_t salen, 159 std::span<const uint8_t> secret); 160 161 std::optional<std::span<const uint8_t>> 162 generate_token(std::span<uint8_t> token, const sockaddr *sa, size_t salen, 163 std::span<const uint8_t> secret, uint8_t km_id); 164 165 int verify_token(std::span<const uint8_t> token, const sockaddr *sa, 166 socklen_t salen, std::span<const uint8_t> secret); 167 168 int generate_quic_connection_id_encryption_key(std::span<uint8_t> key, 169 std::span<const uint8_t> secret, 170 std::span<const uint8_t> salt); 171 172 const QUICKeyingMaterial * 173 select_quic_keying_material(const QUICKeyingMaterials &qkms, uint8_t km_id); 174 175 } // namespace shrpx 176 177 #endif // SHRPX_QUIC_H 178