Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(53)

Side by Side Diff: third_party/tlslite/patches/alpn.patch

Issue 2205433002: Implement ALPN in tlslite. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Rebase. Created 4 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 diff --git a/third_party/tlslite/tlslite/constants.py b/third_party/tlslite/tlsl ite/constants.py
2 index 715def9..e9743e4 100644
3 --- a/third_party/tlslite/tlslite/constants.py
4 +++ b/third_party/tlslite/tlslite/constants.py
5 @@ -54,6 +54,7 @@ class ExtensionType: # RFC 6066 / 4366
6 status_request = 5 # RFC 6066 / 4366
7 srp = 12 # RFC 5054
8 cert_type = 9 # RFC 6091
9 + alpn = 16 # RFC 7301
10 signed_cert_timestamps = 18 # RFC 6962
11 extended_master_secret = 23 # RFC 7627
12 token_binding = 24 # draft-ietf-tokbind-negotiation
13 diff --git a/third_party/tlslite/tlslite/messages.py b/third_party/tlslite/tlsli te/messages.py
14 index 5762ac6..3d684d4 100644
15 --- a/third_party/tlslite/tlslite/messages.py
16 +++ b/third_party/tlslite/tlslite/messages.py
17 @@ -99,6 +99,27 @@ class HandshakeMsg(object):
18 headerWriter.add(len(w.bytes), 3)
19 return headerWriter.bytes + w.bytes
20
21 + def parse_next_protos(self, b):
22 + protos = []
23 + while True:
24 + if len(b) == 0:
25 + break
26 + l = b[0]
27 + b = b[1:]
28 + if len(b) < l:
29 + raise BadNextProtos(len(b))
30 + protos.append(b[:l])
31 + b = b[l:]
32 + return protos
33 +
34 + def next_protos_encoded(self, protocol_list):
35 + b = bytearray()
36 + for e in protocol_list:
37 + if len(e) > 255 or len(e) == 0:
38 + raise BadNextProtos(len(e))
39 + b += bytearray( [len(e)] ) + bytearray(e)
40 + return b
41 +
42 class ClientHello(HandshakeMsg):
43 def __init__(self, ssl2=False):
44 HandshakeMsg.__init__(self, HandshakeType.client_hello)
45 @@ -111,6 +132,7 @@ class ClientHello(HandshakeMsg):
46 self.compression_methods = [] # a list of 8-bit values
47 self.srp_username = None # a string
48 self.tack = False
49 + self.alpn_protos_advertised = None
50 self.supports_npn = False
51 self.server_name = bytearray(0)
52 self.channel_id = False
53 @@ -120,8 +142,8 @@ class ClientHello(HandshakeMsg):
54 self.status_request = False
55
56 def create(self, version, random, session_id, cipher_suites,
57 - certificate_types=None, srpUsername=None,
58 - tack=False, supports_npn=False, serverName=None):
59 + certificate_types=None, srpUsername=None, tack=False,
60 + alpn_protos_advertised=None, supports_npn=False, serverName=None ):
61 self.client_version = version
62 self.random = random
63 self.session_id = session_id
64 @@ -131,6 +153,7 @@ class ClientHello(HandshakeMsg):
65 if srpUsername:
66 self.srp_username = bytearray(srpUsername, "utf-8")
67 self.tack = tack
68 + self.alpn_protos_advertised = alpn_protos_advertised
69 self.supports_npn = supports_npn
70 if serverName:
71 self.server_name = bytearray(serverName, "utf-8")
72 @@ -171,6 +194,11 @@ class ClientHello(HandshakeMsg):
73 self.certificate_types = p.getVarList(1, 1)
74 elif extType == ExtensionType.tack:
75 self.tack = True
76 + elif extType == ExtensionType.alpn:
77 + structLength = p.get(2)
78 + if (structLength + 2 != extLength):
79 + raise SyntaxError()
80 + self.alpn_protos_advertised = self.parse_next_protos(p. getFixBytes(structLength))
81 elif extType == ExtensionType.supports_npn:
82 self.supports_npn = True
83 elif extType == ExtensionType.server_name:
84 @@ -243,6 +271,12 @@ class ClientHello(HandshakeMsg):
85 w2.add(ExtensionType.srp, 2)
86 w2.add(len(self.srp_username)+1, 2)
87 w2.addVarSeq(self.srp_username, 1, 1)
88 + if self.alpn_protos_advertised is not None:
89 + encoded_alpn_protos_advertised = self.next_protos_encoded(self.alpn _protos_advertised)
90 + w2.add(ExtensionType.alpn, 2)
91 + w2.add(len(encoded_alpn_protos_advertised) + 2, 2)
92 + w2.add(len(encoded_alpn_protos_advertised), 2)
93 + w2.addFixSeq(encoded_alpn_protos_advertised, 1)
94 if self.supports_npn:
95 w2.add(ExtensionType.supports_npn, 2)
96 w2.add(0, 2)
97 @@ -267,6 +301,13 @@ class BadNextProtos(Exception):
98 def __str__(self):
99 return 'Cannot encode a list of next protocols because it contains an e lement with invalid length %d. Element lengths must be 0 < x < 256' % self.lengt h
100
101 +class InvalidAlpnResponse(Exception):
102 + def __init__(self, l):
103 + self.length = l
104 +
105 + def __str__(self):
106 + return 'ALPN server response protocol list has invalid length %d. It m ust be of length one.' % self.length
107 +
108 class ServerHello(HandshakeMsg):
109 def __init__(self):
110 HandshakeMsg.__init__(self, HandshakeType.server_hello)
111 @@ -277,6 +318,7 @@ class ServerHello(HandshakeMsg):
112 self.certificate_type = CertificateType.x509
113 self.compression_method = 0
114 self.tackExt = None
115 + self.alpn_proto_selected = None
116 self.next_protos_advertised = None
117 self.next_protos = None
118 self.channel_id = False
119 @@ -286,7 +328,8 @@ class ServerHello(HandshakeMsg):
120 self.status_request = False
121
122 def create(self, version, random, session_id, cipher_suite,
123 - certificate_type, tackExt, next_protos_advertised):
124 + certificate_type, tackExt, alpn_proto_selected,
125 + next_protos_advertised):
126 self.server_version = version
127 self.random = random
128 self.session_id = session_id
129 @@ -294,6 +337,7 @@ class ServerHello(HandshakeMsg):
130 self.certificate_type = certificate_type
131 self.compression_method = 0
132 self.tackExt = tackExt
133 + self.alpn_proto_selected = alpn_proto_selected
134 self.next_protos_advertised = next_protos_advertised
135 return self
136
137 @@ -316,35 +360,22 @@ class ServerHello(HandshakeMsg):
138 self.certificate_type = p.get(1)
139 elif extType == ExtensionType.tack and tackpyLoaded:
140 self.tackExt = TackExtension(p.getFixBytes(extLength))
141 + elif extType == ExtensionType.alpn:
142 + structLength = p.get(2)
143 + if (structLength + 2 != extLength):
144 + raise SyntaxError()
145 + alpn_protos = self.parse_next_protos(p.getFixBytes(structLe ngth))
146 + if (alpn_protos.len() != 1):
147 + raise InvalidAlpnResponse(alpn_protos.len());
148 + self.alpn_proto_selected = alpn_protos[0]
149 elif extType == ExtensionType.supports_npn:
150 - self.next_protos = self.__parse_next_protos(p.getFixBytes(e xtLength))
151 + self.next_protos = self.parse_next_protos(p.getFixBytes(ext Length))
152 else:
153 p.getFixBytes(extLength)
154 soFar += 4 + extLength
155 p.stopLengthCheck()
156 return self
157
158 - def __parse_next_protos(self, b):
159 - protos = []
160 - while True:
161 - if len(b) == 0:
162 - break
163 - l = b[0]
164 - b = b[1:]
165 - if len(b) < l:
166 - raise BadNextProtos(len(b))
167 - protos.append(b[:l])
168 - b = b[l:]
169 - return protos
170 -
171 - def __next_protos_encoded(self):
172 - b = bytearray()
173 - for e in self.next_protos_advertised:
174 - if len(e) > 255 or len(e) == 0:
175 - raise BadNextProtos(len(e))
176 - b += bytearray( [len(e)] ) + bytearray(e)
177 - return b
178 -
179 def write(self):
180 w = Writer()
181 w.add(self.server_version[0], 1)
182 @@ -365,8 +396,16 @@ class ServerHello(HandshakeMsg):
183 w2.add(ExtensionType.tack, 2)
184 w2.add(len(b), 2)
185 w2.bytes += b
186 - if self.next_protos_advertised is not None:
187 - encoded_next_protos_advertised = self.__next_protos_encoded()
188 + if self.alpn_proto_selected is not None:
189 + alpn_protos_single_element_list = [self.alpn_proto_selected]
190 + encoded_alpn_protos_advertised = self.next_protos_encoded(alpn_prot os_single_element_list)
191 + w2.add(ExtensionType.alpn, 2)
192 + w2.add(len(encoded_alpn_protos_advertised) + 2, 2)
193 + w2.add(len(encoded_alpn_protos_advertised), 2)
194 + w2.addFixSeq(encoded_alpn_protos_advertised, 1)
195 + # Do not use NPN if ALPN is used.
196 + elif self.next_protos_advertised is not None:
197 + encoded_next_protos_advertised = self.next_protos_encoded(self.next _protos_advertised)
198 w2.add(ExtensionType.supports_npn, 2)
199 w2.add(len(encoded_next_protos_advertised), 2)
200 w2.addFixSeq(encoded_next_protos_advertised, 1)
201 diff --git a/third_party/tlslite/tlslite/tlsconnection.py b/third_party/tlslite/ tlslite/tlsconnection.py
202 index 41aab85..1dc39e1 100644
203 --- a/third_party/tlslite/tlslite/tlsconnection.py
204 +++ b/third_party/tlslite/tlslite/tlsconnection.py
205 @@ -337,8 +337,8 @@ class TLSConnection(TLSRecordLayer):
206
207 def handshakeClientCert(self, certChain=None, privateKey=None,
208 session=None, settings=None, checker=None,
209 - nextProtos=None, reqTack=True, serverName="",
210 - async=False):
211 + alpnProtos=None, nextProtos=None, reqTack=True,
212 + serverName="", async=False):
213 """Perform a certificate-based handshake in the role of client.
214
215 This function performs an SSL or TLS handshake. The server
216 @@ -383,6 +383,11 @@ class TLSConnection(TLSRecordLayer):
217 @param checker: A Checker instance. This instance will be
218 invoked to examine the other party's authentication
219 credentials, if the handshake completes succesfully.
220 +
221 + @type alpnProtos: list of strings.
222 + @param alpnProtos: A list of upper layer protocols ordered by
223 + preference, to advertise in the Application-Layer Protocol Negotiation
224 + Extension (RFC 7301).
225
226 @type nextProtos: list of strings.
227 @param nextProtos: A list of upper layer protocols ordered by
228 @@ -417,7 +422,8 @@ class TLSConnection(TLSRecordLayer):
229 handshaker = self._handshakeClientAsync(certParams=(certChain,
230 privateKey), session=session, settings=settings,
231 checker=checker, serverName=serverName,
232 - nextProtos=nextProtos, reqTack=reqTack)
233 + alpnProtos=alpnProtos, nextProtos=nextProtos,
234 + reqTack=reqTack)
235 # The handshaker is a Python Generator which executes the handshake.
236 # It allows the handshake to be run in a "piecewise", asynchronous
237 # fashion, returning 1 when it is waiting to able to write, 0 when
238 @@ -433,7 +439,8 @@ class TLSConnection(TLSRecordLayer):
239
240 def _handshakeClientAsync(self, srpParams=(), certParams=(), anonParams=(),
241 session=None, settings=None, checker=None,
242 - nextProtos=None, serverName="", reqTack=True):
243 + alpnProtos=None, nextProtos=None, serverName="",
244 + reqTack=True):
245
246 handshaker = self._handshakeClientAsyncHelper(srpParams=srpParams,
247 certParams=certParams,
248 @@ -441,6 +448,7 @@ class TLSConnection(TLSRecordLayer):
249 session=session,
250 settings=settings,
251 serverName=serverName,
252 + alpnProtos=alpnProtos,
253 nextProtos=nextProtos,
254 reqTack=reqTack)
255 for result in self._handshakeWrapperAsync(handshaker, checker):
256 @@ -448,7 +456,8 @@ class TLSConnection(TLSRecordLayer):
257
258
259 def _handshakeClientAsyncHelper(self, srpParams, certParams, anonParams,
260 - session, settings, serverName, nextProtos, reqTa ck):
261 + session, settings, serverName, alpnProtos,
262 + nextProtos, reqTack):
263
264 self._handshakeStart(client=True)
265
266 @@ -485,6 +494,9 @@ class TLSConnection(TLSRecordLayer):
267 reqTack = False
268 if not settings or not settings.useExperimentalTackExtension:
269 reqTack = False
270 + if alpnProtos is not None:
271 + if len(alpnProtos) == 0:
272 + raise ValueError("Caller passed no alpnProtos")
273 if nextProtos is not None:
274 if len(nextProtos) == 0:
275 raise ValueError("Caller passed no nextProtos")
276 @@ -530,8 +542,8 @@ class TLSConnection(TLSRecordLayer):
277 # Send the ClientHello.
278 for result in self._clientSendClientHello(settings, session,
279 srpUsername, srpParams, certParams,
280 - anonParams, serverName, nextProtos,
281 - reqTack):
282 + anonParams, serverName, alpnProtos,
283 + nextProtos, reqTack):
284 if result in (0,1): yield result
285 else: break
286 clientHello = result
287 @@ -543,9 +555,11 @@ class TLSConnection(TLSRecordLayer):
288 serverHello = result
289 cipherSuite = serverHello.cipher_suite
290
291 - # Choose a matching Next Protocol from server list against ours
292 - # (string or None)
293 - nextProto = self._clientSelectNextProto(nextProtos, serverHello)
294 + #Ignore NPN if server response has ALPN.
295 + if (serverHello.alpn_proto_selected):
296 + nextProto = None
297 + else:
298 + nextProto = self._clientSelectNextProto(nextProtos, serverHello)
299
300 #If the server elected to resume the session, it is handled here.
301 for result in self._clientResume(session, serverHello,
302 @@ -621,7 +635,7 @@ class TLSConnection(TLSRecordLayer):
303
304 def _clientSendClientHello(self, settings, session, srpUsername,
305 srpParams, certParams, anonParams,
306 - serverName, nextProtos, reqTack):
307 + serverName, alpnProtos, nextProtos, reqTack):
308 #Initialize acceptable ciphersuites
309 cipherSuites = [CipherSuite.TLS_EMPTY_RENEGOTIATION_INFO_SCSV]
310 if srpParams:
311 @@ -651,7 +665,7 @@ class TLSConnection(TLSRecordLayer):
312 session.sessionID, cipherSuites,
313 certificateTypes,
314 session.srpUsername,
315 - reqTack, nextProtos is not None,
316 + reqTack, alpnProtos, nextProtos is not None,
317 session.serverName)
318
319 #Or send ClientHello (without)
320 @@ -661,7 +675,7 @@ class TLSConnection(TLSRecordLayer):
321 bytearray(0), cipherSuites,
322 certificateTypes,
323 srpUsername,
324 - reqTack, nextProtos is not None,
325 + reqTack, alpnProtos, nextProtos is not None,
326 serverName)
327 for result in self._sendMsg(clientHello):
328 yield result
329 @@ -714,6 +728,11 @@ class TLSConnection(TLSRecordLayer):
330 AlertDescription.illegal_parameter,
331 "Server responded with unrequested Tack Extension"):
332 yield result
333 + if serverHello.alpn_proto_selected and not clientHello.alpn_protos_adve rtised:
334 + for result in self._sendError(\
335 + AlertDescription.illegal_parameter,
336 + "Server responded with unrequested ALPN Extension"):
337 + yield result
338 if serverHello.next_protos and not clientHello.supports_npn:
339 for result in self._sendError(\
340 AlertDescription.illegal_parameter,
341 @@ -1102,7 +1121,7 @@ class TLSConnection(TLSRecordLayer):
342 sessionCache=None, settings=None, checker=None,
343 reqCAs = None, reqCertTypes = None,
344 tacks=None, activationFlags=0,
345 - nextProtos=None, anon=False,
346 + alpnProtos=None, nextProtos=None, anon=False,
347 signedCertTimestamps=None,
348 fallbackSCSV=False, ocspResponse=None):
349 """Perform a handshake in the role of server.
350 @@ -1172,6 +1191,11 @@ class TLSConnection(TLSRecordLayer):
351 @param reqCertTypes: A list of certificate_type values to be sent
352 along with a certificate request. This does not affect verification.
353
354 + @type alpnProtos: list of strings.
355 + @param alpnProtos: A list of upper layer protocols with zero or one
356 + elements. If not empty, its single element is the protocol negotiated
357 + via the Application-Layer Protocol Negotiation Extension (RFC 7301).
358 +
359 @type nextProtos: list of strings.
360 @param nextProtos: A list of upper layer protocols to expose to the
361 clients through the Next-Protocol Negotiation Extension,
362 @@ -1208,7 +1232,7 @@ class TLSConnection(TLSRecordLayer):
363 certChain, privateKey, reqCert, sessionCache, settings,
364 checker, reqCAs, reqCertTypes,
365 tacks=tacks, activationFlags=activationFlags,
366 - nextProtos=nextProtos, anon=anon,
367 + alpnProtos=alpnProtos, nextProtos=nextProtos, anon=anon,
368 signedCertTimestamps=signedCertTimestamps,
369 fallbackSCSV=fallbackSCSV, ocspResponse=ocspResponse):
370 pass
371 @@ -1218,7 +1242,7 @@ class TLSConnection(TLSRecordLayer):
372 certChain=None, privateKey=None, reqCert=False,
373 sessionCache=None, settings=None, checker=None,
374 reqCAs=None, reqCertTypes=None,
375 - tacks=None, activationFlags=0,
376 + tacks=None, activationFlags=0, alpnProtos=None,
377 nextProtos=None, anon=False,
378 signedCertTimestamps=None,
379 fallbackSCSV=False,
380 @@ -1240,7 +1264,7 @@ class TLSConnection(TLSRecordLayer):
381 privateKey=privateKey, reqCert=reqCert,
382 sessionCache=sessionCache, settings=settings,
383 reqCAs=reqCAs, reqCertTypes=reqCertTypes,
384 - tacks=tacks, activationFlags=activationFlags,
385 + tacks=tacks, activationFlags=activationFlags, alpnProtos=alpnProtos ,
386 nextProtos=nextProtos, anon=anon,
387 signedCertTimestamps=signedCertTimestamps,
388 fallbackSCSV=fallbackSCSV,
389 @@ -1257,7 +1281,7 @@ class TLSConnection(TLSRecordLayer):
390 certChain, privateKey, reqCert, sessionCache,
391 settings, reqCAs, reqCertTypes,
392 tacks, activationFlags,
393 - nextProtos, anon,
394 + alpnProtos, nextProtos, anon,
395 signedCertTimestamps, fallbackSCSV,
396 ocspResponse):
397
398 @@ -1314,7 +1338,16 @@ class TLSConnection(TLSRecordLayer):
399 sessionID = getRandomBytes(32)
400 else:
401 sessionID = bytearray(0)
402 -
403 +
404 + alpn_proto_selected = None
405 + if clientHello.alpn_protos_advertised is not None:
406 + if alpnProtos is not None:
407 + for proto in alpnProtos:
408 + if proto in clientHello.alpn_protos_advertised:
409 + alpn_proto_selected = proto
410 + nextProtos = None
411 + break;
412 +
413 if not clientHello.supports_npn:
414 nextProtos = None
415
416 @@ -1330,7 +1363,7 @@ class TLSConnection(TLSRecordLayer):
417 serverHello = ServerHello()
418 serverHello.create(self.version, getRandomBytes(32), sessionID, \
419 cipherSuite, CertificateType.x509, tackExt,
420 - nextProtos)
421 + alpn_proto_selected, nextProtos)
422 serverHello.channel_id = \
423 clientHello.channel_id and settings.enableChannelID
424 serverHello.extended_master_secret = \
425 @@ -1397,7 +1430,7 @@ class TLSConnection(TLSRecordLayer):
426 for result in self._serverFinished(premasterSecret,
427 clientHello.random, serverHello.random,
428 cipherSuite, settings.cipherImplementations,
429 - nextProtos, serverHello.channel_id,
430 + alpnProtos, nextProtos, serverHello.channel_id,
431 serverHello.extended_master_secret):
432 if result in (0,1): yield result
433 else: break
434 @@ -1540,7 +1573,7 @@ class TLSConnection(TLSRecordLayer):
435 serverHello = ServerHello()
436 serverHello.create(self.version, getRandomBytes(32),
437 session.sessionID, session.cipherSuite,
438 - CertificateType.x509, None, None)
439 + CertificateType.x509, None, None, None)
440 serverHello.extended_master_secret = \
441 clientHello.extended_master_secret and \
442 settings.enableExtendedMasterSecret
443 @@ -1854,8 +1887,8 @@ class TLSConnection(TLSRecordLayer):
444
445
446 def _serverFinished(self, premasterSecret, clientRandom, serverRandom,
447 - cipherSuite, cipherImplementations, nextProtos,
448 - doingChannelID, useExtendedMasterSecret):
449 + cipherSuite, cipherImplementations, alpnProtos,
450 + nextProtos, doingChannelID, useExtendedMasterSecret):
451 masterSecret = calcMasterSecret(self.version, premasterSecret,
452 clientRandom, serverRandom,
453 self._ems_handshake_hash,
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698