Сертификат клиента Indy 10: все в одном .pem файле? - PullRequest
0 голосов
/ 29 августа 2018

тл; др:

Есть ли способ для TIdSSLIOHandlerSocketOpenSSL использовать один файл .pem, который включает в себя сертификат, root и ключ для сертификата клиента?


подробности:

Партнер поставщика требует от нас использования аутентификации mTLS. Они предоставили сертификат, который я экспортировал (включая мой сертификат, корневой сертификат и закрытый ключ) в формате PEM.

Затем я провел несколько простых тестов подключения в PHP, используя cURL.

Обратите внимание, что я смог использовать свой полный файл .pem.

$the_url = 'https://example.com/post-to-me';
$xml_payload = '<foo>bar</foo>';
$headers = array( "Content-type: text/xml",
                  "Content-length: ".strlen($xml_payload),
                  "Connection: close" );

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $the_url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);            // Force curl_exec() to return server response string rather than true/false
curl_setopt($ch, CURLOPT_TIMEOUT, 10);                  // 10-second timeout
curl_setopt($ch, CURLOPT_POSTFIELDS, $xml_payload);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_SSLCERT, 'all-in-one-cert.pem');
curl_setopt($ch, CURLOPT_SSLCERTPASSWD, 'super-secret-password');

$result     = curl_exec($ch);

Это дало ожидаемый результат от сервера, поэтому я перешел к написанию своего кода C ++ Builder:

FHTTP               = new TIdHTTP( 0 );
FSSLIOHandlerSocket = new TIdSSLIOHandlerSocketOpenSSL( 0 );

FLogFile            = new TIdLogFile( 0 );
FLogFile->LogTime   = true;

FSSLIOHandlerSocket->Intercept                  = FLogFile;
FSSLIOHandlerSocket->IPVersion                  = Id_IPv4;
FSSLIOHandlerSocket->MaxLineAction              = maException;
FSSLIOHandlerSocket->SSLOptions->Mode           = sslmClient;
FSSLIOHandlerSocket->SSLOptions->CertFile       = "all-in-one-cert.pem";
FSSLIOHandlerSocket->SSLOptions->RootCertFile   = "all-in-one-cert.pem";
FSSLIOHandlerSocket->SSLOptions->KeyFile        = "all-in-one-cert.pem";
FSSLIOHandlerSocket->OnGetPassword              = GetPassWord;
FSSLIOHandlerSocket->SSLOptions->Method         = sslvTLSv1_2;

FHTTP->IOHandler            = FSSLIOHandlerSocket;
FHTTP->ConnectTimeout       = 10000;
FHTTP->ReadTimeout          = 60000;
FHTTP->MaxAuthRetries       = 0;
FHTTP->Request->ContentType = "text/xml";

TStringStream * MsgStream = new TStringStream();
TStringStream * RspStream = new TStringStream();

MsgStream->WriteString( "<foo>bar</foo>" );

FHTTP->Post( "https://example.com/post-to-me", MsgStream, RspStream );

long StreamSize     = RspStream->Size;
RspStream->Position = 0;
FResponse           = RspStream->ReadString( StreamSize ).Trim();

Это привело к следующей ошибке OpenSSL:

Не удалось загрузить сертификат. ошибка: 00000000: Lib (0): функ (0): причина (0)

Я тоже пробовал:

FSSLIOHandlerSocket->SSLOptions->CertFile       = "all-in-one-cert.pem";
FSSLIOHandlerSocket->OnGetPassword              = GetPassWord;

Это привело к той же ошибке.

Я также пытался использовать файл сертификата .pfx:

FSSLIOHandlerSocket->SSLOptions->CertFile       = "all-in-one-cert.pfx";
FSSLIOHandlerSocket->OnGetPassword              = GetPassWord;

Это позволило загрузить сертификат, но затем привело к сбою рукопожатия при подключении:

Ошибка подключения по SSL. ошибка: 14094410: подпрограммы SSL: SSL3_READ_BYTES: сбой квитирования оповещения sslv3

Я использовал Wireshark, чтобы убедиться, что произошла ошибка рукопожатия, потому что в рукопожатие передавалось 0 сертификатов.

Я решил проблему, разделив клиентский сертификат, root и ключ на три отдельных файла, например:

FSSLIOHandlerSocket->SSLOptions->CertFile       = "cert-only.pem";
FSSLIOHandlerSocket->SSLOptions->RootCertFile   = "root-only.pem";
FSSLIOHandlerSocket->SSLOptions->KeyFile        = "key-only.pem";

Тем не менее, мне любопытно: есть ли способ сделать это со всеми тремя компонентами в одном файле .pem? Или я что-то упустил? Я новичок в этом бизнесе mTLS, поэтому прошу прощения за мое невежество.

...