summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DEPS2
-rw-r--r--net/socket/ssl_client_socket_nss.cc2
-rw-r--r--net/socket/ssl_client_socket_unittest.cc38
-rw-r--r--net/ssl/ssl_cipher_suite_names.cc99
-rw-r--r--net/ssl/ssl_cipher_suite_names.h3
-rw-r--r--net/test/spawned_test_server/base_test_server.cc2
-rw-r--r--net/test/spawned_test_server/base_test_server.h5
-rwxr-xr-xnet/tools/testserver/testserver.py10
-rw-r--r--third_party/boringssl/boringssl.gypi2
-rw-r--r--third_party/boringssl/boringssl_tests.gypi34
-rw-r--r--third_party/boringssl/boringssl_unittest.cc8
-rw-r--r--third_party/boringssl/update_gypi_and_asm.py6
-rw-r--r--third_party/tlslite/README.chromium3
-rw-r--r--third_party/tlslite/patches/ecdhe_rsa.patch428
-rw-r--r--third_party/tlslite/tlslite/constants.py45
-rw-r--r--third_party/tlslite/tlslite/handshakesettings.py2
-rw-r--r--third_party/tlslite/tlslite/messages.py18
-rw-r--r--third_party/tlslite/tlslite/tlsconnection.py31
-rw-r--r--third_party/tlslite/tlslite/utils/p256.py162
19 files changed, 824 insertions, 76 deletions
diff --git a/DEPS b/DEPS
index 229d2c8..818e54f 100644
--- a/DEPS
+++ b/DEPS
@@ -74,7 +74,7 @@ vars = {
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling BoringSSL
# and whatever else without interference from each other.
- 'boringssl_revision': 'e2e13265ff9cb637f8d0cdefc27b13370848472f',
+ 'boringssl_revision': '4d78718cde0a23421ea4d8f1245b21fe37f7a519',
# Three lines of non-changing comments so that
# the commit queue can handle CLs rolling nss
# and whatever else without interference from each other.
diff --git a/net/socket/ssl_client_socket_nss.cc b/net/socket/ssl_client_socket_nss.cc
index 99a4374..e9d468b 100644
--- a/net/socket/ssl_client_socket_nss.cc
+++ b/net/socket/ssl_client_socket_nss.cc
@@ -1621,7 +1621,7 @@ SECStatus SSLClientSocketNSS::Core::CanFalseStartCallback(
SSL_GetChannelInfo(socket, &channel_info, sizeof(channel_info));
if (ok != SECSuccess || channel_info.length != sizeof(channel_info) ||
channel_info.protocolVersion < SSL_LIBRARY_VERSION_TLS_1_2 ||
- !IsSecureTLSCipherSuite(channel_info.cipherSuite)) {
+ !IsFalseStartableTLSCipherSuite(channel_info.cipherSuite)) {
*can_false_start = PR_FALSE;
return SECSuccess;
}
diff --git a/net/socket/ssl_client_socket_unittest.cc b/net/socket/ssl_client_socket_unittest.cc
index 3a4ff5b..38519c5 100644
--- a/net/socket/ssl_client_socket_unittest.cc
+++ b/net/socket/ssl_client_socket_unittest.cc
@@ -2203,7 +2203,9 @@ TEST_F(SSLClientSocketTest, CipherSuiteDisables) {
// http://www.iana.org/assignments/tls-parameters/tls-parameters.xml,
// only disabling those cipher suites that the test server actually
// implements.
- const uint16 kCiphersToDisable[] = {0x0005, // TLS_RSA_WITH_RC4_128_SHA
+ const uint16 kCiphersToDisable[] = {
+ 0x0005, // TLS_RSA_WITH_RC4_128_SHA
+ 0xc011, // TLS_ECDHE_RSA_WITH_RC4_128_SHA
};
SpawnedTestServer::SSLOptions ssl_options;
@@ -2881,10 +2883,10 @@ TEST_F(SSLClientSocketFalseStartTest, FalseStartEnabled) {
return;
}
- // False Start requires NPN/ALPN, perfect forward secrecy, and an AEAD.
+ // False Start requires NPN/ALPN, ECDHE, and an AEAD.
SpawnedTestServer::SSLOptions server_options;
server_options.key_exchanges =
- SpawnedTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA;
+ SpawnedTestServer::SSLOptions::KEY_EXCHANGE_ECDHE_RSA;
server_options.bulk_ciphers =
SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128GCM;
server_options.enable_npn = true;
@@ -2903,7 +2905,7 @@ TEST_F(SSLClientSocketFalseStartTest, NoNPN) {
SpawnedTestServer::SSLOptions server_options;
server_options.key_exchanges =
- SpawnedTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA;
+ SpawnedTestServer::SSLOptions::KEY_EXCHANGE_ECDHE_RSA;
server_options.bulk_ciphers =
SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128GCM;
SSLConfig client_config;
@@ -2912,8 +2914,8 @@ TEST_F(SSLClientSocketFalseStartTest, NoNPN) {
TestFalseStart(server_options, client_config, false));
}
-// Test that False Start is disabled without perfect forward secrecy.
-TEST_F(SSLClientSocketFalseStartTest, NoForwardSecrecy) {
+// Test that False Start is disabled with plain RSA ciphers.
+TEST_F(SSLClientSocketFalseStartTest, RSA) {
if (!SupportsAESGCM()) {
LOG(WARNING) << "Skipping test because AES-GCM is not supported.";
return;
@@ -2931,11 +2933,29 @@ TEST_F(SSLClientSocketFalseStartTest, NoForwardSecrecy) {
TestFalseStart(server_options, client_config, false));
}
+// Test that False Start is disabled with DHE_RSA ciphers.
+TEST_F(SSLClientSocketFalseStartTest, DHE_RSA) {
+ if (!SupportsAESGCM()) {
+ LOG(WARNING) << "Skipping test because AES-GCM is not supported.";
+ return;
+ }
+
+ SpawnedTestServer::SSLOptions server_options;
+ server_options.key_exchanges =
+ SpawnedTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA;
+ server_options.bulk_ciphers =
+ SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128GCM;
+ server_options.enable_npn = true;
+ SSLConfig client_config;
+ client_config.next_protos.push_back(kProtoHTTP11);
+ ASSERT_NO_FATAL_FAILURE(TestFalseStart(server_options, client_config, false));
+}
+
// Test that False Start is disabled without an AEAD.
TEST_F(SSLClientSocketFalseStartTest, NoAEAD) {
SpawnedTestServer::SSLOptions server_options;
server_options.key_exchanges =
- SpawnedTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA;
+ SpawnedTestServer::SSLOptions::KEY_EXCHANGE_ECDHE_RSA;
server_options.bulk_ciphers =
SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128;
server_options.enable_npn = true;
@@ -2954,7 +2974,7 @@ TEST_F(SSLClientSocketFalseStartTest, SessionResumption) {
// Start a server.
SpawnedTestServer::SSLOptions server_options;
server_options.key_exchanges =
- SpawnedTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA;
+ SpawnedTestServer::SSLOptions::KEY_EXCHANGE_ECDHE_RSA;
server_options.bulk_ciphers =
SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128GCM;
server_options.enable_npn = true;
@@ -2992,7 +3012,7 @@ TEST_F(SSLClientSocketFalseStartTest, NoSessionResumptionBeforeFinish) {
// Start a server.
SpawnedTestServer::SSLOptions server_options;
server_options.key_exchanges =
- SpawnedTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA;
+ SpawnedTestServer::SSLOptions::KEY_EXCHANGE_ECDHE_RSA;
server_options.bulk_ciphers =
SpawnedTestServer::SSLOptions::BULK_CIPHER_AES128GCM;
server_options.enable_npn = true;
diff --git a/net/ssl/ssl_cipher_suite_names.cc b/net/ssl/ssl_cipher_suite_names.cc
index de3cff2..56d7521 100644
--- a/net/ssl/ssl_cipher_suite_names.cc
+++ b/net/ssl/ssl_cipher_suite_names.cc
@@ -25,11 +25,13 @@
// 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[] = {
+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
@@ -199,7 +201,7 @@ static const struct CipherSuite kCipherSuites[] = {
{0xcc15, 0x0a8f}, // TLS_DHE_RSA_WITH_CHACHA20_POLY1305
};
-static const struct {
+const struct {
char name[15];
} kKeyExchangeNames[18] = {
{"NULL"}, // 0
@@ -222,7 +224,7 @@ static const struct {
{"ECDH_anon"}, // 17
};
-static const struct {
+const struct {
char name[18];
} kCipherNames[18] = {
{"NULL"}, // 0
@@ -245,7 +247,7 @@ static const struct {
{"CHACHA20_POLY1305"}, // 17
};
-static const struct {
+const struct {
char name[7];
} kMacNames[5] = {
{"NULL"}, // 0
@@ -256,11 +258,9 @@ static const struct {
// 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);
@@ -273,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,
@@ -281,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) {
@@ -347,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/net/ssl/ssl_cipher_suite_names.h b/net/ssl/ssl_cipher_suite_names.h
index 4e02fc6..f7aea96 100644
--- a/net/ssl/ssl_cipher_suite_names.h
+++ b/net/ssl/ssl_cipher_suite_names.h
@@ -57,6 +57,9 @@ NET_EXPORT bool ParseSSLCipherString(const std::string& cipher_string,
// 2) Only uses AEADs
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
#endif // NET_SSL_SSL_CIPHER_SUITE_NAMES_H_
diff --git a/net/test/spawned_test_server/base_test_server.cc b/net/test/spawned_test_server/base_test_server.cc
index b530689..f2eea30 100644
--- a/net/test/spawned_test_server/base_test_server.cc
+++ b/net/test/spawned_test_server/base_test_server.cc
@@ -59,6 +59,8 @@ void GetKeyExchangesList(int key_exchange, base::ListValue* values) {
values->Append(new base::StringValue("rsa"));
if (key_exchange & BaseTestServer::SSLOptions::KEY_EXCHANGE_DHE_RSA)
values->Append(new base::StringValue("dhe_rsa"));
+ if (key_exchange & BaseTestServer::SSLOptions::KEY_EXCHANGE_ECDHE_RSA)
+ values->Append(new base::StringValue("ecdhe_rsa"));
}
void GetCiphersList(int cipher, base::ListValue* values) {
diff --git a/net/test/spawned_test_server/base_test_server.h b/net/test/spawned_test_server/base_test_server.h
index f146d5c..c2d42ee 100644
--- a/net/test/spawned_test_server/base_test_server.h
+++ b/net/test/spawned_test_server/base_test_server.h
@@ -79,10 +79,11 @@ class BaseTestServer {
// Special value used to indicate that any algorithm the server supports
// is acceptable. Preferred over explicitly OR-ing all key exchange
// algorithms.
- KEY_EXCHANGE_ANY = 0,
+ KEY_EXCHANGE_ANY = 0,
- KEY_EXCHANGE_RSA = (1 << 0),
+ KEY_EXCHANGE_RSA = (1 << 0),
KEY_EXCHANGE_DHE_RSA = (1 << 1),
+ KEY_EXCHANGE_ECDHE_RSA = (1 << 2),
};
// Bitmask of bulk encryption algorithms that the test server supports
diff --git a/net/tools/testserver/testserver.py b/net/tools/testserver/testserver.py
index 19409d2..bda4f90 100755
--- a/net/tools/testserver/testserver.py
+++ b/net/tools/testserver/testserver.py
@@ -2258,11 +2258,11 @@ class ServerRunner(testserver_base.TestServerRunner):
self.option_parser.add_option('--ssl-key-exchange', action='append',
help='Specify the key exchange algorithm(s)'
'that will be accepted by the SSL server. '
- 'Valid values are "rsa", "dhe_rsa". If '
- 'omitted, all algorithms will be used. This '
- 'option may appear multiple times, '
- 'indicating multiple algorithms should be '
- 'enabled.');
+ 'Valid values are "rsa", "dhe_rsa", '
+ '"ecdhe_rsa". If omitted, all algorithms '
+ 'will be used. This option may appear '
+ 'multiple times, indicating multiple '
+ 'algorithms should be enabled.');
# TODO(davidben): Add ALPN support to tlslite.
self.option_parser.add_option('--enable-npn', dest='enable_npn',
default=False, const=True,
diff --git a/third_party/boringssl/boringssl.gypi b/third_party/boringssl/boringssl.gypi
index d2fc5d4..01a4230 100644
--- a/third_party/boringssl/boringssl.gypi
+++ b/third_party/boringssl/boringssl.gypi
@@ -182,6 +182,8 @@
'src/crypto/sha/sha512.c',
'src/crypto/stack/stack.c',
'src/crypto/thread.c',
+ 'src/crypto/thread_pthread.c',
+ 'src/crypto/thread_win.c',
'src/crypto/time_support.c',
'src/crypto/x509/a_digest.c',
'src/crypto/x509/a_sign.c',
diff --git a/third_party/boringssl/boringssl_tests.gypi b/third_party/boringssl/boringssl_tests.gypi
index 0373742..e1b606a 100644
--- a/third_party/boringssl/boringssl_tests.gypi
+++ b/third_party/boringssl/boringssl_tests.gypi
@@ -13,7 +13,7 @@
'boringssl.gyp:boringssl',
],
'sources': [
- 'src/crypto/base64/base64_test.c',
+ 'src/crypto/base64/base64_test.cc',
],
# TODO(davidben): Fix size_t truncations in BoringSSL.
# https://crbug.com/429039
@@ -26,7 +26,7 @@
'boringssl.gyp:boringssl',
],
'sources': [
- 'src/crypto/bio/bio_test.c',
+ 'src/crypto/bio/bio_test.cc',
],
# TODO(davidben): Fix size_t truncations in BoringSSL.
# https://crbug.com/429039
@@ -39,7 +39,7 @@
'boringssl.gyp:boringssl',
],
'sources': [
- 'src/crypto/bn/bn_test.c',
+ 'src/crypto/bn/bn_test.cc',
],
# TODO(davidben): Fix size_t truncations in BoringSSL.
# https://crbug.com/429039
@@ -52,7 +52,7 @@
'boringssl.gyp:boringssl',
],
'sources': [
- 'src/crypto/bytestring/bytestring_test.c',
+ 'src/crypto/bytestring/bytestring_test.cc',
],
# TODO(davidben): Fix size_t truncations in BoringSSL.
# https://crbug.com/429039
@@ -117,7 +117,7 @@
'boringssl.gyp:boringssl',
],
'sources': [
- 'src/crypto/digest/digest_test.c',
+ 'src/crypto/digest/digest_test.cc',
],
# TODO(davidben): Fix size_t truncations in BoringSSL.
# https://crbug.com/429039
@@ -182,7 +182,7 @@
'boringssl.gyp:boringssl',
],
'sources': [
- 'src/crypto/err/err_test.c',
+ 'src/crypto/err/err_test.cc',
],
# TODO(davidben): Fix size_t truncations in BoringSSL.
# https://crbug.com/429039
@@ -195,7 +195,7 @@
'boringssl.gyp:boringssl',
],
'sources': [
- 'src/crypto/evp/evp_test.c',
+ 'src/crypto/evp/evp_test.cc',
],
# TODO(davidben): Fix size_t truncations in BoringSSL.
# https://crbug.com/429039
@@ -208,7 +208,7 @@
'boringssl.gyp:boringssl',
],
'sources': [
- 'src/crypto/evp/pbkdf_test.c',
+ 'src/crypto/evp/pbkdf_test.cc',
],
# TODO(davidben): Fix size_t truncations in BoringSSL.
# https://crbug.com/429039
@@ -234,7 +234,7 @@
'boringssl.gyp:boringssl',
],
'sources': [
- 'src/crypto/hmac/hmac_test.c',
+ 'src/crypto/hmac/hmac_test.cc',
],
# TODO(davidben): Fix size_t truncations in BoringSSL.
# https://crbug.com/429039
@@ -293,6 +293,19 @@
'msvs_disabled_warnings': [ 4267, ],
},
{
+ 'target_name': 'boringssl_thread_test',
+ 'type': 'executable',
+ 'dependencies': [
+ 'boringssl.gyp:boringssl',
+ ],
+ 'sources': [
+ 'src/crypto/thread_test.c',
+ ],
+ # TODO(davidben): Fix size_t truncations in BoringSSL.
+ # https://crbug.com/429039
+ 'msvs_disabled_warnings': [ 4267, ],
+ },
+ {
'target_name': 'boringssl_pkcs7_test',
'type': 'executable',
'dependencies': [
@@ -325,7 +338,7 @@
'boringssl.gyp:boringssl',
],
'sources': [
- 'src/ssl/ssl_test.c',
+ 'src/ssl/ssl_test.cc',
],
# TODO(davidben): Fix size_t truncations in BoringSSL.
# https://crbug.com/429039
@@ -359,6 +372,7 @@
'boringssl_pqueue_test',
'boringssl_rsa_test',
'boringssl_ssl_test',
+ 'boringssl_thread_test',
],
}
}
diff --git a/third_party/boringssl/boringssl_unittest.cc b/third_party/boringssl/boringssl_unittest.cc
index d568e33..52bac99 100644
--- a/third_party/boringssl/boringssl_unittest.cc
+++ b/third_party/boringssl/boringssl_unittest.cc
@@ -237,9 +237,13 @@ TEST(BoringSSL, PQueue) {
}
TEST(BoringSSL, HKDF) {
- TestSimple("hkdf_test");
+ TestSimple("hkdf_test");
}
TEST(BoringSSL, PBKDF) {
- TestSimple("pbkdf_test");
+ TestSimple("pbkdf_test");
+}
+
+TEST(BoringSSL, Thread) {
+ TestSimple("thread_test");
}
diff --git a/third_party/boringssl/update_gypi_and_asm.py b/third_party/boringssl/update_gypi_and_asm.py
index 4112c4d..3c6b524 100644
--- a/third_party/boringssl/update_gypi_and_asm.py
+++ b/third_party/boringssl/update_gypi_and_asm.py
@@ -77,9 +77,11 @@ def FindCFiles(directory, filter_func):
for (path, dirnames, filenames) in os.walk(directory):
for filename in filenames:
- if filename.endswith('.c') and filter_func(filename, False):
- cfiles.append(os.path.join(path, filename))
+ if not filename.endswith('.c') and not filename.endswith('.cc'):
continue
+ if not filter_func(filename, False):
+ continue
+ cfiles.append(os.path.join(path, filename))
for (i, dirname) in enumerate(dirnames):
if not filter_func(dirname, True):
diff --git a/third_party/tlslite/README.chromium b/third_party/tlslite/README.chromium
index c2084cd..4468a08 100644
--- a/third_party/tlslite/README.chromium
+++ b/third_party/tlslite/README.chromium
@@ -24,7 +24,7 @@ Local Modifications:
- patches/ssl3_padding.patch: SSL3 requires minimal padding in CBC mode.
- patches/fix_test_file.patch: Fix #! line in random test file to appease our
presubmit checks.
-- patches/dhe_rsa.patch: Implement DHE_RSA-based cipher suites.
+- patches/dhe_rsa.patch: Implement DHE_RSA-based cipher suites on the server.
- patches/req_cert_types.patch: Add a reqCertTypes parameter to populate the
certificate_types field of CertificateRequest. Also fixes type errors.
- patches/ignore_write_failure.patch: Don't invalidate sessions on write
@@ -38,3 +38,4 @@ Local Modifications:
unless >= TLS 1.2 is negotiated.
- patches/alert_after_handshake.patch: Add an option to send a fatal alert
immediately after the handshake completes.
+- patches/ecdhe_rsa.patch: Implement ECDHE_RSA-based ciper suites on the server. \ No newline at end of file
diff --git a/third_party/tlslite/patches/ecdhe_rsa.patch b/third_party/tlslite/patches/ecdhe_rsa.patch
new file mode 100644
index 0000000..054a07a0
--- /dev/null
+++ b/third_party/tlslite/patches/ecdhe_rsa.patch
@@ -0,0 +1,428 @@
+diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlslite/constants.py
+index e5b88af..6d78a20 100644
+--- a/third_party/tlslite/tlslite/constants.py
++++ b/third_party/tlslite/tlslite/constants.py
+@@ -76,6 +76,14 @@ class SignatureAlgorithm:
+ class NameType:
+ host_name = 0
+
++class ECCurveType:
++ explicit_prime = 1
++ explicit_char2 = 2
++ named_curve = 3
++
++class NamedCurve:
++ secp256r1 = 23
++
+ class AlertLevel:
+ warning = 1
+ fatal = 2
+@@ -178,11 +186,19 @@ class CipherSuite:
+ TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C
+ TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E
+
++ TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xc011
++ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xc012
++ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xc013
++ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xc014
++ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xc027
++ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xc02f
++
+ tripleDESSuites = []
+ tripleDESSuites.append(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA)
+ tripleDESSuites.append(TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA)
+ tripleDESSuites.append(TLS_RSA_WITH_3DES_EDE_CBC_SHA)
+ tripleDESSuites.append(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA)
++ tripleDESSuites.append(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA)
+
+ aes128Suites = []
+ aes128Suites.append(TLS_SRP_SHA_WITH_AES_128_CBC_SHA)
+@@ -192,6 +208,8 @@ class CipherSuite:
+ aes128Suites.append(TLS_DH_ANON_WITH_AES_128_CBC_SHA)
+ aes128Suites.append(TLS_RSA_WITH_AES_128_CBC_SHA256)
+ aes128Suites.append(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256)
++ aes128Suites.append(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
++ aes128Suites.append(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256)
+
+ aes256Suites = []
+ aes256Suites.append(TLS_SRP_SHA_WITH_AES_256_CBC_SHA)
+@@ -201,14 +219,17 @@ class CipherSuite:
+ aes256Suites.append(TLS_DHE_RSA_WITH_AES_256_CBC_SHA)
+ aes256Suites.append(TLS_RSA_WITH_AES_256_CBC_SHA256)
+ aes256Suites.append(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256)
++ aes256Suites.append(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
+
+ aes128GcmSuites = []
+ aes128GcmSuites.append(TLS_RSA_WITH_AES_128_GCM_SHA256)
+ aes128GcmSuites.append(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256)
++ aes128GcmSuites.append(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
+
+ rc4Suites = []
+ rc4Suites.append(TLS_RSA_WITH_RC4_128_SHA)
+ rc4Suites.append(TLS_RSA_WITH_RC4_128_MD5)
++ rc4Suites.append(TLS_ECDHE_RSA_WITH_RC4_128_SHA)
+
+ shaSuites = []
+ shaSuites.append(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA)
+@@ -226,6 +247,10 @@ class CipherSuite:
+ shaSuites.append(TLS_DHE_RSA_WITH_AES_256_CBC_SHA)
+ shaSuites.append(TLS_DH_ANON_WITH_AES_128_CBC_SHA)
+ shaSuites.append(TLS_DH_ANON_WITH_AES_256_CBC_SHA)
++ shaSuites.append(TLS_ECDHE_RSA_WITH_RC4_128_SHA)
++ shaSuites.append(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA)
++ shaSuites.append(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
++ shaSuites.append(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
+
+ sha256Suites = []
+ sha256Suites.append(TLS_RSA_WITH_AES_128_CBC_SHA256)
+@@ -234,6 +259,9 @@ class CipherSuite:
+ sha256Suites.append(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256)
+ sha256Suites.append(TLS_RSA_WITH_AES_128_GCM_SHA256)
+ sha256Suites.append(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256)
++ sha256Suites.append(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256)
++ sha256Suites.append(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
++
+
+ aeadSuites = aes128GcmSuites
+
+@@ -275,6 +303,8 @@ class CipherSuite:
+ keyExchangeSuites += CipherSuite.certSuites
+ if "dhe_rsa" in keyExchangeNames:
+ keyExchangeSuites += CipherSuite.dheCertSuites
++ if "ecdhe_rsa" in keyExchangeNames:
++ keyExchangeSuites += CipherSuite.ecdheCertSuites
+ if "srp_sha" in keyExchangeNames:
+ keyExchangeSuites += CipherSuite.srpSuites
+ if "srp_sha_rsa" in keyExchangeNames:
+@@ -335,7 +365,19 @@ class CipherSuite:
+ def getDheCertSuites(settings, version=None):
+ return CipherSuite._filterSuites(CipherSuite.dheCertSuites, settings, version)
+
+- certAllSuites = srpCertSuites + certSuites + dheCertSuites
++ ecdheCertSuites = []
++ ecdheCertSuites.append(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
++ ecdheCertSuites.append(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256)
++ ecdheCertSuites.append(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
++ ecdheCertSuites.append(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
++ ecdheCertSuites.append(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA)
++ ecdheCertSuites.append(TLS_ECDHE_RSA_WITH_RC4_128_SHA)
++
++ @staticmethod
++ def getEcdheCertSuites(settings, version=None):
++ return CipherSuite._filterSuites(CipherSuite.ecdheCertSuites, settings, version)
++
++ certAllSuites = srpCertSuites + certSuites + dheCertSuites + ecdheCertSuites
+
+ anonSuites = []
+ anonSuites.append(TLS_DH_ANON_WITH_AES_256_CBC_SHA)
+@@ -346,6 +388,7 @@ class CipherSuite:
+ return CipherSuite._filterSuites(CipherSuite.anonSuites, settings, version)
+
+ dhAllSuites = dheCertSuites + anonSuites
++ ecdhAllSuites = ecdheCertSuites
+
+ @staticmethod
+ def canonicalCipherName(ciphersuite):
+diff --git a/third_party/tlslite/tlslite/handshakesettings.py b/third_party/tlslite/tlslite/handshakesettings.py
+index e752834..605ed42 100644
+--- a/third_party/tlslite/tlslite/handshakesettings.py
++++ b/third_party/tlslite/tlslite/handshakesettings.py
+@@ -14,7 +14,7 @@ from .utils import cipherfactory
+ CIPHER_NAMES = ["aes128gcm", "rc4", "aes256", "aes128", "3des"]
+ MAC_NAMES = ["sha", "sha256", "aead"] # Don't allow "md5" by default.
+ ALL_MAC_NAMES = MAC_NAMES + ["md5"]
+-KEY_EXCHANGE_NAMES = ["rsa", "dhe_rsa", "srp_sha", "srp_sha_rsa", "dh_anon"]
++KEY_EXCHANGE_NAMES = ["rsa", "dhe_rsa", "ecdhe_rsa", "srp_sha", "srp_sha_rsa", "dh_anon"]
+ CIPHER_IMPLEMENTATIONS = ["openssl", "pycrypto", "python"]
+ CERTIFICATE_TYPES = ["x509"]
+ TLS_INTOLERANCE_TYPES = ["alert", "close", "reset"]
+diff --git a/third_party/tlslite/tlslite/messages.py b/third_party/tlslite/tlslite/messages.py
+index f2e2cfc..9aeff6d 100644
+--- a/third_party/tlslite/tlslite/messages.py
++++ b/third_party/tlslite/tlslite/messages.py
+@@ -509,10 +509,13 @@ class ServerKeyExchange(HandshakeMsg):
+ self.srp_g = 0
+ self.srp_s = bytearray(0)
+ self.srp_B = 0
+- # Anon DH params:
++ # DH params:
+ self.dh_p = 0
+ self.dh_g = 0
+ self.dh_Ys = 0
++ # ECDH params:
++ self.ecdhCurve = 0
++ self.ecdhPublic = bytearray(0)
+ self.signature = bytearray(0)
+
+ def createSRP(self, srp_N, srp_g, srp_s, srp_B):
+@@ -528,6 +531,11 @@ class ServerKeyExchange(HandshakeMsg):
+ self.dh_Ys = dh_Ys
+ return self
+
++ def createECDH(self, ecdhCurve, ecdhPublic):
++ self.ecdhCurve = ecdhCurve
++ self.ecdhPublic = ecdhPublic
++ return self
++
+ def parse(self, p):
+ p.startLengthCheck(3)
+ if self.cipherSuite in CipherSuite.srpAllSuites:
+@@ -555,6 +563,10 @@ class ServerKeyExchange(HandshakeMsg):
+ w.addVarSeq(numberToByteArray(self.dh_p), 1, 2)
+ w.addVarSeq(numberToByteArray(self.dh_g), 1, 2)
+ w.addVarSeq(numberToByteArray(self.dh_Ys), 1, 2)
++ elif self.cipherSuite in CipherSuite.ecdhAllSuites:
++ w.add(ECCurveType.named_curve, 1)
++ w.add(self.ecdhCurve, 2)
++ w.addVarSeq(self.ecdhPublic, 1, 1)
+ else:
+ assert(False)
+ return w.bytes
+@@ -626,7 +638,9 @@ class ClientKeyExchange(HandshakeMsg):
+ else:
+ raise AssertionError()
+ elif self.cipherSuite in CipherSuite.dhAllSuites:
+- self.dh_Yc = bytesToNumber(p.getVarBytes(2))
++ self.dh_Yc = bytesToNumber(p.getVarBytes(2))
++ elif self.cipherSuite in CipherSuite.ecdhAllSuites:
++ self.ecdh_Yc = p.getVarBytes(1)
+ else:
+ raise AssertionError()
+ p.stopLengthCheck()
+diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py
+index 0a85d3c..dfac274 100644
+--- a/third_party/tlslite/tlslite/tlsconnection.py
++++ b/third_party/tlslite/tlslite/tlsconnection.py
+@@ -24,6 +24,7 @@ from .mathtls import *
+ from .handshakesettings import HandshakeSettings
+ from .utils.tackwrapper import *
+ from .utils.rsakey import RSAKey
++from .utils import p256
+
+ class KeyExchange(object):
+ def __init__(self, cipherSuite, clientHello, serverHello, privateKey):
+@@ -127,6 +128,25 @@ DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
+ S = powMod(dh_Yc, self.dh_Xs, self.dh_p)
+ return numberToByteArray(S)
+
++class ECDHE_RSAKeyExchange(KeyExchange):
++ def makeServerKeyExchange(self):
++ public, self.private = p256.generatePublicPrivate()
++
++ version = self.serverHello.server_version
++ serverKeyExchange = ServerKeyExchange(self.cipherSuite, version)
++ serverKeyExchange.createECDH(NamedCurve.secp256r1, bytearray(public))
++ hashBytes = serverKeyExchange.hash(self.clientHello.random,
++ self.serverHello.random)
++ if version >= (3,3):
++ # TODO: Signature algorithm negotiation not supported.
++ hashBytes = RSAKey.addPKCS1SHA1Prefix(hashBytes)
++ serverKeyExchange.signature = self.privateKey.sign(hashBytes)
++ return serverKeyExchange
++
++ def processClientKeyExchange(self, clientKeyExchange):
++ ecdh_Yc = clientKeyExchange.ecdh_Yc
++ return bytearray(p256.generateSharedValue(bytes(ecdh_Yc), self.private))
++
+ class TLSConnection(TLSRecordLayer):
+ """
+ This class wraps a socket and provides TLS handshaking and data
+@@ -1321,9 +1341,8 @@ class TLSConnection(TLSRecordLayer):
+ else: break
+ premasterSecret = result
+
+- # Perform the RSA or DHE_RSA key exchange
+- elif (cipherSuite in CipherSuite.certSuites or
+- cipherSuite in CipherSuite.dheCertSuites):
++ # Perform a certificate-based key exchange
++ elif cipherSuite in CipherSuite.certAllSuites:
+ if cipherSuite in CipherSuite.certSuites:
+ keyExchange = RSAKeyExchange(cipherSuite,
+ clientHello,
+@@ -1334,6 +1353,11 @@ class TLSConnection(TLSRecordLayer):
+ clientHello,
+ serverHello,
+ privateKey)
++ elif cipherSuite in CipherSuite.ecdheCertSuites:
++ keyExchange = ECDHE_RSAKeyExchange(cipherSuite,
++ clientHello,
++ serverHello,
++ privateKey)
+ else:
+ assert(False)
+ for result in self._serverCertKeyExchange(clientHello, serverHello,
+@@ -1450,6 +1474,7 @@ class TLSConnection(TLSRecordLayer):
+ CipherSuite.getSrpCertSuites(settings, self.version)
+ cipherSuites += CipherSuite.getSrpSuites(settings, self.version)
+ elif certChain:
++ cipherSuites += CipherSuite.getEcdheCertSuites(settings, self.version)
+ cipherSuites += CipherSuite.getDheCertSuites(settings, self.version)
+ cipherSuites += CipherSuite.getCertSuites(settings, self.version)
+ elif anon:
+diff --git a/third_party/tlslite/tlslite/utils/p256.py b/third_party/tlslite/tlslite/utils/p256.py
+index e69de29..6eb9a77 100644
+--- a/third_party/tlslite/tlslite/utils/p256.py
++++ b/third_party/tlslite/tlslite/utils/p256.py
+@@ -0,0 +1,162 @@
++# Author: Google
++# See the LICENSE file for legal information regarding use of this file.
++
++import os
++
++p = (
++ 115792089210356248762697446949407573530086143415290314195533631308867097853951)
++order = (
++ 115792089210356248762697446949407573529996955224135760342422259061068512044369)
++p256B = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b
++
++baseX = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296
++baseY = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5
++basePoint = (baseX, baseY)
++
++
++def _pointAdd(a, b):
++ Z1Z1 = (a[2] * a[2]) % p
++ Z2Z2 = (b[2] * b[2]) % p
++ U1 = (a[0] * Z2Z2) % p
++ U2 = (b[0] * Z1Z1) % p
++ S1 = (a[1] * b[2] * Z2Z2) % p
++ S2 = (b[1] * a[2] * Z1Z1) % p
++ if U1 == U2 and S1 == S2:
++ return pointDouble(a)
++ H = (U2 - U1) % p
++ I = (4 * H * H) % p
++ J = (H * I) % p
++ r = (2 * (S2 - S1)) % p
++ V = (U1 * I) % p
++ X3 = (r * r - J - 2 * V) % p
++ Y3 = (r * (V - X3) - 2 * S1 * J) % p
++ Z3 = (((a[2] + b[2]) * (a[2] + b[2]) - Z1Z1 - Z2Z2) * H) % p
++
++ return (X3, Y3, Z3)
++
++
++def _pointDouble(a):
++ delta = (a[2] * a[2]) % p
++ gamma = (a[1] * a[1]) % p
++ beta = (a[0] * gamma) % p
++ alpha = (3 * (a[0] - delta) * (a[0] + delta)) % p
++ X3 = (alpha * alpha - 8 * beta) % p
++ Z3 = ((a[1] + a[2]) * (a[1] + a[2]) - gamma - delta) % p
++ Y3 = (alpha * (4 * beta - X3) - 8 * gamma * gamma) % p
++
++ return (X3, Y3, Z3)
++
++
++def _square(n):
++ return (n * n)
++
++
++def _modpow(a, n, p):
++ if n == 0:
++ return 1
++ if n == 1:
++ return a
++ r = _square(_modpow(a, n >> 1, p)) % p
++ if n & 1 == 1:
++ r = (r * a) % p
++ return r
++
++
++def _scalarMult(k, point):
++ accum = (0, 0, 0)
++ accumIsInfinity = True
++ jacobianPoint = (point[0], point[1], 1)
++
++ for bit in range(255, -1, -1):
++ if not accumIsInfinity:
++ accum = _pointDouble(accum)
++
++ if (k >> bit) & 1 == 1:
++ if accumIsInfinity:
++ accum = jacobianPoint
++ accumIsInfinity = False
++ else:
++ accum = _pointAdd(accum, jacobianPoint)
++
++ if accumIsInfinity:
++ return (0, 0)
++
++ zInv = _modpow(accum[2], p - 2, p)
++ return ((accum[0] * zInv * zInv) % p, (accum[1] * zInv * zInv * zInv) % p)
++
++
++def _scalarBaseMult(k):
++ return _scalarMult(k, basePoint)
++
++
++def _decodeBigEndian(b):
++ return sum([ord(b[len(b) - i - 1]) << 8 * i for i in range(len(b))])
++
++
++def _encodeBigEndian(n):
++ b = []
++ while n != 0:
++ b.append(chr(n & 0xff))
++ n >>= 8
++
++ if len(b) == 0:
++ b.append(0)
++ b.reverse()
++
++ return "".join(b)
++
++
++def _zeroPad(b, length):
++ if len(b) < length:
++ return ("\x00" * (length - len(b))) + b
++ return b
++
++
++def _encodePoint(point):
++ x = point[0]
++ y = point[1]
++ if (y * y) % p != (x * x * x - 3 * x + p256B) % p:
++ raise "point not on curve"
++ return "\x04" + _zeroPad(_encodeBigEndian(point[0]), 32) + _zeroPad(
++ _encodeBigEndian(point[1]), 32)
++
++
++def _decodePoint(b):
++ if len(b) != 1 + 32 + 32 or ord(b[0]) != 4:
++ raise "invalid encoded ec point"
++ x = _decodeBigEndian(b[1:33])
++ y = _decodeBigEndian(b[33:65])
++ if (y * y) % p != (x * x * x - 3 * x + p256B) % p:
++ raise "point not on curve"
++ return (x, y)
++
++
++def generatePublicPrivate():
++ """generatePublicPrivate returns a tuple of (X9.62 encoded public point,
++ private value), where the private value is generated from os.urandom."""
++ private = _decodeBigEndian(os.urandom(40)) % order
++ return _encodePoint(_scalarBaseMult(private)), private
++
++
++def generateSharedValue(theirPublic, private):
++ """generateSharedValue returns the encoded x-coordinate of the
++ multiplication of a peer's X9.62 encoded point and a private value."""
++ return _zeroPad(
++ _encodeBigEndian(_scalarMult(private, _decodePoint(theirPublic))[0]),
++ 32)
++
++if __name__ == "__main__":
++ alice, alicePrivate = generatePublicPrivate()
++ bob, bobPrivate = generatePublicPrivate()
++
++ if generateSharedValue(alice, bobPrivate) != generateSharedValue(
++ bob, alicePrivate):
++ raise "simple DH test failed"
++
++ (x, _) = _scalarBaseMult(1)
++
++ for i in range(1000):
++ (x, _) = _scalarBaseMult(x)
++
++ if x != 2428281965257598569040586318034812501729437946720808289049534492833635302706:
++ raise "loop test failed"
diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlslite/constants.py
index e5b88af..6d78a20 100644
--- a/third_party/tlslite/tlslite/constants.py
+++ b/third_party/tlslite/tlslite/constants.py
@@ -76,6 +76,14 @@ class SignatureAlgorithm:
class NameType:
host_name = 0
+class ECCurveType:
+ explicit_prime = 1
+ explicit_char2 = 2
+ named_curve = 3
+
+class NamedCurve:
+ secp256r1 = 23
+
class AlertLevel:
warning = 1
fatal = 2
@@ -178,11 +186,19 @@ class CipherSuite:
TLS_RSA_WITH_AES_128_GCM_SHA256 = 0x009C
TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 = 0x009E
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA = 0xc011
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA = 0xc012
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA = 0xc013
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA = 0xc014
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 = 0xc027
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 = 0xc02f
+
tripleDESSuites = []
tripleDESSuites.append(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA)
tripleDESSuites.append(TLS_SRP_SHA_RSA_WITH_3DES_EDE_CBC_SHA)
tripleDESSuites.append(TLS_RSA_WITH_3DES_EDE_CBC_SHA)
tripleDESSuites.append(TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA)
+ tripleDESSuites.append(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA)
aes128Suites = []
aes128Suites.append(TLS_SRP_SHA_WITH_AES_128_CBC_SHA)
@@ -192,6 +208,8 @@ class CipherSuite:
aes128Suites.append(TLS_DH_ANON_WITH_AES_128_CBC_SHA)
aes128Suites.append(TLS_RSA_WITH_AES_128_CBC_SHA256)
aes128Suites.append(TLS_DHE_RSA_WITH_AES_128_CBC_SHA256)
+ aes128Suites.append(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
+ aes128Suites.append(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256)
aes256Suites = []
aes256Suites.append(TLS_SRP_SHA_WITH_AES_256_CBC_SHA)
@@ -201,14 +219,17 @@ class CipherSuite:
aes256Suites.append(TLS_DHE_RSA_WITH_AES_256_CBC_SHA)
aes256Suites.append(TLS_RSA_WITH_AES_256_CBC_SHA256)
aes256Suites.append(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256)
+ aes256Suites.append(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
aes128GcmSuites = []
aes128GcmSuites.append(TLS_RSA_WITH_AES_128_GCM_SHA256)
aes128GcmSuites.append(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256)
+ aes128GcmSuites.append(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
rc4Suites = []
rc4Suites.append(TLS_RSA_WITH_RC4_128_SHA)
rc4Suites.append(TLS_RSA_WITH_RC4_128_MD5)
+ rc4Suites.append(TLS_ECDHE_RSA_WITH_RC4_128_SHA)
shaSuites = []
shaSuites.append(TLS_SRP_SHA_WITH_3DES_EDE_CBC_SHA)
@@ -226,6 +247,10 @@ class CipherSuite:
shaSuites.append(TLS_DHE_RSA_WITH_AES_256_CBC_SHA)
shaSuites.append(TLS_DH_ANON_WITH_AES_128_CBC_SHA)
shaSuites.append(TLS_DH_ANON_WITH_AES_256_CBC_SHA)
+ shaSuites.append(TLS_ECDHE_RSA_WITH_RC4_128_SHA)
+ shaSuites.append(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA)
+ shaSuites.append(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
+ shaSuites.append(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
sha256Suites = []
sha256Suites.append(TLS_RSA_WITH_AES_128_CBC_SHA256)
@@ -234,6 +259,9 @@ class CipherSuite:
sha256Suites.append(TLS_DHE_RSA_WITH_AES_256_CBC_SHA256)
sha256Suites.append(TLS_RSA_WITH_AES_128_GCM_SHA256)
sha256Suites.append(TLS_DHE_RSA_WITH_AES_128_GCM_SHA256)
+ sha256Suites.append(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256)
+ sha256Suites.append(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
+
aeadSuites = aes128GcmSuites
@@ -275,6 +303,8 @@ class CipherSuite:
keyExchangeSuites += CipherSuite.certSuites
if "dhe_rsa" in keyExchangeNames:
keyExchangeSuites += CipherSuite.dheCertSuites
+ if "ecdhe_rsa" in keyExchangeNames:
+ keyExchangeSuites += CipherSuite.ecdheCertSuites
if "srp_sha" in keyExchangeNames:
keyExchangeSuites += CipherSuite.srpSuites
if "srp_sha_rsa" in keyExchangeNames:
@@ -335,7 +365,19 @@ class CipherSuite:
def getDheCertSuites(settings, version=None):
return CipherSuite._filterSuites(CipherSuite.dheCertSuites, settings, version)
- certAllSuites = srpCertSuites + certSuites + dheCertSuites
+ ecdheCertSuites = []
+ ecdheCertSuites.append(TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256)
+ ecdheCertSuites.append(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256)
+ ecdheCertSuites.append(TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA)
+ ecdheCertSuites.append(TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA)
+ ecdheCertSuites.append(TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA)
+ ecdheCertSuites.append(TLS_ECDHE_RSA_WITH_RC4_128_SHA)
+
+ @staticmethod
+ def getEcdheCertSuites(settings, version=None):
+ return CipherSuite._filterSuites(CipherSuite.ecdheCertSuites, settings, version)
+
+ certAllSuites = srpCertSuites + certSuites + dheCertSuites + ecdheCertSuites
anonSuites = []
anonSuites.append(TLS_DH_ANON_WITH_AES_256_CBC_SHA)
@@ -346,6 +388,7 @@ class CipherSuite:
return CipherSuite._filterSuites(CipherSuite.anonSuites, settings, version)
dhAllSuites = dheCertSuites + anonSuites
+ ecdhAllSuites = ecdheCertSuites
@staticmethod
def canonicalCipherName(ciphersuite):
diff --git a/third_party/tlslite/tlslite/handshakesettings.py b/third_party/tlslite/tlslite/handshakesettings.py
index e752834..605ed42 100644
--- a/third_party/tlslite/tlslite/handshakesettings.py
+++ b/third_party/tlslite/tlslite/handshakesettings.py
@@ -14,7 +14,7 @@ from .utils import cipherfactory
CIPHER_NAMES = ["aes128gcm", "rc4", "aes256", "aes128", "3des"]
MAC_NAMES = ["sha", "sha256", "aead"] # Don't allow "md5" by default.
ALL_MAC_NAMES = MAC_NAMES + ["md5"]
-KEY_EXCHANGE_NAMES = ["rsa", "dhe_rsa", "srp_sha", "srp_sha_rsa", "dh_anon"]
+KEY_EXCHANGE_NAMES = ["rsa", "dhe_rsa", "ecdhe_rsa", "srp_sha", "srp_sha_rsa", "dh_anon"]
CIPHER_IMPLEMENTATIONS = ["openssl", "pycrypto", "python"]
CERTIFICATE_TYPES = ["x509"]
TLS_INTOLERANCE_TYPES = ["alert", "close", "reset"]
diff --git a/third_party/tlslite/tlslite/messages.py b/third_party/tlslite/tlslite/messages.py
index f2e2cfc..9aeff6d 100644
--- a/third_party/tlslite/tlslite/messages.py
+++ b/third_party/tlslite/tlslite/messages.py
@@ -509,10 +509,13 @@ class ServerKeyExchange(HandshakeMsg):
self.srp_g = 0
self.srp_s = bytearray(0)
self.srp_B = 0
- # Anon DH params:
+ # DH params:
self.dh_p = 0
self.dh_g = 0
self.dh_Ys = 0
+ # ECDH params:
+ self.ecdhCurve = 0
+ self.ecdhPublic = bytearray(0)
self.signature = bytearray(0)
def createSRP(self, srp_N, srp_g, srp_s, srp_B):
@@ -528,6 +531,11 @@ class ServerKeyExchange(HandshakeMsg):
self.dh_Ys = dh_Ys
return self
+ def createECDH(self, ecdhCurve, ecdhPublic):
+ self.ecdhCurve = ecdhCurve
+ self.ecdhPublic = ecdhPublic
+ return self
+
def parse(self, p):
p.startLengthCheck(3)
if self.cipherSuite in CipherSuite.srpAllSuites:
@@ -555,6 +563,10 @@ class ServerKeyExchange(HandshakeMsg):
w.addVarSeq(numberToByteArray(self.dh_p), 1, 2)
w.addVarSeq(numberToByteArray(self.dh_g), 1, 2)
w.addVarSeq(numberToByteArray(self.dh_Ys), 1, 2)
+ elif self.cipherSuite in CipherSuite.ecdhAllSuites:
+ w.add(ECCurveType.named_curve, 1)
+ w.add(self.ecdhCurve, 2)
+ w.addVarSeq(self.ecdhPublic, 1, 1)
else:
assert(False)
return w.bytes
@@ -626,7 +638,9 @@ class ClientKeyExchange(HandshakeMsg):
else:
raise AssertionError()
elif self.cipherSuite in CipherSuite.dhAllSuites:
- self.dh_Yc = bytesToNumber(p.getVarBytes(2))
+ self.dh_Yc = bytesToNumber(p.getVarBytes(2))
+ elif self.cipherSuite in CipherSuite.ecdhAllSuites:
+ self.ecdh_Yc = p.getVarBytes(1)
else:
raise AssertionError()
p.stopLengthCheck()
diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py
index 0a85d3c..dfac274 100644
--- a/third_party/tlslite/tlslite/tlsconnection.py
+++ b/third_party/tlslite/tlslite/tlsconnection.py
@@ -24,6 +24,7 @@ from .mathtls import *
from .handshakesettings import HandshakeSettings
from .utils.tackwrapper import *
from .utils.rsakey import RSAKey
+from .utils import p256
class KeyExchange(object):
def __init__(self, cipherSuite, clientHello, serverHello, privateKey):
@@ -127,6 +128,25 @@ DE2BCBF6 95581718 3995497C EA956AE5 15D22618 98FA0510
S = powMod(dh_Yc, self.dh_Xs, self.dh_p)
return numberToByteArray(S)
+class ECDHE_RSAKeyExchange(KeyExchange):
+ def makeServerKeyExchange(self):
+ public, self.private = p256.generatePublicPrivate()
+
+ version = self.serverHello.server_version
+ serverKeyExchange = ServerKeyExchange(self.cipherSuite, version)
+ serverKeyExchange.createECDH(NamedCurve.secp256r1, bytearray(public))
+ hashBytes = serverKeyExchange.hash(self.clientHello.random,
+ self.serverHello.random)
+ if version >= (3,3):
+ # TODO: Signature algorithm negotiation not supported.
+ hashBytes = RSAKey.addPKCS1SHA1Prefix(hashBytes)
+ serverKeyExchange.signature = self.privateKey.sign(hashBytes)
+ return serverKeyExchange
+
+ def processClientKeyExchange(self, clientKeyExchange):
+ ecdh_Yc = clientKeyExchange.ecdh_Yc
+ return bytearray(p256.generateSharedValue(bytes(ecdh_Yc), self.private))
+
class TLSConnection(TLSRecordLayer):
"""
This class wraps a socket and provides TLS handshaking and data
@@ -1321,9 +1341,8 @@ class TLSConnection(TLSRecordLayer):
else: break
premasterSecret = result
- # Perform the RSA or DHE_RSA key exchange
- elif (cipherSuite in CipherSuite.certSuites or
- cipherSuite in CipherSuite.dheCertSuites):
+ # Perform a certificate-based key exchange
+ elif cipherSuite in CipherSuite.certAllSuites:
if cipherSuite in CipherSuite.certSuites:
keyExchange = RSAKeyExchange(cipherSuite,
clientHello,
@@ -1334,6 +1353,11 @@ class TLSConnection(TLSRecordLayer):
clientHello,
serverHello,
privateKey)
+ elif cipherSuite in CipherSuite.ecdheCertSuites:
+ keyExchange = ECDHE_RSAKeyExchange(cipherSuite,
+ clientHello,
+ serverHello,
+ privateKey)
else:
assert(False)
for result in self._serverCertKeyExchange(clientHello, serverHello,
@@ -1450,6 +1474,7 @@ class TLSConnection(TLSRecordLayer):
CipherSuite.getSrpCertSuites(settings, self.version)
cipherSuites += CipherSuite.getSrpSuites(settings, self.version)
elif certChain:
+ cipherSuites += CipherSuite.getEcdheCertSuites(settings, self.version)
cipherSuites += CipherSuite.getDheCertSuites(settings, self.version)
cipherSuites += CipherSuite.getCertSuites(settings, self.version)
elif anon:
diff --git a/third_party/tlslite/tlslite/utils/p256.py b/third_party/tlslite/tlslite/utils/p256.py
new file mode 100644
index 0000000..6eb9a77
--- /dev/null
+++ b/third_party/tlslite/tlslite/utils/p256.py
@@ -0,0 +1,162 @@
+# Author: Google
+# See the LICENSE file for legal information regarding use of this file.
+
+import os
+
+p = (
+ 115792089210356248762697446949407573530086143415290314195533631308867097853951)
+order = (
+ 115792089210356248762697446949407573529996955224135760342422259061068512044369)
+p256B = 0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b
+
+baseX = 0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296
+baseY = 0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5
+basePoint = (baseX, baseY)
+
+
+def _pointAdd(a, b):
+ Z1Z1 = (a[2] * a[2]) % p
+ Z2Z2 = (b[2] * b[2]) % p
+ U1 = (a[0] * Z2Z2) % p
+ U2 = (b[0] * Z1Z1) % p
+ S1 = (a[1] * b[2] * Z2Z2) % p
+ S2 = (b[1] * a[2] * Z1Z1) % p
+ if U1 == U2 and S1 == S2:
+ return pointDouble(a)
+ H = (U2 - U1) % p
+ I = (4 * H * H) % p
+ J = (H * I) % p
+ r = (2 * (S2 - S1)) % p
+ V = (U1 * I) % p
+ X3 = (r * r - J - 2 * V) % p
+ Y3 = (r * (V - X3) - 2 * S1 * J) % p
+ Z3 = (((a[2] + b[2]) * (a[2] + b[2]) - Z1Z1 - Z2Z2) * H) % p
+
+ return (X3, Y3, Z3)
+
+
+def _pointDouble(a):
+ delta = (a[2] * a[2]) % p
+ gamma = (a[1] * a[1]) % p
+ beta = (a[0] * gamma) % p
+ alpha = (3 * (a[0] - delta) * (a[0] + delta)) % p
+ X3 = (alpha * alpha - 8 * beta) % p
+ Z3 = ((a[1] + a[2]) * (a[1] + a[2]) - gamma - delta) % p
+ Y3 = (alpha * (4 * beta - X3) - 8 * gamma * gamma) % p
+
+ return (X3, Y3, Z3)
+
+
+def _square(n):
+ return (n * n)
+
+
+def _modpow(a, n, p):
+ if n == 0:
+ return 1
+ if n == 1:
+ return a
+ r = _square(_modpow(a, n >> 1, p)) % p
+ if n & 1 == 1:
+ r = (r * a) % p
+ return r
+
+
+def _scalarMult(k, point):
+ accum = (0, 0, 0)
+ accumIsInfinity = True
+ jacobianPoint = (point[0], point[1], 1)
+
+ for bit in range(255, -1, -1):
+ if not accumIsInfinity:
+ accum = _pointDouble(accum)
+
+ if (k >> bit) & 1 == 1:
+ if accumIsInfinity:
+ accum = jacobianPoint
+ accumIsInfinity = False
+ else:
+ accum = _pointAdd(accum, jacobianPoint)
+
+ if accumIsInfinity:
+ return (0, 0)
+
+ zInv = _modpow(accum[2], p - 2, p)
+ return ((accum[0] * zInv * zInv) % p, (accum[1] * zInv * zInv * zInv) % p)
+
+
+def _scalarBaseMult(k):
+ return _scalarMult(k, basePoint)
+
+
+def _decodeBigEndian(b):
+ return sum([ord(b[len(b) - i - 1]) << 8 * i for i in range(len(b))])
+
+
+def _encodeBigEndian(n):
+ b = []
+ while n != 0:
+ b.append(chr(n & 0xff))
+ n >>= 8
+
+ if len(b) == 0:
+ b.append(0)
+ b.reverse()
+
+ return "".join(b)
+
+
+def _zeroPad(b, length):
+ if len(b) < length:
+ return ("\x00" * (length - len(b))) + b
+ return b
+
+
+def _encodePoint(point):
+ x = point[0]
+ y = point[1]
+ if (y * y) % p != (x * x * x - 3 * x + p256B) % p:
+ raise "point not on curve"
+ return "\x04" + _zeroPad(_encodeBigEndian(point[0]), 32) + _zeroPad(
+ _encodeBigEndian(point[1]), 32)
+
+
+def _decodePoint(b):
+ if len(b) != 1 + 32 + 32 or ord(b[0]) != 4:
+ raise "invalid encoded ec point"
+ x = _decodeBigEndian(b[1:33])
+ y = _decodeBigEndian(b[33:65])
+ if (y * y) % p != (x * x * x - 3 * x + p256B) % p:
+ raise "point not on curve"
+ return (x, y)
+
+
+def generatePublicPrivate():
+ """generatePublicPrivate returns a tuple of (X9.62 encoded public point,
+ private value), where the private value is generated from os.urandom."""
+ private = _decodeBigEndian(os.urandom(40)) % order
+ return _encodePoint(_scalarBaseMult(private)), private
+
+
+def generateSharedValue(theirPublic, private):
+ """generateSharedValue returns the encoded x-coordinate of the
+ multiplication of a peer's X9.62 encoded point and a private value."""
+ return _zeroPad(
+ _encodeBigEndian(_scalarMult(private, _decodePoint(theirPublic))[0]),
+ 32)
+
+if __name__ == "__main__":
+ alice, alicePrivate = generatePublicPrivate()
+ bob, bobPrivate = generatePublicPrivate()
+
+ if generateSharedValue(alice, bobPrivate) != generateSharedValue(
+ bob, alicePrivate):
+ raise "simple DH test failed"
+
+ (x, _) = _scalarBaseMult(1)
+
+ for i in range(1000):
+ (x, _) = _scalarBaseMult(x)
+
+ if x != 2428281965257598569040586318034812501729437946720808289049534492833635302706:
+ raise "loop test failed"