SSL 认证

可以将 SSL 服务器与客户端之间的通信配置为使用单向或双向 SSL 认证。

单向 SSL 认证一般是客户端利用服务器传过来的信息验证服务器的合法性,服务器的合法性包括:证书是否过期,发行服务器证书的 CA 是否可靠,发行者证书的公钥能否正确解开服务器证书的“发行者的数字签名”,服务器证书上的域名是否和服务器的实际域名相匹配。

双向 SSL 认证则除了需要对服务器的合法性进行认证,还需要按照单向 SSL 认证方法对客户端的合法性进行认证。

在金融支付过程中,对安全要求级别比较高的接口,不仅要验证签名,还要进行双向验证 SSL 证书,因此有些就需要安装在服务开通之后第三方给我们发送的安全证书了。

为了便于更好的认识和理解 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 选项有以下几个:

  • CURLOPT_SSL_VERIFYPEER: cURL 是否验证对等证书(peer's certificate),值为 1,则验证,为 0 则不验证。要验证的交换证书可以在 CURLOPT_CAINFO 选项中设置,或在 CURLOPT_CAPATH中设置证书目录。
  • CURLOPT_SSL_VERIFYHOST:值为1 : cURL 检查服务器SSL证书中是否存在一个公用名(common name);值为2: cURL 会检查公用名是否存在,并且是否与提供的主机名匹配;0 为不检查名称。这里的 common name 是在创建证书过程中指定,例如 subj 选项值中的 /CN 值; openssl req -subj "/C=CN/ST=IL/L=ShenZhen/O=Tencent/OU=Tencent/CN=luffichen_server.tencent.com/emailAddress=luffichen@www.tencent.com" ...
  • CURLOPT_CAINFO:一个保存着1个或多个用来让服务端验证的证书的文件名。这个参数仅仅在和CURLOPT_SSL_VERIFYPEER一起使用时才有意义。
  • CURLOPT_CAPATH:一个保存着多个CA证书的目录。这个选项是和CURLOPT_SSL_VERIFYPEER一起使用的。

与 SSL 双向认证相关的 curl_easy_setopt 选项有以下几个:

  • CURLOPT_SSLCERT:客户端证书路径
  • CURLOPT_SSLCERTTYPE:证书的类型。支持的格式有"PEM" (默认值), "DER"和"ENG"。
  • CURLOPT_SSLKEY:客户端私钥的文件路径
  • CURLOPT_SSLKEYTYPE:客户端私钥类型,支持的私钥类型为"PEM"(默认值)、"DER"和"ENG"。
  • CURLOPT_KEYPASSWD:客户端私钥密码,私钥在创建时可以选择加密。
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不支持 https

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.

SSL certificate problem, verify that the CA cert is OK

CURLOPT_SSL_VERIFYPEER 为 1 时,表示启用了验证访问的服务器合法性,且必须设置 CURLOPT_CAINFOCURLOPT_CAPATH 其中一个,而 CURLOPT_SSL_VERIFYHOST 为 2 时,表示验证 CA 证书中的 common name 是否与访问的服务器域名是否一致。在测试的时候,需要记得为客户端侧机器添加相应的 host 域名 IP 解析,如果直接使用 IP 访问也会报 SSL certificate problem, verify that the CA cert is OK 错误。

curl: (60) SSL certificate : unable to get local issuer certificate

问题的原因有很多,这里只列举一二。

在验证服务器证书时,找不到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

使用 curl 进行 ssl 认证的更多相关文章

  1. Tomcat 实现双向SSL认证

    大概思路: 使用openssl生产CA证书,使用keytool生产密钥库 实验环境:RHEL6.4+Tomcat8 一.生成CA根证书,并自签名 1.生成CA密钥 # genrsa [产生密钥命令] ...

  2. java中 SSL认证和keystore使用

    java中 SSL认证和keystore使用 2013-10-12 11:08 10488人阅读 评论(0) 收藏 举报   目录(?)[+]     好久没用过SSL认证了,东西久不用,就有点生疏. ...

  3. 执行curl -sSL 提示curl: (35) SSL connect error

    今天,添加容器节点报错,执行如下 curl -sSL https://shipyard-project.com/deploy| ACTION=node DISCOVERY=etcd://192.168 ...

  4. RSA原理、ssl认证、Tomcat中配置数字证书以及网络传输数据中的密码学知识

      情形一:接口的加.解密与加.验签 rsa不是只有加密解密,除此外还有加签和验签.之前一直误以为加密就是加签,解密就是验签.这是错误的! 正确的理解是: 数据传输的机密性:公钥加密私钥解密是密送,保 ...

  5. Apollo单向SSL认证(1)

    参考链接:https://www.cnblogs.com/benwu/articles/4891758.html keytool -genkey -alias mybroker -keyalg RSA ...

  6. 执行curl 提示curl: (35) SSL connect error

    安装acme证书时,执行如下 curl https://get.acme.sh | sh 提示如下报错: curl: (35) SSL connect error curl -v 跟踪时 发现 NSS ...

  7. mosquitto SSL认证

    [11]MQTT mosquitto 双向SSL认证配置方式 [12]MQTT mosquitto 单向SSL认证的配置方式 Mosquitto服务器的搭建以及SSL/TLS安全通信配置(比较可信) ...

  8. mysql多实例安装与ssl认证

    mysql多实例安装有两种形式: 同一数据库版本的多实例安装. 不同数据库版本的多实例安装. 同一数据库的多实例安装: 在同一台机器上安装4台mysql数据库实例. 从官网下载MySQL5.6版本的二 ...

  9. SSL 认证之后,request.getScheme()获取不到https的问题记录

    通过浏览器输入https://www.xxx.com,request.getScheme()获取到的确实http而不是https通过request.getRequestURL()拿到的也是http:/ ...

随机推荐

  1. Python3 文件

    f=open('C:\\Users\\fengx\\Desktop\\sharing\\test.txt') 如果打开文件的格式不匹配,可能会报如下错: >>> open('C:\U ...

  2. CommonsChunkPlugin

    CommonsChunk 插件的作用就是提取代码中的公共代码,然后将公共模块打包到一个独立的文件中,以便在其它的入口和模块中使用,原理就是把多个入口共同的依赖都给定义成一个新入口 多种打包情况: 单一 ...

  3. org.apache.ibatis.binding.BindingException: Invalid bound statement (not found): cn.e3mall.search.mapper.ItemMapper.getItemList

    java.lang.RuntimeException: org.apache.ibatis.binding.BindingException: Invalid bound statement (not ...

  4. windows10下Kafka环境搭建

    内容小白,包含JDK+Zookeeper+Kafka三部分.JDK:1)   安装包:Java SE Development Kit 9.0.1      下载地址:http://www.oracle ...

  5. 虚拟机桥接模式联网方法,Xshell的连接与使用

    1.虚拟机的编辑中的虚拟网络编译器,新建一个VMnet0,选择桥接模式,选择上网时的网卡. 2.虚拟机 -> 设置 -> 网络适配器,选择启动时连接,桥接模式,复制物理网络连接状态. 3. ...

  6. 【阿里聚安全·安全周刊】女主换脸人工合成小电影|伊朗间谍APP苹果安卓皆中招

    本周的七个关键词: 人工智能 丨 HTTP链接=不安全链接 丨  滑动验证码 丨 伊朗间谍APP 丨 加密挖矿 丨  Android应用测试速查表 丨 黑客销售签名证书 -1-   [人工智能]女主换 ...

  7. [.net 面向对象程序设计深入](31)实战设计模式——使用Ioc模式(控制反转或依赖注入)实现松散耦合设计(1)

    [.net 面向对象程序设计深入](31)实战设计模式——使用IoC模式(控制反转或依赖注入)实现松散耦合设计(1) 1,关于IOC模式 先看一些名词含义: IOC: Inversion of con ...

  8. Tomcat线程池配置

    简介  线程池作为提高程序处理数据能力的一种方案,应用非常广泛.大量的服务器都或多或少的使用到了线程池技术,不管是用Java还是C++实现,线程池都有如下的特点:线程池一般有三个重要参数: 最大线程数 ...

  9. [Swift]LeetCode145. 二叉树的后序遍历 | Binary Tree Postorder Traversal

    Given a binary tree, return the postorder traversal of its nodes' values. Example: Input: [1,null,2, ...

  10. 浏览器与服务端请求响应流程与HTTP协议

    浏览器与服务端请求响应流程图: 1.HTTP概要 1.1. 定义 HTTP(HyperText Transfer  Protocol,超文本传输协议)最早就是计算机与计算机之间沟通的一种标准协议,这种 ...