@@ -72,6 +72,7 @@ __attribute__((constructor)) static void register_this_plugin()
7272
7373// Print debug message if debugging is allowed.
7474
75+
7576#ifdef DEBUG_QUIC
7677# define DEBUG_MSG (format, ...) fprintf(stderr, format, ## __VA_ARGS__)
7778#else
@@ -105,11 +106,7 @@ QUICPlugin::QUICPlugin()
105106
106107 memset (decrypted_payload,0 ,1500 );
107108 memset (assembled_payload,0 ,1500 );
108- // decrypted_payload = nullptr;
109- decrypt_buffer_len = 0 ;
110109
111- // assembled_payload = nullptr;
112- assemble_buffer_len = 0 ;
113110
114111 final_payload = nullptr ;
115112
@@ -393,7 +390,7 @@ bool QUICPlugin::parse_tls(RecordExtQUIC *rec)
393390} // QUICPlugin::parse_tls
394391
395392// --------------------------------------------------------------------------------------------------------------------------------
396- // DECRYTP HEADER AND PAYLOAD
393+ // DECRYPT HEADER AND PAYLOAD
397394// --------------------------------------------------------------------------------------------------------------------------------
398395
399396bool QUICPlugin::expand_label (const char *label_prefix, const char *label, const uint8_t *context_hash,
@@ -749,38 +746,50 @@ bool QUICPlugin::quic_decrypt_header()
749746 }
750747
751748 EVP_CIPHER_CTX_free (ctx);
749+ // basically we create mask, as shown in code belove
752750 memcpy (mask, plaintext, sizeof (mask));
753751
754- // https://datatracker.ietf.org/doc/html/draft-ietf-quic-tls-22#section-5.4.1
752+ // https://www.rfc-editor.org/rfc/rfc9001.html#name-header-protection-applicati
753+
754+ /*
755+ code belove shows a sample algorithm for applying header protection.
756+
757+ mask = header_protection(hp_key, sample)
755758
756- // if (packet[0] & 0x80) == 0x80:
757- // # Long header: 4 bits masked
758- // packet[0] ^= mask[0] & 0x0f
759- // else:
760- // # Short header: 5 bits masked
761- // packet[0] ^= mask[0] & 0x1f
759+ pn_length = (packet[0] & 0x03) + 1
760+
761+ if (packet[0] & 0x80) == 0x80:
762+ # Long header: 4 bits masked
763+ packet[0] ^= mask[0] & 0x0f
764+ else:
765+ # Short header: 5 bits masked
766+ packet[0] ^= mask[0] & 0x1f
767+
768+ */
762769
770+
771+
763772 // we do not have to handle short header, Initial packets have only long header
764773
765774 first_byte = quic_h1->first_byte ;
766775 first_byte ^= mask[0 ] & 0x0f ;
767776 uint8_t pkn_len = (first_byte & 0x03 ) + 1 ;
768777
769- // set decrypted first byte
778+ // set deobfuscated first byte
770779 header[0 ] = first_byte;
771780
772781
773- // copy encrypted pkn into buffer
782+ // now we know pkn length, so copy pkn into buffer
774783 memcpy (&full_pkn, pkn, pkn_len);
775784
776785
777- // decrypt pkn
786+ // we now de-obsfuscate pkn
778787 for (unsigned int i = 0 ; i < pkn_len; i++) {
779788 packet_number |= (full_pkn[i] ^ mask[1 + i]) << (8 * (pkn_len - 1 - i));
780789 }
781790
782791
783- // after decrypting first byte , we know packet number length, so we can adjust payload start and lengths
792+ // after de-obfuscating pkn , we know exactly pkn length so we can correctly adjust start of payload
784793 payload = payload + pkn_len;
785794 payload_len = payload_len - pkn_len;
786795
@@ -794,6 +803,8 @@ bool QUICPlugin::quic_decrypt_header()
794803
795804
796805 // adjust nonce for payload decryption
806+ // https://www.rfc-editor.org/rfc/rfc9001.html#name-aead-usage
807+ // The exclusive OR of the padded packet number and the IV forms the AEAD nonce
797808 phton64 (nonce + sizeof (nonce) - 8 , pntoh64 (nonce + sizeof (nonce) - 8 ) ^ packet_number);
798809
799810 return true ;
@@ -841,11 +852,15 @@ bool QUICPlugin::quic_decrypt_payload()
841852 EVP_CIPHER_CTX_free (ctx);
842853 return false ;
843854 }
855+
856+ // SET NONCE and KEY
844857 if (!EVP_DecryptInit_ex (ctx, NULL , NULL , initial_secrets.key , nonce)) {
845858 DEBUG_MSG (" Payload decryption error, setting KEY and NONCE failed\n " );
846859 EVP_CIPHER_CTX_free (ctx);
847860 return false ;
848861 }
862+
863+ // SET ASSOCIATED DATA (HEADER with unprotected PKN)
849864 if (!EVP_DecryptUpdate (ctx, NULL , &len, header, header_len)) {
850865 DEBUG_MSG (" Payload decryption error, initializing authenticated data failed\n " );
851866 EVP_CIPHER_CTX_free (ctx);
@@ -886,12 +901,12 @@ bool QUICPlugin::quic_assemble()
886901 assembled_payload[0 ] = 0x06 ;
887902
888903
889- // compute end of payload
904+ // set end of payload
890905 uint8_t * payload_end = decrypted_payload + payload_len;
891906
892907 uint64_t offset = 0 ;
893- uint64_t offset_frame = 0 ;
894- uint64_t length = 0 ;
908+ uint64_t frame_offset = 0 ;
909+ uint64_t frame_length = 0 ;
895910
896911
897912 // loop through whole padding, the logic is check first fragment (check type and length), if it`s of type crypto
@@ -904,22 +919,24 @@ bool QUICPlugin::quic_assemble()
904919 // process of computing offset length and length field length, is same as above in extracting user agent
905920 if (*(decrypted_payload + offset) == CRYPTO) {
906921 offset += 1 ;
907- offset_frame = quic_get_variable_length (decrypted_payload,offset);
908-
909- length = quic_get_variable_length (decrypted_payload,offset);
910-
911- // copy crypto fragment into the buffer based on offset
912- // + 4 bytes is because of final crypto header (this header technically contains no important information, but we
913- // need the 4 bytes at the start because of compatibility with function which parse tls)
914- if (assembled_payload + offset_frame + 4 * sizeof (uint8_t ) < assembled_payload + 1500
922+
923+ frame_offset = quic_get_variable_length (decrypted_payload,offset);
924+ frame_length = quic_get_variable_length (decrypted_payload,offset);
925+
926+ // beware this part is tricky, tls parse data expects 4 bytes at the start of crypto frame (type(1), offset(1), length(2))
927+ // BUT google quic uses variable length of some fields (more precisely length can have variable length), we consider that
928+ // length field have 2 bytes, this is not wrong because length is not used in tls parse date.
929+ if (assembled_payload + frame_offset + 4 * sizeof (uint8_t ) < assembled_payload + 1500
915930 && decrypted_payload + offset < payload_end
916- && assembled_payload + offset_frame + 4 * sizeof (uint8_t ) + length < assembled_payload + 1500 )
931+ && assembled_payload + frame_offset + 4 * sizeof (uint8_t ) + frame_length < assembled_payload + 1500 )
917932 {
918- memcpy (assembled_payload + offset_frame + 4 * sizeof (uint8_t ), decrypted_payload + offset, length );
919- offset += length ;
933+ memcpy (assembled_payload + frame_offset + 4 * sizeof (uint8_t ), decrypted_payload + offset, frame_length );
934+ offset += frame_length ;
920935 } else {
921936 return false ;
922937 }
938+ // https://www.rfc-editor.org/rfc/rfc9000.html#name-frames-and-frame-types
939+ // only those frames can occure in initial packets
923940 } else if (*(decrypted_payload + offset) == PADDING
924941 || *(decrypted_payload + offset) == PING
925942 || *(decrypted_payload + offset) == ACK1
@@ -938,13 +955,22 @@ bool QUICPlugin::quic_assemble()
938955
939956bool QUICPlugin::quic_parse_data (const Packet &pkt)
940957{
958+
959+
941960 uint8_t *tmp_pointer = (uint8_t *) pkt.payload ;
942961 uint64_t offset = 0 ;
943962 const uint8_t *payload_end = (uint8_t *) pkt.payload + pkt.payload_len ;
944963
964+
965+
966+ // set header pointer to the start of header
945967 header = (uint8_t *) (tmp_pointer + offset); // set header pointer
946968
947- quic_h1 = (quic_header1 *) (tmp_pointer + offset); // read first byte, version and dcid length
969+
970+
971+
972+ // pointer to the first byte, version and dcid length
973+ quic_h1 = (quic_header1 *) (tmp_pointer + offset);
948974
949975
950976 if (quic_h1->version == 0x0 ) {
@@ -953,75 +979,91 @@ bool QUICPlugin::quic_parse_data(const Packet &pkt)
953979
954980 offset += sizeof (quic_header1);
955981
982+
983+
956984 if ((tmp_pointer + offset) > payload_end) {
957985 return false ;
958986 }
959987
988+
989+
990+ // if dcid length is not zero , read dcid
960991 if (quic_h1->dcid_len != 0 ) {
961- dcid = (tmp_pointer + offset); // set dcid if dcid length is not 0
992+ dcid = (tmp_pointer + offset);
993+ offset += quic_h1->dcid_len ;
962994 }
963- offset += quic_h1->dcid_len ;
964995
965- quic_h2 = (quic_header2 *) (tmp_pointer + offset); // read scid length
996+ if ((tmp_pointer + offset) > payload_end) {
997+ return false ;
998+ }
999+
1000+
1001+ // after dcid is scid length, so read scid length
1002+ quic_h2 = (quic_header2 *) (tmp_pointer + offset);
9661003
9671004 offset += sizeof (quic_header2);
9681005
9691006 if ((tmp_pointer + offset) > payload_end) {
9701007 return false ;
9711008 }
9721009
973- if (quic_h2->scid_len != 0 ) { // set scid if scid length is not 0
1010+
1011+ // if scid length is not zero, read scid
1012+ if (quic_h2->scid_len != 0 ) {
9741013 scid = (tmp_pointer + offset);
1014+ offset += quic_h2->scid_len ;
9751015 }
9761016
977- offset += quic_h2->scid_len ;
978-
9791017 if ((tmp_pointer + offset) > payload_end) {
9801018 return false ;
9811019 }
9821020
9831021
984- // token length has variable length based on first two bits, so we cant use structure
1022+ // token length has variable length based on first two bits, after this offset should point to the token
9851023 uint64_t token_length = quic_get_variable_length (tmp_pointer,offset);
9861024
9871025 if ((tmp_pointer + offset) > payload_end) {
9881026 return false ;
9891027 }
9901028
1029+ // after this offset should point after the token
9911030 offset += token_length;
9921031
9931032 if ((tmp_pointer + offset) > payload_end) {
9941033 return false ;
9951034 }
9961035
1036+
1037+ // same as token length, payload length has variable length, after this offset should point to the packet number
9971038 payload_len = quic_get_variable_length (tmp_pointer,offset);
9981039
9991040 if ((tmp_pointer + offset) > payload_end) {
10001041 return false ;
10011042 }
10021043
1003- pkn = (tmp_pointer + offset); // set packet number
10041044
1005- payload = (tmp_pointer + offset); // set payload start too, this pointer is adjusted later, because we do not know exact packet number length atm
1045+ // read packet number
1046+ pkn = (tmp_pointer + offset);
10061047
1007- offset += sizeof (uint8_t ) * 4 ; // skip packet number and go to sample start which is always after packet number(always assuming length of packet number == 4).
10081048
1009- sample = (tmp_pointer + offset); // set sample pointer
1049+ // read payload, we do not know packet number length, so payload will be adjusted later (after de-obfuscating header)
1050+ payload = (tmp_pointer + offset);
1051+
1052+
1053+ // read sample, sample is always assuming that packet number has length 4 bytes, so we do not need to know exact pkn length for reading sample.
1054+ offset += sizeof (uint8_t ) * 4 ;
1055+ sample = (tmp_pointer + offset);
10101056
10111057 if ((tmp_pointer + offset) > payload_end) {
10121058 return false ;
10131059 }
10141060
10151061
10161062 /* DO NOT SET header length this way , if packet contains more frames , pkt.payload_len is length of whole quic packet (so it contains length of all frames inside packet)
1017- * so then header length is not computed correctly. Instead of this approach calculate header length after decrypting packet number , this will ensure header length is computed correctly
1063+ * so then header length is not computed correctly. Instead of this approach calculate header length after de-obfuscating packet number , this will ensure header length is computed correctly
10181064 */
10191065 // header_len = pkt.payload_len - payload_len;
10201066
1021-
1022- if (payload_len > pkt.payload_len ) {
1023- return false ;
1024- }
10251067 return true ;
10261068} // QUICPlugin::quic_parse_data
10271069
@@ -1074,7 +1116,7 @@ bool QUICPlugin::process_quic(RecordExtQUIC *quic_data, const Packet &pkt)
10741116 return true ;
10751117 }
10761118 } else if (pkt.src_port == 443 ) {
1077- if (!quic_create_initial_secrets (CommSide::SERVER_IN,quic_data)) {
1119+ /* if (!quic_create_initial_secrets(CommSide::SERVER_IN,quic_data)) {
10781120 DEBUG_MSG("Error, creation of initial secrets failed (server side)\n");
10791121 return false;
10801122 }
@@ -1098,7 +1140,8 @@ bool QUICPlugin::process_quic(RecordExtQUIC *quic_data, const Packet &pkt)
10981140 }
10991141 else {
11001142 return true;
1101- }
1143+ }*/
1144+ return true ;
11021145 }
11031146 return false ;
11041147} // QUICPlugin::process_quic
0 commit comments