Java 下 SSL 通信原理及实例

澳门新浦京娱乐游戏 3

至于SSL的规律和介绍在网络一度有众多,对于Java下使用keytool生成证书,配置SSL通讯的科目也充裕多。但只要大家不可以亲自动手做三个SSL
Sever和SSL
Client,大概就永恒也无法一语中的地了然Java景况下,SSL的通讯是怎样促成的。对SSL中的种种概念的认识也只怕会只限于能够应用的水平。本文通过布局三个回顾的SSL
Server和SSL Client来讲授Java意况下SSL的通讯原理。

[TOC]

一、 SSL概述

SSL公约使用数字证书及数字签字举办双端实体认证,用非对称加密算法进行密钥协商,用对称加密算法将数据加密后开展传输以有限帮助数据的保密性,而且经过测算数字摘要来声明数据在传输进度中是或不是被点窜和冒充,进而为灵活数据的传输提供了一种安全保持花招。

SSL左券提供的服务重大有:
1)认证顾客和服务器,确定保证数据发送到准确的客商机和服务器
证实客商和服务器的合法性,使它们能够确信数据将被发送到准确的客户机和服务器上。客商机和服务器皆有独家的识别号,那些分辨号由公开密钥进行编号,为注脚顾客是还是不是合法,SSL合同须求在拉手交流数据时实行数字印证,以此保证客户的合法性。
2)加密多少避防备数据中途被偷取
SSL左券所选取的加密本领既有对称密钥手艺,也是有公开密钥本事。在客商机和服务器实行数据沟通前,沟通SSL早先握手消息,在SSL握手音讯中利用了种种加密技艺对其张开加密,以管教其机密性和数目标完整性,况兼用数字证书实行辨别,那样就足以免范不法客商张开破译。
3)维护数据的完整性,确认保障数量在传输进程中不被改成
SSL合同使用Hash函数和秘密分享的艺术提供音信的完整性服务,创立客商机和服务器之间的平安通道,使具备通过SSL左券管理的工作在传输进程中能全部完全准确科学的达到指标地。

SSL类别布局:
SSL左券坐落于TCP/IP合同模型的网络层和应用层之间,使用TCP来提供一种保证的端到端的安全服务,它是客户/服务器应用之间的通讯不被口诛笔伐抓取,并且始终对服务器举办认证,还能选拔对客户开展表明。SSL种类布局如图1所示。

率先大家先想起一下例行的Java
Socket编制程序。在Java下写一个Socket服务器和顾客端的例证依旧比较容易的。

一、HTTPS 身份验证介绍

二、SSL种类布局:

SSL左券坐落于TCP/IP合同模型的网络层和应用层之间,使用TCP来提供一种保障的端到端的安全服务,它是客商/服务器应用之间的通讯不被攻击抓取,并且始终对服务器进行认证,还足以选取对客户扩充求证。
在SSL通信中,首先使用非对称加密交流音信,使得服务器获得浏览器端提供的相反相成加密的密钥,然后利用该密钥实行报纸发表进程中国国投息的加密和解密。为了确认保证音信在传递进程中尚无被窜改,可以加密HASH编码来保障新闻的完整性。SSL通信进程,如图2所示。
平时情状下,当客商端是保密新闻的传递者时,客商端无需数字证书验证自身身价的真实,如电子银行的运用,客商必要将团结的账号和密码发送给银行,由此银行的服务器要求设置数字证书来注解本人身份的实用。在少数应用中,服务器端也急需对客商端之处展开表明,这时候顾客端也供给安装数字证书以担保通信时服务器可以辨认出客户端的身份,验证进度看似于服务器身份的表明进程。

服务端十分轻便:侦听8080端口,并把顾客端发来的字符串再次来到去。以下是服务端的代码:

1. HTTPS 原理

HTTPS(Hyper Text Transfer Protocol over Secure Socket
Layer),说来讲去正是加了安全认证的 HTTP,即HTTP + SSL;大家知晓 HTTP
通信时,借使顾客端C
央求服务器S,那么能够通过网络抓包的格局来获撤除息,以致足以如法炮征服务器 S
端,来骗取与 C
端的简报消息;那对互连网应用在平安世界的拓展特别不利于;HTTPS化解了那个难点。

