Skip to content

Commit

Permalink
verifying DSA signatures in SKE
Browse files Browse the repository at this point in the history
  • Loading branch information
FrantisekKrenzelok authored and fkrenzel committed Nov 13, 2020
1 parent 9951ec1 commit 5dc813f
Show file tree
Hide file tree
Showing 7 changed files with 534 additions and 51 deletions.
15 changes: 13 additions & 2 deletions tlslite/constants.py
Expand Up @@ -304,7 +304,7 @@ def getHash(scheme):
kType, _, hName = vals
else:
kType, _, _, hName = vals
assert kType in ('rsa', 'ecdsa')
assert kType in ('rsa', 'ecdsa', 'dsa')
return hName


Expand Down Expand Up @@ -958,6 +958,7 @@ class CipherSuite:
tripleDESSuites.append(TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA) # unsupported
tripleDESSuites.append(TLS_SRP_SHA_DSS_WITH_3DES_EDE_CBC_SHA) # unsupp


#: AES-128 CBC ciphers
aes128Suites = []
aes128Suites.append(TLS_SRP_SHA_WITH_AES_128_CBC_SHA)
Expand Down Expand Up @@ -1452,6 +1453,16 @@ def getEcdheCertSuites(cls, settings, version=None):
ecdheEcdsaSuites.append(TLS_ECDHE_ECDSA_WITH_RC4_128_SHA)
ecdheEcdsaSuites.append(TLS_ECDHE_ECDSA_WITH_NULL_SHA)

#: DHE key exchange, DSA authentication
dheDsaSuites = []
dheDsaSuites.append(TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA)
dheDsaSuites.append(TLS_DHE_DSS_WITH_AES_128_CBC_SHA)
dheDsaSuites.append(TLS_DHE_DSS_WITH_AES_256_CBC_SHA)
dheDsaSuites.append(TLS_DHE_DSS_WITH_AES_128_CBC_SHA256)
dheDsaSuites.append(TLS_DHE_DSS_WITH_AES_256_CBC_SHA256)
dheDsaSuites.append(TLS_DHE_DSS_WITH_AES_128_GCM_SHA256)
dheDsaSuites.append(TLS_DHE_DSS_WITH_AES_256_GCM_SHA384)

@classmethod
def getEcdsaSuites(cls, settings, version=None):
"""Provide ECDSA authenticated ciphersuites matching settings"""
Expand All @@ -1474,7 +1485,7 @@ def getAnonSuites(cls, settings, version=None):
"""Provide anonymous DH ciphersuites matching settings"""
return cls._filterSuites(CipherSuite.anonSuites, settings, version)

dhAllSuites = dheCertSuites + anonSuites
dhAllSuites = dheCertSuites + anonSuites + dheDsaSuites

