Skip to content

Commit 76fb33f

Browse files
authored
Merge pull request #333 from simo5/tls13clicert
Add support for CertificateRequest (TLS 1.3)
2 parents 3696909 + 2313ba9 commit 76fb33f

File tree

7 files changed

+566
-52
lines changed

7 files changed

+566
-52
lines changed

tests/tlstest.py

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,32 @@ def connect():
416416
settings.maxVersion = (3, 3)
417417
connection.handshakeClientCert(x509Chain, x509Key, settings=settings)
418418
testConnClient(connection)
419+
assert isinstance(connection.session.serverCertChain, X509CertChain)
420+
connection.close()
421+
422+
test_no += 1
423+
424+
print("Test {0} - good mutual X509, TLSv1.3 no certs".format(test_no))
425+
synchro.recv(1)
426+
connection = connect()
427+
settings = HandshakeSettings()
428+
settings.minVersion = (3,4)
429+
settings.maxVersion = (3,4)
430+
connection.handshakeClientCert(settings=settings)
431+
testConnClient(connection)
432+
assert isinstance(connection.session.serverCertChain, X509CertChain)
433+
connection.close()
434+
435+
test_no += 1
436+
437+
print("Test {0} - good mutual X509, TLSv1.3".format(test_no))
438+
synchro.recv(1)
439+
connection = connect()
440+
settings = HandshakeSettings()
441+
settings.minVersion = (3,4)
442+
settings.maxVersion = (3,4)
443+
connection.handshakeClientCert(x509Chain, x509Key, settings=settings)
444+
testConnClient(connection)
419445
assert(isinstance(connection.session.serverCertChain, X509CertChain))
420446
connection.close()
421447

@@ -857,6 +883,37 @@ def connect():
857883

858884
test_no += 1
859885

886+
print("Test {0} - resumption in TLSv1.3 with mutual X509".format(test_no))
887+
synchro.recv(1)
888+
connection = connect()
889+
settings = HandshakeSettings()
890+
settings.minVersion = (3,4)
891+
# force HRR
892+
settings.keyShares = []
893+
connection.handshakeClientCert(x509Chain, x509Key, serverName=address[0],
894+
settings=settings)
895+
testConnClient(connection)
896+
assert isinstance(connection.session.serverCertChain, X509CertChain)
897+
assert connection.session.serverName == address[0]
898+
assert not connection.resumed
899+
assert connection.session.tickets
900+
connection.close()
901+
session = connection.session
902+
903+
# resume
904+
synchro.recv(1)
905+
settings = HandshakeSettings()
906+
settings.minVersion = (3,4)
907+
settings.keyShares = []
908+
connection = connect()
909+
connection.handshakeClientCert(x509Chain, x509Key, serverName=address[0], session=session,
910+
settings=settings)
911+
testConnClient(connection)
912+
assert connection.resumed
913+
connection.close()
914+
915+
test_no += 1
916+
860917
print("Test {0} - Heartbeat extension response callback in TLSv1.2".format(test_no))
861918
heartbeat_payload = os.urandom(50)
862919
def heartbeat_response_check(message):
@@ -1312,6 +1369,32 @@ def connect():
13121369

13131370
test_no += 1
13141371

1372+
print("Test {0} - good mutual X.509, TLSv1.3 no certs".format(test_no))
1373+
synchro.send(b'R')
1374+
connection = connect()
1375+
settings = HandshakeSettings()
1376+
settings.minVersion = (3,4)
1377+
settings.maxVersion = (3,4)
1378+
connection.handshakeServer(certChain=x509Chain, privateKey=x509Key, reqCert=True, settings=settings)
1379+
testConnServer(connection)
1380+
assert not connection.session.clientCertChain
1381+
connection.close()
1382+
1383+
test_no += 1
1384+
1385+
print("Test {0} - good mutual X.509, TLSv1.3".format(test_no))
1386+
synchro.send(b'R')
1387+
connection = connect()
1388+
settings = HandshakeSettings()
1389+
settings.minVersion = (3,4)
1390+
settings.maxVersion = (3,4)
1391+
connection.handshakeServer(certChain=x509Chain, privateKey=x509Key, reqCert=True, settings=settings)
1392+
testConnServer(connection)
1393+
assert isinstance(connection.session.clientCertChain, X509CertChain)
1394+
connection.close()
1395+
1396+
test_no += 1
1397+
13151398
print("Test {0} - good mutual X.509, TLSv1.1".format(test_no))
13161399
synchro.send(b'R')
13171400
connection = connect()
@@ -1660,6 +1743,7 @@ def server_bind(self):
16601743
synchro.send(b'R')
16611744
connection = connect()
16621745
settings = HandshakeSettings()
1746+
settings.minVersion = (3,4)
16631747
settings.ticketKeys = [getRandomBytes(32)]
16641748
connection.handshakeServer(certChain=x509Chain, privateKey=x509Key,
16651749
settings=settings)
@@ -1676,6 +1760,28 @@ def server_bind(self):
16761760

