EmbedTLS + Eclipse C/C++测试用例SSL客户端和服务器

目录

  • ​​EmbedTLS + Eclipse C/C++测试用例SSL客户端和服务器​​
  • ​​(1)说明​​
  • ​​(2)Eclipse的embedtls移植​​
  • ​​(3)OpenSSL公私钥及证书生成​​
  • ​​(4)测试​​
  • ​​embedtls认证模式说明​​
  • ​​embedtls单向认证设置​​
  • ​​embedtlss双向认证设置:​​
  • ​​代码示例​​
  • ​​1、客户端代码模型​​
  • ​​2、服务器代码模型​​

(1)说明

STM32移植使用mbedtls-2.24.0点这

mbedtls下载地址:​​https://github.com/ARMmbed/mbedtls​

embedtls的ssl示例代码在这里可以找到:​​https://github.com/ARMmbed/mbedtls/tree/development/programs/ssl​


(2)Eclipse的embedtls移植

我是用的是Eclipse C/C++和MinGW编译工具链,embedtls移植很简单,只需要把源码目录下的include和library文件夹拷贝到工程目录下即可,如下图:

EmbedTLS + Eclipse C/C++测试用例SSL客户端和服务器_eclipse c/c++

然后右键工程->Properties->C/C++ Build->Settings->Tool Sttings->GCC C Compiler->Include添加头文件包含,如下图:

EmbedTLS + Eclipse C/C++测试用例SSL客户端和服务器_embedtls_02

然后使用C99语法编译规则:

EmbedTLS + Eclipse C/C++测试用例SSL客户端和服务器_ssl_server_03

因为mingw使用的标准系统调用,在win上就得链接windows系统的库,所以还需要添加一个链接标记:

EmbedTLS + Eclipse C/C++测试用例SSL客户端和服务器_ssl_client_04


(3)OpenSSL公私钥及证书生成



(4)测试

