gmssl总结



1、gmssl组成

分为加密和通信两部分

2、加密

主要指的是sm2 sm3 sm4加密算法,以及相关的加密组件

3、通信

指的是gmtls

按照一个 GM/T 0024-2014规范实现的,采用双证书,签名证书+加密证书

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不可以,号称的会自己检测版本并没有实现,貌似默认是使用1.1版本

6、双证书

gmssl对双证书和双密钥的设置

直接设置两个sm2证书和密钥就可以,没有新增接口,都是代码里自己适配:

keyusagedigitalSignature 类型的证书是签名证书,否则是加密证书,密钥呢,加密证书存在的时候是加密密钥,否则是签名密钥

这个其实是有漏洞的,必须先设置签名证书。。然后才是加密证书

tassl是有的,增加了一个设置加密密钥的接口SSL_use_enc_PrivateKey,设置证书的接口也是代码里适配的,证书类型需要keyusage(keyAgreementkeyEnciphermentdataEncipherment)

7、版本

以上总结仅针对GmSSL最新版(v2.3.1)和tassl当前最新版(2018-09-17)

8、最新版的openssl已经支持国密算法

仅仅支持国密的算法,通信还未支持

9、编程实现

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连接已经建立,执行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);

  // 接下来的获取密码和获取服务器端证书的两部是可选的,不会影响数据交换

  // 获取cipher

  std::cout<<"SSL connection using: "<<SSL_get_cipher(ssl)<<std::endl;

  // 获取服务器端的证书

  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;

  }

  ////////////////

  //  数据交换  //

  ////////////////

  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;

}



最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,142评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,298评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,068评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,081评论 1 291
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,099评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,071评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,990评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,832评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,274评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,488评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,649评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,378评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,979评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,625评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,796评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,643评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,545评论 2 352