




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、用JSSE定制SSL连接JSSE( Java Security Socket Extension , Java 安全套接字扩展)是Sun 为了解决在Internet上的安全通讯而推出的解决方案。它实现了SSL和TSL (传输层安全)协议。在 JSSE中包含了数据加密,服务器验证,消息完整性和客户端验证等技术。通过使用JSSE,开发人员可以在客户机和服务器之间通过TCP/IP协议安全地传输数据。这篇文章主要描述如何使用JSSE接口来控制SSL连接。首先我通过一个简单的客户机/服务器程序来介绍如何利用JSSE进行编程。当建立客户端时,我们需要配置KeyStore 和 TrustStore 文件,
2、这样在程序中我们才可以从客户端的文件系统中加载它们。然后文章将讨论授权和身份验证方面的问题。通过从 KeyStore 中选择不同的授权,客户端程序可以连接到不同的服务器。运行例子程序下载例子程序在运行JSSE程序前,你需要正确安装 JSSE如果你安装了 J2SE 1.4 , JSSE已经被自动安装并配置好了, 如果你使用的是其他版本的Java ,你需要从官方站点上下载并安装JSSE, 安装过程这里就不再赘述。由于JSSE是在J2SE1.4中才成为标准的,并且 J2SE 1.4中的JSSE和以前的JSSE有一些细微的差别,而且文中的例子都是在J2SE 1.4 下调试的,因此推荐你使用J2SE 1
3、.4 运行这些例子。在深入介绍JSSE 之前,让我们来一个简单的客户机服务器程序,程序中包含了两个文件:SimpleSSLServer 和 SimpleSSLClient 。 在运行程序之前,你需要配置下面这些KeyStore 和 TrustStore文件: 一个客户端的 KeyStore文件,该文件中包含了对 Alice和Bob的授权。 一个服务器端的 KeyStore文件,该文件中包含了对 server的授权。 一个名为clientTrust 的客户端TrustStore 文件,该文件中包含了对 server的授权。 一个名为serverTrust的服务器端TrustStore 文件,该文
4、件中包含了对 Alice和Bob的授权。使用 keytool 可以帮助你创建这些文件(该工具在Java 的 bin 目录下) : 一个客户端的 KeyStore文件,该文件中包含了对 Alice和Bob的授权。在命令窗口中输入下面的命令:keytool -genkey -alias alice -keystore clientKeys窗口中会出现下面的提示,根据提示输入相应的信息:输入 keystore 密码: password您的名字与姓氏是什么?Unknown : Alice您的组织单位名称是什么?Unknown : Development您的组织名称是什么?Unknown : DCQ您所
5、在的城市或区域名称是什么?Unknown : ChongQing您所在的州或省份名称是什么?Unknown : ChongQing该单位的两字母国家代码是什么Unknown : CHCN=Alice, OU=Development, O=DCQ, L=ChongQing, ST=ChongQing, C=CH 正确吗?否 : 是输入的主密码(如果和keystore 密码相同,按回车):通过相同的方式可以建立对Bob 的授权。keytool -genkey -alias bob -keystore clientKeys注意在名字与姓氏一栏中填写Bob。在完成后可以键入下面的命令来检测是否已经正确
6、完成了授权。keytool -list -v -keystore clientKeys 一个服务器端的KeyStore文件,该文件中包含了对server的授权。在命令窗口中键入下面的命令:keytool -genkey -alias server -keystore serverKeys注意将密码设为password , 名字与姓氏设定为Server 。 完成授权后同样可以通过上面提到的命令来检测。 一个名为clientTrust 的客户端TrustStore 文件,该文件中包含了对server的授权。以及一个名为 serverTrust 的服务器端TrustStore 文件,该文件中包含了对
7、Alice 和 Bob 的授权。keytool -export -alias server -keystore clientKeys -file server.cer输入 keystore 密码: password保存在文件中的认证keytool -export -alias alice -keystore clientKeys -file alice.cer输入 keystore 密码: password保存在文件中的认证keytool -export -alias bob -keystore clientKeys -file bob.cer输入 keystore 密码: password保
8、存在文件中的认证这样 keytool 就在当前目录下创建了三个授权文件。然后我们将server.cer 文件导入到clientTrust 文件中;将alice.cer 和 bob.cer 导入到 serverTrust 文件中:keytool -import -alias server -keystore clientTrust -file server.cerkeytool -import -alias alice -keystore serverTrust -file alice.cerkeytool -import -alias bob -keystore serverTrust -fi
9、le bob.cer到目前为止,在当前目录下包含clientKeys , serverKeys , clientTrust , serverTrust 四个文件。完成了 KeyStore 和 TrustStore 的设置后就可以运行例子程序了。首先需要运行服务器程序:java -D.ssl.keyStore=serverKeys-D.ssl.keyStorePassword=password-D.ssl.trustStore=serverTrust-D.ssl.trustStorePassword=password SimpleSSLServer在命令行中我们指定了keyStore 属性为 s
10、erverKeys 。由于服务器程序需要获得客户端的授权信息,我们指定trustStore 为 serverTrust 。这样 SSLSimpleServer 就可以验证由SSLSimpleClient 提供的授权信息。当服务器程序成功运行后,你会看到下面的提示:SimpleSSLServer running on port 49152这时候服务器会等待客户端发出建立连接的申请。如果你希望在另一个端口上运行服务器程序,可以在命令中指定-port xxx 参数,其中xxx 是端口号。然后在另一个命令窗口中运行客户端程序:java -D.ssl.keyStore=clientKeys-D.ssl.
11、keyStorePassword=password-D.ssl.trustStore=clientTrust-D.ssl.trustStorePassword=password SimpleSSLClient客户端程序会试图向本机的49152 端口建立SSL 连接。同样你可以通过-port 参数指定端口号,也可以通过-host 参数指定主机名称。当连接成功后,会出现下面的提示信息:Connected同时在服务器端会提示用户客户端已经连接成功。SimpleSSLServer让 我 们 先 来 看 一 下 SimpleSSLServer 。 在 main ( ) 方 法 中 , 程 序 获 得 了
12、 缺 省 的 SSLServerSocketFactory 对象;然后利用SSLServerSocketFactory 创建一个SimpleSSLServer 对象,最后调用start ()方法启动SimpleSSLServer 对象。SSLServerSocketFactory ssf=(SSLServerSocketFactory)SSLServerSocketFactory.getDefault();SimpleSSLServer server=new SimpleSSLServer(ssf, port);server.start();由于服务器是在一个单独的线程中运行的,main ()
13、方法启动了服务器之后就退出了。start ()方法启动了一个新的线程,该线程执行run ()方法中的代码。在run ()方法中创建了一个SSLServerSocket 对象,然后设定服务器需要进行客户端验证:SSLServerSocketserverSocket=(SSLServerSocket)serverSocketFactory.createServerSocket(port);serverSocket.setNeedClientAuth(true);调用 run ()方法后,程序进入了一个死循环,等待客户端的连接申请。循环中的每个Socket 对应 一 个 HandshakeCompl
14、etedListener 对 象 ( 该 对 象 是 用 来 显 示 客 户 验 证 信 息 中 的 标 识 名 称 distinguished name 的)。 Socket 的 InputStream 对象被包装在一个InputDisplayer 对象中,这个 InputDisplayer 对象运行在另外一个线程中,用来将Socket 接收到的数据发送到System.out 。下面的代码是SimpleSSLServer 中的主循环体:while (true) String ident=String.valueOf(id+);/ 监听连接请求.SSLSocket socket=(SSLSoc
15、ket)serverSocket.accept();/ 通过使用HandshakeCompletedListener 对象 , 程序进行授权验证.HandshakeCompletedListener hcl=new SimpleHandshakeListener(ident);socket.addHandshakeCompletedListener(hcl);InputStream in=socket.getInputStream();new InputDisplayer(ident, in);程 序 中 的 SimpleHandshakeListener 类 实 现 了 HandshakeC
16、ompletedListerner 接 口 。 在 SimpleHandshakeListener 类中实现了 handshakeCompleted ()方法,该方法在 SSL握手阶段完成后 将被JSSE调用。它将显示出客户端的标识名称:class SimpleHandshakeListener implements HandshakeCompletedListenerString ident;/* 构造函数.*/public SimpleHandshakeListener(String ident)this.ident=ident;/*当SSL握手过程完成后该方法被激活.*/public v
17、oid handshakeCompleted(HandshakeCompletedEvent event) / 显示授权信息.try X509Certificatecert=(X509Certificate)event.getPeerCertificates()0;String peer=cert.getSubjectDN().getName();System.out.println(ident+": Request from "+peer);catch (SSLPeerUnverifiedException pue) System.out.println(ident+&q
18、uot;: Peer unverified");用红色 字体 表示的 两行 代码 是这段 代码 的核心 : getPeerCertificates ()方法返回 一个X509Certificated 对象的数组。这些X509Certificated 对象创建了客户端的身份标识。在数组中的第一个元素是客户端的验证信息,而最后一个通常是 CA验证。当我们有了客户端的验证信息后。我们可以得到其中的标识名称,并将它传送到System.out 。SimpleSSLClientSimpleSSLClient 类比较简单,但是在后面的一些比较复杂的例子中的类会继承该类。在getSLLSocketF
19、actory ()方法中,程序返回缺省的工厂类:protected SSLSocketFactory getSSLSocketFactory()throws IOException, GeneralSecurityExceptionreturn (SSLSocketFactory)SSLSocketFactory.getDefault();在 runClient() 方法中,程序处理了输入参数后,获得SSLSockFactory 对象,调用connect ()方法连接到服务器程序。在connect( ) 方法中, 程序首先创建一个SSLSocket 对象, 然后调用SSLSocket对象的 s
20、tartHandshang ()方法启动和服务器端的握手过程。当握手过程完成后,会触发一个HandshakeCompletedEvent 事件。在服务器端的HandshakeCompletedListener 对象会处理这个事件。事实上,JSSE 可以自动启动握手过程,但是必须是在第一次有数据通过Socket 传输的情况下。由于在例子程序中,直到用户在键盘上输入信息后才会有数据通过Socket 传输, 而我们希望服务器端及时报告连接情况,因此我们用startShake ()方法来手工激活握手过程。public void connect(SSLSocketFactory sf) throws I
21、OExceptionsocket=(SSLSocket)sf.createSocket(host, port);try socket.startHandshake();catch (IOException ioe) / 握手失败. 关闭连接.try socket.close();catch (IOException ioe2) / 忽略该错误.socket=null;throw ioe; SimpleSSLClient 类中的 transmit ()方法也很简单。首先程序将输入流包装到一个Reader 对象中,然后将输出流包装到一个Writer 对象中;最后将数据流输出到Socket :boo
22、lean done=false; while (!done) String line=reader.readLine(); if (line!=null) writer.write(line);writer.write('n');writer.flush();else done=true;定制 KeyStore 和 TrustStore还记得我们是如何运行客户端的吗?我们需要在命令行中指定keyStore, keyStorePasword,trustStore 和 trustStorePassword 参数,以至于整个命令显得过于冗长。事实上你可以在程序中指 定 KeyStor
23、e 和 TrustStore ,后面的例子中将告诉你如何实现这一点。同时在例子中还会演示如何配 置多个 SSLSocketFactory 对象, 其中每个SSLSocketFactory 对象对应不同的KeyStore 和 TrustStore设置。如果没有这种技术,在同一个虚拟机上的所有安全连接都只能使用同一个KeyStore 和TrustStore 。对于比较小的应用程序,这也许不会产生问题;但是对于那些比较大的应用程序来说, 这绝对是一个严重的缺陷。在下面的例子中,我们将使用CustomTrustStoreClient 来动态定义KeyStore 和 TrustStore 。首先让我们先
24、运行一下CustomTrustStoreClient :java CustomTrustStoreClient为什么运行CustomTrustStoreClient 时不需要指定KeyStore 和 TrustStore 参数呢?这是应为在CustomTrustStoreClient 的代码中指定了KeyStore ( ClientKeys )和 TrustStore ( ClientTruts )以及它们的密钥(password ) 。如果你想使用其他的KeyStore 、 TrustStore 或密钥,可以使用-ks 、-kspass 、 -ts 和 -tspass 参 数 来 指 定 。
25、 下 面 让 我 们 来 看 一 下 CustomTrustStoreClient 的 getSSLSocketFactory ()方法。该方法通过调用getTrustManager ()方法获得一个TurstManager对象数组,通过调用getKeyManagers ()方法获得一个KeyManager 对象数组。然后利用得到的TurstManager 和 KeyManager 对象数组构造一个SSLContext 对象,最后通过SSLContext 对象的getSocketFactory ()方法来配置 JSSE需要注意的是在调用SSLContext类的init ()方法时使用的参数。第
26、一个参数是 KeyManager对象数组。第二个参数和第一个参数类似,是 TrustManager数组。 如果前两个参数被设定为null ,程序将使用缺省的 KeyManager和TrustStore (缺省的KeyStore来源 于 系 统 属 性 中 的 .ssl.keyStore 和 .ssl.keyStorePassword 属 性 ; 缺 省 的TrustStore 来源于系统属性中的.ssl.trustStore 和 .ssl.trustStorePassword属性)。通过设定第三个参数可以指定JSSE中的随机数产生器(Random Number Generate, RNG)。由
27、于在SSL中随机数的产生是一个很敏感的问题,错误使用这个参数会导致安全连接变得不安全,因此 我在例子中使用了 null。这样程序将使用缺省的并且是安全的SecureRandom对象。protected SSLSocketFactory getSSLSocketFactory()throws IOException, GeneralSecurityException/ 调用 getTrustManagers 方法获得trust managersTrustManager tms=getTrustManagers();/ 调用 getKeyManagers 方法获得key managerKeyMan
28、ager kms=getKeyManagers();/ 利用 KeyManagers 创建一个SSLContext 对象 . 用获得的KeyStore 和/ TrustStore 初始化该SSLContext 对象 . 我们使用缺省的SecureRandom.SSLContext context=SSLContext.getInstance("SSL");context.init(kms, tms, null);/ 最后获得了SocketFactory 对象 .SSLSocketFactory ssf=context.getSocketFactory();return ss
29、f;下 面 让 我 们 看 一 看 CustomKeyStoreClient 类 中 的 getKeyMangers ( ) 方 法 是 如 何 初 始 化 KeyManagers对象数组的:protected KeyManager getKeyManagers()throws IOException, GeneralSecurityException/ 获得 KeyManagerFactory 对象 .String alg=KeyManagerFactory.getDefaultAlgorithm();KeyManagerFactory kmFact=KeyManagerFactory.ge
30、tInstance(alg);/ 配置 KeyManagerFactory 对象使用的KeyStoree. 我们通过一个文件加载/ KeyStore.FileInputStream fis=new FileInputStream(keyStore);KeyStore ks=KeyStore.getInstance("jks");ks.load(fis, keyStorePassword.toCharArray();fis.close();/ 使用获得的KeyStore 初始化 KeyManagerFactory 对象kmFact.init(ks, keyStorePassw
31、ord.toCharArray();/ 获得 KeyManagers 对象KeyManager kms=kmFact.getKeyManagers();return kms;首先的任务是获得一个KeyManagerFactory对象,但是你必须知道应该使用哪种算法。JSSE中提供 了 一 个 缺 省 的 KeyManagerFactory 算 法 ( 程 序 员 也 可 以 通 过 指 定 ssl.KeyManagerFacotory.algorithm 属性指定缺省算法)。获得 KeyManagerFactory 对象后就可以加载 KeyStore 文件了,程序过一个InputStream
32、对象将信息从文件送入KeyStore 对象中。在这个过程之前, KeyStore 对象需要知道输入流的格式(例子中我使用的是jks ) 和密钥。 当我们完成了KeyStore的加载后,我们就可以用它来初始化 KeyManagerFactory对象了。通常在 JSSE中,在KeyStore中的 所有证书使用和KeyStore 相同的密码,但是通过创建KeyManagerFactory 对象你可以突破这个限制。在初始化了 KeyManagerFactory 对象后,通常使用 getKeyManager ()方法来获得 KeyManager对象数 组。程序员通过使用和 getKeyMangers (
33、)方法类似的流程来初始化 TrustManager数组,这里我就不 再重复了。实现一个KeyManager 类到目前为止,我们已经知道如何在程序中动态生成KeyStore 和 TrustStore 了。最后一个例子将告诉你如何实现一个KeyManager 类。当运行前几个例子的时候,不知道大家是否注意到服务器端显示的授权的标识名称。在前面我们授权给了两个人:Alice和Bob,在运行程序时JSSE会从中任选一个。在我的计算机上JSSE选择的总 是 Bob, 或 许 在 你 的 计 算 机 上 情 况 会 有 所 不 同 。 下 面 让 我 们 来 看 一 看 最 后 一 个 例 子 程 序 :
34、 SelectAliasClient 。这个例子使你能够在运行客户端时使用指定的授权。例如你需要指定使用Alice的授权,由于Alice 的别名是alice ,你需要在命令窗口中键入下面的命令:java SelectAliasClient -alias alice当客户端和服务器端成功连接后,客户器端会出现下面的信息:1: New connection request1: Request from CN=Alice, OU= Development, O=DCQ, L=ChongQing, ST=ChongQing, C=CH为了使程序使用指定的授权,我们需要实现X509KeyManager接
35、口( X509KeyManager是JSSE中最常用的KeyManager) 。 X509KeyManager 接口在 SSL 握手阶段使用了几个方法来获得授权。下面是X509KeyManager接口获得授权的过程:1 .JSSE 调用 chooseClientAlias ()方法获得指定的授权。2 .chooseClientAlias ()方法调用X509KeyManager 接口的 getClientAlaises ()方法获得SSLSocket 对象使用的所有授权的别名,然后检查指定的授权别名是否有效。3 .JSSE 将别名作为参数调用 X509KeyManager接口的 getCert
36、ificateChain ()和 getPrivateKey()方法,这样就获得了指定授权的相关信息。在例子程序中,X509KeyManager接口的实现类是 AliasForcingKeyManager 。在该类中最重要的方法就是就是chooseClientAlias ()方法。下面是该方法的源代码:public String chooseClientAlias(String keyType, Principal issuers, Socket socket)/ 对于每一种类型的授权, 都需要调用一次getClientAliases() 方法来验/ 证别名是否有效.boolean alias
37、Found=false;for (int i=0; iString validAliases=baseKM.getClientAliases(keyTypei, issuers); if (validAliases!=null) for (int j=0; jif (validAliasesj.equals(alias) aliasFound=true; if (aliasFound) return alias;else return null;我们可以看到在程序中,chooserClientAlias ()方法实际上多次调用了getClientAliases ()方法,每次都针对不同的授权类型。AliasForingKeyManager 还实现了 X509KeyManager接口的其他五个方法,在这里就不再一一赘述了。然后我们就可以在程序中用AliasForingKeyManager 对象 来 替 代 KeyManager 对象了。在getSSLSocketFactory ()方法中,我们只需要将通过调用getKeyManagers ()方法获得Key
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 怀化学院《应用商务英语》2023-2024学年第二学期期末试卷
- 郑州财税金融职业学院《经贸英语阅读》2023-2024学年第二学期期末试卷
- 湖南水利水电职业技术学院《画法几何及工程制图》2023-2024学年第二学期期末试卷
- 山东信息职业技术学院《综合商务英语(3)》2023-2024学年第二学期期末试卷
- 吉首大学《针灸推拿技术》2023-2024学年第二学期期末试卷
- 湖北中医药高等专科学校《急诊医学Ⅰ》2023-2024学年第二学期期末试卷
- 房地产代理交易合同
- 水泥运输合同书
- 单位临时工雇佣劳务合同
- 寒暑假工劳务合同
- 21《庄子》二则 北冥有鱼 公开课一等奖创新教案
- JBT 5928-2014 工程机械 驱动桥 试验方法
- 小升初小学生简历模板
- 幼儿园中班绘本课件-《小金鱼逃走了》
- 2023-2024学年三年级下学期综合实践活动水果拼盘教案
- 2024国家粮食和物资储备局垂直管理系事业单位招聘笔试参考题库含答案解析
- DBJ∕T15-232-2021 混凝土氯离子控制标准
- 2024年安全员C3证考试题库附答案
- GB/T 43643-2024澳洲坚果
- 公车拍卖质量保证措施
- 输配电系统的监测与控制
评论
0/150
提交评论