class EncryptedPreMasterSecret(_GenericTLSSessionInheritance): """ Pay attention to implementation notes in section 7.4.7.1 of RFC 5246. """ name = "RSA Encrypted PreMaster Secret" fields_desc = [ _TLSClientVersionField("client_version", None, _tls_version), StrFixedLenField("random", None, 46) ] def pre_dissect(self, m): s = self.tls_session tbd = m if s.tls_version >= 0x0301: if len(m) < 2: # Should not happen return m l = struct.unpack("!H", m[:2])[0] if len(m) != l + 2: err = "TLS 1.0+, but RSA Encrypted PMS with no explicit length" warning(err) else: tbd = m[2:] if s.server_tmp_rsa_key is not None: # priority is given to the tmp_key, if there is one decrypted = s.server_tmp_rsa_key.decrypt(tbd) pms = decrypted[-48:] elif s.server_rsa_key is not None: decrypted = s.server_rsa_key.decrypt(tbd) pms = decrypted[-48:] else: pms = b"\x00" * 48 # Hack but we should not be there anyway err = "No server RSA key to decrypt Pre Master Secret. Skipping." warning(err) s.pre_master_secret = pms s.compute_ms_and_derive_keys() return pms def post_build(self, pkt, pay): """ We encrypt the premaster secret (the 48 bytes) with either the server certificate or the temporary RSA key provided in a server key exchange message. After that step, we add the 2 bytes to provide the length, as described in implementation notes at the end of section 7.4.7.1. """ enc = pkt s = self.tls_session s.pre_master_secret = enc s.compute_ms_and_derive_keys() if s.server_tmp_rsa_key is not None: enc = s.server_tmp_rsa_key.encrypt(pkt, "pkcs") elif s.server_certs is not None and len(s.server_certs) > 0: enc = s.server_certs[0].encrypt(pkt, "pkcs") else: warning("No material to encrypt Pre Master Secret") l = "" if s.tls_version >= 0x0301: l = struct.pack("!H", len(enc)) return "%s%s%s" % (l, enc, pay) def guess_payload_class(self, p): return Padding
class EncryptedPreMasterSecret(_GenericTLSSessionInheritance): """ Pay attention to implementation notes in section 7.4.7.1 of RFC 5246. """ name = "RSA Encrypted PreMaster Secret" fields_desc = [_TLSClientVersionField("client_version", None, _tls_version), StrFixedLenField("random", None, 46)] @classmethod def dispatch_hook(cls, _pkt=None, *args, **kargs): if _pkt and 'tls_session' in kargs: s = kargs['tls_session'] if s.server_tmp_rsa_key is None and s.server_rsa_key is None: return _UnEncryptedPreMasterSecret return EncryptedPreMasterSecret def pre_dissect(self, m): s = self.tls_session tbd = m tls_version = s.tls_version if tls_version is None: tls_version = s.advertised_tls_version if tls_version >= 0x0301: if len(m) < 2: # Should not happen return m tmp_len = struct.unpack("!H", m[:2])[0] if len(m) != tmp_len + 2: err = "TLS 1.0+, but RSA Encrypted PMS with no explicit length" warning(err) else: tbd = m[2:] if s.server_tmp_rsa_key is not None: # priority is given to the tmp_key, if there is one decrypted = s.server_tmp_rsa_key.decrypt(tbd) pms = decrypted[-48:] elif s.server_rsa_key is not None: decrypted = s.server_rsa_key.decrypt(tbd) pms = decrypted[-48:] else: # the dispatch_hook is supposed to prevent this case pms = b"\x00" * 48 err = "No server RSA key to decrypt Pre Master Secret. Skipping." warning(err) s.pre_master_secret = pms if not s.extms or s.session_hash: s.compute_ms_and_derive_keys() return pms def post_build(self, pkt, pay): """ We encrypt the premaster secret (the 48 bytes) with either the server certificate or the temporary RSA key provided in a server key exchange message. After that step, we add the 2 bytes to provide the length, as described in implementation notes at the end of section 7.4.7.1. """ enc = pkt s = self.tls_session s.pre_master_secret = enc if not s.extms or s.session_hash: s.compute_ms_and_derive_keys() if s.server_tmp_rsa_key is not None: enc = s.server_tmp_rsa_key.encrypt(pkt, t="pkcs") elif s.server_certs is not None and len(s.server_certs) > 0: enc = s.server_certs[0].encrypt(pkt, t="pkcs") else: warning("No material to encrypt Pre Master Secret") tmp_len = b"" tls_version = s.tls_version if tls_version is None: tls_version = s.advertised_tls_version if tls_version >= 0x0301: tmp_len = struct.pack("!H", len(enc)) return tmp_len + enc + pay def guess_payload_class(self, p): return Padding
class TLSClientHello(_TLSHandshake): """ TLS ClientHello, with abilities to handle extensions. The Random structure follows the RFC 5246: while it is 32-byte long, many implementations use the first 4 bytes as a gmt_unix_time, and then the remaining 28 byts should be completely random. This was designed in order to (sort of) mitigate broken RNGs. If you prefer to show the full 32 random bytes without any GMT time, just comment in/out the lines below. """ name = "TLS Handshake - Client Hello" fields_desc = [ ByteEnumField("msgtype", 1, _tls_handshake_type), ThreeBytesField("msglen", None), _TLSClientVersionField("version", None, _tls_version), #_TLSRandomBytesField("random_bytes", None, 32), _GMTUnixTimeField("gmt_unix_time", None), _TLSRandomBytesField("random_bytes", None, 28), FieldLenField("sidlen", None, fmt="B", length_of="sid"), _SessionIDField("sid", "", length_from=lambda pkt: pkt.sidlen), FieldLenField("cipherslen", None, fmt="!H", length_of="ciphers"), _CipherSuitesField("ciphers", [TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256], _tls_cipher_suites, itemfmt="!H", length_from=lambda pkt: pkt.cipherslen), FieldLenField("complen", None, fmt="B", length_of="comp"), _CompressionMethodsField("comp", [0], _tls_compression_algs, itemfmt="B", length_from=lambda pkt: pkt.complen), _ExtensionsLenField("extlen", None, length_of="ext"), _ExtensionsField("ext", None, length_from=lambda pkt: (pkt.msglen - (pkt.sidlen or 0) - (pkt.cipherslen or 0) - (pkt.complen or 0) - 40)) ] def post_build(self, p, pay): if self.random_bytes is None: p = p[:10] + randstring(28) + p[10 + 28:] return super(TLSClientHello, self).post_build(p, pay) def tls_session_update(self, msg_str): """ Either for parsing or building, we store the client_random along with the raw string representing this handshake message. """ super(TLSClientHello, self).tls_session_update(msg_str) self.tls_session.advertised_tls_version = self.version self.random_bytes = msg_str[10:38] self.tls_session.client_random = ( struct.pack('!I', self.gmt_unix_time) + self.random_bytes) if self.ext: for e in self.ext: if isinstance(e, TLS_Ext_SupportedVersions): if self.tls_session.tls13_early_secret is None: # this is not recomputed if there was a TLS 1.3 HRR self.tls_session.compute_tls13_early_secrets() break