Reland 'Require ECDHE for False Start.'

This is a reland of https://codereview.chromium.org/1057733002. It rolls
BoringSSL slightly further than previously to fix a Windows build issue.

This adds just enough of an implementation of ECDHE_RSA to tlslite to
support it on the server side.

It also rolls BoringSSL e2e1326..40acdae to pick up the corresponding
BoringSSL change. Summary of changes available at:

https://boringssl.googlesource.com/boringssl/+log/e2e1326..40acdae

BUG=460271
TBR=rsleevi@chromium.org,agl@chromium.org

Review URL: https://codereview.chromium.org/1056153002

Cr-Original-Commit-Position: refs/heads/master@{#323780}
Cr-Mirrored-From: https://chromium.googlesource.com/chromium/src
Cr-Mirrored-Commit: 1f77e1a27417e217dfe0bb1d424f19e2272b47c3
diff --git a/README.chromium b/README.chromium
index c2084cd..4468a08 100644
--- a/README.chromium
+++ b/README.chromium
@@ -24,7 +24,7 @@
 - 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 @@
   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/patches/ecdhe_rsa.patch b/patches/ecdhe_rsa.patch
new file mode 100644
index 0000000..054a07a
--- /dev/null
+++ b/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/tlslite/constants.py b/tlslite/constants.py
index e5b88af..6d78a20 100644
--- a/tlslite/constants.py
+++ b/tlslite/constants.py
@@ -76,6 +76,14 @@
 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 @@
     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 @@
     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 @@
     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 @@
     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 @@
     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 @@
             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 @@
     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 @@
         return CipherSuite._filterSuites(CipherSuite.anonSuites, settings, version)
 
     dhAllSuites = dheCertSuites + anonSuites
+    ecdhAllSuites = ecdheCertSuites
 
     @staticmethod
     def canonicalCipherName(ciphersuite):
diff --git a/tlslite/handshakesettings.py b/tlslite/handshakesettings.py
index e752834..605ed42 100644
--- a/tlslite/handshakesettings.py
+++ b/tlslite/handshakesettings.py
@@ -14,7 +14,7 @@
 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/tlslite/messages.py b/tlslite/messages.py
index f2e2cfc..9aeff6d 100644
--- a/tlslite/messages.py
+++ b/tlslite/messages.py
@@ -509,10 +509,13 @@
         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 @@
         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 @@
             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 @@
             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/tlslite/tlsconnection.py b/tlslite/tlsconnection.py
index 0a85d3c..dfac274 100644
--- a/tlslite/tlsconnection.py
+++ b/tlslite/tlsconnection.py
@@ -24,6 +24,7 @@
 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 @@
         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 @@
                 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 @@
                                                  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 @@
                     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/tlslite/utils/p256.py b/tlslite/utils/p256.py
new file mode 100644
index 0000000..6eb9a77
--- /dev/null
+++ b/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"