MBEDTLS库移植单片机内容记录

前言

最近在工作中收到一个项目需求,其中一部分功能是要求在系统中实现网络通讯的TLS加密功能,网上翻找了许多资料都没有讲解的很详细的,后面缝缝补补总算也是做出来了,特例做一下总结,希望能有所帮助!

功能需求:设备之间通过以太网对接并采用Modbus TCP协议传输,需要支持安全认证与加密传输,建议采用TLS1.2协议,实现证书双向认证。

系统资源说明:本系统使用STM32F407芯片+UCOSIII操作系统,网络通讯使用LWIP库实现。目前系统已经实现基本的tcp通讯,仅需要实现TLS加密通讯即可。

基于以上情况,进行mbedtls库的移植,并最终实现双向认证的加密通讯功能。

基础知识介绍

1、TLS介绍
SSL/TLS是网络安全的基石,广泛应用于互联网上的安全通信,包括HTTPS、安全电子邮件、VPN等多种服务。

在TCP/IP模型中没有正式的“安全层”,TLS位于应用层和传输层之间。它使用传输层提供的服务来建立一个安全的通道,然后应用层协议通过这个安全通道传输数据。TLS协议确保了数据的机密性、完整性和认证。

在实际的数据传输中,TLS协议会加密应用层的数据,并将加密后的数据传递给传输层。传输层将这些数据封装在TCP或UDP数据包中,并将它们发送到网络层。网络层进一步封装这些数据包并在网络中传输它们。当数据到达目的地时,这个过程会反向进行,最终应用层会接收到通过TLS解密后的原始数据。

详细内容链接:
SSL/TLS详解
SSL/TLS协议运行机制

2、MBEDTLS介绍
MbedTLS(原名PolarSSL)是一个开源的、轻量级的加密库,它提供了多种加密算法和协议,例如RSA、AES、TLS等。mbedTLS采用C语言实现,代码简洁、清晰,并且具有高度的可移植性和灵活性。mbedTLS可以应用于嵌入式设备、服务器、客户端等各种场景。

MbedTLS库提供了一组可单独使用和编译的加密组件,还可以使用单个配置头文件加入或排除这些组件。从功能角度来看,该MbedTLS分为三个主要部分:
SSL/TLS 协议实施。
一个加密库。
一个 X.509 证书处理库。

详细内容链接:
mbedTLS介绍
mbedtls 库基础及其应用

MBEDTLS库移植

1、源码获取
链接:https://github.com/Mbed-TLS/mbedtls#make

2、文件架构介绍

3、将include和library文件复制到项目中

注意:添加头文件路径时,只需要添加到 include路径即可!
4、屏蔽config.h中所有宏定义
找到config.h文件,把里面所有的#define全部屏蔽,后续需要用哪个功能打开那个功能。

5、编译运行一下项目,不会报错即可,就此mbedtls库的移植工作就做完了

加密功能测试

1、SHA1加密功能测试
(1)在 config.h里面打开 MBEDTLS_SHA1_C

(2)编写代码,对"yang"字符串进行SHA1加密

(3)可通过加密软件测试加密的正确性。
2、HMAC-SHA256加密
(1)在 config.h里面打开 MBEDTLS_MD_C和MBEDTLS_SHA256_C
(2)编写加密函数(由于开发需求默认输出的加密后的长度为48,因此未做变量传入)

/*
   函数功能: mbedtls hamc sha256加密函数
   输入参数: U8_T *out_data:加密后的数据
    U8_T *key_data:密钥
    U8_T *raw_data:需要加密的数据
    U8_T raw_len:需要加密数据长度
   输出参数:0成功 1错误代码
*/
int i_mbedtls_hmac_sha256(U8_T *out_data,U8_T *key_data,U8_T *raw_data,U8_T raw_len)
{
    int ret = 0;
    U8_T key_len = 48;  //密钥长度默认48
    mbedtls_md_context_t ctx;  
    mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256; 

	mbedtls_md_init(&ctx);  
    if ((ret = mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1)) != 0) 
    {  
        logMsg("mbedtls_md_setup failed: %d\n", ret);  
        return ret;  
    }  
  
    if ((ret = mbedtls_md_hmac_starts(&ctx, (unsigned char*)key_data, key_len)) != 0) 
    {  
        logMsg("mbedtls_md_hmac_starts failed: %d\n", ret);  
        return ret;  
    }  
  
    if ((ret = mbedtls_md_hmac_update(&ctx, (unsigned char*)raw_data, raw_len)) != 0) 
    {  
        logMsg("mbedtls_md_hmac_update failed: %d\n", ret);  
        return ret;  
    }  
  
    if ((ret = mbedtls_md_hmac_finish(&ctx, out_data)) != 0) 
    {  
        logMsg("mbedtls_md_hmac_finish failed: %d\n", ret);  
        return ret;  
    }  
    mbedtls_md_free(&ctx); 

    return ret;
}

