comparison src/event/ngx_event_quic.c @ 8199:1297dc83a6b9 quic

Generic payload handler for quic packets. - added basic parsing of ACK, PING and PADDING frames on input - added preliminary parsing of SHORT headers The ngx_quic_output() is now called after processing of each input packet. Frames are added into output queue according to their level: inital packets go ahead of handshake and application data, so they can be merged properly. The payload handler is called from both new, handshake and applicataion data handlers (latter is a stub).
author Vladimir Homutov <vl@nginx.com>
date Tue, 10 Mar 2020 18:24:39 +0300
parents ff14b0fe9731
children 9582adbc7d70
comparison
equal deleted inserted replaced
8198:ff14b0fe9731 8199:1297dc83a6b9
132 typedef enum ssl_encryption_level_t ngx_quic_level_t; 132 typedef enum ssl_encryption_level_t ngx_quic_level_t;
133 133
134 typedef struct ngx_quic_frame_s ngx_quic_frame_t; 134 typedef struct ngx_quic_frame_s ngx_quic_frame_t;
135 135
136 typedef struct { 136 typedef struct {
137 ngx_uint_t pn; 137 ngx_uint_t pn;
138 // ngx_uint_t nranges; 138
139 // ... 139 // input
140 uint64_t largest;
141 uint64_t delay;
142 uint64_t range_count;
143 uint64_t first_range;
144 uint64_t ranges[20];
145 /* ecn counts */
140 } ngx_quic_ack_frame_t; 146 } ngx_quic_ack_frame_t;
141 147
142 typedef ngx_str_t ngx_quic_crypto_frame_t; 148 typedef struct {
149 size_t offset;
150 size_t len;
151 u_char *data;
152 } ngx_quic_crypto_frame_t;
153
143 154
144 struct ngx_quic_frame_s { 155 struct ngx_quic_frame_s {
145 ngx_uint_t type; 156 ngx_uint_t type;
146 ngx_quic_level_t level; 157 ngx_quic_level_t level;
147 ngx_quic_frame_t *next; 158 ngx_quic_frame_t *next;
205 216
206 217
207 static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, 218 static ngx_int_t ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl,
208 ngx_buf_t *b); 219 ngx_buf_t *b);
209 static ngx_int_t ngx_quic_handshake_input(ngx_connection_t *c, ngx_buf_t *b); 220 static ngx_int_t ngx_quic_handshake_input(ngx_connection_t *c, ngx_buf_t *b);
221 static ngx_int_t ngx_quic_app_input(ngx_connection_t *c, ngx_buf_t *b);
210 222
211 static int ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn, 223 static int ngx_quic_set_encryption_secrets(ngx_ssl_conn_t *ssl_conn,
212 enum ssl_encryption_level_t level, const uint8_t *read_secret, 224 enum ssl_encryption_level_t level, const uint8_t *read_secret,
213 const uint8_t *write_secret, size_t secret_len); 225 const uint8_t *write_secret, size_t secret_len);
214 static int ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn, 226 static int ngx_quic_add_handshake_data(ngx_ssl_conn_t *ssl_conn,
223 static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn, 235 static int ngx_quic_send_alert(ngx_ssl_conn_t *ssl_conn,
224 enum ssl_encryption_level_t level, uint8_t alert); 236 enum ssl_encryption_level_t level, uint8_t alert);
225 237
226 static ngx_int_t ngx_quic_process_long_header(ngx_connection_t *c, 238 static ngx_int_t ngx_quic_process_long_header(ngx_connection_t *c,
227 ngx_quic_header_t *pkt); 239 ngx_quic_header_t *pkt);
240 static ngx_int_t ngx_quic_process_short_header(ngx_connection_t *c,
241 ngx_quic_header_t *pkt);
228 static ngx_int_t ngx_quic_process_initial_header(ngx_connection_t *c, 242 static ngx_int_t ngx_quic_process_initial_header(ngx_connection_t *c,
229 ngx_quic_header_t *pkt); 243 ngx_quic_header_t *pkt);
230 static ngx_int_t ngx_quic_process_handshake_header(ngx_connection_t *c, 244 static ngx_int_t ngx_quic_process_handshake_header(ngx_connection_t *c,
231 ngx_quic_header_t *pkt); 245 ngx_quic_header_t *pkt);
232 static ngx_int_t ngx_quic_initial_secret(ngx_connection_t *c); 246 static ngx_int_t ngx_quic_initial_secret(ngx_connection_t *c);
274 288
275 ngx_int_t 289 ngx_int_t
276 ngx_quic_input(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b) 290 ngx_quic_input(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b)
277 { 291 {
278 if (c->quic == NULL) { 292 if (c->quic == NULL) {
279 return ngx_quic_new_connection(c, ssl, b); //TODO: change state by results 293 return ngx_quic_new_connection(c, ssl, b);
280 } 294 }
281 295
282 switch (c->quic->state) { 296 if (b->start[0] & NGX_QUIC_PKT_LONG) {
283 case NGX_QUIC_ST_INITIAL: 297 // TODO: check current state
284 case NGX_QUIC_ST_HANDSHAKE:
285 return ngx_quic_handshake_input(c, b); 298 return ngx_quic_handshake_input(c, b);
286 default: 299 }
287 /* application data */ 300
288 break; 301 return ngx_quic_app_input(c, b);
289 }
290
291 return NGX_OK;
292 } 302 }
293 303
294 static ngx_int_t 304 static ngx_int_t
295 ngx_quic_send_packet(ngx_connection_t *c, ngx_quic_connection_t *qc, 305 ngx_quic_send_packet(ngx_connection_t *c, ngx_quic_connection_t *qc,
296 ngx_quic_level_t level, ngx_str_t *payload) 306 ngx_quic_level_t level, ngx_str_t *payload)
377 } 387 }
378 388
379 start = p; 389 start = p;
380 390
381 ngx_quic_build_int(&p, NGX_QUIC_FT_CRYPTO); 391 ngx_quic_build_int(&p, NGX_QUIC_FT_CRYPTO);
382 ngx_quic_build_int(&p, 0); 392 ngx_quic_build_int(&p, crypto->offset);
383 ngx_quic_build_int(&p, crypto->len); 393 ngx_quic_build_int(&p, crypto->len);
384 p = ngx_cpymem(p, crypto->data, crypto->len); 394 p = ngx_cpymem(p, crypto->data, crypto->len);
385 395
386 return p - start; 396 return p - start;
387 } 397 }
450 return NGX_ERROR; 460 return NGX_ERROR;
451 } 461 }
452 462
453 return NGX_OK; 463 return NGX_OK;
454 } 464 }
465
455 466
456 ngx_int_t 467 ngx_int_t
457 ngx_quic_output(ngx_connection_t *c) 468 ngx_quic_output(ngx_connection_t *c)
458 { 469 {
459 size_t len; 470 size_t len;
800 if (qc->frames == NULL) { 811 if (qc->frames == NULL) {
801 qc->frames = frame; 812 qc->frames = frame;
802 return; 813 return;
803 } 814 }
804 815
805 for (f = qc->frames; f->next; f = f->next) { /* void */ } 816 for (f = qc->frames; f->next; f = f->next) {
806 817 if (f->next->level > frame->level) {
818 break;
819 }
820 }
821
822 frame->next = f->next;
807 f->next = frame; 823 f->next = frame;
808 } 824 }
809 825
810 826
811 static int 827 static int
842 858
843 ngx_sprintf(frame->info, "crypto, generated by SSL len=%ui level=%d", len, level); 859 ngx_sprintf(frame->info, "crypto, generated by SSL len=%ui level=%d", len, level);
844 860
845 ngx_quic_queue_frame(qc, frame); 861 ngx_quic_queue_frame(qc, frame);
846 862
847 if (level == ssl_encryption_initial) {
848 frame = ngx_pcalloc(c->pool, sizeof(ngx_quic_frame_t));
849 if (frame == NULL) {
850 return 0;
851 }
852 frame->level = level;
853 frame->type = NGX_QUIC_FT_ACK;
854 frame->u.ack.pn = 0;
855 ngx_sprintf(frame->info, "ACK for PN=0 at initial, added manually from add_handshake_data");
856
857 ngx_quic_queue_frame(qc, frame);
858 }
859
860 return 1; 863 return 1;
861 } 864 }
862 865
863 866
864 static int 867 static int
867 ngx_connection_t *c; 870 ngx_connection_t *c;
868 871
869 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn); 872 c = ngx_ssl_get_connection((ngx_ssl_conn_t *) ssl_conn);
870 873
871 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "ngx_quic_flush_flight()"); 874 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "ngx_quic_flush_flight()");
872
873 if (ngx_quic_output(c) != NGX_OK) {
874 return 0;
875 }
876 875
877 return 1; 876 return 1;
878 } 877 }
879 878
880 879
889 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, 888 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
890 "ngx_quic_send_alert(), lvl=%d, alert=%d", 889 "ngx_quic_send_alert(), lvl=%d, alert=%d",
891 (int) level, (int) alert); 890 (int) level, (int) alert);
892 891
893 return 1; 892 return 1;
893 }
894
895
896 /* TODO: stub for short packet header processing */
897 static ngx_int_t
898 ngx_quic_process_short_header(ngx_connection_t *c, ngx_quic_header_t *pkt)
899 {
900 u_char *p;
901
902 p = pkt->buf.data;
903
904 ngx_quic_hexdump0(c->log, "input", pkt->buf.data, pkt->buf.len);
905
906 if ((p[0] & NGX_QUIC_PKT_LONG)) {
907 ngx_log_error(NGX_LOG_INFO, c->log, 0, "not a short packet");
908 return NGX_ERROR;
909 }
910
911 pkt->flags = *p++;
912
913 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
914 "quic flags:%xi", pkt->flags);
915
916 if (ngx_memcmp(p, c->quic->dcid.data, c->quic->dcid.len) != 0) {
917 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcid");
918 return NGX_ERROR;
919 }
920
921 pkt->dcid.data = p;
922 p += c->quic->dcid.len;
923
924 pkt->pos = p;
925
926 return NGX_OK;
894 } 927 }
895 928
896 929
897 static ngx_int_t 930 static ngx_int_t
898 ngx_quic_process_long_header(ngx_connection_t *c, ngx_quic_header_t *pkt) 931 ngx_quic_process_long_header(ngx_connection_t *c, ngx_quic_header_t *pkt)
1158 1191
1159 if (ngx_quic_tls_hp(c, hp, pkt->secret, mask, sample) != NGX_OK) { 1192 if (ngx_quic_tls_hp(c, hp, pkt->secret, mask, sample) != NGX_OK) {
1160 return NGX_ERROR; 1193 return NGX_ERROR;
1161 } 1194 }
1162 1195
1163 clearflags = pkt->flags ^ (mask[0] & 0x0f); 1196 if (pkt->flags & NGX_QUIC_PKT_LONG) {
1197 clearflags = pkt->flags ^ (mask[0] & 0x0f);
1198
1199 } else {
1200 clearflags = pkt->flags ^ (mask[0] & 0x1f);
1201 }
1202
1164 pnl = (clearflags & 0x03) + 1; 1203 pnl = (clearflags & 0x03) + 1;
1165 pn = ngx_quic_parse_pn(&p, pnl, &mask[1]); 1204 pn = ngx_quic_parse_pn(&p, pnl, &mask[1]);
1166 1205
1167 pkt->pn = pn; 1206 pkt->pn = pn;
1168 1207
1173 "quic packet number: %uL, len: %xi", pn, pnl); 1212 "quic packet number: %uL, len: %xi", pn, pnl);
1174 1213
1175 /* packet protection */ 1214 /* packet protection */
1176 1215
1177 in.data = p; 1216 in.data = p;
1178 in.len = pkt->buf.len - pnl; 1217
1179 1218 if (pkt->flags & NGX_QUIC_PKT_LONG) {
1180 ad.len = p - pkt->buf.data;; 1219 in.len = pkt->buf.len - pnl;
1220
1221 } else {
1222 in.len = pkt->buf.data + pkt->buf.len - p;
1223 }
1224
1225 ad.len = p - pkt->buf.data;
1181 ad.data = ngx_pnalloc(c->pool, ad.len); 1226 ad.data = ngx_pnalloc(c->pool, ad.len);
1182 if (ad.data == NULL) { 1227 if (ad.data == NULL) {
1183 return NGX_ERROR; 1228 return NGX_ERROR;
1184 } 1229 }
1185 1230
1197 nonce, &in, &ad); 1242 nonce, &in, &ad);
1198 1243
1199 ngx_quic_hexdump0(c->log, "packet payload", 1244 ngx_quic_hexdump0(c->log, "packet payload",
1200 pkt->payload.data, pkt->payload.len); 1245 pkt->payload.data, pkt->payload.len);
1201 1246
1247 pkt->pos = pkt->payload.data;
1248
1202 return rc; 1249 return rc;
1203 } 1250 }
1204 1251
1205 1252
1253 ngx_int_t
1254 ngx_quic_read_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
1255 ngx_quic_frame_t *frame)
1256 {
1257 u_char *p, *end;
1258
1259 size_t npad;
1260
1261 p = pkt->pos;
1262 end = pkt->payload.data + pkt->payload.len;
1263
1264 frame->type = *p++;
1265
1266 switch (frame->type) {
1267
1268 case NGX_QUIC_FT_CRYPTO:
1269 frame->u.crypto.offset = *p++;
1270 frame->u.crypto.len = ngx_quic_parse_int(&p);
1271 frame->u.crypto.data = p;
1272 p += frame->u.crypto.len;
1273
1274 ngx_quic_hexdump0(c->log, "CRYPTO frame",
1275 frame->u.crypto.data, frame->u.crypto.len);
1276
1277 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
1278 "quic CRYPTO frame length: %uL off:%uL pp:%p",
1279 frame->u.crypto.len, frame->u.crypto.offset,
1280 frame->u.crypto.data);
1281 break;
1282
1283 case NGX_QUIC_FT_PADDING:
1284 npad = 0;
1285 while (p < end && *p == NGX_QUIC_FT_PADDING) { // XXX
1286 p++; npad++;
1287 }
1288
1289 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
1290 "PADDING frame length %uL", npad);
1291
1292 break;
1293
1294 case NGX_QUIC_FT_ACK:
1295 case NGX_QUIC_FT_ACK_ECN:
1296
1297 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "ACK frame");
1298
1299 frame->u.ack.largest = ngx_quic_parse_int(&p);
1300 frame->u.ack.delay = ngx_quic_parse_int(&p);
1301 frame->u.ack.range_count =ngx_quic_parse_int(&p);
1302 frame->u.ack.first_range =ngx_quic_parse_int(&p);
1303
1304 if (frame->u.ack.range_count) {
1305 frame->u.ack.ranges[0] = ngx_quic_parse_int(&p);
1306 }
1307
1308 if (frame->type ==NGX_QUIC_FT_ACK_ECN) {
1309 return NGX_ERROR;
1310 }
1311
1312 break;
1313
1314 case NGX_QUIC_FT_PING:
1315 ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, "PING frame");
1316 p++;
1317 break;
1318 default:
1319 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
1320 "unknown frame type %xi", frame->type);
1321 return NGX_ERROR;
1322 }
1323
1324 pkt->pos = p;
1325
1326 return NGX_OK;
1327 }
1328
1329
1206 static ngx_int_t 1330 static ngx_int_t
1207 ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b) 1331 ngx_quic_handle_crypto_frame(ngx_connection_t *c, ngx_quic_header_t *pkt,
1208 { 1332 ngx_quic_frame_t *frame)
1209 int n, sslerr; 1333 {
1210 ngx_str_t out; 1334 int sslerr;
1211 ngx_quic_connection_t *qc; 1335 ssize_t n;
1212 1336 ngx_ssl_conn_t *ssl_conn;
1213 ngx_quic_header_t pkt = { 0 }; 1337
1214
1215 pkt.buf.data = b->start;
1216 pkt.buf.len = b->last - b->pos;
1217
1218 if (ngx_buf_size(b) < 1200) {
1219 ngx_log_error(NGX_LOG_INFO, c->log, 0, "too small UDP datagram");
1220 return NGX_ERROR;
1221 }
1222
1223 if (ngx_quic_process_long_header(c, &pkt) != NGX_OK) {
1224 return NGX_ERROR;
1225 }
1226
1227 if ((pkt.flags & 0xf0) != NGX_QUIC_PKT_INITIAL) {
1228 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1229 "invalid initial packet: 0x%xi", pkt.flags);
1230 return NGX_ERROR;
1231 }
1232
1233 if (ngx_quic_process_initial_header(c, &pkt) != NGX_OK) {
1234 return NGX_ERROR;
1235 }
1236
1237 qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t));
1238 if (qc == NULL) {
1239 return NGX_ERROR;
1240 }
1241
1242 c->quic = qc;
1243
1244 qc->dcid.len = pkt.dcid.len;
1245 qc->dcid.data = ngx_pnalloc(c->pool, pkt.dcid.len);
1246 if (qc->dcid.data == NULL) {
1247 return NGX_ERROR;
1248 }
1249 ngx_memcpy(qc->dcid.data, pkt.dcid.data, qc->dcid.len);
1250
1251 qc->scid.len = pkt.scid.len;
1252 qc->scid.data = ngx_pnalloc(c->pool, qc->scid.len);
1253 if (qc->scid.data == NULL) {
1254 return NGX_ERROR;
1255 }
1256 ngx_memcpy(qc->scid.data, pkt.scid.data, qc->scid.len);
1257
1258 qc->token.len = pkt.token.len;
1259 qc->token.data = ngx_pnalloc(c->pool, qc->token.len);
1260 if (qc->token.data == NULL) {
1261 return NGX_ERROR;
1262 }
1263 ngx_memcpy(qc->token.data, pkt.token.data, qc->token.len);
1264
1265
1266 if (ngx_quic_initial_secret(c) != NGX_OK) {
1267 return NGX_ERROR;
1268 }
1269
1270 pkt.secret = &qc->client_in;
1271
1272 if (ngx_quic_decrypt(c, &pkt) != NGX_OK) {
1273 return NGX_ERROR;
1274 }
1275
1276 out = pkt.payload;
1277
1278 if (out.data[0] != NGX_QUIC_FT_CRYPTO) {
1279 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1280 "unexpected frame in initial packet");
1281 return NGX_ERROR;
1282 }
1283
1284 if (out.data[1] != 0x00) {
1285 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1286 "unexpected CRYPTO offset in initial packet");
1287 return NGX_ERROR;
1288 }
1289
1290 uint8_t *crypto = &out.data[2];
1291 uint64_t crypto_len = ngx_quic_parse_int(&crypto);
1292
1293 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
1294 "quic initial packet CRYPTO length: %uL pp:%p:%p",
1295 crypto_len, out.data, crypto);
1296
1297 if (ngx_ssl_create_connection(ssl, c, NGX_SSL_BUFFER) != NGX_OK) {
1298 return NGX_ERROR;
1299 }
1300
1301 /* STUB: initial_max_streams_uni=3, active_connection_id_limit=5 */
1302 static const uint8_t params[12] = "\x00\x0a\x00\x0e\x00\x01\x05\x00\x09\x00\x01\x03";
1303
1304 if (SSL_set_quic_transport_params(c->ssl->connection, params,
1305 sizeof(params)) == 0)
1306 {
1307 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1308 "SSL_set_quic_transport_params() failed");
1309 return NGX_ERROR;
1310 }
1311
1312 n = SSL_do_handshake(c->ssl->connection);
1313
1314 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n);
1315
1316 if (n == -1) {
1317 sslerr = SSL_get_error(c->ssl->connection, n);
1318
1319 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d",
1320 sslerr);
1321 }
1322
1323 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
1324 "SSL_quic_read_level: %d, SSL_quic_write_level: %d",
1325 (int) SSL_quic_read_level(c->ssl->connection),
1326 (int) SSL_quic_write_level(c->ssl->connection));
1327
1328 if (!SSL_provide_quic_data(c->ssl->connection,
1329 SSL_quic_read_level(c->ssl->connection),
1330 crypto, crypto_len))
1331 {
1332 ngx_ssl_error(NGX_LOG_INFO, c->log, 0,
1333 "SSL_provide_quic_data() failed");
1334 return NGX_ERROR;
1335 }
1336
1337 n = SSL_do_handshake(c->ssl->connection);
1338
1339 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n);
1340
1341 if (n == -1) {
1342 sslerr = SSL_get_error(c->ssl->connection, n);
1343
1344 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d",
1345 sslerr);
1346
1347 if (sslerr == SSL_ERROR_SSL) {
1348 ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "SSL_do_handshake() failed");
1349 }
1350 }
1351
1352 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
1353 "SSL_quic_read_level: %d, SSL_quic_write_level: %d",
1354 (int) SSL_quic_read_level(c->ssl->connection),
1355 (int) SSL_quic_write_level(c->ssl->connection));
1356
1357 return NGX_OK;
1358 }
1359
1360
1361 static ngx_int_t
1362 ngx_quic_handshake_input(ngx_connection_t *c, ngx_buf_t *b)
1363 {
1364 int sslerr;
1365 ssize_t n;
1366 ngx_str_t out;
1367 ngx_ssl_conn_t *ssl_conn;
1368 ngx_quic_connection_t *qc;
1369
1370 ngx_quic_header_t pkt = { 0 };
1371
1372 qc = c->quic;
1373 ssl_conn = c->ssl->connection; 1338 ssl_conn = c->ssl->connection;
1374
1375 pkt.buf.data = b->start;
1376 pkt.buf.len = b->last - b->pos;
1377
1378 /* extract cleartext data into pkt */
1379 if (ngx_quic_process_long_header(c, &pkt) != NGX_OK) {
1380 return NGX_ERROR;
1381 }
1382
1383 if (pkt.dcid.len != qc->dcid.len) {
1384 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcidl");
1385 return NGX_ERROR;
1386 }
1387
1388 if (ngx_memcmp(pkt.dcid.data, qc->dcid.data, qc->dcid.len) != 0) {
1389 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcid");
1390 return NGX_ERROR;
1391 }
1392
1393 if (pkt.scid.len != qc->scid.len) {
1394 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic scidl");
1395 return NGX_ERROR;
1396 }
1397
1398 if (ngx_memcmp(pkt.scid.data, qc->scid.data, qc->scid.len) != 0) {
1399 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic scid");
1400 return NGX_ERROR;
1401 }
1402
1403 if ((pkt.flags & 0xf0) != NGX_QUIC_PKT_HANDSHAKE) {
1404 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1405 "invalid packet type: 0x%xi", pkt.flags);
1406 return NGX_ERROR;
1407 }
1408
1409 if (ngx_quic_process_handshake_header(c, &pkt) != NGX_OK) {
1410 return NGX_ERROR;
1411 }
1412
1413 pkt.secret = &qc->client_hs;
1414
1415 if (ngx_quic_decrypt(c, &pkt) != NGX_OK) {
1416 return NGX_ERROR;
1417 }
1418
1419 out = pkt.payload;
1420
1421 if (out.data[0] != NGX_QUIC_FT_CRYPTO) {
1422 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1423 "non-CRYPTO frame in HS packet, skipping");
1424 return NGX_OK;
1425 }
1426
1427 if (out.data[1] != 0x00) {
1428 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1429 "not yet supported CRYPTO offset in initial packet");
1430 return NGX_ERROR;
1431 }
1432
1433 uint8_t *crypto = &out.data[2];
1434 uint64_t crypto_len = ngx_quic_parse_int(&crypto);
1435
1436 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, c->log, 0,
1437 "quic Handshake packet CRYPTO length: %uL pp:%p:%p",
1438 crypto_len, out.data, crypto);
1439 1339
1440 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, 1340 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
1441 "SSL_quic_read_level: %d, SSL_quic_write_level: %d", 1341 "SSL_quic_read_level: %d, SSL_quic_write_level: %d",
1442 (int) SSL_quic_read_level(ssl_conn), 1342 (int) SSL_quic_read_level(ssl_conn),
1443 (int) SSL_quic_write_level(ssl_conn)); 1343 (int) SSL_quic_write_level(ssl_conn));
1444 1344
1345
1445 if (!SSL_provide_quic_data(ssl_conn, SSL_quic_read_level(ssl_conn), 1346 if (!SSL_provide_quic_data(ssl_conn, SSL_quic_read_level(ssl_conn),
1446 crypto, crypto_len)) 1347 frame->u.crypto.data, frame->u.crypto.len))
1447 { 1348 {
1448 ngx_ssl_error(NGX_LOG_INFO, c->log, 0, 1349 ngx_ssl_error(NGX_LOG_INFO, c->log, 0,
1449 "SSL_provide_quic_data() failed"); 1350 "SSL_provide_quic_data() failed");
1450 return NGX_ERROR; 1351 return NGX_ERROR;
1451 } 1352 }
1462 1363
1463 if (sslerr == SSL_ERROR_SSL) { 1364 if (sslerr == SSL_ERROR_SSL) {
1464 ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "SSL_do_handshake() failed"); 1365 ngx_ssl_error(NGX_LOG_ERR, c->log, 0, "SSL_do_handshake() failed");
1465 } 1366 }
1466 } 1367 }
1368
1369 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
1370 "quic ssl cipher: %s", SSL_get_cipher(ssl_conn));
1467 1371
1468 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0, 1372 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
1469 "SSL_quic_read_level: %d, SSL_quic_write_level: %d", 1373 "SSL_quic_read_level: %d, SSL_quic_write_level: %d",
1470 (int) SSL_quic_read_level(ssl_conn), 1374 (int) SSL_quic_read_level(ssl_conn),
1471 (int) SSL_quic_write_level(ssl_conn)); 1375 (int) SSL_quic_write_level(ssl_conn));
1472 1376
1473 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0,
1474 "quic ssl cipher: %s", SSL_get_cipher(ssl_conn));
1475
1476 // ACK Client Finished
1477
1478 ngx_quic_frame_t *frame;
1479
1480 frame = ngx_pcalloc(c->pool, sizeof(ngx_quic_frame_t));
1481 if (frame == NULL) {
1482 return 0;
1483 }
1484
1485 frame->level = ssl_encryption_handshake;
1486 frame->type = NGX_QUIC_FT_ACK;
1487 frame->u.ack.pn = pkt.pn;
1488
1489 ngx_sprintf(frame->info, "ACK for PN=%d at handshake level, in respond to client finished", pkt.pn);
1490 ngx_quic_queue_frame(qc, frame);
1491
1492 if (ngx_quic_output(c) != NGX_OK) {
1493 return 0;
1494 }
1495
1496 return NGX_OK; 1377 return NGX_OK;
1378 }
1379
1380
1381
1382 static ngx_int_t
1383 ngx_quic_init_connection(ngx_connection_t *c, ngx_quic_header_t *pkt)
1384 {
1385 int n, sslerr;
1386 ngx_ssl_conn_t *ssl_conn;
1387 ngx_quic_connection_t *qc;
1388
1389 /* STUB: initial_max_streams_uni=3, active_connection_id_limit=5 */
1390 static const uint8_t params[12] = "\x00\x0a\x00\x0e\x00\x01\x05\x00\x09\x00\x01\x03";
1391
1392 qc = c->quic;
1393
1394 if (ngx_ssl_create_connection(qc->ssl, c, NGX_SSL_BUFFER) != NGX_OK) {
1395 return NGX_ERROR;
1396 }
1397
1398 ssl_conn = c->ssl->connection;
1399
1400 if (SSL_set_quic_transport_params(ssl_conn, params, sizeof(params)) == 0) {
1401 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1402 "SSL_set_quic_transport_params() failed");
1403 return NGX_ERROR;
1404 }
1405
1406 n = SSL_do_handshake(ssl_conn);
1407
1408 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_do_handshake: %d", n);
1409
1410 if (n == -1) {
1411 sslerr = SSL_get_error(ssl_conn, n);
1412
1413 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_get_error: %d",
1414 sslerr);
1415 }
1416
1417 ngx_log_debug2(NGX_LOG_DEBUG_EVENT, c->log, 0,
1418 "SSL_quic_read_level: %d, SSL_quic_write_level: %d",
1419 (int) SSL_quic_read_level(ssl_conn),
1420 (int) SSL_quic_write_level(ssl_conn));
1421
1422 return NGX_OK;
1423 }
1424
1425
1426 /* process all payload from the current packet and generate ack if required */
1427 static ngx_int_t
1428 ngx_quic_payload_handler(ngx_connection_t *c, ngx_quic_header_t *pkt)
1429 {
1430 u_char *end;
1431 ngx_uint_t ack_this;
1432 ngx_quic_frame_t frame, *ack_frame;
1433 ngx_quic_connection_t *qc;
1434
1435 qc = c->quic;
1436 end = pkt->payload.data + pkt->payload.len;
1437
1438 ack_this = 0;
1439
1440 while (pkt->pos < end) {
1441
1442 if (ngx_quic_read_frame(c, pkt, &frame) != NGX_OK) {
1443 return NGX_ERROR;
1444 }
1445
1446 switch (frame.type) {
1447
1448 case NGX_QUIC_FT_ACK:
1449
1450 // TODO: handle ack
1451
1452 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, c->log, 0,
1453 "ACK: { largest=%ui delay=%ui first=%ui count=%ui}",
1454 frame.u.ack.largest,
1455 frame.u.ack.delay,
1456 frame.u.ack.first_range,
1457 frame.u.ack.range_count);
1458
1459 break;
1460
1461 case NGX_QUIC_FT_CRYPTO:
1462
1463 if (frame.u.crypto.offset != 0x0) {
1464 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1465 "crypto frame with non-zero offset");
1466 // TODO: support packet spanning with offsets
1467 return NGX_ERROR;
1468 }
1469
1470 if (ngx_quic_handle_crypto_frame(c, pkt, &frame) != NGX_OK) {
1471 return NGX_ERROR;
1472 }
1473
1474 ack_this = 1;
1475
1476 continue;
1477
1478 case NGX_QUIC_FT_PADDING:
1479 continue;
1480
1481 case NGX_QUIC_FT_PING:
1482 ack_this = 1;
1483 continue;
1484
1485 default:
1486 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1487 "unexpected frame type 0x%xd in packet", frame.type);
1488 return NGX_ERROR;
1489 }
1490 }
1491
1492 if (ack_this == 0) {
1493 /* do not ack packets with ACKs and PADDING */
1494 return NGX_OK;
1495 }
1496
1497 // packet processed, ACK it now if required
1498 // TODO: if (ack_required) ... - currently just ack each packet
1499
1500 ack_frame = ngx_pcalloc(c->pool, sizeof(ngx_quic_frame_t));
1501 if (ack_frame == NULL) {
1502 return NGX_ERROR;
1503 }
1504
1505 ack_frame->level = pkt->level;
1506 ack_frame->type = NGX_QUIC_FT_ACK;
1507 ack_frame->u.ack.pn = pkt->pn;
1508
1509 ngx_sprintf(ack_frame->info, "ACK for PN=%d from frame handler", pkt->pn);
1510 ngx_quic_queue_frame(qc, ack_frame);
1511
1512 return ngx_quic_output(c);
1513 }
1514
1515
1516 static ngx_int_t
1517 ngx_quic_new_connection(ngx_connection_t *c, ngx_ssl_t *ssl, ngx_buf_t *b)
1518 {
1519 ngx_quic_connection_t *qc;
1520
1521 ngx_quic_header_t pkt = { 0 };
1522
1523 pkt.buf.data = b->start;
1524 pkt.buf.len = b->last - b->pos;
1525
1526 if (ngx_buf_size(b) < 1200) {
1527 ngx_log_error(NGX_LOG_INFO, c->log, 0, "too small UDP datagram");
1528 return NGX_ERROR;
1529 }
1530
1531 if (ngx_quic_process_long_header(c, &pkt) != NGX_OK) {
1532 return NGX_ERROR;
1533 }
1534
1535 if ((pkt.flags & 0xf0) != NGX_QUIC_PKT_INITIAL) {
1536 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1537 "invalid initial packet: 0x%xi", pkt.flags);
1538 return NGX_ERROR;
1539 }
1540
1541 if (ngx_quic_process_initial_header(c, &pkt) != NGX_OK) {
1542 return NGX_ERROR;
1543 }
1544
1545 qc = ngx_pcalloc(c->pool, sizeof(ngx_quic_connection_t));
1546 if (qc == NULL) {
1547 return NGX_ERROR;
1548 }
1549
1550 c->quic = qc;
1551 qc->ssl = ssl;
1552
1553 qc->dcid.len = pkt.dcid.len;
1554 qc->dcid.data = ngx_pnalloc(c->pool, pkt.dcid.len);
1555 if (qc->dcid.data == NULL) {
1556 return NGX_ERROR;
1557 }
1558 ngx_memcpy(qc->dcid.data, pkt.dcid.data, qc->dcid.len);
1559
1560 qc->scid.len = pkt.scid.len;
1561 qc->scid.data = ngx_pnalloc(c->pool, qc->scid.len);
1562 if (qc->scid.data == NULL) {
1563 return NGX_ERROR;
1564 }
1565 ngx_memcpy(qc->scid.data, pkt.scid.data, qc->scid.len);
1566
1567 qc->token.len = pkt.token.len;
1568 qc->token.data = ngx_pnalloc(c->pool, qc->token.len);
1569 if (qc->token.data == NULL) {
1570 return NGX_ERROR;
1571 }
1572 ngx_memcpy(qc->token.data, pkt.token.data, qc->token.len);
1573
1574
1575 if (ngx_quic_initial_secret(c) != NGX_OK) {
1576 return NGX_ERROR;
1577 }
1578
1579 pkt.secret = &qc->client_in;
1580 pkt.level = ssl_encryption_initial;
1581
1582 if (ngx_quic_decrypt(c, &pkt) != NGX_OK) {
1583 return NGX_ERROR;
1584 }
1585
1586 if (ngx_quic_init_connection(c, &pkt) != NGX_OK) {
1587 return NGX_ERROR;
1588 }
1589
1590 return ngx_quic_payload_handler(c, &pkt);
1591 }
1592
1593
1594 static ngx_int_t
1595 ngx_quic_handshake_input(ngx_connection_t *c, ngx_buf_t *b)
1596 {
1597 ngx_ssl_conn_t *ssl_conn;
1598 ngx_quic_connection_t *qc;
1599
1600 ngx_quic_header_t pkt = { 0 };
1601
1602 qc = c->quic;
1603 ssl_conn = c->ssl->connection;
1604
1605 pkt.buf.data = b->start;
1606 pkt.buf.len = b->last - b->pos;
1607
1608 /* extract cleartext data into pkt */
1609 if (ngx_quic_process_long_header(c, &pkt) != NGX_OK) {
1610 return NGX_ERROR;
1611 }
1612
1613 if (pkt.dcid.len != qc->dcid.len) {
1614 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcidl");
1615 return NGX_ERROR;
1616 }
1617
1618 if (ngx_memcmp(pkt.dcid.data, qc->dcid.data, qc->dcid.len) != 0) {
1619 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic dcid");
1620 return NGX_ERROR;
1621 }
1622
1623 if (pkt.scid.len != qc->scid.len) {
1624 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic scidl");
1625 return NGX_ERROR;
1626 }
1627
1628 if (ngx_memcmp(pkt.scid.data, qc->scid.data, qc->scid.len) != 0) {
1629 ngx_log_error(NGX_LOG_INFO, c->log, 0, "unexpected quic scid");
1630 return NGX_ERROR;
1631 }
1632
1633 if ((pkt.flags & 0xf0) != NGX_QUIC_PKT_HANDSHAKE) {
1634 ngx_log_error(NGX_LOG_INFO, c->log, 0,
1635 "invalid packet type: 0x%xi", pkt.flags);
1636 return NGX_ERROR;
1637 }
1638
1639 if (ngx_quic_process_handshake_header(c, &pkt) != NGX_OK) {
1640 return NGX_ERROR;
1641 }
1642
1643 pkt.secret = &qc->client_hs;
1644 pkt.level = ssl_encryption_handshake;
1645
1646 if (ngx_quic_decrypt(c, &pkt) != NGX_OK) {
1647 return NGX_ERROR;
1648 }
1649
1650 return ngx_quic_payload_handler(c, &pkt);
1651 }
1652
1653
1654 static ngx_int_t
1655 ngx_quic_app_input(ngx_connection_t *c, ngx_buf_t *b)
1656 {
1657 ngx_quic_connection_t *qc;
1658
1659 qc = c->quic;
1660
1661 /* TODO: this is a stub, untested */
1662
1663 ngx_quic_header_t pkt = { 0 };
1664
1665 pkt.buf.data = b->start;
1666 pkt.buf.len = b->last - b->pos;
1667
1668 if (ngx_quic_process_short_header(c, &pkt) != NGX_OK) {
1669 return NGX_ERROR;
1670 }
1671
1672 pkt.secret = &qc->client_ad;
1673 pkt.level = ssl_encryption_application;
1674
1675 if (ngx_quic_decrypt(c, &pkt) != NGX_OK) {
1676 return NGX_ERROR;
1677 }
1678
1679 return ngx_quic_payload_handler(c, &pkt);
1497 } 1680 }
1498 1681
1499 1682
1500 uint64_t 1683 uint64_t
1501 ngx_quic_parse_int(u_char **pos) 1684 ngx_quic_parse_int(u_char **pos)