Skip to content

Commit 7e6cd9b

Browse files
verifying DSA signatures in SKE
1 parent a6cde37 commit 7e6cd9b

11 files changed

+721
-72
lines changed

tlslite/constants.py

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ def getHash(scheme):
304304
kType, _, hName = vals
305305
else:
306306
kType, _, _, hName = vals
307-
assert kType in ('rsa', 'ecdsa')
307+
assert kType in ('rsa', 'ecdsa', 'dsa')
308308
return hName
309309

310310

@@ -960,6 +960,7 @@ class CipherSuite:
960960
tripleDESSuites.append(TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) # unsupported
961961
tripleDESSuites.append(TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) # unsupp
962962

963+
963964
#: AES-128 CBC ciphers
964965
aes128Suites = []
965966
aes128Suites.append(TLS_SRP_SHA_WITH_AES_128_CBC_SHA)
@@ -1258,6 +1259,8 @@ def filter_for_certificate(suites, cert_chain):
12581259
CipherSuite.certSuites)
12591260
if cert_chain.x509List[0].certAlg == "ecdsa":
12601261
includeSuites.update(CipherSuite.ecdheEcdsaSuites)
1262+
if cert_chain.x509List[0].certAlg == "dsa":
1263+
includeSuites.update(CipherSuite.dheDsaSuites)
12611264
else:
12621265
includeSuites.update(CipherSuite.srpSuites)
12631266
includeSuites.update(CipherSuite.anonSuites)
@@ -1318,6 +1321,8 @@ def _filterSuites(suites, settings, version=None):
13181321
keyExchangeSuites += CipherSuite.certSuites
13191322
if "dhe_rsa" in keyExchangeNames:
13201323
keyExchangeSuites += CipherSuite.dheCertSuites
1324+
if "dhe_dsa" in keyExchangeNames:
1325+
keyExchangeSuites += CipherSuite.dheDsaSuites
13211326
if "ecdhe_rsa" in keyExchangeNames:
13221327
keyExchangeSuites += CipherSuite.ecdheCertSuites
13231328
if "ecdhe_ecdsa" in keyExchangeNames:
@@ -1361,6 +1366,17 @@ def getSrpCertSuites(cls, settings, version=None):
13611366
"""Return SRP cipher suites that use server certificates"""
13621367
return cls._filterSuites(CipherSuite.srpCertSuites, settings, version)
13631368

1369+
#: SRP key exchange, DSA authentication
1370+
srpDsaSuites = []
1371+
srpDsaSuites.append(TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) # unsupported
1372+
srpDsaSuites.append(TLS_SRP_SHA_DSS_WITH_AES_128_CBC_SHA) # unsupported
1373+
srpDsaSuites.append(TLS_SRP_SHA_DSS_WITH_AES_256_CBC_SHA) # unsupported
1374+
1375+
@classmethod
1376+
def getSrpDsaSuites(cls, settings, version=None):
1377+
"""Return SRP DSA cipher suites that use server certificates"""
1378+
return cls._filterSuites(CipherSuite.srpCertSuites, settings, version)
1379+
13641380
#: All that use SRP key exchange
13651381
srpAllSuites = srpSuites + srpCertSuites
13661382

@@ -1460,6 +1476,22 @@ def getEcdsaSuites(cls, settings, version=None):
14601476
return cls._filterSuites(CipherSuite.ecdheEcdsaSuites,
14611477
settings, version)
14621478

1479+
#: DHE key exchange, DSA authentication
1480+
dheDsaSuites = []
1481+
dheDsaSuites.append(TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA)
1482+
dheDsaSuites.append(TLS_DHE_DSS_WITH_AES_128_CBC_SHA)
1483+
dheDsaSuites.append(TLS_DHE_DSS_WITH_AES_256_CBC_SHA)
1484+
dheDsaSuites.append(TLS_DHE_DSS_WITH_AES_128_CBC_SHA256)
1485+
dheDsaSuites.append(TLS_DHE_DSS_WITH_AES_256_CBC_SHA256)
1486+
dheDsaSuites.append(TLS_DHE_DSS_WITH_AES_128_GCM_SHA256)
1487+
dheDsaSuites.append(TLS_DHE_DSS_WITH_AES_256_GCM_SHA384)
1488+
1489+
@classmethod
1490+
def getDheDsaSuites(cls, settings, version=None):
1491+
"""Provide DSA authenticated ciphersuites matching settings"""
1492+
return cls._filterSuites(CipherSuite.dheDsaSuites,
1493+
settings, version)
1494+
14631495
#: anon FFDHE key exchange
14641496
anonSuites = []
14651497
anonSuites.append(TLS_DH_ANON_WITH_AES_256_GCM_SHA384)
@@ -1476,7 +1508,7 @@ def getAnonSuites(cls, settings, version=None):
14761508
"""Provide anonymous DH ciphersuites matching settings"""
14771509
return cls._filterSuites(CipherSuite.anonSuites, settings, version)
14781510

1479-
dhAllSuites = dheCertSuites + anonSuites
1511+
dhAllSuites = dheCertSuites + anonSuites + dheDsaSuites
14801512

