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
在网络调试组手里面,创建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/
作者:简卡拉卡