comparison src/http/ngx_http_request.c @ 8167:5d91389e0fd3 quic

Initial QUIC support in http.
author Sergey Kandaurov <pluknet@nginx.com>
date Fri, 28 Feb 2020 13:09:51 +0300
parents 7999d3fbb765
children b507592c15a7
comparison
equal deleted inserted replaced
8166:7999d3fbb765 8167:5d91389e0fd3
60 ngx_http_request_t *sr, u_char *buf, size_t len); 60 ngx_http_request_t *sr, u_char *buf, size_t len);
61 61
62 #if (NGX_HTTP_SSL) 62 #if (NGX_HTTP_SSL)
63 static void ngx_http_ssl_handshake(ngx_event_t *rev); 63 static void ngx_http_ssl_handshake(ngx_event_t *rev);
64 static void ngx_http_ssl_handshake_handler(ngx_connection_t *c); 64 static void ngx_http_ssl_handshake_handler(ngx_connection_t *c);
65
66 static void ngx_http_quic_handshake(ngx_event_t *rev);
65 #endif 67 #endif
66 68
67 69
68 static char *ngx_http_client_errors[] = { 70 static char *ngx_http_client_errors[] = {
69 71
326 328
327 if (c->shared) { 329 if (c->shared) {
328 rev->ready = 1; 330 rev->ready = 1;
329 } 331 }
330 332
333 #if (NGX_HTTP_SSL)
334 if (hc->addr_conf->http3) {
335 hc->quic = 1;
336 c->log->action = "QUIC handshaking";
337 rev->handler = ngx_http_quic_handshake;
338 }
339 #endif
340
331 #if (NGX_HTTP_V2) 341 #if (NGX_HTTP_V2)
332 if (hc->addr_conf->http2) { 342 if (hc->addr_conf->http2) {
333 rev->handler = ngx_http_v2_init; 343 rev->handler = ngx_http_v2_init;
334 } 344 }
335 #endif 345 #endif
644 return r; 654 return r;
645 } 655 }
646 656
647 657
648 #if (NGX_HTTP_SSL) 658 #if (NGX_HTTP_SSL)
659
660 static uint64_t
661 ngx_quic_parse_int(u_char **pos)
662 {
663 u_char *p;
664 uint64_t value;
665 ngx_uint_t len;
666
667 p = *pos;
668 len = 1 << ((*p & 0xc0) >> 6);
669 value = *p++ & 0x3f;
670
671 while (--len) {
672 value = (value << 8) + *p++;
673 }
674
675 *pos = p;
676 return value;
677 }
678
679
680 static uint64_t
681 ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask)
682 {
683 u_char *p;
684 uint64_t value;
685
686 p = *pos;
687 value = *p++ ^ *mask++;
688
689 while (--len) {
690 value = (value << 8) + (*p++ ^ *mask++);
691 }
692
693 *pos = p;
694 return value;
695 }
696
697
698 static void
699 ngx_http_quic_handshake(ngx_event_t *rev)
700 {
701 int n, sslerr;
702 #if (NGX_DEBUG)
703 u_char buf[512];
704 size_t m;
705 #endif
706 ngx_buf_t *b;
707 ngx_connection_t *c;
708 ngx_http_connection_t *hc;
709 ngx_quic_connection_t *qc;
710 ngx_http_ssl_srv_conf_t *sscf;
711
712 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "quic handshake");
713
714 c = rev->data;
715 hc = c->data;
716 b = c->buffer;
717
718 qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t));
719 if (qc == NULL) {
720 ngx_http_close_connection(c);
721 return;
722 }
723
724 c->quic = qc;
725
726 printf("buffer %p %p:%p:%p:%p \n", b, b->start, b->pos, b->last, b->end);
727
728 if ((b->pos[0] & 0xf0) != 0xc0) {
729 ngx_log_error(NGX_LOG_INFO, rev->log, 0, "invalid initial packet");
730 ngx_http_close_connection(c);
731 return;
732 }
733
734 if (ngx_buf_size(b) < 1200) {
735 ngx_log_error(NGX_LOG_INFO, rev->log, 0, "too small UDP datagram");
736 ngx_http_close_connection(c);
737 return;
738 }
739
740 ngx_int_t flags = *b->pos++;
741 uint32_t version = ngx_http_v2_parse_uint32(b->pos);
742 b->pos += 4;
743
744 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
745 "quic flags:%xi version:%xD", flags, version);
746
747 if (version != 0xff000017) {
748 ngx_log_error(NGX_LOG_INFO, rev->log, 0, "unsupported quic version");
749 ngx_http_close_connection(c);
750 return;
751 }
752
753 qc->dcid.len = *b->pos++;
754 qc->dcid.data = ngx_pnalloc(c->pool, qc->dcid.len);
755 if (qc->dcid.data == NULL) {
756 ngx_http_close_connection(c);
757 return;
758 }
759
760 ngx_memcpy(qc->dcid.data, b->pos, qc->dcid.len);
761 b->pos += qc->dcid.len;
762
763 qc->scid.len = *b->pos++;
764 qc->scid.data = ngx_pnalloc(c->pool, qc->scid.len);
765 if (qc->scid.data == NULL) {
766 ngx_http_close_connection(c);
767 return;
768 }
769
770 ngx_memcpy(qc->scid.data, b->pos, qc->scid.len);
771 b->pos += qc->scid.len;
772
773 qc->token.len = ngx_quic_parse_int(&b->pos);
774 qc->token.data = ngx_pnalloc(c->pool, qc->token.len);
775 if (qc->token.data == NULL) {
776 ngx_http_close_connection(c);
777 return;
778 }
779
780 ngx_memcpy(qc->token.data, b->pos, qc->token.len);
781 b->pos += qc->token.len;
782
783 uint64_t plen = ngx_quic_parse_int(&b->pos);
784 /* draft-ietf-quic-tls-23#section-5.4.2:
785 * the Packet Number field is assumed to be 4 bytes long
786 * draft-ietf-quic-tls-23#section-5.4.3:
787 * AES-Based header protection samples 16 bytes
788 */
789 u_char *sample = b->pos + 4;
790
791 #if (NGX_DEBUG)
792 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
793 m = ngx_hex_dump(buf, qc->dcid.data, qc->dcid.len) - buf;
794 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
795 "quic DCID: %*s, len: %uz", m, buf, qc->dcid.len);
796
797 m = ngx_hex_dump(buf, qc->scid.data, qc->scid.len) - buf;
798 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
799 "quic SCID: %*s, len: %uz", m, buf, qc->scid.len);
800
801 m = ngx_hex_dump(buf, qc->token.data, qc->token.len) - buf;
802 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
803 "quic token: %*s, len: %uz", m, buf, qc->token.len);
804
805 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, rev->log, 0,
806 "quic packet length: %d", plen);
807
808 m = ngx_hex_dump(buf, sample, 16) - buf;
809 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
810 "quic sample: %*s", m, buf);
811 }
812 #endif
813
814 // initial secret
815
816 size_t is_len;
817 uint8_t is[SHA256_DIGEST_LENGTH];
818 const EVP_MD *digest;
819 static const uint8_t salt[20] =
820 "\xc3\xee\xf7\x12\xc7\x2e\xbb\x5a\x11\xa7"
821 "\xd2\x43\x2b\xb4\x63\x65\xbe\xf9\xf5\x02";
822
823 digest = EVP_sha256();
824 HKDF_extract(is, &is_len, digest, qc->dcid.data, qc->dcid.len, salt,
825 sizeof(salt));
826
827 #if (NGX_DEBUG)
828 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
829 m = ngx_hex_dump(buf, (uint8_t *) salt, sizeof(salt)) - buf;
830 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
831 "quic salt: %*s, len: %uz", m, buf, sizeof(salt));
832
833 m = ngx_hex_dump(buf, is, is_len) - buf;
834 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
835 "quic initial secret: %*s, len: %uz", m, buf, is_len);
836 }
837 #endif
838
839 size_t hkdfl_len;
840 uint8_t hkdfl[20];
841 uint8_t *p;
842
843 /* draft-ietf-quic-tls-23#section-5.2 */
844
845 qc->client_in.len = SHA256_DIGEST_LENGTH;
846 qc->client_in.data = ngx_pnalloc(c->pool, qc->client_in.len);
847 if (qc->client_in.data == NULL) {
848 ngx_http_close_connection(c);
849 return;
850 }
851
852 hkdfl_len = 2 + 1 + sizeof("tls13 client in") - 1 + 1;
853 hkdfl[0] = 0;
854 hkdfl[1] = qc->client_in.len;
855 hkdfl[2] = sizeof("tls13 client in") - 1;
856 p = ngx_cpymem(&hkdfl[3], "tls13 client in",
857 sizeof("tls13 client in") - 1);
858 *p = '\0';
859
860 if (HKDF_expand(qc->client_in.data, qc->client_in.len,
861 digest, is, is_len, hkdfl, hkdfl_len)
862 == 0)
863 {
864 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
865 "HKDF_expand(client_in) failed");
866 ngx_http_close_connection(c);
867 return;
868 }
869
870 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
871 "quic EVP key:%d tag:%d nonce:%d",
872 EVP_AEAD_key_length(EVP_aead_aes_128_gcm()),
873 EVP_AEAD_max_tag_len(EVP_aead_aes_128_gcm()),
874 EVP_AEAD_nonce_length(EVP_aead_aes_128_gcm()));
875
876 /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.3 */
877
878 qc->client_in_key.len = EVP_AEAD_key_length(EVP_aead_aes_128_gcm());
879 qc->client_in_key.data = ngx_pnalloc(c->pool, qc->client_in_key.len);
880 if (qc->client_in_key.data == NULL) {
881 ngx_http_close_connection(c);
882 return;
883 }
884
885 hkdfl_len = 2 + 1 + sizeof("tls13 quic key") - 1 + 1;
886 hkdfl[1] = qc->client_in_key.len;
887 hkdfl[2] = sizeof("tls13 quic key") - 1;
888 p = ngx_cpymem(&hkdfl[3], "tls13 quic key",
889 sizeof("tls13 quic key") - 1);
890 *p = '\0';
891
892 if (HKDF_expand(qc->client_in_key.data, qc->client_in_key.len,
893 digest, qc->client_in.data, qc->client_in.len,
894 hkdfl, hkdfl_len)
895 == 0)
896 {
897 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
898 "HKDF_expand(client_in_key) failed");
899 ngx_http_close_connection(c);
900 return;
901 }
902
903 qc->client_in_iv.len = EVP_AEAD_nonce_length(EVP_aead_aes_128_gcm());
904 qc->client_in_iv.data = ngx_pnalloc(c->pool, qc->client_in_iv.len);
905 if (qc->client_in_iv.data == NULL) {
906 ngx_http_close_connection(c);
907 return;
908 }
909
910 hkdfl_len = 2 + 1 + sizeof("tls13 quic iv") - 1 + 1;
911 hkdfl[1] = qc->client_in_iv.len;
912 hkdfl[2] = sizeof("tls13 quic iv") - 1;
913 p = ngx_cpymem(&hkdfl[3], "tls13 quic iv", sizeof("tls13 quic iv") - 1);
914 *p = '\0';
915
916 if (HKDF_expand(qc->client_in_iv.data, qc->client_in_iv.len, digest,
917 qc->client_in.data, qc->client_in.len, hkdfl, hkdfl_len)
918 == 0)
919 {
920 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
921 "HKDF_expand(client_in_iv) failed");
922 ngx_http_close_connection(c);
923 return;
924 }
925
926 /* AEAD_AES_128_GCM prior to handshake, quic-tls-23#section-5.4.1 */
927
928 qc->client_in_hp.len = EVP_AEAD_key_length(EVP_aead_aes_128_gcm());
929 qc->client_in_hp.data = ngx_pnalloc(c->pool, qc->client_in_hp.len);
930 if (qc->client_in_hp.data == NULL) {
931 ngx_http_close_connection(c);
932 return;
933 }
934
935 hkdfl_len = 2 + 1 + sizeof("tls13 quic hp") - 1 + 1;
936 hkdfl[1] = qc->client_in_hp.len;
937 hkdfl[2] = sizeof("tls13 quic hp") - 1;
938 p = ngx_cpymem(&hkdfl[3], "tls13 quic hp", sizeof("tls13 quic hp") - 1);
939 *p = '\0';
940
941 if (HKDF_expand(qc->client_in_hp.data, qc->client_in_hp.len, digest,
942 qc->client_in.data, qc->client_in.len, hkdfl, hkdfl_len)
943 == 0)
944 {
945 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
946 "HKDF_expand(client_in_hp) failed");
947 ngx_http_close_connection(c);
948 return;
949 }
950
951 #if (NGX_DEBUG)
952 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
953 m = ngx_hex_dump(buf, qc->client_in.data, qc->client_in.len) - buf;
954 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
955 "quic client initial secret: %*s, len: %uz",
956 m, buf, qc->client_in.len);
957
958 m = ngx_hex_dump(buf, qc->client_in_key.data, qc->client_in_key.len)
959 - buf;
960 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
961 "quic key: %*s, len: %uz",
962 m, buf, qc->client_in_key.len);
963
964 m = ngx_hex_dump(buf, qc->client_in_iv.data, qc->client_in_iv.len)
965 - buf;
966 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
967 "quic iv: %*s, len: %uz", m, buf, qc->client_in_iv.len);
968
969 m = ngx_hex_dump(buf, qc->client_in_hp.data, qc->client_in_hp.len)
970 - buf;
971 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
972 "quic hp: %*s, len: %uz", m, buf, qc->client_in_hp.len);
973 }
974 #endif
975
976 // header protection
977
978 EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
979 uint8_t mask[16];
980 int outlen;
981
982 if (EVP_EncryptInit_ex(ctx, EVP_aes_128_ecb(), NULL,
983 qc->client_in_hp.data, NULL)
984 != 1)
985 {
986 EVP_CIPHER_CTX_free(ctx);
987 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
988 "EVP_EncryptInit_ex() failed");
989 ngx_http_close_connection(c);
990 return;
991 }
992
993 if (!EVP_EncryptUpdate(ctx, mask, &outlen, sample, 16)) {
994 EVP_CIPHER_CTX_free(ctx);
995 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
996 "EVP_EncryptUpdate() failed");
997 ngx_http_close_connection(c);
998 return;
999 }
1000
1001 EVP_CIPHER_CTX_free(ctx);
1002
1003 u_char clearflags = flags ^ (mask[0] & 0x0f);
1004 ngx_int_t pnl = (clearflags & 0x03) + 1;
1005 uint64_t pn = ngx_quic_parse_pn(&b->pos, pnl, &mask[1]);
1006
1007 #if (NGX_DEBUG)
1008 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
1009 m = ngx_hex_dump(buf, sample, 16) - buf;
1010 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1011 "quic sample: %*s", m, buf);
1012
1013 m = ngx_hex_dump(buf, mask, 5) - buf;
1014 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1015 "quic mask: %*s", m, buf);
1016
1017 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1018 "quic packet number: %uL, len: %xi", pn, pnl);
1019 }
1020 #endif
1021
1022 // packet protection
1023
1024 ngx_str_t ciphertext;
1025 ciphertext.data = b->pos;
1026 ciphertext.len = plen - pnl;
1027
1028 ngx_str_t ad;
1029 ad.len = b->pos - b->start;
1030 ad.data = ngx_pnalloc(c->pool, ad.len);
1031 if (ad.data == NULL) {
1032 ngx_http_close_connection(c);
1033 return;
1034 }
1035
1036 ngx_memcpy(ad.data, b->start, ad.len);
1037 ad.data[0] = clearflags;
1038 ad.data[ad.len - pnl] = (u_char)pn;
1039
1040 uint8_t *nonce = ngx_pstrdup(c->pool, &qc->client_in_iv);
1041 nonce[11] ^= pn;
1042
1043 #if (NGX_DEBUG)
1044 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
1045 m = ngx_hex_dump(buf, nonce, 12) - buf;
1046 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1047 "quic nonce: %*s, len: %uz", m, buf, 12);
1048
1049 m = ngx_hex_dump(buf, ad.data, ad.len) - buf;
1050 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1051 "quic ad: %*s, len: %uz", m, buf, ad.len);
1052 }
1053 #endif
1054
1055 EVP_AEAD_CTX *aead = EVP_AEAD_CTX_new(EVP_aead_aes_128_gcm(),
1056 qc->client_in_key.data,
1057 qc->client_in_key.len,
1058 EVP_AEAD_DEFAULT_TAG_LENGTH);
1059 uint8_t cleartext[1600];
1060 size_t cleartext_len = sizeof(cleartext);
1061
1062 if (EVP_AEAD_CTX_open(aead, cleartext, &cleartext_len, sizeof(cleartext),
1063 nonce, qc->client_in_iv.len, ciphertext.data,
1064 ciphertext.len, ad.data, ad.len)
1065 != 1)
1066 {
1067 EVP_AEAD_CTX_free(aead);
1068 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
1069 "EVP_AEAD_CTX_open() failed");
1070 ngx_http_close_connection(c);
1071 return;
1072 }
1073
1074 EVP_AEAD_CTX_free(aead);
1075
1076 #if (NGX_DEBUG)
1077 if (c->log->log_level & NGX_LOG_DEBUG_EVENT) {
1078 m = ngx_hex_dump(buf, cleartext, ngx_min(cleartext_len, 256)) - buf;
1079 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, rev->log, 0,
1080 "quic packet: %*s%s, len: %uz",
1081 m, buf, m < 512 ? "" : "...", cleartext_len);
1082 }
1083 #endif
1084
1085 sscf = ngx_http_get_module_srv_conf(hc->conf_ctx, ngx_http_ssl_module);
1086
1087 if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER)
1088 != NGX_OK)
1089 {
1090 ngx_http_close_connection(c);
1091 return;
1092 }
1093
1094 n = SSL_do_handshake(c->ssl->connection);
1095
1096 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n);
1097
1098 if (n == -1) {
1099 sslerr = SSL_get_error(c->ssl->connection, n);
1100
1101 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d",
1102 sslerr);
1103 }
1104
1105 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
1106 "SSL_quic_read_level: %d, SSL_quic_write_level: %d",
1107 (int) SSL_quic_read_level(c->ssl->connection),
1108 (int) SSL_quic_write_level(c->ssl->connection));
1109
1110 if (!SSL_provide_quic_data(c->ssl->connection,
1111 SSL_quic_read_level(c->ssl->connection),
1112 &cleartext[4], cleartext_len - 4))
1113 {
1114 ngx_ssl_error(NGX_LOG_INFO, rev->log, 0,
1115 "SSL_provide_quic_data() failed");
1116 ngx_http_close_connection(c);
1117 return;
1118 }
1119
1120 n = SSL_do_handshake(c->ssl->connection);
1121
1122 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n);
1123
1124 if (n == -1) {
1125 sslerr = SSL_get_error(c->ssl->connection, n);
1126
1127 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d",
1128 sslerr);
1129
1130 if (sslerr == SSL_ERROR_SSL) {
1131 ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "SSL_do_handshake() failed");
1132 }
1133 }
1134
1135 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
1136 "SSL_quic_read_level: %d, SSL_quic_write_level: %d",
1137 (int) SSL_quic_read_level(c->ssl->connection),
1138 (int) SSL_quic_write_level(c->ssl->connection));
1139
1140 ngx_http_close_connection(c);
1141 return;
1142 }
1143
649 1144
650 static void 1145 static void
651 ngx_http_ssl_handshake(ngx_event_t *rev) 1146 ngx_http_ssl_handshake(ngx_event_t *rev)
652 { 1147 {
653 u_char *p, buf[NGX_PROXY_PROTOCOL_MAX_HEADER + 1]; 1148 u_char *p, buf[NGX_PROXY_PROTOCOL_MAX_HEADER + 1];