14811513
#: anon ECDHE key exchange
14821514
ecdhAnonSuites = []

tlslite/handshakesettings.py

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
CIPHER_IMPLEMENTATIONS = ["openssl", "pycrypto", "python"]
2929
CERTIFICATE_TYPES = ["x509"]
3030
RSA_SIGNATURE_HASHES = ["sha512", "sha384", "sha256", "sha224", "sha1"]
31+
DSA_SIGNATURE_HASHES = ["sha512", "sha384", "sha256", "sha224", "sha1"]
3132
ECDSA_SIGNATURE_HASHES = ["sha512", "sha384", "sha256", "sha224", "sha1"]
3233
ALL_RSA_SIGNATURE_HASHES = RSA_SIGNATURE_HASHES + ["md5"]
3334
RSA_SCHEMES = ["pss", "pkcs1"]
@@ -234,6 +235,16 @@ class HandshakeSettings(object):
234235
The allowed hashes are: "md5", "sha1", "sha224", "sha256",
235236
"sha384" and "sha512". The default list does not include md5.
236237
238+
:vartype dsaSigHashes: list(str)
239+
:ivar dsaSigHashes: List of hashes supported (and advertised as such) for
240+
TLS 1.2 signatures over Server Key Exchange or Certificate Verify with
241+
DSA signature algorithm.
242+
243+
The list is sorted from most wanted to least wanted algorithm.
244+
245+
The allowed hashes are: "sha1", "sha224", "sha256",
246+
"sha384" and "sha512".
247+
237248
:vartype ecdsaSigHashes: list(str)
238249
:ivar ecdsaSigHashes: List of hashes supported (and advertised as such) for
239250
TLS 1.2 signatures over Server Key Exchange or Certificate Verify with
@@ -337,6 +348,7 @@ def _init_key_settings(self):
337348
self.maxKeySize = 8193
338349
self.rsaSigHashes = list(RSA_SIGNATURE_HASHES)
339350
self.rsaSchemes = list(RSA_SCHEMES)
351+
self.dsaSigHashes = list(DSA_SIGNATURE_HASHES)
340352
self.virtual_hosts = []
341353
# DH key settings
342354
self.eccCurves = list(CURVE_NAMES)
@@ -510,8 +522,14 @@ def _sanityCheckPrimitivesNames(other):
510522
raise ValueError("Unknown RSA padding mode: '{0}'"
511523
.format(unknownRSAPad))
512524

525+
unknownSigHash = not_matching(other.dsaSigHashes,
526+
ALL_RSA_SIGNATURE_HASHES)
527+
if unknownSigHash:
528+
raise ValueError("Unknown DSA signature hash: '{0}'"
529+
.format(unknownSigHash))
530+
513531
if not other.rsaSigHashes and not other.ecdsaSigHashes and \
514-
other.maxVersion >= (3, 3):
532+
not other.dsaSigHashes and other.maxVersion >= (3, 3):
515533
raise ValueError("TLS 1.2 requires signature algorithms to be set")
516534

517535
@staticmethod
@@ -668,6 +686,7 @@ def _copy_key_settings(self, other):
668686
other.certificateTypes = self.certificateTypes
669687
other.rsaSigHashes = self.rsaSigHashes
670688
other.rsaSchemes = self.rsaSchemes
689+
other.dsaSigHashes = self.dsaSigHashes
671690
other.ecdsaSigHashes = self.ecdsaSigHashes
672691
other.virtual_hosts = self.virtual_hosts
673692
# DH key params

tlslite/keyexchange.py

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,34 @@ def _tls12_sign_ecdsa_SKE(self, serverKeyExchange, sigHash=None):
100100
ecdsa.util.sigdecode_der):
101101
raise TLSInternalError("signature validation failure")
102102

103+
def _tls12_sign_dsa_SKE(self, serverKeyExchange, sigHash=None):
104+
"""Sign a TLSv1.2 SKE message."""
105+
try:
106+
serverKeyExchange.hashAlg, serverKeyExchange.signAlg = \
107+
getattr(SignatureScheme, sigHash)
108+
hashName = SignatureScheme.getHash(sigHash)
109+
110+
except AttributeError:
111+
serverKeyExchange.signAlg = SignatureAlgorithm.dsa
112+
serverKeyExchange.hashAlg = getattr(HashAlgorithm, sigHash)
113+
keyType = 'dsa'
114+
hashName = sigHash
115+
116+
hash_bytes = serverKeyExchange.hash(self.clientHello.random,
117+
self.serverHello.random)
118+
119+
serverKeyExchange.signature = \
120+
self.privateKey.sign(hashBytes,
121+
hashAlg=hashName)
122+
123+
if not serverKeyExchange.signature:
124+
raise TLSInternalError("Empty signature")
125+
126+
if not self.privateKey.verify(serverKeyExchange.signature,
127+
hashBytes,
128+
hashAlg=hashName):
129+
raise TLSInternalError("Server Key Exchange signature invalid")
130+
103131
def _tls12_signSKE(self, serverKeyExchange, sigHash=None):
104132
"""Sign a TLSv1.2 SKE message."""
105133
try:
@@ -148,6 +176,8 @@ def signServerKeyExchange(self, serverKeyExchange, sigHash=None):
148176
if self.serverHello.server_version < (3, 3):
149177
if self.privateKey.key_type == "ecdsa":
150178
serverKeyExchange.signAlg = SignatureAlgorithm.ecdsa
179+
if self.privateKey.key_type == "dsa":
180+
serverKeyExchange.signAlg = SignatureAlgorithm.dsa
151181
hashBytes = serverKeyExchange.hash(self.clientHello.random,
152182
self.serverHello.random)
153183

