unable python ssl m2crypto

unable - ¿Cómo puedo recuperar el certificado de par TLS/SSL de un host remoto utilizando Python?



no module named m2crypto (3)

Necesito escanear a través de una lista de IP y recuperar el nombre común del certificado en esa IP (para cada IP que permita las conexiones del puerto 443). He podido hacer esto con éxito utilizando los sockets y los módulos ssl. Funciona para todas las direcciones IP con certificados válidos y firmados, pero no funciona para los certificados autofirmados.

Si utilizo este método, se requiere un certificado válido que mi paquete de CA verifique:

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 cert_reqs=ssl.CERT_REQUIRED , se conecta pero no obtiene el certificado.

¿Cómo puedo recuperar el nombre común para un certificado en un IP si valida contra el paquete ca o no?


En Mac necesitas instalar Swig y M2Crypto

En la ejecución de la terminal:

brew install swig

Y entonces:

sudo pip install m2crypto

Entonces puedes ejecutar el código de arriba:

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'')]


La biblioteca python ssl parece que solo analiza el certificado por ti si tiene una firma válida.

"""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."""

Aún puede obtener el certificado del servidor con la función ssl.get_server_certificate() , pero lo devuelve en formato PEM. (Alternativamente, puede llamar a c.getpeercert(True) , que devuelve el certificado en formato binario DER, independientemente de si está validado o no).

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

Desde aquí, usaría M2Crypto o OpenSSL para leer el certificado y obtener valores:

# 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'')]


Si alguien está luchando con SNI (Server Name Indication) (mencionado por @mootmoot), consulte mi respuesta aquí https://.com/a/49132495/8370670 .