embedtls认证模式说明

  • MBEDTLS_SSL_VERIFY_NONE:不检查对等证书(也就是无认证)。(服务器默认值,如果客户端配置为此选项那么连接是不安全的;如果服务器配置为此值那么是单向认证。
  • MBEDTLS_SSL_VERIFY_OPTIONAL :检查对等证书(也就是单向认证),但即使验证失败,握手仍将继续;可以在握手完成后调用mbedtls_ssl_get_verify_result()查看验证结果。
  • MBEDTLS_SSL_VERIFY_REQUIRED :客户端服务器必须同时出示有效证书(也就是双向认证),如果验证失败,握手将终止。(客户端默认值)

embedtls单向认证设置

  • 服务器认证模式设置:MBEDTLS_SSL_VERIFY_OPTIONAL、MBEDTLS_SSL_VERIFY_NONE。如果服务器设置为MBEDTLS_SSL_VERIFY_NONE,不管客户端设置什么属性,在握手时候都不会对证书进行认证;如果设置为MBEDTLS_SSL_VERIFY_OPTIONAL,那么进行单向认证,验证失败的话,通信仍然有效。
  • 客户端认证模式设置:根据需求可选择MBEDTLS_SSL_VERIFY_NONE(不认证)、MBEDTLS_SSL_VERIFY_OPTIONAL(验证若失败也会继续保持通信)、MBEDTLS_SSL_VERIFY_REQUIRED(验证失败将终止连接)。

embedtlss双向认证设置:

  • 服务器设置为MBEDTLS_SSL_VERIFY_REQUIRED
  • 客户端根据安全需求选择MBEDTLS_SSL_VERIFY_NONE(不检查)、MBEDTLS_SSL_VERIFY_OPTIONAL(验证但是验证失败通信仍有效)、MBEDTLS_SSL_VERIFY_REQUIRED(验证失败通信无效)

在代码中这个宏定义控制着是否加载服务器的证书和密钥,如果是单向认证,客户端是不需要加载服务器的证书和密钥的,当然加载上也不影响。

EmbedTLS + Eclipse C/C++测试用例SSL客户端和服务器_eclipse c/c++_05

代码示例

1、客户端代码模型

/*
* main.c
*
* Created on: 2020年10月29日
* Author: hello
*/

#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "mbedtls/config.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/debug.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/error.h"
#include "mbedtls/certs.h"

#define debug_e(fmt, ...) do{fprintf(stderr, fmt, ##__VA_ARGS__);fflush(stderr);}while(0);
#define debug(fmt, ...) do{printf(fmt, ##__VA_ARGS__);fflush(stdout);}while(0);

unsigned char mbedtls_ca_crt[] =
{
"-----BEGIN CERTIFICATE-----\r\n" \
"MIIDPTCCAiUCFAyaaimE7qW89Z0Verz2WN3cABu4MA0GCSqGSIb3DQEBCwUAMFox\r\n" \
"CzAJBgNVBAYTAkNOMQswCQYDVQQIDAJTRDELMAkGA1UEBwwCSk4xDTALBgNVBAoM\r\n" \
"BFFEWlkxFTATBgNVBAsMDHd3dy5xZHp5LmNvbTELMAkGA1UEAwwCQ0EwIBcNMjAx\r\n" \
"MTA1MDgxOTM0WhgPMjEyMDEwMTIwODE5MzRaMFoxCzAJBgNVBAYTAkNOMQswCQYD\r\n" \
"VQQIDAJTRDELMAkGA1UEBwwCSk4xDTALBgNVBAoMBFFEWlkxFTATBgNVBAsMDHd3\r\n" \
"dy5xZHp5LmNvbTELMAkGA1UEAwwCQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\r\n" \
"ggEKAoIBAQDWU0v4jZ1OPxpGJT8kGKer3tWtLE8Lc7DdDIiikerznKsBXtjxMjZH\r\n" \
"+HlEjf/dp5LqQhsEfVQa7+YXJGVmdXvTpGrIkP0YiAlQscdgmFkoRcyEVJY/oCgE\r\n" \
"BhIKh68otjZkVgK/E4qzpv2C6575iR4WxJG01LAVzdRvDPYyK08aXfKgTxygxJOC\r\n" \
"40iQicOVZ8/s9iBfPxXXPaYf5tOf9nGi4fOba8eGa32ZtpJCBHS45Z5JYAWSM2aW\r\n" \
"s9O7WQRvehw4eOza5gtw/+SlKHB4SlguwNBxz+kMS6t5PN16GPZW+vsY4aVSaXw6\r\n" \
"5z2fZTTtvFoUT0j40fRF8N1BPV5ubZr5AgMBAAEwDQYJKoZIhvcNAQELBQADggEB\r\n" \
"AK+6MRg6U7cT2fFsKRlhYGB1Q7pY8jn8RmdEOHwfbEFiW1as2DantVs1S8ZWgIL8\r\n" \
"+gu0FlNC1QlPOVceF2SCl/44dtgXSSGqivZfnK9v8Gg7HMQMSgXtQlULu4piVpVw\r\n" \
"pi3HkzIBsQiHtBaLB7ukmOmFXFXorrHbVxsIK9ZZW+OAP+E8O0byEVkyUMCLugxd\r\n" \
"B8IQiGN0SmIOIuM5VoRujnLBBs8GCY+XmEf3qgHU+Tv5I6IhSL+p0eTfVP17ZFU4\r\n" \
"a6xkq64n74XDOKlpIEQ9NnHpHiQmCYkMBZwC2NBNXKG/uw5PKkV51kFqaHe8T29n\r\n" \
"4uhXD15/+AkOnvhSt7Uuooc=\r\n" \
"-----END CERTIFICATE-----\r\n"
};

unsigned char mbedtls_client_crt[] =
{
"-----BEGIN CERTIFICATE-----\r\n" \
"MIIDYDCCAkgCFG2ck7C9+1Hyz/ipV3TxBxUYfvHdMA0GCSqGSIb3DQEBCwUAMFox\r\n" \
"CzAJBgNVBAYTAkNOMQswCQYDVQQIDAJTRDELMAkGA1UEBwwCSk4xDTALBgNVBAoM\r\n" \
"BFFEWlkxFTATBgNVBAsMDHd3dy5xZHp5LmNvbTELMAkGA1UEAwwCQ0EwIBcNMjAx\r\n" \
"MTA2MDUzNjM2WhgPMjEyMDEwMTMwNTM2MzZaMH0xCzAJBgNVBAYTAkNOMQswCQYD\r\n" \
"VQQIDAJTRDELMAkGA1UEBwwCSk4xDTALBgNVBAoMBFFEWlkxFTATBgNVBAsMDHd3\r\n" \
"dy50ZXN0LmNvbTEPMA0GA1UEAwwGQ0xJRU5UMR0wGwYJKoZIhvcNAQkBFg5hZG1p\r\n" \
"bkB0ZXN0LmNvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK/MX5t+\r\n" \
"FU6de4bgZer45C5CjkwtbS7nSdBiMmZSbN4NRHDqhsBTnqK4W2TkYxKjY+YOos5S\r\n" \
"LCN/gaRY1SANJ10Ohdvyr+GJBv/MKPdCWA0MScCUT9B+ihgX4MhBLwz0SNnlcT97\r\n" \
"zA5owB6ynj/hY26foOto9eFVRVl1tUaXm94g6JcMZdI7/ie0KtzMLb0vnSII5eXk\r\n" \
"61vRQ03XOh9D3iiYQ6CfYLwC7NA2i2fYi7mFCGhFJyUIgZSF70Qd5lzd2bYZEfYr\r\n" \
"zZs7m4TZ60Gs78meystKN1AxtPHTMhW3tjekWIqvbVWE2H+QQwWosmOovRr1dNDh\r\n" \
"h+JNJZeNJAY7rHMCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAZnoOOJfqLVxYLKrQ\r\n" \
"o9nlhHmN+Fh/8Gs+gECocg0f4Yj+XFHnwGut3M79aPHGgNLt62sIK03tAPzjBh89\r\n" \
"+PLMsM80nh17AgE5xNEJUl2jxOzwAKMuBILgP9IAXSTqAs+xEd7ZJki0eiNXIAoV\r\n" \
"GJgsXxL7MoXMO/x6B5inwIIhbaPdC2VzHC/SV5V1HvGVV/OJnJuLwemjCaJTEcaZ\r\n" \
"x9JVlal7CXk8W8DeSz+PgrdFwdnT0NU+KGFuW5hCZHdsASYtURsdpO9jYFBxQdsF\r\n" \
"jMGWYZbUH6t5hHVfjp/lLPxGHvqR90EcYS+PwWzNSw2IACw2EnyvDYZwzmUM9J9g\r\n" \
"Ak7ypg==\r\n" \
"-----END CERTIFICATE-----\r\n"
};


unsigned char mbedtls_client_key[] =
{
"-----BEGIN RSA PRIVATE KEY-----\r\n" \
"Proc-Type: 4,ENCRYPTED\r\n" \
"DEK-Info: AES-256-CBC,784C65C31E5AB3918DD25BC12DF00B4B\r\n" \
"\r\n" \
"R3IW5IZg7ClBUiPec7wTdjBBs6WSWLacnThO/3X77kY3OzEApIpQq8RVS8oiMZB7\r\n" \
"N7Q65KTP1TOCZl/AWiiGcW0RCUAeuVM9cWw4GqfEYk0l1x7OWdc8AZu11FJ8WcUy\r\n" \
"BJDgv1h1fY+XzM4+cgDUUzHOJt9QHjQ6iEaheisqeHIZkHfRYqR8kNQOBi1280tL\r\n" \
"9lO8Ns75py9YvkPWHT9lUy1T3avJeuoU7JiL1v4iUHW9wUi1NuPwxamoDjrtwUtJ\r\n" \
"zi0vy8/Xs4x38gLT0fv1UIvD1yS7W1R+c5melHkLYboPUg8i5azuSLYXSD0yIHh/\r\n" \
"Xhb2AhpQF6PuGdapR1+tMne6pP2+rI3B9J9bPwfMN0m/SBy4me9McYfLs08dsmuz\r\n" \
"eLGwwcLWQDtigCjFshTwhXVeStS0vVDEJmLGMOPiLtXFNdPyZthdI/QvJVlLAOXS\r\n" \
"76Q4mKzczWBqWRDLknkKxq5fgGqvXkiIRgecXNTkFanVebIT74O8egWvTQT6CSQ6\r\n" \
"TYckto3rBw+5MCM0wlhEh+5CgDJ3+1UsQkeqAizz3We/p0qTKR+0bwnm9HO8V3MW\r\n" \
"62QmPzLEzdDvPSLxjSOT61Qe5LxQMyhvRw9JXl1flcJex/PLCZIu9/Qn/QlM9oyU\r\n" \
"rspMDEJH9nVI8VyE94krwvCQYJ163bRRvraj/zQ8hPaCnpMuORYbBl1BG1e6DeHH\r\n" \
"o++DtJ1aEPF2M8QNIORi5YQKfgcfqzEMMULw8ZoToomEIj3Mox/gL3idB9YYX5o+\r\n" \
"GgerK6mjNkbAErpcf5XQG8jKdaQILp/JyUy8a+HdP7oFUr9Sc7Wr+Kg0KqVnlhMM\r\n" \
"w09U3xHAcbc4yuRK7inozGixWEBvXlb4e7SEAg2Jeh6gjDEBWOCDQR09FXmkZw/I\r\n" \
"dY484u0r/Uikme39IXVtPE8ovaNUjLrTf8pcKgZiRg51+k/xoRJXRmUTFc2pE67g\r\n" \
"niy4JhdG1bd1SWy3AYfVSd6aST/VJGjxxu71qg6LPAzu7S9ihuRQNaiEabk+O34x\r\n" \
"cHKbD7QO0O4ke/1wCeJFmcVEFHxrscoQM7g2TD5T4F0lA+c+D/jDq/LIOLvHIWSb\r\n" \
"CAXnOsJd0vxg99IBZV+9IqvIiWuxh0Aian1XUxaQU/Uc0qE9h/JL2wxMLgG9CVxU\r\n" \
"U2KdbcBLnq3/UqFDr536ANufJss/9eccowT/jr3vwoIfnRMYyp++D6XfmZqWlPuF\r\n" \
"SKw20WGADuAl1vHYdDbaPBbH2IkvIRwO/tjCG16D/I1KnAZcMIAPSAzDIi9vhvfS\r\n" \
"w2YXgTXJ3jXzJ7T30pc+0GVFckVqivMDNyq0kIWOR47CrL5dBub/KZyIBtKASHMe\r\n" \
"AguG7jvtz/3zIVdVJwGc31MxPrtINf0A33IGOx/uwzlcxOChwKNeRn63IGLU3rqW\r\n" \
"0xWpYNeeL/YKxKYttnpw3JQ0/8J2TrGvMg7hWLKl1rCXdIqAaz1ZmlczDRLbznCl\r\n" \
"dNBKN67zwe/YqyGAoi6jfvIEHs7k7JPQQhwbDlY9XzEDAvc5kNQ4BToeDf8DFW+N\r\n" \
"wvbgXy04sFIXOYCCkgEcrqOURMTU8dQ+/gSqAnMdFE1CbZSELQVe9pcO8ea3Usis\r\n" \
"-----END RSA PRIVATE KEY-----\r\n" \
};

typedef struct
{
mbedtls_net_context netctx;
mbedtls_ssl_context sslctx;
mbedtls_ssl_config sslcfg;
mbedtls_ctr_drbg_context drbgctx;
mbedtls_entropy_context etpyctx;
mbedtls_x509_crt x509cacrt;
mbedtls_x509_crt x509clicrt;
mbedtls_pk_context pkey;
}mbedtls_client_t;

size_t mbedtls_client_key_len = sizeof(mbedtls_client_key);
size_t mbedtls_client_crt_len = sizeof(mbedtls_client_crt);
size_t mbedtls_ca_crt_len = sizeof(mbedtls_ca_crt);

unsigned char Buffer[1024];
mbedtls_client_t client;

#define IP "192.168.31.16"
#define PORT "5004"

mbedtls_x509_crt_profile x509_crt_profile =
{
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ),
0xFFFFFFF, /* Any PK alg */
0xFFFFFFF, /* Any curve */
2048, /* 密钥长度为2048 */
};

