C:mbedtls库实现https双向认证毗连示例_七侠镇莫尛貝大侠20241122 ...

打印 上一主题 下一主题

主题 833|帖子 833|积分 2499

目的:使用C mbedtls库实现https(RSA证书)双向认证毗连。
开发环境:windows 11, VS2022,mbedtls-3.6.2
私钥格式:p1/p8

  1. #include "mbedtls/net_sockets.h"
  2. #include "mbedtls/ssl.h"
  3. #include "mbedtls/entropy.h"
  4. #include "mbedtls/ctr_drbg.h"
  5. #include "mbedtls/debug.h"
  6. #include "mbedtls/error.h"
  7. #include "mbedtls/certs.h"
  8. #include <mbedtls/pk.h>
  9. #include <mbedtls/pem.h>
  10. #include <mbedtls/base64.h>
  11. // 这个函数假设 SSL 握手已经成功完成
  12. void print_server_san(mbedtls_ssl_context* ssl) {
  13.     const mbedtls_x509_crt* cert = mbedtls_ssl_get_peer_cert(ssl);
  14.     if (cert == NULL) {
  15.         printf("No server certificate found.\n");
  16.         return;
  17.     }
  18.     // 确保 `subject_alt_names` 是正确的类型
  19.     const mbedtls_x509_sequence* san = &cert->subject_alt_names;
  20.     while (san != NULL) {
  21.         const mbedtls_asn1_buf* entry = &san->buf;
  22.         unsigned char tag = entry->tag;
  23.         // 检查是否为 IP 地址 (context-specific tag 7)
  24.         if ((tag & MBEDTLS_ASN1_TAG_CLASS_MASK) == MBEDTLS_ASN1_CONTEXT_SPECIFIC &&
  25.             (tag & MBEDTLS_ASN1_TAG_VALUE_MASK) == 7) {
  26.             // IP 地址以二进制形式存储
  27.             if (entry->len == 4) { // IPv4 地址
  28.                 printf("Server certificate SAN (IP): %u.%u.%u.%u\n",
  29.                     entry->p[0], entry->p[1], entry->p[2], entry->p[3]);
  30.             }
  31.             else if (entry->len == 16) { // IPv6 地址
  32.                 printf("Server certificate SAN (IPv6): ");
  33.                 for (int i = 0; i < 16; i++) {
  34.                     printf("%02x", entry->p[i]);
  35.                     if (i % 2 == 1 && i < 15) {
  36.                         printf(":");
  37.                     }
  38.                 }
  39.                 printf("\n");
  40.             }
  41.         }
  42.         san = san->next;
  43.     }
  44. }
  45. void print_mbedtls_error(int ret) {
  46.     char error_buf[100];
  47.     mbedtls_strerror(ret, error_buf, sizeof(error_buf));
  48.     fprintf(stderr, "Error: %s\n", error_buf);
  49. }
  50. int print_prikey_b64() {
  51.     int ret;
  52.     mbedtls_pk_context pkey;
  53.     unsigned char* key_buffer = NULL;
  54.     size_t key_len = 0;
  55.     unsigned char* base64_buffer = NULL;
  56.     size_t base64_len = 0;
  57.     mbedtls_pk_init(&pkey);
  58.     // 读取私钥文件
  59.     ret = mbedtls_pk_parse_keyfile(&pkey, "res/yax/client_p8.key", NULL);
  60.     if (ret != 0) {
  61.         print_mbedtls_error(ret);
  62.         goto cleanup;
  63.     }
  64.     // 获取私钥的 DER 格式所需的缓冲区长度
  65.     key_len = mbedtls_pk_write_key_der(&pkey, NULL, 0);
  66.     if (key_len <= 0) {
  67.         print_mbedtls_error(key_len);
  68.         goto cleanup;
  69.     }
  70.     printf("Key length required for DER format: %zu bytes\n", key_len);
  71.     // 分配比所需长度更大的缓冲区来确保足够的空间
  72.     key_buffer = (unsigned char*)malloc(key_len);
  73.     if (!key_buffer) {
  74.         fprintf(stderr, "Memory allocation failed for key_buffer with size %zu bytes\n", key_len);
  75.         ret = -1;
  76.         goto cleanup;
  77.     }
  78.     // 将私钥写入 DER 格式缓冲区,注意返回值是实际写入的字节数
  79.     ret = mbedtls_pk_write_key_der(&pkey, key_buffer, key_len);
  80.     if (ret < 0) {
  81.         print_mbedtls_error(ret);
  82.         goto cleanup;
  83.     }
  84.     // 计算 Base64 编码所需的缓冲区长度
  85.     key_len = ret;  // 实际写入的字节数
  86.     ret = mbedtls_base64_encode(NULL, 0, &base64_len, key_buffer + (key_len - ret), key_len);
  87.     if (ret != MBEDTLS_ERR_BASE64_BUFFER_TOO_SMALL) {
  88.         print_mbedtls_error(ret);
  89.         goto cleanup;
  90.     }
  91.     // 分配缓冲区以存储 Base64 编码的数据
  92.     base64_buffer = (unsigned char*)malloc(base64_len);
  93.     if (!base64_buffer) {
  94.         fprintf(stderr, "Memory allocation failed for base64_buffer\n");
  95.         ret = -1;
  96.         goto cleanup;
  97.     }
  98.     // 将 DER 格式的私钥转换为 Base64 编码
  99.     ret = mbedtls_base64_encode(base64_buffer, base64_len, &base64_len, key_buffer + (key_len - ret), key_len);
  100.     if (ret != 0) {
  101.         print_mbedtls_error(ret);
  102.         goto cleanup;
  103.     }
  104.     // 打印 Base64 编码的私钥
  105.     printf("Base64 Encoded Private Key:\n%s\n", base64_buffer);
  106. cleanup:
  107.     mbedtls_pk_free(&pkey);
  108.     if (key_buffer) {
  109.         free(key_buffer);
  110.     }
  111.     if (base64_buffer) {
  112.         free(base64_buffer);
  113.     }
  114.     //Key length required for DER format: 18446744073709551508 bytes
  115.     //Memory allocation failed for key_buffer with size 18446744073709551508 bytes
  116.     return ret != 0 ? EXIT_FAILURE : EXIT_SUCCESS;
  117. }
  118. int testHttps_p8() {
  119.         printf("Https功能演示start:\n");
  120.     int ret;
  121.     mbedtls_net_context server_fd;
  122.     mbedtls_ssl_context ssl;
  123.     mbedtls_ssl_config conf;
  124.     mbedtls_x509_crt cacert, clicert;
  125.     mbedtls_pk_context pkey;
  126.     mbedtls_entropy_context entropy;
  127.     mbedtls_ctr_drbg_context ctr_drbg;
  128.     const char* pers = "ssl_client1";
  129.     // Initialize structures
  130.     mbedtls_net_init(&server_fd);
  131.     mbedtls_ssl_init(&ssl);
  132.     mbedtls_ssl_config_init(&conf);
  133.     mbedtls_x509_crt_init(&cacert);
  134.     mbedtls_x509_crt_init(&clicert);
  135.     mbedtls_pk_init(&pkey);
  136.     mbedtls_ctr_drbg_init(&ctr_drbg);
  137.     mbedtls_entropy_init(&entropy);
  138.     // 设置 RNG
  139.     //ret = mbedtls_ctr_drbg_seed(&(hc->tls.ctr_drbg), mbedtls_entropy_func, &hc->tls.entropy, NULL, 0);
  140.     //ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)pers, strlen(pers));
  141.     ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
  142.     if (ret != 0)
  143.     {
  144.         return ret;
  145.     }
  146.     // Load certificates
  147.     //mbedtls_x509_crt_parse_file(&clicert, "res/yax/client_https_with_chain.cer");  //含有客户端证书链
  148.     mbedtls_x509_crt_parse_file(&clicert, "res/yax/client_https.cer");  //不含有证书链
  149.     mbedtls_x509_crt_parse_file(&cacert, "res/yax/ca.cer");   //所有客户端和服务端所有证书链
  150.     //mbedtls_x509_crt_parse_file(&cacert, "res/yax/root.cer");   //只提供一个服务器证书的root证书即可
  151.     mbedtls_pk_parse_keyfile(&pkey, "res/yax/client_p8.key", NULL);    //p1或p8格式都可以,但必须包含头尾
  152.     //mbedtls_pk_parse_keyfile(&pkey, "res/yax2/client_p8.key", NULL);
  153.     mbedtls_ssl_conf_authmode(&ssl, MBEDTLS_SSL_VERIFY_REQUIRED);  //设置认证模式为 MBEDTLS_SSL_VERIFY_OPTIONAL 或 MBEDTLS_SSL_VERIFY_NONE 来调试是否由于证书验证失败引起的问题
  154.                                                                   //但是,这仅用于调试,生产环境应该始终使用 MBEDTLS_SSL_VERIFY_REQUIRED。         
  155.     // Seed the random number generator
  156.     //mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)pers, strlen(pers));
  157.     // Setup SSL configuration
  158.     mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
  159.     mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
  160.     mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
  161.     mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
  162.     mbedtls_ssl_conf_own_cert(&conf, &clicert, &pkey);
  163.    
  164.     //mbedtls_ssl_set_hostname(&ssl, "4.3.2.1");   //服务器证书alt name dns = ip而不是域名时,不要调用这个
  165.     //mbedtls_ssl_set_hostname(&ssl, NULL); //忽略主机名验证
  166.     //mbedtls_ssl_conf_verify(&conf, 0, NULL);  // 设置自定义的证书验证回调
  167.     // Connect to server
  168.     mbedtls_net_connect(&server_fd, "4.3.2.1", "443", MBEDTLS_NET_PROTO_TCP);    //rsa https 测试服务端
  169.     //mbedtls_net_connect(&server_fd, "4.3.2.1", "443", MBEDTLS_NET_PROTO_TCP); //RSA 国密sm2 双算法证书https 不适用。
  170.     // Setup SSL context
  171.     mbedtls_ssl_setup(&ssl, &conf);
  172.     mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
  173.     // Perform SSL handshake
  174.     while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
  175.         if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
  176.             char error_buf[100];
  177.             mbedtls_strerror(ret, error_buf, 100);
  178.             printf("Handshake failed: %s\n", error_buf);
  179.             return 1;
  180.         }
  181.     }
  182.     //打印服务器证书的san
  183.     print_server_san(&ssl);
  184.     //print_prikey_b64();
  185.     // Communicate with the server
  186.     // ...
  187.     // Send data to server
  188.     const char* msg = "Hello, Server!";
  189.     mbedtls_ssl_write(&ssl, (const unsigned char*)msg, strlen(msg));
  190.     // Read response
  191.     char buffer[1024];
  192.     do {
  193.         memset(buffer, 0, sizeof(buffer));
  194.         ret = mbedtls_ssl_read(&ssl, (unsigned char*)buffer, sizeof(buffer) - 1);
  195.         if (ret > 0) {
  196.             printf("Received %d bytes:\n%s\n", ret, buffer);
  197.         }
  198.         else if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
  199.             break;
  200.         }
  201.     } while (ret > 0);
  202.     // Clean up
  203.     mbedtls_ssl_close_notify(&ssl);
  204.     mbedtls_net_free(&server_fd);
  205.     mbedtls_x509_crt_free(&cacert);
  206.     mbedtls_x509_crt_free(&clicert);
  207.     mbedtls_pk_free(&pkey);
  208.     mbedtls_ssl_free(&ssl);
  209.     mbedtls_ssl_config_free(&conf);
  210.     mbedtls_ctr_drbg_free(&ctr_drbg);
  211.     mbedtls_entropy_free(&entropy);
  212.     printf("Https功能演示End:\n");
  213.         return EXIT_SUCCESS;
  214. }
  215. //在证书base64编码前后添加头尾
  216. char* cert_add_ht(const char* filename) {
  217.     FILE* file = fopen(filename, "r");
  218.     if (!file) {
  219.         perror("无法打开文件");
  220.         return NULL;
  221.     }
  222.     // 获取文件大小
  223.     fseek(file, 0, SEEK_END);
  224.     long filesize = ftell(file);
  225.     fseek(file, 0, SEEK_SET);
  226.     // 分配内存读取文件内容
  227.     char* base64_data = (char*)malloc(filesize + 1);
  228.     if (!base64_data) {
  229.         perror("内存分配失败");
  230.         fclose(file);
  231.         return NULL;
  232.     }
  233.     fread(base64_data, 1, filesize, file);
  234.     base64_data[filesize] = '\0';  // 确保字符串结束
  235.     fclose(file);
  236.     const char* pem_header = "-----BEGIN CERTIFICATE-----\n";
  237.     const char* pem_footer = "\n-----END CERTIFICATE-----\n";
  238.     // 计算 PEM 格式总长度
  239.     size_t pem_size = strlen(pem_header) + strlen(base64_data) + strlen(pem_footer) + 1;
  240.     // 分配内存以存储 PEM 格式数据
  241.     char* pem_cert = (char*)malloc(pem_size);
  242.     if (!pem_cert) {
  243.         perror("内存分配失败");
  244.         free(base64_data);
  245.         return NULL;
  246.     }
  247.     // 生成 PEM 格式数据
  248.     snprintf(pem_cert, pem_size, "%s%s%s", pem_header, base64_data, pem_footer);
  249.     free(base64_data);
  250.     return pem_cert;
  251. }
  252. char* pkcs1_key_add_ht(const char* filename) {
  253.     FILE* file = fopen(filename, "r");
  254.     if (!file) {
  255.         perror("无法打开文件");
  256.         return NULL;
  257.     }
  258.     // 获取文件大小
  259.     fseek(file, 0, SEEK_END);
  260.     long filesize = ftell(file);
  261.     fseek(file, 0, SEEK_SET);
  262.     // 分配内存读取文件内容
  263.     char* base64_data = (char*)malloc(filesize + 1);
  264.     if (!base64_data) {
  265.         perror("内存分配失败");
  266.         fclose(file);
  267.         return NULL;
  268.     }
  269.     fread(base64_data, 1, filesize, file);
  270.     base64_data[filesize] = '\0';  // 确保字符串结束
  271.     fclose(file);
  272.     const char* pem_header = "-----BEGIN RSA PRIVATE KEY-----\n";
  273.     const char* pem_footer = "\n-----END RSA PRIVATE KEY-----\n";
  274.     // 计算 PEM 格式总长度
  275.     size_t pem_size = strlen(pem_header) + strlen(base64_data) + strlen(pem_footer) + 1;
  276.     // 分配内存以存储 PEM 格式数据
  277.     char* pem_cert = (char*)malloc(pem_size);
  278.     if (!pem_cert) {
  279.         perror("内存分配失败");
  280.         free(base64_data);
  281.         return NULL;
  282.     }
  283.     // 生成 PEM 格式数据
  284.     snprintf(pem_cert, pem_size, "%s%s%s", pem_header, base64_data, pem_footer);
  285.     free(base64_data);
  286.     return pem_cert;
  287. }
  288. int testHttps() {
  289.     printf("Https功能演示start:\n");
  290.     int ret;
  291.     mbedtls_net_context server_fd;
  292.     mbedtls_ssl_context ssl;
  293.     mbedtls_ssl_config conf;
  294.     mbedtls_x509_crt cacert, clicert;
  295.     mbedtls_pk_context pkey;
  296.     mbedtls_entropy_context entropy;
  297.     mbedtls_ctr_drbg_context ctr_drbg;
  298.     const char* pers = "ssl_client1";
  299.     // Initialize structures
  300.     mbedtls_net_init(&server_fd);
  301.     mbedtls_ssl_init(&ssl);
  302.     mbedtls_ssl_config_init(&conf);
  303.     mbedtls_x509_crt_init(&cacert);
  304.     mbedtls_x509_crt_init(&clicert);
  305.     mbedtls_pk_init(&pkey);
  306.     mbedtls_ctr_drbg_init(&ctr_drbg);
  307.     mbedtls_entropy_init(&entropy);
  308.     // 设置 RNG
  309.     //ret = mbedtls_ctr_drbg_seed(&(hc->tls.ctr_drbg), mbedtls_entropy_func, &hc->tls.entropy, NULL, 0);
  310.     //ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)pers, strlen(pers));
  311.     ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, NULL, 0);
  312.     if (ret != 0)
  313.     {
  314.         return ret;
  315.     }
  316.     const char* file_cert_b64 = "res/yax2/client_https_noht.cer";
  317.     // 读取证书文件(不包含头尾)并转换为 PEM 格式(包含头尾)
  318.     char* pem_cert = cert_add_ht(file_cert_b64);
  319.     // 获取 PEM 证书的大小
  320.     size_t pem_size = strlen(pem_cert) + 1;  // 包括终止符
  321.     mbedtls_x509_crt_parse(&clicert, (const unsigned char*)pem_cert, pem_size);
  322.     free(pem_cert);
  323.     const char* file_key_p1_b64 = "res/yax2/client_p1_noht.key";
  324.     // 读取证书文件(不包含头尾)并转换为 PEM 格式(包含头尾)
  325.     char* pem_key = pkcs1_key_add_ht(file_key_p1_b64);
  326.     // 获取 PEM 证书的大小
  327.     size_t key_size = strlen(pem_key) + 1;  // 包括终止符
  328.     mbedtls_pk_parse_key(&pkey, (const unsigned char*)pem_key, key_size,NULL,0);
  329.     free(pem_key);
  330.     mbedtls_x509_crt_parse_file(&cacert, "res/yax/ca.cer");   //所有客户端和服务端所有证书链
  331.     // Load certificates
  332.     //mbedtls_x509_crt_parse_file(&clicert, "res/yax/client_https_with_chain.cer");  //含有客户端证书链
  333.     //mbedtls_x509_crt_parse_file(&clicert, "res/yax2/client_https_noht.cer");  //不含有证书链
  334.     //mbedtls_x509_crt_parse_file(&cacert, "res/yax/ca.cer");   //所有客户端和服务端所有证书链
  335.     //mbedtls_x509_crt_parse_file(&cacert, "res/yax/root.cer");   //只提供一个服务器证书的root证书即可
  336.     //mbedtls_pk_parse_keyfile(&pkey, "res/yax2/client_p1.key", NULL);    //p1或p8格式都可以,但必须包含头尾
  337.     //mbedtls_pk_parse_keyfile(&pkey, "res/yax2/client_p8.key", NULL);
  338.     mbedtls_ssl_conf_authmode(&ssl, MBEDTLS_SSL_VERIFY_REQUIRED);  //设置认证模式为 MBEDTLS_SSL_VERIFY_OPTIONAL 或 MBEDTLS_SSL_VERIFY_NONE 来调试是否由于证书验证失败引起的问题
  339.     //但是,这仅用于调试,生产环境应该始终使用 MBEDTLS_SSL_VERIFY_REQUIRED。         
  340. // Seed the random number generator
  341. //mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char*)pers, strlen(pers));
  342. // Setup SSL configuration
  343.     mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
  344.     mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
  345.     mbedtls_ssl_conf_dbg(&conf, my_debug, stdout);
  346.     mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL);
  347.     mbedtls_ssl_conf_own_cert(&conf, &clicert, &pkey);
  348.     //mbedtls_ssl_set_hostname(&ssl, "1.2.3.4");   //服务器证书alt name dns = ip而不是域名时,不要调用这个
  349.     //mbedtls_ssl_set_hostname(&ssl, NULL); //忽略主机名验证
  350.     //mbedtls_ssl_conf_verify(&conf, 0, NULL);  // 设置自定义的证书验证回调
  351.     // Connect to server
  352.     mbedtls_net_connect(&server_fd, "2.3.4.5", "443", MBEDTLS_NET_PROTO_TCP);    //rsa https 测试服务端
  353.     //mbedtls_net_connect(&server_fd, "2.3.4.5", "443", MBEDTLS_NET_PROTO_TCP); //RSA 国密sm2 双算法证书https 不适用。
  354.     // Setup SSL context
  355.     mbedtls_ssl_setup(&ssl, &conf);
  356.     mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
  357.     // Perform SSL handshake
  358.     while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) {
  359.         if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
  360.             char error_buf[100];
  361.             mbedtls_strerror(ret, error_buf, 100);
  362.             printf("Handshake failed: %s\n", error_buf);
  363.             return 1;
  364.         }
  365.     }
  366.     //打印服务器证书的san
  367.     print_server_san(&ssl);
  368.     //print_prikey_b64();
  369.     // Communicate with the server
  370.     // ...
  371.     // Send data to server
  372.     const char* msg = "Hello, Server!";
  373.     mbedtls_ssl_write(&ssl, (const unsigned char*)msg, strlen(msg));
  374.     // Read response
  375.     char buffer[1024];
  376.     do {
  377.         memset(buffer, 0, sizeof(buffer));
  378.         ret = mbedtls_ssl_read(&ssl, (unsigned char*)buffer, sizeof(buffer) - 1);
  379.         if (ret > 0) {
  380.             printf("Received %d bytes:\n%s\n", ret, buffer);
  381.         }
  382.         else if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) {
  383.             break;
  384.         }
  385.     } while (ret > 0);
  386.     // Clean up
  387.     mbedtls_ssl_close_notify(&ssl);
  388.     mbedtls_net_free(&server_fd);
  389.     mbedtls_x509_crt_free(&cacert);
  390.     mbedtls_x509_crt_free(&clicert);
  391.     mbedtls_pk_free(&pkey);
  392.     mbedtls_ssl_free(&ssl);
  393.     mbedtls_ssl_config_free(&conf);
  394.     mbedtls_ctr_drbg_free(&ctr_drbg);
  395.     mbedtls_entropy_free(&entropy);
  396.     printf("Https功能演示End:\n");
  397.     return EXIT_SUCCESS;
  398. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

熊熊出没

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表