用JSSE定制SSL连接http://www.yunyo ub ar.c o m/邮件群发
JSSE Java SecuritySocket Extension Java安全套接字扩展是Sun为了解决在Internet上的安全通讯而推出的解决方案。它实现了SSL和TSL传输层安全协议。在JSSE中包含了数据加密服务器验证消息完整性和客户端验证等技术。
通过使用JS SE开发人员可以在客户机和服务器之间通过T CP/IP协议安全地传输数据。这篇文章主要描述如何使用JSSE接口来控制SSL连接。
首先我通过一个简单的客户机服务器程序来介绍如何利用JSSE进行编程。当建立客户端时我们需要配置KeyStore和TrustStore文件这样在程序中我们才可以从客户端的文件系统中加载它们。然后文章将讨论授权和身份验证方面的问题。通过从KeyStore中选择不同的授权客户端程序可以连接到不同的服务器。
在运行JSSE程序前你需要正确安装JSSE。如果你安装了J2SE 1.4 JSSE已经被自动安装并配置好了如果你使用的是其他版本的Java你需要从官方站点上下载并安装JSSE安装过程这里就不再赘述。 由于JSSE是在J2SE 1.4中才成为标准的并且J2SE 1.4中的JSSE和以前的JSSE有一些细微的差别而且文中的例子都是在J2SE 1.4下调试的 因此推荐你使用J2SE 1.4运行这些例子。
在深入介绍JSSE之前让我们来一个简单的客户机服务器程序程序中包含了两个文件 S imp le S S LS erve r和S imp le S S LC lie nt。在运行程序之前你需要配置下面这些KeyStor e和Tres tStor e文件
·一个客户端的KeyStore文件该文件中包含了对Alic e和Bo b的授权。
·一个服务器端的KeyS tor e文件该文件中包含了对server的授权。
·一个名为c lientTrust的客户端TrustS tore文件该文件中包含了对server的授权。·一个名为serverTrus t的服务器端TrustSto re文件该文件中包含了对Alice和Bob的授权。
使用keytoo l可以帮助你创建这些文件该工具在Java的b in目录下
·一个客户端的KeyStore文件该文件中包含了对Alic e和Bo b的授权。
在命令窗口中输入下面的命令keytoo l-genkey-alias alice-keystore c lientKeys
窗口中会出现下面的提示根据提示输入相应的信息
输入keys tore密码 p ass word
您的名字与姓氏是什么
[Unknown] Alice
您的组织单位名称是什么
[Unknown] Development
您的组织名称是什么
[Unknown] DCQ
您所在的城市或区域名称是什么
[Unknown] ChongQ ing
您所在的州或省份名称是什么
[Unknown] ChongQ ing
该单位的两字母国家代码是什么
[Unknown] CH
CN=Alice,OU=Development,O=DCQ,L=ChongQ ing,S T=ChongQ ing,C=CH正确吗
[否] 是
输入的主密码
如果和keys tore密码相同按回车
通过相同的方式可以建立对Bob的授权。keytoo l-genkey-alias bob-keystore c lientKeys
注意在名字与姓氏一栏中填写Bob。在完成后可以键入下面的命令来检测是否已经
正确完成了授权。keytoo l-lis t-v-ke ysto re c lie ntKe ys????
·一个服务器端的KeyS tor e文件该文件中包含了对server的授权。
在命令窗口中键入下面的命令keytoo l-genkey-alias s erver-keystore serverKeys
注意将密码设为passwo rd名字与姓氏设定为Server。完成授权后同样可以通过上面提到的命令来检测。
·一个名为c lientTrust的客户端TrustS tore文件该文件中包含了对server的授权。以及一个名为serverTrus t的服务器端TrustSto re文件该文件中包含了对Alice和Bob的授权。keytool-export-alias server-keystore clientKeys -file server.cer
输入keys tore密码 p ass word
保存在文件中的认证keytoo l-export-alias alice-keystore clientKeys -file alice.cer
输入keys tore密码 p ass word
保存在文件中的认证keytoo l-export-alias bob-keystore clientKeys -file bob.cer
输入keys tore密码 p ass word
保存在文件中的认证
这样keytoo l就在当前目录下创建了三个授权文件。然后我们将serve r.cer文件导入到c lientTrust文件中将alice.cer和bob.cer导入到serverTruest文件中keytoo l-import-alias server-keystore c lientTrust -file server.cer
keytoo l-import-alia s alice-keystore serverTrust -file alice.cerkeytool-import-alias bob-keystore serverTrust-file bob.cer
到目前为止在当前目录下包含clientKeys serverKeys clientTrust serverTrust四个文件。完成了KeyStore和Trus tStore的设置后就可以运行例子程序了。首先需要运行服务器程序java-Djavax.net.ssl.keyStore=serverKeys
-Dj avax.net.s s l.ke ySto reP ass word=pa sswo rd
-Djavax.net.s s l.trustS tore#NAME?
-Djavax.net.s s l.trustS torePa sswo rd=password S imp leS S LS erver
在命令行中我们指定了keyS tore属性为s erverKe ys。 由于服务器程序需要获得客户端的授权信息我们指定trustStore为serverTrust。这样S S LS imp leServer就可以验证由S SLS imp leC lient提供的授权信息。当服务器程序成功运行后你会看到下面的提示
SimpleSSLServer running on port 49152????
这时候服务器会等待客户端发出建立连接的申请。如果你希望在另一个端口上运行服务器程序可以在命令中指定-port xxx参数其中xxx是端口号。
然后在另一个命令窗口中运行客户端程序java-Djavax.net.ss l.keyStore=c lientKeys
-Dj avax.net.s s l.ke ySto reP ass word=pa sswo rd
-Djavax.net.s s l.trustS tore=c lientTrust
-Dj avax.net.s s l.trustS torePa sswo rd=pass word S imp leS S LC lie nt
客户端程序会试图向本机的49152端口建立SSL连接。 同样你可以通过-port参数指定端口号也可以通过-host参数指定主机名称。当连接成功后会出现下面的提示信息
C onnected
同时在服务器端会提示用户客户端已经连接成功。
Simp leS S LServer
让我们先来看一下Simp leS S LServer。在main 方法中程序获得了缺省的S SLServerSocketFactory对象然后利用S S LServerSocketFactory创建一个Simp leS S LS erve r对象最后调用s tart 方法启动S imp leS S LS erve r对象。SSLServerSocketFactory ss f=
(S SLServerSocketFactory)S S LServerSocketFactory.getDefault();
SimpleSSLServer server=new SimpleSSLServer(ssf,port);server.s tart();
由于服务器是在一个单独的线程中运行的 main 方法启动了服务器之后就退出了。 s tar t 方法启动了一个新的线程该线程执行r un 方法中的代码。在r un
方法中创建了一个S SLServerSocket对象然后设定服务器需要进行客户端验证
SSLServerSocket serverSocket=
(S SLServerSocket)serverSocketFactory.createServerSocket(port);serverSocket.setNeedC lientAuth(true);
调用run 方法后程序进入了一个死循环等待客户端的连接申请。循环中的每个Socket对应一个HandshakeCo mp letedListener对象该对象是用来显示客户验证信息中的标识名称distinguished name的 。 Socket的InputStream对象被包装在一个InputDisp layer对象中这个InputDisp layer对象运行在另外一个线程中用来将Socket接收到的数据发送到S ystem.out。下面的代码是S imp leS SLServer中的主循环体while(true) {
String ident=String.valueO f(id++);
//监听连接请求.
SSLSocket socket=(SSLSocket)serverSocket.aclearcase/"target="_blank">ccept();
//通过使用HandshakeCo mp letedListener对象,程序进行授权验证.
HandshakeComp letedListener hcl=new S imp leHandshakeListener(ident);socket.addHandshakeCo mp letedListener(hc l);
InputStream in=socket.getInputStream();new InputDisplayer(ident, in);
}
程序中的Simp leHandshakeListener类实现了HandshakeComp letedListerner接口。在Simp leHandshakeListener类中实现了handshakeComp leted 方法该方法在S S L握手阶段完成后将被JSSE调用。它将显示出客户端的标识名称class S imp leHandshakeListener imp lements HandshakeComp letedListener
{
String ident;
/**
*构造函数.
*/public S impleHandshakeListener(String ident)
{this.ident=ident;
}
/**当SSL握手过程完成后该方法被激活. */public void handshakeCompleted(HandshakeCompletedEvent event)
{
//显示授权信息.try{
X509 C ertific atecert=(X509C ertificate)e ve nt.getPeerC e rtificates()[0];
String peer=cert.getSubjectDN().getName();
System.out.println(ident+":Request from"+peer);
}catch(SS LPeerUnverifiedException pue) {
System.out.println(ident+":Peer unverified");
}
}
}
用红色字体表示的两行代码是这段代码的核心 getPeerCertificates 方法返回一个X509C ertific ated对象的数组。这些X509C ertificated对象创建了客户端的身份标识。在数组中的第一个元素是客户端的验证信息而最后一个通常是CA验证。当我们有了客户端的验证信息后。我们可以得到其中的标识名称并将它传送到Sys te m.o ut。
S imp le S S LC lie nt
S imp le S S LC lie nt类比较简单但是在后面的一些比较复杂的例子中的类会继承该类。在getSLLSocketFacto ry 方法中程序返回缺省的工厂类protected S SLSocketFactory getS S LSocketFactory()throws IOException,GeneralSecurityException
{return(S SLSocketFactory)S S LSocketFactory.getDe fault();
}
在runC lie nt()方法中程序处理了输入参数后获得S S LS ockFacto ry对象调用
connect 方法连接到服务器程序。在connect 方法中程序首先创建一个S SLSocket对象然后调用S S LSocket对象的startHandshang 方法启动和服务器端的握手过程。当握手过程完成后会触发一个HandshakeCo mp letedEvent事件。在服务器端的HandshakeCo mp letedListener对象会处理这个事件。事实上JSSE可以自动启动握手过程但是必须是在第一次有数据通过Socket传输的情况下。 由于在例子程序中直到用户在键盘上输入信息后才会有数据通过Socket传输而我们希望服务器端及时报告连接情况 因此我们用startS hake 方法来手工激活握手过程。public void connect(SSLSocketFactory sf)throws IOException
{socket=(SSLSocket)sf.createSocket(host,port);try{s ocket.startHands hake();
}catch(IOException ioe) {
//握手失败.关闭连接.try{socket.close();
}catch(IOException ioe2) {
//忽略该错误.
}socket=null;throw io e;
}
}
Simp leS SLClient类中的transmit 方法也很简单。首先程序将输入流包装到一个Reader对象中然后将输出流包装到一个Writer对象中最后将数据流输出到Socketboolean done=false;
while(!done) {
String line=reader.readLine();if(line!=null) {wr iter.wr ite(lin e);wr ite r.wr ite('\n');wr iter.flu s h();
}else done=true;
}
定制KeyS tor e和TrustS tore?
还记得我们是如何运行客户端的吗我们需要在命令行中指定keySto re,ke ySto reP as word, trustS tore和trus tSto rePass word参数 以至于整个命令显得过于冗长。事实上你可以在程序中指定KeyS tor e和Trus tS tore后面的例子中将告诉你如何实现这一点。 同时在例子中还会演示如何配置多个S SLSocketFactory对象其中每个S SLS ocketFac tory对象对应不同的KeySto re和Trus tSto re设置。如果没有这种技术在同一个虚拟机上的所有安全连接都只能使用同一个K eyS to re和TrustStore。对于比较小的应用程序这也许不会产生问题但是对于那些比较大的应用程序来说这绝对是一个严重的缺陷。
在下面的例子中我们将使用Custo mTrus tStoreC lie nt来动态定义Ke yStore和Trus tStore。首先让我们先运行一下Custo mTrustS toreC lientjava CustomTrustS toreC lient
为什么运行Custo mTrus tStoreC lie nt时不需要指定KeyS tore和TrustS tore参数呢这是应为在Custo mTrus tStoreC lie nt的代码中指定了KeyS tore C lie ntKe ys和TrustStore C lientTruts以及它们的密钥password 。如果你想使用其他的KeyStore、 TrustS tore或密钥可以使用-ks、 -kspass、 -ts和-tspa ss参数来指定。下
近日CloudCone发布了最新的补货消息,针对此前新年闪购年付便宜VPS云服务器计划方案进行了少量补货,KVM虚拟架构,美国洛杉矶CN2 GT线路,1Gbps带宽,最低3TB流量,仅需14美元/年,有需要国外便宜美国洛杉矶VPS云服务器的朋友可以尝试一下。CloudCone怎么样?CloudCone服务器好不好?CloudCone值不值得购买?CloudCone是一家成立于2017年的美国服务器...
已经有一段时间没有听到Gigsgigscloud服务商的信息,这不今天看到商家有新增一款国际版线路的美国VPS主机,年付也是比较便宜的只需要26美元。线路上是接入Cogentco、NTT、AN2YIX以及其他亚洲Peering。这款方案的VPS主机默认的配置是1Gbps带宽,比较神奇的需要等待手工人工开通激活,不是立即开通的。我们看看这款服务器在哪里选择看到套餐。内存CPUSSD流量价格购买地址1...
ShockHosting商家在前面文章中有介绍过几次。ShockHosting商家成立于2013年的美国主机商,目前主要提供虚拟主机、VPS主机、独立服务器和域名注册等综合IDC业务,现有美国洛杉矶、新泽西、芝加哥、达拉斯、荷兰阿姆斯特丹、英国和澳大利亚悉尼七大数据中心。这次有新增日本东京机房。而且同时有推出5折优惠促销,而且即刻使用支付宝下单的话还可获赠10美金的账户信用额度,折扣相比之前的常规...