Экспорт сертификата HTTPS в формате, приемлемом для PHP SSL контекстной опции "cafile" - PullRequest
6 голосов
/ 18 июня 2020

Как экспортировать сертификат в формате, который будет приемлем для PHP Параметр контекста SSL cafile?

В моем коде ниже используется openssl_x509_export для экспорта цепочки сертификатов stackoverflow.com в файл. Код основан на Как получить информацию о сертификате SSL с CURL в PHP?

$context = stream_context_create(["ssl" => ["capture_peer_cert_chain" => true]]);
$h = stream_socket_client(
         "ssl://stackoverflow.com:443", $errno, $errstr, 30, STREAM_CLIENT_CONNECT,
         $context);
$params = stream_context_get_params($h);

$ca = null;

foreach ($params["options"]["ssl"]["peer_certificate_chain"] as $cert)
{
    openssl_x509_export($cert, $output);
    $ca .= $output;
}

file_put_contents("cafile", $ca);

(я знаю, что нет необходимости экспортировать всю цепочку. )

Затем я пытаюсь с помощью следующего фрагмента кода подключиться к тому же хосту, используя экспортированный файл для проверки сертификата. Но код не работает с:

PHP Предупреждение: file_get_contents (): операция SSL завершилась неудачно с кодом 1. Сообщения об ошибках OpenSSL:

ошибка: 14090086: подпрограммы SSL: SSL3_GET_SERVER_CERTIFICATE: проверка сертификата не удалась в /path/test.php в строке 22 * ​​1024 *

$context = stream_context_create(["ssl" => ["cafile" => "cafile"]]);

file_get_contents("https://stackoverflow.com/", false, $context);

Что не так с форматом файла?

Интересно, что wget доволен экспортированный сертификат успешно завершится следующим образом:

wget --ca-certificate=cafile https://sourceforge.net/

Экспорт:

