| Index: net/quic/crypto/cert_compressor.cc
|
| diff --git a/net/quic/crypto/cert_compressor.cc b/net/quic/crypto/cert_compressor.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..aaa5f554acff5c006e54c5383229622a6a74d6c6
|
| --- /dev/null
|
| +++ b/net/quic/crypto/cert_compressor.cc
|
| @@ -0,0 +1,641 @@
|
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
| +// Use of this source code is governed by a BSD-style license that can be
|
| +// found in the LICENSE file.
|
| +
|
| +#include "net/quic/crypto/cert_compressor.h"
|
| +
|
| +#include "base/logging.h"
|
| +#include "base/memory/scoped_ptr.h"
|
| +#include "net/quic/quic_utils.h"
|
| +#include "third_party/zlib/zlib.h"
|
| +
|
| +using base::StringPiece;
|
| +using std::string;
|
| +using std::vector;
|
| +
|
| +namespace net {
|
| +
|
| +namespace {
|
| +
|
| +// kCommonCertSubstrings contains ~1500 bytes of common certificate substrings
|
| +// in order to help zlib.
|
| +static unsigned char kCommonCertSubstrings[] = {
|
| + 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,
|
| +};
|
| +
|
| +// CertEntry represents a certificate in compressed form. Each entry is one of
|
| +// the three types enumerated in |Type|.
|
| +struct CertEntry {
|
| + public:
|
| + enum Type {
|
| + // COMPRESSED means that the certificate is included in the trailing zlib
|
| + // data.
|
| + COMPRESSED = 1,
|
| + // CACHED means that the certificate is already known to the peer and will
|
| + // be replaced by its 64-bit hash (in |hash|).
|
| + CACHED = 2,
|
| + // COMMON means that the certificate is in a common certificate set known
|
| + // to the peer with hash |set_hash| and index |index|.
|
| + COMMON = 3,
|
| + };
|
| +
|
| + Type type;
|
| + uint64 hash;
|
| + uint64 set_hash;
|
| + uint32 index;
|
| +};
|
| +
|
| +// MatchCerts returns a vector of CertEntries describing how to most
|
| +// efficiently represent |certs| to a peer who has the common sets identified
|
| +// by |client_common_set_hashes| and who has cached the certificates with the
|
| +// 64-bit, FNV-1a hashes in |client_cached|.
|
| +vector<CertEntry> MatchCerts(const vector<string>& certs,
|
| + StringPiece client_common_set_hashes,
|
| + StringPiece client_cached,
|
| + CommonCertSet* common_set) {
|
| + vector<CertEntry> entries;
|
| + entries.reserve(certs.size());
|
| +
|
| + const bool cached_valid = client_cached.size() % sizeof(uint64) == 0 &&
|
| + !client_cached.empty();
|
| +
|
| + for (vector<string>::const_iterator i = certs.begin();
|
| + i != certs.end(); ++i) {
|
| + CertEntry entry;
|
| +
|
| + if (cached_valid) {
|
| + bool cached = false;
|
| +
|
| + uint64 hash = QuicUtils::FNV1a_64_Hash(i->data(), i->size());
|
| + // This assumes that the machine is little-endian.
|
| + for (size_t i = 0; i < client_cached.size(); i += sizeof(uint64)) {
|
| + uint64 cached_hash;
|
| + memcpy(&cached_hash, client_cached.data() + i, sizeof(uint64));
|
| + if (hash != cached_hash) {
|
| + continue;
|
| + }
|
| +
|
| + entry.type = CertEntry::CACHED;
|
| + entry.hash = hash;
|
| + entries.push_back(entry);
|
| + cached = true;
|
| + break;
|
| + }
|
| +
|
| + if (cached) {
|
| + continue;
|
| + }
|
| + }
|
| +
|
| + if (common_set &&
|
| + common_set->MatchCert(*i, client_common_set_hashes, &entry.set_hash,
|
| + &entry.index)) {
|
| + entry.type = CertEntry::COMMON;
|
| + entries.push_back(entry);
|
| + continue;
|
| + }
|
| +
|
| + entry.type = CertEntry::COMPRESSED;
|
| + entries.push_back(entry);
|
| + }
|
| +
|
| + return entries;
|
| +}
|
| +
|
| +// CertEntriesSize returns the size, in bytes, of the serialised form of
|
| +// |entries|.
|
| +size_t CertEntriesSize(const vector<CertEntry>& entries) {
|
| + size_t entries_size = 0;
|
| +
|
| + for (vector<CertEntry>::const_iterator i = entries.begin();
|
| + i != entries.end(); ++i) {
|
| + switch (i->type) {
|
| + case CertEntry::COMPRESSED:
|
| + entries_size++;
|
| + break;
|
| + case CertEntry::CACHED:
|
| + entries_size += 1 + sizeof(uint64);
|
| + break;
|
| + case CertEntry::COMMON:
|
| + entries_size += 1 + sizeof(uint64) + sizeof(uint32);
|
| + break;
|
| + }
|
| + }
|
| +
|
| + entries_size++; // for end marker
|
| +
|
| + return entries_size;
|
| +}
|
| +
|
| +// SerializeCertEntries serialises |entries| to |out|, which must have enough
|
| +// space to contain them.
|
| +void SerializeCertEntries(uint8* out, const vector<CertEntry>& entries) {
|
| + for (vector<CertEntry>::const_iterator i = entries.begin();
|
| + i != entries.end(); ++i) {
|
| + *out++ = i->type;
|
| + switch (i->type) {
|
| + case CertEntry::COMPRESSED:
|
| + break;
|
| + case CertEntry::CACHED:
|
| + memcpy(out, &i->hash, sizeof(i->hash));
|
| + out += sizeof(uint64);
|
| + break;
|
| + case CertEntry::COMMON:
|
| + // Assumes a little-endian machine.
|
| + memcpy(out, &i->set_hash, sizeof(i->set_hash));
|
| + out += sizeof(i->set_hash);
|
| + memcpy(out, &i->index, sizeof(uint32));
|
| + out += sizeof(uint32);
|
| + break;
|
| + }
|
| + }
|
| +
|
| + *out++ = 0; // end marker
|
| +}
|
| +
|
| +// ZlibDictForEntries returns a string that contains the zlib pre-shared
|
| +// dictionary to use in order to decompress a zlib block following |entries|.
|
| +// |certs| is one-to-one with |entries| and contains the certificates for those
|
| +// entries that are CACHED or COMMON.
|
| +string ZlibDictForEntries(const vector<CertEntry>& entries,
|
| + const vector<string>& certs) {
|
| + string zlib_dict;
|
| +
|
| + // The dictionary starts with the common and cached certs in reverse order.
|
| + size_t zlib_dict_size = 0;
|
| + for (size_t i = certs.size() - 1; i < certs.size(); i--) {
|
| + if (entries[i].type != CertEntry::COMPRESSED) {
|
| + zlib_dict_size += certs[i].size();
|
| + }
|
| + }
|
| +
|
| + // At the end of the dictionary is a block of common certificate substrings.
|
| + zlib_dict_size += sizeof(kCommonCertSubstrings);
|
| +
|
| + zlib_dict.reserve(zlib_dict_size);
|
| +
|
| + for (size_t i = certs.size() - 1; i < certs.size(); i--) {
|
| + if (entries[i].type != CertEntry::COMPRESSED) {
|
| + zlib_dict += certs[i];
|
| + }
|
| + }
|
| +
|
| + zlib_dict += string(reinterpret_cast<const char*>(kCommonCertSubstrings),
|
| + sizeof(kCommonCertSubstrings));
|
| +
|
| + DCHECK_EQ(zlib_dict.size(), zlib_dict_size);
|
| +
|
| + return zlib_dict;
|
| +}
|
| +
|
| +// HashCerts returns the FNV-1a hashes of |certs|.
|
| +vector<uint64> HashCerts(const vector<string>& certs) {
|
| + vector<uint64> ret;
|
| +
|
| + for (vector<string>::const_iterator i = certs.begin();
|
| + i != certs.end(); ++i) {
|
| + ret.push_back(QuicUtils::FNV1a_64_Hash(i->data(), i->size()));
|
| + }
|
| +
|
| + return ret;
|
| +}
|
| +
|
| +// ParseEntries parses the serialised form of a vector of CertEntries from
|
| +// |in_out| and writes them to |out_entries|. CACHED and COMMON entries are
|
| +// resolved using |cached_certs| and |common_set| and written to |out_certs|.
|
| +// |in_out| is updated to contain the trailing data.
|
| +bool ParseEntries(StringPiece* in_out,
|
| + const vector<string>& cached_certs,
|
| + CommonCertSet* common_set,
|
| + vector<CertEntry>* out_entries,
|
| + vector<string>* out_certs) {
|
| + StringPiece in = *in_out;
|
| + vector<uint64> cached_hashes;
|
| +
|
| + out_entries->clear();
|
| + out_certs->clear();
|
| +
|
| + for (;;) {
|
| + if (in.empty()) {
|
| + return false;
|
| + }
|
| + CertEntry entry;
|
| + const uint8 type_byte = in[0];
|
| + in.remove_prefix(1);
|
| +
|
| + if (type_byte == 0) {
|
| + break;
|
| + }
|
| +
|
| + entry.type = static_cast<CertEntry::Type>(type_byte);
|
| +
|
| + switch (entry.type) {
|
| + case CertEntry::COMPRESSED:
|
| + out_certs->push_back(string());
|
| + break;
|
| + case CertEntry::CACHED: {
|
| + if (in.size() < sizeof(uint64)) {
|
| + return false;
|
| + }
|
| + memcpy(&entry.hash, in.data(), sizeof(uint64));
|
| + in.remove_prefix(sizeof(uint64));
|
| +
|
| + if (cached_hashes.size() != cached_certs.size()) {
|
| + cached_hashes = HashCerts(cached_certs);
|
| + }
|
| + bool found = false;
|
| + for (size_t i = 0; i < cached_hashes.size(); i++) {
|
| + if (cached_hashes[i] == entry.hash) {
|
| + out_certs->push_back(cached_certs[i]);
|
| + found = true;
|
| + break;
|
| + }
|
| + }
|
| + if (!found) {
|
| + return false;
|
| + }
|
| + break;
|
| + }
|
| + case CertEntry::COMMON: {
|
| + if (!common_set) {
|
| + return false;
|
| + }
|
| + if (in.size() < sizeof(uint64)) {
|
| + return false;
|
| + }
|
| + memcpy(&entry.set_hash, in.data(), sizeof(uint64));
|
| + in.remove_prefix(sizeof(uint64));
|
| +
|
| + if (in.size() < sizeof(uint32)) {
|
| + return false;
|
| + }
|
| + memcpy(&entry.index, in.data(), sizeof(uint32));
|
| + in.remove_prefix(sizeof(uint32));
|
| +
|
| + StringPiece cert = common_set->GetCert(entry.set_hash, entry.index);
|
| + if (cert.empty()) {
|
| + return false;
|
| + }
|
| + out_certs->push_back(cert.as_string());
|
| + break;
|
| + }
|
| + default:
|
| + return false;
|
| + }
|
| + out_entries->push_back(entry);
|
| + }
|
| +
|
| + *in_out = in;
|
| + return true;
|
| +}
|
| +
|
| +class ScopedZLib {
|
| + public:
|
| + enum Type {
|
| + INFLATE,
|
| + DEFLATE,
|
| + };
|
| +
|
| + explicit ScopedZLib(Type type)
|
| + : z_(NULL),
|
| + type_(type) {
|
| + }
|
| +
|
| + void reset(z_stream* z) {
|
| + z_ = z;
|
| + }
|
| +
|
| + ~ScopedZLib() {
|
| + if (z_) {
|
| + if (type_ == DEFLATE) {
|
| + deflateEnd(z_);
|
| + } else {
|
| + inflateEnd(z_);
|
| + }
|
| + z_ = NULL;
|
| + }
|
| + }
|
| +
|
| + private:
|
| + z_stream* z_;
|
| + const Type type_;
|
| +};
|
| +
|
| +} // anonymous namespace
|
| +
|
| +
|
| +// static
|
| +string CertCompressor::CompressChain(const vector<string>& certs,
|
| + StringPiece client_common_set_hashes,
|
| + StringPiece client_cached,
|
| + CommonCertSet* common_set) {
|
| + const vector<CertEntry> entries = MatchCerts(
|
| + certs, client_common_set_hashes, client_cached, common_set);
|
| + DCHECK_EQ(entries.size(), certs.size());
|
| +
|
| + size_t uncompressed_size = 0;
|
| + for (size_t i = 0; i < entries.size(); i++) {
|
| + if (entries[i].type == CertEntry::COMPRESSED) {
|
| + uncompressed_size += 4 /* uint32 length */ + certs[i].size();
|
| + }
|
| + }
|
| +
|
| + size_t compressed_size = 0;
|
| + z_stream z;
|
| + ScopedZLib scoped_z(ScopedZLib::DEFLATE);
|
| +
|
| + if (uncompressed_size > 0) {
|
| + memset(&z, 0, sizeof(z));
|
| + int rv = deflateInit(&z, Z_DEFAULT_COMPRESSION);
|
| + DCHECK_EQ(Z_OK, rv);
|
| + if (rv != Z_OK) {
|
| + return "";
|
| + }
|
| + scoped_z.reset(&z);
|
| +
|
| + string zlib_dict = ZlibDictForEntries(entries, certs);
|
| +
|
| + rv = deflateSetDictionary(&z, reinterpret_cast<const uint8*>(&zlib_dict[0]),
|
| + zlib_dict.size());
|
| + DCHECK_EQ(Z_OK, rv);
|
| + if (rv != Z_OK) {
|
| + return "";
|
| + }
|
| +
|
| + compressed_size = deflateBound(&z, uncompressed_size);
|
| + }
|
| +
|
| + const size_t entries_size = CertEntriesSize(entries);
|
| +
|
| + string result;
|
| + result.resize(entries_size + (uncompressed_size > 0 ? 4 : 0) +
|
| + compressed_size);
|
| +
|
| + uint8* j = reinterpret_cast<uint8*>(&result[0]);
|
| + SerializeCertEntries(j, entries);
|
| + j += entries_size;
|
| +
|
| + if (uncompressed_size == 0) {
|
| + return result;
|
| + }
|
| +
|
| + uint32 uncompressed_size_32 = uncompressed_size;
|
| + memcpy(j, &uncompressed_size_32, sizeof(uint32));
|
| + j += sizeof(uint32);
|
| +
|
| + int rv;
|
| +
|
| + z.next_out = j;
|
| + z.avail_out = compressed_size;
|
| +
|
| + for (size_t i = 0; i < certs.size(); i++) {
|
| + if (entries[i].type != CertEntry::COMPRESSED) {
|
| + continue;
|
| + }
|
| +
|
| + uint32 length = certs[i].size();
|
| + z.next_in = reinterpret_cast<uint8*>(&length);
|
| + z.avail_in = sizeof(length);
|
| + rv = deflate(&z, Z_NO_FLUSH);
|
| + DCHECK_EQ(Z_OK, rv);
|
| + DCHECK_EQ(0u, z.avail_in);
|
| + if (rv != Z_OK || z.avail_in) {
|
| + return "";
|
| + }
|
| +
|
| + z.next_in =
|
| + const_cast<uint8*>(reinterpret_cast<const uint8*>(certs[i].data()));
|
| + z.avail_in = certs[i].size();
|
| + rv = deflate(&z, Z_NO_FLUSH);
|
| + DCHECK_EQ(Z_OK, rv);
|
| + DCHECK_EQ(0u, z.avail_in);
|
| + if (rv != Z_OK || z.avail_in) {
|
| + return "";
|
| + }
|
| + }
|
| +
|
| + z.avail_in = 0;
|
| + rv = deflate(&z, Z_FINISH);
|
| + DCHECK_EQ(Z_STREAM_END, rv);
|
| + if (rv != Z_STREAM_END) {
|
| + return "";
|
| + }
|
| +
|
| + result.resize(result.size() - z.avail_out);
|
| + return result;
|
| +}
|
| +
|
| +// static
|
| +bool CertCompressor::DecompressChain(StringPiece in,
|
| + const vector<string>& cached_certs,
|
| + CommonCertSet* common_set,
|
| + vector<string>* out_certs) {
|
| + vector<CertEntry> entries;
|
| + if (!ParseEntries(&in, cached_certs, common_set, &entries, out_certs)) {
|
| + return false;
|
| + }
|
| + DCHECK_EQ(entries.size(), out_certs->size());
|
| +
|
| + scoped_ptr<uint8[]> uncompressed_data;
|
| + StringPiece uncompressed;
|
| +
|
| + if (!in.empty()) {
|
| + if (in.size() < sizeof(uint32)) {
|
| + return false;
|
| + }
|
| +
|
| + uint32 uncompressed_size;
|
| + memcpy(&uncompressed_size, in.data(), sizeof(uncompressed_size));
|
| + in.remove_prefix(sizeof(uint32));
|
| +
|
| + if (uncompressed_size > 128 * 1024) {
|
| + return false;
|
| + }
|
| +
|
| + uncompressed_data.reset(new uint8[uncompressed_size]);
|
| + z_stream z;
|
| + ScopedZLib scoped_z(ScopedZLib::INFLATE);
|
| +
|
| + memset(&z, 0, sizeof(z));
|
| + z.next_out = uncompressed_data.get();
|
| + z.avail_out = uncompressed_size;
|
| + z.next_in = const_cast<uint8*>(reinterpret_cast<const uint8*>(in.data()));
|
| + z.avail_in = in.size();
|
| +
|
| + if (Z_OK != inflateInit(&z)) {
|
| + return false;
|
| + }
|
| + scoped_z.reset(&z);
|
| +
|
| + int rv = inflate(&z, Z_FINISH);
|
| + if (rv == Z_NEED_DICT) {
|
| + string zlib_dict = ZlibDictForEntries(entries, *out_certs);
|
| + const uint8* dict = reinterpret_cast<const uint8*>(zlib_dict.data());
|
| + if (Z_OK != inflateSetDictionary(&z, dict, zlib_dict.size())) {
|
| + return false;
|
| + }
|
| + rv = inflate(&z, Z_FINISH);
|
| + }
|
| +
|
| + if (Z_STREAM_END != rv ||
|
| + z.avail_out > 0 ||
|
| + z.avail_in > 0) {
|
| + return false;
|
| + }
|
| +
|
| + uncompressed = StringPiece(reinterpret_cast<char*>(uncompressed_data.get()),
|
| + uncompressed_size);
|
| + }
|
| +
|
| + for (size_t i = 0; i < entries.size(); i++) {
|
| + switch (entries[i].type) {
|
| + case CertEntry::COMPRESSED:
|
| + if (uncompressed.size() < sizeof(uint32)) {
|
| + return false;
|
| + }
|
| + uint32 cert_len;
|
| + memcpy(&cert_len, uncompressed.data(), sizeof(cert_len));
|
| + uncompressed.remove_prefix(sizeof(uint32));
|
| + if (uncompressed.size() < cert_len) {
|
| + return false;
|
| + }
|
| + (*out_certs)[i] = uncompressed.substr(0, cert_len).as_string();
|
| + uncompressed.remove_prefix(cert_len);
|
| + break;
|
| + case CertEntry::CACHED:
|
| + case CertEntry::COMMON:
|
| + break;
|
| + }
|
| + }
|
| +
|
| + if (!uncompressed.empty()) {
|
| + return false;
|
| + }
|
| +
|
| + return true;
|
| +}
|
| +
|
| +} // namespace net
|
|
|