You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Sorry, it is a long story, but I tried to mention all the most important points here.
I have a server ("target") which works via https but has self-signed certificates (and just in case this certificate is outdated). In general, I do not have the access to root-certificate which was used to build "target"-server certificate.
And I am trying to use proxy.py as something like proxy authentication - I need to add some headers (like, Authorization) in order to authenticte on the "target"-server.
and it looks quite correct for this case - sercificate is "bad" and cannot be used to establish a secure connection.
But I need an option to work even with such servers. I have tried to make some workarounds for this case, more or less it works but it looks clunky and ugly and I am asking community-help besause I think there is a proper and better way to do this.
Right now I redefined TcpServerConnection.The main change is ctx.verify_mode = ssl.VerifyMode.CERT_NONE:
This "update" allows me to avoid exception in wrap_socket-function. But after that when I am making a new request I have another exception here:
2024-02-07 11:35:22,429 - pid:2623584 [E] base_events.default_exception_handler:1771 - Task exception was never retrieved
future: <Task finished name='Task-1' coro=<Threadless._run_forever() done, defined at /home/kav/AK/proxy_py/.venv/lib/python3.11/site-packages/proxy/core/work/threadless.py:376> exception=KeyError('subject')>
Traceback (most recent call last):
File "/home/kav/AK/proxy_py/.venv/lib/python3.11/site-packages/proxy/core/work/threadless.py", line 380, in _run_forever
if await self._run_once():
^^^^^^^^^^^^^^^^^^^^^^
File "/home/kav/AK/proxy_py/.venv/lib/python3.11/site-packages/proxy/core/work/threadless.py", line 364, in _run_once
teardown = task.result()
^^^^^^^^^^^^^
File "/home/kav/AK/proxy_py/.venv/lib/python3.11/site-packages/proxy/http/handler.py", line 149, in handle_events
teardown = await self.handle_readables(readables)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kav/AK/proxy_py/.venv/lib/python3.11/site-packages/proxy/http/handler.py", line 219, in handle_readables
teardown = await super().handle_readables(readables)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kav/AK/proxy_py/.venv/lib/python3.11/site-packages/proxy/core/base/tcp_server.py", line 210, in handle_readables
r = self.handle_data(data)
^^^^^^^^^^^^^^^^^^^^^^
File "/home/kav/AK/proxy_py/.venv/lib/python3.11/site-packages/proxy/http/handler.py", line 172, in handle_data
if self._parse_first_request(data):
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kav/AK/proxy_py/.venv/lib/python3.11/site-packages/proxy/http/handler.py", line 300, in _parse_first_request
output = self.plugin.on_request_complete()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kav/AK/proxy_py/.venv/lib/python3.11/site-packages/proxy/http/proxy/server.py", line 513, in on_request_complete
return self.intercept()
^^^^^^^^^^^^^^^^
File "/home/kav/AK/proxy_py/.venv/lib/python3.11/site-packages/proxy/http/proxy/server.py", line 742, in intercept
teardown = self.wrap_client()
^^^^^^^^^^^^^^^^^^
File "/home/kav/AK/proxy_py/.venv/lib/python3.11/site-packages/proxy/http/proxy/server.py", line 797, in wrap_client
generated_cert = self.generate_upstream_certificate(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/kav/AK/proxy_py/.venv/lib/python3.11/site-packages/proxy/http/proxy/server.py", line 731, in generate_upstream_certificate
self.gen_ca_signed_certificate(cert_file_path, certificate)
File "/home/kav/AK/proxy_py/.venv/lib/python3.11/site-packages/proxy/http/proxy/server.py", line 641, in gen_ca_signed_certificate
upstream_subject = {s[0][0]: s[0][1] for s in certificate['subject']}
~~~~~~~~~~~^^^^^^^^^^^
KeyError: 'subject'
If I understand correctly this happens when proxy.py tries to create a new certificate based on data of original "target"-server certificate and gen_ca_signed_certificate expects a "target"-certificate data in dictionary form but gets empty dictionary. And It gets empty dictionary because getpeercert returns empty dict for non-validated certificates (https://docs.python.org/3/library/ssl.html#ssl.SSLSocket.getpeercert):
If the certificate was not validated, the dict is empty
I have tried to workaround this somehow too and stopped on the following (but very very clunky) way - I redefined wrap_client too.
The main idea is to pass binary_form=True to getpeercert. This allows me to get certificate data (in DER-format) even it is not validated (proof: https://github.com/python/cpython/blob/3.11/Modules/_ssl.c#L1841), then I converts certificate data from DER to PEM via openssl command, parses certificate data to dictionary via "undocumented" test_decode_cert-function (because I cannot call _decode_certificate directly, https://github.com/python/cpython/blob/3.11/Modules/_ssl.c#L1769) and finally passes obtained dictionary to generate_upstream_certificate. The example of code is bellow:
After that I am able to proxy requests to servers with self-signed (and not valid) certificates but as I said it looks ugly and I think there is a better way to do this. I will be very apreciated to any suggestions (and critica, like for security holes).
reacted with thumbs up emoji reacted with thumbs down emoji reacted with laugh emoji reacted with hooray emoji reacted with confused emoji reacted with heart emoji reacted with rocket emoji reacted with eyes emoji
-
Sorry, it is a long story, but I tried to mention all the most important points here.
I have a server ("target") which works via https but has self-signed certificates (and just in case this certificate is outdated). In general, I do not have the access to root-certificate which was used to build "target"-server certificate.
And I am trying to use
proxy.py
as something like proxy authentication - I need to add some headers (like,Authorization
) in order to authenticte on the "target"-server.I am running
proxy.py
so:ca-key.pem
,ca-cert.pem
,ca-signing-key.pem
were made viamake ca-certificates
.Now I am trying to perform a request to "target"-server:
*localhost:8899 - is the address of
proxy.py
instance.I get something like this:
I have same error when ask curl to ignore SSL checking (
-k
option):In the
proxy.py
log I have the following warning:The error is generated here
proxy.py/proxy/core/connection/server.py
Line 62 in 30574fd
and it looks quite correct for this case - sercificate is "bad" and cannot be used to establish a secure connection.
But I need an option to work even with such servers. I have tried to make some workarounds for this case, more or less it works but it looks clunky and ugly and I am asking community-help besause I think there is a proper and better way to do this.
Right now I redefined
TcpServerConnection
.The main change isctx.verify_mode = ssl.VerifyMode.CERT_NONE
:In order to enable
TcpServerConnectionWithSelfSigned
I had to copy-paste more code fromHttpProxyPlugin
:After that I need to run
proxy.py
like:This "update" allows me to avoid exception in
wrap_socket
-function. But after that when I am making a new request I have another exception here:If I understand correctly this happens when
proxy.py
tries to create a new certificate based on data of original "target"-server certificate andgen_ca_signed_certificate
expects a "target"-certificate data in dictionary form but gets empty dictionary. And It gets empty dictionary becausegetpeercert
returns empty dict for non-validated certificates (https://docs.python.org/3/library/ssl.html#ssl.SSLSocket.getpeercert):I have tried to workaround this somehow too and stopped on the following (but very very clunky) way - I redefined
wrap_client
too.The main idea is to pass
binary_form=True
togetpeercert
. This allows me to get certificate data (inDER
-format) even it is not validated (proof: https://github.com/python/cpython/blob/3.11/Modules/_ssl.c#L1841), then I converts certificate data fromDER
toPEM
via openssl command, parses certificate data to dictionary via "undocumented"test_decode_cert
-function (because I cannot call_decode_certificate
directly, https://github.com/python/cpython/blob/3.11/Modules/_ssl.c#L1769) and finally passes obtained dictionary togenerate_upstream_certificate
. The example of code is bellow:After that I am able to proxy requests to servers with self-signed (and not valid) certificates but as I said it looks ugly and I think there is a better way to do this. I will be very apreciated to any suggestions (and critica, like for security holes).
Beta Was this translation helpful? Give feedback.
All reactions