目录php
能够将 SSL 服务器与客户端之间的通讯配置为使用单向或双向 SSL 认证。html
单向 SSL 认证通常是客户端利用服务器传过来的信息验证服务器的合法性,服务器的合法性包括:证书是否过时,发行服务器证书的 CA 是否可靠,发行者证书的公钥可否正确解开服务器证书的“发行者的数字签名”,服务器证书上的域名是否和服务器的实际域名相匹配。git
双向 SSL 认证则除了须要对服务器的合法性进行认证,还须要按照单向 SSL 认证方法对客户端的合法性进行认证。算法
在金融支付过程当中,对安全要求级别比较高的接口,不只要验证签名,还要进行双向验证 SSL 证书,所以有些就须要安装在服务开通以后第三方给咱们发送的安全证书了。shell
为了便于更好的认识和理解 SSL 协议,这里着重介绍 SSL 协议的握手协议。SSL 协议既用到了公钥加密技术又用到了对称加密技术,对称加密技术虽然比公钥加密技术的速度快,但是公钥加密技术提供了更好的身份认证技术。SSL 的握手协议很是有效的让客户和服务器之间完成相互之间的身份认证,其主要过程以下:
① 客户端的浏览器向服务器传送客户端 SSL 协议的版本号,加密算法的种类,产生的随机数,以及其余服务器和客户端之间通信所须要的各类信息。
② 服务器向客户端传送 SSL 协议的版本号,加密算法的种类,随机数以及其余相关信息,同时服务器还将向客户端传送本身的证书。
③ 客户利用服务器传过来的信息验证服务器的合法性,服务器的合法性包括:证书是否过时,发行服务器证书的 CA 是否可靠,发行者证书的公钥可否正确解开服务器证书的“发行者的数字签名”,服务器证书上的域名是否和服务器的实际域名相匹配。若是合法性验证没有经过,通信将断开;若是合法性验证经过,将继续进行第四步。
④ 用户端随机产生一个用于后面通信的“对称密码”,而后用服务器的公钥(服务器的公钥从步骤②中的服务器的证书中得到)对其加密,而后将加密后的“预主密码”传给服务器。
⑤ 若是服务器要求客户的身份认证(在握手过程当中为可选),用户能够创建一个随机数而后对其进行数据签名,将这个含有签名的随机数和客户本身的证书以及加密过的“预主密码”一块儿传给服务器。
⑥ 若是服务器要求客户的身份认证,服务器必须检验客户证书和签名随机数的合法性,具体的合法性验证过程包括:客户的证书使用日期是否有效,为客户提供证书的 CA 是否可靠,发行 CA 的公钥可否正确解开客户证书的发行 CA 的数字签名,检查客户的证书是否在证书废止列表(CRL)中。检验若是没有经过,通信马上中断;若是验证经过,服务器将用本身的私钥解开加密的“预主密码”,而后执行一系列步骤来产生主通信密码(客户端也将经过一样的方法产生相同的主通信密码)。
⑦ 服务器和客户端用相同的主密码即“通话密码”,一个对称密钥用于 SSL 协议的安全数据通信的加解密通信。同时在 SSL 通信过程当中还要完成数据通信的完整性,防止数据通信中的任何变化。
⑧ 客户端向服务器端发出信息,指明后面的数据通信将使用的步骤⑦中的主密码为对称密钥,同时通知服务器客户端的握手过程结束。
⑨ 服务器向客户端发出信息,指明后面的数据通信将使用的步骤⑦中的主密码为对称密钥,同时通知客户端服务器端的握手过程结束。
⑩ SSL 的握手部分结束,SSL 安全通道的数据通信开始,客户和服务器开始使用相同的对称密钥进行数据通信,同时进行通信完整性的检验。浏览器
双向认证 SSL 协议的具体过程
① 浏览器发送一个链接请求给安全服务器。
② 服务器将本身的证书,以及同证书相关的信息发送给客户浏览器。
③ 客户浏览器检查服务器送过来的证书是不是由本身信赖的 CA 中心所签发的。若是是,就继续执行协议;若是不是,客户浏览器就给客户一个警告消息:警告客户这个证书不是能够信赖的,询问客户是否须要继续。
④ 接着客户浏览器比较证书里的消息,例如域名和公钥,与服务器刚刚发送的相关消息是否一致,若是是一致的,客户浏览器承认这个服务器的合法身份。
⑤ 服务器要求客户发送客户本身的证书。收到后,服务器验证客户的证书,若是没有经过验证,拒绝链接;若是经过验证,服务器得到用户的公钥。
⑥ 客户浏览器告诉服务器本身所可以支持的通信对称密码方案。
⑦ 服务器从客户发送过来的密码方案中,选择一种加密程度最高的密码方案,用客户的公钥加过密后通知浏览器。
⑧ 浏览器针对这个密码方案,选择一个通话密钥,接着用服务器的公钥加过密后发送给服务器。
⑨ 服务器接收到浏览器送过来的消息,用本身的私钥解密,得到通话密钥。
⑩ 服务器、浏览器接下来的通信都是用对称密码方案,对称密钥是加过密的。
上面所述的是双向认证 SSL 协议的具体通信过程,这种状况要求服务器和用户双方都有证书。单向认证 SSL 协议不须要客户拥有 CA 证书,具体的过程相对于上面的步骤,只需将服务器端验证客户证书的过程去掉,以及在协商对称密码方案,对称通话密钥时,服务器发送给客户的是没有加过密的(这并不影响 SSL 过程的安全性)密码方案。 这样,双方具体的通信内容,就是加过密的数据,若是有第三方攻击,得到的只是加密的数据,第三方要得到有用的信息,就须要对加密的数据进行解密,这时候的安全就依赖于密码方案的安全。而幸运的是,目前所用的密码方案,只要通信密钥长度足够的长,就足够的安全。这也是咱们强调要求使用 128 位加密通信的缘由。安全
与 SSL 单向认证相关的 curl_easy_setopt
选项有如下几个:服务器
/CN
值; openssl req -subj "/C=CN/ST=IL/L=ShenZhen/O=Tencent/OU=Tencent/CN=luffichen_server.tencent.com/emailAddress=luffichen@www.tencent.com" ...
与 SSL 双向认证相关的 curl_easy_setopt
选项有如下几个:dom
if(!oneway_certification) { // 验证服务器证书有效性 curl_easy_setopt(m_curl_handler, CURLOPT_SSL_VERIFYPEER, 1); // 检验证书中的主机名和你访问的主机名一致 curl_easy_setopt(m_curl_handler, CURLOPT_SSL_VERIFYHOST, 2); // 指定 CA 证书路径 curl_easy_setopt(m_curl_handler, CURLOPT_CAINFO, m_ca_cert_file.c_str()); } else { // 不验证服务器证书 curl_easy_setopt(m_curl_handler, CURLOPT_SSL_VERIFYPEER, 0); curl_easy_setopt(m_curl_handler, CURLOPT_SSL_VERIFYHOST, 0); } if(!client_cert_file.empty()) { // 客户端证书,用于双向认证 curl_easy_setopt(m_curl_handler, CURLOPT_SSLCERT, client_cert_file.c_str()); } if(!client_cert_type.empty()) { // 客户端证书类型,用于双向认证 curl_easy_setopt(m_curl_handler, CURLOPT_SSLCERTTYPE, client_cert_type.c_str()); } if(!private_key.empty()) { // 客户端证书私钥,用于双向认证 curl_easy_setopt(m_curl_handler, CURLOPT_SSLKEY, private_key.c_str()); } if(!private_key_type.empty()) { // 客户端证书私钥类型,用于双向认证 curl_easy_setopt(m_curl_handler, CURLOPT_SSLKEYTYPE, private_key_type.c_str()); } if(!private_key_passwd.empty()) { // 客户端证书私钥密码 curl_easy_setopt(m_curl_handler, CURLOPT_KEYPASSWD, private_key_passwd.c_str()); }
说明:设置 curl 选项时,这里对空值进行判断,若是为空,则不进行双向认证了。curl
curl -V curl 7.56.0-DEV (Linux) libcurl/7.56.0-DEV OpenSSL/1.0.1e zlib/1.2.3 Release-Date: [unreleased] Protocols: dict file ftp ftps gopher http https imap imaps pop3 pop3s rtsp smb smbs smtp smtps telnet tftp Features: AsynchDNS IPv6 Largefile NTLM SSL libz UnixSockets HTTPS-proxy
若是没有,Features 中没有 ssl,则须要从新编译支持 ssl 的 curl 版本(./configure --with-ssl)
在编译时,可按照 curl 官网给出的方法进行:
./configure --with-ssl If you have OpenSSL installed somewhere else (for example, /opt/OpenSSL) and you have pkg-config installed, set the pkg-config path first, like this: env PKG_CONFIG_PATH=/opt/OpenSSL/lib/pkgconfig ./configure --with-ssl Without pkg-config installed, use this: ./configure --with-ssl=/opt/OpenSSL If you insist on forcing a build without SSL support, even though you may have OpenSSL installed in your system, you can run configure like this: ./configure --without-ssl If you have OpenSSL installed, but with the libraries in one place and the header files somewhere else, you have to set the LDFLAGS and CPPFLAGS environment variables prior to running configure. Something like this should work: CPPFLAGS="-I/path/to/ssl/include" LDFLAGS="-L/path/to/ssl/lib" ./configure If you have shared SSL libs installed in a directory where your run-time linker doesn't find them (which usually causes configure failures), you can provide the -R option to ld on some operating systems to set a hard-coded path to the run-time linker: LDFLAGS=-R/usr/local/ssl/lib ./configure --with-ssl
另外要注意 openssl 不一样版本对 ssl 协议版本的支持。仅 openssl 1.0.2 及其以上版本目前支持 TLS 1.2 版本的。
在编译 openssl 1.0.2h 时发现其生成的 libssl 文件为 libss.so.1.0.0/libcrypto.so.1.0.0 而不是 libssl.so.1.0.2/libcrypto.so.1.0.2,这里的 ssl 库的版本和软件版本的编号是不一致的,这么作的缘由 Richard Levitte 作了解释:
We recognised that our shared library version numbering was confusing, so from OpenSSL version 1.1.0 and up, the shared library version retains the two first digits of the OpenSSL version only, which reflects our intent that for any versions x.y.z where x.y stays the same, ABI backward compatibility will be maintained.
当 CURLOPT_SSL_VERIFYPEER
为 1 时,表示启用了验证访问的服务器合法性,且必须设置 CURLOPT_CAINFO
或 CURLOPT_CAPATH
其中一个,而 CURLOPT_SSL_VERIFYHOST
为 2 时,表示验证 CA 证书中的 common name 是否与访问的服务器域名是否一致。在测试的时候,须要记得为客户端侧机器添加相应的 host 域名 IP 解析,若是直接使用 IP 访问也会报 SSL certificate problem, verify that the CA cert is OK
错误。
问题的缘由有不少,这里只列举一二。
在验证服务器证书时,找不到CA证书,若是正确设置了 cainfo 或 capath 参数且 CA 证书已是 rootCA,依然出错,那么多是证书生成的时候出错,再从新生成一个;若是 CA 证书由一个中间证书签发,rootCA 签发中间证书,那么若是服务器没有提供中间证书,在验证过程当中,openssl 在造成完整的证书链也会报这个错误,因此 cat intermediate.crt >> domain.crt
将全部中间证书与rootCA证书捆绑在一块儿。
curl_easy_setopt - set options for a curl easy handle
curl_easy_setopt
ssl介绍以及双向认证和单向认证原理
how to install curl and libcurl
OpenSSL 1.0.2h generates libss.so.1.0.0 instead of libssl.so.1.0.2
CURL使用SSL证书访问HTTPS
HowTo: Create CSR using OpenSSL Without Prompt (Non-Interactive)
curl: (60) SSL certificate : unable to get local issuer certificate