三、SSL Socket双向认证的完结

SSL
Socket通讯是对Socket通讯的拓宽。在Socket通讯的幼功上增多了一层安全性爱慕,提供了越来越高的安全性,包蕴身份验证、数据加密以致完整性验证。
SSL Socket双向认证完成技能: JSSE(Java Security Socket
Extension),它实现了SSL和TSL(传输层安全)契约。在JSSE中带有了数额加密,服务器验证,音信完整性和顾客端验证等技艺。通过采取JSSE,能够在顾客机和服务器之间通过TCP/IP左券安全地传输数据。为了促成消息证实:

package org.bluedash.tryssl;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
public class Server extends Thread {
    private Socket socket;
    public Server(Socket socket) {
        this.socket = socket;
    }
    public void run() {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            PrintWriter writer = new PrintWriter(socket.getOutputStream());
            String data = reader.readLine();
            writer.println(data);
            writer.close();
            socket.close();
        } catch (IOException e) {

        }
    }
    public static void main(String[] args) throws Exception {
        while (true) {
            new Server((new ServerSocket(8080)).accept()).start();
        }
    }
}
HTTPS 与 HTTP 的区别

1)HTTPS 的服务器要求到 CA 申请证书,以验证本人服务器的用途;

2)HTTP 音讯是领会传输,HTTPS 新闻是密文字传递输;

3)HTTP 与 HTTPS 的默许端口不相同,前面三个是 80 端口,后面一个是 443 端口;

能够说 HTTP 与 HTTPS 是天壤之别的接连形式,HTTPS
集结了加密传输,身份验证,更加的平安。

劳动器端要求:

1、KeyStore: 其中保存服务器端的私钥
2、Trust KeyStore: 其中保存客户端的授权证书

客商端也特别简单:向服务端发起呼吁,发送二个”hello”字串,然后拿走服务端的回到。上面是客商端的代码:

2. HTTPS 身份验证流程

澳门新浦京娱乐游戏,client 向 server 发送实际的职业 HTTPS 央浼在此以前,会先与 server
实行四遍握手,相互印证身份:

拉手的流程图:

澳门新浦京娱乐游戏 1

HTTPS 身份验证握手流程图

一种解释:

1)客商端央求服务器,发送握手新闻

2)服务器再次回到客商端自身的加密算法、数字证书和公钥;

3)顾客端验证服务器端发送来的数字证书是不是与地点受信赖的证件相关新闻一致;假使分化则顾客端浏览器提醒证书不安全。倘使阐明通过,则浏览器会接收自己的轻易数算法产生三个私行数,并用服务器发送来的公钥加密;发送给服务器;这里假设有人因而攻击得到了这么些新闻,那也没用,因为她从没解密此段新闻所急需私钥;验证通过的网址在浏览器地址栏的入手会有一完好无损锁的标记;

3)服务器解密得到此随机数,并用此随机数作为密钥选取对称加密算法加密一段握手音信发送给浏览器;

4)浏览器收到新闻后解密成功,则握手结束,后续的音信都因此此随机密钥加密传输。

以上是服务端认证的景色,若是服务端对拜望的顾客端也可能有认证必要,则顾客端也供给将和谐的证书发送给服务器,服务器认证不经过,通信停止;原理同上;

除此以外,通常在传输进度中为了幸免音信窜改,还有只怕会动用消息摘要后再加密的主意,以此保险音讯传递的不错。

另一种解释表明:

  1. 客户端发起三个 https 的乞求,把自家扶持的一雨后春笋 Cipher
    Suite(密钥算法套件,简单称谓Cipher)发送给服务端。

  2. 服务端,选拔到顾客端具有的 Cipher
    后与本身扶持的自己检查自纠,假设不协助则接二连三断开,反之则会从中选出一种加密算法和HASH算法,以申明的形式再次来到给客商端
    证书中还包含了:公钥、颁证机构、网址、失效日期等等。

  3. 客户端收到服务端响应后会做以下几件事:

    3.1 验证证书的合法性

公布证书的单位是还是不是合法与是或不是过期,证书中蕴藏的网址地址是不是与正在访问的地点雷同等


