Skip to content

Commit 14e8321

Browse files
lukacanPavel Siska
authored andcommitted
QUIC: ack1,ack2,connection_close frames parsing added, refactor of supported implementation/versions (partially supported Qv2)
1 parent 8ea5418 commit 14e8321

File tree

2 files changed

+191
-40
lines changed

2 files changed

+191
-40
lines changed

process/quic.cpp

Lines changed: 188 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -41,11 +41,46 @@
4141
*
4242
*/
4343

44+
45+
46+
47+
// known versions
48+
/*
49+
0x00000000 -- version negotiation
50+
0x00000001 -- newest , rfc 9000
51+
0xff0000xx -- drafts (IETF)
52+
0x709a50c4 -- quic version 2 -- newest draft (IETF)
53+
0xff020000 -- quic version 2 draft 00
54+
55+
56+
Google
57+
0x51303433 -- Q043 -- no evidence -- based on google doc , this should not be encrypted
58+
0x51303434 -- Q044 -- no evidence
59+
0x51303436 -- Q046 -- wireshark cant parse -- based on google doc , this should not be encrypted
60+
0x51303530 -- Q050 -- looks like no TLS inside crypto
61+
62+
0x54303530 -- T050
63+
0x54303531 -- T051
64+
65+
66+
MVFST
67+
0xfaceb001 -- should be draft 22
68+
0xfaceb002 -- should be draft 27
69+
0xfaceb003 -- ?
70+
0xfaceb00e -- experimental
71+
0xfaceb010 -- mvfst alias
72+
0xfaceb00f -- MVFST_INVALID
73+
0xfaceb011 -- MVFST_EXPERIMENTAL2
74+
0xfaceb013 -- MVFST_EXPERIMENTAL3
75+
*/
76+
77+
4478
#include <iostream>
4579
#include <cstring>
4680
#include <sstream>
4781
#include <endian.h>
4882

83+
4984
#include <openssl/kdf.h>
5085
#include <openssl/evp.h>
5186

@@ -58,6 +93,8 @@
5893
#include "quic.hpp"
5994

6095

96+
int counter = 0;
97+
6198
namespace ipxp {
6299

63100
int RecordExtQUIC::REGISTERED_ID = -1;
@@ -72,7 +109,6 @@ __attribute__((constructor)) static void register_this_plugin()
72109

73110
// Print debug message if debugging is allowed.
74111

75-
76112
#ifdef DEBUG_QUIC
77113
# define DEBUG_MSG(format, ...) fprintf(stderr, format, ## __VA_ARGS__)
78114
#else
@@ -115,7 +151,7 @@ QUICPlugin::QUICPlugin()
115151
quic_ptr = nullptr;
116152

117153

118-
google_QUIC = false;
154+
ietf_quic = false;
119155
}
120156

121157
QUICPlugin::~QUICPlugin()
@@ -502,25 +538,28 @@ bool QUICPlugin::quic_derive_secrets(uint8_t *secret)
502538

503539
uint8_t QUICPlugin::quic_draft_version(uint32_t version)
504540
{
541+
542+
// this is IETF implementation, older version used
505543
if ((version >> 8) == 0xff0000) {
506544
return (uint8_t) version;
507545
}
508-
509546
switch (version) {
547+
// older mvfst version, but still used, based on draft 22, but salt 21 used
510548
case (0xfaceb001):
511549
return 22;
550+
// more used atm, salt 23 used
512551
case 0xfaceb002:
513552
case 0xfaceb00e:
514-
case 0x51303530:
515-
case 0x54303530:
516-
case 0x54303531:
517553
return 27;
518554
case (0x0a0a0a0a & 0x0F0F0F0F):
519555
return 29;
520-
case 0x00000001:
521-
return 33;
556+
// version 2 draft 00
557+
// newest
558+
case 0xff020000:
559+
case 0x709a50c4:
560+
return 100;
522561
default:
523-
return 0;
562+
return 255;
524563
}
525564
}
526565