在线加密工具:https://www.toolhelper.cn/DigestAlgorithm/SHA
内容资料参考:https://www.cnblogs.com/yangfengwu/p/13693511.html

TLS单向认证功能实现

1、打开需要用到的宏定义
(如下宏定义为参考其他博主移植方式,为快速实现需求功能,还未深究各个宏的功能)

#define MBEDTLS_HAVE_ASM

#define MBEDTLS_NO_UDBL_DIVISION

#define MBEDTLS_HAVE_TIME

#define MBEDTLS_ENTROPY_HARDWARE_ALT 

#define MBEDTLS_AES_ROM_TABLES

#define MBEDTLS_CIPHER_MODE_CBC

#define MBEDTLS_KEY_EXCHANGE_RSA_ENABLED

#define MBEDTLS_NO_PLATFORM_ENTROPY

#define MBEDTLS_PKCS1_V15

#define MBEDTLS_SSL_PROTO_TLS1_2

#define MBEDTLS_AES_C

#define MBEDTLS_ASN1_PARSE_C

#define MBEDTLS_ASN1_WRITE_C

#define MBEDTLS_BIGNUM_C

#define MBEDTLS_CIPHER_C

#define MBEDTLS_CTR_DRBG_C

#define MBEDTLS_ENTROPY_C

#define MBEDTLS_GCM_C

#define MBEDTLS_MD_C

#define MBEDTLS_MD5_C

#define MBEDTLS_OID_C

#define MBEDTLS_PK_C

#define MBEDTLS_PK_PARSE_C

#define MBEDTLS_PLATFORM_C

#define MBEDTLS_RSA_C

#define MBEDTLS_SHA1_C

#define MBEDTLS_SHA256_C

#define MBEDTLS_SHA512_C

#define MBEDTLS_SSL_CLI_C

#define MBEDTLS_SSL_TLS_C

#define MBEDTLS_X509_USE_C

#define MBEDTLS_X509_CRT_PARSE_C

//下面这个是自己设置的加密套件

#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_RSA_WITH_AES_256_CBC_SHA256

2、增加自己的随机数函数 和 时间戳返回函数

//
_ARMABI time_t time(time_t *t){
    Comm_Time ctTime;

    GetCurrentTime(&ctTime);//获取系统当前时间

    return xDate2Seconds(&ctTime); //转化成时间戳
}
int mbedtls_hardware_poll( void *data,
                           unsigned char *output, size_t len, size_t *olen ){

    // 初始化随机数生成器种子
    size_t i;
    srand((unsigned int) time(NULL)); //使用当前时间做种子

    // 生成随机数
    for (i = 0; i < len; i++)
    {
        output[i] = (rand() & 0xFF);
    }
    *olen = len;
      
    return 0;                            
}

3、增加SSL底层获取数据函数
(嵌入式系统默认不支持tcp协议库,需要自己创建tcp连接并配置收发接口函数,以供mbedtls库做接口使用)

/**
* @brief  自定义接收函数(把自己的接收函数放到此函数中)
* @param  None
* @param  None
* @param  None
* @retval None
* @example 
**/
//int net_recv_data_len=0; 
//int net_recv_data_len_count=0;
//char net_recv_buff[2000];
int custom_ssl_recv( void *ctx, unsigned char *buf, size_t len )
{
    S16_T s16_recvLen = 0;
    S32_T fd = s32_get_tcp_fd(); //获取网络fd

    //以太网--自己系统的网络接收函数
    if(fd >= 0)
    	s16_recvLen = eth_recv((int)fd, (char *)buf, len, 1);

    return s16_recvLen;
}

/*增加发送函数*/
int custom_ssl_send( void *ctx, unsigned char *buf, size_t len )
{
    S32_T fd = s32_get_tcp_fd();

    //以太网
    if(fd >= 0)
    {
        eth_send((int)(fd), (char *)buf, len, 0);
    }

    return (int)len;
}

