20

I want the 'issued to' information from certificate in python. I try to use the SSL and SSLSocket library but did not happen.

enter image description here

Sid
  • 5,662
  • 2
  • 15
  • 18
Raj
  • 419
  • 1
  • 4
  • 10

5 Answers5

42

Updated answer

If you can establish a connection to the remote server you can use the ssl standard library module:

import ssl, socket

hostname = 'google.com'
ctx = ssl.create_default_context()
with ctx.wrap_socket(socket.socket(), server_hostname=hostname) as s:
    s.connect((hostname, 443))
    cert = s.getpeercert()

subject = dict(x[0] for x in cert['subject'])
issued_to = subject['commonName']
issuer = dict(x[0] for x in cert['issuer'])
issued_by = issuer['commonName']

>>> issued_to
u'*.google.com'
>>> issued_by
u'Google Internet Authority G2'

Original answer

Use pyOpenSSL.

from OpenSSL import crypto

cert_file = '/path/to/your/certificate'
cert = crypto.load_certificate(crypto.FILETYPE_PEM, open(cert_file).read())
subject = cert.get_subject()
issued_to = subject.CN    # the Common Name field
issuer = cert.get_issuer()
issued_by = issuer.CN

You can also access additional components, e.g. organisation (subject.O/issuer.O), organisational unit (subject.OU/issuer.OU).

Your certificate file might be in another format, so you could try crypto.FILETYPE_ASN1 instead of crypto.FILETYPE_PEM.

phoenix
  • 7,988
  • 6
  • 39
  • 45
mhawke
  • 84,695
  • 9
  • 117
  • 138
  • Thanks for reply.. I have tried this before but got ImportError: No module named cryptography.hazmat.bindings.openssl.binding and but tried to import it but looks very complex.. do you have any simpler method than this. @mhawke – Raj Jun 16 '15 at 10:08
  • It looks like you haven't properly installed pyOpenSSL. There are a number of dependencies which are missing. One of them is the `cryptography` package which is the one causing your error. You can install with `pip install pyopenssl` which should install the dependencies too, however, you might need a build environment. Your screenshot suggests a Windows environment - that might be more difficult to get going. – mhawke Jun 16 '15 at 12:33
  • 1
    I have updated my original answer with an alternative that relies only on the standard library `ssl` and `socket` modules. This method requires connecting to the remote server, which your acceptance of the `keytool` answer indicates is possible. I think this a better solution because it does not rely on an external tool (which you have to obtain/install/maintain), and it is based entirely on the standard library so it will be portable between OSes without worrying about dependencies. – mhawke Jun 16 '15 at 12:46
  • Thanks for the answer.. There were no method create_default_context() in python 2.7.6 , then i upgrade it to 2.7.9. and this code works. and yes for this i dont need to install any external tool .. thanks again !!! @mhawke – Raj Jun 17 '15 at 11:14
  • Hey! in most cases this works, although I get Timeouts on some sites, for example alipay.com:443, any ideas? – Matan Dobrushin Jan 04 '20 at 10:12
  • @MatanDobrushin: the site is not responsive. Try it from your browser: https://allpay.com. If you try [http://allpay.com](http://allpay.com) you'll see that the site is not operational. I doubt that they have any certificate installed there. – mhawke Jan 26 '21 at 11:54
3

The pyOpenSSL library does not seem to be well suited for this task. Here is what they say in official docs

Note: The Python Cryptographic Authority strongly suggests the use of pyca/cryptography where possible.

There are some workarounds using Python's standard library, but most of those seem to be messy.

Here is the way to do it through pyca/cryptography. It looks pretty straightforward and clean

from cryptography.x509 import load_pem_x509_certificate

cert = load_pem_x509_certificate(certificate_content)
certificate_serial_number = cert.serial_number
certificate_issuer_info = cert.issuer.rfc4514_string()
certificate_subject_info = cert.subject.rfc4514_string()

the result will print the whole line with issuer details

CN=name,O=Org\, Inc.,L=Tucson,ST=Arizona,C=US
CN=Sectigo RSA Organization Validation Secure Server CA,O=Sectigo Limited,L=Salford,ST=Greater Manchester,C=GB

To access particular details about the certificate, you can use the cert.issuer object.

