玩玩数字证书

最近在学校做了个小项目, 计划使用SSL实现服务器与客户端的双向认证,却因各种理由、借口而废弃。在做这个小项目之前,我自以为只要了解过相关知识,到做起项目来就能较快的掌握那些知识了,但我想我现在之只能说是听说过SSL以及数字证书的相关绯闻罢了。真的是不做不知道,做了吓一跳。在真正用代码实现自己的猜想之前,切忌说自己有多大多大的把握。

原计划使用Mina实现TSL/SSL双向认证,所以就上网搜了些相关API的使用案例,于是便开始了我的玩数字证书以及被数字证书玩的历程,思维不严谨,有不对的地方,还望指教。

由于我对Mina以及SSL原理的理解有限,所以本文将不对其原理做详细介绍,但提供了验证我的猜想而使用的代码, 本文所讲的都只是对证书进行的操作,代码上不做改动(证书库文件路径以及访问证书库的口令除外),修改后的证书库文件直接将原来的替换即可,也不对各API做介绍,对Mina实现通信的方式以及怎么实现TSL/SSL认证有疑问的请参考一下链接:
http://mzhx-com.iteye.com/blog/946558
http://sundoctor.iteye.com/blog/579662



我在Mina中实现TSL/SSL双向认证的方式是:服务器端和客户端各自拥有自签名的私有密钥证书,并且互相交换公钥,通过对方公钥互相确认对方身份。客户端使用自己的私钥对数据进行加密,服务器端接到数据后使用客户端提供的公钥进行验证;同理,服务器端使用自己的私钥对数据进行加密,客户端接到数据后使用服务器端提供的公钥进行验证。客户端与服务器端的认证流程如下图所示。


要实现我所希望的TSL/SSL双向认证,则客户端以及服务器端都需要有一个保存自己证书的证书库(clientKeys.jks或serverKeys.jks)和一个用来保存对方证书的信任证书库(clientTrust.jks或serverTrust.jks),下文所说的证书库指的是前一类证书库。我的证书库构造如下图所示:

引用

keytool -genkey -alias server -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=evil, OU=evil.org, O=evil.org, L=HuNan, S=ChangSha, C=CH" -keypass server -storepass server -keystore serverKeys.jks

keytool -genkey -alias client1 -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=evil, OU=evil.org, O=evil.org, L=HuNan, S=ChangSha, C=CH" -keypass client -storepass client -keystore clientKeys.jks


keytool -export -alias server -file se.cer -keystore serverKeys.jks -storepass server
keytool -export -alias client1 -file ce1.cer -keystore clientKeys.jks -storepass client


keytool -import -file se.cer -keystore clientTrust.jks -alias server -keypass server -storepass client
keytool -import -file ce1.cer -keystore serverTrust.jks -alias client1 -keypass client -storepass server

看到客户端以及服务器端打印输出确认语句时,有点小得意。

但现在想到一个问题是,客户不能只有一个啊,同一个客户端也有可能被多个客户使用。于是,在原证书库基础上的客户端证书库里添加了一份证书,并公开给服务器,如下图所示:

引用

keytool -genkey -alias client2 -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=evil, OU=evil.org, O=evil.org, L=HuNan, S=ChangSha, C=CH" -keypass client -storepass client -keystore clientKeys.jks

keytool -export -alias client2 -file ce2.cer -keystore clientKeys.jks -storepass client

keytool -import -file ce2.cer -keystore serverTrust.jks -alias client2 -keypass client -storepass server


还是原来的代码,客户端以及服务器端各一条进程。经测试,服务器、客户端输出没问题。但后来仔细想了想,到底用了哪一份证书做了的认证,这个就不得而知了。

于是,继续。我把刚导入到服务器信任证书库的那份证书删掉,此时,证书库构造图如下:

引用
keytool -delete -alias client2 -keystore serverTrust.jks -storepass server

