Ответ 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
.