Skip to content

Commit 23a61e1

Browse files
Support for compressed_certificate extension
Added support in client and server for the TLS Certificate Compression as described in https://www.rfc-editor.org/rfc/rfc8879.html
1 parent 77ef321 commit 23a61e1

30 files changed

+3110
-148
lines changed

.github/workflows/ci.yml

Lines changed: 64 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -149,42 +149,77 @@ jobs:
149149
os: ubuntu-latest
150150
python-version: '3.12'
151151
opt-deps: ['gmpy2']
152+
- name: py2.7 with brotli
153+
os: ubuntu-20.04
154+
python-version: 2.7
155+
# zstandard is available for py3.8 and above
156+
opt-deps: ['brotli']
157+
- name: py3.6 with brotli
158+
os: ubuntu-20.04
159+
python-version: 3.6
160+
# zstandard is available for py3.8 and above
161+
opt-deps: ['brotli']
162+
- name: py3.7 with brotli
163+
os: ubuntu-latest
164+
python-version: 3.7
165+
# zstandard is available for py3.8 and above
166+
opt-deps: ['brotli']
167+
- name: py3.8 with brotli and zstandard
168+
os: ubuntu-latest
169+
python-version: 3.8
170+
opt-deps: ['brotli', 'zstd']
171+
- name: py3.9 with brotli and zstandard
172+
os: ubuntu-latest
173+
python-version: 3.9
174+
opt-deps: ['brotli', 'zstd']
175+
- name: py3.10 with brotli and zstandard
176+
os: ubuntu-latest
177+
python-version: '3.10'
178+
opt-deps: ['brotli', 'zstd']
179+
- name: py3.11 with brotli and zstandard
180+
os: ubuntu-latest
181+
python-version: '3.11'
182+
opt-deps: ['brotli', 'zstd']
183+
- name: py3.12with brotli and zstandard
184+
os: ubuntu-latest
185+
python-version: '3.12'
186+
opt-deps: ['brotli', 'zstd']
152187
# finally test with multiple dependencies installed at the same time
153-
- name: py2.7 with m2crypto, pycrypto, gmpy, and gmpy2
188+
- name: py2.7 with m2crypto, pycrypto, gmpy, gmpy2, and brotli
154189
os: ubuntu-20.04
155190
python-version: 2.7
156-
opt-deps: ['m2crypto', 'pycrypto', 'gmpy', 'gmpy2']
157-
- name: py3.6 with m2crypto, pycrypto, gmpy, and gmpy2
191+
opt-deps: ['m2crypto', 'pycrypto', 'gmpy', 'gmpy2', 'brotli']
192+
- name: py3.6 with m2crypto, pycrypto, gmpy, gmpy2, and brotli
158193
os: ubuntu-20.04
159194
python-version: 3.6
160-
opt-deps: ['m2crypto', 'pycrypto', 'gmpy', 'gmpy2']
161-
- name: py3.7 with m2crypto, gmpy, and gmpy2
195+
opt-deps: ['m2crypto', 'pycrypto', 'gmpy', 'gmpy2', 'brotli']
196+
- name: py3.7 with m2crypto, gmpy, gmpy2, and brotli
162197
os: ubuntu-latest
163198
python-version: 3.7
164-
opt-deps: ['m2crypto', 'gmpy', 'gmpy2']
165-
- name: py3.8 with m2crypto, gmpy, and gmpy2
199+
opt-deps: ['m2crypto', 'gmpy', 'gmpy2', 'brotli']
200+
- name: py3.8 with m2crypto, gmpy, gmpy2, and brotli
166201
os: ubuntu-latest
167202
python-version: 3.8
168-
opt-deps: ['m2crypto', 'gmpy', 'gmpy2']
169-
- name: py3.9 with m2crypto, gmpy, and gmpy2
203+
opt-deps: ['m2crypto', 'gmpy', 'gmpy2', 'brotli', 'zstd']
204+
- name: py3.9 with m2crypto, gmpy, gmpy2, brotli, and zstandard
170205
os: ubuntu-latest
171206
python-version: 3.9
172-
opt-deps: ['m2crypto', 'gmpy', 'gmpy2']
173-
- name: py3.10 with m2crypto, gmpy, and gmpy2
207+
opt-deps: ['m2crypto', 'gmpy', 'gmpy2', 'brotli', 'zstd']
208+
- name: py3.10 with m2crypto, gmpy, gmpy2, brotli, and zstandard
174209
os: ubuntu-latest
175210
python-version: '3.10'
176-
opt-deps: ['m2crypto', 'gmpy', 'gmpy2']
177-
- name: py3.11 with m2crypto, gmpy, and gmpy2
211+
opt-deps: ['m2crypto', 'gmpy', 'gmpy2', 'brotli', 'zstd']
212+
- name: py3.11 with m2crypto, gmpy, gmpy2, brotli, and zstandard
178213
os: ubuntu-latest
179214
python-version: '3.11'
180215
# gmpy doesn't build with 3.11
181-
opt-deps: ['m2crypto', 'gmpy2']
182-
- name: py3.12 with m2crypto, gmpy, and gmpy2
216+
opt-deps: ['m2crypto', 'gmpy2', 'brotli', 'zstd']
217+
- name: py3.12 with m2crypto, gmpy, gmpy2, brotli, and zstandard
183218
os: ubuntu-latest
184219
python-version: '3.12'
185220
# gmpy doesn't build with 3.12
186221
# coverage to codeclimate can be submitted just once
187-
opt-deps: ['m2crypto', 'gmpy2', 'codeclimate']
222+
opt-deps: ['m2crypto', 'gmpy2', 'codeclimate', 'brotli', 'zstd']
188223
steps:
189224
- uses: actions/checkout@v2
190225
if: ${{ !matrix.container }}
@@ -300,6 +335,17 @@ jobs:
300335
if: ${{ contains(matrix.opt-deps, 'gmpy2') && matrix.python-version == '3.12' }}
301336
# for py3.12 we need pre-release version: https://github.com/aleaxit/gmpy/issues/446
302337
run: pip install --pre gmpy2
338+
- name: Install brotli for Python 2
339+
if: ${{ contains(matrix.opt-deps, 'brotli') && matrix.python-version == '2.7' }}
340+
# using 1.0.9 for Python 2 because latest is not compatible
341+
# https://github.com/google/brotli/issues/1074
342+
run: pip install brotli==1.0.9
343+
- name: Install brotli
344+
if: ${{ contains(matrix.opt-deps, 'brotli') && matrix.python-version != '2.7' }}
345+
run: pip install brotli
346+
- name: Install zstandard for py3.8 and after
347+
if: ${{ contains(matrix.opt-deps, 'zstd') }}
348+
run: pip install zstandard
303349
- name: Install build dependencies (2.6)
304350
if: ${{ matrix.python-version == '2.6' }}
305351
run: |
@@ -310,7 +356,7 @@ jobs:
310356
wget https://files.pythonhosted.org/packages/72/20/7f0f433060a962200b7272b8c12ba90ef5b903e218174301d0abfd523813/unittest2-1.1.0-py2.py3-none-any.whl
311357
wget https://files.pythonhosted.org/packages/85/d5/818d0e603685c4a613d56f065a721013e942088047ff1027a632948bdae6/coverage-4.5.4.tar.gz
312358
wget https://files.pythonhosted.org/packages/a8/5a/5cf074e1c6681dcbb4e640113f58bed16955e7da9a6c8090b518031775e7/hypothesis-2.0.0.tar.gz
313-
wget https://files.pythonhosted.org/packages/f8/86/410d53faff049641f34951843245d168261512aea787a1f9f05c3fa025a0/pylint-1.7.6-py2.py3-none-any.whl
359+
wget https://files.pythonhosted.org/packages/f8/86/410d53faff049641f34951843245d168261512aea787a1f9f05c3fa025a0/pylint-1.7.6-py2.py3-none-any.whl
314360
wget https://files.pythonhosted.org/packages/81/a6/d076eeb83f383ac7a25e030709abebc6781bcf930d67316be6d47641637e/diff_cover-4.0.0-py2.py3-none-any.whl
315361
wget https://files.pythonhosted.org/packages/8c/2d/aad7f16146f4197a11f8e91fb81df177adcc2073d36a17b1491fd09df6ed/pycparser-2.18.tar.gz
316362
wget https://files.pythonhosted.org/packages/4b/2a/0276479a4b3caeb8a8c1af2f8e4355746a97fab05a372e4a2c6a6b876165/idna-2.7-py2.py3-none-any.whl
@@ -336,7 +382,7 @@ jobs:
336382
wget https://files.pythonhosted.org/packages/c2/f8/49697181b1651d8347d24c095ce46c7346c37335ddc7d255833e7cde674d/ipaddress-1.0.23-py2.py3-none-any.whl
337383
wget https://files.pythonhosted.org/packages/c7/a3/c5da2a44c85bfbb6eebcfc1dde24933f8704441b98fdde6528f4831757a6/linecache2-1.0.0-py2.py3-none-any.whl
338384
wget https://files.pythonhosted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl
339-
wget https://files.pythonhosted.org/packages/bd/c9/6fdd990019071a4a32a5e7cb78a1d92c53851ef4f56f62a3486e6a7d8ffb/urllib3-1.23-py2.py3-none-any.whl
385+
wget https://files.pythonhosted.org/packages/bd/c9/6fdd990019071a4a32a5e7cb78a1d92c53851ef4f56f62a3486e6a7d8ffb/urllib3-1.23-py2.py3-none-any.whl
340386
wget https://files.pythonhosted.org/packages/5e/a0/5f06e1e1d463903cf0c0eebeb751791119ed7a4b3737fdc9a77f1cdfb51f/certifi-2020.12.5-py2.py3-none-any.whl
341387
wget https://files.pythonhosted.org/packages/8d/08/00aab975c99d156aec2d47e9e7a947ac3af3efab5065f666c8b157acc7a8/lazy_object_proxy-1.3.1-cp26-cp26mu-manylinux1_x86_64.whl
342388
wget https://files.pythonhosted.org/packages/82/f7/e43cefbe88c5fd371f4cf0cf5eb3feccd07515af9fd6cf7dbf1d1793a797/wrapt-1.12.1.tar.gz

