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