New option: Add server certs to client chain

If enabled, append all server certificates to the certificate chain
served to the client, as extras. Can be used to bypass certain
certificate pinning impementations.
This commit is contained in:
ikoz 2016-03-02 15:23:33 +00:00
parent ea3742c393
commit 0169271bf9
4 changed files with 26 additions and 1 deletions

View File

@ -434,6 +434,12 @@ def proxy_ssl_options(parser):
action="store_true", dest="no_upstream_cert",
help="Don't connect to upstream server to look up certificate details."
)
group.add_argument(
"--add-server-certs-to-client-chain", default=False,
action="store_true", dest="add_server_certs_to_client_chain",
help="Add all the certificates of the server to the certificate chain "
"that will be served to the client, as extras."
)
group.add_argument(
"--verify-upstream-cert", default=False,
action="store_true", dest="ssl_verify_upstream_cert",

View File

@ -432,6 +432,11 @@ class TlsLayer(Layer):
self.log("Establish TLS with client", "debug")
cert, key, chain_file = self._find_cert()
if self.config.add_server_certs_to_client_chain:
extra_certs = self.server_conn.server_certs
else:
extra_certs = None
try:
self.client_conn.convert_to_ssl(
cert, key,
@ -441,6 +446,7 @@ class TlsLayer(Layer):
dhparams=self.config.certstore.dhparams,
chain_file=chain_file,
alpn_select_callback=self.__alpn_select_callback,
extra_chain_certs = extra_certs,
)
# Some TLS clients will not fail the handshake,
# but will immediately throw an "unexpected eof" error on the first read.

View File

@ -67,6 +67,7 @@ class ProxyConfig:
ssl_verify_upstream_cert=False,
ssl_verify_upstream_trusted_cadir=None,
ssl_verify_upstream_trusted_ca=None,
add_server_certs_to_client_chain=False,
):
self.host = host
self.port = port
@ -107,6 +108,7 @@ class ProxyConfig:
self.openssl_verification_mode_server = SSL.VERIFY_NONE
self.openssl_trusted_cadir_server = ssl_verify_upstream_trusted_cadir
self.openssl_trusted_ca_server = ssl_verify_upstream_trusted_ca
self.add_server_certs_to_client_chain = add_server_certs_to_client_chain
def process_proxy_options(parser, options):
@ -206,5 +208,6 @@ def process_proxy_options(parser, options):
ssl_version_server=options.ssl_version_server,
ssl_verify_upstream_cert=options.ssl_verify_upstream_cert,
ssl_verify_upstream_trusted_cadir=options.ssl_verify_upstream_trusted_cadir,
ssl_verify_upstream_trusted_ca=options.ssl_verify_upstream_trusted_ca
ssl_verify_upstream_trusted_ca=options.ssl_verify_upstream_trusted_ca,
add_server_certs_to_client_chain=options.add_server_certs_to_client_chain,
)

View File

@ -584,6 +584,7 @@ class TCPClient(_Connection):
self.address = address
self.source_address = source_address
self.cert = None
self.server_certs = []
self.ssl_verification_error = None
self.sni = None
@ -668,6 +669,10 @@ class TCPClient(_Connection):
self.cert = certutils.SSLCert(self.connection.get_peer_certificate())
# Keep all server certificates in a list
for i in self.connection.get_peer_cert_chain():
self.server_certs.append(certutils.SSLCert(i))
# Validate TLS Hostname
try:
crt = dict(
@ -734,6 +739,7 @@ class BaseHandler(_Connection):
request_client_cert=None,
chain_file=None,
dhparams=None,
extra_chain_certs=None,
**sslctx_kwargs):
"""
cert: A certutils.SSLCert object or the path to a certificate
@ -769,6 +775,10 @@ class BaseHandler(_Connection):
else:
context.use_certificate_chain_file(cert)
if extra_chain_certs:
for i in extra_chain_certs:
context.add_extra_chain_cert(i.x509)
if handle_sni:
# SNI callback happens during do_handshake()
context.set_tlsext_servername_callback(handle_sni)