【发布时间】:2018-08-31 11:37:58
【问题描述】:
我正在尝试使用带有公钥固定的 libcurl,以便在下载文件时验证服务器的真实性。
Curl 被编译,因此它不使用系统上的任何证书,而仅依赖于它从用户那里收到的证书:
./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 只需要用户的公钥,以便与从服务器证书中提取的公钥进行比较。
我在这里错过了什么?
【问题讨论】:
-
请注意,您不应再使用公钥固定,因为它已被 google 删除。例如看这里:zdnet.com/article/…
-
@PowerStat 这是关于 HPKP 的,据我了解,服务器使用 HTTP 标头告诉客户端要固定到哪些公钥;因此 Chrome 不再响应服务器发送的那些标头。但是公钥固定技术本身仍然有效,并且可能比证书固定更安全。
-
对于对问题投反对票的用户 - 我也非常感谢您的反馈,以便我可以改进这个问题和未来的问题。
-
固定的问题是您必须在更新密钥/证书之前(取决于您的刷新间隔)更新固定。当您考虑让我们每 2 个月加密和更新您的公钥/证书时,这可能会成为一个问题 - 请记住这一点。由于较短的可更新时间段,固定可能会变得邪恶,因此网站在几天/几周/几个月内无法访问!
-
@PowerStat 当然,经常刷新引脚是执行固定的应用程序的责任。例如,Curl 允许一次设置多个公钥;因此,当您当前的证书即将到期时,您将发布新证书并将两个公钥传递给 curl。当新证书生效时,它将在以前的 pin 上失败,但在新的 pin 上工作。所以是的,它有更多问题,但它肯定是可行的。
标签: curl libcurl public-key-pinning