commit 28bb44a8b21c8b2488580f2fdbbf10cd1a5ccd75 Author: Isis Lovecruft isis@torproject.org Date: Thu Feb 28 04:35:09 2013 +0000
Add reporting mechanisms to handshakeSucceeded() for storing the x509 certificate and chain in a way that YAML won't complain about.
* TODO: we may want to look into a better method for serialising certificates that is compatible with YAML, rather than just storing them as PEM encoded certs in a string. * Also, pyOpenSSL will segfault if you try to check the cert. Added a warning in the docstring of method handshakeSucceeded() about that. --- nettests/experimental/tls_handshake.py | 66 ++++++++++++++++++++++++++------ 1 file changed, 55 insertions(+), 11 deletions(-)
diff --git a/nettests/experimental/tls_handshake.py b/nettests/experimental/tls_handshake.py index c77682d..da6cbc0 100644 --- a/nettests/experimental/tls_handshake.py +++ b/nettests/experimental/tls_handshake.py @@ -506,17 +506,61 @@ class TLSHandshakeTest(nettest.NetTestCase): return connection
def handshakeSucceeded(connection): - if connection: - host, port = connection.getpeername() - self.report['host'] = host - self.report['port'] = port - self.report['state'] = connection.state_string() - - def handshakeFailed(connection, addr, port): - if connection is None: - self.report['host'] = addr - self.report['port'] = port - self.report['state'] = 'FAILED' + """ + Get the details from the server certificate, cert chain, and + server ciphersuite list, and put them in our report. + + WARNING: do *not* do this: + >>> server_cert.get_pubkey() + <OpenSSL.crypto.PKey at 0x4985d28> + >>> pk = server_cert.get_pubkey() + >>> pk.check + <function check> + >>> pk.check() + Segmentation fault + + @param connection: A :class:`OpenSSL.SSL.Connection`. + @returns: None. + """ + host, port = connection.getpeername() + server_cert = self.getPeerCert(connection) + server_cert_chain = self.getPeerCert(connection, get_chain=True) + + s_cert = connection.get_peer_certificate() + cert_subject = s_cert.get_subject() + cert_subj_hash = s_cert.subject_name_hash() + cert_issuer = s_cert.get_issuer() + cert_public_key = s_cert.get_pubkey() + cert_serial_no = s_cert.get_serial_number() + cert_sig_algo = s_cert.get_signature_algorithm() + + self.report['host'] = host + self.report['port'] = port + self.report['state'] = connection.state_string() + self.report['renegotiations'] = connection.total_renegotiations() + self.report['server_cert'] = server_cert + self.report['server_cert_chain'] = \ + ''.join([cert for cert in server_cert_chain]) + self.report['server_ciphersuite'] = connection.get_cipher_list() + self.report['cert_subject'] = str(cert_subject) + self.report['cert_subj_hash'] = str(cert_subj_hash) + self.report['cert_issuer'] = str(cert_issuer) + ## xxx this needs to be parsed into PEM also + self.report['cert_public_key'] = str(cert_public_key) + self.report['cert_serial_no'] = str(cert_serial_no) + self.report['cert_sig_algo'] = str(cert_sig_algo) + + ## The session's master key is only valid for that session, and + ## will allow us to decrypt any packet captures (if they were + ## collected). Because we are not requesting URLs, only host:port + ## (which would be visible in pcaps anyway, since the FQDN is + ## never encrypted) I do not see a way for this to log any user or + ## identifying information. Correct me if I'm wrong. + self.report['session_key'] = connection.master_key() + + ## xxx do we need this? + #return connection + else: return handshakeSucceeded(connection)