Android平台通过HttpClient调用国密SSL密码套件访问国密HTTPS安全服务的详细方法介绍

系统要求
Android 7.0(API 24)及以上 

功能介绍

  1. 单向认证,客户端不需要国密证书和密钥
  2. 接收并显示服务器端国密数字证书
  3. 忽略服务端域名与国密证书不一致的警告
  4. 忽略不信任服务端国密根证书的警告
  5. 使用PP软件授权平台获取授权数据的简要说明  

核心代码

/**
 *
 */
package com.pplic.android.sample.doublecasseandroidlibproject;

import java.io.FileInputStream;
import java.io.IOException;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.SecureRandom;
import java.security.Security;
import java.security.UnrecoverableKeyException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import org.apache.commons.collections4.MapUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.NameValuePair;
import org.apache.http.StatusLine;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnManagerParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.CoreConnectionPNames;
import org.apache.http.params.CoreProtocolPNames;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;

import doubleca.security.gmssl.provider.DoubleCASSE;
import doubleca.security.provider.DoubleCA;

/**
 * @author www.DoubleCA.com
 */
public class HttpClientUtil
{
    private static final String ENCODING = "UTF-8";

    private static HttpClient client = null;
    private static SchemeRegistry schemeRegistry; // 协议控制
    private static PoolingClientConnectionManager ccm; // HttpClient连接池(多连接的线程安全的管理器)

    private static DoubleCASSE dcsse = null;

    /**
     * 用授权数据初始化dcsse
     */
    public boolean initLic(DoubleCASSE obj, String licData)
    {
        dcsse = obj;
        // 获得的本机授权数据,在https://www.PPLIC.com软件授权平台获取
        if (licData == null)
        {
            // 未授权,生成授权请求数据,与授权码一起在PP软件授权平台生成终端的授权数据,也可以请求PP软件授权平台的网络API在线申请授权数据
            StringBuffer requestDataBuffer = new StringBuffer();
            dcsse.generateLicRequest(requestDataBuffer);
            System.out.println("Android终端授权请求数据:" + requestDataBuffer.toString());
            return false;
        }
        else
        {
            dcsse.setLicData(licData);
            Date licDate = dcsse.getLicEndTime();
            if (licDate == null)
            {
                System.out.println("非法授权数据!");
                return false;
            }
            else
            {
                System.out.println("授权有效期:" + dcsse.getLicEndTime().toLocaleString());
                initClient();
                return true;
            }
        }
    }