-----BEGIN CERTIFICATE-----
MIIHJDCCBgygAwIBAgISA76ZNTywMU3d6zogRjuFkuFnMA0GCSqGSIb3DQEBCwUA
MEoxCzAJBgNVBAYTAlVTMRYwFAYDVQQKEw1MZXQncyBFbmNyeXB0MSMwIQYDVQQD
ExpMZXQncyBFbmNyeXB0IEF1dGhvcml0eSBYMzAeFw0yMDA2MDgxNjI0MDBaFw0y
MDA5MDYxNjI0MDBaMB4xHDAaBgNVBAMMEyouc3RhY2tleGNoYW5nZS5jb20wggEi
MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCp1azQ2CMWUtXrIZDFim7tu2xF
NFYSLt+lIjyZJ1MeCJkljjaiNB02guKeFRSuPsMk2J3Xz8OmOoEfbvVQejMcaw6i
BVP1V+QhF+JhgyOORQkZQV8JJ58IcOJ1PwokyMCAMOWvdxHzaj73jXsxC+n/+MU7
yuq+Y2LuZE1hQYtftYia/e0QtnPDUlpnjUSd7YEDvAzNnKY3+r1smFOHChDjAxMs
W+lJfKLscNKspncihsx16JhZcGZbXiPPOd90B/zA5xNFOCUolldtMAdxFHKoKYpN
mgWrQwVvDB7VCGAQ3CiNGRvdcMa/TpB4SVsZc07C6TvD35dr0wLoZN4WqKfrAgMB
AAGjggQuMIIEKjAOBgNVHQ8BAf8EBAMCBaAwHQYDVR0lBBYwFAYIKwYBBQUHAwEG
CCsGAQUFBwMCMAwGA1UdEwEB/wQCMAAwHQYDVR0OBBYEFM73q8X//0OoBswZWBlG
kTPmW5HPMB8GA1UdIwQYMBaAFKhKamMEfd265tE5t6ZFZe/zqOyhMG8GCCsGAQUF
BwEBBGMwYTAuBggrBgEFBQcwAYYiaHR0cDovL29jc3AuaW50LXgzLmxldHNlbmNy
eXB0Lm9yZzAvBggrBgEFBQcwAoYjaHR0cDovL2NlcnQuaW50LXgzLmxldHNlbmNy
eXB0Lm9yZy8wggHkBgNVHREEggHbMIIB14IPKi5hc2t1YnVudHUuY29tghIqLmJs
b2dvdmVyZmxvdy5jb22CEioubWF0aG92ZXJmbG93Lm5ldIIYKi5tZXRhLnN0YWNr
ZXhjaGFuZ2UuY29tghgqLm1ldGEuc3RhY2tvdmVyZmxvdy5jb22CESouc2VydmVy
ZmF1bHQuY29tgg0qLnNzdGF0aWMubmV0ghMqLnN0YWNrZXhjaGFuZ2UuY29tghMq
LnN0YWNrb3ZlcmZsb3cuY29tghUqLnN0YWNrb3ZlcmZsb3cuZW1haWyCDyouc3Vw
ZXJ1c2VyLmNvbYINYXNrdWJ1bnR1LmNvbYIQYmxvZ292ZXJmbG93LmNvbYIQbWF0
aG92ZXJmbG93Lm5ldIIUb3BlbmlkLnN0YWNrYXV0aC5jb22CD3NlcnZlcmZhdWx0
LmNvbYILc3N0YXRpYy5uZXSCDXN0YWNrYXBwcy5jb22CDXN0YWNrYXV0aC5jb22C
EXN0YWNrZXhjaGFuZ2UuY29tghJzdGFja292ZXJmbG93LmJsb2eCEXN0YWNrb3Zl
cmZsb3cuY29tghNzdGFja292ZXJmbG93LmVtYWlsghFzdGFja3NuaXBwZXRzLm5l
dIINc3VwZXJ1c2VyLmNvbTBMBgNVHSAERTBDMAgGBmeBDAECATA3BgsrBgEEAYLf
EwEBATAoMCYGCCsGAQUFBwIBFhpodHRwOi8vY3BzLmxldHNlbmNyeXB0Lm9yZzCC
AQIGCisGAQQB1nkCBAIEgfMEgfAA7gB1AF6nc/nfVsDntTZIfdBJ4DJ6kZoMhKES
EoQYdZaBcUVYAAABcpT136gAAAQDAEYwRAIhAP68FqsHN7WAMY3gio0PiAX1o0ID
d9G35wA7pgn/OetjAh9f9JkgTdN4U58fsIVcZAPstOIoKOblbzAof32fixlAAHUA
B7dcG+V9aP/xsMYdIxXHuuZXfFeUt2ruvGE6GmnTohwAAAFylPXfyQAABAMARjBE
AiArXFv1bOQ2wDYjJvVjSm13AnPCQmbkRRgw6YEaSDhP7gIgJQPAbeBEhu44aJQe
Ih4j33U59OY4Ux2f02dWw3oqhNIwDQYJKoZIhvcNAQELBQADggEBAHyW5+Ss+0vt
jKPFOL9atcI3WZYlwp7Djg3dXByWFBgVEzhrRGGJKEZyK9N178cG9zGXXXbxrxGY
L81pxfZNGiPBYueQ191bTKRS0/9NyCfQhSjFG9SUy7BHDC8OTX5OxEZfnG4wglCf
vPcBkdZ49b0TsTiDrRfCltQvqkeY+/6CfJnayFV/RuZcfRV2bcnu2lLE3da57mA0
TEc9hSW/AefP5ad4noqhSsPISPPbo8S1U4JAFnn1M0KnoEKr5/awHenQeqKgPSKr
DmtDcoy8Tf0RpqSMUwIKqBZEERthO6FC506E64wcuYww3EqA7Um7MM1MkQ8hosFN
WK9ZLI8ylk4=
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIEkjCCA3qgAwIBAgIQCgFBQgAAAVOFc2oLheynCDANBgkqhkiG9w0BAQsFADA/
MSQwIgYDVQQKExtEaWdpdGFsIFNpZ25hdHVyZSBUcnVzdCBDby4xFzAVBgNVBAMT
DkRTVCBSb290IENBIFgzMB4XDTE2MDMxNzE2NDA0NloXDTIxMDMxNzE2NDA0Nlow
SjELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUxldCdzIEVuY3J5cHQxIzAhBgNVBAMT
GkxldCdzIEVuY3J5cHQgQXV0aG9yaXR5IFgzMIIBIjANBgkqhkiG9w0BAQEFAAOC
AQ8AMIIBCgKCAQEAnNMM8FrlLke3cl03g7NoYzDq1zUmGSXhvb418XCSL7e4S0EF
q6meNQhY7LEqxGiHC6PjdeTm86dicbp5gWAf15Gan/PQeGdxyGkOlZHP/uaZ6WA8
SMx+yk13EiSdRxta67nsHjcAHJyse6cF6s5K671B5TaYucv9bTyWaN8jKkKQDIZ0
Z8h/pZq4UmEUEz9l6YKHy9v6Dlb2honzhT+Xhq+w3Brvaw2VFn3EK6BlspkENnWA
a6xK8xuQSXgvopZPKiAlKQTGdMDQMc2PMTiVFrqoM7hD8bEfwzB/onkxEz0tNvjj
/PIzark5McWvxI0NHWQWM6r6hCm21AvA2H3DkwIDAQABo4IBfTCCAXkwEgYDVR0T
AQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAYYwfwYIKwYBBQUHAQEEczBxMDIG
CCsGAQUFBzABhiZodHRwOi8vaXNyZy50cnVzdGlkLm9jc3AuaWRlbnRydXN0LmNv
bTA7BggrBgEFBQcwAoYvaHR0cDovL2FwcHMuaWRlbnRydXN0LmNvbS9yb290cy9k
c3Ryb290Y2F4My5wN2MwHwYDVR0jBBgwFoAUxKexpHsscfrb4UuQdf/EFWCFiRAw
VAYDVR0gBE0wSzAIBgZngQwBAgEwPwYLKwYBBAGC3xMBAQEwMDAuBggrBgEFBQcC
ARYiaHR0cDovL2Nwcy5yb290LXgxLmxldHNlbmNyeXB0Lm9yZzA8BgNVHR8ENTAz
MDGgL6AthitodHRwOi8vY3JsLmlkZW50cnVzdC5jb20vRFNUUk9PVENBWDNDUkwu
Y3JsMB0GA1UdDgQWBBSoSmpjBH3duubRObemRWXv86jsoTANBgkqhkiG9w0BAQsF
AAOCAQEA3TPXEfNjWDjdGBX7CVW+dla5cEilaUcne8IkCJLxWh9KEik3JHRRHGJo
uM2VcGfl96S8TihRzZvoroed6ti6WqEBmtzw3Wodatg+VyOeph4EYpr/1wXKtx8/
wApIvJSwtmVi4MFU5aMqrSDE6ea73Mj2tcMyo5jMd6jmeWUHK8so/joWUoHOUgwu
X4Po1QYz+3dszkDqMp4fklxBwXRsW10KXzPMTZ+sOPAveyxindmjkW8lGy+QsRlG
PfZ+G6Z6h7mjem0Y+iWlkYcV4PIWL1iwBi8saCbGS5jN2p8M+X+Q7UNKEkROb3N6
KOqkqm57TH2H3eDJAkSnh6/DNFu0Qg==
-----END CERTIFICATE-----