static int mbedtls_ssl_sig_hashes[] =
{
MBEDTLS_MD_SHA512,
MBEDTLS_MD_SHA384,
MBEDTLS_MD_SHA256,
MBEDTLS_MD_SHA224,
MBEDTLS_MD_SHA1,
MBEDTLS_MD_NONE
};

int mbedtls_ssl_client_init(mbedtls_client_t* client,
const void* cacert, size_t cacertLength,
const void* clicert,size_t clicertLength,
const void* clikey, size_t clikeyLength,
const void* clipwd, size_t clipwdLength,
const void* pers, size_t persLength,
const void* CNname)
{
int ret = 0;

//
// 初始化
//
mbedtls_net_init(&client->netctx);
mbedtls_ssl_init(&client->sslctx);
mbedtls_ssl_config_init(&client->sslcfg);
mbedtls_ctr_drbg_init(&client->drbgctx);
mbedtls_x509_crt_init(&client->x509cacrt);
mbedtls_x509_crt_init(&client->x509clicrt);
mbedtls_pk_init(&client->pkey);
mbedtls_entropy_init(&client->etpyctx);

// 加载CA证书
if((ret = mbedtls_x509_crt_parse(&client->x509cacrt, (const unsigned char *)cacert, cacertLength)) != 0)
return -1;

if(clicert != NULL)
{
// 加载客户端证书
if((ret = mbedtls_x509_crt_parse(&client->x509clicrt, (const unsigned char *)clicert, clicertLength)) != 0)
return -2;

// 加载服务器密钥
if((ret = mbedtls_pk_parse_key(&client->pkey, (const unsigned char *) clikey, clikeyLength, (const unsigned char *)clipwd, clipwdLength)) != 0)
return -3;

// 设置客户端证书和密钥关联
if ((ret = mbedtls_ssl_conf_own_cert(&client->sslcfg, &client->x509clicrt, &client->pkey)) != 0)
return -4;
}

// 设置SSL/TLS熵源
if((ret = mbedtls_ctr_drbg_seed(&client->drbgctx, mbedtls_entropy_func, &client->etpyctx, (const unsigned char *)pers, persLength)) != 0)
return -5;

// 设置SSL为客户端
ret = mbedtls_ssl_config_defaults(&client->sslcfg, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT);
if(ret != 0)
return -6;

// 设置用于验证的X.509安全配置文件
mbedtls_ssl_conf_cert_profile(&client->sslcfg, &x509_crt_profile);

// 设置握手签名的允许/首选散列算法
mbedtls_ssl_conf_sig_hashes(&client->sslcfg, mbedtls_ssl_sig_hashes);

//
// 设置认证模式
//
// MBEDTLS_SSL_VERIFY_NONE :不检查对等证书(服务器默认值)。如果客户端配置为此选项那么连接是不安全的。
//
// MBEDTLS_SSL_VERIFY_OPTIONAL :检查对等证书,但即使验证失败,握手仍将继续;
// 可以在握手完成后调用mbedtls_ssl_get_verify_result()查看验证结果。
//
// MBEDTLS_SSL_VERIFY_REQUIRED :同时必须出示有效证书,如果验证失败,握手将终止。(客户端默认值)
//
mbedtls_ssl_conf_authmode(&client->sslcfg, MBEDTLS_SSL_VERIFY_REQUIRED);

// 设置随机数生成器回调
mbedtls_ssl_conf_rng(&client->sslcfg, mbedtls_ctr_drbg_random, &client->drbgctx);

// 设置CA证书
mbedtls_ssl_conf_ca_chain(&client->sslcfg, &client->x509cacrt, NULL);

// 配置设置
if((ret = mbedtls_ssl_setup(&client->sslctx, &client->sslcfg)) != 0)
return -7;

// 设置SSL服务器CN名称
if((ret = mbedtls_ssl_set_hostname(&client->sslctx, (const char *)CNname)) != 0)
return -8;

return 0;
}

