JKS证书异常导致SSL通讯加密异常

转载请注明出处:http://www.cnblogs.com/apm70

最近在对Andriod客户端与服务器socket通讯链路进行SSL加密时,服务器端在读取“.jks”证书时总是报下面的异常,很是苦恼。

 1 java.security.cert.CertificateException: Could not parse certificate: java.io.IOException: DerInputStream.getLength(): lengthTag=109, too big.
 2     at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:109)
 3     at java.security.cert.CertificateFactory.generateCertificate(CertificateFactory.java:305)
 4     at test.socket.SocketServerWithSSL.loadKeyStore(SocketServerWithSSL.java:85)
 5     at test.socket.SocketServerWithSSL.init(SocketServerWithSSL.java:38)
 6     at test.socket.SocketServerWithSSL.main(SocketServerWithSSL.java:130)
 7 Caused by: java.io.IOException: DerInputStream.getLength(): lengthTag=109, too big.
 8     at sun.security.util.DerInputStream.getLength(DerInputStream.java:544)
 9     at sun.security.util.DerValue.init(DerValue.java:347)
10     at sun.security.util.DerValue.<init>(DerValue.java:303)
11     at sun.security.provider.X509Factory.engineGenerateCertificate(X509Factory.java:104)
12     ... 4 more

开始以为是服务器端代码写得有问题,但经过排查,否定了这个假设。看来问题出在证书格式上面了。

在开发的过程中图方便,让客户端的同学把双向认证的证书密钥都一并生成了,也就是说两对密钥都是由客户端的同学生成的,那会不会是他们生成的文件有问题呢?答案是肯定的。

当时客户端提供的两对密钥文件是酱紫滴:

根据客户端滴同事反馈,andriod客户端在读取client端的两个.bks文件没有问题,看来问题就出在服务器端的两个.jks文件了。

那就来验证下吧,先尝试着自己生成两对.keystore文件先,生成这个用来验证下通讯正常的情况。

利用keytool工具生成我们所需要的文件。

1.生成服务器端私钥:

keytool -genkey -alias serverkey -keystore kserver.keystore

其中红色标注的部分可自定义,kserver.keystore就是存储服务器私钥的容器,下同。

在输入keystore密码及姓名、组织等参数后,输入y确认即可。

2.导出服务器端公钥(证书):

keytool -export -alias serverkey -keystore kserver.keystorefile server.crt

输入密码后即可导出公钥

3.将服务器端的公钥(证书)导入到客户端的Trust Keystore中:

keytool -import -alias serverkey -file server.crt -keystore tclient.keystore

在输入keystore密码后,输入y确认即可。

4.生成客户端私钥:

keytool -genkey -alias clientkey -keystore kclient.keystore

5.导出客户端公钥(证书):

keytool -export -alias clientkey -keystore kclient.keystorefile client.crt

6.将客户端的公钥(证书)导入到服务器端的Trust Keystore中:

keytool -import -alias clientkeyfile client.crt -keystore tserver.keystore

具体测试代码见本文末尾。

使用测试客户端(非andriod客户端,因为andriod证书生成还需BKS包)及服务端通讯正常,再一次证明代码逻辑正常。

将验证正确的两对.keystore及两个.crt文件交给客户端同事生成.bks(for client)及.jks(for server),出现问题。看来开始猜测得没错。

 

定位到问题,接下来就来解决它吧。

从.keystore文件的测试情况看,密钥对是没有问题的,问题出在存储密钥的容器上,即.bks及.jks上,由于服务器端的.jks是客户端生成的(使用了BKS包),导致服务器端在读取.jks文件时异常。

 

我们来梳理下公钥(证书)的交换及导入过程:

由于客户端(android)与服务器端生成证书的格式不同,客户端最终生成的证书格式为.bks(andriod必需),服务器端为.keystore。

 

根据这次生成的证书联调,结果正常。问题解决。


附测试SSL服务端及客户端代码:

1.客户端:

  1 /**
  2  * 
  3  */
  4 package test.socket;
  5 
  6 import java.io.BufferedInputStream;
  7 import java.io.BufferedOutputStream;
  8 import java.io.FileInputStream;
  9 import java.io.IOException;
 10 import java.io.InputStream;
 11 import java.io.OutputStream;
 12 import java.security.KeyStore;
 13 
 14 import javax.net.ssl.KeyManagerFactory;
 15 import javax.net.ssl.SSLContext;
 16 import javax.net.ssl.SSLSocket;
 17 import javax.net.ssl.TrustManagerFactory;
 18 
 19 /**
 20  * @author Administrator
 21  * 
 22  */
 23 public class SocketSSLClient {
 24 
 25     private static final String DEFAULT_HOST = "127.0.0.1";
 26     private static final int DEFAULT_PORT = 7777;
 27 
 28     private static final String CLIENT_KEY_STORE_PASSWORD = "123456";
 29     private static final String CLIENT_TRUST_KEY_STORE_PASSWORD = "123456";
 30 
 31     private static final String PRIVATE_KEY_CLIENT = "D:\\test\\kclient.keystore";
 32     private static final String TRUST_KEY_CLIENT = "D:\\test\\tclient.keystore";
 33 
 34     private SSLSocket sslSocket;
 35 
 36     /**
 37      * 启动客户端程序
 38      * 
 39      * @param args
 40      */
 41     public static void main(String[] args) {
 42         SocketSSLClient client = new SocketSSLClient();
 43         client.init();
 44         client.process();
 45     }
 46 
 47     public void process() {
 48         String msg = "hello world";
 49         if (sslSocket == null) {
 50             System.out.println("ERROR");
 51             return;
 52         }
 53         try {
 54             InputStream input = sslSocket.getInputStream();
 55             OutputStream output = sslSocket.getOutputStream();
 56 
 57             BufferedInputStream bis = new BufferedInputStream(input);
 58             BufferedOutputStream bos = new BufferedOutputStream(output);
 59 
 60             bos.write(msg.getBytes());
 61             bos.flush();
 62 
 63             byte[] buffer = new byte[20];
 64             bis.read(buffer);
 65             System.out.println(new String(buffer));
 66 
 67             sslSocket.close();
 68         } catch (IOException e) {
 69             System.out.println(e);
 70         }
 71     }
 72 
 73     public void init() {
 74         try {
 75             SSLContext ctx = SSLContext.getInstance("SSL");
 76 
 77             KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
 78             TrustManagerFactory tmf = TrustManagerFactory
 79                     .getInstance("SunX509");
 80 
 81             KeyStore ks = KeyStore.getInstance("JKS");
 82             KeyStore tks = KeyStore.getInstance("JKS");
 83 
 84             ks.load(new FileInputStream(PRIVATE_KEY_CLIENT),
 85                     CLIENT_KEY_STORE_PASSWORD.toCharArray());
 86             tks.load(new FileInputStream(TRUST_KEY_CLIENT),
 87                     CLIENT_TRUST_KEY_STORE_PASSWORD.toCharArray());
 88 
 89             kmf.init(ks, CLIENT_KEY_STORE_PASSWORD.toCharArray());
 90             tmf.init(tks);
 91 
 92             ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
 93 
 94             sslSocket = (SSLSocket) ctx.getSocketFactory().createSocket(
 95                     DEFAULT_HOST, DEFAULT_PORT);
 96         } catch (Exception e) {
 97             System.out.println(e);
 98         }
 99     }
100 
101 }

