2

I am trying to capture the subject field as a string using the hostname. Like this:

/C=US/ST=California/L=Mountain View/O=Google LLC/CN=*.google.com

The same output can be obtained using

echo -n | openssl s_client -connect google.com:443 2>/dev/null | grep subject
subject=/C=US/ST=California/L=Mountain View/O=Google LLC/CN=*.google.com

Tried some subprocess module to get the above output but ended up falling on OpenSSL module to help me out because I am not well versed in Subprocess module. Using OpenSSL, I was able to get the desired output but it is returning it as an X509Name Object:

import socket, ssl
import OpenSSL

hostname = "google.com"

cert = ssl.get_server_certificate((hostname, 443))
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
print(x509.get_subject())

<X509Name object '/C=US/ST=California/L=Mountain View/O=Google LLC/CN=*.google.com'>

I want it to return this as a string. Can this be achievable?

jww
  • 97,681
  • 90
  • 411
  • 885
Moh
  • 91
  • 2
  • 7

1 Answers1

6

Check [pyOpenSSL]: crypto - X509Name objects (get_components) for more details.

It is possible, with a bit of processing. The distinguished name string is the concatenation of the individual component strings, where each component string is in the form of /name=value.

Example:

>>> import ssl
>>> import OpenSSL
>>>
>>> pem = ssl.get_server_certificate(("google.com", 443))
>>> cert_x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
>>>
>>> subject = cert_x509.get_subject()
>>> subject
<X509Name object '/C=US/ST=California/L=Mountain View/O=Google LLC/CN=*.google.com'>
>>>
>>> subject_str = "".join("/{:s}={:s}".format(name.decode(), value.decode()) for name, value in subject.get_components())
>>> subject_str
'/C=US/ST=California/L=Mountain View/O=Google LLC/CN=*.google.com'

There are multiple ways of getting certificate data, here's another one: [SO]: How can I decode a SSL certificate using python? (@CristiFati's answer).

CristiFati
  • 38,250
  • 9
  • 50
  • 87
  • 1
    Yours is the better solution as you use the module. I'm replacing my own `re.sub` with your solution. For reference `re.sub(r'^.+)\'>$', '\g', x509.get_subject().__str__())` – sastorsl Jun 30 '22 at 13:10