int mbedtls_ssl_client_connect(mbedtls_client_t* client,const void* ip, const void* port)
{
int ret = 0;

// 重置客户端连接
mbedtls_net_free(&client->netctx);

// 重置SSL会话信息
mbedtls_ssl_session_reset(&client->sslctx);

// 连接到服务器
if((ret = mbedtls_net_connect(&client->netctx, (const char *)ip, (const char *)port, MBEDTLS_NET_PROTO_TCP)) != 0)
return -1;

// 设置数据接收发送回调
mbedtls_ssl_set_bio(&client->sslctx,
&client->netctx,
mbedtls_net_send,
mbedtls_net_recv,
mbedtls_net_recv_timeout);

// 握手
while((ret = mbedtls_ssl_handshake(&client->sslctx)) != 0)
{
if((ret != MBEDTLS_ERR_SSL_WANT_READ) && (ret != MBEDTLS_ERR_SSL_WANT_WRITE))
return -2;
}

// 获取验证结果
if((ret = mbedtls_ssl_get_verify_result(&client->sslctx)) != 0)
{
char vrfy_buf[128];
int flags = mbedtls_ssl_get_verify_result(&client->sslctx);
mbedtls_x509_crt_verify_info( vrfy_buf, sizeof( vrfy_buf ), " ! ", flags );
debug_e( "%s\n", vrfy_buf );
// return -3;
}

return 0;
}

void mbedtls_ssl_client_destory(mbedtls_client_t* client)
{
mbedtls_net_free(&client->netctx);
mbedtls_x509_crt_free(&client->x509cacrt);
mbedtls_x509_crt_free(&client->x509clicrt);
mbedtls_pk_free(&client->pkey);
mbedtls_ssl_free(&client->sslctx);
mbedtls_ssl_config_free(&client->sslcfg);
mbedtls_ctr_drbg_free(&client->drbgctx);
mbedtls_entropy_free(&client->etpyctx);
}

void mbedtls_ssl_client_disconnect(mbedtls_client_t* client)
{
mbedtls_ssl_close_notify(&client->sslctx);
}

#define AUTOMODE 1 // =1:双向认证 =0:单向认证

