I am a Windows user. I use Python 3.6.5
and I import this version of OpenSSL OpenSSL 1.0.2k
.
I need to write a script for a python TLS client that I can customize in terms of the supported TLS versions and ciphersuites and other configurations. The client should be able to make connections with self-signed certificates. Therefore, I believe I should use: ssl.SSLContext()
to create my context and not ssl.create_default_context()
.
However, with the following script, I can never get the peer's certificate. Please, provide clear answers with code as otherwise I tried many solutions and looked at previous posts with no hope.
context = ssl.SSLContext() # ssl.create_default_context()
#context.verify_mode = ssl.CERT_NONE
#context.check_hostname = True
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
domain="google.com"
ssl_sock = context.wrap_socket(s, server_hostname=domain)
ssl_sock.connect((domain, 443))
print("====== peer's certificate ======")
try:
cert = ssl_sock.getpeercert()
print ("issued to:", dict(itertools.chain(*cert["subject"]))["commonName"])
print ("issued by:", dict(itertools.chain(*cert["issuer"]))["commonName"])
print("issuance date:", cert["notBefore"])
print("expairy date: ", cert["notAfter"])
if (cert == None):
print("no certificate")
except Exception as e:
print("Error:",e)
ssl_sock.close()
The problem is that I do not receive the peer's certificate when I use ssl.SSLContext()
but when I use ssl.create_default_context()
it is received correctly. However, I need to be able to receive self-signed certificates (i.e. unverified certificates) that's why I have to use ssl.SSLContext()
.
Thanks for the solution posted. But I need to parse the certificate even if it is not verified (self-signed). I trust this certificate and I need its info. I looked at several posts including this one. I did these steps:
.pem
content of my server's certificate.C:\Python36\Lib\site-packages\certifi
cacert.pem
which is placed in the directory (step 2)-----BEGIN CERTIFICATE-----
and ends with -----END CERTIFICATE-----
I get this error:
ssl.SSLError: [SSL: CERTIFICATE_VERIFY_FAILED] certificate verify failed (_ssl.c:833)
Here is a 9 line snippet that grabs cert data from any url.
import ssl
import socket
def getcertmeta(url="",port=443):
hostname = socket.gethostbyaddr(url)[0]
context = ssl.create_default_context()
with socket.create_connection((hostname, port)) as sock:
with context.wrap_socket(sock, server_hostname=hostname) as ssock:
return ssock.context.get_ca_certs()
Tin Foil Note: Something fishy is going with this cert stuff. They are the source of all kinds of problems but tech companies are obsessed with them. They provide no security benefit, every single cert authority has been hacked(except LetsEncrypt iirc) this is irrefutable and can be looked up and found online in idk 5mins, there's something else going on but they are so damn complicated and needlessly complex that its very difficult to figure out what. Imo they are being used along with intel ME to backdoor server data to central locations(like the hack revealed by wileaks v7), the certs on my phone included like 3-4 governments, just straight up says Japanese Government or Chinese Government and it has a bunch of intel agency companies like 'starlight technologies' its all very shady imo.
EDIT2: The above snippet is wrong, it only gets the certificate authority certs not the actual url, here is a 13 line snippet to get the cert for the actual url.
import socket,ssl
from contextlib import contextmanager
@contextmanager
def fetch_certificate(url="", port=443, timeout=0.5):
cxt = ssl.create_default_context()
sslctxsock = cxt.wrap_socket(socket.socket(), server_hostname=hostname)
sslctxsock.settimeout(timeout)
sslctxsock.connect((url,port))
cert = sslctxsock.getpeercert()
try:
yield cert
finally:
sslctxsock.close()
Use it like this:
with fetch_certificate(url=url) as cert:
print(cert)