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