4、初始化变量,编写tls单向连接程序代码(可参考mbedtls源代码中ssl_client1.c文件)

#include "mbedtls/sha256.h"
#include "mbedtls/md.h"
#include "mbedtls/config.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/debug.h"
#include "mbedtls/entropy_poll.h"
#include "mbedtls/platform.h"
#include "mbedtls/net_sockets.h"

//定义系统使用到的全局变量
#define SERVER_NAME "SERVER_NAME"   //根据自己的证书信息配置

int ret;//
const char *pers = "ssl_client1";
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
mbedtls_x509_crt cacert;

//ssl初始化函数,默认此时tcp连接已经建立 返回1:tls连接成功;返回其他数,tls连接失败
int ssl_int(void)
{
    int cnt = 0;
    mbedtls_ssl_close_notify( &ssl );
    mbedtls_ssl_free( &ssl );
    mbedtls_ssl_config_free( &conf );
    mbedtls_ctr_drbg_free( &ctr_drbg );
    mbedtls_entropy_free( &entropy );
    
    mbedtls_ssl_init( &ssl );
    mbedtls_ssl_config_init( &conf );
    mbedtls_ctr_drbg_init( &ctr_drbg );
    mbedtls_entropy_init( &entropy );
    mbedtls_x509_crt_init( &cacert );


    #ifdef MBEDTLS_DEBUG_C  //打印标志  需要打印时,可开启MBEDTLS_DEBUG_C宏
    mbedtls_debug_set_threshold( 2 );//
    #endif

    logMsg( "\n  . Seeding the random number generator..." );
    //DRBG---->Deterministic Random Bit Generators 伪随机数产生器
    if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
                                                         (const unsigned char *) pers,
                                                         strlen( pers ) ) ) != 0 )
    {
            logMsg( " failed\n  ! mbedtls_ctr_drbg_seed returned %d\n", ret );
    }
    
	//配置证书信息,单向认证如果不需要客户端检查证书,可不配置进行证书
    ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) mbedtls_test_cas_pem,
                          mbedtls_test_cas_pem_len );
    if( ret < 0 )
    {
        logMsg( " failed\n  !  mbedtls_x509_crt_parse returned -0x%x\n\n", (unsigned int) -ret );
    }

    //MBEDTLS_SSL_IS_CLIENT 表示配置为客户端
    //MBEDTLS_SSL_TRANSPORT_STREAM 表示传输方式为TLS
    //设置版本, MBEDTLS_SSL_PRESET_DEFAULT 表示 TLS1.0
    if( ( ret = mbedtls_ssl_config_defaults( &conf,
                                    MBEDTLS_SSL_IS_CLIENT,
                                    MBEDTLS_SSL_TRANSPORT_STREAM,
                                    MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 )
    {
            logMsg( " failed\n  ! mbedtls_ssl_config_defaults returned %d\r\n", ret );
    }
 
    // 配置随机数生成器的回调函数
    mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
    // 配置调试回调函数
    mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
        /*设置数字证书检查模式 
    *  MBEDTLS_SSL_VERIFY_NONE:      peer certificate is not checked
    *                        (default on server)
    *                        (insecure on client)
    *
    *  MBEDTLS_SSL_VERIFY_OPTIONAL:  peer certificate is checked, however the
    *                        handshake continues even if verification failed;
    *                        mbedtls_ssl_get_verify_result() can be called after the
    *                        handshake is complete.
    *
    *  MBEDTLS_SSL_VERIFY_REQUIRED:  peer *must* present a valid certificate,
    *                        handshake is aborted if verification failed.
    *                        (default on client)
    */
    //单向认证是客户端检查证书,服务器不检查。设置MBEDTLS_SSL_VERIFY_NONE为不进行证书检查,可不进行配置客户端的证书信息
    mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_NONE);
    mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL );

	//不进行证书检查时,可不配置hostname
    if( ( ret = mbedtls_ssl_set_hostname( &ssl, SERVER_NAME ) ) != 0 )
    {
        logMsg( " failed\n  ! mbedtls_ssl_set_hostname returned %d\n\n", ret );
    }

    // 根据conf设置ssl结构
    if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
    {
            logMsg( " failed\n  ! mbedtls_ssl_setup returned 0x%x\r\n", -ret );
    }

    
    //设置发送和接收接口
    mbedtls_ssl_set_bio( &ssl, NULL, custom_ssl_send, custom_ssl_recv, NULL );

	//初始化完成,进行ssl握手连接
    while ((ret = mbedtls_ssl_handshake(&ssl)) != 0)
    {
        if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE){
            logMsg("failed\n ssl err -0x%x\n",(unsigned int) -ret);
            //return 0;
        }

        if(cnt++ >10*10){
                logMsg("ssl 10s outtime\n");
                return 0;
        }
        Sleep(100);
    }
    logMsg("TLS ok!\n");

    return 1;
}

