基于GmSSL的国密SSL单向验证客户端Java源码/JNI
1 安装GmSSL和搭建测试Nginx服务器
基于GmSSL搭建Nginx国密反代服务器
2 安装openJDK
> yum install -y java-1.8.0-openjdk.x86_64 java-1.8.0-openjdk-devel.x86_64>vi $HOME/.bashrc# 添加环境变量export JAVA_HOME=/usr/lib/jvm/java-1.8.0export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/jre/lib/rt.jarexport PATH=$PATH:$JAVA_HOME/bin> source .bashrc
3 GmSSLClient.java
文件路径:GmSSL-master/java/GmSSLClient.java
package org.gmssl;public class GmSSLClient { public native String exec(String host, int port, String send, int timeout); static { System.loadLibrary("gmsslclientjni"); } public static void main(String args[]){ GmSSLClient client = new GmSSLClient(); String ip = "192.168.218.141"; int port = 1443; int timeout = 10; String body = "{\"loginName\":\"jiean\"}"; String send; String recv; send = "POST /horn/pushmsg HTTP/1.1\r\n" + "Accept: */*\r\n" + "Accept-Language: zh-cn\r\n" + "Content-Type: application/json\r\n" + "User-Agent: herve\r\n" + "Host: "+ip+":"+port+"\r\n" + "Content-Length: "+body.length()+"\r\n" + "Connection: close\r\n" + "Cache-Control: no-cache\r\n\r\n" + body; recv = client.exec(ip,port,send,timeout); if (null == recv) { System.out.println("exec error"); } else { System.out.println(recv); } }}
编译代码
> cd GmSSL-master/java> javac -d . GmSSLClient.java> javah org.gmssl.GmSSLClient # 生成 org_gmssl_GmSSLClient.h
4 org_gmssl_GmSSLClient.c
文件路径:GmSSL-master/java/org_gmssl_GmSSLClient.c
#include #include #include #include #include #include #include #include #include #include #include #include "org_gmssl_GmSSLClient.h"#define Eprintf printf("[%s][%s][%d] ",__FILE__,__func__,__LINE__);printf#define SSL_RECV_BUF 2048static int ssl_alarm_flag;#define SSL_IS_TIMEOUT (-1 == ssl_alarm_flag)static void ssl_sigset_alarm(int sig){ssl_alarm_flag = -1; alarm(0); signal(SIGALRM, SIG_DFL);}static void ssl_set_alarm(int time_out){ssl_alarm_flag = 0;signal(SIGALRM , ssl_sigset_alarm);alarm(time_out);}static void ssl_unset_alarm(void){ alarm(0); signal(SIGALRM, SIG_DFL);}JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved){SSLeay_add_ssl_algorithms(); SSL_load_error_strings();return JNI_VERSION_1_2;}JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved){}/* * Class: org_gmssl_GmSSLClient * Method: exec * Signature: (Ljava/lang/String;ILjava/lang/String;)Ljava/lang/String; */JNIEXPORT jstring JNICALL Java_org_gmssl_GmSSLClient_exec (JNIEnv *env, jobject this, jstring ip, jint port, jstring send, jint time_out){jstring recv = NULL;int ret;int client_fd = -1; int total_len = 0; int len= 0; struct sockaddr_in stSockAddr; char recv_buf[SSL_RECV_BUF]; SSL_CTX *ctx = NULL; SSL*ssl = NULL;const SSL_METHOD *meth = NULL; char *c_ip = (char*)(*env)->GetStringUTFChars(env, ip, NULL); char *c_send = (char*)(*env)->GetStringUTFChars(env, send, NULL); meth = GMTLS_client_method(); //使用GMTLSv1.1协议 //meth = SSLv23_client_method(); //ssl协议版本,v2,v3 自适应 if(meth == NULL) { Eprintf("SSLv23_client_method err [%d:%s]\n", errno,strerror(errno)); ret = -1; goto _ErrorRet; } ctx = SSL_CTX_new(meth); //申请SSL会话环境 if(NULL == ctx) { Eprintf("SSL_CTX_new err [%d:%s]\n", errno,strerror(errno)); goto _ErrorRet; } //建立普通的TCP连接 client_fd = socket(AF_INET, SOCK_STREAM, 0); if(client_fd < 0) { Eprintf("socket fail, err[%d:%s]\n", errno, strerror(errno)); goto _ErrorRet; } memset(&stSockAddr, 0, sizeof(stSockAddr)); stSockAddr.sin_family = AF_INET; stSockAddr.sin_port = htons(port); stSockAddr.sin_addr.s_addr = inet_addr(c_ip); Eprintf("connect[%s:%d]\n" , c_ip, port); ssl_set_alarm(time_out); ret = connect(client_fd,(struct sockaddr *) &stSockAddr, sizeof(stSockAddr)); ssl_unset_alarm(); if (SSL_IS_TIMEOUT) { Eprintf("connect server[%s:%d] time out\n", c_ip,port);goto _ErrorRet; } else if(ret != 0) { Eprintf("connect server[%s:%d] fail, err[%d:%s]\n", c_ip, port, errno, strerror(errno)); goto _ErrorRet; } ssl = SSL_new(ctx); //创建SSL套接字 if(NULL == ssl) { Eprintf("SSL_new err [%d:%s]\n", errno,strerror(errno)); goto _ErrorRet; } SSL_set_fd(ssl, client_fd); //将TCP套接字与SSL套接字联系起来 ssl_set_alarm(time_out); ret = SSL_connect(ssl); //启动SSL链接 ssl_unset_alarm();if (SSL_IS_TIMEOUT) {Eprintf("SSL_connect [%s:%d] time out\n", c_ip,port);goto _ErrorRet;} else if(ret <= 0) { ERR_print_errors_fp(stderr); Eprintf("SSL_connect ret[%d][%d:%s]\n", ret, errno, strerror(errno)); goto _ErrorRet; } total_len = strlen(c_send); len= 0; while (len < total_len) { ssl_set_alarm(time_out);ret = SSL_write(ssl, c_send+len, total_len-len);ssl_unset_alarm();if (SSL_IS_TIMEOUT) {Eprintf("SSL_write server[%s:%d] time out\n", c_ip,port);goto _ErrorRet;} else if(ret <= 0) {Eprintf("SSL_write err [%d:%s]\n", errno,strerror(errno));goto _ErrorRet;}len += ret; } ssl_set_alarm(time_out);ret = SSL_read(ssl, recv_buf, SSL_RECV_BUF-1);ssl_unset_alarm();if (SSL_IS_TIMEOUT) {Eprintf("SSL_read server[%s:%d] time out\n", c_ip,port);goto _ErrorRet;} else if(ret NewStringUTF(env, recv_buf);_ErrorRet:if(NULL != ssl) {SSL_shutdown(ssl); //结束SSL通信SSL_free(ssl); //释放SSL套接字}if(-1 != client_fd) {close(client_fd);}if(NULL != ctx) {SSL_CTX_free(ctx); //释放SSL会话环境} /*通知虚拟机平台相关代码无需再访问*/(*env)->ReleaseStringUTFChars(env, ip, c_ip);(*env)->ReleaseStringUTFChars(env, ip, c_send);return recv;}
编译代码:
>gcc -shared -fPIC -Wall -I./jni org_gmssl_GmSSLClient.c -lcrypto -lssl -o libgmsslclientjni.so
5 执行HTTPS请求
> java -Djava.library.path=./ org.gmssl.GmSSLClient
[org_gmssl_GmSSLClient.c][Java_org_gmssl_GmSSLClient_exec][106] connect[192.168.218.141:1443][org_gmssl_GmSSLClient.c][Java_org_gmssl_GmSSLClient_exec][141] SSL using cipher : SM2-WITH-SMS4-SM3[org_gmssl_GmSSLClient.c][Java_org_gmssl_GmSSLClient_exec][142] SSL using cipher_name : SM2-WITH-SMS4-SM3[org_gmssl_GmSSLClient.c][Java_org_gmssl_GmSSLClient_exec][143] SSL using cipher_version: GMTLSv1.1HTTP/1.1 404 Not FoundServer: nginx/1.20.1Date: Fri, 15 Apr 2022 15:46:51 GMTContent-Type: text/htmlContent-Length: 153Connection: close404 Not Found 404 Not Found
nginx/1.20.1