How can i get Certificate issuer information in python?
Asked Answered
J

5

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

Jesuitism answered 16/6, 2015 at 8:11 Comment(0)
P
43

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.

Pierro answered 16/6, 2015 at 9:6 Comment(6)
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. @PierroJesuitism
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.Pierro
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.Pierro
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 !!! @PierroJesuitism
Hey! in most cases this works, although I get Timeouts on some sites, for example alipay.com:443, any ideas?Merc
@MatanDobrushin: the site is not responsive. Try it from your browser: allpay.com. If you try http://allpay.com you'll see that the site is not operational. I doubt that they have any certificate installed there.Pierro
I
4

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.

Integrant answered 3/11, 2021 at 0:55 Comment(2)
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.Lem
@Lem fair point, will update the answerIntegrant
L
3

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.

Lem answered 7/11, 2022 at 15:29 Comment(0)
O
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')]
Ocker answered 26/10, 2017 at 1:22 Comment(0)
H
-4

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
Hooch answered 16/6, 2015 at 9:31 Comment(3)
thanks for reply.. could you please tell me, What is keytool? @pyAnnaJesuitism
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.Hooch
Thanks @pyAnna after installing JDK the code has worked :)Jesuitism

© 2022 - 2024 — McMap. All rights reserved.