16771761
test_no += 1
16781762

1763+
print("Test {0} - resumption in TLSv1.3 with mutual X509".format(test_no))
1764+
synchro.send(b'R')
1765+
connection = connect()
1766+
settings = HandshakeSettings()
1767+
settings.minVersion = (3,4)
1768+
settings.ticketKeys = [getRandomBytes(32)]
1769+
connection.handshakeServer(certChain=x509Chain, privateKey=x509Key,
1770+
reqCert=True, settings=settings)
1771+
testConnServer(connection)
1772+
connection.close()
1773+
1774+
# resume
1775+
synchro.send(b'R')
1776+
connection = connect()
1777+
connection.handshakeServer(certChain=x509Chain, privateKey=x509Key,
1778+
reqCert=True, settings=settings)
1779+
testConnServer(connection)
1780+
assert connection.session.clientCertChain
1781+
connection.close()
1782+
1783+
test_no += 1
1784+
16791785
print("Test {0} - Heartbeat extension response callback in TLSv1.2".format(test_no))
16801786
heartbeat_payload = os.urandom(50)
16811787
def heartbeat_response_check(message):

tlslite/constants.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ class SignatureScheme(TLSEnum):
203203
"""
204204

205205
rsa_pkcs1_sha1 = (2, 1)
206+
rsa_pkcs1_sha224 = (3, 1)
206207
rsa_pkcs1_sha256 = (4, 1)
207208
rsa_pkcs1_sha384 = (5, 1)
208209
rsa_pkcs1_sha512 = (6, 1)

tlslite/keyexchange.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
getPointByteSize
1818
from .utils.rsakey import RSAKey
1919
from .utils.cryptomath import bytesToNumber, getRandomBytes, powMod, \
20-
numBits, numberToByteArray, divceil, numBytes
20+
numBits, numberToByteArray, divceil, numBytes, secureHash
2121
from .utils.lists import getFirstMatching
2222
from .utils import tlshashlib as hashlib
2323
from .utils.x25519 import x25519, x448, X25519_G, X448_G, X25519_ORDER_SIZE, \
@@ -200,7 +200,8 @@ def verifyServerKeyExchange(serverKeyExchange, publicKey, clientRandom,
200200

201201
@staticmethod
202202
def calcVerifyBytes(version, handshakeHashes, signatureAlg,
203-
premasterSecret, clientRandom, serverRandom):
203+
premasterSecret, clientRandom, serverRandom,
204+
prf_name = None, peer_tag=b'client'):
204205
"""Calculate signed bytes for Certificate Verify"""
205206
if version == (3, 0):
206207
masterSecret = calcMasterSecret(version,
@@ -222,6 +223,17 @@ def calcVerifyBytes(version, handshakeHashes, signatureAlg,
222223
verifyBytes = handshakeHashes.digest(hashName)
223224
if padding == 'pkcs1':
224225
verifyBytes = RSAKey.addPKCS1Prefix(verifyBytes, hashName)
226+
elif version == (3, 4):
227+
scheme = SignatureScheme.toRepr(signatureAlg)
228+
hash_name = SignatureScheme.getHash(scheme)
229+
verifyBytes = bytearray(b'\x20' * 64 +
230+
b'TLS 1.3, ' + peer_tag +
231+
b' CertificateVerify' +
232+
b'\x00') + \
233+
handshakeHashes.digest(prf_name)
234+
verifyBytes = secureHash(verifyBytes, hash_name)
235+
else:
236+
raise ValueError("Unsupported TLS version {}".format(version))
225237
return verifyBytes
226238

227239
@staticmethod

0 commit comments

Comments
 (0)