Некоторая предыстория: я использую пакет сертификатов от https://curl.haxx.se/docs/caextract.html.

По какой-то причине PHP не может проверить сертификаты, выданные «центром сертификации USERTrust RSA», хотя сертификат root вроде бы присутствует в комплекте. Например сам сертификат sectigo.com. Это часть моей попытки найти причину root или обходной путь.

Ответы [ 3 ]

4 голосов
/ 23 июня 2020

stackoverflow предоставляет только сертификат сервера и промежуточный сертификат CA. не сертификат root ca.

openssl cafile работает только в том случае, если полная цепочка (до самоподписанного root ca) может быть проверена,

, поэтому вам нужно либо доверять ROOT CA самостоятельно, загрузив его, или используйте какой-то pki, чтобы у вас были все глобальные доверенные root CA.

на машинах на базе Debian GNU / Linux вы можете установить пакет ca-сертификатов , sudo apt-get install ca-certificates

или вы можете использовать cacert из mozilla https://curl.haxx.se/docs/caextract.html

0 голосов
/ 28 июня 2020

Возможно недопонимание. stream_context_create() - создать TCP-сервер. Он может обрабатывать рукопожатия, но для этого должен иметь целую связку ключей, отформатированную, как показано ниже:

Это .crt и частный .key файл, сгенерированный openssl, объединенный в один файл.

