Mercurial > hg > nginx-quic
comparison src/event/ngx_event_quic.c @ 7659:4355efde26d8 quic
Added functions to decrypt long packets.
author | Vladimir Homutov <vl@nginx.com> |
---|---|
date | Thu, 05 Mar 2020 17:18:33 +0300 |
parents | fb0879c65650 |
children | 817c82af127f |
comparison
equal
deleted
inserted
replaced
7658:fb0879c65650 | 7659:4355efde26d8 |
---|---|
183 typedef struct { | 183 typedef struct { |
184 ngx_quic_secret_t *secret; | 184 ngx_quic_secret_t *secret; |
185 ngx_uint_t type; | 185 ngx_uint_t type; |
186 ngx_uint_t *number; | 186 ngx_uint_t *number; |
187 ngx_uint_t flags; | 187 ngx_uint_t flags; |
188 ngx_uint_t version; | 188 uint32_t version; |
189 ngx_str_t *token; | 189 ngx_str_t token; |
190 ngx_quic_level_t level; | 190 ngx_quic_level_t level; |
191 | |
192 /* filled in by parser */ | |
193 ngx_str_t buf; /* quic packet from wire */ | |
194 u_char *pos; /* current parser position */ | |
195 | |
196 /* cleartext fields */ | |
197 ngx_str_t dcid; | |
198 ngx_str_t scid; | |
199 | |
200 uint64_t pn; | |
201 | |
202 ngx_str_t payload; /* decrypted payload */ | |
203 | |
191 } ngx_quic_header_t; | 204 } ngx_quic_header_t; |
192 | 205 |
193 | 206 |
194 static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, | 207 static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, |
195 ngx_buf_t *b); | 208 ngx_buf_t *b); |
208 ngx_str_t *res); | 221 ngx_str_t *res); |
209 static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn); | 222 static int ngx_quic_flush_flight(ngx_ssl_conn_t *ssl_conn); |
210 static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, | 223 static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, |
211 enum ssl_encryption_level_t level, uint8_t alert); | 224 enum ssl_encryption_level_t level, uint8_t alert); |
212 | 225 |
226 static ngx_int_t ngx_quic_process_long_header(ngx_connection_t *c, | |
227 ngx_quic_header_t *pkt); | |
228 static ngx_int_t ngx_quic_process_initial_header(ngx_connection_t *c, | |
229 ngx_quic_header_t *pkt); | |
230 static ngx_int_t ngx_quic_process_handshake_header(ngx_connection_t *c, | |
231 ngx_quic_header_t *pkt); | |
232 static ngx_int_t ngx_quic_initial_secret(ngx_connection_t *c); | |
233 static ngx_int_t ngx_quic_decrypt(ngx_connection_t *c, ngx_quic_header_t *pkt); | |
234 | |
213 static uint64_t ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask); | 235 static uint64_t ngx_quic_parse_pn(u_char **pos, ngx_int_t len, u_char *mask); |
214 static uint64_t ngx_quic_parse_int(u_char **pos); | 236 static uint64_t ngx_quic_parse_int(u_char **pos); |
215 static void ngx_quic_build_int(u_char **pos, uint64_t value); | 237 static void ngx_quic_build_int(u_char **pos, uint64_t value); |
216 | 238 |
217 static ngx_int_t ngx_hkdf_extract(u_char *out_key, size_t *out_len, | 239 static ngx_int_t ngx_hkdf_extract(u_char *out_key, size_t *out_len, |
285 | 307 |
286 if (level == ssl_encryption_initial) { | 308 if (level == ssl_encryption_initial) { |
287 pkt.number = &qc->initial_pn; | 309 pkt.number = &qc->initial_pn; |
288 pkt.flags = NGX_QUIC_PKT_INITIAL; | 310 pkt.flags = NGX_QUIC_PKT_INITIAL; |
289 pkt.secret = &qc->server_in; | 311 pkt.secret = &qc->server_in; |
290 pkt.token = &initial_token; | 312 pkt.token = initial_token; |
291 | 313 |
292 if (ngx_quic_create_long_packet(c, c->ssl->connection, | 314 if (ngx_quic_create_long_packet(c, c->ssl->connection, |
293 &pkt, payload, &res) | 315 &pkt, payload, &res) |
294 != NGX_OK) | 316 != NGX_OK) |
295 { | 317 { |
597 p = ngx_cpymem(p, qc->scid.data, qc->scid.len); | 619 p = ngx_cpymem(p, qc->scid.data, qc->scid.len); |
598 | 620 |
599 *p++ = qc->dcid.len; | 621 *p++ = qc->dcid.len; |
600 p = ngx_cpymem(p, qc->dcid.data, qc->dcid.len); | 622 p = ngx_cpymem(p, qc->dcid.data, qc->dcid.len); |
601 | 623 |
602 if (pkt->token) { // if pkt->flags & initial ? | 624 if (pkt->level == ssl_encryption_initial) { |
603 ngx_quic_build_int(&p, pkt->token->len); | 625 ngx_quic_build_int(&p, pkt->token.len); |
604 } | 626 } |
605 | 627 |
606 ngx_quic_build_int(&p, out.len + 1); // length (inc. pnl) | 628 ngx_quic_build_int(&p, out.len + 1); // length (inc. pnl) |
607 pnp = p; | 629 pnp = p; |
608 | 630 |
863 return 1; | 885 return 1; |
864 } | 886 } |
865 | 887 |
866 | 888 |
867 static ngx_int_t | 889 static ngx_int_t |
868 ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b) | 890 ngx_quic_process_long_header(ngx_connection_t *c, ngx_quic_header_t *pkt) |
869 { | 891 { |
870 int n, sslerr; | 892 u_char *p; |
871 ngx_quic_connection_t *qc; | 893 |
872 | 894 p = pkt->buf.data; |
873 if ((b->pos[0] & 0xf0) != NGX_QUIC_PKT_INITIAL) { | 895 |
874 ngx_log_error(NGX_LOG_INFO, c->log, 0, "invalid initial packet"); | 896 ngx_quic_hexdump0(c->log, "input", pkt->buf.data, pkt->buf.len); |
875 return NGX_ERROR; | 897 |
876 } | 898 if (!(p[0] & NGX_QUIC_PKT_LONG)) { |
877 | 899 ngx_log_error(NGX_LOG_INFO, c->log, 0, "not a long packet"); |
878 if (ngx_buf_size(b) < 1200) { | 900 return NGX_ERROR; |
879 ngx_log_error(NGX_LOG_INFO, c->log, 0, "too small UDP datagram"); | 901 } |
880 return NGX_ERROR; | 902 |
881 } | 903 pkt->flags = *p++; |
882 | 904 |
883 ngx_int_t flags = *b->pos++; | 905 pkt->version = ngx_quic_parse_uint32(p); |
884 uint32_t version = ngx_quic_parse_uint32(b->pos); | 906 p += sizeof(uint32_t); |
885 b->pos += sizeof(uint32_t); | |
886 | 907 |
887 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | 908 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, |
888 "quic flags:%xi version:%xD", flags, version); | 909 "quic flags:%xi version:%xD", pkt->flags, pkt->version); |
889 | 910 |
890 if (version != quic_version) { | 911 if (pkt->version != quic_version) { |
891 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unsupported quic version"); | 912 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unsupported quic version"); |
892 return NGX_ERROR; | 913 return NGX_ERROR; |
893 } | 914 } |
894 | 915 |
895 qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t)); | 916 pkt->dcid.len = *p++; |
896 if (qc == NULL) { | 917 pkt->dcid.data = p; |
897 return NGX_ERROR; | 918 p += pkt->dcid.len; |
898 } | 919 |
899 | 920 pkt->scid.len = *p++; |
900 c->quic = qc; | 921 pkt->scid.data = p; |
901 | 922 p += pkt->scid.len; |
902 qc->dcid.len = *b->pos++; | 923 |
903 qc->dcid.data = ngx_pnalloc(c->pool, qc->dcid.len); | 924 pkt->pos = p; |
904 if (qc->dcid.data == NULL) { | 925 |
905 return NGX_ERROR; | 926 return NGX_OK; |
906 } | 927 } |
907 | 928 |
908 ngx_memcpy(qc->dcid.data, b->pos, qc->dcid.len); | 929 |
909 b->pos += qc->dcid.len; | 930 static ngx_int_t |
910 | 931 ngx_quic_process_initial_header(ngx_connection_t *c, ngx_quic_header_t *pkt) |
911 qc->scid.len = *b->pos++; | 932 { |
912 qc->scid.data = ngx_pnalloc(c->pool, qc->scid.len); | 933 u_char *p; |
913 if (qc->scid.data == NULL) { | 934 ngx_int_t plen; |
914 return NGX_ERROR; | 935 |
915 } | 936 p = pkt->pos; |
916 | 937 |
917 ngx_memcpy(qc->scid.data, b->pos, qc->scid.len); | 938 pkt->token.len = ngx_quic_parse_int(&p); |
918 b->pos += qc->scid.len; | 939 pkt->token.data = p; |
919 | 940 |
920 qc->token.len = ngx_quic_parse_int(&b->pos); | 941 p += pkt->token.len; |
921 qc->token.data = ngx_pnalloc(c->pool, qc->token.len); | 942 |
922 if (qc->token.data == NULL) { | 943 plen = ngx_quic_parse_int(&p); |
923 return NGX_ERROR; | 944 |
924 } | |
925 | |
926 ngx_memcpy(qc->token.data, b->pos, qc->token.len); | |
927 b->pos += qc->token.len; | |
928 | |
929 ngx_int_t plen = ngx_quic_parse_int(&b->pos); | |
930 | |
931 if (plen > b->last - b->pos) { | |
932 ngx_log_error(NGX_LOG_INFO, c->log, 0, "truncated initial packet"); | |
933 return NGX_ERROR; | |
934 } | |
935 | |
936 /* draft-ietf-quic-tls-23#section-5.4.2: | |
937 * the Packet Number field is assumed to be 4 bytes long | |
938 * draft-ietf-quic-tls-23#section-5.4.[34]: | |
939 * AES-Based and ChaCha20-Based header protections sample 16 bytes | |
940 */ | |
941 u_char *sample = b->pos + 4; | |
942 | |
943 ngx_quic_hexdump0(c->log, "DCID", qc->dcid.data, qc->dcid.len); | |
944 ngx_quic_hexdump0(c->log, "SCID", qc->scid.data, qc->scid.len); | |
945 ngx_quic_hexdump0(c->log, "token", qc->token.data, qc->token.len); | |
946 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | 945 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, |
947 "quic packet length: %d", plen); | 946 "quic packet length: %d", plen); |
948 ngx_quic_hexdump0(c->log, "sample", sample, 16); | 947 |
949 | 948 if (plen > pkt->buf.data + pkt->buf.len - p) { |
950 | 949 ngx_log_error(NGX_LOG_INFO, c->log, 0, "truncated initial packet"); |
951 // initial secret | 950 return NGX_ERROR; |
951 } | |
952 | |
953 pkt->pos = p; | |
954 pkt->buf.len = plen; | |
955 | |
956 ngx_quic_hexdump0(c->log, "DCID", pkt->dcid.data, pkt->dcid.len); | |
957 ngx_quic_hexdump0(c->log, "SCID", pkt->scid.data, pkt->scid.len); | |
958 ngx_quic_hexdump0(c->log, "token", pkt->token.data, pkt->token.len); | |
959 | |
960 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
961 "quic packet length: %d", plen); | |
962 | |
963 return NGX_OK; | |
964 } | |
965 | |
966 static ngx_int_t | |
967 ngx_quic_process_handshake_header(ngx_connection_t *c, ngx_quic_header_t *pkt) | |
968 { | |
969 u_char *p; | |
970 ngx_int_t plen; | |
971 | |
972 p = pkt->pos; | |
973 | |
974 plen = ngx_quic_parse_int(&p); | |
975 | |
976 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
977 "quic packet length: %d", plen); | |
978 | |
979 if (plen > pkt->buf.data + pkt->buf.len - p) { | |
980 ngx_log_error(NGX_LOG_INFO, c->log, 0, "truncated handshake packet"); | |
981 return NGX_ERROR; | |
982 } | |
983 | |
984 pkt->pos = p; | |
985 pkt->buf.len = plen; | |
986 | |
987 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
988 "quic packet length: %d", plen); | |
989 | |
990 return NGX_OK; | |
991 } | |
992 | |
993 | |
994 static ngx_int_t | |
995 ngx_quic_initial_secret(ngx_connection_t *c) | |
996 { | |
997 ngx_quic_connection_t *qc = c->quic; | |
952 | 998 |
953 size_t is_len; | 999 size_t is_len; |
954 uint8_t is[SHA256_DIGEST_LENGTH]; | 1000 uint8_t is[SHA256_DIGEST_LENGTH]; |
955 ngx_uint_t i; | 1001 ngx_uint_t i; |
956 const EVP_MD *digest; | 1002 const EVP_MD *digest; |
1045 { | 1091 { |
1046 return NGX_ERROR; | 1092 return NGX_ERROR; |
1047 } | 1093 } |
1048 } | 1094 } |
1049 | 1095 |
1050 // header protection | 1096 return NGX_OK; |
1051 | 1097 } |
1052 uint8_t mask[16]; | 1098 |
1053 if (ngx_quic_tls_hp(c, EVP_aes_128_ecb(), &qc->client_in, mask, sample) | 1099 |
1100 static ngx_int_t | |
1101 ngx_quic_decrypt(ngx_connection_t *c, ngx_quic_header_t *pkt) | |
1102 { | |
1103 u_char clearflags, *p, *sample; | |
1104 uint8_t *nonce; | |
1105 uint64_t pn; | |
1106 ngx_int_t pnl, rc; | |
1107 ngx_str_t in, ad; | |
1108 | |
1109 const EVP_CIPHER *cipher; | |
1110 | |
1111 uint8_t mask[16]; | |
1112 | |
1113 p = pkt->pos; | |
1114 | |
1115 /* draft-ietf-quic-tls-23#section-5.4.2: | |
1116 * the Packet Number field is assumed to be 4 bytes long | |
1117 * draft-ietf-quic-tls-23#section-5.4.[34]: | |
1118 * AES-Based and ChaCha20-Based header protections sample 16 bytes | |
1119 */ | |
1120 | |
1121 sample = p + 4; | |
1122 | |
1123 ngx_quic_hexdump0(c->log, "sample", sample, 16); | |
1124 | |
1125 /* header protection */ | |
1126 | |
1127 if (ngx_quic_tls_hp(c, EVP_aes_128_ecb(), pkt->secret, mask, sample) | |
1054 != NGX_OK) | 1128 != NGX_OK) |
1055 { | 1129 { |
1056 return NGX_ERROR; | 1130 return NGX_ERROR; |
1057 } | 1131 } |
1058 | 1132 |
1059 u_char clearflags = flags ^ (mask[0] & 0x0f); | 1133 clearflags = pkt->flags ^ (mask[0] & 0x0f); |
1060 ngx_int_t pnl = (clearflags & 0x03) + 1; | 1134 pnl = (clearflags & 0x03) + 1; |
1061 uint64_t pn = ngx_quic_parse_pn(&b->pos, pnl, &mask[1]); | 1135 pn = ngx_quic_parse_pn(&p, pnl, &mask[1]); |
1062 | 1136 |
1063 ngx_quic_hexdump0(c->log, "sample", sample, 16); | 1137 pkt->pn = pn; |
1138 | |
1064 ngx_quic_hexdump0(c->log, "mask", mask, 5); | 1139 ngx_quic_hexdump0(c->log, "mask", mask, 5); |
1140 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1141 "quic clear flags: %xi", clearflags); | |
1065 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | 1142 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, |
1066 "quic packet number: %uL, len: %xi", pn, pnl); | 1143 "quic packet number: %uL, len: %xi", pn, pnl); |
1067 | 1144 |
1068 // packet protection | 1145 /* packet protection */ |
1069 | 1146 |
1070 ngx_str_t in; | 1147 in.data = p; |
1071 in.data = b->pos; | 1148 in.len = pkt->buf.len - pnl; |
1072 in.len = plen - pnl; | 1149 |
1073 | 1150 ad.len = p - pkt->buf.data;; |
1074 ngx_str_t ad; | |
1075 ad.len = b->pos - b->start; | |
1076 ad.data = ngx_pnalloc(c->pool, ad.len); | 1151 ad.data = ngx_pnalloc(c->pool, ad.len); |
1077 if (ad.data == NULL) { | 1152 if (ad.data == NULL) { |
1078 return NGX_ERROR; | 1153 return NGX_ERROR; |
1079 } | 1154 } |
1080 | 1155 |
1081 ngx_memcpy(ad.data, b->start, ad.len); | 1156 ngx_memcpy(ad.data, pkt->buf.data, ad.len); |
1082 ad.data[0] = clearflags; | 1157 ad.data[0] = clearflags; |
1083 ad.data[ad.len - pnl] = (u_char)pn; | 1158 ad.data[ad.len - pnl] = (u_char) pn; |
1084 | 1159 |
1085 uint8_t *nonce = ngx_pstrdup(c->pool, &qc->client_in.iv); | 1160 nonce = ngx_pstrdup(c->pool, &pkt->secret->iv); |
1086 nonce[11] ^= pn; | 1161 nonce[11] ^= pn; |
1087 | 1162 |
1088 ngx_quic_hexdump0(c->log, "nonce", nonce, 12); | 1163 ngx_quic_hexdump0(c->log, "nonce", nonce, 12); |
1089 ngx_quic_hexdump0(c->log, "ad", ad.data, ad.len); | 1164 ngx_quic_hexdump0(c->log, "ad", ad.data, ad.len); |
1090 | 1165 |
1091 ngx_str_t out; | 1166 if (c->ssl) { |
1092 | 1167 switch (SSL_CIPHER_get_id(SSL_get_current_cipher(c->ssl->connection)) & 0xffff) { |
1093 if (ngx_quic_tls_open(c, EVP_aes_128_gcm(), &qc->client_in, &out, nonce, | 1168 |
1094 &in, &ad) | 1169 case NGX_AES_128_GCM_SHA256: |
1095 != NGX_OK) | 1170 cipher = EVP_aes_128_gcm(); |
1096 { | 1171 break; |
1097 return NGX_ERROR; | 1172 case NGX_AES_256_GCM_SHA384: |
1098 } | 1173 cipher = EVP_aes_256_gcm(); |
1099 | 1174 break; |
1100 ngx_quic_hexdump0(c->log, "packet payload", out.data, out.len); | 1175 default: |
1176 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "unexpected cipher"); | |
1177 return NGX_ERROR; | |
1178 } | |
1179 | |
1180 } else { | |
1181 /* initial packets */ | |
1182 cipher = EVP_aes_128_gcm(); | |
1183 } | |
1184 | |
1185 rc = ngx_quic_tls_open(c, cipher, pkt->secret, &pkt->payload, | |
1186 nonce, &in, &ad); | |
1187 | |
1188 ngx_quic_hexdump0(c->log, "packet payload", | |
1189 pkt->payload.data, pkt->payload.len); | |
1190 | |
1191 return rc; | |
1192 } | |
1193 | |
1194 | |
1195 static ngx_int_t | |
1196 ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b) | |
1197 { | |
1198 int n, sslerr; | |
1199 ngx_str_t out; | |
1200 ngx_quic_connection_t *qc; | |
1201 | |
1202 ngx_quic_header_t pkt = { 0 }; | |
1203 | |
1204 pkt.buf.data = b->start; | |
1205 pkt.buf.len = b->last - b->pos; | |
1206 | |
1207 if (ngx_buf_size(b) < 1200) { | |
1208 ngx_log_error(NGX_LOG_INFO, c->log, 0, "too small UDP datagram"); | |
1209 return NGX_ERROR; | |
1210 } | |
1211 | |
1212 if (ngx_quic_process_long_header(c, &pkt) != NGX_OK) { | |
1213 return NGX_ERROR; | |
1214 } | |
1215 | |
1216 if ((pkt.flags & 0xf0) != NGX_QUIC_PKT_INITIAL) { | |
1217 ngx_log_error(NGX_LOG_INFO, c->log, 0, | |
1218 "invalid initial packet: 0x%x", pkt.flags); | |
1219 return NGX_ERROR; | |
1220 } | |
1221 | |
1222 if (ngx_quic_process_initial_header(c, &pkt) != NGX_OK) { | |
1223 return NGX_ERROR; | |
1224 } | |
1225 | |
1226 qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t)); | |
1227 if (qc == NULL) { | |
1228 return NGX_ERROR; | |
1229 } | |
1230 | |
1231 c->quic = qc; | |
1232 | |
1233 qc->dcid.len = pkt.dcid.len; | |
1234 qc->dcid.data = ngx_pnalloc(c->pool, pkt.dcid.len); | |
1235 if (qc->dcid.data == NULL) { | |
1236 return NGX_ERROR; | |
1237 } | |
1238 ngx_memcpy(qc->dcid.data, pkt.dcid.data, qc->dcid.len); | |
1239 | |
1240 qc->scid.len = pkt.scid.len; | |
1241 qc->scid.data = ngx_pnalloc(c->pool, qc->scid.len); | |
1242 if (qc->scid.data == NULL) { | |
1243 return NGX_ERROR; | |
1244 } | |
1245 ngx_memcpy(qc->scid.data, pkt.scid.data, qc->scid.len); | |
1246 | |
1247 qc->token.len = pkt.token.len; | |
1248 qc->token.data = ngx_pnalloc(c->pool, qc->token.len); | |
1249 if (qc->token.data == NULL) { | |
1250 return NGX_ERROR; | |
1251 } | |
1252 ngx_memcpy(qc->token.data, pkt.token.data, qc->token.len); | |
1253 | |
1254 | |
1255 if (ngx_quic_initial_secret(c) != NGX_OK) { | |
1256 return NGX_ERROR; | |
1257 } | |
1258 | |
1259 pkt.secret = &qc->client_in; | |
1260 | |
1261 if (ngx_quic_decrypt(c, &pkt) != NGX_OK) { | |
1262 return NGX_ERROR; | |
1263 } | |
1264 | |
1265 out = pkt.payload; | |
1101 | 1266 |
1102 if (out.data[0] != 0x06) { | 1267 if (out.data[0] != 0x06) { |
1103 ngx_log_error(NGX_LOG_INFO, c->log, 0, | 1268 ngx_log_error(NGX_LOG_INFO, c->log, 0, |
1104 "unexpected frame in initial packet"); | 1269 "unexpected frame in initial packet"); |
1105 return NGX_ERROR; | 1270 return NGX_ERROR; |
1181 return NGX_OK; | 1346 return NGX_OK; |
1182 } | 1347 } |
1183 | 1348 |
1184 | 1349 |
1185 static ngx_int_t | 1350 static ngx_int_t |
1186 ngx_quic_handshake_input(ngx_connection_t *c, ngx_buf_t *bb) | 1351 ngx_quic_handshake_input(ngx_connection_t *c, ngx_buf_t *b) |
1187 { | 1352 { |
1188 int sslerr; | 1353 int sslerr; |
1189 u_char *p, *b; | |
1190 ssize_t n; | 1354 ssize_t n; |
1191 ngx_str_t out; | 1355 ngx_str_t out; |
1192 ngx_ssl_conn_t *ssl_conn; | 1356 ngx_ssl_conn_t *ssl_conn; |
1193 const EVP_CIPHER *cipher; | |
1194 ngx_quic_connection_t *qc; | 1357 ngx_quic_connection_t *qc; |
1358 | |
1359 ngx_quic_header_t pkt = { 0 }; | |
1195 | 1360 |
1196 qc = c->quic; | 1361 qc = c->quic; |
1197 ssl_conn = c->ssl->connection; | 1362 ssl_conn = c->ssl->connection; |
1198 | 1363 |
1199 n = bb->last - bb->pos; | 1364 pkt.buf.data = b->start; |
1200 p = bb->pos; | 1365 pkt.buf.len = b->last - b->pos; |
1201 b = bb->start; | 1366 |
1202 | 1367 /* extract cleartext data into pkt */ |
1203 ngx_quic_hexdump0(c->log, "input", p, n); | 1368 if (ngx_quic_process_long_header(c, &pkt) != NGX_OK) { |
1204 | 1369 return NGX_ERROR; |
1205 if ((p[0] & 0xf0) != NGX_QUIC_PKT_HANDSHAKE) { | 1370 } |
1206 ngx_log_error(NGX_LOG_INFO, c->log, 0, "invalid packet type"); | 1371 |
1207 return NGX_ERROR; | 1372 if (pkt.dcid.len != qc->dcid.len) { |
1208 } | |
1209 | |
1210 ngx_int_t flags = *p++; | |
1211 uint32_t version = ngx_quic_parse_uint32(p); | |
1212 p += sizeof(uint32_t); | |
1213 | |
1214 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1215 "quic flags:%xi version:%xD", flags, version); | |
1216 | |
1217 if (version != quic_version) { | |
1218 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unsupported quic version"); | |
1219 return NGX_ERROR; | |
1220 } | |
1221 | |
1222 if (*p++ != qc->dcid.len) { | |
1223 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcidl"); | 1373 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcidl"); |
1224 return NGX_ERROR; | 1374 return NGX_ERROR; |
1225 } | 1375 } |
1226 | 1376 |
1227 if (ngx_memcmp(p, qc->dcid.data, qc->dcid.len) != 0) { | 1377 if (ngx_memcmp(pkt.dcid.data, qc->dcid.data, qc->dcid.len) != 0) { |
1228 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcid"); | 1378 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcid"); |
1229 return NGX_ERROR; | 1379 return NGX_ERROR; |
1230 } | 1380 } |
1231 | 1381 |
1232 p += qc->dcid.len; | 1382 if (pkt.scid.len != qc->scid.len) { |
1233 | |
1234 if (*p++ != qc->scid.len) { | |
1235 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic scidl"); | 1383 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic scidl"); |
1236 return NGX_ERROR; | 1384 return NGX_ERROR; |
1237 } | 1385 } |
1238 | 1386 |
1239 if (ngx_memcmp(p, qc->scid.data, qc->scid.len) != 0) { | 1387 if (ngx_memcmp(pkt.scid.data, qc->scid.data, qc->scid.len) != 0) { |
1240 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic scid"); | 1388 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic scid"); |
1241 return NGX_ERROR; | 1389 return NGX_ERROR; |
1242 } | 1390 } |
1243 | 1391 |
1244 p += qc->scid.len; | 1392 if ((pkt.flags & 0xf0) != NGX_QUIC_PKT_HANDSHAKE) { |
1245 | 1393 ngx_log_error(NGX_LOG_INFO, c->log, 0, |
1246 ngx_int_t plen = ngx_quic_parse_int(&p); | 1394 "invalid packet type: 0x%x", pkt.flags); |
1247 | 1395 return NGX_ERROR; |
1248 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | 1396 } |
1249 "quic packet length: %d", plen); | 1397 |
1250 | 1398 if (ngx_quic_process_handshake_header(c, &pkt) != NGX_OK) { |
1251 if (plen > b + n - p) { | 1399 return NGX_ERROR; |
1252 ngx_log_error(NGX_LOG_INFO, c->log, 0, "truncated handshake packet"); | 1400 } |
1253 return NGX_ERROR; | 1401 |
1254 } | 1402 pkt.secret = &qc->client_hs; |
1255 | 1403 |
1256 u_char *sample = p + 4; | 1404 if (ngx_quic_decrypt(c, &pkt) != NGX_OK) { |
1257 | 1405 return NGX_ERROR; |
1258 ngx_quic_hexdump0(c->log, "sample", sample, 16); | 1406 } |
1259 | 1407 |
1260 // header protection | 1408 out = pkt.payload; |
1261 | |
1262 uint8_t mask[16]; | |
1263 if (ngx_quic_tls_hp(c, EVP_aes_128_ecb(), &qc->client_hs, mask, sample) | |
1264 != NGX_OK) | |
1265 { | |
1266 return NGX_ERROR; | |
1267 } | |
1268 | |
1269 u_char clearflags = flags ^ (mask[0] & 0x0f); | |
1270 ngx_int_t pnl = (clearflags & 0x03) + 1; | |
1271 uint64_t pn = ngx_quic_parse_pn(&p, pnl, &mask[1]); | |
1272 | |
1273 ngx_quic_hexdump0(c->log, "mask", mask, 5); | |
1274 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1275 "quic clear flags: %xi", clearflags); | |
1276 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, | |
1277 "quic packet number: %uL, len: %xi", pn, pnl); | |
1278 | |
1279 // packet protection | |
1280 | |
1281 ngx_str_t in; | |
1282 in.data = p; | |
1283 in.len = plen - pnl; | |
1284 | |
1285 ngx_str_t ad; | |
1286 ad.len = p - b; | |
1287 ad.data = ngx_pnalloc(c->pool, ad.len); | |
1288 if (ad.data == NULL) { | |
1289 return NGX_ERROR; | |
1290 } | |
1291 | |
1292 ngx_memcpy(ad.data, b, ad.len); | |
1293 ad.data[0] = clearflags; | |
1294 ad.data[ad.len - pnl] = (u_char)pn; | |
1295 | |
1296 uint8_t *nonce = ngx_pstrdup(c->pool, &qc->client_hs.iv); | |
1297 nonce[11] ^= pn; | |
1298 | |
1299 ngx_quic_hexdump0(c->log, "nonce", nonce, 12); | |
1300 ngx_quic_hexdump0(c->log, "ad", ad.data, ad.len); | |
1301 | |
1302 switch (SSL_CIPHER_get_id(SSL_get_current_cipher(ssl_conn)) & 0xffff) { | |
1303 | |
1304 case NGX_AES_128_GCM_SHA256: | |
1305 cipher = EVP_aes_128_gcm(); | |
1306 break; | |
1307 | |
1308 case NGX_AES_256_GCM_SHA384: | |
1309 cipher = EVP_aes_256_gcm(); | |
1310 break; | |
1311 | |
1312 default: | |
1313 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, "unexpected cipher"); | |
1314 return NGX_ERROR; | |
1315 } | |
1316 | |
1317 if (ngx_quic_tls_open(c, cipher, &qc->client_hs, &out, nonce, &in, &ad) | |
1318 != NGX_OK) | |
1319 { | |
1320 return NGX_ERROR; | |
1321 } | |
1322 | |
1323 ngx_quic_hexdump0(c->log, "packet payload", out.data, out.len); | |
1324 | 1409 |
1325 if (out.data[0] != 0x06) { | 1410 if (out.data[0] != 0x06) { |
1326 ngx_log_error(NGX_LOG_INFO, c->log, 0, | 1411 ngx_log_error(NGX_LOG_INFO, c->log, 0, |
1327 "non-CRYPTO frame in HS packet, skipping"); | 1412 "non-CRYPTO frame in HS packet, skipping"); |
1328 return NGX_OK; | 1413 return NGX_OK; |
1386 return 0; | 1471 return 0; |
1387 } | 1472 } |
1388 | 1473 |
1389 frame->level = ssl_encryption_handshake; | 1474 frame->level = ssl_encryption_handshake; |
1390 frame->type = NGX_QUIC_FT_ACK; | 1475 frame->type = NGX_QUIC_FT_ACK; |
1391 frame->u.ack.pn = pn; | 1476 frame->u.ack.pn = pkt.pn; |
1392 | 1477 |
1393 ngx_sprintf(frame->info, "ACK for PN=%d at handshake level, in respond to client finished", pn); | 1478 ngx_sprintf(frame->info, "ACK for PN=%d at handshake level, in respond to client finished", pkt.pn); |
1394 ngx_quic_queue_frame(qc, frame); | 1479 ngx_quic_queue_frame(qc, frame); |
1395 | 1480 |
1396 if (ngx_quic_output(c) != NGX_OK) { | 1481 if (ngx_quic_output(c) != NGX_OK) { |
1397 return 0; | 1482 return 0; |
1398 } | 1483 } |