zoukankan      html  css  js  c++  java
  • 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! ",s);

    #define CHK_RV(rv, s) if((rv) != 1) { printf("%s error ", s); return -1; }else printf("%s  success! ",s);

    #define CHK_NULL(x, s) if((x) == NULL) { printf("%s error ", s); return -1; }else printf("%s  success! ",s);

    #define CHK_SSL(err, s) if((err) == -1) { ERR_print_errors_fp(stderr);  return -1;}else printf("%s  success! ",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 ", 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 ");

      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 ",

    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] = '';

    printf("Got %d chars :%s ", 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] = '';

      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;

    }



    作者:高文茂
    链接:https://www.jianshu.com/p/0dc9708e34de
    来源:简书
    著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
  • 相关阅读:
    codeforces1068——D.Array Without Local Maximums(计数DP+前缀和优化)
    codeforces1253——D. Harmonious Graph(并查集)
    LDUOJ——I. 买汽水(折半搜索+双指针)
    洛谷P3360 ——偷天换日(dfs读入+树形DP+01背包)
    洛谷P1270 ——“访问”美术馆(dfs读入+树形DP)
    LDUOJ——最小生成树(欧拉函数+思维)
    [LeetCode] 1551. Minimum Operations to Make Array Equal
    [LeetCode] 1553. Minimum Number of Days to Eat N Oranges
    [LeetCode] 161. One Edit Distance
    [LeetCode] 1260. Shift 2D Grid
  • 原文地址:https://www.cnblogs.com/bigben0123/p/12628453.html
Copyright © 2011-2022 走看看