经测试,客户端以及服务器端依然能够输出确认语句。我了个去。同一个客户端只要一个客户通过了认证,其他的就不用了啊?难道通过这种方式实现双向认证,客户与客户端就只能一对一吗?试试用两个客户端去访问服务器,看看会是怎么个情况。
证书库构造图如下所示:

引用
keytool -genkey -alias server -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=evil, OU=evil.org, O=evil.org, L=HuNan, S=ChangSha, C=CH" -keypass server -storepass server -keystore serverKeys.jks
keytool -genkey -alias client1 -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=evil, OU=evil.org, O=evil.org, L=HuNan, S=ChangSha, C=CH" -keypass client -storepass client -keystore clientKeys1.jks
keytool -genkey -alias client2 -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=evil, OU=evil.org, O=evil.org, L=HuNan, S=ChangSha, C=CH" -keypass client -storepass client -keystore clientKeys2.jks

keytool -export -alias server -file se.cer -keystore serverKeys.jks -storepass server
keytool -export -alias client1 -file ce1.cer -keystore clientKeys1.jks -storepass client
keytool -export -alias client2 -file ce2.cer -keystore clientKeys2.jks -storepass client

keytool -import -file se.cer -keystore clientTrust1.jks -alias server -keypass server -storepass client
keytool -import -file se.cer -keystore clientTrust2.jks -alias server -keypass server -storepass client
keytool -import -file ce1.cer -keystore serverTrust.jks -alias client1 -keypass client -storepass server
keytool -import -file ce2.cer -keystore serverTrust.jks -alias client2 -keypass client -storepass server

此时,两个客户端以及服务器端都能通过认证并输出确认语句。接着,我再把服务器端的信任证书库里的client2删掉。

引用
keytool -delete -alias client2 -keystore serverTrust.jks -storepass server

此时,服务器的信任证书库中存在的client1证书对应的客户端能与服务器进行认证并通过;而client2则未能通过认证,其对应客户端没能打印出确认语句。

难道说,使用“客户端、服务器端各自拥有自己的私钥证书,并向对方公开公钥证书”——这种方式进行双向认证,每一个客户都必须要有自己的证书库,而不仅仅是一份证书。

看来,我得好好地去了解一下证书库与证书的关系了。

现在,回去看看一开始创建证书时所用到命令行语句
引用
keytool -genkey -alias server -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=evil, OU=evil.org, O=evil.org, L=HuNan, S=ChangSha, C=CH" -keypass server -storepass server -keystore serverKeys.jks

另外,上面用到的证书库以及证书都是用来测试的,一切都是已经安排好了的,但到了真正要去发布项目时,客户是位置的,所以证书也就还不能制作出来,得等有客户安装使用客户端了,才会使用证书。使用我这种方式实现双向认证的该如何设计?也许在客户端,我们可以让客户提交他们的证书库,而不是证书;但在服务器端,服务器需要的不是证书库啊。难不成要客户注册的时候提交证书,当使用客户端登录时提交证书库。显然,没有哪位客户愿意做这么麻烦的事,客户端包含一个空证书库,一并都只提交证书不就得了呗。那试试看,将客户端的证书库清空后再添加由其他证书库里导出的证书。
证书库构造图如下所示:

引用
keytool -genkey -alias server -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=evil, OU=evil.org, O=evil.org, L=HuNan, S=ChangSha, C=CH" -keypass server -storepass server -keystore serverKeys.jks
keytool -genkey -alias client -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=evil, OU=evil.org, O=evil.org, L=HuNan, S=ChangSha, C=CH" -keypass client -storepass client -keystore clientKeys.jks

keytool -delete -alias client -keystore clientKeys.jks -storepass client

keytool -genkey -alias client1 -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=evil, OU=evil.org, O=evil.org, L=HuNan, S=ChangSha, C=CH" -keypass client -storepass client -keystore clientKeys1.jks

keytool -export -alias client1 -file ce1.cer -keystore clientKeys1.jks -storepass client