证书验证通过后,在浏览器的地址栏会加上一把小锁(每家浏览器验证通过后的唤醒不雷同不做探讨卡塔尔国

3.2 生成自由密码


假如注解验证通过,或然客户接收了不授信的证书,那个时候浏览器会生成一串随机数,然后用注明中的公钥加密。

3.3 HASH握手音讯

​ 用一初步预约好的 HASH 格局,把握手音讯取 HASH 值, 然后用随机数加密
“握手消息 + 握手消息 HASH 值(签名)” 并联合发送给服务端。

​ 在此边之所以要取握手音信的 HASH
值,重若是把握手音信做三个签定,用于注解握手音讯在传输进程中平素不被篡校勘。

  1. 服务端获得客商端传来的密文,用自个儿的私钥来解密握手音信收取随机数密码,再用随便数密码
    解密 握手音信与HASH值,并与传过来的HASH值做相比较确认是否一律。

​ 然后用随机密码加密一段握手音讯(握手新闻+握手音信的HASH值 卡塔尔给顾客端

  1. 客商端用随机数解密并思忖握手音信的 HASH,假如与服务端发来的 HASH
    一致,此时握手进度截至,之后有所的通讯数据将由事前浏览器生成的随机密码并应用对称加密算法进行加密,因为那串密钥唯有客商端和服务端知道,所以即使中间诉求被阻碍也是不得已解密数据的,以此保障了通讯的平安。
  • 非对称加密算法:迈凯伦570SA,DSA/DSS
    在客商端与服务端相互验证的进度中用的是对称加密
  • 对称加密算法:AES,RC4,3DES
    客商端与服务端互相印证通过后,以随机数作为密钥时,便是对称加密
  • HASH算法:MD5,SHA1,SHA256 在明确握手音信并未有被曲解时

顾客端须求:

1、KeyStore:其中保存客户端的私钥
2、Trust KeyStore:其中保存服务端的授权证书

密钥和授权证书的转移方法:
接收Java自带的keytool命令,在命令行生成。
1、生成服务器端私钥kserver.keystore文件
keytool -genkey -alias serverkey -validity 1 -keystore
kserver.keystore
2、依照私钥,导出服务器端安全评释
keytool -export -alias serverkey -keystore kserver.keystore -file
server.crt
3、将劳动器端证书,导入到顾客端的Trust KeyStore中
keytool -import -alias serverkey -file server.crt -keystore
tclient.keystore
4、生成客户端私钥kclient.keystore文件
keytool -genkey -alias clientkey -validity 1 -keystore
kclient.keystore
5、依据私钥,导出客商端安全表明
keytool -export -alias clientkey -keystore kclient.keystore -file
client.crt
6、将客商端证书,导入到服务器端的Trust KeyStore中
keytool -import -alias clientkey -file client.crt -keystore
tserver.keystore

转移的公文分为两组,服务器端保存:kserver.keystore tserver.keystore
顾客端保存:kclient.keystore tclient.kyestore。

顾客端应用kclient.keystore中的私钥进行多少加密,发送给服务端,服务器端采取tserver.keystore中的client.crt证书对数码解密,假若解密成功,注解音信来源可信赖的客商端,实行逻辑管理;
服务器端采纳kserver.keystore中的私钥进行多少加密,发送给客户端,顾客端选拔tclient.keystore中的server.crt证书对数据解密,即使解密成功,表明音信来源可信的劳动器端,进行逻辑管理。假诺解密失败,那么表明新闻来源错误。不举办逻辑管理。

SSL Socket双向认证的安全性:
(1)能够保证数量传送到准确的服务器端和客商端。
(2)可防止御音讯传递进程中被偷取。
(3)幸免新闻在传递进程中被改善.。

在系统运作中或然现身以下境况:
(1)
服务器端、客商端都具备正确的密钥和平安评释,那时候服务器端和客户端能够打开正规通讯。
(2)
客户端的密钥和安全证书不精确,那时候服务器端和客商端不得以拓宽常规通讯。
(3)
客商端未持有密钥和安全证书,那时候劳动器端和顾客端也不得以开展常规通讯。

package org.bluedash.tryssl;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
public class Client {
    public static void main(String[] args) throws Exception {
        Socket s = new Socket("localhost", 8080);
        PrintWriter writer = new PrintWriter(s.getOutputStream());
        BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));
        writer.println("hello");
        writer.flush();
        System.out.println(reader.readLine());
        s.close();
    }
}

