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          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 
20 21 -class KeyExchange(object):
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
35 - def makeServerKeyExchange(self, sigHash=None):
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
45 - def makeClientKeyExchange(self):
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
55 - def processClientKeyExchange(self, clientKeyExchange):
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
64 - def processServerKeyExchange(self, srvPublicKey, 65 serverKeyExchange):
66 """Process the server KEX and return premaster secret""" 67 raise NotImplementedError()
68
69 - def signServerKeyExchange(self, serverKeyExchange, sigHash=None):
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
88 - def verifyServerKeyExchange(serverKeyExchange, publicKey, clientRandom, 89 serverRandom, validSigAlgs):
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 # in TLS 1.2 we must decide which algorithm to use for signing 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 # if none acceptable, do a last resort: 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
173 -class RSAKeyExchange(KeyExchange):
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
185 - def makeServerKeyExchange(self, sigHash=None):
186 """Don't create a server key exchange for RSA key exchange""" 187 return None
188
189 - def processClientKeyExchange(self, clientKeyExchange):
190 """Decrypt client key exchange, return premaster secret""" 191 premasterSecret = self.privateKey.decrypt(\ 192 clientKeyExchange.encryptedPreMasterSecret) 193 194 # On decryption failure randomize premaster secret to avoid 195 # Bleichenbacher's "million message" attack 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 #Tolerate buggy IE clients 205 if versionCheck != self.serverHello.server_version: 206 premasterSecret = randomPreMasterSecret 207 return premasterSecret
208
209 - def processServerKeyExchange(self, srvPublicKey, 210 serverKeyExchange):
211 """Generate premaster secret for server""" 212 del serverKeyExchange # not present in RSA key exchange 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
220 - def makeClientKeyExchange(self):
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
226 # the DHE_RSA part comes from IETF ciphersuite names, we want to keep it 227 #pylint: disable = invalid-name 228 -class DHE_RSAKeyExchange(KeyExchange):
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 #pylint: enable = invalid-name 239 self.dh_Xs = None 240 self.dh_Yc = None
241 242 # 2048-bit MODP Group (RFC 3526, Section 3) 243 dh_g, dh_p = goodGroupParameters[2] 244 245 # RFC 3526, Section 8. 246 strength = 160 247
248 - def makeServerKeyExchange(self, sigHash=None):
249 """Prepare server side of key exchange with selected parameters""" 250 # Per RFC 3526, Section 1, the exponent should have double the entropy 251 # of the strength of the curve. 252 self.dh_Xs = bytesToNumber(getRandomBytes(self.strength * 2 // 8)) 253 dh_Ys = powMod(self.dh_g, self.dh_Xs, self.dh_p) 254 255 version = self.serverHello.server_version 256 serverKeyExchange = ServerKeyExchange(self.cipherSuite, version) 257 serverKeyExchange.createDH(self.dh_p, self.dh_g, dh_Ys) 258 self.signServerKeyExchange(serverKeyExchange, sigHash) 259 return serverKeyExchange
260
261 - def processClientKeyExchange(self, clientKeyExchange):
262 """Use client provided parameters to establish premaster secret""" 263 dh_Yc = clientKeyExchange.dh_Yc 264 265 # First half of RFC 2631, Section 2.1.5. Validate the client's public 266 # key. 267 if not 2 <= dh_Yc <= self.dh_p - 1: 268 raise TLSLocalAlert(AlertDescription.illegal_parameter, 269 "Invalid dh_Yc value") 270 271 S = powMod(dh_Yc, self.dh_Xs, self.dh_p) 272 return numberToByteArray(S)
273
274 - def processServerKeyExchange(self, srvPublicKey, serverKeyExchange):
275 """Process the server key exchange, return premaster secret""" 276 del srvPublicKey 277 dh_p = serverKeyExchange.dh_p 278 # TODO make the minimum changeable 279 if dh_p < 2**1023: 280 raise TLSInsufficientSecurity("DH prime too small") 281 dh_g = serverKeyExchange.dh_g 282 dh_Xc = bytesToNumber(getRandomBytes(32)) 283 dh_Ys = serverKeyExchange.dh_Ys 284 self.dh_Yc = powMod(dh_g, dh_Xc, dh_p) 285 286 S = powMod(dh_Ys, dh_Xc, dh_p) 287 return numberToByteArray(S)
288
289 - def makeClientKeyExchange(self):
290 """Create client key share for the key exchange""" 291 cke = super(DHE_RSAKeyExchange, self).makeClientKeyExchange() 292 cke.createDH(self.dh_Yc) 293 return cke
294
295 # The ECDHE_RSA part comes from the IETF names of ciphersuites, so we want to 296 # keep it 297 #pylint: disable = invalid-name 298 -class ECDHE_RSAKeyExchange(KeyExchange):
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 #pylint: enable = invalid-name 306 self.ecdhXs = None 307 self.acceptedCurves = acceptedCurves 308 self.group_id = None 309 self.ecdhYc = None
310
311 - def makeServerKeyExchange(self, sigHash=None):
312 """Create ECDHE version of Server Key Exchange""" 313 #Get client supported groups 314 client_curves = self.clientHello.getExtension(\ 315 ExtensionType.supported_groups) 316 if client_curves is None or client_curves.groups is None or \ 317 len(client_curves.groups) == 0: 318 raise TLSInternalError("Can't do ECDHE with no client curves") 319 client_curves = client_curves.groups 320 321 #Pick first client preferred group we support 322 self.group_id = next((x for x in client_curves \ 323 if x in self.acceptedCurves), 324 None) 325 if self.group_id is None: 326 raise TLSInsufficientSecurity("No mutual groups") 327 generator = getCurveByName(GroupName.toRepr(self.group_id)).generator 328 self.ecdhXs = ecdsa.util.randrange(generator.order()) 329 330 ecdhYs = encodeX962Point(generator * self.ecdhXs) 331 332 version = self.serverHello.server_version 333 serverKeyExchange = ServerKeyExchange(self.cipherSuite, version) 334 serverKeyExchange.createECDH(ECCurveType.named_curve, 335 named_curve=self.group_id, 336 point=ecdhYs) 337 self.signServerKeyExchange(serverKeyExchange, sigHash) 338 return serverKeyExchange
339
340 - def processClientKeyExchange(self, clientKeyExchange):
341 """Calculate premaster secret from previously generated SKE and CKE""" 342 curveName = GroupName.toRepr(self.group_id) 343 ecdhYc = decodeX962Point(clientKeyExchange.ecdh_Yc, 344 getCurveByName(curveName)) 345 346 sharedSecret = ecdhYc * self.ecdhXs 347 348 return numberToByteArray(sharedSecret.x(), getPointByteSize(ecdhYc))
349
350 - def processServerKeyExchange(self, srvPublicKey, serverKeyExchange):
351 """Process the server key exchange, return premaster secret""" 352 del srvPublicKey 353 354 if serverKeyExchange.curve_type != ECCurveType.named_curve \ 355 or serverKeyExchange.named_curve not in self.acceptedCurves: 356 raise TLSIllegalParameterException("Server picked curve we " 357 "didn't advertise") 358 359 curveName = GroupName.toStr(serverKeyExchange.named_curve) 360 curve = getCurveByName(curveName) 361 generator = curve.generator 362 363 ecdhXc = ecdsa.util.randrange(generator.order()) 364 ecdhYs = decodeX962Point(serverKeyExchange.ecdh_Ys, curve) 365 self.ecdhYc = encodeX962Point(generator * ecdhXc) 366 S = ecdhYs * ecdhXc 367 return numberToByteArray(S.x(), getPointByteSize(S))
368
369 - def makeClientKeyExchange(self):
370 """Make client key exchange for ECDHE""" 371 cke = super(ECDHE_RSAKeyExchange, self).makeClientKeyExchange() 372 cke.createECDH(self.ecdhYc) 373 return cke
374
375 -class SRPKeyExchange(KeyExchange):
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
393 - def makeServerKeyExchange(self, sigHash=None):
394 """Create SRP version of Server Key Exchange""" 395 srpUsername = self.clientHello.srp_username.decode("utf-8") 396 #Get parameters from username 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 #Calculate server's ephemeral DH values (b, B) 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 #Create ServerKeyExchange, signing it if necessary 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
416 - def processClientKeyExchange(self, clientKeyExchange):
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 #Calculate u 423 u = makeU(self.N, A, self.B) 424 425 #Calculate premaster secret 426 S = powMod((A * powMod(self.v, u, self.N)) % self.N, self.b, self.N) 427 return numberToByteArray(S)
428
429 - def processServerKeyExchange(self, srvPublicKey, serverKeyExchange):
430 """Calculate premaster secret from ServerKeyExchange""" 431 del srvPublicKey # irrelevant for SRP 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 #Client ephemeral value 449 a = bytesToNumber(getRandomBytes(32)) 450 self.A = powMod(g, a, N) 451 452 #Calculate client's static DH values (x, v) 453 x = makeX(s, bytearray(self.srpUsername, "utf-8"), 454 bytearray(self.password, "utf-8")) 455 v = powMod(g, x, N) 456 457 #Calculate u 458 u = makeU(N, self.A, B) 459 460 #Calculate premaster secret 461 k = makeK(N, g) 462 S = powMod((B - (k*v)) % N, a+(u*x), N) 463 return numberToByteArray(S)
464
465 - def makeClientKeyExchange(self):
466 """Create ClientKeyExchange""" 467 cke = super(SRPKeyExchange, self).makeClientKeyExchange() 468 cke.createSRP(self.A) 469 return cke
470