Comment puis-je récupérer le certificat homologue TLS/SSL d'un hôte distant en utilisant python?

J'ai besoin de parcourir une liste D'adresses IP et de récupérer le nom commun du certificat sur cette adresse IP (pour chaque adresse IP qui autorise les connexions au port 443). J'ai pu le faire avec succès en utilisant les sockets et les modules ssl. Cela fonctionne pour toutes les adresses IP avec des certificats valides et signés, mais cela ne fonctionne pas pour les certificats auto-signés.

Si j'utilise cette méthode, elle nécessite un certificat valide qui est vérifié par mon CA-bundle:

from socket import socket
import ssl

s = socket()
c = ssl.wrap_socket(s,cert_reqs=ssl.CERT_REQUIRED, ca_certs='ca-bundle.crt')
c.connect(('127.0.0.1', 443))

print c.getpeercert()

Si je supprime le cert_reqs=ssl.CERT_REQUIRED alors il se connecte mais ne le fait pas obtenez le certificat du tout.

Comment puis-je récupérer le nom commun d'un certificat sur une adresse IP, qu'il soit valide ou non par rapport au CA-bundle?

27
demandé sur Flow 2011-10-07 20:07:13

3 réponses

La bibliothèque ssl Python semble n'analyser le certificat que si elle a une signature valide.

    """Returns a formatted version of the data in the
    certificate provided by the other end of the SSL channel.
    Return None if no certificate was provided, {} if a
    certificate was provided, but not validated."""

Vous pouvez toujours obtenir le certificat de serveur avec la fonction ssl.get_server_certificate(), mais il le renvoie au format PEM. (Alternativement, vous pouvez appeler c.getpeercert(True), qui renvoie le certificat au format DER binaire, qu'il soit validé ou non.)

>>> print ssl.get_server_certificate(('server.test.com', 443))
-----BEGIN CERTIFICATE-----
MIID4zCCAsugAwIBA.....

À partir d'ici, j'utiliserais m2crypto ou OpenSSL pour lire le cert et obtenir des valeurs:

# M2Crypto
cert = ssl.get_server_certificate(('www.google.com', 443))
x509 = M2Crypto.X509.load_cert_string(cert)
x509.get_subject().as_text()
# 'C=US, ST=California, L=Mountain View, O=Google Inc, CN=www.google.com'

# OpenSSL
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
x509.get_subject().get_components()
#[('C', 'US'),
# ('ST', 'California'),
# ('L', 'Mountain View'),
# ('O', 'Google Inc'),
# ('CN', 'www.google.com')]
38
répondu JimB 2011-10-07 18:50:04

Sur Mac, vous devez installer swig et M2Crypto

Lors de l'exécution du terminal:

brew install swig

Puis:

sudo pip install m2crypto

Ensuite, vous pouvez exécuter le code ci-dessus:

from socket import socket
import ssl
import M2Crypto
import OpenSSL

# M2Crypto
cert = ssl.get_server_certificate(('www.google.com', 443))
x509 = M2Crypto.X509.load_cert_string(cert)
print x509.get_subject().as_text()
# 'C=US, ST=California, L=Mountain View, O=Google Inc, CN=www.google.com'

# OpenSSL
x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, cert)
print x509.get_subject().get_components()
#[('C', 'US'),
# ('ST', 'California'),
# ('L', 'Mountain View'),
# ('O', 'Google Inc'),
# ('CN', 'www.google.com')]
4
répondu Gil Allen 2015-06-21 12:46:02

Si quelqu'un est aux prises avec SNI (Indication du nom du serveur) (mentionné par @mootmoot) reportez-vous à ma réponse ici https://stackoverflow.com/a/49132495/8370670 .

0
répondu serbia99 2018-03-07 06:01:38