Port SpawnedTestServer to Python 3
Porting tlslite was more straightforward than it seemed, probably
because they already internally used bytearray everywhere, rather
than str.
One complication is getting a copy of Python 3 onto one of the
CrOS builders. It runs out of space if we ship both Python 2
and Python 3, so I've switched it to only Python 3. This requires
disabling one test, but that test only exists to test Python 2
works.
https://groups.google.com/a/chromium.org/g/python/c/KK60bQcwoCw/m/VctNoDYHCAAJ
We probably should remove GetPythonCommand from //net, since we
don't use it anymore. There's some code in //chrome/browser/media.
But that will take a bit more work to disentangle, so leave it
alone for this CL.
Bug: 1248530
Change-Id: I16b6d077648a436f0f2b42194b19d3104d198614
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/3156548
Reviewed-by: Ryan Sleevi <rsleevi@chromium.org>
Reviewed-by: Amr Aboelkher <amraboelkher@chromium.org>
Reviewed-by: Dirk Pranke <dpranke@google.com>
Reviewed-by: Pavol Marko <pmarko@chromium.org>
Reviewed-by: Ben Pastene <bpastene@chromium.org>
Commit-Queue: David Benjamin <davidben@chromium.org>
Cr-Commit-Position: refs/heads/main@{#922697}
NOKEYCHECK=True
GitOrigin-RevId: 5af020cfe8e17f1d24ce85ee6585d79df0664c6f
diff --git a/README.chromium b/README.chromium
index b189e12..1cd7d32 100644
--- a/README.chromium
+++ b/README.chromium
@@ -64,3 +64,4 @@
inspired by tlslite-ng implementation.
- patches/signature_algorithms.patch: Add basic signature algorithms
negotiation.
+- patches/python3.patch: Fix with Python 3.
diff --git a/patches/python3.patch b/patches/python3.patch
new file mode 100644
index 0000000..12cffa1
--- /dev/null
+++ b/patches/python3.patch
@@ -0,0 +1,272 @@
+diff --git a/third_party/tlslite/tlslite/integration/asyncstatemachine.py b/third_party/tlslite/tlslite/integration/asyncstatemachine.py
+index 50a6f4a355c14..9faf84f966a31 100644
+--- a/third_party/tlslite/tlslite/integration/asyncstatemachine.py
++++ b/third_party/tlslite/tlslite/integration/asyncstatemachine.py
+@@ -192,7 +192,7 @@ class AsyncStateMachine:
+ @type handshaker: generator
+ @param handshaker: A generator created by using one of the
+ asynchronous handshake functions (i.e. handshakeServerAsync, or
+- handshakeClientxxx(..., async=True).
++ handshakeClientxxx(..., is_async=True).
+ """
+ try:
+ self._checkAssert(0)
+diff --git a/third_party/tlslite/tlslite/messages.py b/third_party/tlslite/tlslite/messages.py
+index ce4f1a6e15eb2..5df50d34cd3ad 100644
+--- a/third_party/tlslite/tlslite/messages.py
++++ b/third_party/tlslite/tlslite/messages.py
+@@ -9,6 +9,8 @@
+
+ """Classes representing TLS messages."""
+
++from __future__ import division
++
+ from .utils.compat import *
+ from .utils.cryptomath import *
+ from .errors import *
+@@ -262,7 +264,7 @@ class ClientHello(HandshakeMsg):
+ numBytes = p.get(2)
+ if numBytes + 2 != extLength or numBytes % 2 != 0:
+ raise SyntaxError()
+- for _ in range(numBytes / 2):
++ for _ in range(numBytes // 2):
+ hashAlg = p.get(1)
+ sigAlg = p.get(1)
+ self.signature_algorithms.append((hashAlg, sigAlg))
+diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py
+index 6d7c859884a41..f64c848a511c0 100644
+--- a/third_party/tlslite/tlslite/tlsconnection.py
++++ b/third_party/tlslite/tlslite/tlsconnection.py
+@@ -202,7 +202,7 @@ class TLSConnection(TLSRecordLayer):
+
+ def handshakeClientAnonymous(self, session=None, settings=None,
+ checker=None, serverName="",
+- async=False):
++ is_async=False):
+ """Perform an anonymous handshake in the role of client.
+
+ This function performs an SSL or TLS handshake using an
+@@ -236,8 +236,8 @@ class TLSConnection(TLSRecordLayer):
+ @type serverName: string
+ @param serverName: The ServerNameIndication TLS Extension.
+
+- @type async: bool
+- @param async: If False, this function will block until the
++ @type is_async: bool
++ @param is_async: If False, this function will block until the
+ handshake is completed. If True, this function will return a
+ generator. Successive invocations of the generator will
+ return 0 if it is waiting to read from the socket, 1 if it is
+@@ -245,7 +245,7 @@ class TLSConnection(TLSRecordLayer):
+ the handshake operation is completed.
+
+ @rtype: None or an iterable
+- @return: If 'async' is True, a generator object will be
++ @return: If 'is_async' is True, a generator object will be
+ returned.
+
+ @raise socket.error: If a socket error occurs.
+@@ -260,7 +260,7 @@ class TLSConnection(TLSRecordLayer):
+ settings=settings,
+ checker=checker,
+ serverName=serverName)
+- if async:
++ if is_async:
+ return handshaker
+ for result in handshaker:
+ pass
+@@ -268,7 +268,7 @@ class TLSConnection(TLSRecordLayer):
+ def handshakeClientSRP(self, username, password, session=None,
+ settings=None, checker=None,
+ reqTack=True, serverName="",
+- async=False):
++ is_async=False):
+ """Perform an SRP handshake in the role of client.
+
+ This function performs a TLS/SRP handshake. SRP mutually
+@@ -313,8 +313,8 @@ class TLSConnection(TLSRecordLayer):
+ @type serverName: string
+ @param serverName: The ServerNameIndication TLS Extension.
+
+- @type async: bool
+- @param async: If False, this function will block until the
++ @type is_async: bool
++ @param is_async: If False, this function will block until the
+ handshake is completed. If True, this function will return a
+ generator. Successive invocations of the generator will
+ return 0 if it is waiting to read from the socket, 1 if it is
+@@ -322,7 +322,7 @@ class TLSConnection(TLSRecordLayer):
+ the handshake operation is completed.
+
+ @rtype: None or an iterable
+- @return: If 'async' is True, a generator object will be
++ @return: If 'is_async' is True, a generator object will be
+ returned.
+
+ @raise socket.error: If a socket error occurs.
+@@ -340,9 +340,9 @@ class TLSConnection(TLSRecordLayer):
+ # fashion, returning 1 when it is waiting to able to write, 0 when
+ # it is waiting to read.
+ #
+- # If 'async' is True, the generator is returned to the caller,
+- # otherwise it is executed to completion here.
+- if async:
++ # If 'is_async' is True, the generator is returned to the caller,
++ # otherwise it is executed to completion here.
++ if is_async:
+ return handshaker
+ for result in handshaker:
+ pass
+@@ -350,7 +350,7 @@ class TLSConnection(TLSRecordLayer):
+ def handshakeClientCert(self, certChain=None, privateKey=None,
+ session=None, settings=None, checker=None,
+ nextProtos=None, reqTack=True, serverName="",
+- async=False):
++ is_async=False):
+ """Perform a certificate-based handshake in the role of client.
+
+ This function performs an SSL or TLS handshake. The server
+@@ -407,8 +407,8 @@ class TLSConnection(TLSRecordLayer):
+ @type serverName: string
+ @param serverName: The ServerNameIndication TLS Extension.
+
+- @type async: bool
+- @param async: If False, this function will block until the
++ @type is_async: bool
++ @param is_async: If False, this function will block until the
+ handshake is completed. If True, this function will return a
+ generator. Successive invocations of the generator will
+ return 0 if it is waiting to read from the socket, 1 if it is
+@@ -416,7 +416,7 @@ class TLSConnection(TLSRecordLayer):
+ the handshake operation is completed.
+
+ @rtype: None or an iterable
+- @return: If 'async' is True, a generator object will be
++ @return: If 'is_async' is True, a generator object will be
+ returned.
+
+ @raise socket.error: If a socket error occurs.
+@@ -435,9 +435,9 @@ class TLSConnection(TLSRecordLayer):
+ # fashion, returning 1 when it is waiting to able to write, 0 when
+ # it is waiting to read.
+ #
+- # If 'async' is True, the generator is returned to the caller,
+- # otherwise it is executed to completion here.
+- if async:
++ # If 'is_async' is True, the generator is returned to the caller,
++ # otherwise it is executed to completion here.
++ if is_async:
+ return handshaker
+ for result in handshaker:
+ pass
+@@ -1368,10 +1368,10 @@ class TLSConnection(TLSRecordLayer):
+ # See https://tools.ietf.org/html/rfc8446#section-4.1.3
+ if settings.simulateTLS13Downgrade:
+ serverRandom = serverRandom[:24] + \
+- bytearray("\x44\x4f\x57\x4e\x47\x52\x44\x01")
++ bytearray(b"\x44\x4f\x57\x4e\x47\x52\x44\x01")
+ elif settings.simulateTLS12Downgrade:
+ serverRandom = serverRandom[:24] + \
+- bytearray("\x44\x4f\x57\x4e\x47\x52\x44\x00")
++ bytearray(b"\x44\x4f\x57\x4e\x47\x52\x44\x00")
+ serverHello = ServerHello()
+ serverHello.create(self.version, serverRandom, sessionID, \
+ cipherSuite, CertificateType.x509, tackExt,
+diff --git a/third_party/tlslite/tlslite/utils/aesgcm.py b/third_party/tlslite/tlslite/utils/aesgcm.py
+index 7319c268536a3..c887f2f518e77 100644
+--- a/third_party/tlslite/tlslite/utils/aesgcm.py
++++ b/third_party/tlslite/tlslite/utils/aesgcm.py
+@@ -13,6 +13,8 @@
+ # x^127 term. This bit reversal also applies to polynomials used as indices in a
+ # look-up table.
+
++from __future__ import division
++
+ from .cryptomath import bytesToNumber, numberToByteArray
+
+ class AESGCM(object):
+@@ -47,7 +49,7 @@ class AESGCM(object):
+ self._productTable[_reverseBits(1)] = h
+ for i in range(2, 16, 2):
+ self._productTable[_reverseBits(i)] = \
+- _gcmShift(self._productTable[_reverseBits(i/2)])
++ _gcmShift(self._productTable[_reverseBits(i//2)])
+ self._productTable[_reverseBits(i+1)] = \
+ _gcmAdd(self._productTable[_reverseBits(i)], h)
+
+diff --git a/third_party/tlslite/tlslite/utils/p256.py b/third_party/tlslite/tlslite/utils/p256.py
+index 6eb9a7799accc..45159000fa499 100644
+--- a/third_party/tlslite/tlslite/utils/p256.py
++++ b/third_party/tlslite/tlslite/utils/p256.py
+@@ -2,6 +2,7 @@
+ # See the LICENSE file for legal information regarding use of this file.
+
+ import os
++import six
+
+ p = (
+ 115792089210356248762697446949407573530086143415290314195533631308867097853951)
+@@ -90,25 +91,27 @@ def _scalarBaseMult(k):
+
+
+ def _decodeBigEndian(b):
+- return sum([ord(b[len(b) - i - 1]) << 8 * i for i in range(len(b))])
++ # TODO(davidben): Replace with int.from_bytes when removing Python 2.
++ return sum([six.indexbytes(b, len(b) - i - 1) << 8 * i
++ for i in range(len(b))])
+
+
+ def _encodeBigEndian(n):
+- b = []
++ b = bytearray()
+ while n != 0:
+- b.append(chr(n & 0xff))
++ b.append(n & 0xff)
+ n >>= 8
+
+ if len(b) == 0:
+ b.append(0)
+ b.reverse()
+
+- return "".join(b)
++ return bytes(b)
+
+
+ def _zeroPad(b, length):
+ if len(b) < length:
+- return ("\x00" * (length - len(b))) + b
++ return (b"\x00" * (length - len(b))) + b
+ return b
+
+
+@@ -117,12 +120,12 @@ def _encodePoint(point):
+ 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(
++ return b"\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:
++ if len(b) != 1 + 32 + 32 or six.indexbytes(b, 0) != 4:
+ raise "invalid encoded ec point"
+ x = _decodeBigEndian(b[1:33])
+ y = _decodeBigEndian(b[33:65])
+diff --git a/third_party/tlslite/tlslite/utils/pycrypto_rsakey.py b/third_party/tlslite/tlslite/utils/pycrypto_rsakey.py
+index d76ea2d1b13a6..453785664565c 100644
+--- a/third_party/tlslite/tlslite/utils/pycrypto_rsakey.py
++++ b/third_party/tlslite/tlslite/utils/pycrypto_rsakey.py
+@@ -15,9 +15,9 @@ if pycryptoLoaded:
+ class PyCrypto_RSAKey(RSAKey):
+ def __init__(self, n=0, e=0, d=0, p=0, q=0, dP=0, dQ=0, qInv=0):
+ if not d:
+- self.rsa = RSA.construct( (long(n), long(e)) )
++ self.rsa = RSA.construct( (n, e) )
+ else:
+- self.rsa = RSA.construct( (long(n), long(e), long(d), long(p), long(q)) )
++ self.rsa = RSA.construct( (n, e, d, p, q) )
+
+ def __getattr__(self, name):
+ return getattr(self.rsa, name)
diff --git a/tlslite/integration/asyncstatemachine.py b/tlslite/integration/asyncstatemachine.py
index 50a6f4a..9faf84f 100644
--- a/tlslite/integration/asyncstatemachine.py
+++ b/tlslite/integration/asyncstatemachine.py
@@ -192,7 +192,7 @@
@type handshaker: generator
@param handshaker: A generator created by using one of the
asynchronous handshake functions (i.e. handshakeServerAsync, or
- handshakeClientxxx(..., async=True).
+ handshakeClientxxx(..., is_async=True).
"""
try:
self._checkAssert(0)
diff --git a/tlslite/messages.py b/tlslite/messages.py
index ce4f1a6..5df50d3 100644
--- a/tlslite/messages.py
+++ b/tlslite/messages.py
@@ -9,6 +9,8 @@
"""Classes representing TLS messages."""
+from __future__ import division
+
from .utils.compat import *
from .utils.cryptomath import *
from .errors import *
@@ -262,7 +264,7 @@
numBytes = p.get(2)
if numBytes + 2 != extLength or numBytes % 2 != 0:
raise SyntaxError()
- for _ in range(numBytes / 2):
+ for _ in range(numBytes // 2):
hashAlg = p.get(1)
sigAlg = p.get(1)
self.signature_algorithms.append((hashAlg, sigAlg))
diff --git a/tlslite/tlsconnection.py b/tlslite/tlsconnection.py
index 6d7c859..f64c848 100644
--- a/tlslite/tlsconnection.py
+++ b/tlslite/tlsconnection.py
@@ -202,7 +202,7 @@
def handshakeClientAnonymous(self, session=None, settings=None,
checker=None, serverName="",
- async=False):
+ is_async=False):
"""Perform an anonymous handshake in the role of client.
This function performs an SSL or TLS handshake using an
@@ -236,8 +236,8 @@
@type serverName: string
@param serverName: The ServerNameIndication TLS Extension.
- @type async: bool
- @param async: If False, this function will block until the
+ @type is_async: bool
+ @param is_async: If False, this function will block until the
handshake is completed. If True, this function will return a
generator. Successive invocations of the generator will
return 0 if it is waiting to read from the socket, 1 if it is
@@ -245,7 +245,7 @@
the handshake operation is completed.
@rtype: None or an iterable
- @return: If 'async' is True, a generator object will be
+ @return: If 'is_async' is True, a generator object will be
returned.
@raise socket.error: If a socket error occurs.
@@ -260,7 +260,7 @@
settings=settings,
checker=checker,
serverName=serverName)
- if async:
+ if is_async:
return handshaker
for result in handshaker:
pass
@@ -268,7 +268,7 @@
def handshakeClientSRP(self, username, password, session=None,
settings=None, checker=None,
reqTack=True, serverName="",
- async=False):
+ is_async=False):
"""Perform an SRP handshake in the role of client.
This function performs a TLS/SRP handshake. SRP mutually
@@ -313,8 +313,8 @@
@type serverName: string
@param serverName: The ServerNameIndication TLS Extension.
- @type async: bool
- @param async: If False, this function will block until the
+ @type is_async: bool
+ @param is_async: If False, this function will block until the
handshake is completed. If True, this function will return a
generator. Successive invocations of the generator will
return 0 if it is waiting to read from the socket, 1 if it is
@@ -322,7 +322,7 @@
the handshake operation is completed.
@rtype: None or an iterable
- @return: If 'async' is True, a generator object will be
+ @return: If 'is_async' is True, a generator object will be
returned.
@raise socket.error: If a socket error occurs.
@@ -340,9 +340,9 @@
# fashion, returning 1 when it is waiting to able to write, 0 when
# it is waiting to read.
#
- # If 'async' is True, the generator is returned to the caller,
- # otherwise it is executed to completion here.
- if async:
+ # If 'is_async' is True, the generator is returned to the caller,
+ # otherwise it is executed to completion here.
+ if is_async:
return handshaker
for result in handshaker:
pass
@@ -350,7 +350,7 @@
def handshakeClientCert(self, certChain=None, privateKey=None,
session=None, settings=None, checker=None,
nextProtos=None, reqTack=True, serverName="",
- async=False):
+ is_async=False):
"""Perform a certificate-based handshake in the role of client.
This function performs an SSL or TLS handshake. The server
@@ -407,8 +407,8 @@
@type serverName: string
@param serverName: The ServerNameIndication TLS Extension.
- @type async: bool
- @param async: If False, this function will block until the
+ @type is_async: bool
+ @param is_async: If False, this function will block until the
handshake is completed. If True, this function will return a
generator. Successive invocations of the generator will
return 0 if it is waiting to read from the socket, 1 if it is
@@ -416,7 +416,7 @@
the handshake operation is completed.
@rtype: None or an iterable
- @return: If 'async' is True, a generator object will be
+ @return: If 'is_async' is True, a generator object will be
returned.
@raise socket.error: If a socket error occurs.
@@ -435,9 +435,9 @@
# fashion, returning 1 when it is waiting to able to write, 0 when
# it is waiting to read.
#
- # If 'async' is True, the generator is returned to the caller,
- # otherwise it is executed to completion here.
- if async:
+ # If 'is_async' is True, the generator is returned to the caller,
+ # otherwise it is executed to completion here.
+ if is_async:
return handshaker
for result in handshaker:
pass
@@ -1368,10 +1368,10 @@
# See https://tools.ietf.org/html/rfc8446#section-4.1.3
if settings.simulateTLS13Downgrade:
serverRandom = serverRandom[:24] + \
- bytearray("\x44\x4f\x57\x4e\x47\x52\x44\x01")
+ bytearray(b"\x44\x4f\x57\x4e\x47\x52\x44\x01")
elif settings.simulateTLS12Downgrade:
serverRandom = serverRandom[:24] + \
- bytearray("\x44\x4f\x57\x4e\x47\x52\x44\x00")
+ bytearray(b"\x44\x4f\x57\x4e\x47\x52\x44\x00")
serverHello = ServerHello()
serverHello.create(self.version, serverRandom, sessionID, \
cipherSuite, CertificateType.x509, tackExt,
diff --git a/tlslite/utils/aesgcm.py b/tlslite/utils/aesgcm.py
index 7319c26..c887f2f 100644
--- a/tlslite/utils/aesgcm.py
+++ b/tlslite/utils/aesgcm.py
@@ -13,6 +13,8 @@
# x^127 term. This bit reversal also applies to polynomials used as indices in a
# look-up table.
+from __future__ import division
+
from .cryptomath import bytesToNumber, numberToByteArray
class AESGCM(object):
@@ -47,7 +49,7 @@
self._productTable[_reverseBits(1)] = h
for i in range(2, 16, 2):
self._productTable[_reverseBits(i)] = \
- _gcmShift(self._productTable[_reverseBits(i/2)])
+ _gcmShift(self._productTable[_reverseBits(i//2)])
self._productTable[_reverseBits(i+1)] = \
_gcmAdd(self._productTable[_reverseBits(i)], h)
diff --git a/tlslite/utils/p256.py b/tlslite/utils/p256.py
index 6eb9a77..4515900 100644
--- a/tlslite/utils/p256.py
+++ b/tlslite/utils/p256.py
@@ -2,6 +2,7 @@
# See the LICENSE file for legal information regarding use of this file.
import os
+import six
p = (
115792089210356248762697446949407573530086143415290314195533631308867097853951)
@@ -90,25 +91,27 @@
def _decodeBigEndian(b):
- return sum([ord(b[len(b) - i - 1]) << 8 * i for i in range(len(b))])
+ # TODO(davidben): Replace with int.from_bytes when removing Python 2.
+ return sum([six.indexbytes(b, len(b) - i - 1) << 8 * i
+ for i in range(len(b))])
def _encodeBigEndian(n):
- b = []
+ b = bytearray()
while n != 0:
- b.append(chr(n & 0xff))
+ b.append(n & 0xff)
n >>= 8
if len(b) == 0:
b.append(0)
b.reverse()
- return "".join(b)
+ return bytes(b)
def _zeroPad(b, length):
if len(b) < length:
- return ("\x00" * (length - len(b))) + b
+ return (b"\x00" * (length - len(b))) + b
return b
@@ -117,12 +120,12 @@
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(
+ return b"\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:
+ if len(b) != 1 + 32 + 32 or six.indexbytes(b, 0) != 4:
raise "invalid encoded ec point"
x = _decodeBigEndian(b[1:33])
y = _decodeBigEndian(b[33:65])
diff --git a/tlslite/utils/pycrypto_rsakey.py b/tlslite/utils/pycrypto_rsakey.py
index d76ea2d..4537856 100644
--- a/tlslite/utils/pycrypto_rsakey.py
+++ b/tlslite/utils/pycrypto_rsakey.py
@@ -15,9 +15,9 @@
class PyCrypto_RSAKey(RSAKey):
def __init__(self, n=0, e=0, d=0, p=0, q=0, dP=0, dQ=0, qInv=0):
if not d:
- self.rsa = RSA.construct( (long(n), long(e)) )
+ self.rsa = RSA.construct( (n, e) )
else:
- self.rsa = RSA.construct( (long(n), long(e), long(d), long(p), long(q)) )
+ self.rsa = RSA.construct( (n, e, d, p, q) )
def __getattr__(self, name):
return getattr(self.rsa, name)