class SSLv2ClientCertificate(_SSLv2Handshake): """ SSLv2 ClientCertificate. """ name = "SSLv2 Handshake - Client Certificate" fields_desc = [ByteEnumField("msgtype", 8, _sslv2_handshake_type), ByteEnumField("certtype", 1, {1: "x509_cert"}), FieldLenField("certlen", None, fmt="!H", length_of="certdata"), FieldLenField("responselen", None, fmt="!H", length_of="responsedata"), _SSLv2CertDataField("certdata", b"", length_from=lambda pkt: pkt.certlen), _TLSSignatureField("responsedata", None, length_from=lambda pkt: pkt.responselen)] def build(self, *args, **kargs): s = self.tls_session sig = self.getfieldval("responsedata") test = (sig is None and s.sslv2_key_material is not None and s.sslv2_challenge_clientcert is not None and len(s.server_certs) > 0) if test: s = self.tls_session m = (s.sslv2_key_material + s.sslv2_challenge_clientcert + s.server_certs[0].der) self.responsedata = _TLSSignature(tls_session=s) self.responsedata._update_sig(m, s.client_key) else: self.responsedata = b"" return super(SSLv2ClientCertificate, self).build(*args, **kargs) def post_dissection_tls_session_update(self, msg_str): self.tls_session_update(msg_str) s = self.tls_session test = (len(s.client_certs) > 0 and s.sslv2_key_material is not None and s.sslv2_challenge_clientcert is not None and len(s.server_certs) > 0) if test: m = (s.sslv2_key_material + s.sslv2_challenge_clientcert + s.server_certs[0].der) sig_test = self.responsedata._verify_sig(m, s.client_certs[0]) if not sig_test: pkt_info = self.firstlayer().summary() log_runtime.info("TLS: invalid client CertificateVerify signature [%s]", pkt_info) def tls_session_update(self, msg_str): super(SSLv2ClientCertificate, self).tls_session_update(msg_str) if self.certdata: self.tls_session.client_certs = [self.certdata]
class TLSCertificateVerify(_TLSHandshake): name = "TLS Handshake - Certificate Verify" fields_desc = [ ByteEnumField("msgtype", 15, _tls_handshake_type), ThreeBytesField("msglen", None), _TLSSignatureField("sig", None, length_from=lambda pkt: pkt.msglen) ] def build(self, *args, **kargs): sig = self.getfieldval("sig") if sig is None: s = self.tls_session m = "".join(s.handshake_messages) if s.tls_version >= 0x0304: if s.connection_end == "client": context_string = "TLS 1.3, client CertificateVerify" elif s.connection_end == "server": context_string = "TLS 1.3, server CertificateVerify" m = b"\x20" * 64 + context_string + b"\x00" + s.wcs.hash.digest( m) self.sig = _TLSSignature(tls_session=s) if s.connection_end == "client": self.sig._update_sig(m, s.client_key) elif s.connection_end == "server": # should be TLS 1.3 only self.sig._update_sig(m, s.server_key) return _TLSHandshake.build(self, *args, **kargs) def post_dissection(self, pkt): s = self.tls_session m = "".join(s.handshake_messages) if s.tls_version >= 0x0304: if s.connection_end == "client": context_string = "TLS 1.3, server CertificateVerify" elif s.connection_end == "server": context_string = "TLS 1.3, client CertificateVerify" m = b"\x20" * 64 + context_string + b"\x00" + s.rcs.hash.digest(m) if s.connection_end == "server": if s.client_certs and len(s.client_certs) > 0: sig_test = self.sig._verify_sig(m, s.client_certs[0]) if not sig_test: pkt_info = pkt.firstlayer().summary() log_runtime.info( "TLS: invalid CertificateVerify signature [%s]", pkt_info) elif s.connection_end == "client": # should be TLS 1.3 only if s.server_certs and len(s.server_certs) > 0: sig_test = self.sig._verify_sig(m, s.server_certs[0]) if not sig_test: pkt_info = pkt.firstlayer().summary() log_runtime.info( "TLS: invalid CertificateVerify signature [%s]", pkt_info)
class TLSServerKeyExchange(_TLSHandshake): name = "TLS Handshake - Server Key Exchange" fields_desc = [ ByteEnumField("msgtype", 12, _tls_handshake_type), ThreeBytesField("msglen", None), _TLSServerParamsField("params", None, length_from=lambda pkt: pkt.msglen), _TLSSignatureField( "sig", None, length_from=lambda pkt: pkt.msglen - len(pkt.params)) ] def build(self, *args, **kargs): """ We overload build() method in order to provide a valid default value for params based on TLS session if not provided. This cannot be done by overriding i2m() because the method is called on a copy of the packet. The 'params' field is built according to key_exchange.server_kx_msg_cls which should have been set after receiving a cipher suite in a previous ServerHello. Usual cases are: - None: for RSA encryption or fixed FF/ECDH. This should never happen, as no ServerKeyExchange should be generated in the first place. - ServerDHParams: for ephemeral FFDH. In that case, the parameter to server_kx_msg_cls does not matter. - ServerECDH*Params: for ephemeral ECDH. There are actually three classes, which are dispatched by _tls_server_ecdh_cls_guess on the first byte retrieved. The default here is b"\03", which corresponds to ServerECDHNamedCurveParams (implicit curves). When the Server*DHParams are built via .fill_missing(), the session server_kx_privkey will be updated accordingly. """ fval = self.getfieldval("params") if fval is None: s = self.tls_session if s.pwcs: if s.pwcs.key_exchange.export: cls = ServerRSAParams(tls_session=s) else: cls = s.pwcs.key_exchange.server_kx_msg_cls(b"\x03") cls = cls(tls_session=s) try: cls.fill_missing() except: pass else: cls = Raw() self.params = cls fval = self.getfieldval("sig") if fval is None: s = self.tls_session if s.pwcs: if not s.pwcs.key_exchange.anonymous: p = self.params if p is None: p = "" m = s.client_random + s.server_random + str(p) cls = _TLSSignature(tls_session=s) cls._update_sig(m, s.server_key) else: cls = Raw() else: cls = Raw() self.sig = cls return _TLSHandshake.build(self, *args, **kargs) def post_dissection(self, pkt): """ While previously dissecting Server*DHParams, the session server_kx_pubkey should have been updated. XXX Add a 'fixed_dh' OR condition to the 'anonymous' test. """ s = self.tls_session if s.prcs and s.prcs.key_exchange.no_ske: print("USELESS SERVER KEY EXCHANGE") if (s.prcs and not s.prcs.key_exchange.anonymous and s.client_random and s.server_random and s.server_certs and len(s.server_certs) > 0): m = s.client_random + s.server_random + str(self.params) sig_test = self.sig._verify_sig(m, s.server_certs[0]) if not sig_test: print("INVALID SERVER KEY EXCHANGE SIGNATURE")