LICENSE

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ TLS Lite includes code from different sources. All code is either dedicated to
33
the public domain by its authors, available under a BSD-style license or
44
available under GNU LGPL v2 license. In particular:
55

6-
-
6+
-
77

88
Code written by Trevor Perrin, Kees Bos, Sam Rushing, Dimitris Moraitis,
99
Marcelo Fernandez, Martin von Loewis, Dave Baggett, Yngve Pettersen, and
@@ -38,7 +38,7 @@ its author. See rijndael.py for details.
3838

3939
Code written by Google is available under the following terms:
4040

41-
Copyright (c) 2008, The Chromium Authors
41+
Copyright (c) 2008, The Chromium Authors
4242
All rights reserved.
4343

4444
Redistribution and use in source and binary forms, with or without
@@ -68,6 +68,29 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
6868

6969
-
7070

71+
Code written by Sidney Markowitz is available under the following terms:
72+
Copyright (c) 2021 by Sidney Markowitz.
73+
74+
Permission is hereby granted, free of charge, to any person obtaining a copy
75+
of this software and associated documentation files (the "Software"), to deal
76+
in the Software without restriction, including without limitation the rights
77+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
78+
copies of the Software, and to permit persons to whom the Software is
79+
furnished to do so, subject to the following conditions:
80+
81+
The above copyright notice and this permission notice shall be included in
82+
all copies or substantial portions of the Software.
83+
84+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
85+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
86+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
87+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
88+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
89+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
90+
THE SOFTWARE.
91+
92+
-
93+
7194
Code written by Hubert Kario is available under the following terms:
7295

