Skip to content

Commit

Permalink
Log cipher, certificate and temp key info on establishing an SSL conn…
Browse files Browse the repository at this point in the history
…ection.
  • Loading branch information
wRAR committed Oct 5, 2018
1 parent 7223978 commit 94d0764
Showing 1 changed file with 55 additions and 1 deletion.
56 changes: 55 additions & 1 deletion scrapy/core/downloader/tls.py
@@ -1,7 +1,9 @@
import logging
from OpenSSL import SSL
import OpenSSL._util as pyOpenSSLutil

from scrapy import twisted_version
from scrapy.utils.python import to_native_str


logger = logging.getLogger(__name__)
Expand All @@ -20,6 +22,20 @@
METHOD_TLSv12: getattr(SSL, 'TLSv1_2_METHOD', 6), # TLS 1.2 only
}


def ffi_buf_to_string(buf):
return to_native_str(pyOpenSSLutil.ffi.string(buf))


def x509name_to_string(x509name):
# from OpenSSL.crypto.X509Name.__repr__
result_buffer = pyOpenSSLutil.ffi.new("char[]", 512)
format_result = pyOpenSSLutil.lib.X509_NAME_oneline(
x509name._name, result_buffer, len(result_buffer))

return ffi_buf_to_string(result_buffer)


if twisted_version >= (14, 0, 0):
# ClientTLSOptions requires a recent-enough version of Twisted.
# Not having ScrapyClientTLSOptions should not matter for older
Expand Down Expand Up @@ -65,13 +81,51 @@ class ScrapyClientTLSOptions(ClientTLSOptions):
Same as Twisted's private _sslverify.ClientTLSOptions,
except that VerificationError, CertificateError and ValueError
exceptions are caught, so that the connection is not closed, only
logging warnings.
logging warnings. Also, HTTPS connection parameters logging is added.
"""

def _identityVerifyingInfoCallback(self, connection, where, ret):
if where & SSL_CB_HANDSHAKE_START:
set_tlsext_host_name(connection, self._hostnameBytes)
elif where & SSL_CB_HANDSHAKE_DONE:
logger.debug('SSL connection to %s using protocol %s, cipher %s',
self._hostnameASCII,
connection.get_protocol_version_name(),
connection.get_cipher_name(),
)
server_cert = connection.get_peer_certificate()
logger.debug('SSL connection certificate: issuer "%s", subject "%s"',
x509name_to_string(server_cert.get_issuer()),
x509name_to_string(server_cert.get_subject()),
)

if hasattr(pyOpenSSLutil.lib, 'SSL_get_server_tmp_key'): # requires OpenSSL 1.0.2
# adapted from OpenSSL apps/s_cb.c::ssl_print_tmp_key()
temp_key_p = pyOpenSSLutil.ffi.new("EVP_PKEY **")
pyOpenSSLutil.lib.SSL_get_server_tmp_key(connection._ssl, temp_key_p)
if temp_key_p != pyOpenSSLutil.ffi.NULL:
temp_key = temp_key_p[0]
pyOpenSSLutil.ffi.gc(temp_key, pyOpenSSLutil.lib.EVP_PKEY_free)
key_info = []
key_type = pyOpenSSLutil.lib.EVP_PKEY_id(temp_key)
if key_type == pyOpenSSLutil.lib.EVP_PKEY_RSA:
key_info.append('RSA')
elif key_type == pyOpenSSLutil.lib.EVP_PKEY_DH:
key_info.append('DH')
elif key_type == pyOpenSSLutil.lib.EVP_PKEY_EC:
key_info.append('ECDH')
ec_key = pyOpenSSLutil.lib.EVP_PKEY_get1_EC_KEY(temp_key)
pyOpenSSLutil.ffi.gc(ec_key, pyOpenSSLutil.lib.EC_KEY_free)
nid = pyOpenSSLutil.lib.EC_GROUP_get_curve_name(pyOpenSSLutil.lib.EC_KEY_get0_group(ec_key))
cname = pyOpenSSLutil.lib.EC_curve_nid2nist(nid)
if cname == pyOpenSSLutil.ffi.NULL:
cname = pyOpenSSLutil.lib.OBJ_nid2sn(nid)
key_info.append(ffi_buf_to_string(cname))
else:
key_info.append(ffi_buf_to_string(pyOpenSSLutil.lib.OBJ_nid2sn(key_type)))
key_info.append('%s bits' % pyOpenSSLutil.lib.EVP_PKEY_bits(temp_key))
logger.debug('SSL temp key: %s', ', '.join(key_info))

try:
verifyHostname(connection, self._hostnameASCII)
except verification_errors as e:
Expand Down

0 comments on commit 94d0764

Please sign in to comment.