int main(void)
{
int ret = 0;

debug("-------------------- SSL Client Demo ---------------------------\r\n");

#if (AUTOMODE == 1)
if((ret = mbedtls_ssl_client_init(&client,
mbedtls_ca_crt,
mbedtls_ca_crt_len,
mbedtls_client_crt,
mbedtls_client_crt_len,
mbedtls_client_key,
mbedtls_client_key_len,
"zxcvbnm.",
strlen("zxcvbnm."),
"ssl_client",
strlen("ssl_client"),
"SERVER")) != 0)
#else
if((ret = mbedtls_ssl_client_init(&client,
mbedtls_ca_crt,
mbedtls_ca_crt_len,
NULL,
0,
NULL,
0,
NULL,
0,
"ssl_client",
strlen("ssl_client"),
"SERVER")) != 0)
#endif
{
debug_e(" init failed,err:%d.\r\n", ret);
goto __exit;
}
debug(" ssl client init ok. \r\n");

if((ret = mbedtls_ssl_client_connect(&client, IP, PORT)) != 0)
{
debug_e(" connect failed,err:%X\r\n", ret);
goto __exit;
}

debug(" ssl connect ok. \r\n");

if(mbedtls_ssl_write(&client.sslctx, (const unsigned char *)"Hello Server !", strlen("Hello Server !")) < 0)
{
debug_e(" write failed,errcode:%d.\r\n", ret);
goto __exit;
}

debug(" %d bytes written. \r\n", strlen("Hello Server !"));

do
{
memset(Buffer, 0X00, sizeof(Buffer));

ret = mbedtls_ssl_read(&client.sslctx, Buffer, sizeof(Buffer));

if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
{
continue;
}

if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) // 远程关闭了连接
{
break;
}

if(ret <= 0)
{
break;
}

debug(" %d bytes read:[%s]\r\n", ret, Buffer);

}while(1);

__exit:
mbedtls_ssl_client_disconnect(&client);
mbedtls_ssl_client_destory(&client);
return 0;
}

2、服务器代码模型

/*
* main.c
*
* Created on: 2020年10月29日
* Author: hello
*/


#include <stdlib.h>
#include <string.h>

#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/certs.h"
#include "mbedtls/x509.h"
#include "mbedtls/ssl.h"
#include "mbedtls/net_sockets.h"
#include "mbedtls/error.h"
#include "mbedtls/debug.h"
#include "mbedtls/config.h"

#define debug_e(fmt, ...) do{fprintf(stderr, fmt, ##__VA_ARGS__);fflush(stderr);}while(0);
#define debug(fmt, ...) do{printf(fmt, ##__VA_ARGS__);fflush(stdout);}while(0);

#define IP "192.168.31.16"
#define PORT "5004"

unsigned char mbedtls_ca_crt[] =
{
"-----BEGIN CERTIFICATE-----\r\n" \
"MIIDPTCCAiUCFAyaaimE7qW89Z0Verz2WN3cABu4MA0GCSqGSIb3DQEBCwUAMFox\r\n" \
"CzAJBgNVBAYTAkNOMQswCQYDVQQIDAJTRDELMAkGA1UEBwwCSk4xDTALBgNVBAoM\r\n" \
"BFFEWlkxFTATBgNVBAsMDHd3dy5xZHp5LmNvbTELMAkGA1UEAwwCQ0EwIBcNMjAx\r\n" \
"MTA1MDgxOTM0WhgPMjEyMDEwMTIwODE5MzRaMFoxCzAJBgNVBAYTAkNOMQswCQYD\r\n" \
"VQQIDAJTRDELMAkGA1UEBwwCSk4xDTALBgNVBAoMBFFEWlkxFTATBgNVBAsMDHd3\r\n" \
"dy5xZHp5LmNvbTELMAkGA1UEAwwCQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw\r\n" \
"ggEKAoIBAQDWU0v4jZ1OPxpGJT8kGKer3tWtLE8Lc7DdDIiikerznKsBXtjxMjZH\r\n" \
"+HlEjf/dp5LqQhsEfVQa7+YXJGVmdXvTpGrIkP0YiAlQscdgmFkoRcyEVJY/oCgE\r\n" \
"BhIKh68otjZkVgK/E4qzpv2C6575iR4WxJG01LAVzdRvDPYyK08aXfKgTxygxJOC\r\n" \
"40iQicOVZ8/s9iBfPxXXPaYf5tOf9nGi4fOba8eGa32ZtpJCBHS45Z5JYAWSM2aW\r\n" \
"s9O7WQRvehw4eOza5gtw/+SlKHB4SlguwNBxz+kMS6t5PN16GPZW+vsY4aVSaXw6\r\n" \
"5z2fZTTtvFoUT0j40fRF8N1BPV5ubZr5AgMBAAEwDQYJKoZIhvcNAQELBQADggEB\r\n" \
"AK+6MRg6U7cT2fFsKRlhYGB1Q7pY8jn8RmdEOHwfbEFiW1as2DantVs1S8ZWgIL8\r\n" \
"+gu0FlNC1QlPOVceF2SCl/44dtgXSSGqivZfnK9v8Gg7HMQMSgXtQlULu4piVpVw\r\n" \
"pi3HkzIBsQiHtBaLB7ukmOmFXFXorrHbVxsIK9ZZW+OAP+E8O0byEVkyUMCLugxd\r\n" \
"B8IQiGN0SmIOIuM5VoRujnLBBs8GCY+XmEf3qgHU+Tv5I6IhSL+p0eTfVP17ZFU4\r\n" \
"a6xkq64n74XDOKlpIEQ9NnHpHiQmCYkMBZwC2NBNXKG/uw5PKkV51kFqaHe8T29n\r\n" \
"4uhXD15/+AkOnvhSt7Uuooc=\r\n" \
"-----END CERTIFICATE-----\r\n"
};

