[Android WebView] Fix webview perf bot switchover to use org.chromium.webview_shell...
[chromium-blink-merge.git] / net / quic / crypto / cert_compressor.cc
blobcb44d355a8dd357b04e6bcbb34ed08c981bb54be
1 // 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.
5 #include "net/quic/crypto/cert_compressor.h"
7 #include "base/logging.h"
8 #include "base/memory/scoped_ptr.h"
9 #include "net/quic/quic_utils.h"
10 #include "third_party/zlib/zlib.h"
12 using base::StringPiece;
13 using std::string;
14 using std::vector;
16 namespace net {
18 namespace {
20 // kCommonCertSubstrings contains ~1500 bytes of common certificate substrings
21 // in order to help zlib. This was generated via a fairly dumb algorithm from
22 // the Alexa Top 5000 set - we could probably do better.
23 static const unsigned char kCommonCertSubstrings[] = {
24 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x25, 0x04,
25 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03,
26 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x03, 0x02, 0x30,
27 0x5f, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x86, 0xf8, 0x42, 0x04, 0x01,
28 0x06, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86, 0xfd, 0x6d, 0x01, 0x07,
29 0x17, 0x01, 0x30, 0x33, 0x20, 0x45, 0x78, 0x74, 0x65, 0x6e, 0x64, 0x65,
30 0x64, 0x20, 0x56, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e,
31 0x20, 0x53, 0x20, 0x4c, 0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x31, 0x34,
32 0x20, 0x53, 0x53, 0x4c, 0x20, 0x43, 0x41, 0x30, 0x1e, 0x17, 0x0d, 0x31,
33 0x32, 0x20, 0x53, 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x53, 0x65, 0x72,
34 0x76, 0x65, 0x72, 0x20, 0x43, 0x41, 0x30, 0x2d, 0x61, 0x69, 0x61, 0x2e,
35 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d,
36 0x2f, 0x45, 0x2d, 0x63, 0x72, 0x6c, 0x2e, 0x76, 0x65, 0x72, 0x69, 0x73,
37 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x45, 0x2e, 0x63, 0x65,
38 0x72, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01,
39 0x01, 0x05, 0x05, 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x4a, 0x2e, 0x63,
40 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73,
41 0x2f, 0x63, 0x70, 0x73, 0x20, 0x28, 0x63, 0x29, 0x30, 0x30, 0x09, 0x06,
42 0x03, 0x55, 0x1d, 0x13, 0x04, 0x02, 0x30, 0x00, 0x30, 0x1d, 0x30, 0x0d,
43 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05,
44 0x00, 0x03, 0x82, 0x01, 0x01, 0x00, 0x7b, 0x30, 0x1d, 0x06, 0x03, 0x55,
45 0x1d, 0x0e, 0x30, 0x82, 0x01, 0x22, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86,
46 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x82, 0x01,
47 0x0f, 0x00, 0x30, 0x82, 0x01, 0x0a, 0x02, 0x82, 0x01, 0x01, 0x00, 0xd2,
48 0x6f, 0x64, 0x6f, 0x63, 0x61, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x43, 0x2e,
49 0x63, 0x72, 0x6c, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x1d, 0x0e, 0x04, 0x16,
50 0x04, 0x14, 0xb4, 0x2e, 0x67, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x73, 0x69,
51 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x30, 0x0b, 0x06, 0x03,
52 0x55, 0x1d, 0x0f, 0x04, 0x04, 0x03, 0x02, 0x01, 0x30, 0x0d, 0x06, 0x09,
53 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30,
54 0x81, 0xca, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03, 0x55, 0x04, 0x06, 0x13,
55 0x02, 0x55, 0x53, 0x31, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x04, 0x08,
56 0x13, 0x07, 0x41, 0x72, 0x69, 0x7a, 0x6f, 0x6e, 0x61, 0x31, 0x13, 0x30,
57 0x11, 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x0a, 0x53, 0x63, 0x6f, 0x74,
58 0x74, 0x73, 0x64, 0x61, 0x6c, 0x65, 0x31, 0x1a, 0x30, 0x18, 0x06, 0x03,
59 0x55, 0x04, 0x0a, 0x13, 0x11, 0x47, 0x6f, 0x44, 0x61, 0x64, 0x64, 0x79,
60 0x2e, 0x63, 0x6f, 0x6d, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31, 0x33,
61 0x30, 0x31, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x2a, 0x68, 0x74, 0x74,
62 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66, 0x69, 0x63,
63 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79,
64 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74,
65 0x6f, 0x72, 0x79, 0x31, 0x30, 0x30, 0x2e, 0x06, 0x03, 0x55, 0x04, 0x03,
66 0x13, 0x27, 0x47, 0x6f, 0x20, 0x44, 0x61, 0x64, 0x64, 0x79, 0x20, 0x53,
67 0x65, 0x63, 0x75, 0x72, 0x65, 0x20, 0x43, 0x65, 0x72, 0x74, 0x69, 0x66,
68 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x41, 0x75, 0x74, 0x68,
69 0x6f, 0x72, 0x69, 0x74, 0x79, 0x31, 0x11, 0x30, 0x0f, 0x06, 0x03, 0x55,
70 0x04, 0x05, 0x13, 0x08, 0x30, 0x37, 0x39, 0x36, 0x39, 0x32, 0x38, 0x37,
71 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x31, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d,
72 0x0f, 0x01, 0x01, 0xff, 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x0c,
73 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff, 0x04, 0x02, 0x30, 0x00,
74 0x30, 0x1d, 0x30, 0x0f, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01, 0x01, 0xff,
75 0x04, 0x05, 0x30, 0x03, 0x01, 0x01, 0x00, 0x30, 0x1d, 0x06, 0x03, 0x55,
76 0x1d, 0x25, 0x04, 0x16, 0x30, 0x14, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05,
77 0x05, 0x07, 0x03, 0x01, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07,
78 0x03, 0x02, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01, 0xff,
79 0x04, 0x04, 0x03, 0x02, 0x05, 0xa0, 0x30, 0x33, 0x06, 0x03, 0x55, 0x1d,
80 0x1f, 0x04, 0x2c, 0x30, 0x2a, 0x30, 0x28, 0xa0, 0x26, 0xa0, 0x24, 0x86,
81 0x22, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x72, 0x6c, 0x2e,
82 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
83 0x67, 0x64, 0x73, 0x31, 0x2d, 0x32, 0x30, 0x2a, 0x30, 0x28, 0x06, 0x08,
84 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x02, 0x01, 0x16, 0x1c, 0x68, 0x74,
85 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76, 0x65,
86 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63,
87 0x70, 0x73, 0x30, 0x34, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x17,
88 0x0d, 0x31, 0x33, 0x30, 0x35, 0x30, 0x39, 0x06, 0x08, 0x2b, 0x06, 0x01,
89 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x3a,
90 0x2f, 0x2f, 0x73, 0x30, 0x39, 0x30, 0x37, 0x06, 0x08, 0x2b, 0x06, 0x01,
91 0x05, 0x05, 0x07, 0x02, 0x30, 0x44, 0x06, 0x03, 0x55, 0x1d, 0x20, 0x04,
92 0x3d, 0x30, 0x3b, 0x30, 0x39, 0x06, 0x0b, 0x60, 0x86, 0x48, 0x01, 0x86,
93 0xf8, 0x45, 0x01, 0x07, 0x17, 0x06, 0x31, 0x0b, 0x30, 0x09, 0x06, 0x03,
94 0x55, 0x04, 0x06, 0x13, 0x02, 0x47, 0x42, 0x31, 0x1b, 0x53, 0x31, 0x17,
95 0x30, 0x15, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x13, 0x0e, 0x56, 0x65, 0x72,
96 0x69, 0x53, 0x69, 0x67, 0x6e, 0x2c, 0x20, 0x49, 0x6e, 0x63, 0x2e, 0x31,
97 0x1f, 0x30, 0x1d, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x16, 0x56, 0x65,
98 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e, 0x20, 0x54, 0x72, 0x75, 0x73, 0x74,
99 0x20, 0x4e, 0x65, 0x74, 0x77, 0x6f, 0x72, 0x6b, 0x31, 0x3b, 0x30, 0x39,
100 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x32, 0x54, 0x65, 0x72, 0x6d, 0x73,
101 0x20, 0x6f, 0x66, 0x20, 0x75, 0x73, 0x65, 0x20, 0x61, 0x74, 0x20, 0x68,
102 0x74, 0x74, 0x70, 0x73, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x76,
103 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d, 0x2f,
104 0x72, 0x70, 0x61, 0x20, 0x28, 0x63, 0x29, 0x30, 0x31, 0x10, 0x30, 0x0e,
105 0x06, 0x03, 0x55, 0x04, 0x07, 0x13, 0x07, 0x53, 0x31, 0x13, 0x30, 0x11,
106 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x0a, 0x47, 0x31, 0x13, 0x30, 0x11,
107 0x06, 0x0b, 0x2b, 0x06, 0x01, 0x04, 0x01, 0x82, 0x37, 0x3c, 0x02, 0x01,
108 0x03, 0x13, 0x02, 0x55, 0x31, 0x16, 0x30, 0x14, 0x06, 0x03, 0x55, 0x04,
109 0x03, 0x14, 0x31, 0x19, 0x30, 0x17, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
110 0x31, 0x1d, 0x30, 0x1b, 0x06, 0x03, 0x55, 0x04, 0x0f, 0x13, 0x14, 0x50,
111 0x72, 0x69, 0x76, 0x61, 0x74, 0x65, 0x20, 0x4f, 0x72, 0x67, 0x61, 0x6e,
112 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x31, 0x12, 0x31, 0x21, 0x30,
113 0x1f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x18, 0x44, 0x6f, 0x6d, 0x61,
114 0x69, 0x6e, 0x20, 0x43, 0x6f, 0x6e, 0x74, 0x72, 0x6f, 0x6c, 0x20, 0x56,
115 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x64, 0x31, 0x14, 0x31, 0x31,
116 0x30, 0x2f, 0x06, 0x03, 0x55, 0x04, 0x0b, 0x13, 0x28, 0x53, 0x65, 0x65,
117 0x20, 0x77, 0x77, 0x77, 0x2e, 0x72, 0x3a, 0x2f, 0x2f, 0x73, 0x65, 0x63,
118 0x75, 0x72, 0x65, 0x2e, 0x67, 0x47, 0x6c, 0x6f, 0x62, 0x61, 0x6c, 0x53,
119 0x69, 0x67, 0x6e, 0x31, 0x53, 0x65, 0x72, 0x76, 0x65, 0x72, 0x43, 0x41,
120 0x2e, 0x63, 0x72, 0x6c, 0x56, 0x65, 0x72, 0x69, 0x53, 0x69, 0x67, 0x6e,
121 0x20, 0x43, 0x6c, 0x61, 0x73, 0x73, 0x20, 0x33, 0x20, 0x45, 0x63, 0x72,
122 0x6c, 0x2e, 0x67, 0x65, 0x6f, 0x74, 0x72, 0x75, 0x73, 0x74, 0x2e, 0x63,
123 0x6f, 0x6d, 0x2f, 0x63, 0x72, 0x6c, 0x73, 0x2f, 0x73, 0x64, 0x31, 0x1a,
124 0x30, 0x18, 0x06, 0x03, 0x55, 0x04, 0x0a, 0x68, 0x74, 0x74, 0x70, 0x3a,
125 0x2f, 0x2f, 0x45, 0x56, 0x49, 0x6e, 0x74, 0x6c, 0x2d, 0x63, 0x63, 0x72,
126 0x74, 0x2e, 0x67, 0x77, 0x77, 0x77, 0x2e, 0x67, 0x69, 0x63, 0x65, 0x72,
127 0x74, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x31, 0x6f, 0x63, 0x73, 0x70, 0x2e,
128 0x76, 0x65, 0x72, 0x69, 0x73, 0x69, 0x67, 0x6e, 0x2e, 0x63, 0x6f, 0x6d,
129 0x30, 0x39, 0x72, 0x61, 0x70, 0x69, 0x64, 0x73, 0x73, 0x6c, 0x2e, 0x63,
130 0x6f, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63,
131 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x6f, 0x72,
132 0x79, 0x2f, 0x30, 0x81, 0x80, 0x06, 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05,
133 0x07, 0x01, 0x01, 0x04, 0x74, 0x30, 0x72, 0x30, 0x24, 0x06, 0x08, 0x2b,
134 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x01, 0x86, 0x18, 0x68, 0x74, 0x74,
135 0x70, 0x3a, 0x2f, 0x2f, 0x6f, 0x63, 0x73, 0x70, 0x2e, 0x67, 0x6f, 0x64,
136 0x61, 0x64, 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x30, 0x4a, 0x06,
137 0x08, 0x2b, 0x06, 0x01, 0x05, 0x05, 0x07, 0x30, 0x02, 0x86, 0x3e, 0x68,
138 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x65, 0x72, 0x74, 0x69, 0x66,
139 0x69, 0x63, 0x61, 0x74, 0x65, 0x73, 0x2e, 0x67, 0x6f, 0x64, 0x61, 0x64,
140 0x64, 0x79, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x72, 0x65, 0x70, 0x6f, 0x73,
141 0x69, 0x74, 0x6f, 0x72, 0x79, 0x2f, 0x67, 0x64, 0x5f, 0x69, 0x6e, 0x74,
142 0x65, 0x72, 0x6d, 0x65, 0x64, 0x69, 0x61, 0x74, 0x65, 0x2e, 0x63, 0x72,
143 0x74, 0x30, 0x1f, 0x06, 0x03, 0x55, 0x1d, 0x23, 0x04, 0x18, 0x30, 0x16,
144 0x80, 0x14, 0xfd, 0xac, 0x61, 0x32, 0x93, 0x6c, 0x45, 0xd6, 0xe2, 0xee,
145 0x85, 0x5f, 0x9a, 0xba, 0xe7, 0x76, 0x99, 0x68, 0xcc, 0xe7, 0x30, 0x27,
146 0x86, 0x29, 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x63, 0x86, 0x30,
147 0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x73,
150 // CertEntry represents a certificate in compressed form. Each entry is one of
151 // the three types enumerated in |Type|.
152 struct CertEntry {
153 public:
154 enum Type {
155 // Type 0 is reserved to mean "end of list" in the wire format.
157 // COMPRESSED means that the certificate is included in the trailing zlib
158 // data.
159 COMPRESSED = 1,
160 // CACHED means that the certificate is already known to the peer and will
161 // be replaced by its 64-bit hash (in |hash|).
162 CACHED = 2,
163 // COMMON means that the certificate is in a common certificate set known
164 // to the peer with hash |set_hash| and certificate index |index|.
165 COMMON = 3,
168 Type type;
169 uint64 hash;
170 uint64 set_hash;
171 uint32 index;
174 // MatchCerts returns a vector of CertEntries describing how to most
175 // efficiently represent |certs| to a peer who has the common sets identified
176 // by |client_common_set_hashes| and who has cached the certificates with the
177 // 64-bit, FNV-1a hashes in |client_cached_cert_hashes|.
178 vector<CertEntry> MatchCerts(const vector<string>& certs,
179 StringPiece client_common_set_hashes,
180 StringPiece client_cached_cert_hashes,
181 const CommonCertSets* common_sets) {
182 vector<CertEntry> entries;
183 entries.reserve(certs.size());
185 const bool cached_valid =
186 client_cached_cert_hashes.size() % sizeof(uint64) == 0 &&
187 !client_cached_cert_hashes.empty();
189 for (vector<string>::const_iterator i = certs.begin();
190 i != certs.end(); ++i) {
191 CertEntry entry;
193 if (cached_valid) {
194 bool cached = false;
196 uint64 hash = QuicUtils::FNV1a_64_Hash(i->data(), i->size());
197 // This assumes that the machine is little-endian.
198 for (size_t j = 0; j < client_cached_cert_hashes.size();
199 j += sizeof(uint64)) {
200 uint64 cached_hash;
201 memcpy(&cached_hash, client_cached_cert_hashes.data() + j,
202 sizeof(uint64));
203 if (hash != cached_hash) {
204 continue;
207 entry.type = CertEntry::CACHED;
208 entry.hash = hash;
209 entries.push_back(entry);
210 cached = true;
211 break;
214 if (cached) {
215 continue;
219 if (common_sets && common_sets->MatchCert(*i, client_common_set_hashes,
220 &entry.set_hash, &entry.index)) {
221 entry.type = CertEntry::COMMON;
222 entries.push_back(entry);
223 continue;
226 entry.type = CertEntry::COMPRESSED;
227 entries.push_back(entry);
230 return entries;
233 // CertEntriesSize returns the size, in bytes, of the serialised form of
234 // |entries|.
235 size_t CertEntriesSize(const vector<CertEntry>& entries) {
236 size_t entries_size = 0;
238 for (vector<CertEntry>::const_iterator i = entries.begin();
239 i != entries.end(); ++i) {
240 entries_size++;
241 switch (i->type) {
242 case CertEntry::COMPRESSED:
243 break;
244 case CertEntry::CACHED:
245 entries_size += sizeof(uint64);
246 break;
247 case CertEntry::COMMON:
248 entries_size += sizeof(uint64) + sizeof(uint32);
249 break;
253 entries_size++; // for end marker
255 return entries_size;
258 // SerializeCertEntries serialises |entries| to |out|, which must have enough
259 // space to contain them.
260 void SerializeCertEntries(uint8* out, const vector<CertEntry>& entries) {
261 for (vector<CertEntry>::const_iterator i = entries.begin();
262 i != entries.end(); ++i) {
263 *out++ = static_cast<uint8>(i->type);
264 switch (i->type) {
265 case CertEntry::COMPRESSED:
266 break;
267 case CertEntry::CACHED:
268 memcpy(out, &i->hash, sizeof(i->hash));
269 out += sizeof(uint64);
270 break;
271 case CertEntry::COMMON:
272 // Assumes a little-endian machine.
273 memcpy(out, &i->set_hash, sizeof(i->set_hash));
274 out += sizeof(i->set_hash);
275 memcpy(out, &i->index, sizeof(uint32));
276 out += sizeof(uint32);
277 break;
281 *out++ = 0; // end marker
284 // ZlibDictForEntries returns a string that contains the zlib pre-shared
285 // dictionary to use in order to decompress a zlib block following |entries|.
286 // |certs| is one-to-one with |entries| and contains the certificates for those
287 // entries that are CACHED or COMMON.
288 string ZlibDictForEntries(const vector<CertEntry>& entries,
289 const vector<string>& certs) {
290 string zlib_dict;
292 // The dictionary starts with the common and cached certs in reverse order.
293 size_t zlib_dict_size = 0;
294 for (size_t i = certs.size() - 1; i < certs.size(); i--) {
295 if (entries[i].type != CertEntry::COMPRESSED) {
296 zlib_dict_size += certs[i].size();
300 // At the end of the dictionary is a block of common certificate substrings.
301 zlib_dict_size += sizeof(kCommonCertSubstrings);
303 zlib_dict.reserve(zlib_dict_size);
305 for (size_t i = certs.size() - 1; i < certs.size(); i--) {
306 if (entries[i].type != CertEntry::COMPRESSED) {
307 zlib_dict += certs[i];
311 zlib_dict += string(reinterpret_cast<const char*>(kCommonCertSubstrings),
312 sizeof(kCommonCertSubstrings));
314 DCHECK_EQ(zlib_dict.size(), zlib_dict_size);
316 return zlib_dict;
319 // HashCerts returns the FNV-1a hashes of |certs|.
320 vector<uint64> HashCerts(const vector<string>& certs) {
321 vector<uint64> ret;
322 ret.reserve(certs.size());
324 for (vector<string>::const_iterator i = certs.begin();
325 i != certs.end(); ++i) {
326 ret.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size()));
329 return ret;
332 // ParseEntries parses the serialised form of a vector of CertEntries from
333 // |in_out| and writes them to |out_entries|. CACHED and COMMON entries are
334 // resolved using |cached_certs| and |common_sets| and written to |out_certs|.
335 // |in_out| is updated to contain the trailing data.
336 bool ParseEntries(StringPiece* in_out,
337 const vector<string>& cached_certs,
338 const CommonCertSets* common_sets,
339 vector<CertEntry>* out_entries,
340 vector<string>* out_certs) {
341 StringPiece in = *in_out;
342 vector<uint64> cached_hashes;
344 out_entries->clear();
345 out_certs->clear();
347 for (;;) {
348 if (in.empty()) {
349 return false;
351 CertEntry entry;
352 const uint8 type_byte = in[0];
353 in.remove_prefix(1);
355 if (type_byte == 0) {
356 break;
359 entry.type = static_cast<CertEntry::Type>(type_byte);
361 switch (entry.type) {
362 case CertEntry::COMPRESSED:
363 out_certs->push_back(string());
364 break;
365 case CertEntry::CACHED: {
366 if (in.size() < sizeof(uint64)) {
367 return false;
369 memcpy(&entry.hash, in.data(), sizeof(uint64));
370 in.remove_prefix(sizeof(uint64));
372 if (cached_hashes.size() != cached_certs.size()) {
373 cached_hashes = HashCerts(cached_certs);
375 bool found = false;
376 for (size_t i = 0; i < cached_hashes.size(); i++) {
377 if (cached_hashes[i] == entry.hash) {
378 out_certs->push_back(cached_certs[i]);
379 found = true;
380 break;
383 if (!found) {
384 return false;
386 break;
388 case CertEntry::COMMON: {
389 if (!common_sets) {
390 return false;
392 if (in.size() < sizeof(uint64) + sizeof(uint32)) {
393 return false;
395 memcpy(&entry.set_hash, in.data(), sizeof(uint64));
396 in.remove_prefix(sizeof(uint64));
397 memcpy(&entry.index, in.data(), sizeof(uint32));
398 in.remove_prefix(sizeof(uint32));
400 StringPiece cert = common_sets->GetCert(entry.set_hash, entry.index);
401 if (cert.empty()) {
402 return false;
404 out_certs->push_back(cert.as_string());
405 break;
407 default:
408 return false;
410 out_entries->push_back(entry);
413 *in_out = in;
414 return true;
417 // ScopedZLib deals with the automatic destruction of a zlib context.
418 class ScopedZLib {
419 public:
420 enum Type {
421 INFLATE,
422 DEFLATE,
425 explicit ScopedZLib(Type type) : z_(nullptr), type_(type) {}
427 void reset(z_stream* z) {
428 Clear();
429 z_ = z;
432 ~ScopedZLib() {
433 Clear();
436 private:
437 void Clear() {
438 if (!z_) {
439 return;
442 if (type_ == DEFLATE) {
443 deflateEnd(z_);
444 } else {
445 inflateEnd(z_);
447 z_ = nullptr;
450 z_stream* z_;
451 const Type type_;
454 } // anonymous namespace
457 // static
458 string CertCompressor::CompressChain(const vector<string>& certs,
459 StringPiece client_common_set_hashes,
460 StringPiece client_cached_cert_hashes,
461 const CommonCertSets* common_sets) {
462 const vector<CertEntry> entries = MatchCerts(
463 certs, client_common_set_hashes, client_cached_cert_hashes, common_sets);
464 DCHECK_EQ(entries.size(), certs.size());
466 size_t uncompressed_size = 0;
467 for (size_t i = 0; i < entries.size(); i++) {
468 if (entries[i].type == CertEntry::COMPRESSED) {
469 uncompressed_size += 4 /* uint32 length */ + certs[i].size();
473 size_t compressed_size = 0;
474 z_stream z;
475 ScopedZLib scoped_z(ScopedZLib::DEFLATE);
477 if (uncompressed_size > 0) {
478 memset(&z, 0, sizeof(z));
479 int rv = deflateInit(&z, Z_DEFAULT_COMPRESSION);
480 DCHECK_EQ(Z_OK, rv);
481 if (rv != Z_OK) {
482 return "";
484 scoped_z.reset(&z);
486 string zlib_dict = ZlibDictForEntries(entries, certs);
488 rv = deflateSetDictionary(&z, reinterpret_cast<const uint8*>(&zlib_dict[0]),
489 zlib_dict.size());
490 DCHECK_EQ(Z_OK, rv);
491 if (rv != Z_OK) {
492 return "";
495 compressed_size = deflateBound(&z, uncompressed_size);
498 const size_t entries_size = CertEntriesSize(entries);
500 string result;
501 result.resize(entries_size + (uncompressed_size > 0 ? 4 : 0) +
502 compressed_size);
504 uint8* j = reinterpret_cast<uint8*>(&result[0]);
505 SerializeCertEntries(j, entries);
506 j += entries_size;
508 if (uncompressed_size == 0) {
509 return result;
512 uint32 uncompressed_size_32 = uncompressed_size;
513 memcpy(j, &uncompressed_size_32, sizeof(uint32));
514 j += sizeof(uint32);
516 int rv;
518 z.next_out = j;
519 z.avail_out = compressed_size;
521 for (size_t i = 0; i < certs.size(); i++) {
522 if (entries[i].type != CertEntry::COMPRESSED) {
523 continue;
526 uint32 length32 = certs[i].size();
527 z.next_in = reinterpret_cast<uint8*>(&length32);
528 z.avail_in = sizeof(length32);
529 rv = deflate(&z, Z_NO_FLUSH);
530 DCHECK_EQ(Z_OK, rv);
531 DCHECK_EQ(0u, z.avail_in);
532 if (rv != Z_OK || z.avail_in) {
533 return "";
536 z.next_in =
537 const_cast<uint8*>(reinterpret_cast<const uint8*>(certs[i].data()));
538 z.avail_in = certs[i].size();
539 rv = deflate(&z, Z_NO_FLUSH);
540 DCHECK_EQ(Z_OK, rv);
541 DCHECK_EQ(0u, z.avail_in);
542 if (rv != Z_OK || z.avail_in) {
543 return "";
547 z.avail_in = 0;
548 rv = deflate(&z, Z_FINISH);
549 DCHECK_EQ(Z_STREAM_END, rv);
550 if (rv != Z_STREAM_END) {
551 return "";
554 result.resize(result.size() - z.avail_out);
555 return result;
558 // static
559 bool CertCompressor::DecompressChain(StringPiece in,
560 const vector<string>& cached_certs,
561 const CommonCertSets* common_sets,
562 vector<string>* out_certs) {
563 vector<CertEntry> entries;
564 if (!ParseEntries(&in, cached_certs, common_sets, &entries, out_certs)) {
565 return false;
567 DCHECK_EQ(entries.size(), out_certs->size());
569 scoped_ptr<uint8[]> uncompressed_data;
570 StringPiece uncompressed;
572 if (!in.empty()) {
573 if (in.size() < sizeof(uint32)) {
574 return false;
577 uint32 uncompressed_size;
578 memcpy(&uncompressed_size, in.data(), sizeof(uncompressed_size));
579 in.remove_prefix(sizeof(uint32));
581 if (uncompressed_size > 128 * 1024) {
582 return false;
585 uncompressed_data.reset(new uint8[uncompressed_size]);
586 z_stream z;
587 ScopedZLib scoped_z(ScopedZLib::INFLATE);
589 memset(&z, 0, sizeof(z));
590 z.next_out = uncompressed_data.get();
591 z.avail_out = uncompressed_size;
592 z.next_in = const_cast<uint8*>(reinterpret_cast<const uint8*>(in.data()));
593 z.avail_in = in.size();
595 if (Z_OK != inflateInit(&z)) {
596 return false;
598 scoped_z.reset(&z);
600 int rv = inflate(&z, Z_FINISH);
601 if (rv == Z_NEED_DICT) {
602 string zlib_dict = ZlibDictForEntries(entries, *out_certs);
603 const uint8* dict = reinterpret_cast<const uint8*>(zlib_dict.data());
604 if (Z_OK != inflateSetDictionary(&z, dict, zlib_dict.size())) {
605 return false;
607 rv = inflate(&z, Z_FINISH);
610 if (Z_STREAM_END != rv || z.avail_out > 0 || z.avail_in > 0) {
611 return false;
614 uncompressed = StringPiece(reinterpret_cast<char*>(uncompressed_data.get()),
615 uncompressed_size);
618 for (size_t i = 0; i < entries.size(); i++) {
619 switch (entries[i].type) {
620 case CertEntry::COMPRESSED:
621 if (uncompressed.size() < sizeof(uint32)) {
622 return false;
624 uint32 cert_len;
625 memcpy(&cert_len, uncompressed.data(), sizeof(cert_len));
626 uncompressed.remove_prefix(sizeof(uint32));
627 if (uncompressed.size() < cert_len) {
628 return false;
630 (*out_certs)[i] = uncompressed.substr(0, cert_len).as_string();
631 uncompressed.remove_prefix(cert_len);
632 break;
633 case CertEntry::CACHED:
634 case CertEntry::COMMON:
635 break;
639 if (!uncompressed.empty()) {
640 return false;
643 return true;
646 } // namespace net