SSL 开发指导_Rev1.0
修订记录
版本 |
日期 |
作者 |
修订内容 |
|---|---|---|---|
Rev1.0 |
2026-03-17 |
MBB |
创建文档 |
1 简介
本文档介绍 LTE-EC71X SSL2 函数接口,函数接口位于 components/kernel/lierda_api/liot_ssl2/liot_ssl2.h 文件声明。
1.1 SSL 原理简介
SSL/TLS 支持三种认证方式:无认证(不验证证书,通信加密)、单向认证(客户端验证服务器证书)、双向认证(客户端和服务器互相验证证书)。区别主要在于证书验证方向和客户端需准备的证书不同。
认证方式 |
auth_type 配置 |
客户端需准备证书 |
|---|---|---|
无认证 |
LIOT_SSL_VERIFY_NONE (0) |
无需证书 |
单向认证 |
LIOT_SSL_VERIFY_SERVER (1) |
CA 根证书(验证服务器) |
双向认证 |
LIOT_SSL_VERIFY_CLIENT_SERVER (2) |
CA 根证书 + 客户端证书 + 客户端私钥 |
2 API 函数概览
函数 |
说明 |
|---|---|
|
设置 SSL 配置信息 |
|
打开 SSL 连接 |
|
发送 SSL 数据 |
|
获取 SSL 连接状态 |
|
关闭 SSL 连接 |
3 类型说明
3.1 liot_ssl_session_t
SSL 会话句柄。
声明
typedef int liot_ssl_session_t;
3.2 liot_ssl_client_t
SSL 客户端句柄。
声明
typedef void *liot_ssl_client_t;
3.3 liot_ssl_config
SSL 配置句柄。
声明
typedef void *liot_ssl_config;
3.4 liot_sslClient_recvCb_t
SSL 客户端数据接收回调函数。
函数声明
typedef void (liot_sslClient_recvCb_t)(uint8_t clientId, void data, uint32_t dataLen, void *arg);
参数说明
参数
说明
clientId
SSL 客户端 ID
data
接收到的数据
dataLen
数据长度
arg
用户参数
4.5 liot_ssl_error_code_e
SSL 错误码。
枚举类型声明
typedef enum {
LIOT_SSL_SUCCESS = 0,
LIOT_SSL_ERROR_UNKOWN = -1,
LIOT_SSL_ERROR_WOUNDBLOCK = -2,
LIOT_SSL_ERROR_INVALID_PARAM = -3,
LIOT_SSL_ERROR_OUT_OF_MEM = -4,
LIOT_SSL_ERROR_NOT_SUPPORT = -5,
LIOT_SSL_ERROR_HS_FAILURE = -6,
LIOT_SSL_ERROR_DECRYPT_FAILURE = -7,
LIOT_SSL_ERROR_ENCRYPT_FAILURE = -8,
LIOT_SSL_ERROR_HS_INPROGRESS = -9,
LIOT_SSL_ERROR_BAD_REQUEST = -10,
LIOT_SSL_ERROR_WANT_READ = -11,
LIOT_SSL_ERROR_WANT_WRITE = -12,
LIOT_SSL_ERROR_SOCKET_RESET = -13,
LIOT_SSL_ERROR_TIMEOUT = -14,
LIOT_SSL_ERROR_SOCKET_CLOSED = -15,
LIOT_SSL_ERROR_SOCKET_ERROR = -16,
LIOT_SSL_ERROR_INVALID_CERT = -17,
LIOT_SSL_ERROR_VERIFY_FAILED = -18,
LIOT_SSL_ERROR_SEND_FAILURE = -19,
LIOT_SSL_ERROR_STATUS_ERROR = -20,
} liot_ssl_error_code_e;
枚举说明
参数 |
说明 |
|---|---|
|
操作成功 |
|
未知错误 |
|
阻塞错误 |
|
无效参数 |
|
内存不足 |
|
不支持的功能 |
|
握手失败 |
|
解密失败 |
|
加密失败 |
|
握手中 |
|
错误请求 |
|
需要读取 |
|
需要写入 |
|
Socket 重置 |
|
操作超时 |
|
Socket 已关闭 |
|
Socket 错误 |
|
无效证书 |
|
验证失败 |
|
发送失败 |
|
状态错误 |
3.6 liot_ssl_client_status_e
SSL 客户端状态。
枚举类型声明
typedef enum { LIOT_SSL_CLIENT_STATUS_INIT = 0, LIOT_SSL_CLIENT_STATUS_CONNECTING, LIOT_SSL_CLIENT_STATUS_CONNECTED, LIOT_SSL_CLIENT_STATUS_DISCONNECTING, LIOT_SSL_CLIENT_STATUS_DISCONNECTED, LIOT_SSL_CLIENT_STATUS_CLOSED, } liot_ssl_client_status_e;
枚举说明
参数 |
说明 |
|---|---|
|
初始状态 |
|
连接中 |
|
已连接 |
|
断开中 |
|
已断开 |
|
已关闭 |
3.7 liot_ssl_ca_chain_s
SSL CA 证书链结构。
结构体声明
typedef struct { char *ca_cert_list[LIOT_SSL_CA_CERT_MAX_CNT]; int ca_depth; } liot_ssl_ca_chain_s;
结构体说明
成员 |
说明 |
|---|---|
ca_cert_list |
CA 证书列表 |
ca_depth |
CA 证书深度 |
3.8 liot_ssl_user_cert_s
用户证书信息结构。
结构体声明
typedef struct { char *cert_file; char *key_file; char *key_password; } liot_ssl_user_cert_s;
结构体说明
成员 |
说明 |
|---|---|
cert_file |
证书文件 |
key_file |
私钥文件 |
key_password |
私钥密码 |
3.9 liot_ssl_psk_info_s
PSK 信息结构。
结构体声明
typedef struct { unsigned short psk_len; char *psk; unsigned short psk_identity_len; char *psk_identity; } liot_ssl_psk_info_s;
结构体说明
成员 |
说明 |
|---|---|
psk_len |
PSK 长度 |
psk |
预共享密钥 |
psk_identity_len |
PSK 身份长度 |
psk_identity |
PSK 身份 |
3.10 Liot_sslContext_t
SSL 上下文配置结构。
结构体声明
typedef struct { uint8_t ssl_version; uint8_t auth_type; int32_t ciphersuite[2]; uint8_t *alpn_list[LIOT_SSL_ALPN_NAME_LEN]; uint8_t sni_support; uint8_t cert_buffer_type; uint32_t r_timeout; uint32_t s_timeout; uint8_t transport_protocol; uint8_t *ca_cert; uint32_t ca_cert_length; uint8_t ca_cert_index; uint8_t *user_cert; uint32_t user_cert_length; uint8_t *user_key; uint32_t user_key_length; uint8_t *user_key_pwd; uint8_t *psk; uint32_t psk_length; uint8_t *psk_identity; uint32_t psk_identity_length; uint32_t ignore_cert_flag; uint32_t ignore_certitem; uint8_t is_ignore_multicertchain_verify; uint8_t cache_enable; } Liot_sslContext_t;
结构体说明
成员 |
说明 |
|---|---|
ssl_version |
SSL 版本 |
auth_type |
认证类型(0=无认证,1=单向,2=双向) |
ciphersuite |
加密套件 |
alpn_list |
ALPN 列表 |
sni_support |
SNI 支持 |
r_timeout |
接收超时 |
s_timeout |
发送超时 |
transport_protocol |
传输协议 |
ca_cert |
CA 证书 |
user_cert |
用户证书(双向认证需要) |
user_key |
用户私钥(双向认证需要) |
psk |
PSK 密钥 |
psk_identity |
PSK 身份 |
cache_enable |
缓存使能 |
3.11 Liot_sslClientInfo_t
SSL 客户端信息结构。
结构体声明
typedef struct { uint8_t sslClientId; uint8_t cid; uint8_t socket_type; uint8_t *host; uint16_t port; uint16_t local_port; uint8_t KeepaliveEn; uint8_t keepidle; uint8_t keepinterval; uint8_t keepcount; Liot_sslContext_t *ssl_context; liot_sslClient_recvCb_t sslClient_cb; } Liot_sslClientInfo_t;
结构体说明
成员 |
说明 |
|---|---|
sslClientId |
SSL 客户端 ID |
host |
服务器主机名 |
port |
服务器端口 |
local_port |
本地端口 |
KeepaliveEn |
心跳使能 |
keepidle |
心跳空闲时间 |
keepinterval |
心跳间隔 |
keepcount |
心跳次数 |
ssl_context |
SSL配置 |
sslClient_cb |
接收回调函数 |
4 API 函数详解
4.1 Liot_SSLSetCfg
该函数用于设置 SSL 配置信息。
声明
int32_t Liot_SSLSetCfg(void *ssl_cfg);
参数
sslClientID:[In] SSL 配置指针,指向Liot_sslClientInfo_t结构体。
返回值
0:配置成功。
-1:配置失败。
4.2 Liot_SSLSocketOpen
该函数用于打开 SSL 连接。
声明
int32_t Liot_SSLSocketOpen(int32_t sslClientID);
参数
sslClientID:[In] SSL 客户端 ID
返回值
执行结果码,请参考liot_ssl_error_code_e。
4.3 Liot_SSLSocketSend
该函数用于发送 SSL 数据。
声明
int32_t Liot_SSLSocketSend(int32_t sslClientID, uint8_t *data, uint16_t len);
参数
sslClientID:[In] SSL 客户端 ID
data:[In] SSL 待发送数据指针
len:[In] 数据长度
返回值
执行结果码,请参考liot_ssl_error_code_e。
4.4 Liot_SSLSocketGetStatus
该函数用于获取 SSL 连接状态。
声明
int32_t Liot_SSLSocketGetStatus(int32_t sslClientID);
参数
sslClientID:[In] SSL 客户端 ID
返回值
返回 SSL 客户端状态,请参考liot_ssl_error_code_e。
4.5 Liot_SSLSocketClose
该函数用于关闭 SSL 连接。
声明
int32_t Liot_SSLSocketClose(int32_t sslClientID);
参数
sslClientID:[In] SSL 客户端 ID
返回值
执行结果码,请参考liot_ssl_error_code_e。
5 代码示例
5.1 示例代码
示例代码参考 examples\demo\src\demo_ssl2.c 文件。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "lierda_app_main.h"
#include "liot_datacall.h"
#include "liot_os.h"
#include "liot_type.h"
#include "liot_fs_api.h"
#include "liot_nw.h"
#include "liot_sockets.h"
#include "liot_ssl2.h"
#define LIOT_SSL_LOG liot_trace
#if 1
#define LIOT_TEST_HOST_ADDR "cmp-tcp-monitor.xiot.senthink.com"
#define LIOT_TEST_HOST_PORT 41003
#define LIOT_TEST_SEND_DATA \
"Hello Lierda\0"
#else
#define LIOT_TEST_HOST_ADDR "220.180.239.212"
#define LIOT_TEST_HOST_PORT 8586
#define LIOT_TEST_SEND_DATA "1234567890123456789012345678901234567890"
#endif
#define LIOT_ROOT_CRT_PATH "UFS:root.crt"
#define LIOT_CLIENT_KEY_PATH "UFS:client.key"
#define LIOT_CLIENT_CRT_PATH "UFS:client.crt"
#define liot_root_crt \
"-----BEGIN CERTIFICATE-----\n\
MIIEQjCCAyqgAwIBAgIIUqzcXCgwtxUwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE\n\
BhMCQ04xDzANBgNVBBETBjMxMTEyMTEZMBcGA1UEChMQTGllcmRhIEdyb3VwIElu\n\
YzEfMB0GA1UEAxMWTGllcmRhIFJTQSBDQSBUTFMgMjAyMzEgMB4GCSqGSIb3DQEJ\n\
AQwRZGV2b3BzQGxpZXJkYS5jb20wIBcNMjMwMzIzMDM1NzEwWhgPMjEyMzAzMjMw\n\
MzU3MTBaMHwxCzAJBgNVBAYTAkNOMQ8wDQYDVQQREwYzMTExMjExGTAXBgNVBAoT\n\
EExpZXJkYSBHcm91cCBJbmMxHzAdBgNVBAMTFkxpZXJkYSBSU0EgQ0EgVExTIDIw\n\
MjMxIDAeBgkqhkiG9w0BCQEMEWRldm9wc0BsaWVyZGEuY29tMIIBIjANBgkqhkiG\n\
9w0BAQEFAAOCAQ8AMIIBCgKCAQEA7Km6RoA8W+ABfVi4Su5CBXXXX03W4tRft2CU\n\
PL2WxSXmt+NLa6qVpXwdXhnOFka7W3Yky7sJsEa+4L3ZAdvLAaV+T/YWjWUs4kBS\n\
g4m1qvNbVBf+QRMnN7T4KDykAmVt9slk5hrl9wmaza2uC0mVybCus1hWFl4O6bEK\n\
NVfVj67RMYJ0/V8rGo1RaM9gY9ocfsvCWnfmoBCBWVJqgKHt3zw3eVdgiK1c3/ZD\n\
Uksl+YEnHc0xZpUp++K/xn5BdgWJPY/5Xe/YGOMGXIJqINoW9br2ZKXIGsWmByus\n\
LltumLIThO6fnP2cyJjhJM+UnTUGJ/38tk7zjp2NnFQFFEjhlQIDAQABo4HFMIHC\n\
MA4GA1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUHAwEw\n\
DwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU3amZSimWqD7Ws6eB19/JaiRbJMQw\n\
KwYIKwYBBQUHAQEEHzAdMBsGCCsGAQUFBzAChg94aW90LmxpZXJkYS5jb20wNAYD\n\
VR0RBC0wK4IWTGllcmRhIFJTQSBDQSBUTFMgMjAyM4ERZGV2b3BzQGxpZXJkYS5j\n\
b20wDQYJKoZIhvcNAQELBQADggEBADGONA83hjydoGGSfbAF9KLDYUXGqLuAk3w+\n\
hZSt22x/nrq24TTGp/nVdhPs1CWNKzm/E0J+PpR/igWE/wYoLPCBZp1Yw5Lr+Gsu\n\
1dREldvcrnwCD6lGBk+liL3e/JTa7XTpoN+gYbpr9LVzPPlSwbFv8HXUQpoKCCXl\n\
A3L2TgoXCWKmW/TlPveT4eeSBPKif03hA6LsIFC5ebKztIe8cLRQiC+nuVg+vgOn\n\
L2o7gudAW9oeLHHwaZaJ862g0QlzhP+xKbK5vF2hRVpuE3VOWXFmUiWOhPw9BBgb\n\
6qrLAy26wFxdlnE8Q5yJcNGdJHk2d7TnnCohghLOjdhfE5lUWGc=\n\
-----END CERTIFICATE-----\n\
-----BEGIN CERTIFICATE-----\n\
MIIElTCCA32gAwIBAgIIEv+6yZm7eTMwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE\n\
BhMCQ04xDzANBgNVBBETBjMxMTEyMTEZMBcGA1UEChMQTGllcmRhIEdyb3VwIElu\n\
YzEfMB0GA1UEAxMWTGllcmRhIFJTQSBDQSBUTFMgMjAyMzEgMB4GCSqGSIb3DQEJ\n\
AQwRZGV2b3BzQGxpZXJkYS5jb20wIBcNMjMwMzIzMDQ0MDU4WhgPMjEyMzAyMjMw\n\
NDQwNThaMIGCMQswCQYDVQQGEwJDTjEPMA0GA1UEERMGMzExMTIxMQ8wDQYDVQQK\n\
EwZMaWVyZGExETAPBgNVBAsTCFNlbnRoaW5rMRwwGgYDVQQDDBMqLnhpb3Quc2Vu\n\
dGhpbmsuY29tMSAwHgYJKoZIhvcNAQkBDBFkZXZvcHNAbGllcmRhLmNvbTCCASIw\n\
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOZp21VtvMnztvuhLiBUGD8rZXcP\n\
5Co3WXMM1All0MvRxrWPMxMUUlvhfXCbq8KEizjpirnjZEMroPdNj7yDS7Ua4wQ9\n\
NfCMKy/xpZFRRfCAFEZmMQnbA3RDGZbIMtc2sWv9DbzEKNmxFbSd52aEFT08qpjC\n\
tToQpFzDsmdNGGW/kT/3hjBMPsB/MusREh93V8QAc+91bsMPhadQbhpZ+KfDXkO2\n\
yqosbjttywmKh53nCTrjWz+ti8rXEGcLOhUEIinMeEGFFSql9X5AUGEE3hAVw4T4\n\
N9JD5xGSW5xoiVI81zwjOF1I0ytfcnuxyoODQ7pMfdMnGh10wGwHvMsDLNsCAwEA\n\
AaOCARAwggEMMA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYI\n\
KwYBBQUHAwIwHQYDVR0OBBYEFIdFQk2DWZPhKuxN75FM9ru8TsvQMB8GA1UdIwQY\n\
MBaAFN2pmUoplqg+1rOngdffyWokWyTEMCsGCCsGAQUFBwEBBB8wHTAbBggrBgEF\n\
BQcwAoYPeGlvdC5saWVyZGEuY29tMG4GA1UdEQRnMGWCEyoueGlvdC5zZW50aGlu\n\
ay5jb22CESoueGlvdC5saWVyZGEuY29tghMqLnRlc3Quc2VudGhpbmsuY29tghMq\n\
LnN0YWcuc2VudGhpbmsuY29tgRFkZXZvcHNAbGllcmRhLmNvbTANBgkqhkiG9w0B\n\
AQsFAAOCAQEABF/qYc9/+9YhabnGLpUGSYtbht1fXHM9LOc1yqaoJbkP6tTxdrex\n\
kewzR5N4bLV+sl8QirsKZjxBmmnyjjBFJE9wnmeGiEr3pRO3MjCxjbQC/hLNjGNj\n\
fvPrxmAEyOcrp6drYGPum49p4/ecXRlM5vNKYXZSEsm2hxU2Mp1xcPVZSU4ttzoQ\n\
73BbdO1SYgPqYeQjw4sawqTW60aurDZNzW5yMnkh56320kjcy1DwI6xYW4q7HPnI\n\
8lmgl1ARntMlAQPCi77aLid91sxPFttfnH+NAe4UTjL6B7xCD2RqpiJRb3DyFaUl\n\
L3ZMQQC9ylYlcmYE6RUNKgVZ7WaJLPzl4g==\n\
-----END CERTIFICATE-----"
#define liot_client_crt \
"-----BEGIN CERTIFICATE-----\n\
MIIEizCCA3OgAwIBAgIIEaRUDbqjWgEwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE\n\
BhMCQ04xDzANBgNVBBETBjMxMTEyMTEZMBcGA1UEChMQTGllcmRhIEdyb3VwIElu\n\
YzEfMB0GA1UEAxMWTGllcmRhIFJTQSBDQSBUTFMgMjAyMzEgMB4GCSqGSIb3DQEJ\n\
AQwRZGV2b3BzQGxpZXJkYS5jb20wIBcNMjMwMzIzMDQ0MjU1WhgPMjEyMzAyMjMw\n\
NDQyNTVaMIGCMQswCQYDVQQGEwJDTjEPMA0GA1UEERMGMzExMTIxMQ8wDQYDVQQK\n\
EwZMaWVyZGExETAPBgNVBAsTCFNlbnRoaW5rMRwwGgYDVQQDDBMqLnhpb3Quc2Vu\n\
dGhpbmsuY29tMSAwHgYJKoZIhvcNAQkBDBFkZXZvcHNAbGllcmRhLmNvbTCCASIw\n\
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAPIGB6UVDXHwiVEfeUTo+zKMzz4c\n\
MDPfKTpRciDLmmg27blh5+jVBC7xMNaM5ran6GjF7JuYO9EipYPCMv5WnfyPzAU3\n\
HFDbynaGhPLE/ZTs71PU8fPgK7M8WxesPCDJ5Q9NOkIGq+PtI2pHMRMaDUOjMEGE\n\
ftm7VGSMwfE+dQTeOBwDNoQ6ENTVg0a5yfy+SXgKXW3QI9flW//Wagw6WLjIVeYQ\n\
ffXc8IuJHmlYtaYrFeZaL1tRXoscnlFRUMdB60XIq5JOyxqFtPEYgv8LwYDgozpW\n\
2jJTpH+Tp/+Sxc2rQHO56XCx1Z51W3Ia7Q30Mu1WJHYsLphdWeeMlkXT+eECAwEA\n\
AaOCAQYwggECMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAjAd\n\
BgNVHQ4EFgQUBqMN+wB9BUK01w1HHL+ZonufeOowHwYDVR0jBBgwFoAU3amZSimW\n\
qD7Ws6eB19/JaiRbJMQwKwYIKwYBBQUHAQEEHzAdMBsGCCsGAQUFBzAChg94aW90\n\
LmxpZXJkYS5jb20wbgYDVR0RBGcwZYITKi54aW90LnNlbnRoaW5rLmNvbYIRKi54\n\
aW90LmxpZXJkYS5jb22CEyoudGVzdC5zZW50aGluay5jb22CEyouc3RhZy5zZW50\n\
aGluay5jb22BEWRldm9wc0BsaWVyZGEuY29tMA0GCSqGSIb3DQEBCwUAA4IBAQDP\n\
tC24Uw1ud4wO2C3qWHZluLrNtsIVcD5tLcYMlX2oa3uuNaI9fsvFEPikf8LI7LYU\n\
NKQVBbeKpnIfBCtrmarj6jOQumSZXKC02f3w52Z1BFGvMj8GNj8ts7EHMqe8yohJ\n\
3lsoReAb0VDPerExFX/uhkmxd4OEQatpvjLR8nKrjlvq2sNQ+SrQALvM3/iVQ0Vo\n\
ld3qaIy/rpg+SRJeSmoh3tPl18H5CEqQYImWs5G9bKS7eFCj4Rr/a+4NeRwaV/0y\n\
hwt7V7AaWKdpwEpRoV3ecxIdyIod313T18ndIDLIWlcVTllLA3Y60f6G8J4Lp9Gs\n\
Utn0AVYamn42u8y+Itjh\n\
-----END CERTIFICATE-----"
#define liot_client_key \
"-----BEGIN RSA PRIVATE KEY-----\n\
MIIEpAIBAAKCAQEA8gYHpRUNcfCJUR95ROj7MozPPhwwM98pOlFyIMuaaDbtuWHn\n\
6NUELvEw1ozmtqfoaMXsm5g70SKlg8Iy/lad/I/MBTccUNvKdoaE8sT9lOzvU9Tx\n\
8+ArszxbF6w8IMnlD006Qgar4+0jakcxExoNQ6MwQYR+2btUZIzB8T51BN44HAM2\n\
hDoQ1NWDRrnJ/L5JeApdbdAj1+Vb/9ZqDDpYuMhV5hB99dzwi4keaVi1pisV5lov\n\
W1FeixyeUVFQx0HrRcirkk7LGoW08RiC/wvBgOCjOlbaMlOkf5On/5LFzatAc7np\n\
cLHVnnVbchrtDfQy7VYkdiwumF1Z54yWRdP54QIDAQABAoIBAQCHibTyUG3tJ0Xf\n\
dn7VhpxW3OCa6fJculc+X6pIj31za3+KWDgl/lWPbGdrYBE8rZ/MPTuaj5DAOGT0\n\
+ubP5PYpIOai7RAggFZMNl1yD7vrkR0el5zAdQREJkLlaQFrY2WyQg+kNlRBGubA\n\
eAoVpntTK6q0plzb1rsWbHWYgt/JzwpU078m2BnF0PG6sqZWRPjSqpMBHkkKPn52\n\
nThKlTL2/XfpahxWnN+j3Gq7eSI3t7XXopHBOxSPbPa0Hx+jLLPfxnRihzhIb9IZ\n\
r7CCBhGFrab+/VbOJc+FUstTGEd/2tO2+AbqZnonUTPgkPMMPrWGqCKlsIoUxwqV\n\
lS1B+/FZAoGBAPmZAp7cFMp3DWqd8NiR4EutrH2tfOoK3zAt1S7ErVmiS+UKBaZ+\n\
WcWnUzn27DZ3uslnB2aIQ8ZFaunM6NkdG7jkpNQpw2myFTK7Vd5VsqUHjPNJwPhT\n\
xjAdxvBTED3c12U3xlxmfgob9Mv3EwmseH+AZPGcojw7Vg8VbeZDsjw7AoGBAPg7\n\
SKjFA4ZpiWEiELWl/i5IrQsuLINM/hM7fAPNCzFrN2/ZVfqoe6kbkII5c8DIgU6i\n\
5LxTkgaEYC3ne8pGjnB0WN1xI/nbqtg3ZNrN4S9ArlEkzHiI9r0xsnyRUt99wAlB\n\
3jjOPBPXzFRgDy/VXoE1k4OUrCPnwV1JVwM2j+yTAoGAGu0UyUp4u7bILb5IIzTp\n\
e4CK4Sv8E8uEdFAddWQmR0so4NaJ8YIj8Ryx78jhhqa38c45kCgXF6aZeAtw+ysW\n\
uIWB+pleyWI6wzROeSPJl+AOpphIRwHSmZI8yeRMFkBixDqWHZW49yI48GABH8QJ\n\
Y8fYG/CH1/OWvx3Ss0qOSc0CgYB5UohVrEznwecaKUsfbOzJdE3XHA83cUbw4W7g\n\
cLPayHtE2GV0aCpgYY+Ehk3z2EuSwnynKvVA6CwV44CWQVvWzJauTGD3+owKtzA8\n\
3MkFjkhkcmbZNp/ZolOJHIHzp4NXQvE4tFuamytLxdNGXrOc1TGu6tgjiF7ymCjF\n\
8kHvrwKBgQCpbYvfsn9T2hE1jyK5Qh7P8XqSprQ7cZ05VYhDbMZ8iOn2LWXJLf1j\n\
DQEUjO44VzU4IRb2f0hiw7SYMjPbNh+rKkjUxCdLa5RvJ9CWT9xddjQZHjfv1Px2\n\
I2H+OQwOo8QOUXH6z8gUAw8MsNYiDlvtRw/6GFAkc4D5A25UzVBmcA==\n\
-----END RSA PRIVATE KEY-----"
#define DEMO_SSL_CLIENT_ID 1
#define DEMO_SEND_INTERVAL 60000 // 发送间隔,单位:毫秒
#define LIOT_SSL_LOG liot_trace
Liot_sslClientInfo_t ssl_client_info;
/
* ssl recv callback
* @param[in] clientId ssl client id
* @param[in] data received data
* @param[in] arg user argument
* @return none
*/
void ssl_recv_callback(uint8_t clientId, void *data, uint32_t dataLen, void *arg)
{
LIOT_SSL_LOG("Received data: %d.*%s", dataLen, (char *)data);
}
/
* ssl client init
* @return none
*/
void liot_ssl_init(void)
{
memset(&ssl_client_info, 0, sizeof(ssl_client_info));
ssl_client_info.sslClientId = DEMO_SSL_CLIENT_ID;
ssl_client_info.socket_type = 1; // TCP
ssl_client_info.host = (uint8_t *)LIOT_TEST_HOST_ADDR;
ssl_client_info.port = LIOT_TEST_HOST_PORT;
if(ssl_client_info.ssl_context == NULL)
{
ssl_client_info.ssl_context = liot_rtos_malloc(sizeof(Liot_sslContext_t));
if (ssl_client_info.ssl_context == NULL)
{
LIOT_SSL_LOG("Failed to allocate memory for SSL context");
return;
}
}
memset(ssl_client_info.ssl_context, 0, sizeof(Liot_sslContext_t));
ssl_client_info.ssl_context->auth_type = LIOT_SSL_VERIFY_CLIENT_SERVER; //
ssl_client_info.ssl_context->ca_cert = (uint8_t *)liot_root_crt;
ssl_client_info.ssl_context->ca_cert_length = strlen(liot_root_crt) + 1;
ssl_client_info.ssl_context->user_cert = (uint8_t *)liot_client_crt;
ssl_client_info.ssl_context->user_cert_length = strlen(liot_client_crt) + 1;
ssl_client_info.ssl_context->user_key = (uint8_t *)liot_client_key;
ssl_client_info.ssl_context->user_key_length = strlen(liot_client_key) + 1;
ssl_client_info.ssl_context->ssl_version = LIOT_SSL_VERSION_3; // TLS 1.2
ssl_client_info.ssl_context->r_timeout = 10;
ssl_client_info.ssl_context->sni_support = 1;
ssl_client_info.ssl_context->ciphersuite[0] =0XFFFF ;
ssl_client_info.KeepaliveEn = 1; // enable Keepalive
ssl_client_info.keepidle = 30;
ssl_client_info.keepinterval = 10;
ssl_client_info.keepcount = 5;
ssl_client_info.sslClient_cb = ssl_recv_callback;
int ret = Liot_SSLSetCfg(&ssl_client_info);
if (ret != LIOT_SSL_SUCCESS)
{
LIOT_SSL_LOG("Liot_SSLSetCfg failed, ret: %d", ret);
liot_rtos_free(ssl_client_info.ssl_context);
return;
}
}
/
* ssl test
* @param[in] profile_idx profile index
* @return none
*/
static int liot_ssl_test(int profile_idx)
{
liot_data_call_info_t info;
int ret = LIOT_SSL_SUCCESS;
int i = 0;
int ssl_status = 0;
// Get data call information for the specified profile
liot_get_data_call_info(0, profile_idx, &info);
start:
liot_ssl_init();
ret = Liot_SSLSocketOpen(DEMO_SSL_CLIENT_ID);
if (ret != LIOT_SSL_SUCCESS)
{
LIOT_SSL_LOG("Liot_SSLSocketOpen failed, ret: %d", ret);
liot_rtos_free(ssl_client_info.ssl_context);
return LIOT_SSL_ERROR_UNKOWN;
}
while (1)
{
ssl_status = Liot_SSLSocketGetStatus(DEMO_SSL_CLIENT_ID);
LIOT_SSL_LOG("Current SSL status: %d", ssl_status);
const char *send_data = LIOT_TEST_SEND_DATA;
ret = Liot_SSLSocketSend(DEMO_SSL_CLIENT_ID, (uint8_t *)send_data, strlen(send_data));
if (ret < 0)
{
LIOT_SSL_LOG("Liot_SSLSocketSend failed, ret: %d", ret);
ret = LIOT_SSL_ERROR_SEND_FAILURE;
break;
}
LIOT_SSL_LOG("Data sent: %s", send_data);
i++;
if (i >= 3)
{
break;
}
ssl_status = Liot_SSLSocketGetStatus(DEMO_SSL_CLIENT_ID);
LIOT_SSL_LOG("Current SSL status: %d", ssl_status);
liot_rtos_task_sleep_ms(DEMO_SEND_INTERVAL);
}
if(ssl_status == LIOT_SSL_CLIENT_STATUS_CLOSED)
{
LIOT_SSL_LOG("SSL is closed, start reconnecting!! : %d", ssl_status);
goto start;
}
Liot_SSLSocketClose(DEMO_SSL_CLIENT_ID);
liot_rtos_free(ssl_client_info.ssl_context);
LIOT_SSL_LOG("SSL demo task finished");
return ret;
}
/
* @brief Main SSL application thread.
* This thread handles the complete SSL demo workflow including:
* 1. Establishing data connection
* 2. Initializing certificates
* 3. Performing SSL/TLS operations
* 4. Cleaning up resources
*
* @param arg Thread arguments (unused)
*/
void liot_ssl2_demo_thread(void *arg)
{
int ret = 0;
int profile_idx = 1;
liot_data_call_info_t info;
// char ip4_addr_str[16] = {0};
uint8_t nSim = 0;
LIOT_SSL_LOG("========== ssl demo start ==========");
LIOT_SSL_LOG("===start data call begin====");
liot_start_data_call(nSim, profile_idx, LIOT_DATA_TYPE_IP, "APNTEST", "", "", LIOT_DATA_AUTH_TYPE_NONE);
LIOT_SSL_LOG("===start data call end====");
ret = liot_get_data_call_info(nSim, profile_idx, &info);
if (ret != 0)
{
liot_stop_data_call(nSim, profile_idx);
liot_trace("liot_get_data_call_info ret: %d", ret);
goto exit;
}
liot_trace("info->cid: %d", info.cid);
liot_trace("info->ip_version: %d", info.ip_version);
ret = liot_ssl_test(profile_idx);
liot_trace("liot_ssl_test ret: %d", ret);
exit:
liot_rtos_task_delete(NULL);
return;
}
5.2 无认证模式配置示例
#include "liot_ssl2.h"
#define DEMO_SSL_CLIENT_ID 0
Liot_sslClientInfo_t ssl_client_info;
void ssl_recv_callback(uint8_t clientId, void *data, uint32_t dataLen, void *arg)
{
printf("Received %d bytes\n", dataLen);
}
void ssl_none_auth_init(void)
{
memset(&ssl_client_info, 0, sizeof(ssl_client_info));
ssl_client_info.sslClientId = DEMO_SSL_CLIENT_ID;
ssl_client_info.socket_type = 1;
ssl_client_info.host = (uint8_t *)"192.168.1.100";
ssl_client_info.port = 8883;
ssl_client_info.ssl_context = liot_rtos_malloc(sizeof(Liot_sslContext_t));
memset(ssl_client_info.ssl_context, 0, sizeof(Liot_sslContext_t));
// ========== 无认证配置 ==========
ssl_client_info.ssl_context->auth_type = LIOT_SSL_VERIFY_NONE;
ssl_client_info.ssl_context->ssl_version = LIOT_SSL_VERSION_3;
ssl_client_info.ssl_context->sni_support = 1;
ssl_client_info.ssl_context->ciphersuite[0] = 0xFFFF;
ssl_client_info.ssl_context->r_timeout = 10;
ssl_client_info.sslClient_cb = ssl_recv_callback;
Liot_SSLSetCfg(&ssl_client_info);
}
5.3 单向认证模式配置
#include "liot_ssl2.h"
#define DEMO_SSL_CLIENT_ID 0
// CA 根证书 (PEM 格式字符串)
#define liot_root_crt \
"-----BEGIN CERTIFICATE-----\n" \
"MIIEQjCCAyqgAwIBAgIIUqzcXCgwtxUwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE\n" \
"BhMCQ04xDzANBgNVBBETBjMxMTEyMTEZMBcGA1UEChMQTGllcmRhIEdyb3VwIElu\n" \
"...(证书内容)...\n" \
"-----END CERTIFICATE-----"
Liot_sslClientInfo_t ssl_client_info;
void ssl_recv_callback(uint8_t clientId, void *data, uint32_t dataLen, void *arg)
{
printf("Received %d bytes\n", dataLen);
}
void ssl_server_auth_init(void)
{
memset(&ssl_client_info, 0, sizeof(ssl_client_info));
ssl_client_info.sslClientId = DEMO_SSL_CLIENT_ID;
ssl_client_info.socket_type = 1;
ssl_client_info.host = (uint8_t *)"mqtt.example.com"; // 服务器域名 (用于 SNI)
ssl_client_info.port = 8883;
ssl_client_info.ssl_context = liot_rtos_malloc(sizeof(Liot_sslContext_t));
memset(ssl_client_info.ssl_context, 0, sizeof(Liot_sslContext_t));
// ========== 单向认证配置 ==========
ssl_client_info.ssl_context->auth_type = LIOT_SSL_VERIFY_SERVER;
ssl_client_info.ssl_context->ssl_version = LIOT_SSL_VERSION_3;
ssl_client_info.ssl_context->sni_support = 1;
ssl_client_info.ssl_context->ciphersuite[0] = 0xFFFF;
ssl_client_info.ssl_context->r_timeout = 30;
// CA 证书配置
ssl_client_info.ssl_context->ca_cert = (uint8_t *)liot_root_crt;
ssl_client_info.ssl_context->ca_cert_length = strlen(liot_root_crt) + 1;
ssl_client_info.sslClient_cb = ssl_recv_callback;
Liot_SSLSetCfg(&ssl_client_info);
}
5.4 双向认证模式配置
#include "liot_ssl2.h"
#define DEMO_SSL_CLIENT_ID 0
// CA 根证书
#define liot_root_crt \
"-----BEGIN CERTIFICATE-----\n" \
"MIIEQjCCAyqgAwIBAgIIUqzcXCgwtxUwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE\n" \
"...(CA 证书内容)...\n" \
"-----END CERTIFICATE-----"
// 客户端证书
#define liot_client_crt \
"-----BEGIN CERTIFICATE-----\n" \
"MIIEizCCA3OgAwIBAgIIEaRUDbqjWgEwDQYJKoZIhvcNAQELBQAwfDELMAkGA1UE\n" \
"...(客户端证书内容)...\n" \
"-----END CERTIFICATE-----"
// 客户端私钥
#define liot_client_key \
"-----BEGIN RSA PRIVATE KEY-----\n" \
"MIIEpAIBAAKCAQEA8gYHpRUNcfCJUR95ROj7MozPPhwwM98pOlFyIMuaaDbtuWHn\n" \
"...(私钥内容)...\n" \
"-----END RSA PRIVATE KEY-----"
Liot_sslClientInfo_t ssl_client_info;
void ssl_recv_callback(uint8_t clientId, void *data, uint32_t dataLen, void *arg)
{
printf("Received %d bytes\n", dataLen);
}
void ssl_mutual_auth_init(void)
{
memset(&ssl_client_info, 0, sizeof(ssl_client_info));
ssl_client_info.sslClientId = DEMO_SSL_CLIENT_ID;
ssl_client_info.socket_type = 1;
ssl_client_info.host = (uint8_t *)"secure.example.com";
ssl_client_info.port = 8883;
ssl_client_info.ssl_context = liot_rtos_malloc(sizeof(Liot_sslContext_t));
memset(ssl_client_info.ssl_context, 0, sizeof(Liot_sslContext_t));
// ========== 双向认证配置 ==========
ssl_client_info.ssl_context->auth_type = LIOT_SSL_VERIFY_CLIENT_SERVER;
ssl_client_info.ssl_context->ssl_version = LIOT_SSL_VERSION_3;
ssl_client_info.ssl_context->sni_support = 1;
ssl_client_info.ssl_context->ciphersuite[0] = 0xFFFF;
ssl_client_info.ssl_context->r_timeout = 30;
// CA 证书配置
ssl_client_info.ssl_context->ca_cert = (uint8_t *)liot_root_crt;
ssl_client_info.ssl_context->ca_cert_length = strlen(liot_root_crt) + 1;
// 客户端证书配置
ssl_client_info.ssl_context->user_cert = (uint8_t *)liot_client_crt;
ssl_client_info.ssl_context->user_cert_length = strlen(liot_client_crt) + 1;
// 客户端私钥配置
ssl_client_info.ssl_context->user_key = (uint8_t *)liot_client_key;
ssl_client_info.ssl_context->user_key_length = strlen(liot_client_key) + 1;
ssl_client_info.sslClient_cb = ssl_recv_callback;
Liot_SSLSetCfg(&ssl_client_info);
}