Mercurial > hg > nginx
comparison src/event/ngx_event_quic.c @ 8221:69345a26ba69 quic
Split transport and crypto parts into separate files.
New files:
src/event/ngx_event_quic_protection.h
src/event/ngx_event_quic_protection.c
The protection.h header provides interface to the crypto part of the QUIC:
2 functions to initialize corresponding secrets:
ngx_quic_set_initial_secret()
ngx_quic_set_encryption_secret()
and 2 functions to deal with packet processing:
ngx_quic_encrypt()
ngx_quic_decrypt()
Also, structures representing secrets are defined there.
All functions require SSL connection and a pool, only crypto operations
inside, no access to nginx connections or events.
Currently pool->log is used for the logging (instead of original c->log).
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Mon, 16 Mar 2020 19:00:47 +0300 |
parents | 7ada2feeac18 |
children | bec4cd55361e |
comparison
equal
deleted
inserted
replaced
8220:7ada2feeac18 | 8221:69345a26ba69 |
---|---|
6 | 6 |
7 #include <ngx_config.h> | 7 #include <ngx_config.h> |
8 #include <ngx_core.h> | 8 #include <ngx_core.h> |
9 #include <ngx_event.h> | 9 #include <ngx_event.h> |
10 | 10 |
11 | |
12 #define quic_version 0xff000018 | |
13 | |
14 #define NGX_AES_128_GCM_SHA256 0x1301 | |
15 #define NGX_AES_256_GCM_SHA384 0x1302 | |
16 #define NGX_CHACHA20_POLY1305_SHA256 0x1303 | |
17 | |
18 #define NGX_QUIC_IV_LEN 12 | |
19 | |
20 #ifdef OPENSSL_IS_BORINGSSL | |
21 #define ngx_quic_cipher_t EVP_AEAD | |
22 #else | |
23 #define ngx_quic_cipher_t EVP_CIPHER | |
24 #endif | |
25 | |
26 | |
27 #if (NGX_HAVE_NONALIGNED) | |
28 | |
29 #define ngx_quic_parse_uint16(p) ntohs(*(uint16_t *) (p)) | |
30 #define ngx_quic_parse_uint32(p) ntohl(*(uint32_t *) (p)) | |
31 | |
32 #define ngx_quic_write_uint16 ngx_quic_write_uint16_aligned | |
33 #define ngx_quic_write_uint32 ngx_quic_write_uint32_aligned | |
34 | |
35 #else | |
36 | |
37 #define ngx_quic_parse_uint16(p) ((p)[0] << 8 | (p)[1]) | |
38 #define ngx_quic_parse_uint32(p) \ | |
39 ((uint32_t) (p)[0] << 24 | (p)[1] << 16 | (p)[2] << 8 | (p)[3]) | |
40 | |
41 #define ngx_quic_write_uint16(p, s) \ | |
42 ((p)[0] = (u_char) ((s) >> 8), \ | |
43 (p)[1] = (u_char) (s), \ | |
44 (p) + sizeof(uint16_t)) | |
45 | |
46 #define ngx_quic_write_uint32(p, s) \ | |
47 ((p)[0] = (u_char) ((s) >> 24), \ | |
48 (p)[1] = (u_char) ((s) >> 16), \ | |
49 (p)[2] = (u_char) ((s) >> 8), \ | |
50 (p)[3] = (u_char) (s), \ | |
51 (p) + sizeof(uint32_t)) | |
52 | |
53 #endif | |
54 | |
55 | |
56 #define ngx_quic_write_uint16_aligned(p, s) \ | |
57 (*(uint16_t *) (p) = htons((uint16_t) (s)), (p) + sizeof(uint16_t)) | |
58 | |
59 #define ngx_quic_write_uint32_aligned(p, s) \ | |
60 (*(uint32_t *) (p) = htonl((uint32_t) (s)), (p) + sizeof(uint32_t)) | |
61 | |
62 #define ngx_quic_varint_len(value) \ | |
63 ((value) <= 63 ? 1 : ((uint32_t)value) <= 16383 ? 2 : ((uint64_t)value) <= 1073741823 ? 4 : 8) | |
64 | |
65 | |
66 #if (NGX_DEBUG) | |
67 | |
68 #define ngx_quic_hexdump(log, fmt, data, len, ...) \ | |
69 do { \ | |
70 ngx_int_t m; \ | |
71 u_char buf[2048]; \ | |
72 \ | |
73 if (log->log_level & NGX_LOG_DEBUG_EVENT) { \ | |
74 m = ngx_hex_dump(buf, (u_char *) data, ngx_min(len, 1024)) - buf; \ | |
75 ngx_log_debug(NGX_LOG_DEBUG_EVENT, log, 0, \ | |
76 "%s: " fmt " %*s%s, len: %uz", \ | |
77 __FUNCTION__, __VA_ARGS__, m, buf, \ | |
78 len < 2048 ? "" : "...", len); \ | |
79 } \ | |
80 } while (0) | |
81 | |
82 #else | |
83 | |
84 #define ngx_quic_hexdump(log, fmt, data, len, ...) | |
85 | |
86 #endif | |
87 | |
88 #define ngx_quic_hexdump0(log, fmt, data, len) \ | |
89 ngx_quic_hexdump(log, fmt "%s", data, len, "") \ | |
90 | |
91 | |
92 /* 17.2. Long Header Packets */ | |
93 | |
94 #define NGX_QUIC_PKT_LONG 0x80 | |
95 | |
96 #define NGX_QUIC_PKT_INITIAL 0xc0 | |
97 #define NGX_QUIC_PKT_HANDSHAKE 0xe0 | |
98 | 11 |
99 /* 12.4. Frames and Frame Types */ | 12 /* 12.4. Frames and Frame Types */ |
100 #define NGX_QUIC_FT_PADDING 0x00 | 13 #define NGX_QUIC_FT_PADDING 0x00 |
101 #define NGX_QUIC_FT_PING 0x01 | 14 #define NGX_QUIC_FT_PING 0x01 |
102 #define NGX_QUIC_FT_ACK 0x02 | 15 #define NGX_QUIC_FT_ACK 0x02 |
178 NGX_QUIC_ST_HANDSHAKE, | 91 NGX_QUIC_ST_HANDSHAKE, |
179 NGX_QUIC_ST_APP_DATA | 92 NGX_QUIC_ST_APP_DATA |
180 } ngx_quic_state_t; | 93 } ngx_quic_state_t; |
181 | 94 |
182 | 95 |
183 typedef struct { | |
184 ngx_str_t secret; | |
185 ngx_str_t key; | |
186 ngx_str_t iv; | |
187 ngx_str_t hp; | |
188 } ngx_quic_secret_t; | |
189 | |
190 typedef struct { | |
191 const ngx_quic_cipher_t *c; | |
192 const EVP_CIPHER *hp; | |
193 const EVP_MD *d; | |
194 } ngx_quic_ciphers_t; | |
195 | |
196 typedef enum ssl_encryption_level_t ngx_quic_level_t; | |
197 | |
198 typedef struct ngx_quic_frame_s ngx_quic_frame_t; | 96 typedef struct ngx_quic_frame_s ngx_quic_frame_t; |
199 | 97 |
200 typedef struct { | 98 typedef struct { |
201 ngx_uint_t pn; | 99 ngx_uint_t pn; |
202 | 100 |
272 /* current packet numbers for each namespace */ | 170 /* current packet numbers for each namespace */ |
273 ngx_uint_t initial_pn; | 171 ngx_uint_t initial_pn; |
274 ngx_uint_t handshake_pn; | 172 ngx_uint_t handshake_pn; |
275 ngx_uint_t appdata_pn; | 173 ngx_uint_t appdata_pn; |
276 | 174 |
277 ngx_quic_secret_t client_in; | 175 ngx_quic_secrets_t secrets; |
278 ngx_quic_secret_t client_hs; | |
279 ngx_quic_secret_t client_ad; | |
280 ngx_quic_secret_t server_in; | |
281 ngx_quic_secret_t server_hs; | |
282 ngx_quic_secret_t server_ad; | |
283 | 176 |
284 /* streams */ | 177 /* streams */ |
285 ngx_rbtree_t stree; | 178 ngx_rbtree_t stree; |
286 ngx_rbtree_node_t stree_sentinel; | 179 ngx_rbtree_node_t stree_sentinel; |
287 ngx_msec_t stream_timeout; | 180 ngx_msec_t stream_timeout; |
295 ngx_connection_t *c; | 188 ngx_connection_t *c; |
296 ngx_quic_stream_t s; | 189 ngx_quic_stream_t s; |
297 } ngx_quic_stream_node_t; | 190 } ngx_quic_stream_node_t; |
298 | 191 |
299 | 192 |
300 typedef struct { | 193 static ngx_int_t ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b); |
301 ngx_quic_secret_t *secret; | 194 static ngx_int_t ngx_quic_output(ngx_connection_t *c); |
302 ngx_uint_t type; | |
303 ngx_uint_t *number; | |
304 ngx_uint_t flags; | |
305 uint32_t version; | |
306 ngx_str_t token; | |
307 ngx_quic_level_t level; | |
308 | |
309 /* filled in by parser */ | |
310 ngx_buf_t *raw; /* udp datagram from wire */ | |
311 | |
312 u_char *data; /* quic packet */ | |
313 size_t len; | |
314 | |
315 /* cleartext fields */ | |
316 ngx_str_t dcid; | |
317 ngx_str_t scid; | |
318 | |
319 uint64_t pn; | |
320 | |
321 ngx_str_t payload; /* decrypted payload */ | |
322 | |
323 } ngx_quic_header_t; | |
324 | |
325 | 195 |
326 static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, | 196 static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, |
327 ngx_quic_header_t *pkt); | 197 ngx_quic_header_t *pkt); |
328 static void ngx_quic_close_connection(ngx_connection_t *c); | 198 static void ngx_quic_close_connection(ngx_connection_t *c); |
329 | 199 |
351 enum ssl_encryption_level_t level, const uint8_t *read_secret, | 221 enum ssl_encryption_level_t level, const uint8_t *read_secret, |
352 const uint8_t *write_secret, size_t secret_len); | 222 const uint8_t *write_secret, size_t secret_len); |
353 #endif | 223 #endif |
354 static int ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, | 224 static int ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, |
355 enum ssl_encryption_level_t level, const uint8_t *data, size_t len); | 225 enum ssl_encryption_level_t level, const uint8_t *data, size_t len); |
356 static ngx_int_t ngx_quic_create_long_packet(ngx_connection_t *c, | |
357 ngx_ssl_conn_t *ssl_conn, ngx_quic_header_t *pkt, ngx_str_t *in, | |
358 ngx_str_t *res); | |
359 static ngx_int_t ngx_quic_create_short_packet(ngx_connection_t *c, | |
360 ngx_ssl_conn_t *ssl_conn, ngx_quic_header_t *pkt, ngx_str_t *in, | |
361 ngx_str_t *res); | |
362 static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn); | 226 static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn); |
363 static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, | 227 static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, |
364 enum ssl_encryption_level_t level, uint8_t alert); | 228 enum ssl_encryption_level_t level, uint8_t alert); |
365 | 229 |
366 static ngx_int_t ngx_quic_process_long_header(ngx_connection_t *c, | 230 static ngx_int_t ngx_quic_process_long_header(ngx_connection_t *c, |
369 ngx_quic_header_t *pkt); | 233 ngx_quic_header_t *pkt); |
370 static ngx_int_t ngx_quic_process_initial_header(ngx_connection_t *c, | 234 static ngx_int_t ngx_quic_process_initial_header(ngx_connection_t *c, |
371 ngx_quic_header_t *pkt); | 235 ngx_quic_header_t *pkt); |
372 static ngx_int_t ngx_quic_process_handshake_header(ngx_connection_t *c, | 236 static ngx_int_t ngx_quic_process_handshake_header(ngx_connection_t *c, |
373 ngx_quic_header_t *pkt); | 237 ngx_quic_header_t *pkt); |
374 static ngx_int_t ngx_quic_initial_secret(ngx_connection_t *c); | 238 |
375 static ngx_int_t ngx_quic_decrypt(ngx_connection_t *c, ngx_quic_header_t *pkt); | |
376 | |
377 static uint64_t ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask); | |
378 static uint64_t ngx_quic_parse_int(u_char **pos); | 239 static uint64_t ngx_quic_parse_int(u_char **pos); |
379 static void ngx_quic_build_int(u_char **pos, uint64_t value); | |
380 | |
381 static ngx_int_t ngx_hkdf_extract(u_char *out_key, size_t *out_len, | |
382 const EVP_MD *digest, const u_char *secret, size_t secret_len, | |
383 const u_char *salt, size_t salt_len); | |
384 static ngx_int_t ngx_hkdf_expand(u_char *out_key, size_t out_len, | |
385 const EVP_MD *digest, const u_char *prk, size_t prk_len, | |
386 const u_char *info, size_t info_len); | |
387 | |
388 static ngx_int_t ngx_quic_hkdf_expand(ngx_connection_t *c, const EVP_MD *digest, | |
389 ngx_str_t *out, ngx_str_t *label, const uint8_t *prk, size_t prk_len); | |
390 | |
391 static ngx_int_t ngx_quic_tls_open(ngx_connection_t *c, | |
392 const ngx_quic_cipher_t *cipher, ngx_quic_secret_t *s, ngx_str_t *out, | |
393 u_char *nonce, ngx_str_t *in, ngx_str_t *ad); | |
394 static ngx_int_t ngx_quic_tls_seal(ngx_connection_t *c, | |
395 const ngx_quic_cipher_t *cipher, ngx_quic_secret_t *s, ngx_str_t *out, | |
396 u_char *nonce, ngx_str_t *in, ngx_str_t *ad); | |
397 | |
398 static ngx_int_t ngx_quic_tls_hp(ngx_connection_t *c, const EVP_CIPHER *cipher, | |
399 ngx_quic_secret_t *s, u_char *out, u_char *in); | |
400 | |
401 static ngx_int_t ngx_quic_ciphers(ngx_connection_t *c, | |
402 ngx_quic_ciphers_t *ciphers, enum ssl_encryption_level_t level); | |
403 | 240 |
404 static ssize_t ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf, | 241 static ssize_t ngx_quic_stream_recv(ngx_connection_t *c, u_char *buf, |
405 size_t size); | 242 size_t size); |
406 static ssize_t ngx_quic_stream_send(ngx_connection_t *c, u_char *buf, | 243 static ssize_t ngx_quic_stream_send(ngx_connection_t *c, u_char *buf, |
407 size_t size); | 244 size_t size); |
503 return; | 340 return; |
504 } | 341 } |
505 | 342 |
506 b.last += n; | 343 b.last += n; |
507 | 344 |
508 if (ngx_quic_input(c, NULL, &b) != NGX_OK) { | 345 if (ngx_quic_input(c, &b) != NGX_OK) { |
509 ngx_quic_close_connection(c); | 346 ngx_quic_close_connection(c); |
510 return; | 347 return; |
511 } | 348 } |
512 } | 349 } |
513 | 350 |
546 /* XXX */ | 383 /* XXX */ |
547 return NULL; | 384 return NULL; |
548 } | 385 } |
549 | 386 |
550 | 387 |
551 ngx_int_t | 388 static ngx_int_t |
552 ngx_quic_input(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b) | 389 ngx_quic_input(ngx_connection_t *c, ngx_buf_t *b) |
553 { | 390 { |
554 u_char *p; | 391 u_char *p; |
555 ngx_quic_header_t pkt; | 392 ngx_quic_header_t pkt; |
556 | 393 |
557 if (c->quic == NULL) { | 394 if (c->quic == NULL) { |
600 | 437 |
601 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); | 438 ngx_memzero(&pkt, sizeof(ngx_quic_header_t)); |
602 ngx_quic_hexdump0(c->log, "payload", payload->data, payload->len); | 439 ngx_quic_hexdump0(c->log, "payload", payload->data, payload->len); |
603 | 440 |
604 pkt.level = level; | 441 pkt.level = level; |
442 pkt.dcid = qc->dcid; | |
443 pkt.scid = qc->scid; | |
605 | 444 |
606 if (level == ssl_encryption_initial) { | 445 if (level == ssl_encryption_initial) { |
607 pkt.number = &qc->initial_pn; | 446 pkt.number = &qc->initial_pn; |
608 pkt.flags = NGX_QUIC_PKT_INITIAL; | 447 pkt.flags = NGX_QUIC_PKT_INITIAL; |
609 pkt.secret = &qc->server_in; | 448 pkt.secret = &qc->secrets.server.in; |
610 pkt.token = initial_token; | 449 pkt.token = initial_token; |
611 | |
612 if (ngx_quic_create_long_packet(c, c->ssl->connection, | |
613 &pkt, payload, &res) | |
614 != NGX_OK) | |
615 { | |
616 return NGX_ERROR; | |
617 } | |
618 | 450 |
619 } else if (level == ssl_encryption_handshake) { | 451 } else if (level == ssl_encryption_handshake) { |
620 pkt.number = &qc->handshake_pn; | 452 pkt.number = &qc->handshake_pn; |
621 pkt.flags = NGX_QUIC_PKT_HANDSHAKE; | 453 pkt.flags = NGX_QUIC_PKT_HANDSHAKE; |
622 pkt.secret = &qc->server_hs; | 454 pkt.secret = &qc->secrets.server.hs; |
623 | |
624 if (ngx_quic_create_long_packet(c, c->ssl->connection, | |
625 &pkt, payload, &res) | |
626 != NGX_OK) | |
627 { | |
628 return NGX_ERROR; | |
629 } | |
630 | 455 |
631 } else { | 456 } else { |
632 pkt.number = &qc->appdata_pn; | 457 pkt.number = &qc->appdata_pn; |
633 pkt.secret = &qc->server_ad; | 458 pkt.secret = &qc->secrets.server.ad; |
634 | 459 } |
635 if (ngx_quic_create_short_packet(c, c->ssl->connection, | 460 |
636 &pkt, payload, &res) | 461 if (ngx_quic_encrypt(c->pool, c->ssl->connection, &pkt, payload, &res) |
637 != NGX_OK) | 462 != NGX_OK) |
638 { | 463 { |
639 return NGX_ERROR; | 464 return NGX_ERROR; |
640 } | |
641 } | 465 } |
642 | 466 |
643 ngx_quic_hexdump0(c->log, "packet to send", res.data, res.len); | 467 ngx_quic_hexdump0(c->log, "packet to send", res.data, res.len); |
644 | 468 |
645 c->send(c, res.data, res.len); // TODO: err handling | 469 c->send(c, res.data, res.len); // TODO: err handling |
470 | |
471 (*pkt.number)++; | |
646 | 472 |
647 return NGX_OK; | 473 return NGX_OK; |
648 } | 474 } |
649 | 475 |
650 | 476 |
838 | 664 |
839 return NGX_OK; | 665 return NGX_OK; |
840 } | 666 } |
841 | 667 |
842 | 668 |
843 ngx_int_t | 669 static ngx_int_t |
844 ngx_quic_output(ngx_connection_t *c) | 670 ngx_quic_output(ngx_connection_t *c) |
845 { | 671 { |
846 size_t len; | 672 size_t len; |
847 ngx_uint_t lvl; | 673 ngx_uint_t lvl; |
848 ngx_quic_frame_t *f, *start; | 674 ngx_quic_frame_t *f, *start; |
892 #if BORINGSSL_API_VERSION >= 10 | 718 #if BORINGSSL_API_VERSION >= 10 |
893 | 719 |
894 static int | 720 static int |
895 ngx_quic_set_read_secret(ngx_ssl_conn_t *ssl_conn, | 721 ngx_quic_set_read_secret(ngx_ssl_conn_t *ssl_conn, |
896 enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, | 722 enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, |
897 const uint8_t *secret, size_t secret_len) | 723 const uint8_t *rsecret, size_t secret_len) |
898 { | 724 { |
899 ngx_int_t key_len; | 725 ngx_connection_t *c; |
900 ngx_uint_t i; | |
901 ngx_connection_t *c; | |
902 ngx_quic_secret_t *client; | |
903 ngx_quic_ciphers_t ciphers; | |
904 | 726 |
905 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | 727 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); |
906 | 728 |
907 ngx_quic_hexdump(c->log, "level:%d read", secret, secret_len, level); | 729 ngx_quic_hexdump(c->log, "level:%d read secret", |
908 | 730 rsecret, secret_len, level); |
909 key_len = ngx_quic_ciphers(c, &ciphers, level); | 731 |
910 | 732 return ngx_quic_set_encryption_secret(c->pool, ssl_conn, level, |
911 if (key_len == NGX_ERROR) { | 733 rsecret, secret_len, |
912 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "unexpected cipher"); | 734 &c->quic->secrets.client); |
913 return 0; | |
914 } | |
915 | |
916 switch (level) { | |
917 | |
918 case ssl_encryption_handshake: | |
919 client = &c->quic->client_hs; | |
920 break; | |
921 | |
922 case ssl_encryption_application: | |
923 client = &c->quic->client_ad; | |
924 break; | |
925 | |
926 default: | |
927 return 0; | |
928 } | |
929 | |
930 client->key.len = key_len; | |
931 client->iv.len = NGX_QUIC_IV_LEN; | |
932 client->hp.len = key_len; | |
933 | |
934 struct { | |
935 ngx_str_t label; | |
936 ngx_str_t *key; | |
937 const uint8_t *secret; | |
938 } seq[] = { | |
939 { ngx_string("tls13 quic key"), &client->key, secret }, | |
940 { ngx_string("tls13 quic iv"), &client->iv, secret }, | |
941 { ngx_string("tls13 quic hp"), &client->hp, secret }, | |
942 }; | |
943 | |
944 for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { | |
945 | |
946 if (ngx_quic_hkdf_expand(c, ciphers.d, seq[i].key, &seq[i].label, | |
947 seq[i].secret, secret_len) | |
948 != NGX_OK) | |
949 { | |
950 return 0; | |
951 } | |
952 } | |
953 | |
954 return 1; | |
955 } | 735 } |
956 | 736 |
957 | 737 |
958 static int | 738 static int |
959 ngx_quic_set_write_secret(ngx_ssl_conn_t *ssl_conn, | 739 ngx_quic_set_write_secret(ngx_ssl_conn_t *ssl_conn, |
960 enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, | 740 enum ssl_encryption_level_t level, const SSL_CIPHER *cipher, |
961 const uint8_t *secret, size_t secret_len) | 741 const uint8_t *wsecret, size_t secret_len) |
962 { | 742 { |
963 ngx_int_t key_len; | 743 ngx_connection_t *c; |
964 ngx_uint_t i; | |
965 ngx_connection_t *c; | |
966 ngx_quic_secret_t *server; | |
967 ngx_quic_ciphers_t ciphers; | |
968 | 744 |
969 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | 745 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); |
970 | 746 |
971 ngx_quic_hexdump(c->log, "level:%d write", secret, secret_len, level); | 747 ngx_quic_hexdump(c->log, "level:%d write secret", |
972 | 748 wsecret, secret_len, level); |
973 key_len = ngx_quic_ciphers(c, &ciphers, level); | 749 |
974 | 750 return ngx_quic_set_encryption_secret(c->pool, ssl_conn, level, |
975 if (key_len == NGX_ERROR) { | 751 wsecret, secret_len, |
976 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "unexpected cipher"); | 752 &c->quic->secrets.server); |
977 return 0; | |
978 } | |
979 | |
980 switch (level) { | |
981 | |
982 case ssl_encryption_handshake: | |
983 server = &c->quic->server_hs; | |
984 break; | |
985 | |
986 case ssl_encryption_application: | |
987 server = &c->quic->server_ad; | |
988 break; | |
989 | |
990 default: | |
991 return 0; | |
992 } | |
993 | |
994 server->key.len = key_len; | |
995 server->iv.len = NGX_QUIC_IV_LEN; | |
996 server->hp.len = key_len; | |
997 | |
998 struct { | |
999 ngx_str_t label; | |
1000 ngx_str_t *key; | |
1001 const uint8_t *secret; | |
1002 } seq[] = { | |
1003 { ngx_string("tls13 quic key"), &server->key, secret }, | |
1004 { ngx_string("tls13 quic iv"), &server->iv, secret }, | |
1005 { ngx_string("tls13 quic hp"), &server->hp, secret }, | |
1006 }; | |
1007 | |
1008 for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { | |
1009 | |
1010 if (ngx_quic_hkdf_expand(c, ciphers.d, seq[i].key, &seq[i].label, | |
1011 seq[i].secret, secret_len) | |
1012 != NGX_OK) | |
1013 { | |
1014 return 0; | |
1015 } | |
1016 } | |
1017 | |
1018 return 1; | |
1019 } | 753 } |
1020 | 754 |
1021 #else | 755 #else |
1022 | 756 |
1023 static int | 757 static int |
1024 ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn, | 758 ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn, |
1025 enum ssl_encryption_level_t level, const uint8_t *read_secret, | 759 enum ssl_encryption_level_t level, const uint8_t *rsecret, |
1026 const uint8_t *write_secret, size_t secret_len) | 760 const uint8_t *wsecret, size_t secret_len) |
1027 { | 761 { |
1028 ngx_int_t key_len; | 762 ngx_int_t rc; |
1029 ngx_uint_t i; | 763 ngx_connection_t *c; |
1030 ngx_connection_t *c; | |
1031 ngx_quic_secret_t *client, *server; | |
1032 ngx_quic_ciphers_t ciphers; | |
1033 | 764 |
1034 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); | 765 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); |
1035 | 766 |
1036 ngx_quic_hexdump(c->log, "level:%d read", read_secret, secret_len, level); | 767 ngx_quic_hexdump(c->log, "level:%d read", recret, secret_len, level); |
1037 ngx_quic_hexdump(c->log, "level:%d write", write_secret, secret_len, level); | 768 ngx_quic_hexdump(c->log, "level:%d write", wsecret, secret_len, level); |
1038 | 769 |
1039 key_len = ngx_quic_ciphers(c, &ciphers, level); | 770 rc = ngx_quic_set_encryption_secret(c->pool, ssl_conn, level, |
1040 | 771 rsecret, secret_len, |
1041 if (key_len == NGX_ERROR) { | 772 &c->quic->secrets.client); |
1042 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "unexpected cipher"); | 773 if (rc != 1) { |
1043 return 0; | 774 return rc; |
1044 } | 775 } |
1045 | 776 |
1046 switch (level) { | 777 return ngx_quic_set_encryption_secret(c->pool, ssl_conn, level, |
1047 | 778 wsecret, secret_len, |
1048 case ssl_encryption_handshake: | 779 &c->quic->secrets.server); |
1049 client = &c->quic->client_hs; | |
1050 server = &c->quic->server_hs; | |
1051 | |
1052 break; | |
1053 | |
1054 case ssl_encryption_application: | |
1055 client = &c->quic->client_ad; | |
1056 server = &c->quic->server_ad; | |
1057 | |
1058 break; | |
1059 | |
1060 default: | |
1061 return 0; | |
1062 } | |
1063 | |
1064 client->key.len = key_len; | |
1065 server->key.len = key_len; | |
1066 | |
1067 client->iv.len = NGX_QUIC_IV_LEN; | |
1068 server->iv.len = NGX_QUIC_IV_LEN; | |
1069 | |
1070 client->hp.len = key_len; | |
1071 server->hp.len = key_len; | |
1072 | |
1073 struct { | |
1074 ngx_str_t label; | |
1075 ngx_str_t *key; | |
1076 const uint8_t *secret; | |
1077 } seq[] = { | |
1078 { ngx_string("tls13 quic key"), &client->key, read_secret }, | |
1079 { ngx_string("tls13 quic iv"), &client->iv, read_secret }, | |
1080 { ngx_string("tls13 quic hp"), &client->hp, read_secret }, | |
1081 { ngx_string("tls13 quic key"), &server->key, write_secret }, | |
1082 { ngx_string("tls13 quic iv"), &server->iv, write_secret }, | |
1083 { ngx_string("tls13 quic hp"), &server->hp, write_secret }, | |
1084 }; | |
1085 | |
1086 for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { | |
1087 | |
1088 if (ngx_quic_hkdf_expand(c, ciphers.d, seq[i].key, &seq[i].label, | |
1089 seq[i].secret, secret_len) | |
1090 != NGX_OK) | |
1091 { | |
1092 return 0; | |
1093 } | |
1094 } | |
1095 | |
1096 return 1; | |
1097 } | 780 } |
1098 | 781 |
1099 #endif | 782 #endif |
1100 | |
1101 | |
1102 static ngx_int_t | |
1103 ngx_quic_create_long_packet(ngx_connection_t *c, ngx_ssl_conn_t *ssl_conn, | |
1104 ngx_quic_header_t *pkt, ngx_str_t *payload, ngx_str_t *res) | |
1105 { | |
1106 u_char *p, *pnp, *nonce, *sample, *packet; | |
1107 ngx_str_t ad, out; | |
1108 ngx_quic_ciphers_t ciphers; | |
1109 ngx_quic_connection_t *qc; | |
1110 u_char mask[16]; | |
1111 | |
1112 qc = c->quic; | |
1113 | |
1114 out.len = payload->len + EVP_GCM_TLS_TAG_LEN; | |
1115 | |
1116 ad.data = ngx_alloc(346 /*max header*/, c->log); | |
1117 if (ad.data == 0) { | |
1118 return NGX_ERROR; | |
1119 } | |
1120 | |
1121 p = ad.data; | |
1122 | |
1123 *p++ = pkt->flags; | |
1124 | |
1125 p = ngx_quic_write_uint32(p, quic_version); | |
1126 | |
1127 *p++ = qc->scid.len; | |
1128 p = ngx_cpymem(p, qc->scid.data, qc->scid.len); | |
1129 | |
1130 *p++ = qc->dcid.len; | |
1131 p = ngx_cpymem(p, qc->dcid.data, qc->dcid.len); | |
1132 | |
1133 if (pkt->level == ssl_encryption_initial) { | |
1134 ngx_quic_build_int(&p, pkt->token.len); | |
1135 } | |
1136 | |
1137 ngx_quic_build_int(&p, out.len + 1); // length (inc. pnl) | |
1138 pnp = p; | |
1139 | |
1140 *p++ = (*pkt->number)++; | |
1141 | |
1142 ad.len = p - ad.data; | |
1143 | |
1144 ngx_quic_hexdump0(c->log, "ad", ad.data, ad.len); | |
1145 | |
1146 if (ngx_quic_ciphers(c, &ciphers, pkt->level) == NGX_ERROR) { | |
1147 return NGX_ERROR; | |
1148 } | |
1149 | |
1150 nonce = ngx_pstrdup(c->pool, &pkt->secret->iv); | |
1151 if (pkt->level == ssl_encryption_handshake) { | |
1152 nonce[11] ^= (*pkt->number - 1); | |
1153 } | |
1154 | |
1155 ngx_quic_hexdump0(c->log, "server_iv", pkt->secret->iv.data, 12); | |
1156 ngx_quic_hexdump0(c->log, "nonce", nonce, 12); | |
1157 | |
1158 if (ngx_quic_tls_seal(c, ciphers.c, pkt->secret, &out, nonce, payload, &ad) | |
1159 != NGX_OK) | |
1160 { | |
1161 return NGX_ERROR; | |
1162 } | |
1163 | |
1164 sample = &out.data[3]; // pnl=0 | |
1165 if (ngx_quic_tls_hp(c, ciphers.hp, pkt->secret, mask, sample) != NGX_OK) { | |
1166 return NGX_ERROR; | |
1167 } | |
1168 | |
1169 ngx_quic_hexdump0(c->log, "sample", sample, 16); | |
1170 ngx_quic_hexdump0(c->log, "mask", mask, 16); | |
1171 ngx_quic_hexdump0(c->log, "hp_key", pkt->secret->hp.data, 16); | |
1172 | |
1173 // header protection, pnl = 0 | |
1174 ad.data[0] ^= mask[0] & 0x0f; | |
1175 *pnp ^= mask[1]; | |
1176 | |
1177 packet = ngx_alloc(ad.len + out.len, c->log); | |
1178 if (packet == 0) { | |
1179 return NGX_ERROR; | |
1180 } | |
1181 | |
1182 p = ngx_cpymem(packet, ad.data, ad.len); | |
1183 p = ngx_cpymem(p, out.data, out.len); | |
1184 | |
1185 res->data = packet; | |
1186 res->len = p - packet; | |
1187 | |
1188 return NGX_OK; | |
1189 } | |
1190 | |
1191 | |
1192 static ngx_int_t | |
1193 ngx_quic_create_short_packet(ngx_connection_t *c, ngx_ssl_conn_t *ssl_conn, | |
1194 ngx_quic_header_t *pkt, ngx_str_t *payload, ngx_str_t *res) | |
1195 { | |
1196 u_char *p, *pnp, *nonce, *sample, *packet; | |
1197 ngx_str_t ad, out; | |
1198 ngx_quic_ciphers_t ciphers; | |
1199 ngx_quic_connection_t *qc; | |
1200 u_char mask[16]; | |
1201 | |
1202 qc = c->quic; | |
1203 | |
1204 out.len = payload->len + EVP_GCM_TLS_TAG_LEN; | |
1205 | |
1206 ad.data = ngx_alloc(25 /*max header*/, c->log); | |
1207 if (ad.data == 0) { | |
1208 return NGX_ERROR; | |
1209 } | |
1210 | |
1211 p = ad.data; | |
1212 | |
1213 *p++ = 0x40; | |
1214 | |
1215 p = ngx_cpymem(p, qc->scid.data, qc->scid.len); | |
1216 | |
1217 pnp = p; | |
1218 | |
1219 *p++ = (*pkt->number)++; | |
1220 | |
1221 ad.len = p - ad.data; | |
1222 | |
1223 ngx_quic_hexdump0(c->log, "ad", ad.data, ad.len); | |
1224 | |
1225 if (ngx_quic_ciphers(c, &ciphers, pkt->level) == NGX_ERROR) { | |
1226 return NGX_ERROR; | |
1227 } | |
1228 | |
1229 nonce = ngx_pstrdup(c->pool, &pkt->secret->iv); | |
1230 if (pkt->level == ssl_encryption_handshake | |
1231 || pkt->level == ssl_encryption_application) | |
1232 { | |
1233 nonce[11] ^= (*pkt->number - 1); | |
1234 } | |
1235 | |
1236 ngx_quic_hexdump0(c->log, "server_iv", pkt->secret->iv.data, 12); | |
1237 ngx_quic_hexdump0(c->log, "nonce", nonce, 12); | |
1238 | |
1239 if (ngx_quic_tls_seal(c, ciphers.c, pkt->secret, &out, nonce, payload, &ad) | |
1240 != NGX_OK) | |
1241 { | |
1242 return NGX_ERROR; | |
1243 } | |
1244 | |
1245 ngx_quic_hexdump0(c->log, "out", out.data, out.len); | |
1246 | |
1247 sample = &out.data[3]; // pnl=0 | |
1248 if (ngx_quic_tls_hp(c, ciphers.hp, pkt->secret, mask, sample) != NGX_OK) { | |
1249 return NGX_ERROR; | |
1250 } | |
1251 | |
1252 ngx_quic_hexdump0(c->log, "sample", sample, 16); | |
1253 ngx_quic_hexdump0(c->log, "mask", mask, 16); | |
1254 ngx_quic_hexdump0(c->log, "hp_key", pkt->secret->hp.data, 16); | |
1255 | |
1256 // header protection, pnl = 0 | |
1257 ad.data[0] ^= mask[0] & 0x1f; | |
1258 *pnp ^= mask[1]; | |
1259 | |
1260 packet = ngx_alloc(ad.len + out.len, c->log); | |
1261 if (packet == 0) { | |
1262 return NGX_ERROR; | |
1263 } | |
1264 | |
1265 p = ngx_cpymem(packet, ad.data, ad.len); | |
1266 p = ngx_cpymem(p, out.data, out.len); | |
1267 | |
1268 ngx_quic_hexdump0(c->log, "packet", packet, p - packet); | |
1269 | |
1270 res->data = packet; | |
1271 res->len = p - packet; | |
1272 | |
1273 return NGX_OK; | |
1274 } | |
1275 | 783 |
1276 | 784 |
1277 static void | 785 static void |
1278 ngx_quic_queue_frame(ngx_quic_connection_t *qc, ngx_quic_frame_t *frame) | 786 ngx_quic_queue_frame(ngx_quic_connection_t *qc, ngx_quic_frame_t *frame) |
1279 { | 787 { |
1498 | 1006 |
1499 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | 1007 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, |
1500 "quic packet length: %d", plen); | 1008 "quic packet length: %d", plen); |
1501 | 1009 |
1502 return NGX_OK; | 1010 return NGX_OK; |
1503 } | |
1504 | |
1505 | |
1506 static ngx_int_t | |
1507 ngx_quic_initial_secret(ngx_connection_t *c) | |
1508 { | |
1509 size_t is_len; | |
1510 uint8_t is[SHA256_DIGEST_LENGTH]; | |
1511 ngx_uint_t i; | |
1512 const EVP_MD *digest; | |
1513 const EVP_CIPHER *cipher; | |
1514 ngx_quic_connection_t *qc; | |
1515 | |
1516 static const uint8_t salt[20] = | |
1517 "\xc3\xee\xf7\x12\xc7\x2e\xbb\x5a\x11\xa7" | |
1518 "\xd2\x43\x2b\xb4\x63\x65\xbe\xf9\xf5\x02"; | |
1519 | |
1520 /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */ | |
1521 | |
1522 cipher = EVP_aes_128_gcm(); | |
1523 digest = EVP_sha256(); | |
1524 | |
1525 qc = c->quic; | |
1526 | |
1527 if (ngx_hkdf_extract(is, &is_len, digest, qc->dcid.data, qc->dcid.len, | |
1528 salt, sizeof(salt)) | |
1529 != NGX_OK) | |
1530 { | |
1531 return NGX_ERROR; | |
1532 } | |
1533 | |
1534 ngx_str_t iss = { | |
1535 .data = is, | |
1536 .len = is_len | |
1537 }; | |
1538 | |
1539 ngx_quic_hexdump0(c->log, "salt", salt, sizeof(salt)); | |
1540 ngx_quic_hexdump0(c->log, "initial secret", is, is_len); | |
1541 | |
1542 /* draft-ietf-quic-tls-23#section-5.2 */ | |
1543 qc->client_in.secret.len = SHA256_DIGEST_LENGTH; | |
1544 qc->server_in.secret.len = SHA256_DIGEST_LENGTH; | |
1545 | |
1546 qc->client_in.key.len = EVP_CIPHER_key_length(cipher); | |
1547 qc->server_in.key.len = EVP_CIPHER_key_length(cipher); | |
1548 | |
1549 qc->client_in.hp.len = EVP_CIPHER_key_length(cipher); | |
1550 qc->server_in.hp.len = EVP_CIPHER_key_length(cipher); | |
1551 | |
1552 qc->client_in.iv.len = EVP_CIPHER_iv_length(cipher); | |
1553 qc->server_in.iv.len = EVP_CIPHER_iv_length(cipher); | |
1554 | |
1555 struct { | |
1556 ngx_str_t label; | |
1557 ngx_str_t *key; | |
1558 ngx_str_t *prk; | |
1559 } seq[] = { | |
1560 | |
1561 /* draft-ietf-quic-tls-23#section-5.2 */ | |
1562 { ngx_string("tls13 client in"), &qc->client_in.secret, &iss }, | |
1563 { | |
1564 ngx_string("tls13 quic key"), | |
1565 &qc->client_in.key, | |
1566 &qc->client_in.secret, | |
1567 }, | |
1568 { | |
1569 ngx_string("tls13 quic iv"), | |
1570 &qc->client_in.iv, | |
1571 &qc->client_in.secret, | |
1572 }, | |
1573 { | |
1574 /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */ | |
1575 ngx_string("tls13 quic hp"), | |
1576 &qc->client_in.hp, | |
1577 &qc->client_in.secret, | |
1578 }, | |
1579 { ngx_string("tls13 server in"), &qc->server_in.secret, &iss }, | |
1580 { | |
1581 /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */ | |
1582 ngx_string("tls13 quic key"), | |
1583 &qc->server_in.key, | |
1584 &qc->server_in.secret, | |
1585 }, | |
1586 { | |
1587 ngx_string("tls13 quic iv"), | |
1588 &qc->server_in.iv, | |
1589 &qc->server_in.secret, | |
1590 }, | |
1591 { | |
1592 /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */ | |
1593 ngx_string("tls13 quic hp"), | |
1594 &qc->server_in.hp, | |
1595 &qc->server_in.secret, | |
1596 }, | |
1597 | |
1598 }; | |
1599 | |
1600 for (i = 0; i < (sizeof(seq) / sizeof(seq[0])); i++) { | |
1601 | |
1602 if (ngx_quic_hkdf_expand(c, digest, seq[i].key, &seq[i].label, | |
1603 seq[i].prk->data, seq[i].prk->len) | |
1604 != NGX_OK) | |
1605 { | |
1606 return NGX_ERROR; | |
1607 } | |
1608 } | |
1609 | |
1610 return NGX_OK; | |
1611 } | |
1612 | |
1613 | |
1614 static ngx_int_t | |
1615 ngx_quic_decrypt(ngx_connection_t *c, ngx_quic_header_t *pkt) | |
1616 { | |
1617 u_char clearflags, *p, *sample; | |
1618 uint8_t *nonce; | |
1619 uint64_t pn; | |
1620 ngx_int_t pnl, rc; | |
1621 ngx_str_t in, ad; | |
1622 ngx_quic_ciphers_t ciphers; | |
1623 uint8_t mask[16]; | |
1624 | |
1625 if (ngx_quic_ciphers(c, &ciphers, pkt->level) == NGX_ERROR) { | |
1626 return NGX_ERROR; | |
1627 } | |
1628 | |
1629 p = pkt->raw->pos; | |
1630 | |
1631 /* draft-ietf-quic-tls-23#section-5.4.2: | |
1632 * the Packet Number field is assumed to be 4 bytes long | |
1633 * draft-ietf-quic-tls-23#section-5.4.[34]: | |
1634 * AES-Based and ChaCha20-Based header protections sample 16 bytes | |
1635 */ | |
1636 | |
1637 sample = p + 4; | |
1638 | |
1639 ngx_quic_hexdump0(c->log, "sample", sample, 16); | |
1640 | |
1641 /* header protection */ | |
1642 | |
1643 if (ngx_quic_tls_hp(c, ciphers.hp, pkt->secret, mask, sample) != NGX_OK) { | |
1644 return NGX_ERROR; | |
1645 } | |
1646 | |
1647 if (pkt->flags & NGX_QUIC_PKT_LONG) { | |
1648 clearflags = pkt->flags ^ (mask[0] & 0x0f); | |
1649 | |
1650 } else { | |
1651 clearflags = pkt->flags ^ (mask[0] & 0x1f); | |
1652 } | |
1653 | |
1654 pnl = (clearflags & 0x03) + 1; | |
1655 pn = ngx_quic_parse_pn(&p, pnl, &mask[1]); | |
1656 | |
1657 pkt->pn = pn; | |
1658 | |
1659 ngx_quic_hexdump0(c->log, "mask", mask, 5); | |
1660 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1661 "quic clear flags: %xi", clearflags); | |
1662 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1663 "quic packet number: %uL, len: %xi", pn, pnl); | |
1664 | |
1665 /* packet protection */ | |
1666 | |
1667 in.data = p; | |
1668 | |
1669 if (pkt->flags & NGX_QUIC_PKT_LONG) { | |
1670 in.len = pkt->len - pnl; | |
1671 | |
1672 } else { | |
1673 in.len = pkt->data + pkt->len - p; | |
1674 } | |
1675 | |
1676 ad.len = p - pkt->data; | |
1677 ad.data = ngx_pnalloc(c->pool, ad.len); | |
1678 if (ad.data == NULL) { | |
1679 return NGX_ERROR; | |
1680 } | |
1681 | |
1682 ngx_memcpy(ad.data, pkt->data, ad.len); | |
1683 ad.data[0] = clearflags; | |
1684 | |
1685 do { | |
1686 ad.data[ad.len - pnl] = pn >> (8 * (pnl - 1)) % 256; | |
1687 } while (--pnl); | |
1688 | |
1689 nonce = ngx_pstrdup(c->pool, &pkt->secret->iv); | |
1690 nonce[11] ^= pn; | |
1691 | |
1692 ngx_quic_hexdump0(c->log, "nonce", nonce, 12); | |
1693 ngx_quic_hexdump0(c->log, "ad", ad.data, ad.len); | |
1694 | |
1695 rc = ngx_quic_tls_open(c, ciphers.c, pkt->secret, &pkt->payload, | |
1696 nonce, &in, &ad); | |
1697 | |
1698 ngx_quic_hexdump0(c->log, "packet payload", | |
1699 pkt->payload.data, pkt->payload.len); | |
1700 | |
1701 return rc; | |
1702 } | 1011 } |
1703 | 1012 |
1704 | 1013 |
1705 ssize_t | 1014 ssize_t |
1706 ngx_quic_read_frame(ngx_connection_t *c, u_char *start, u_char *end, | 1015 ngx_quic_read_frame(ngx_connection_t *c, u_char *start, u_char *end, |
1889 } | 1198 } |
1890 | 1199 |
1891 | 1200 |
1892 | 1201 |
1893 static ngx_int_t | 1202 static ngx_int_t |
1894 ngx_quic_init_connection(ngx_connection_t *c, ngx_quic_header_t *pkt) | 1203 ngx_quic_init_connection(ngx_connection_t *c) |
1895 { | 1204 { |
1896 int n, sslerr; | 1205 int n, sslerr; |
1897 ngx_ssl_conn_t *ssl_conn; | 1206 ngx_ssl_conn_t *ssl_conn; |
1898 ngx_quic_connection_t *qc; | 1207 ngx_quic_connection_t *qc; |
1899 | 1208 |
2442 return NGX_ERROR; | 1751 return NGX_ERROR; |
2443 } | 1752 } |
2444 ngx_memcpy(qc->token.data, pkt->token.data, qc->token.len); | 1753 ngx_memcpy(qc->token.data, pkt->token.data, qc->token.len); |
2445 | 1754 |
2446 | 1755 |
2447 if (ngx_quic_initial_secret(c) != NGX_OK) { | 1756 if (ngx_quic_set_initial_secret(c->pool, &qc->secrets, &qc->dcid) |
2448 return NGX_ERROR; | 1757 != NGX_OK) |
2449 } | 1758 { |
2450 | 1759 return NGX_ERROR; |
2451 pkt->secret = &qc->client_in; | 1760 } |
1761 | |
1762 pkt->secret = &qc->secrets.client.in; | |
2452 pkt->level = ssl_encryption_initial; | 1763 pkt->level = ssl_encryption_initial; |
2453 | 1764 |
2454 if (ngx_quic_decrypt(c, pkt) != NGX_OK) { | 1765 if (ngx_quic_decrypt(c->pool, NULL, pkt) != NGX_OK) { |
2455 return NGX_ERROR; | 1766 return NGX_ERROR; |
2456 } | 1767 } |
2457 | 1768 |
2458 if (ngx_quic_init_connection(c, pkt) != NGX_OK) { | 1769 if (ngx_quic_init_connection(c) != NGX_OK) { |
2459 return NGX_ERROR; | 1770 return NGX_ERROR; |
2460 } | 1771 } |
2461 | 1772 |
2462 return ngx_quic_payload_handler(c, pkt); | 1773 return ngx_quic_payload_handler(c, pkt); |
2463 } | 1774 } |
2505 | 1816 |
2506 if (ngx_quic_process_handshake_header(c, pkt) != NGX_OK) { | 1817 if (ngx_quic_process_handshake_header(c, pkt) != NGX_OK) { |
2507 return NGX_ERROR; | 1818 return NGX_ERROR; |
2508 } | 1819 } |
2509 | 1820 |
2510 pkt->secret = &qc->client_hs; | 1821 pkt->secret = &qc->secrets.client.hs; |
2511 pkt->level = ssl_encryption_handshake; | 1822 pkt->level = ssl_encryption_handshake; |
2512 | 1823 |
2513 if (ngx_quic_decrypt(c, pkt) != NGX_OK) { | 1824 if (ngx_quic_decrypt(c->pool, c->ssl->connection, pkt) != NGX_OK) { |
2514 return NGX_ERROR; | 1825 return NGX_ERROR; |
2515 } | 1826 } |
2516 | 1827 |
2517 return ngx_quic_payload_handler(c, pkt); | 1828 return ngx_quic_payload_handler(c, pkt); |
2518 } | 1829 } |
2529 | 1840 |
2530 if (ngx_quic_process_short_header(c, pkt) != NGX_OK) { | 1841 if (ngx_quic_process_short_header(c, pkt) != NGX_OK) { |
2531 return NGX_ERROR; | 1842 return NGX_ERROR; |
2532 } | 1843 } |
2533 | 1844 |
2534 pkt->secret = &qc->client_ad; | 1845 pkt->secret = &qc->secrets.client.ad; |
2535 pkt->level = ssl_encryption_application; | 1846 pkt->level = ssl_encryption_application; |
2536 | 1847 |
2537 if (ngx_quic_decrypt(c, pkt) != NGX_OK) { | 1848 if (ngx_quic_decrypt(c->pool, c->ssl->connection, pkt) != NGX_OK) { |
2538 return NGX_ERROR; | 1849 return NGX_ERROR; |
2539 } | 1850 } |
2540 | 1851 |
2541 return ngx_quic_payload_handler(c, pkt); | 1852 return ngx_quic_payload_handler(c, pkt); |
2542 } | 1853 } |
2589 | 1900 |
2590 *pos = p; | 1901 *pos = p; |
2591 // return len2; | 1902 // return len2; |
2592 } | 1903 } |
2593 | 1904 |
2594 | |
2595 static uint64_t | |
2596 ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask) | |
2597 { | |
2598 u_char *p; | |
2599 uint64_t value; | |
2600 | |
2601 p = *pos; | |
2602 value = *p++ ^ *mask++; | |
2603 | |
2604 while (--len) { | |
2605 value = (value << 8) + (*p++ ^ *mask++); | |
2606 } | |
2607 | |
2608 *pos = p; | |
2609 return value; | |
2610 } | |
2611 | |
2612 | |
2613 static ngx_int_t | |
2614 ngx_hkdf_extract(u_char *out_key, size_t *out_len, const EVP_MD *digest, | |
2615 const u_char *secret, size_t secret_len, const u_char *salt, | |
2616 size_t salt_len) | |
2617 { | |
2618 #ifdef OPENSSL_IS_BORINGSSL | |
2619 if (HKDF_extract(out_key, out_len, digest, secret, secret_len, salt, | |
2620 salt_len) | |
2621 == 0) | |
2622 { | |
2623 return NGX_ERROR; | |
2624 } | |
2625 #else | |
2626 | |
2627 EVP_PKEY_CTX *pctx; | |
2628 | |
2629 pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); | |
2630 | |
2631 if (EVP_PKEY_derive_init(pctx) <= 0) { | |
2632 return NGX_ERROR; | |
2633 } | |
2634 | |
2635 if (EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXTRACT_ONLY) <= 0) { | |
2636 return NGX_ERROR; | |
2637 } | |
2638 | |
2639 if (EVP_PKEY_CTX_set_hkdf_md(pctx, digest) <= 0) { | |
2640 return NGX_ERROR; | |
2641 } | |
2642 | |
2643 if (EVP_PKEY_CTX_set1_hkdf_key(pctx, secret, secret_len) <= 0) { | |
2644 return NGX_ERROR; | |
2645 } | |
2646 | |
2647 if (EVP_PKEY_CTX_set1_hkdf_salt(pctx, salt, salt_len) <= 0) { | |
2648 return NGX_ERROR; | |
2649 } | |
2650 | |
2651 if (EVP_PKEY_derive(pctx, out_key, out_len) <= 0) { | |
2652 return NGX_ERROR; | |
2653 } | |
2654 | |
2655 #endif | |
2656 | |
2657 return NGX_OK; | |
2658 } | |
2659 | |
2660 | |
2661 static ngx_int_t | |
2662 ngx_quic_hkdf_expand(ngx_connection_t *c, const EVP_MD *digest, ngx_str_t *out, | |
2663 ngx_str_t *label, const uint8_t *prk, size_t prk_len) | |
2664 { | |
2665 uint8_t *p; | |
2666 size_t info_len; | |
2667 uint8_t info[20]; | |
2668 | |
2669 out->data = ngx_pnalloc(c->pool, out->len); | |
2670 if (out->data == NULL) { | |
2671 return NGX_ERROR; | |
2672 } | |
2673 | |
2674 info_len = 2 + 1 + label->len + 1; | |
2675 | |
2676 info[0] = 0; | |
2677 info[1] = out->len; | |
2678 info[2] = label->len; | |
2679 p = ngx_cpymem(&info[3], label->data, label->len); | |
2680 *p = '\0'; | |
2681 | |
2682 if (ngx_hkdf_expand(out->data, out->len, digest, | |
2683 prk, prk_len, info, info_len) | |
2684 != NGX_OK) | |
2685 { | |
2686 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, | |
2687 "ngx_hkdf_expand(%V) failed", label); | |
2688 return NGX_ERROR; | |
2689 } | |
2690 | |
2691 ngx_quic_hexdump(c->log, "%V info", info, info_len, label); | |
2692 ngx_quic_hexdump(c->log, "%V key", out->data, out->len, label); | |
2693 | |
2694 return NGX_OK; | |
2695 } | |
2696 | |
2697 | |
2698 static ngx_int_t | |
2699 ngx_hkdf_expand(u_char *out_key, size_t out_len, const EVP_MD *digest, | |
2700 const uint8_t *prk, size_t prk_len, const u_char *info, size_t info_len) | |
2701 { | |
2702 #ifdef OPENSSL_IS_BORINGSSL | |
2703 if (HKDF_expand(out_key, out_len, digest, prk, prk_len, info, info_len) | |
2704 == 0) | |
2705 { | |
2706 return NGX_ERROR; | |
2707 } | |
2708 #else | |
2709 | |
2710 EVP_PKEY_CTX *pctx; | |
2711 | |
2712 pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_HKDF, NULL); | |
2713 | |
2714 if (EVP_PKEY_derive_init(pctx) <= 0) { | |
2715 return NGX_ERROR; | |
2716 } | |
2717 | |
2718 if (EVP_PKEY_CTX_hkdf_mode(pctx, EVP_PKEY_HKDEF_MODE_EXPAND_ONLY) <= 0) { | |
2719 return NGX_ERROR; | |
2720 } | |
2721 | |
2722 if (EVP_PKEY_CTX_set_hkdf_md(pctx, digest) <= 0) { | |
2723 return NGX_ERROR; | |
2724 } | |
2725 | |
2726 if (EVP_PKEY_CTX_set1_hkdf_key(pctx, prk, prk_len) <= 0) { | |
2727 return NGX_ERROR; | |
2728 } | |
2729 | |
2730 if (EVP_PKEY_CTX_add1_hkdf_info(pctx, info, info_len) <= 0) { | |
2731 return NGX_ERROR; | |
2732 } | |
2733 | |
2734 if (EVP_PKEY_derive(pctx, out_key, &out_len) <= 0) { | |
2735 return NGX_ERROR; | |
2736 } | |
2737 | |
2738 #endif | |
2739 | |
2740 return NGX_OK; | |
2741 } | |
2742 | |
2743 | |
2744 static ngx_int_t | |
2745 ngx_quic_tls_open(ngx_connection_t *c, const ngx_quic_cipher_t *cipher, | |
2746 ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce, ngx_str_t *in, | |
2747 ngx_str_t *ad) | |
2748 { | |
2749 out->len = in->len - EVP_GCM_TLS_TAG_LEN; | |
2750 out->data = ngx_pnalloc(c->pool, out->len); | |
2751 if (out->data == NULL) { | |
2752 return NGX_ERROR; | |
2753 } | |
2754 | |
2755 #ifdef OPENSSL_IS_BORINGSSL | |
2756 EVP_AEAD_CTX *ctx; | |
2757 | |
2758 ctx = EVP_AEAD_CTX_new(cipher, s->key.data, s->key.len, | |
2759 EVP_AEAD_DEFAULT_TAG_LENGTH); | |
2760 if (ctx == NULL) { | |
2761 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_AEAD_CTX_new() failed"); | |
2762 return NGX_ERROR; | |
2763 } | |
2764 | |
2765 if (EVP_AEAD_CTX_open(ctx, out->data, &out->len, out->len, nonce, s->iv.len, | |
2766 in->data, in->len, ad->data, ad->len) | |
2767 != 1) | |
2768 { | |
2769 EVP_AEAD_CTX_free(ctx); | |
2770 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_AEAD_CTX_open() failed"); | |
2771 return NGX_ERROR; | |
2772 } | |
2773 | |
2774 EVP_AEAD_CTX_free(ctx); | |
2775 #else | |
2776 int len; | |
2777 u_char *tag; | |
2778 EVP_CIPHER_CTX *ctx; | |
2779 | |
2780 ctx = EVP_CIPHER_CTX_new(); | |
2781 if (ctx == NULL) { | |
2782 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_CIPHER_CTX_new() failed"); | |
2783 return NGX_ERROR; | |
2784 } | |
2785 | |
2786 if (EVP_DecryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1) { | |
2787 EVP_CIPHER_CTX_free(ctx); | |
2788 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_DecryptInit_ex() failed"); | |
2789 return NGX_ERROR; | |
2790 } | |
2791 | |
2792 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, s->iv.len, NULL) | |
2793 == 0) | |
2794 { | |
2795 EVP_CIPHER_CTX_free(ctx); | |
2796 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, | |
2797 "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_IVLEN) failed"); | |
2798 return NGX_ERROR; | |
2799 } | |
2800 | |
2801 if (EVP_DecryptInit_ex(ctx, NULL, NULL, s->key.data, nonce) != 1) { | |
2802 EVP_CIPHER_CTX_free(ctx); | |
2803 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_DecryptInit_ex() failed"); | |
2804 return NGX_ERROR; | |
2805 } | |
2806 | |
2807 if (EVP_DecryptUpdate(ctx, NULL, &len, ad->data, ad->len) != 1) { | |
2808 EVP_CIPHER_CTX_free(ctx); | |
2809 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_DecryptUpdate() failed"); | |
2810 return NGX_ERROR; | |
2811 } | |
2812 | |
2813 if (EVP_DecryptUpdate(ctx, out->data, &len, in->data, | |
2814 in->len - EVP_GCM_TLS_TAG_LEN) | |
2815 != 1) | |
2816 { | |
2817 EVP_CIPHER_CTX_free(ctx); | |
2818 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_DecryptUpdate() failed"); | |
2819 return NGX_ERROR; | |
2820 } | |
2821 | |
2822 out->len = len; | |
2823 tag = in->data + in->len - EVP_GCM_TLS_TAG_LEN; | |
2824 | |
2825 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, EVP_GCM_TLS_TAG_LEN, tag) | |
2826 == 0) | |
2827 { | |
2828 EVP_CIPHER_CTX_free(ctx); | |
2829 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, | |
2830 "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_TAG) failed"); | |
2831 return NGX_ERROR; | |
2832 } | |
2833 | |
2834 if (EVP_DecryptFinal_ex(ctx, out->data + len, &len) <= 0) { | |
2835 EVP_CIPHER_CTX_free(ctx); | |
2836 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_DecryptFinal_ex failed"); | |
2837 return NGX_ERROR; | |
2838 } | |
2839 | |
2840 out->len += len; | |
2841 | |
2842 EVP_CIPHER_CTX_free(ctx); | |
2843 #endif | |
2844 | |
2845 return NGX_OK; | |
2846 } | |
2847 | |
2848 | |
2849 static ngx_int_t | |
2850 ngx_quic_tls_seal(ngx_connection_t *c, const ngx_quic_cipher_t *cipher, | |
2851 ngx_quic_secret_t *s, ngx_str_t *out, u_char *nonce, ngx_str_t *in, | |
2852 ngx_str_t *ad) | |
2853 { | |
2854 out->len = in->len + EVP_GCM_TLS_TAG_LEN; | |
2855 out->data = ngx_pnalloc(c->pool, out->len); | |
2856 if (out->data == NULL) { | |
2857 return NGX_ERROR; | |
2858 } | |
2859 | |
2860 #ifdef OPENSSL_IS_BORINGSSL | |
2861 EVP_AEAD_CTX *ctx; | |
2862 | |
2863 ctx = EVP_AEAD_CTX_new(cipher, s->key.data, s->key.len, | |
2864 EVP_AEAD_DEFAULT_TAG_LENGTH); | |
2865 if (ctx == NULL) { | |
2866 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_AEAD_CTX_new() failed"); | |
2867 return NGX_ERROR; | |
2868 } | |
2869 | |
2870 if (EVP_AEAD_CTX_seal(ctx, out->data, &out->len, out->len, nonce, s->iv.len, | |
2871 in->data, in->len, ad->data, ad->len) | |
2872 != 1) | |
2873 { | |
2874 EVP_AEAD_CTX_free(ctx); | |
2875 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_AEAD_CTX_seal() failed"); | |
2876 return NGX_ERROR; | |
2877 } | |
2878 | |
2879 EVP_AEAD_CTX_free(ctx); | |
2880 #else | |
2881 int len; | |
2882 EVP_CIPHER_CTX *ctx; | |
2883 | |
2884 ctx = EVP_CIPHER_CTX_new(); | |
2885 if (ctx == NULL) { | |
2886 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_CIPHER_CTX_new() failed"); | |
2887 return NGX_ERROR; | |
2888 } | |
2889 | |
2890 if (EVP_EncryptInit_ex(ctx, cipher, NULL, NULL, NULL) != 1) { | |
2891 EVP_CIPHER_CTX_free(ctx); | |
2892 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_EncryptInit_ex() failed"); | |
2893 return NGX_ERROR; | |
2894 } | |
2895 | |
2896 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, s->iv.len, NULL) | |
2897 == 0) | |
2898 { | |
2899 EVP_CIPHER_CTX_free(ctx); | |
2900 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, | |
2901 "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_SET_IVLEN) failed"); | |
2902 return NGX_ERROR; | |
2903 } | |
2904 | |
2905 if (EVP_EncryptInit_ex(ctx, NULL, NULL, s->key.data, nonce) != 1) { | |
2906 EVP_CIPHER_CTX_free(ctx); | |
2907 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_EncryptInit_ex() failed"); | |
2908 return NGX_ERROR; | |
2909 } | |
2910 | |
2911 if (EVP_EncryptUpdate(ctx, NULL, &len, ad->data, ad->len) != 1) { | |
2912 EVP_CIPHER_CTX_free(ctx); | |
2913 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_EncryptUpdate() failed"); | |
2914 return NGX_ERROR; | |
2915 } | |
2916 | |
2917 if (EVP_EncryptUpdate(ctx, out->data, &len, in->data, in->len) != 1) { | |
2918 EVP_CIPHER_CTX_free(ctx); | |
2919 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_EncryptUpdate() failed"); | |
2920 return NGX_ERROR; | |
2921 } | |
2922 | |
2923 out->len = len; | |
2924 | |
2925 if (EVP_EncryptFinal_ex(ctx, out->data + out->len, &len) <= 0) { | |
2926 EVP_CIPHER_CTX_free(ctx); | |
2927 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_EncryptFinal_ex failed"); | |
2928 return NGX_ERROR; | |
2929 } | |
2930 | |
2931 out->len += len; | |
2932 | |
2933 if (EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, EVP_GCM_TLS_TAG_LEN, | |
2934 out->data + in->len) | |
2935 == 0) | |
2936 { | |
2937 EVP_CIPHER_CTX_free(ctx); | |
2938 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, | |
2939 "EVP_CIPHER_CTX_ctrl(EVP_CTRL_GCM_GET_TAG) failed"); | |
2940 return NGX_ERROR; | |
2941 } | |
2942 | |
2943 EVP_CIPHER_CTX_free(ctx); | |
2944 | |
2945 out->len += EVP_GCM_TLS_TAG_LEN; | |
2946 #endif | |
2947 | |
2948 return NGX_OK; | |
2949 } | |
2950 | |
2951 | |
2952 static ngx_int_t | |
2953 ngx_quic_tls_hp(ngx_connection_t *c, const EVP_CIPHER *cipher, | |
2954 ngx_quic_secret_t *s, u_char *out, u_char *in) | |
2955 { | |
2956 int outlen; | |
2957 EVP_CIPHER_CTX *ctx; | |
2958 u_char zero[5] = {0}; | |
2959 | |
2960 #ifdef OPENSSL_IS_BORINGSSL | |
2961 uint32_t counter; | |
2962 | |
2963 ngx_memcpy(&counter, in, sizeof(uint32_t)); | |
2964 | |
2965 if (cipher == (const EVP_CIPHER *) EVP_aead_chacha20_poly1305()) { | |
2966 CRYPTO_chacha_20(out, zero, 5, s->hp.data, &in[4], counter); | |
2967 return NGX_OK; | |
2968 } | |
2969 #endif | |
2970 | |
2971 ctx = EVP_CIPHER_CTX_new(); | |
2972 if (ctx == NULL) { | |
2973 return NGX_ERROR; | |
2974 } | |
2975 | |
2976 if (EVP_EncryptInit_ex(ctx, cipher, NULL, s->hp.data, in) != 1) { | |
2977 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_EncryptInit_ex() failed"); | |
2978 goto failed; | |
2979 } | |
2980 | |
2981 if (!EVP_EncryptUpdate(ctx, out, &outlen, zero, 5)) { | |
2982 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_EncryptUpdate() failed"); | |
2983 goto failed; | |
2984 } | |
2985 | |
2986 if (!EVP_EncryptFinal_ex(ctx, out + 5, &outlen)) { | |
2987 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "EVP_EncryptFinal_Ex() failed"); | |
2988 goto failed; | |
2989 } | |
2990 | |
2991 EVP_CIPHER_CTX_free(ctx); | |
2992 | |
2993 return NGX_OK; | |
2994 | |
2995 failed: | |
2996 | |
2997 EVP_CIPHER_CTX_free(ctx); | |
2998 | |
2999 return NGX_ERROR; | |
3000 } | |
3001 | |
3002 | |
3003 static ngx_int_t | |
3004 ngx_quic_ciphers(ngx_connection_t *c, ngx_quic_ciphers_t *ciphers, | |
3005 enum ssl_encryption_level_t level) | |
3006 { | |
3007 ngx_int_t id, len; | |
3008 | |
3009 if (level == ssl_encryption_initial) { | |
3010 id = NGX_AES_128_GCM_SHA256; | |
3011 | |
3012 } else { | |
3013 id = SSL_CIPHER_get_id(SSL_get_current_cipher(c->ssl->connection)) | |
3014 & 0xffff; | |
3015 } | |
3016 | |
3017 switch (id) { | |
3018 | |
3019 case NGX_AES_128_GCM_SHA256: | |
3020 #ifdef OPENSSL_IS_BORINGSSL | |
3021 ciphers->c = EVP_aead_aes_128_gcm(); | |
3022 #else | |
3023 ciphers->c = EVP_aes_128_gcm(); | |
3024 #endif | |
3025 ciphers->hp = EVP_aes_128_ctr(); | |
3026 ciphers->d = EVP_sha256(); | |
3027 len = 16; | |
3028 break; | |
3029 | |
3030 case NGX_AES_256_GCM_SHA384: | |
3031 #ifdef OPENSSL_IS_BORINGSSL | |
3032 ciphers->c = EVP_aead_aes_256_gcm(); | |
3033 #else | |
3034 ciphers->c = EVP_aes_256_gcm(); | |
3035 #endif | |
3036 ciphers->hp = EVP_aes_256_ctr(); | |
3037 ciphers->d = EVP_sha384(); | |
3038 len = 32; | |
3039 break; | |
3040 | |
3041 case NGX_CHACHA20_POLY1305_SHA256: | |
3042 #ifdef OPENSSL_IS_BORINGSSL | |
3043 ciphers->c = EVP_aead_chacha20_poly1305(); | |
3044 #else | |
3045 ciphers->c = EVP_chacha20_poly1305(); | |
3046 #endif | |
3047 #ifdef OPENSSL_IS_BORINGSSL | |
3048 ciphers->hp = (const EVP_CIPHER *) EVP_aead_chacha20_poly1305(); | |
3049 #else | |
3050 ciphers->hp = EVP_chacha20(); | |
3051 #endif | |
3052 ciphers->d = EVP_sha256(); | |
3053 len = 32; | |
3054 break; | |
3055 | |
3056 default: | |
3057 return NGX_ERROR; | |
3058 } | |
3059 | |
3060 return len; | |
3061 } |