Package tlslite :: Module keyexchange
[hide private]
[frames] | no frames]

Source Code for Module tlslite.keyexchange

  1  # Authors: 
  2  #   Hubert Kario (2015) 
  3  # 
  4  # See the LICENSE file for legal information regarding use of this file. 
  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  from .messages import ServerKeyExchange, ClientKeyExchange, CertificateVerify 
 11  from .constants import SignatureAlgorithm, HashAlgorithm, CipherSuite, \ 
 12          ExtensionType, GroupName, ECCurveType 
 13  from .utils.ecc import decodeX962Point, encodeX962Point, getCurveByName, \ 
 14          getPointByteSize 
 15  from .utils.rsakey import RSAKey 
 16  from .utils.cryptomath import bytesToNumber, getRandomBytes, powMod, \ 
 17          numBits, numberToByteArray 
 18  import ecdsa 
19 20 -class KeyExchange(object):
21 """ 22 Common API for calculating Premaster secret 23 24 NOT stable, will get moved from this file 25 """ 26
27 - def __init__(self, cipherSuite, clientHello, serverHello, privateKey):
28 """Initialize KeyExchange. privateKey is the signing private key""" 29 self.cipherSuite = cipherSuite 30 self.clientHello = clientHello 31 self.serverHello = serverHello 32 self.privateKey = privateKey
33
34 - def makeServerKeyExchange(self, sigHash=None):
35 """ 36 Create a ServerKeyExchange object 37 38 Returns a ServerKeyExchange object for the server's initial leg in the 39 handshake. If the key exchange method does not send ServerKeyExchange 40 (e.g. RSA), it returns None. 41 """ 42 raise NotImplementedError()
43
44 - def makeClientKeyExchange(self):
45 """ 46 Create a ClientKeyExchange object 47 48 Returns a ClientKeyExchange for the second flight from client in the 49 handshake. 50 """ 51 return ClientKeyExchange(self.cipherSuite, 52 self.serverHello.server_version)
53
54 - def processClientKeyExchange(self, clientKeyExchange):
55 """ 56 Process ClientKeyExchange and return premaster secret 57 58 Processes the client's ClientKeyExchange message and returns the 59 premaster secret. Raises TLSLocalAlert on error. 60 """ 61 raise NotImplementedError()
62
63 - def processServerKeyExchange(self, srvPublicKey, 64 serverKeyExchange):
65 """Process the server KEX and return premaster secret""" 66 raise NotImplementedError()
67
68 - def signServerKeyExchange(self, serverKeyExchange, sigHash=None):
69 """ 70 Sign a server key best matching supported algorithms 71 72 @type sigHash: str 73 @param sigHash: name of the hash used for signing 74 """ 75 if self.serverHello.server_version >= (3, 3): 76 serverKeyExchange.signAlg = SignatureAlgorithm.rsa 77 serverKeyExchange.hashAlg = getattr(HashAlgorithm, sigHash) 78 hashBytes = serverKeyExchange.hash(self.clientHello.random, 79 self.serverHello.random) 80 81 if self.serverHello.server_version >= (3, 3): 82 hashBytes = RSAKey.addPKCS1Prefix(hashBytes, sigHash) 83 84 serverKeyExchange.signature = self.privateKey.sign(hashBytes) 85 86 if not serverKeyExchange.signature: 87 raise TLSInternalError("Empty signature") 88 89 if not self.privateKey.verify(serverKeyExchange.signature, hashBytes): 90 raise TLSInternalError("Server Key Exchange signature invalid")
91 92 @staticmethod
93 - def verifyServerKeyExchange(serverKeyExchange, publicKey, clientRandom, 94 serverRandom, validSigAlgs):
95 """Verify signature on the Server Key Exchange message 96 97 the only acceptable signature algorithms are specified by validSigAlgs 98 """ 99 if serverKeyExchange.version >= (3, 3): 100 if (serverKeyExchange.hashAlg, serverKeyExchange.signAlg) not in \ 101 validSigAlgs: 102 raise TLSIllegalParameterException("Server selected " 103 "invalid signature " 104 "algorithm") 105 assert serverKeyExchange.signAlg == SignatureAlgorithm.rsa 106 hashName = HashAlgorithm.toRepr(serverKeyExchange.hashAlg) 107 if hashName is None: 108 raise TLSIllegalParameterException("Unknown signature " 109 "algorithm") 110 hashBytes = serverKeyExchange.hash(clientRandom, serverRandom) 111 112 if serverKeyExchange.version == (3, 3): 113 hashBytes = RSAKey.addPKCS1Prefix(hashBytes, hashName) 114 115 sigBytes = serverKeyExchange.signature 116 if not sigBytes: 117 raise TLSIllegalParameterException("Empty signature") 118 119 if not publicKey.verify(sigBytes, hashBytes): 120 raise TLSDecryptionFailed("Server Key Exchange signature " 121 "invalid")
122 123 @staticmethod
124 - def calcVerifyBytes(version, handshakeHashes, signatureAlg, 125 premasterSecret, clientRandom, serverRandom):
126 """Calculate signed bytes for Certificate Verify""" 127 if version == (3, 0): 128 masterSecret = calcMasterSecret(version, 129 0, 130 premasterSecret, 131 clientRandom, 132 serverRandom) 133 verifyBytes = handshakeHashes.digestSSL(masterSecret, b"") 134 elif version in ((3, 1), (3, 2)): 135 verifyBytes = handshakeHashes.digest() 136 elif version == (3, 3): 137 hashName = HashAlgorithm.toRepr(signatureAlg[0]) 138 verifyBytes = handshakeHashes.digest(hashName) 139 verifyBytes = RSAKey.addPKCS1Prefix(verifyBytes, hashName) 140 return verifyBytes
141 142 @staticmethod
143 - def makeCertificateVerify(version, handshakeHashes, validSigAlgs, 144 privateKey, certificateRequest, premasterSecret, 145 clientRandom, serverRandom):
146 """Create a Certificate Verify message 147 148 @param version: protocol version in use 149 @param handshakeHashes: the running hash of all handshake messages 150 @param validSigAlgs: acceptable signature algorithms for client side, 151 applicable only to TLSv1.2 (or later) 152 @param certificateRequest: the server provided Certificate Request 153 message 154 @param premasterSecret: the premaster secret, needed only for SSLv3 155 @param clientRandom: client provided random value, needed only for SSLv3 156 @param serverRandom: server provided random value, needed only for SSLv3 157 """ 158 signatureAlgorithm = None 159 # in TLS 1.2 we must decide which algorithm to use for signing 160 if version == (3, 3): 161 serverSigAlgs = certificateRequest.supported_signature_algs 162 signatureAlgorithm = next((sigAlg for sigAlg in validSigAlgs \ 163 if sigAlg in serverSigAlgs), None) 164 # if none acceptable, do a last resort: 165 if signatureAlgorithm is None: 166 signatureAlgorithm = validSigAlgs[0] 167 verifyBytes = KeyExchange.calcVerifyBytes(version, handshakeHashes, 168 signatureAlgorithm, 169 premasterSecret, 170 clientRandom, 171 serverRandom) 172 signedBytes = privateKey.sign(verifyBytes) 173 certificateVerify = CertificateVerify(version) 174 certificateVerify.create(signedBytes, signatureAlgorithm) 175 176 return certificateVerify
177
178 -class RSAKeyExchange(KeyExchange):
179 """ 180 Handling of RSA key exchange 181 182 NOT stable API, do NOT use 183 """ 184
185 - def __init__(self, cipherSuite, clientHello, serverHello, privateKey):
186 super(RSAKeyExchange, self).__init__(cipherSuite, clientHello, 187 serverHello, privateKey) 188 self.encPremasterSecret = None
189
190 - def makeServerKeyExchange(self, sigHash=None):
191 """Don't create a server key exchange for RSA key exchange""" 192 return None
193
194 - def processClientKeyExchange(self, clientKeyExchange):
195 """Decrypt client key exchange, return premaster secret""" 196 premasterSecret = self.privateKey.decrypt(\ 197 clientKeyExchange.encryptedPreMasterSecret) 198 199 # On decryption failure randomize premaster secret to avoid 200 # Bleichenbacher's "million message" attack 201 randomPreMasterSecret = getRandomBytes(48) 202 if not premasterSecret: 203 premasterSecret = randomPreMasterSecret 204 elif len(premasterSecret) != 48: 205 premasterSecret = randomPreMasterSecret 206 else: 207 versionCheck = (premasterSecret[0], premasterSecret[1]) 208 if versionCheck != self.clientHello.client_version: 209 #Tolerate buggy IE clients 210 if versionCheck != self.serverHello.server_version: 211 premasterSecret = randomPreMasterSecret 212 return premasterSecret
213
214 - def processServerKeyExchange(self, srvPublicKey, 215 serverKeyExchange):
216 """Generate premaster secret for server""" 217 del serverKeyExchange # not present in RSA key exchange 218 premasterSecret = getRandomBytes(48) 219 premasterSecret[0] = self.clientHello.client_version[0] 220 premasterSecret[1] = self.clientHello.client_version[1] 221 222 self.encPremasterSecret = srvPublicKey.encrypt(premasterSecret) 223 return premasterSecret
224
225 - def makeClientKeyExchange(self):
226 """Return a client key exchange with clients key share""" 227 clientKeyExchange = super(RSAKeyExchange, self).makeClientKeyExchange() 228 clientKeyExchange.createRSA(self.encPremasterSecret) 229 return clientKeyExchange
230
231 # the DHE_RSA part comes from IETF ciphersuite names, we want to keep it 232 #pylint: disable = invalid-name 233 -class DHE_RSAKeyExchange(KeyExchange):
234 """ 235 Handling of ephemeral Diffe-Hellman Key exchange 236 237 NOT stable API, do NOT use 238 """ 239
240 - def __init__(self, cipherSuite, clientHello, serverHello, privateKey):
241 super(DHE_RSAKeyExchange, self).__init__(cipherSuite, clientHello, 242 serverHello, privateKey) 243 #pylint: enable = invalid-name 244 self.dh_Xs = None 245 self.dh_Yc = None
246 247 # 2048-bit MODP Group (RFC 3526, Section 3) 248 dh_g, dh_p = goodGroupParameters[2] 249 250 # RFC 3526, Section 8. 251 strength = 160 252
253 - def makeServerKeyExchange(self, sigHash=None):
254 """Prepare server side of key exchange with selected parameters""" 255 # Per RFC 3526, Section 1, the exponent should have double the entropy 256 # of the strength of the curve. 257 self.dh_Xs = bytesToNumber(getRandomBytes(self.strength * 2 // 8)) 258 dh_Ys = powMod(self.dh_g, self.dh_Xs, self.dh_p) 259 260 version = self.serverHello.server_version 261 serverKeyExchange = ServerKeyExchange(self.cipherSuite, version) 262 serverKeyExchange.createDH(self.dh_p, self.dh_g, dh_Ys) 263 self.signServerKeyExchange(serverKeyExchange, sigHash) 264 return serverKeyExchange
265
266 - def processClientKeyExchange(self, clientKeyExchange):
267 """Use client provided parameters to establish premaster secret""" 268 dh_Yc = clientKeyExchange.dh_Yc 269 270 # First half of RFC 2631, Section 2.1.5. Validate the client's public 271 # key. 272 if not 2 <= dh_Yc <= self.dh_p - 1: 273 raise TLSIllegalParameterException("Invalid dh_Yc value") 274 275 S = powMod(dh_Yc, self.dh_Xs, self.dh_p) 276 return numberToByteArray(S)
277
278 - def processServerKeyExchange(self, srvPublicKey, serverKeyExchange):
279 """Process the server key exchange, return premaster secret""" 280 del srvPublicKey 281 dh_p = serverKeyExchange.dh_p 282 # TODO make the minimum changeable 283 if dh_p < 2**1023: 284 raise TLSInsufficientSecurity("DH prime too small") 285 dh_g = serverKeyExchange.dh_g 286 dh_Xc = bytesToNumber(getRandomBytes(32)) 287 dh_Ys = serverKeyExchange.dh_Ys 288 self.dh_Yc = powMod(dh_g, dh_Xc, dh_p) 289 290 S = powMod(dh_Ys, dh_Xc, dh_p) 291 return numberToByteArray(S)
292
293 - def makeClientKeyExchange(self):
294 """Create client key share for the key exchange""" 295 cke = super(DHE_RSAKeyExchange, self).makeClientKeyExchange() 296 cke.createDH(self.dh_Yc) 297 return cke
298
299 # The ECDHE_RSA part comes from the IETF names of ciphersuites, so we want to 300 # keep it 301 #pylint: disable = invalid-name 302 -class ECDHE_RSAKeyExchange(KeyExchange):
303 """Helper class for conducting ECDHE key exchange""" 304
305 - def __init__(self, cipherSuite, clientHello, serverHello, privateKey, 306 acceptedCurves):
307 super(ECDHE_RSAKeyExchange, self).__init__(cipherSuite, clientHello, 308 serverHello, privateKey) 309 #pylint: enable = invalid-name 310 self.ecdhXs = None 311 self.acceptedCurves = acceptedCurves 312 self.group_id = None 313 self.ecdhYc = None
314
315 - def makeServerKeyExchange(self, sigHash=None):
316 """Create ECDHE version of Server Key Exchange""" 317 #Get client supported groups 318 client_curves = self.clientHello.getExtension(\ 319 ExtensionType.supported_groups) 320 if client_curves is None or client_curves.groups is None or \ 321 len(client_curves.groups) == 0: 322 raise TLSInternalError("Can't do ECDHE with no client curves") 323 client_curves = client_curves.groups 324 325 #Pick first client preferred group we support 326 self.group_id = next((x for x in client_curves \ 327 if x in self.acceptedCurves), 328 None) 329 if self.group_id is None: 330 raise TLSInsufficientSecurity("No mutual groups") 331 generator = getCurveByName(GroupName.toRepr(self.group_id)).generator 332 self.ecdhXs = ecdsa.util.randrange(generator.order()) 333 334 ecdhYs = encodeX962Point(generator * self.ecdhXs) 335 336 version = self.serverHello.server_version 337 serverKeyExchange = ServerKeyExchange(self.cipherSuite, version) 338 serverKeyExchange.createECDH(ECCurveType.named_curve, 339 named_curve=self.group_id, 340 point=ecdhYs) 341 self.signServerKeyExchange(serverKeyExchange, sigHash) 342 return serverKeyExchange
343
344 - def processClientKeyExchange(self, clientKeyExchange):
345 """Calculate premaster secret from previously generated SKE and CKE""" 346 curveName = GroupName.toRepr(self.group_id) 347 try: 348 ecdhYc = decodeX962Point(clientKeyExchange.ecdh_Yc, 349 getCurveByName(curveName)) 350 # TODO update python-ecdsa library to raise something more on point 351 except AssertionError: 352 raise TLSIllegalParameterException("Invalid ECC point") 353 354 sharedSecret = ecdhYc * self.ecdhXs 355 356 return numberToByteArray(sharedSecret.x(), getPointByteSize(ecdhYc))
357
358 - def processServerKeyExchange(self, srvPublicKey, serverKeyExchange):
359 """Process the server key exchange, return premaster secret""" 360 del srvPublicKey 361 362 if serverKeyExchange.curve_type != ECCurveType.named_curve \ 363 or serverKeyExchange.named_curve not in self.acceptedCurves: 364 raise TLSIllegalParameterException("Server picked curve we " 365 "didn't advertise") 366 367 curveName = GroupName.toStr(serverKeyExchange.named_curve) 368 curve = getCurveByName(curveName) 369 generator = curve.generator 370 371 ecdhXc = ecdsa.util.randrange(generator.order()) 372 ecdhYs = decodeX962Point(serverKeyExchange.ecdh_Ys, curve) 373 self.ecdhYc = encodeX962Point(generator * ecdhXc) 374 S = ecdhYs * ecdhXc 375 return numberToByteArray(S.x(), getPointByteSize(S))
376
377 - def makeClientKeyExchange(self):
378 """Make client key exchange for ECDHE""" 379 cke = super(ECDHE_RSAKeyExchange, self).makeClientKeyExchange() 380 cke.createECDH(self.ecdhYc) 381 return cke
382
383 -class SRPKeyExchange(KeyExchange):
384 """Helper class for conducting SRP key exchange""" 385
386 - def __init__(self, cipherSuite, clientHello, serverHello, privateKey, 387 verifierDB, srpUsername=None, password=None, settings=None):
388 """Link Key Exchange options with verifierDB for SRP""" 389 super(SRPKeyExchange, self).__init__(cipherSuite, clientHello, 390 serverHello, privateKey) 391 self.N = None 392 self.v = None 393 self.b = None 394 self.B = None 395 self.verifierDB = verifierDB 396 self.A = None 397 self.srpUsername = srpUsername 398 self.password = password 399 self.settings = settings
400
401 - def makeServerKeyExchange(self, sigHash=None):
402 """Create SRP version of Server Key Exchange""" 403 srpUsername = self.clientHello.srp_username.decode("utf-8") 404 #Get parameters from username 405 try: 406 entry = self.verifierDB[srpUsername] 407 except KeyError: 408 raise TLSUnknownPSKIdentity("Unknown identity") 409 (self.N, g, s, self.v) = entry 410 411 #Calculate server's ephemeral DH values (b, B) 412 self.b = bytesToNumber(getRandomBytes(32)) 413 k = makeK(self.N, g) 414 self.B = (powMod(g, self.b, self.N) + (k * self.v)) % self.N 415 416 #Create ServerKeyExchange, signing it if necessary 417 serverKeyExchange = ServerKeyExchange(self.cipherSuite, 418 self.serverHello.server_version) 419 serverKeyExchange.createSRP(self.N, g, s, self.B) 420 if self.cipherSuite in CipherSuite.srpCertSuites: 421 self.signServerKeyExchange(serverKeyExchange, sigHash) 422 return serverKeyExchange
423
424 - def processClientKeyExchange(self, clientKeyExchange):
425 """Calculate premaster secret from Client Key Exchange and sent SKE""" 426 A = clientKeyExchange.srp_A 427 if A % self.N == 0: 428 raise TLSIllegalParameterException("Invalid SRP A value") 429 430 #Calculate u 431 u = makeU(self.N, A, self.B) 432 433 #Calculate premaster secret 434 S = powMod((A * powMod(self.v, u, self.N)) % self.N, self.b, self.N) 435 return numberToByteArray(S)
436
437 - def processServerKeyExchange(self, srvPublicKey, serverKeyExchange):
438 """Calculate premaster secret from ServerKeyExchange""" 439 del srvPublicKey # irrelevant for SRP 440 N = serverKeyExchange.srp_N 441 g = serverKeyExchange.srp_g 442 s = serverKeyExchange.srp_s 443 B = serverKeyExchange.srp_B 444 445 if (g, N) not in goodGroupParameters: 446 raise TLSInsufficientSecurity("Unknown group parameters") 447 if numBits(N) < self.settings.minKeySize: 448 raise TLSInsufficientSecurity("N value is too small: {0}".\ 449 format(numBits(N))) 450 if numBits(N) > self.settings.maxKeySize: 451 raise TLSInsufficientSecurity("N value is too large: {0}".\ 452 format(numBits(N))) 453 if B % N == 0: 454 raise TLSIllegalParameterException("Suspicious B value") 455 456 #Client ephemeral value 457 a = bytesToNumber(getRandomBytes(32)) 458 self.A = powMod(g, a, N) 459 460 #Calculate client's static DH values (x, v) 461 x = makeX(s, bytearray(self.srpUsername, "utf-8"), 462 bytearray(self.password, "utf-8")) 463 v = powMod(g, x, N) 464 465 #Calculate u 466 u = makeU(N, self.A, B) 467 468 #Calculate premaster secret 469 k = makeK(N, g) 470 S = powMod((B - (k*v)) % N, a+(u*x), N) 471 return numberToByteArray(S)
472
473 - def makeClientKeyExchange(self):
474 """Create ClientKeyExchange""" 475 cke = super(SRPKeyExchange, self).makeClientKeyExchange() 476 cke.createSRP(self.A) 477 return cke
478