web-dev-qa-db-fra.com

Python Erreur SSL Urllib2

Python 2.7.9 est désormais beaucoup plus strict sur la vérification des certificats SSL. Impressionnant!

Je ne suis pas surpris que les programmes qui fonctionnaient auparavant obtiennent maintenant des erreurs CERTIFICATE_VERIFY_FAILED. Mais je n'arrive pas à les faire fonctionner (sans désactiver complètement la vérification des certificats).

Un programme utilisait urllib2 pour se connecter à Amazon S3 via https.

Je télécharge le certificat d'autorité de certification racine dans un fichier appelé "verisign.pem" et j'essaye ceci:

import urllib2, ssl
context = ssl.create_default_context()
context.load_verify_locations(cafile = "./verisign.pem")
print context.get_ca_certs()
urllib2.urlopen("https://bucket.s3.amazonaws.com/", context=context)

et j'obtiens toujours des erreurs CERTIFICATE_VERIFY_FAILED, même si l'autorité de certification racine est imprimée correctement à la ligne 4.

openssl peut très bien se connecter à ce serveur. En fait, voici la commande que j'ai utilisée pour obtenir le certificat CA:

openssl s_client -showcerts -connect bucket.s3.amazonaws.com:443 < /dev/null

J'ai pris le dernier certificat de la chaîne et l'ai mis dans un fichier PEM, qui ouvre bien. C'est un certificat Verisign avec:

Serial number: 35:97:31:87:f3:87:3a:07:32:7e:ce:58:0c:9b:7e:da
Subject key identifier: 7F:D3:65:A7:C2:DD:EC:BB:F0:30:09:F3:43:39:FA:02:AF:33:31:33
SHA1 fingerprint: F4:A8:0A:0C:D1:E6:CF:19:0B:8C:BC:6F:BC:99:17:11:D4:82:C9:D0

Des idées sur la façon de faire fonctionner cela avec la validation activée?

18
abjennings

Pour résumer les commentaires sur la cause du problème et expliquer le vrai problème plus en détail:

Si vous vérifiez la chaîne de confiance pour le client OpenSSL, vous obtenez ce qui suit:

 [0] 54:7D:B3:AC:BF:... /CN=*.s3.amazonaws.com 
 [1] 5D:EB:8F:33:9E:... /CN=VeriSign Class 3 Secure Server CA - G3
 [2] F4:A8:0A:0C:D1:... /CN=VeriSign Class 3 Public Primary Certification Authority - G5
[OT] A1:DB:63:93:91:... /C=US/O=VeriSign, Inc./OU=Class 3 Public Primary Certification Authority

Le premier certificat [0] est le certificat feuille envoyé par le serveur. Les certificats suivants [1] et [2] sont des certificats de chaîne envoyés par le serveur. Le dernier certificat [OT] est le certificat racine approuvé, qui n'est pas envoyé par le serveur mais se trouve dans le stockage local de l'autorité de certification approuvée. Chaque certificat de la chaîne est signé par le suivant et le dernier certificat [OT] est approuvé, de sorte que la chaîne d'approbation est terminée.

Si vous vérifiez plutôt la chaîne de confiance par un navigateur (par exemple, Google Chrome utilisant la bibliothèque NSS), vous obtenez la chaîne suivante:

 [0] 54:7D:B3:AC:BF:... /CN=*.s3.amazonaws.com 
 [1] 5D:EB:8F:33:9E:... /CN=VeriSign Class 3 Secure Server CA - G3
[NT] 4E:B6:D5:78:49:... /CN=VeriSign Class 3 Public Primary Certification Authority - G5

Ici, [0] et [1] sont à nouveau envoyés par le serveur, mais [NT] est le certificat racine de confiance. Bien que cela ressemble au sujet exactement au certificat de chaîne [2], l'empreinte digitale indique que les certificats sont différents. Si vous examiniez de plus près les certificats [2] et [NT], vous verriez que la clé publique à l'intérieur du certificat est la même et donc [2] et [NT] peuvent être utilisés pour vérifier la signature de [ 1] et peut donc être utilisé pour construire la chaîne de confiance.

Cela signifie que, bien que le serveur envoie la même chaîne de certificats dans tous les cas, il existe plusieurs façons de vérifier la chaîne jusqu'à un certificat racine approuvé. La procédure à suivre dépend de la bibliothèque SSL et des certificats racine de confiance connus:

                          [0] (*.s3.amazonaws.com)
                           |
                          [1] (Verisign G3) --------------------------\
                           |                                          |
      /------------------ [2] (Verisign G5 F4:A8:0A:0C:D1...)         |
      |                                                               |
      |              certificates sent by server                      |
 .....|...............................................................|................
      |              locally trusted root certificates                |
      |                                                               |
     [OT] Public Primary Certification Authority        [NT] Verisign G5 4E:B6:D5:78:49
     OpenSSL library                                    Google Chrome (NSS library)

Mais la question demeure, pourquoi votre vérification a échoué. Ce que vous avez fait était de prendre le certificat racine de confiance utilisé par le navigateur (Verisign G5 4E: B6: D5: 78: 49) avec OpenSSL. Mais la vérification dans le navigateur (NSS) et OpenSSL fonctionne légèrement différemment:

  • NSS: créer une chaîne de confiance à partir des certificats envoyés par le serveur. Arrêtez de créer la chaîne lorsque nous avons obtenu un certificat signé par l'un des certificats racine approuvés localement.
  • OpenSSL_ build trust chain à partir des certificats envoyés par le serveur. Après cela, vérifiez si nous avons un certificat racine de confiance signant le dernier certificat de la chaîne.

En raison de cette différence subtile, OpenSSL n'est pas en mesure de vérifier la chaîne [0], [1], [2] par rapport au certificat racine [NT], car ce certificat ne signe pas le dernier élément de la chaîne [2] mais à la place [1] . Si le serveur envoyait uniquement une chaîne de [0], [1], la vérification réussirait.

Il s'agit d'un bug connu depuis longtemps et il existe correctifs et nous espérons que le problème sera finalement résolu dans OpenSSL 1.0.2 avec l'introduction du X509_V_FLAG_TRUSTED_FIRST option.

32
Steffen Ullrich