blob: 09973ddfa3b29e73f3ee793039af630a0dff19cc [file] [log] [blame]
QUICHE teama6ef0a62019-03-07 20:34:33 -05001// Copyright (c) 2013 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "net/third_party/quiche/src/quic/core/crypto/cert_compressor.h"
6
7#include <cstdint>
8#include <memory>
vasilvv872e7a32019-03-12 16:42:44 -07009#include <string>
QUICHE teama6ef0a62019-03-07 20:34:33 -050010
11#include "net/third_party/quiche/src/quic/core/quic_utils.h"
12#include "net/third_party/quiche/src/quic/platform/api/quic_ptr_util.h"
QUICHE teama6ef0a62019-03-07 20:34:33 -050013#include "third_party/zlib/zlib.h"
14
15namespace quic {
16
17namespace {
18
19// kCommonCertSubstrings contains ~1500 bytes of common certificate substrings
20// in order to help zlib. This was generated via a fairly dumb algorithm from
21// the Alexa Top 5000 set - we could probably do better.
22static const unsigned char kCommonCertSubstrings[] = {
23 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04,
24 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03,
25 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30,
26 0x5f, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x04, 0x01,
27 0x06, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd, 0x6d, 0x01, 0x07,
28 0x17, 0x01, 0x30, 0x33, 0x20, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65,
29 0x64, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e,
30 0x20, 0x53, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x34,
31 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31,
32 0x32, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72,
33 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x30, 0x2d, 0x61, 0x69, 0x61, 0x2e,
34 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d,
35 0x2f, 0x45, 0x2d, 0x63, 0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73,
36 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x45, 0x2e, 0x63, 0x65,
37 0x72, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
38 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x4a, 0x2e, 0x63,
39 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73,
40 0x2f, 0x63, 0x70, 0x73, 0x20, 0x28, 0x63, 0x29, 0x30, 0x30, 0x09, 0x06,
41 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x30, 0x0d,
42 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
43 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x7b, 0x30, 0x1d, 0x06, 0x03, 0x55,
44 0x1d, 0x0e, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
45 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
46 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd2,
47 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x2e,
48 0x63, 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
49 0x04, 0x14, 0xb4, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69,
50 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x30, 0x0b, 0x06, 0x03,
51 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x30, 0x0d, 0x06, 0x09,
52 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
53 0x81, 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
54 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08,
55 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30,
56 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74,
57 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03,
58 0x55, 0x04, 0x0a, 0x13, 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64, 0x64, 0x79,
59 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x33,
60 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x68, 0x74, 0x74,
61 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
62 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79,
63 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74,
64 0x6f, 0x72, 0x79, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03,
65 0x13, 0x27, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x53,
66 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
67 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
68 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
69 0x04, 0x05, 0x13, 0x08, 0x30, 0x37, 0x39, 0x36, 0x39, 0x32, 0x38, 0x37,
70 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
71 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0c,
72 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00,
73 0x30, 0x1d, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
74 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55,
75 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
76 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
77 0x03, 0x02, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
78 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x33, 0x06, 0x03, 0x55, 0x1d,
79 0x1f, 0x04, 0x2c, 0x30, 0x2a, 0x30, 0x28, 0xa0, 0x26, 0xa0, 0x24, 0x86,
80 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e,
81 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
82 0x67, 0x64, 0x73, 0x31, 0x2d, 0x32, 0x30, 0x2a, 0x30, 0x28, 0x06, 0x08,
83 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74,
84 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65,
85 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63,
86 0x70, 0x73, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17,
87 0x0d, 0x31, 0x33, 0x30, 0x35, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, 0x01,
88 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x3a,
89 0x2f, 0x2f, 0x73, 0x30, 0x39, 0x30, 0x37, 0x06, 0x08, 0x2b, 0x06, 0x01,
90 0x05, 0x05, 0x07, 0x02, 0x30, 0x44, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04,
91 0x3d, 0x30, 0x3b, 0x30, 0x39, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86,
92 0xf8, 0x45, 0x01, 0x07, 0x17, 0x06, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
93 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x1b, 0x53, 0x31, 0x17,
94 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72,
95 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31,
96 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, 0x65,
97 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74,
98 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x3b, 0x30, 0x39,
99 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x32, 0x54, 0x65, 0x72, 0x6d, 0x73,
100 0x20, 0x6f, 0x66, 0x20, 0x75, 0x73, 0x65, 0x20, 0x61, 0x74, 0x20, 0x68,
101 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76,
102 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
103 0x72, 0x70, 0x61, 0x20, 0x28, 0x63, 0x29, 0x30, 0x31, 0x10, 0x30, 0x0e,
104 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x53, 0x31, 0x13, 0x30, 0x11,
105 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x47, 0x31, 0x13, 0x30, 0x11,
106 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x3c, 0x02, 0x01,
107 0x03, 0x13, 0x02, 0x55, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04,
108 0x03, 0x14, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
109 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0f, 0x13, 0x14, 0x50,
110 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x20, 0x4f, 0x72, 0x67, 0x61, 0x6e,
111 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x12, 0x31, 0x21, 0x30,
112 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x44, 0x6f, 0x6d, 0x61,
113 0x69, 0x6e, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x20, 0x56,
114 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x31, 0x14, 0x31, 0x31,
115 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x28, 0x53, 0x65, 0x65,
116 0x20, 0x77, 0x77, 0x77, 0x2e, 0x72, 0x3a, 0x2f, 0x2f, 0x73, 0x65, 0x63,
117 0x75, 0x72, 0x65, 0x2e, 0x67, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53,
118 0x69, 0x67, 0x6e, 0x31, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x41,
119 0x2e, 0x63, 0x72, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e,
120 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x45, 0x63, 0x72,
121 0x6c, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63,
122 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x73, 0x64, 0x31, 0x1a,
123 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x3a,
124 0x2f, 0x2f, 0x45, 0x56, 0x49, 0x6e, 0x74, 0x6c, 0x2d, 0x63, 0x63, 0x72,
125 0x74, 0x2e, 0x67, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x69, 0x63, 0x65, 0x72,
126 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x31, 0x6f, 0x63, 0x73, 0x70, 0x2e,
127 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d,
128 0x30, 0x39, 0x72, 0x61, 0x70, 0x69, 0x64, 0x73, 0x73, 0x6c, 0x2e, 0x63,
129 0x6f, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63,
130 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72,
131 0x79, 0x2f, 0x30, 0x81, 0x80, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
132 0x07, 0x01, 0x01, 0x04, 0x74, 0x30, 0x72, 0x30, 0x24, 0x06, 0x08, 0x2b,
133 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74,
134 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6f, 0x64,
135 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x4a, 0x06,
136 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x3e, 0x68,
137 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66,
138 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64,
139 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73,
140 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x67, 0x64, 0x5f, 0x69, 0x6e, 0x74,
141 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72,
142 0x74, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
143 0x80, 0x14, 0xfd, 0xac, 0x61, 0x32, 0x93, 0x6c, 0x45, 0xd6, 0xe2, 0xee,
144 0x85, 0x5f, 0x9a, 0xba, 0xe7, 0x76, 0x99, 0x68, 0xcc, 0xe7, 0x30, 0x27,
145 0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x86, 0x30,
146 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73,
147};
148
149// CertEntry represents a certificate in compressed form. Each entry is one of
150// the three types enumerated in |Type|.
151struct CertEntry {
152 public:
153 enum Type {
154 // Type 0 is reserved to mean "end of list" in the wire format.
155
156 // COMPRESSED means that the certificate is included in the trailing zlib
157 // data.
158 COMPRESSED = 1,
159 // CACHED means that the certificate is already known to the peer and will
160 // be replaced by its 64-bit hash (in |hash|).
161 CACHED = 2,
162 // COMMON means that the certificate is in a common certificate set known
163 // to the peer with hash |set_hash| and certificate index |index|.
164 COMMON = 3,
165 };
166
167 Type type;
168 uint64_t hash;
169 uint64_t set_hash;
170 uint32_t index;
171};
172
173// MatchCerts returns a vector of CertEntries describing how to most
174// efficiently represent |certs| to a peer who has the common sets identified
175// by |client_common_set_hashes| and who has cached the certificates with the
176// 64-bit, FNV-1a hashes in |client_cached_cert_hashes|.
vasilvvc48c8712019-03-11 13:38:16 -0700177std::vector<CertEntry> MatchCerts(const std::vector<std::string>& certs,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500178 QuicStringPiece client_common_set_hashes,
179 QuicStringPiece client_cached_cert_hashes,
180 const CommonCertSets* common_sets) {
181 std::vector<CertEntry> entries;
182 entries.reserve(certs.size());
183
184 const bool cached_valid =
185 client_cached_cert_hashes.size() % sizeof(uint64_t) == 0 &&
186 !client_cached_cert_hashes.empty();
187
188 for (auto i = certs.begin(); i != certs.end(); ++i) {
189 CertEntry entry;
190
191 if (cached_valid) {
192 bool cached = false;
193
194 uint64_t hash = QuicUtils::FNV1a_64_Hash(*i);
195 // This assumes that the machine is little-endian.
196 for (size_t j = 0; j < client_cached_cert_hashes.size();
197 j += sizeof(uint64_t)) {
198 uint64_t cached_hash;
199 memcpy(&cached_hash, client_cached_cert_hashes.data() + j,
200 sizeof(uint64_t));
201 if (hash != cached_hash) {
202 continue;
203 }
204
205 entry.type = CertEntry::CACHED;
206 entry.hash = hash;
207 entries.push_back(entry);
208 cached = true;
209 break;
210 }
211
212 if (cached) {
213 continue;
214 }
215 }
216
217 if (common_sets && common_sets->MatchCert(*i, client_common_set_hashes,
218 &entry.set_hash, &entry.index)) {
219 entry.type = CertEntry::COMMON;
220 entries.push_back(entry);
221 continue;
222 }
223
224 entry.type = CertEntry::COMPRESSED;
225 entries.push_back(entry);
226 }
227
228 return entries;
229}
230
231// CertEntriesSize returns the size, in bytes, of the serialised form of
232// |entries|.
233size_t CertEntriesSize(const std::vector<CertEntry>& entries) {
234 size_t entries_size = 0;
235
236 for (auto i = entries.begin(); i != entries.end(); ++i) {
237 entries_size++;
238 switch (i->type) {
239 case CertEntry::COMPRESSED:
240 break;
241 case CertEntry::CACHED:
242 entries_size += sizeof(uint64_t);
243 break;
244 case CertEntry::COMMON:
245 entries_size += sizeof(uint64_t) + sizeof(uint32_t);
246 break;
247 }
248 }
249
250 entries_size++; // for end marker
251
252 return entries_size;
253}
254
255// SerializeCertEntries serialises |entries| to |out|, which must have enough
256// space to contain them.
257void SerializeCertEntries(uint8_t* out, const std::vector<CertEntry>& entries) {
258 for (auto i = entries.begin(); i != entries.end(); ++i) {
259 *out++ = static_cast<uint8_t>(i->type);
260 switch (i->type) {
261 case CertEntry::COMPRESSED:
262 break;
263 case CertEntry::CACHED:
264 memcpy(out, &i->hash, sizeof(i->hash));
265 out += sizeof(uint64_t);
266 break;
267 case CertEntry::COMMON:
268 // Assumes a little-endian machine.
269 memcpy(out, &i->set_hash, sizeof(i->set_hash));
270 out += sizeof(i->set_hash);
271 memcpy(out, &i->index, sizeof(uint32_t));
272 out += sizeof(uint32_t);
273 break;
274 }
275 }
276
277 *out++ = 0; // end marker
278}
279
280// ZlibDictForEntries returns a string that contains the zlib pre-shared
281// dictionary to use in order to decompress a zlib block following |entries|.
282// |certs| is one-to-one with |entries| and contains the certificates for those
283// entries that are CACHED or COMMON.
vasilvvc48c8712019-03-11 13:38:16 -0700284std::string ZlibDictForEntries(const std::vector<CertEntry>& entries,
285 const std::vector<std::string>& certs) {
286 std::string zlib_dict;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500287
288 // The dictionary starts with the common and cached certs in reverse order.
289 size_t zlib_dict_size = 0;
290 for (size_t i = certs.size() - 1; i < certs.size(); i--) {
291 if (entries[i].type != CertEntry::COMPRESSED) {
292 zlib_dict_size += certs[i].size();
293 }
294 }
295
296 // At the end of the dictionary is a block of common certificate substrings.
297 zlib_dict_size += sizeof(kCommonCertSubstrings);
298
299 zlib_dict.reserve(zlib_dict_size);
300
301 for (size_t i = certs.size() - 1; i < certs.size(); i--) {
302 if (entries[i].type != CertEntry::COMPRESSED) {
303 zlib_dict += certs[i];
304 }
305 }
306
vasilvvc48c8712019-03-11 13:38:16 -0700307 zlib_dict += std::string(reinterpret_cast<const char*>(kCommonCertSubstrings),
308 sizeof(kCommonCertSubstrings));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500309
310 DCHECK_EQ(zlib_dict.size(), zlib_dict_size);
311
312 return zlib_dict;
313}
314
315// HashCerts returns the FNV-1a hashes of |certs|.
vasilvvc48c8712019-03-11 13:38:16 -0700316std::vector<uint64_t> HashCerts(const std::vector<std::string>& certs) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500317 std::vector<uint64_t> ret;
318 ret.reserve(certs.size());
319
320 for (auto i = certs.begin(); i != certs.end(); ++i) {
321 ret.push_back(QuicUtils::FNV1a_64_Hash(*i));
322 }
323
324 return ret;
325}
326
327// ParseEntries parses the serialised form of a vector of CertEntries from
328// |in_out| and writes them to |out_entries|. CACHED and COMMON entries are
329// resolved using |cached_certs| and |common_sets| and written to |out_certs|.
330// |in_out| is updated to contain the trailing data.
331bool ParseEntries(QuicStringPiece* in_out,
vasilvvc48c8712019-03-11 13:38:16 -0700332 const std::vector<std::string>& cached_certs,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500333 const CommonCertSets* common_sets,
334 std::vector<CertEntry>* out_entries,
vasilvvc48c8712019-03-11 13:38:16 -0700335 std::vector<std::string>* out_certs) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500336 QuicStringPiece in = *in_out;
337 std::vector<uint64_t> cached_hashes;
338
339 out_entries->clear();
340 out_certs->clear();
341
342 for (;;) {
343 if (in.empty()) {
344 return false;
345 }
346 CertEntry entry;
347 const uint8_t type_byte = in[0];
348 in.remove_prefix(1);
349
350 if (type_byte == 0) {
351 break;
352 }
353
354 entry.type = static_cast<CertEntry::Type>(type_byte);
355
356 switch (entry.type) {
357 case CertEntry::COMPRESSED:
vasilvvc48c8712019-03-11 13:38:16 -0700358 out_certs->push_back(std::string());
QUICHE teama6ef0a62019-03-07 20:34:33 -0500359 break;
360 case CertEntry::CACHED: {
361 if (in.size() < sizeof(uint64_t)) {
362 return false;
363 }
364 memcpy(&entry.hash, in.data(), sizeof(uint64_t));
365 in.remove_prefix(sizeof(uint64_t));
366
367 if (cached_hashes.size() != cached_certs.size()) {
368 cached_hashes = HashCerts(cached_certs);
369 }
370 bool found = false;
371 for (size_t i = 0; i < cached_hashes.size(); i++) {
372 if (cached_hashes[i] == entry.hash) {
373 out_certs->push_back(cached_certs[i]);
374 found = true;
375 break;
376 }
377 }
378 if (!found) {
379 return false;
380 }
381 break;
382 }
383 case CertEntry::COMMON: {
384 if (!common_sets) {
385 return false;
386 }
387 if (in.size() < sizeof(uint64_t) + sizeof(uint32_t)) {
388 return false;
389 }
390 memcpy(&entry.set_hash, in.data(), sizeof(uint64_t));
391 in.remove_prefix(sizeof(uint64_t));
392 memcpy(&entry.index, in.data(), sizeof(uint32_t));
393 in.remove_prefix(sizeof(uint32_t));
394
395 QuicStringPiece cert =
396 common_sets->GetCert(entry.set_hash, entry.index);
397 if (cert.empty()) {
398 return false;
399 }
vasilvvc48c8712019-03-11 13:38:16 -0700400 out_certs->push_back(std::string(cert));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500401 break;
402 }
403 default:
404 return false;
405 }
406 out_entries->push_back(entry);
407 }
408
409 *in_out = in;
410 return true;
411}
412
413// ScopedZLib deals with the automatic destruction of a zlib context.
414class ScopedZLib {
415 public:
416 enum Type {
417 INFLATE,
418 DEFLATE,
419 };
420
421 explicit ScopedZLib(Type type) : z_(nullptr), type_(type) {}
422
423 void reset(z_stream* z) {
424 Clear();
425 z_ = z;
426 }
427
428 ~ScopedZLib() { Clear(); }
429
430 private:
431 void Clear() {
432 if (!z_) {
433 return;
434 }
435
436 if (type_ == DEFLATE) {
437 deflateEnd(z_);
438 } else {
439 inflateEnd(z_);
440 }
441 z_ = nullptr;
442 }
443
444 z_stream* z_;
445 const Type type_;
446};
447
448} // anonymous namespace
449
450// static
vasilvvc48c8712019-03-11 13:38:16 -0700451std::string CertCompressor::CompressChain(
452 const std::vector<std::string>& certs,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500453 QuicStringPiece client_common_set_hashes,
454 QuicStringPiece client_cached_cert_hashes,
455 const CommonCertSets* common_sets) {
456 const std::vector<CertEntry> entries = MatchCerts(
457 certs, client_common_set_hashes, client_cached_cert_hashes, common_sets);
458 DCHECK_EQ(entries.size(), certs.size());
459
460 size_t uncompressed_size = 0;
461 for (size_t i = 0; i < entries.size(); i++) {
462 if (entries[i].type == CertEntry::COMPRESSED) {
463 uncompressed_size += 4 /* uint32_t length */ + certs[i].size();
464 }
465 }
466
467 size_t compressed_size = 0;
468 z_stream z;
469 ScopedZLib scoped_z(ScopedZLib::DEFLATE);
470
471 if (uncompressed_size > 0) {
472 memset(&z, 0, sizeof(z));
473 int rv = deflateInit(&z, Z_DEFAULT_COMPRESSION);
474 DCHECK_EQ(Z_OK, rv);
475 if (rv != Z_OK) {
476 return "";
477 }
478 scoped_z.reset(&z);
479
vasilvvc48c8712019-03-11 13:38:16 -0700480 std::string zlib_dict = ZlibDictForEntries(entries, certs);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500481
482 rv = deflateSetDictionary(
483 &z, reinterpret_cast<const uint8_t*>(&zlib_dict[0]), zlib_dict.size());
484 DCHECK_EQ(Z_OK, rv);
485 if (rv != Z_OK) {
486 return "";
487 }
488
489 compressed_size = deflateBound(&z, uncompressed_size);
490 }
491
492 const size_t entries_size = CertEntriesSize(entries);
493
vasilvvc48c8712019-03-11 13:38:16 -0700494 std::string result;
QUICHE teama6ef0a62019-03-07 20:34:33 -0500495 result.resize(entries_size + (uncompressed_size > 0 ? 4 : 0) +
496 compressed_size);
497
498 uint8_t* j = reinterpret_cast<uint8_t*>(&result[0]);
499 SerializeCertEntries(j, entries);
500 j += entries_size;
501
502 if (uncompressed_size == 0) {
503 return result;
504 }
505
506 uint32_t uncompressed_size_32 = uncompressed_size;
507 memcpy(j, &uncompressed_size_32, sizeof(uint32_t));
508 j += sizeof(uint32_t);
509
510 int rv;
511
512 z.next_out = j;
513 z.avail_out = compressed_size;
514
515 for (size_t i = 0; i < certs.size(); i++) {
516 if (entries[i].type != CertEntry::COMPRESSED) {
517 continue;
518 }
519
520 uint32_t length32 = certs[i].size();
521 z.next_in = reinterpret_cast<uint8_t*>(&length32);
522 z.avail_in = sizeof(length32);
523 rv = deflate(&z, Z_NO_FLUSH);
524 DCHECK_EQ(Z_OK, rv);
525 DCHECK_EQ(0u, z.avail_in);
526 if (rv != Z_OK || z.avail_in) {
527 return "";
528 }
529
530 z.next_in =
531 const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(certs[i].data()));
532 z.avail_in = certs[i].size();
533 rv = deflate(&z, Z_NO_FLUSH);
534 DCHECK_EQ(Z_OK, rv);
535 DCHECK_EQ(0u, z.avail_in);
536 if (rv != Z_OK || z.avail_in) {
537 return "";
538 }
539 }
540
541 z.avail_in = 0;
542 rv = deflate(&z, Z_FINISH);
543 DCHECK_EQ(Z_STREAM_END, rv);
544 if (rv != Z_STREAM_END) {
545 return "";
546 }
547
548 result.resize(result.size() - z.avail_out);
549 return result;
550}
551
552// static
553bool CertCompressor::DecompressChain(
554 QuicStringPiece in,
vasilvvc48c8712019-03-11 13:38:16 -0700555 const std::vector<std::string>& cached_certs,
QUICHE teama6ef0a62019-03-07 20:34:33 -0500556 const CommonCertSets* common_sets,
vasilvvc48c8712019-03-11 13:38:16 -0700557 std::vector<std::string>* out_certs) {
QUICHE teama6ef0a62019-03-07 20:34:33 -0500558 std::vector<CertEntry> entries;
559 if (!ParseEntries(&in, cached_certs, common_sets, &entries, out_certs)) {
560 return false;
561 }
562 DCHECK_EQ(entries.size(), out_certs->size());
563
564 std::unique_ptr<uint8_t[]> uncompressed_data;
565 QuicStringPiece uncompressed;
566
567 if (!in.empty()) {
568 if (in.size() < sizeof(uint32_t)) {
569 return false;
570 }
571
572 uint32_t uncompressed_size;
573 memcpy(&uncompressed_size, in.data(), sizeof(uncompressed_size));
574 in.remove_prefix(sizeof(uint32_t));
575
576 if (uncompressed_size > 128 * 1024) {
577 return false;
578 }
579
vasilvv0fc587f2019-09-06 13:33:08 -0700580 uncompressed_data = std::make_unique<uint8_t[]>(uncompressed_size);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500581 z_stream z;
582 ScopedZLib scoped_z(ScopedZLib::INFLATE);
583
584 memset(&z, 0, sizeof(z));
585 z.next_out = uncompressed_data.get();
586 z.avail_out = uncompressed_size;
587 z.next_in =
588 const_cast<uint8_t*>(reinterpret_cast<const uint8_t*>(in.data()));
589 z.avail_in = in.size();
590
591 if (Z_OK != inflateInit(&z)) {
592 return false;
593 }
594 scoped_z.reset(&z);
595
596 int rv = inflate(&z, Z_FINISH);
597 if (rv == Z_NEED_DICT) {
vasilvvc48c8712019-03-11 13:38:16 -0700598 std::string zlib_dict = ZlibDictForEntries(entries, *out_certs);
QUICHE teama6ef0a62019-03-07 20:34:33 -0500599 const uint8_t* dict = reinterpret_cast<const uint8_t*>(zlib_dict.data());
600 if (Z_OK != inflateSetDictionary(&z, dict, zlib_dict.size())) {
601 return false;
602 }
603 rv = inflate(&z, Z_FINISH);
604 }
605
606 if (Z_STREAM_END != rv || z.avail_out > 0 || z.avail_in > 0) {
607 return false;
608 }
609
610 uncompressed = QuicStringPiece(
611 reinterpret_cast<char*>(uncompressed_data.get()), uncompressed_size);
612 }
613
614 for (size_t i = 0; i < entries.size(); i++) {
615 switch (entries[i].type) {
616 case CertEntry::COMPRESSED:
617 if (uncompressed.size() < sizeof(uint32_t)) {
618 return false;
619 }
620 uint32_t cert_len;
621 memcpy(&cert_len, uncompressed.data(), sizeof(cert_len));
622 uncompressed.remove_prefix(sizeof(uint32_t));
623 if (uncompressed.size() < cert_len) {
624 return false;
625 }
vasilvvc48c8712019-03-11 13:38:16 -0700626 (*out_certs)[i] = std::string(uncompressed.substr(0, cert_len));
QUICHE teama6ef0a62019-03-07 20:34:33 -0500627 uncompressed.remove_prefix(cert_len);
628 break;
629 case CertEntry::CACHED:
630 case CertEntry::COMMON:
631 break;
632 }
633 }
634
635 if (!uncompressed.empty()) {
636 return false;
637 }
638
639 return true;
640}
641
642} // namespace quic