1、gmssl組成
分為加密和通信兩部分
2侵浸、加密
主要指的是sm2 sm3 sm4加密算法,以及相關(guān)的加密組件
3氢妈、通信
指的是gmtls
按照一個 GM/T 0024-2014規(guī)范實現(xiàn)的,采用雙證書精刷,簽名證書+加密證書
4魁巩、生成證書
可使用地址https://github.com/jntass/TASSL/tree/master/Tassl_demo/mk_tls_cert 下的SM2certgen.sh生成雙證書。
注意:生成請求時指定的摘要算法 在用請求生成證書時并不生效澳腹,需要重新指定,否則會使用默認的算法rsa-sha256
針對gmssl,簽名算法一定要是sm2sign-with-sm3
針對tassl,只要加密用的是sm2即可,sm2sign-with-sm3不是必須
5贯溅、兼容性
指的是gmssl對openssl的兼容性
ssl/tls下拄氯,僅支持有限的套件:
ECDHE-SM2-WITH-SMS4-SM3
ECDHE-SM2-WITH-SMS4-SHA256
不是完全兼容的
采用老的openssl證書,要指定tls版本為1或1.2才可以盗迟,或者直接使用TSLv1_2_method坤邪,使用TSL_method不可以,號稱的會自己檢測版本并沒有實現(xiàn)罚缕,貌似默認是使用1.1版本
6艇纺、雙證書
gmssl對雙證書和雙密鑰的設(shè)置
直接設(shè)置兩個sm2證書和密鑰就可以,沒有新增接口邮弹,都是代碼里自己適配:
keyusagedigitalSignature 類型的證書是簽名證書黔衡,否則是加密證書,密鑰呢,加密證書存在的時候是加密密鑰腌乡,否則是簽名密鑰
這個其實是有漏洞的盟劫,必須先設(shè)置簽名證書。与纽。然后才是加密證書
tassl是有的侣签,增加了一個設(shè)置加密密鑰的接口SSL_use_enc_PrivateKey,設(shè)置證書的接口也是代碼里適配的,證書類型需要keyusage(keyAgreementkeyEnciphermentdataEncipherment)
7急迂、版本
以上總結(jié)僅針對GmSSL最新版(v2.3.1)和tassl當前最新版(2018-09-17)
8影所、最新版的openssl已經(jīng)支持國密算法
僅僅支持國密的算法,通信還未支持
9僚碎、編程實現(xiàn)
server.c:
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <openssl/ssl.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>?
//#define CERTSERVER "/tmp/testopenssl/demoCA/cacert.pem"
//#define KEYSERVER "/tmp/testopenssl/demoCA/private/cakey.pem"
#define CERTSERVER "SS.pem"
#define KEYSERVER "SS.key.pem"
#define SM2_SERVER_ENC_CERT? ? "SE.pem"
#define SM2_SERVER_ENC_KEY? ? ? "SE.key.pem"
#define CHK_ERR(err, s) if((err) == -1) { perror(s); return -1; }else printf("%s? success!\n",s);
#define CHK_RV(rv, s) if((rv) != 1) { printf("%s error\n", s); return -1; }else printf("%s? success!\n",s);
#define CHK_NULL(x, s) if((x) == NULL) { printf("%s error\n", s); return -1; }else printf("%s? success!\n",s);
#define CHK_SSL(err, s) if((err) == -1) { ERR_print_errors_fp(stderr);? return -1;}else printf("%s? success!\n",s);
int main()
{
int rv, err;
SSL_CTX *ctx = NULL;
SSL_METHOD *meth = NULL;
int listen_sd;
int accept_sd;
struct sockaddr_in socketAddrServer;
struct sockaddr_in socketAddrClient;
socklen_t socketAddrClientLen;
SSL *ssl = NULL;
char buf[4096];
rv = SSL_library_init();
CHK_RV(rv, "SSL_library_init");
meth = (SSL_METHOD *)GMTLS_server_method();
ctx = SSL_CTX_new(meth);
CHK_NULL(ctx, "SSL_CTX_new");
rv = SSL_CTX_use_certificate_file(ctx, CERTSERVER, SSL_FILETYPE_PEM);
CHK_RV(rv, "SSL_CTX_use_certicificate_file");
rv = SSL_CTX_use_PrivateKey_file(ctx, KEYSERVER, SSL_FILETYPE_PEM);
CHK_RV(rv, "SSL_CTX_use_PrivateKey_file");
rv = SSL_CTX_check_private_key(ctx);
CHK_RV(rv, "SSL_CTX_check_private_key");
rv = SSL_CTX_use_certificate_file(ctx, SM2_SERVER_ENC_CERT, SSL_FILETYPE_PEM);
CHK_RV(rv, "SSL_CTX_use_certicificate_file2");
rv = SSL_CTX_use_PrivateKey_file(ctx, SM2_SERVER_ENC_KEY, SSL_FILETYPE_PEM);
CHK_RV(rv, "SSL_CTX_use_PrivateKey_file2");
rv = SSL_CTX_check_private_key(ctx);
CHK_RV(rv, "SSL_CTX_check_private_key2");
SSL_CTX_set_security_level(ctx, 0);
listen_sd = socket(AF_INET, SOCK_STREAM, 0);
CHK_ERR(listen_sd, "socket");
memset(&socketAddrServer, 0, sizeof(socketAddrServer));
socketAddrServer.sin_family = AF_INET;
socketAddrServer.sin_port = htons(8443);
socketAddrServer.sin_addr.s_addr = INADDR_ANY;
err = bind(listen_sd, (struct sockaddr *)&socketAddrServer, sizeof(socketAddrServer));
CHK_ERR(err, "bind");
err = listen(listen_sd, 5);
CHK_ERR(err, "listen");
socketAddrClientLen = sizeof(socketAddrClient);
accept_sd = accept(listen_sd, (struct sockaddr *)&socketAddrClient, &socketAddrClientLen);
CHK_ERR(accept_sd, "accept");
close(listen_sd);
printf("Connect from %lx, port %x\n", socketAddrClient.sin_addr.s_addr, socketAddrClient.sin_port);
ssl = SSL_new(ctx);
CHK_NULL(ssl, "SSL_new");
rv = SSL_set_fd(ssl, accept_sd);
CHK_RV(rv, "SSL_set_fd");
rv = SSL_accept(ssl);
CHK_RV(rv, "SSL_accpet");
/* Check for Client authentication error */
? if (SSL_get_verify_result(ssl) != X509_V_OK) {
? printf("SSL Client Authentication error\n");
? SSL_free(ssl);
? close(accept_sd);
? SSL_CTX_free(ctx);
? exit(0);
? }
/*Print out connection details*/
printf("SSL connection on socket %x,Version: %s, Cipher: %s\n",
accept_sd,
SSL_get_version(ssl),
SSL_get_cipher(ssl));
rv = SSL_read(ssl, buf, sizeof(buf) - 1);
CHK_SSL(rv, "SSL_read");
buf[rv] = '\0';
printf("Got %d chars :%s\n", rv, buf);
rv = SSL_write(ssl, "I accept your request", strlen("I accept your request"));
CHK_SSL(rv, "SSL_write");
close(accept_sd);
SSL_free(ssl);
SSL_CTX_free(ctx);
return 0;
}
client.c:
#include <stdio.h>
#include <string.h>
#include <openssl/evp.h>
#include <openssl/x509.h>
#include <openssl/ssl.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>?
#include <arpa/inet.h>
#include <iostream>
#define SERVER_IP? ? ? "127.0.0.1"
#define SERVER_PORT? ? 8443
int main( int argc, char* argv[] ) {
? int ret;
? ////////////
? // 初始化 //
? ////////////
? SSL_CTX* ctx;
? SSL_METHOD *meth;
? OpenSSL_add_ssl_algorithms();
? SSL_load_error_strings();
? //meth = (SSL_METHOD *)TLS_client_method();
? meth = (SSL_METHOD *)GMTLS_client_method();
? ctx = SSL_CTX_new (meth);
? if (!ctx) {
? ? ERR_print_errors_fp(stderr);
? ? std::cout<<"SSL_CTX_new error."<<std::endl;
? ? return -1;
? }
? //SSL_CTX_set_cipher_list(ctx, "ECDHE-RSA-AES256-GCM-SHA384");
//? SSL_CTX_set_max_proto_version(ctx,TLS1_2_VERSION);
//? SSL_CTX_set_min_proto_version(ctx,TLS1_2_VERSION);
? ///////////////////////
? // 建立原始的TCP連接 //
? ///////////////////////
? int client_socket;
? struct sockaddr_in addr_server;
? client_socket = socket (AF_INET, SOCK_STREAM, 0);?
? if( client_socket == -1? ) {
? ? std::cout<<"socket error."<<std::endl;
? ? return -1;
? }
? memset (&addr_server, 0, sizeof(addr_server));
? addr_server.sin_family? ? ? ? ? = AF_INET;
? addr_server.sin_addr.s_addr = inet_addr(SERVER_IP);
? addr_server.sin_port? ? ? ? ? ? = htons (SERVER_PORT);
? ret = connect(client_socket, (struct sockaddr*) &addr_server, sizeof(addr_server));
? if( ret == -1? ) {
? ? std::cout<<"connect error."<<std::endl;
? ? return -1;
? }
? /////////////////////////////////////
? // TCP連接已經(jīng)建立猴娩,執(zhí)行Client SSL //
? /////////////////////////////////////
? SSL*? ? ssl;
? X509*? ? server_certificate;
? char*? ? str;
? ssl = SSL_new (ctx);? ? ? ? ? ? ? ? ? ? ? ?
? if( ssl == NULL ) {
? ? std::cout<<"SSL_new error."<<std::endl;
? ? return -1;
? }
? SSL_set_fd (ssl, client_socket);
? ret = SSL_connect (ssl);? ? ? ? ? ? ? ? ? ?
? if( ret == -1 ) {
? ? std::cout<<"SSL_connect error."<<std::endl;
ERR_print_errors_fp(stderr);
? ? return -1;
? }
? ? ERR_print_errors_fp(stderr);
? // 接下來的獲取密碼和獲取服務(wù)器端證書的兩部是可選的,不會影響數(shù)據(jù)交換
? // 獲取cipher
? std::cout<<"SSL connection using: "<<SSL_get_cipher(ssl)<<std::endl;
? // 獲取服務(wù)器端的證書
? server_certificate = SSL_get_peer_certificate (ssl);? ? ?
? if( server_certificate != NULL ) {
? ? std::cout<<"Server certificate:"<<std::endl;
? ? str = X509_NAME_oneline (X509_get_subject_name (server_certificate),0,0);
? ? if( str == NULL ) {
? ? ? std::cout<<"X509_NAME_oneline error."<<std::endl;
? ? } else {
? ? ? std::cout<<"subject: "<<str<<std::endl;
? ? ? OPENSSL_free (str);
? ? }
? ? str = X509_NAME_oneline (X509_get_issuer_name? (server_certificate),0,0);
? ? if( str == NULL ) {
? ? ? std::cout<<"X509_NAME_oneline error."<<std::endl;
? ? } else {
? ? ? std::cout<<"issuer: "<<str<<std::endl;
? ? ? OPENSSL_free (str);
? ? }
? ? X509_free (server_certificate);
? } else {
? ? std::cout<<"Server does not have certificate. we sould Esc!"<<std::endl;
? ? return -1;
? }
? ////////////////
? //? 數(shù)據(jù)交換? //
? ////////////////
? char? ? buf [4096];
? ret = SSL_write (ssl, "Hello World!", strlen("Hello World!"));?
? if( ret == -1 ) {
? ? std::cout<<"SSL_write error."<<std::endl;
? ? return -1;
? }
? ret = SSL_read (ssl, buf, sizeof(buf) - 1);?
? if( ret == -1 ) {
? ? std::cout<<"SSL_read error."<<std::endl;
? ? return -1;
? }
? buf[ret] = '\0';
? std::cout<<buf<<std::endl;
? SSL_shutdown(ssl);? /* send SSL/TLS close_notify */
? /////////////
? // Cleanup //
? /////////////
? close(client_socket);
? SSL_free (ssl);
? SSL_CTX_free (ctx);
? return 0;
}