7396
Copyright (c) 2014, Hubert Kario, Red Hat Inc.

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Authors:
1+
# Authors:
22
# Trevor Perrin
33
# Hubert Kario - test and test-dev
44
#

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ Hubert Kario. TLS Lite was written (mostly) by Trevor
8181
Perrin. It includes code from Bram Cohen, Google, Kees Bos, Sam Rushing,
8282
Dimitris Moraitis, Marcelo Fernandez, Martin von Loewis, Dave Baggett, Yngve
8383
N. Pettersen (ported by Paul Sokolovsky), Mirko Dziadzka, David Benjamin,
84-
and Hubert Kario.
84+
Sidney Markowitz, and Hubert Kario.
8585

8686
Original code in TLS Lite has either been dedicated to the public domain by its
8787
authors, or placed under a BSD-style license. See the LICENSE file for

scripts/tls.py

Lines changed: 38 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#!/usr/bin/env python
22

3-
# Authors:
3+
# Authors:
44
# Trevor Perrin
55
# Marcelo Fernandez - bugfix and NPN support
66
# Martin von Loewis - python 3 port
@@ -38,6 +38,7 @@
3838
from tlslite.utils.dns_utils import is_valid_hostname
3939
from tlslite.utils.cryptomath import getRandomBytes
4040
from tlslite.constants import KeyUpdateMessageType
41+
from tlslite.utils.compression import compression_algo_impls
4142

4243
try:
4344
from tack.structures.Tack import Tack
@@ -58,7 +59,7 @@ def printUsage(s=None):
5859
if tackpyLoaded:
5960
print(" tackpy : Loaded")
6061
else:
61-
print(" tackpy : Not Loaded")
62+
print(" tackpy : Not Loaded")
6263
if m2cryptoLoaded:
6364
print(" M2Crypto : Loaded")
6465
else:
@@ -76,10 +77,30 @@ def printUsage(s=None):
7677
else:
7778
print(" GMPY2 : Not Loaded")
7879

