• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include "shrpx_quic.h"
26 
27 #include <sys/types.h>
28 #include <sys/socket.h>
29 #include <netdb.h>
30 #include <netinet/udp.h>
31 
32 #include <array>
33 #include <chrono>
34 
35 #include <ngtcp2/ngtcp2_crypto.h>
36 
37 #include <nghttp3/nghttp3.h>
38 
39 #include "ssl_compat.h"
40 
41 #ifdef NGHTTP2_OPENSSL_IS_WOLFSSL
42 #  include <wolfssl/options.h>
43 #  include <wolfssl/openssl/rand.h>
44 #else // !NGHTTP2_OPENSSL_IS_WOLFSSL
45 #  include <openssl/rand.h>
46 #endif // !NGHTTP2_OPENSSL_IS_WOLFSSL
47 
48 #include "shrpx_config.h"
49 #include "shrpx_log.h"
50 #include "util.h"
51 #include "xsi_strerror.h"
52 
operator ==(const ngtcp2_cid & lhs,const ngtcp2_cid & rhs)53 bool operator==(const ngtcp2_cid &lhs, const ngtcp2_cid &rhs) {
54   return ngtcp2_cid_eq(&lhs, &rhs);
55 }
56 
57 namespace shrpx {
58 
quic_timestamp()59 ngtcp2_tstamp quic_timestamp() {
60   return std::chrono::duration_cast<std::chrono::nanoseconds>(
61            std::chrono::steady_clock::now().time_since_epoch())
62     .count();
63 }
64 
quic_send_packet(const UpstreamAddr * faddr,const sockaddr * remote_sa,size_t remote_salen,const sockaddr * local_sa,size_t local_salen,const ngtcp2_pkt_info & pi,std::span<const uint8_t> data,size_t gso_size)65 int quic_send_packet(const UpstreamAddr *faddr, const sockaddr *remote_sa,
66                      size_t remote_salen, const sockaddr *local_sa,
67                      size_t local_salen, const ngtcp2_pkt_info &pi,
68                      std::span<const uint8_t> data, size_t gso_size) {
69   assert(gso_size);
70 
71   iovec msg_iov = {const_cast<uint8_t *>(data.data()), data.size()};
72   msghdr msg{};
73   msg.msg_name = const_cast<sockaddr *>(remote_sa);
74   msg.msg_namelen = remote_salen;
75   msg.msg_iov = &msg_iov;
76   msg.msg_iovlen = 1;
77 
78   uint8_t msg_ctrl[CMSG_SPACE(sizeof(int)) +
79 #ifdef UDP_SEGMENT
80                    CMSG_SPACE(sizeof(uint16_t)) +
81 #endif // UDP_SEGMENT
82                    CMSG_SPACE(sizeof(in6_pktinfo))];
83 
84   memset(msg_ctrl, 0, sizeof(msg_ctrl));
85 
86   msg.msg_control = msg_ctrl;
87   msg.msg_controllen = sizeof(msg_ctrl);
88 
89   size_t controllen = 0;
90 
91   auto cm = CMSG_FIRSTHDR(&msg);
92 
93   switch (local_sa->sa_family) {
94   case AF_INET: {
95     controllen += CMSG_SPACE(sizeof(in_pktinfo));
96     cm->cmsg_level = IPPROTO_IP;
97     cm->cmsg_type = IP_PKTINFO;
98     cm->cmsg_len = CMSG_LEN(sizeof(in_pktinfo));
99     in_pktinfo pktinfo{};
100     auto addrin =
101       reinterpret_cast<sockaddr_in *>(const_cast<sockaddr *>(local_sa));
102     pktinfo.ipi_spec_dst = addrin->sin_addr;
103     memcpy(CMSG_DATA(cm), &pktinfo, sizeof(pktinfo));
104 
105     break;
106   }
107   case AF_INET6: {
108     controllen += CMSG_SPACE(sizeof(in6_pktinfo));
109     cm->cmsg_level = IPPROTO_IPV6;
110     cm->cmsg_type = IPV6_PKTINFO;
111     cm->cmsg_len = CMSG_LEN(sizeof(in6_pktinfo));
112     in6_pktinfo pktinfo{};
113     auto addrin =
114       reinterpret_cast<sockaddr_in6 *>(const_cast<sockaddr *>(local_sa));
115     pktinfo.ipi6_addr = addrin->sin6_addr;
116     memcpy(CMSG_DATA(cm), &pktinfo, sizeof(pktinfo));
117 
118     break;
119   }
120   default:
121     assert(0);
122   }
123 
124 #ifdef UDP_SEGMENT
125   if (data.size() > gso_size) {
126     controllen += CMSG_SPACE(sizeof(uint16_t));
127     cm = CMSG_NXTHDR(&msg, cm);
128     cm->cmsg_level = SOL_UDP;
129     cm->cmsg_type = UDP_SEGMENT;
130     cm->cmsg_len = CMSG_LEN(sizeof(uint16_t));
131     uint16_t n = gso_size;
132     memcpy(CMSG_DATA(cm), &n, sizeof(n));
133   }
134 #endif // UDP_SEGMENT
135 
136   controllen += CMSG_SPACE(sizeof(int));
137   cm = CMSG_NXTHDR(&msg, cm);
138   cm->cmsg_len = CMSG_LEN(sizeof(int));
139   unsigned int tos = pi.ecn;
140   memcpy(CMSG_DATA(cm), &tos, sizeof(tos));
141 
142   switch (local_sa->sa_family) {
143   case AF_INET:
144     cm->cmsg_level = IPPROTO_IP;
145     cm->cmsg_type = IP_TOS;
146 
147     break;
148   case AF_INET6:
149     cm->cmsg_level = IPPROTO_IPV6;
150     cm->cmsg_type = IPV6_TCLASS;
151 
152     break;
153   default:
154     assert(0);
155   }
156 
157   msg.msg_controllen = controllen;
158 
159   ssize_t nwrite;
160 
161   do {
162     nwrite = sendmsg(faddr->fd, &msg, 0);
163   } while (nwrite == -1 && errno == EINTR);
164 
165   if (nwrite == -1) {
166     if (LOG_ENABLED(INFO)) {
167       auto error = errno;
168       LOG(INFO) << "sendmsg failed: errno=" << error;
169     }
170 
171     return -errno;
172   }
173 
174   if (LOG_ENABLED(INFO)) {
175     LOG(INFO) << "QUIC sent packet: local="
176               << util::to_numeric_addr(local_sa, local_salen)
177               << " remote=" << util::to_numeric_addr(remote_sa, remote_salen)
178               << " ecn=" << log::hex << pi.ecn << log::dec << " " << nwrite
179               << " bytes";
180   }
181 
182   assert(static_cast<size_t>(nwrite) == data.size());
183 
184   return 0;
185 }
186 
generate_quic_retry_connection_id(ngtcp2_cid & cid,uint32_t server_id,uint8_t km_id,EVP_CIPHER_CTX * ctx)187 int generate_quic_retry_connection_id(ngtcp2_cid &cid, uint32_t server_id,
188                                       uint8_t km_id, EVP_CIPHER_CTX *ctx) {
189   if (RAND_bytes(cid.data, SHRPX_QUIC_SCIDLEN) != 1) {
190     return -1;
191   }
192 
193   cid.datalen = SHRPX_QUIC_SCIDLEN;
194   cid.data[0] = (cid.data[0] & (~SHRPX_QUIC_DCID_KM_ID_MASK)) | km_id;
195 
196   auto p = cid.data + SHRPX_QUIC_CID_WORKER_ID_OFFSET;
197 
198   std::copy_n(reinterpret_cast<uint8_t *>(&server_id), sizeof(server_id), p);
199 
200   return encrypt_quic_connection_id(p, p, ctx);
201 }
202 
generate_quic_connection_id(ngtcp2_cid & cid,const WorkerID & wid,uint8_t km_id,EVP_CIPHER_CTX * ctx)203 int generate_quic_connection_id(ngtcp2_cid &cid, const WorkerID &wid,
204                                 uint8_t km_id, EVP_CIPHER_CTX *ctx) {
205   if (RAND_bytes(cid.data, SHRPX_QUIC_SCIDLEN) != 1) {
206     return -1;
207   }
208 
209   cid.datalen = SHRPX_QUIC_SCIDLEN;
210   cid.data[0] = (cid.data[0] & (~SHRPX_QUIC_DCID_KM_ID_MASK)) | km_id;
211 
212   auto p = cid.data + SHRPX_QUIC_CID_WORKER_ID_OFFSET;
213 
214   std::copy_n(reinterpret_cast<const uint8_t *>(&wid), sizeof(wid), p);
215 
216   return encrypt_quic_connection_id(p, p, ctx);
217 }
218 
encrypt_quic_connection_id(uint8_t * dest,const uint8_t * src,EVP_CIPHER_CTX * ctx)219 int encrypt_quic_connection_id(uint8_t *dest, const uint8_t *src,
220                                EVP_CIPHER_CTX *ctx) {
221   int len;
222 
223   if (!EVP_EncryptUpdate(ctx, dest, &len, src, SHRPX_QUIC_DECRYPTED_DCIDLEN) ||
224       !EVP_EncryptFinal_ex(ctx, dest + len, &len)) {
225     return -1;
226   }
227 
228   return 0;
229 }
230 
decrypt_quic_connection_id(ConnectionID & dest,const uint8_t * src,EVP_CIPHER_CTX * ctx)231 int decrypt_quic_connection_id(ConnectionID &dest, const uint8_t *src,
232                                EVP_CIPHER_CTX *ctx) {
233   int len;
234   auto p = reinterpret_cast<uint8_t *>(&dest);
235 
236   if (!EVP_DecryptUpdate(ctx, p, &len, src, SHRPX_QUIC_DECRYPTED_DCIDLEN) ||
237       !EVP_DecryptFinal_ex(ctx, p + len, &len)) {
238     return -1;
239   }
240 
241   return 0;
242 }
243 
generate_quic_hashed_connection_id(ngtcp2_cid & dest,const Address & remote_addr,const Address & local_addr,const ngtcp2_cid & cid)244 int generate_quic_hashed_connection_id(ngtcp2_cid &dest,
245                                        const Address &remote_addr,
246                                        const Address &local_addr,
247                                        const ngtcp2_cid &cid) {
248   auto ctx = EVP_MD_CTX_new();
249   auto d = defer(EVP_MD_CTX_free, ctx);
250 
251   std::array<uint8_t, 32> h;
252   unsigned int hlen = EVP_MD_size(EVP_sha256());
253 
254   if (!EVP_DigestInit_ex(ctx, EVP_sha256(), nullptr) ||
255       !EVP_DigestUpdate(ctx, &remote_addr.su.sa, remote_addr.len) ||
256       !EVP_DigestUpdate(ctx, &local_addr.su.sa, local_addr.len) ||
257       !EVP_DigestUpdate(ctx, cid.data, cid.datalen) ||
258       !EVP_DigestFinal_ex(ctx, h.data(), &hlen)) {
259     return -1;
260   }
261 
262   assert(hlen == h.size());
263 
264   std::copy_n(std::begin(h), sizeof(dest.data), std::begin(dest.data));
265   dest.datalen = sizeof(dest.data);
266 
267   return 0;
268 }
269 
generate_quic_stateless_reset_token(uint8_t * token,const ngtcp2_cid & cid,const uint8_t * secret,size_t secretlen)270 int generate_quic_stateless_reset_token(uint8_t *token, const ngtcp2_cid &cid,
271                                         const uint8_t *secret,
272                                         size_t secretlen) {
273   if (ngtcp2_crypto_generate_stateless_reset_token(token, secret, secretlen,
274                                                    &cid) != 0) {
275     return -1;
276   }
277 
278   return 0;
279 }
280 
281 std::optional<std::span<const uint8_t>>
generate_retry_token(std::span<uint8_t> token,uint32_t version,const sockaddr * sa,socklen_t salen,const ngtcp2_cid & retry_scid,const ngtcp2_cid & odcid,std::span<const uint8_t> secret)282 generate_retry_token(std::span<uint8_t> token, uint32_t version,
283                      const sockaddr *sa, socklen_t salen,
284                      const ngtcp2_cid &retry_scid, const ngtcp2_cid &odcid,
285                      std::span<const uint8_t> secret) {
286   auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(
287              std::chrono::system_clock::now().time_since_epoch())
288              .count();
289 
290   auto tokenlen = ngtcp2_crypto_generate_retry_token(
291     token.data(), secret.data(), secret.size(), version, sa, salen, &retry_scid,
292     &odcid, t);
293   if (tokenlen < 0) {
294     return {};
295   }
296 
297   return {{std::begin(token), static_cast<size_t>(tokenlen)}};
298 }
299 
verify_retry_token(ngtcp2_cid & odcid,std::span<const uint8_t> token,uint32_t version,const ngtcp2_cid & dcid,const sockaddr * sa,socklen_t salen,std::span<const uint8_t> secret)300 int verify_retry_token(ngtcp2_cid &odcid, std::span<const uint8_t> token,
301                        uint32_t version, const ngtcp2_cid &dcid,
302                        const sockaddr *sa, socklen_t salen,
303                        std::span<const uint8_t> secret) {
304   auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(
305              std::chrono::system_clock::now().time_since_epoch())
306              .count();
307 
308   if (ngtcp2_crypto_verify_retry_token(
309         &odcid, token.data(), token.size(), secret.data(), secret.size(),
310         version, sa, salen, &dcid, 10 * NGTCP2_SECONDS, t) != 0) {
311     return -1;
312   }
313 
314   return 0;
315 }
316 
317 std::optional<std::span<const uint8_t>>
generate_token(std::span<uint8_t> token,const sockaddr * sa,size_t salen,std::span<const uint8_t> secret,uint8_t km_id)318 generate_token(std::span<uint8_t> token, const sockaddr *sa, size_t salen,
319                std::span<const uint8_t> secret, uint8_t km_id) {
320   auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(
321              std::chrono::system_clock::now().time_since_epoch())
322              .count();
323 
324   auto tokenlen = ngtcp2_crypto_generate_regular_token(
325     token.data(), secret.data(), secret.size(), sa, salen, t);
326   if (tokenlen < 0) {
327     return {};
328   }
329 
330   token[tokenlen++] = km_id;
331 
332   return {{std::begin(token), static_cast<size_t>(tokenlen)}};
333 }
334 
verify_token(std::span<const uint8_t> token,const sockaddr * sa,socklen_t salen,std::span<const uint8_t> secret)335 int verify_token(std::span<const uint8_t> token, const sockaddr *sa,
336                  socklen_t salen, std::span<const uint8_t> secret) {
337   if (token.empty()) {
338     return -1;
339   }
340 
341   auto t = std::chrono::duration_cast<std::chrono::nanoseconds>(
342              std::chrono::system_clock::now().time_since_epoch())
343              .count();
344 
345   if (ngtcp2_crypto_verify_regular_token(
346         token.data(), token.size() - 1, secret.data(), secret.size(), sa, salen,
347         3600 * NGTCP2_SECONDS, t) != 0) {
348     return -1;
349   }
350 
351   return 0;
352 }
353 
generate_quic_connection_id_encryption_key(std::span<uint8_t> key,std::span<const uint8_t> secret,std::span<const uint8_t> salt)354 int generate_quic_connection_id_encryption_key(std::span<uint8_t> key,
355                                                std::span<const uint8_t> secret,
356                                                std::span<const uint8_t> salt) {
357   constexpr uint8_t info[] = "connection id encryption key";
358   ngtcp2_crypto_md sha256;
359   ngtcp2_crypto_md_init(
360     &sha256, reinterpret_cast<void *>(const_cast<EVP_MD *>(EVP_sha256())));
361 
362   if (ngtcp2_crypto_hkdf(key.data(), key.size(), &sha256, secret.data(),
363                          secret.size(), salt.data(), salt.size(), info,
364                          str_size(info)) != 0) {
365     return -1;
366   }
367 
368   return 0;
369 }
370 
371 const QUICKeyingMaterial *
select_quic_keying_material(const QUICKeyingMaterials & qkms,uint8_t km_id)372 select_quic_keying_material(const QUICKeyingMaterials &qkms, uint8_t km_id) {
373   for (auto &qkm : qkms.keying_materials) {
374     if (km_id == qkm.id) {
375       return &qkm;
376     }
377   }
378 
379   return &qkms.keying_materials.front();
380 }
381 
382 } // namespace shrpx
383