ssl证书openssl.docx
- 文档编号:28366024
- 上传时间:2023-07-10
- 格式:DOCX
- 页数:21
- 大小:620.75KB
ssl证书openssl.docx
《ssl证书openssl.docx》由会员分享,可在线阅读,更多相关《ssl证书openssl.docx(21页珍藏版)》请在冰豆网上搜索。
ssl证书openssl
ssl证书&&openssl
序
以一个问题来开始此篇文章的讲解。
你知道我们通常访问的https是如何保障你的安全的吗?
你是否会想到加密、认证和数字证书?
那么
加密:
如何加密,怎么保证数据不被泄露?
认证:
誰认证誰,如何进行认证?
数字证书:
数字证书是何物?
为什么有这个东西?
作用是什么?
本文主要简单地讲述证书及openssl的使用,让我们带着这些问题开始文章的旅程。
一、加密和算法
1.散列(hash)
Hash,一般翻译做"散列",也有直接音译为"哈希"的,就是把任意长度的输入,通过散列算法,变换成固定长度的输出,该输出就是散列值。
常用的散列函数是SHA1和MD5。
哈希是单向的,不可通过散列值得到原文;
不同的内容做散列计算,计算出的散列值为相同的概率几乎等于0;
哈希主要用在:
文件校验、数字签名、快速查找等。
例如:
图1文件校验(散列应用)
图1说明了如何校验文件是否被修改,但是如果中间存在一个攻击者,截获报文后,修改下文件内容,一样可以计算出一个散列值,所以是不够安全的。
图2则使用了密钥化散列信息认证码(HMAC,Keyed-hashMessageAuthenticationCode),通过加入共享密钥(仅用户A和用户B知道密钥),在计算散列,这样来保证数据是完整的,不被修改的。
图2文件校验(HMAC)
2.对称加密(SymmetricCryptography)
需要对加密和解密使用相同密钥的加密算法。
由于其速度快,对称性加密通常在消息发送方需要加密大量数据时使用。
但是管理密钥不方便,要求共享密钥。
如果N个人相互之间都要用对称加密进行通讯,则每个人维护的密钥是N-1个。
目前流行的对称加密算法有AES、DES、3DES、Blowfish、RC2、RC4、RC5等等。
3.非对称加密(AsymmetricCryptography)
与对称加密算法不同,非对称加密算法需要两个密钥:
公开密钥(publickey)和私有密钥(privatekey)。
公开密钥与私有密钥是一对,如果用公开密钥对数据进行加密,只有用对应的私有密钥才能解密;如果用私有密钥对数据进行加密,那么只有用对应的公开密钥才能解密。
因为加密和解密使用的是两个不同的密钥,所以这种算法叫作非对称加密算法。
非对称加密算法的优点是密钥管理很方便,缺点是速度慢。
通常来讲,公钥是每个人都能得到的,私钥是只有自己持有;
A与B之间进行通信,安全的方式:
1.A给B发送消息,使用B的公钥进行加密,然后发给B,只有B用私钥才能解密成明文;
2.B给A发送消息,使用A的公钥进行加密,然后发给A,只有A用私钥才能解密成明文;
A获取B的公钥,必须是安全的方式;B获取A的公钥,也必须是安全的方式;
一个例子:
4.数字签名(DigitalSignature)
现实生活中,我们用签名来证明某个东西是与签名者相关的,是不可否认的,不可伪造的;
在虚拟世界里,我们有数字签名来帮助证明某个文档是你创建的,或者是你认可的。
数字签名所用的技术是散列和非对称加密。
基于前面非对称加密的介绍,对签名的信息进行散列计算,用私钥对这个散列值进行加密;这样就得到一个签名。
图3签名示例
当用户B比对散列值3与散列值2是否相同,如果相同则认为是A签名的,否则不是。
二、数字证书
如果现实生活中是用身份证来证明身份,那么在虚拟世界中,则会使用数字证书来证明身份。
并不是每个人都需要用数字证书来证明身份,那么什么情况下,会使用数字证书来证明身份呢?
普通用户一般情况下,不需要证明自己的身份,大部分网站不关心是谁访问了网站,现在的网站只关心流量啊~反过来,网站就需要证明自己的身份了。
比如你想要提交信用卡信息给预定航班的网站,那么你如何确定你正在访问的网站就是你所想要访问的那个呢?
现在钓鱼网站很多的。
比如你想访问的是“”,但其实你访问的是“”,所以在提交自己的信息之前你需要验证一下网站的身份,要求网站出示数字证书。
一般正常的网站都会主动出示自己的数字证书。
由于证书在网页浏览中最为常见,所以我下面举的例子都是基于浏览器的。
1.数字证书的构成
我们的身份证是由公安机关颁发的,并加有很多防伪技术,不能伪造(或者说很难)。
同样的,数字证书也有专门的发证机关(CertificateAuthority,简称CA,其实是一些商业公司啦)。
比较常见的发证机关是VeriSign。
数字证书的发证机关会对自己发放的证书加上自己的数字签名,以保证证书不能被伪造。
那数字证书到底包含了些什么呢?
1.持有者姓名(CommonName)
2.发证机关(Issuer)
3.有效日期(Validity)
4.证书持有人的公钥(Subject’sPublicKeyInfo)
5.扩展信息(Extension)
6.用发证机关对该证书的数字签名(CertificateSignature)
基本信息就这些了(这些信息会在后面的章节有所解释),为了更清晰的说明问题,来几张截图(火狐->工具->选项->高级->证书->查看证书):
图4证书信息
从图4我们可以看到,Certificate(证书)和Signature(签名)是分开的,但其实这个Signature也是证书的一部分。
可以这么理解,数字证书包含证书主体和数字签名。
证书中的签名是对证书主体的签名。
2.如何验证数字证书
当浏览器拿到一个数字证书:
1.先看发证机关(图5),主要是看以下三个:
OrganizationName(O),OrganizationalUnitName(OU),CommonName(CN)
2.找到相应的发证机关的证书,获得发证机关的公钥,用此公钥解密被加密的SHA1,这样就获得了此证书的SHA1值,我们称它为Hash1(图6、图7)。
3.浏览器用SHA1算法对此证书重新计算一遍SHA1,获得Hash2。
4.然后比较Hash1和Hash2是否相等。
如果相等就证明这张证书是由发证机关颁发的,并且没有被篡改过。
图5服务器的公钥证书
图6签名过程
图7验证Server的证书
3.验证证书持有者
经过上述的证书验证后,可以认为证书没问题,是可靠的。
但是还需要做一步,需要查看下发送者是否是证书的持有者(也就是通常意义上的身份证上的照片是否是本人,看完证件,还要比对下脸)。
通过证书里的公钥加密一段信息发送给证书持有者,如果对方能发送回来(加密的或者明文),说明对方是证书的持有者(也即,对方有对应的私钥)。
4.核对名字
通常对于用证书来做web服务器的应用来说,证书中的名字(Commonname)很重要,一般与根域名相等。
如果不相等,则认为证书存在问题。
5.证书的级联
所有的证书都是基于另一张证书(可信任证书)进行认证的。
换句话说,用一张已知合法的证书来证明另一张未知的证书。
发证机关的证书默认是可信任的,这些证书称之为“根证书”。
由于申请证书的人数众多,发证机关忙不过来,这时候需要一些代理来帮忙签发证书,代理可能也需要代理来帮忙签发证书。
这样就存在了层级关系:
图8级联证书
这里的”USERTrustLegacySecureServerCA”是由根证书”AddTrustExternalCARoot”签发的。
验证这张证书的时候,需要从下往上递归验证。
是否是CA证书,可以看下扩展信息中的”基本约束”,如下图:
图9查看是否是CA
三、SSL的基本原理
现在回到我们最原始的问题,由于Internet的架构问题,信息在网络上传输是很容易被别人获取的,那如何建立一个安全的传输网络呢?
前面我们讨论了很多保证信息安全的技术,而SSL就是建立在这些技术的基础上的一套协议,用来保证通信的安全。
SSL全称是SecureSocketsLayer,它是一种间于传输层(比如TCP/IP)和应用层(比如HTTP)的协议。
具体的SSL协议很复杂,我这里只讲一个大概。
最简单的方法来保证通信安全是用非对称加密。
我们前面讲过数字证书的认证,如果双方都认证了对方的数字证书,那么每次传输信息的时候都用对方的公钥加密,这样就只有对方能解密,从而保证了信息的安全。
但是对于日常应用(比如网页浏览)有两个问题:
1.非对称加密速度缓慢,消耗资源
如果客户端和服务器之间传输文件用非对称加密的话,速度一定慢的忍无可忍。
2.不可能要求每个用户都去申请数字证书
申请数字证书是一个相当麻烦的过程,要求每个上网的用户都拥有证书是不可能的事情。
SSL通过“握手协议”和“传输协议”来解决上述问题。
握手协议是基于非对称加密的,而传输协议是基于对称加密的。
根据不同的应用,SSL对证书的要求也是不一样的,可以是单方认证(比如HTTP,FTP),也可以是双方认证(比如网上银行)。
通常情况下,服务器端的证书是一定要具备的,客户端的证书不是必须的。
图10握手过程
Phase1:
图11阶段1
client_hello:
包括一个随机数和一系列的可支持的加密组件(以性能高到低的方式排列)
server_hello:
包含一个随机数和一个从客户端发来的组件中选择的加密组件
加密组件:
每个加密组件包含一个密钥交换算法、加密算法、MAC(消息认证码),例如:
TLS_RSA_WITH_AES_256_CBC_SHA256
密钥交换算法:
DH(Diffie-Hellman)算法、RSA(公钥/私钥)
Phase2(例如使用DH):
图12DH交换密钥
server_key_exchange中包括p、a、S1;
client_key_exchange中包括C1;
最后生成K是共用密钥。
Phase3:
客户端的认证:
服务器或许会请求客户端发送证书,如果客户端有,则发送证书,如果没有则发送一个no_certificate的警告信息。
如果发送了证书才会有certificate_verify,包括了客户端的认证,包括了一个之前握手消息的散列值。
Phase4:
客户端发送ChangeCipherSpec消息,通知SSL服务器后续报文将采用协商好的密钥和加密套件进行加密和MAC计算。
SSL客户端计算已交互的握手消息(除ChangeCipherSpec消息外所有已交互的消息)的Hash值,利用协商好的密钥和加密套件处理Hash值(计算并添加MAC值、加密等),并通过Finished消息发送给SSL服务器。
SSL服务器利用同样的方法计算已交互的握手消息的Hash值,并与Finished消息的解密结果比较,如果二者相同,且MAC值验证成功,则证明密钥和加密套件协商成功。
同样地,SSL服务器发送ChangeCipherSpec消息,通知SSL客户端后续报文将采用协商好的密钥和加密套件进行加密和MAC计算。
SSL服务器计算已交互的握手消息的Hash值,利用协商好的密钥和加密套件处理Hash值(计算并添加MAC值、加密等),并通过Finished消息发送给SSL客户端。
SSL客户端利用同样的方法计算已交互的握手消息的Hash值,并与Finished消息的解密结果比较,如果二者相同,且MAC值验证成功,则证明密钥和加密套件协商成功。
四、openssl开源库的使用(客户端)
openssl开源库的网址https:
//www.openssl.org/,包括源码、文档等内容。
这一节,我们主要使用的是ssl/tls库。
1.初始化
作为一个客户端,首先要初始化一个Context对象(一个SSL_CTX),这个对象是用来创建一个新的连接对象。
Context初始化,包括四个主要的部分,如下:
SSL_METHOD*meth;
SSL_CTX*ctx;
SSL_library_init();//初始化整个库,加载了一些openssl的算法等内容,只需要在程序启动的时候,初始化一次就可以了。
meth=SSLv23_method();//用SSLv2或者V3兼容的方式
ctx=SSL_CTX_new(meth);//创建一个Context对象
/*Loadourkeysandcertificates*/
if(!
(SSL_CTX_use_certificate_chain_file(ctx,keyfile)))//加载证书
berr_exit("Can’treadcertificatefile");
SSL_CTX_set_default_passwd_cb(ctx,password_cb);//如果密码是加密过的,password_cb是个回调函数,可以还原密码
if(!
(SSL_CTX_use_PrivateKey_file(ctx,keyfile,SSL_FILETYPE_PEM)))//加载私有密钥
berr_exit("Can’treadkeyfile");
/*LoadtheCAswetrust*/
if(!
(SSL_CTX_load_verify_locations(ctx,CA_LIST,0)))//加载可信任的CA证书
berr_exit("Ca’treadCAlist");
如果一个client要去执行认证,则需要加载自己的public/privatekey对儿和相关证书。
SSL_CTX_use_certificate_chain_file用来加载CA证书;
SSL_CTX_use_PrivateKey_file用来加载私钥,通常密码是加密的,可以通过SSL_CTX_set_default_passwd_cb回调函数来获取密码。
加载根CA列表,如果你要认证对端,则需要知道CA,加载函数:
SSL_CTX_load_verify_locations
2.握手处理
SSL连接的第一步就是要执行SSL握手过程。
握手认证server(可选的认证client),并且建立关键材料用来保护后续的数据。
SSL_connect()函数用来执行SSL的握手协议。
如果使用阻塞协议,SSL_connect会一直阻塞,直到握手完成,或者返回一个错误。
SSL_connect返回1表示成功,0或者负数表示一个错误。
代码如下:
sock=tcp_connect(host,port);//假设tcp_connect是用来建立一个tcp连接的函数
ssl=SSL_new(ctx);//初始化TLS/SSL
sbio=BIO_new_socket(sock,BIO_NOCLOSE);//创建一个BIO对象,关联到TCPsocket
SSL_set_bio(ssl,sbio,sbio);//将ssl关联到BIO对象上
if(SSL_connect(ssl)<=0)//这里执行握手
berr_exit("SSLconnecterror");
3.检查server的证书
X509*peer;
charpeer_CN[256];
if(SSL_get_verify_result(ssl)!
=X509_V_OK)//对端发来的证书验证,如果不是X509
berr_exit("Certificatedoesn’tverify");
/*Checkthecommonname*/
peer=SSL_get_peer_certificate(ssl);//提取server的证书
X509_NAME_get_text_by_NID(X509_get_subject_name(peer),NID_commonName,peer_CN,256);//获取CommonName
if(strcasecmp(peer_CN,host))
err_exit("Commonnamedoesn’tmatchhostname");
4.读写数据
SSL_write()函数用来发送数据到对端,像write()一样使用。
只是传的参数是SSL对象而不是文件描述符。
在阻塞的模式,SSL_write()不会返回,直到数据都发送完,或者一个错误返回,然而write可能只写部分数据。
注意:
SSL_MODE_ENABLE_PARTIAL_WRITE标记使能部分写的功能。
代码如下:
r=SSL_write(ssl,request,request_len);//写数据,数据在request中,长度是request_len
switch(SSL_get_error(ssl,r)){
caseSSL_ERROR_NONE:
if(request_len!
=r)
err_exit("Incompletewrite!
");
break;
default:
berr_exit("SSLwriteproblem");
break;
}
SSL_read()用来读取数据,就像read一样,我们选择合适的参数传给SSL_read()。
SSL_read返回读到的数据长度。
如果不存在数据可读,则SSL_read是阻塞的,会一直等待。
r=SSL_read(ssl,buf,BUFSIZZ);//读取数据
switch(SSL_get_error(ssl,r)){
caseSSL_ERROR_NONE:
len=r;
break;
caseSSL_ERROR_ZERO_RETURN:
gotoshutdown;
caseSSL_ERROR_SYSCALL:
fprintf(stderr,"SSLError:
Prematureclose0);
gotodone;
default:
berr_exit("SSLreadproblem");
}
//这里对数据进行处理
例子中使用函数SSL_get_error()来替代errno,SSL_get_error()检查返回值,并且指出是否错误发生了,并且错误是什么。
5.关闭Closure/shutdown/cleanup
TCP使用FIN标记来说明发送者已经发完所有的数据。
SSLv2简单的允许任何一方使用一个TCPFIN来终止SSL连接。
这会导致“截断攻击”:
攻击者通过简单地伪造TCPFIN来使看起来消息是短的。
除非受害者有某种方式知道消息的长度。
为了避免这种情况,SSLv3引进了一个close_notify警告。
close_notify是一个SSL消息(因此是安全的),但是不是数据流本身的一部分,不背应用所看到。
当发送完close_notify后,不会再有数据会被发送。
因此,SSL_read返回0,说明socket被关闭了,已经收到了close_notify消息。
如果client先收到一个FIN,则认为是一个“过早关闭”。
如果我们读到SSL_read返回0,没有任何错,则我们需要发送close_notify到server端(通过SSL_shutdown()来发送)。
SSL_shutdown()返回1表示完全关闭,0表示不完全关闭,-1是出现一个错误。
当收到服务器发来的close_notify,唯一可能出错的是发送我们的close_notify,否则SSL_shutdown总是会成功。
代码片段(client):
while
(1)
{
r=SSL_read(ssl,buf,BUFSIZZ);
switch(SSL_get_error(ssl,r))
{
caseSSL_ERROR_NONE:
//未出错
len=r;
break;
caseSSL_ERROR_ZERO_RETURN:
//未出错,我们已经收到close_notify
gotoshutdown;//这里去发送我们的close_notify
caseSSL_ERROR_SYSCALL:
fprintf(stderr,"SSLError:
Prematureclose\n");//收到一个“过早关闭”的信息
gotodone;
default:
berr_exit("SSLreadproblem");/*错误处理,这里是退出程序*/
}
/*数据处理*/
}
shutdown:
r=SSL_shutdown(ssl);//发送给server端一个close_nofity
switch(r)
{
case1:
break;/*Success*/
case0:
case-1:
default:
berr_exit("Shutdownfailed");
}
done:
SSL_free(ssl);/*释放资源*/
/*释放相关变量*/
五、openssl证书常用命令
x509证书一般会用到三类文,key,csr,crt。
Key是私用密钥openssl格,通常是rsa算法。
Csr是证书请求文件,用于申请证书。
在制作csr文件的时,必须使用自己的私钥来签署申,还可以设定一个密钥。
crt是CA认证后的证书文,(windows下面的,其实是crt),签署人用自己的key给你签署的凭证。
1.key的生成
opensslgenrsa-des3-outserver.key2048
这样是生成rsa私钥,des3算法,openssl格式,2048位强度。
server.key是密钥文件名。
为了生成这样的密钥,需要一个至少四位的密码。
可以通过以下方法生成没有密码的key:
opensslrsa-inserver.key-outserver.key
server.key就是没有密码的版本了。
这种没密码的私钥这种用法挺多,比如webserver(lighttpd)这种方式,不可能每次启动server的时候,都要求用户输入密码,太过麻烦。
2.生成CA的crt
opensslreq-new-x509-keyserver.key-outca.crt-days3650
生成的ca.crt文件是用来签署下面的server.csr文件。
需要输入一堆信息,有一个Commonname通常是CA机构的域名(这里,我们可以自己取一个名字)。
3.csr的生成方法
opensslreq-new-keyserver.key-outserver.csr
需要依次输入国家,地区,组织,email。
最重要的是有一个commonname,可以写你的名字或者域名。
如果为了https申请,这个必须和域名吻合,否则会引发浏览器警报。
生成的csr文件交给CA签名后形成服务端自己的证书。
注意Commonname与CA的Commonname要不一样,否则会校验失败。
4.crt生成方法
CSR文件必须有CA的签名才可形成证书,可将此文件发送到verisign等地方由它验证,要交一大笔钱,何不自己做CA呢。
opensslx509-req-days3650-inserver.csr-CAca.crt-CAkeyserver.key-CAcreateserial-outserver.crt
输入
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- ssl 证书 openssl