#: anon ECDHE key exchange
ecdhAnonSuites = []
Expand Down
21 changes: 21 additions & 0 deletions tlslite/keyexchange.py
Expand Up @@ -183,6 +183,19 @@ def _tls12_verify_ecdsa_SKE(serverKeyExchange, publicKey, clientRandom,
raise TLSDecryptionFailed("Server Key Exchange signature "
"invalid")

@staticmethod
def _tls12_verify_dsa_SKE(serverKeyExchange, publicKey, clientRandom,
serverRandom, validSigAlgs):
hashName = HashAlgorithm.toRepr(serverKeyExchange.hashAlg)
if not hashName:
raise TLSIllegalParameterException("Unknown hash algorithm")

hashBytes = serverKeyExchange.hash(clientRandom, serverRandom)

if not publicKey.verify(serverKeyExchange.signature, hashBytes):
raise TLSDecryptionFailed("Server Key Exchange signature "
"invalid")

@staticmethod
def _tls12_verify_SKE(serverKeyExchange, publicKey, clientRandom,
serverRandom, validSigAlgs):
Expand All @@ -198,6 +211,14 @@ def _tls12_verify_SKE(serverKeyExchange, publicKey, clientRandom,
clientRandom,
serverRandom,
validSigAlgs)

elif serverKeyExchange.signAlg == SignatureAlgorithm.dsa:
return KeyExchange._tls12_verify_dsa_SKE(serverKeyExchange,
publicKey,
clientRandom,
serverRandom,
validSigAlgs)

schemeID = (serverKeyExchange.hashAlg,
serverKeyExchange.signAlg)
scheme = SignatureScheme.toRepr(schemeID)
Expand Down
11 changes: 7 additions & 4 deletions tlslite/messages.py
Expand Up @@ -1517,7 +1517,8 @@ def parse(self, parser):
raise AssertionError()

if self.cipherSuite in CipherSuite.certAllSuites or\
self.cipherSuite in CipherSuite.ecdheEcdsaSuites:
self.cipherSuite in CipherSuite.ecdheEcdsaSuites or\
self.cipherSuite in CipherSuite.dheDsaSuites:
if self.version == (3, 3):
self.hashAlg = parser.get(1)
self.signAlg = parser.get(1)
Expand Down Expand Up @@ -1566,7 +1567,8 @@ def write(self):
writer = Writer()
writer.bytes += self.writeParams()
if self.cipherSuite in CipherSuite.certAllSuites or \
self.cipherSuite in CipherSuite.ecdheEcdsaSuites:
self.cipherSuite in CipherSuite.ecdheEcdsaSuites or \
self.cipherSuite in CipherSuite.dheDsaSuites:
if self.version >= (3, 3):
assert self.hashAlg != 0 and self.signAlg != 0
writer.add(self.hashAlg, 1)
Expand All @@ -1591,9 +1593,10 @@ def hash(self, clientRandom, serverRandom):
else:
hashAlg = SignatureScheme.getHash(sigScheme)
return secureHash(bytesToHash, hashAlg)
# ECDSA ciphers in TLS 1.1 and earlier sign the messages using
# DSA and ECDSA ciphers in TLS 1.1 and earlier sign the messages using
# SHA-1 only
if self.cipherSuite in CipherSuite.ecdheEcdsaSuites:
if self.cipherSuite in CipherSuite.ecdheEcdsaSuites or\
self.cipherSuite in CipherSuite.dheDsaSuites:
return SHA1(bytesToHash)
return MD5(bytesToHash) + SHA1(bytesToHash)

Expand Down
41 changes: 23 additions & 18 deletions tlslite/utils/python_dsakey.py
@@ -1,12 +1,11 @@
# Author: Frantisek Krenzelok

"""Pure-Python RSA implementation."""
from ecdsa.der import encode_sequence, encode_integer, \
remove_sequence, remove_integer

from .cryptomath import getRandomNumber, getRandomPrime, \
powMod, numBits, bytesToNumber, invMod, secureHash, \
GMPY2_LOADED, gmpyLoaded
powMod, numBits, bytesToNumber, invMod, \
secureHash, GMPY2_LOADED, gmpyLoaded

if GMPY2_LOADED:
from gmpy2 import mpz
Expand Down Expand Up @@ -78,29 +77,28 @@ def generate_qp(L, N):
return (q, p)

def hashAndSign(self, data, hAlg="sha1"):
digest = bytesToNumber(secureHash(bytearray(data), hAlg))
digest_size = numBits(digest)

# extract min(|hAlg|, N) left bits of digest
hashData = (secureHash(bytearray(data), hAlg))
N = numBits(self.q)
if N < digest_size:
digest &= ~(~0 << (digest_size - N))
digest_len = len(hashData) * 8
digest = bytesToNumber(hashData)
if N < digest_len:
digest = (digest & (~0 << (digest_len - N))) >> (digest_len - N)

k = getRandomNumber(1, (self.q-1))
r = powMod(self.g, k, self.p) % self.q
s = invMod(k, self.q) * (digest + self.private_key * r) % self.q

return encode_sequence(encode_integer(r), encode_integer(s))

def hashAndVerify(self, signature, data, hAlg="sha1"):
# Get r, s components from signature
digest = bytesToNumber(secureHash(bytearray(data), hAlg))
digest_size = numBits(digest)

# extract min(|hAlg|, N) left bits of digest
def verify(self, signature, hashData):
N = numBits(self.q)
if N < digest_size:
digest &= ~(~0 << (digest_size - N))
digest_len = len(hashData) * 8
digest = bytesToNumber(hashData)

if N < digest_len:
digest = (digest & (~0 << (digest_len - N))) >> (digest_len - N)

signature = bytes(signature) #fix for python 2.6

# get r, s keys
if not signature:
Expand All @@ -113,13 +111,20 @@ def hashAndVerify(self, signature, data, hAlg="sha1"):
if rest:
return False

if gmpyLoaded or GMPY2_LOADED:
r = mpz(r)
s = mpz(s)

# check the signature
if 0 < r < self.q and 0 < s < self.q:
w = invMod(s, self.q)
u1 = (digest * w) % self.q
u2 = (r * w) % self.q
v = ((powMod(self.g, u1, self.p) * \
powMod(self.public_key, u2, self.p)) % self.p) % self.q

return r == v
return False

def hashAndVerify(self, signature, data, hAlg="sha1"):
digest = secureHash(bytearray(data), hAlg)
return self.verify(signature, digest)

0 comments on commit 5dc813f

Please sign in to comment.