专栏首页国密SSL集成国密SSL协议之Java编程
原创

国密SSL协议之Java编程

1 背景

Java自身通过JCE和JSSE支持标准的SSL协议,但并不支持国密SSL协议。本文描述了Java使用国密JCE和国密JSSE开发一个简单的客户端程序,连接国密Web网站,发送HTTP请求,并接收HTTP应答。

2 环境

JRE是jre8。

国密JCE和国密JSSE。下载参https://www.gmssl.cn/gmssl/index.jsp?go=gmsdk

gmjce.jar和gmjsse.jar放到jre的lib/ext/目录下

3 源码

package cn.gmssl.test;

import java.net.*;
import java.io.*;
import java.security.*;
import java.security.cert.*;

import javax.net.*;
import javax.net.ssl.*;

public class SocketGet
{
 public static void main(String[] args)
 {
   SocketFactory fact = null;
   SSLSocket socket = null;

   String addr = "ebssec.boc.cn";
   int port = 443;
   String uri = "/";
 
 try
{
  if(args.length > 0)
{
   addr = args[0];
   port = Integer.parseInt(args[1]);
   uri = args[2];
}

   System.out.println("\r\naddr="+addr);
   System.out.println("port="+port);
   System.out.println("uri="+uri);
   
  // 加载国密提供者
   Security.insertProviderAt(new cn.gmssl.jce.provider.GMJCE(), 1);
   Security.insertProviderAt(new cn.gmssl.jsse.provider.GMJSSE(), 2);
  
   fact = createSocketFactory(null, null);
   socket = (SSLSocket)fact.createSocket();
   socket.setTcpNoDelay(true);
  
   System.out.println("\r\nGM SSL connecting...");
   socket.connect(new InetSocketAddress(addr, port), 5000);
   socket.setTcpNoDelay(true);
   socket.startHandshake();
   
   System.out.println("Connected!\n");
   
   DataInputStream in = new DataInputStream(socket.getInputStream());
   OutputStream out = socket.getOutputStream();
   
   String s = "GET " + uri + " HTTP/1.1\r\n";
   s+= "Accept: */*\r\n";
   s+= "User-Agent: Mozilla/4.0 (compatible; MSIE 8.0; Windows NT 5.1; Trident/4.0)\r\n";
   s+= "Host: " + addr + (port == 443 ? "" : ":"+port) + "\r\n";
   s+= "Connection: Close\r\n";
   s+= "\r\n";
   out.write(s.getBytes());
   out.flush();
   
   // 读取HTTP头
   while(true)
   {
     byte[] lineBuffer = ReadLine.read(in);
     if ( lineBuffer == null || lineBuffer.length == 0)
     {
     System.out.println();
    break;
     }
     String line = new String(lineBuffer);
     System.out.println(line);
   }
   // 读取HTTP内容
   {
   byte[] buf = new byte[1024];
   while(true)
   {
    int len = in.read(buf);
    if(len == -1)
    {
    break;
    }
    System.out.println(new String(buf, 0, len));
   }
   }
  in.close();
  out.close();
 }
 catch(Exception e)
 {
 e.printStackTrace();
 }
 finally
 {
    try
    {
    socket.close();
    }
    catch(Exception e)
    {}
 }
 }
 private static SSLSocketFactory createSocketFactory(KeyStore kepair, char[] pwd) throws Exception
  {
  X509TrustManager[] trust = { new MyTrustAllManager() };
    KeyManager[] kms = null;
   if (kepair != null)
   {
   KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
   kmf.init(kepair, pwd);
   kms = kmf.getKeyManagers();
  }
  // 使用国密SSL
  String protocol = cn.gmssl.jsse.provider.GMJSSE.GMSSLv11;
  String provider = cn.gmssl.jsse.provider.GMJSSE.NAME;
  SSLContext ctx = SSLContext.getInstance(protocol, provider);
  java.security.SecureRandom secureRandom = new java.security.SecureRandom();
  ctx.init(kms, trust, secureRandom);
  SSLSocketFactory factory = ctx.getSocketFactory();
  return factory;
  }
}
class MyTrustAllManager implements X509TrustManager
{
 private X509Certificate[] issuers;
 public MyTrustAllManager()
 {
 this.issuers = new X509Certificate[0];
 }
 public X509Certificate[] getAcceptedIssuers()
 {
 return issuers ;
 }
 public void checkClientTrusted(X509Certificate[] chain, String authType)
 {}
 public void checkServerTrusted(X509Certificate[] chain, String authType)
 {}
}
class ReadLine
{
 public static final byte[] CRLF = {'\r', '\n'};
 public static final byte CR = '\r';
 public static final byte LF = '\n';
 private static final int LINE_MAX_SIZE = 16384;
 public static byte[] read(DataInputStream in) throws IOException, SocketException
 {
 ByteArrayOutputStream baos = new ByteArrayOutputStream();
 DataOutputStream s = new DataOutputStream(baos);
 boolean previousIsCR = false;
 int len = 0;
 byte b = 0;
 try
 {
 b = in.readByte();
 len ++;
 }
 catch(EOFException e)
 {
    return new byte[0];
 }
 while(true)
 {
 if(b == LF)
 {
 if(previousIsCR)
 {
 s.flush();
 byte[] rs = baos.toByteArray();
 s.close();
 return rs;
 }
 else
 {
 s.flush();
 byte[] rs = baos.toByteArray();
 s.close();
 return rs;
 }
 }
 else if(b == CR)
 {
 if(previousIsCR)
 {
 s.writeByte(CR);
 }
 previousIsCR = true;
 }
 else
 {
 if(previousIsCR)
 {
 s.writeByte(CR);
 }
 previousIsCR = false;
 s.write(b);
 }
 if(len > LINE_MAX_SIZE)
 {
   s.close();
 throw new IOException("Reach line size limit");
 }
 try
 {
 b = in.readByte();
 len ++;
 }
 catch(EOFException e)
 {
 s.flush();
 byte[] rs = baos.toByteArray();
 s.close();
 return rs;
 }
 }
 }
}

