DTLS(Datagram Transport Layer Security)是运行在UDP之上的安全通讯协议,大部分和TLS是一样的,只是针对UDP在不可靠传输问题增加了新特性,用来解决UDP传输的报文乱序和报文丢失等问题,DTLS主要通过下面方法来解决
DTLS加入了超时重传机制,所以需要注册设置定时器和获得定时器接口,这个例子不是加载X.509证书派发密钥,而是采用PSK密钥交换。
/* mbed TLS feature support */
#define MBEDTLS_KEY_EXCHANGE_PSK_ENABLED 启用PSK密钥协商方案
#define MBEDTLS_SSL_PROTO_TLS1_2 选择TLS1.2
#define MBEDTLS_SSL_PROTO_DTLS 启用DTLS
/* mbed TLS modules */
#define MBEDTLS_AES_C
#define MBEDTLS_CCM_C
#define MBEDTLS_CIPHER_C
#define MBEDTLS_CTR_DRBG_C
#define MBEDTLS_ENTROPY_C
#define MBEDTLS_MD_C
#define MBEDTLS_SHA256_C
#define MBEDTLS_SSL_CLI_C
#define MBEDTLS_SSL_TLS_C 启用TLS/SSL功能
#define MBEDTLS_AES_ROM_TABLES
/* Save some RAM by adjusting to your exact needs */
#define MBEDTLS_PSK_MAX_LEN 16 /* 128-bits keys are generally enough */
/*
* You should adjust this to the exact number of sources you're using: default
* is the "platform_entropy_poll" source, but you may want to add other ones
* Minimum is 2 for the entropy test suite.
*/
#define MBEDTLS_ENTROPY_MAX_SOURCES 2
/*
* Use only CCM_8 ciphersuites, and
* save ROM and a few bytes of RAM by specifying our own ciphersuite list
*/
#define MBEDTLS_SSL_CIPHERSUITES MBEDTLS_TLS_PSK_WITH_AES_128_CCM_8
/*
* Save RAM at the expense of interoperability: do this only if you control
* both ends of the connection! (See comments in "mbedtls/ssl.h".)
* The optimal size here depends on the typical size of records.
*/
#define MBEDTLS_SSL_MAX_CONTENT_LEN 4096 TLS缓存区,这个可以极大减少TLS占用RAM
#include
#include
#include
#include
#include "mbedtls/net.h"
#include "mbedtls/ssl.h"
#include "mbedtls/entropy.h"
#include "mbedtls/ctr_drbg.h"
#include "mbedtls/platform.h"
#define assert_exit(cond, ret) \
do { if (!(cond)) { \
printf(" !. assert: failed [line: %d, error: -0x%04X]\n", __LINE__, -ret); \
goto cleanup; \
} } while (0)
#define SERVER_PORT "8888"
#define SERVER_ADDR "192.168.1.101"
#define MESSAGE "Echo this\r\n"
// 000102030405060708090a0b0c0d0e0f
const uint8_t psk[] = {
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f
};
const char psk_id[] = "Client_identity";
struct dtls_timing_context
{
uint32_t snapshot;
uint32_t int_ms;
uint32_t fin_ms;
};
static struct dtls_timing_context timer;
//这里是获得系统时间函数
uint32_t OS_Get_time()
{
return 0;
}
void dtls_timing_set_delay(void *data, uint32_t int_ms, uint32_t fin_ms)
{
struct dtls_timing_context *ctx = (struct dtls_timing_context *)data;
ctx->int_ms = int_ms;
ctx->fin_ms = fin_ms;
if (fin_ms != 0) {
ctx->snapshot = OS_Get_time();
}
}
int dtls_timing_get_delay(void *data)
{
struct dtls_timing_context *ctx = (struct dtls_timing_context *)data;
unsigned long elapsed_ms;
if (ctx->fin_ms == 0) {
return -1;
}
elapsed_ms = OS_Get_time() - ctx->snapshot;
if (elapsed_ms >= ctx->fin_ms)
return 2;
if (elapsed_ms >= ctx->int_ms)
return 1;
return 0;
}
/*
static int entropy_source(void *data, uint8_t *output, size_t len, size_t *olen)
{
uint32_t seed;
ARG_UNUSED(data);
seed = sys_rand32_get();
if (len > sizeof(seed)) {
len = sizeof(seed);
}
memcpy(output, &seed, len);
*olen = len;
return 0;
}*/
int main(void)
{
int ret = 0, len = 0;
unsigned char buf[256];
const char *pers = "dtls_client";
mbedtls_entropy_context entropy;
mbedtls_ctr_drbg_context ctr_drbg;
mbedtls_platform_set_printf(printf);
mbedtls_ssl_context ssl;
mbedtls_ssl_config conf;
mbedtls_net_context ctx;
mbedtls_net_init(&ctx);
mbedtls_ssl_init(&ssl);
mbedtls_ssl_config_init(&conf);
mbedtls_ctr_drbg_init(&ctr_drbg);
mbedtls_printf("\n . Seeding the random number generator...");
mbedtls_entropy_init(&entropy);
/*mbedtls_entropy_add_source(&entropy, entropy_source, NULL,
MBEDTLS_ENTROPY_MAX_GATHER, MBEDTLS_ENTROPY_SOURCE_STRONG);*/
ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
(const uint8_t *)pers, strlen(pers));
assert_exit(ret == 0, ret);
mbedtls_printf(" ok\n . Setting up the SSL/TLS structure...");
//这里是DATAGRAM
ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT,
MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT);
assert_exit(ret == 0, ret);
mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg);
//这里选择PSK密钥
mbedtls_ssl_conf_psk(&conf, psk, sizeof(psk),
(const uint8_t *)psk_id, strlen((char*)psk_id));
ret = mbedtls_ssl_setup(&ssl, &conf);
assert_exit(ret == 0, ret);
mbedtls_printf(" ok\n . Connecting to %s:%s...", SERVER_ADDR, SERVER_PORT);
//连接采用UDP
ret = mbedtls_net_connect( &ctx, SERVER_ADDR, SERVER_PORT, MBEDTLS_NET_PROTO_UDP );
assert_exit(ret == 0, ret);
//注册设置定时器和获取定时器回调
mbedtls_ssl_set_timer_cb(&ssl, &timer, dtls_timing_set_delay, dtls_timing_get_delay);
mbedtls_ssl_set_bio( &ssl, &ctx, mbedtls_net_send, mbedtls_net_recv, NULL );
mbedtls_printf(" ok\n . Performing the SSL/TLS handshake...");
while ((ret = mbedtls_ssl_handshake(&ssl)) != 0)
{
if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE)
{
mbedtls_printf(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", -ret);
goto cleanup;
}
}
mbedtls_printf(" ok\n > Write to server:");
do {
ret = mbedtls_ssl_write(&ssl, (const uint8_t *)MESSAGE, strlen(MESSAGE));
} while (ret == MBEDTLS_ERR_SSL_WANT_READ ||
ret == MBEDTLS_ERR_SSL_WANT_WRITE);
assert_exit(ret > 0, ret);
len = ret;
mbedtls_printf( " %d bytes written\n\n%s\n", len, MESSAGE);
mbedtls_printf(" > Read from server:");
len = sizeof(buf) - 1;
memset(buf, 0x00, sizeof(buf));
do {
ret = mbedtls_ssl_read(&ssl, buf, len);
} while (ret == MBEDTLS_ERR_SSL_WANT_READ ||
ret == MBEDTLS_ERR_SSL_WANT_WRITE);
assert_exit(ret > 0, ret);
len = ret;
mbedtls_printf( " %d bytes read\n\n%s\n", len, buf);
mbedtls_ssl_close_notify(&ssl);
mbedtls_printf(" . Closing the connection ... done\n");
cleanup:
mbedtls_net_free(&ctx);
mbedtls_ssl_free(&ssl);
mbedtls_ssl_config_free(&conf);
mbedtls_ctr_drbg_free(&ctr_drbg);
mbedtls_entropy_free(&entropy);
return ret;
}