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 <openssl/evp.h> 37 38 #include <ngtcp2/ngtcp2.h> 39 40 #include "network.h" 41 42 using namespace nghttp2; 43 44 namespace std { 45 template <> struct hash<ngtcp2_cid> { 46 std::size_t operator()(const ngtcp2_cid &cid) const noexcept { 47 // FNV-1a 64bits variant 48 constexpr uint64_t basis = 0xCBF29CE484222325ULL; 49 const uint8_t *p = cid.data, *end = cid.data + cid.datalen; 50 uint64_t h = basis; 51 52 for (; p != end;) { 53 h ^= *p++; 54 h *= basis; 55 } 56 57 return static_cast<size_t>(h); 58 } 59 }; 60 } // namespace std 61 62 bool operator==(const ngtcp2_cid &lhs, const ngtcp2_cid &rhs); 63 64 namespace shrpx { 65 66 struct UpstreamAddr; 67 struct QUICKeyingMaterials; 68 struct QUICKeyingMaterial; 69 70 constexpr size_t SHRPX_QUIC_CID_WORKER_ID_OFFSET = 1; 71 constexpr size_t SHRPX_QUIC_SERVER_IDLEN = 4; 72 constexpr size_t SHRPX_QUIC_SOCK_IDLEN = 4; 73 constexpr size_t SHRPX_QUIC_WORKER_IDLEN = 74 SHRPX_QUIC_SERVER_IDLEN + SHRPX_QUIC_SOCK_IDLEN; 75 constexpr size_t SHRPX_QUIC_CLIENT_IDLEN = 8; 76 constexpr size_t SHRPX_QUIC_DECRYPTED_DCIDLEN = 77 SHRPX_QUIC_WORKER_IDLEN + SHRPX_QUIC_CLIENT_IDLEN; 78 constexpr size_t SHRPX_QUIC_SCIDLEN = 79 SHRPX_QUIC_CID_WORKER_ID_OFFSET + SHRPX_QUIC_DECRYPTED_DCIDLEN; 80 constexpr size_t SHRPX_QUIC_CID_ENCRYPTION_KEYLEN = 16; 81 constexpr size_t SHRPX_QUIC_CONN_CLOSE_PKTLEN = 256; 82 constexpr size_t SHRPX_QUIC_STATELESS_RESET_BURST = 100; 83 constexpr size_t SHRPX_QUIC_SECRET_RESERVEDLEN = 4; 84 constexpr size_t SHRPX_QUIC_SECRETLEN = 32; 85 constexpr size_t SHRPX_QUIC_SALTLEN = 32; 86 constexpr uint8_t SHRPX_QUIC_DCID_KM_ID_MASK = 0xe0; 87 88 struct WorkerID { 89 union { 90 struct { 91 uint32_t server; 92 uint16_t worker_process; 93 uint16_t thread; 94 }; 95 uint64_t worker; 96 }; 97 }; 98 99 static_assert(sizeof(WorkerID) == SHRPX_QUIC_WORKER_IDLEN, 100 "WorkerID length assertion failure"); 101 102 inline bool operator==(const WorkerID &lhd, const WorkerID &rhd) { 103 return lhd.worker == rhd.worker; 104 } 105 106 inline bool operator!=(const WorkerID &lhd, const WorkerID &rhd) { 107 return lhd.worker != rhd.worker; 108 } 109 110 struct ConnectionID { 111 WorkerID worker; 112 uint64_t client; 113 }; 114 115 ngtcp2_tstamp quic_timestamp(); 116 117 int quic_send_packet(const UpstreamAddr *faddr, const sockaddr *remote_sa, 118 size_t remote_salen, const sockaddr *local_sa, 119 size_t local_salen, const ngtcp2_pkt_info &pi, 120 std::span<const uint8_t> data, size_t gso_size); 121 122 int generate_quic_retry_connection_id(ngtcp2_cid &cid, uint32_t server_id, 123 uint8_t km_id, EVP_CIPHER_CTX *ctx); 124 125 int generate_quic_connection_id(ngtcp2_cid &cid, const WorkerID &wid, 126 uint8_t km_id, EVP_CIPHER_CTX *ctx); 127 128 int encrypt_quic_connection_id(uint8_t *dest, const uint8_t *src, 129 EVP_CIPHER_CTX *ctx); 130 131 int decrypt_quic_connection_id(ConnectionID &dest, const uint8_t *src, 132 EVP_CIPHER_CTX *ctx); 133 134 int generate_quic_hashed_connection_id(ngtcp2_cid &dest, 135 const Address &remote_addr, 136 const Address &local_addr, 137 const ngtcp2_cid &cid); 138 139 int generate_quic_stateless_reset_token(uint8_t *token, const ngtcp2_cid &cid, 140 const uint8_t *secret, 141 size_t secretlen); 142 143 std::optional<std::span<const uint8_t>> 144 generate_retry_token(std::span<uint8_t> token, uint32_t version, 145 const sockaddr *sa, socklen_t salen, 146 const ngtcp2_cid &retry_scid, const ngtcp2_cid &odcid, 147 std::span<const uint8_t> secret); 148 149 int verify_retry_token(ngtcp2_cid &odcid, std::span<const uint8_t> token, 150 uint32_t version, const ngtcp2_cid &dcid, 151 const sockaddr *sa, socklen_t salen, 152 std::span<const uint8_t> secret); 153 154 std::optional<std::span<const uint8_t>> 155 generate_token(std::span<uint8_t> token, const sockaddr *sa, size_t salen, 156 std::span<const uint8_t> secret, uint8_t km_id); 157 158 int verify_token(std::span<const uint8_t> token, const sockaddr *sa, 159 socklen_t salen, std::span<const uint8_t> secret); 160 161 int generate_quic_connection_id_encryption_key(std::span<uint8_t> key, 162 std::span<const uint8_t> secret, 163 std::span<const uint8_t> salt); 164 165 const QUICKeyingMaterial * 166 select_quic_keying_material(const QUICKeyingMaterials &qkms, uint8_t km_id); 167 168 } // namespace shrpx 169 170 #endif // SHRPX_QUIC_H 171