Skip to content

Commit

Permalink
Merge 9a4d655 into c32629e
Browse files Browse the repository at this point in the history
  • Loading branch information
inikolcev committed Mar 31, 2020
2 parents c32629e + 9a4d655 commit 203462d
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 133 deletions.
12 changes: 6 additions & 6 deletions tlslite/keyexchange.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@

import ecdsa
from .mathtls import goodGroupParameters, makeK, makeU, makeX, \
calcMasterSecret, paramStrength, RFC7919_GROUPS
paramStrength, RFC7919_GROUPS, calcKey
from .errors import TLSInsufficientSecurity, TLSUnknownPSKIdentity, \
TLSIllegalParameterException, TLSDecryptionFailed, TLSInternalError, \
TLSDecodeError
Expand Down Expand Up @@ -260,11 +260,11 @@ def calcVerifyBytes(version, handshakeHashes, signatureAlg,
prf_name = None, peer_tag=b'client', key_type="rsa"):
"""Calculate signed bytes for Certificate Verify"""
if version == (3, 0):
masterSecret = calcMasterSecret(version,
0,
premasterSecret,
clientRandom,
serverRandom)
masterSecret = calcKey(version, premasterSecret,
0, "master secret",
clientRandom=clientRandom,
serverRandom=serverRandom,
outputLength=48)
verifyBytes = handshakeHashes.digestSSL(masterSecret, b"")
elif version in ((3, 1), (3, 2)):
if key_type != "ecdsa":
Expand Down
79 changes: 79 additions & 0 deletions tlslite/mathtls.py
Original file line number Diff line number Diff line change
Expand Up @@ -595,6 +595,85 @@ def calcFinished(version, masterSecret, cipherSuite, handshakeHashes,

return verifyData

def calcKey(version, secret, cipherSuite, label, handshakeHashes=None,
clientRandom=None, serverRandom=None, outputLength=None):
"""
Method for calculating different keys depending on input.
It can be used to calculate finished value, master secret,
extended master secret or key expansion.
:param version: TLS protocol version tuple
:param secret: master secret or premasterSecret which will be
used in the PRF.
:param cipherSuite: Negotiated cipher suite of the connection.
:param label: label for the key you want to calculate
(ex. 'master secret', 'extended master secret', etc).
:param handshakeHashes: running hash of the handshake messages
needed for calculating extended master secret or finished value.
:param clientRandom: client random needed for calculating
master secret or key expansion.
:param serverRandom: server random needed for calculating
master secret or key expansion.
:outputLength: Number of bytes to output.
"""


# SSL3 calculations.
if version == (3, 0):
# Calculating Finished value, either for message sent
# by server or by client
if label == "client finished":
senderStr = b"\x43\x4C\x4E\x54"
return handshakeHashes.digestSSL(secret, senderStr)
elif label == "server finished":
senderStr = b"\x53\x52\x56\x52"
return handshakeHashes.digestSSL(secret, senderStr)
else:
assert label in ["key expansion", "master secret"]
func = PRF_SSL

# TLS1.0 or TLS1.1 calculations.
elif version in ((3, 1), (3, 2)):
func = PRF
# Seed needed for calculating extended master secret
if label == "extended master secret":
seed = handshakeHashes.digest('md5') + \
handshakeHashes.digest('sha1')
# Seed needed for calculating Finished value
elif label in ["server finished", "client finished"]:
seed = handshakeHashes.digest()
else:
assert label in ["key expansion", "master secret"]

# TLS1.2 calculations.
else:
assert version == (3, 3)
if cipherSuite in CipherSuite.sha384PrfSuites:
func = PRF_1_2_SHA384
# Seed needed for calculating Finished value or extended master
# secret
if label in ["extended master secret", "server finished",
"client finished"]:
seed = handshakeHashes.digest('sha384')
else:
assert label in ["key expansion", "master secret"]
else:
# Same as above, just using sha256
func = PRF_1_2
if label in ["extended master secret", "server finished",
"client finished"]:
seed = handshakeHashes.digest('sha256')
else:
assert label in ["key expansion", "master secret"]

# Seed needed for calculating key expansion or master secret
if label == "key expansion": seed = serverRandom + clientRandom
if label == "master secret": seed = clientRandom + serverRandom

if func == PRF_SSL:
return func(secret, seed, outputLength)
return func(secret, compatAscii2Bytes(label), seed, outputLength)

def makeX(salt, username, password):
if len(username)>=256:
raise ValueError("username too long")
Expand Down
37 changes: 5 additions & 32 deletions tlslite/recordlayer.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@
from .errors import TLSRecordOverflow, TLSIllegalParameterException,\
TLSAbruptCloseError, TLSDecryptionFailed, TLSBadRecordMAC, \
TLSUnexpectedMessage
from .mathtls import createMAC_SSL, createHMAC, PRF_SSL, PRF, PRF_1_2, \
PRF_1_2_SHA384
from .mathtls import createMAC_SSL, createHMAC, calcKey

class RecordSocket(object):
"""
Expand Down Expand Up @@ -1097,34 +1096,6 @@ def _getHMACMethod(version):

return createMACFunc

def _calcKeyBlock(self, cipherSuite, masterSecret, clientRandom,
serverRandom, outputLength):
"""Calculate the overall key to slice up"""
if self.version == (3, 0):
keyBlock = PRF_SSL(masterSecret,
serverRandom + clientRandom,
outputLength)
elif self.version in ((3, 1), (3, 2)):
keyBlock = PRF(masterSecret,
b"key expansion",
serverRandom + clientRandom,
outputLength)
elif self.version == (3, 3):
if cipherSuite in CipherSuite.sha384PrfSuites:
keyBlock = PRF_1_2_SHA384(masterSecret,
b"key expansion",
serverRandom + clientRandom,
outputLength)
else:
keyBlock = PRF_1_2(masterSecret,
b"key expansion",
serverRandom + clientRandom,
outputLength)
else:
raise AssertionError()

return keyBlock

def calcSSL2PendingStates(self, cipherSuite, masterSecret, clientRandom,
serverRandom, implementations):
"""
Expand Down Expand Up @@ -1215,8 +1186,10 @@ def calcPendingStates(self, cipherSuite, masterSecret, clientRandom,
outputLength = (macLength*2) + (keyLength*2) + (ivLength*2)

#Calculate Keying Material from Master Secret
keyBlock = self._calcKeyBlock(cipherSuite, masterSecret, clientRandom,
serverRandom, outputLength)
keyBlock = calcKey(self.version, masterSecret, cipherSuite,
"key expansion", clientRandom=clientRandom,
serverRandom=serverRandom,
outputLength=outputLength)

#Slice up Keying Material
clientPendingState = ConnectionState()
Expand Down
65 changes: 37 additions & 28 deletions tlslite/tlsconnection.py
Original file line number Diff line number Diff line change
Expand Up @@ -1788,16 +1788,16 @@ def _clientFinished(self, premasterSecret, clientRandom, serverRandom,
# use the certificate authentication, the hashes are the same
if not cvhh:
cvhh = self._handshake_hash
masterSecret = calcExtendedMasterSecret(self.version,
cipherSuite,
premasterSecret,
cvhh)
masterSecret = calcKey(self.version, premasterSecret,
cipherSuite, "extended master secret",
handshakeHashes=cvhh,
outputLength=48)
else:
masterSecret = calcMasterSecret(self.version,
cipherSuite,
premasterSecret,
clientRandom,
serverRandom)
masterSecret = calcKey(self.version, premasterSecret,
cipherSuite, "master secret",
clientRandom=clientRandom,
serverRandom=serverRandom,
outputLength=48)
self._calcPendingStates(cipherSuite, masterSecret,
clientRandom, serverRandom,
cipherImplementations)
Expand Down Expand Up @@ -4069,16 +4069,16 @@ def _serverFinished(self, premasterSecret, clientRandom, serverRandom,
# to regular handshake hash
if not cvhh:
cvhh = self._handshake_hash
masterSecret = calcExtendedMasterSecret(self.version,
cipherSuite,
premasterSecret,
cvhh)
masterSecret = calcKey(self.version, premasterSecret,
cipherSuite, "extended master secret",
handshakeHashes=cvhh,
outputLength=48)
else:
masterSecret = calcMasterSecret(self.version,
cipherSuite,
premasterSecret,
clientRandom,
serverRandom)
masterSecret = calcKey(self.version, premasterSecret,
cipherSuite, "master secret",
clientRandom=clientRandom,
serverRandom=serverRandom,
outputLength=48)

#Calculate pending connection states
self._calcPendingStates(cipherSuite, masterSecret,
Expand Down Expand Up @@ -4125,12 +4125,16 @@ def _sendFinished(self, masterSecret, cipherSuite=None, nextProto=None,
for result in self._sendMsg(nextProtoMsg):
yield result

#Figure out the correct label to use
if self._client:
label = "client finished"
else:
label = "server finished"
#Calculate verification data
verifyData = calcFinished(self.version,
masterSecret,
cipherSuite,
self._handshake_hash,
self._client)
verifyData = calcKey(self.version, masterSecret,
cipherSuite, label,
handshakeHashes=self._handshake_hash,
outputLength=12)
if self.fault == Fault.badFinished:
verifyData[0] = (verifyData[0]+1)%256

Expand Down Expand Up @@ -4175,12 +4179,17 @@ def _getFinished(self, masterSecret, cipherSuite=None,
if nextProto:
self.next_proto = nextProto

#Figure out which label to use.
if self._client:
label = "server finished"
else:
label = "client finished"

#Calculate verification data
verifyData = calcFinished(self.version,
masterSecret,
cipherSuite,
self._handshake_hash,
not self._client)
verifyData = calcKey(self.version, masterSecret,
cipherSuite, label,
handshakeHashes=self._handshake_hash,
outputLength=12)

#Get and check Finished message under new state
for result in self._getMsg(ContentType.handshake,
Expand Down

0 comments on commit 203462d

Please sign in to comment.