首先创建服务器端私有密钥和公共密钥
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. iterm快捷键及操作技巧(附Linux快捷键)

    标签操作 新建标签:command + t 关闭标签:command + w 切换标签:command + 数字 command + 左右方向键 切换全屏:command + enter 查找:com ...

  2. Why stackedit

    马克飞象 这个小工具很不错.初初看上了他能够很好写Latex,然后能同步到Evernode.但有个问题,在ipad上面用evernote的App时,latex不能显示.可能是权限的问题. Stacke ...

  3. #include <stdint.h>

    stdint.h是c99中引进的一个标准C库的头文件. #include<stdio.h> #include<stdint.h> main() { /* 数据类型可以跨平台移植 ...

  4. Python 随即生成DAG(有向无环图)

    给校队选拔赛出了道DAG上的背包问题,需要生成DAG数据. 最开始使用的方法是先随机生成再判环,如果有环就重新生成.这种方法得到DAG的概率随着点数和边数的增加而急速降低,为了一个DAG要生成很多次, ...

  5. 套接字编程(VC_Win32)

    简介(源于维基) Berkeley套接字(也作BSD套接字应用程序接口)刚开始是4.2BSD Unix操作系统(于1983发布)的一套应用程序接口.然而,由于AT&T的专利保护着UNIX,所以 ...

  6. eclipse序列化生成serialVersionUID

    serialVersionUID作用: 序列化时为了保持版本的兼容性,即在版本升级时反序列化仍保持对象的唯一性. 如果你修改代码重新部署后出现序列化错误,可以考虑给相应的类增加serialVersio ...

  7. struts2在result中使用el表达式碰到的问题

    <result name="success">/html/portlet/ext/trainingmanagement/download_file.jsp?path=$ ...

  8. ajax防止重复提交请求1

    ajax防止重复提交请求 A. 独占型提交 只允许同时存在一次提交操作,并且直到本次提交完成才能进行下一次提交. module.submit = function() {   if (this.pro ...

  9. Android Studio常用小技巧

    1. Debug 模式查看变量的值: To quickly evaluate the value of any expression while debugging the program, hold ...

  10. css复合属性的写法

    # 复合属性也称为 "shortcut" property (快捷属性),它作用是为了简化代码,提高页面运行的效率. # 下面的内容会介绍 2 个比较常用的复合属性 "f ...