Как я могу декодировать SSL-сертификат с помощью python?
Как я могу декодировать закодированный в pem (base64) сертификат с помощью Python? Например это здесь от github.com:
-----BEGIN CERTIFICATE-----
MIIHKjCCBhKgAwIBAgIQDnd2il0H8OV5WcoqnVCCtTANBgkqhkiG9w0BAQUFADBp
MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
d3cuZGlnaWNlcnQuY29tMSgwJgYDVQQDEx9EaWdpQ2VydCBIaWdoIEFzc3VyYW5j
ZSBFViBDQS0xMB4XDTExMDUyNzAwMDAwMFoXDTEzMDcyOTEyMDAwMFowgcoxHTAb
BgNVBA8MFFByaXZhdGUgT3JnYW5pemF0aW9uMRMwEQYLKwYBBAGCNzwCAQMTAlVT
MRswGQYLKwYBBAGCNzwCAQITCkNhbGlmb3JuaWExETAPBgNVBAUTCEMzMjY4MTAy
MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTEWMBQGA1UEBxMNU2Fu
IEZyYW5jaXNjbzEVMBMGA1UEChMMR2l0SHViLCBJbmMuMRMwEQYDVQQDEwpnaXRo
dWIuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7dOJw11wcgnz
M08acnTZtlqVULtoYZ/3+x8Z4doEMa8VfBp/+XOvHeVDK1YJAEVpSujEW9/Cd1JR
GVvRK9k5ZTagMhkcQXP7MrI9n5jsglsLN2Q5LLcQg3LN8OokS/rZlC7DhRU5qTr2
iNr0J4mmlU+EojdOfCV4OsmDbQIXlXh9R6hVg+4TyBkaszzxX/47AuGF+xFmqwld
n0xD8MckXilyKM7UdWhPJHIprjko/N+NT02Dc3QMbxGbp91i3v/i6xfm/wy/wC0x
O9ZZovLdh0pIe20zERRNNJ8yOPbIGZ3xtj3FRu9RC4rGM+1IYcQdFxu9fLZn6TnP
pVKACvTqzQIDAQABo4IDajCCA2YwHwYDVR0jBBgwFoAUTFjLJfBBT1L0KMiBQ5um
qKDmkuUwHQYDVR0OBBYEFIfRjxlu5IdvU4x3kQdQ36O/VUcgMCUGA1UdEQQeMByC
CmdpdGh1Yi5jb22CDnd3dy5naXRodWIuY29tMIGBBggrBgEFBQcBAQR1MHMwJAYI
KwYBBQUHMAGGGGh0dHA6Ly9vY3NwLmRpZ2ljZXJ0LmNvbTBLBggrBgEFBQcwAoY/
aHR0cDovL3d3dy5kaWdpY2VydC5jb20vQ0FDZXJ0cy9EaWdpQ2VydEhpZ2hBc3N1
cmFuY2VFVkNBLTEuY3J0MAwGA1UdEwEB/wQCMAAwYQYDVR0fBFowWDAqoCigJoYk
aHR0cDovL2NybDMuZGlnaWNlcnQuY29tL2V2MjAwOWEuY3JsMCqgKKAmhiRodHRw
Oi8vY3JsNC5kaWdpY2VydC5jb20vZXYyMDA5YS5jcmwwggHEBgNVHSAEggG7MIIB
tzCCAbMGCWCGSAGG/WwCATCCAaQwOgYIKwYBBQUHAgEWLmh0dHA6Ly93d3cuZGln
aWNlcnQuY29tL3NzbC1jcHMtcmVwb3NpdG9yeS5odG0wggFkBggrBgEFBQcCAjCC
AVYeggFSAEEAbgB5ACAAdQBzAGUAIABvAGYAIAB0AGgAaQBzACAAQwBlAHIAdABp
AGYAaQBjAGEAdABlACAAYwBvAG4AcwB0AGkAdAB1AHQAZQBzACAAYQBjAGMAZQBw
AHQAYQBuAGMAZQAgAG8AZgAgAHQAaABlACAARABpAGcAaQBDAGUAcgB0ACAAQwBQ
AC8AQwBQAFMAIABhAG4AZAAgAHQAaABlACAAUgBlAGwAeQBpAG4AZwAgAFAAYQBy
AHQAeQAgAEEAZwByAGUAZQBtAGUAbgB0ACAAdwBoAGkAYwBoACAAbABpAG0AaQB0
ACAAbABpAGEAYgBpAGwAaQB0AHkAIABhAG4AZAAgAGEAcgBlACAAaQBuAGMAbwBy
AHAAbwByAGEAdABlAGQAIABoAGUAcgBlAGkAbgAgAGIAeQAgAHIAZQBmAGUAcgBl
AG4AYwBlAC4wHQYDVR0lBBYwFAYIKwYBBQUHAwEGCCsGAQUFBwMCMBEGCWCGSAGG
+EIBAQQEAwIGwDAOBgNVHQ8BAf8EBAMCBaAwDQYJKoZIhvcNAQEFBQADggEBABRS
cR+GnW01Poa7ZhqLhZi5AEzLQrVG/AbnRDnI6FLYERQjs3KW6RSUni8AKPfVBEVA
AMb0V0JC3gmJlxENFFxrvQv3GKNfZwLzCThjv8ESnTC6jqVUdFlTZ6EbUFsm2v0T
flkXv0nvlH5FpP06STLwav+JjalhqaqblkbIHOAYHOb7gvQKq1KmyuhUItnbKj1a
InuA6gcF1PnH8FNZX7t3ft6TcEFOI8t4eXnELurXZioY99HFfOISeIKNHeyCngGi
5QK+eKG5WVjFTG9PpTG0SVtemB4uOPYZxDmiSvt5BbjyWeUmEnCtwOh1Ix8Y0Qvg
n2Xkw9dJh1tybLEvrG8=
-----END CERTIFICATE-----
По словам ssl-shopper это должно быть что-то вроде этого:
Common Name: github.com
Subject Alternative Names: github.com, www.github.com
Organization: GitHub, Inc.
Locality: San Francisco
State: California
Country: US
Valid From: May 26, 2011
Valid To: July 29, 2013
Как я могу получить этот открытый текст с помощью Python?
Ответы
Ответ 1
Стандартная библиотека Python, даже в последней версии, не содержит ничего, что может декодировать сертификаты X.509. Тем не менее, дополнительный пакет cryptography
поддерживает это. Цитирование примера из документации:
>>> from cryptography import x509
>>> from cryptography.hazmat.backends import default_backend
>>> cert = x509.load_pem_x509_certificate(pem_data, default_backend())
>>> cert.serial_number
2
Другим дополнительным пакетом, который может быть вариантом, является pyopenssl
. Это тонкая оболочка вокруг API OpenSSL C, что означает, что можно будет делать то, что вы хотите, но ожидайте провести пару дней, разрывая волосы в документации.
Если вы не можете установить дополнительные пакеты Python, но у вас есть утилита командной строки openssl
,
import subprocess
cert_txt = subprocess.check_output(["openssl", "x509", "-text", "-noout",
"-in", certificate])
должен отображать примерно тот же материал, который вы получили от своей веб-утилиты в cert_txt
.
Кстати, причина, заключающаяся в прямом расширении base64, дает вам двоичный gobbledygook, так как здесь есть два уровня кодирования. сертификаты X.509 ASN.1 структуры данных, сериализованные на X.690 DER, а затем, поскольку DER является двоичным форматом, base64-armored для удобства передачи файлов. (Многие стандарты в этой области были написаны еще в девяностые годы, когда вы не могли надежно отправить что-либо, кроме семибитного ASCII.)
Ответ 2
Вы можете использовать пакеты pyasn1
и pyasn1_modules
для анализа такого рода данных. Например:
from pyasn1_modules import pem, rfc2459
from pyasn1.codec.der import decoder
substrate = pem.readPemFromFile(open('cert.pem'))
cert = decoder.decode(substrate, asn1Spec=rfc2459.Certificate())[0]
print(cert.prettyPrint())
Прочитайте документы для pyasn1 для остальных.
Ответ 3
Примечания:
Относительно сертификата (PEM) от вопроса:
- Сохранено в файле с именем q016899247.crt (в директории скрипта (code00.py))
- В конце тега: ("-----END CERTIFICATE----") отсутствовал дефис (-) в конце; исправлено в вопросе @VERSION # 4.)
code00.py:
#!/usr/bin/env python3
import sys
import os
import ssl
import pprint
def main():
cert_file_base_name = "q016899247.crt"
cert_file_name = os.path.join(os.path.dirname(__file__), cert_file_base_name)
try:
cert_dict = ssl._ssl._test_decode_cert(cert_file_name)
except Exception as e:
print("Error decoding certificate: {0:}".format(e))
else:
print("Certificate ({0:s}) data:\n".format(cert_file_base_name))
pprint.pprint(cert_dict)
if __name__ == "__main__":
print("Python {0:s} {1:d}bit on {2:s}\n".format(" ".join(item.strip() for item in sys.version.split("\n")), 64 if sys.maxsize > 0x100000000 else 32, sys.platform))
main()
print("\nDone.")
Выход:
[[email protected]:e:\Work\Dev\Qaru\q016899247]> "e:\Work\Dev\VEnvs\py_064_03.07.03_test0\Scripts\python.exe" code00.py
Python 3.7.3 (v3.7.3:ef4ec6ed12, Mar 25 2019, 22:22:05) [MSC v.1916 64 bit (AMD64)] 64bit on win32
Certificate (q016899247.crt) data:
{'OCSP': ('http://ocsp.digicert.com',),
'caIssuers': ('http://www.digicert.com/CACerts/DigiCertHighAssuranceEVCA-1.crt',),
'crlDistributionPoints': ('http://crl3.digicert.com/ev2009a.crl',
'http://crl4.digicert.com/ev2009a.crl'),
'issuer': ((('countryName', 'US'),),
(('organizationName', 'DigiCert Inc'),),
(('organizationalUnitName', 'www.digicert.com'),),
(('commonName', 'DigiCert High Assurance EV CA-1'),)),
'notAfter': 'Jul 29 12:00:00 2013 GMT',
'notBefore': 'May 27 00:00:00 2011 GMT',
'serialNumber': '0E77768A5D07F0E57959CA2A9D5082B5',
'subject': ((('businessCategory', 'Private Organization'),),
(('jurisdictionCountryName', 'US'),),
(('jurisdictionStateOrProvinceName', 'California'),),
(('serialNumber', 'C3268102'),),
(('countryName', 'US'),),
(('stateOrProvinceName', 'California'),),
(('localityName', 'San Francisco'),),
(('organizationName', 'GitHub, Inc.'),),
(('commonName', 'github.com'),)),
'subjectAltName': (('DNS', 'github.com'), ('DNS', 'www.github.com')),
'version': 3}
Done.
Ответ 4
Этот код выводит содержимое файла сертификата:
import OpenSSL.crypto
cert = OpenSSL.crypto.load_certificate(
OpenSSL.crypto.FILETYPE_PEM,
open('/path/to/cert/file.crt').read()
)
print OpenSSL.crypto.dump_certificate(OpenSSL.crypto.FILETYPE_TEXT, cert)
Попробуй.
Ответ 5
Я не уверен, как вы получили его, но еще один простой способ установить его - просто записать его в виде двоичного файла, а затем запустить его с помощью ОС
import os
cert= function_gives_binary_cert()
with open('RecvdCert.der','wb') as file:
file.write(cert)
os.startfile('RecvdCert.der')
Остерегайтесь запуска полученного двоичного файла из неизвестного источника. Просто хотите декодировать, а затем использовать OpenSSL, как упоминалось в других ответах.