2015-06-08 19 views
7

Ich arbeite an der Implementierung einer Webanwendung, die eine API verwendet. Während einer Antwort sendet der API-Server eine Verbindung zu einem X509-Zertifikat (im PEM-Format, das aus einem Signaturzertifikat und einem oder mehreren Zwischenzertifikaten für ein Stammzertifizierungsstellenzertifikat besteht), das ich herunterladen und zur weiteren Überprüfung verwenden muss.Wie validiere/verifiziere ich eine X509-Zertifikat-Vertrauenskette in Python?

Bevor das Zertifikat verwendet wird, muss sichergestellt werden, dass alle Zertifikate in der Kette kombiniert werden, um eine Vertrauenskette zu einem vertrauenswürdigen Stammzertifizierungsstellenzertifikat zu erstellen (um böswillige Anforderungen zu erkennen und zu vermeiden). Es fällt mir schwer, dies in Python zu tun, und meine Forschung zu diesem Thema liefert nichts Nützliches.

Das Zertifikat wird leicht ergriffen und geladen und unter Verwendung von Anfragen m2crypto

import requests 
from M2Crypto import RSA, X509 

mypem = requests.get('https://server.com/my_certificate.pem') 
cert = X509.load_cert_string(str(mypem.text), X509.FORMAT_PEM) 

