diff options
author | Allan Sandfeld Jensen <allan.jensen@theqtcompany.com> | 2015-06-18 14:10:49 +0200 |
---|---|---|
committer | Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com> | 2015-06-18 13:53:24 +0000 |
commit | 813fbf95af77a531c57a8c497345ad2c61d475b3 (patch) | |
tree | 821b2c8de8365f21b6c9ba17a236fb3006a1d506 /chromium/net/ssl | |
parent | af6588f8d723931a298c995fa97259bb7f7deb55 (diff) | |
download | qtwebengine-chromium-813fbf95af77a531c57a8c497345ad2c61d475b3.tar.gz |
BASELINE: Update chromium to 44.0.2403.47
Change-Id: Ie056fedba95cf5e5c76b30c4b2c80fca4764aa2f
Reviewed-by: Oswald Buddenhagen <oswald.buddenhagen@theqtcompany.com>
Diffstat (limited to 'chromium/net/ssl')
28 files changed, 1502 insertions, 292 deletions
diff --git a/chromium/net/ssl/channel_id_service.cc b/chromium/net/ssl/channel_id_service.cc index 9bc21794a9c..7fcbc539b32 100644 --- a/chromium/net/ssl/channel_id_service.cc +++ b/chromium/net/ssl/channel_id_service.cc @@ -27,7 +27,7 @@ #include "net/cert/x509_util.h" #include "url/gurl.h" -#if defined(USE_NSS) +#if !defined(USE_OPENSSL) #include <private/pprthred.h> // PR_DetachThread #endif @@ -246,7 +246,7 @@ class ChannelIDServiceWorker { scoped_ptr<ChannelIDStore::ChannelID> cert = GenerateChannelID(server_identifier_, serial_number_, &error); DVLOG(1) << "GenerateCert " << server_identifier_ << " returned " << error; -#if defined(USE_NSS) +#if !defined(USE_OPENSSL) // Detach the thread from NSPR. // Calling NSS functions attaches the thread to NSPR, which stores // the NSPR thread ID in thread-specific data. diff --git a/chromium/net/ssl/client_cert_store.h b/chromium/net/ssl/client_cert_store.h index fe050e5f099..b1172deb7d9 100644 --- a/chromium/net/ssl/client_cert_store.h +++ b/chromium/net/ssl/client_cert_store.h @@ -14,8 +14,10 @@ namespace net { class SSLCertRequestInfo; -// The caller is expected to keep the ClientCertStore alive until the callback -// supplied to GetClientCerts has been run. +// A handle to a client certificate store to query matching certificates when a +// server requests client auth. Note that there may be multiple ClientCertStore +// objects corresponding to the same platform certificate store; each request +// gets its own uniquely owned handle. class NET_EXPORT ClientCertStore { public: virtual ~ClientCertStore() {} @@ -23,8 +25,8 @@ class NET_EXPORT ClientCertStore { // Get client certs matching the |cert_request_info|. On completion, the // results will be stored in |selected_certs| and the |callback| will be run. // The |callback| may be called sychronously. The caller must ensure the - // ClientCertStore and the |selected_certs| object remain alive until the - // callback has been run. + // ClientCertStore, |cert_request_info|, and |selected_certs| remain alive + // until the callback has been run. virtual void GetClientCerts(const SSLCertRequestInfo& cert_request_info, CertificateList* selected_certs, const base::Closure& callback) = 0; diff --git a/chromium/net/ssl/client_cert_store_chromeos.h b/chromium/net/ssl/client_cert_store_chromeos.h index 5e9922daab4..2bc359cd9a5 100644 --- a/chromium/net/ssl/client_cert_store_chromeos.h +++ b/chromium/net/ssl/client_cert_store_chromeos.h @@ -38,19 +38,19 @@ class NET_EXPORT ClientCertStoreChromeOS : public ClientCertStoreNSS { ClientCertStoreChromeOS( scoped_ptr<CertFilter> cert_filter, const PasswordDelegateFactory& password_delegate_factory); - virtual ~ClientCertStoreChromeOS(); + ~ClientCertStoreChromeOS() override; // ClientCertStoreNSS: - virtual void GetClientCerts(const SSLCertRequestInfo& cert_request_info, - CertificateList* selected_certs, - const base::Closure& callback) override; + void GetClientCerts(const SSLCertRequestInfo& cert_request_info, + CertificateList* selected_certs, + const base::Closure& callback) override; protected: // ClientCertStoreNSS: - virtual void GetClientCertsImpl(CERTCertList* cert_list, - const SSLCertRequestInfo& request, - bool query_nssdb, - CertificateList* selected_certs) override; + void GetClientCertsImpl(CERTCertList* cert_list, + const SSLCertRequestInfo& request, + bool query_nssdb, + CertificateList* selected_certs) override; private: void CertFilterInitialized(const SSLCertRequestInfo* request, diff --git a/chromium/net/ssl/client_cert_store_chromeos_unittest.cc b/chromium/net/ssl/client_cert_store_chromeos_unittest.cc index ca2c0494088..94acac6273a 100644 --- a/chromium/net/ssl/client_cert_store_chromeos_unittest.cc +++ b/chromium/net/ssl/client_cert_store_chromeos_unittest.cc @@ -20,7 +20,7 @@ namespace net { namespace { -class TestCertFilter : public net::ClientCertStoreChromeOS::CertFilter { +class TestCertFilter : public ClientCertStoreChromeOS::CertFilter { public: explicit TestCertFilter(bool init_finished) : init_finished_(init_finished), init_called_(false) {} @@ -36,7 +36,7 @@ class TestCertFilter : public net::ClientCertStoreChromeOS::CertFilter { } bool IsCertAllowed( - const scoped_refptr<net::X509Certificate>& cert) const override { + const scoped_refptr<X509Certificate>& cert) const override { if (not_allowed_cert_.get() && cert->Equals(not_allowed_cert_.get())) return false; return true; diff --git a/chromium/net/ssl/client_cert_store_win.h b/chromium/net/ssl/client_cert_store_win.h index 567c267abef..3c6f187f991 100644 --- a/chromium/net/ssl/client_cert_store_win.h +++ b/chromium/net/ssl/client_cert_store_win.h @@ -17,12 +17,12 @@ namespace net { class NET_EXPORT ClientCertStoreWin : public ClientCertStore { public: ClientCertStoreWin(); - virtual ~ClientCertStoreWin(); + ~ClientCertStoreWin() override; // ClientCertStore: - virtual void GetClientCerts(const SSLCertRequestInfo& cert_request_info, - CertificateList* selected_certs, - const base::Closure& callback) override; + void GetClientCerts(const SSLCertRequestInfo& cert_request_info, + CertificateList* selected_certs, + const base::Closure& callback) override; private: friend class ClientCertStoreWinTestDelegate; diff --git a/chromium/net/ssl/openssl_client_key_store.cc b/chromium/net/ssl/openssl_client_key_store.cc index de65cd9d677..0bc97beb48e 100644 --- a/chromium/net/ssl/openssl_client_key_store.cc +++ b/chromium/net/ssl/openssl_client_key_store.cc @@ -37,18 +37,17 @@ OpenSSLClientKeyStore::OpenSSLClientKeyStore() { OpenSSLClientKeyStore::~OpenSSLClientKeyStore() { } -OpenSSLClientKeyStore::KeyPair::KeyPair(EVP_PKEY* pub_key, - EVP_PKEY* priv_key) - : public_key(EVP_PKEY_dup(pub_key)), - private_key(EVP_PKEY_dup(priv_key)) { +OpenSSLClientKeyStore::KeyPair::KeyPair(EVP_PKEY* pub_key, EVP_PKEY* priv_key) + : public_key(EVP_PKEY_up_ref(pub_key)), + private_key(EVP_PKEY_up_ref(priv_key)) { } OpenSSLClientKeyStore::KeyPair::~KeyPair() { } OpenSSLClientKeyStore::KeyPair::KeyPair(const KeyPair& other) - : public_key(EVP_PKEY_dup(other.public_key.get())), - private_key(EVP_PKEY_dup(other.private_key.get())) { + : public_key(EVP_PKEY_up_ref(other.public_key.get())), + private_key(EVP_PKEY_up_ref(other.private_key.get())) { } void OpenSSLClientKeyStore::KeyPair::operator=(KeyPair other) { @@ -109,7 +108,8 @@ crypto::ScopedEVP_PKEY OpenSSLClientKeyStore::FetchClientCertPrivateKey( if (index < 0) return crypto::ScopedEVP_PKEY(); - return crypto::ScopedEVP_PKEY(EVP_PKEY_dup(pairs_[index].private_key.get())); + return crypto::ScopedEVP_PKEY( + EVP_PKEY_up_ref(pairs_[index].private_key.get())); } void OpenSSLClientKeyStore::Flush() { diff --git a/chromium/net/ssl/openssl_client_key_store_unittest.cc b/chromium/net/ssl/openssl_client_key_store_unittest.cc index 7909afd5a82..f1d8a304b4c 100644 --- a/chromium/net/ssl/openssl_client_key_store_unittest.cc +++ b/chromium/net/ssl/openssl_client_key_store_unittest.cc @@ -27,7 +27,7 @@ class OpenSSLClientKeyStoreTest : public ::testing::Test { : store_(OpenSSLClientKeyStore::GetInstance()) { } - virtual ~OpenSSLClientKeyStoreTest() { + ~OpenSSLClientKeyStoreTest() override { if (store_) store_->Flush(); } diff --git a/chromium/net/ssl/openssl_platform_key_mac.cc b/chromium/net/ssl/openssl_platform_key_mac.cc index d36924455df..34857afda35 100644 --- a/chromium/net/ssl/openssl_platform_key_mac.cc +++ b/chromium/net/ssl/openssl_platform_key_mac.cc @@ -4,7 +4,9 @@ #include "net/ssl/openssl_platform_key.h" +#include <openssl/ec_key.h> #include <openssl/err.h> +#include <openssl/engine.h> #include <openssl/evp.h> #include <openssl/rsa.h> diff --git a/chromium/net/ssl/openssl_platform_key_nss.cc b/chromium/net/ssl/openssl_platform_key_nss.cc new file mode 100644 index 00000000000..a9471e44523 --- /dev/null +++ b/chromium/net/ssl/openssl_platform_key_nss.cc @@ -0,0 +1,17 @@ +// Copyright 2015 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 "base/logging.h" +#include "net/ssl/openssl_platform_key.h" + +namespace net { + +crypto::ScopedEVP_PKEY FetchClientCertPrivateKey( + const X509Certificate* certificate) { + // TODO(davidben): Implement client auth for NSS. https://crbug.com/479036 + NOTIMPLEMENTED(); + return nullptr; +} + +} // namespace net diff --git a/chromium/net/ssl/openssl_platform_key_win.cc b/chromium/net/ssl/openssl_platform_key_win.cc index c7db5cbd7dc..c250581cfa9 100644 --- a/chromium/net/ssl/openssl_platform_key_win.cc +++ b/chromium/net/ssl/openssl_platform_key_win.cc @@ -4,15 +4,640 @@ #include "net/ssl/openssl_platform_key.h" +#include <windows.h> +#include <NCrypt.h> + +#include <string.h> + +#include <algorithm> +#include <vector> + +#include <openssl/bn.h> +#include <openssl/digest.h> +#include <openssl/ec_key.h> +#include <openssl/err.h> +#include <openssl/engine.h> +#include <openssl/evp.h> +#include <openssl/md5.h> +#include <openssl/obj_mac.h> +#include <openssl/rsa.h> +#include <openssl/sha.h> +#include <openssl/x509.h> + +#include "base/debug/debugger.h" +#include "base/debug/stack_trace.h" +#include "base/lazy_instance.h" #include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/win/windows_version.h" +#include "crypto/openssl_util.h" +#include "crypto/scoped_capi_types.h" +#include "crypto/wincrypt_shim.h" +#include "net/base/net_errors.h" +#include "net/cert/x509_certificate.h" +#include "net/ssl/openssl_ssl_util.h" +#include "net/ssl/scoped_openssl_types.h" namespace net { +namespace { + +using NCryptFreeObjectFunc = SECURITY_STATUS(WINAPI*)(NCRYPT_HANDLE); +using NCryptSignHashFunc = + SECURITY_STATUS(WINAPI*)(NCRYPT_KEY_HANDLE, // hKey + VOID*, // pPaddingInfo + PBYTE, // pbHashValue + DWORD, // cbHashValue + PBYTE, // pbSignature + DWORD, // cbSignature + DWORD*, // pcbResult + DWORD); // dwFlags + +class CNGFunctions { + public: + CNGFunctions() + : ncrypt_free_object_(nullptr), + ncrypt_sign_hash_(nullptr) { + HMODULE ncrypt = GetModuleHandle(L"ncrypt.dll"); + if (ncrypt != nullptr) { + ncrypt_free_object_ = reinterpret_cast<NCryptFreeObjectFunc>( + GetProcAddress(ncrypt, "NCryptFreeObject")); + ncrypt_sign_hash_ = reinterpret_cast<NCryptSignHashFunc>( + GetProcAddress(ncrypt, "NCryptSignHash")); + } + } + + NCryptFreeObjectFunc ncrypt_free_object() const { + return ncrypt_free_object_; + } + + NCryptSignHashFunc ncrypt_sign_hash() const { return ncrypt_sign_hash_; } + + private: + NCryptFreeObjectFunc ncrypt_free_object_; + NCryptSignHashFunc ncrypt_sign_hash_; +}; + +base::LazyInstance<CNGFunctions>::Leaky g_cng_functions = + LAZY_INSTANCE_INITIALIZER; + +struct CERT_KEY_CONTEXTDeleter { + void operator()(PCERT_KEY_CONTEXT key) { + if (key->dwKeySpec == CERT_NCRYPT_KEY_SPEC) { + g_cng_functions.Get().ncrypt_free_object()(key->hNCryptKey); + } else { + CryptReleaseContext(key->hCryptProv, 0); + } + delete key; + } +}; + +using ScopedCERT_KEY_CONTEXT = + scoped_ptr<CERT_KEY_CONTEXT, CERT_KEY_CONTEXTDeleter>; + +// KeyExData contains the data that is contained in the EX_DATA of the +// RSA and ECDSA objects that are created to wrap Windows system keys. +struct KeyExData { + KeyExData(ScopedCERT_KEY_CONTEXT key, size_t key_length) + : key(key.Pass()), key_length(key_length) {} + + ScopedCERT_KEY_CONTEXT key; + size_t key_length; +}; + +// ExDataDup is called when one of the RSA or EC_KEY objects is +// duplicated. This is not supported and should never happen. +int ExDataDup(CRYPTO_EX_DATA* to, + const CRYPTO_EX_DATA* from, + void** from_d, + int idx, + long argl, + void* argp) { + CHECK_EQ((void*)nullptr, *from_d); + return 0; +} + +// ExDataFree is called when one of the RSA or EC_KEY objects is freed. +void ExDataFree(void* parent, + void* ptr, + CRYPTO_EX_DATA* ex_data, + int idx, + long argl, + void* argp) { + KeyExData* data = reinterpret_cast<KeyExData*>(ptr); + delete data; +} + +extern const RSA_METHOD win_rsa_method; +extern const ECDSA_METHOD win_ecdsa_method; + +// BoringSSLEngine is a BoringSSL ENGINE that implements RSA and ECDSA +// by forwarding the requested operations to CAPI or CNG. +class BoringSSLEngine { + public: + BoringSSLEngine() + : rsa_index_(RSA_get_ex_new_index(0 /* argl */, + nullptr /* argp */, + nullptr /* new_func */, + ExDataDup, + ExDataFree)), + ec_key_index_(EC_KEY_get_ex_new_index(0 /* argl */, + nullptr /* argp */, + nullptr /* new_func */, + ExDataDup, + ExDataFree)), + engine_(ENGINE_new()) { + ENGINE_set_RSA_method(engine_, &win_rsa_method, sizeof(win_rsa_method)); + ENGINE_set_ECDSA_method(engine_, &win_ecdsa_method, + sizeof(win_ecdsa_method)); + } + + int rsa_ex_index() const { return rsa_index_; } + int ec_key_ex_index() const { return ec_key_index_; } + + const ENGINE* engine() const { return engine_; } + + private: + const int rsa_index_; + const int ec_key_index_; + ENGINE* const engine_; +}; + +base::LazyInstance<BoringSSLEngine>::Leaky global_boringssl_engine = + LAZY_INSTANCE_INITIALIZER; + +// Signs |in| with |key|, writing the output to |out| and the size to |out_len|. +// Although the buffer is preallocated, this calls NCryptSignHash twice. Some +// smartcards are buggy and assume the two-call pattern. See +// https://crbug.com/470204. Returns true on success and false on error. +bool DoNCryptSignHash(NCRYPT_KEY_HANDLE key, + void* padding, + const BYTE* in, + DWORD in_len, + BYTE* out, + DWORD max_out, + DWORD* out_len, + DWORD flags) { + // Determine the output length. + DWORD signature_len; + SECURITY_STATUS ncrypt_status = g_cng_functions.Get().ncrypt_sign_hash()( + key, padding, const_cast<BYTE*>(in), in_len, nullptr, 0, &signature_len, + flags); + if (FAILED(ncrypt_status)) { + LOG(ERROR) << "NCryptSignHash failed: " << ncrypt_status; + return false; + } + // Check |max_out| externally rather than trust the smartcard. + if (signature_len == 0 || signature_len > max_out) { + LOG(ERROR) << "Bad signature length."; + return false; + } + // It is important that |signature_len| already be initialized with the + // correct size. Some smartcards are buggy and do not write to it on the + // second call. + ncrypt_status = g_cng_functions.Get().ncrypt_sign_hash()( + key, padding, const_cast<PBYTE>(in), in_len, out, signature_len, + &signature_len, flags); + if (FAILED(ncrypt_status)) { + LOG(ERROR) << "NCryptSignHash failed: " << ncrypt_status; + return false; + } + if (signature_len == 0) { + LOG(ERROR) << "Bad signature length."; + return false; + } + *out_len = signature_len; + return true; +} + +// Custom RSA_METHOD that uses the platform APIs for signing. + +const KeyExData* RsaGetExData(const RSA* rsa) { + return reinterpret_cast<const KeyExData*>( + RSA_get_ex_data(rsa, global_boringssl_engine.Get().rsa_ex_index())); +} + +size_t RsaMethodSize(const RSA* rsa) { + const KeyExData* ex_data = RsaGetExData(rsa); + return (ex_data->key_length + 7) / 8; +} + +int RsaMethodSign(int hash_nid, + const uint8_t* in, + unsigned in_len, + uint8_t* out, + unsigned* out_len, + const RSA* rsa) { + // TODO(davidben): Switch BoringSSL's sign hook to using size_t rather than + // unsigned. + const KeyExData* ex_data = RsaGetExData(rsa); + if (!ex_data) { + NOTREACHED(); + OPENSSL_PUT_ERROR(RSA, RSA_sign, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (ex_data->key->dwKeySpec == CERT_NCRYPT_KEY_SPEC) { + BCRYPT_PKCS1_PADDING_INFO rsa_padding_info; + switch (hash_nid) { + case NID_md5_sha1: + rsa_padding_info.pszAlgId = nullptr; + break; + case NID_sha1: + rsa_padding_info.pszAlgId = BCRYPT_SHA1_ALGORITHM; + break; + case NID_sha256: + rsa_padding_info.pszAlgId = BCRYPT_SHA256_ALGORITHM; + break; + case NID_sha384: + rsa_padding_info.pszAlgId = BCRYPT_SHA384_ALGORITHM; + break; + case NID_sha512: + rsa_padding_info.pszAlgId = BCRYPT_SHA512_ALGORITHM; + break; + default: + OPENSSL_PUT_ERROR(RSA, RSA_sign, RSA_R_UNKNOWN_ALGORITHM_TYPE); + return 0; + } + + DWORD signature_len; + if (!DoNCryptSignHash(ex_data->key->hNCryptKey, &rsa_padding_info, in, + in_len, out, RSA_size(rsa), &signature_len, + BCRYPT_PAD_PKCS1)) { + OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); + return 0; + } + *out_len = signature_len; + return 1; + } + + ALG_ID hash_alg; + switch (hash_nid) { + case NID_md5_sha1: + hash_alg = CALG_SSL3_SHAMD5; + break; + case NID_sha1: + hash_alg = CALG_SHA1; + break; + case NID_sha256: + hash_alg = CALG_SHA_256; + break; + case NID_sha384: + hash_alg = CALG_SHA_384; + break; + case NID_sha512: + hash_alg = CALG_SHA_512; + break; + default: + OPENSSL_PUT_ERROR(RSA, RSA_sign, RSA_R_UNKNOWN_ALGORITHM_TYPE); + return 0; + } + + HCRYPTHASH hash; + if (!CryptCreateHash(ex_data->key->hCryptProv, hash_alg, 0, 0, &hash)) { + PLOG(ERROR) << "CreateCreateHash failed"; + OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); + return 0; + } + DWORD hash_len; + DWORD arg_len = sizeof(hash_len); + if (!CryptGetHashParam(hash, HP_HASHSIZE, reinterpret_cast<BYTE*>(&hash_len), + &arg_len, 0)) { + PLOG(ERROR) << "CryptGetHashParam HP_HASHSIZE failed"; + OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); + return 0; + } + if (hash_len != in_len) { + OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); + return 0; + } + if (!CryptSetHashParam(hash, HP_HASHVAL, const_cast<BYTE*>(in), 0)) { + PLOG(ERROR) << "CryptSetHashParam HP_HASHVAL failed"; + OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); + return 0; + } + DWORD signature_len = RSA_size(rsa); + if (!CryptSignHash(hash, ex_data->key->dwKeySpec, nullptr, 0, out, + &signature_len)) { + PLOG(ERROR) << "CryptSignHash failed"; + OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); + return 0; + } + + /* CryptoAPI signs in little-endian, so reverse it. */ + std::reverse(out, out + signature_len); + *out_len = signature_len; + return 1; +} + +int RsaMethodEncrypt(RSA* rsa, + size_t* out_len, + uint8_t* out, + size_t max_out, + const uint8_t* in, + size_t in_len, + int padding) { + NOTIMPLEMENTED(); + OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_UNKNOWN_ALGORITHM_TYPE); + return 0; +} + +int RsaMethodSignRaw(RSA* rsa, + size_t* out_len, + uint8_t* out, + size_t max_out, + const uint8_t* in, + size_t in_len, + int padding) { + NOTIMPLEMENTED(); + OPENSSL_PUT_ERROR(RSA, encrypt, RSA_R_UNKNOWN_ALGORITHM_TYPE); + return 0; +} + +int RsaMethodDecrypt(RSA* rsa, + size_t* out_len, + uint8_t* out, + size_t max_out, + const uint8_t* in, + size_t in_len, + int padding) { + NOTIMPLEMENTED(); + OPENSSL_PUT_ERROR(RSA, decrypt, RSA_R_UNKNOWN_ALGORITHM_TYPE); + return 0; +} + +int RsaMethodVerifyRaw(RSA* rsa, + size_t* out_len, + uint8_t* out, + size_t max_out, + const uint8_t* in, + size_t in_len, + int padding) { + NOTIMPLEMENTED(); + OPENSSL_PUT_ERROR(RSA, verify_raw, RSA_R_UNKNOWN_ALGORITHM_TYPE); + return 0; +} + +int RsaMethodSupportsDigest(const RSA* rsa, const EVP_MD* md) { + const KeyExData* ex_data = RsaGetExData(rsa); + if (!ex_data) { + NOTREACHED(); + return 0; + } + + int hash_nid = EVP_MD_type(md); + if (ex_data->key->dwKeySpec == CERT_NCRYPT_KEY_SPEC) { + // Only hashes which appear in RsaSignPKCS1 are supported. + if (hash_nid != NID_sha1 && hash_nid != NID_sha256 && + hash_nid != NID_sha384 && hash_nid != NID_sha512) { + return 0; + } + + // If the key is a 1024-bit RSA, assume conservatively that it may only be + // able to sign SHA-1 hashes. This is the case for older Estonian ID cards + // that have 1024-bit RSA keys. + // + // CNG does provide NCryptIsAlgSupported and NCryptEnumAlgorithms functions, + // however they seem to both return NTE_NOT_SUPPORTED when querying the + // NCRYPT_PROV_HANDLE at the key's NCRYPT_PROVIDER_HANDLE_PROPERTY. + if (ex_data->key_length <= 1024 && hash_nid != NID_sha1) + return 0; + + return 1; + } else { + // If the key is in CAPI, assume conservatively that the CAPI service + // provider may only be able to sign SHA-1 hashes. + return hash_nid == NID_sha1; + } +} + +const RSA_METHOD win_rsa_method = { + { + 0, // references + 1, // is_static + }, + nullptr, // app_data + + nullptr, // init + nullptr, // finish + RsaMethodSize, + RsaMethodSign, + nullptr, // verify + RsaMethodEncrypt, + RsaMethodSignRaw, + RsaMethodDecrypt, + RsaMethodVerifyRaw, + nullptr, // private_transform + nullptr, // mod_exp + nullptr, // bn_mod_exp + RSA_FLAG_OPAQUE, + nullptr, // keygen + RsaMethodSupportsDigest, +}; + +// Custom ECDSA_METHOD that uses the platform APIs. +// Note that for now, only signing through ECDSA_sign() is really supported. +// all other method pointers are either stubs returning errors, or no-ops. + +const KeyExData* EcKeyGetExData(const EC_KEY* ec_key) { + return reinterpret_cast<const KeyExData*>(EC_KEY_get_ex_data( + ec_key, global_boringssl_engine.Get().ec_key_ex_index())); +} + +size_t EcdsaMethodGroupOrderSize(const EC_KEY* ec_key) { + const KeyExData* ex_data = EcKeyGetExData(ec_key); + // key_length is the size of the group order for EC keys. + return (ex_data->key_length + 7) / 8; +} + +int EcdsaMethodSign(const uint8_t* digest, + size_t digest_len, + uint8_t* out_sig, + unsigned int* out_sig_len, + EC_KEY* ec_key) { + const KeyExData* ex_data = EcKeyGetExData(ec_key); + // Only CNG supports ECDSA. + if (!ex_data || ex_data->key->dwKeySpec != CERT_NCRYPT_KEY_SPEC) { + NOTREACHED(); + OPENSSL_PUT_ERROR(RSA, sign_raw, ERR_R_INTERNAL_ERROR); + return 0; + } + + // An ECDSA signature is two integers, modulo the order of the group. + size_t order_len = (ex_data->key_length + 7) / 8; + if (order_len == 0) { + NOTREACHED(); + OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); + return 0; + } + std::vector<uint8_t> raw_sig(order_len * 2); + + DWORD signature_len; + if (!DoNCryptSignHash(ex_data->key->hNCryptKey, nullptr, digest, digest_len, + &raw_sig[0], raw_sig.size(), &signature_len, 0)) { + OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); + return 0; + } + if (signature_len != raw_sig.size()) { + LOG(ERROR) << "Bad signature length"; + OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); + return 0; + } + + // Convert the RAW ECDSA signature to a DER-encoded ECDSA-Sig-Value. + crypto::ScopedECDSA_SIG sig(ECDSA_SIG_new()); + if (!sig) { + OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); + return 0; + } + sig->r = BN_bin2bn(&raw_sig[0], order_len, nullptr); + sig->s = BN_bin2bn(&raw_sig[order_len], order_len, nullptr); + if (!sig->r || !sig->s) { + OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); + return 0; + } + + // Ensure the DER-encoded signature fits in the bounds. + int len = i2d_ECDSA_SIG(sig.get(), nullptr); + if (len < 0 || static_cast<size_t>(len) > ECDSA_size(ec_key)) { + OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); + return 0; + } + + len = i2d_ECDSA_SIG(sig.get(), &out_sig); + if (len < 0) { + OpenSSLPutNetError(FROM_HERE, ERR_SSL_CLIENT_AUTH_SIGNATURE_FAILED); + return 0; + } + *out_sig_len = len; + return 1; +} + +int EcdsaMethodVerify(const uint8_t* digest, + size_t digest_len, + const uint8_t* sig, + size_t sig_len, + EC_KEY* eckey) { + NOTIMPLEMENTED(); + OPENSSL_PUT_ERROR(ECDSA, ECDSA_do_verify, ECDSA_R_NOT_IMPLEMENTED); + return 0; +} + +const ECDSA_METHOD win_ecdsa_method = { + { + 0, // references + 1, // is_static + }, + nullptr, // app_data + + nullptr, // init + nullptr, // finish + EcdsaMethodGroupOrderSize, + EcdsaMethodSign, + EcdsaMethodVerify, + ECDSA_FLAG_OPAQUE, +}; + +// Determines the key type and length of |certificate|'s public key. The type is +// returned as an OpenSSL EVP_PKEY type. The key length for RSA key is the size +// of the RSA modulus in bits. For an ECDSA key, it is the number of bits to +// represent the group order. It returns true on success and false on failure. +bool GetKeyInfo(const X509Certificate* certificate, + int* out_type, + size_t* out_length) { + crypto::OpenSSLErrStackTracer tracker(FROM_HERE); + + std::string der_encoded; + if (!X509Certificate::GetDEREncoded(certificate->os_cert_handle(), + &der_encoded)) + return false; + const uint8_t* bytes = reinterpret_cast<const uint8_t*>(der_encoded.data()); + ScopedX509 x509(d2i_X509(NULL, &bytes, der_encoded.size())); + if (!x509) + return false; + crypto::ScopedEVP_PKEY key(X509_get_pubkey(x509.get())); + if (!key) + return false; + *out_type = EVP_PKEY_id(key.get()); + *out_length = EVP_PKEY_bits(key.get()); + return true; +} + +crypto::ScopedEVP_PKEY CreateRSAWrapper(ScopedCERT_KEY_CONTEXT key, + size_t key_length) { + crypto::ScopedRSA rsa(RSA_new_method(global_boringssl_engine.Get().engine())); + if (!rsa) + return nullptr; + + RSA_set_ex_data(rsa.get(), global_boringssl_engine.Get().rsa_ex_index(), + new KeyExData(key.Pass(), key_length)); + + crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); + if (!pkey || !EVP_PKEY_set1_RSA(pkey.get(), rsa.get())) + return nullptr; + return pkey.Pass(); +} + +crypto::ScopedEVP_PKEY CreateECDSAWrapper(ScopedCERT_KEY_CONTEXT key, + size_t key_length) { + crypto::ScopedEC_KEY ec_key( + EC_KEY_new_method(global_boringssl_engine.Get().engine())); + if (!ec_key) + return nullptr; + + EC_KEY_set_ex_data(ec_key.get(), + global_boringssl_engine.Get().ec_key_ex_index(), + new KeyExData(key.Pass(), key_length)); + + crypto::ScopedEVP_PKEY pkey(EVP_PKEY_new()); + if (!pkey || !EVP_PKEY_set1_EC_KEY(pkey.get(), ec_key.get())) + return nullptr; + + return pkey.Pass(); +} + +} // namespace + crypto::ScopedEVP_PKEY FetchClientCertPrivateKey( const X509Certificate* certificate) { - // TODO(davidben): Implement on Windows. - NOTIMPLEMENTED(); - return crypto::ScopedEVP_PKEY(); + PCCERT_CONTEXT cert_context = certificate->os_cert_handle(); + + HCRYPTPROV_OR_NCRYPT_KEY_HANDLE crypt_prov = 0; + DWORD key_spec = 0; + BOOL must_free = FALSE; + DWORD flags = 0; + if (base::win::GetVersion() >= base::win::VERSION_VISTA) + flags |= CRYPT_ACQUIRE_PREFER_NCRYPT_KEY_FLAG; + + if (!CryptAcquireCertificatePrivateKey(cert_context, flags, nullptr, + &crypt_prov, &key_spec, &must_free)) { + PLOG(WARNING) << "Could not acquire private key"; + return nullptr; + } + + // Should never get a cached handle back - ownership must always be + // transferred. + CHECK_EQ(must_free, TRUE); + ScopedCERT_KEY_CONTEXT key(new CERT_KEY_CONTEXT); + key->dwKeySpec = key_spec; + key->hCryptProv = crypt_prov; + + // Rather than query the private key for metadata, extract the public key from + // the certificate without using Windows APIs. CAPI and CNG do not + // consistently work depending on the system. See https://crbug.com/468345. + int key_type; + size_t key_length; + if (!GetKeyInfo(certificate, &key_type, &key_length)) + return nullptr; + + switch (key_type) { + case EVP_PKEY_RSA: + return CreateRSAWrapper(key.Pass(), key_length); + case EVP_PKEY_EC: + return CreateECDSAWrapper(key.Pass(), key_length); + default: + return nullptr; + } } } // namespace net diff --git a/chromium/net/ssl/openssl_ssl_util.cc b/chromium/net/ssl/openssl_ssl_util.cc index 9fb83a43f5d..54a34009323 100644 --- a/chromium/net/ssl/openssl_ssl_util.cc +++ b/chromium/net/ssl/openssl_ssl_util.cc @@ -67,7 +67,6 @@ int MapOpenSSLErrorSSL(uint32_t error_code) { case SSL_R_UNKNOWN_CERTIFICATE_TYPE: case SSL_R_UNKNOWN_CIPHER_TYPE: case SSL_R_UNKNOWN_KEY_EXCHANGE_TYPE: - case SSL_R_UNKNOWN_PKEY_TYPE: case SSL_R_UNKNOWN_SSL_VERSION: return ERR_NOT_IMPLEMENTED; case SSL_R_UNSUPPORTED_SSL_VERSION: @@ -114,17 +113,11 @@ int MapOpenSSLErrorSSL(uint32_t error_code) { case SSL_R_EXTRA_DATA_IN_MESSAGE: case SSL_R_GOT_A_FIN_BEFORE_A_CCS: case SSL_R_INVALID_COMMAND: - case SSL_R_INVALID_STATUS_RESPONSE: case SSL_R_INVALID_TICKET_KEYS_LENGTH: // SSL_do_handshake reports this error when the server responds to a // ClientHello with a fatal close_notify alert. - case SSL_AD_REASON_OFFSET + SSL_AD_CLOSE_NOTIFY: + case SSL_R_SSLV3_ALERT_CLOSE_NOTIFY: case SSL_R_SSLV3_ALERT_UNEXPECTED_MESSAGE: - // TODO(joth): SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE may be returned from the - // server after receiving ClientHello if there's no common supported cipher. - // Ideally we'd map that specific case to ERR_SSL_VERSION_OR_CIPHER_MISMATCH - // to match the NSS implementation. See also http://goo.gl/oMtZW - case SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE: case SSL_R_SSLV3_ALERT_NO_CERTIFICATE: case SSL_R_SSLV3_ALERT_ILLEGAL_PARAMETER: case SSL_R_TLSV1_ALERT_DECODE_ERROR: @@ -139,8 +132,20 @@ int MapOpenSSLErrorSSL(uint32_t error_code) { // The only way that the certificate verify callback can fail is if // the leaf certificate changed during a renegotiation. return ERR_SSL_SERVER_CERT_CHANGED; - case SSL_AD_REASON_OFFSET + SSL3_AD_INAPPROPRIATE_FALLBACK: + case SSL_R_TLSV1_ALERT_INAPPROPRIATE_FALLBACK: return ERR_SSL_INAPPROPRIATE_FALLBACK; + // SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE may be returned from the server after + // receiving ClientHello if there's no common supported cipher. Map that + // specific case to ERR_SSL_VERSION_OR_CIPHER_MISMATCH to match the NSS + // implementation. See https://goo.gl/oMtZW and https://crbug.com/446505. + case SSL_R_SSLV3_ALERT_HANDSHAKE_FAILURE: { + uint32_t previous = ERR_peek_error(); + if (previous != 0 && ERR_GET_LIB(previous) == ERR_LIB_SSL && + ERR_GET_REASON(previous) == SSL_R_HANDSHAKE_FAILURE_ON_CLIENT_HELLO) { + return ERR_SSL_VERSION_OR_CIPHER_MISMATCH; + } + return ERR_SSL_PROTOCOL_ERROR; + } default: LOG(WARNING) << "Unmapped error reason: " << ERR_GET_REASON(error_code); return ERR_SSL_PROTOCOL_ERROR; @@ -150,7 +155,7 @@ int MapOpenSSLErrorSSL(uint32_t error_code) { base::Value* NetLogOpenSSLErrorCallback(int net_error, int ssl_error, const OpenSSLErrorInfo& error_info, - NetLog::LogLevel /* log_level */) { + NetLogCaptureMode /* capture_mode */) { base::DictionaryValue* dict = new base::DictionaryValue(); dict->SetInteger("net_error", net_error); dict->SetInteger("ssl_error", ssl_error); diff --git a/chromium/net/ssl/openssl_ssl_util.h b/chromium/net/ssl/openssl_ssl_util.h index a0339fca18d..6c886cc1c9c 100644 --- a/chromium/net/ssl/openssl_ssl_util.h +++ b/chromium/net/ssl/openssl_ssl_util.h @@ -5,7 +5,7 @@ #ifndef NET_SSL_OPENSSL_SSL_UTIL_H_ #define NET_SSL_OPENSSL_SSL_UTIL_H_ -#include "net/base/net_log.h" +#include "net/log/net_log.h" namespace crypto { class OpenSSLErrStackTracer; @@ -51,7 +51,8 @@ struct OpenSSLErrorInfo { // Converts an OpenSSL error code into a net error code, walking the OpenSSL // error stack if needed. If a value on the stack is used, the error code and // associated information are returned in |*out_error_info|. Otherwise its -// fields are set to 0 and NULL. +// fields are set to 0 and NULL. This function will never return OK, so +// SSL_ERROR_ZERO_RETURN must be handled externally. // // Note that |tracer| is not currently used in the implementation, but is passed // in anyway as this ensures the caller will clear any residual codes left on diff --git a/chromium/net/ssl/scoped_openssl_types.h b/chromium/net/ssl/scoped_openssl_types.h new file mode 100644 index 00000000000..a8c3c345975 --- /dev/null +++ b/chromium/net/ssl/scoped_openssl_types.h @@ -0,0 +1,24 @@ +// Copyright 2015 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. + +#ifndef NET_SSL_SCOPED_OPENSSL_TYPES_H_ +#define NET_SSL_SCOPED_OPENSSL_TYPES_H_ + +#include <openssl/ssl.h> +#include <openssl/x509.h> + +#include "crypto/scoped_openssl_types.h" + +namespace net { + +using ScopedPKCS8_PRIV_KEY_INFO = + crypto::ScopedOpenSSL<PKCS8_PRIV_KEY_INFO, PKCS8_PRIV_KEY_INFO_free>; +using ScopedSSL = crypto::ScopedOpenSSL<SSL, SSL_free>; +using ScopedSSL_CTX = crypto::ScopedOpenSSL<SSL_CTX, SSL_CTX_free>; +using ScopedSSL_SESSION = crypto::ScopedOpenSSL<SSL_SESSION, SSL_SESSION_free>; +using ScopedX509 = crypto::ScopedOpenSSL<X509, X509_free>; + +} // namespace net + +#endif // NET_SSL_SCOPED_OPENSSL_TYPES_H_ diff --git a/chromium/net/ssl/ssl_cipher_suite_names.cc b/chromium/net/ssl/ssl_cipher_suite_names.cc index 55b0276ee5c..87a3259e54c 100644 --- a/chromium/net/ssl/ssl_cipher_suite_names.cc +++ b/chromium/net/ssl/ssl_cipher_suite_names.cc @@ -25,180 +25,183 @@ // The following tables were generated by ssl_cipher_suite_names_generate.go, // found in the same directory as this file. +namespace { + struct CipherSuite { uint16 cipher_suite, encoded; }; -static const struct CipherSuite kCipherSuites[] = { - {0x0, 0x0}, // TLS_NULL_WITH_NULL_NULL - {0x1, 0x101}, // TLS_RSA_WITH_NULL_MD5 - {0x2, 0x102}, // TLS_RSA_WITH_NULL_SHA - {0x3, 0x209}, // TLS_RSA_EXPORT_WITH_RC4_40_MD5 - {0x4, 0x111}, // TLS_RSA_WITH_RC4_128_MD5 - {0x5, 0x112}, // TLS_RSA_WITH_RC4_128_SHA - {0x6, 0x219}, // TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 - {0x7, 0x122}, // TLS_RSA_WITH_IDEA_CBC_SHA - {0x8, 0x22a}, // TLS_RSA_EXPORT_WITH_DES40_CBC_SHA - {0x9, 0x132}, // TLS_RSA_WITH_DES_CBC_SHA - {0xa, 0x13a}, // TLS_RSA_WITH_3DES_EDE_CBC_SHA - {0xb, 0x32a}, // TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA - {0xc, 0x432}, // TLS_DH_DSS_WITH_DES_CBC_SHA - {0xd, 0x43a}, // TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA - {0xe, 0x52a}, // TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA - {0xf, 0x632}, // TLS_DH_RSA_WITH_DES_CBC_SHA - {0x10, 0x63a}, // TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA - {0x11, 0x72a}, // TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA - {0x12, 0x832}, // TLS_DHE_DSS_WITH_DES_CBC_SHA - {0x13, 0x83a}, // TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA - {0x14, 0x92a}, // TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA - {0x15, 0xa32}, // TLS_DHE_RSA_WITH_DES_CBC_SHA - {0x16, 0xa3a}, // TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA - {0x17, 0xb09}, // TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 - {0x18, 0xc11}, // TLS_DH_anon_WITH_RC4_128_MD5 - {0x19, 0xb2a}, // TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA - {0x1a, 0xc32}, // TLS_DH_anon_WITH_DES_CBC_SHA - {0x1b, 0xc3a}, // TLS_DH_anon_WITH_3DES_EDE_CBC_SHA - {0x2f, 0x142}, // TLS_RSA_WITH_AES_128_CBC_SHA - {0x30, 0x442}, // TLS_DH_DSS_WITH_AES_128_CBC_SHA - {0x31, 0x642}, // TLS_DH_RSA_WITH_AES_128_CBC_SHA - {0x32, 0x842}, // TLS_DHE_DSS_WITH_AES_128_CBC_SHA - {0x33, 0xa42}, // TLS_DHE_RSA_WITH_AES_128_CBC_SHA - {0x34, 0xc42}, // TLS_DH_anon_WITH_AES_128_CBC_SHA - {0x35, 0x14a}, // TLS_RSA_WITH_AES_256_CBC_SHA - {0x36, 0x44a}, // TLS_DH_DSS_WITH_AES_256_CBC_SHA - {0x37, 0x64a}, // TLS_DH_RSA_WITH_AES_256_CBC_SHA - {0x38, 0x84a}, // TLS_DHE_DSS_WITH_AES_256_CBC_SHA - {0x39, 0xa4a}, // TLS_DHE_RSA_WITH_AES_256_CBC_SHA - {0x3a, 0xc4a}, // TLS_DH_anon_WITH_AES_256_CBC_SHA - {0x3b, 0x103}, // TLS_RSA_WITH_NULL_SHA256 - {0x3c, 0x143}, // TLS_RSA_WITH_AES_128_CBC_SHA256 - {0x3d, 0x14b}, // TLS_RSA_WITH_AES_256_CBC_SHA256 - {0x3e, 0x443}, // TLS_DH_DSS_WITH_AES_128_CBC_SHA256 - {0x3f, 0x643}, // TLS_DH_RSA_WITH_AES_128_CBC_SHA256 - {0x40, 0x843}, // TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 - {0x41, 0x152}, // TLS_RSA_WITH_CAMELLIA_128_CBC_SHA - {0x42, 0x452}, // TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA - {0x43, 0x652}, // TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA - {0x44, 0x852}, // TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA - {0x45, 0xa52}, // TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA - {0x46, 0xc52}, // TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA - {0x67, 0xa43}, // TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 - {0x68, 0x44b}, // TLS_DH_DSS_WITH_AES_256_CBC_SHA256 - {0x69, 0x64b}, // TLS_DH_RSA_WITH_AES_256_CBC_SHA256 - {0x6a, 0x84b}, // TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 - {0x6b, 0xa4b}, // TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 - {0x6c, 0xc43}, // TLS_DH_anon_WITH_AES_128_CBC_SHA256 - {0x6d, 0xc4b}, // TLS_DH_anon_WITH_AES_256_CBC_SHA256 - {0x84, 0x15a}, // TLS_RSA_WITH_CAMELLIA_256_CBC_SHA - {0x85, 0x45a}, // TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA - {0x86, 0x65a}, // TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA - {0x87, 0x85a}, // TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA - {0x88, 0xa5a}, // TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA - {0x89, 0xc5a}, // TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA - {0x96, 0x162}, // TLS_RSA_WITH_SEED_CBC_SHA - {0x97, 0x462}, // TLS_DH_DSS_WITH_SEED_CBC_SHA - {0x98, 0x662}, // TLS_DH_RSA_WITH_SEED_CBC_SHA - {0x99, 0x862}, // TLS_DHE_DSS_WITH_SEED_CBC_SHA - {0x9a, 0xa62}, // TLS_DHE_RSA_WITH_SEED_CBC_SHA - {0x9b, 0xc62}, // TLS_DH_anon_WITH_SEED_CBC_SHA - {0x9c, 0x16f}, // TLS_RSA_WITH_AES_128_GCM_SHA256 - {0x9d, 0x177}, // TLS_RSA_WITH_AES_256_GCM_SHA384 - {0x9e, 0xa6f}, // TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 - {0x9f, 0xa77}, // TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 - {0xa0, 0x66f}, // TLS_DH_RSA_WITH_AES_128_GCM_SHA256 - {0xa1, 0x677}, // TLS_DH_RSA_WITH_AES_256_GCM_SHA384 - {0xa2, 0x86f}, // TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 - {0xa3, 0x877}, // TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 - {0xa4, 0x46f}, // TLS_DH_DSS_WITH_AES_128_GCM_SHA256 - {0xa5, 0x477}, // TLS_DH_DSS_WITH_AES_256_GCM_SHA384 - {0xa6, 0xc6f}, // TLS_DH_anon_WITH_AES_128_GCM_SHA256 - {0xa7, 0xc77}, // TLS_DH_anon_WITH_AES_256_GCM_SHA384 - {0xba, 0x153}, // TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 - {0xbb, 0x453}, // TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 - {0xbc, 0x653}, // TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 - {0xbd, 0x853}, // TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 - {0xbe, 0xa53}, // TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 - {0xbf, 0xc53}, // TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 - {0xc0, 0x15b}, // TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 - {0xc1, 0x45b}, // TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 - {0xc2, 0x65b}, // TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 - {0xc3, 0x85b}, // TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 - {0xc4, 0xa5b}, // TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 - {0xc5, 0xc5b}, // TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 - {0xc001, 0xd02}, // TLS_ECDH_ECDSA_WITH_NULL_SHA - {0xc002, 0xd12}, // TLS_ECDH_ECDSA_WITH_RC4_128_SHA - {0xc003, 0xd3a}, // TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA - {0xc004, 0xd42}, // TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA - {0xc005, 0xd4a}, // TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA - {0xc006, 0xe02}, // TLS_ECDHE_ECDSA_WITH_NULL_SHA - {0xc007, 0xe12}, // TLS_ECDHE_ECDSA_WITH_RC4_128_SHA - {0xc008, 0xe3a}, // TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA - {0xc009, 0xe42}, // TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA - {0xc00a, 0xe4a}, // TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA - {0xc00b, 0xf02}, // TLS_ECDH_RSA_WITH_NULL_SHA - {0xc00c, 0xf12}, // TLS_ECDH_RSA_WITH_RC4_128_SHA - {0xc00d, 0xf3a}, // TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA - {0xc00e, 0xf42}, // TLS_ECDH_RSA_WITH_AES_128_CBC_SHA - {0xc00f, 0xf4a}, // TLS_ECDH_RSA_WITH_AES_256_CBC_SHA - {0xc010, 0x1002}, // TLS_ECDHE_RSA_WITH_NULL_SHA - {0xc011, 0x1012}, // TLS_ECDHE_RSA_WITH_RC4_128_SHA - {0xc012, 0x103a}, // TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA - {0xc013, 0x1042}, // TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA - {0xc014, 0x104a}, // TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA - {0xc015, 0x1102}, // TLS_ECDH_anon_WITH_NULL_SHA - {0xc016, 0x1112}, // TLS_ECDH_anon_WITH_RC4_128_SHA - {0xc017, 0x113a}, // TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA - {0xc018, 0x1142}, // TLS_ECDH_anon_WITH_AES_128_CBC_SHA - {0xc019, 0x114a}, // TLS_ECDH_anon_WITH_AES_256_CBC_SHA - {0xc023, 0xe43}, // TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 - {0xc024, 0xe4c}, // TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 - {0xc025, 0xd43}, // TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 - {0xc026, 0xd4c}, // TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 - {0xc027, 0x1043}, // TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 - {0xc028, 0x104c}, // TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 - {0xc029, 0xf43}, // TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 - {0xc02a, 0xf4c}, // TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 - {0xc02b, 0xe6f}, // TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - {0xc02c, 0xe77}, // TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - {0xc02d, 0xd6f}, // TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 - {0xc02e, 0xd77}, // TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 - {0xc02f, 0x106f}, // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - {0xc030, 0x1077}, // TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - {0xc031, 0xf6f}, // TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 - {0xc032, 0xf77}, // TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 - {0xc072, 0xe53}, // TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 - {0xc073, 0xe5c}, // TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 - {0xc074, 0xd53}, // TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 - {0xc075, 0xd5c}, // TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 - {0xc076, 0x1053}, // TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 - {0xc077, 0x105c}, // TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 - {0xc078, 0xf53}, // TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 - {0xc079, 0xf5c}, // TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 - {0xc07a, 0x17f}, // TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 - {0xc07b, 0x187}, // TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 - {0xc07c, 0xa7f}, // TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 - {0xc07d, 0xa87}, // TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 - {0xc07e, 0x67f}, // TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 - {0xc07f, 0x687}, // TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 - {0xc080, 0x87f}, // TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 - {0xc081, 0x887}, // TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 - {0xc082, 0x47f}, // TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 - {0xc083, 0x487}, // TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 - {0xc084, 0xc7f}, // TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 - {0xc085, 0xc87}, // TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 - {0xc086, 0xe7f}, // TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 - {0xc087, 0xe87}, // TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 - {0xc088, 0xd7f}, // TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 - {0xc089, 0xd87}, // TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 - {0xc08a, 0x107f}, // TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 - {0xc08b, 0x1087}, // TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 - {0xc08c, 0xf7f}, // TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 - {0xc08d, 0xf87}, // TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 - {0xcc13, 0x108f}, // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 - {0xcc14, 0x0e8f}, // TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 +const struct CipherSuite kCipherSuites[] = { + {0x0, 0x0}, // TLS_NULL_WITH_NULL_NULL + {0x1, 0x101}, // TLS_RSA_WITH_NULL_MD5 + {0x2, 0x102}, // TLS_RSA_WITH_NULL_SHA + {0x3, 0x209}, // TLS_RSA_EXPORT_WITH_RC4_40_MD5 + {0x4, 0x111}, // TLS_RSA_WITH_RC4_128_MD5 + {0x5, 0x112}, // TLS_RSA_WITH_RC4_128_SHA + {0x6, 0x219}, // TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5 + {0x7, 0x122}, // TLS_RSA_WITH_IDEA_CBC_SHA + {0x8, 0x22a}, // TLS_RSA_EXPORT_WITH_DES40_CBC_SHA + {0x9, 0x132}, // TLS_RSA_WITH_DES_CBC_SHA + {0xa, 0x13a}, // TLS_RSA_WITH_3DES_EDE_CBC_SHA + {0xb, 0x32a}, // TLS_DH_DSS_EXPORT_WITH_DES40_CBC_SHA + {0xc, 0x432}, // TLS_DH_DSS_WITH_DES_CBC_SHA + {0xd, 0x43a}, // TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA + {0xe, 0x52a}, // TLS_DH_RSA_EXPORT_WITH_DES40_CBC_SHA + {0xf, 0x632}, // TLS_DH_RSA_WITH_DES_CBC_SHA + {0x10, 0x63a}, // TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA + {0x11, 0x72a}, // TLS_DHE_DSS_EXPORT_WITH_DES40_CBC_SHA + {0x12, 0x832}, // TLS_DHE_DSS_WITH_DES_CBC_SHA + {0x13, 0x83a}, // TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA + {0x14, 0x92a}, // TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA + {0x15, 0xa32}, // TLS_DHE_RSA_WITH_DES_CBC_SHA + {0x16, 0xa3a}, // TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA + {0x17, 0xb09}, // TLS_DH_anon_EXPORT_WITH_RC4_40_MD5 + {0x18, 0xc11}, // TLS_DH_anon_WITH_RC4_128_MD5 + {0x19, 0xb2a}, // TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA + {0x1a, 0xc32}, // TLS_DH_anon_WITH_DES_CBC_SHA + {0x1b, 0xc3a}, // TLS_DH_anon_WITH_3DES_EDE_CBC_SHA + {0x2f, 0x142}, // TLS_RSA_WITH_AES_128_CBC_SHA + {0x30, 0x442}, // TLS_DH_DSS_WITH_AES_128_CBC_SHA + {0x31, 0x642}, // TLS_DH_RSA_WITH_AES_128_CBC_SHA + {0x32, 0x842}, // TLS_DHE_DSS_WITH_AES_128_CBC_SHA + {0x33, 0xa42}, // TLS_DHE_RSA_WITH_AES_128_CBC_SHA + {0x34, 0xc42}, // TLS_DH_anon_WITH_AES_128_CBC_SHA + {0x35, 0x14a}, // TLS_RSA_WITH_AES_256_CBC_SHA + {0x36, 0x44a}, // TLS_DH_DSS_WITH_AES_256_CBC_SHA + {0x37, 0x64a}, // TLS_DH_RSA_WITH_AES_256_CBC_SHA + {0x38, 0x84a}, // TLS_DHE_DSS_WITH_AES_256_CBC_SHA + {0x39, 0xa4a}, // TLS_DHE_RSA_WITH_AES_256_CBC_SHA + {0x3a, 0xc4a}, // TLS_DH_anon_WITH_AES_256_CBC_SHA + {0x3b, 0x103}, // TLS_RSA_WITH_NULL_SHA256 + {0x3c, 0x143}, // TLS_RSA_WITH_AES_128_CBC_SHA256 + {0x3d, 0x14b}, // TLS_RSA_WITH_AES_256_CBC_SHA256 + {0x3e, 0x443}, // TLS_DH_DSS_WITH_AES_128_CBC_SHA256 + {0x3f, 0x643}, // TLS_DH_RSA_WITH_AES_128_CBC_SHA256 + {0x40, 0x843}, // TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 + {0x41, 0x152}, // TLS_RSA_WITH_CAMELLIA_128_CBC_SHA + {0x42, 0x452}, // TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA + {0x43, 0x652}, // TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA + {0x44, 0x852}, // TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA + {0x45, 0xa52}, // TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA + {0x46, 0xc52}, // TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA + {0x67, 0xa43}, // TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 + {0x68, 0x44b}, // TLS_DH_DSS_WITH_AES_256_CBC_SHA256 + {0x69, 0x64b}, // TLS_DH_RSA_WITH_AES_256_CBC_SHA256 + {0x6a, 0x84b}, // TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 + {0x6b, 0xa4b}, // TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 + {0x6c, 0xc43}, // TLS_DH_anon_WITH_AES_128_CBC_SHA256 + {0x6d, 0xc4b}, // TLS_DH_anon_WITH_AES_256_CBC_SHA256 + {0x84, 0x15a}, // TLS_RSA_WITH_CAMELLIA_256_CBC_SHA + {0x85, 0x45a}, // TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA + {0x86, 0x65a}, // TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA + {0x87, 0x85a}, // TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA + {0x88, 0xa5a}, // TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA + {0x89, 0xc5a}, // TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA + {0x96, 0x162}, // TLS_RSA_WITH_SEED_CBC_SHA + {0x97, 0x462}, // TLS_DH_DSS_WITH_SEED_CBC_SHA + {0x98, 0x662}, // TLS_DH_RSA_WITH_SEED_CBC_SHA + {0x99, 0x862}, // TLS_DHE_DSS_WITH_SEED_CBC_SHA + {0x9a, 0xa62}, // TLS_DHE_RSA_WITH_SEED_CBC_SHA + {0x9b, 0xc62}, // TLS_DH_anon_WITH_SEED_CBC_SHA + {0x9c, 0x16f}, // TLS_RSA_WITH_AES_128_GCM_SHA256 + {0x9d, 0x177}, // TLS_RSA_WITH_AES_256_GCM_SHA384 + {0x9e, 0xa6f}, // TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 + {0x9f, 0xa77}, // TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 + {0xa0, 0x66f}, // TLS_DH_RSA_WITH_AES_128_GCM_SHA256 + {0xa1, 0x677}, // TLS_DH_RSA_WITH_AES_256_GCM_SHA384 + {0xa2, 0x86f}, // TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 + {0xa3, 0x877}, // TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 + {0xa4, 0x46f}, // TLS_DH_DSS_WITH_AES_128_GCM_SHA256 + {0xa5, 0x477}, // TLS_DH_DSS_WITH_AES_256_GCM_SHA384 + {0xa6, 0xc6f}, // TLS_DH_anon_WITH_AES_128_GCM_SHA256 + {0xa7, 0xc77}, // TLS_DH_anon_WITH_AES_256_GCM_SHA384 + {0xba, 0x153}, // TLS_RSA_WITH_CAMELLIA_128_CBC_SHA256 + {0xbb, 0x453}, // TLS_DH_DSS_WITH_CAMELLIA_128_CBC_SHA256 + {0xbc, 0x653}, // TLS_DH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + {0xbd, 0x853}, // TLS_DHE_DSS_WITH_CAMELLIA_128_CBC_SHA256 + {0xbe, 0xa53}, // TLS_DHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + {0xbf, 0xc53}, // TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA256 + {0xc0, 0x15b}, // TLS_RSA_WITH_CAMELLIA_256_CBC_SHA256 + {0xc1, 0x45b}, // TLS_DH_DSS_WITH_CAMELLIA_256_CBC_SHA256 + {0xc2, 0x65b}, // TLS_DH_RSA_WITH_CAMELLIA_256_CBC_SHA256 + {0xc3, 0x85b}, // TLS_DHE_DSS_WITH_CAMELLIA_256_CBC_SHA256 + {0xc4, 0xa5b}, // TLS_DHE_RSA_WITH_CAMELLIA_256_CBC_SHA256 + {0xc5, 0xc5b}, // TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA256 + {0xc001, 0xd02}, // TLS_ECDH_ECDSA_WITH_NULL_SHA + {0xc002, 0xd12}, // TLS_ECDH_ECDSA_WITH_RC4_128_SHA + {0xc003, 0xd3a}, // TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA + {0xc004, 0xd42}, // TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA + {0xc005, 0xd4a}, // TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA + {0xc006, 0xe02}, // TLS_ECDHE_ECDSA_WITH_NULL_SHA + {0xc007, 0xe12}, // TLS_ECDHE_ECDSA_WITH_RC4_128_SHA + {0xc008, 0xe3a}, // TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA + {0xc009, 0xe42}, // TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA + {0xc00a, 0xe4a}, // TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA + {0xc00b, 0xf02}, // TLS_ECDH_RSA_WITH_NULL_SHA + {0xc00c, 0xf12}, // TLS_ECDH_RSA_WITH_RC4_128_SHA + {0xc00d, 0xf3a}, // TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA + {0xc00e, 0xf42}, // TLS_ECDH_RSA_WITH_AES_128_CBC_SHA + {0xc00f, 0xf4a}, // TLS_ECDH_RSA_WITH_AES_256_CBC_SHA + {0xc010, 0x1002}, // TLS_ECDHE_RSA_WITH_NULL_SHA + {0xc011, 0x1012}, // TLS_ECDHE_RSA_WITH_RC4_128_SHA + {0xc012, 0x103a}, // TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA + {0xc013, 0x1042}, // TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA + {0xc014, 0x104a}, // TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA + {0xc015, 0x1102}, // TLS_ECDH_anon_WITH_NULL_SHA + {0xc016, 0x1112}, // TLS_ECDH_anon_WITH_RC4_128_SHA + {0xc017, 0x113a}, // TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA + {0xc018, 0x1142}, // TLS_ECDH_anon_WITH_AES_128_CBC_SHA + {0xc019, 0x114a}, // TLS_ECDH_anon_WITH_AES_256_CBC_SHA + {0xc023, 0xe43}, // TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 + {0xc024, 0xe4c}, // TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 + {0xc025, 0xd43}, // TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 + {0xc026, 0xd4c}, // TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 + {0xc027, 0x1043}, // TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 + {0xc028, 0x104c}, // TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 + {0xc029, 0xf43}, // TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 + {0xc02a, 0xf4c}, // TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 + {0xc02b, 0xe6f}, // TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + {0xc02c, 0xe77}, // TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 + {0xc02d, 0xd6f}, // TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 + {0xc02e, 0xd77}, // TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 + {0xc02f, 0x106f}, // TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 + {0xc030, 0x1077}, // TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 + {0xc031, 0xf6f}, // TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 + {0xc032, 0xf77}, // TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 + {0xc072, 0xe53}, // TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + {0xc073, 0xe5c}, // TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + {0xc074, 0xd53}, // TLS_ECDH_ECDSA_WITH_CAMELLIA_128_CBC_SHA256 + {0xc075, 0xd5c}, // TLS_ECDH_ECDSA_WITH_CAMELLIA_256_CBC_SHA384 + {0xc076, 0x1053}, // TLS_ECDHE_RSA_WITH_CAMELLIA_128_CBC_SHA256 + {0xc077, 0x105c}, // TLS_ECDHE_RSA_WITH_CAMELLIA_256_CBC_SHA384 + {0xc078, 0xf53}, // TLS_ECDH_RSA_WITH_CAMELLIA_128_CBC_SHA256 + {0xc079, 0xf5c}, // TLS_ECDH_RSA_WITH_CAMELLIA_256_CBC_SHA384 + {0xc07a, 0x17f}, // TLS_RSA_WITH_CAMELLIA_128_GCM_SHA256 + {0xc07b, 0x187}, // TLS_RSA_WITH_CAMELLIA_256_GCM_SHA384 + {0xc07c, 0xa7f}, // TLS_DHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + {0xc07d, 0xa87}, // TLS_DHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + {0xc07e, 0x67f}, // TLS_DH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + {0xc07f, 0x687}, // TLS_DH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + {0xc080, 0x87f}, // TLS_DHE_DSS_WITH_CAMELLIA_128_GCM_SHA256 + {0xc081, 0x887}, // TLS_DHE_DSS_WITH_CAMELLIA_256_GCM_SHA384 + {0xc082, 0x47f}, // TLS_DH_DSS_WITH_CAMELLIA_128_GCM_SHA256 + {0xc083, 0x487}, // TLS_DH_DSS_WITH_CAMELLIA_256_GCM_SHA384 + {0xc084, 0xc7f}, // TLS_DH_anon_WITH_CAMELLIA_128_GCM_SHA256 + {0xc085, 0xc87}, // TLS_DH_anon_WITH_CAMELLIA_256_GCM_SHA384 + {0xc086, 0xe7f}, // TLS_ECDHE_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + {0xc087, 0xe87}, // TLS_ECDHE_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + {0xc088, 0xd7f}, // TLS_ECDH_ECDSA_WITH_CAMELLIA_128_GCM_SHA256 + {0xc089, 0xd87}, // TLS_ECDH_ECDSA_WITH_CAMELLIA_256_GCM_SHA384 + {0xc08a, 0x107f}, // TLS_ECDHE_RSA_WITH_CAMELLIA_128_GCM_SHA256 + {0xc08b, 0x1087}, // TLS_ECDHE_RSA_WITH_CAMELLIA_256_GCM_SHA384 + {0xc08c, 0xf7f}, // TLS_ECDH_RSA_WITH_CAMELLIA_128_GCM_SHA256 + {0xc08d, 0xf87}, // TLS_ECDH_RSA_WITH_CAMELLIA_256_GCM_SHA384 + {0xcc13, 0x108f}, // TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 + {0xcc14, 0x0e8f}, // TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 + {0xcc15, 0x0a8f}, // TLS_DHE_RSA_WITH_CHACHA20_POLY1305 }; -static const struct { +const struct { char name[15]; } kKeyExchangeNames[18] = { {"NULL"}, // 0 @@ -221,7 +224,7 @@ static const struct { {"ECDH_anon"}, // 17 }; -static const struct { +const struct { char name[18]; } kCipherNames[18] = { {"NULL"}, // 0 @@ -244,22 +247,20 @@ static const struct { {"CHACHA20_POLY1305"}, // 17 }; -static const struct { - char name[7]; +const struct { + char name[12]; } kMacNames[5] = { {"NULL"}, // 0 - {"MD5"}, // 1 - {"SHA1"}, // 2 - {"SHA256"}, // 3 - {"SHA384"}, // 4 + {"HMAC-MD5"}, // 1 + {"HMAC-SHA1"}, // 2 + {"HMAC-SHA256"}, // 3 + {"HMAC-SHA384"}, // 4 // 7 is reserved to indicate an AEAD cipher suite. }; -static const int kAEADMACValue = 7; - -namespace net { +const int kAEADMACValue = 7; -static int CipherSuiteCmp(const void* ia, const void* ib) { +int CipherSuiteCmp(const void* ia, const void* ib) { const CipherSuite* a = static_cast<const CipherSuite*>(ia); const CipherSuite* b = static_cast<const CipherSuite*>(ib); @@ -272,6 +273,29 @@ static int CipherSuiteCmp(const void* ia, const void* ib) { } } +bool GetCipherProperties(uint16 cipher_suite, + int* out_key_exchange, + int* out_cipher, + int* out_mac) { + CipherSuite desired = {0}; + desired.cipher_suite = cipher_suite; + void* r = bsearch(&desired, kCipherSuites, arraysize(kCipherSuites), + sizeof(kCipherSuites[0]), CipherSuiteCmp); + + if (!r) + return false; + + const CipherSuite* cs = static_cast<const CipherSuite*>(r); + *out_key_exchange = cs->encoded >> 8; + *out_cipher = (cs->encoded >> 3) & 0x1f; + *out_mac = cs->encoded & 0x7; + return true; +} + +} // namespace + +namespace net { + void SSLCipherSuiteToStrings(const char** key_exchange_str, const char** cipher_str, const char** mac_str, @@ -280,22 +304,10 @@ void SSLCipherSuiteToStrings(const char** key_exchange_str, *key_exchange_str = *cipher_str = *mac_str = "???"; *is_aead = false; - struct CipherSuite desired = {0}; - desired.cipher_suite = cipher_suite; - - void* r = bsearch(&desired, kCipherSuites, - arraysize(kCipherSuites), sizeof(kCipherSuites[0]), - CipherSuiteCmp); - - if (!r) + int key_exchange, cipher, mac; + if (!GetCipherProperties(cipher_suite, &key_exchange, &cipher, &mac)) return; - const CipherSuite* cs = static_cast<CipherSuite*>(r); - - const int key_exchange = cs->encoded >> 8; - const int cipher = (cs->encoded >> 3) & 0x1f; - const int mac = cs->encoded & 0x7; - *key_exchange_str = kKeyExchangeNames[key_exchange].name; *cipher_str = kCipherNames[cipher].name; if (mac == kAEADMACValue) { @@ -346,27 +358,43 @@ bool ParseSSLCipherString(const std::string& cipher_string, } bool IsSecureTLSCipherSuite(uint16 cipher_suite) { - CipherSuite desired = {0}; - desired.cipher_suite = cipher_suite; + int key_exchange, cipher, mac; + if (!GetCipherProperties(cipher_suite, &key_exchange, &cipher, &mac)) + return false; + + // Only allow forward secure key exchanges. + switch (key_exchange) { + case 10: // DHE_RSA + case 14: // ECDHE_ECDSA + case 16: // ECDHE_RSA + break; + default: + return false; + } - void* r = bsearch(&desired, - kCipherSuites, - arraysize(kCipherSuites), - sizeof(kCipherSuites[0]), - CipherSuiteCmp); + switch (cipher) { + case 13: // AES_128_GCM + case 14: // AES_256_GCM + case 17: // CHACHA20_POLY1305 + break; + default: + return false; + } - if (!r) + // Only AEADs allowed. + if (mac != kAEADMACValue) return false; - const CipherSuite* cs = static_cast<const CipherSuite*>(r); + return true; +} - const int key_exchange = cs->encoded >> 8; - const int cipher = (cs->encoded >> 3) & 0x1f; - const int mac = cs->encoded & 0x7; +bool IsFalseStartableTLSCipherSuite(uint16 cipher_suite) { + int key_exchange, cipher, mac; + if (!GetCipherProperties(cipher_suite, &key_exchange, &cipher, &mac)) + return false; - // Only allow forward secure key exchanges. + // Only allow ECDHE key exchanges. switch (key_exchange) { - case 10: // DHE_RSA case 14: // ECDHE_ECDSA case 16: // ECDHE_RSA break; diff --git a/chromium/net/ssl/ssl_cipher_suite_names.h b/chromium/net/ssl/ssl_cipher_suite_names.h index 29c03a1aea0..f7aea964b91 100644 --- a/chromium/net/ssl/ssl_cipher_suite_names.h +++ b/chromium/net/ssl/ssl_cipher_suite_names.h @@ -55,7 +55,10 @@ NET_EXPORT bool ParseSSLCipherString(const std::string& cipher_string, // Currently, this function follows these criteria: // 1) Only uses forward secure key exchanges // 2) Only uses AEADs -NET_EXPORT_PRIVATE bool IsSecureTLSCipherSuite(uint16 cipher_suite); +NET_EXPORT bool IsSecureTLSCipherSuite(uint16 cipher_suite); + +// Returns true if |cipher_suite| is suitable for use with False Start. +NET_EXPORT bool IsFalseStartableTLSCipherSuite(uint16 cipher_suite); } // namespace net diff --git a/chromium/net/ssl/ssl_cipher_suite_names_unittest.cc b/chromium/net/ssl/ssl_cipher_suite_names_unittest.cc index 042ca82a5d3..6334c30d686 100644 --- a/chromium/net/ssl/ssl_cipher_suite_names_unittest.cc +++ b/chromium/net/ssl/ssl_cipher_suite_names_unittest.cc @@ -18,7 +18,7 @@ TEST(CipherSuiteNamesTest, Basic) { SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, &is_aead, 0xc001); EXPECT_STREQ("ECDH_ECDSA", key_exchange); EXPECT_STREQ("NULL", cipher); - EXPECT_STREQ("SHA1", mac); + EXPECT_STREQ("HMAC-SHA1", mac); EXPECT_FALSE(is_aead); SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, &is_aead, 0x009f); @@ -27,6 +27,12 @@ TEST(CipherSuiteNamesTest, Basic) { EXPECT_TRUE(is_aead); EXPECT_EQ(NULL, mac); + SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, &is_aead, 0xcc15); + EXPECT_STREQ("DHE_RSA", key_exchange); + EXPECT_STREQ("CHACHA20_POLY1305", cipher); + EXPECT_TRUE(is_aead); + EXPECT_EQ(NULL, mac); + SSLCipherSuiteToStrings(&key_exchange, &cipher, &mac, &is_aead, 0xff31); EXPECT_STREQ("???", key_exchange); EXPECT_STREQ("???", cipher); @@ -70,6 +76,7 @@ TEST(CipherSuiteNamesTest, SecureCipherSuites) { // Secure ones. EXPECT_TRUE(IsSecureTLSCipherSuite(0xcc13)); EXPECT_TRUE(IsSecureTLSCipherSuite(0xcc14)); + EXPECT_TRUE(IsSecureTLSCipherSuite(0xcc15)); } } // anonymous namespace diff --git a/chromium/net/ssl/ssl_client_cert_type.h b/chromium/net/ssl/ssl_client_cert_type.h index dd6e997a1c5..d15d06d5c28 100644 --- a/chromium/net/ssl/ssl_client_cert_type.h +++ b/chromium/net/ssl/ssl_client_cert_type.h @@ -11,7 +11,6 @@ namespace net { // http://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-1 enum SSLClientCertType { CLIENT_CERT_RSA_SIGN = 1, - CLIENT_CERT_DSS_SIGN = 2, CLIENT_CERT_ECDSA_SIGN = 64, // 224-255 are Reserved for Private Use, we pick one to use as "invalid". CLIENT_CERT_INVALID_TYPE = 255, diff --git a/chromium/net/ssl/ssl_client_session_cache_openssl.cc b/chromium/net/ssl/ssl_client_session_cache_openssl.cc new file mode 100644 index 00000000000..a0f03247a7a --- /dev/null +++ b/chromium/net/ssl/ssl_client_session_cache_openssl.cc @@ -0,0 +1,99 @@ +// Copyright 2015 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/ssl/ssl_client_session_cache_openssl.h" + +#include <utility> + +#include "base/time/clock.h" +#include "base/time/default_clock.h" + +namespace net { + +SSLClientSessionCacheOpenSSL::SSLClientSessionCacheOpenSSL(const Config& config) + : clock_(new base::DefaultClock), + config_(config), + cache_(config.max_entries), + lookups_since_flush_(0) { +} + +SSLClientSessionCacheOpenSSL::~SSLClientSessionCacheOpenSSL() { + Flush(); +} + +size_t SSLClientSessionCacheOpenSSL::size() const { + return cache_.size(); +} + +SSL_SESSION* SSLClientSessionCacheOpenSSL::Lookup( + const std::string& cache_key) { + base::AutoLock lock(lock_); + + // Expire stale sessions. + lookups_since_flush_++; + if (lookups_since_flush_ >= config_.expiration_check_count) { + lookups_since_flush_ = 0; + FlushExpiredSessions(); + } + + CacheEntryMap::iterator iter = cache_.Get(cache_key); + if (iter == cache_.end()) + return nullptr; + if (IsExpired(iter->second, clock_->Now())) { + cache_.Erase(iter); + return nullptr; + } + return iter->second->session.get(); +} + +void SSLClientSessionCacheOpenSSL::Insert(const std::string& cache_key, + SSL_SESSION* session) { + base::AutoLock lock(lock_); + + // Make a new entry. + CacheEntry* entry = new CacheEntry; + entry->session.reset(SSL_SESSION_up_ref(session)); + entry->creation_time = clock_->Now(); + + // Takes ownership. + cache_.Put(cache_key, entry); +} + +void SSLClientSessionCacheOpenSSL::Flush() { + base::AutoLock lock(lock_); + + cache_.Clear(); +} + +void SSLClientSessionCacheOpenSSL::SetClockForTesting( + scoped_ptr<base::Clock> clock) { + clock_ = clock.Pass(); +} + +SSLClientSessionCacheOpenSSL::CacheEntry::CacheEntry() { +} + +SSLClientSessionCacheOpenSSL::CacheEntry::~CacheEntry() { +} + +bool SSLClientSessionCacheOpenSSL::IsExpired( + SSLClientSessionCacheOpenSSL::CacheEntry* entry, + const base::Time& now) { + return now < entry->creation_time || + entry->creation_time + config_.timeout < now; +} + +void SSLClientSessionCacheOpenSSL::FlushExpiredSessions() { + base::Time now = clock_->Now(); + CacheEntryMap::iterator iter = cache_.begin(); + while (iter != cache_.end()) { + if (IsExpired(iter->second, now)) { + iter = cache_.Erase(iter); + } else { + ++iter; + } + } +} + +} // namespace net diff --git a/chromium/net/ssl/ssl_client_session_cache_openssl.h b/chromium/net/ssl/ssl_client_session_cache_openssl.h new file mode 100644 index 00000000000..9d2f4b57b9b --- /dev/null +++ b/chromium/net/ssl/ssl_client_session_cache_openssl.h @@ -0,0 +1,96 @@ +// Copyright 2015 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. + +#ifndef NET_SSL_SSL_CLIENT_SESSION_CACHE_OPENSSL_H +#define NET_SSL_SSL_CLIENT_SESSION_CACHE_OPENSSL_H + +#include <openssl/ssl.h> + +#include <string> + +#include "base/containers/mru_cache.h" +#include "base/macros.h" +#include "base/memory/scoped_ptr.h" +#include "base/synchronization/lock.h" +#include "base/threading/thread_checker.h" +#include "base/time/time.h" +#include "net/base/net_export.h" +#include "net/ssl/scoped_openssl_types.h" + +namespace base { +class Clock; +} + +namespace net { + +class NET_EXPORT SSLClientSessionCacheOpenSSL { + public: + struct Config { + // The maximum number of entries in the cache. + size_t max_entries = 1024; + // The number of calls to Lookup before a new check for expired sessions. + size_t expiration_check_count = 256; + // How long each session should last. + base::TimeDelta timeout = base::TimeDelta::FromHours(1); + }; + + explicit SSLClientSessionCacheOpenSSL(const Config& config); + ~SSLClientSessionCacheOpenSSL(); + + size_t size() const; + + // Returns the session associated with |cache_key| and moves it to the front + // of the MRU list. Returns null if there is none. The caller is responsible + // for taking a reference to the pointer if the cache is destroyed or a call + // to Insert is made. + SSL_SESSION* Lookup(const std::string& cache_key); + + // Inserts |session| into the cache at |cache_key|. If there is an existing + // one, it is released. Every |expiration_check_count| calls, the cache is + // checked for stale entries. + void Insert(const std::string& cache_key, SSL_SESSION* session); + + // Removes all entries from the cache. + void Flush(); + + void SetClockForTesting(scoped_ptr<base::Clock> clock); + + private: + struct CacheEntry { + CacheEntry(); + ~CacheEntry(); + + ScopedSSL_SESSION session; + // The time at which this entry was created. + base::Time creation_time; + }; + + using CacheEntryMap = + base::MRUCacheBase<std::string, + CacheEntry*, + base::MRUCachePointerDeletor<CacheEntry*>, + base::MRUCacheHashMap>; + + // Returns true if |entry| is expired as of |now|. + bool IsExpired(CacheEntry* entry, const base::Time& now); + + // Removes all expired sessions from the cache. + void FlushExpiredSessions(); + + scoped_ptr<base::Clock> clock_; + Config config_; + CacheEntryMap cache_; + size_t lookups_since_flush_; + + // TODO(davidben): After https://crbug.com/458365 is fixed, replace this with + // a ThreadChecker. The session cache should be single-threaded like other + // classes in net. + base::Lock lock_; + + DISALLOW_COPY_AND_ASSIGN(SSLClientSessionCacheOpenSSL); +}; + +} // namespace net + +#endif // NET_SSL_SSL_CLIENT_SESSION_CACHE_OPENSSL_H diff --git a/chromium/net/ssl/ssl_client_session_cache_openssl_unittest.cc b/chromium/net/ssl/ssl_client_session_cache_openssl_unittest.cc new file mode 100644 index 00000000000..8cb9eabb6d6 --- /dev/null +++ b/chromium/net/ssl/ssl_client_session_cache_openssl_unittest.cc @@ -0,0 +1,226 @@ +// Copyright 2015 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/ssl/ssl_client_session_cache_openssl.h" + +#include <openssl/ssl.h> + +#include "base/strings/string_number_conversions.h" +#include "base/test/simple_test_clock.h" +#include "net/ssl/scoped_openssl_types.h" +#include "testing/gtest/include/gtest/gtest.h" + +namespace net { + +// Test basic insertion and lookup operations. +TEST(SSLClientSessionCacheOpenSSLTest, Basic) { + SSLClientSessionCacheOpenSSL::Config config; + SSLClientSessionCacheOpenSSL cache(config); + + ScopedSSL_SESSION session1(SSL_SESSION_new()); + ScopedSSL_SESSION session2(SSL_SESSION_new()); + ScopedSSL_SESSION session3(SSL_SESSION_new()); + EXPECT_EQ(1, session1->references); + EXPECT_EQ(1, session2->references); + EXPECT_EQ(1, session3->references); + + EXPECT_EQ(nullptr, cache.Lookup("key1")); + EXPECT_EQ(nullptr, cache.Lookup("key2")); + EXPECT_EQ(0u, cache.size()); + + cache.Insert("key1", session1.get()); + EXPECT_EQ(session1.get(), cache.Lookup("key1")); + EXPECT_EQ(nullptr, cache.Lookup("key2")); + EXPECT_EQ(1u, cache.size()); + + cache.Insert("key2", session2.get()); + EXPECT_EQ(session1.get(), cache.Lookup("key1")); + EXPECT_EQ(session2.get(), cache.Lookup("key2")); + EXPECT_EQ(2u, cache.size()); + + EXPECT_EQ(2, session1->references); + EXPECT_EQ(2, session2->references); + + cache.Insert("key1", session3.get()); + EXPECT_EQ(session3.get(), cache.Lookup("key1")); + EXPECT_EQ(session2.get(), cache.Lookup("key2")); + EXPECT_EQ(2u, cache.size()); + + EXPECT_EQ(1, session1->references); + EXPECT_EQ(2, session2->references); + EXPECT_EQ(2, session3->references); + + cache.Flush(); + EXPECT_EQ(nullptr, cache.Lookup("key1")); + EXPECT_EQ(nullptr, cache.Lookup("key2")); + EXPECT_EQ(nullptr, cache.Lookup("key3")); + EXPECT_EQ(0u, cache.size()); + + EXPECT_EQ(1, session1->references); + EXPECT_EQ(1, session2->references); + EXPECT_EQ(1, session3->references); +} + +// Test that a session may be inserted at two different keys. This should never +// be necessary, but the API doesn't prohibit it. +TEST(SSLClientSessionCacheOpenSSLTest, DoubleInsert) { + SSLClientSessionCacheOpenSSL::Config config; + SSLClientSessionCacheOpenSSL cache(config); + + ScopedSSL_SESSION session(SSL_SESSION_new()); + EXPECT_EQ(1, session->references); + + EXPECT_EQ(nullptr, cache.Lookup("key1")); + EXPECT_EQ(nullptr, cache.Lookup("key2")); + EXPECT_EQ(0u, cache.size()); + + cache.Insert("key1", session.get()); + EXPECT_EQ(session.get(), cache.Lookup("key1")); + EXPECT_EQ(nullptr, cache.Lookup("key2")); + EXPECT_EQ(1u, cache.size()); + + EXPECT_EQ(2, session->references); + + cache.Insert("key2", session.get()); + EXPECT_EQ(session.get(), cache.Lookup("key1")); + EXPECT_EQ(session.get(), cache.Lookup("key2")); + EXPECT_EQ(2u, cache.size()); + + EXPECT_EQ(3, session->references); + + cache.Flush(); + EXPECT_EQ(nullptr, cache.Lookup("key1")); + EXPECT_EQ(nullptr, cache.Lookup("key2")); + EXPECT_EQ(0u, cache.size()); + + EXPECT_EQ(1, session->references); +} + +// Tests that the session cache's size is correctly bounded. +TEST(SSLClientSessionCacheOpenSSLTest, MaxEntries) { + SSLClientSessionCacheOpenSSL::Config config; + config.max_entries = 3; + SSLClientSessionCacheOpenSSL cache(config); + + ScopedSSL_SESSION session1(SSL_SESSION_new()); + ScopedSSL_SESSION session2(SSL_SESSION_new()); + ScopedSSL_SESSION session3(SSL_SESSION_new()); + ScopedSSL_SESSION session4(SSL_SESSION_new()); + + // Insert three entries. + cache.Insert("key1", session1.get()); + cache.Insert("key2", session2.get()); + cache.Insert("key3", session3.get()); + EXPECT_EQ(session1.get(), cache.Lookup("key1")); + EXPECT_EQ(session2.get(), cache.Lookup("key2")); + EXPECT_EQ(session3.get(), cache.Lookup("key3")); + EXPECT_EQ(3u, cache.size()); + + // On insertion of a fourth, the first is removed. + cache.Insert("key4", session4.get()); + EXPECT_EQ(nullptr, cache.Lookup("key1")); + EXPECT_EQ(session4.get(), cache.Lookup("key4")); + EXPECT_EQ(session3.get(), cache.Lookup("key3")); + EXPECT_EQ(session2.get(), cache.Lookup("key2")); + EXPECT_EQ(3u, cache.size()); + + // Despite being newest, the next to be removed is session4 as it was accessed + // least. recently. + cache.Insert("key1", session1.get()); + EXPECT_EQ(session1.get(), cache.Lookup("key1")); + EXPECT_EQ(session2.get(), cache.Lookup("key2")); + EXPECT_EQ(session3.get(), cache.Lookup("key3")); + EXPECT_EQ(nullptr, cache.Lookup("key4")); + EXPECT_EQ(3u, cache.size()); +} + +// Tests that session expiration works properly. +TEST(SSLClientSessionCacheOpenSSLTest, Expiration) { + const size_t kNumEntries = 20; + const size_t kExpirationCheckCount = 10; + const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(1000); + + SSLClientSessionCacheOpenSSL::Config config; + config.expiration_check_count = kExpirationCheckCount; + config.timeout = kTimeout; + SSLClientSessionCacheOpenSSL cache(config); + base::SimpleTestClock* clock = new base::SimpleTestClock; + cache.SetClockForTesting(make_scoped_ptr(clock)); + + // Add |kNumEntries - 1| entries. + for (size_t i = 0; i < kNumEntries - 1; i++) { + ScopedSSL_SESSION session(SSL_SESSION_new()); + cache.Insert(base::SizeTToString(i), session.get()); + } + EXPECT_EQ(kNumEntries - 1, cache.size()); + + // Expire all the previous entries and insert one more entry. + clock->Advance(kTimeout * 2); + ScopedSSL_SESSION session(SSL_SESSION_new()); + cache.Insert("key", session.get()); + + // All entries are still in the cache. + EXPECT_EQ(kNumEntries, cache.size()); + + // Perform one fewer lookup than needed to trigger the expiration check. This + // shall not expire any session. + for (size_t i = 0; i < kExpirationCheckCount - 1; i++) + cache.Lookup("key"); + + // All entries are still in the cache. + EXPECT_EQ(kNumEntries, cache.size()); + + // Perform one more lookup. This will expire all sessions but the last one. + cache.Lookup("key"); + EXPECT_EQ(1u, cache.size()); + EXPECT_EQ(session.get(), cache.Lookup("key")); + for (size_t i = 0; i < kNumEntries - 1; i++) { + SCOPED_TRACE(i); + EXPECT_EQ(nullptr, cache.Lookup(base::SizeTToString(i))); + } +} + +// Tests that Lookup performs an expiration check before returning a cached +// session. +TEST(SSLClientSessionCacheOpenSSLTest, LookupExpirationCheck) { + // kExpirationCheckCount is set to a suitably large number so the automated + // pruning never triggers. + const size_t kExpirationCheckCount = 1000; + const base::TimeDelta kTimeout = base::TimeDelta::FromSeconds(1000); + + SSLClientSessionCacheOpenSSL::Config config; + config.expiration_check_count = kExpirationCheckCount; + config.timeout = kTimeout; + SSLClientSessionCacheOpenSSL cache(config); + base::SimpleTestClock* clock = new base::SimpleTestClock; + cache.SetClockForTesting(make_scoped_ptr(clock)); + + // Insert an entry into the session cache. + ScopedSSL_SESSION session(SSL_SESSION_new()); + cache.Insert("key", session.get()); + EXPECT_EQ(session.get(), cache.Lookup("key")); + EXPECT_EQ(1u, cache.size()); + + // Expire the session. + clock->Advance(kTimeout * 2); + + // The entry has not been removed yet. + EXPECT_EQ(1u, cache.size()); + + // But it will not be returned on lookup and gets pruned at that point. + EXPECT_EQ(nullptr, cache.Lookup("key")); + EXPECT_EQ(0u, cache.size()); + + // Sessions also are treated as expired if the clock rewinds. + cache.Insert("key", session.get()); + EXPECT_EQ(session.get(), cache.Lookup("key")); + EXPECT_EQ(1u, cache.size()); + + clock->Advance(-kTimeout * 2); + + EXPECT_EQ(nullptr, cache.Lookup("key")); + EXPECT_EQ(0u, cache.size()); +} + +} // namespace net diff --git a/chromium/net/ssl/ssl_config.cc b/chromium/net/ssl/ssl_config.cc index 8efdd58386e..ada954f1db3 100644 --- a/chromium/net/ssl/ssl_config.cc +++ b/chromium/net/ssl/ssl_config.cc @@ -4,12 +4,12 @@ #include "net/ssl/ssl_config.h" +#include "net/socket/ssl_client_socket.h" + namespace net { const uint16 kDefaultSSLVersionMin = SSL_PROTOCOL_VERSION_TLS1; -const uint16 kDefaultSSLVersionMax = SSL_PROTOCOL_VERSION_TLS1_2; - const uint16 kDefaultSSLVersionFallbackMin = SSL_PROTOCOL_VERSION_TLS1; SSLConfig::CertAndStatus::CertAndStatus() : cert_status(0) {} @@ -20,16 +20,20 @@ SSLConfig::SSLConfig() : rev_checking_enabled(false), rev_checking_required_local_anchors(false), version_min(kDefaultSSLVersionMin), - version_max(kDefaultSSLVersionMax), + version_max(SSLClientSocket::GetMaxSupportedSSLVersion()), version_fallback_min(kDefaultSSLVersionFallbackMin), + enable_deprecated_cipher_suites(false), channel_id_enabled(true), false_start_enabled(true), signed_cert_timestamps_enabled(true), - require_forward_secrecy(false), + require_ecdhe(false), send_client_cert(false), verify_ev_cert(false), version_fallback(false), - cert_io_enabled(true) { + cert_io_enabled(true), + renego_allowed_default(false), + fastradio_padding_enabled(false), + fastradio_padding_eligible(false) { } SSLConfig::~SSLConfig() {} diff --git a/chromium/net/ssl/ssl_config.h b/chromium/net/ssl/ssl_config.h index 1deaf6e653b..853e8812223 100644 --- a/chromium/net/ssl/ssl_config.h +++ b/chromium/net/ssl/ssl_config.h @@ -9,6 +9,7 @@ #include "base/memory/ref_counted.h" #include "net/base/net_export.h" #include "net/cert/x509_certificate.h" +#include "net/socket/next_proto.h" namespace net { @@ -20,7 +21,6 @@ namespace net { // The most significant byte is |major|, and the least significant byte // is |minor|. enum { - SSL_PROTOCOL_VERSION_SSL3 = 0x0300, SSL_PROTOCOL_VERSION_TLS1 = 0x0301, SSL_PROTOCOL_VERSION_TLS1_1 = 0x0302, SSL_PROTOCOL_VERSION_TLS1_2 = 0x0303, @@ -29,8 +29,8 @@ enum { // Default minimum protocol version. NET_EXPORT extern const uint16 kDefaultSSLVersionMin; -// Default maximum protocol version. -NET_EXPORT extern const uint16 kDefaultSSLVersionMax; +// For maximum supported protocol version, use +// SSLClientSocket::GetMaxSupportedSSLVersion(). // Default minimum protocol version that it's acceptable to fallback to. NET_EXPORT extern const uint16 kDefaultSSLVersionFallbackMin; @@ -38,7 +38,6 @@ NET_EXPORT extern const uint16 kDefaultSSLVersionFallbackMin; // A collection of SSL-related configuration settings. struct NET_EXPORT SSLConfig { // Default to revocation checking. - // Default to SSL 3.0 ~ default_version_max() on. SSLConfig(); ~SSLConfig(); @@ -69,10 +68,9 @@ struct NET_EXPORT SSLConfig { bool rev_checking_required_local_anchors; // The minimum and maximum protocol versions that are enabled. - // SSL 3.0 is 0x0300, TLS 1.0 is 0x0301, TLS 1.1 is 0x0302, and so on. // (Use the SSL_PROTOCOL_VERSION_xxx enumerators defined above.) - // SSL 2.0 is not supported. If version_max < version_min, it means no - // protocol versions are enabled. + // SSL 2.0 and SSL 3.0 are not supported. If version_max < version_min, it + // means no protocol versions are enabled. uint16 version_min; uint16 version_max; @@ -105,16 +103,19 @@ struct NET_EXPORT SSLConfig { // disable TLS_ECDH_ECDSA_WITH_RC4_128_SHA, specify 0xC002. std::vector<uint16> disabled_cipher_suites; + // Enables deprecated cipher suites. Currently, RC4 is deprecated. + bool enable_deprecated_cipher_suites; + bool channel_id_enabled; // True if TLS channel ID extension is enabled. bool false_start_enabled; // True if we'll use TLS False Start. // True if the Certificate Transparency signed_certificate_timestamp // TLS extension is enabled. bool signed_cert_timestamps_enabled; - // require_forward_secrecy, if true, causes only (EC)DHE cipher suites to be - // enabled. NOTE: this only applies to server sockets currently, although - // that could be extended if needed. - bool require_forward_secrecy; + // If true, causes only ECDHE cipher suites to be enabled. NOTE: This only + // applies to server sockets currently, although that could be extended if + // needed. + bool require_ecdhe; // TODO(wtc): move the following members to a new SSLParams structure. They // are not SSL configuration settings. @@ -155,9 +156,26 @@ struct NET_EXPORT SSLConfig { // Protocol Negotiation, but there is no overlap between the server's and // client's protocol sets, then the first protocol in this list will be // requested by the client. - std::vector<std::string> next_protos; + NextProtoVector next_protos; + + // True if renegotiation should be allowed for the default application-level + // protocol when the peer negotiates neither ALPN nor NPN. + bool renego_allowed_default; + + // The list of application-level protocols to enable renegotiation for. + NextProtoVector renego_allowed_for_protos; scoped_refptr<X509Certificate> client_cert; + + // Information about how to proceed with fastradio padding. + // |fastradio_padding_enabled| determines if the feature is enabled globally. + // |fastradio_padding_eligible| determines if the endpoint associated with + // this config should use it. + // |fastradio_padding_eligible| can be true when |fastradio_padding_enabled| + // is false: in this case, fastradio padding would not be enabled, but + // metrics can be collected for experiments. + bool fastradio_padding_enabled; + bool fastradio_padding_eligible; }; } // namespace net diff --git a/chromium/net/ssl/ssl_config_service.cc b/chromium/net/ssl/ssl_config_service.cc index 4661930dc51..5b57cc2c4a9 100644 --- a/chromium/net/ssl/ssl_config_service.cc +++ b/chromium/net/ssl/ssl_config_service.cc @@ -77,6 +77,10 @@ void SSLConfigService::NotifySSLConfigChange() { FOR_EACH_OBSERVER(Observer, observer_list_, OnSSLConfigChanged()); } +bool SSLConfigService::SupportsFastradioPadding(const GURL& url) { + return false; +} + SSLConfigService::~SSLConfigService() { } @@ -92,8 +96,7 @@ void SSLConfigService::ProcessConfigUpdate(const SSLConfig& orig_config, new_config.disabled_cipher_suites) || (orig_config.channel_id_enabled != new_config.channel_id_enabled) || (orig_config.false_start_enabled != new_config.false_start_enabled) || - (orig_config.require_forward_secrecy != - new_config.require_forward_secrecy); + (orig_config.require_ecdhe != new_config.require_ecdhe); if (config_changed) NotifySSLConfigChange(); diff --git a/chromium/net/ssl/ssl_config_service.h b/chromium/net/ssl/ssl_config_service.h index e074309ffac..dd3236d2a58 100644 --- a/chromium/net/ssl/ssl_config_service.h +++ b/chromium/net/ssl/ssl_config_service.h @@ -14,6 +14,8 @@ #include "net/cert/ct_ev_whitelist.h" #include "net/ssl/ssl_config.h" +class GURL; + namespace net { // The interface for retrieving the SSL configuration. This interface @@ -66,6 +68,9 @@ class NET_EXPORT SSLConfigService // called on the IO thread. void NotifySSLConfigChange(); + // Returns true if the |url| should use fastradio padding. + virtual bool SupportsFastradioPadding(const GURL& url); + protected: friend class base::RefCountedThreadSafe<SSLConfigService>; diff --git a/chromium/net/ssl/ssl_config_service_unittest.cc b/chromium/net/ssl/ssl_config_service_unittest.cc index 7306c68d713..7428dd00eb9 100644 --- a/chromium/net/ssl/ssl_config_service_unittest.cc +++ b/chromium/net/ssl/ssl_config_service_unittest.cc @@ -49,8 +49,8 @@ TEST(SSLConfigServiceTest, NoChangesWontNotifyObservers) { SSLConfig initial_config; initial_config.rev_checking_enabled = true; initial_config.false_start_enabled = false; - initial_config.version_min = SSL_PROTOCOL_VERSION_SSL3; - initial_config.version_max = SSL_PROTOCOL_VERSION_TLS1_1; + initial_config.version_min = SSL_PROTOCOL_VERSION_TLS1; + initial_config.version_max = SSL_PROTOCOL_VERSION_TLS1_2; scoped_refptr<MockSSLConfigService> mock_service( new MockSSLConfigService(initial_config)); @@ -67,8 +67,8 @@ TEST(SSLConfigServiceTest, ConfigUpdatesNotifyObservers) { SSLConfig initial_config; initial_config.rev_checking_enabled = true; initial_config.false_start_enabled = false; - initial_config.version_min = SSL_PROTOCOL_VERSION_SSL3; - initial_config.version_max = SSL_PROTOCOL_VERSION_TLS1_1; + initial_config.version_min = SSL_PROTOCOL_VERSION_TLS1; + initial_config.version_max = SSL_PROTOCOL_VERSION_TLS1_2; scoped_refptr<MockSSLConfigService> mock_service( new MockSSLConfigService(initial_config)); @@ -85,11 +85,11 @@ TEST(SSLConfigServiceTest, ConfigUpdatesNotifyObservers) { mock_service->SetSSLConfig(initial_config); // Test that changing the SSL version range triggers updates. - initial_config.version_min = SSL_PROTOCOL_VERSION_TLS1; + initial_config.version_min = SSL_PROTOCOL_VERSION_TLS1_1; EXPECT_CALL(observer, OnSSLConfigChanged()).Times(1); mock_service->SetSSLConfig(initial_config); - initial_config.version_max = SSL_PROTOCOL_VERSION_SSL3; + initial_config.version_max = SSL_PROTOCOL_VERSION_TLS1_1; EXPECT_CALL(observer, OnSSLConfigChanged()).Times(1); mock_service->SetSSLConfig(initial_config); diff --git a/chromium/net/ssl/ssl_connection_status_flags.h b/chromium/net/ssl/ssl_connection_status_flags.h index faae306a505..5d806ae7d72 100644 --- a/chromium/net/ssl/ssl_connection_status_flags.h +++ b/chromium/net/ssl/ssl_connection_status_flags.h @@ -13,7 +13,6 @@ namespace net { // Status flags for SSLInfo::connection_status. enum { // The lower 16 bits are reserved for the TLS ciphersuite id. - SSL_CONNECTION_CIPHERSUITE_SHIFT = 0, SSL_CONNECTION_CIPHERSUITE_MASK = 0xffff, // The next two bits are reserved for the compression used. @@ -38,7 +37,8 @@ enum { }; // NOTE: the SSL version enum constants must be between 0 and -// SSL_CONNECTION_VERSION_MASK, inclusive. +// SSL_CONNECTION_VERSION_MASK, inclusive. These values are persisted to disk +// and used in UMA, so they must remain stable. enum { SSL_CONNECTION_VERSION_UNKNOWN = 0, // Unknown SSL version. SSL_CONNECTION_VERSION_SSL2 = 1, @@ -50,12 +50,11 @@ enum { SSL_CONNECTION_VERSION_QUIC = 7, SSL_CONNECTION_VERSION_MAX, }; -COMPILE_ASSERT(SSL_CONNECTION_VERSION_MAX - 1 <= SSL_CONNECTION_VERSION_MASK, - SSL_CONNECTION_VERSION_MASK_too_small); +static_assert(SSL_CONNECTION_VERSION_MAX - 1 <= SSL_CONNECTION_VERSION_MASK, + "SSL_CONNECTION_VERSION_MASK too small"); -inline int SSLConnectionStatusToCipherSuite(int connection_status) { - return (connection_status >> SSL_CONNECTION_CIPHERSUITE_SHIFT) & - SSL_CONNECTION_CIPHERSUITE_MASK; +inline uint16 SSLConnectionStatusToCipherSuite(int connection_status) { + return static_cast<uint16>(connection_status); } inline int SSLConnectionStatusToVersion(int connection_status) { @@ -63,14 +62,12 @@ inline int SSLConnectionStatusToVersion(int connection_status) { SSL_CONNECTION_VERSION_MASK; } -inline void SSLConnectionStatusSetCipherSuite(int cipher_suite, +inline void SSLConnectionStatusSetCipherSuite(uint16 cipher_suite, int* connection_status) { // Clear out the old ciphersuite. - *connection_status &= - ~(SSL_CONNECTION_CIPHERSUITE_MASK << SSL_CONNECTION_CIPHERSUITE_SHIFT); + *connection_status &= ~SSL_CONNECTION_CIPHERSUITE_MASK; // Set the new ciphersuite. - *connection_status |= ((cipher_suite & SSL_CONNECTION_CIPHERSUITE_MASK) - << SSL_CONNECTION_CIPHERSUITE_SHIFT); + *connection_status |= cipher_suite; } inline void SSLConnectionStatusSetVersion(int version, int* connection_status) { diff --git a/chromium/net/ssl/ssl_connection_status_flags_unittest.cc b/chromium/net/ssl/ssl_connection_status_flags_unittest.cc index 64fea1313a3..98e4f53b3fd 100644 --- a/chromium/net/ssl/ssl_connection_status_flags_unittest.cc +++ b/chromium/net/ssl/ssl_connection_status_flags_unittest.cc @@ -15,13 +15,13 @@ TEST(SSLConnectionStatusTest, SetCipherSuite) { int expected_version = SSLConnectionStatusToVersion(connection_status); SSLConnectionStatusSetCipherSuite(12345, &connection_status); - EXPECT_EQ(12345, SSLConnectionStatusToCipherSuite(connection_status)); + EXPECT_EQ(12345U, SSLConnectionStatusToCipherSuite(connection_status)); EXPECT_EQ(expected_version, SSLConnectionStatusToVersion(connection_status)); } TEST(SSLConnectionStatusTest, SetVersion) { int connection_status = 0xDEADBEEF; - int expected_cipher_suite = + uint16 expected_cipher_suite = SSLConnectionStatusToCipherSuite(connection_status); SSLConnectionStatusSetVersion(SSL_CONNECTION_VERSION_TLS1_2, diff --git a/chromium/net/ssl/ssl_failure_state.h b/chromium/net/ssl/ssl_failure_state.h new file mode 100644 index 00000000000..5f43e0ab434 --- /dev/null +++ b/chromium/net/ssl/ssl_failure_state.h @@ -0,0 +1,49 @@ +// Copyright 2015 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. + +#ifndef NET_SSL_SSL_FAILURE_STATE_H_ +#define NET_SSL_SSL_FAILURE_STATE_H_ + +namespace net { + +// Describes the most likely cause for the TLS handshake failure. This is an +// approximation used to classify the causes of TLS version fallback. These +// values are used in histograms, so new values must be appended. +enum SSLFailureState { + // The connection was successful. + SSL_FAILURE_NONE = 0, + + // The connection failed for unknown reasons. + SSL_FAILURE_UNKNOWN = 1, + + // The connection failed after sending ClientHello and before receiving + // ServerHello. + SSL_FAILURE_CLIENT_HELLO = 2, + + // The connection failed after negotiating TLS_RSA_WITH_AES_128_GCM_SHA256 or + // TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 and completing the client's second + // leg. Some Microsoft IIS servers fail at this point. See + // https://crbug.com/433406. + SSL_FAILURE_BUGGY_GCM = 3, + + // The connection failed after CertificateVerify was sent. Some servers are + // known to incorrectly implement TLS 1.2 client auth. + SSL_FAILURE_CLIENT_AUTH = 4, + + // The connection failed because the server attempted to resume a session at + // the wrong version. Some versions of OpenSSL may do this in rare + // circumstances. See https://crbug.com/441456 + SSL_FAILURE_SESSION_MISMATCH = 5, + + // The connection failed after sending the NextProto message. Some F5 servers + // fail to parse such messages in TLS 1.1 and TLS 1.2, but not 1.0. See + // https://crbug.com/466977. + SSL_FAILURE_NEXT_PROTO = 6, + + SSL_FAILURE_MAX, +}; + +} // namespace net + +#endif // NET_SSL_SSL_FAILURE_STATE_H_ |