4 注释

首先要注册国密提供者

  Security.insertProviderAt(new cn.gmssl.jce.provider.GMJCE(), 1);
  Security.insertProviderAt(new cn.gmssl.jsse.provider.GMJSSE(), 2);

其中要使用国密SSL来连接

  String protocol = cn.gmssl.jsse.provider.GMJSSE.GMSSLv11;
  String provider = cn.gmssl.jsse.provider.GMJSSE.NAME;
  SSLContext ctx = SSLContext.getInstance(protocol, provider);

是不是比想象中要简单?

5 测试运行

java cn.gmssl.test.SocketGet
addr=ebssec.boc.cn
port=443
uri=/
GM SSL connecting...
Connected!
HTTP/1.1 200 OK
Date: Mon, 24 Aug 2020 03:45:28 GMT
Last-Modified: Sat, 27 Jun 2015 16:48:38 GMT
Accept-Ranges: bytes
Content-Length: 156
Cache-Control: max-age=300
Expires: Mon, 24 Aug 2020 03:50:28 GMT
Vary: Accept-Encoding,User-Agent
Connection: close
Content-Type: text/html
<!DOCTYPE html><html><head><meta http-equiv="refresh" content="0;url=/boc15/login.html"><meta name="renderer" content="ie-stand"></head><body></body></html>

6 小结

通过使用国密JCE和国密JSSE,Java很容易编程来使用国密SSL连接国密Web网站。gmssl.cn提供了全部免费的测试组件,并且支持双向国密SSL,可供学习和测试。

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 国密SSL协议之Nginx集成

    Nginx自身支持标准的SSL协议,但并不支持国密SSL协议。本文描述了Nginx配置的国密SSL协议(单向)的完整过程,仅供学习和参考之用。

    gmssl
  • 国密SSL协议之Tomcat集成

    Tomcat自身支持标准的SSL协议,但并不支持国密SSL协议。本文描述了Tomcat配置的国密SSL协议(单向)的完整过程,仅供学习和参考之用。

    gmssl
  • 国密SSL协议之Apache集成

    Apache httpd自身支持标准的SSL协议,但并不支持国密SSL协议。本文描述了Apache httpd配置的国密SSL协议(单向)的完整过程,仅供学习和...

    gmssl
  • 16.IO之其他流

    六月的雨
  • 直播软件开发底层搭建技术是如何实现的?

    对于直播软件开发的底层搭建技术,可能还有很多人不太了解。其实对于直播来讲,底层的搭建也是至关重要的部分,就像我们现实生活中盖楼一样,要先打好地基才可以继续搭建。...

    肉2466131704
  • 面试题66(StringBuffer)

    面试例题1:对于如下代码,以下哪一个结论是正确的? public class Foo { public static void main(String[] ...

    Java学习
  • Java总结IO篇之其他IO流对象

    张风捷特烈
  • 【适合收藏】为了多点时间陪女朋友,我向BAT大佬跪求了这15条JS技巧

    为了减少加班,从而挤出更多的时间来陪女朋友,我就厚着脸皮向一些BAT大佬求来了这15条JS技巧,现在分享给大家,千万别错过。

    童欧巴
  • 【适合收藏】为了多点时间陪女朋友,我向BAT大佬跪求了这15条JS技巧

    为了减少加班,从而挤出更多的时间来陪女朋友,我就厚着脸皮向一些BAT大佬求来了这15条JS技巧,现在分享给大家,千万别错过。

    刘小夕
  • 【JavaWeb基础】权限管理系统(修订版)

    现在我有一个管理商品、订单的页面。当用户点击某个超链接时,过滤器会检测该用户是否有权限!

    Java3y

扫码关注云+社区

领取腾讯云代金券