内容资料参考:https://www.cnblogs.com/yangfengwu/p/13845772.html

TLS双向认证功能实现

双向认证为客户端、服务器都会进行证书的检查,因此需要在捂手过程中,将客户端的证书信息发送到服务器端,因此需要在客户端配置好相关的证书信息。可在单向认证的基础上,做如下修改:

mbedtls_x509_crt clicert;//定义变量,用于进行客户端证书操作
mbedtls_pk_context pkey;//定义客户端密钥

//初始化
mbedtls_x509_crt_init( &clicert );
mbedtls_pk_init( &pkey );

//配置客户端证书信息(可自行找到源码库中的位置,进行证书更换)
ret = mbedtls_x509_crt_parse( &clicert,
                (const unsigned char *) mbedtls_test_cli_crt,
                mbedtls_test_cli_crt_len );
if( ret < 0 )
{
    logMsg( " failed\n  !  mbedtls_x509_crt_parse clicert returned -0x%x\n\n", (unsigned int) -ret );
}

//配置客户端密钥(可自行找到源码库中的位置,进行密钥更换)
ret = mbedtls_pk_parse_key( &pkey,
                (const unsigned char *) mbedtls_test_cli_key,
                mbedtls_test_cli_key_len, NULL, 0 );
if( ret < 0 )
{
    logMsg( " failed\n  !  mbedtls_pk_parse_key returned -0x%x\n\n", (unsigned int) -ret );
}
//认证方式改为MBEDTLS_SSL_VERIFY_OPTIONAL(认证失败,任然可以进行握手)或者MBEDTLS_SSL_VERIFY_REQUIRED(必须认证成功才可以进行握手)
mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_OPTIONAL );