unsigned char mbedtls_srv_crt[] =
{
"-----BEGIN CERTIFICATE-----\r\n" \
"MIIDQTCCAikCFG2ck7C9+1Hyz/ipV3TxBxUYfvHbMA0GCSqGSIb3DQEBCwUAMFox\r\n" \
"CzAJBgNVBAYTAkNOMQswCQYDVQQIDAJTRDELMAkGA1UEBwwCSk4xDTALBgNVBAoM\r\n" \
"BFFEWlkxFTATBgNVBAsMDHd3dy5xZHp5LmNvbTELMAkGA1UEAwwCQ0EwIBcNMjAx\r\n" \
"MTA1MDgyMDAwWhgPMjEyMDEwMTIwODIwMDBaMF4xCzAJBgNVBAYTAkNOMQswCQYD\r\n" \
"VQQIDAJTRDELMAkGA1UEBwwCSk4xDTALBgNVBAoMBFFEWlkxFTATBgNVBAsMDHd3\r\n" \
"dy5xZHp5LmNvbTEPMA0GA1UEAwwGU0VSVkVSMIIBIjANBgkqhkiG9w0BAQEFAAOC\r\n" \
"AQ8AMIIBCgKCAQEAt9su9lcpQ+UjSuk9t3WDes/XmRNvC05XfyEWELwFAJXtumAD\r\n" \
"HSLD3xiZE+VPOdYkicUl9LwJmZrpS+M+777klhYUKijrinz9f3pFdT9e3s1cDFu4\r\n" \
"J4+DE6rtIq7tXlS9bC54SKua+HPsVnNd3xEyxIFyEahZKAkYfB9gb9Qh/meHFQC7\r\n" \
"q0erggt8/haabjvAqdXw8A1I1zgVfqTAVP9TuHAN+sZsnkA4uIXJh9bjtmQDP7k9\r\n" \
"tvTO3+WJz3KwYp5Q9VeHv3zXRlnILfyyNgQuGFUyjoTnyY6DfLsYUn81Vv+e3S3H\r\n" \
"NdujwhulZKY7Nc43VPunLUk9HEjGpCli8VVQpwIDAQABMA0GCSqGSIb3DQEBCwUA\r\n" \
"A4IBAQB0tQ7PbyxnTWCLCbNFZMlbj2yerI5QhOI+3RKoIlkUh6OaTuJhczzhhJ5C\r\n" \
"RuUqwAtxjF6AShp7yL8WQl9JHkohDi9JZ2qZMnFWigEJejjW+t66k85zh5zbYGNI\r\n" \
"HV+5wJlkF+SyXZCZgAB0u2j/21itqhNSPQ/Y2UH4eENq0vNbehZiFFzdFZyqHIXl\r\n" \
"N2UAT6cyWdf5WqRHmXlymSpwXgHikpnXCXYxYNvHYgRacMPMR2DqcbvkZ8FY9n8x\r\n" \
"bNK0HLzmKp2Gk73MMySmsDCAnv4TXSJriR08WTAUEvVBDQQfSZGtYhXCtCS9zLAj\r\n" \
"SAo+7/18VhyYyAsWq5W4fUtTY+rV\r\n" \
"-----END CERTIFICATE-----\r\n"
};

unsigned char mbedtls_srv_key[] =
{
"-----BEGIN RSA PRIVATE KEY-----\r\n" \
"Proc-Type: 4,ENCRYPTED\r\n" \
"DEK-Info: AES-256-CBC,D40A7C926A0DFC3E4F0B137FE4D2AC74\r\n" \
"\r\n" \
"xxjNIwzrrFMQ2iWhlCHh0Ck8z2tgp/C8ieXHbjUdvOzHVTLeNsGIaGK4m9mGbcBn\r\n" \
"HEheWMqHAnEYTNzA2SFxZdQlzxhee1d7ATu4TSSkN4JM8Ahi3f44w2irqL3hBiHT\r\n" \
"sQMRUjg62snAiNS5Cz0CllP74kZwJXFuiRWCJSFaXUI0U2yrp6AuFIOBPVSN5cvM\r\n" \
"if8+8lMRaXlESB9LzQomg8q4Qh1vQGBR5k10pVn/GhngwBDm8uhCyqH0lq+RKq3H\r\n" \
"wCGYmL8v1qW7CG8Wqm4UexZpgbMnOWg0xLEnr8Xvjl1YmCFWcG+wRtybEErSxlbD\r\n" \
"QzWQCK51UE5HTmdD3O5F0FZ/ksopH+SD/xPpKRdMa9px8wIeAlXc5jY2U2IbaTe5\r\n" \
"Bo0ma5O7QrmqxjkiVIXOT+hJgzR3xm/AxYNVB8vSP+L427C+eynI43hcHNpyVD/1\r\n" \
"n60bYR9cGf6rilpW9F6fvBOAleRsQ4m40TGszwlh42HsnrLY+nNtsBr3Z7h2nCEr\r\n" \
"UFfWENvqSa1+r5J9MqCnQorqvXEGSoNdtr2NPQDgSJb0cJx45XgKMqwP/i0+nz5B\r\n" \
"0imaJ6/9J/oLaiNfcEJHFRsZL/Gs558oCypzfhhJEuRnrmKn4deGboGdFS+1ChiP\r\n" \
"4lCIJqUEpj7ExTae/Ea7L+xd3UGmrRGnF4aJ9O4i4ElyY6CRK9O/19k2s/F5m+WP\r\n" \
"LkFJMdxHDIkJWzIxix7sTVd92zBcnsoqS/h6zlU+LspfZ8GGMf4ThObi7zg80Zsk\r\n" \
"xxJNahlyItZzGSeXu2FGhzt9I30gle2kIY8febB+c8OdHH+giFZGEiE6oqgbuKgc\r\n" \
"8W6xqaBQpL8LnTkfizcH9IfiZdUCPwrUsUssa5PXsiehUZB0DLYNAFM7jiVZfeQM\r\n" \
"GwAzPQJi2Y/GIkP7eSxRcGfB4FM2UWUBKA5awfYh7UbunGu85rgsFVfunwNXYrcd\r\n" \
"BFy8CK8sXFUwhwiprawfya6iO5GXfbOeSoi3HMhbXbdcdxFxMWPBzKzag+GQhB9M\r\n" \
"Q08ujKWW3WYrCvby0K5yZq4Up7+4bBQgWiifcL7laEfl0snio2oD9dtZBezgy6/n\r\n" \
"vWiTW0lounaU/tK5GsHtgsgDBcOwbVLirt8KXHsWlI22weLrBLYaImgzmxXn0U7O\r\n" \
"06ab+3aP12ICQY1stWLK9DowDmjCqWsBiuUoMMtB9a2yF/ra2a3QVe99N6yxGRz2\r\n" \
"xmtv9NJwkTX7KSmLw0SWHHhqepwOEFW4ckkLd7Y5jD053bgSFNrBtbfPi+C9Ustv\r\n" \
"GXdnvGzrAkhy9vq+tCAHuzwuBXnTMTf43fbWRbzQi7ZKVpubYFS7mqEfXXqkHhpl\r\n" \
"v1P3fpURqWfSQOfPt5kIwjzc3swUKo1czZnfACcIB274FQlDOZq2sxNJYxyI2iAG\r\n" \
"hK9hPqbYfswT53978BYe2R9ChDsFHFcSZyJFb4Sydr755PFFHL6LV1k2w8z4RGpJ\r\n" \
"dZbH4WuYHlNs04K8TqbZGg0d8T544yHPdlMGY72YFJ4DbW/uckjSo/z4djyls6NT\r\n" \
"vJPCm1ZvcTu+FyL/lEL/jNsNF17kdipDhtmhFr3KPbxKycFe+mZnhVHPTZ/Gcm3U\r\n" \
"-----END RSA PRIVATE KEY-----\r\n"
};