-----BEGIN CERTIFICATE-----
MIIDaDCCAlCgAwIB(...)
-----END CERTIFICATE-----
-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAK(...)
-----END RSA PRIVATE KEY-----

С такой связкой ключей я могу реализовать ssl / https и защитить серверы wss: // websockets.

Не уверен, что вы хотите сделать, почему file_get_contents () не Не работает без контекста. Обычно вам не нужно импортировать какой-либо CAcert, и если да, то он принадлежит браузеру.

Это может быть полезно в контексте предприятия или во избежание ошибок с самоподписанными связками ключей.

Таким образом, что не так с просто:

echo file_get_contents("https://stackoverflow.com/");

или

wget https://sourceforge.net/

Это просто работает без проблем.

Пожалуйста, объясните точно, чего вы пытаетесь достичь, много заметки из экспериментов с ssl и php.

Чтобы извлечь publi c ключ данного сервера, вы должны запросить через порт 443:

<?php
$opt = [
  "capture_peer_cert" => true,
  "capture_peer_cert_chain" => true
];
$a = stream_context_create(["ssl"=>$opt]);
$b = stream_socket_client("tls://stackoverflow.com:443", $errno, $errstr, 30, STREAM_CLIENT_CONNECT, $a);
$cont = stream_context_get_params($b);
$key = openssl_pkey_get_public($cont["options"]["ssl"]["peer_certificate"]);
$c = openssl_pkey_get_details($key);
var_dump($c["key"]);

Output

string(451) "-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAqdWs0NgjFlLV6yGQxYpu
7btsRTRWEi7fpSI8mSdTHgiZJY42ojQdNoLinhUUrj7DJNid18/DpjqBH271UHoz
HGsOogVT9VfkIRfiYYMjjkUJGUFfCSefCHDidT8KJMjAgDDlr3cR82o+9417MQvp
//jFO8rqvmNi7mRNYUGLX7WImv3tELZzw1JaZ41Ene2BA7wMzZymN/q9bJhThwoQ
4wMTLFvpSXyi7HDSrKZ3IobMdeiYWXBmW14jzznfdAf8wOcTRTglKJZXbTAHcRRy
qCmKTZoFq0MFbwwe1QhgENwojRkb3XDGv06QeElbGXNOwuk7w9+Xa9MC6GTeFqin
6wIDAQAB
-----END PUBLIC KEY-----
"

Возможно, этот ответ поможет

0 голосов
/ 25 июня 2020
  1. Скачать сертификат CA отсюда https://curl.haxx.se/ca/cacert.pem
  2. Выполните следующий код:
<?php

$context = stream_context_create([
    "ssl" => [
        "cafile" => "cacert.pem"
    ]
]);

file_get_contents("https://stackoverflow.com/", false, $context);
вы не увидите ошибок

Пояснения : относительно документации cafile accept Certificate Authority file но вы пытались поставить сертификаты цепочки

...