//将密钥添加到证书中(必要步骤)
if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &clicert, &pkey ) ) != 0 )
{
   logMsg( " failed\n  ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret );
}

内容资料参考:https://blog.csdn.net/baidu_39191253/article/details/105119644

个人实现双向认证的程序源码分享

//主函数 逻辑控制(仅做逻辑参考)
{
while(1){
		if(s_host_data.u8_tcp_connet_flag == 0)         //未联网,则联网
        {
            s_host_data.u8_tcp_connet_flag = u8_huawei_tcp_connet();
			Sleep(250);
        }
        else if(s_host_data.u8_tcp_connet_flag == 1)         //联网 则进行tls连接
        {
            if(ssl_int() == 1){
                      s_host_data.u8_tcp_connet_flag = 2;
                      logMsg("ssl ok\n");
            }
            Sleep(250);      
        }
        else                                            //联网则进行数据发生
        {
            S16_T s16_recvLen = 0;
            static U8_T cnt = 0;
            char mag[] = "hello word";

            s16_recvLen = s16_mbedtls_recv(s_host_data.u8_recvBuf);

            if(s16_recvLen > 0)
            {
                logMsg("recv: ",s_host_data.u8_recvBuf);
                for ( i = 0; i < s16_recvLen; i++)
                {
                    logMsg("%x ",s_host_data.u8_recvBuf[i]);
                }
                 logMsg("\n");
                
            }

            if(cnt++ > 4*10){
                v_mbedtls_send(mag,strlen(mag));
                logMsg("send \n");
                cnt=0;
            }

			Sleep(250);
        }
}
}
#include "type.h"
#include "main.h"
#include "Modbus_tcp.h"

#include "sockets.h"
#include "eth_bsp.h"
#include "icmp.h"
#include "ip.h"

#include <string.h>
#include <time.h>

#if 1
#include "mbedtls/sha256.h"
#include "mbedtls/md.h"
#include "mbedtls/config.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/debug.h"
#include "mbedtls/entropy_poll.h"
#include "mbedtls/platform.h"
#include "mbedtls/net_sockets.h"

#ifdef MBEDTLS_WTO_WAY_FLAG
#include "mbedtls/certs.h"

#define SERVER_NAME "Lierda RSA CA TLS 2023"

#endif

//
_ARMABI time_t time(time_t *t){
    Comm_Time ctTime;

    GetCurrentTime(&ctTime);//获取时间

    return xDate2Seconds(&ctTime);
    return 0;
}
int mbedtls_hardware_poll( void *data,
                           unsigned char *output, size_t len, size_t *olen ){
    // 初始化随机数生成器种子
    size_t i;
    srand((unsigned int) time(NULL));

    // 生成一个介于 0 和 99 之间的随机数
    for (i = 0; i < len; i++)
    {
        output[i] = (rand() & 0xFF);
    }
    *olen = len;
      
    return 0;                            
}

/*
   函数功能: mbedtls hamc sha256加密函数
   输入参数: U8_T *out_data:加密后的数据
    U8_T *key_data:密钥
    U8_T *raw_data:需要加密的数据
    U8_T raw_len:需要加密数据长度
   输出参数:0成功 1错误代码
*/
int i_mbedtls_hmac_sha256(U8_T *out_data,U8_T *key_data,U8_T *raw_data,U8_T raw_len)
{
    int ret = 0;
    U8_T key_len = 48;  //密钥长度默认48
    mbedtls_md_context_t ctx;  
    mbedtls_md_type_t md_type = MBEDTLS_MD_SHA256; 

	mbedtls_md_init(&ctx);  
    if ((ret = mbedtls_md_setup(&ctx, mbedtls_md_info_from_type(md_type), 1)) != 0) 
    {  
        logMsg("mbedtls_md_setup failed: %d\n", ret);  
        return ret;  
    }  
  
    if ((ret = mbedtls_md_hmac_starts(&ctx, (unsigned char*)key_data, key_len)) != 0) 
    {  
        logMsg("mbedtls_md_hmac_starts failed: %d\n", ret);  
        return ret;  
    }  
  
    if ((ret = mbedtls_md_hmac_update(&ctx, (unsigned char*)raw_data, raw_len)) != 0) 
    {  
        logMsg("mbedtls_md_hmac_update failed: %d\n", ret);  
        return ret;  
    }  
  
    if ((ret = mbedtls_md_hmac_finish(&ctx, out_data)) != 0) 
    {  
        logMsg("mbedtls_md_hmac_finish failed: %d\n", ret);  
        return ret;  
    }  
    mbedtls_md_free(&ctx); 

    return ret;
}


/**
* @brief  自定义接收函数(把自己的接收函数放到此函数中)
* @param  None
* @param  None
* @param  None
* @retval None
* @example 
**/
//int net_recv_data_len=0; 
//int net_recv_data_len_count=0;
//char net_recv_buff[2000];
int custom_ssl_recv( void *ctx, unsigned char *buf, size_t len )
{
    S16_T s16_recvLen = 0;
    S32_T fd = s32_get_tcp_fd();
    U16_T i,timer = 0;

    //以太网
    //if(fd >= 0){
    //while (timer++ < 100) //1秒
    {
        s16_recvLen = eth_recv((int)fd, (char *)buf, len, 1);
		if(s16_recvLen > 0){
			// logMsg("net recv len = %d\n",s16_recvLen);
            // for (i = 0; i < s16_recvLen; i++)
            // {
            //     logMsg("%x ",buf[i]);
            // }
            // logMsg("\n");
            
            //break;
        }
        Sleep(10);
    }
    
        
	//}

    return s16_recvLen;
}

/*增加发送函数*/
int custom_ssl_send( void *ctx, unsigned char *buf, size_t len )
{
    S32_T fd = s32_get_tcp_fd();

    //以太网
    if(fd >= 0)
    {
        eth_send((int)(fd), (char *)buf, len, 0);
		logMsg("net send len = %d\n",len);
    }

    return (int)len;
}
/*设置 debug 输出函数*/
static void my_debug( void *ctx, int level,
                      const char *file, int line, const char *str )
{
    logMsg("%04d: %s\r\n", line, str );
}


int ret;//
const char *pers = "ssl_client1";
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
#ifdef MBEDTLS_WTO_WAY_FLAG  
mbedtls_x509_crt cacert;
mbedtls_x509_crt clicert;
mbedtls_pk_context pkey;
#endif

/********mbedtls 网口数据发送***********
 * 函数说明:
 * 输入参数: sendBuf 发送数据数组地址  sendLen 发送数据长度
 * 输出参数:1 发送成功 0 发送失败
**********************************/
void v_mbedtls_send(U8_T *sendBuf, U32_T sendLen)        //发送接口函数
{

    mbedtls_ssl_write(&ssl , sendBuf ,sendLen );
}
/********mbedtls 数据接收***********
 * 函数说明:
 * 输入参数:接收数据地址
 * 输出参数:接收数据数量
**********************************/
S16_T s16_mbedtls_recv(U8_T *recvBuf)  //
{
    S16_T s16_recvLen = 0;

    s16_recvLen = mbedtls_ssl_read(&ssl,(unsigned char *)recvBuf, 255);

    return s16_recvLen;
}



int ssl_int(void)
{
    int cnt = 0;
    mbedtls_ssl_close_notify( &ssl );
    mbedtls_ssl_free( &ssl );
    mbedtls_ssl_config_free( &conf );
    mbedtls_ctr_drbg_free( &ctr_drbg );
    mbedtls_entropy_free( &entropy );
    
    
    mbedtls_ssl_init( &ssl );
    mbedtls_ssl_config_init( &conf );
    mbedtls_ctr_drbg_init( &ctr_drbg );
    mbedtls_entropy_init( &entropy );

    #ifdef MBEDTLS_WTO_WAY_FLAG  //双向认证使能标志
    mbedtls_x509_crt_init( &cacert );
    mbedtls_x509_crt_init( &clicert );
    mbedtls_pk_init( &pkey );
    #endif

    #ifdef MBEDTLS_DEBUG_C  //打印标志
    mbedtls_debug_set_threshold( 2 );//
    #endif

    logMsg( "\n  . Seeding the random number generator..." );
    //DRBG---->Deterministic Random Bit Generators 伪随机数产生器
    if( ( ret = mbedtls_ctr_drbg_seed( &ctr_drbg, mbedtls_entropy_func, &entropy,
                                                         (const unsigned char *) pers,
                                                         strlen( pers ) ) ) != 0 )
    {
            logMsg( " failed\n  ! mbedtls_ctr_drbg_seed returned %d\n", ret );
    }
    
    #ifdef MBEDTLS_WTO_WAY_FLAG  
    ret = mbedtls_x509_crt_parse( &cacert, (const unsigned char *) mbedtls_test_cas_pem,
                          mbedtls_test_cas_pem_len );
    if( ret < 0 )
    {
        logMsg( " failed\n  !  mbedtls_x509_crt_parse returned -0x%x\n\n", (unsigned int) -ret );
    }

    ret = mbedtls_x509_crt_parse( &clicert,
                (const unsigned char *) mbedtls_test_cli_crt,
                mbedtls_test_cli_crt_len );
    if( ret < 0 )
    {
        logMsg( " failed\n  !  mbedtls_x509_crt_parse clicert returned -0x%x\n\n", (unsigned int) -ret );
    }

    ret = mbedtls_pk_parse_key( &pkey,
                (const unsigned char *) mbedtls_test_cli_key,
                mbedtls_test_cli_key_len, NULL, 0 );
    if( ret < 0 )
    {
        logMsg( " failed\n  !  mbedtls_pk_parse_key returned -0x%x\n\n", (unsigned int) -ret );
    }
    #endif
    //MBEDTLS_SSL_IS_CLIENT 表示配置为客户端
    //MBEDTLS_SSL_TRANSPORT_STREAM 表示传输方式为TLS
    //设置版本, MBEDTLS_SSL_PRESET_DEFAULT 表示 TLS1.0
    if( ( ret = mbedtls_ssl_config_defaults( &conf,
                                    MBEDTLS_SSL_IS_CLIENT,
                                    MBEDTLS_SSL_TRANSPORT_STREAM,
                                    MBEDTLS_SSL_PRESET_DEFAULT ) ) != 0 )
    {
            logMsg( " failed\n  ! mbedtls_ssl_config_defaults returned %d\r\n", ret );
    }
 
 
    /*设置数字证书检查模式 
    *  MBEDTLS_SSL_VERIFY_NONE:      peer certificate is not checked
    *                        (default on server)
    *                        (insecure on client)
    *
    *  MBEDTLS_SSL_VERIFY_OPTIONAL:  peer certificate is checked, however the
    *                        handshake continues even if verification failed;
    *                        mbedtls_ssl_get_verify_result() can be called after the
    *                        handshake is complete.
    *
    *  MBEDTLS_SSL_VERIFY_REQUIRED:  peer *must* present a valid certificate,
    *                        handshake is aborted if verification failed.
    *                        (default on client)
    */
    // 配置随机数生成器的回调函数
    mbedtls_ssl_conf_rng( &conf, mbedtls_ctr_drbg_random, &ctr_drbg );
    // 配置调试回调函数
    mbedtls_ssl_conf_dbg( &conf, my_debug, stdout );
    #ifdef MBEDTLS_WTO_WAY_FLAG  
    mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_OPTIONAL );
    mbedtls_ssl_conf_ca_chain( &conf, &cacert, NULL );

    // if ((ret = mbedtls_ssl_conf_own_cert(&conf, &cacert, &pkey)) != 0)
	// {
	// 	logMsg(" failed\n  ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret);
	// }
    if( ( ret = mbedtls_ssl_conf_own_cert( &conf, &clicert, &pkey ) ) != 0 )
    {
        logMsg( " failed\n  ! mbedtls_ssl_conf_own_cert returned %d\n\n", ret );
    }

    if( ( ret = mbedtls_ssl_set_hostname( &ssl, SERVER_NAME ) ) != 0 )
    {
        logMsg( " failed\n  ! mbedtls_ssl_set_hostname returned %d\n\n", ret );
    }

    #else
    mbedtls_ssl_conf_authmode( &conf, MBEDTLS_SSL_VERIFY_NONE );
    #endif

    // 根据conf设置ssl结构
    if( ( ret = mbedtls_ssl_setup( &ssl, &conf ) ) != 0 )
    {
            logMsg( " failed\n  ! mbedtls_ssl_setup returned 0x%x\r\n", -ret );
    }

    
    //设置发送和接收接口
    mbedtls_ssl_set_bio( &ssl, NULL, custom_ssl_send, custom_ssl_recv, NULL );

    while ((ret = mbedtls_ssl_handshake(&ssl)) != 0)
    {
        if(ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE){
            logMsg("failed\n ssl err -0x%x\n",(unsigned int) -ret);
            //return 0;
        }

        if(cnt++ >10*10){
                logMsg("ssl 10s outtime\n");
                return 0;
        }
        Sleep(100);
    }
    logMsg("TLS ok!\n");

    return 1;
}
#endif

