I want to get the informations of a ssl certificate from a domain name. By using the following code I get wired responses. The code :
import ssl
import socket
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(1)
wrappedSocket = ssl.wrap_socket(sock)
try:
wrappedSocket.connect(('www.google.com', 443))
except:
response = False
else:
der_cert = wrappedSocket.getpeercert(False)
der_cert_bin = wrappedSocket.getpeercert(True)
print(der_cert)
print(der_cert_bin)
pem_cert = ssl.DER_cert_to_PEM_cert(wrappedSocket.getpeercert(True))
print(pem_cert)
wrappedSocket.close()
This code display :
{}
b'0\x82\x04v0\x82\x03^\xa0\x03\x02\x01\x02\x02\x08\x19\xab\x97n|\x13q\xc20\r\x06\t*\x86H\x86\xf7\r\x01\x01\x05\x05\x000I1\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x130\x11\x06\x03U\x04\n\x13\nGoogle Inc1%0#\x06\x03U\x04\x03\x13\x1cGoogle Internet Authority G20\x1e\x17\r150618085256Z\x17\r150916000000Z0h1\x0b0\t\x06\x03U\x04\x06\x13\x02US1\x130\x11\x06\x03U\x04\x08\x0c\nCalifornia1\x160\x14\x06\x03U\x04\x07\x0c\rMountain View1\x130\x11\x06\x03U\x04\n\x0c\nGoogle Inc1\x170\x15\x06\x03U\x04\x03\x0c\x0ewww.google.com0\x82\x01"0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x01\x05\x00\x03\x82\x01\x0f\x000\x82\x01\n\x02\x82\x01\x01\x00\xca\xa9\\\x03\xb4\x07g\xb4\x87b\xeb\xf6\xd3\xc7,\xeb\ta\x07j\xaa\xab\xf80,\xd3\xbc9:p%-D\xe9\x94\xb4\xac\x12\x84P$\nUV\x15\xe3\r\xb8,\xb1[<\xc6\xf6\x8c\xf1\x8f\xbb\xfc\xc3\xec\x9f!\xee\xc4\xc9\xa4\xfc/\x8b\x02\xeb\xce\xa5\xc5\xb8\xc9[N3\xeet\x91\\\xf7\x1e\xd6\xf7|\xde\xd0\xd1\x11\xeal\xc5\r\x8c\x0b\x8c\xb4/\x8a\xc1\xbb>\x1e\xa1,\x1d01\xc1k\xdc\xca\x9b\xebH-\xa9\x19\xfc\xff\x81<\xb8\xefm\xf0\x8b\x91\x02\xf9\xe9\x07(\'\xed\xe6\x98|4\xe7\xef\x9c\xea;\x13\xcf1\xaa\xe3}\x96\x95?\xef]\x1f\x86\xc5,\xed\xbf K9j \xaad6\xf2\x10G\xcdY\x9c\xd0\x89\xeb\xc1\x11\xc3\xa5\xd5\xac\x17)\xf7\xff\x01\x9d\xa5\xd1\x1aN\xc1[\xa8\xd3L\xb1\x8b\xa7`\xac\x12\xc2\xcf\xc6RF\x88\x02\x8f4\x1ak1\xad\xeeom}\x1d"\xdc\x84~\xe2\x9d\xfe\xf2\xd9\r\xa0JH\xd6>3.\xb6J\xd4\xde\xa1X\xd5\x9c\x9b\xc3\xb8\xab\x02\x03\x01\x00\x01\xa3\x82\x01A0\x82\x01=0\x1d\x06\x03U\x1d%\x04\x160\x14\x06\x08+\x06\x01\x05\x05\x07\x03\x01\x06\x08+\x06\x01\x05\x05\x07\x03\x020\x19\x06\x03U\x1d\x11\x04\x120\x10\x82\x0ewww.google.com0h\x06\x08+\x06\x01\x05\x05\x07\x01\x01\x04\\0Z0+\x06\x08+\x06\x01\x05\x05\x070\x02\x86\x1fhttp://pki.google.com/GIAG2.crt0+\x06\x08+\x06\x01\x05\x05\x070\x01\x86\x1fhttp://clients1.google.com/ocsp0\x1d\x06\x03U\x1d\x0e\x04\x16\x04\x14\x14\xd9\xa1\xe1\x91@$\xf3\x03\xf1\xd0\xfaIg\x11R\xe4 hT0\x0c\x06\x03U\x1d\x13\x01\x01\xff\x04\x020\x000\x1f\x06\x03U\x1d#\x04\x180\x16\x80\x14J\xdd\x06\x16\x1b\xbc\xf6h\xb5v\xf5\x81\xb6\xbbb\x1a\xbaZ\x81/0\x17\x06\x03U\x1d \x04\x100\x0e0\x0c\x06\n+\x06\x01\x04\x01\xd6y\x02\x05\x0100\x06\x03U\x1d\x1f\x04)0\'0%\xa0#\xa0!\x86\x1fhttp://pki.google.com/GIAG2.crl0\r\x06\t*\x86H\x86\xf7\r\x01\x01\x05\x05\x00\x03\x82\x01\x01\x00q]\x07r\x9e\x9b\xc1\xb0\xe7\xb7aV\xd9M%\xdf\xa4\x9c\xfd\xbc\x10\xc1,!8\xc2\xe2\x81f\x87\xf6\xc9\x95\x14\xe8\x99@\xb8\x97Xh\x9d\\\xd6\xe9ZVDQ\\o\x9aXD\xfd\x15\xead<@U!\xc2\x84\x14&\x91\xdb\x85/Ek\xdc\x80\xc4\xf4\xd9\xe0\x00\xca\xbb=\x0f\xcd5\xd0.\xbb\xd3 4\xab\xfa\xec\xe9]\x040\xfc\xe8\xea\xee\xe6*\xe8\xf5\x8e\xf8\x91\x0b\xba\xf92\x02\xe6\x04<V\xac^\x9a\x95\xa3;\t\xd8\x8b\n\x8ab\xf3\x8b\x91\xe3\x87,\x85\xf3\xad3?x\x8d\xc6N\xdcR\xcd\xb9\x16f\xab\xc6\xa5V\xe5\xb2Kqv\xba\xd8\xb2\xf8g\xb7\x1a\xd7+m\xe1s\x0f\xdb\x8f/\x08\x07\xd1Y*[\x8aP\x8c\x01p\xa8\xb9/\x98\x1f\xd2y\xef\xf9\x8fX\x19<jY\xa5\x85\xb5(\xcd1\x9c\xff\x1b\xe2j62+*\xc3\x9b\x81\xe5:\xa2\x82*m\xb53\x00\x88\x0e\x08t\x99\xce\x91]DRg\xf3\xacH\xd1\x92D\x95oG;9\x95\x11\x1d\xde9'
-----BEGIN CERTIFICATE-----
MIIEdjCCA16gAwIBAgIIGauXbnwTccIwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
cm5ldCBBdXRob3JpdHkgRzIwHhcNMTUwNjE4MDg1MjU2WhcNMTUwOTE2MDAwMDAw
WjBoMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEXMBUGA1UEAwwOd3d3
Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDKqVwD
tAdntIdi6/bTxyzrCWEHaqqr+DAs07w5OnAlLUTplLSsEoRQJApVVhXjDbgssVs8
xvaM8Y+7/MPsnyHuxMmk/C+LAuvOpcW4yVtOM+50kVz3Htb3fN7Q0RHqbMUNjAuM
tC+Kwbs+HqEsHTAxwWvcypvrSC2pGfz/gTy4723wi5EC+ekHKCft5ph8NOfvnOo7
E88xquN9lpU/710fhsUs7b8gSzlqIKpkNvIQR81ZnNCJ68ERw6XVrBcp9/8BnaXR
Gk7BW6jTTLGLp2CsEsLPxlJGiAKPNBprMa3ub219HSLchH7inf7y2Q2gSkjWPjMu
tkrU3qFY1Zybw7irAgMBAAGjggFBMIIBPTAdBgNVHSUEFjAUBggrBgEFBQcDAQYI
KwYBBQUHAwIwGQYDVR0RBBIwEIIOd3d3Lmdvb2dsZS5jb20waAYIKwYBBQUHAQEE
XDBaMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lBRzIuY3J0
MCsGCCsGAQUFBzABhh9odHRwOi8vY2xpZW50czEuZ29vZ2xlLmNvbS9vY3NwMB0G
A1UdDgQWBBQU2aHhkUAk8wPx0PpJZxFS5CBoVDAMBgNVHRMBAf8EAjAAMB8GA1Ud
IwQYMBaAFErdBhYbvPZotXb1gba7Yhq6WoEvMBcGA1UdIAQQMA4wDAYKKwYBBAHW
eQIFATAwBgNVHR8EKTAnMCWgI6Ahhh9odHRwOi8vcGtpLmdvb2dsZS5jb20vR0lB
RzIuY3JsMA0GCSqGSIb3DQEBBQUAA4IBAQBxXQdynpvBsOe3YVbZTSXfpJz9vBDB
LCE4wuKBZof2yZUU6JlAuJdYaJ1c1ulaVkRRXG+aWET9FepkPEBVIcKEFCaR24Uv
RWvcgMT02eAAyrs9D8010C670yA0q/rs6V0EMPzo6u7mKuj1jviRC7r5MgLmBDxW
rF6alaM7CdiLCopi84uR44cshfOtMz94jcZO3FLNuRZmq8alVuWyS3F2utiy+Ge3
GtcrbeFzD9uPLwgH0VkqW4pQjAFwqLkvmB/See/5j1gZPGpZpYW1KM0xnP8b4mo2
Misqw5uB5TqigipttTMAiA4IdJnOkV1EUmfzrEjRkkSVb0c7OZURHd45
-----END CERTIFICATE-----
Do you know why the first print display only {} ?
The documentation (https://docs.python.org/3.2/library/ssl.html#ssl.SSLSocket.getpeercert) indicate it's empty because certificate is not valid. In this case, why the two following print display an non-empty certificate ?
According to [Python.Docs]: SSLSocket.getpeercert(binary_form=False) (emphasis is mine):
If the
binary_form
parameter is False, and a certificate was received from the peer, this method returns a dict instance. If the certificate was not validated, the dict is empty. If the certificate was validated, it returns a dict with several keys, amongst themsubject
(the principal for which the certificate was issued) andissuer
(the principal issuing the certificate). If a certificate contains an instance of the Subject Alternative Name extension (see RFC 3280), there will also be asubjectAltName
key in the dictionary.
If you want to validate the certificate you must pass cert_reqs=ssl.CERT_REQUIRED
to [Python 3.11.Docs]: ssl.wrap_socket(sock, keyfile=None, certfile=None, server_side=False, cert_reqs=CERT_NONE, ssl_version=PROTOCOL_TLS, ca_certs=None, do_handshake_on_connect=True, suppress_ragged_eofs=True, ciphers=None):
As you see, by default it passes CERT_NONE, which doesn't validate the peer certificate, therefore you get an empty dict.
The above URL also states that the function is deprecated (v3.11 is the last one having it), so for newer Python versions you should do something like:
import socket
import ssl
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.settimeout(1)
ctx = ssl.SSLContext(ssl.PROTOCOL_TLS)
ctx.verify_mode = ssl.CERT_REQUIRED
addr = "www.google.com"
ctx.load_default_certs()
sslsock = ctx.wrap_socket(sock, server_hostname=addr)
sslsock.connect((addr, 443))
peer_cert = sslsock.getpeercert(False)
# ...