Ошибка Python Urllib2 SSL
Python 2.7.9 теперь намного более строг в отношении проверки SSL-сертификатов. Потрясающие!
Я не удивлен, что программы, которые работали раньше, теперь получают ошибки CERTIFICATE_VERIFY_FAILED. Но я не могу заставить их работать (без полного отключения проверки сертификата).
Одна программа использовала urllib2 для подключения к Amazon S3 через https.
Я загружаю сертификат корневого CA в файл с именем "verisign.pem" и пробую это:
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)
и я по-прежнему получаю ошибки CERTIFICATE_VERIFY_FAILED, даже если корневой ЦС распечатан правильно в строке 4.
openssl может подключиться к этому серверу нормально. Фактически, вот команда, которую я использовал, чтобы получить сертификат CA:
openssl s_client -showcerts -connect bucket.s3.amazonaws.com:443 < /dev/null
Я взял последний сертификат в цепочке и поместил его в файл PEM, который openssl читает хорошо. Это сертификат Verisign с:
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
Любые идеи, как заставить это работать с включенной проверкой?
1 ответ
Чтобы суммировать комментарии о причине проблемы и объяснить реальную проблему более подробно:
Если вы проверите цепочку доверия для клиента OpenSSL, вы получите следующее:
[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
Первый сертификат [0] является листовым сертификатом, отправленным сервером. Следующие сертификаты [1] и [2] являются цепными сертификатами, отправленными сервером. Последний сертификат [OT] является доверенным корневым сертификатом, который не отправляется сервером, а находится в локальном хранилище доверенного ЦС. Каждый сертификат в цепочке подписан следующим, и последний сертификат [OT] является доверенным, поэтому цепочка доверия завершена.
Если вместо этого вы проверяете цепочку доверия с помощью браузера (например, Google Chrome с использованием библиотеки NSS), вы получаете следующую цепочку:
[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
Здесь [0] и [1] снова отправляются сервером, но [NT] является доверенным корневым сертификатом. Хотя это выглядит из предмета точно так же, как сертификат цепочки [2], отпечаток пальца говорит, что сертификаты разные. Если вы поближе познакомитесь с сертификатами [2] и [NT], то увидите, что открытый ключ внутри сертификата одинаков и, следовательно, [2] и [NT] можно использовать для проверки подписи для [ 1] и, следовательно, может быть использован для создания цепочки доверия.
Это означает, что хотя сервер отправляет одну и ту же цепочку сертификатов во всех случаях, существует несколько способов проверить цепочку до доверенного корневого сертификата. Как это сделать, зависит от библиотеки SSL и известных доверенных корневых сертификатов:
[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)
Но остается вопрос, почему ваша проверка не удалась. Вам нужно было взять доверенный корневой сертификат, используемый браузером (Verisign G5 4E:B6:D5:78:49) вместе с OpenSSL. Но проверка в браузере (NSS) и OpenSSL работает немного по-другому:
- NSS: построить цепочку доверия из сертификатов, отправленных сервером. Прекратите строить цепочку, когда мы получили сертификат, подписанный любым из локально доверенных корневых сертификатов.
- OpenSSL_ построить цепочку доверия из сертификатов, отправленных сервером. После этого проверьте, есть ли у нас доверенный корневой сертификат, подписывающий последний сертификат в цепочке.
Из-за этой тонкой разницы OpenSSL не может проверить цепочку [0],[1],[2] по корневому сертификату [NT], потому что этот сертификат не подписывает последний элемент в цепочке [2], а вместо этого [1], Если сервер вместо этого отправит только цепочку [0], [1], тогда проверка будет успешной.
Это давно известная ошибка, и существуют патчи, и, надеюсь, эта проблема будет решена в OpenSSL 1.0.2 после введения X509_V_FLAG_TRUSTED_FIRST
вариант.