测试方法分享

开发此功能,理论上可以自行在linux服务器上使用源码库快速搭建客户端和服务端进行功能测试,由于个人能力有限,并未在此上面研究学习,使用的是一个在线服务器进行功能测试,可自行注册使用。
在线服务器链接分享:https://account.xiot.senthink.com/console/debug/net/tcp

![在这里插入图片描述](https://i3.wp.com/i-blog.csdnimg.cn/direct/c7bd275d7aca4197b3837473313b4583.png

在网络调试组手里面,创建IPV4服务器,可选择认证方式,按照自己需求使用即可。需要认证证书,可直接下载使用。

其他使用知识点补充

1、下载证书如何查看


下载完整数后,可使用记事本或者Notepad++打开,查看证书原始数据

证书内容可以在mbedtls源码库中certs.c文件中对应修改

2、如何查看证书的CN信息,设置hostname

//这里设置的 hostname 必须对应服务器证书中的 common name,即 CN 字段。
int mbedtls_ssl_set_hostname( mbedtls_ssl_context *ssl, const char *hostname );

可在电脑直接双击证书文件,即会展示证书相关信息,在详细信息、颁发者中可以查看证书的CN信息

总结

就此,TLS加密双向认证的功能开发完成,后续按照个人的项目需求进行改动即可。能力有限,就记录到这里了。

2024年12月17日补充:
到此,这个项目仅仅是在自己搭建的环境中调通了,后面上机测试还是有问题,无奈继续对相关的内容进行学习。后续包括自签证书的生成、openssl服务端服务器测试环境的搭建等功能,记录在了另一篇文章里,有兴趣的欢迎查看指正。

(抱怨一句:测试的加密套件使用的 TLS_RSA_WITH_AES_256_CBC_SHA256,结果客户的设置需要使用TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,又去了解怎么配置、怎么测试,来回的折腾…)

文章链接:使用openssl生成签名证书以及客户端服务器测试程序的编写

其他网络资源引用

https://www.cnblogs.com/yangfengwu/p/13845772.html
https://www.pianshen.com/article/3763372592/

作者:简卡拉卡

物联沃分享整理
物联沃-IOTWORD物联网 » MBEDTLS库移植单片机内容记录

发表回复