2025-10-10 16:07:00 +08:00

1182 lines
36 KiB
C
Executable File

// Copyright 2019 Espressif Systems (Shanghai) PTE LTD
// Copyright 2023 Beken Corporation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
/*
* Change Logs:
* Date Author Notes
* 2023-05-05 Beken adapter to Beken sdk
*/
#include <string.h>
#include <stddef.h>
#include <stdio.h>
#include <common/bk_include.h>
#include <os/mem.h>
#include <os/str.h>
#include <os/os.h>
#ifdef CONFIG_HTTPS
#include <bk_ssl.h>
#include <portmacro.h>
#include "mbedtls/ssl.h"
#include "mbedtls/x509_crl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/net_sockets.h"
#include <http_parser.h>
#include <http_header.h>
#include <http_utils.h>
#include <components/system.h>
#include <bk_rom_md5.h>
#define TAG "SSL"
/*-------------------------------mbedtls--------------------------------------*/
#define _bk_create_ssl_handle bk_create_mbedtls_handle
#define _bk_tls_handshake bk_mbedtls_handshake
#define _bk_tls_read bk_mbedtls_read
#define _bk_tls_write bk_mbedtls_write
#define _bk_tls_conn_delete bk_mbedtls_conn_delete
#define _bk_tls_net_init bk_mbedtls_net_init
#define _bk_tls_get_bytes_avail bk_mbedtls_get_bytes_avail
static mbedtls_x509_crt *global_cacert = NULL;
ssize_t bk_mbedtls_get_bytes_avail(bk_tls_t *tls)
{
if (!tls) {
BK_LOGE(TAG, "empty arg passed to bk_tls_get_bytes_avail()\r\n");
return BK_FAIL;
}
return mbedtls_ssl_get_bytes_avail(&tls->ssl);
}
void bk_mbedtls_cleanup(bk_tls_t *tls)
{
if (!tls) {
return;
}
if (tls->cacert_ptr != global_cacert) {
mbedtls_x509_crt_free(tls->cacert_ptr);
}
tls->cacert_ptr = NULL;
mbedtls_x509_crt_free(&tls->cacert);
mbedtls_x509_crt_free(&tls->clientcert);
mbedtls_pk_free(&tls->clientkey);
mbedtls_entropy_free(&tls->entropy);
mbedtls_ssl_config_free(&tls->conf);
mbedtls_ctr_drbg_free(&tls->ctr_drbg);
mbedtls_ssl_free(&tls->ssl);
}
static bk_err_t set_global_ca_store(bk_tls_t *tls)
{
if (global_cacert == NULL) {
BK_LOGE(TAG, "global_cacert is NULL\r\n");
return -1;
}
tls->cacert_ptr = global_cacert;
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL);
return BK_OK;
}
static bk_err_t set_ca_cert(bk_tls_t *tls, const unsigned char *cacert, size_t cacert_len)
{
tls->cacert_ptr = &tls->cacert;
mbedtls_x509_crt_init(tls->cacert_ptr);
BK_LOGE(TAG, "mbedtls_x509_crt_parse cacert_len: %d\r\n", cacert_len);
int ret = mbedtls_x509_crt_parse(tls->cacert_ptr, cacert, cacert_len);
if (ret < 0) {
BK_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%04X\r\n", -ret);
return BK_ERR_MBEDTLS_X509_CRT_PARSE_FAILED;
}
if (ret > 0) {
BK_LOGE(TAG, "mbedtls_x509_crt_parse was partly successful. No. of failed certificates: %d\r\n", ret);
}
if (ret == 0)
BK_LOGD(TAG, "mbedtls_x509_crt_parse returned 0 \r\n");
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_OPTIONAL);
#if CONFIG_PSA_MBEDTLS
BK_LOGI(TAG, "mbedtls_ssl_conf_authmode\r\n");
#else
BK_LOGI(TAG, "mbedtls_ssl_conf_authmode, mode:%d\r\n", tls->conf.authmode);
#endif
BK_LOGD(TAG, "mbedtls_ssl_conf_ca_chain\r\n");
mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL);
return BK_OK;
}
static bk_err_t set_pki_context(bk_tls_t *tls, const bk_tls_pki_t *pki)
{
int ret;
if (pki->publiccert_pem_buf != NULL &&
pki->public_cert != NULL &&
pki->pk_key != NULL) {
mbedtls_x509_crt_init(pki->public_cert);
mbedtls_pk_init(pki->pk_key);
ret = mbedtls_x509_crt_parse(pki->public_cert, pki->publiccert_pem_buf, pki->publiccert_pem_bytes);
if (ret < 0) {
BK_LOGE(TAG, "mbedtls_x509_crt_parse returned -0x%04X\r\n", -ret);
return BK_ERR_MBEDTLS_X509_CRT_PARSE_FAILED;
}
if (pki->privkey_pem_buf != NULL) {
#if CONFIG_PSA_MBEDTLS && !CONFIG_PSA_MBEDTLS_FORWARD_COMPATIBILITY
ret = mbedtls_pk_parse_key(pki->pk_key, pki->privkey_pem_buf, pki->privkey_pem_bytes,
pki->privkey_password, pki->privkey_password_len,
NULL, NULL);
#else
ret = mbedtls_pk_parse_key(pki->pk_key, pki->privkey_pem_buf, pki->privkey_pem_bytes,
pki->privkey_password, pki->privkey_password_len);
#endif
} else {
return -1;
}
if (ret < 0) {
BK_LOGE(TAG, "mbedtls_pk_parse_keyfile returned -0x%04X\r\n", -ret);
return BK_ERR_MBEDTLS_PK_PARSE_KEY_FAILED;
}
ret = mbedtls_ssl_conf_own_cert(&tls->conf, pki->public_cert, pki->pk_key);
if (ret < 0) {
BK_LOGE(TAG, "mbedtls_ssl_conf_own_cert returned -0x%04X\r\n", -ret);
return BK_ERR_MBEDTLS_SSL_CONF_OWN_CERT_FAILED;
}
} else {
return -1;
}
return BK_OK;
}
bk_err_t set_client_config(const char *hostname, size_t hostlen, bk_tls_cfg_t *cfg, bk_tls_t *tls)
{
int ret;
if (!cfg->skip_common_name) {
char *use_host = NULL;
if (cfg->common_name != NULL) {
use_host = strndup(cfg->common_name, strlen(cfg->common_name));
} else {
use_host = strndup(hostname, hostlen);
}
if (use_host == NULL) {
return BK_ERR_NO_MEM;
}
/* Hostname set here should match CN in server certificate */
BK_LOGD(TAG, "mbedtls_ssl_set_hostname use_host: %s\r\n", use_host);
if ((ret = mbedtls_ssl_set_hostname(&tls->ssl, use_host)) != 0) {
BK_LOGE(TAG, "mbedtls_ssl_set_hostname returned -0x%04X\r\n", -ret);
free(use_host);
return BK_ERR_MBEDTLS_SSL_SET_HOSTNAME_FAILED;
}
free(use_host);
}
BK_LOGD(TAG, "mbedtls_ssl_config_defaults\r\n");
if ((ret = mbedtls_ssl_config_defaults(&tls->conf,
MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_STREAM,
MBEDTLS_SSL_PRESET_DEFAULT)) != 0) {
BK_LOGE(TAG, "mbedtls_ssl_config_defaults returned -0x%04X\r\n", -ret);
return BK_ERR_MBEDTLS_SSL_CONFIG_DEFAULTS_FAILED;
}
#ifdef CONFIG_MBEDTLS_SSL_RENEGOTIATION
BK_LOGD(TAG, "mbedtls_ssl_conf_renegotiation\r\n");
mbedtls_ssl_conf_renegotiation(&tls->conf, MBEDTLS_SSL_RENEGOTIATION_ENABLED);
#endif
if (cfg->alpn_protos) {
#ifdef CONFIG_MBEDTLS_SSL_ALPN
BK_LOGE(TAG, "mbedtls_ssl_conf_alpn_protocols\r\n");
if ((ret = mbedtls_ssl_conf_alpn_protocols(&tls->conf, cfg->alpn_protos)) != 0) {
BK_LOGE(TAG, "mbedtls_ssl_conf_alpn_protocols returned -0x%04X\r\n", -ret);
return BK_ERR_MBEDTLS_SSL_CONF_ALPN_PROTOCOLS_FAILED;
}
#else
BK_LOGE(TAG, "alpn_protos configured but not enabled in menuconfig: Please enable MBEDTLS_SSL_ALPN option\r\n");
return -1;
#endif
}
#ifdef CONFIG_BK_TLS_CLIENT_SESSION_TICKETS
BK_LOGE(TAG, "Enabling client-side tls session ticket support\r\n");
mbedtls_ssl_conf_session_tickets(&tls->conf, MBEDTLS_SSL_SESSION_TICKETS_ENABLED);
mbedtls_ssl_conf_renegotiation(&tls->conf, MBEDTLS_SSL_RENEGOTIATION_ENABLED);
#endif
#if defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
if ((ret = mbedtls_ssl_conf_max_frag_len(&tls->conf, MBEDTLS_SSL_MAX_FRAG_LEN_4096)) != 0) {
BK_LOGE(TAG, " failed\n ! mbedtls_ssl_conf_max_frag_len returned %d\n\n", ret);
return BK_ERR_MBEDTLS_SSL_CONF_MFL_FAILED;
}
#endif
if (cfg->crt_bundle_attach != NULL) {
#ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
BK_LOGD(TAG, "mbedtls_ssl_conf_authmode\r\n");
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_REQUIRED);
cfg->crt_bundle_attach(&tls->conf);
BK_LOGE(TAG, "use_crt_bundle configured but not enabled in menuconfig: Please enable MBEDTLS_CERTIFICATE_BUNDLE option\r\n");
return -1;
#endif
} else if (cfg->use_global_ca_store == true) {
BK_LOGD(TAG, "set_global_ca_store\r\n");
int bk_ret = set_global_ca_store(tls);
if (bk_ret != BK_OK) {
return bk_ret;
}
} else if (cfg->cacert_buf != NULL) {
BK_LOGD(TAG, "set_ca_cert\r\n");
int bk_ret = set_ca_cert(tls, cfg->cacert_buf, cfg->cacert_bytes);
if (bk_ret != BK_OK) {
return bk_ret;
}
BK_LOGD(TAG, "mbedtls_ssl_conf_ca_chain\r\n");
mbedtls_ssl_conf_ca_chain(&tls->conf, tls->cacert_ptr, NULL);
} else if (cfg->psk_hint_key) {
#if defined(CONFIG_BK_TLS_PSK_VERIFICATION)
// PSK encryption mode is configured only if no certificate supplied and psk pointer not null
BK_LOGE(TAG, "mbedtls_ssl_conf_psk\r\n");
ret = mbedtls_ssl_conf_psk(&tls->conf, cfg->psk_hint_key->key, cfg->psk_hint_key->key_size,
(const unsigned char *)cfg->psk_hint_key->hint, strlen(cfg->psk_hint_key->hint));
if (ret != 0) {
BK_LOGE(TAG, "mbedtls_ssl_conf_psk returned -0x%04X\r\n", -ret);
return BK_ERR_MBEDTLS_SSL_CONF_PSK_FAILED;
}
#else
BK_LOGE(TAG, "psk_hint_key configured but not enabled in menuconfig: Please enable BK_TLS_PSK_VERIFICATION option\r\n");
return -1;
#endif
#ifdef CONFIG_BK_TLS_CLIENT_SESSION_TICKETS
} else if (cfg->client_session != NULL) {
BK_LOGE(TAG, "Resuing the saved client session\r\n");
#endif
} else {
#ifdef CONFIG_BK_TLS_SKIP_SERVER_CERT_VERIFY
BK_LOGE(TAG, "mbedtls_ssl_conf_authmode\r\n");
mbedtls_ssl_conf_authmode(&tls->conf, MBEDTLS_SSL_VERIFY_NONE);
#else
BK_LOGE(TAG, "No server verification option set in bk_tls_cfg_t structure.\r\n");
return BK_ERR_MBEDTLS_SSL_SETUP_FAILED;
#endif
}
if (cfg->use_secure_element) {
#ifdef CONFIG_BK_TLS_USE_SECURE_ELEMENT
ret = bk_set_atecc608a_pki_context(tls, (bk_tls_cfg_t *)cfg);
if (ret != BK_OK) {
return ret;
}
#else
BK_LOGE(TAG, "Please enable secure element support for BK-TLS in menuconfig\r\n");
return BK_FAIL;
#endif
} else if (cfg->ds_data != NULL) {
#ifdef CONFIG_BK_TLS_USE_DS_PERIPHERAL
if (cfg->clientcert_pem_buf == NULL) {
BK_LOGE(TAG, "Client certificate is also required with the DS parameters\r\n");
return -1;
}
bk_ds_set_session_timeout(cfg->timeout_ms);
/* set private key pointer to NULL since the DS peripheral with its own configuration data is used */
bk_tls_pki_t pki = {
.public_cert = &tls->clientcert,
.pk_key = &tls->clientkey,
.publiccert_pem_buf = cfg->clientcert_buf,
.publiccert_pem_bytes = cfg->clientcert_bytes,
.privkey_pem_buf = NULL,
.privkey_pem_bytes = 0,
.privkey_password = NULL,
.privkey_password_len = 0,
.bk_ds_data = cfg->ds_data,
};
bk_err_t bk_ret = set_pki_context(tls, &pki);
if (bk_ret != BK_OK) {
BK_LOGE(TAG, "Failed to set client pki context for the DS peripheral, returned [0x%04X]]\r\n", ret);
return bk_ret;
}
#else
BK_LOGE(TAG, "Please enable the DS peripheral support for the BK-TLS in menuconfig.\r\n");
return BK_FAIL;
#endif
} else if (cfg->clientcert_pem_buf != NULL && cfg->clientkey_pem_buf != NULL) {
BK_LOGD(TAG, "clientcert_pem_buf\r\n");
bk_tls_pki_t pki = {
.public_cert = &tls->clientcert,
.pk_key = &tls->clientkey,
.publiccert_pem_buf = cfg->clientcert_buf,
.publiccert_pem_bytes = cfg->clientcert_bytes,
.privkey_pem_buf = cfg->clientkey_buf,
.privkey_pem_bytes = cfg->clientkey_bytes,
.privkey_password = cfg->clientkey_password,
.privkey_password_len = cfg->clientkey_password_len,
};
int bk_ret = set_pki_context(tls, &pki);
if (bk_ret != BK_OK) {
BK_LOGE(TAG, "Failed to set client pki context\r\n");
return bk_ret;
}
} else if (cfg->clientcert_buf != NULL || cfg->clientkey_buf != NULL) {
BK_LOGE(TAG, "You have to provide both clientcert_buf and clientkey_buf for mutual authentication\r\n");
return -1;
}
return BK_OK;
}
#if CONFIG_PSA_MBEDTLS
static int mbedtls_bk_entropy_poll(void *data, unsigned char *output, size_t len, size_t *olen)
{
uint32_t seed = bk_rand();
if (len > sizeof(seed)) {
len = sizeof(seed);
}
memcpy(output, &seed, len);
*olen = len;
return 0;
}
#endif
bk_err_t bk_create_mbedtls_handle(const char *hostname, size_t hostlen, const void *cfg, bk_tls_t *tls)
{
int ret;
int bk_ret = BK_FAIL;
tls->server_fd.fd = tls->sockfd;
mbedtls_ssl_init(&tls->ssl);
mbedtls_ctr_drbg_init(&tls->ctr_drbg);
mbedtls_ssl_config_init(&tls->conf);
mbedtls_entropy_init(&tls->entropy);
if (tls->role == BK_TLS_CLIENT) {
BK_LOGD(TAG, "BK_TLS_CLIENT\r\n");
bk_ret = set_client_config(hostname, hostlen, (bk_tls_cfg_t *)cfg, tls);
if (bk_ret != BK_OK) {
BK_LOGE(TAG, "Failed to set client configurations, returned [0x%04X]\r\n", bk_ret);
goto exit;
}
}
BK_LOGD(TAG, "mbedtls_ctr_drbg_seed\r\n");
#if CONFIG_PSA_MBEDTLS
mbedtls_entropy_add_source(&tls->entropy, mbedtls_bk_entropy_poll, NULL,
MBEDTLS_ENTROPY_MAX_GATHER,
MBEDTLS_ENTROPY_SOURCE_STRONG);
#endif
if ((ret = mbedtls_ctr_drbg_seed(&tls->ctr_drbg,
mbedtls_entropy_func, &tls->entropy, NULL, 0)) != 0) {
BK_LOGE(TAG, "mbedtls_ctr_drbg_seed returned -0x%04X\r\n", -ret);
bk_ret = BK_ERR_MBEDTLS_CTR_DRBG_SEED_FAILED;
goto exit;
}
BK_LOGD(TAG, "mbedtls_ssl_conf_rng\r\n");
mbedtls_ssl_conf_rng(&tls->conf, mbedtls_ctr_drbg_random, &tls->ctr_drbg);
BK_LOGD(TAG, "mbedtls_ssl_setup\r\n");
if ((ret = mbedtls_ssl_setup(&tls->ssl, &tls->conf)) != 0) {
BK_LOGE(TAG, "mbedtls_ssl_setup returned -0x%04X\r\n", -ret);
bk_ret = BK_ERR_MBEDTLS_SSL_SETUP_FAILED;
goto exit;
}
BK_LOGD(TAG, "mbedtls_ssl_set_bio\r\n");
mbedtls_ssl_set_bio(&tls->ssl, &tls->server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
return BK_OK;
exit:
bk_mbedtls_cleanup(tls);
return bk_ret;
}
void bk_mbedtls_verify_certificate(bk_tls_t *tls)
{
int flags;
if ((flags = mbedtls_ssl_get_verify_result(&tls->ssl)) != 0) {
BK_LOGE(TAG, "Failed to verify peer certificate!\r\n");
char buf[100];
bzero(buf, sizeof(buf));
mbedtls_x509_crt_verify_info(buf, sizeof(buf), " ! ", flags);
BK_LOGE(TAG, "verification info: %s\r\n", buf);
} else {
BK_LOGE(TAG, "Certificate verified.\r\n");
}
}
int bk_mbedtls_handshake(bk_tls_t *tls, const bk_tls_cfg_t *cfg)
{
int ret;
BK_LOGE(TAG, "mbedtls_ssl_handshake\r\n");
ret = mbedtls_ssl_handshake(&tls->ssl);
if (ret == 0) {
BK_LOGE(TAG, "ssl_handshake done\r\n");
tls->conn_state = BK_TLS_DONE;
#if 0//defined(MBEDTLS_SSL_MAX_FRAGMENT_LENGTH)
BK_LOGI(TAG, " [ Maximum incoming record payload length is %u ]\n",
(unsigned int) mbedtls_ssl_get_max_in_record_payload(&tls->ssl));
BK_LOGI(TAG, " [ Maximum outgoing record payload length is %u ]\n",
(unsigned int) mbedtls_ssl_get_max_out_record_payload(&tls->ssl));
#endif
return 1;
} else {
if (ret != BK_TLS_ERR_SSL_WANT_READ && ret != BK_TLS_ERR_SSL_WANT_WRITE) {
BK_LOGE(TAG, "mbedtls_ssl_handshake returned -0x%04X\r\n", -ret);
if (cfg->cacert_buf != NULL || cfg->use_global_ca_store == true) {
/* This is to check whether handshake failed due to invalid certificate*/
bk_mbedtls_verify_certificate(tls);
}
tls->conn_state = BK_TLS_FAIL;
return -1;
}
else
BK_LOGE(TAG, "ssl_handshake ret: -0x%04X\r\n", -ret);
return 0;
}
}
ssize_t bk_mbedtls_read(bk_tls_t *tls, char *data, size_t datalen)
{
ssize_t ret = mbedtls_ssl_read(&tls->ssl, (unsigned char *)data, datalen);
if (ret < 0) {
if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) {
BK_LOGE(TAG, "bk_mbedtls_read MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY\r\n");
return 0;
}
if (ret != BK_TLS_ERR_SSL_WANT_READ && ret != BK_TLS_ERR_SSL_WANT_WRITE) {
BK_LOGE(TAG, "read error :-0x%04X:\r\n", -ret);
}
}
return ret;
}
ssize_t bk_mbedtls_write(bk_tls_t *tls, const char *data, size_t datalen)
{
size_t written = 0;
size_t write_len = datalen;
BK_LOGD(TAG, "bk_mbedtls_write, write_len:%d\r\n", write_len);
while (written < datalen) {
if (write_len > MBEDTLS_SSL_OUT_CONTENT_LEN) {
write_len = MBEDTLS_SSL_OUT_CONTENT_LEN;
}
if (datalen > MBEDTLS_SSL_OUT_CONTENT_LEN) {
BK_LOGE(TAG, "Fragmenting data of excessive size :%d, offset: %d, size %d\r\n", datalen, written, write_len);
}
ssize_t ret = mbedtls_ssl_write(&tls->ssl, (unsigned char*) data + written, write_len);
if (ret <= 0) {
if (ret != BK_TLS_ERR_SSL_WANT_READ && ret != BK_TLS_ERR_SSL_WANT_WRITE && ret != 0) {
BK_LOGE(TAG, "write error :-0x%04X:\r\n", -ret);
return ret;
} else {
// Exiting the tls-write process as less than desired datalen are writable
BK_LOGE(TAG, "mbedtls_ssl_write() returned -0x%04X, already written %d, exitting...\r\n", -ret, written);
return (written > 0) ? written : ret;
}
}
else
BK_LOGE(TAG, "mbedtls_ssl_write, ret:%d\r\n", ret);
written += ret;
write_len = datalen - written;
}
return written;
}
void bk_mbedtls_conn_delete(bk_tls_t *tls)
{
if (tls != NULL) {
bk_mbedtls_cleanup(tls);
if (tls->is_tls) {
mbedtls_net_free(&tls->server_fd);
tls->sockfd = tls->server_fd.fd;
}
}
}
static inline void bk_mbedtls_net_init(bk_tls_t *tls)
{
mbedtls_net_init(&tls->server_fd);
}
/*---------------------------------tls------------------------------------*/
static bk_err_t bk_tls_hostname_to_fd(const char *host, size_t hostlen, int port, struct sockaddr_storage *address, int* fd)
{
struct addrinfo *address_info;
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
char *use_host = strndup(host, hostlen);
if (!use_host) {
return -1;
}
BK_LOGE(TAG, "host:%s: strlen %lu\r\n", use_host, (unsigned long)hostlen);
int res = getaddrinfo(use_host, NULL, &hints, &address_info);
if (res != 0 || address_info == NULL) {
BK_LOGE(TAG, "couldn't get hostname for :%s: "
"getaddrinfo() returns %d, addrinfo=%p\r\n", use_host, res, address_info);
free(use_host);
return BK_ERR_BK_TLS_CANNOT_RESOLVE_HOSTNAME;
}
free(use_host);
*fd = socket(address_info->ai_family, address_info->ai_socktype, address_info->ai_protocol);
if (*fd < 0) {
BK_LOGE(TAG, "Failed to create socket (family %d socktype %d protocol %d)\r\n", address_info->ai_family, address_info->ai_socktype, address_info->ai_protocol);
freeaddrinfo(address_info);
return BK_ERR_BK_TLS_CANNOT_CREATE_SOCKET;
}
if (address_info->ai_family == AF_INET) {
struct sockaddr_in *p = (struct sockaddr_in *)address_info->ai_addr;
p->sin_port = htons(port);
BK_LOGD(TAG, "[sock=%d] Resolved IPv4 address: %s\r\n", *fd, ipaddr_ntoa((const ip_addr_t*)&p->sin_addr.s_addr));
memcpy(address, p, sizeof(struct sockaddr ));
}
#if CONFIG_LWIP_IPV6
else if (address_info->ai_family == AF_INET6) {
struct sockaddr_in6 *p = (struct sockaddr_in6 *)address_info->ai_addr;
p->sin6_port = htons(port);
p->sin6_family = AF_INET6;
BK_LOGD(TAG, "[sock=%d] Resolved IPv6 address: %s\r\n", *fd, ip6addr_ntoa((const ip6_addr_t*)&p->sin6_addr));
memcpy(address, p, sizeof(struct sockaddr_in6 ));
}
#endif
else {
BK_LOGE(TAG, "Unsupported protocol family %d\r\n", address_info->ai_family);
close(*fd);
freeaddrinfo(address_info);
return BK_ERR_BK_TLS_UNSUPPORTED_PROTOCOL_FAMILY;
}
freeaddrinfo(address_info);
return BK_OK;
}
static void ms_to_timeval(int timeout_ms, struct timeval *tv)
{
tv->tv_sec = timeout_ms / 1000;
tv->tv_usec = (timeout_ms % 1000) * 1000;
}
static bk_err_t bk_tls_set_socket_options(int fd, const bk_tls_cfg_t *cfg)
{
if (cfg) {
if (cfg->timeout_ms >= 0) {
struct timeval tv;
ms_to_timeval(cfg->timeout_ms, &tv);
if (setsockopt(fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) != 0) {
BK_LOGE(TAG, "Fail to setsockopt SO_RCVTIMEO\r\n");
return BK_ERR_BK_TLS_SOCKET_SETOPT_FAILED;
}
if (setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)) != 0) {
BK_LOGE(TAG, "Fail to setsockopt SO_SNDTIMEO\r\n");
return BK_ERR_BK_TLS_SOCKET_SETOPT_FAILED;
}
}
if (cfg->keep_alive_cfg && cfg->keep_alive_cfg->keep_alive_enable) {
int keep_alive_enable = 1;
int keep_alive_idle = cfg->keep_alive_cfg->keep_alive_idle;
int keep_alive_interval = cfg->keep_alive_cfg->keep_alive_interval;
int keep_alive_count = cfg->keep_alive_cfg->keep_alive_count;
BK_LOGD(TAG, "Enable TCP keep alive. idle: %d, interval: %d, count: %d\r\n", keep_alive_idle, keep_alive_interval, keep_alive_count);
if (setsockopt(fd, SOL_SOCKET, SO_KEEPALIVE, &keep_alive_enable, sizeof(keep_alive_enable)) != 0) {
BK_LOGE(TAG, "Fail to setsockopt SO_KEEPALIVE\r\n");
return BK_ERR_BK_TLS_SOCKET_SETOPT_FAILED;
}
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPIDLE, &keep_alive_idle, sizeof(keep_alive_idle)) != 0) {
BK_LOGE(TAG, "Fail to setsockopt TCP_KEEPIDLE\r\n");
return BK_ERR_BK_TLS_SOCKET_SETOPT_FAILED;
}
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPINTVL, &keep_alive_interval, sizeof(keep_alive_interval)) != 0) {
BK_LOGE(TAG, "Fail to setsockopt TCP_KEEPINTVL\r\n");
return BK_ERR_BK_TLS_SOCKET_SETOPT_FAILED;
}
if (setsockopt(fd, IPPROTO_TCP, TCP_KEEPCNT, &keep_alive_count, sizeof(keep_alive_count)) != 0) {
BK_LOGE(TAG, "Fail to setsockopt TCP_KEEPCNT\r\n");
return BK_ERR_BK_TLS_SOCKET_SETOPT_FAILED;
}
}
if (cfg->if_name) {
if (cfg->if_name->ifr_name[0] != 0) {
BK_LOGD(TAG, "Bind [sock=%d] to interface %s\r\n", fd, cfg->if_name->ifr_name);
if (setsockopt(fd, SOL_SOCKET, SO_BINDTODEVICE, cfg->if_name, sizeof(struct ifreq)) != 0) {
BK_LOGE(TAG, "Bind [sock=%d] to interface %s fail\r\n", fd, cfg->if_name->ifr_name);
return BK_ERR_BK_TLS_SOCKET_SETOPT_FAILED;
}
}
}
}
return BK_OK;
}
static bk_err_t bk_tls_set_socket_non_blocking(int fd, bool non_blocking)
{
int flags;
if ((flags = fcntl(fd, F_GETFL, 0)) < 0) {
BK_LOGE(TAG, "[sock=%d] get file flags error: %s\r\n", fd, strerror(errno));
return BK_ERR_BK_TLS_SOCKET_SETOPT_FAILED;
}
if (non_blocking) {
flags |= O_NONBLOCK;
} else {
flags &= ~O_NONBLOCK;
}
if (fcntl(fd, F_SETFL, flags) < 0) {
BK_LOGE(TAG, "[sock=%d] set blocking/nonblocking error: %s\r\n", fd, strerror(errno));
return BK_ERR_BK_TLS_SOCKET_SETOPT_FAILED;
}
return BK_OK;
}
ssize_t bk_tls_get_bytes_avail(bk_tls_t *tls)
{
return _bk_tls_get_bytes_avail(tls);
}
int bk_tls_conn_destroy(bk_tls_t *tls)
{
if (tls != NULL) {
int ret = 0;
BK_LOGE(TAG, "bk_tls_conn_destroy\r\n");
_bk_tls_conn_delete(tls);
if (tls->sockfd >= 0) {
ret = close(tls->sockfd);
}
free(tls);
return ret;
}
return -1; // invalid argument
}
static bk_err_t create_ssl_handle(const char *hostname, size_t hostlen, const void *cfg, bk_tls_t *tls)
{
return _bk_create_ssl_handle(hostname, hostlen, cfg, tls);
}
static bk_err_t bk_tls_handshake(bk_tls_t *tls, const bk_tls_cfg_t *cfg)
{
return _bk_tls_handshake(tls, cfg);
}
static inline bk_err_t tls_tcp_connect(const char *host, int hostlen, int port, const bk_tls_cfg_t *cfg, int *sockfd)
{
struct sockaddr_storage address;
int fd;
bk_err_t ret = bk_tls_hostname_to_fd(host, hostlen, port, &address, &fd);
if (ret != BK_OK) {
return ret;
}
// Set timeout options, keep-alive options and bind device options if configured
ret = bk_tls_set_socket_options(fd, cfg);
if (ret != BK_OK) {
goto err;
}
// Set to non block before connecting to better control connection timeout
ret = bk_tls_set_socket_non_blocking(fd, true);
if (ret != BK_OK) {
goto err;
}
ret = BK_ERR_BK_TLS_FAILED_CONNECT_TO_HOST;
BK_LOGE(TAG, "[sock=%d] Connecting to server. HOST: %s, Port: %d\r\n", fd, host, port);
if (connect(fd, (struct sockaddr *)&address, sizeof(struct sockaddr)) < 0) {
if (errno == EINPROGRESS) {
fd_set fdset;
struct timeval tv = { .tv_usec = 0, .tv_sec = 10 }; // Default connection timeout is 10 s
if (cfg && cfg->non_block) {
// Non-blocking mode -> just return successfully at this stage
*sockfd = fd;
return BK_OK;
}
if ( cfg && cfg->timeout_ms > 0 ) {
ms_to_timeval(cfg->timeout_ms, &tv);
}
FD_ZERO(&fdset);
FD_SET(fd, &fdset);
int res = select(fd+1, NULL, &fdset, NULL, &tv);
if (res < 0) {
BK_LOGE(TAG, "[sock=%d] select() error: %s\r\n", fd, strerror(errno));
goto err;
}
else if (res == 0) {
ret = BK_ERR_BK_TLS_CONNECTION_TIMEOUT;
goto err;
} else {
int sockerr;
socklen_t len = (socklen_t)sizeof(int);
if (getsockopt(fd, SOL_SOCKET, SO_ERROR, (void*)(&sockerr), &len) < 0) {
ret = BK_ERR_BK_TLS_SOCKET_SETOPT_FAILED;
goto err;
}
else if (sockerr) {
BK_LOGE(TAG, "[sock=%d] delayed connect error: %s\r\n", fd, strerror(sockerr));
goto err;
}
}
} else {
BK_LOGE(TAG, "[sock=%d] connect() error: %s\r\n", fd, strerror(errno));
goto err;
}
}
if (cfg && cfg->non_block == false) {
// reset back to blocking mode (unless non_block configured)
ret = bk_tls_set_socket_non_blocking(fd, false);
if (ret != BK_OK) {
goto err;
}
}
*sockfd = fd;
BK_LOGE(TAG, "%s, sockfd:%d\r\n", __func__, *sockfd);
return BK_OK;
err:
close(fd);
return ret;
}
static ssize_t tls_tcp_read(bk_tls_t *tls, char *data, size_t datalen)
{
return recv(tls->sockfd, data, datalen, 0);
}
static ssize_t tls_tcp_write(bk_tls_t *tls, const char *data, size_t datalen)
{
return send(tls->sockfd, data, datalen, 0);
}
static int tls_low_level_conn(const char *hostname, int hostlen, int port, const bk_tls_cfg_t *cfg, bk_tls_t *tls)
{
if (!tls) {
BK_LOGE(TAG, "empty bk_tls parameter\r\n");
return -1;
}
int bk_ret;
switch (tls->conn_state) {
case BK_TLS_INIT:
tls->sockfd = -1;
if (cfg != NULL && cfg->is_plain_tcp == false) {
_bk_tls_net_init(tls);
tls->is_tls = true;
}
if ((bk_ret = tls_tcp_connect(hostname, hostlen, port, cfg, &tls->sockfd)) != BK_OK) {
return -1;
}
if (tls->is_tls == false) {
tls->read = tls_tcp_read;
tls->write = tls_tcp_write;
BK_LOGE(TAG, "non-tls connection established\r\n");
return 1;
}
if (cfg && cfg->non_block) {
FD_ZERO(&tls->rset);
FD_SET(tls->sockfd, &tls->rset);
tls->wset = tls->rset;
}
tls->conn_state = BK_TLS_CONNECTING;
/* falls through */
case BK_TLS_CONNECTING:
if (cfg && cfg->non_block) {
BK_LOGE(TAG, "connecting...\r\n");
struct timeval tv;
ms_to_timeval(cfg->timeout_ms, &tv);
/* In case of non-blocking I/O, we use the select() API to check whether
connection has been established or not*/
if (select(tls->sockfd + 1, &tls->rset, &tls->wset, NULL,
cfg->timeout_ms>0 ? &tv : NULL) == 0) {
BK_LOGD(TAG, "select() timed out\r\n");
return 0;
}
if (FD_ISSET(tls->sockfd, &tls->rset) || FD_ISSET(tls->sockfd, &tls->wset)) {
int error;
socklen_t len = sizeof(error);
/* pending error check */
if (getsockopt(tls->sockfd, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
BK_LOGD(TAG, "Non blocking connect failed\r\n");
tls->conn_state = BK_TLS_FAIL;
return -1;
}
}
}
/* By now, the connection has been established */
bk_ret = create_ssl_handle(hostname, hostlen, cfg, tls);
if (bk_ret != BK_OK) {
BK_LOGE(TAG, "create_ssl_handle failed\r\n");
tls->conn_state = BK_TLS_FAIL;
return -1;
}
tls->read = _bk_tls_read;
tls->write = _bk_tls_write;
tls->conn_state = BK_TLS_HANDSHAKE;
/* falls through */
case BK_TLS_HANDSHAKE:
BK_LOGE(TAG, "handshake in progress...\r\n");
return bk_tls_handshake(tls, cfg);
break;
case BK_TLS_FAIL:
BK_LOGE(TAG, "failed to open a new connection\r\n");
break;
default:
BK_LOGE(TAG, "invalid bk-tls state\r\n");
break;
}
return -1;
}
#define pdMS_TO_TICKS( xTimeInMs ) ( ( TickType_t ) ( ( ( TickType_t ) ( xTimeInMs ) * ( TickType_t ) configTICK_RATE_HZ ) / ( TickType_t ) 1000U ) )
int tls_conn_new_sync(const char *hostname, int hostlen, int port, const bk_tls_cfg_t *cfg, bk_tls_t *tls)
{
size_t start = xTaskGetTickCount();
while (1) {
int ret = tls_low_level_conn(hostname, hostlen, port, cfg, tls);
if (ret == 1) {
BK_LOGE(TAG, "open new connection\r\n");
return ret;
} else if (ret == -1) {
BK_LOGE(TAG, "Failed to open new connection\r\n");
return -1;
} else if (ret == 0 && cfg->timeout_ms >= 0) {
size_t timeout_ticks = pdMS_TO_TICKS(cfg->timeout_ms);
uint32_t expired = xTaskGetTickCount() - start;
if (expired >= timeout_ticks) {
BK_LOGE(TAG, "Failed to open new connection in specified timeout\r\n");
return 0;
}
}
}
return 0;
}
bk_tls_t *bk_tls_init(void)
{
bk_tls_t *tls = (bk_tls_t *)calloc(1, sizeof(bk_tls_t));
if (!tls) {
return NULL;
}
_bk_tls_net_init(tls);
tls->sockfd = -1;
return tls;
}
/*---------------------------------ssl-------------------------------------*/
struct timeval* bk_transport_utils_ms_to_timeval(int timeout_ms, struct timeval *tv)
{
if (timeout_ms == -1) {
return NULL;
}
tv->tv_sec = timeout_ms / 1000;
tv->tv_usec = (timeout_ms - (tv->tv_sec * 1000)) * 1000;
return tv;
}
static int ssl_base_poll_read(transport_bk_tls_t *ssl, int timeout_ms)
{
int ret = -1;
int remain = 0;
struct timeval timeout;
fd_set readset;
fd_set errset;
FD_ZERO(&readset);
FD_ZERO(&errset);
FD_SET(ssl->sockfd, &readset);
FD_SET(ssl->sockfd, &errset);
if (ssl->tls && (remain = bk_tls_get_bytes_avail(ssl->tls)) > 0) {
BK_LOGD(TAG, "remain data in cache, need to read again\r\n");
return remain;
}
else
BK_LOGD(TAG, "NO data available\r\n");
ret = select(ssl->sockfd + 1, &readset, NULL, &errset, bk_transport_utils_ms_to_timeval(timeout_ms, &timeout));
if (ret > 0 && FD_ISSET(ssl->sockfd, &errset)) {
int sock_errno = 0;
uint32_t optlen = sizeof(sock_errno);
getsockopt(ssl->sockfd, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen);
BK_LOGE(TAG, "poll_read select error %d, errno = %s, fd = %d\r\n", sock_errno, strerror(sock_errno), ssl->sockfd);
ret = -1;
}
return ret;
}
static int ssl_base_poll_write(transport_bk_tls_t *ssl, int timeout_ms)
{
int ret = -1;
struct timeval timeout;
fd_set writeset;
fd_set errset;
FD_ZERO(&writeset);
FD_ZERO(&errset);
FD_SET(ssl->sockfd, &writeset);
FD_SET(ssl->sockfd, &errset);
ret = select(ssl->sockfd + 1, NULL, &writeset, &errset, bk_transport_utils_ms_to_timeval(timeout_ms, &timeout));
if (ret > 0 && FD_ISSET(ssl->sockfd, &errset)) {
int sock_errno = 0;
uint32_t optlen = sizeof(sock_errno);
getsockopt(ssl->sockfd, SOL_SOCKET, SO_ERROR, &sock_errno, &optlen);
BK_LOGE(TAG, "poll_write select error %d, errno = %s, fd = %d\r\n", sock_errno, strerror(sock_errno), ssl->sockfd);
ret = -1;
}
return ret;
}
int ssl_connect(transport_bk_tls_t *ssl, const char *host, int port, int timeout_ms)
{
ssl->cfg.timeout_ms = timeout_ms;
ssl->cfg.is_plain_tcp = false;
ssl->ssl_initialized = true;
BK_LOGD(TAG, "%s\r\n", __func__);
ssl->tls = bk_tls_init();
if (ssl->tls == NULL) {
BK_LOGE(TAG, "Failed to initialize new connection object\r\n");
return -1;
}
if (tls_conn_new_sync(host, strlen(host), port, &ssl->cfg, ssl->tls) <= 0) {
BK_LOGE(TAG, "Failed to open a new connection\r\n");
bk_tls_conn_destroy(ssl->tls);
ssl->tls = NULL;
ssl->sockfd = -1;
return -1;
}
ssl->sockfd = ssl->tls->sockfd;
BK_LOGE(TAG, "%s, sockfd:%d\r\n", __func__, ssl->sockfd);
return 0;
}
int ssl_tcp_connect(transport_bk_tls_t *ssl, const char *host, int port, int timeout_ms)
{
bk_err_t ret;
ssl->cfg.timeout_ms = timeout_ms;
ret = tls_tcp_connect(host, strlen(host), port, &ssl->cfg, &ssl->sockfd);
if (ret != BK_OK) {
ssl->sockfd = -1;
return -1;
}
BK_LOGE(TAG, "%s, sockfd:%d\r\n", __func__, ssl->sockfd);
return 0;
}
int ssl_write(transport_bk_tls_t *ssl, const char *buffer, int len, int timeout_ms)
{
int poll;
BK_LOGD(TAG, "ssl_write\r\n");
if ((poll = ssl_base_poll_write(ssl, timeout_ms)) <= 0) {
BK_LOGE(TAG, "Poll timeout or error, errno=%s, fd=%d, timeout_ms=%d\r\n", strerror(errno), ssl->sockfd, timeout_ms);
return poll;
}
else
BK_LOGD(TAG, "ssl_base_poll_write, poll=%d, poll success\r\n", poll);
int ret = _bk_tls_write(ssl->tls, (const char *) buffer, len);
if (ret < 0) {
BK_LOGE(TAG, "bk_tls_conn_write error, errno=%s\r\n", strerror(errno));
}
return ret;
}
int ssl_tcp_write(transport_bk_tls_t *ssl, const char *buffer, int len, int timeout_ms)
{
int ret, poll;
BK_LOGD(TAG, "tcp_write\r\n");
if ((poll = ssl_base_poll_write(ssl, timeout_ms)) <= 0) {
BK_LOGE(TAG, "Poll timeout or error, errno=%s, fd=%d, timeout_ms=%d\r\n", strerror(errno), ssl->sockfd, timeout_ms);
return poll;
} else {
BK_LOGD(TAG, "ssl_base_poll_write, poll=%d, poll success\r\n", poll);
}
ret = send(ssl->sockfd, buffer, len, 0);
if (ret < 0) {
BK_LOGE(TAG, "bk_tls_conn_write error, errno=%s\r\n", strerror(errno));
}
return ret;
}
int ssl_read(transport_bk_tls_t *ssl, char *buffer, int len, int timeout_ms)
{
int poll;
BK_LOGD(TAG, "ssl_read, len:%d\r\n", len);
if ((poll = ssl_base_poll_read(ssl, timeout_ms)) <= 0) {
BK_LOGE(TAG, "ssl_base_poll_read fail\r\n");
return poll;
}
else
BK_LOGD(TAG, "ssl_base_poll_read:%d\r\n", poll);
int ret = _bk_tls_read(ssl->tls, ( char *)buffer, len);
if (ret < 0) {
BK_LOGE(TAG, "bk_tls_conn_read error, errno=%s, ret:-0x%04x\r\n", strerror(errno), -ret);
}
if (ret == 0) {
if (poll > 0) {
BK_LOGE(TAG, "_bk_tls_read, socket reads 0\r\n");
// no error, socket reads 0 while previously detected as readable -> connection has been closed cleanly
}
ret = -1;
}
if(ret > 0)
BK_LOGD(TAG, "_bk_tls_read, ret:%d\r\n", ret);
return ret;
}
int ssl_tcp_read(transport_bk_tls_t *ssl, char *buffer, int len, int timeout_ms)
{
int ret, poll;
BK_LOGD(TAG, "tcp_read, len:%d\r\n", len);
if ((poll = ssl_base_poll_read(ssl, timeout_ms)) <= 0) {
BK_LOGE(TAG, "ssl_base_poll_read fail\r\n");
return poll;
}
else {
BK_LOGD(TAG, "ssl_base_poll_read:%d\r\n", poll);
}
ret = recv(ssl->sockfd, buffer, len, 0);
if (ret < 0) {
BK_LOGE(TAG, "bk_tls_conn_read error, errno=%s, ret:-0x%04x\r\n", strerror(errno), ret);
}
if (ret == 0) {
if (poll > 0) {
BK_LOGE(TAG, "_bk_tls_read, socket reads 0\r\n");
// no error, socket reads 0 while previously detected as readable -> connection has been closed cleanly
}
ret = -1;
}
if (ret > 0) {
BK_LOGD(TAG, "_bk_tls_read, ret:%d\r\n", ret);
}
return ret;
}
int ssl_base_close(transport_bk_tls_t *ssl)
{
int ret = -1;
BK_LOGE(TAG, "ssl_base_close\r\n");
if (ssl && ssl->ssl_initialized) {
ret = bk_tls_conn_destroy(ssl->tls);
ssl->tls = NULL;
ssl->conn_state = TRANS_SSL_INIT;
ssl->ssl_initialized = false;
ssl->sockfd = -1;
} else if (ssl && ssl->sockfd >= 0) {
ret = close(ssl->sockfd);
ssl->sockfd = -1;
}
return ret;
}
void bk_transport_ssl_set_interface_name(transport_bk_tls_t *ssl, struct ifreq *if_name)
{
ssl->cfg.if_name = if_name;
}
void bk_transport_ssl_enable_global_ca_store(transport_bk_tls_t *ssl)
{
ssl->cfg.use_global_ca_store = true;
}
#ifdef CONFIG_BK_TLS_PSK_VERIFICATION
void bk_transport_ssl_set_psk_key_hint(transport_bk_tls_t *ssl, const psk_hint_key_t* psk_hint_key)
{
ssl->cfg.psk_hint_key = psk_hint_key;
}
#endif
void bk_transport_ssl_set_cert_data(transport_bk_tls_t *ssl, const char *data, int len)
{
ssl->cfg.cacert_pem_buf = (void *)data;
ssl->cfg.cacert_pem_bytes = len + 1;
}
void bk_transport_ssl_set_cert_data_der(transport_bk_tls_t *ssl, const char *data, int len)
{
ssl->cfg.cacert_buf = (void *)data;
ssl->cfg.cacert_bytes = len;
}
void bk_transport_ssl_set_client_cert_data(transport_bk_tls_t *ssl, const char *data, int len)
{
ssl->cfg.clientcert_pem_buf = (void *)data;
ssl->cfg.clientcert_pem_bytes = len + 1;
}
void bk_transport_ssl_set_client_cert_data_der(transport_bk_tls_t *ssl, const char *data, int len)
{
ssl->cfg.clientcert_buf = (void *)data;
ssl->cfg.clientcert_bytes = len;
}
void bk_transport_ssl_set_client_key_data(transport_bk_tls_t *ssl, const char *data, int len)
{
ssl->cfg.clientkey_pem_buf = (void *)data;
ssl->cfg.clientkey_pem_bytes = len + 1;
}
void bk_transport_ssl_set_client_key_password(transport_bk_tls_t *ssl, const char *password, int password_len)
{
ssl->cfg.clientkey_password = (void *)password;
ssl->cfg.clientkey_password_len = password_len;
}
void bk_transport_ssl_set_client_key_data_der(transport_bk_tls_t *ssl, const char *data, int len)
{
ssl->cfg.clientkey_buf = (void *)data;
ssl->cfg.clientkey_bytes = len;
}
void bk_transport_ssl_set_keep_alive(transport_bk_tls_t *ssl, bk_transport_keep_alive_t *keep_alive_cfg)
{
ssl->cfg.keep_alive_cfg = (tls_keep_alive_cfg_t *) keep_alive_cfg;
}
#ifdef CONFIG_MBEDTLS_CERTIFICATE_BUNDLE
void bk_transport_ssl_crt_bundle_attach(transport_bk_tls_t *ssl, bk_err_t ((*crt_bundle_attach)(void *conf)))
{
ssl->cfg.crt_bundle_attach = crt_bundle_attach;
}
#endif
void bk_transport_ssl_skip_common_name_check(transport_bk_tls_t *ssl)
{
ssl->cfg.skip_common_name = true;
}
#endif