如果不使用系统中的证书,curl中的公钥固定不起作用

问题描述 投票:0回答:1

我正在尝试将libcurl与公钥锁定一起使用,以便在下载文件时验证服务器的真实性。

卷曲被编译,以便它不使用系统上的任何证书,但只依赖于它从用户收到的证书:

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

首先,我获取服务器证书的公钥的sha256总和,如here所述:

$ 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只需要来自用户的公钥,以便将其与从服务器证书中提取的公钥进行比较。

我在这里错过了什么?

curl libcurl public-key-pinning
1个回答
0
投票

问题是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,但在这种情况下它是安全的,因为正在进行公钥锁定。

有关更多详细信息,请参阅this curl issue

© www.soinside.com 2019 - 2024. All rights reserved.