/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */ #include #include #include #include #include #include #ifndef WIN32 #else #include #include #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 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; itype = 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; ibuf; 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; ihash) { 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; } }