825 lines
27 KiB
C
825 lines
27 KiB
C
/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */
|
|
#include <assert.h>
|
|
#include <stdbool.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include <zlib.h>
|
|
|
|
#include <openssl/ssl.h>
|
|
#ifndef WIN32
|
|
#else
|
|
#include <stdlib.h>
|
|
#include <vc_compat.h>
|
|
#endif
|
|
|
|
#include "lsquic_int_types.h"
|
|
#include "lsquic_crypto.h"
|
|
#include "lsquic_crt_compress.h"
|
|
#include "lsquic_util.h"
|
|
|
|
#include "lsquic_str.h"
|
|
|
|
#include "common_cert_set_2.c"
|
|
#include "common_cert_set_3.c"
|
|
|
|
/*
|
|
* common_cert_sub_strings contains ~1500 bytes of common certificate substrings
|
|
* as a dictionary of zlib from the Alexa Top 5000 set.
|
|
*/
|
|
static const unsigned char common_cert_sub_strings[] = {
|
|
0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04,
|
|
0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03,
|
|
0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30,
|
|
0x5f, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x04, 0x01,
|
|
0x06, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd, 0x6d, 0x01, 0x07,
|
|
0x17, 0x01, 0x30, 0x33, 0x20, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65,
|
|
0x64, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e,
|
|
0x20, 0x53, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x34,
|
|
0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31,
|
|
0x32, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72,
|
|
0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x30, 0x2d, 0x61, 0x69, 0x61, 0x2e,
|
|
0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d,
|
|
0x2f, 0x45, 0x2d, 0x63, 0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73,
|
|
0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x45, 0x2e, 0x63, 0x65,
|
|
0x72, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
|
|
0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x4a, 0x2e, 0x63,
|
|
0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73,
|
|
0x2f, 0x63, 0x70, 0x73, 0x20, 0x28, 0x63, 0x29, 0x30, 0x30, 0x09, 0x06,
|
|
0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x30, 0x0d,
|
|
0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
|
|
0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x7b, 0x30, 0x1d, 0x06, 0x03, 0x55,
|
|
0x1d, 0x0e, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
|
|
0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
|
|
0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd2,
|
|
0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x2e,
|
|
0x63, 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
|
|
0x04, 0x14, 0xb4, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69,
|
|
0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x30, 0x0b, 0x06, 0x03,
|
|
0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x30, 0x0d, 0x06, 0x09,
|
|
0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
|
|
0x81, 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
|
|
0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08,
|
|
0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30,
|
|
0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74,
|
|
0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03,
|
|
0x55, 0x04, 0x0a, 0x13, 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64, 0x64, 0x79,
|
|
0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x33,
|
|
0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x68, 0x74, 0x74,
|
|
0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
|
|
0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79,
|
|
0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74,
|
|
0x6f, 0x72, 0x79, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03,
|
|
0x13, 0x27, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x53,
|
|
0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
|
|
0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
|
|
0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
|
|
0x04, 0x05, 0x13, 0x08, 0x30, 0x37, 0x39, 0x36, 0x39, 0x32, 0x38, 0x37,
|
|
0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
|
|
0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0c,
|
|
0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00,
|
|
0x30, 0x1d, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
|
|
0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55,
|
|
0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
|
|
0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
|
|
0x03, 0x02, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
|
|
0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x33, 0x06, 0x03, 0x55, 0x1d,
|
|
0x1f, 0x04, 0x2c, 0x30, 0x2a, 0x30, 0x28, 0xa0, 0x26, 0xa0, 0x24, 0x86,
|
|
0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e,
|
|
0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
|
0x67, 0x64, 0x73, 0x31, 0x2d, 0x32, 0x30, 0x2a, 0x30, 0x28, 0x06, 0x08,
|
|
0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74,
|
|
0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65,
|
|
0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63,
|
|
0x70, 0x73, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17,
|
|
0x0d, 0x31, 0x33, 0x30, 0x35, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, 0x01,
|
|
0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x3a,
|
|
0x2f, 0x2f, 0x73, 0x30, 0x39, 0x30, 0x37, 0x06, 0x08, 0x2b, 0x06, 0x01,
|
|
0x05, 0x05, 0x07, 0x02, 0x30, 0x44, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04,
|
|
0x3d, 0x30, 0x3b, 0x30, 0x39, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86,
|
|
0xf8, 0x45, 0x01, 0x07, 0x17, 0x06, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
|
|
0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x1b, 0x53, 0x31, 0x17,
|
|
0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72,
|
|
0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31,
|
|
0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, 0x65,
|
|
0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74,
|
|
0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x3b, 0x30, 0x39,
|
|
0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x32, 0x54, 0x65, 0x72, 0x6d, 0x73,
|
|
0x20, 0x6f, 0x66, 0x20, 0x75, 0x73, 0x65, 0x20, 0x61, 0x74, 0x20, 0x68,
|
|
0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76,
|
|
0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
|
|
0x72, 0x70, 0x61, 0x20, 0x28, 0x63, 0x29, 0x30, 0x31, 0x10, 0x30, 0x0e,
|
|
0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x53, 0x31, 0x13, 0x30, 0x11,
|
|
0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x47, 0x31, 0x13, 0x30, 0x11,
|
|
0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x3c, 0x02, 0x01,
|
|
0x03, 0x13, 0x02, 0x55, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04,
|
|
0x03, 0x14, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
|
|
0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0f, 0x13, 0x14, 0x50,
|
|
0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x20, 0x4f, 0x72, 0x67, 0x61, 0x6e,
|
|
0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x12, 0x31, 0x21, 0x30,
|
|
0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x44, 0x6f, 0x6d, 0x61,
|
|
0x69, 0x6e, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x20, 0x56,
|
|
0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x31, 0x14, 0x31, 0x31,
|
|
0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x28, 0x53, 0x65, 0x65,
|
|
0x20, 0x77, 0x77, 0x77, 0x2e, 0x72, 0x3a, 0x2f, 0x2f, 0x73, 0x65, 0x63,
|
|
0x75, 0x72, 0x65, 0x2e, 0x67, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53,
|
|
0x69, 0x67, 0x6e, 0x31, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x41,
|
|
0x2e, 0x63, 0x72, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e,
|
|
0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x45, 0x63, 0x72,
|
|
0x6c, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63,
|
|
0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x73, 0x64, 0x31, 0x1a,
|
|
0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x3a,
|
|
0x2f, 0x2f, 0x45, 0x56, 0x49, 0x6e, 0x74, 0x6c, 0x2d, 0x63, 0x63, 0x72,
|
|
0x74, 0x2e, 0x67, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x69, 0x63, 0x65, 0x72,
|
|
0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x31, 0x6f, 0x63, 0x73, 0x70, 0x2e,
|
|
0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d,
|
|
0x30, 0x39, 0x72, 0x61, 0x70, 0x69, 0x64, 0x73, 0x73, 0x6c, 0x2e, 0x63,
|
|
0x6f, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63,
|
|
0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72,
|
|
0x79, 0x2f, 0x30, 0x81, 0x80, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
|
|
0x07, 0x01, 0x01, 0x04, 0x74, 0x30, 0x72, 0x30, 0x24, 0x06, 0x08, 0x2b,
|
|
0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74,
|
|
0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6f, 0x64,
|
|
0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x4a, 0x06,
|
|
0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x3e, 0x68,
|
|
0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66,
|
|
0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64,
|
|
0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73,
|
|
0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x67, 0x64, 0x5f, 0x69, 0x6e, 0x74,
|
|
0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72,
|
|
0x74, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
|
|
0x80, 0x14, 0xfd, 0xac, 0x61, 0x32, 0x93, 0x6c, 0x45, 0xd6, 0xe2, 0xee,
|
|
0x85, 0x5f, 0x9a, 0xba, 0xe7, 0x76, 0x99, 0x68, 0xcc, 0xe7, 0x30, 0x27,
|
|
0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x86, 0x30,
|
|
0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73,
|
|
};
|
|
|
|
#define common_certs_num 2
|
|
const common_cert_t common_cert_set[common_certs_num] = {
|
|
{common_certs2_num, common_certs2, common_certs2_lens, common_certs2_hash},
|
|
{common_certs3_num, common_certs3, common_certs3_lens, common_certs3_hash},
|
|
};
|
|
|
|
|
|
static lsquic_str_t *s_ccsbuf;
|
|
|
|
static int
|
|
match_common_cert (lsquic_str_t * cert, lsquic_str_t * common_set_hashes,
|
|
uint64_t* out_hash, uint32_t* out_index);
|
|
|
|
int
|
|
lsquic_crt_init (void)
|
|
{
|
|
unsigned i;
|
|
|
|
s_ccsbuf = lsquic_str_new(NULL, 0);
|
|
if (!s_ccsbuf)
|
|
return -1;
|
|
for (i=0 ;i<common_certs_num; ++i)
|
|
{
|
|
if (0 != lsquic_str_append(s_ccsbuf, (const char *)&common_cert_set[i].hash, 8))
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
lsquic_str_t *
|
|
lsquic_get_common_certs_hash()
|
|
{
|
|
return s_ccsbuf;
|
|
}
|
|
|
|
|
|
/* return 0 found, -1 not found */
|
|
int
|
|
lsquic_get_common_cert(uint64_t hash, uint32_t index, lsquic_str_t *buf)
|
|
{
|
|
int i;
|
|
for (i = 0; i < common_certs_num; i++)
|
|
{
|
|
if (common_cert_set[i].hash == hash)
|
|
{
|
|
if (index < common_cert_set[i].num_certs)
|
|
{
|
|
lsquic_str_setto(buf, (const char *) common_cert_set[i].certs[index],
|
|
common_cert_set[i].lens[index]);
|
|
return 0;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
|
|
static int
|
|
comp_ls_str (lsquic_str_t * a, const void * b, size_t b_len)
|
|
{
|
|
size_t a_len;
|
|
int r;
|
|
|
|
a_len = lsquic_str_len(a);
|
|
r = memcmp(lsquic_str_buf(a), b, a_len < b_len ? a_len : b_len);
|
|
if (r)
|
|
return r;
|
|
else
|
|
return (a_len > b_len) - (b_len > a_len);
|
|
}
|
|
|
|
|
|
/* 0, matched -1, error */
|
|
static int
|
|
match_common_cert (lsquic_str_t * cert, lsquic_str_t * common_set_hashes,
|
|
uint64_t* out_hash, uint32_t* out_index)
|
|
{
|
|
size_t i, j;
|
|
int n;
|
|
uint64_t hash;
|
|
size_t min, max, mid;
|
|
|
|
if (lsquic_str_len(common_set_hashes) % sizeof(uint64_t) != 0)
|
|
return -1;
|
|
|
|
for (i = 0; i < lsquic_str_len(common_set_hashes) / sizeof(uint64_t); i++)
|
|
{
|
|
memcpy(&hash, lsquic_str_buf(common_set_hashes) + i * sizeof(uint64_t),
|
|
sizeof(uint64_t));
|
|
|
|
for (j = 0; j < common_certs_num; j++)
|
|
{
|
|
if (common_cert_set[j].hash != hash)
|
|
continue;
|
|
|
|
if (common_cert_set[j].num_certs == 0)
|
|
continue;
|
|
|
|
min = 0;
|
|
max = common_cert_set[j].num_certs - 1;
|
|
while (max >= min)
|
|
{
|
|
mid = min + ((max - min) / 2);
|
|
n = comp_ls_str(cert, common_cert_set[j].certs[mid],
|
|
common_cert_set[j].lens[mid]);
|
|
if (n < 0)
|
|
{
|
|
if (mid == 0)
|
|
break;
|
|
max = mid - 1;
|
|
}
|
|
else if (n > 0)
|
|
min = mid + 1;
|
|
else
|
|
{
|
|
*out_hash = hash;
|
|
*out_index = mid;
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
|
|
/* result is written to dict */
|
|
static void
|
|
make_zlib_dict_for_entries(cert_entry_t *entries,
|
|
lsquic_str_t **certs, size_t certs_count,
|
|
lsquic_str_t *dict)
|
|
{
|
|
int i;
|
|
size_t zlib_dict_size = 0;
|
|
for (i = certs_count - 1; i >= 0; --i)
|
|
{
|
|
if (entries[i].type != ENTRY_COMPRESSED)
|
|
{
|
|
zlib_dict_size += lsquic_str_len(certs[i]);
|
|
}
|
|
}
|
|
|
|
// At the end of the dictionary is a block of common certificate substrings.
|
|
zlib_dict_size += sizeof(common_cert_sub_strings);
|
|
|
|
for (i = certs_count - 1; i >= 0; --i)
|
|
{
|
|
if (entries[i].type != ENTRY_COMPRESSED)
|
|
{
|
|
lsquic_str_append(dict, lsquic_str_buf(certs[i]), lsquic_str_len(certs[i]));
|
|
}
|
|
}
|
|
|
|
lsquic_str_append(dict, (const char *)common_cert_sub_strings, sizeof(common_cert_sub_strings));
|
|
assert((size_t)lsquic_str_len(dict) == zlib_dict_size);
|
|
}
|
|
|
|
|
|
static
|
|
void get_certs_hash(lsquic_str_t *certs, size_t certs_count, uint64_t *hashs)
|
|
{
|
|
size_t i;
|
|
for(i = 0; i < certs_count; ++i)
|
|
{
|
|
hashs[i] = lsquic_fnv1a_64((const uint8_t *)lsquic_str_buf(&certs[i]), lsquic_str_len(&certs[i]));
|
|
}
|
|
}
|
|
|
|
|
|
static void get_certs_entries(lsquic_str_t **certs, size_t certs_count,
|
|
lsquic_str_t *client_common_set_hashes,
|
|
lsquic_str_t *client_cached_cert_hashes,
|
|
cert_entry_t *entries)
|
|
{
|
|
size_t i;
|
|
int j;
|
|
cert_entry_t *entry;
|
|
uint64_t hash, cached_hash;
|
|
bool cached;
|
|
|
|
const bool cached_valid = (lsquic_str_len(client_cached_cert_hashes) % sizeof(uint64_t) == 0)
|
|
&& (lsquic_str_len(client_cached_cert_hashes) > 0);
|
|
|
|
assert(&entries[certs_count - 1]);
|
|
|
|
for (i = 0; i<certs_count; ++i)
|
|
{
|
|
entry = &entries[i];
|
|
if (cached_valid)
|
|
{
|
|
cached = false;
|
|
hash = lsquic_fnv1a_64((const uint8_t *)lsquic_str_buf(certs[i]), lsquic_str_len(certs[i]));
|
|
|
|
for (j = 0; j < (int)lsquic_str_len(client_cached_cert_hashes);
|
|
j += sizeof(uint64_t))
|
|
{
|
|
memcpy(&cached_hash, lsquic_str_buf(client_cached_cert_hashes) + j,
|
|
sizeof(uint64_t));
|
|
if (hash != cached_hash)
|
|
continue;
|
|
|
|
entry->type = ENTRY_CACHED;
|
|
entry->hash = hash;
|
|
cached = true;
|
|
break;
|
|
}
|
|
|
|
if (cached)
|
|
continue;
|
|
}
|
|
|
|
if (0 == match_common_cert(certs[i], client_common_set_hashes,
|
|
&entry->set_hash, &entry->index))
|
|
{
|
|
entry->type = ENTRY_COMMON;
|
|
continue;
|
|
}
|
|
|
|
entry->type = ENTRY_COMPRESSED;
|
|
}
|
|
}
|
|
|
|
static size_t
|
|
get_entries_size(cert_entry_t *entries, size_t entries_count)
|
|
{
|
|
size_t i;
|
|
size_t entries_size = 0;
|
|
for(i=0; i<entries_count; ++i)
|
|
{
|
|
entries_size++;
|
|
switch (entries[i].type)
|
|
{
|
|
case ENTRY_COMPRESSED:
|
|
break;
|
|
case ENTRY_CACHED:
|
|
entries_size += sizeof(uint64_t);
|
|
break;
|
|
case ENTRY_COMMON:
|
|
entries_size += sizeof(uint64_t) + sizeof(uint32_t);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
entries_size++; /* for end marker */
|
|
return entries_size;
|
|
}
|
|
|
|
static
|
|
void serialize_cert_entries(uint8_t* out, int *out_len, cert_entry_t *entries,
|
|
size_t entries_count)
|
|
{
|
|
size_t i;
|
|
uint8_t *start = out;
|
|
for(i=0; i<entries_count; ++i)
|
|
{
|
|
*out++ = (uint8_t)(entries[i].type);
|
|
switch (entries[i].type)
|
|
{
|
|
case ENTRY_COMPRESSED:
|
|
break;
|
|
case ENTRY_CACHED:
|
|
memcpy(out, &entries[i].hash, sizeof(uint64_t));
|
|
out += sizeof(uint64_t);
|
|
break;
|
|
case ENTRY_COMMON:
|
|
memcpy(out, &entries[i].set_hash, sizeof(uint64_t));
|
|
out += sizeof(uint64_t);
|
|
memcpy(out, &entries[i].index, sizeof(uint32_t));
|
|
out += sizeof(uint32_t);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
*out++ = 0; // end marker
|
|
*out_len = out - start;
|
|
}
|
|
|
|
|
|
int
|
|
lsquic_get_certs_count (const struct compressed_cert *ccert)
|
|
{
|
|
const unsigned char *in = ccert->buf;
|
|
const unsigned char *in_end = in + ccert->len;
|
|
size_t idx = 0;
|
|
uint8_t type_byte;
|
|
|
|
for (;;)
|
|
{
|
|
if (in >= in_end)
|
|
return -1;
|
|
|
|
type_byte = in[0];
|
|
++in;
|
|
if (type_byte == 0)
|
|
break;
|
|
|
|
++idx;
|
|
switch(type_byte)
|
|
{
|
|
case ENTRY_COMPRESSED:
|
|
break;
|
|
case ENTRY_CACHED:
|
|
{
|
|
if (in_end - in < (int)sizeof(uint64_t))
|
|
return -1;
|
|
in += sizeof(uint64_t);
|
|
break;
|
|
}
|
|
case ENTRY_COMMON:
|
|
{
|
|
if (in_end - in < (int)(sizeof(uint64_t) + sizeof(uint32_t)))
|
|
return -1;
|
|
in += sizeof(uint64_t) + sizeof(uint32_t);
|
|
break;
|
|
}
|
|
default:
|
|
return -1;
|
|
}
|
|
}
|
|
return idx;
|
|
}
|
|
|
|
|
|
/* return 0: OK, -1, error */
|
|
static int parse_entries(const unsigned char **in_out, const unsigned char *const in_end,
|
|
lsquic_str_t *cached_certs, size_t cached_certs_count,
|
|
cert_entry_t *out_entries,
|
|
lsquic_str_t **out_certs, size_t *out_certs_count)
|
|
{
|
|
const unsigned char *in = *in_out;
|
|
size_t idx = 0;
|
|
uint64_t* cached_hashes;
|
|
cert_entry_t *entry;
|
|
lsquic_str_t *cert;
|
|
uint8_t type_byte;
|
|
int rv;
|
|
size_t i;
|
|
|
|
cached_hashes = NULL;
|
|
|
|
for (;;)
|
|
{
|
|
/* XXX potential invalid read */
|
|
type_byte = in[0];
|
|
++in;
|
|
|
|
if (type_byte == 0)
|
|
break;
|
|
|
|
entry = &out_entries[idx];
|
|
cert = out_certs[idx];
|
|
/* XXX This seems dangerous -- there is no guard that `idx' does not
|
|
* exceed `out_certs_count'.
|
|
*/
|
|
lsquic_str_d(cert);
|
|
|
|
++idx;
|
|
entry->type = type_byte;
|
|
switch (entry->type)
|
|
{
|
|
case ENTRY_COMPRESSED:
|
|
break;
|
|
case ENTRY_CACHED:
|
|
{
|
|
memcpy(&entry->hash, in, sizeof(uint64_t));
|
|
in += sizeof(uint64_t);
|
|
|
|
if (!cached_hashes)
|
|
{
|
|
cached_hashes = malloc(cached_certs_count * sizeof(uint64_t));;
|
|
if (!cached_hashes)
|
|
goto err;
|
|
get_certs_hash(cached_certs, cached_certs_count, cached_hashes);
|
|
}
|
|
|
|
for (i=0; i<cached_certs_count; ++i)
|
|
{
|
|
if (cached_hashes[i] == entry->hash)
|
|
{
|
|
lsquic_str_append(cert, lsquic_str_buf(&cached_certs[i]),
|
|
lsquic_str_len(&cached_certs[i]));
|
|
break;
|
|
}
|
|
}
|
|
/* XXX: return -1 if not found? Logic removed in
|
|
4fd7e76bc031ac637e76c7f0930aff53f5b71705 */
|
|
break;
|
|
}
|
|
case ENTRY_COMMON:
|
|
{
|
|
memcpy(&entry->set_hash, in, sizeof(uint64_t));
|
|
in += sizeof(uint64_t);
|
|
memcpy(&entry->index, in, sizeof(uint32_t));
|
|
in += sizeof(uint32_t);
|
|
|
|
if (0 == lsquic_get_common_cert(entry->set_hash, entry->index, cert))
|
|
break;
|
|
else
|
|
goto err;
|
|
}
|
|
default:
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
rv = 0;
|
|
*in_out = in;
|
|
*out_certs_count = idx;
|
|
|
|
cleanup:
|
|
free(cached_hashes);
|
|
return rv;
|
|
|
|
err:
|
|
rv = -1;
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
struct compressed_cert *
|
|
lsquic_compress_certs (lsquic_str_t **certs, size_t certs_count,
|
|
lsquic_str_t *client_common_set_hashes,
|
|
lsquic_str_t *client_cached_cert_hashes)
|
|
{
|
|
size_t i;
|
|
size_t uncompressed_size = 0, compressed_size = 0 ;
|
|
z_stream z;
|
|
lsquic_str_t *dict;
|
|
size_t entries_size, result_length;
|
|
int out_len;
|
|
uint8_t* out;
|
|
uint32_t tmp_size_32;
|
|
cert_entry_t *entries;
|
|
struct compressed_cert *ccert;
|
|
|
|
ccert = NULL;
|
|
entries = malloc(sizeof(cert_entry_t) * certs_count);
|
|
if (!entries)
|
|
return NULL;
|
|
|
|
dict = lsquic_str_new(NULL, 0);
|
|
if (!dict)
|
|
goto err;
|
|
|
|
get_certs_entries(certs, certs_count, client_common_set_hashes,
|
|
client_cached_cert_hashes, entries);
|
|
|
|
for (i = 0; i < certs_count; i++)
|
|
{
|
|
if (entries[i].type == ENTRY_COMPRESSED)
|
|
{
|
|
/*uint32_t length + cert content*/
|
|
uncompressed_size += 4 + lsquic_str_len(certs[i]);
|
|
}
|
|
}
|
|
|
|
if (uncompressed_size > 0)
|
|
{
|
|
memset(&z, 0, sizeof(z));
|
|
if (Z_OK != deflateInit(&z, Z_DEFAULT_COMPRESSION))
|
|
goto err;
|
|
|
|
make_zlib_dict_for_entries(entries, certs, certs_count, dict);
|
|
if(Z_OK != deflateSetDictionary(&z, (const unsigned char *)lsquic_str_buf(dict), lsquic_str_len(dict)))
|
|
goto err;
|
|
compressed_size = deflateBound(&z, uncompressed_size);
|
|
}
|
|
|
|
entries_size = get_entries_size(entries, certs_count);
|
|
result_length = entries_size + (uncompressed_size > 0 ? 4 : 0) +
|
|
compressed_size;
|
|
ccert = malloc(sizeof(*ccert) + result_length);
|
|
if (!ccert)
|
|
goto err;
|
|
ccert->refcnt = 0;
|
|
|
|
out = ccert->buf;
|
|
serialize_cert_entries(out, &out_len, entries, certs_count);
|
|
out += entries_size;
|
|
|
|
if (uncompressed_size == 0)
|
|
{
|
|
ccert->len = entries_size;
|
|
goto cleanup;
|
|
}
|
|
|
|
tmp_size_32 = uncompressed_size;
|
|
memcpy(out, &tmp_size_32, sizeof(uint32_t));
|
|
out += sizeof(uint32_t);
|
|
|
|
z.next_out = out;
|
|
z.avail_out = compressed_size;
|
|
|
|
for (i = 0; i < certs_count; ++i)
|
|
{
|
|
if (entries[i].type != ENTRY_COMPRESSED)
|
|
continue;
|
|
|
|
tmp_size_32 = lsquic_str_len(certs[i]);
|
|
z.next_in = (uint8_t*)(&tmp_size_32);
|
|
z.avail_in = sizeof(tmp_size_32);
|
|
if (Z_OK != deflate(&z, Z_NO_FLUSH) || z.avail_in)
|
|
goto err;
|
|
z.next_in = (unsigned char *)lsquic_str_buf(certs[i]);
|
|
z.avail_in = lsquic_str_len(certs[i]);
|
|
if (Z_OK != deflate(&z, Z_NO_FLUSH) || z.avail_in)
|
|
goto err;
|
|
}
|
|
|
|
z.avail_in = 0;
|
|
if (Z_STREAM_END != deflate(&z, Z_FINISH))
|
|
goto err;
|
|
|
|
ccert->len = result_length - z.avail_out;
|
|
|
|
cleanup:
|
|
free(entries);
|
|
if (dict)
|
|
lsquic_str_delete(dict);
|
|
if (uncompressed_size)
|
|
deflateEnd(&z);
|
|
return ccert;
|
|
|
|
err:
|
|
if (ccert)
|
|
free(ccert);
|
|
ccert = NULL;
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
/* 0: ok */
|
|
int
|
|
lsquic_decompress_certs (const unsigned char *in, const unsigned char *in_end,
|
|
lsquic_str_t *cached_certs, size_t cached_certs_count,
|
|
lsquic_str_t **out_certs, size_t *out_certs_count)
|
|
{
|
|
int ret;
|
|
size_t i;
|
|
uint8_t* uncompressed_data, *uncompressed_data_buf;
|
|
lsquic_str_t *dict;
|
|
uint32_t uncompressed_size;
|
|
size_t count = *out_certs_count;
|
|
cert_entry_t *entries;
|
|
z_stream z;
|
|
|
|
assert(*out_certs_count > 0 && *out_certs_count < 10000
|
|
&& "Call lsquic_get_certs_count() to get right certificates count first and make enough room for out_certs_count");
|
|
|
|
if (count == 0 || count > 10000)
|
|
return -1;
|
|
|
|
dict = lsquic_str_new(NULL, 0);
|
|
if (!dict)
|
|
return -1;
|
|
|
|
uncompressed_data_buf = NULL;
|
|
#ifdef WIN32
|
|
uncompressed_data = NULL;
|
|
#endif
|
|
entries = malloc(count * sizeof(cert_entry_t));
|
|
if (!entries)
|
|
goto err;
|
|
|
|
ret = parse_entries(&in, in_end, cached_certs, cached_certs_count,
|
|
entries, out_certs, out_certs_count);
|
|
if (ret)
|
|
goto err;
|
|
|
|
/* re-assign count with real valus */
|
|
count = *out_certs_count;
|
|
|
|
if (in < in_end)
|
|
{
|
|
if (in_end - in < (int)sizeof(uint32_t))
|
|
goto err;
|
|
|
|
memcpy(&uncompressed_size, in, sizeof(uncompressed_size));
|
|
in += sizeof(uint32_t);
|
|
/* XXX Is 128 KB an arbitrary limit or is there a reason behind it? */
|
|
if (uncompressed_size > 128 * 1024)
|
|
goto err;
|
|
|
|
uncompressed_data_buf = uncompressed_data = malloc(uncompressed_size);
|
|
if (!uncompressed_data)
|
|
goto err;
|
|
|
|
memset(&z, 0, sizeof(z));
|
|
z.next_out = uncompressed_data;
|
|
z.avail_out = uncompressed_size;
|
|
z.next_in = (unsigned char *) in;
|
|
z.avail_in = in_end - in;
|
|
|
|
if (Z_OK != inflateInit(&z))
|
|
goto err;
|
|
|
|
ret = inflate(&z, Z_FINISH);
|
|
if (ret == Z_NEED_DICT)
|
|
{
|
|
lsquic_str_d(dict);
|
|
make_zlib_dict_for_entries(entries, out_certs, count, dict);
|
|
if (Z_OK != inflateSetDictionary(&z, (const unsigned char *)lsquic_str_buf(dict), lsquic_str_len(dict)))
|
|
goto err;
|
|
ret = inflate(&z, Z_FINISH);
|
|
}
|
|
|
|
if (Z_STREAM_END != ret || z.avail_out > 0 || z.avail_in > 0)
|
|
goto err;
|
|
}
|
|
else
|
|
uncompressed_size = 0;
|
|
|
|
for (i = 0; i < count; i++)
|
|
{
|
|
switch (entries[i].type)
|
|
{
|
|
case ENTRY_COMPRESSED:
|
|
if (uncompressed_size < sizeof(uint32_t))
|
|
goto err;
|
|
lsquic_str_d(out_certs[i]);
|
|
uint32_t cert_len;
|
|
memcpy(&cert_len, uncompressed_data, sizeof(cert_len));
|
|
uncompressed_data += sizeof(uint32_t);
|
|
uncompressed_size -= sizeof(uint32_t);
|
|
if (uncompressed_size < cert_len)
|
|
goto err;
|
|
lsquic_str_append(out_certs[i], (const char *)uncompressed_data, cert_len);
|
|
uncompressed_data += cert_len;
|
|
uncompressed_size -= cert_len;
|
|
break;
|
|
case ENTRY_CACHED:
|
|
case ENTRY_COMMON:
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
cleanup:
|
|
lsquic_str_delete(dict);
|
|
free(entries);
|
|
if (uncompressed_data_buf)
|
|
inflateEnd(&z);
|
|
free(uncompressed_data_buf);
|
|
if (0 == uncompressed_size)
|
|
return 0;
|
|
else
|
|
return -1;
|
|
|
|
err:
|
|
uncompressed_size = 1; /* This triggers return -1 above */
|
|
goto cleanup;
|
|
}
|
|
|
|
|
|
void
|
|
lsquic_crt_cleanup (void)
|
|
{
|
|
if (s_ccsbuf)
|
|
{
|
|
lsquic_str_delete(s_ccsbuf);
|
|
s_ccsbuf = NULL;
|
|
}
|
|
}
|