lsquic_crt_compress.c revision 2f4629f2
17d09751dSDmitri Tikhonov/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc.  See LICENSE. */
250aadb33SDmitri Tikhonov#include <assert.h>
350aadb33SDmitri Tikhonov#include <stdbool.h>
450aadb33SDmitri Tikhonov#include <string.h>
550aadb33SDmitri Tikhonov#include <time.h>
650aadb33SDmitri Tikhonov#include <zlib.h>
750aadb33SDmitri Tikhonov
850aadb33SDmitri Tikhonov#include <openssl/ssl.h>
9461e84d8SAmol Deshpande#ifndef WIN32
10461e84d8SAmol Deshpande#else
11461e84d8SAmol Deshpande#include <stdlib.h>
12461e84d8SAmol Deshpande#include <vc_compat.h>
13461e84d8SAmol Deshpande#endif
1450aadb33SDmitri Tikhonov
1550aadb33SDmitri Tikhonov#include "lsquic_int_types.h"
1650aadb33SDmitri Tikhonov#include "lsquic_crypto.h"
1750aadb33SDmitri Tikhonov#include "lsquic_crt_compress.h"
1850aadb33SDmitri Tikhonov#include "lsquic_util.h"
1950aadb33SDmitri Tikhonov
2050aadb33SDmitri Tikhonov#include "lsquic_str.h"
2150aadb33SDmitri Tikhonov
2250aadb33SDmitri Tikhonov#include "common_cert_set_2.c"
2350aadb33SDmitri Tikhonov#include "common_cert_set_3.c"
2450aadb33SDmitri Tikhonov
2550aadb33SDmitri Tikhonov/*
2650aadb33SDmitri Tikhonov * common_cert_sub_strings contains ~1500 bytes of common certificate substrings
2750aadb33SDmitri Tikhonov * as a dictionary of zlib from the Alexa Top 5000 set.
2850aadb33SDmitri Tikhonov */
2950aadb33SDmitri Tikhonovstatic const unsigned char common_cert_sub_strings[] = {
3050aadb33SDmitri Tikhonov    0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04,
3150aadb33SDmitri Tikhonov    0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03,
3250aadb33SDmitri Tikhonov    0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30,
3350aadb33SDmitri Tikhonov    0x5f, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x04, 0x01,
3450aadb33SDmitri Tikhonov    0x06, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd, 0x6d, 0x01, 0x07,
3550aadb33SDmitri Tikhonov    0x17, 0x01, 0x30, 0x33, 0x20, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65,
3650aadb33SDmitri Tikhonov    0x64, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e,
3750aadb33SDmitri Tikhonov    0x20, 0x53, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x34,
3850aadb33SDmitri Tikhonov    0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31,
3950aadb33SDmitri Tikhonov    0x32, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72,
4050aadb33SDmitri Tikhonov    0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x30, 0x2d, 0x61, 0x69, 0x61, 0x2e,
4150aadb33SDmitri Tikhonov    0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d,
4250aadb33SDmitri Tikhonov    0x2f, 0x45, 0x2d, 0x63, 0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73,
4350aadb33SDmitri Tikhonov    0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x45, 0x2e, 0x63, 0x65,
4450aadb33SDmitri Tikhonov    0x72, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
4550aadb33SDmitri Tikhonov    0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x4a, 0x2e, 0x63,
4650aadb33SDmitri Tikhonov    0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73,
4750aadb33SDmitri Tikhonov    0x2f, 0x63, 0x70, 0x73, 0x20, 0x28, 0x63, 0x29, 0x30, 0x30, 0x09, 0x06,
4850aadb33SDmitri Tikhonov    0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x30, 0x0d,
4950aadb33SDmitri Tikhonov    0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
5050aadb33SDmitri Tikhonov    0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x7b, 0x30, 0x1d, 0x06, 0x03, 0x55,
5150aadb33SDmitri Tikhonov    0x1d, 0x0e, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
5250aadb33SDmitri Tikhonov    0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
5350aadb33SDmitri Tikhonov    0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd2,
5450aadb33SDmitri Tikhonov    0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x2e,
5550aadb33SDmitri Tikhonov    0x63, 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
5650aadb33SDmitri Tikhonov    0x04, 0x14, 0xb4, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69,
5750aadb33SDmitri Tikhonov    0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x30, 0x0b, 0x06, 0x03,
5850aadb33SDmitri Tikhonov    0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x30, 0x0d, 0x06, 0x09,
5950aadb33SDmitri Tikhonov    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
6050aadb33SDmitri Tikhonov    0x81, 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
6150aadb33SDmitri Tikhonov    0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08,
6250aadb33SDmitri Tikhonov    0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30,
6350aadb33SDmitri Tikhonov    0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74,
6450aadb33SDmitri Tikhonov    0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03,
6550aadb33SDmitri Tikhonov    0x55, 0x04, 0x0a, 0x13, 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64, 0x64, 0x79,
6650aadb33SDmitri Tikhonov    0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x33,
6750aadb33SDmitri Tikhonov    0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x68, 0x74, 0x74,
6850aadb33SDmitri Tikhonov    0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
6950aadb33SDmitri Tikhonov    0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79,
7050aadb33SDmitri Tikhonov    0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74,
7150aadb33SDmitri Tikhonov    0x6f, 0x72, 0x79, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03,
7250aadb33SDmitri Tikhonov    0x13, 0x27, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x53,
7350aadb33SDmitri Tikhonov    0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
7450aadb33SDmitri Tikhonov    0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
7550aadb33SDmitri Tikhonov    0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
7650aadb33SDmitri Tikhonov    0x04, 0x05, 0x13, 0x08, 0x30, 0x37, 0x39, 0x36, 0x39, 0x32, 0x38, 0x37,
7750aadb33SDmitri Tikhonov    0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
7850aadb33SDmitri Tikhonov    0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0c,
7950aadb33SDmitri Tikhonov    0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00,
8050aadb33SDmitri Tikhonov    0x30, 0x1d, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
8150aadb33SDmitri Tikhonov    0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55,
8250aadb33SDmitri Tikhonov    0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
8350aadb33SDmitri Tikhonov    0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
8450aadb33SDmitri Tikhonov    0x03, 0x02, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
8550aadb33SDmitri Tikhonov    0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x33, 0x06, 0x03, 0x55, 0x1d,
8650aadb33SDmitri Tikhonov    0x1f, 0x04, 0x2c, 0x30, 0x2a, 0x30, 0x28, 0xa0, 0x26, 0xa0, 0x24, 0x86,
8750aadb33SDmitri Tikhonov    0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e,
8850aadb33SDmitri Tikhonov    0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
8950aadb33SDmitri Tikhonov    0x67, 0x64, 0x73, 0x31, 0x2d, 0x32, 0x30, 0x2a, 0x30, 0x28, 0x06, 0x08,
9050aadb33SDmitri Tikhonov    0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74,
9150aadb33SDmitri Tikhonov    0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65,
9250aadb33SDmitri Tikhonov    0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63,
9350aadb33SDmitri Tikhonov    0x70, 0x73, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17,
9450aadb33SDmitri Tikhonov    0x0d, 0x31, 0x33, 0x30, 0x35, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, 0x01,
9550aadb33SDmitri Tikhonov    0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x3a,
9650aadb33SDmitri Tikhonov    0x2f, 0x2f, 0x73, 0x30, 0x39, 0x30, 0x37, 0x06, 0x08, 0x2b, 0x06, 0x01,
9750aadb33SDmitri Tikhonov    0x05, 0x05, 0x07, 0x02, 0x30, 0x44, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04,
9850aadb33SDmitri Tikhonov    0x3d, 0x30, 0x3b, 0x30, 0x39, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86,
9950aadb33SDmitri Tikhonov    0xf8, 0x45, 0x01, 0x07, 0x17, 0x06, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
10050aadb33SDmitri Tikhonov    0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x1b, 0x53, 0x31, 0x17,
10150aadb33SDmitri Tikhonov    0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72,
10250aadb33SDmitri Tikhonov    0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31,
10350aadb33SDmitri Tikhonov    0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, 0x65,
10450aadb33SDmitri Tikhonov    0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74,
10550aadb33SDmitri Tikhonov    0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x3b, 0x30, 0x39,
10650aadb33SDmitri Tikhonov    0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x32, 0x54, 0x65, 0x72, 0x6d, 0x73,
10750aadb33SDmitri Tikhonov    0x20, 0x6f, 0x66, 0x20, 0x75, 0x73, 0x65, 0x20, 0x61, 0x74, 0x20, 0x68,
10850aadb33SDmitri Tikhonov    0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76,
10950aadb33SDmitri Tikhonov    0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
11050aadb33SDmitri Tikhonov    0x72, 0x70, 0x61, 0x20, 0x28, 0x63, 0x29, 0x30, 0x31, 0x10, 0x30, 0x0e,
11150aadb33SDmitri Tikhonov    0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x53, 0x31, 0x13, 0x30, 0x11,
11250aadb33SDmitri Tikhonov    0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x47, 0x31, 0x13, 0x30, 0x11,
11350aadb33SDmitri Tikhonov    0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x3c, 0x02, 0x01,
11450aadb33SDmitri Tikhonov    0x03, 0x13, 0x02, 0x55, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04,
11550aadb33SDmitri Tikhonov    0x03, 0x14, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
11650aadb33SDmitri Tikhonov    0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0f, 0x13, 0x14, 0x50,
11750aadb33SDmitri Tikhonov    0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x20, 0x4f, 0x72, 0x67, 0x61, 0x6e,
11850aadb33SDmitri Tikhonov    0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x12, 0x31, 0x21, 0x30,
11950aadb33SDmitri Tikhonov    0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x44, 0x6f, 0x6d, 0x61,
12050aadb33SDmitri Tikhonov    0x69, 0x6e, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x20, 0x56,
12150aadb33SDmitri Tikhonov    0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x31, 0x14, 0x31, 0x31,
12250aadb33SDmitri Tikhonov    0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x28, 0x53, 0x65, 0x65,
12350aadb33SDmitri Tikhonov    0x20, 0x77, 0x77, 0x77, 0x2e, 0x72, 0x3a, 0x2f, 0x2f, 0x73, 0x65, 0x63,
12450aadb33SDmitri Tikhonov    0x75, 0x72, 0x65, 0x2e, 0x67, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53,
12550aadb33SDmitri Tikhonov    0x69, 0x67, 0x6e, 0x31, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x41,
12650aadb33SDmitri Tikhonov    0x2e, 0x63, 0x72, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e,
12750aadb33SDmitri Tikhonov    0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x45, 0x63, 0x72,
12850aadb33SDmitri Tikhonov    0x6c, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63,
12950aadb33SDmitri Tikhonov    0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x73, 0x64, 0x31, 0x1a,
13050aadb33SDmitri Tikhonov    0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x3a,
13150aadb33SDmitri Tikhonov    0x2f, 0x2f, 0x45, 0x56, 0x49, 0x6e, 0x74, 0x6c, 0x2d, 0x63, 0x63, 0x72,
13250aadb33SDmitri Tikhonov    0x74, 0x2e, 0x67, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x69, 0x63, 0x65, 0x72,
13350aadb33SDmitri Tikhonov    0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x31, 0x6f, 0x63, 0x73, 0x70, 0x2e,
13450aadb33SDmitri Tikhonov    0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d,
13550aadb33SDmitri Tikhonov    0x30, 0x39, 0x72, 0x61, 0x70, 0x69, 0x64, 0x73, 0x73, 0x6c, 0x2e, 0x63,
13650aadb33SDmitri Tikhonov    0x6f, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63,
13750aadb33SDmitri Tikhonov    0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72,
13850aadb33SDmitri Tikhonov    0x79, 0x2f, 0x30, 0x81, 0x80, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
13950aadb33SDmitri Tikhonov    0x07, 0x01, 0x01, 0x04, 0x74, 0x30, 0x72, 0x30, 0x24, 0x06, 0x08, 0x2b,
14050aadb33SDmitri Tikhonov    0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74,
14150aadb33SDmitri Tikhonov    0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6f, 0x64,
14250aadb33SDmitri Tikhonov    0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x4a, 0x06,
14350aadb33SDmitri Tikhonov    0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x3e, 0x68,
14450aadb33SDmitri Tikhonov    0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66,
14550aadb33SDmitri Tikhonov    0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64,
14650aadb33SDmitri Tikhonov    0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73,
14750aadb33SDmitri Tikhonov    0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x67, 0x64, 0x5f, 0x69, 0x6e, 0x74,
14850aadb33SDmitri Tikhonov    0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72,
14950aadb33SDmitri Tikhonov    0x74, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
15050aadb33SDmitri Tikhonov    0x80, 0x14, 0xfd, 0xac, 0x61, 0x32, 0x93, 0x6c, 0x45, 0xd6, 0xe2, 0xee,
15150aadb33SDmitri Tikhonov    0x85, 0x5f, 0x9a, 0xba, 0xe7, 0x76, 0x99, 0x68, 0xcc, 0xe7, 0x30, 0x27,
15250aadb33SDmitri Tikhonov    0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x86, 0x30,
15350aadb33SDmitri Tikhonov    0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73,
15450aadb33SDmitri Tikhonov};
15550aadb33SDmitri Tikhonov
15650aadb33SDmitri Tikhonov#define common_certs_num 2
15750aadb33SDmitri Tikhonovconst common_cert_t common_cert_set[common_certs_num] = {
15850aadb33SDmitri Tikhonov    {common_certs2_num, common_certs2, common_certs2_lens, common_certs2_hash},
15950aadb33SDmitri Tikhonov    {common_certs3_num, common_certs3, common_certs3_lens, common_certs3_hash},
16050aadb33SDmitri Tikhonov};
16150aadb33SDmitri Tikhonov
16250aadb33SDmitri Tikhonov
16350aadb33SDmitri Tikhonovstatic lsquic_str_t *s_ccsbuf;
16450aadb33SDmitri Tikhonov
165a5fa05f9SDmitri Tikhonovstatic int
166a5fa05f9SDmitri Tikhonovmatch_common_cert (lsquic_str_t * cert, lsquic_str_t * common_set_hashes,
167a5fa05f9SDmitri Tikhonov        uint64_t* out_hash, uint32_t* out_index);
168a5fa05f9SDmitri Tikhonov
1692f4629f2SDmitri Tikhonovint
1702f4629f2SDmitri Tikhonovlsquic_crt_init (void)
17150aadb33SDmitri Tikhonov{
1722f4629f2SDmitri Tikhonov    unsigned i;
1732f4629f2SDmitri Tikhonov
1742f4629f2SDmitri Tikhonov    s_ccsbuf = lsquic_str_new(NULL, 0);
1752f4629f2SDmitri Tikhonov    if (!s_ccsbuf)
1762f4629f2SDmitri Tikhonov        return -1;
1772f4629f2SDmitri Tikhonov    for (i=0 ;i<common_certs_num; ++i)
17850aadb33SDmitri Tikhonov    {
1792f4629f2SDmitri Tikhonov        if (0 != lsquic_str_append(s_ccsbuf, (const char *)&common_cert_set[i].hash, 8))
1802f4629f2SDmitri Tikhonov            return -1;
18150aadb33SDmitri Tikhonov    }
1822f4629f2SDmitri Tikhonov    return 0;
1832f4629f2SDmitri Tikhonov}
1842f4629f2SDmitri Tikhonov
1852f4629f2SDmitri Tikhonov
1862f4629f2SDmitri Tikhonovlsquic_str_t *
1872f4629f2SDmitri Tikhonovlsquic_get_common_certs_hash()
1882f4629f2SDmitri Tikhonov{
18950aadb33SDmitri Tikhonov    return s_ccsbuf;
19050aadb33SDmitri Tikhonov}
19150aadb33SDmitri Tikhonov
19250aadb33SDmitri Tikhonov
19350aadb33SDmitri Tikhonov/* return 0 found, -1 not found */
194a5fa05f9SDmitri Tikhonovint
195a5fa05f9SDmitri Tikhonovlsquic_get_common_cert(uint64_t hash, uint32_t index, lsquic_str_t *buf)
19650aadb33SDmitri Tikhonov{
19750aadb33SDmitri Tikhonov    int i;
19850aadb33SDmitri Tikhonov    for (i = 0; i < common_certs_num; i++)
19950aadb33SDmitri Tikhonov    {
20050aadb33SDmitri Tikhonov        if (common_cert_set[i].hash == hash)
20150aadb33SDmitri Tikhonov        {
20250aadb33SDmitri Tikhonov            if (index < common_cert_set[i].num_certs)
20350aadb33SDmitri Tikhonov            {
20450aadb33SDmitri Tikhonov                lsquic_str_setto(buf, (const char *) common_cert_set[i].certs[index],
20550aadb33SDmitri Tikhonov                         common_cert_set[i].lens[index]);
20650aadb33SDmitri Tikhonov                return 0;
20750aadb33SDmitri Tikhonov            }
20850aadb33SDmitri Tikhonov            break;
20950aadb33SDmitri Tikhonov        }
21050aadb33SDmitri Tikhonov    }
21150aadb33SDmitri Tikhonov    return -1;
21250aadb33SDmitri Tikhonov}
21350aadb33SDmitri Tikhonov
21450aadb33SDmitri Tikhonov
2155392f7a3SLiteSpeed Techstatic int
2165392f7a3SLiteSpeed Techcomp_ls_str (lsquic_str_t * a, const void * b, size_t b_len)
2175392f7a3SLiteSpeed Tech{
2185392f7a3SLiteSpeed Tech    size_t a_len;
2195392f7a3SLiteSpeed Tech    int r;
2205392f7a3SLiteSpeed Tech
2215392f7a3SLiteSpeed Tech    a_len = lsquic_str_len(a);
2225392f7a3SLiteSpeed Tech    r = memcmp(lsquic_str_buf(a), b, a_len < b_len ? a_len : b_len);
2235392f7a3SLiteSpeed Tech    if (r)
2245392f7a3SLiteSpeed Tech        return r;
2255392f7a3SLiteSpeed Tech    else
2265392f7a3SLiteSpeed Tech        return (a_len > b_len) - (b_len > a_len);
2275392f7a3SLiteSpeed Tech}
2285392f7a3SLiteSpeed Tech
2295392f7a3SLiteSpeed Tech
2305392f7a3SLiteSpeed Tech/* 0, matched -1, error */
231a5fa05f9SDmitri Tikhonovstatic int
232a5fa05f9SDmitri Tikhonovmatch_common_cert (lsquic_str_t * cert, lsquic_str_t * common_set_hashes,
2335392f7a3SLiteSpeed Tech        uint64_t* out_hash, uint32_t* out_index)
2345392f7a3SLiteSpeed Tech{
2355392f7a3SLiteSpeed Tech    size_t i, j;
2365392f7a3SLiteSpeed Tech    int n;
2375392f7a3SLiteSpeed Tech    uint64_t hash;
2385392f7a3SLiteSpeed Tech    size_t min, max, mid;
2395392f7a3SLiteSpeed Tech
2405392f7a3SLiteSpeed Tech    if (lsquic_str_len(common_set_hashes) % sizeof(uint64_t) != 0)
2415392f7a3SLiteSpeed Tech        return -1;
2425392f7a3SLiteSpeed Tech
2435392f7a3SLiteSpeed Tech    for (i = 0; i < lsquic_str_len(common_set_hashes) / sizeof(uint64_t); i++)
2445392f7a3SLiteSpeed Tech    {
2455392f7a3SLiteSpeed Tech        memcpy(&hash, lsquic_str_buf(common_set_hashes) + i * sizeof(uint64_t),
2465392f7a3SLiteSpeed Tech               sizeof(uint64_t));
2475392f7a3SLiteSpeed Tech
2485392f7a3SLiteSpeed Tech        for (j = 0; j < common_certs_num; j++)
2495392f7a3SLiteSpeed Tech        {
2505392f7a3SLiteSpeed Tech            if (common_cert_set[j].hash != hash)
2515392f7a3SLiteSpeed Tech                continue;
2525392f7a3SLiteSpeed Tech
2535392f7a3SLiteSpeed Tech            if (common_cert_set[j].num_certs == 0)
2545392f7a3SLiteSpeed Tech                continue;
2555392f7a3SLiteSpeed Tech
2565392f7a3SLiteSpeed Tech            min = 0;
2575392f7a3SLiteSpeed Tech            max = common_cert_set[j].num_certs - 1;
2585392f7a3SLiteSpeed Tech            while (max >= min)
2595392f7a3SLiteSpeed Tech            {
2605392f7a3SLiteSpeed Tech                mid = min + ((max - min) / 2);
2615392f7a3SLiteSpeed Tech                n = comp_ls_str(cert, common_cert_set[j].certs[mid],
2625392f7a3SLiteSpeed Tech                                 common_cert_set[j].lens[mid]);
2635392f7a3SLiteSpeed Tech                if (n < 0)
2645392f7a3SLiteSpeed Tech                {
2655392f7a3SLiteSpeed Tech                    if (mid == 0)
2665392f7a3SLiteSpeed Tech                        break;
2675392f7a3SLiteSpeed Tech                    max = mid - 1;
2685392f7a3SLiteSpeed Tech                }
2695392f7a3SLiteSpeed Tech                else if (n > 0)
2705392f7a3SLiteSpeed Tech                    min = mid + 1;
2715392f7a3SLiteSpeed Tech                else
2725392f7a3SLiteSpeed Tech                {
2735392f7a3SLiteSpeed Tech                    *out_hash = hash;
2745392f7a3SLiteSpeed Tech                    *out_index = mid;
2755392f7a3SLiteSpeed Tech                    return 0;
2765392f7a3SLiteSpeed Tech                }
2775392f7a3SLiteSpeed Tech            }
2785392f7a3SLiteSpeed Tech        }
2795392f7a3SLiteSpeed Tech    }
2805392f7a3SLiteSpeed Tech
2815392f7a3SLiteSpeed Tech    return -1;
2825392f7a3SLiteSpeed Tech}
2835392f7a3SLiteSpeed Tech
2845392f7a3SLiteSpeed Tech
28550aadb33SDmitri Tikhonov/* result is written to dict */
28650aadb33SDmitri Tikhonovstatic void
28750aadb33SDmitri Tikhonovmake_zlib_dict_for_entries(cert_entry_t *entries,
28850aadb33SDmitri Tikhonov                                lsquic_str_t **certs, size_t certs_count,
28950aadb33SDmitri Tikhonov                                lsquic_str_t *dict)
29050aadb33SDmitri Tikhonov{
29150aadb33SDmitri Tikhonov    int i;
29250aadb33SDmitri Tikhonov    size_t zlib_dict_size = 0;
29350aadb33SDmitri Tikhonov    for (i = certs_count - 1; i >= 0; --i)
29450aadb33SDmitri Tikhonov    {
29550aadb33SDmitri Tikhonov        if (entries[i].type != ENTRY_COMPRESSED)
29650aadb33SDmitri Tikhonov        {
29750aadb33SDmitri Tikhonov            zlib_dict_size += lsquic_str_len(certs[i]);
29850aadb33SDmitri Tikhonov        }
29950aadb33SDmitri Tikhonov    }
30050aadb33SDmitri Tikhonov
30150aadb33SDmitri Tikhonov    // At the end of the dictionary is a block of common certificate substrings.
30250aadb33SDmitri Tikhonov    zlib_dict_size += sizeof(common_cert_sub_strings);
30350aadb33SDmitri Tikhonov
30450aadb33SDmitri Tikhonov    for (i = certs_count - 1; i >= 0; --i)
30550aadb33SDmitri Tikhonov    {
30650aadb33SDmitri Tikhonov        if (entries[i].type != ENTRY_COMPRESSED)
30750aadb33SDmitri Tikhonov        {
30850aadb33SDmitri Tikhonov            lsquic_str_append(dict, lsquic_str_buf(certs[i]), lsquic_str_len(certs[i]));
30950aadb33SDmitri Tikhonov        }
31050aadb33SDmitri Tikhonov    }
31150aadb33SDmitri Tikhonov
31250aadb33SDmitri Tikhonov    lsquic_str_append(dict, (const char *)common_cert_sub_strings, sizeof(common_cert_sub_strings));
31350aadb33SDmitri Tikhonov    assert((size_t)lsquic_str_len(dict) == zlib_dict_size);
31450aadb33SDmitri Tikhonov}
31550aadb33SDmitri Tikhonov
31650aadb33SDmitri Tikhonov
317a5fa05f9SDmitri Tikhonovstatic
31850aadb33SDmitri Tikhonovvoid get_certs_hash(lsquic_str_t *certs, size_t certs_count, uint64_t *hashs)
31950aadb33SDmitri Tikhonov{
32050aadb33SDmitri Tikhonov    size_t i;
32150aadb33SDmitri Tikhonov    for(i = 0; i < certs_count; ++i)
32250aadb33SDmitri Tikhonov    {
323a5fa05f9SDmitri Tikhonov        hashs[i] = lsquic_fnv1a_64((const uint8_t *)lsquic_str_buf(&certs[i]), lsquic_str_len(&certs[i]));
32450aadb33SDmitri Tikhonov    }
32550aadb33SDmitri Tikhonov}
32650aadb33SDmitri Tikhonov
32750aadb33SDmitri Tikhonov
3285392f7a3SLiteSpeed Techstatic void get_certs_entries(lsquic_str_t **certs, size_t certs_count,
3295392f7a3SLiteSpeed Tech                              lsquic_str_t *client_common_set_hashes,
3305392f7a3SLiteSpeed Tech                              lsquic_str_t *client_cached_cert_hashes,
3315392f7a3SLiteSpeed Tech                              cert_entry_t *entries)
3325392f7a3SLiteSpeed Tech{
3335392f7a3SLiteSpeed Tech    size_t i;
3345392f7a3SLiteSpeed Tech    int j;
3355392f7a3SLiteSpeed Tech    cert_entry_t *entry;
3365392f7a3SLiteSpeed Tech    uint64_t hash, cached_hash;
3375392f7a3SLiteSpeed Tech    bool cached;
3385392f7a3SLiteSpeed Tech
3395392f7a3SLiteSpeed Tech    const bool cached_valid = (lsquic_str_len(client_cached_cert_hashes) % sizeof(uint64_t) == 0)
3405392f7a3SLiteSpeed Tech                                && (lsquic_str_len(client_cached_cert_hashes) > 0);
3415392f7a3SLiteSpeed Tech
3425392f7a3SLiteSpeed Tech    assert(&entries[certs_count - 1]);
3435392f7a3SLiteSpeed Tech
3445392f7a3SLiteSpeed Tech    for (i = 0; i<certs_count; ++i)
3455392f7a3SLiteSpeed Tech    {
3465392f7a3SLiteSpeed Tech        entry = &entries[i];
3475392f7a3SLiteSpeed Tech        if (cached_valid)
3485392f7a3SLiteSpeed Tech        {
3495392f7a3SLiteSpeed Tech            cached = false;
350a5fa05f9SDmitri Tikhonov            hash = lsquic_fnv1a_64((const uint8_t *)lsquic_str_buf(certs[i]), lsquic_str_len(certs[i]));
3515392f7a3SLiteSpeed Tech
3525392f7a3SLiteSpeed Tech            for (j = 0; j < (int)lsquic_str_len(client_cached_cert_hashes);
3535392f7a3SLiteSpeed Tech                 j += sizeof(uint64_t))
3545392f7a3SLiteSpeed Tech            {
3555392f7a3SLiteSpeed Tech                memcpy(&cached_hash, lsquic_str_buf(client_cached_cert_hashes) + j,
3565392f7a3SLiteSpeed Tech                       sizeof(uint64_t));
3575392f7a3SLiteSpeed Tech                if (hash != cached_hash)
3585392f7a3SLiteSpeed Tech                    continue;
3595392f7a3SLiteSpeed Tech
3605392f7a3SLiteSpeed Tech                entry->type = ENTRY_CACHED;
3615392f7a3SLiteSpeed Tech                entry->hash = hash;
3625392f7a3SLiteSpeed Tech                cached = true;
3635392f7a3SLiteSpeed Tech                break;
3645392f7a3SLiteSpeed Tech            }
3655392f7a3SLiteSpeed Tech
3665392f7a3SLiteSpeed Tech            if (cached)
3675392f7a3SLiteSpeed Tech                continue;
3685392f7a3SLiteSpeed Tech        }
3695392f7a3SLiteSpeed Tech
3705392f7a3SLiteSpeed Tech        if (0 == match_common_cert(certs[i], client_common_set_hashes,
3715392f7a3SLiteSpeed Tech            &entry->set_hash, &entry->index))
3725392f7a3SLiteSpeed Tech        {
3735392f7a3SLiteSpeed Tech            entry->type = ENTRY_COMMON;
3745392f7a3SLiteSpeed Tech            continue;
3755392f7a3SLiteSpeed Tech        }
3765392f7a3SLiteSpeed Tech
3775392f7a3SLiteSpeed Tech        entry->type = ENTRY_COMPRESSED;
3785392f7a3SLiteSpeed Tech   }
3795392f7a3SLiteSpeed Tech}
3805392f7a3SLiteSpeed Tech
381a5fa05f9SDmitri Tikhonovstatic size_t
382a5fa05f9SDmitri Tikhonovget_entries_size(cert_entry_t *entries, size_t entries_count)
38350aadb33SDmitri Tikhonov{
38450aadb33SDmitri Tikhonov    size_t i;
38550aadb33SDmitri Tikhonov    size_t entries_size = 0;
38650aadb33SDmitri Tikhonov    for(i=0; i<entries_count; ++i)
38750aadb33SDmitri Tikhonov    {
38850aadb33SDmitri Tikhonov        entries_size++;
38950aadb33SDmitri Tikhonov        switch (entries[i].type)
39050aadb33SDmitri Tikhonov        {
39150aadb33SDmitri Tikhonov        case ENTRY_COMPRESSED:
39250aadb33SDmitri Tikhonov            break;
39350aadb33SDmitri Tikhonov        case ENTRY_CACHED:
39450aadb33SDmitri Tikhonov            entries_size += sizeof(uint64_t);
39550aadb33SDmitri Tikhonov            break;
39650aadb33SDmitri Tikhonov        case ENTRY_COMMON:
39750aadb33SDmitri Tikhonov            entries_size += sizeof(uint64_t) + sizeof(uint32_t);
39850aadb33SDmitri Tikhonov            break;
39950aadb33SDmitri Tikhonov        default:
40050aadb33SDmitri Tikhonov            break;
40150aadb33SDmitri Tikhonov        }
40250aadb33SDmitri Tikhonov    }
40350aadb33SDmitri Tikhonov    entries_size++;  /* for end marker */
40450aadb33SDmitri Tikhonov    return entries_size;
40550aadb33SDmitri Tikhonov}
40650aadb33SDmitri Tikhonov
407a5fa05f9SDmitri Tikhonovstatic
40850aadb33SDmitri Tikhonovvoid serialize_cert_entries(uint8_t* out, int *out_len, cert_entry_t *entries,
40950aadb33SDmitri Tikhonov                            size_t entries_count)
41050aadb33SDmitri Tikhonov{
41150aadb33SDmitri Tikhonov    size_t i;
41250aadb33SDmitri Tikhonov    uint8_t *start = out;
41350aadb33SDmitri Tikhonov    for(i=0; i<entries_count; ++i)
41450aadb33SDmitri Tikhonov    {
41550aadb33SDmitri Tikhonov        *out++ = (uint8_t)(entries[i].type);
41650aadb33SDmitri Tikhonov        switch (entries[i].type)
41750aadb33SDmitri Tikhonov        {
41850aadb33SDmitri Tikhonov        case ENTRY_COMPRESSED:
41950aadb33SDmitri Tikhonov            break;
42050aadb33SDmitri Tikhonov        case ENTRY_CACHED:
42150aadb33SDmitri Tikhonov            memcpy(out, &entries[i].hash, sizeof(uint64_t));
42250aadb33SDmitri Tikhonov            out += sizeof(uint64_t);
42350aadb33SDmitri Tikhonov            break;
42450aadb33SDmitri Tikhonov        case ENTRY_COMMON:
42550aadb33SDmitri Tikhonov            memcpy(out, &entries[i].set_hash, sizeof(uint64_t));
42650aadb33SDmitri Tikhonov            out += sizeof(uint64_t);
42750aadb33SDmitri Tikhonov            memcpy(out, &entries[i].index, sizeof(uint32_t));
42850aadb33SDmitri Tikhonov            out += sizeof(uint32_t);
42950aadb33SDmitri Tikhonov            break;
43050aadb33SDmitri Tikhonov        default:
43150aadb33SDmitri Tikhonov            break;
43250aadb33SDmitri Tikhonov        }
43350aadb33SDmitri Tikhonov    }
43450aadb33SDmitri Tikhonov
43550aadb33SDmitri Tikhonov    *out++ = 0;  // end marker
43650aadb33SDmitri Tikhonov    *out_len = out - start;
43750aadb33SDmitri Tikhonov}
43850aadb33SDmitri Tikhonov
43950aadb33SDmitri Tikhonov
440a5fa05f9SDmitri Tikhonovint
441a5fa05f9SDmitri Tikhonovlsquic_get_certs_count(lsquic_str_t *compressed_crt_buf)
44250aadb33SDmitri Tikhonov{
44350aadb33SDmitri Tikhonov    char *in = lsquic_str_buf(compressed_crt_buf);
44450aadb33SDmitri Tikhonov    char *in_end = in + lsquic_str_len(compressed_crt_buf);
44550aadb33SDmitri Tikhonov    size_t idx = 0;
44650aadb33SDmitri Tikhonov    uint8_t type_byte;
44750aadb33SDmitri Tikhonov
44850aadb33SDmitri Tikhonov    for (;;)
44950aadb33SDmitri Tikhonov    {
45050aadb33SDmitri Tikhonov        if (in >= in_end)
45150aadb33SDmitri Tikhonov            return -1;
45250aadb33SDmitri Tikhonov
45350aadb33SDmitri Tikhonov        type_byte = in[0];
45450aadb33SDmitri Tikhonov        ++in;
45550aadb33SDmitri Tikhonov        if (type_byte == 0)
45650aadb33SDmitri Tikhonov            break;
45750aadb33SDmitri Tikhonov
45850aadb33SDmitri Tikhonov        ++idx;
45950aadb33SDmitri Tikhonov        switch(type_byte)
46050aadb33SDmitri Tikhonov        {
46150aadb33SDmitri Tikhonov        case ENTRY_COMPRESSED:
46250aadb33SDmitri Tikhonov            break;
46350aadb33SDmitri Tikhonov        case ENTRY_CACHED:
46450aadb33SDmitri Tikhonov        {
46550aadb33SDmitri Tikhonov            if (in_end - in < (int)sizeof(uint64_t))
46650aadb33SDmitri Tikhonov                return -1;
46750aadb33SDmitri Tikhonov            in += sizeof(uint64_t);
46850aadb33SDmitri Tikhonov            break;
46950aadb33SDmitri Tikhonov        }
47050aadb33SDmitri Tikhonov        case ENTRY_COMMON:
47150aadb33SDmitri Tikhonov        {
47250aadb33SDmitri Tikhonov            if (in_end - in < (int)(sizeof(uint64_t) + sizeof(uint32_t)))
47350aadb33SDmitri Tikhonov                return -1;
47450aadb33SDmitri Tikhonov            in += sizeof(uint64_t) + sizeof(uint32_t);
47550aadb33SDmitri Tikhonov            break;
47650aadb33SDmitri Tikhonov        }
47750aadb33SDmitri Tikhonov        default:
47850aadb33SDmitri Tikhonov            return -1;
47950aadb33SDmitri Tikhonov        }
48050aadb33SDmitri Tikhonov    }
48150aadb33SDmitri Tikhonov    return idx;
48250aadb33SDmitri Tikhonov}
48350aadb33SDmitri Tikhonov
48450aadb33SDmitri Tikhonov
48550aadb33SDmitri Tikhonov/* return 0: OK, -1, error */
48650aadb33SDmitri Tikhonovstatic int parse_entries(const unsigned char **in_out, const unsigned char *const in_end,
48750aadb33SDmitri Tikhonov                         lsquic_str_t *cached_certs, size_t cached_certs_count,
48850aadb33SDmitri Tikhonov                         cert_entry_t *out_entries,
48950aadb33SDmitri Tikhonov                         lsquic_str_t **out_certs, size_t *out_certs_count)
49050aadb33SDmitri Tikhonov{
49150aadb33SDmitri Tikhonov    const unsigned char *in = *in_out;
49250aadb33SDmitri Tikhonov    size_t idx = 0;
49350aadb33SDmitri Tikhonov    uint64_t* cached_hashes;
49450aadb33SDmitri Tikhonov    cert_entry_t *entry;
49550aadb33SDmitri Tikhonov    lsquic_str_t *cert;
49650aadb33SDmitri Tikhonov    uint8_t type_byte;
49750aadb33SDmitri Tikhonov    int rv;
49850aadb33SDmitri Tikhonov    size_t i;
49950aadb33SDmitri Tikhonov
50050aadb33SDmitri Tikhonov    cached_hashes = NULL;
50150aadb33SDmitri Tikhonov
50250aadb33SDmitri Tikhonov    for (;;)
50350aadb33SDmitri Tikhonov    {
50450aadb33SDmitri Tikhonov        /* XXX potential invalid read */
50550aadb33SDmitri Tikhonov        type_byte = in[0];
50650aadb33SDmitri Tikhonov        ++in;
50750aadb33SDmitri Tikhonov
50850aadb33SDmitri Tikhonov        if (type_byte == 0)
50950aadb33SDmitri Tikhonov            break;
51050aadb33SDmitri Tikhonov
51150aadb33SDmitri Tikhonov        entry = &out_entries[idx];
51250aadb33SDmitri Tikhonov        cert = out_certs[idx];
51350aadb33SDmitri Tikhonov        /* XXX This seems dangerous -- there is no guard that `idx' does not
51450aadb33SDmitri Tikhonov         * exceed `out_certs_count'.
51550aadb33SDmitri Tikhonov         */
51650aadb33SDmitri Tikhonov        lsquic_str_d(cert);
51750aadb33SDmitri Tikhonov
51850aadb33SDmitri Tikhonov        ++idx;
51950aadb33SDmitri Tikhonov        entry->type = type_byte;
52050aadb33SDmitri Tikhonov        switch (entry->type)
52150aadb33SDmitri Tikhonov        {
52250aadb33SDmitri Tikhonov        case ENTRY_COMPRESSED:
52350aadb33SDmitri Tikhonov            break;
52450aadb33SDmitri Tikhonov        case ENTRY_CACHED:
52550aadb33SDmitri Tikhonov        {
52650aadb33SDmitri Tikhonov            memcpy(&entry->hash, in, sizeof(uint64_t));
52750aadb33SDmitri Tikhonov            in += sizeof(uint64_t);
52850aadb33SDmitri Tikhonov
52950aadb33SDmitri Tikhonov            if (!cached_hashes)
53050aadb33SDmitri Tikhonov            {
53150aadb33SDmitri Tikhonov                cached_hashes = malloc(cached_certs_count * sizeof(uint64_t));;
53250aadb33SDmitri Tikhonov                if (!cached_hashes)
53350aadb33SDmitri Tikhonov                    goto err;
53450aadb33SDmitri Tikhonov                get_certs_hash(cached_certs, cached_certs_count, cached_hashes);
53550aadb33SDmitri Tikhonov            }
53650aadb33SDmitri Tikhonov
53750aadb33SDmitri Tikhonov            for (i=0; i<cached_certs_count; ++i)
53850aadb33SDmitri Tikhonov            {
53950aadb33SDmitri Tikhonov                if (cached_hashes[i] == entry->hash)
54050aadb33SDmitri Tikhonov                {
54150aadb33SDmitri Tikhonov                    lsquic_str_append(cert, lsquic_str_buf(&cached_certs[i]),
54250aadb33SDmitri Tikhonov                                  lsquic_str_len(&cached_certs[i]));
54350aadb33SDmitri Tikhonov                    break;
54450aadb33SDmitri Tikhonov                }
54550aadb33SDmitri Tikhonov            }
54650aadb33SDmitri Tikhonov            /* XXX: return -1 if not found?  Logic removed in
54750aadb33SDmitri Tikhonov                                4fd7e76bc031ac637e76c7f0930aff53f5b71705 */
54850aadb33SDmitri Tikhonov            break;
54950aadb33SDmitri Tikhonov        }
55050aadb33SDmitri Tikhonov        case ENTRY_COMMON:
55150aadb33SDmitri Tikhonov        {
55250aadb33SDmitri Tikhonov            memcpy(&entry->set_hash, in, sizeof(uint64_t));
55350aadb33SDmitri Tikhonov            in += sizeof(uint64_t);
55450aadb33SDmitri Tikhonov            memcpy(&entry->index, in, sizeof(uint32_t));
55550aadb33SDmitri Tikhonov            in += sizeof(uint32_t);
55650aadb33SDmitri Tikhonov
557a5fa05f9SDmitri Tikhonov            if (0 == lsquic_get_common_cert(entry->set_hash, entry->index, cert))
55850aadb33SDmitri Tikhonov                break;
55950aadb33SDmitri Tikhonov            else
56050aadb33SDmitri Tikhonov                goto err;
56150aadb33SDmitri Tikhonov        }
56250aadb33SDmitri Tikhonov        default:
56350aadb33SDmitri Tikhonov            goto err;
56450aadb33SDmitri Tikhonov        }
56550aadb33SDmitri Tikhonov    }
56650aadb33SDmitri Tikhonov
56750aadb33SDmitri Tikhonov    rv = 0;
56850aadb33SDmitri Tikhonov    *in_out = in;
56950aadb33SDmitri Tikhonov    *out_certs_count = idx;
57050aadb33SDmitri Tikhonov
57150aadb33SDmitri Tikhonov  cleanup:
57250aadb33SDmitri Tikhonov    free(cached_hashes);
57350aadb33SDmitri Tikhonov    return rv;
57450aadb33SDmitri Tikhonov
57550aadb33SDmitri Tikhonov  err:
57650aadb33SDmitri Tikhonov    rv = -1;
57750aadb33SDmitri Tikhonov    goto cleanup;
57850aadb33SDmitri Tikhonov}
57950aadb33SDmitri Tikhonov
58050aadb33SDmitri Tikhonov
5815392f7a3SLiteSpeed Tech/* return 0 for OK */
582a5fa05f9SDmitri Tikhonovint
583a5fa05f9SDmitri Tikhonovlsquic_compress_certs (lsquic_str_t **certs, size_t certs_count,
5845392f7a3SLiteSpeed Tech                   lsquic_str_t *client_common_set_hashes,
5855392f7a3SLiteSpeed Tech                   lsquic_str_t *client_cached_cert_hashes,
5865392f7a3SLiteSpeed Tech                   lsquic_str_t *result)
5875392f7a3SLiteSpeed Tech{
5885392f7a3SLiteSpeed Tech    int rv;
5895392f7a3SLiteSpeed Tech    size_t i;
5905392f7a3SLiteSpeed Tech    size_t uncompressed_size = 0, compressed_size = 0 ;
5915392f7a3SLiteSpeed Tech    z_stream z;
5925392f7a3SLiteSpeed Tech    lsquic_str_t *dict;
5935392f7a3SLiteSpeed Tech    size_t entries_size, result_length;
5945392f7a3SLiteSpeed Tech    int out_len;
5955392f7a3SLiteSpeed Tech    uint8_t* out;
5965392f7a3SLiteSpeed Tech    uint32_t tmp_size_32;
5975392f7a3SLiteSpeed Tech    cert_entry_t *entries;
5985392f7a3SLiteSpeed Tech
5995392f7a3SLiteSpeed Tech    entries = malloc(sizeof(cert_entry_t) * certs_count);
6005392f7a3SLiteSpeed Tech    if (!entries)
6015392f7a3SLiteSpeed Tech        return -1;
6025392f7a3SLiteSpeed Tech
6035392f7a3SLiteSpeed Tech    dict = lsquic_str_new(NULL, 0);
6045392f7a3SLiteSpeed Tech    if (!dict)
6055392f7a3SLiteSpeed Tech        goto err;
6065392f7a3SLiteSpeed Tech
6075392f7a3SLiteSpeed Tech    get_certs_entries(certs, certs_count, client_common_set_hashes,
6085392f7a3SLiteSpeed Tech                              client_cached_cert_hashes, entries);
6095392f7a3SLiteSpeed Tech
6105392f7a3SLiteSpeed Tech    for (i = 0; i < certs_count; i++)
6115392f7a3SLiteSpeed Tech    {
6125392f7a3SLiteSpeed Tech        if (entries[i].type == ENTRY_COMPRESSED)
6135392f7a3SLiteSpeed Tech        {
6145392f7a3SLiteSpeed Tech             /*uint32_t length + cert content*/
6155392f7a3SLiteSpeed Tech            uncompressed_size += 4 + lsquic_str_len(certs[i]);
6165392f7a3SLiteSpeed Tech        }
6175392f7a3SLiteSpeed Tech    }
6185392f7a3SLiteSpeed Tech
6195392f7a3SLiteSpeed Tech    if (uncompressed_size > 0)
6205392f7a3SLiteSpeed Tech    {
6215392f7a3SLiteSpeed Tech        memset(&z, 0, sizeof(z));
6225392f7a3SLiteSpeed Tech        if (Z_OK != deflateInit(&z, Z_DEFAULT_COMPRESSION))
6235392f7a3SLiteSpeed Tech            goto err;
6245392f7a3SLiteSpeed Tech
6255392f7a3SLiteSpeed Tech        make_zlib_dict_for_entries(entries, certs, certs_count, dict);
6265392f7a3SLiteSpeed Tech        if(Z_OK != deflateSetDictionary(&z, (const unsigned char *)lsquic_str_buf(dict), lsquic_str_len(dict)))
6275392f7a3SLiteSpeed Tech            goto err;
6285392f7a3SLiteSpeed Tech        compressed_size = deflateBound(&z, uncompressed_size);
6295392f7a3SLiteSpeed Tech    }
6305392f7a3SLiteSpeed Tech
6315392f7a3SLiteSpeed Tech    entries_size = get_entries_size(entries, certs_count);
6325392f7a3SLiteSpeed Tech    result_length = entries_size + (uncompressed_size > 0 ? 4 : 0) +
6335392f7a3SLiteSpeed Tech                    compressed_size;
6345392f7a3SLiteSpeed Tech    lsquic_str_prealloc(result, result_length);
6355392f7a3SLiteSpeed Tech
6365392f7a3SLiteSpeed Tech    out = (unsigned char *)lsquic_str_buf(result);
6375392f7a3SLiteSpeed Tech    serialize_cert_entries(out, &out_len, entries, certs_count);
6385392f7a3SLiteSpeed Tech    out += entries_size;
6395392f7a3SLiteSpeed Tech
6405392f7a3SLiteSpeed Tech    if (uncompressed_size == 0)
6415392f7a3SLiteSpeed Tech    {
6425392f7a3SLiteSpeed Tech        lsquic_str_setlen(result, entries_size);
6435392f7a3SLiteSpeed Tech        rv = 0;
6445392f7a3SLiteSpeed Tech        goto cleanup;
6455392f7a3SLiteSpeed Tech    }
6465392f7a3SLiteSpeed Tech
6475392f7a3SLiteSpeed Tech    tmp_size_32 = uncompressed_size;
6485392f7a3SLiteSpeed Tech    memcpy(out, &tmp_size_32, sizeof(uint32_t));
6495392f7a3SLiteSpeed Tech    out += sizeof(uint32_t);
6505392f7a3SLiteSpeed Tech
6515392f7a3SLiteSpeed Tech    z.next_out = out;
6525392f7a3SLiteSpeed Tech    z.avail_out = compressed_size;
6535392f7a3SLiteSpeed Tech
6545392f7a3SLiteSpeed Tech    for (i = 0; i < certs_count; ++i)
6555392f7a3SLiteSpeed Tech    {
6565392f7a3SLiteSpeed Tech        if (entries[i].type != ENTRY_COMPRESSED)
6575392f7a3SLiteSpeed Tech            continue;
6585392f7a3SLiteSpeed Tech
6595392f7a3SLiteSpeed Tech        tmp_size_32 = lsquic_str_len(certs[i]);
6605392f7a3SLiteSpeed Tech        z.next_in = (uint8_t*)(&tmp_size_32);
6615392f7a3SLiteSpeed Tech        z.avail_in = sizeof(tmp_size_32);
6625392f7a3SLiteSpeed Tech        if (Z_OK != deflate(&z, Z_NO_FLUSH) || z.avail_in)
6635392f7a3SLiteSpeed Tech            goto err;
6645392f7a3SLiteSpeed Tech        z.next_in = (unsigned char *)lsquic_str_buf(certs[i]);
6655392f7a3SLiteSpeed Tech        z.avail_in = lsquic_str_len(certs[i]);
6665392f7a3SLiteSpeed Tech        if (Z_OK != deflate(&z, Z_NO_FLUSH) || z.avail_in)
6675392f7a3SLiteSpeed Tech            goto err;
6685392f7a3SLiteSpeed Tech    }
6695392f7a3SLiteSpeed Tech
6705392f7a3SLiteSpeed Tech    z.avail_in = 0;
6715392f7a3SLiteSpeed Tech    if (Z_STREAM_END != deflate(&z, Z_FINISH))
6725392f7a3SLiteSpeed Tech        goto err;
6735392f7a3SLiteSpeed Tech
6745392f7a3SLiteSpeed Tech    rv = 0;
6755392f7a3SLiteSpeed Tech    result_length -= z.avail_out;
6765392f7a3SLiteSpeed Tech    lsquic_str_setlen(result, result_length);
6775392f7a3SLiteSpeed Tech
6785392f7a3SLiteSpeed Tech  cleanup:
6795392f7a3SLiteSpeed Tech    free(entries);
6805392f7a3SLiteSpeed Tech    if (dict)
6815392f7a3SLiteSpeed Tech        lsquic_str_delete(dict);
6825392f7a3SLiteSpeed Tech    if (uncompressed_size)
6835392f7a3SLiteSpeed Tech        deflateEnd(&z);
6845392f7a3SLiteSpeed Tech    return rv;
6855392f7a3SLiteSpeed Tech
6865392f7a3SLiteSpeed Tech  err:
6875392f7a3SLiteSpeed Tech    rv = -1;
6885392f7a3SLiteSpeed Tech    goto cleanup;
6895392f7a3SLiteSpeed Tech}
6905392f7a3SLiteSpeed Tech
6915392f7a3SLiteSpeed Tech
69250aadb33SDmitri Tikhonov/* 0: ok */
693a5fa05f9SDmitri Tikhonovint
694a5fa05f9SDmitri Tikhonovlsquic_decompress_certs (const unsigned char *in, const unsigned char *in_end,
69550aadb33SDmitri Tikhonov                     lsquic_str_t *cached_certs, size_t cached_certs_count,
69650aadb33SDmitri Tikhonov                     lsquic_str_t **out_certs, size_t *out_certs_count)
69750aadb33SDmitri Tikhonov{
69850aadb33SDmitri Tikhonov    int ret;
69950aadb33SDmitri Tikhonov    size_t i;
700b93f59beSBob Perper    uint8_t* uncompressed_data, *uncompressed_data_buf;
70150aadb33SDmitri Tikhonov    lsquic_str_t *dict;
70250aadb33SDmitri Tikhonov    uint32_t uncompressed_size;
70350aadb33SDmitri Tikhonov    size_t count = *out_certs_count;
70450aadb33SDmitri Tikhonov    cert_entry_t *entries;
70550aadb33SDmitri Tikhonov    z_stream z;
70650aadb33SDmitri Tikhonov
70750aadb33SDmitri Tikhonov    assert(*out_certs_count > 0 && *out_certs_count < 10000
708a5fa05f9SDmitri Tikhonov            && "Call lsquic_get_certs_count() to get right certificates count first and make enough room for out_certs_count");
70950aadb33SDmitri Tikhonov
71050aadb33SDmitri Tikhonov    if (count == 0 || count > 10000)
71150aadb33SDmitri Tikhonov        return -1;
71250aadb33SDmitri Tikhonov
71350aadb33SDmitri Tikhonov    dict = lsquic_str_new(NULL, 0);
71450aadb33SDmitri Tikhonov    if (!dict)
71550aadb33SDmitri Tikhonov        return -1;
71650aadb33SDmitri Tikhonov
71750aadb33SDmitri Tikhonov    uncompressed_data_buf = NULL;
718b93f59beSBob Perper#ifdef WIN32
719b93f59beSBob Perper    uncompressed_data = NULL;
720b93f59beSBob Perper#endif
72150aadb33SDmitri Tikhonov    entries = malloc(count * sizeof(cert_entry_t));
72250aadb33SDmitri Tikhonov    if (!entries)
72350aadb33SDmitri Tikhonov        goto err;
72450aadb33SDmitri Tikhonov
72550aadb33SDmitri Tikhonov    ret = parse_entries(&in, in_end, cached_certs, cached_certs_count,
72650aadb33SDmitri Tikhonov                  entries, out_certs, out_certs_count);
72750aadb33SDmitri Tikhonov    if (ret)
72850aadb33SDmitri Tikhonov        goto err;
72950aadb33SDmitri Tikhonov
73050aadb33SDmitri Tikhonov    /* re-assign count with real valus */
73150aadb33SDmitri Tikhonov    count = *out_certs_count;
73250aadb33SDmitri Tikhonov
73350aadb33SDmitri Tikhonov    if (in < in_end)
73450aadb33SDmitri Tikhonov    {
73550aadb33SDmitri Tikhonov        if (in_end - in < (int)sizeof(uint32_t))
73650aadb33SDmitri Tikhonov            goto err;
73750aadb33SDmitri Tikhonov
73850aadb33SDmitri Tikhonov        memcpy(&uncompressed_size, in, sizeof(uncompressed_size));
73950aadb33SDmitri Tikhonov        in += sizeof(uint32_t);
74050aadb33SDmitri Tikhonov        /* XXX Is 128 KB an arbitrary limit or is there a reason behind it? */
74150aadb33SDmitri Tikhonov        if (uncompressed_size > 128 * 1024)
74250aadb33SDmitri Tikhonov            goto err;
74350aadb33SDmitri Tikhonov
74450aadb33SDmitri Tikhonov        uncompressed_data_buf = uncompressed_data = malloc(uncompressed_size);
745b93f59beSBob Perper        if (!uncompressed_data)
746b93f59beSBob Perper            goto err;
747b93f59beSBob Perper
74850aadb33SDmitri Tikhonov        memset(&z, 0, sizeof(z));
74950aadb33SDmitri Tikhonov        z.next_out  = uncompressed_data;
75050aadb33SDmitri Tikhonov        z.avail_out = uncompressed_size;
75150aadb33SDmitri Tikhonov        z.next_in   = (unsigned char *) in;
75250aadb33SDmitri Tikhonov        z.avail_in  = in_end - in;
75350aadb33SDmitri Tikhonov
75450aadb33SDmitri Tikhonov        if (Z_OK != inflateInit(&z))
75550aadb33SDmitri Tikhonov            goto err;
75650aadb33SDmitri Tikhonov
75750aadb33SDmitri Tikhonov        ret = inflate(&z, Z_FINISH);
75850aadb33SDmitri Tikhonov        if (ret == Z_NEED_DICT)
75950aadb33SDmitri Tikhonov        {
76050aadb33SDmitri Tikhonov            lsquic_str_d(dict);
76150aadb33SDmitri Tikhonov            make_zlib_dict_for_entries(entries, out_certs, count, dict);
76250aadb33SDmitri Tikhonov            if (Z_OK != inflateSetDictionary(&z, (const unsigned char *)lsquic_str_buf(dict), lsquic_str_len(dict)))
76350aadb33SDmitri Tikhonov                goto err;
76450aadb33SDmitri Tikhonov            ret = inflate(&z, Z_FINISH);
76550aadb33SDmitri Tikhonov        }
76650aadb33SDmitri Tikhonov
76750aadb33SDmitri Tikhonov        if (Z_STREAM_END != ret || z.avail_out > 0 || z.avail_in > 0)
76850aadb33SDmitri Tikhonov            goto err;
76950aadb33SDmitri Tikhonov    }
77050aadb33SDmitri Tikhonov    else
77150aadb33SDmitri Tikhonov        uncompressed_size = 0;
77250aadb33SDmitri Tikhonov
77350aadb33SDmitri Tikhonov    for (i = 0; i < count; i++)
77450aadb33SDmitri Tikhonov    {
77550aadb33SDmitri Tikhonov        switch (entries[i].type)
77650aadb33SDmitri Tikhonov        {
77750aadb33SDmitri Tikhonov          case ENTRY_COMPRESSED:
77850aadb33SDmitri Tikhonov              if (uncompressed_size < sizeof(uint32_t))
77950aadb33SDmitri Tikhonov                  goto err;
78050aadb33SDmitri Tikhonov              lsquic_str_d(out_certs[i]);
78150aadb33SDmitri Tikhonov              uint32_t cert_len;
78250aadb33SDmitri Tikhonov              memcpy(&cert_len, uncompressed_data, sizeof(cert_len));
78350aadb33SDmitri Tikhonov              uncompressed_data += sizeof(uint32_t);
78450aadb33SDmitri Tikhonov              uncompressed_size -= sizeof(uint32_t);
78550aadb33SDmitri Tikhonov              if (uncompressed_size < cert_len)
78650aadb33SDmitri Tikhonov                  goto err;
78750aadb33SDmitri Tikhonov              lsquic_str_append(out_certs[i], (const char *)uncompressed_data, cert_len);
78850aadb33SDmitri Tikhonov              uncompressed_data += cert_len;
78950aadb33SDmitri Tikhonov              uncompressed_size -= cert_len;
79050aadb33SDmitri Tikhonov              break;
79150aadb33SDmitri Tikhonov          case ENTRY_CACHED:
79250aadb33SDmitri Tikhonov          case ENTRY_COMMON:
79350aadb33SDmitri Tikhonov          default:
79450aadb33SDmitri Tikhonov            break;
79550aadb33SDmitri Tikhonov        }
79650aadb33SDmitri Tikhonov    }
79750aadb33SDmitri Tikhonov
79850aadb33SDmitri Tikhonov  cleanup:
79950aadb33SDmitri Tikhonov    lsquic_str_delete(dict);
80050aadb33SDmitri Tikhonov    free(entries);
80150aadb33SDmitri Tikhonov    if (uncompressed_data_buf)
80250aadb33SDmitri Tikhonov        inflateEnd(&z);
80350aadb33SDmitri Tikhonov    free(uncompressed_data_buf);
80450aadb33SDmitri Tikhonov    if (0 == uncompressed_size)
80550aadb33SDmitri Tikhonov        return 0;
80650aadb33SDmitri Tikhonov    else
80750aadb33SDmitri Tikhonov        return -1;
80850aadb33SDmitri Tikhonov
80950aadb33SDmitri Tikhonov  err:
81050aadb33SDmitri Tikhonov    uncompressed_size = 1;  /* This triggers return -1 above */
81150aadb33SDmitri Tikhonov    goto cleanup;
81250aadb33SDmitri Tikhonov}
81350aadb33SDmitri Tikhonov
81450aadb33SDmitri Tikhonov
81550aadb33SDmitri Tikhonovvoid
81650aadb33SDmitri Tikhonovlsquic_crt_cleanup (void)
81750aadb33SDmitri Tikhonov{
81850aadb33SDmitri Tikhonov    if (s_ccsbuf)
81950aadb33SDmitri Tikhonov    {
82050aadb33SDmitri Tikhonov        lsquic_str_delete(s_ccsbuf);
82150aadb33SDmitri Tikhonov        s_ccsbuf = NULL;
82250aadb33SDmitri Tikhonov    }
82350aadb33SDmitri Tikhonov}
824