    private void initClient()
    {
        try
        {
            /*
             * 与https请求相关的操作
             */
            KeyStore sm2ClientKeyStore = KeyStore.getInstance("DCKS");
            sm2ClientKeyStore.load(null, null);
            SSLSocketFactory sf = new SSLSocketFactoryEx(sm2ClientKeyStore);
            sf.setHostnameVerifier(SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);  //允许所有主机的验证
            HttpParams httpParams = new BasicHttpParams();
            httpParams.setParameter(CoreConnectionPNames.CONNECTION_TIMEOUT, 1000);// 连接超时时间(ms)
            httpParams.setParameter(CoreConnectionPNames.SO_TIMEOUT, 2000);// 操作超时时间(ms)
            httpParams.setParameter(CoreProtocolPNames.PROTOCOL_VERSION, HttpVersion.HTTP_1_1);// 设置http1.1或http1.0
            // 设置http https支持
            /*
             * 定义访问协议
             */
            SchemeRegistry schReg = new SchemeRegistry();
            schReg.register(new Scheme("http", PlainSocketFactory.getSocketFactory(), 80));
            schReg.register(new Scheme("https", sf, 443));

            ClientConnectionManager conManager = new ThreadSafeClientConnManager(httpParams, schReg);
            client = new DefaultHttpClient(conManager, httpParams);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    /**
     * get请求
     *
     * @param url       请求URL
     * @param paramMap  请求参数
     * @param headerMap 请求头信息
     */
    public String get(String url, Map paramMap, Map headerMap) throws ClientProtocolException, IOException
    {
        /*
         * 拼接URL与参数
         */
        if (MapUtils.isNotEmpty(paramMap))
        {
            List params = new ArrayList();
            for (String key : paramMap.keySet())
            {
                params.add(new BasicNameValuePair(key, paramMap.get(key)));
            }
            String queryString = URLEncodedUtils.format(params, ENCODING);
            if (url.indexOf("?") > -1)
            {// 存在?,表示这时的URL已经带参数了
                url += "&" + queryString;
            }
            else
            {
                url += "?" + queryString;
            }
        }

        HttpGet httpGet = new HttpGet(url);

        /*
         * 设置头信息
         */
        if (MapUtils.isNotEmpty(headerMap))
        {
            Set keySet = headerMap.keySet();
            for (String key : keySet)
            {
                httpGet.addHeader(key, headerMap.get(key));
            }
        }

        String result = "";

        HttpResponse response = client.execute(httpGet); // 发出get请求
        StatusLine status = response.getStatusLine(); // 获取返回的状态码
        HttpEntity entity = response.getEntity(); // 获取返回的响应内容
        if (status.getStatusCode() == HttpStatus.SC_OK)
        { // 200
            result = EntityUtils.toString(entity, ENCODING);
        }

        httpGet.abort();// 中止请求,连接被释放回连接池
        return result;
    }

    /**
     * post请求
     *
     * @param url       //请求URL
     * @param paramMap  //请求参数
     * @param headerMap //请求头信息
     */
    public String post(String url, Map paramMap, Map headerMap) throws ClientProtocolException, IOException
    {
        HttpPost httpPost = new HttpPost(url);
        /*
         * 处理参数
         */
        List params = new ArrayList();
        if (MapUtils.isNotEmpty(paramMap))
        {
            Set keySet = paramMap.keySet();
            for (String key : keySet)
            {
                params.add(new BasicNameValuePair(key, paramMap.get(key)));
            }
        }
        /*
         * 设置头信息
         */
        if (MapUtils.isNotEmpty(headerMap))
        {
            Set keySet = headerMap.keySet();
            for (String key : keySet)
            {
                httpPost.addHeader(key, headerMap.get(key));
            }
        }

        String result = "";

        httpPost.setEntity(new UrlEncodedFormEntity(params, ENCODING));// 设置参数
        HttpResponse response = client.execute(httpPost); // 发出post请求
        StatusLine status = response.getStatusLine(); // 获取返回的状态码
        HttpEntity entity = response.getEntity(); // 获取响应内容
        if (status.getStatusCode() == HttpStatus.SC_OK)
        {
            result = EntityUtils.toString(entity, ENCODING);
        }

        httpPost.abort();// 中止请求,连接被释放回连接池
        return result;
    }

    class SSLSocketFactoryEx extends SSLSocketFactory
    {
        SSLContext sslContext = null;

        public SSLSocketFactoryEx(KeyStore truststore) throws NoSuchAlgorithmException, KeyManagementException, KeyStoreException, UnrecoverableKeyException, NoSuchProviderException
        {
            super(truststore);
            sslContext = SSLContext.getInstance("GMSSLv1.1", DoubleCASSE.PROVIDER_NAME);
            TrustManager tm = new X509TrustManager()
            {
                @Override
                public java.security.cert.X509Certificate[] getAcceptedIssuers()
                {
                    return null;
                }
                @Override
                public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException
                {
                }
                @Override
                public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) throws java.security.cert.CertificateException
                {
                    System.out.println("服务端国密证书信息:");
                    for (int i = 0; i < chain.length; i++)
                    {
                        System.out.println(chain[i].getSubjectDN().getName());
                    }
                }
            };
            sslContext.init(null, new TrustManager[]{tm}, null);
        }

        @Override
        public Socket createSocket(Socket socket, String host, int port, boolean autoClose) throws IOException, UnknownHostException
        {
            return sslContext.getSocketFactory().createSocket(socket, host, port, autoClose);
        }

        @Override
        public Socket createSocket() throws IOException
        {
            return sslContext.getSocketFactory().createSocket();
        }
    }
}

Android平台运行结果

Android平台通过HttpClient调用国密SSL密码套件访问国密HTTPS安全服务的详细方法介绍_第1张图片

国密数字证书

DCKS国密SSL通信证书和密钥文件在 大宝CA https://www.DoubleCA.com 网站上免费申请

 

学习交流与商业授权

Android版本国密SSL协议密码套件的商业应用需要大宝CA的授权许可,有如下两种方式进行授权:

1. 离线授权,通过访问PP商业软件自主授权平台:https://www.PPLIC.com,在页面上进行人工授权
2. 在线授权,通过调用PP商业软件自主授权平台的网络授权服务API函数可自动获取Android终端的授权数据

 

库文件和示例代码的下载

Android平台通过HttpClient调用大宝CA国密SSL密码套件访问国密HTTPS安全服务示例代码的下载地址:https://download.csdn.net/download/upset_ming/11729467

你可能感兴趣的:(Android平台通过HttpClient调用国密SSL密码套件访问国密HTTPS安全服务的详细方法介绍)