@@ -538,23 +577,51 @@ bool QUICPlugin::quic_create_initial_secrets(CommSide side,RecordExtQUIC * rec)
538577
version = ntohl(version);
539578
rec->quic_version = version;
540579

541-
static const uint8_t handshake_salt_draft_22[SALT_LENGTH] = {
580+
// this salt is used to draft 7-9
581+
static const uint8_t handshake_salt_draft_7[SALT_LENGTH] = {
582+
0xaf, 0xc8, 0x24, 0xec, 0x5f, 0xc7, 0x7e, 0xca, 0x1e, 0x9d,
583+
0x36, 0xf3, 0x7f, 0xb2, 0xd4, 0x65, 0x18, 0xc3, 0x66, 0x39
584+
};
585+
// this salt is used to draft 10-16
586+
static const uint8_t handshake_salt_draft_10[SALT_LENGTH] = {
587+
0x9c, 0x10, 0x8f, 0x98, 0x52, 0x0a, 0x5c, 0x5c, 0x32, 0x96,
588+
0x8e, 0x95, 0x0e, 0x8a, 0x2c, 0x5f, 0xe0, 0x6d, 0x6c, 0x38
589+
};
590+
// this salt is used to draft 17-20
591+
static const uint8_t handshake_salt_draft_17[SALT_LENGTH] = {
592+
0xef, 0x4f, 0xb0, 0xab, 0xb4, 0x74, 0x70, 0xc4, 0x1b, 0xef,
593+
0xcf, 0x80, 0x31, 0x33, 0x4f, 0xae, 0x48, 0x5e, 0x09, 0xa0
594+
};
595+
// this salt is used to draft 21-22
596+
static const uint8_t handshake_salt_draft_21[SALT_LENGTH] = {
542597
0x7f, 0xbc, 0xdb, 0x0e, 0x7c, 0x66, 0xbb, 0xe9, 0x19, 0x3a,
543598
0x96, 0xcd, 0x21, 0x51, 0x9e, 0xbd, 0x7a, 0x02, 0x64, 0x4a
544599
};
600+
// this salt is used to draft 23-28
545601
static const uint8_t handshake_salt_draft_23[SALT_LENGTH] = {
546602
0xc3, 0xee, 0xf7, 0x12, 0xc7, 0x2e, 0xbb, 0x5a, 0x11, 0xa7,
547603
0xd2, 0x43, 0x2b, 0xb4, 0x63, 0x65, 0xbe, 0xf9, 0xf5, 0x02,
548604
};
605+
// this salt is used to draft 29-32
549606
static const uint8_t handshake_salt_draft_29[SALT_LENGTH] = {
550607
0xaf, 0xbf, 0xec, 0x28, 0x99, 0x93, 0xd2, 0x4c, 0x9e, 0x97,
551608
0x86, 0xf1, 0x9c, 0x61, 0x11, 0xe0, 0x43, 0x90, 0xa8, 0x99
552609
};
610+
// newest 33 -
553611
static const uint8_t handshake_salt_v1[SALT_LENGTH] = {
554612
0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17,
555613
0x9a, 0xe6, 0xa4, 0xc8, 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a
556614
};
557-
static const uint8_t hanshake_salt_draft_q50[SALT_LENGTH] = {
615+
616+
static const uint8_t handshake_salt_v2[SALT_LENGTH] = {
617+
0xa7, 0x07, 0xc2, 0x03, 0xa5, 0x9b, 0x47, 0x18, 0x4a, 0x1d,
618+
0x62, 0xca, 0x57, 0x04, 0x06, 0xea, 0x7a, 0xe3, 0xe5, 0xd3
619+
};
620+
621+
622+
623+
// google salts
624+
/*static const uint8_t hanshake_salt_draft_q50[SALT_LENGTH] = {
558625
0x50, 0x45, 0x74, 0xEF, 0xD0, 0x66, 0xFE, 0x2F, 0x9D, 0x94,
559626
0x5C, 0xFC, 0xDB, 0xD3, 0xA7, 0xF0, 0xD3, 0xB5, 0x6B, 0x45
560627
};
@@ -565,37 +632,47 @@ bool QUICPlugin::quic_create_initial_secrets(CommSide side,RecordExtQUIC * rec)
565632
static const uint8_t hanshake_salt_draft_t51[SALT_LENGTH] = {
566633
0x7a, 0x4e, 0xde, 0xf4, 0xe7, 0xcc, 0xee, 0x5f, 0xa4, 0x50,
567634
0x6c, 0x19, 0x12, 0x4f, 0xc8, 0xcc, 0xda, 0x6e, 0x03, 0x3d
568-
};
635+
};*/
569636

570637

571638
const uint8_t *salt;
572639

573640

574641
// these three are Google QUIC version
575-
if (version == 0x51303530) {
576-
salt = hanshake_salt_draft_q50;
577-
google_QUIC = true;
578-
} else if (version == 0x54303530) {
579-
salt = hanshake_salt_draft_t50;
580-
google_QUIC = true;
581-
} else if (version == 0x54303531) {
582-
salt = hanshake_salt_draft_t51;
583-
google_QUIC = true;
642+
643+
// we do not parse gQUIC
644+
if (version == 0x00000000) {
645+
DEBUG_MSG("Error, version negotiation\n");
646+
return false;
647+
} else if (version == 0x00000001){
648+
salt = handshake_salt_v1;
649+
ietf_quic = true;
650+
} else if (quic_check_version(version, 9)) {
651+
salt = handshake_salt_draft_7;
652+
ietf_quic = true;
653+
} else if (quic_check_version(version, 16)) {
654+
salt = handshake_salt_draft_10;
655+
ietf_quic = true;
656+
} else if (quic_check_version(version, 20)) {
657+
salt = handshake_salt_draft_17;
658+
ietf_quic = true;
584659
} else if (quic_check_version(version, 22)) {
585-
salt = handshake_salt_draft_22;
586-
google_QUIC = false;
660+
salt = handshake_salt_draft_21;
661+
ietf_quic = true;
587662
} else if (quic_check_version(version, 28)) {
588663
salt = handshake_salt_draft_23;
589-
google_QUIC = false;
664+
ietf_quic = true;
590665
} else if (quic_check_version(version, 32)) {
591666
salt = handshake_salt_draft_29;
592-
google_QUIC = false;
667+
ietf_quic = true;
668+
} else if (quic_check_version(version, 100)) {
669+
salt = handshake_salt_v2;
670+
ietf_quic = true;
593671
} else {
594-
salt = handshake_salt_v1;
595-
google_QUIC = false;
672+
DEBUG_MSG("Error, version not supported\n");
673+
return false;
596674
}
597675

598-
599676
uint8_t extracted_secret[HASH_SHA2_256_LENGTH] = { 0 };
600677
uint8_t expanded_secret[HASH_SHA2_256_LENGTH] = { 0 };
601678
size_t expd_len = HASH_SHA2_256_LENGTH;
@@ -790,9 +867,12 @@ bool QUICPlugin::quic_decrypt_header()
790867

791868

792869
// after de-obfuscating pkn, we know exactly pkn length so we can correctly adjust start of payload
870+
DEBUG_MSG("PPKN LEN %d\n",pkn_len);
793871
payload = payload + pkn_len;
794872
payload_len = payload_len - pkn_len;
795873

874+
DEBUG_MSG("PAYLOAD LEN %d\n",payload_len);
875+
796876
// SET HEADER LENGTH, if header length is set incorrectly AEAD will calculate wrong tag, so decryption will fail
797877
header_len = payload - header;
798878

@@ -937,14 +1017,74 @@ bool QUICPlugin::quic_assemble()
9371017
}
9381018
// https://www.rfc-editor.org/rfc/rfc9000.html#name-frames-and-frame-types
9391019
// only those frames can occure in initial packets
1020+
} else if (*(decrypted_payload + offset) == ACK1)
1021+
{
1022+
// https://www.rfc-editor.org/rfc/rfc9000.html#name-ack-frames
1023+
//skip type
1024+
offset++;
1025+
uint64_t quic_largest_acknowledged = quic_get_variable_length(decrypted_payload,offset);
1026+
uint64_t quic_ack_delay = quic_get_variable_length(decrypted_payload,offset);
1027+
uint64_t quic_ack_range_count = quic_get_variable_length(decrypted_payload,offset);
1028+
uint64_t quic_first_ack_range = quic_get_variable_length(decrypted_payload,offset);
1029+
1030+
1031+
uint64_t quic_gap;
1032+
uint64_t quic_ack_range_length;
1033+
1034+
for (uint x = 0 ; x < quic_ack_range_count;x++)
1035+
{
1036+
quic_gap = quic_get_variable_length(decrypted_payload,offset);
1037+
quic_ack_range_length = quic_get_variable_length(decrypted_payload,offset);
1038+
}
1039+
1040+
} else if (*(decrypted_payload + offset) == ACK2)
1041+
{
1042+
// https://www.rfc-editor.org/rfc/rfc9000.html#name-ack-frames
1043+
//skip type
1044+
offset++;
1045+
uint64_t quic_largest_acknowledged = quic_get_variable_length(decrypted_payload,offset);
1046+
uint64_t quic_ack_delay = quic_get_variable_length(decrypted_payload,offset);
1047+
uint64_t quic_ack_range_count = quic_get_variable_length(decrypted_payload,offset);
1048+
uint64_t quic_first_ack_range = quic_get_variable_length(decrypted_payload,offset);
1049+
1050+
1051+
uint64_t quic_gap;
1052+
uint64_t quic_ack_range_length;
1053+
1054+
for (uint x = 0 ; x < quic_ack_range_count;x++)
1055+
{
1056+
quic_gap = quic_get_variable_length(decrypted_payload,offset);
1057+
quic_ack_range_length = quic_get_variable_length(decrypted_payload,offset);
1058+
}
1059+
1060+
uint64_t ect0 = quic_get_variable_length(decrypted_payload,offset);
1061+
uint64_t ect1 = quic_get_variable_length(decrypted_payload,offset);
1062+
uint64_t ecn_ce = quic_get_variable_length(decrypted_payload,offset);
1063+
1064+
1065+
} else if (*(decrypted_payload + offset) == CONNECTION_CLOSE1)
1066+
{
1067+
//skip type
1068+
offset++;
1069+
1070+
uint64_t error_code = quic_get_variable_length(decrypted_payload,offset);
1071+
uint64_t frame_type = quic_get_variable_length(decrypted_payload,offset);
1072+
uint64_t reason_phrase_length = quic_get_variable_length(decrypted_payload,offset);
1073+
offset+= reason_phrase_length;
1074+
1075+
} else if (*(decrypted_payload + offset) == CONNECTION_CLOSE2)
1076+
{
1077+
//skip type
1078+
offset++;
1079+
uint64_t error_code = quic_get_variable_length(decrypted_payload,offset);
1080+
uint64_t reason_phrase_length = quic_get_variable_length(decrypted_payload,offset);
1081+
offset+= reason_phrase_length;
1082+
9401083
} else if (*(decrypted_payload + offset) == PADDING
941-
|| *(decrypted_payload + offset) == PING
942-
|| *(decrypted_payload + offset) == ACK1
943-
|| *(decrypted_payload + offset) == ACK2
944-
|| *(decrypted_payload + offset) == CONNECTION_CLOSE)
1084+
|| *(decrypted_payload + offset) == PING)
9451085
{
9461086
offset++;
947-
} else{
1087+
}else{
9481088
DEBUG_MSG("Wrong Frame type read during frames assemble\n");
9491089
return false;
9501090
}
@@ -1073,9 +1213,19 @@ bool QUICPlugin::quic_check_initial(uint8_t packet0)
10731213
return (packet0 & 0xB0) == 0x80;
10741214
}
10751215