二、windows 景况下安排 tomcat HTTPS

还是找 CA 授信部门颁发证书,要么自个儿给协和颁证书(不受信赖的HTTPS)

上边大家在 windows 上配备 tomcat 的HTTPS 访问

把服务端运营起来后,施行客户端,大家将赢得”hello”的归来。

1. 生成密钥库 keystore

先是接受 JDK 的 keytool 命令,生成 keystore,在 cmd 命令行情势下执行:

keytool -genkey -alias uzipi.com -keyalg RSA -keystore 1024 -validity 365 -keystore d:/server.keystore -keypass Cs123456 -storepass Cs123456

-genkey     表示要生成密钥
-keyalg     指定密钥算法,这里指定为 RSA 算法。
-keysize    指定密钥长度,默认 1024 bit,这里指定为 2048 bit。
-sigalg     指定数字签名算法,这里指定为 SHA1withRSA 算法。
-validity   指定证书有效期,这里指定为 365 天。
-alias      指定生成的密钥库的别名,这里是 uzipi.com
-keystore   指定密钥库存储位置,这里设定的是 d:/server.keystore
-keypass    密钥口令
-storepass  密钥库口令

正是那样一套轻易的互联网通讯的代码,我们来把它改产生选用SSL通讯。在SSL通讯合同中,大家都精晓首先服务端必得有叁个数字证书,当顾客端连接到服务端时,会得到这么些表明,然后客户端会判定那么些评释是不是是可信赖的,若是是,则交流信道加密密钥,实行通讯。倘诺不相信这么些表明,则总是失利。

2. 配置 Tomcat

故而,大家率先要为服务端生成三个数字证书。Java情状下,数字证书是用keytool生成的,那一个证件被寄放在store的概念中,就是证书仓库。大家来调用keytool命令为劳动端生成数字证书和保存它利用的证书货仓:

2.1 将 server.keystore 文件移动到 汤姆cat 根目录下

​ 为何要运动到 汤姆cat 根目录下吧?因为 汤姆cat
运维时优先扫描当前根目录。

keytool -genkey -v -alias bluedash-ssl-demo-server -keyalg RSA -keystore ./server_ks -dname "CN=localhost,OU=cn,O=cn,L=cn,ST=cn,C=cn" -storepass server -keypass 123123
2.2 配置 server.xml 文件

​ 进入 ${TOMCAT_BASE}/conf,编辑 server.xml 文件,根据 汤姆cat
官方网站的晋升,我们能够找到 port="8443"<Connector>
标签注释,解开注释改善内容,
也能够一向复制如下内容(本身改密码),出席到 server.xml 文件:

<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"
            maxThreads="150" scheme="https" secure="true"
            keystoreFile="server.keystore" keystorePass="Cs123456"
            clientAuth="false" sslProtocol="TLS" />
  • keystoreFile 属性值,填写我们正巧创造的 server.keystore
    的公文(假如身处了其他目录下,需求内定路线)
  • keystorePass 属性值,填写早先创造的密钥库密码

这么,大家就将服务端证书bluedash-ssl-demo-server保存在了server_ksy那个store文件当中。有关keytool的用法在本文中就不再多废话。试行上边的一声令下获得如下结果:

2.3 配置项目标 web.xml

安插 webapps 目录中的项目,找到 WEB-INF/web.xml 文件,增多如下内容:

