一、算法原理概述
证书的组成
首先,有一个权威的证书签发机构,称为CA——全球就那么几个公司比较权威啦,这个机构,先用RSA产生一对公私钥。
私钥自己留着藏起来,你要是能偷到手就厉害了。
然后用自己的私钥对自己的公钥进行签名,生成所谓的数字证书。
这个过程大概是这样的:
先生成一个文件,文件内容大概是这样的:
- 公钥内容
- 签发者ID—-谁签发的证书
- Subject—-也就是这个证书签发给谁。这里subject和签发者ID相同。
- 有效期
- 其他信息
以上内容都是明文。我们称为内容P。
然后使用hash算法,对内容P进行hash计算,得到一个hash值H。
然后使用签发机构的私钥对H进行RSA加密,得到签名信息S。这个步骤称为签名,就是用私钥对某公开内容的hash值进行加密。
然后将P,S连成一个文件,这个文件就是所谓的数字证书了。所以数字证书里,包括证书持有者的身份信息,证书信息,证书持有人的公钥,以及签名信息。
证书的验证
现在假设某人得到了这个证书,如何确认这个证书属于谁的呢?
我们看数字证书里有些什么?可以得到P,可以得到S。
我们用同样的hash算法对P进行hash计数,得到一个hash值H1。
P里有公钥,签发者ID,Subject,有效期,及其他信息。我们用公钥解密S,得到了一个值H’。
这个H‘就是制作数字证书的时候,用私钥对S加密的H。
现在对比H’和H1是否相等,如果相等,那么就证明这个证书是有签发者签发给subject的证书。否则就说明:1.内容P被篡改过,或者2.证书不是由CA签发的。
这个是对自签发证书的验证过程。需要说明的是,这种自签发证书的验证不常使用,但如何验证证书的原理类似。
证书管理机构 - Certificate Authority
既然自己可以给自己签发证书,那黑客宣称自己是某著名CA,然后给自己签发一个证书。那验证者如何来验证这个证书是黑客自己的呢还是那个著名的CA呢?
如果仅仅按照上文所说的自签发证书验证过程来看,是无法确认身份的。这个问题,就是CA存在的意义了。
所谓全球权威的CA,就那么几个公司,这几个公司的证书,被各软件厂商设置成“可信任的根证书”了。至于这些CA是怎么把自己的数字证书交给软件厂商而且让他们信任自己,我也不知道。
如果你知道了,你就可以自己给自己签发一个证书,交给微软的IE,或者firefox等,让他们把你的证书嵌入到软件里去。这样一来,你就成了全球权威的CA之一了!
现在知道了,自签发的数字证书,要被各软件信任,是不容易的。一旦CA的根证书存在用户的系统了,就可以用这个根证书来验证其他证书了。并用被验证过的证书来认证身份。
我们举一个例子,说明数字证书用来进行身份认证,就是https连接某网站的时候的身份认证过程。
首先,某网站当然是一个web服务器,它要有一个数字证书。这个证书,要么是自己签发的,要么是由第三方签发的,一般这个第三方是全球权威的CA。
IE或者firefox用https连上web server,这个时候,IE或者firefox最担心的是这个web server是冒充的网站,比如我登录某银行网站,结果连上了一个钓鱼网站,用户也没有发现,就在这个钓鱼网站做的和真网站一样的页面里,输入了自己的用户名密码,岂不是就这么泄露了机密信息么?
那么怎么确认这个网站是正确的呢?这个就需要浏览器要求web server提供自己的数字证书来证明自己的身份。
网站的身份是什么?域名,比如https://www.zhihu.com。你如果打了https://www.zihu.com,也出现跟知乎一样的网站,浏览器没有警告你说此网站不合法,结果你输入了自己的用户名和密码登录,你觉得这个是什么问题?
继续刚才的话题。浏览器要求web server的证书来证明我在浏览器中输入的网址,并没有连接到错误的网站上去,于是web server把自己的数字证书传给浏览器。浏览器对之进行验证,确认此网站的身份。
请注意两个情况的区别:一,我在浏览器输入https://www.zhihu.com,连接到了黑客的钓鱼服务器,而没有连接到真正的服务器;二,我在浏览器输入https://www.zihu.com,连接到了一个黑客的钓鱼服务器。
现在我们继续看这个数字证书怎么证明自己的身份。
假设数字证书是第三方签发的,但这个第三方却不权威。也就是说,给网站签发证书的这个CA,没有被IE等浏览器认可。
x.509证书结构的RFC文档
1 | Certificate ::= SEQUENCE { |
X.509证书的结构解读
X.509证书基本部分- 版本号:标识证书的版本(版本1、版本2或是版本3)
- 序列号:标识证书的唯一整数,由证书颁发者分配的本证书的唯一标识符
- 签名:用于签证书的算法标识,由对象标识符加上相关的参数组成,用于说明本证书所用的数字签名算法。例如,SHA-1和RSA的对象标识符就用来说明该数字签名是利用RSA对SHA-1杂凑加密。
- 颁发者:证书颁发者的可识别名(DN)
- 有效期:证书有效期的时间段。本字段由”Not Before”和”Not After”两项组成,它们分别由UTC时间或一般的时间表示(在RFC2459中有详细的时间表示规则)
- 主体:证书拥有者的可识别名,这个字段必须是非空的,除非你在证书扩展中有别名
- 主体公钥信息:主体的公钥(以及算法标识符)
- 颁发者唯一标识符:标识符—证书颁发者的唯一标识符,仅在版本2和版本3中有要求,属于可选项
- 主体唯一标识符:证书拥有者的唯一标识符,仅在版本2和版本3中有要求,属于可选项。
X.509证书扩展部分
- 发行者密钥标识符:证书所含密钥的唯一标识符,用来区分同一证书拥有者的多对密钥
- 密钥使用:一个比特串,指明(限定)证书的公钥可以完成的功能或服务,如:证书签名、数据加密等。如果某一证书将 KeyUsage 扩展标记为“极重要”,而且设置为“keyCertSign”,则在 SSL 通信期间该证书出现时将被拒绝,因为该证书扩展表示相关私钥应只用于签写证书,而不应该用于 SSL
- CRL分布点:指明CRL的分布地点
- 私钥的使用期:指明证书中与公钥相联系的私钥的使用期限,它也有Not Before和Not After组成。若此项不存在时,公私钥的使用期是一样的
- 证书策略:由对象标识符和限定符组成,这些对象标识符说明证书的颁发和使用策略有关
- 策略映射:表明两个CA域之间的一个或多个策略对象标识符的等价关系,仅在CA证书里存在
- 主体别名:指出证书拥有者的别名,如电子邮件地址、IP地址等,别名是和DN绑定在一起的
- 颁发者别名:指出证书颁发者的别名,如电子邮件地址、IP地址等,但颁发者的DN必须出现在证书的颁发者字段
- 主体目录属性:指出证书拥有者的一系列属性。可以使用这一项来传递访问控制信息。
二、总体结构
先使用File类得到证书文件
然后转成InputStream,
使用CertificateFactory的getInstance方法(传入一个值为“x.509”的CERT_TYPE字符串)
生成具体的X509Certificate 类型的oCert
再调用oCert的方法打印出证书的各个字段值,或者直接使用oCert的toString方法使用自带的输出格式显示证书
三、数据结构
使用了java的java.security.cert.X509Certificate类
1 |
|
CERT_PATH证书路径
CERT_TYPE证书类型
CertificateFactory cf证书工厂,一个生成证书对象的工厂类
X509Certificate oCertx.509类型证书的具体类
PublicKey publicKeyx.509证书公钥的base64编码后的结果
四、运行结果
学校的iNode的证书inode.cer


1 | 【输出证书信息】: |
百度的证书baidu.cer
1 | 【输出证书信息】: |
五、源代码
1 | import java.io.File; |
六、参考资料
RFC2459
X.509证书结构简介
数字证书工作原理