@@ -162,6 +192,8 @@ def signServerKeyExchange(self, serverKeyExchange, sigHash=None):
162192
else:
163193
if self.privateKey.key_type == "ecdsa":
164194
self._tls12_sign_ecdsa_SKE(serverKeyExchange, sigHash)
195+
elif self.privateKey.key_type == "dsa":
196+
self._tls12_sign_dsa_SKE(serverKeyExchange, sigHash)
165197
else:
166198
self._tls12_signSKE(serverKeyExchange, sigHash)
167199

@@ -183,6 +215,19 @@ def _tls12_verify_ecdsa_SKE(serverKeyExchange, publicKey, clientRandom,
183215
raise TLSDecryptionFailed("Server Key Exchange signature "
184216
"invalid")
185217

218+
@staticmethod
219+
def _tls12_verify_dsa_SKE(serverKeyExchange, publicKey, clientRandom,
220+
serverRandom, validSigAlgs):
221+
hashName = HashAlgorithm.toRepr(serverKeyExchange.hashAlg)
222+
if not hashName:
223+
raise TLSIllegalParameterException("Unknown hash algorithm")
224+
225+
hashBytes = serverKeyExchange.hash(clientRandom, serverRandom)
226+
227+
if not publicKey.verify(serverKeyExchange.signature, hashBytes):
228+
raise TLSDecryptionFailed("Server Key Exchange signature "
229+
"invalid")
230+
186231
@staticmethod
187232
def _tls12_verify_SKE(serverKeyExchange, publicKey, clientRandom,
188233
serverRandom, validSigAlgs):
@@ -198,6 +243,14 @@ def _tls12_verify_SKE(serverKeyExchange, publicKey, clientRandom,
198243
clientRandom,
199244
serverRandom,
200245
validSigAlgs)
246+
247+
elif serverKeyExchange.signAlg == SignatureAlgorithm.dsa:
248+
return KeyExchange._tls12_verify_dsa_SKE(serverKeyExchange,
249+
publicKey,
250+
clientRandom,
251+
serverRandom,
252+
validSigAlgs)
253+
201254
schemeID = (serverKeyExchange.hashAlg,
202255
serverKeyExchange.signAlg)
203256
scheme = SignatureScheme.toRepr(schemeID)

tlslite/messages.py

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1517,7 +1517,8 @@ def parse(self, parser):
15171517
raise AssertionError()
15181518

15191519
if self.cipherSuite in CipherSuite.certAllSuites or\
1520-
self.cipherSuite in CipherSuite.ecdheEcdsaSuites:
1520+
self.cipherSuite in CipherSuite.ecdheEcdsaSuites or\
1521+
self.cipherSuite in CipherSuite.dheDsaSuites:
15211522
if self.version == (3, 3):
15221523
self.hashAlg = parser.get(1)
15231524
self.signAlg = parser.get(1)
@@ -1566,7 +1567,8 @@ def write(self):
15661567
writer = Writer()
15671568
writer.bytes += self.writeParams()
15681569
if self.cipherSuite in CipherSuite.certAllSuites or \
1569-
self.cipherSuite in CipherSuite.ecdheEcdsaSuites:
1570+
self.cipherSuite in CipherSuite.ecdheEcdsaSuites or \
1571+
self.cipherSuite in CipherSuite.dheDsaSuites:
15701572
if self.version >= (3, 3):
15711573
assert self.hashAlg != 0 and self.signAlg != 0
15721574
writer.add(self.hashAlg, 1)
@@ -1591,9 +1593,10 @@ def hash(self, clientRandom, serverRandom):
15911593
else:
15921594
hashAlg = SignatureScheme.getHash(sigScheme)
15931595
return secureHash(bytesToHash, hashAlg)
1594-
# ECDSA ciphers in TLS 1.1 and earlier sign the messages using
1596+
# DSA and ECDSA ciphers in TLS 1.1 and earlier sign the messages using
15951597
# SHA-1 only
1596-
if self.cipherSuite in CipherSuite.ecdheEcdsaSuites:
1598+
if self.cipherSuite in CipherSuite.ecdheEcdsaSuites or\
1599+
self.cipherSuite in CipherSuite.dheDsaSuites:
15971600
return SHA1(bytesToHash)
15981601
return MD5(bytesToHash) + SHA1(bytesToHash)
15991602

0 commit comments

Comments
 (0)