nfqws: verify quic auth tag. improve initial packet detection

This commit is contained in:
bol-van 2022-03-26 21:00:58 +03:00
parent 3753349058
commit 2eec88c2bf
12 changed files with 57 additions and 41 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,38 +1,13 @@
#include "aes-gcm.h"
int aes_gcm_encrypt(unsigned char* output, const unsigned char* input, size_t input_length, const unsigned char* key, const size_t key_len, const unsigned char * iv, const size_t iv_len) {
int ret = 0; // our return value
gcm_context ctx; // includes the AES context structure
size_t tag_len = 0;
unsigned char * tag_buf = NULL;
int aes_gcm_crypt(int mode, uint8_t *output, const uint8_t *input, size_t input_length, const uint8_t *key, const size_t key_len, const uint8_t *iv, const size_t iv_len, const uint8_t *adata, size_t adata_len, uint8_t *atag, size_t atag_len)
{
int ret = 0;
gcm_context ctx;
gcm_setkey(&ctx, key, (const uint)key_len);
ret = gcm_crypt_and_tag(&ctx, ENCRYPT, iv, iv_len, NULL, 0,
input, output, input_length, tag_buf, tag_len);
ret = gcm_crypt_and_tag(&ctx, mode, iv, iv_len, adata, adata_len, input, output, input_length, atag, atag_len);
gcm_zero_ctx(&ctx);
return(ret);
return ret;
}
int aes_gcm_decrypt(unsigned char* output, const unsigned char* input, size_t input_length, const unsigned char* key, const size_t key_len, const unsigned char * iv, const size_t iv_len) {
int ret = 0; // our return value
gcm_context ctx; // includes the AES context structure
size_t tag_len = 0;
unsigned char * tag_buf = NULL;
gcm_setkey(&ctx, key, (const uint)key_len);
ret = gcm_crypt_and_tag(&ctx, DECRYPT, iv, iv_len, NULL, 0,
input, output, input_length, tag_buf, tag_len);
gcm_zero_ctx(&ctx);
return(ret);
}

View File

@ -2,5 +2,5 @@
#include "gcm.h"
int aes_gcm_encrypt(unsigned char* output, const unsigned char* input, size_t input_length, const unsigned char* key, const size_t key_len, const unsigned char * iv, const size_t iv_len);
int aes_gcm_decrypt(unsigned char* output, const unsigned char* input, size_t input_length, const unsigned char* key, const size_t key_len, const unsigned char * iv, const size_t iv_len);
// mode : ENCRYPT, DECRYPT
int aes_gcm_crypt(int mode, uint8_t *output, const uint8_t *input, size_t input_length, const uint8_t *key, const size_t key_len, const uint8_t *iv, const size_t iv_len, const uint8_t *adata, size_t adata_len, uint8_t *atag, size_t atag_len);

View File

@ -247,6 +247,10 @@ static bool is_quic_version_with_v1_labels(uint32_t version)
return true;
return is_quic_draft_max(QUICDraftVersion(version), 34);
}
static bool is_quic_v2(uint32_t version)
{
return version == 0x709A50C4;
}
static bool quic_hkdf_expand_label(const uint8_t *secret, uint8_t secret_len, const char *label, uint8_t *out, size_t out_len)
@ -424,7 +428,18 @@ bool QUICDecryptInitial(const uint8_t *data, size_t data_len, uint8_t *clean, si
*clean_len = cryptlen;
const uint8_t *decrypt_begin = data + pn_offset + pkn_len;
return !aes_gcm_decrypt(clean, decrypt_begin, cryptlen, aeskey, sizeof(aeskey), aesiv, sizeof(aesiv));
uint8_t atag[16],header[256];
size_t header_len = pn_offset + pkn_len;
if (header_len > sizeof(header)) return false; // not likely header will be so large
memcpy(header, data, header_len);
header[0] = packet0;
for(uint8_t i = 0; i < pkn_len; i++) header[header_len - 1 - i] = (uint8_t)(pkn >> (8 * i));
if (aes_gcm_crypt(DECRYPT, clean, decrypt_begin, cryptlen, aeskey, sizeof(aeskey), aesiv, sizeof(aesiv), header, header_len, atag, sizeof(atag)))
return false;
// check if message was decrypted correctly : good keys , no data corruption
return !memcmp(data + pn_offset + pkn_len + cryptlen, atag, 16);
}
bool QUICDefragCrypto(const uint8_t *clean,size_t clean_len, uint8_t *defrag,size_t *defrag_len)
@ -509,12 +524,38 @@ bool QUICExtractHostFromInitial(const uint8_t *data, size_t data_len, char *host
bool IsQUICInitial(const uint8_t *data, size_t len)
{
// long header, fixed bit, type=initial
if (len < 512 || (data[0] & 0xF0) != 0xC0) return false;
const uint8_t *p = data + 1;
uint32_t ver = ntohl(*(uint32_t*)p);
// too small packets are not likely to be initials with client hello
if (len < 256) return false;
// this also ensures long header
uint32_t ver = QUICExtractVersion(data,len);
if (QUICDraftVersion(ver) < 11) return false;
p += 4;
if (!*p || *p > QUIC_MAX_CID_LENGTH) return false;
return true;
// quic v1 : initial packets are 00b
// quic v2 : initial packets are 01b
if ((data[0] & 0x30) != (is_quic_v2(ver) ? 0x10 : 0x00)) return false;
uint64_t offset=5, sz;
// DCID. must be present
if (!data[offset] || data[offset] > QUIC_MAX_CID_LENGTH) return false;
offset += 1 + data[offset];
// SCID
if (data[offset] > QUIC_MAX_CID_LENGTH) return false;
offset += 1 + data[offset];
// token length
offset += tvb_get_varint(data + offset, &sz);
offset += sz;
if (offset >= len) return false;
// payload length
if ((offset + tvb_get_size(data[offset])) >= len) return false;
tvb_get_varint(data + offset, &sz);
offset += sz;
if (offset > len) return false;
// client hello cannot be too small. likely ACK
return sz>=96;
}