mirror of https://github.com/scrapy/scrapy.git
Log cipher, certificate and temp key info on establishing an SSL connection.
This commit is contained in:
parent
4c755f1ddc
commit
69b1d5d3d7
|
|
@ -2,6 +2,7 @@ import logging
|
|||
from OpenSSL import SSL
|
||||
|
||||
from scrapy import twisted_version
|
||||
from scrapy.utils.ssl import x509name_to_string, get_temp_key_info
|
||||
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
|
@ -20,6 +21,7 @@ openssl_methods = {
|
|||
METHOD_TLSv12: getattr(SSL, 'TLSv1_2_METHOD', 6), # TLS 1.2 only
|
||||
}
|
||||
|
||||
|
||||
if twisted_version >= (14, 0, 0):
|
||||
# ClientTLSOptions requires a recent-enough version of Twisted.
|
||||
# Not having ScrapyClientTLSOptions should not matter for older
|
||||
|
|
@ -65,13 +67,27 @@ if twisted_version >= (14, 0, 0):
|
|||
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()),
|
||||
)
|
||||
key_info = get_temp_key_info(connection._ssl)
|
||||
if key_info:
|
||||
logger.debug('SSL temp key: %s', key_info)
|
||||
|
||||
try:
|
||||
verifyHostname(connection, self._hostnameASCII)
|
||||
except verification_errors as e:
|
||||
|
|
|
|||
|
|
@ -0,0 +1,50 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
|
||||
import OpenSSL._util as pyOpenSSLutil
|
||||
|
||||
from scrapy.utils.python import to_native_str
|
||||
|
||||
|
||||
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)
|
||||
pyOpenSSLutil.lib.X509_NAME_oneline(x509name._name, result_buffer, len(result_buffer))
|
||||
|
||||
return ffi_buf_to_string(result_buffer)
|
||||
|
||||
|
||||
def get_temp_key_info(ssl_object):
|
||||
if not hasattr(pyOpenSSLutil.lib, 'SSL_get_server_tmp_key'): # requires OpenSSL 1.0.2
|
||||
return None
|
||||
|
||||
# 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(ssl_object, temp_key_p)
|
||||
if temp_key_p == pyOpenSSLutil.ffi.NULL:
|
||||
return None
|
||||
|
||||
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))
|
||||
return ', '.join(key_info)
|
||||
Loading…
Reference in New Issue