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 # use of safe primes also means that the p-1 is invalid 276 if not 2 <= dh_Yc < self.dh_p - 1: 277 raise TLSIllegalParameterException("Invalid dh_Yc value") 278 279 S = powMod(dh_Yc, self.dh_Xs, self.dh_p) 280 if S in (1, self.dh_p - 1): 281 raise TLSIllegalParameterException("Small subgroup capture") 282 return numberToByteArray(S)
283
284 - def processServerKeyExchange(self, srvPublicKey, serverKeyExchange):
285 """Process the server key exchange, return premaster secret.""" 286 del srvPublicKey 287 dh_p = serverKeyExchange.dh_p 288 # TODO make the minimum changeable 289 if dh_p < 2**1023: 290 raise TLSInsufficientSecurity("DH prime too small") 291 292 dh_g = serverKeyExchange.dh_g 293 if not 2 <= dh_g < dh_p - 1: 294 raise TLSIllegalParameterException("Invalid DH generator") 295 296 dh_Xc = bytesToNumber(getRandomBytes(32)) 297 dh_Ys = serverKeyExchange.dh_Ys 298 if not 2 <= dh_Ys < dh_p - 1: 299 raise TLSIllegalParameterException("Invalid server key share") 300 301 self.dh_Yc = powMod(dh_g, dh_Xc, dh_p) 302 if self.dh_Yc in (1, dh_p - 1): 303 raise TLSIllegalParameterException("Small subgroup capture") 304 305 S = powMod(dh_Ys, dh_Xc, dh_p) 306 if S in (1, dh_p - 1): 307 raise TLSIllegalParameterException("Small subgroup capture") 308 309 return numberToByteArray(S)
310
311 - def makeClientKeyExchange(self):
312 """Create client key share for the key exchange""" 313 cke = super(ADHKeyExchange, self).makeClientKeyExchange() 314 cke.createDH(self.dh_Yc) 315 return cke
316
317 318 # the DHE_RSA part comes from IETF ciphersuite names, we want to keep it 319 #pylint: disable = invalid-name 320 -class DHE_RSAKeyExchange(ADHKeyExchange):
321 """ 322 Handling of ephemeral Diffe-Hellman Key exchange 323 324 NOT stable API, do NOT use 325 """ 326
327 - def __init__(self, cipherSuite, clientHello, serverHello, privateKey):
328 super(DHE_RSAKeyExchange, self).__init__(cipherSuite, clientHello, 329 serverHello) 330 #pylint: enable = invalid-name 331 self.privateKey = privateKey
332
333 - def makeServerKeyExchange(self, sigHash=None):
334 """Prepare server side of key exchange with selected parameters""" 335 ske = super(DHE_RSAKeyExchange, self).makeServerKeyExchange() 336 self.signServerKeyExchange(ske, sigHash) 337 return ske
338
339 340 -class AECDHKeyExchange(KeyExchange):
341 """ 342 Handling of anonymous Eliptic curve Diffie-Hellman Key exchange 343 344 ECDHE without signing serverKeyExchange useful for anonymous ECDH 345 """
346 - def __init__(self, cipherSuite, clientHello, serverHello, acceptedCurves):
347 super(AECDHKeyExchange, self).__init__(cipherSuite, clientHello, 348 serverHello) 349 self.ecdhXs = None 350 self.acceptedCurves = acceptedCurves 351 self.group_id = None 352 self.ecdhYc = None
353
354 - def makeServerKeyExchange(self, sigHash=None):
355 """Create AECDHE version of Server Key Exchange""" 356 #Get client supported groups 357 client_curves = self.clientHello.getExtension(\ 358 ExtensionType.supported_groups) 359 if client_curves is None or client_curves.groups is None or \ 360 len(client_curves.groups) == 0: 361 raise TLSInternalError("Can't do ECDHE with no client curves") 362 client_curves = client_curves.groups 363 364 #Pick first client preferred group we support 365 self.group_id = next((x for x in client_curves \ 366 if x in self.acceptedCurves), None) 367 if self.group_id is None: 368 raise TLSInsufficientSecurity("No mutual groups") 369 generator = getCurveByName(GroupName.toRepr(self.group_id)).generator 370 self.ecdhXs = ecdsa.util.randrange(generator.order()) 371 372 ecdhYs = encodeX962Point(generator * self.ecdhXs) 373 374 version = self.serverHello.server_version 375 serverKeyExchange = ServerKeyExchange(self.cipherSuite, version) 376 serverKeyExchange.createECDH(ECCurveType.named_curve, 377 named_curve=self.group_id, 378 point=ecdhYs) 379 # No sign for anonymous ServerKeyExchange 380 return serverKeyExchange
381
382 - def processClientKeyExchange(self, clientKeyExchange):
383 """Calculate premaster secret from previously generated SKE and CKE""" 384 curveName = GroupName.toRepr(self.group_id) 385 try: 386 ecdhYc = decodeX962Point(clientKeyExchange.ecdh_Yc, 387 getCurveByName(curveName)) 388 # TODO update python-ecdsa library to raise something more on point 389 except AssertionError: 390 raise TLSIllegalParameterException("Invalid ECC point") 391 392 sharedSecret = ecdhYc * self.ecdhXs 393 394 return numberToByteArray(sharedSecret.x(), getPointByteSize(ecdhYc))
395
396 - def processServerKeyExchange(self, srvPublicKey, serverKeyExchange):
397 """Process the server key exchange, return premaster secret""" 398 del srvPublicKey 399 400 if serverKeyExchange.curve_type != ECCurveType.named_curve \ 401 or serverKeyExchange.named_curve not in self.acceptedCurves: 402 raise TLSIllegalParameterException("Server picked curve we " 403 "didn't advertise") 404 405 curveName = GroupName.toStr(serverKeyExchange.named_curve) 406 curve = getCurveByName(curveName) 407 generator = curve.generator 408 409 ecdhXc = ecdsa.util.randrange(generator.order()) 410 ecdhYs = decodeX962Point(serverKeyExchange.ecdh_Ys, curve) 411 self.ecdhYc = encodeX962Point(generator * ecdhXc) 412 S = ecdhYs * ecdhXc 413 return numberToByteArray(S.x(), getPointByteSize(S))
414
415 - def makeClientKeyExchange(self):
416 """Make client key exchange for ECDHE""" 417 cke = super(AECDHKeyExchange, self).makeClientKeyExchange() 418 cke.createECDH(self.ecdhYc) 419 return cke
420
421 422 # The ECDHE_RSA part comes from the IETF names of ciphersuites, so we want to 423 # keep it 424 #pylint: disable = invalid-name 425 -class ECDHE_RSAKeyExchange(AECDHKeyExchange):
426 """Helper class for conducting ECDHE key exchange""" 427
428 - def __init__(self, cipherSuite, clientHello, serverHello, privateKey, 429 acceptedCurves):
430 super(ECDHE_RSAKeyExchange, self).__init__(cipherSuite, clientHello, 431 serverHello, 432 acceptedCurves) 433 #pylint: enable = invalid-name 434 self.privateKey = privateKey
435
436 - def makeServerKeyExchange(self, sigHash=None):
437 """Create ECDHE version of Server Key Exchange""" 438 ske = super(ECDHE_RSAKeyExchange, self).makeServerKeyExchange() 439 self.signServerKeyExchange(ske, sigHash) 440 return ske
441
442 443 -class SRPKeyExchange(KeyExchange):
444 """Helper class for conducting SRP key exchange""" 445
446 - def __init__(self, cipherSuite, clientHello, serverHello, privateKey, 447 verifierDB, srpUsername=None, password=None, settings=None):
448 """Link Key Exchange options with verifierDB for SRP""" 449 super(SRPKeyExchange, self).__init__(cipherSuite, clientHello, 450 serverHello, privateKey) 451 self.N = None 452 self.v = None 453 self.b = None 454 self.B = None 455 self.verifierDB = verifierDB 456 self.A = None 457 self.srpUsername = srpUsername 458 self.password = password 459 self.settings = settings 460 if srpUsername is not None and not isinstance(srpUsername, bytearray): 461 raise TypeError("srpUsername must be a bytearray object") 462 if password is not None and not isinstance(password, bytearray): 463 raise TypeError("password must be a bytearray object")
464
465 - def makeServerKeyExchange(self, sigHash=None):
466 """Create SRP version of Server Key Exchange""" 467 srpUsername = bytes(self.clientHello.srp_username) 468 #Get parameters from username 469 try: 470 entry = self.verifierDB[srpUsername] 471 except KeyError: 472 raise TLSUnknownPSKIdentity("Unknown identity") 473 (self.N, g, s, self.v) = entry 474 475 #Calculate server's ephemeral DH values (b, B) 476 self.b = bytesToNumber(getRandomBytes(32)) 477 k = makeK(self.N, g) 478 self.B = (powMod(g, self.b, self.N) + (k * self.v)) % self.N 479 480 #Create ServerKeyExchange, signing it if necessary 481 serverKeyExchange = ServerKeyExchange(self.cipherSuite, 482 self.serverHello.server_version) 483 serverKeyExchange.createSRP(self.N, g, s, self.B) 484 if self.cipherSuite in CipherSuite.srpCertSuites: 485 self.signServerKeyExchange(serverKeyExchange, sigHash) 486 return serverKeyExchange
487
488 - def processClientKeyExchange(self, clientKeyExchange):
489 """Calculate premaster secret from Client Key Exchange and sent SKE""" 490 A = clientKeyExchange.srp_A 491 if A % self.N == 0: 492 raise TLSIllegalParameterException("Invalid SRP A value") 493 494 #Calculate u 495 u = makeU(self.N, A, self.B) 496 497 #Calculate premaster secret 498 S = powMod((A * powMod(self.v, u, self.N)) % self.N, self.b, self.N) 499 return numberToByteArray(S)
500
501 - def processServerKeyExchange(self, srvPublicKey, serverKeyExchange):
502 """Calculate premaster secret from ServerKeyExchange""" 503 del srvPublicKey # irrelevant for SRP 504 N = serverKeyExchange.srp_N 505 g = serverKeyExchange.srp_g 506 s = serverKeyExchange.srp_s 507 B = serverKeyExchange.srp_B 508 509 if (g, N) not in goodGroupParameters: 510 raise TLSInsufficientSecurity("Unknown group parameters") 511 if numBits(N) < self.settings.minKeySize: 512 raise TLSInsufficientSecurity("N value is too small: {0}".\ 513 format(numBits(N))) 514 if numBits(N) > self.settings.maxKeySize: 515 raise TLSInsufficientSecurity("N value is too large: {0}".\ 516 format(numBits(N))) 517 if B % N == 0: 518 raise TLSIllegalParameterException("Suspicious B value") 519 520 #Client ephemeral value 521 a = bytesToNumber(getRandomBytes(32)) 522 self.A = powMod(g, a, N) 523 524 #Calculate client's static DH values (x, v) 525 x = makeX(s, self.srpUsername, self.password) 526 v = powMod(g, x, N) 527 528 #Calculate u 529 u = makeU(N, self.A, B) 530 531 #Calculate premaster secret 532 k = makeK(N, g) 533 S = powMod((B - (k*v)) % N, a+(u*x), N) 534 return numberToByteArray(S)
535
536 - def makeClientKeyExchange(self):
537 """Create ClientKeyExchange""" 538 cke = super(SRPKeyExchange, self).makeClientKeyExchange() 539 cke.createSRP(self.A) 540 return cke
541