keytool -import -file ce1.cer -keystore clientKeys.jks -alias client1 -keypass client -storepass client
keytool -import -file ce1.cer -keystore serverTrust.jks -alias client1 -keypass client -storepass server

一测试,客户端以及服务器端都没有输出确认语句,认证失败。
再来一个测试,上一个测试是用了两个证书库,这次用一个证书库,创建两份证书,只将第二份证书导入到服务器的信任证书库。证书库构造图如下所示,跟第三个测试有点类似:

引用
keytool -genkey -alias server -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=evil, OU=evil.org, O=evil.org, L=HuNan, S=ChangSha, C=CH" -keypass server -storepass server -keystore serverKeys.jks
keytool -genkey -alias client1 -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=evil, OU=evil.org, O=evil.org, L=HuNan, S=ChangSha, C=CH" -keypass client -storepass client -keystore clientKeys.jks
keytool -genkey -alias client2 -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=evil, OU=evil.org, O=evil.org, L=HuNan, S=ChangSha, C=CH" -keypass client -storepass client -keystore clientKeys.jks

keytool -export -alias server -file se.cer -keystore serverKeys.jks -storepass server
keytool -export -alias client1 -file ce1.cer -keystore clientKeys.jks -storepass client
keytool -export -alias client2 -file ce2.cer -keystore clientKeys.jks -storepass client

keytool -import -file se.cer -keystore clientTrust.jks -alias server -keypass server -storepass client
keytool -import -file ce2.cer -keystore serverTrust.jks -alias client2 -keypass client -storepass server

经测试,客户端以及服务器端都没有输出确认语句,认证失败。
再来一个测试,将客户端证书库中的第一份证书删掉,此时的证书库构造图如下所示:

引用
keytool -delete -alias client1 -keystore clientKeys.jks -storepass client

经测试,客户端以及服务器端也都没有输出确认语句,认证失败。

综合前面的测试来看,已经创建好一份证书的证书库若再去创建证书,得到的新证书则没有认证的功效。
引用
keytool -genkey -alias client1 -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=client1, OU=client1, O=client1, L=HuNan, S=ChangSha, C=CH" -keypass client -storepass client -keystore clientKeys.jks
keytool -genkey -alias client2 -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=client2, OU=client2, O=client2, L=HuNan, S=ChangSha, C=CH" -keypass client -storepass client -keystore clientKeys.jks

以上两条语句创建的证书条目都是PrivateKeyEntry类型的,为什么删掉第一条之后就不能进行认证了呢?郁闷,难道真的只有让客户提交证书库吗?

注:以上创建证书时用到的命令行语句中,证书库和证书的口令是相同的,这不是为了省事,你可以试试个性化一点,看看会是啥情况。



后话 写道


如果事先查看一下相关的概念,也就不会有这么一出笑话了。

引用
keytool -genkey -alias client1 -keysize 1024 -validity 3650 -keyalg RSA -dname "CN=owner,……" -keypass client -storepass client -keystore clientKeys.jks

此命令行语句执行结果产生一份keystore文件,后缀名为jks(java key store),当然后缀名随便起没问题,java提供了可以对该类文件进行读写操作的API,其用来保存、管理密钥以及证书。此证书库文件中保存了一份别名(alias)为client1的privatekeyentry类型的条目,该条目保存了一个加密的 PrivateKey,还随附一个相应公钥的证书链,该链的长度为1,也就是说含有一份证书,此证书由该条目签发。该条目还可以签发多份证书。该条目的拥有者使用私钥和证书链(链上的某一份证书即可)进行自验证。

引用
keytool -export -alias client1 -file ce1.cer -keystore clientKeys.jks -storepass client

导出的证书中只包含了对应条目的公钥,在通信过程中,其只能对使用对应条目的私钥加密的数据解密以验证身份,不能加密数据,所以上面有几个测试就很二了。





至此,还有两个问题还没搞明白,继续……





keytool工具使用详解 http://blog.csdn.net/guo_rui22/article/details/3947716

猜你喜欢

转载自jianweili007-163-com.iteye.com/blog/1473415