80+
print("")
81+
print("Certificate compression algorithms:")
82+
print(" zlib compress : Loaded")
83+
print(" zlib decompress : Loaded")
84+
print(" brotli compress : {0}".format(
85+
"Loaded" if compression_algo_impls["brotli_compress"]
86+
else "Not Loaded"
87+
))
88+
print(" brotli decompress : {0}".format(
89+
"Loaded" if compression_algo_impls["brotli_decompress"]
90+
else "Not Loaded"
91+
))
92+
print(" zstd decompress : {0}".format(
93+
"Loaded" if compression_algo_impls["zstd_compress"]
94+
else "Not Loaded"
95+
))
96+
print(" zstd decompress : {0}".format(
97+
"Loaded" if compression_algo_impls["zstd_decompress"]
98+
else "Not Loaded"
99+
))
79100
print("")
80101
print("""Commands:
81102
82-
server
103+
server
83104
[-c CERT] [-k KEY] [-t TACK] [-v VERIFIERDB] [-d DIR] [-l LABEL] [-L LENGTH]
84105
[--reqcert] [--param DHFILE] [--psk PSK] [--psk-ident IDENTITY]
85106
[--psk-sha384] [--ssl3] [--max-ver VER] [--tickets COUNT] [--cipherlist]
@@ -144,8 +165,8 @@ def handleArgs(argv, argString, flagsList=[]):
144165
try:
145166
opts, argv = getopt.getopt(argv, getOptArgString, flagsList)
146167
except getopt.GetoptError as e:
147-
printError(e)
148-
# Default values if arg not present
168+
printError(e)
169+
# Default values if arg not present
149170
privateKey = None
150171
cert_chain = None
151172
virtual_hosts = []
@@ -367,6 +388,12 @@ def printGoodConnection(connection, seconds):
367388
print(" Extended Master Secret: {0}".format(
368389
connection.extendedMasterSecret))
369390
print(" Session Resumed: {0}".format(connection.resumed))
391+
if connection.client_cert_compression_algo:
392+
print(" Client compression algorithm used: {0}".format(
393+
connection.client_cert_compression_algo))
394+
if connection.server_cert_compression_algo:
395+
print(" Server compression algorithm used: {0}".format(
396+
connection.server_cert_compression_algo))
370397

371398
def printExporter(connection, expLabel, expLength):
372399
if expLabel is None:
@@ -378,7 +405,7 @@ def printExporter(connection, expLabel, expLength):
378405
print(" Exporter length: {0}".format(expLength))
379406
print(" Keying material: {0}".format(exp))
380407

381-
408+
382409
def clientCmd(argv):
383410
(address, privateKey, cert_chain, virtual_hosts, username, password,
384411
expLabel,
@@ -387,7 +414,7 @@ def clientCmd(argv):
387414
handleArgs(argv, "kcuplLa", ["psk=", "psk-ident=", "psk-sha384",
388415
"resumption", "ssl3", "max-ver=",
389416
"cipherlist="])
390-
417+
391418
if (cert_chain and not privateKey) or (not cert_chain and privateKey):
392419
raise SyntaxError("Must specify CERT and KEY together")
393420
if (username and not password) or (not username and password):
@@ -403,7 +430,7 @@ def clientCmd(argv):
403430
sock.connect(address)
404431
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
405432
connection = TLSConnection(sock)
406-
433+
407434
settings = HandshakeSettings()
408435
if psk:
409436
settings.pskConfigs = [(psk_ident, psk, psk_hash)]
@@ -418,13 +445,13 @@ def clientCmd(argv):
418445
try:
419446
start = time_stamp()
420447
if username and password:
421-
connection.handshakeClientSRP(username, password,
448+
connection.handshakeClientSRP(username, password,
422449
settings=settings, serverName=address[0])
423450
else:
424451
connection.handshakeClientCert(cert_chain, privateKey,
425452
settings=settings, serverName=address[0], alpn=alpn)
426453
stop = time_stamp()
427-
print("Handshake success")
454+
print("Handshake success")
428455
except TLSLocalAlert as a:
429456
if a.description == AlertDescription.user_canceled:
430457
print(str(a))
@@ -544,7 +571,7 @@ def serverCmd(argv):
544571
print("Using Tacks...")
545572
if reqCert:
546573
print("Asking for client certificates...")
547-
574+
548575
#############
549576
sessionCache = SessionCache()
550577
username = None

0 commit comments

Comments
 (0)