Henry Harutyunyan
  • 2,355
  • 1
  • 16
  • 22
  • The `pyOpenSSL` module is NOT outdated and is being actively maintained by the same team responsible for the `cryptography` module. In fact `pyOpenSSL` uses `cryptography` under the hood. What the note in the docs means is that the module should be used for the tasks it was made for, otherwise you risk shooting yourself in the foot. – wombatonfire Nov 07 '22 at 15:35
  • @wombatonfire fair point, will update the answer – Henry Harutyunyan Nov 29 '22 at 11:35
2

If you use requests, a simple code is here:

#!/usr/bin/python
# -*- coding: utf-8 -*-


from requests.packages.urllib3.contrib import pyopenssl as reqs


def https_cert_subject_alt_names(host, port):
    """Read subject domains in https cert from remote server"""

    x509 = reqs.OpenSSL.crypto.load_certificate(
        reqs.OpenSSL.crypto.FILETYPE_PEM,
        reqs.ssl.get_server_certificate((host, port))
    )
    return reqs.get_subj_alt_name(x509)

if __name__ == '__main__':
    domains = https_cert_subject_alt_names("www.yahoo.com", 443)
    print(domains)

The result is as follow:

[('DNS', '*.www.yahoo.com'), 
 ('DNS', 'www.yahoo.com'), 
 ('DNS', 'add.my.yahoo.com'), 
 ('DNS', 'au.yahoo.com'), 
 ('DNS', 'be.yahoo.com'), 
 ('DNS', 'br.yahoo.com'), 
 ('DNS', 'ca.my.yahoo.com'), 
 ('DNS', 'ca.rogers.yahoo.com'), 
 ('DNS', 'ca.yahoo.com'), 
 ('DNS', 'ddl.fp.yahoo.com'), 
 ('DNS', 'de.yahoo.com'), 
 ...
 ('DNS', 'mbp.yimg.com')]
debug
  • 991
  • 10
  • 14
2

The problem with the currently accepted answer, recommending the use of the ssl module, is that it'll work only if the certificate of interest can be successfully verified. If, for any reason, verification fails, like, for example, with expired or a self-signed certificate, we'll get ssl.SSLCertVerificationError instead of the requested info. This is because the SSLContext's default verify_mode is CERT_REQUIRED.

We can change it:

context = ssl.create_default_context()
    
context.check_hostname = False
    
context.verify_mode = ssl.CERT_NONE

But then we'll find out that secure socket's getpeercert() method returns an empty dictionary. That's a bummer!

We can workaround this by asking for the certificate in the binary form:

getpeercert(binary_form=True)

But now we have to convert it, and thus we need a third party cryptography module:

from cryptography.x509 import load_der_x509_certificate

# create SSLContext and wrap the socket as ssock here

certificate_content = ssock.getpeercert(binary_form=True)

cert = load_der_x509_certificate(certificate_content) 
certificate_subject_info = cert.subject.rfc4514_string()


This example is adapted from Henry's answer with the DER loader being used instead of the PEM loader.

Now, I do understand why anyone would prefer built-in modules instead of additional dependencies, but, since a third party module is needed anyway (by "anyway" I mean if we want to handle corner cases), I believe an easier choice for this task would be to use pyOpenSSL:

import socket
from OpenSSL import SSL

context = SSL.Context(SSL.TLS_CLIENT_METHOD)
    
conn = SSL.Connection(context, socket.socket())
 
conn.connect(address)
print(conn.get_peer_certificate().get_subject())
    
# or: print(conn.get_peer_certificate().get_subject().get_components())
# or: print(conn.get_peer_certificate().to_cryptography().subject.rfc4514_string())

pyOpenSSL uses cryptography module under the hood and provides convenient methods to access certificate's properties.

wombatonfire
  • 4,585
  • 28
  • 36
-3

import os
import re
os.system('keytool -printcert -sslserver google.com:443 >cert.txt')
fh = open("cert.txt", "r")
content = fh.readlines()
fh.close()
content = content[2]
m = re.search('CN=(.+?),', content)
if m:
    found = m.group(1)
print found
  • thanks for reply.. could you please tell me, What is keytool? @pyAnna – Raj Jun 16 '15 at 10:09
  • keytool is a key and certificate management utility. It allows users to administer their own public/private key pairs and associated certificates for use in self-authentication (where the user authenticates himself/herself to other users/services) or data integrity and authentication services, using digital signatures. It also allows users to cache the public keys (in the form of certificates) of their communicating peers. – Tarun Venugopal Nair Jun 16 '15 at 10:17
  • Thanks @pyAnna after installing JDK the code has worked :) – Raj Jun 16 '15 at 10:57