首先创建服务器端私有密钥和公共密钥
1, keytool -genkey -alias serverkey -keystore kserver.ks
    密码: serverpass
2, keytool -export -alias serverkey -keystore kserver.ks -file server.crt
3, keytool -import -alias serverkey -file server.crt -keystore tclient.ks
    密码: clientpublicpass

下面创建客户器端私有密钥和公共密钥
1, keytool -genkey -alias clientkey -keystore kclient.ks
    密码: clientpass
2, keytool -export -alias clientkey -keystore kclient.ks -file client.crt
3, keytool -import -alias clientkey -file client.crt -keystore tserver.ks
    密码: serverpublicpass

把服务器端产生的公共密钥放到客户端, 同样把客户端创建的公共密钥放到服务器端.

下面是服务器端代码:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLServerSocket;
import javax.net.ssl.TrustManagerFactory;

public class SSLTestServer {

public static void main(String[] args) throws Exception {
        SSLContext ctx = SSLContext.getInstance("SSL");

KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");

KeyStore ks = KeyStore.getInstance("JKS");
        KeyStore tks = KeyStore.getInstance("JKS");

ks.load(new FileInputStream("cert/kserver.ks"), "serverpass".toCharArray());
        tks.load(new FileInputStream("cert/tserver.ks"), "serverpublicpass".toCharArray());

kmf.init(ks, "serverpass".toCharArray());
        tmf.init(tks);

ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);

SSLServerSocket serverSocket = (SSLServerSocket) ctx.getServerSocketFactory().createServerSocket(8443);
        serverSocket.setNeedClientAuth(true);

while (true) {
            try {
                Socket s = serverSocket.accept();
                InputStream input = s.getInputStream();
                OutputStream utput = s.getOutputStream();

BufferedInputStream bis = new BufferedInputStream(input);
                BufferedOutputStream bos = new BufferedOutputStream(output);

byte[] buffer = new byte[20];
                int length = bis.read(buffer);
                System.out.println("Receive: " + new String(buffer, 0, length).toString());

bos.write("Hello".getBytes());
                bos.flush();

s.close();
            } catch (Exception e) {
                System.out.println(e);
            }
        }
    }
}

下面是客户端代码:
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.KeyStore;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.TrustManagerFactory;

public class SSLTestClient {

public static void main(String[] args) throws Exception {
        SSLContext ctx = SSLContext.getInstance("SSL");

KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
        TrustManagerFactory tmf = TrustManagerFactory.getInstance("SunX509");

KeyStore ks = KeyStore.getInstance("JKS");
        KeyStore tks = KeyStore.getInstance("JKS");

ks.load(new FileInputStream("cert/kclient.ks"), "clientpass".toCharArray());
        tks.load(new FileInputStream("cert/tclient.ks"), "clientpublicpass".toCharArray());

kmf.init(ks, "clientpass".toCharArray());
        tmf.init(tks);

ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
        SSLSocket sslSocket = (SSLSocket) ctx.getSocketFactory().createSocket("localhost", 8443);
        InputStream input = sslSocket.getInputStream();
        OutputStream utput = sslSocket.getOutputStream();

BufferedInputStream bis = new BufferedInputStream(input);
        BufferedOutputStream bos = new BufferedOutputStream(output);

bos.write("Hello".getBytes());
        bos.flush();

byte[] buffer = new byte[20];
        int length = bis.read(buffer);
        System.out.println(new String(buffer, 0, length));

sslSocket.close();   
    }

}

常见的HTTPS传输, 不需要进行客户端认证, 也就是单向认证. 这时也就不需要创建客户端的私钥和公钥. 服务器端也只要配置一下服务器端的私钥即可, 当客户端浏览器访问时会生成一个证书文件,类似于上面创建的crt文件. 如果需要程序访问,可以通过这个crt文件生成一个keystore. 然后是用这个keystore作为trust keystore即可.

目前我用keytool.exe生成的keystore和证书用于双向认证是没有问题的,但是使用ejbca系统生成的由某CA机构颁发的证书以及生成的keystore用来做双向认证就会报错。

javax.net.ssl.SSLHandshakeException: null cert chain

这个问题还需要进一步跟踪解决。

