Ошибка 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 вариант.

Другие вопросы по тегам