typedef struct
{
mbedtls_net_context listen_netctx;
mbedtls_net_context client_netctx;
mbedtls_ssl_context sslctx;
mbedtls_ssl_config sslcfg;
mbedtls_ctr_drbg_context drbgctx;
mbedtls_entropy_context etpyctx;
mbedtls_x509_crt x509cacrt;
mbedtls_x509_crt x509srvcrt;
mbedtls_pk_context pkey;
} mbedtls_server_t;

mbedtls_server_t server;

size_t mbedtls_ca_crt_len = sizeof(mbedtls_ca_crt);
size_t mbedtls_srv_crt_len = sizeof(mbedtls_srv_crt);
size_t mbedtls_srv_key_len = sizeof(mbedtls_srv_key);

mbedtls_x509_crt_profile x509_crt_profile =
{
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA1 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA224 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA256 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA384 ) |
MBEDTLS_X509_ID_FLAG( MBEDTLS_MD_SHA512 ),
0xFFFFFFF, /* Any PK alg */
0xFFFFFFF, /* Any curve */
2048, /* 密钥长度为2048 */
};

static int mbedtls_ssl_sig_hashes[] =
{
MBEDTLS_MD_SHA512,
MBEDTLS_MD_SHA384,
MBEDTLS_MD_SHA256,
MBEDTLS_MD_SHA224,
MBEDTLS_MD_SHA1,
MBEDTLS_MD_NONE
};

uint8_t Buffer[1024];

/**
* SSL服务器网络初始化
* @param server
* @param ip ip地址字符串形式
* @param port 端口字符串形式
* @return 成功返回0,失败返回负值
*/
int mbedtls_ssl_server_wait_for_connect(mbedtls_server_t* server, const void* ip, const void* port)
{
int ret = 0;

// 绑定本地IP地址端口
if ((ret = mbedtls_net_bind(&server->listen_netctx, (const char *)ip, (const char *)port, MBEDTLS_NET_PROTO_TCP)) != 0)
return -1;

// 清理客户端连接
mbedtls_net_free(&server->client_netctx);

// 清理SSL会话信息
mbedtls_ssl_session_reset(&server->sslctx);

// 等待客户端连接
if ((ret = mbedtls_net_accept(&server->listen_netctx, &server->client_netctx, NULL, 0, NULL)) != 0)
return -2;

// 设置收发数据接口函数
mbedtls_ssl_set_bio(&server->sslctx, &server->client_netctx, mbedtls_net_send, mbedtls_net_recv, NULL);

// 握手
while ((ret = mbedtls_ssl_handshake(&server->sslctx)) != 0)
{
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
return -3;
}

// 获取验证结果
if((ret = mbedtls_ssl_get_verify_result(&server->sslctx)) != 0)
{
char vrfy_buf[128];
int flags = mbedtls_ssl_get_verify_result(&server->sslctx);
mbedtls_x509_crt_verify_info( vrfy_buf, sizeof( vrfy_buf ), " ! ", flags );
debug_e( "%s\n", vrfy_buf );
// return -4;
}

return 0;
}

/// 断开连接
void mbedtls_ssl_server_close(mbedtls_server_t* server)
{
mbedtls_ssl_close_notify(&server->sslctx);
}

/// 清理
void mbedtls_ssl_server_destory(mbedtls_server_t* server)
{
mbedtls_net_free(&server->client_netctx);
mbedtls_net_free(&server->listen_netctx);
mbedtls_x509_crt_free(&server->x509cacrt);
mbedtls_x509_crt_free(&server->x509srvcrt);
mbedtls_pk_free(&server->pkey);
mbedtls_ssl_free(&server->sslctx);
mbedtls_ssl_config_free(&server->sslcfg);
mbedtls_ctr_drbg_free(&server->drbgctx);
mbedtls_entropy_free(&server->etpyctx);
}

