1 安装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.0
export CLASSPATH=.:$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:$JAVA_HOME/jre/lib/rt.jar
export 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 <stdio.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <netdb.h>
#include <unistd.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <openssl/err.h>
#include <openssl/ssl.h>
#include "org_gmssl_GmSSLClient.h"
#define Eprintf printf("[%s][%s][%d] ",__FILE__,__func__,__LINE__);printf
#define SSL_RECV_BUF 2048
static 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 <= 0) {
Eprintf("SSL_read err [%d:%s]", errno,strerror(errno));
goto _ErrorRet;
}
recv_buf[ret] = '\0';
recv = (*env)->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.1
HTTP/1.1 404 Not Found
Server: nginx/1.20.1
Date: Fri, 15 Apr 2022 15:46:51 GMT
Content-Type: text/html
Content-Length: 153
Connection: close
<html>
<head><title>404 Not Found</title></head>
<body>
<center><h1>404 Not Found</h1></center>
<hr><center>nginx/1.20.1</center>
</body>
</html>