Jedoch ist die Zertifikatkette Validieren Problem. Es ist nicht praktikabel für mich, das Zertifikat auf Platte zu schreiben, um ein Kommandozeilen-Dienstprogramm wie openssl über etwas wie Subprozess zu verwenden, also muss es durch Python gemacht werden. Ich habe auch keine offenen Verbindungen und so funktioniert auch die Verwendung einer verbindungsbasierten Validierungslösung (wie in dieser Antwort/Thread erwähnt: https://stackoverflow.com/a/1088224/4984533) nicht.

auf einem anderen Thread über dieses Problem (bei https://stackoverflow.com/a/4427081) Abt erklärt, dass m2crypto diese Validierung zu tun, nicht in der Lage ist und sagt, dass er eine Verlängerung Validierung zu ermöglichen geschrieben hat (das Modul m2ext mit), aber seine Patch scheint nie Arbeit, immer wiederkehr falsch, obwohl ich weiß, es ist gültig:

from m2ext import SSL 
ctx = SSL.Context() 
ctx.load_verify_locations(capath='/etc/ssl/certs/') # I have run c_rehash in this directory to generate a list of cert files with signature based names 
if not ctx.validate_certificate(cert): # always happens 
    print('Invalid certificate!') 

es gibt auch diese Antwort auf einem ähnlichen Thread hier https://stackoverflow.com/a/9007764/4984533, in dem John Matthews einen Patch, der es tun wird geschrieben haben behauptet, aber leider ist der Patch Link jetzt tot - und überhaupt gibt es einen Kommentar zu diesem Thread, der besagt, dass der Patch nicht mit openssl 0.9.8e funktioniert hat.

Alle Antworten in Bezug auf die Validierung einer Zertifikatskette des Vertrauens in Python scheinen entweder mit dem toten Patch zu verknüpfen oder gehen Sie zurück zu m2ext.

Gibt es eine einfache, direkte Möglichkeit, meine Zertifikats-Vertrauenskette in Python zu überprüfen?

+0

Btw pyopenssl openssl hüllt so würde man es nicht über die Befehlszeile verwenden müssen. Auch lesenswert wenn du noch nicht https://www.python.org/dev/peps/pep-0476/ –

+0

Danke für den Link Avi, hatte ich das vorher nicht gesehen. Es hilft mir nicht in meiner gegenwärtigen Zwangslage (es scheint jedoch um HTTP-Clients zu gehen). Ich habe kein Problem mit einem Befehlszeilenprogramm, um die Verifizierung bei Bedarf durchzuführen - aber nicht, wenn ich die pem-Datei bei jeder Anfrage auf Platte schreiben muss. Wenn der Befehl openssl verify stattdessen eine rohe Zeichenkette aufnehmen könnte, könnte ich das verwenden (auch wenn es wie ein hacky Workaround für etwas erscheint, das ich für sicher hielt, wäre in Python trivial). – speznot

Antwort

4

Ich schaute in pyopenssl Bibliothek und fand dies für die Validierung der Zertifikatskette. Das folgende Beispiel ist von their tests und scheint zu tun, was Sie wollen, was die Vertrauenskette zu einem vertrauenswürdigen Stammzertifikat überprüft. Hier sind die entsprechenden Dokumente für X509Store and X509StoreContext

from OpenSSL.crypto import load_certificate, load_privatekey 
from OpenSSL.crypto import X509Store, X509StoreContext 
from six import u, b, binary_type, PY3 
root_cert_pem = b("""-----BEGIN CERTIFICATE----- 
MIIC7TCCAlagAwIBAgIIPQzE4MbeufQwDQYJKoZIhvcNAQEFBQAwWDELMAkGA1UE 
BhMCVVMxCzAJBgNVBAgTAklMMRAwDgYDVQQHEwdDaGljYWdvMRAwDgYDVQQKEwdU 
ZXN0aW5nMRgwFgYDVQQDEw9UZXN0aW5nIFJvb3QgQ0EwIhgPMjAwOTAzMjUxMjM2 
NThaGA8yMDE3MDYxMTEyMzY1OFowWDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAklM 
MRAwDgYDVQQHEwdDaGljYWdvMRAwDgYDVQQKEwdUZXN0aW5nMRgwFgYDVQQDEw9U 
ZXN0aW5nIFJvb3QgQ0EwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAPmaQumL 
urpE527uSEHdL1pqcDRmWzu+98Y6YHzT/J7KWEamyMCNZ6fRW1JCR782UQ8a07fy 
2xXsKy4WdKaxyG8CcatwmXvpvRQ44dSANMihHELpANTdyVp6DCysED6wkQFurHlF 
1dshEaJw8b/ypDhmbVIo6Ci1xvCJqivbLFnbAgMBAAGjgbswgbgwHQYDVR0OBBYE 
FINVdy1eIfFJDAkk51QJEo3IfgSuMIGIBgNVHSMEgYAwfoAUg1V3LV4h8UkMCSTn 
VAkSjch+BK6hXKRaMFgxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJJTDEQMA4GA1UE 
BxMHQ2hpY2FnbzEQMA4GA1UEChMHVGVzdGluZzEYMBYGA1UEAxMPVGVzdGluZyBS 
b290IENBggg9DMTgxt659DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GB 
AGGCDazMJGoWNBpc03u6+smc95dEead2KlZXBATOdFT1VesY3+nUOqZhEhTGlDMi 
hkgaZnzoIq/Uamidegk4hirsCT/R+6vsKAAxNTcBjUeZjlykCJWy5ojShGftXIKY 
w/njVbKMXrvc83qmTdGl3TAM0fxQIpqgcglFLveEBgzn 
-----END CERTIFICATE----- 
""") 
intermediate_cert_pem = b("""-----BEGIN CERTIFICATE----- 
MIICVzCCAcCgAwIBAgIRAMPzhm6//0Y/g2pmnHR2C4cwDQYJKoZIhvcNAQENBQAw 
WDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAklMMRAwDgYDVQQHEwdDaGljYWdvMRAw 
DgYDVQQKEwdUZXN0aW5nMRgwFgYDVQQDEw9UZXN0aW5nIFJvb3QgQ0EwHhcNMTQw 
ODI4MDIwNDA4WhcNMjQwODI1MDIwNDA4WjBmMRUwEwYDVQQDEwxpbnRlcm1lZGlh 
dGUxDDAKBgNVBAoTA29yZzERMA8GA1UECxMIb3JnLXVuaXQxCzAJBgNVBAYTAlVT 
MQswCQYDVQQIEwJDQTESMBAGA1UEBxMJU2FuIERpZWdvMIGfMA0GCSqGSIb3DQEB 
AQUAA4GNADCBiQKBgQDYcEQw5lfbEQRjr5Yy4yxAHGV0b9Al+Lmu7wLHMkZ/ZMmK 
FGIbljbviiD1Nz97Oh2cpB91YwOXOTN2vXHq26S+A5xe8z/QJbBsyghMur88CjdT 
21H2qwMa+r5dCQwEhuGIiZ3KbzB/n4DTMYI5zy4IYPv0pjxShZn4aZTCCK2IUwID 
AQABoxMwETAPBgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBDQUAA4GBAPIWSkLX 
QRMApOjjyC+tMxumT5e2pMqChHmxobQK4NMdrf2VCx+cRT6EmY8sK3/Xl/X8UBQ+ 
9n5zXb1ZwhW/sTWgUvmOceJ4/XVs9FkdWOOn1J0XBch9ZIiFe/s5ASIgG7fUdcUF 
9mAWS6FK2ca3xIh5kIupCXOFa0dPvlw/YUFT 
-----END CERTIFICATE----- 
""") 
intermediate_server_cert_pem = b("""-----BEGIN CERTIFICATE----- 
MIICWDCCAcGgAwIBAgIRAPQFY9jfskSihdiNSNdt6GswDQYJKoZIhvcNAQENBQAw 
ZjEVMBMGA1UEAxMMaW50ZXJtZWRpYXRlMQwwCgYDVQQKEwNvcmcxETAPBgNVBAsT 
CG9yZy11bml0MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVNh 
biBEaWVnbzAeFw0xNDA4MjgwMjEwNDhaFw0yNDA4MjUwMjEwNDhaMG4xHTAbBgNV 
BAMTFGludGVybWVkaWF0ZS1zZXJ2aWNlMQwwCgYDVQQKEwNvcmcxETAPBgNVBAsT 
CG9yZy11bml0MQswCQYDVQQGEwJVUzELMAkGA1UECBMCQ0ExEjAQBgNVBAcTCVNh 
biBEaWVnbzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAqpJZygd+w1faLOr1 
iOAmbBhx5SZWcTCZ/ZjHQTJM7GuPT624QkqsixFghRKdDROwpwnAP7gMRukLqiy4 
+kRuGT5OfyGggL95i2xqA+zehjj08lSTlvGHpePJgCyTavIy5+Ljsj4DKnKyuhxm 
biXTRrH83NDgixVkObTEmh/OVK0CAwEAATANBgkqhkiG9w0BAQ0FAAOBgQBa0Npw 
UkzjaYEo1OUE1sTI6Mm4riTIHMak4/nswKh9hYup//WVOlr/RBSBtZ7Q/BwbjobN 
3bfAtV7eSAqBsfxYXyof7G1ALANQERkq3+oyLP1iVt08W1WOUlIMPhdCF/QuCwy6 
x9MJLhUCGLJPM+O2rAPWVD9wCmvq10ALsiH3yA== 
-----END CERTIFICATE----- 
""") 

root_cert = load_certificate(FILETYPE_PEM, root_cert_pem) 
intermediate_cert = load_certificate(FILETYPE_PEM, intermediate_cert_pem) 
intermediate_server_cert = load_certificate(FILETYPE_PEM, intermediate_server_cert_pem) 
store = X509Store() 
store.add_cert(root_cert) 
store.add_cert(intermediate_cert) 
store_ctx = X509StoreContext(store, intermediate_server_cert) 
print(store_ctx.verify_certificate()) 
+0

Also kann ich dieses Beispiel nicht zur Arbeit bringen - fehle ich etwas? Der Aufruf verify_cert gibt immer "None" zurück (für das in Ihrem Beispiel bereitgestellte Zertifikat und mein eigenes Zertifikat, mit dem ich getestet habe). Ich musste den 'FILETYPE_PEM'-Import oben zusammen mit Ihren anderen Importen von OpenSSL.crypto hinzufügen.Ich habe auch versucht, die überflüssigen Zeilenumbrüche (nach den Zeilen "END CERTIFICATE") in den Cert-Strings zu entfernen, aber es gibt immer noch keine zurück. Vielen Dank für Ihre Gedanken und Ihre Zeit dazu! – speznot

+0

Ah! Ich hatte die Bemerkung verpasst, dass ich in dieser Dokumentation direkt ins Gesicht starrte und sagte: "Keine ist eine gültige Antwort - ich entschuldige mich." Ich habe versucht, mit meinen eigenen Zertifikaten zu testen und bekomme "Fehler" [lokales] Ausstellerzertifikat nicht bekommen. In der Befehlszeile verwende ich Folgendes, um erfolgreich zu verifizieren: 'openssl verify -untrusted intermediate_cert.pem -CAfile rootcert.pem tovalidate.pem' (ohne den -untrusted schalte es mit ähnlichen Fehlern aus, die ich sehe) - ist es Korrigieren Sie, dass in Ihrem Beispiel 'intermediate_server_cert' das Zertifikat ist, das ich validiere? – speznot

+0

Korrekt, intermediate_server_cert ist das Zertifikat, das in diesem Beispiel validiert wird. Ich denke, dass dieser Fehler im Allgemeinen bedeutet, dass ein bestimmtes Zertifikat irgendwo in der Kette fehlt. Das ist allerdings seltsam, ich habe es mit einem anderen Beispiel versucht und es ist mir gelungen, es zu lösen. –