From 4f3bbfa21cdc5cd3cc937e2e1405a289c9005edb Mon Sep 17 00:00:00 2001 From: huitema <huitema@huitema.net> Date: Sun, 8 Jul 2018 22:07:53 -0700 Subject: [PATCH] Implement the retry token, and fix a number of issues in the parsing of headers and packets. --- UnitTest1/unittest1.cpp | 76 ++++--- picoquic/frames.c | 4 +- picoquic/packet.c | 388 +++++++++++++++++---------------- picoquic/picoquic_internal.h | 19 +- picoquic/quicctx.c | 67 +++--- picoquic/sender.c | 256 ++++++++-------------- picoquic_t/picoquic_t.c | 10 +- picoquictest/parseheadertest.c | 21 +- picoquictest/tls_api_test.c | 80 ++++--- 9 files changed, 452 insertions(+), 469 deletions(-) diff --git a/UnitTest1/unittest1.cpp b/UnitTest1/unittest1.cpp index fd36b540..e4ac1509 100644 --- a/UnitTest1/unittest1.cpp +++ b/UnitTest1/unittest1.cpp @@ -30,12 +30,19 @@ namespace UnitTest1 TEST_CLASS(UnitTest1) { public: - TEST_METHOD(test_picohash) - { + TEST_METHOD(test_picohash) + { int ret = picohash_test(); Assert::AreEqual(ret, 0); - } + } + + TEST_METHOD(splay) + { + int ret = splay_test(); + + Assert::AreEqual(ret, 0); + } TEST_METHOD(test_cnxcreation) { @@ -72,23 +79,23 @@ namespace UnitTest1 Assert::AreEqual(ret, 0); } - TEST_METHOD(test_sack) + TEST_METHOD(test_float16) { - int ret = sacktest(); + int ret = float16test(); Assert::AreEqual(ret, 0); } - TEST_METHOD(test_float16) + TEST_METHOD(test_varints) { - int ret = float16test(); + int ret = varint_test(); Assert::AreEqual(ret, 0); } - TEST_METHOD(test_varints) + TEST_METHOD(test_sack) { - int ret = varint_test(); + int ret = sacktest(); Assert::AreEqual(ret, 0); } @@ -106,6 +113,13 @@ namespace UnitTest1 Assert::AreEqual(ret, 0); } + + TEST_METHOD(test_logger) + { + int ret = logger_test(); + + Assert::AreEqual(ret, 0); + } TEST_METHOD(test_TlsStreamFrame) { @@ -146,6 +160,20 @@ namespace UnitTest1 { int ret = sim_link_test(); + Assert::AreEqual(ret, 0); + } + + TEST_METHOD(test_cleartext_pn_enc) + { + int ret = cleartext_pn_enc_test(); + + Assert::AreEqual(ret, 0); + } + + TEST_METHOD(test_pn_enc_1rtt) + { + int ret = pn_enc_1rtt_test(); + Assert::AreEqual(ret, 0); } @@ -352,13 +380,6 @@ namespace UnitTest1 Assert::AreEqual(ret, 0); } - TEST_METHOD(test_logger) - { - int ret = logger_test(); - - Assert::AreEqual(ret, 0); - } - TEST_METHOD(test_sockets) { int ret = socket_test(); @@ -429,20 +450,6 @@ namespace UnitTest1 Assert::AreEqual(ret, 0); } - TEST_METHOD(test_cleartext_pn_enc) - { - int ret = cleartext_pn_enc_test(); - - Assert::AreEqual(ret, 0); - } - - TEST_METHOD(test_pn_enc_1rtt) - { - int ret = pn_enc_1rtt_test(); - - Assert::AreEqual(ret, 0); - } - TEST_METHOD(test_tls_zero_share) { int ret = tls_zero_share_test(); @@ -582,14 +589,5 @@ namespace UnitTest1 Assert::AreEqual(ret, 0); } - - - TEST_METHOD(splay) - { - int ret = splay_test(); - - Assert::AreEqual(ret, 0); - } - }; } diff --git a/picoquic/frames.c b/picoquic/frames.c index bc73918b..1e6f7a57 100644 --- a/picoquic/frames.c +++ b/picoquic/frames.c @@ -2090,7 +2090,7 @@ int picoquic_decode_frames(picoquic_cnx_t* cnx, uint8_t* bytes, } bytes = picoquic_decode_stream_frame(cnx, bytes, bytes_max, current_time); - pkt_ctx->ack_needed = 1; + ack_needed = 1; } else if (first_byte == picoquic_frame_type_ack) { bytes = picoquic_decode_ack_frame(cnx, bytes, bytes_max, current_time, epoch); @@ -2187,7 +2187,7 @@ int picoquic_decode_frames(picoquic_cnx_t* cnx, uint8_t* bytes, pkt_ctx->ack_needed = 1; } - return bytes != NULL ? 0 : 1; + return bytes != NULL ? 0 : PICOQUIC_ERROR_DETECTED; } /* diff --git a/picoquic/packet.c b/picoquic/packet.c index d2ebb488..beb7db15 100644 --- a/picoquic/packet.c +++ b/picoquic/packet.c @@ -108,9 +108,6 @@ int picoquic_parse_packet_header( length - ph->offset, &payload_length); ph->version_index = picoquic_get_version_index(ph->vn); - if ((picoquic_supported_versions[ph->version_index].version_flags&picoquic_version_use_pn_encryption) == 0) { - pn_length_clear = 4; - } if (var_length <= 0 || ph->offset + var_length + pn_length_clear + payload_length > length || ph->version_index < 0) { @@ -122,12 +119,6 @@ int picoquic_parse_packet_header( ph->offset += var_length; ph->pn_offset = ph->offset; - if ((picoquic_supported_versions[ph->version_index].version_flags&picoquic_version_use_pn_encryption) == 0) { - ph->pn = PICOPARSE_32(bytes + ph->offset); - ph->pnmask = 0xFFFFFFFF00000000ull; - ph->offset += 4; - } - /* Retrieve the connection context */ if (*pcnx == NULL) { *pcnx = picoquic_cnx_by_id(quic, ph->dest_cnx_id); @@ -265,10 +256,9 @@ int picoquic_parse_packet_header( else { ph->ptype = picoquic_packet_1rtt_protected_phi1; } - - ph->has_spin_bit = 1; + ph->has_spin_bit = 1; ph->spin = (bytes[0] >> 2) & 1; - ph->spin_vec = bytes[0] & 0x03 ; + ph->spin_vec = bytes[0] & 0x03 ; ph->pn_offset = ph->offset; ph->pn = 0; @@ -293,24 +283,6 @@ int picoquic_parse_packet_header( return ret; } -/* Check whether a packet was sent in clear text */ -int picoquic_is_packet_encrypted(picoquic_packet_type_enum ptype) -{ - int ret = 0; - switch (ptype) { - case picoquic_packet_0rtt_protected: - case picoquic_packet_1rtt_protected_phi0: - case picoquic_packet_1rtt_protected_phi1: - ret = 1; - break; - default: - ret = 0; - break; - } - - return ret; -} - /* The packet number logic */ uint64_t picoquic_get_packet_number64(uint64_t highest, uint64_t mask, uint32_t pn) { @@ -338,123 +310,121 @@ uint64_t picoquic_get_packet_number64(uint64_t highest, uint64_t mask, uint32_t } /* + * Decrypt the incoming packet. * Apply packet number decryption. This may require updating the * sequence number and the offset */ size_t picoquic_decrypt_packet(picoquic_cnx_t* cnx, - uint8_t* bytes, size_t length, picoquic_packet_header* ph, + uint8_t* bytes, size_t packet_length, picoquic_packet_header* ph, void * pn_enc, void* aead_context, int * already_received) { - /* - * If needed, decrypt the packet number, in place. - */ - size_t decoded = length + 32; + size_t decoded = packet_length + 32; /* by conventions, values larger than input indicate error */ + size_t length = ph->offset + ph->payload_length; /* this may change after decrypting the PN */ if (already_received != NULL) { *already_received = 0; } - - if ((picoquic_supported_versions[cnx->version_index].version_flags&picoquic_version_use_pn_encryption) != 0) + + if (pn_enc != NULL) { - if (pn_enc != NULL) - { - /* The header length is not yet known, will only be known after the sequence number is decrypted */ - size_t encrypted_length = 4; - size_t sample_offset = ph->pn_offset + encrypted_length; - size_t aead_checksum_length = picoquic_aead_get_checksum_length(aead_context); - uint8_t decoded_pn_bytes[4]; + /* The header length is not yet known, will only be known after the sequence number is decrypted */ + size_t encrypted_length = 4; + size_t sample_offset = ph->pn_offset + encrypted_length; + size_t aead_checksum_length = picoquic_aead_get_checksum_length(aead_context); + uint8_t decoded_pn_bytes[4]; - if (sample_offset + aead_checksum_length > length) - { - sample_offset = length - aead_checksum_length; - if (ph->pn_offset < sample_offset) { - encrypted_length = sample_offset - ph->pn_offset; - } - else { - encrypted_length = 0; - } + if (sample_offset + aead_checksum_length > length) + { + sample_offset = length - aead_checksum_length; + if (ph->pn_offset < sample_offset) { + encrypted_length = sample_offset - ph->pn_offset; } - if (encrypted_length > 0) - { - if (picoquic_supported_versions[ph->version_index].version_header_encoding == picoquic_version_header_11) { - /* Decode */ - picoquic_pn_encrypt(pn_enc, bytes + sample_offset, decoded_pn_bytes, bytes + ph->pn_offset, encrypted_length); - /* Packet encoding is varint, specialized for sequence number */ - switch (bytes[0] & 0x03) { - case 0x00:/* single byte encoding */ - ph->pn = decoded_pn_bytes[0]; - ph->pnmask = 0xFFFFFFFFFFFFFF00ull; - ph->offset = ph->pn_offset + 1; - ph->payload_length -= 1; - break; - case 0x01: /* two byte encoding */ - ph->pn = PICOPARSE_16(decoded_pn_bytes); - ph->pnmask = 0xFFFFFFFFFFFF0000ull; - ph->offset = ph->pn_offset + 2; - ph->payload_length -= 2; - break; - case 0x02: - ph->pn = PICOPARSE_32(decoded_pn_bytes); - ph->pnmask = 0xFFFFFFFF00000000ull; - ph->offset = ph->pn_offset + 4; - ph->payload_length -= 4; - break; - default: - /* Invalid packet format. Avoid crash! */ - ph->pn = 0xFFFFFFFF; - ph->pnmask = 0xFFFFFFFF00000000ull; - ph->offset = ph->pn_offset; - break; - } - } - else { - /* Decode */ - picoquic_pn_encrypt(pn_enc, bytes + sample_offset, decoded_pn_bytes, bytes + ph->pn_offset, encrypted_length); - /* Packet encoding is varint, specialized for sequence number */ - switch (decoded_pn_bytes[0] & 0xC0) { - case 0x00: - case 0x40: /* single byte encoding */ - ph->pn = decoded_pn_bytes[0] & 0x7F; - ph->pnmask = 0xFFFFFFFFFFFFFF80ull; - ph->offset = ph->pn_offset + 1; - ph->payload_length -= 1; - break; - case 0x80: /* two byte encoding */ - ph->pn = (PICOPARSE_16(decoded_pn_bytes)) & 0x3FFF; - ph->pnmask = 0xFFFFFFFFFFFFC000ull; - ph->offset = ph->pn_offset + 2; - ph->payload_length -= 2; - break; - case 0xC0: - ph->pn = (PICOPARSE_32(decoded_pn_bytes)) & 0x3FFFFFFF; - ph->pnmask = 0xFFFFFFFFC0000000ull; - ph->offset = ph->pn_offset + 4; - ph->payload_length -= 4; - break; - } + else { + encrypted_length = 0; + } + } + if (encrypted_length > 0) + { + if (picoquic_supported_versions[ph->version_index].version_header_encoding == picoquic_version_header_11) { + /* Decode */ + picoquic_pn_encrypt(pn_enc, bytes + sample_offset, decoded_pn_bytes, bytes + ph->pn_offset, encrypted_length); + /* Packet encoding is varint, specialized for sequence number */ + switch (bytes[0] & 0x03) { + case 0x00:/* single byte encoding */ + ph->pn = decoded_pn_bytes[0]; + ph->pnmask = 0xFFFFFFFFFFFFFF00ull; + ph->offset = ph->pn_offset + 1; + ph->payload_length -= 1; + break; + case 0x01: /* two byte encoding */ + ph->pn = PICOPARSE_16(decoded_pn_bytes); + ph->pnmask = 0xFFFFFFFFFFFF0000ull; + ph->offset = ph->pn_offset + 2; + ph->payload_length -= 2; + break; + case 0x02: + ph->pn = PICOPARSE_32(decoded_pn_bytes); + ph->pnmask = 0xFFFFFFFF00000000ull; + ph->offset = ph->pn_offset + 4; + ph->payload_length -= 4; + break; + default: + /* Invalid packet format. Avoid crash! */ + ph->pn = 0xFFFFFFFF; + ph->pnmask = 0xFFFFFFFF00000000ull; + ph->offset = ph->pn_offset; + break; } - if (ph->offset > ph->pn_offset) { - memcpy(bytes + ph->pn_offset, decoded_pn_bytes, ph->offset - ph->pn_offset); + } + else { + /* Decode */ + picoquic_pn_encrypt(pn_enc, bytes + sample_offset, decoded_pn_bytes, bytes + ph->pn_offset, encrypted_length); + /* Packet encoding is varint, specialized for sequence number */ + switch (decoded_pn_bytes[0] & 0xC0) { + case 0x00: + case 0x40: /* single byte encoding */ + ph->pn = decoded_pn_bytes[0] & 0x7F; + ph->pnmask = 0xFFFFFFFFFFFFFF80ull; + ph->offset = ph->pn_offset + 1; + ph->payload_length -= 1; + break; + case 0x80: /* two byte encoding */ + ph->pn = (PICOPARSE_16(decoded_pn_bytes)) & 0x3FFF; + ph->pnmask = 0xFFFFFFFFFFFFC000ull; + ph->offset = ph->pn_offset + 2; + ph->payload_length -= 2; + break; + case 0xC0: + ph->pn = (PICOPARSE_32(decoded_pn_bytes)) & 0x3FFFFFFF; + ph->pnmask = 0xFFFFFFFFC0000000ull; + ph->offset = ph->pn_offset + 4; + ph->payload_length -= 4; + break; } - } else { - /* Invalid packet format. Avoid crash! */ - ph->pn = 0xFFFFFFFF; - ph->pnmask = 0xFFFFFFFF00000000ull; - ph->offset = ph->pn_offset; - - DBG_PRINTF("Invalid packet format, type: %d, epoch: %d, pc: %d, pn: %d\n", - ph->ptype, ph->epoch, ph->pc, (int) ph->pn); } - } else { - /* The pn_enc algorithm was not initialized. Avoid crash! */ + if (ph->offset > ph->pn_offset) { + memcpy(bytes + ph->pn_offset, decoded_pn_bytes, ph->offset - ph->pn_offset); + } + } + else { + /* Invalid packet format. Avoid crash! */ ph->pn = 0xFFFFFFFF; ph->pnmask = 0xFFFFFFFF00000000ull; ph->offset = ph->pn_offset; - DBG_PRINTF("PN dec not ready, type: %d, epoch: %d, pc: %d, pn: %d\n", + DBG_PRINTF("Invalid packet format, type: %d, epoch: %d, pc: %d, pn: %d\n", ph->ptype, ph->epoch, ph->pc, (int)ph->pn); } } + else { + /* The pn_enc algorithm was not initialized. Avoid crash! */ + ph->pn = 0xFFFFFFFF; + ph->pnmask = 0xFFFFFFFF00000000ull; + ph->offset = ph->pn_offset; + + DBG_PRINTF("PN dec not ready, type: %d, epoch: %d, pc: %d, pn: %d\n", + ph->ptype, ph->epoch, ph->pc, (int)ph->pn); + } /* Build a packet number to 64 bits */ ph->pn64 = picoquic_get_packet_number64( @@ -466,10 +436,32 @@ size_t picoquic_decrypt_packet(picoquic_cnx_t* cnx, /* Set error type: already received */ *already_received = 1; } else { - /* Attempt to decrypt the packet */ - decoded = picoquic_aead_decrypt_generic(bytes + ph->offset, - bytes + ph->offset, length - ph->offset, ph->pn64, bytes, ph->offset, aead_context); + /* special case of the initial packets. They contain a retry token between the header + * and the encrypted payload */ + + if (ph->ptype == picoquic_packet_initial) { + uint64_t tok_len = 0; + size_t l_tok_len = picoquic_varint_decode(bytes + ph->offset, length - ph->offset, &tok_len); + + if (l_tok_len == 0) { + /* packet is malformed */ + } + else { + ph->token_length = (uint32_t)tok_len; + ph->token_offset = ph->offset + 1; + ph->offset += 1 + (size_t)tok_len; + + if (ph->offset + ph->payload_length > packet_length) { + ph->offset = length; + ph->token_offset = 0; + ph->token_length = 0; + } + } + } } + + decoded = picoquic_aead_decrypt_generic(bytes + ph->offset, + bytes + ph->offset, ph->payload_length, ph->pn64, bytes, ph->offset, aead_context); return decoded; } @@ -494,6 +486,7 @@ int picoquic_parse_header_and_decrypt( int new_ctx_created = 0; if (ret == 0) { + /* TODO: clarify length, payload length, packet length -- special case of initial packet */ length = ph->offset + ph->payload_length; *consumed = length; @@ -510,6 +503,8 @@ int picoquic_parse_header_and_decrypt( } } + /* TODO: replace switch by reference to epoch */ + if (*pcnx != NULL) { if (receiving) { switch (ph->ptype) { @@ -517,14 +512,14 @@ int picoquic_parse_header_and_decrypt( /* Packet is not encrypted */ break; case picoquic_packet_initial: - decoded_length = picoquic_decrypt_packet(*pcnx, bytes, length, ph, + decoded_length = picoquic_decrypt_packet(*pcnx, bytes, packet_length, ph, (*pcnx)->crypto_context[0].pn_dec, (*pcnx)->crypto_context[0].aead_decrypt, &already_received); + length = ph->offset + ph->payload_length; + *consumed = length; break; case picoquic_packet_retry: - decoded_length = picoquic_decrypt_packet(*pcnx, bytes, length, ph, - (*pcnx)->crypto_context[0].pn_dec, - (*pcnx)->crypto_context[0].aead_decrypt, &already_received); + /* packet is not encrypted */ break; case picoquic_packet_handshake: decoded_length = picoquic_decrypt_packet(*pcnx, bytes, length, ph, @@ -560,12 +555,12 @@ int picoquic_parse_header_and_decrypt( /* Packet is not encrypted */ break; case picoquic_packet_initial: - decoded_length = picoquic_decrypt_packet(*pcnx, bytes, length, ph, + decoded_length = picoquic_decrypt_packet(*pcnx, bytes, packet_length, ph, (*pcnx)->crypto_context[0].pn_enc, (*pcnx)->crypto_context[0].aead_de_encrypt, NULL); + length = ph->offset + packet_length; break; case picoquic_packet_retry: - decoded_length = picoquic_decrypt_packet(*pcnx, bytes, length, ph, - (*pcnx)->crypto_context[0].pn_enc, (*pcnx)->crypto_context[0].aead_de_encrypt, NULL); + /* packet is not encrypted */ break; case picoquic_packet_handshake: decoded_length = picoquic_decrypt_packet(*pcnx, bytes, length, ph, @@ -613,6 +608,7 @@ int picoquic_parse_header_and_decrypt( return ret; } + /* * Processing of a version renegotiation packet. * @@ -781,9 +777,7 @@ void picoquic_queue_stateless_reset(picoquic_cnx_t* cnx, if (picoquic_prepare_crypto_hs_frame(cnx, 0 /* assume stateless reply in initial state */, bytes + byte_index, PICOQUIC_MAX_PACKET_SIZE - byte_index - checksum_length, &data_bytes) == 0) { - uint64_t sequence_number = - ((picoquic_supported_versions[cnx->version_index].version_flags&picoquic_version_use_pn_encryption) != 0) - ? 0 : ph->pn; + uint64_t sequence_number = 0; byte_index += (uint32_t)data_bytes; /* AEAD Encrypt, to the send buffer */ @@ -820,9 +814,17 @@ int picoquic_incoming_initial( uint64_t current_time) { int ret = 0; + size_t l_tok_len = 0; + uint64_t tok_len = 0; + size_t extra_offset = 0; + + /* TODO: if there is a problem with the retry token, schedule a retry packet */ - ret = picoquic_decode_frames(cnx, - bytes + ph->offset, ph->payload_length, ph->epoch, current_time); + /* decode the incoming frames */ + if (ret == 0) { + ret = picoquic_decode_frames(cnx, + bytes + ph->offset + extra_offset, ph->payload_length - extra_offset, ph->epoch, current_time); + } /* processing of client initial packet */ if (ret == 0) { @@ -830,6 +832,7 @@ int picoquic_incoming_initial( /* TODO: find path to send data produced by TLS. */ ret = picoquic_tls_stream_process(cnx); + /* TODO: remove the stateless reset code, not needed with retry token */ if (cnx->cnx_state == picoquic_state_server_send_hrr) { picoquic_queue_stateless_reset(cnx, ph, addr_from, addr_to, if_index_to, current_time); cnx->cnx_state = picoquic_state_disconnected; @@ -853,7 +856,7 @@ int picoquic_incoming_initial( } /* - * Processing of a server stateless packet. + * Processing of a server retry * * The packet number and connection ID fields echo the corresponding fields from the * triggering client packet. This allows a client to verify that the server received its packet. @@ -862,74 +865,79 @@ int picoquic_incoming_initial( * Receiving another Client Initial packet implicitly acknowledges a Server Stateless Retry packet. * * After receiving a Server Stateless Retry packet, the client uses a new Client Initial packet - * containing the next cryptographic handshake message. The client retains the state of its - * cryptographic handshake, but discards all transport state. In effect, the next cryptographic - * handshake message is sent on a new connection. The new Client Initial packet is sent in a - * packet with a newly randomized packet number and starting at a stream offset of 0. - * - * Continuing the cryptographic handshake is necessary to ensure that an attacker cannot force - * a downgrade of any cryptographic parameters. In addition to continuing the cryptographic - * handshake, the client MUST remember the results of any version negotiation that occurred - * (see Section 7.1). The client MAY also retain any observed RTT or congestion state that it - * has accumulated for the flow, but other transport state MUST be discarded. + * containing the next token. In effect, the next cryptographic + * handshake message is sent on a new connection. */ -int picoquic_incoming_server_stateless( +int picoquic_incoming_retry( picoquic_cnx_t* cnx, uint8_t* bytes, picoquic_packet_header* ph, uint64_t current_time) { - picoquic_packet_context_enum pc = ph->pc; int ret = 0; + size_t token_length = 0; + uint8_t * token = NULL; if (cnx->cnx_state != picoquic_state_client_init_sent && cnx->cnx_state != picoquic_state_client_init_resent) { ret = PICOQUIC_ERROR_UNEXPECTED_PACKET; - } - else { + } else { /* Verify that the header is a proper echo of what was sent */ - if (ph->vn != picoquic_supported_versions[cnx->version_index].version || - ((picoquic_supported_versions[cnx->version_index].version_flags&picoquic_version_use_pn_encryption) == 0 && ( - (cnx->pkt_ctx[pc].retransmit_newest == NULL || ph->pn64 > cnx->pkt_ctx[pc].retransmit_newest->sequence_number) || - (cnx->pkt_ctx[pc].retransmit_oldest == NULL || ph->pn64 < cnx->pkt_ctx[pc].retransmit_oldest->sequence_number)))) { + if (ph->vn != picoquic_supported_versions[cnx->version_index].version) { /* Packet that do not match the "echo" checks should be logged and ignored */ ret = PICOQUIC_ERROR_UNEXPECTED_PACKET; - } - - if ((picoquic_supported_versions[cnx->version_index].version_flags&picoquic_version_use_pn_encryption) != 0 && - ph->pn64 != 0) { + } else if (ph->pn64 != 0) { /* after draft-12, PN is required to be 0 */ ret = PICOQUIC_ERROR_UNEXPECTED_PACKET; } } if (ret == 0) { - /* Accept the incoming frames */ - ret = picoquic_decode_frames(cnx, - bytes + ph->offset, ph->payload_length, ph->epoch, current_time); + /* Parse the retry frame */ + size_t byte_index = ph->offset; + + uint8_t odcil = bytes[byte_index++]; + + if (odcil < 8 || odcil != cnx->initial_cnxid.id_len || odcil + 1 > ph->payload_length || + memcmp(cnx->initial_cnxid.id, &bytes[byte_index], odcil) != 0) { + /* malformed ODCIL, or does not match initial cid; ignore */ + ret = PICOQUIC_ERROR_UNEXPECTED_PACKET; + } else { + byte_index += odcil; + token_length = ph->offset + ph->payload_length - byte_index; + + if (token_length > 0) { + token = malloc(token_length); + if (token == NULL) { + ret = PICOQUIC_ERROR_MEMORY; + } else { + memcpy(token, &bytes[byte_index], odcil); + } + } + } } - /* processing of the TLS message */ if (ret == 0) { - /* set the state to HRR received, will trigger behavior when processing stream zero */ - cnx->cnx_state = picoquic_state_client_hrr_received; - /* Remove the resume ticket if any */ - picoquic_tlscontext_remove_ticket(cnx); - /* submit the embedded message (presumably HRR) to stream zero */ - ret = picoquic_tls_stream_process(cnx); - if (ret == 0) - { - /* reset the initial CNX_ID to the version sent by the server */ - cnx->initial_cnxid = ph->srce_cnx_id; + /* reset the initial CNX_ID to the version sent by the server */ + cnx->initial_cnxid = ph->srce_cnx_id; - /* reset the encryption contexts */ - for (int i = 0; i < 4; i++) { - picoquic_crypto_context_free(&cnx->crypto_context[i]); - } + /* keep a copy of the retry token */ + if (cnx->retry_token != NULL) { + free(cnx->retry_token); + } + cnx->retry_token = token; + cnx->retry_token_length = token_length; + + /* reset the initial stream, keep a copy of the 0-RTT packets sent. */ + picoquic_reset_packet_context(cnx, picoquic_packet_context_initial); - /* Reinit the clear text AEAD */ - ret = picoquic_setup_initial_traffic_keys(cnx); + /* reset the encryption contexts */ + for (int i = 0; i < 4; i++) { + picoquic_crypto_context_free(&cnx->crypto_context[i]); } + + /* Reinit the clear text AEAD */ + ret = picoquic_setup_initial_traffic_keys(cnx); } if (ret == 0) { /* Mark the packet as not required for ack */ @@ -1248,7 +1256,8 @@ int picoquic_incoming_segment( break; case picoquic_packet_initial: /* Initial packet: either crypto handshakes or acks. */ - if (picoquic_compare_connection_id(&ph.dest_cnx_id, &cnx->initial_cnxid) == 0) { + if (picoquic_compare_connection_id(&ph.dest_cnx_id, &cnx->initial_cnxid) == 0 || + picoquic_compare_connection_id(&ph.dest_cnx_id, &cnx->local_cnxid) == 0) { if (cnx->client_mode == 0) { /* TODO: finish processing initial connection packet */ ret = picoquic_incoming_initial(cnx, bytes, @@ -1265,7 +1274,7 @@ int picoquic_incoming_segment( break; case picoquic_packet_retry: /* TODO: server retry is completely revised in the new version. */ - ret = picoquic_incoming_server_stateless(cnx, bytes, &ph, current_time); + ret = picoquic_incoming_retry(cnx, bytes, &ph, current_time); break; case picoquic_packet_handshake: if (cnx->client_mode) @@ -1311,7 +1320,7 @@ int picoquic_incoming_segment( if (cnx != NULL) { cnx->pkt_ctx[ph.pc].ack_needed = 1; } - ret = 0; + ret = -1; } else if (ret == PICOQUIC_ERROR_AEAD_CHECK || ret == PICOQUIC_ERROR_INITIAL_TOO_SHORT || ret == PICOQUIC_ERROR_UNEXPECTED_PACKET || ret == PICOQUIC_ERROR_FNV1A_CHECK || ret == PICOQUIC_ERROR_CNXID_CHECK || ret == PICOQUIC_ERROR_HRR || ret == PICOQUIC_ERROR_DETECTED || @@ -1321,17 +1330,17 @@ int picoquic_incoming_segment( DBG_PRINTF("Packet (%d) dropped, t: %d, e: %d, pc: %d, pn: %d, l: %d, ret : %x\n", (cnx == NULL) ? -1 : cnx->client_mode, ph.ptype, ph.epoch, ph.pc, (int)ph.pn, length, ret); - ret = 0; - } else if (ret == 1) - { + ret = -1; + } else if (ret == 1) { /* wonder what happened ! */ DBG_PRINTF("Packet (%d) get ret=1, t: %d, e: %d, pc: %d, pn: %d, l: %d\n", (cnx == NULL) ? -1 : cnx->client_mode, ph.ptype, ph.epoch, ph.pc, (int)ph.pn, length); - ret = 0; + ret = -1; } else if (ret != 0) { DBG_PRINTF("Packet (%d) error, t: %d, e: %d, pc: %d, pn: %d, l: %d, ret : %x\n", (cnx == NULL) ? -1 : cnx->client_mode, ph.ptype, ph.epoch, ph.pc, (int)ph.pn, length, ret); + ret = -1; } return ret; @@ -1359,6 +1368,7 @@ int picoquic_incoming_packet( if (ret == 0) { consumed_index += consumed; } else { + ret = 0; break; } } diff --git a/picoquic/picoquic_internal.h b/picoquic/picoquic_internal.h index 034ad344..845e6195 100644 --- a/picoquic/picoquic_internal.h +++ b/picoquic/picoquic_internal.h @@ -113,8 +113,7 @@ typedef enum { */ typedef enum { - picoquic_version_no_flag = 0, - picoquic_version_use_pn_encryption = 1 + picoquic_version_no_flag = 0 } picoquic_version_feature_flags; /* @@ -424,7 +423,6 @@ typedef struct st_picoquic_cnx_t { int version_index; /* Series of flags showing the state or choices of the connection */ - unsigned int use_pn_encryption : 1; unsigned int is_0RTT_accepted : 1; /* whether 0-RTT is accepted */ unsigned int remote_parameters_received : 1; /* whether remote parameters where received */ unsigned int current_spin : 1; /* Current value of the spin bit */ @@ -461,6 +459,9 @@ typedef struct st_picoquic_cnx_t { uint16_t remote_application_error; uint16_t remote_error; uint16_t remote_crypto_error; + uint32_t retry_token_length; + uint8_t * retry_token; + /* Next time sending data is expected */ uint64_t next_wake_time; @@ -537,6 +538,10 @@ void picoquic_dequeue_retransmit_packet(picoquic_cnx_t* cnx, picoquic_packet* p, /* Reset connection after receiving version negotiation */ int picoquic_reset_cnx_version(picoquic_cnx_t* cnx, uint8_t* bytes, size_t length, uint64_t current_time); +/* Reset packet context */ +void picoquic_reset_packet_context(picoquic_cnx_t* cnx, + picoquic_packet_context_enum pc); + /* Notify error on connection */ int picoquic_connection_error(picoquic_cnx_t* cnx, uint16_t local_error); @@ -598,6 +603,8 @@ typedef struct _picoquic_packet_header { unsigned int spin : 1; unsigned int spin_vec : 2; unsigned int has_spin_bit : 1; + uint32_t token_length; + uint32_t token_offset; } picoquic_packet_header; int picoquic_parse_packet_header( @@ -614,7 +621,8 @@ uint32_t picoquic_create_packet_header( picoquic_packet_type_enum packet_type, uint64_t sequence_number, uint8_t* bytes, - uint32_t * pn_offset); + uint32_t * pn_offset, + uint32_t * pn_length); uint32_t picoquic_predict_packet_header_length( picoquic_cnx_t* cnx, @@ -745,9 +753,6 @@ int picoquic_prepare_transport_extensions(picoquic_cnx_t* cnx, int extension_mod int picoquic_receive_transport_extensions(picoquic_cnx_t* cnx, int extension_mode, uint8_t* bytes, size_t bytes_max, size_t* consumed); -/* Check whether a packet was sent in clear text */ -int picoquic_is_packet_encrypted(picoquic_packet_type_enum ptype); - /* Queue stateless reset */ void picoquic_queue_stateless_reset(picoquic_cnx_t* cnx, picoquic_packet_header* ph, struct sockaddr* addr_from, diff --git a/picoquic/quicctx.c b/picoquic/quicctx.c index 8dacc9c5..f1ac0db6 100644 --- a/picoquic/quicctx.c +++ b/picoquic/quicctx.c @@ -139,11 +139,11 @@ static uint8_t picoquic_cleartext_draft_10_salt[] = { /* Support for draft 13! */ const picoquic_version_parameters_t picoquic_supported_versions[] = { - { PICOQUIC_INTERNAL_TEST_VERSION_1, picoquic_version_use_pn_encryption, + { PICOQUIC_INTERNAL_TEST_VERSION_1, 0, picoquic_version_header_12, sizeof(picoquic_cleartext_internal_test_1_salt), picoquic_cleartext_internal_test_1_salt }, - { PICOQUIC_SEVENTH_INTEROP_VERSION, picoquic_version_use_pn_encryption, + { PICOQUIC_SEVENTH_INTEROP_VERSION, 0, picoquic_version_header_12, sizeof(picoquic_cleartext_draft_10_salt), picoquic_cleartext_draft_10_salt } @@ -1161,6 +1161,41 @@ void picoquic_dequeue_retransmit_packet(picoquic_cnx_t* cnx, picoquic_packet* p, } } +void picoquic_reset_packet_context(picoquic_cnx_t* cnx, + picoquic_packet_context_enum pc) +{ + /* TODO: special case for 0-RTT packets! */ + picoquic_packet_context_t * pkt_ctx = &cnx->pkt_ctx[pc]; + + while (pkt_ctx->retransmit_newest != NULL) { + picoquic_dequeue_retransmit_packet(cnx, pkt_ctx->retransmit_newest, 1); + } + + while (pkt_ctx->retransmitted_newest != NULL) { + picoquic_packet* p = pkt_ctx->retransmitted_newest; + pkt_ctx->retransmitted_newest = p->next_packet; + free(p); + } + + pkt_ctx->retransmitted_oldest = NULL; + +#if 0 + /* BUG #225: this crashes in some tests not related to this PR. */ + /* Reset the sack lists*/ + while (pkt_ctx->first_sack_item.next_sack != NULL) { + picoquic_sack_item_t * next = pkt_ctx->first_sack_item.next_sack; + cnx->pkt_ctx->first_sack_item.next_sack = next->next_sack; + free(next); + } +#else + /* BUG: see above */ + pkt_ctx->first_sack_item.next_sack = NULL; +#endif + + pkt_ctx->first_sack_item.start_of_sack_range = (uint64_t)((int64_t)-1); + pkt_ctx->first_sack_item.end_of_sack_range = 0; +} + /* * Reset the version to a new supported value. * @@ -1195,25 +1230,13 @@ int picoquic_reset_cnx_version(picoquic_cnx_t* cnx, uint8_t* bytes, size_t lengt cnx->version_index = (int)i; cnx->cnx_state = picoquic_state_client_renegotiate; - /* TODO: Reset the clear text context */ - /* Delete the packets queued for retransmission */ for (picoquic_packet_context_enum pc = 0; pc < picoquic_nb_packet_context; pc++) { - while (cnx->pkt_ctx[pc].retransmit_newest != NULL) { - picoquic_dequeue_retransmit_packet(cnx, cnx->pkt_ctx[pc].retransmit_newest, 1); - } - /* Reset the sack lists*/ - while (cnx->pkt_ctx[pc].first_sack_item.next_sack != NULL) { - picoquic_sack_item_t * next = cnx->pkt_ctx[pc].first_sack_item.next_sack; - cnx->pkt_ctx[pc].first_sack_item.next_sack = next->next_sack; - free(next); - } - cnx->pkt_ctx[pc].first_sack_item.start_of_sack_range = (uint64_t)((int64_t)-1); - cnx->pkt_ctx[pc].first_sack_item.end_of_sack_range = 0; + picoquic_reset_packet_context(cnx, pc); } - /* Reset the streams */ + /* Reset the crypto stream */ picoquic_clear_stream(&cnx->tls_stream); cnx->tls_stream.consumed_offset = 0; cnx->tls_stream.stream_flags = 0; @@ -1308,18 +1331,10 @@ void picoquic_delete_cnx(picoquic_cnx_t* cnx) for (int i = 0; i < 4; i++) { picoquic_crypto_context_free(&cnx->crypto_context[i]); } + for (picoquic_packet_context_enum pc = 0; pc < picoquic_nb_packet_context; pc++) { - while (cnx->pkt_ctx[pc].retransmit_newest != NULL) { - picoquic_dequeue_retransmit_packet(cnx, cnx->pkt_ctx[pc].retransmit_newest, 1); - } - - while (cnx->pkt_ctx[pc].retransmitted_newest != NULL) { - picoquic_packet* p = cnx->pkt_ctx[pc].retransmitted_newest; - cnx->pkt_ctx[pc].retransmitted_newest = p->next_packet; - free(p); - } - cnx->pkt_ctx[pc].retransmitted_oldest = NULL; + picoquic_reset_packet_context(cnx, pc); } while ((misc_frame = cnx->first_misc_frame) != NULL) { diff --git a/picoquic/sender.c b/picoquic/sender.c index d984879e..61cc3802 100644 --- a/picoquic/sender.c +++ b/picoquic/sender.c @@ -193,79 +193,6 @@ void picoquic_update_payload_length( } } -uint32_t picoquic_create_packet_header_11( - picoquic_cnx_t* cnx, - picoquic_packet_type_enum packet_type, - picoquic_connection_id_t dest_cnx_id, - picoquic_connection_id_t srce_cnx_id, - uint64_t sequence_number, - uint8_t* bytes, - uint32_t * pn_offset) -{ - uint32_t length = 0; - - /* Prepare the packet header */ - if (packet_type == picoquic_packet_1rtt_protected_phi0 || packet_type == picoquic_packet_1rtt_protected_phi1) { - /* Create a short packet -- using 32 bit sequence numbers for now */ - uint8_t K = (packet_type == picoquic_packet_1rtt_protected_phi0) ? 0 : 0x40; - const uint8_t C = 0x32; - uint8_t spin_bit = (uint8_t)((cnx->current_spin) << 2); - - length = 0; - bytes[length++] = (K | C | spin_bit); - length += picoquic_format_connection_id(&bytes[length], PICOQUIC_MAX_PACKET_SIZE - length, dest_cnx_id); - - *pn_offset = length; - picoformat_32(&bytes[length], (uint32_t)sequence_number); - length += 4; - } - else { - /* Create a long packet */ - - switch (packet_type) { - case picoquic_packet_initial: - bytes[0] = 0xFF; - break; - case picoquic_packet_retry: - bytes[0] = 0xFE; - break; - case picoquic_packet_handshake: - bytes[0] = 0xFD; - break; - case picoquic_packet_0rtt_protected: - bytes[0] = 0xFC; - break; - default: - bytes[0] = 0x80; - break; - } - length = 1; - if ((cnx->cnx_state == picoquic_state_client_init || cnx->cnx_state == picoquic_state_client_init_sent) && packet_type == picoquic_packet_initial) { - picoformat_32(&bytes[length], cnx->proposed_version); - } - else { - picoformat_32(&bytes[length], - picoquic_supported_versions[cnx->version_index].version); - } - length += 4; - - bytes[length++] = picoquic_create_packet_header_cnxid_lengths(dest_cnx_id.id_len, srce_cnx_id.id_len); - - length += picoquic_format_connection_id(&bytes[length], PICOQUIC_MAX_PACKET_SIZE - length, dest_cnx_id); - length += picoquic_format_connection_id(&bytes[length], PICOQUIC_MAX_PACKET_SIZE - length, srce_cnx_id); - - /* Reserve two bytes for payload length */ - bytes[length++] = 0; - bytes[length++] = 0; - /* Encode the length */ - *pn_offset = length; - picoformat_32(&bytes[length], (uint32_t)sequence_number); - length += 4; - } - - return length; -} - uint32_t picoquic_predict_packet_header_length_11( picoquic_packet_type_enum packet_type, picoquic_connection_id_t dest_cnx_id, @@ -286,45 +213,47 @@ uint32_t picoquic_predict_packet_header_length_11( return length; } - -uint32_t picoquic_create_packet_header_12( +uint32_t picoquic_create_packet_header( picoquic_cnx_t* cnx, picoquic_packet_type_enum packet_type, - picoquic_connection_id_t dest_cnx_id, - picoquic_connection_id_t srce_cnx_id, uint64_t sequence_number, uint8_t* bytes, - uint32_t * pn_offset) + uint32_t * pn_offset, + uint32_t * pn_length) { uint32_t length = 0; + picoquic_connection_id_t dest_cnx_id = + ((packet_type == picoquic_packet_initial && cnx->client_mode) || + packet_type == picoquic_packet_0rtt_protected) ? + cnx->initial_cnxid : cnx->remote_cnxid; /* Prepare the packet header */ if (packet_type == picoquic_packet_1rtt_protected_phi0 || packet_type == picoquic_packet_1rtt_protected_phi1) { /* Create a short packet -- using 32 bit sequence numbers for now */ uint8_t K = (packet_type == picoquic_packet_1rtt_protected_phi0) ? 0 : 0x40; const uint8_t C = 0x30; - uint8_t spin_vec = (uint8_t) (cnx->spin_vec ); - uint8_t spin_bit = (uint8_t)((cnx->current_spin) << 2); - - if (!cnx->spin_edge) spin_vec = 0; - else { - cnx->spin_edge = 0; - uint64_t dt = picoquic_get_quic_time(cnx->quic) - cnx->spin_last_trigger; - if (dt > PICOQUIC_SPIN_VEC_LATE) { // DELAYED - spin_vec = 1; - // fprintf(stderr, "Delayed Outgoing Spin=%d DT=%ld\n", cnx->current_spin, dt); - } - } - - length = 0; + uint8_t spin_vec = (uint8_t)(cnx->spin_vec); + uint8_t spin_bit = (uint8_t)((cnx->current_spin) << 2); + + if (!cnx->spin_edge) spin_vec = 0; + else { + cnx->spin_edge = 0; + uint64_t dt = picoquic_get_quic_time(cnx->quic) - cnx->spin_last_trigger; + if (dt > PICOQUIC_SPIN_VEC_LATE) { // DELAYED + spin_vec = 1; + // fprintf(stderr, "Delayed Outgoing Spin=%d DT=%ld\n", cnx->current_spin, dt); + } + } + + length = 0; bytes[length++] = (K | C | spin_bit | spin_vec); length += picoquic_format_connection_id(&bytes[length], PICOQUIC_MAX_PACKET_SIZE - length, dest_cnx_id); *pn_offset = length; + *pn_length = 4; picoquic_headint_encode_32(&bytes[length], sequence_number); length += 4; - } - else { + } else { /* Create a long packet */ switch (packet_type) { @@ -354,70 +283,70 @@ uint32_t picoquic_create_packet_header_12( } length += 4; - bytes[length++] = picoquic_create_packet_header_cnxid_lengths(dest_cnx_id.id_len, srce_cnx_id.id_len); + bytes[length++] = picoquic_create_packet_header_cnxid_lengths(dest_cnx_id.id_len, cnx->local_cnxid.id_len); length += picoquic_format_connection_id(&bytes[length], PICOQUIC_MAX_PACKET_SIZE - length, dest_cnx_id); - length += picoquic_format_connection_id(&bytes[length], PICOQUIC_MAX_PACKET_SIZE - length, srce_cnx_id); + length += picoquic_format_connection_id(&bytes[length], PICOQUIC_MAX_PACKET_SIZE - length, cnx->local_cnxid); /* Reserve two bytes for payload length */ bytes[length++] = 0; bytes[length++] = 0; - /* Encode the length */ + /* Encode the sequence number */ *pn_offset = length; + *pn_length = 4; picoquic_headint_encode_32(&bytes[length], sequence_number); length += 4; + /* Special case of packet initial */ + if (packet_type == picoquic_packet_initial) { + length += picoquic_varint_encode(&bytes[length], 16, cnx->retry_token_length); + if (cnx->retry_token_length > 0) { + memcpy(&bytes[length], cnx->retry_token, cnx->retry_token_length); + } + } } return length; } - uint32_t picoquic_predict_packet_header_length( picoquic_cnx_t* cnx, picoquic_packet_type_enum packet_type) { uint32_t header_length = 0; - switch (picoquic_supported_versions[cnx->version_index].version_header_encoding) { - case picoquic_version_header_11: - case picoquic_version_header_12: - header_length = picoquic_predict_packet_header_length_11(packet_type, - (packet_type == picoquic_packet_initial || - packet_type == picoquic_packet_0rtt_protected) ? - cnx->initial_cnxid : cnx->remote_cnxid, - cnx->local_cnxid); - break; - default: - break; + + if (packet_type == picoquic_packet_1rtt_protected_phi0 || + packet_type == picoquic_packet_1rtt_protected_phi1) { + /* Compute length of a short packet header */ + + header_length = 1 + cnx->remote_cnxid.id_len + 4; } - return header_length; -} + else { + /* Compute length of a long packet header */ + header_length = 1 + /* version */ 4 + /* cnx_id prefix */ 1; -uint32_t picoquic_create_packet_header( - picoquic_cnx_t* cnx, - picoquic_packet_type_enum packet_type, - uint64_t sequence_number, - uint8_t* bytes, - uint32_t * pn_offset) -{ - uint32_t header_length = 0; - switch (picoquic_supported_versions[cnx->version_index].version_header_encoding) { - case picoquic_version_header_11: - header_length = picoquic_create_packet_header_11(cnx, packet_type, - (packet_type==picoquic_packet_initial || - packet_type == picoquic_packet_0rtt_protected)? - cnx->initial_cnxid:cnx->remote_cnxid, - cnx->local_cnxid, sequence_number, bytes, pn_offset); - break; - case picoquic_version_header_12: - header_length = picoquic_create_packet_header_12(cnx, packet_type, - (packet_type == picoquic_packet_initial || - packet_type == picoquic_packet_0rtt_protected) ? - cnx->initial_cnxid : cnx->remote_cnxid, - cnx->local_cnxid, sequence_number, bytes, pn_offset); - break; - default: - break; + /* add dest-id length */ + if ((packet_type == picoquic_packet_initial && cnx->client_mode) || + packet_type == picoquic_packet_0rtt_protected) { + header_length += cnx->initial_cnxid.id_len; + } + else { + header_length += cnx->remote_cnxid.id_len; + } + + /* add srce-id length */ + header_length += cnx->local_cnxid.id_len; + + /* add length of payload length and packet number */ + header_length += 2 + 4; + + /* add length of tokens for initial packets */ + if (packet_type == picoquic_packet_initial) { + uint8_t useless[16]; + header_length += picoquic_varint_encode(useless, 16, cnx->retry_token_length); + header_length += cnx->retry_token_length; + } } + return header_length; } @@ -447,20 +376,17 @@ uint32_t picoquic_protect_packet(picoquic_cnx_t* cnx, { uint32_t send_length; uint32_t h_length; - uint32_t pnum_offset = 0; + uint32_t pn_offset = 0; + size_t sample_offset = 0; + size_t pn_length = 0; size_t aead_checksum_length = picoquic_aead_get_checksum_length(aead_context); /* Create the packet header just before encrypting the content */ h_length = picoquic_create_packet_header(cnx, ptype, - sequence_number, send_buffer, &pnum_offset); + sequence_number, send_buffer, &pn_offset, &pn_length); /* Make sure that the payload length is encoded in the header */ - if (picoquic_supported_versions[cnx->version_index].version_flags&picoquic_version_use_pn_encryption) - { - /* If using encryption, the "payload" length also includes the encrypted packet length */ - picoquic_update_payload_length(send_buffer, pnum_offset, pnum_offset, length + aead_checksum_length); - } else { - picoquic_update_payload_length(send_buffer, pnum_offset, h_length, length + aead_checksum_length); - } + /* Using encryption, the "payload" length also includes the encrypted packet length */ + picoquic_update_payload_length(send_buffer, pn_offset, h_length - pn_length, length + aead_checksum_length); send_length = (uint32_t)picoquic_aead_encrypt_generic(send_buffer + /* header_length */ h_length, bytes + header_length, length - header_length, @@ -468,24 +394,18 @@ uint32_t picoquic_protect_packet(picoquic_cnx_t* cnx, send_length += /* header_length */ h_length; - /* Next, encrypt the PN, if needed */ + /* Next, encrypt the PN -- The sample is located after the pn_offset */ + sample_offset = /* header_length */ pn_offset + 4; - if (picoquic_supported_versions[cnx->version_index].version_flags&picoquic_version_use_pn_encryption) + if (sample_offset + aead_checksum_length > send_length) { - /* The sample is located at the offset */ - size_t sample_offset = /* header_length */ h_length; - size_t pn_length = h_length - pnum_offset; - - if (sample_offset + aead_checksum_length > send_length) - { - sample_offset = length - aead_checksum_length; - } - if (pnum_offset < sample_offset) - { - /* Encode */ - picoquic_pn_encrypt(pn_enc, send_buffer + sample_offset, send_buffer + /* pn_offset */ pnum_offset, - send_buffer + /* pn_offset */ pnum_offset, pn_length); - } + sample_offset = length - aead_checksum_length; + } + if (pn_offset < sample_offset) + { + /* Encode */ + picoquic_pn_encrypt(pn_enc, send_buffer + sample_offset, send_buffer + /* pn_offset */ pn_offset, + send_buffer + /* pn_offset */ pn_offset, pn_length); } return send_length; @@ -747,12 +667,6 @@ int picoquic_retransmit_needed(picoquic_cnx_t* cnx, *header_length = length; - if (p->ptype < picoquic_packet_1rtt_protected_phi0) { - DBG_PRINTF("Retransmit packet type %d, pc=%d, seq = %llx, is_client = %d\n", - p->ptype, p->pc, - (unsigned long long)p->sequence_number, cnx->client_mode); - } - if (p->ptype == picoquic_packet_1rtt_protected_phi0 || p->ptype == picoquic_packet_1rtt_protected_phi1 || p->ptype == picoquic_packet_0rtt_protected) { *is_cleartext_mode = 0; } else { @@ -830,6 +744,12 @@ int picoquic_retransmit_needed(picoquic_cnx_t* cnx, } if (should_retransmit != 0) { + if (p->ptype < picoquic_packet_1rtt_protected_phi0) { + DBG_PRINTF("Retransmit packet type %d, pc=%d, seq = %llx, is_client = %d\n", + p->ptype, p->pc, + (unsigned long long)p->sequence_number, cnx->client_mode); + } + /* special case for the client initial */ if (p->ptype == picoquic_packet_initial && cnx->client_mode != 0) { while (length < (path_x->send_mtu - checksum_length)) { @@ -1632,7 +1552,7 @@ int picoquic_prepare_packet_server_init(picoquic_cnx_t* cnx, picoquic_path_t * p packet->checksum_overhead = checksum_overhead; } else { - /* when in a clear text mode, only send packets if there is + /* when in a handshake mode, only send packets if there is * actually something to send, or resend */ length = 0; packet->length = 0; diff --git a/picoquic_t/picoquic_t.c b/picoquic_t/picoquic_t.c index dae9fbe9..f5c96f7d 100644 --- a/picoquic_t/picoquic_t.c +++ b/picoquic_t/picoquic_t.c @@ -42,6 +42,7 @@ typedef enum { static const picoquic_test_def_t test_table[] = { { "picohash", picohash_test }, + { "splay", splay_test }, { "cnxcreation", cnxcreation_test }, { "parseheader", parseheadertest }, { "pn2pn64", pn2pn64test }, @@ -49,15 +50,16 @@ static const picoquic_test_def_t test_table[] = { { "fnv1a", fnv1atest }, { "float16", float16test }, { "varint", varint_test }, + { "sack", sacktest }, { "skip_frames", skip_frame_test }, + { "parse_frames", parse_frame_test }, + { "logger", logger_test }, { "TlsStreamFrame", TlsStreamFrameTest }, { "StreamZeroFrame", StreamZeroFrameTest }, - { "sack", sacktest }, { "sendack", sendacktest }, { "ackrange", ackrange_test }, { "ack_of_ack", ack_of_ack_test }, { "sim_link", sim_link_test }, - { "logger", logger_test }, { "tls_api", tls_api_test }, { "silence_test", tls_api_silence_test }, { "tls_api_version_negotiation", tls_api_version_negotiation_test }, @@ -118,9 +120,7 @@ static const picoquic_test_def_t test_table[] = { { "pn_vector", cleartext_pn_vector_test }, { "zero_rtt_spurious", zero_rtt_spurious_test }, { "zero_rtt_retry", zero_rtt_retry_test }, - { "parse_frames", parse_frame_test }, - { "stress", stress_test }, - { "splay", splay_test } + { "stress", stress_test } }; static size_t const nb_tests = sizeof(test_table) / sizeof(picoquic_test_def_t); diff --git a/picoquictest/parseheadertest.c b/picoquictest/parseheadertest.c index f99711f8..ea9a3e1b 100644 --- a/picoquictest/parseheadertest.c +++ b/picoquictest/parseheadertest.c @@ -76,6 +76,8 @@ static picoquic_packet_header hinitial10 = { picoquic_packet_context_initial, 0, 0, + 0, + 0, 0 }; @@ -105,6 +107,8 @@ static picoquic_packet_header hinitial10_l = { picoquic_packet_context_initial, 0, 0, + 0, + 0, 0 }; @@ -144,6 +148,8 @@ static picoquic_packet_header hvnego10 = { picoquic_packet_context_initial, 0, 0, + 0, + 0, 0 }; @@ -173,6 +179,8 @@ static picoquic_packet_header hhandshake = { picoquic_packet_context_handshake, 0, 0, + 0, + 0, 0 }; @@ -198,7 +206,9 @@ static picoquic_packet_header hphi0_c_32 = { picoquic_packet_context_application, 0, 0, - 1 + 1, + 0, + 0 }; static uint8_t packet_short_phi0_c_32_spin[] = { @@ -223,7 +233,9 @@ static picoquic_packet_header hphi0_c_32_spin = { picoquic_packet_context_application, 1, 0, - 1 + 1, + 0, + 0 }; static uint8_t packet_short_phi0_noc_32[] = { @@ -247,6 +259,8 @@ static picoquic_packet_header hphi0_noc_32 = { picoquic_packet_context_application, 0, 0, + 0, + 0, 0 }; @@ -350,6 +364,7 @@ int parseheadertest() for (size_t i = 0; ret == 0 && i < nb_test_entries; i++) { uint32_t header_length; uint32_t pn_offset; + uint32_t pn_length; if (test_entries[i].decode_test_only) { continue; @@ -359,7 +374,7 @@ int parseheadertest() memset(packet, 0xcc, sizeof(packet)); /* Prepare the header inside the packet */ header_length = picoquic_create_packet_header(cnx_10, test_entries[i].ph->ptype, - test_entries[i].ph->pn, packet, &pn_offset); + test_entries[i].ph->pn, packet, &pn_offset, &pn_length); picoquic_update_payload_length(packet, pn_offset, pn_offset, pn_offset + test_entries[i].ph->payload_length); diff --git a/picoquictest/tls_api_test.c b/picoquictest/tls_api_test.c index c5dcbf32..6c67fbc7 100644 --- a/picoquictest/tls_api_test.c +++ b/picoquictest/tls_api_test.c @@ -897,13 +897,53 @@ static int tls_api_data_sending_loop(picoquic_test_tls_api_ctx_t* test_ctx, return ret; /* end of sending loop */ } + +static int wait_application_pn_enc_ready(picoquic_test_tls_api_ctx_t* test_ctx, + uint64_t * simulated_time) +{ + int ret = 0; + uint64_t time_out = *simulated_time + 4000000; + int nb_trials = 0; + int nb_inactive = 0; + + while (*simulated_time < time_out && + test_ctx->cnx_client->cnx_state == picoquic_state_client_ready && + test_ctx->cnx_server->cnx_state == picoquic_state_server_ready && + test_ctx->cnx_server->crypto_context[3].aead_decrypt == NULL && + nb_trials < 1024 && + nb_inactive < 64 && + ret == 0) { + int was_active = 0; + nb_trials++; + + ret = tls_api_one_sim_round(test_ctx, simulated_time, &was_active); + + if (was_active) { + nb_inactive = 0; + } + else { + nb_inactive++; + } + } + + if (test_ctx->cnx_server->crypto_context[3].aead_decrypt == NULL) { + DBG_PRINTF("Could not obtain the 1-RTT decryption key, state = %d\n", + test_ctx->cnx_server->cnx_state); + ret = -1; + } + + return ret; +} + static int tls_api_attempt_to_close( picoquic_test_tls_api_ctx_t* test_ctx, uint64_t* simulated_time) { int ret = 0; int nb_rounds = 0; - ret = picoquic_close(test_ctx->cnx_client, 0); + if (ret == 0) { + ret = picoquic_close(test_ctx->cnx_client, 0); + } if (ret == 0) { /* packet from client to server */ @@ -1267,6 +1307,10 @@ int tls_api_server_reset_test() ret = tls_api_connection_loop(test_ctx, &loss_mask, 0, &simulated_time); } + if (ret == 0) { + ret = wait_application_pn_enc_ready(test_ctx, &simulated_time); + } + /* verify that client and server have the same reset secret */ if (ret == 0 && memcmp(test_ctx->cnx_client->reset_secret, test_ctx->cnx_server->reset_secret, PICOQUIC_RESET_SECRET_SIZE) != 0) { ret = -1; @@ -2474,35 +2518,7 @@ int pn_enc_1rtt_test() } if (ret == 0) { - uint64_t time_out = simulated_time + 4000000; - int nb_trials = 0; - int nb_inactive = 0; - - while (simulated_time <time_out && - test_ctx->cnx_client->cnx_state == picoquic_state_client_ready && - test_ctx->cnx_server->cnx_state == picoquic_state_server_ready && - test_ctx->cnx_server->crypto_context[3].aead_decrypt == NULL && - nb_trials < 1024 && - nb_inactive < 64 && - ret == 0) { - int was_active = 0; - nb_trials++; - - ret = tls_api_one_sim_round(test_ctx, &simulated_time, &was_active); - - if (was_active) { - nb_inactive = 0; - } - else { - nb_inactive++; - } - } - - if (test_ctx->cnx_server->crypto_context[3].aead_decrypt == NULL) { - DBG_PRINTF("Could not obtain the 1-RTT decryption key, state = %d\n", - test_ctx->cnx_server->cnx_state); - ret = -1; - } + ret = wait_application_pn_enc_ready(test_ctx, &simulated_time); } if (ret == 0) @@ -3288,6 +3304,10 @@ int client_error_test() ret = tls_api_connection_loop(test_ctx, &loss_mask, 0, &simulated_time); } + if (ret == 0){ + ret = wait_application_pn_enc_ready(test_ctx, &simulated_time); + } + if (ret == 0) { ret = tls_api_attempt_to_close(test_ctx, &simulated_time); } -- GitLab