国密SSL协议之Java编程

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

背景

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

环境

JRE是jre8。
国密JCE和国密JSSE。下载参 
https://www.gmssl.cn/gmssl/index.jsp?go=gmsdk
gmjce.jar和gmjsse.jar放到jre的lib/ext/目录下

源码

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;
            }
        }
    }
}

注释

首先要注册国密提供者

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);

是不是比想象中要简单?

测试运行

>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
...

小结

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

目录
相关文章
|
安全 应用服务中间件 网络安全
Nginx SSL/TLS协议栈中配置深度解析与实践指南-优雅草卓伊凡
Nginx SSL/TLS协议栈中配置深度解析与实践指南-优雅草卓伊凡
848 0
Nginx SSL/TLS协议栈中配置深度解析与实践指南-优雅草卓伊凡
|
安全 网络安全 数据安全/隐私保护
HTTP 与 HTTPS 协议及 SSL 证书解析-http和https到底有什么区别?-优雅草卓伊凡
HTTP 与 HTTPS 协议及 SSL 证书解析-http和https到底有什么区别?-优雅草卓伊凡
797 3
|
算法 安全 应用服务中间件
云上部署WoSign SSL“国密RSA双证书”,助力国密合规建设
我国网络安全法规体系不断完善,形成了以《网络安全法》为核心的立体化法律框架。阿里云数字证书管理服务提供国产品牌SSL证书,支持签发基于国密算法的SSL/TLS证书,助力金融、政务等行业满足“网络与通信安全”合规需求。通过部署WoSign SSL国密RSA双证书方案,实现国际和国密算法自适应兼容,确保信息系统全球通用性与安全性。2025年3月阿里云“智惠采购季”活动期间,用户可享受SSL证书优惠折扣,助力信息安全建设。
564 2
云上部署WoSign SSL“国密RSA双证书”,助力国密合规建设
|
算法 应用服务中间件 网络安全
阿里云WoSign“国密RSA双SSL证书”应用实践
阿里云WoSign品牌SSL证书是阿里云平台热销的国产品牌证书之一,支持签发国密合规的SM2算法SSL证书以及全球信任的RSA算法SSL证书,能够满足平台用户不同的SSL证书应用需求,同时为用户提供国密模块支持,实现“国密/RSA双证书部署”。
1719 6
阿里云WoSign“国密RSA双SSL证书”应用实践
|
安全 算法 网络安全
SSL/TLS协议是什么?
SSL/TLS协议是什么?
2044 57
|
Java 网络安全 Maven
Exception in thread "main" java.lang.NoSuchMethodError: okhttp3.OkHttpClient$Builder.sslSocketFactory(Ljavax/net/ssl/SSLSocketFactory;Ljavax/net/ssl/X509TrustManager;)Lokhttp3/OkHttpClient$Builder; 问题处理
【10月更文挑战第26天】Exception in thread "main" java.lang.NoSuchMethodError: okhttp3.OkHttpClient$Builder.sslSocketFactory(Ljavax/net/ssl/SSLSocketFactory;Ljavax/net/ssl/X509TrustManager;)Lokhttp3/OkHttpClient$Builder; 问题处理
835 2
|
算法 小程序 网络安全
阿里云WoSign SSL证书,RSA和国密有什么区别?_沃通SSL技术文档
阿里云WoSign品牌SSL证书为用户提供国密合规SM2算法SSL证书、全球信任RSA算法SSL证书,全球信任、国密合规,能够满足阿里云平台用户不同的SSL证书应用需求。那么阿里云WoSign SSL证书分别提供的RSA算法和国密算法,有什么区别呢?
1235 6
|
JavaScript 安全 Java
谈谈UDP、HTTP、SSL、TLS协议在java中的实际应用
下面我将详细介绍UDP、HTTP、SSL、TLS协议及其工作原理,并提供Java代码示例(由于Deno是一个基于Node.js的运行时,Java代码无法直接在Deno中运行,但可以通过理解Java示例来类比Deno中的实现)。
384 1
|
消息中间件 安全 Kafka
Kafka支持SSL/TLS协议技术深度解析
SSL(Secure Socket Layer,安全套接层)及其继任者TLS(Transport Layer Security,传输层安全)是为网络通信提供安全及数据完整性的一种安全协议。这些协议在传输层对网络连接进行加密,确保数据在传输过程中不被窃取或篡改。
1386 0
|
算法 Java 测试技术
java 访问ingress https报错javax.net.ssl.SSLHandshakeException: Received fatal alert: protocol_version
java 访问ingress https报错javax.net.ssl.SSLHandshakeException: Received fatal alert: protocol_version
2569 1