1
2
3
4
5 """Handling of cryptographic operations for key exchange"""
6
7 from .mathtls import goodGroupParameters, makeK, makeU, makeX, calcMasterSecret
8 from .errors import TLSInsufficientSecurity, TLSUnknownPSKIdentity, \
9 TLSIllegalParameterException, TLSDecryptionFailed, TLSInternalError, \
10 TLSLocalAlert
11 from .messages import ServerKeyExchange, ClientKeyExchange, CertificateVerify
12 from .constants import SignatureAlgorithm, HashAlgorithm, CipherSuite, \
13 ExtensionType, GroupName, ECCurveType, AlertDescription
14 from .utils.ecc import decodeX962Point, encodeX962Point, getCurveByName, \
15 getPointByteSize
16 from .utils.rsakey import RSAKey
17 from .utils.cryptomath import bytesToNumber, getRandomBytes, powMod, \
18 numBits, numberToByteArray
19 import ecdsa
22 """
23 Common API for calculating Premaster secret
24
25 NOT stable, will get moved from this file
26 """
27
28 - def __init__(self, cipherSuite, clientHello, serverHello, privateKey):
29 """Initialize KeyExchange. privateKey is the signing private key"""
30 self.cipherSuite = cipherSuite
31 self.clientHello = clientHello
32 self.serverHello = serverHello
33 self.privateKey = privateKey
34
36 """
37 Create a ServerKeyExchange object
38
39 Returns a ServerKeyExchange object for the server's initial leg in the
40 handshake. If the key exchange method does not send ServerKeyExchange
41 (e.g. RSA), it returns None.
42 """
43 raise NotImplementedError()
44
46 """
47 Create a ClientKeyExchange object
48
49 Returns a ClientKeyExchange for the second flight from client in the
50 handshake.
51 """
52 return ClientKeyExchange(self.cipherSuite,
53 self.serverHello.server_version)
54
56 """
57 Process ClientKeyExchange and return premaster secret
58
59 Processes the client's ClientKeyExchange message and returns the
60 premaster secret. Raises TLSLocalAlert on error.
61 """
62 raise NotImplementedError()
63
66 """Process the server KEX and return premaster secret"""
67 raise NotImplementedError()
68
70 """
71 Sign a server key best matching supported algorithms
72
73 @type sigHash: str
74 @param sigHash: name of the hash used for signing
75 """
76 if self.serverHello.server_version >= (3, 3):
77 serverKeyExchange.signAlg = SignatureAlgorithm.rsa
78 serverKeyExchange.hashAlg = getattr(HashAlgorithm, sigHash)
79 hashBytes = serverKeyExchange.hash(self.clientHello.random,
80 self.serverHello.random)
81
82 if self.serverHello.server_version >= (3, 3):
83 hashBytes = RSAKey.addPKCS1Prefix(hashBytes, sigHash)
84
85 serverKeyExchange.signature = self.privateKey.sign(hashBytes)
86
87 @staticmethod
90 """Verify signature on the Server Key Exchange message
91
92 the only acceptable signature algorithms are specified by validSigAlgs
93 """
94 if serverKeyExchange.version >= (3, 3):
95 if (serverKeyExchange.hashAlg, serverKeyExchange.signAlg) not in \
96 validSigAlgs:
97 raise TLSIllegalParameterException("Server selected "
98 "invalid signature "
99 "algorithm")
100 assert serverKeyExchange.signAlg == SignatureAlgorithm.rsa
101 hashName = HashAlgorithm.toRepr(serverKeyExchange.hashAlg)
102 if hashName is None:
103 raise TLSIllegalParameterException("Unknown signature "
104 "algorithm")
105 hashBytes = serverKeyExchange.hash(clientRandom, serverRandom)
106
107 if serverKeyExchange.version == (3, 3):
108 hashBytes = RSAKey.addPKCS1Prefix(hashBytes, hashName)
109
110 sigBytes = serverKeyExchange.signature
111 if not sigBytes:
112 raise TLSIllegalParameterException("Empty signature")
113
114 if not publicKey.verify(sigBytes, hashBytes):
115 raise TLSDecryptionFailed("Server Key Exchange signature "
116 "invalid")
117
118 @staticmethod
119 - def calcVerifyBytes(version, handshakeHashes, signatureAlg,
120 premasterSecret, clientRandom, serverRandom):
121 """Calculate signed bytes for Certificate Verify"""
122 if version == (3, 0):
123 masterSecret = calcMasterSecret(version,
124 0,
125 premasterSecret,
126 clientRandom,
127 serverRandom)
128 verifyBytes = handshakeHashes.digestSSL(masterSecret, b"")
129 elif version in ((3, 1), (3, 2)):
130 verifyBytes = handshakeHashes.digest()
131 elif version == (3, 3):
132 hashName = HashAlgorithm.toRepr(signatureAlg[0])
133 verifyBytes = handshakeHashes.digest(hashName)
134 verifyBytes = RSAKey.addPKCS1Prefix(verifyBytes, hashName)
135 return verifyBytes
136
137 @staticmethod
138 - def makeCertificateVerify(version, handshakeHashes, validSigAlgs,
139 privateKey, certificateRequest, premasterSecret,
140 clientRandom, serverRandom):
141 """Create a Certificate Verify message
142
143 @param version: protocol version in use
144 @param handshakeHashes: the running hash of all handshake messages
145 @param validSigAlgs: acceptable signature algorithms for client side,
146 applicable only to TLSv1.2 (or later)
147 @param certificateRequest: the server provided Certificate Request
148 message
149 @param premasterSecret: the premaster secret, needed only for SSLv3
150 @param clientRandom: client provided random value, needed only for SSLv3
151 @param serverRandom: server provided random value, needed only for SSLv3
152 """
153 signatureAlgorithm = None
154
155 if version == (3, 3):
156 serverSigAlgs = certificateRequest.supported_signature_algs
157 signatureAlgorithm = next((sigAlg for sigAlg in validSigAlgs \
158 if sigAlg in serverSigAlgs), None)
159
160 if signatureAlgorithm is None:
161 signatureAlgorithm = validSigAlgs[0]
162 verifyBytes = KeyExchange.calcVerifyBytes(version, handshakeHashes,
163 signatureAlgorithm,
164 premasterSecret,
165 clientRandom,
166 serverRandom)
167 signedBytes = privateKey.sign(verifyBytes)
168 certificateVerify = CertificateVerify(version)
169 certificateVerify.create(signedBytes, signatureAlgorithm)
170
171 return certificateVerify
172
174 """
175 Handling of RSA key exchange
176
177 NOT stable API, do NOT use
178 """
179
180 - def __init__(self, cipherSuite, clientHello, serverHello, privateKey):
181 super(RSAKeyExchange, self).__init__(cipherSuite, clientHello,
182 serverHello, privateKey)
183 self.encPremasterSecret = None
184
186 """Don't create a server key exchange for RSA key exchange"""
187 return None
188
190 """Decrypt client key exchange, return premaster secret"""
191 premasterSecret = self.privateKey.decrypt(\
192 clientKeyExchange.encryptedPreMasterSecret)
193
194
195
196 randomPreMasterSecret = getRandomBytes(48)
197 if not premasterSecret:
198 premasterSecret = randomPreMasterSecret
199 elif len(premasterSecret) != 48:
200 premasterSecret = randomPreMasterSecret
201 else:
202 versionCheck = (premasterSecret[0], premasterSecret[1])
203 if versionCheck != self.clientHello.client_version:
204
205 if versionCheck != self.serverHello.server_version:
206 premasterSecret = randomPreMasterSecret
207 return premasterSecret
208
211 """Generate premaster secret for server"""
212 del serverKeyExchange
213 premasterSecret = getRandomBytes(48)
214 premasterSecret[0] = self.clientHello.client_version[0]
215 premasterSecret[1] = self.clientHello.client_version[1]
216
217 self.encPremasterSecret = srvPublicKey.encrypt(premasterSecret)
218 return premasterSecret
219
221 """Return a client key exchange with clients key share"""
222 clientKeyExchange = super(RSAKeyExchange, self).makeClientKeyExchange()
223 clientKeyExchange.createRSA(self.encPremasterSecret)
224 return clientKeyExchange
225
229 """
230 Handling of ephemeral Diffe-Hellman Key exchange
231
232 NOT stable API, do NOT use
233 """
234
235 - def __init__(self, cipherSuite, clientHello, serverHello, privateKey):
236 super(DHE_RSAKeyExchange, self).__init__(cipherSuite, clientHello,
237 serverHello, privateKey)
238
239 self.dh_Xs = None
240 self.dh_Yc = None
241
242
243 dh_g, dh_p = goodGroupParameters[2]
244
245
246 strength = 160
247
260
273
288
294
299 """Helper class for conducting ECDHE key exchange"""
300
301 - def __init__(self, cipherSuite, clientHello, serverHello, privateKey,
302 acceptedCurves):
303 super(ECDHE_RSAKeyExchange, self).__init__(cipherSuite, clientHello,
304 serverHello, privateKey)
305
306 self.ecdhXs = None
307 self.acceptedCurves = acceptedCurves
308 self.group_id = None
309 self.ecdhYc = None
310
339
349
368
374
376 """Helper class for conducting SRP key exchange"""
377
378 - def __init__(self, cipherSuite, clientHello, serverHello, privateKey,
379 verifierDB, srpUsername=None, password=None, settings=None):
380 """Link Key Exchange options with verifierDB for SRP"""
381 super(SRPKeyExchange, self).__init__(cipherSuite, clientHello,
382 serverHello, privateKey)
383 self.N = None
384 self.v = None
385 self.b = None
386 self.B = None
387 self.verifierDB = verifierDB
388 self.A = None
389 self.srpUsername = srpUsername
390 self.password = password
391 self.settings = settings
392
394 """Create SRP version of Server Key Exchange"""
395 srpUsername = self.clientHello.srp_username.decode("utf-8")
396
397 try:
398 entry = self.verifierDB[srpUsername]
399 except KeyError:
400 raise TLSUnknownPSKIdentity("Unknown identity")
401 (self.N, g, s, self.v) = entry
402
403
404 self.b = bytesToNumber(getRandomBytes(32))
405 k = makeK(self.N, g)
406 self.B = (powMod(g, self.b, self.N) + (k * self.v)) % self.N
407
408
409 serverKeyExchange = ServerKeyExchange(self.cipherSuite,
410 self.serverHello.server_version)
411 serverKeyExchange.createSRP(self.N, g, s, self.B)
412 if self.cipherSuite in CipherSuite.srpCertSuites:
413 self.signServerKeyExchange(serverKeyExchange, sigHash)
414 return serverKeyExchange
415
417 """Calculate premaster secret from Client Key Exchange and sent SKE"""
418 A = clientKeyExchange.srp_A
419 if A % self.N == 0:
420 raise TLSIllegalParameterException("Invalid SRP A value")
421
422
423 u = makeU(self.N, A, self.B)
424
425
426 S = powMod((A * powMod(self.v, u, self.N)) % self.N, self.b, self.N)
427 return numberToByteArray(S)
428
430 """Calculate premaster secret from ServerKeyExchange"""
431 del srvPublicKey
432 N = serverKeyExchange.srp_N
433 g = serverKeyExchange.srp_g
434 s = serverKeyExchange.srp_s
435 B = serverKeyExchange.srp_B
436
437 if (g, N) not in goodGroupParameters:
438 raise TLSInsufficientSecurity("Unknown group parameters")
439 if numBits(N) < self.settings.minKeySize:
440 raise TLSInsufficientSecurity("N value is too small: {0}".\
441 format(numBits(N)))
442 if numBits(N) > self.settings.maxKeySize:
443 raise TLSInsufficientSecurity("N value is too large: {0}".\
444 format(numBits(N)))
445 if B % N == 0:
446 raise TLSIllegalParameterException("Suspicious B value")
447
448
449 a = bytesToNumber(getRandomBytes(32))
450 self.A = powMod(g, a, N)
451
452
453 x = makeX(s, bytearray(self.srpUsername, "utf-8"),
454 bytearray(self.password, "utf-8"))
455 v = powMod(g, x, N)
456
457
458 u = makeU(N, self.A, B)
459
460
461 k = makeK(N, g)
462 S = powMod((B - (k*v)) % N, a+(u*x), N)
463 return numberToByteArray(S)
464
470