<security-constraint>
    <web-resource-collection>
        <web-resource-name>SSL</web-resource-name>
        <url-pattern>/*</url-pattern>
    </web-resource-collection>
    <user-data-constraint>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
</security-constraint>
Generating 1,024 bit RSA key pair and self-signed certificate (SHA1withRSA) with a validity of 90 days
        for: CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn
[Storing ./server_ks]

3. 起步 汤姆cat,使用 Https + 8443 端口情势访谈项目

用 https + 8443 端口方式访谈项目,会意识与前边普通 http + 8080
端口情势访谈的区分:浏览器地址栏前边多了不安全的警戒。因为是我们本人发表的证件,所以是不被别的机关信赖的。

接下来,改变大家的服务端代码,让服务端使用那么些评释,并提供SSL通信:

三、linux 情状下布置 tomcat HTTPS

linux 上的布局与 windows 景况的铺排是同一的。

package org.bluedash.tryssl;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.security.KeyStore;

import javax.net.ServerSocketFactory;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;

public class SSLServer extends Thread {
    private Socket socket;

    public SSLServer(Socket socket) {
        this.socket = socket;
    }

    public void run() {
        try {
            BufferedReader reader = new BufferedReader(new InputStreamReader(socket.getInputStream()));
            PrintWriter writer = new PrintWriter(socket.getOutputStream());

            String data = reader.readLine();
            writer.println(data);
            writer.close();
            socket.close();
        } catch (IOException e) {

        }
    }

    private static String SERVER_KEY_STORE = "/Users/liweinan/projs/ssl/src/main/resources/META-INF/server_ks";
    private static String SERVER_KEY_STORE_PASSWORD = "123123";

    public static void main(String[] args) throws Exception {
        System.setProperty("javax.net.ssl.trustStore", SERVER_KEY_STORE);
        SSLContext context = SSLContext.getInstance("TLS");

        KeyStore ks = KeyStore.getInstance("jceks");
        ks.load(new FileInputStream(SERVER_KEY_STORE), null);
        KeyManagerFactory kf = KeyManagerFactory.getInstance("SunX509");
        kf.init(ks, SERVER_KEY_STORE_PASSWORD.toCharArray());
        context.init(kf.getKeyManagers(), null, null);
        ServerSocketFactory factory = context.getServerSocketFactory();
        ServerSocket _socket = factory.createServerSocket(8443);
        ((SSLServerSocket) _socket).setNeedClientAuth(false);

        while (true) {
            new SSLServer(_socket.accept()).start();
        }
    }
}

1. 生成密钥库 keystore

(1)cd 转向到 tomcat 主目录,实践命令生成 keystore 文件

keytool -genkey -alias uzipi.com -keyalg RSA -keypass Cs123456 -storepass Cs123456 -keystore server.keystore -validity 3600

推行命令之后,将会在tomcat主目录下生成 server.keystore 文件;

(2)根据 keystore 文件发出的证书央求,向 CA 申请服务器数字证书:

keytool -export -trustcacerts -alias uzipi.com -file server.cer -keystore server.keystore -storepass Cs123456

施行命令之后,将会在tomcat主目录下生成 server.cer 文件;

(3)将音信基本签发的服务器证书 server.cer 导入到 server.keystore
文件:

keytool -import -trustcacerts -alias uzipi.com -file server.cer -keystore server.keystore -storepass Cs123456

能够看看,服务端的Socket绸缪安装职业余大学大扩展了,扩充的代码的效能主若是将表明导入并开展利用。其余,所选拔的Socket产生了SSLServerSocket,其余端口改到了8443(这一个不是挟持的,仅仅是为了坚决守住习贯)。其余,最注重的少数,服务端证书里面的CN一定和服务端的域名统一,大家的证书服务的域名是localhost,那么大家的顾客端在三番四次服务端时早晚也要用localhost来三番五次,不然依据SSL合同正式,域名与证书的CN不相配,表明这一个注脚是不安全的,通讯将不能不荒谬运作。

2. 生成客户端证书

(1)为了确认保障客商端证书能够如愿导入到 IE 和 Firefox
浏览器,须将证书格式为 PKCS12,命令如下:

keytool -genkey -v -alias clientAlias -keyalg RSA -storetype PKCS12 -validity 3600 -keystore client.p12 -storepass clientStorePass -keypass clientKeyPass

施行命令之后,将会在tomcat主目录下生成 client.p12 文件;

有了服务端,大家本来的顾客端就不可能动用了,应当要走SSL左券。由于服务端的证件是我们生死与共生成的,未有其余受信赖机构的签订,所以顾客端是回天无力表达服务端证书的实用的,通讯必然会停业。所以大家要求为客户端创设两个保存全部信任证书的库房,然后把服务端证书导进那个库房。那样,当顾客端连接服务端时,会意识服务端的证书在谐和的深信列表中,就能够平常通讯了。

3. 让服务器信赖顾客端证书

双向 SSL
认证,服务器必要信赖客商端证书,因而要把顾客端证书增添为服务器的信赖认证。
出于不可能一向将 PKCS12 格式的注明导入,要先把客商端证书导出为二个单独的
CER 文件,命令如下:

keytool -export -alias clientAlias -keystore client.p12 -storetype PKCS12 -storepass clientStorePass -rfc -file client.cer

实施命令之后,将会在tomcat主目录下生成 client.cer 文件;

然后将 client.cer 导入到服务器的评释库
server.keystore,加多为一个信赖证书:

keytool -import -v -file client.cer -keystore server.keystore -storepass Cs123456

进行后,认证就已增添至 keystore 中了。

为此以后我们要做的是生成二个用户端的证件货仓,因为keytool不能仅生成三个赤手饭馆,所以和服务端相通,大家还是生成一个注解加一个库房(顾客端证书加旅馆):

4. keytool 的其他命令选项

(1)通过list命令查看服务器的证书库,可以看出八个输入,八个是服务器证书,一个是受信任的顾客端证书:

keytool -list -keystore server.keystore -storepass Cs123456

(2)删除证书命令

keytool -delete -alias myKey -keystore server.keystore -storepass Cs123456
keytool -genkey -v -alias bluedash-ssl-demo-client -keyalg RSA -keystore ./client_ks -dname "CN=localhost,OU=cn,O=cn,L=cn,ST=cn,C=cn" -storepass client -keypass 456456

5. 修改 tomcat 配置

修改 conf/server.xml 文件,配置 <Connector> port="8443"

<!-- Define a SSL HTTP/1.1 Connector on port 8443 This connector uses the JSSE configuration, when using APR, the  connector should be using the OpenSSL style configuration described in the APR documentation -->
<Connector port="8443" protocol="HTTP/1.1" SSLEnabled="true"   
    maxThreads="150" scheme="https" secure="true"
    clientAuth="false" sslProtocol="TLS" 
    keystoreFile="server.keystore" keystorePass="Cs123456"
    truststoreFile="server.keystore" truststorePass="Cs123456" />
  • clientAuth="true",双向认证;
  • clientAuth="false",单向认证;

结果如下:

6. 重启 tomcat,访谈应用

执行 ./bin/startup.sh 命令,访问 https://127.0.0.1:8443
(你协和的地点卡塔尔(قطر‎ 。

单向认证相关的安顿到此停止。如果还须要配置双向认证,继续往下看。

server.xml 文件中的 clientAuth="true",设置为双向认证,张开Firefox 菜单:编辑->首选项->高级->加密->查看证书->你的证书,将
client.p12 导入到 IE 中,依据 Firefox 提醒达成报到 tomcat 首页;

Generating 1,024 bit RSA key pair and self-signed certificate (SHA1withRSA) with a validity of 90 days
        for: CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn
[Storing ./client_ks]

7. 双向认证,让服务器 SSL 证书获得代码

if(request.isSecure()) { //如果是SSL通信
    Java.security.cert.X509Certificate[] certs = 
 (java.security.cert.X509Certificate[])request.getAttribute("javax.servlet.request.X509Certificate");
    if(certs!=null && certs.lengtt>0) {
        subjectDN="Certificates found";
    }
}

动用java深入剖析证书可获得证书中客商消息:

issue=certs.getIssuerDN().toString();   //证书签发者
subject=certs.getSubjectDN().getName(); //证书所有者
after=certs.getNotAfter().toString();   //证书起效时间
before=certs.getNotBefore().toString(); //证书到期时间
version=Integer.toString(certs.getVersion());   //证书版本
serialno=certs.getSerialNumber().toString();    //证书序列号

参谋文章:

http://tomcat.apache.org/tomcat-7.0-doc/ssl-howto.html
tomcat7.0 ssl配置

http://wenku.baidu.com/view/e7b22df0f90f76c661371a6f.html
Tomcat SSL 配置

接下去,我们要把服务端的证书导出来,并导入到顾客端的仓库。第一步是导出服务端的证书:

keytool -export -alias bluedash-ssl-demo-server -keystore ./server_ks -file server_key.cer

施行结果如下:

Enter keystore password:  server
Certificate stored in file <server_key.cer>

然后是把导出的证件导入到顾客端证书酒店:

keytool -import -trustcacerts -alias bluedash-ssl-demo-server -file ./server_key.cer -keystore ./client_ks

结果如下:

Enter keystore password:  client
Owner: CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn
Issuer: CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn
Serial number: 4c57c7de
Valid from: Tue Aug 03 15:40:14 CST 2010 until: Mon Nov 01 15:40:14 CST 2010
Certificate fingerprints:
         MD5:  FC:D4:8B:36:3F:1B:30:EA:6D:63:55:4F:C7:68:3B:0C
         SHA1: E1:54:2F:7C:1A:50:F5:74:AA:63:1E:F9:CC:B1:1C:73:AA:34:8A:C4
         Signature algorithm name: SHA1withRSA
         Version: 3
Trust this certificate? [no]:  yes
Certificate was added to keystore

好,计划干活做完了,大家来撰写客商端的代码:

package org.bluedash.tryssl;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;

import javax.net.SocketFactory;
import javax.net.ssl.SSLSocketFactory;

public class SSLClient {

    private static String CLIENT_KEY_STORE = "/Users/liweinan/projs/ssl/src/main/resources/META-INF/client_ks";

    public static void main(String[] args) throws Exception {
        // Set the key store to use for validating the server cert.
        System.setProperty("javax.net.ssl.trustStore", CLIENT_KEY_STORE);

        System.setProperty("javax.net.debug", "ssl,handshake");

        SSLClient client = new SSLClient();
        Socket s = client.clientWithoutCert();

        PrintWriter writer = new PrintWriter(s.getOutputStream());
        BufferedReader reader = new BufferedReader(new InputStreamReader(s
                .getInputStream()));
        writer.println("hello");
        writer.flush();
        System.out.println(reader.readLine());
        s.close();
    }

    private Socket clientWithoutCert() throws Exception {
        SocketFactory sf = SSLSocketFactory.getDefault();
        Socket s = sf.createSocket("localhost", 8443);
        return s;
    }
}

可以观察,除了把有个别类成为SSL通讯类以外,顾客端也多出了利用信赖证书仓库的代码。以上,大家便产生了SSL单向握手通讯。即:顾客端验证服务端的表明,服务端不表明客商端的申明。
上述正是Java情形下SSL单向握手的全经过。因为大家在客商端设置了日志输出品级为DEBUG:

System.setProperty("javax.net.debug", "ssl,handshake");

所以大家能够阅览SSL通信的全经过,这一个日记能够帮忙大家更跃然纸上地打听通过SSL公约建构互连网连接时的全经过。
重新整合日志,大家来看一下SSL双向认证的全经过:
澳门新浦京娱乐游戏 2
首先步:
顾客端发送ClientHello音讯,发起SSL连接央浼,告诉服务器自个儿帮忙的SSL选项(加密方法等)。

*** ClientHello, TLSv1

其次步: 服务器响应央浼,回复ServerHello消息,和客商端确认SSL加密方法:

*** ServerHello, TLSv1

其三步: 服务端向客商端发表自个儿的公钥。

第四步: 客商端与服务端的协通沟通实现,服务端发送ServerHelloDone音讯:

*** ServerHelloDone

第五步:
顾客端使用服务端授予的公钥,创制会话用密钥(SSL证书认证完成后,为了增长质量,全体的新闻互相就或许会选择对称加密算法),并经过ClientKeyExchange新闻发给服务器:

*** ClientKeyExchange, RSA PreMasterSecret, TLSv1

第六步:
顾客端通告服务器改造加密算法,通过ChangeCipherSpec音信发给服务端:

main, WRITE: TLSv1 Change Cipher Spec, length = 1

第七步: 顾客端发送Finished新闻,告知服务器请检查加密算法的改造伏乞:

*** Finished

第八步:服务端确认算法更改,再次回到ChangeCipherSpec音讯

main, READ: TLSv1 Change Cipher Spec, length = 1

第九步:服务端发送Finished音讯,加密算法生效:

*** Finished

这正是说什么样让服务端也证实客户端的地位,即双向握手呢?其实相当粗略,在服务端代码中,把这一行:

((SSLServerSocket) _socket).setNeedClientAuth(false);

改成:

((SSLServerSocket) _socket).setNeedClientAuth(true);

就足以了。可是,同样的道理,未来服务端并未相信客商端的证书,因为客商端的表明也是和睦生成的。所以,对于服务端,需求做相像的行事:把顾客端的证书导出来,并导入到服务端的证书堆栈:

keytool -export -alias bluedash-ssl-demo-client -keystore ./client_ks -file client_key.cer
Enter keystore password:  client
Certificate stored in file <client_key.cer>

keytool -import -trustcacerts -alias bluedash-ssl-demo-client -file ./client_key.cer -keystore ./server_ks
Enter keystore password:  server
Owner: CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn
Issuer: CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn
Serial number: 4c57c80b
Valid from: Tue Aug 03 15:40:59 CST 2010 until: Mon Nov 01 15:40:59 CST 2010
Certificate fingerprints:
         MD5:  DB:91:F4:1E:65:D1:81:F2:1E:A6:A3:55:3F:E8:12:79
         SHA1: BF:77:56:61:04:DD:95:FC:E5:84:48:5C:BE:60:AF:02:96:A2:E1:E2
         Signature algorithm name: SHA1withRSA
         Version: 3
Trust this certificate? [no]:  yes
Certificate was added to keystore

成功了证件的导入,还要在顾客端需求插足一段代码,用于在连年时,客商端向服务端出示自身的表明:

package org.bluedash.tryssl;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.security.KeyStore;
import javax.net.SocketFactory;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;

public class SSLClient {
    private static String CLIENT_KEY_STORE = "/Users/liweinan/projs/ssl/src/main/resources/META-INF/client_ks";
    private static String CLIENT_KEY_STORE_PASSWORD = "456456";

    public static void main(String[] args) throws Exception {
        // Set the key store to use for validating the server cert.
        System.setProperty("javax.net.ssl.trustStore", CLIENT_KEY_STORE);
        System.setProperty("javax.net.debug", "ssl,handshake");
        SSLClient client = new SSLClient();
        Socket s = client.clientWithCert();

        PrintWriter writer = new PrintWriter(s.getOutputStream());
        BufferedReader reader = new BufferedReader(new InputStreamReader(s.getInputStream()));
        writer.println("hello");
        writer.flush();
        System.out.println(reader.readLine());
        s.close();
    }

    private Socket clientWithoutCert() throws Exception {
        SocketFactory sf = SSLSocketFactory.getDefault();
        Socket s = sf.createSocket("localhost", 8443);
        return s;
    }

    private Socket clientWithCert() throws Exception {
        SSLContext context = SSLContext.getInstance("TLS");
        KeyStore ks = KeyStore.getInstance("jceks");

        ks.load(new FileInputStream(CLIENT_KEY_STORE), null);
        KeyManagerFactory kf = KeyManagerFactory.getInstance("SunX509");
        kf.init(ks, CLIENT_KEY_STORE_PASSWORD.toCharArray());
        context.init(kf.getKeyManagers(), null, null);

        SocketFactory factory = context.getSocketFactory();
        Socket s = factory.createSocket("localhost", 8443);
        return s;
    }
}

经过比对单向认证的日志输出,大家得以窥见双向认证时,多出了服务端认证客商端证书的步骤:

*** CertificateRequest
Cert Types: RSA, DSS
Cert Authorities:
<CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn>
<CN=localhost, OU=cn, O=cn, L=cn, ST=cn, C=cn>
*** ServerHelloDone

*** CertificateVerify
main, WRITE: TLSv1 Handshake, length = 134
main, WRITE: TLSv1 Change Cipher Spec, length = 1

在 @*** ServerHelloDone@ 早先,服务端向顾客端发起了索要申明的诉求@*** CertificateRequest@ 。
在客户端向服务端发出 @Change Cipher Spec@
央求以前,多了一步客商端证书认证的长河 @*** CertificateVerify@ 。
顾客端与服务端互相印证证书的场馆,可参照下图:

澳门新浦京娱乐游戏 3

参谋资料

1. Change Cipher Spec
Protocol
2. SSL & TLS Essentials: Securing the
Web

You can leave a response, or trackback from your own site.

Leave a Reply

网站地图xml地图