Закрепление открытого ключа в curl не работает без использования сертификатов из системы - PullRequest
0 голосов
/ 31 августа 2018

Я пытаюсь использовать libcurl с закреплением открытого ключа для проверки подлинности сервера при загрузке файла.

Curl скомпилирован так, что он не использует никаких сертификатов в системе, а полагается только на сертификаты, которые он получает от пользователя:

./configure --without-ca-bundle --without-ca-path --without-ca-fallback && make

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

$ openssl s_client -servername www.example.com -connect www.example.com:443 < /dev/null | sed -n "/-----BEGIN/,/-----END/p" > www.example.com.pem
depth=2 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert High Assurance EV Root CA
verify return:1
depth=1 C = US, O = DigiCert Inc, OU = www.digicert.com, CN = DigiCert SHA2 High Assurance Server CA
verify return:1
depth=0 C = US, ST = California, L = Los Angeles, O = Internet Corporation for Assigned Names and Numbers, OU = Technology, CN = www.example.org
verify return:1
DONE
$ openssl x509 -in www.example.com.pem -pubkey -noout > www.example.com.pubkey.pem
$ openssl asn1parse -noout -inform pem -in www.example.com.pubkey.pem -out www.example.com.pubkey.der
$ openssl dgst -sha256 -binary www.example.com.pubkey.der | openssl base64
xmvvalwaPni4IBbhPzFPPMX6JbHlKqua257FmJsWWto=

Затем я установил хеш открытого ключа и другие связанные параметры в libcurl:

curl_easy_setopt(conn, CURLOPT_PINNEDPUBLICKEY, "sha256//xmvvalwaPni4IBbhPzFPPMX6JbHlKqua257FmJsWWto=");
curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 1);
curl_easy_setopt(conn, CURLOPT_SSL_VERIFYHOST, 2);
curl_easy_setopt(conn, CURLOPT_URL, "https://example.com/index.html");
curl_easy_setopt(conn, CURLOPT_VERBOSE, 1);
curl_code = curl_easy_perform(conn);
if (curl_code != CURLE_OK)
{
    printf("%s\n", curl_easy_strerror(curl_code));
}

Загрузка не удалась с ошибкой:

* SSL certificate problem: unable to get local issuer certificate
...
Peer certificate cannot be authenticated with given CA certificates

Что ж, похоже, что curl ищет некоторые сертификаты, поэтому я перекомпилирую его, чтобы включить сертификаты по умолчанию:

./configure && make

Теперь загрузка будет работать:

* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
...
*  SSL certificate verify ok.
*    public key hash: sha256//xmvvalwaPni4IBbhPzFPPMX6JbHlKqua257FmJsWWto=
...

В документации CURLOPT_PINNEDPUBLICKEY объясняется:

When negotiating a TLS or SSL connection, the server sends a certificate
indicating its identity. A public key is extracted from this certificate
and if it does not exactly match the public key provided to this option,
curl will abort the connection before sending or receiving any data. 

Поэтому у меня сложилось впечатление, что curl нужен только открытый ключ от пользователя, чтобы сравнить его с открытым ключом, извлеченным из сертификата сервера.

Что мне здесь не хватает?

1 Ответ

0 голосов
/ 04 сентября 2018

Проблема состоит в том, что CURLOPT_SSL_VERIFYPEER, установленный в 1, включает закрепление CA. Curl принимает настройку закрепления CA и закрепления с открытым ключом одновременно, и поскольку закрепление CA пробуется перед закреплением с открытым ключом, закрепление CA завершается неудачно, и ему никогда не удается выполнить закрепление с открытым ключом.

Решение состоит в том, чтобы явно отключить закрепление CA при выполнении закрепления с открытым ключом:

curl_easy_setopt(conn, CURLOPT_SSL_VERIFYPEER, 0);

Это нужно сделать явно, потому что значение по умолчанию для CURLOPT_SSL_VERIFYPEER равно 1.

ПРИМЕЧАНИЕ: обычно следует избегать установки CURLOPT_SSL_VERIFYPEER в 0, но в этом случае это безопасно, поскольку выполняется закрепление открытым ключом.

Для получения дополнительной информации см. эту проблему с завитком .

...