SSLSocket实现服务端和客户端双向认证的例子的更多相关文章

  1. openssl实现双向认证教程(服务端代码+客户端代码+证书生成)

    一.背景说明 1.1 面临问题 最近一份产品检测报告建议使用基于pki的认证方式,由于产品已实现https,商量之下认为其意思是使用双向认证以处理中间人形式攻击. <信息安全工程>中接触过 ...

  2. C#在服务端验证客户端证书(Certificate)

    使用https协议进行通讯的时候可以设置双向证书认证,客户端验证服务端证书的方法前面已经介绍过了,现在说一下在服务端验证客户端证书的方案. 这里给出的方案比较简单,只需要在Service端的配置文件中 ...

  3. (转)SVN 服务端、客户端安装及配置、导入导出项目

    SVN服务器搭建和使用(一) Subversion是优秀的版本控制工具,其具体的的优点和详细介绍,这里就不再多说. 首先来下载和搭建SVN服务器. 现在Subversion已经迁移到apache网站上 ...

  4. 使用flask_socketio实现服务端向客户端定时推送

    websocket连接是客户端与服务器之间永久的双向通信通道,直到某方断开连接. 双向通道意味着在连接时,服务端随时可以发送消息给客户端,反之亦然,这在一些需要即时通讯的场景比如多人聊天室非常重要. ...

  5. 常量,字段,构造方法 调试 ms 源代码 一个C#二维码图片识别的Demo 近期ASP.NET问题汇总及对应的解决办法 c# chart控件柱状图,改变柱子宽度 使用C#创建Windows服务 C#服务端判断客户端socket是否已断开的方法 线程 线程池 Task .NET 单元测试的利剑——模拟框架Moq

    常量,字段,构造方法   常量 1.什么是常量 ​ 常量是值从不变化的符号,在编译之前值就必须确定.编译后,常量值会保存到程序集元数据中.所以,常量必须是编译器识别的基元类型的常量,如:Boolean ...

  6. 红帽学习笔记[RHCE]OpenLDAP 服务端与客户端配置

    目录 OpenLDAP 服务端与客户端配置 关于LDIF 一个LDIF基本结构一个条目 属性 Object的类型 服务端 安装 生成证书 生成默认数据 修改基本的配置 导入基础数据 关于ldif的格式 ...

  7. eureka服务端和客户端的简单搭建

    本篇博客简单记录一下,eureka 服务端和 客户端的简单搭建. 目标: 1.完成单机 eureka server 和 eureka client 的搭建. 2.完成eureka server 的添加 ...

  8. asp.net获取服务端和客户端信息

    asp.net获取服务端和客户端信息 获取服务器名:Page.Server.ManchineName获取用户信息:Page.User 获取客户端电脑名:Page.Request.UserHostNam ...

  9. python thrift 服务端与客户端使用

    一.简介 thrift是一个软件框架,用来进行可扩展且跨语言的服务的开发.它结合了功能强大的软件堆栈和代码生成引擎,以构建在 C++, Java, Python, PHP, Ruby, Erlang, ...

随机推荐

  1. 用Python写的一个多线程机器人聊天程序

    本人是从事php开发的, 近来想通过php实现即时通讯(兼容windows).后来发现实现起来特别麻烦, 就想到python.听说这家伙在什么地方都能发挥作用.所以想用python来做通讯模块...所 ...

  2. 高仿精仿微信应用ios源码下载

    微信,超过3亿人使用,能够通过手机网络给好友发送语音.文字消息.表情.图片和视频,还可以分享照片到朋友圈.通过摇一摇.查看附近的人,你可以认识新的朋友.使用扫一扫,你可以扫描二维码.条码.图书和街景. ...

  3. Struts2之自定义局部类型转换器、全局类型转换器

    Struts2自定义类型转换器分为局部类型转换器和全局类型转换器 (1)局部类型转换器  如果页面传来一个参数reg.action?birthday=2010-11-12到后台action,然后属性用 ...

  4. position:relative可以默认提升元素的z-index;

    position:relative可以默认提升元素的z-index; 相对没有添加position的元素来说:

  5. Shortest Path(思维,dfs)

    Shortest Path  Accepts: 40  Submissions: 610  Time Limit: 4000/2000 MS (Java/Others)  Memory Limit: ...

  6. [Regionals 2012 :: Asia - Tokyo ]

    链接: https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&category=56 ...

  7. MongoDB无法启动的解决方法

    http://dmyz.org/archives/423 遇到MongoDB突然无法启动,第一反应是删除mongod.lock.这个文件在MongoDB的数据库目录下,默认是/data/db.这是最常 ...

  8. 20151204--JDBC

    <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding= ...

  9. javascript新窗口打开链接window.open()被阻拦的解决办法

    场景是ajax提交,比较后端效验数据,需要用户登录,提示后并需要新窗口打开登录的链接,使用window.open(url);往往会被浏览器认为是广告而被拦截. data.url是ajax返回的链接地址 ...

  10. ie6,ie7,ie8 css bug汇总以及兼容解决方法

    1:li边距“无故”增加 任何事情都是有原因的,li边距也不例外. 先描述一下具体状况:有些时候li边距会突然增 加很多,值也不固定(只在IE6/IE7有这种现象),让人摸不着头脑,仔细“研究”发现是 ...