Chromium Code Reviews| Index: net/socket/ssl_client_socket_nss.cc |
| diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc |
| index 60f03240ab9e07f0496a1ffd71a6ec0c5cab599a..13c33950ac851582b6dd7d34d3a7c635b606df23 100644 |
| --- a/net/socket/ssl_client_socket_nss.cc |
| +++ b/net/socket/ssl_client_socket_nss.cc |
| @@ -68,6 +68,7 @@ |
| #include "base/bind_helpers.h" |
| #include "base/callback_helpers.h" |
| #include "base/compiler_specific.h" |
| +#include "base/cpu.h" |
| #include "base/logging.h" |
| #include "base/memory/singleton.h" |
| #include "base/metrics/histogram.h" |
| @@ -490,6 +491,55 @@ int MapNSSClientHandshakeError(PRErrorCode err) { |
| } |
| } |
| +// CiphersRemove takes a zero-terminated array of cipher suite ids in |
| +// |to_remove| and sets every instance of them in |ciphers| to zero. It returns |
| +// true if it found and removed every element of |to_remove|. It assumes that |
| +// there are no duplicates in |ciphers| nor in |to_remove|. |
| +bool CiphersRemove(const uint16* to_remove, uint16* ciphers, size_t num) { |
| + size_t num_remove, found = 0; |
| + |
| + for (num_remove = 0; ; num_remove++) { |
| + if (to_remove[num_remove] == 0) |
| + break; |
| + } |
| + |
| + for (size_t i = 0; i < num; i++) { |
| + for (size_t j = 0; j < num_remove; j++) { |
| + if (to_remove[j] == ciphers[i]) { |
| + ciphers[i] = 0; |
| + found++; |
| + break; |
| + } |
| + } |
| + } |
| + |
| + return found == num_remove; |
| +} |
| + |
| +// CiphersCompact takes an array of cipher suite ids in |ciphers|, where some |
| +// entries are zero, and moves the entries so that all the non-zero elements |
| +// are compacted at the end of the array. |
| +size_t CiphersCompact(uint16* ciphers, size_t num) { |
| + size_t j = num - 1; |
| + |
| + for (size_t i = num - 1; i < num; i--) { |
| + printf("@%u %d %u\n", (unsigned) i, ciphers[i], (unsigned) j); |
| + if (ciphers[i] == 0) |
| + continue; |
| + ciphers[j--] = ciphers[i]; |
| + } |
| + return j+1; |
| +} |
| + |
| +// CiphersCopy copies the zero-terminated array |in| to |out|. |
| +size_t CiphersCopy(const uint16* in, uint16* out) { |
| + for (size_t i = 0; ; i++) { |
| + if (in[i] == 0) |
| + return i; |
| + out[i] = in[i]; |
| + } |
| +} |
| + |
| } // namespace |
| // SSLClientSocketNSS::Core provides a thread-safe, ref-counted core that is |
| @@ -3118,6 +3168,45 @@ int SSLClientSocketNSS::InitializeSSLOptions() { |
| SSL_CipherPrefSet(nss_fd_, *it, PR_FALSE); |
| } |
| + /* Our top preference cipher suites are either forward-secure AES-GCM or |
| + * forward secure ChaCha20-Poly1305. If the local machine has AES-NI then we |
| + * prefer AES-GCM, otherwise ChaCha20. The remainder of the cipher suite |
| + * preference is inheriented from NSS. */ |
| + static const uint16 chacha_ciphers[] = { |
| + 0xcc14 /* TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 */, |
| + 0xcc13 /* TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 */, |
| + 0, |
| + }; |
| + static const uint16 aes_gcm_ciphers[] = { |
| + 0xc02b /* TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 */, |
| + 0xc02f /* TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 */, |
| + 0x9e /* TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 */, |
| + 0, |
| + }; |
| + const PRUint16 *all_ciphers = SSL_GetImplementedCiphers(); |
| + const size_t num_ciphers = SSL_GetNumImplementedCiphers(); |
| + scoped_ptr<uint16[]> ciphers(new uint16[num_ciphers]); |
| + memcpy(ciphers.get(), all_ciphers, sizeof(uint16)*num_ciphers); |
| + |
| + if (CiphersRemove(chacha_ciphers, ciphers.get(), num_ciphers) && |
| + CiphersRemove(aes_gcm_ciphers, ciphers.get(), num_ciphers)) { |
| + CiphersCompact(ciphers.get(), num_ciphers); |
| + |
| + const uint16 *preference_ciphers = chacha_ciphers; |
| + const uint16 *other_ciphers = aes_gcm_ciphers; |
| + if (base::CPU().has_aesni()) { |
|
wtc
2013/11/19 23:00:44
Since this won't change over time, we should ideal
agl
2013/11/20 18:21:07
Done.
|
| + preference_ciphers = aes_gcm_ciphers; |
| + other_ciphers = chacha_ciphers; |
| + } |
| + unsigned i = CiphersCopy(preference_ciphers, ciphers.get()); |
| + CiphersCopy(other_ciphers, &ciphers[i]); |
| + |
| + rv = SSL_CipherOrderSet(nss_fd_, ciphers.get(), num_ciphers); |
| + if (rv != SECSuccess) { |
| + LogFailedNSSFunction(net_log_, "SSL_CipherOrderSet", ""); |
| + } |
| + } |
| + |
| // Support RFC 5077 |
| rv = SSL_OptionSet(nss_fd_, SSL_ENABLE_SESSION_TICKETS, PR_TRUE); |
| if (rv != SECSuccess) { |