/**
* SSL服务器初始化
* @param server
* @param cacrt CA证书
* @param cacrtLength CA证书长度
* @param srvcrt 服务器证书
* @param srvcrtLength 服务器整数长度
* @param srvkey 服务器密钥
* @param srvkeyLength 服务器密钥长度
* @param srvpwd 服务器密码
* @param srvpwdLength 服务器密码长度
* @param pers 熵字符串,任意字符串即可
* @param persLength 熵字符串长度
* @return 成功返回0,失败返回负值
*/
int mbedtls_ssl_server_init(
mbedtls_server_t* server,
const void* cacrt, size_t cacrtLength,
const void* srvcrt, size_t srvcrtLength,
const void* srvkey, size_t srvkeyLength,
const void* srvpwd, size_t srvpwdLength,
const void* pers, size_t persLength)
{
int ret = 0;

//
// 初始化
//
mbedtls_net_init(&server->listen_netctx);
mbedtls_net_init(&server->client_netctx);
mbedtls_ssl_init(&server->sslctx);
mbedtls_ssl_config_init(&server->sslcfg);
mbedtls_x509_crt_init(&server->x509cacrt);
mbedtls_x509_crt_init(&server->x509srvcrt);
mbedtls_pk_init(&server->pkey);
mbedtls_entropy_init(&server->etpyctx);
mbedtls_ctr_drbg_init(&server->drbgctx);

// 加载服务器证书
if ((ret = mbedtls_x509_crt_parse(&server->x509srvcrt, (const unsigned char *) srvcrt, srvcrtLength)) != 0)
return -1;

// 加载CA证书
if ((ret = mbedtls_x509_crt_parse(&server->x509cacrt, (const unsigned char *) cacrt, cacrtLength)) != 0)
return -2;

// 加载服务器密钥
if ((ret = mbedtls_pk_parse_key(&server->pkey, (const unsigned char *) srvkey, srvkeyLength, (const unsigned char *)srvpwd, srvpwdLength)) != 0)
return -3;

// 设置SSL/TLS熵源
if ((ret = mbedtls_ctr_drbg_seed(&server->drbgctx, mbedtls_entropy_func, &server->etpyctx, (const unsigned char *) pers, persLength)) != 0)
return -4;

// 设置SSL连接模式
if ((ret = mbedtls_ssl_config_defaults(&server->sslcfg, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0)
return -5;

// 设置随机数生成器回调
mbedtls_ssl_conf_rng(&server->sslcfg, mbedtls_ctr_drbg_random, &server->drbgctx);

// 设置CA证书认证关联到SSL结构上
mbedtls_ssl_conf_ca_chain(&server->sslcfg, &server->x509cacrt, NULL);

// 设置服务器证书和密钥关联
if ((ret = mbedtls_ssl_conf_own_cert(&server->sslcfg, &server->x509srvcrt, &server->pkey)) != 0)
return -6;

// 设置用于验证的X.509安全配置文件
mbedtls_ssl_conf_cert_profile(&server->sslcfg, &x509_crt_profile);

// 设置握手签名的允许/首选散列算法
mbedtls_ssl_conf_sig_hashes(&server->sslcfg, mbedtls_ssl_sig_hashes);

//
// 设置认证模式
//
// MBEDTLS_SSL_VERIFY_NONE :不检查对等证书
// (服务器默认值,如果客户端配置为此选项那么连接是不安全的;如果服务器配置为此值那么是单向认证。)
//
// MBEDTLS_SSL_VERIFY_OPTIONAL :检查对等证书,但即使验证失败,握手仍将继续;
// 可以在握手完成后调用mbedtls_ssl_get_verify_result()查看验证结果。
// (如果服务器设置为此值,那么就是双向认证)
//
// MBEDTLS_SSL_VERIFY_REQUIRED :同时必须出示有效证书,如果验证失败,握手将终止。
// (客户端默认值,如果服务器设置为此值,那么就是双向认证)
//
mbedtls_ssl_conf_authmode(&server->sslcfg, MBEDTLS_SSL_VERIFY_REQUIRED);

// 配置设置
if ((ret = mbedtls_ssl_setup(&server->sslctx, &server->sslcfg)) != 0)
return -7;

return 0;
}

int main(void)
{
int ret = 0;

debug("-------------------- SSL Server Demo ---------------------------\r\n");

ret = mbedtls_ssl_server_init(
&server,
mbedtls_ca_crt,
mbedtls_ca_crt_len,
mbedtls_srv_crt,
mbedtls_srv_crt_len,
mbedtls_srv_key,
mbedtls_srv_key_len,
"zxcvbnm.",
strlen("zxcvbnm."),
"ssl_server",
strlen("ssl_server"));
if(ret != 0)
{
debug_e(" ssl server init failed,errcode:%d\r\n", ret);
goto __exit;
}

debug(" ssl server init ok. \r\n");

debug(" wait for connect...\r\n");
if ((ret = mbedtls_ssl_server_wait_for_connect(&server, IP, PORT)) != 0)
{
debug_e(" wait for connect failed,errcode:%d\r\n", ret);
goto __exit;
}

debug(" client connected.\r\n");

//
// 接收数据
//
do
{
ret = mbedtls_ssl_read(&server.sslctx, Buffer, sizeof(Buffer));
if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)
{
continue;
}

if (ret <= 0)
{
break;
}

Buffer[ret] = 0;
debug(" %d bytes recv:[%s]\r\n", ret, Buffer);
break;
} while (1);

//
// 发送数据
//
while ((ret = mbedtls_ssl_write(&server.sslctx, (const unsigned char *)"Hello Client !", strlen("Hello Client !"))) <= 0)
{
if (ret == MBEDTLS_ERR_NET_CONN_RESET)
{
goto __exit;
}

if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
{
goto __exit;
}
}
debug(" %d bytes written.\r\n", strlen("Hello Client !"));

__exit:
mbedtls_ssl_server_close(&server);
mbedtls_ssl_server_destory(&server);
return 0;
}

ends…