Index: third_party/tlslite/tlslite/tlsconnection.py |
diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/tlslite/tlsconnection.py |
index 41aab85a71b3726d8cafb6060c94c44000e999a8..1dc39e1de60ce9b38f75c2ab0b1ef37b7da06607 100644 |
--- a/third_party/tlslite/tlslite/tlsconnection.py |
+++ b/third_party/tlslite/tlslite/tlsconnection.py |
@@ -337,8 +337,8 @@ class TLSConnection(TLSRecordLayer): |
def handshakeClientCert(self, certChain=None, privateKey=None, |
session=None, settings=None, checker=None, |
- nextProtos=None, reqTack=True, serverName="", |
- async=False): |
+ alpnProtos=None, nextProtos=None, reqTack=True, |
davidben
2016/08/03 23:34:22
Please do move this to the settings object. You wo
Bence
2016/08/04 18:41:45
Done. Also moved nextProtos so that they are toge
|
+ serverName="", async=False): |
"""Perform a certificate-based handshake in the role of client. |
This function performs an SSL or TLS handshake. The server |
@@ -383,6 +383,11 @@ class TLSConnection(TLSRecordLayer): |
@param checker: A Checker instance. This instance will be |
invoked to examine the other party's authentication |
credentials, if the handshake completes succesfully. |
+ |
+ @type alpnProtos: list of strings. |
+ @param alpnProtos: A list of upper layer protocols ordered by |
+ preference, to advertise in the Application-Layer Protocol Negotiation |
+ Extension (RFC 7301). |
@type nextProtos: list of strings. |
@param nextProtos: A list of upper layer protocols ordered by |
@@ -417,7 +422,8 @@ class TLSConnection(TLSRecordLayer): |
handshaker = self._handshakeClientAsync(certParams=(certChain, |
privateKey), session=session, settings=settings, |
checker=checker, serverName=serverName, |
- nextProtos=nextProtos, reqTack=reqTack) |
+ alpnProtos=alpnProtos, nextProtos=nextProtos, |
+ reqTack=reqTack) |
# The handshaker is a Python Generator which executes the handshake. |
# It allows the handshake to be run in a "piecewise", asynchronous |
# fashion, returning 1 when it is waiting to able to write, 0 when |
@@ -433,7 +439,8 @@ class TLSConnection(TLSRecordLayer): |
def _handshakeClientAsync(self, srpParams=(), certParams=(), anonParams=(), |
session=None, settings=None, checker=None, |
- nextProtos=None, serverName="", reqTack=True): |
+ alpnProtos=None, nextProtos=None, serverName="", |
+ reqTack=True): |
handshaker = self._handshakeClientAsyncHelper(srpParams=srpParams, |
certParams=certParams, |
@@ -441,6 +448,7 @@ class TLSConnection(TLSRecordLayer): |
session=session, |
settings=settings, |
serverName=serverName, |
+ alpnProtos=alpnProtos, |
nextProtos=nextProtos, |
reqTack=reqTack) |
for result in self._handshakeWrapperAsync(handshaker, checker): |
@@ -448,7 +456,8 @@ class TLSConnection(TLSRecordLayer): |
def _handshakeClientAsyncHelper(self, srpParams, certParams, anonParams, |
- session, settings, serverName, nextProtos, reqTack): |
+ session, settings, serverName, alpnProtos, |
+ nextProtos, reqTack): |
self._handshakeStart(client=True) |
@@ -485,6 +494,9 @@ class TLSConnection(TLSRecordLayer): |
reqTack = False |
if not settings or not settings.useExperimentalTackExtension: |
reqTack = False |
+ if alpnProtos is not None: |
+ if len(alpnProtos) == 0: |
+ raise ValueError("Caller passed no alpnProtos") |
if nextProtos is not None: |
if len(nextProtos) == 0: |
raise ValueError("Caller passed no nextProtos") |
@@ -530,8 +542,8 @@ class TLSConnection(TLSRecordLayer): |
# Send the ClientHello. |
for result in self._clientSendClientHello(settings, session, |
srpUsername, srpParams, certParams, |
- anonParams, serverName, nextProtos, |
- reqTack): |
+ anonParams, serverName, alpnProtos, |
+ nextProtos, reqTack): |
if result in (0,1): yield result |
else: break |
clientHello = result |
@@ -543,9 +555,11 @@ class TLSConnection(TLSRecordLayer): |
serverHello = result |
cipherSuite = serverHello.cipher_suite |
- # Choose a matching Next Protocol from server list against ours |
- # (string or None) |
- nextProto = self._clientSelectNextProto(nextProtos, serverHello) |
+ #Ignore NPN if server response has ALPN. |
davidben
2016/08/03 23:34:22
This isn't right. If the ServerHello contains both
Bence
2016/08/04 18:41:45
Done.
|
+ if (serverHello.alpn_proto_selected): |
+ nextProto = None |
+ else: |
+ nextProto = self._clientSelectNextProto(nextProtos, serverHello) |
#If the server elected to resume the session, it is handled here. |
for result in self._clientResume(session, serverHello, |
@@ -621,7 +635,7 @@ class TLSConnection(TLSRecordLayer): |
def _clientSendClientHello(self, settings, session, srpUsername, |
srpParams, certParams, anonParams, |
- serverName, nextProtos, reqTack): |
+ serverName, alpnProtos, nextProtos, reqTack): |
#Initialize acceptable ciphersuites |
cipherSuites = [CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV] |
if srpParams: |
@@ -651,7 +665,7 @@ class TLSConnection(TLSRecordLayer): |
session.sessionID, cipherSuites, |
certificateTypes, |
session.srpUsername, |
- reqTack, nextProtos is not None, |
+ reqTack, alpnProtos, nextProtos is not None, |
session.serverName) |
#Or send ClientHello (without) |
@@ -661,7 +675,7 @@ class TLSConnection(TLSRecordLayer): |
bytearray(0), cipherSuites, |
certificateTypes, |
srpUsername, |
- reqTack, nextProtos is not None, |
+ reqTack, alpnProtos, nextProtos is not None, |
serverName) |
for result in self._sendMsg(clientHello): |
yield result |
@@ -714,6 +728,11 @@ class TLSConnection(TLSRecordLayer): |
AlertDescription.illegal_parameter, |
"Server responded with unrequested Tack Extension"): |
yield result |
+ if serverHello.alpn_proto_selected and not clientHello.alpn_protos_advertised: |
+ for result in self._sendError(\ |
+ AlertDescription.illegal_parameter, |
+ "Server responded with unrequested ALPN Extension"): |
+ yield result |
davidben
2016/08/03 23:34:22
Add a check that ALPN + NPN in a ServerHello is il
Bence
2016/08/04 18:41:45
Done.
|
if serverHello.next_protos and not clientHello.supports_npn: |
for result in self._sendError(\ |
AlertDescription.illegal_parameter, |
@@ -1102,7 +1121,7 @@ class TLSConnection(TLSRecordLayer): |
sessionCache=None, settings=None, checker=None, |
reqCAs = None, reqCertTypes = None, |
tacks=None, activationFlags=0, |
- nextProtos=None, anon=False, |
+ alpnProtos=None, nextProtos=None, anon=False, |
signedCertTimestamps=None, |
fallbackSCSV=False, ocspResponse=None): |
"""Perform a handshake in the role of server. |
@@ -1172,6 +1191,11 @@ class TLSConnection(TLSRecordLayer): |
@param reqCertTypes: A list of certificate_type values to be sent |
along with a certificate request. This does not affect verification. |
+ @type alpnProtos: list of strings. |
+ @param alpnProtos: A list of upper layer protocols with zero or one |
+ elements. If not empty, its single element is the protocol negotiated |
+ via the Application-Layer Protocol Negotiation Extension (RFC 7301). |
+ |
@type nextProtos: list of strings. |
@param nextProtos: A list of upper layer protocols to expose to the |
clients through the Next-Protocol Negotiation Extension, |
@@ -1208,7 +1232,7 @@ class TLSConnection(TLSRecordLayer): |
certChain, privateKey, reqCert, sessionCache, settings, |
checker, reqCAs, reqCertTypes, |
tacks=tacks, activationFlags=activationFlags, |
- nextProtos=nextProtos, anon=anon, |
+ alpnProtos=alpnProtos, nextProtos=nextProtos, anon=anon, |
signedCertTimestamps=signedCertTimestamps, |
fallbackSCSV=fallbackSCSV, ocspResponse=ocspResponse): |
pass |
@@ -1218,7 +1242,7 @@ class TLSConnection(TLSRecordLayer): |
certChain=None, privateKey=None, reqCert=False, |
sessionCache=None, settings=None, checker=None, |
reqCAs=None, reqCertTypes=None, |
- tacks=None, activationFlags=0, |
+ tacks=None, activationFlags=0, alpnProtos=None, |
nextProtos=None, anon=False, |
signedCertTimestamps=None, |
fallbackSCSV=False, |
@@ -1240,7 +1264,7 @@ class TLSConnection(TLSRecordLayer): |
privateKey=privateKey, reqCert=reqCert, |
sessionCache=sessionCache, settings=settings, |
reqCAs=reqCAs, reqCertTypes=reqCertTypes, |
- tacks=tacks, activationFlags=activationFlags, |
+ tacks=tacks, activationFlags=activationFlags, alpnProtos=alpnProtos, |
nextProtos=nextProtos, anon=anon, |
signedCertTimestamps=signedCertTimestamps, |
fallbackSCSV=fallbackSCSV, |
@@ -1257,7 +1281,7 @@ class TLSConnection(TLSRecordLayer): |
certChain, privateKey, reqCert, sessionCache, |
settings, reqCAs, reqCertTypes, |
tacks, activationFlags, |
- nextProtos, anon, |
+ alpnProtos, nextProtos, anon, |
signedCertTimestamps, fallbackSCSV, |
ocspResponse): |
@@ -1314,7 +1338,16 @@ class TLSConnection(TLSRecordLayer): |
sessionID = getRandomBytes(32) |
else: |
sessionID = bytearray(0) |
- |
+ |
+ alpn_proto_selected = None |
+ if clientHello.alpn_protos_advertised is not None: |
+ if alpnProtos is not None: |
+ for proto in alpnProtos: |
+ if proto in clientHello.alpn_protos_advertised: |
+ alpn_proto_selected = proto |
+ nextProtos = None |
+ break; |
+ |
if not clientHello.supports_npn: |
nextProtos = None |
@@ -1330,7 +1363,7 @@ class TLSConnection(TLSRecordLayer): |
serverHello = ServerHello() |
serverHello.create(self.version, getRandomBytes(32), sessionID, \ |
cipherSuite, CertificateType.x509, tackExt, |
- nextProtos) |
+ alpn_proto_selected, nextProtos) |
serverHello.channel_id = \ |
clientHello.channel_id and settings.enableChannelID |
serverHello.extended_master_secret = \ |
@@ -1397,7 +1430,7 @@ class TLSConnection(TLSRecordLayer): |
for result in self._serverFinished(premasterSecret, |
clientHello.random, serverHello.random, |
cipherSuite, settings.cipherImplementations, |
- nextProtos, serverHello.channel_id, |
+ alpnProtos, nextProtos, serverHello.channel_id, |
serverHello.extended_master_secret): |
if result in (0,1): yield result |
else: break |
@@ -1540,7 +1573,7 @@ class TLSConnection(TLSRecordLayer): |
serverHello = ServerHello() |
serverHello.create(self.version, getRandomBytes(32), |
session.sessionID, session.cipherSuite, |
- CertificateType.x509, None, None) |
+ CertificateType.x509, None, None, None) |
davidben
2016/08/03 23:34:22
ALPN also should happen on session resumption.
Bence
2016/08/04 18:41:45
Done.
|
serverHello.extended_master_secret = \ |
clientHello.extended_master_secret and \ |
settings.enableExtendedMasterSecret |
@@ -1854,8 +1887,8 @@ class TLSConnection(TLSRecordLayer): |
def _serverFinished(self, premasterSecret, clientRandom, serverRandom, |
- cipherSuite, cipherImplementations, nextProtos, |
- doingChannelID, useExtendedMasterSecret): |
+ cipherSuite, cipherImplementations, alpnProtos, |
+ nextProtos, doingChannelID, useExtendedMasterSecret): |
davidben
2016/08/03 23:34:22
(ALPN doesn't interact interestingly with the Fini
Bence
2016/08/04 18:41:44
Done.
|
masterSecret = calcMasterSecret(self.version, premasterSecret, |
clientRandom, serverRandom, |
self._ems_handshake_hash, |