2.服务器端:

  1 /**
  2  * 
  3  */
  4 package test.socket;
  5 
  6 import java.io.BufferedInputStream;
  7 import java.io.BufferedOutputStream;
  8 import java.io.FileInputStream;
  9 import java.io.InputStream;
 10 import java.io.OutputStream;
 11 import java.net.Socket;
 12 import java.security.KeyStore;
 13 
 14 import javax.net.ssl.KeyManagerFactory;
 15 import javax.net.ssl.SSLContext;
 16 import javax.net.ssl.SSLServerSocket;
 17 import javax.net.ssl.TrustManagerFactory;
 18 
 19 /**
 20  * @author Administrator
 21  * 
 22  */
 23 public class SocketSSLServer implements Runnable {
 24 
 25     private static final int DEFAULT_PORT = 7777;
 26 
 27     private static final String SERVER_KEY_STORE_PASSWORD = "123456";
 28     private static final String SERVER_TRUST_KEY_STORE_PASSWORD = "123456";
 29 
 30     private static final String PRIVATE_KEY_SERVER = "D:\\test\\kserver.keystore";
 31     private static final String TRUST_KEY_SERVER = "D:\\test\\tserver.keystore";
 32 
 33     private SSLServerSocket serverSocket;
 34 
 35     /**
 36      * 启动程序
 37      * 
 38      * @param args
 39      */
 40     public static void main(String[] args) {
 41         SocketSSLServer server = new SocketSSLServer();
 42         server.init();
 43         Thread thread = new Thread(server);
 44         thread.start();
 45     }
 46 
 47     public synchronized void start() {
 48         if (serverSocket == null) {
 49             System.out.println("ERROR");
 50             return;
 51         }
 52         while (true) {
 53             try {
 54                 Socket s = serverSocket.accept();
 55                 InputStream input = s.getInputStream();
 56                 OutputStream output = s.getOutputStream();
 57 
 58                 BufferedInputStream bis = new BufferedInputStream(input);
 59                 BufferedOutputStream bos = new BufferedOutputStream(output);
 60 
 61                 byte[] buffer = new byte[20];
 62                 bis.read(buffer);
 63                 System.out.println("------receive:--------"
 64                         + new String(buffer).toString());
 65 
 66                 bos.write("yes".getBytes());
 67                 bos.flush();
 68 
 69                 s.close();
 70             } catch (Exception e) {
 71                 System.out.println(e);
 72             }
 73         }
 74     }
 75 
 76     public void init() {
 77         try {
 78             SSLContext ctx = SSLContext.getInstance("SSL");
 79 
 80             KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
 81             TrustManagerFactory tmf = TrustManagerFactory
 82                     .getInstance("SunX509");
 83 
 84             KeyStore ks = KeyStore.getInstance("JKS");
 85             KeyStore tks = KeyStore.getInstance("JKS");
 86 
 87             ks.load(new FileInputStream(PRIVATE_KEY_SERVER),
 88                     SERVER_KEY_STORE_PASSWORD.toCharArray());
 89             tks.load(new FileInputStream(TRUST_KEY_SERVER),
 90                     SERVER_TRUST_KEY_STORE_PASSWORD.toCharArray());
 91 
 92             kmf.init(ks, SERVER_KEY_STORE_PASSWORD.toCharArray());
 93             tmf.init(tks);
 94 
 95             ctx.init(kmf.getKeyManagers(), tmf.getTrustManagers(), null);
 96 
 97             serverSocket = (SSLServerSocket) ctx.getServerSocketFactory()
 98                     .createServerSocket(DEFAULT_PORT);
 99             serverSocket.setNeedClientAuth(true);
100         } catch (Exception e) {
101             System.out.println(e);
102         }
103     }
104 
105     public void run() {
106         // TODO Auto-generated method stub
107         start();
108     }
109 }

转载于:https://www.cnblogs.com/apm70/archive/2012/08/13/SSL%e9%93%be%e8%b7%af%e5%8a%a0%e5%af%86.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值