Ошибка 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.