1216+
10761217
bool QUICPlugin::process_quic(RecordExtQUIC *quic_data, const Packet &pkt)
10771218
{
10781219

1220+
1221+
DEBUG_MSG("COUNTER %d\n",counter++);
1222+
DEBUG_MSG("FIRST %02x\n",pkt.payload[0] & 0xB0);
1223+
DEBUG_MSG("FIRSTTT %02x\n",pkt.payload[0]);
1224+
1225+
1226+
memset(decrypted_payload,0,1500);
1227+
memset(assembled_payload,0,1500);
1228+
10791229
// check if packet contains LONG HEADER and is of type INITIAL
10801230
if (pkt.ip_proto != 17 || !quic_check_initial(pkt.payload[0])) {
10811231
DEBUG_MSG("Packet is not Initial or does not contains LONG HEADER\n");
@@ -1102,12 +1252,12 @@ bool QUICPlugin::process_quic(RecordExtQUIC *quic_data, const Packet &pkt)
11021252
DEBUG_MSG("Error, payload decryption failed (client side)\n");
11031253
return false;
11041254
}
1105-
if (!google_QUIC && !quic_assemble())
1255+
if (ietf_quic && !quic_assemble())
11061256
{
11071257
DEBUG_MSG("Error, reassembling of crypto frames failed (client side)\n");
11081258
return false;
11091259
}
1110-
if (!google_QUIC && !parse_tls(quic_data))
1260+
if (ietf_quic && !parse_tls(quic_data))
11111261
{
11121262
DEBUG_MSG("SNI and User Agent Extraction failed\n");
11131263
return false;
@@ -1128,12 +1278,12 @@ bool QUICPlugin::process_quic(RecordExtQUIC *quic_data, const Packet &pkt)
11281278
DEBUG_MSG("Error, payload decryption failed (server side)\n");
11291279
return false;
11301280
}
1131-
if (!google_QUIC && !quic_assemble())
1281+
if (ietf_quic && !quic_assemble())
11321282
{
11331283
DEBUG_MSG("Error, reassembling of crypto frames failed (server side)\n");
11341284
return false;
11351285
}
1136-
if (!google_QUIC && !parse_tls(quic_data))
1286+
if (ietf_quic && !parse_tls(quic_data))
11371287
{
11381288
DEBUG_MSG("SNI and User Agent Extraction failed\n");
11391289
return false;
@@ -1147,7 +1297,7 @@ bool QUICPlugin::process_quic(RecordExtQUIC *quic_data, const Packet &pkt)
11471297
} // QUICPlugin::process_quic
11481298

11491299
int QUICPlugin::pre_create(Packet &pkt)
1150-
{
1300+
{
11511301
return 0;
11521302
}
11531303

process/quic.hpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ UR_FIELDS(
104104
#define PING 0x01
105105
#define ACK1 0x02
106106
#define ACK2 0x03
107-
#define CONNECTION_CLOSE 0x1C
107+
#define CONNECTION_CLOSE1 0x1C
108+
#define CONNECTION_CLOSE2 0x1D
108109

109110

110111
typedef struct __attribute__ ((packed)) quic_ext {
@@ -307,7 +308,7 @@ class QUICPlugin : public ProcessPlugin
307308
Initial_Secrets initial_secrets;
308309

309310

310-
bool google_QUIC;
311+
bool ietf_quic;
311312
};
312313

313314
}

0 commit comments

Comments
 (0)