Chromium Code Reviews| 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, |