0

Pretty straight forward. I'm trying to do some SSL Handshake and get the endpoint certificate from sslsocket documentation: do_handshake. Instead, I greeted with this specific error:

  File "/usr/lib/python3.10/ssl.py", line 1342, in do_handshake
    self._sslobj.do_handshake()
ssl.SSLError: [SSL: SSLV3_ALERT_HANDSHAKE_FAILURE] sslv3 alert handshake failure (_ssl.c:997)

The certificate will be used to extract any SubjectName or CommonName. Been looking around with 100 chrome tabs, busting my memory only for browsing. I have tried many steps:

# Monkey Patch to use Unverified Context
ssl._create_default_https_context = ssl._create_unverified_context

# Disable SSL Verification
sslContext.check_hostname = False
sslContext.verify_mode = ssl.CERT_NONE

# Using Custom Ciphers
cipher = (':ECDHE-RSA-AES128-GCM-SHA256:DES-CBC3-SHA:AES256-SHA:AES128-SHA:AES128-SHA256:AES256-GCM-SHA384:AES256-SHA256:ECDHE-RSA-DES-CBC3:EDH-RSA-DES-CBC3:EECDH+AESGCM:EDH-RSA-DES-CBC3-SHA:EDH-AESGCM:AES256+EECDH:ECHDE-RSA-AES256-GCM-SHA384:ECHDE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECHDE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-A$:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK')
sslContext.set_ciphers(cipher)

# Using Custom OpenSSL Config

openssl_conf = openssl_init

[openssl_init]
ssl_conf = ssl_sect

[ssl_sect]
system_default = system_default_sect

[system_default_sect]
Options = UnsafeLegacyRenegotiation

None of them that able to fix the issue. Here's my current modified script based on sslsocket documentation

import socket
import ssl
import platform
import time

cipher = (':ECDHE-RSA-AES128-GCM-SHA256:DES-CBC3-SHA:AES256-SHA:AES128-SHA:AES128-SHA256:AES256-GCM-SHA384:AES256-SHA256:ECDHE-RSA-DES-CBC3:EDH-RSA-DES-CBC3:EECDH+AESGCM:EDH-RSA-DES-CBC3-SHA:EDH-AESGCM:AES256+EECDH:ECHDE-RSA-AES256-GCM-SHA384:ECHDE-ECDSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECHDE-ECDSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:AES256+EDH:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-A$:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:DHE-RSA-AES256-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!3DES:!MD5:!PSK')
ssl._create_default_https_context = ssl._create_unverified_context

sslContext = ssl.create_default_context()
sslContext.check_hostname = False
sslContext.set_ciphers(cipher)
sslContext.verify_mode = ssl.CERT_NONE

clientSocket = socket.socket()
secureClientSocket = sslContext.wrap_socket(clientSocket, do_handshake_on_connect=False)

t1 = time.time()
retval = secureClientSocket.connect(("example.com", 443))
print("Time taken to establish the connection:%2.3f"%(time.time() - t1))

t3 = time.time()
secureClientSocket.do_handshake()
print("Time taken for SSL handshake:%2.3f"%(time.time() - t3))

serverCertificate = secureClientSocket.getpeercert()
print("Certificate obtained from the server:")
print(serverCertificate)

My Setup

openssl version
OpenSSL 3.0.7 1 Nov 2022 (Library: OpenSSL 3.0.7 1 Nov 2022)

python3 --version
Python 3.10.8

I'm in desperate situation, anyhelp is highly appreciated.

Xavi
  • 129
  • 1
  • 9
  • 1
    I cannot reproduce the problem with your code. Are you really testing against example.com or do you use another target domain? Also note that getpeercert will be empty if you disable certificate validation. And you might get the wrong certificate since you don't give the expected `server_name` in wrap_socket and thus no SNI is used. – Steffen Ullrich Jan 13 '23 at 16:37
  • Yeah, I've been noticing. Disabling SSL Verification because of desperation. I have test it against list of Domains and the result is the same @SteffenUllrich – Xavi Jan 13 '23 at 16:46
  • Moving the Environment from WSL to Windows, the script works but does not print any certificate (it's empty). @SteffenUllrich – Xavi Jan 13 '23 at 16:47
  • 1
    *"the script works but does not produce print any certificate (it's empty)"* - this is expected as you disabled certificate validation. See https://stackoverflow.com/questions/45478536/python-getting-common-name-from-url-using-ssl-getpeercert on how to deal with this – Steffen Ullrich Jan 13 '23 at 16:50
  • 1
    *"Moving the Environment from WSL to Windows,"* - interesting detail. Do things like curl work in WSL for this specific sites? If they do, could you provide the output for `curl -v https://example.com` ? – Steffen Ullrich Jan 13 '23 at 16:51
  • @SteffenUllrich .Curl is working as intended but it is very long, I can't put it here: https://pastebin.com/v1XFLsN7 – Xavi Jan 13 '23 at 17:07
  • 1
    So this does not look like some SSL interception done from some antivirus then. Strange then that curl works in WSL, Python does not but Python works in the underlying plain Windows. Unfortunately I have no access to WSL for testing myself. – Steffen Ullrich Jan 13 '23 at 17:57
  • Sorry for late responses. Since it doesn't work on WSL, I'm thinking to experimenting with TLS. Is there any reference to do TLS Connection without involving local server? I wanted to purely use TLS Connection against google @SteffenUllrich – Xavi Jan 14 '23 at 05:23
  • 1
    *" Is there any reference to do TLS Connection without involving local server?"* - I'm not sure what you are asking. Isn't that what you are doing already? What kind of reference you expect apart from the ssl documentation in Python? – Steffen Ullrich Jan 14 '23 at 06:17
  • I wanted to inititate connection only on TLS Level without involving proxy. For example, I can explicitly add `server_hostname = domain` on `wrap_socket` and use only that without `socket.connect((domain, 443))` which falls into a proxy level. @SteffenUllrich – Xavi Jan 14 '23 at 06:21
  • Finding a similar approach in Python to `go`-lang `tls.Client()`, where you can just initiate handshake without the need of `tls.Server()`: https://github.com/golang/go/blob/master/src/crypto/tls/tls.go @SteffenUllrich – Xavi Jan 14 '23 at 06:23
  • 1
    Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/251134/discussion-between-steffen-ullrich-and-xavi). – Steffen Ullrich Jan 14 '23 at 06:38

0 Answers0