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=None):
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 179 -class RSAKeyExchange(KeyExchange):
180 """ 181 Handling of RSA key exchange 182 183 NOT stable API, do NOT use 184 """ 185
186 - def __init__(self, cipherSuite, clientHello, serverHello, privateKey):
187 super(RSAKeyExchange, self).__init__(cipherSuite, clientHello, 188 serverHello, privateKey) 189 self.encPremasterSecret = None
190
191 - def makeServerKeyExchange(self, sigHash=None):
192 """Don't create a server key exchange for RSA key exchange""" 193 return None
194
195 - def processClientKeyExchange(self, clientKeyExchange):
196 """Decrypt client key exchange, return premaster secret""" 197 premasterSecret = self.privateKey.decrypt(\ 198 clientKeyExchange.encryptedPreMasterSecret) 199 200 # On decryption failure randomize premaster secret to avoid 201 # Bleichenbacher's "million message" attack 202 randomPreMasterSecret = getRandomBytes(48) 203 if not premasterSecret: 204 premasterSecret = randomPreMasterSecret 205 elif len(premasterSecret) != 48: 206 premasterSecret = randomPreMasterSecret 207 else: 208 versionCheck = (premasterSecret[0], premasterSecret[1]) 209 if versionCheck != self.clientHello.client_version: 210 #Tolerate buggy IE clients 211 if versionCheck != self.serverHello.server_version: 212 premasterSecret = randomPreMasterSecret 213 return premasterSecret
214
215 - def processServerKeyExchange(self, srvPublicKey, 216 serverKeyExchange):
217 """Generate premaster secret for server""" 218 del serverKeyExchange # not present in RSA key exchange 219 premasterSecret = getRandomBytes(48) 220 premasterSecret[0] = self.clientHello.client_version[0] 221 premasterSecret[1] = self.clientHello.client_version[1] 222 223 self.encPremasterSecret = srvPublicKey.encrypt(premasterSecret) 224 return premasterSecret
225
226 - def makeClientKeyExchange(self):
227 """Return a client key exchange with clients key share""" 228 clientKeyExchange = super(RSAKeyExchange, self).makeClientKeyExchange() 229 clientKeyExchange.createRSA(self.encPremasterSecret) 230 return clientKeyExchange
231
232 233 -class ADHKeyExchange(KeyExchange):
234 """ 235 Handling of anonymous Diffie-Hellman Key exchange 236 237 FFDHE without signing serverKeyExchange useful for anonymous DH 238 """ 239
240 - def __init__(self, cipherSuite, clientHello, serverHello):
241 super(ADHKeyExchange, self).__init__(cipherSuite, clientHello, 242 serverHello) 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 # TODO make configurable 249 dh_g, dh_p = goodGroupParameters[2] 250 251 # RFC 3526, Section 8. 252 strength = 160 253
254 - def makeServerKeyExchange(self):
255 """ 256 Prepare server side of anonymous key exchange with selected parameters 257 """ 258 # Per RFC 3526, Section 1, the exponent should have double the entropy 259 # of the strength of the curve. 260 self.dh_Xs = bytesToNumber(getRandomBytes(self.strength * 2 // 8)) 261 dh_Ys = powMod(self.dh_g, self.dh_Xs, self.dh_p) 262 263 version = self.serverHello.server_version 264 serverKeyExchange = ServerKeyExchange(self.cipherSuite, version) 265 serverKeyExchange.createDH(self.dh_p, self.dh_g, dh_Ys) 266 # No sign for anonymous ServerKeyExchange. 267 return serverKeyExchange
268
269 - def processClientKeyExchange(self, clientKeyExchange):
270 """Use client provided parameters to establish premaster secret""" 271 dh_Yc = clientKeyExchange.dh_Yc 272 273 # First half of RFC 2631, Section 2.1.5. Validate the client's public 274 # key. 275 if not 2 <= dh_Yc <= self.dh_p - 1: 276 raise TLSIllegalParameterException("Invalid dh_Yc value") 277 278 S = powMod(dh_Yc, self.dh_Xs, self.dh_p) 279 return numberToByteArray(S)
280
281 - def processServerKeyExchange(self, srvPublicKey, serverKeyExchange):
282 """Process the server key exchange, return premaster secret""" 283 del srvPublicKey 284 dh_p = serverKeyExchange.dh_p 285 # TODO make the minimum changeable 286 if dh_p < 2**1023: 287 raise TLSInsufficientSecurity("DH prime too small") 288 dh_g = serverKeyExchange.dh_g 289 dh_Xc = bytesToNumber(getRandomBytes(32)) 290 dh_Ys = serverKeyExchange.dh_Ys 291 self.dh_Yc = powMod(dh_g, dh_Xc, dh_p) 292 293 S = powMod(dh_Ys, dh_Xc, dh_p) 294 return numberToByteArray(S)
295
296 - def makeClientKeyExchange(self):
297 """Create client key share for the key exchange""" 298 cke = super(ADHKeyExchange, self).makeClientKeyExchange() 299 cke.createDH(self.dh_Yc) 300 return cke
301
302 303 # the DHE_RSA part comes from IETF ciphersuite names, we want to keep it 304 #pylint: disable = invalid-name 305 -class DHE_RSAKeyExchange(ADHKeyExchange):
306 """ 307 Handling of ephemeral Diffe-Hellman Key exchange 308 309 NOT stable API, do NOT use 310 """ 311
312 - def __init__(self, cipherSuite, clientHello, serverHello, privateKey):
313 super(DHE_RSAKeyExchange, self).__init__(cipherSuite, clientHello, 314 serverHello) 315 #pylint: enable = invalid-name 316 self.privateKey = privateKey
317
318 - def makeServerKeyExchange(self, sigHash=None):
319 """Prepare server side of key exchange with selected parameters""" 320 ske = super(DHE_RSAKeyExchange, self).makeServerKeyExchange() 321 self.signServerKeyExchange(ske, sigHash) 322 return ske
323
324 325 -class AECDHKeyExchange(KeyExchange):
326 """ 327 Handling of anonymous Eliptic curve Diffie-Hellman Key exchange 328 329 ECDHE without signing serverKeyExchange useful for anonymous ECDH 330 """
331 - def __init__(self, cipherSuite, clientHello, serverHello, acceptedCurves):
332 super(AECDHKeyExchange, self).__init__(cipherSuite, clientHello, 333 serverHello) 334 self.ecdhXs = None 335 self.acceptedCurves = acceptedCurves 336 self.group_id = None 337 self.ecdhYc = None
338
339 - def makeServerKeyExchange(self, sigHash=None):
340 """Create AECDHE version of Server Key Exchange""" 341 #Get client supported groups 342 client_curves = self.clientHello.getExtension(\ 343 ExtensionType.supported_groups) 344 if client_curves is None or client_curves.groups is None or \ 345 len(client_curves.groups) == 0: 346 raise TLSInternalError("Can't do ECDHE with no client curves") 347 client_curves = client_curves.groups 348 349 #Pick first client preferred group we support 350 self.group_id = next((x for x in client_curves \ 351 if x in self.acceptedCurves), None) 352 if self.group_id is None: 353 raise TLSInsufficientSecurity("No mutual groups") 354 generator = getCurveByName(GroupName.toRepr(self.group_id)).generator 355 self.ecdhXs = ecdsa.util.randrange(generator.order()) 356 357 ecdhYs = encodeX962Point(generator * self.ecdhXs) 358 359 version = self.serverHello.server_version 360 serverKeyExchange = ServerKeyExchange(self.cipherSuite, version) 361 serverKeyExchange.createECDH(ECCurveType.named_curve, 362 named_curve=self.group_id, 363 point=ecdhYs) 364 # No sign for anonymous ServerKeyExchange 365 return serverKeyExchange
366
367 - def processClientKeyExchange(self, clientKeyExchange):
368 """Calculate premaster secret from previously generated SKE and CKE""" 369 curveName = GroupName.toRepr(self.group_id) 370 try: 371 ecdhYc = decodeX962Point(clientKeyExchange.ecdh_Yc, 372 getCurveByName(curveName)) 373 # TODO update python-ecdsa library to raise something more on point 374 except AssertionError: 375 raise TLSIllegalParameterException("Invalid ECC point") 376 377 sharedSecret = ecdhYc * self.ecdhXs 378 379 return numberToByteArray(sharedSecret.x(), getPointByteSize(ecdhYc))
380
381 - def processServerKeyExchange(self, srvPublicKey, serverKeyExchange):
382 """Process the server key exchange, return premaster secret""" 383 del srvPublicKey 384 385 if serverKeyExchange.curve_type != ECCurveType.named_curve \ 386 or serverKeyExchange.named_curve not in self.acceptedCurves: 387 raise TLSIllegalParameterException("Server picked curve we " 388 "didn't advertise") 389 390 curveName = GroupName.toStr(serverKeyExchange.named_curve) 391 curve = getCurveByName(curveName) 392 generator = curve.generator 393 394 ecdhXc = ecdsa.util.randrange(generator.order()) 395 ecdhYs = decodeX962Point(serverKeyExchange.ecdh_Ys, curve) 396 self.ecdhYc = encodeX962Point(generator * ecdhXc) 397 S = ecdhYs * ecdhXc 398 return numberToByteArray(S.x(), getPointByteSize(S))
399
400 - def makeClientKeyExchange(self):
401 """Make client key exchange for ECDHE""" 402 cke = super(AECDHKeyExchange, self).makeClientKeyExchange() 403 cke.createECDH(self.ecdhYc) 404 return cke
405
406 407 # The ECDHE_RSA part comes from the IETF names of ciphersuites, so we want to 408 # keep it 409 #pylint: disable = invalid-name 410 -class ECDHE_RSAKeyExchange(AECDHKeyExchange):
411 """Helper class for conducting ECDHE key exchange""" 412
413 - def __init__(self, cipherSuite, clientHello, serverHello, privateKey, 414 acceptedCurves):
415 super(ECDHE_RSAKeyExchange, self).__init__(cipherSuite, clientHello, 416 serverHello, 417 acceptedCurves) 418 #pylint: enable = invalid-name 419 self.privateKey = privateKey
420
421 - def makeServerKeyExchange(self, sigHash=None):
422 """Create ECDHE version of Server Key Exchange""" 423 ske = super(ECDHE_RSAKeyExchange, self).makeServerKeyExchange() 424 self.signServerKeyExchange(ske, sigHash) 425 return ske
426
427 428 -class SRPKeyExchange(KeyExchange):
429 """Helper class for conducting SRP key exchange""" 430
431 - def __init__(self, cipherSuite, clientHello, serverHello, privateKey, 432 verifierDB, srpUsername=None, password=None, settings=None):
433 """Link Key Exchange options with verifierDB for SRP""" 434 super(SRPKeyExchange, self).__init__(cipherSuite, clientHello, 435 serverHello, privateKey) 436 self.N = None 437 self.v = None 438 self.b = None 439 self.B = None 440 self.verifierDB = verifierDB 441 self.A = None 442 self.srpUsername = srpUsername 443 self.password = password 444 self.settings = settings 445 if srpUsername is not None and not isinstance(srpUsername, bytearray): 446 raise TypeError("srpUsername must be a bytearray object") 447 if password is not None and not isinstance(password, bytearray): 448 raise TypeError("password must be a bytearray object")
449
450 - def makeServerKeyExchange(self, sigHash=None):
451 """Create SRP version of Server Key Exchange""" 452 srpUsername = bytes(self.clientHello.srp_username) 453 #Get parameters from username 454 try: 455 entry = self.verifierDB[srpUsername] 456 except KeyError: 457 raise TLSUnknownPSKIdentity("Unknown identity") 458 (self.N, g, s, self.v) = entry 459 460 #Calculate server's ephemeral DH values (b, B) 461 self.b = bytesToNumber(getRandomBytes(32)) 462 k = makeK(self.N, g) 463 self.B = (powMod(g, self.b, self.N) + (k * self.v)) % self.N 464 465 #Create ServerKeyExchange, signing it if necessary 466 serverKeyExchange = ServerKeyExchange(self.cipherSuite, 467 self.serverHello.server_version) 468 serverKeyExchange.createSRP(self.N, g, s, self.B) 469 if self.cipherSuite in CipherSuite.srpCertSuites: 470 self.signServerKeyExchange(serverKeyExchange, sigHash) 471 return serverKeyExchange
472
473 - def processClientKeyExchange(self, clientKeyExchange):
474 """Calculate premaster secret from Client Key Exchange and sent SKE""" 475 A = clientKeyExchange.srp_A 476 if A % self.N == 0: 477 raise TLSIllegalParameterException("Invalid SRP A value") 478 479 #Calculate u 480 u = makeU(self.N, A, self.B) 481 482 #Calculate premaster secret 483 S = powMod((A * powMod(self.v, u, self.N)) % self.N, self.b, self.N) 484 return numberToByteArray(S)
485
486 - def processServerKeyExchange(self, srvPublicKey, serverKeyExchange):
487 """Calculate premaster secret from ServerKeyExchange""" 488 del srvPublicKey # irrelevant for SRP 489 N = serverKeyExchange.srp_N 490 g = serverKeyExchange.srp_g 491 s = serverKeyExchange.srp_s 492 B = serverKeyExchange.srp_B 493 494 if (g, N) not in goodGroupParameters: 495 raise TLSInsufficientSecurity("Unknown group parameters") 496 if numBits(N) < self.settings.minKeySize: 497 raise TLSInsufficientSecurity("N value is too small: {0}".\ 498 format(numBits(N))) 499 if numBits(N) > self.settings.maxKeySize: 500 raise TLSInsufficientSecurity("N value is too large: {0}".\ 501 format(numBits(N))) 502 if B % N == 0: 503 raise TLSIllegalParameterException("Suspicious B value") 504 505 #Client ephemeral value 506 a = bytesToNumber(getRandomBytes(32)) 507 self.A = powMod(g, a, N) 508 509 #Calculate client's static DH values (x, v) 510 x = makeX(s, self.srpUsername, self.password) 511 v = powMod(g, x, N) 512 513 #Calculate u 514 u = makeU(N, self.A, B) 515 516 #Calculate premaster secret 517 k = makeK(N, g) 518 S = powMod((B - (k*v)) % N, a+(u*x), N) 519 return numberToByteArray(S)
520
521 - def makeClientKeyExchange(self):
522 """Create ClientKeyExchange""" 523 cke = super(SRPKeyExchange, self).makeClientKeyExchange() 524 cke.createSRP(self.A) 525 return cke
526