Merge branch 'feature/coap_mbedtls_support' into 'master'

Add DTLS support to libcoap using MbedTLS

See merge request espressif/esp-idf!5560
This commit is contained in:
Mahavir Jain 2019-08-06 14:23:54 +08:00
commit d260ee6955
27 changed files with 4233 additions and 1547 deletions

View File

@ -8,7 +8,7 @@ set(srcs
"libcoap/src/coap_hashkey.c"
"libcoap/src/coap_session.c"
"libcoap/src/coap_time.c"
"libcoap/src/coap_debug.c"
"port/coap_debug.c"
"libcoap/src/encode.c"
"libcoap/src/mem.c"
"libcoap/src/net.c"
@ -18,17 +18,15 @@ set(srcs
"libcoap/src/str.c"
"libcoap/src/subscribe.c"
"libcoap/src/uri.c"
"libcoap/src/coap_notls.c"
"port/coap_io.c")
set(COMPONENT_REQUIRES lwip)
"libcoap/src/coap_io.c"
"port/coap_mbedtls.c")
idf_component_register(SRCS "${srcs}"
INCLUDE_DIRS "${include_dirs}"
REQUIRES lwip)
REQUIRES lwip mbedtls)
# Silence format truncation warning, until it is fixed upstream
set_source_files_properties(libcoap/src/coap_debug.c PROPERTIES COMPILE_FLAGS -Wno-format-truncation)
set_source_files_properties(port/coap_debug.c PROPERTIES COMPILE_FLAGS -Wno-format-truncation)
# Needed for coap headers in public builds, also.
#

74
components/coap/Kconfig Normal file
View File

@ -0,0 +1,74 @@
menu "CoAP Configuration"
choice COAP_MBEDTLS_ENCRYPTION_MODE
prompt "CoAP Encryption method"
default COAP_MBEDTLS_PSK
help
If the CoAP information is to be encrypted, the encryption environment
can be set up in one of two ways (default being Pre-Shared key mode)
- Encrypt using defined Pre-Shared Keys (PSK if uri includes coaps://)
- Encrypt using defined Public Key Infrastructure (PKI if uri includes coaps://)
config COAP_MBEDTLS_PSK
select MBEDTLS_SSL_PROTO_DTLS
select MBEDTLS_PSK_MODES
select MBEDTLS_KEY_EXCHANGE_PSK
bool "Pre-Shared Keys"
config COAP_MBEDTLS_PKI
select MBEDTLS_SSL_PROTO_DTLS
select MBEDTLS_PSK_MODES
select MBEDTLS_KEY_EXCHANGE_PSK
bool "PKI Certificates"
endchoice #COAP_MBEDTLS_ENCRYPTION_MODE
config COAP_MBEDTLS_DEBUG
bool "Enable CoAP debugging"
default n
help
Enable CoAP debugging functions at compile time for the example code.
If this option is enabled, call coap_set_log_level()
at runtime in order to enable CoAP debug output via the ESP
log mechanism.
choice COAP_MBEDTLS_DEBUG_LEVEL
bool "Set CoAP debugging level"
depends on COAP_MBEDTLS_DEBUG
default COAP_LOG_WARNING
help
Set CoAP debugging level
config COAP_LOG_EMERG
bool "Emergency"
config COAP_LOG_ALERT
bool "Alert"
config COAP_LOG_CRIT
bool "Critical"
config COAP_LOG_ERROR
bool "Error"
config COAP_LOG_WARNING
bool "Warning"
config COAP_LOG_NOTICE
bool "Notice"
config COAP_LOG_INFO
bool "Info"
config COAP_LOG_DEBUG
bool "Debug"
endchoice
config COAP_LOG_DEFAULT_LEVEL
int
default 0 if !COAP_MBEDTLS_DEBUG
default 0 if COAP_LOG_EMERG
default 1 if COAP_LOG_ALERT
default 2 if COAP_LOG_CRIT
default 3 if COAP_LOG_ERROR
default 4 if COAP_LOG_WARNING
default 5 if COAP_LOG_NOTICE
default 6 if COAP_LOG_INFO
default 7 if COAP_LOG_DEBUG
endmenu

View File

@ -4,11 +4,11 @@
COMPONENT_ADD_INCLUDEDIRS := port/include port/include/coap libcoap/include libcoap/include/coap2
COMPONENT_OBJS = libcoap/src/address.o libcoap/src/async.o libcoap/src/block.o libcoap/src/coap_event.o libcoap/src/coap_hashkey.o libcoap/src/coap_session.o libcoap/src/coap_time.o libcoap/src/coap_debug.o libcoap/src/encode.o libcoap/src/mem.o libcoap/src/net.o libcoap/src/option.o libcoap/src/pdu.o libcoap/src/resource.o libcoap/src/str.o libcoap/src/subscribe.o libcoap/src/uri.o libcoap/src/coap_notls.o port/coap_io.o
COMPONENT_OBJS = libcoap/src/address.o libcoap/src/async.o libcoap/src/block.o libcoap/src/coap_event.o libcoap/src/coap_hashkey.o libcoap/src/coap_session.o libcoap/src/coap_time.o port/coap_debug.o libcoap/src/encode.o libcoap/src/mem.o libcoap/src/net.o libcoap/src/option.o libcoap/src/pdu.o libcoap/src/resource.o libcoap/src/str.o libcoap/src/subscribe.o libcoap/src/uri.o port/coap_mbedtls.o libcoap/src/coap_io.o
COMPONENT_SRCDIRS := libcoap/src libcoap port
COMPONENT_SUBMODULES += libcoap
# Silence format truncation warning, until it is fixed upstream
libcoap/src/coap_debug.o: CFLAGS += -Wno-format-truncation
port/coap_debug.o: CFLAGS += -Wno-format-truncation

@ -1 +1 @@
Subproject commit cfec0d072c5b99ed3e54828ca50ea2f6b91e1f50
Subproject commit 98954eb30a2e728e172a6cd29430ae5bc999b585

View File

@ -0,0 +1,888 @@
/* debug.c -- debug utilities
*
* Copyright (C) 2010--2012,2014--2019 Olaf Bergmann <bergmann@tzi.org> and others
*
* This file is part of the CoAP library libcoap. Please see
* README for terms of use.
*/
#include "coap_config.h"
#if defined(HAVE_STRNLEN) && defined(__GNUC__) && !defined(_GNU_SOURCE)
#define _GNU_SOURCE 1
#endif
#if defined(HAVE_ASSERT_H) && !defined(assert)
# include <assert.h>
#endif
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#ifdef HAVE_ARPA_INET_H
#include <arpa/inet.h>
#endif
#ifdef HAVE_WS2TCPIP_H
#include <ws2tcpip.h>
#endif
#ifdef HAVE_TIME_H
#include <time.h>
#endif
#include "libcoap.h"
#include "coap_dtls.h"
#include "block.h"
#include "coap_debug.h"
#include "encode.h"
#include "net.h"
#include "coap_mutex.h"
#ifdef WITH_LWIP
# define fprintf(fd, ...) LWIP_PLATFORM_DIAG((__VA_ARGS__))
# define fflush(...)
#endif
#ifdef WITH_CONTIKI
# ifndef DEBUG
# define DEBUG DEBUG_PRINT
# endif /* DEBUG */
#include "net/ip/uip-debug.h"
#endif
static coap_log_t maxlog = LOG_WARNING; /* default maximum log level */
static int use_fprintf_for_show_pdu = 1; /* non zero to output with fprintf */
const char *coap_package_name(void) {
return PACKAGE_NAME;
}
const char *coap_package_version(void) {
return PACKAGE_STRING;
}
void
coap_set_show_pdu_output(int use_fprintf) {
use_fprintf_for_show_pdu = use_fprintf;
}
coap_log_t
coap_get_log_level(void) {
return maxlog;
}
void
coap_set_log_level(coap_log_t level) {
maxlog = level;
}
/* this array has the same order as the type log_t */
static const char *loglevels[] = {
"EMRG", "ALRT", "CRIT", "ERR ", "WARN", "NOTE", "INFO", "DEBG"
};
#ifdef HAVE_TIME_H
COAP_STATIC_INLINE size_t
print_timestamp(char *s, size_t len, coap_tick_t t) {
struct tm *tmp;
time_t now = coap_ticks_to_rt(t);
tmp = localtime(&now);
return strftime(s, len, "%b %d %H:%M:%S", tmp);
}
#else /* alternative implementation: just print the timestamp */
COAP_STATIC_INLINE size_t
print_timestamp(char *s, size_t len, coap_tick_t t) {
#ifdef HAVE_SNPRINTF
return snprintf(s, len, "%u.%03u",
(unsigned int)coap_ticks_to_rt(t),
(unsigned int)(t % COAP_TICKS_PER_SECOND));
#else /* HAVE_SNPRINTF */
/* @todo do manual conversion of timestamp */
return 0;
#endif /* HAVE_SNPRINTF */
}
#endif /* HAVE_TIME_H */
#ifndef HAVE_STRNLEN
/**
* A length-safe strlen() fake.
*
* @param s The string to count characters != 0.
* @param maxlen The maximum length of @p s.
*
* @return The length of @p s.
*/
static inline size_t
strnlen(const char *s, size_t maxlen) {
size_t n = 0;
while(*s++ && n < maxlen)
++n;
return n;
}
#endif /* HAVE_STRNLEN */
static size_t
print_readable( const uint8_t *data, size_t len,
unsigned char *result, size_t buflen, int encode_always ) {
const uint8_t hex[] = "0123456789ABCDEF";
size_t cnt = 0;
assert(data || len == 0);
if (buflen == 0) { /* there is nothing we can do here but return */
return 0;
}
while (len) {
if (!encode_always && isprint(*data)) {
if (cnt+1 < buflen) { /* keep one byte for terminating zero */
*result++ = *data;
++cnt;
} else {
break;
}
} else {
if (cnt+4 < buflen) { /* keep one byte for terminating zero */
*result++ = '\\';
*result++ = 'x';
*result++ = hex[(*data & 0xf0) >> 4];
*result++ = hex[*data & 0x0f];
cnt += 4;
} else
break;
}
++data; --len;
}
*result = '\0'; /* add a terminating zero */
return cnt;
}
#ifndef min
#define min(a,b) ((a) < (b) ? (a) : (b))
#endif
size_t
coap_print_addr(const struct coap_address_t *addr, unsigned char *buf, size_t len) {
#if defined( HAVE_ARPA_INET_H ) || defined( HAVE_WS2TCPIP_H )
const void *addrptr = NULL;
in_port_t port;
unsigned char *p = buf;
size_t need_buf;
switch (addr->addr.sa.sa_family) {
case AF_INET:
addrptr = &addr->addr.sin.sin_addr;
port = ntohs(addr->addr.sin.sin_port);
need_buf = INET_ADDRSTRLEN;
break;
case AF_INET6:
if (len < 7) /* do not proceed if buffer is even too short for [::]:0 */
return 0;
*p++ = '[';
addrptr = &addr->addr.sin6.sin6_addr;
port = ntohs(addr->addr.sin6.sin6_port);
need_buf = INET6_ADDRSTRLEN;
break;
default:
memcpy(buf, "(unknown address type)", min(22, len));
return min(22, len);
}
/* Cast needed for Windows, since it doesn't have the correct API signature. */
if (inet_ntop(addr->addr.sa.sa_family, addrptr, (char *)p,
min(len, need_buf)) == 0) {
perror("coap_print_addr");
return 0;
}
p += strnlen((char *)p, len);
if (addr->addr.sa.sa_family == AF_INET6) {
if (p < buf + len) {
*p++ = ']';
} else
return 0;
}
p += snprintf((char *)p, buf + len - p + 1, ":%d", port);
return buf + len - p;
#else /* HAVE_ARPA_INET_H */
# if WITH_CONTIKI
unsigned char *p = buf;
uint8_t i;
# if NETSTACK_CONF_WITH_IPV6
const uint8_t hex[] = "0123456789ABCDEF";
if (len < 41)
return 0;
*p++ = '[';
for (i=0; i < 16; i += 2) {
if (i) {
*p++ = ':';
}
*p++ = hex[(addr->addr.u8[i] & 0xf0) >> 4];
*p++ = hex[(addr->addr.u8[i] & 0x0f)];
*p++ = hex[(addr->addr.u8[i+1] & 0xf0) >> 4];
*p++ = hex[(addr->addr.u8[i+1] & 0x0f)];
}
*p++ = ']';
# else /* WITH_UIP6 */
# warning "IPv4 network addresses will not be included in debug output"
if (len < 21)
return 0;
# endif /* WITH_UIP6 */
if (buf + len - p < 6)
return 0;
#ifdef HAVE_SNPRINTF
p += snprintf((char *)p, buf + len - p + 1, ":%d", uip_htons(addr->port));
#else /* HAVE_SNPRINTF */
/* @todo manual conversion of port number */
#endif /* HAVE_SNPRINTF */
return p - buf;
# else /* WITH_CONTIKI */
/* TODO: output addresses manually */
# warning "inet_ntop() not available, network addresses will not be included in debug output"
# endif /* WITH_CONTIKI */
return 0;
#endif
}
#ifdef WITH_CONTIKI
# define fprintf(fd, ...) PRINTF(__VA_ARGS__)
# define fflush(...)
# ifdef HAVE_VPRINTF
# define vfprintf(fd, ...) vprintf(__VA_ARGS__)
# else /* HAVE_VPRINTF */
# define vfprintf(fd, ...) PRINTF(__VA_ARGS__)
# endif /* HAVE_VPRINTF */
#endif /* WITH_CONTIKI */
/** Returns a textual description of the message type @p t. */
static const char *
msg_type_string(uint16_t t) {
static const char *types[] = { "CON", "NON", "ACK", "RST", "???" };
return types[min(t, sizeof(types)/sizeof(char *) - 1)];
}
/** Returns a textual description of the method or response code. */
static const char *
msg_code_string(uint16_t c) {
static const char *methods[] = { "0.00", "GET", "POST", "PUT", "DELETE",
"FETCH", "PATCH", "iPATCH" };
static const char *signals[] = { "7.00", "CSM", "Ping", "Pong", "Release",
"Abort" };
static char buf[5];
if (c < sizeof(methods)/sizeof(const char *)) {
return methods[c];
} else if (c >= 224 && c - 224 < (int)(sizeof(signals)/sizeof(const char *))) {
return signals[c-224];
} else {
snprintf(buf, sizeof(buf), "%u.%02u", (c >> 5) & 0x7, c & 0x1f);
return buf;
}
}
/** Returns a textual description of the option name. */
static const char *
msg_option_string(uint8_t code, uint16_t option_type) {
struct option_desc_t {
uint16_t type;
const char *name;
};
static struct option_desc_t options[] = {
{ COAP_OPTION_IF_MATCH, "If-Match" },
{ COAP_OPTION_URI_HOST, "Uri-Host" },
{ COAP_OPTION_ETAG, "ETag" },
{ COAP_OPTION_IF_NONE_MATCH, "If-None-Match" },
{ COAP_OPTION_OBSERVE, "Observe" },
{ COAP_OPTION_URI_PORT, "Uri-Port" },
{ COAP_OPTION_LOCATION_PATH, "Location-Path" },
{ COAP_OPTION_URI_PATH, "Uri-Path" },
{ COAP_OPTION_CONTENT_FORMAT, "Content-Format" },
{ COAP_OPTION_MAXAGE, "Max-Age" },
{ COAP_OPTION_URI_QUERY, "Uri-Query" },
{ COAP_OPTION_ACCEPT, "Accept" },
{ COAP_OPTION_LOCATION_QUERY, "Location-Query" },
{ COAP_OPTION_BLOCK2, "Block2" },
{ COAP_OPTION_BLOCK1, "Block1" },
{ COAP_OPTION_PROXY_URI, "Proxy-Uri" },
{ COAP_OPTION_PROXY_SCHEME, "Proxy-Scheme" },
{ COAP_OPTION_SIZE1, "Size1" },
{ COAP_OPTION_SIZE2, "Size2" },
{ COAP_OPTION_NORESPONSE, "No-Response" }
};
static struct option_desc_t options_csm[] = {
{ COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE, "Max-Message-Size" },
{ COAP_SIGNALING_OPTION_BLOCK_WISE_TRANSFER, "Block-wise-Transfer" }
};
static struct option_desc_t options_pingpong[] = {
{ COAP_SIGNALING_OPTION_CUSTODY, "Custody" }
};
static struct option_desc_t options_release[] = {
{ COAP_SIGNALING_OPTION_ALTERNATIVE_ADDRESS, "Alternative-Address" },
{ COAP_SIGNALING_OPTION_HOLD_OFF, "Hold-Off" }
};
static struct option_desc_t options_abort[] = {
{ COAP_SIGNALING_OPTION_BAD_CSM_OPTION, "Bad-CSM-Option" }
};
static char buf[6];
size_t i;
if (code == COAP_SIGNALING_CSM) {
for (i = 0; i < sizeof(options_csm)/sizeof(struct option_desc_t); i++) {
if (option_type == options_csm[i].type) {
return options_csm[i].name;
}
}
} else if (code == COAP_SIGNALING_PING || code == COAP_SIGNALING_PONG) {
for (i = 0; i < sizeof(options_pingpong)/sizeof(struct option_desc_t); i++) {
if (option_type == options_pingpong[i].type) {
return options_pingpong[i].name;
}
}
} else if (code == COAP_SIGNALING_RELEASE) {
for (i = 0; i < sizeof(options_release)/sizeof(struct option_desc_t); i++) {
if (option_type == options_release[i].type) {
return options_release[i].name;
}
}
} else if (code == COAP_SIGNALING_ABORT) {
for (i = 0; i < sizeof(options_abort)/sizeof(struct option_desc_t); i++) {
if (option_type == options_abort[i].type) {
return options_abort[i].name;
}
}
} else {
/* search option_type in list of known options */
for (i = 0; i < sizeof(options)/sizeof(struct option_desc_t); i++) {
if (option_type == options[i].type) {
return options[i].name;
}
}
}
/* unknown option type, just print to buf */
snprintf(buf, sizeof(buf), "%u", option_type);
return buf;
}
static unsigned int
print_content_format(unsigned int format_type,
unsigned char *result, unsigned int buflen) {
struct desc_t {
unsigned int type;
const char *name;
};
static struct desc_t formats[] = {
{ COAP_MEDIATYPE_TEXT_PLAIN, "text/plain" },
{ COAP_MEDIATYPE_APPLICATION_LINK_FORMAT, "application/link-format" },
{ COAP_MEDIATYPE_APPLICATION_XML, "application/xml" },
{ COAP_MEDIATYPE_APPLICATION_OCTET_STREAM, "application/octet-stream" },
{ COAP_MEDIATYPE_APPLICATION_EXI, "application/exi" },
{ COAP_MEDIATYPE_APPLICATION_JSON, "application/json" },
{ COAP_MEDIATYPE_APPLICATION_CBOR, "application/cbor" },
{ COAP_MEDIATYPE_APPLICATION_COSE_SIGN, "application/cose; cose-type=\"cose-sign\"" },
{ COAP_MEDIATYPE_APPLICATION_COSE_SIGN1, "application/cose; cose-type=\"cose-sign1\"" },
{ COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT, "application/cose; cose-type=\"cose-encrypt\"" },
{ COAP_MEDIATYPE_APPLICATION_COSE_ENCRYPT0, "application/cose; cose-type=\"cose-encrypt0\"" },
{ COAP_MEDIATYPE_APPLICATION_COSE_MAC, "application/cose; cose-type=\"cose-mac\"" },
{ COAP_MEDIATYPE_APPLICATION_COSE_MAC0, "application/cose; cose-type=\"cose-mac0\"" },
{ COAP_MEDIATYPE_APPLICATION_COSE_KEY, "application/cose-key" },
{ COAP_MEDIATYPE_APPLICATION_COSE_KEY_SET, "application/cose-key-set" },
{ COAP_MEDIATYPE_APPLICATION_SENML_JSON, "application/senml+json" },
{ COAP_MEDIATYPE_APPLICATION_SENSML_JSON, "application/sensml+json" },
{ COAP_MEDIATYPE_APPLICATION_SENML_CBOR, "application/senml+cbor" },
{ COAP_MEDIATYPE_APPLICATION_SENSML_CBOR, "application/sensml+cbor" },
{ COAP_MEDIATYPE_APPLICATION_SENML_EXI, "application/senml-exi" },
{ COAP_MEDIATYPE_APPLICATION_SENSML_EXI, "application/sensml-exi" },
{ COAP_MEDIATYPE_APPLICATION_SENML_XML, "application/senml+xml" },
{ COAP_MEDIATYPE_APPLICATION_SENSML_XML, "application/sensml+xml" },
{ 75, "application/dcaf+cbor" }
};
size_t i;
/* search format_type in list of known content formats */
for (i = 0; i < sizeof(formats)/sizeof(struct desc_t); i++) {
if (format_type == formats[i].type) {
return snprintf((char *)result, buflen, "%s", formats[i].name);
}
}
/* unknown content format, just print numeric value to buf */
return snprintf((char *)result, buflen, "%d", format_type);
}
/**
* Returns 1 if the given @p content_format is either unknown or known
* to carry binary data. The return value @c 0 hence indicates
* printable data which is also assumed if @p content_format is @c 01.
*/
COAP_STATIC_INLINE int
is_binary(int content_format) {
return !(content_format == -1 ||
content_format == COAP_MEDIATYPE_TEXT_PLAIN ||
content_format == COAP_MEDIATYPE_APPLICATION_LINK_FORMAT ||
content_format == COAP_MEDIATYPE_APPLICATION_XML ||
content_format == COAP_MEDIATYPE_APPLICATION_JSON);
}
#define COAP_DO_SHOW_OUTPUT_LINE \
do { \
if (use_fprintf_for_show_pdu) { \
fprintf(COAP_DEBUG_FD, "%s", outbuf); \
} \
else { \
coap_log(level, "%s", outbuf); \
} \
} while (0)
void
coap_show_pdu(coap_log_t level, const coap_pdu_t *pdu) {
#if COAP_CONSTRAINED_STACK
static coap_mutex_t static_show_pdu_mutex = COAP_MUTEX_INITIALIZER;
static unsigned char buf[1024]; /* need some space for output creation */
static char outbuf[COAP_DEBUG_BUF_SIZE];
#else /* ! COAP_CONSTRAINED_STACK */
unsigned char buf[1024]; /* need some space for output creation */
char outbuf[COAP_DEBUG_BUF_SIZE];
#endif /* ! COAP_CONSTRAINED_STACK */
size_t buf_len = 0; /* takes the number of bytes written to buf */
int encode = 0, have_options = 0, i;
coap_opt_iterator_t opt_iter;
coap_opt_t *option;
int content_format = -1;
size_t data_len;
unsigned char *data;
int outbuflen = 0;
/* Save time if not needed */
if (level > coap_get_log_level())
return;
#if COAP_CONSTRAINED_STACK
coap_mutex_lock(&static_show_pdu_mutex);
#endif /* COAP_CONSTRAINED_STACK */
snprintf(outbuf, sizeof(outbuf), "v:%d t:%s c:%s i:%04x {",
COAP_DEFAULT_VERSION, msg_type_string(pdu->type),
msg_code_string(pdu->code), pdu->tid);
for (i = 0; i < pdu->token_length; i++) {
outbuflen = strlen(outbuf);
snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
"%02x", pdu->token[i]);
}
outbuflen = strlen(outbuf);
snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, "}");
/* show options, if any */
coap_option_iterator_init(pdu, &opt_iter, COAP_OPT_ALL);
outbuflen = strlen(outbuf);
snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, " [");
while ((option = coap_option_next(&opt_iter))) {
if (!have_options) {
have_options = 1;
} else {
outbuflen = strlen(outbuf);
snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, ",");
}
if (pdu->code == COAP_SIGNALING_CSM) switch(opt_iter.type) {
case COAP_SIGNALING_OPTION_MAX_MESSAGE_SIZE:
buf_len = snprintf((char *)buf, sizeof(buf), "%u",
coap_decode_var_bytes(coap_opt_value(option),
coap_opt_length(option)));
break;
default:
buf_len = 0;
break;
} else if (pdu->code == COAP_SIGNALING_PING
|| pdu->code == COAP_SIGNALING_PONG) {
buf_len = 0;
} else if (pdu->code == COAP_SIGNALING_RELEASE) switch(opt_iter.type) {
case COAP_SIGNALING_OPTION_ALTERNATIVE_ADDRESS:
buf_len = print_readable(coap_opt_value(option),
coap_opt_length(option),
buf, sizeof(buf), 0);
break;
case COAP_SIGNALING_OPTION_HOLD_OFF:
buf_len = snprintf((char *)buf, sizeof(buf), "%u",
coap_decode_var_bytes(coap_opt_value(option),
coap_opt_length(option)));
break;
default:
buf_len = 0;
break;
} else if (pdu->code == COAP_SIGNALING_ABORT) switch(opt_iter.type) {
case COAP_SIGNALING_OPTION_BAD_CSM_OPTION:
buf_len = snprintf((char *)buf, sizeof(buf), "%u",
coap_decode_var_bytes(coap_opt_value(option),
coap_opt_length(option)));
break;
default:
buf_len = 0;
break;
} else switch (opt_iter.type) {
case COAP_OPTION_CONTENT_FORMAT:
content_format = (int)coap_decode_var_bytes(coap_opt_value(option),
coap_opt_length(option));
buf_len = print_content_format(content_format, buf, sizeof(buf));
break;
case COAP_OPTION_BLOCK1:
case COAP_OPTION_BLOCK2:
/* split block option into number/more/size where more is the
* letter M if set, the _ otherwise */
buf_len = snprintf((char *)buf, sizeof(buf), "%u/%c/%u",
coap_opt_block_num(option), /* block number */
COAP_OPT_BLOCK_MORE(option) ? 'M' : '_', /* M bit */
(1 << (COAP_OPT_BLOCK_SZX(option) + 4))); /* block size */
break;
case COAP_OPTION_URI_PORT:
case COAP_OPTION_MAXAGE:
case COAP_OPTION_OBSERVE:
case COAP_OPTION_SIZE1:
case COAP_OPTION_SIZE2:
/* show values as unsigned decimal value */
buf_len = snprintf((char *)buf, sizeof(buf), "%u",
coap_decode_var_bytes(coap_opt_value(option),
coap_opt_length(option)));
break;
default:
/* generic output function for all other option types */
if (opt_iter.type == COAP_OPTION_URI_PATH ||
opt_iter.type == COAP_OPTION_PROXY_URI ||
opt_iter.type == COAP_OPTION_URI_HOST ||
opt_iter.type == COAP_OPTION_LOCATION_PATH ||
opt_iter.type == COAP_OPTION_LOCATION_QUERY ||
opt_iter.type == COAP_OPTION_URI_QUERY) {
encode = 0;
} else {
encode = 1;
}
buf_len = print_readable(coap_opt_value(option),
coap_opt_length(option),
buf, sizeof(buf), encode);
}
outbuflen = strlen(outbuf);
snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
" %s:%.*s", msg_option_string(pdu->code, opt_iter.type),
(int)buf_len, buf);
}
outbuflen = strlen(outbuf);
snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, " ]");
if (coap_get_data(pdu, &data_len, &data)) {
outbuflen = strlen(outbuf);
snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, " :: ");
if (is_binary(content_format)) {
int keep_data_len = data_len;
uint8_t *keep_data = data;
outbuflen = strlen(outbuf);
snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
"binary data length %zu\n", data_len);
COAP_DO_SHOW_OUTPUT_LINE;
/*
* Output hex dump of binary data as a continuous entry
*/
outbuf[0] = '\000';
snprintf(outbuf, sizeof(outbuf), "<<");
while (data_len--) {
outbuflen = strlen(outbuf);
snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
"%02x", *data++);
}
outbuflen = strlen(outbuf);
snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, ">>");
data_len = keep_data_len;
data = keep_data;
outbuflen = strlen(outbuf);
snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, "\n");
COAP_DO_SHOW_OUTPUT_LINE;
/*
* Output ascii readable (if possible), immediately under the
* hex value of the character output above to help binary debugging
*/
outbuf[0] = '\000';
snprintf(outbuf, sizeof(outbuf), "<<");
while (data_len--) {
outbuflen = strlen(outbuf);
snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen,
"%c ", isprint (*data) ? *data : '.');
data++;
}
outbuflen = strlen(outbuf);
snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, ">>");
} else {
if (print_readable(data, data_len, buf, sizeof(buf), 0)) {
outbuflen = strlen(outbuf);
snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, "'%s'", buf);
}
}
}
outbuflen = strlen(outbuf);
snprintf(&outbuf[outbuflen], sizeof(outbuf)-outbuflen, "\n");
COAP_DO_SHOW_OUTPUT_LINE;
#if COAP_CONSTRAINED_STACK
coap_mutex_unlock(&static_show_pdu_mutex);
#endif /* COAP_CONSTRAINED_STACK */
}
void coap_show_tls_version(coap_log_t level)
{
char buffer[64];
coap_string_tls_version(buffer, sizeof(buffer));
coap_log(level, "%s\n", buffer);
}
char *coap_string_tls_version(char *buffer, size_t bufsize)
{
coap_tls_version_t *tls_version = coap_get_tls_library_version();
char beta[8];
char sub[2];
char b_beta[8];
char b_sub[2];
switch (tls_version->type) {
case COAP_TLS_LIBRARY_NOTLS:
snprintf(buffer, bufsize, "TLS Library: None");
break;
case COAP_TLS_LIBRARY_TINYDTLS:
snprintf(buffer, bufsize, "TLS Library: TinyDTLS - runtime %lu.%lu.%lu, "
"libcoap built for %lu.%lu.%lu",
(unsigned long)(tls_version->version >> 16),
(unsigned long)((tls_version->version >> 8) & 0xff),
(unsigned long)(tls_version->version & 0xff),
(unsigned long)(tls_version->built_version >> 16),
(unsigned long)((tls_version->built_version >> 8) & 0xff),
(unsigned long)(tls_version->built_version & 0xff));
break;
case COAP_TLS_LIBRARY_OPENSSL:
switch (tls_version->version &0xf) {
case 0:
strcpy(beta, "-dev");
break;
case 0xf:
strcpy(beta, "");
break;
default:
strcpy(beta, "-beta");
beta[5] = (tls_version->version &0xf) + '0';
beta[6] = '\000';
break;
}
sub[0] = ((tls_version->version >> 4) & 0xff) ?
((tls_version->version >> 4) & 0xff) + 'a' -1 : '\000';
sub[1] = '\000';
switch (tls_version->built_version &0xf) {
case 0:
strcpy(b_beta, "-dev");
break;
case 0xf:
strcpy(b_beta, "");
break;
default:
strcpy(b_beta, "-beta");
b_beta[5] = (tls_version->built_version &0xf) + '0';
b_beta[6] = '\000';
break;
}
b_sub[0] = ((tls_version->built_version >> 4) & 0xff) ?
((tls_version->built_version >> 4) & 0xff) + 'a' -1 : '\000';
b_sub[1] = '\000';
snprintf(buffer, bufsize, "TLS Library: OpenSSL - runtime "
"%lu.%lu.%lu%s%s, libcoap built for %lu.%lu.%lu%s%s",
(unsigned long)(tls_version->version >> 28),
(unsigned long)((tls_version->version >> 20) & 0xff),
(unsigned long)((tls_version->version >> 12) & 0xff), sub, beta,
(unsigned long)(tls_version->built_version >> 28),
(unsigned long)((tls_version->built_version >> 20) & 0xff),
(unsigned long)((tls_version->built_version >> 12) & 0xff),
b_sub, b_beta);
break;
case COAP_TLS_LIBRARY_GNUTLS:
snprintf(buffer, bufsize, "TLS Library: GnuTLS - runtime %lu.%lu.%lu, "
"libcoap built for %lu.%lu.%lu",
(unsigned long)(tls_version->version >> 16),
(unsigned long)((tls_version->version >> 8) & 0xff),
(unsigned long)(tls_version->version & 0xff),
(unsigned long)(tls_version->built_version >> 16),
(unsigned long)((tls_version->built_version >> 8) & 0xff),
(unsigned long)(tls_version->built_version & 0xff));
break;
case COAP_TLS_LIBRARY_MBEDTLS:
snprintf(buffer, bufsize, "TLS Library: MbedTLS - runtime %lu.%lu.%lu, "
"libcoap built for %lu.%lu.%lu",
(unsigned long)(tls_version->version >> 24),
(unsigned long)((tls_version->version >> 16) & 0xff),
(unsigned long)((tls_version->version >> 8) & 0xff),
(unsigned long)(tls_version->built_version >> 24),
(unsigned long)((tls_version->built_version >> 16) & 0xff),
(unsigned long)((tls_version->built_version >> 8) & 0xff));
break;
default:
snprintf(buffer, bufsize, "Library type %d unknown", tls_version->type);
break;
}
return buffer;
}
static coap_log_handler_t log_handler = NULL;
void coap_set_log_handler(coap_log_handler_t handler) {
log_handler = handler;
}
void
coap_log_impl(coap_log_t level, const char *format, ...) {
if (maxlog < level)
return;
if (log_handler) {
#if COAP_CONSTRAINED_STACK
static coap_mutex_t static_log_mutex = COAP_MUTEX_INITIALIZER;
static char message[COAP_DEBUG_BUF_SIZE];
#else /* ! COAP_CONSTRAINED_STACK */
char message[COAP_DEBUG_BUF_SIZE];
#endif /* ! COAP_CONSTRAINED_STACK */
va_list ap;
va_start(ap, format);
#if COAP_CONSTRAINED_STACK
coap_mutex_lock(&static_log_mutex);
#endif /* COAP_CONSTRAINED_STACK */
vsnprintf( message, sizeof(message), format, ap);
va_end(ap);
log_handler(level, message);
#if COAP_CONSTRAINED_STACK
coap_mutex_unlock(&static_log_mutex);
#endif /* COAP_CONSTRAINED_STACK */
} else {
char timebuf[32];
coap_tick_t now;
va_list ap;
FILE *log_fd;
log_fd = level <= LOG_CRIT ? COAP_ERR_FD : COAP_DEBUG_FD;
coap_ticks(&now);
if (print_timestamp(timebuf,sizeof(timebuf), now))
fprintf(log_fd, "%s ", timebuf);
if (level <= LOG_DEBUG)
fprintf(log_fd, "%s ", loglevels[level]);
va_start(ap, format);
vfprintf(log_fd, format, ap);
va_end(ap);
fflush(log_fd);
}
}
static struct packet_num_interval {
int start;
int end;
} packet_loss_intervals[10];
static int num_packet_loss_intervals = 0;
static int packet_loss_level = 0;
static int send_packet_count = 0;
int coap_debug_set_packet_loss(const char *loss_level) {
const char *p = loss_level;
char *end = NULL;
int n = (int)strtol(p, &end, 10), i = 0;
if (end == p || n < 0)
return 0;
if (*end == '%') {
if (n > 100)
n = 100;
packet_loss_level = n * 65536 / 100;
coap_log(LOG_DEBUG, "packet loss level set to %d%%\n", n);
} else {
if (n <= 0)
return 0;
while (i < 10) {
packet_loss_intervals[i].start = n;
if (*end == '-') {
p = end + 1;
n = (int)strtol(p, &end, 10);
if (end == p || n <= 0)
return 0;
}
packet_loss_intervals[i++].end = n;
if (*end == 0)
break;
if (*end != ',')
return 0;
p = end + 1;
n = (int)strtol(p, &end, 10);
if (end == p || n <= 0)
return 0;
}
if (i == 10)
return 0;
num_packet_loss_intervals = i;
}
send_packet_count = 0;
return 1;
}
int coap_debug_send_packet(void) {
++send_packet_count;
if (num_packet_loss_intervals > 0) {
int i;
for (i = 0; i < num_packet_loss_intervals; i++) {
if (send_packet_count >= packet_loss_intervals[i].start
&& send_packet_count <= packet_loss_intervals[i].end)
return 0;
}
}
if ( packet_loss_level > 0 ) {
uint16_t r = 0;
prng( (uint8_t*)&r, 2 );
if ( r < packet_loss_level )
return 0;
}
return 1;
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,631 @@
/*
* coap_dtls.h -- (Datagram) Transport Layer Support for libcoap
*
* Copyright (C) 2016 Olaf Bergmann <bergmann@tzi.org>
* Copyright (C) 2017 Jean-Claude Michelou <jcm@spinetix.com>
*
* This file is part of the CoAP library libcoap. Please see README for terms
* of use.
*/
#ifndef COAP_DTLS_H_
#define COAP_DTLS_H_
#include "coap_time.h"
#include "str.h"
struct coap_context_t;
struct coap_session_t;
struct coap_dtls_pki_t;
/**
* @defgroup dtls DTLS Support
* API functions for interfacing with DTLS libraries.
* @{
*/
/**
* Check whether DTLS is available.
*
* @return @c 1 if support for DTLS is enabled, or @c 0 otherwise.
*/
int coap_dtls_is_supported(void);
/**
* Check whether TLS is available.
*
* @return @c 1 if support for TLS is enabled, or @c 0 otherwise.
*/
int coap_tls_is_supported(void);
typedef enum coap_tls_library_t {
COAP_TLS_LIBRARY_NOTLS = 0, /**< No DTLS library */
COAP_TLS_LIBRARY_TINYDTLS, /**< Using TinyDTLS library */
COAP_TLS_LIBRARY_OPENSSL, /**< Using OpenSSL library */
COAP_TLS_LIBRARY_GNUTLS, /**< Using GnuTLS library */
COAP_TLS_LIBRARY_MBEDTLS, /**< Using MbedTLS library */
} coap_tls_library_t;
/**
* The structure used for returning the underlying (D)TLS library
* information.
*/
typedef struct coap_tls_version_t {
uint64_t version; /**< (D)TLS runtime Library Version */
coap_tls_library_t type; /**< Library type. One of COAP_TLS_LIBRARY_* */
uint64_t built_version; /**< (D)TLS Built against Library Version */
} coap_tls_version_t;
/**
* Determine the type and version of the underlying (D)TLS library.
*
* @return The version and type of library libcoap was compiled against.
*/
coap_tls_version_t *coap_get_tls_library_version(void);
/**
* Additional Security setup handler that can be set up by
* coap_context_set_pki().
* Invoked when libcoap has done the validation checks at the TLS level,
* but the application needs to do some additional checks/changes/updates.
*
* @param tls_session The security session definition - e.g. SSL * for OpenSSL.
* NULL if server call-back.
* This will be dependent on the underlying TLS library -
* see coap_get_tls_library_version()
* @param setup_data A structure containing setup data originally passed into
* coap_context_set_pki() or coap_new_client_session_pki().
*
* @return @c 1 if successful, else @c 0.
*/
typedef int (*coap_dtls_security_setup_t)(void* tls_session,
struct coap_dtls_pki_t *setup_data);
/**
* CN Validation call-back that can be set up by coap_context_set_pki().
* Invoked when libcoap has done the validation checks at the TLS level,
* but the application needs to check that the CN is allowed.
* CN is the SubjectAltName in the cert, if not present, then the leftmost
* Common Name (CN) component of the subject name.
*
* @param cn The determined CN from the certificate
* @param asn1_public_cert The ASN.1 DER encoded X.509 certificate
* @param asn1_length The ASN.1 length
* @param coap_session The CoAP session associated with the certificate update
* @param depth Depth in cert chain. If 0, then client cert, else a CA
* @param validated TLS layer can find no issues if 1
* @param arg The same as was passed into coap_context_set_pki()
* in setup_data->cn_call_back_arg
*
* @return @c 1 if accepted, else @c 0 if to be rejected.
*/
typedef int (*coap_dtls_cn_callback_t)(const char *cn,
const uint8_t *asn1_public_cert,
size_t asn1_length,
struct coap_session_t *coap_session,
unsigned depth,
int validated,
void *arg);
/**
* The enum used for determining the provided PKI ASN.1 (DER) Private Key
* formats.
*/
typedef enum coap_asn1_privatekey_type_t {
COAP_ASN1_PKEY_NONE, /**< NONE */
COAP_ASN1_PKEY_RSA, /**< RSA type */
COAP_ASN1_PKEY_RSA2, /**< RSA2 type */
COAP_ASN1_PKEY_DSA, /**< DSA type */
COAP_ASN1_PKEY_DSA1, /**< DSA1 type */
COAP_ASN1_PKEY_DSA2, /**< DSA2 type */
COAP_ASN1_PKEY_DSA3, /**< DSA3 type */
COAP_ASN1_PKEY_DSA4, /**< DSA4 type */
COAP_ASN1_PKEY_DH, /**< DH type */
COAP_ASN1_PKEY_DHX, /**< DHX type */
COAP_ASN1_PKEY_EC, /**< EC type */
COAP_ASN1_PKEY_HMAC, /**< HMAC type */
COAP_ASN1_PKEY_CMAC, /**< CMAC type */
COAP_ASN1_PKEY_TLS1_PRF, /**< TLS1_PRF type */
COAP_ASN1_PKEY_HKDF /**< HKDF type */
} coap_asn1_privatekey_type_t;
/**
* The enum used for determining the PKI key formats.
*/
typedef enum coap_pki_key_t {
COAP_PKI_KEY_PEM = 0, /**< The PKI key type is PEM file */
COAP_PKI_KEY_ASN1, /**< The PKI key type is ASN.1 (DER) */
COAP_PKI_KEY_PEM_BUF, /**< The PKI key type is PEM buffer */
} coap_pki_key_t;
/**
* The structure that holds the PKI PEM definitions.
*/
typedef struct coap_pki_key_pem_t {
const char *ca_file; /**< File location of Common CA in PEM format */
const char *public_cert; /**< File location of Public Cert in PEM format */
const char *private_key; /**< File location of Private Key in PEM format */
} coap_pki_key_pem_t;
/**
* The structure that holds the PKI PEM buffer definitions.
*/
typedef struct coap_pki_key_pem_buf_t {
const uint8_t *ca_cert; /**< PEM buffer Common CA Cert */
const uint8_t *public_cert; /**< PEM buffer Public Cert */
const uint8_t *private_key; /**< PEM buffer Private Key */
size_t ca_cert_len; /**< PEM buffer CA Cert length */
size_t public_cert_len; /**< PEM buffer Public Cert length */
size_t private_key_len; /**< PEM buffer Private Key length */
} coap_pki_key_pem_buf_t;
/**
* The structure that holds the PKI ASN.1 (DER) definitions.
*/
typedef struct coap_pki_key_asn1_t {
const uint8_t *ca_cert; /**< ASN1 (DER) Common CA Cert */
const uint8_t *public_cert; /**< ASN1 (DER) Public Cert */
const uint8_t *private_key; /**< ASN1 (DER) Private Key */
size_t ca_cert_len; /**< ASN1 CA Cert length */
size_t public_cert_len; /**< ASN1 Public Cert length */
size_t private_key_len; /**< ASN1 Private Key length */
coap_asn1_privatekey_type_t private_key_type; /**< Private Key Type */
} coap_pki_key_asn1_t;
/**
* The structure that holds the PKI key information.
*/
typedef struct coap_dtls_key_t {
coap_pki_key_t key_type; /**< key format type */
union {
coap_pki_key_pem_t pem; /**< for PEM file keys */
coap_pki_key_pem_buf_t pem_buf; /**< for PEM memory keys */
coap_pki_key_asn1_t asn1; /**< for ASN.1 (DER) file keys */
} key;
} coap_dtls_key_t;
/**
* Server Name Indication (SNI) Validation call-back that can be set up by
* coap_context_set_pki().
* Invoked if the SNI is not previously seen and prior to sending a certificate
* set back to the client so that the appropriate certificate set can be used
* based on the requesting SNI.
*
* @param sni The requested SNI
* @param arg The same as was passed into coap_context_set_pki()
* in setup_data->sni_call_back_arg
*
* @return New set of certificates to use, or @c NULL if SNI is to be rejected.
*/
typedef coap_dtls_key_t *(*coap_dtls_sni_callback_t)(const char *sni,
void* arg);
#define COAP_DTLS_PKI_SETUP_VERSION 1 /**< Latest PKI setup version */
/**
* The structure used for defining the PKI setup data to be used.
*/
typedef struct coap_dtls_pki_t {
uint8_t version; /** Set to 1 to support this version of the struct */
/* Options to enable different TLS functionality in libcoap */
uint8_t verify_peer_cert; /**< 1 if peer cert is to be verified */
uint8_t require_peer_cert; /**< 1 if peer cert is required */
uint8_t allow_self_signed; /**< 1 if self signed certs are allowed */
uint8_t allow_expired_certs; /**< 1 if expired certs are allowed */
uint8_t cert_chain_validation; /**< 1 if to check cert_chain_verify_depth */
uint8_t cert_chain_verify_depth; /**< recommended depth is 3 */
uint8_t check_cert_revocation; /**< 1 if revocation checks wanted */
uint8_t allow_no_crl; /**< 1 ignore if CRL not there */
uint8_t allow_expired_crl; /**< 1 if expired crl is allowed */
uint8_t allow_bad_md_hash; /**< 1 if expired certs are allowed */
uint8_t allow_short_rsa_length; /**< 1 if expired certs are allowed */
uint8_t reserved[4]; /**< Reserved - must be set to 0 for
future compatibility */
/* Size of 4 chosen to align to next
* parameter, so if newly defined option
* it can use one of the reserverd slot so
* no need to change
* COAP_DTLS_PKI_SETUP_VERSION and just
* decrement the reserved[] count.
*/
/** CN check call-back function.
* If not NULL, is called when the TLS connection has passed the configured
* TLS options above for the application to verify if the CN is valid.
*/
coap_dtls_cn_callback_t validate_cn_call_back;
void *cn_call_back_arg; /**< Passed in to the CN call-back function */
/** SNI check call-back function.
* If not @p NULL, called if the SNI is not previously seen and prior to
* sending a certificate set back to the client so that the appropriate
* certificate set can be used based on the requesting SNI.
*/
coap_dtls_sni_callback_t validate_sni_call_back;
void *sni_call_back_arg; /**< Passed in to the sni call-back function */
/** Additional Security call-back handler that is invoked when libcoap has
* done the standerd, defined validation checks at the TLS level,
* If not @p NULL, called from within the TLS Client Hello connection
* setup.
*/
coap_dtls_security_setup_t additional_tls_setup_call_back;
char* client_sni; /**< If not NULL, SNI to use in client TLS setup.
Owned by the client app and must remain valid
during the call to coap_new_client_session_pki() */
coap_dtls_key_t pki_key; /**< PKI key definition */
} coap_dtls_pki_t;
/** @} */
/**
* @defgroup dtls_internal DTLS Support (Internal)
* Internal API functions for interfacing with DTLS libraries.
* @{
*/
/**
* Creates a new DTLS context for the given @p coap_context. This function
* returns a pointer to a new DTLS context object or @c NULL on error.
*
* Internal function.
*
* @param coap_context The CoAP context where the DTLS object shall be used.
*
* @return A DTLS context object or @c NULL on error.
*/
void *
coap_dtls_new_context(struct coap_context_t *coap_context);
typedef enum coap_dtls_role_t {
COAP_DTLS_ROLE_CLIENT, /**< Internal function invoked for client */
COAP_DTLS_ROLE_SERVER /**< Internal function invoked for server */
} coap_dtls_role_t;
/**
* Set the DTLS context's default PSK information.
* This does the PSK specifics following coap_dtls_new_context().
* If @p COAP_DTLS_ROLE_SERVER, then identity hint will also get set.
* If @p COAP_DTLS_ROLE_SERVER, then the information will get put into the
* TLS library's context (from which sessions are derived).
* If @p COAP_DTLS_ROLE_CLIENT, then the information will get put into the
* TLS library's session.
*
* Internal function.
*
* @param coap_context The CoAP context.
* @param identity_hint The default PSK server identity hint sent to a client.
* Required parameter. If @p NULL, will be set to "".
* Empty string is a valid hint.
* This parameter is ignored if COAP_DTLS_ROLE_CLIENT
* @param role One of @p COAP_DTLS_ROLE_CLIENT or @p COAP_DTLS_ROLE_SERVER
*
* @return @c 1 if successful, else @c 0.
*/
int
coap_dtls_context_set_psk(struct coap_context_t *coap_context,
const char *identity_hint,
coap_dtls_role_t role);
/**
* Set the DTLS context's default server PKI information.
* This does the PKI specifics following coap_dtls_new_context().
* If @p COAP_DTLS_ROLE_SERVER, then the information will get put into the
* TLS library's context (from which sessions are derived).
* If @p COAP_DTLS_ROLE_CLIENT, then the information will get put into the
* TLS library's session.
*
* Internal function.
*
* @param coap_context The CoAP context.
* @param setup_data Setup information defining how PKI is to be setup.
* Required parameter. If @p NULL, PKI will not be
* set up.
* @param role One of @p COAP_DTLS_ROLE_CLIENT or @p COAP_DTLS_ROLE_SERVER
*
* @return @c 1 if successful, else @c 0.
*/
int
coap_dtls_context_set_pki(struct coap_context_t *coap_context,
coap_dtls_pki_t *setup_data,
coap_dtls_role_t role);
/**
* Set the dtls context's default Root CA information for a client or server.
*
* Internal function.
*
* @param coap_context The current coap_context_t object.
* @param ca_file If not @p NULL, is the full path name of a PEM encoded
* file containing all the Root CAs to be used.
* @param ca_dir If not @p NULL, points to a directory containing PEM
* encoded files containing all the Root CAs to be used.
*
* @return @c 1 if successful, else @c 0.
*/
int
coap_dtls_context_set_pki_root_cas(struct coap_context_t *coap_context,
const char *ca_file,
const char *ca_dir);
/**
* Check whether one of the coap_dtls_context_set_{psk|pki}() functions have
* been called.
*
* Internal function.
*
* @param coap_context The current coap_context_t object.
*
* @return @c 1 if coap_dtls_context_set_{psk|pki}() called, else @c 0.
*/
int coap_dtls_context_check_keys_enabled(struct coap_context_t *coap_context);
/**
* Releases the storage allocated for @p dtls_context.
*
* Internal function.
*
* @param dtls_context The DTLS context as returned by coap_dtls_new_context().
*/
void coap_dtls_free_context(void *dtls_context);
/**
* Create a new client-side session. This should send a HELLO to the server.
*
* Internal function.
*
* @param coap_session The CoAP session.
*
* @return Opaque handle to underlying TLS library object containing security
* parameters for the session.
*/
void *coap_dtls_new_client_session(struct coap_session_t *coap_session);
/**
* Create a new DTLS server-side session.
* Called after coap_dtls_hello() has returned @c 1, signalling that a validated
* HELLO was received from a client.
* This should send a HELLO to the server.
*
* Internal function.
*
* @param coap_session The CoAP session.
*
* @return Opaque handle to underlying TLS library object containing security
* parameters for the DTLS session.
*/
void *coap_dtls_new_server_session(struct coap_session_t *coap_session);
/**
* Terminates the DTLS session (may send an ALERT if necessary) then frees the
* underlying TLS library object containing security parameters for the session.
*
* Internal function.
*
* @param coap_session The CoAP session.
*/
void coap_dtls_free_session(struct coap_session_t *coap_session);
/**
* Notify of a change in the CoAP session's MTU, for example after
* a PMTU update.
*
* Internal function.
*
* @param coap_session The CoAP session.
*/
void coap_dtls_session_update_mtu(struct coap_session_t *coap_session);
/**
* Send data to a DTLS peer.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param data pointer to data.
* @param data_len Number of bytes to send.
*
* @return @c 0 if this would be blocking, @c -1 if there is an error or the
* number of cleartext bytes sent.
*/
int coap_dtls_send(struct coap_session_t *coap_session,
const uint8_t *data,
size_t data_len);
/**
* Check if timeout is handled per CoAP session or per CoAP context.
*
* Internal function.
*
* @return @c 1 of timeout and retransmit is per context, @c 0 if it is
* per session.
*/
int coap_dtls_is_context_timeout(void);
/**
* Do all pending retransmits and get next timeout
*
* Internal function.
*
* @param dtls_context The DTLS context.
*
* @return @c 0 if no event is pending or date of the next retransmit.
*/
coap_tick_t coap_dtls_get_context_timeout(void *dtls_context);
/**
* Get next timeout for this session.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param now The current time in ticks.
*
* @return @c 0 If no event is pending or ticks time of the next retransmit.
*/
coap_tick_t coap_dtls_get_timeout(struct coap_session_t *coap_session,
coap_tick_t now);
/**
* Handle a DTLS timeout expiration.
*
* Internal function.
*
* @param coap_session The CoAP session.
*/
void coap_dtls_handle_timeout(struct coap_session_t *coap_session);
/**
* Handling incoming data from a DTLS peer.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param data Encrypted datagram.
* @param data_len Encrypted datagram size.
*
* @return Result of coap_handle_dgram on the decrypted CoAP PDU
* or @c -1 for error.
*/
int coap_dtls_receive(struct coap_session_t *coap_session,
const uint8_t *data,
size_t data_len);
/**
* Handling client HELLO messages from a new candiate peer.
* Note that session->tls is empty.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param data Encrypted datagram.
* @param data_len Encrypted datagram size.
*
* @return @c 0 if a cookie verification message has been sent, @c 1 if the
* HELLO contains a valid cookie and a server session should be created,
* @c -1 if the message is invalid.
*/
int coap_dtls_hello(struct coap_session_t *coap_session,
const uint8_t *data,
size_t data_len);
/**
* Get DTLS overhead over cleartext PDUs.
*
* Internal function.
*
* @param coap_session The CoAP session.
*
* @return Maximum number of bytes added by DTLS layer.
*/
unsigned int coap_dtls_get_overhead(struct coap_session_t *coap_session);
/**
* Create a new TLS client-side session.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param connected Updated with whether the connection is connected yet or not.
* @c 0 is not connected, @c 1 is connected.
*
* @return Opaque handle to underlying TLS library object containing security
* parameters for the session.
*/
void *coap_tls_new_client_session(struct coap_session_t *coap_session, int *connected);
/**
* Create a TLS new server-side session.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param connected Updated with whether the connection is connected yet or not.
* @c 0 is not connected, @c 1 is connected.
*
* @return Opaque handle to underlying TLS library object containing security
* parameters for the session.
*/
void *coap_tls_new_server_session(struct coap_session_t *coap_session, int *connected);
/**
* Terminates the TLS session (may send an ALERT if necessary) then frees the
* underlying TLS library object containing security parameters for the session.
*
* Internal function.
*
* @param coap_session The CoAP session.
*/
void coap_tls_free_session( struct coap_session_t *coap_session );
/**
* Send data to a TLS peer, with implicit flush.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param data Pointer to data.
* @param data_len Number of bytes to send.
*
* @return @c 0 if this should be retried, @c -1 if there is an error
* or the number of cleartext bytes sent.
*/
ssize_t coap_tls_write(struct coap_session_t *coap_session,
const uint8_t *data,
size_t data_len
);
/**
* Read some data from a TLS peer.
*
* Internal function.
*
* @param coap_session The CoAP session.
* @param data Pointer to data.
* @param data_len Maximum number of bytes to read.
*
* @return @c 0 if this should be retried, @c -1 if there is an error
* or the number of cleartext bytes read.
*/
ssize_t coap_tls_read(struct coap_session_t *coap_session,
uint8_t *data,
size_t data_len
);
/**
* Initialize the underlying (D)TLS Library layer.
*
* Internal function.
*
*/
void coap_dtls_startup(void);
/** @} */
/**
* @ingroup logging
* Sets the (D)TLS logging level to the specified @p level.
* Note: coap_log_level() will influence output if at a specified level.
*
* @param level The logging level to use - LOG_*
*/
void coap_dtls_set_log_level(int level);
/**
* @ingroup logging
* Get the current (D)TLS logging.
*
* @return The current log level (one of LOG_*).
*/
int coap_dtls_get_log_level(void);
#endif /* COAP_DTLS_H */

View File

@ -21,18 +21,27 @@
#ifdef WITH_POSIX
#include <sys/socket.h>
#include <net/if.h>
#define HAVE_SYS_SOCKET_H
#define HAVE_MALLOC
#define HAVE_ARPA_INET_H
#define HAVE_TIME_H
#define HAVE_NETDB_H
#define HAVE_NETINET_IN_H
#define IPV6_PKTINFO IPV6_V6ONLY
#define PACKAGE_NAME "libcoap-posix"
#define PACKAGE_VERSION "?"
#define COAP_BAD_RECVMSG
#define HAVE_MBEDTLS
#define COAP_CONSTRAINED_STACK 1
#define ESPIDF_VERSION
#define _POSIX_TIMERS 1
#define gai_strerror(x) "gai_strerror() not supported"
#endif /* WITH_POSIX */
#endif /* COAP_CONFIG_POSIX_H_ */

View File

@ -25,6 +25,7 @@ target_sources(mbedtls PRIVATE "${COMPONENT_DIR}/port/esp_bignum.c"
"${COMPONENT_DIR}/port/esp_sha1.c"
"${COMPONENT_DIR}/port/esp_sha256.c"
"${COMPONENT_DIR}/port/esp_sha512.c"
"${COMPONENT_DIR}/port/esp_timing.c"
"${COMPONENT_DIR}/port/mbedtls_debug.c"
"${COMPONENT_DIR}/port/net_sockets.c"
"${COMPONENT_DIR}/port/esp32/aes.c"
@ -36,4 +37,4 @@ foreach(target ${mbedtls_targets})
endforeach()
# Link mbedtls libraries to component library
target_link_libraries(${COMPONENT_LIB} INTERFACE ${mbedtls_targets})
target_link_libraries(${COMPONENT_LIB} INTERFACE ${mbedtls_targets})

View File

@ -0,0 +1,102 @@
/*
* Portable interface to the CPU cycle counter
*
* Copyright (C) 2006-2015, ARM Limited, All Rights Reserved
* SPDX-License-Identifier: Apache-2.0
*
* 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.
*
* This file is part of mbed TLS (https://tls.mbed.org)
*/
/*
* mbedtls_timing_get_timer()m mbedtls_timing_set_delay() and
* mbedtls_timing_set_delay only abstracted from mbedtls/library/timing.c
* as that does not build on ESP-IDF but these 2 functions are needed for
* DTLS (in particular mbedtls_ssl_set_timer_cb() must be called for DTLS
* which requires these 2 delay functions).
*/
#if !defined(MBEDTLS_CONFIG_FILE)
#include "mbedtls/config.h"
#else
#include MBEDTLS_CONFIG_FILE
#endif
#if !defined(MBEDTLS_ESP_TIMING_C)
#include <sys/time.h>
#include "mbedtls/timing.h"
struct _hr_time
{
struct timeval start;
};
unsigned long mbedtls_timing_get_timer( struct mbedtls_timing_hr_time *val, int reset )
{
struct _hr_time *t = (struct _hr_time *) val;
if( reset )
{
gettimeofday( &t->start, NULL );
return( 0 );
}
else
{
unsigned long delta;
struct timeval now;
gettimeofday( &now, NULL );
delta = ( now.tv_sec - t->start.tv_sec ) * 1000ul
+ ( now.tv_usec - t->start.tv_usec ) / 1000;
return( delta );
}
}
/*
* Set delays to watch
*/
void mbedtls_timing_set_delay( void *data, uint32_t int_ms, uint32_t fin_ms )
{
mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data;
ctx->int_ms = int_ms;
ctx->fin_ms = fin_ms;
if( fin_ms != 0 )
(void) mbedtls_timing_get_timer( &ctx->timer, 1 );
}
/*
* Get number of delays expired
*/
int mbedtls_timing_get_delay( void *data )
{
mbedtls_timing_delay_context *ctx = (mbedtls_timing_delay_context *) data;
unsigned long elapsed_ms;
if( ctx->fin_ms == 0 )
return( -1 );
elapsed_ms = mbedtls_timing_get_timer( &ctx->timer, 0 );
if( elapsed_ms >= ctx->fin_ms )
return( 2 );
if( elapsed_ms >= ctx->int_ms )
return( 1 );
return( 0 );
}
#endif /* MBEDTLS_ESP_TIMING_C */

View File

@ -2,14 +2,27 @@
# CoAP client example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
this CoAP client example is adaptation of one of the [libcoap](https://github.com/obgm/libcoap) example.
This CoAP client example is very simplified adaptation of one of the
[libcoap](https://github.com/obgm/libcoap) examples.
CoAP client example would connect your ESP32 device to any CoAP server, fetch data from CoAP server and upstream data to CoAP server.
CoAP client example will connect your ESP32 device to a CoAP server, send off a GET request and
fetch the response data from CoAP server. The client can be extended to PUT / POST / DELETE requests,
as well as supporting the Observer extensions [RFC7641](https://tools.ietf.org/html/rfc7641).
The Constrained Application Protocol (CoAP) is a specialized web transfer protocol for use with constrained nodes and constrained networks in the Internet of Things.
The protocol is designed for machine-to-machine (M2M) applications such as smart energy and building automation.
If the URI is prefixed with coaps:// instead of coap://, then the CoAP client will attempt to use
the DTLS protocol using the defined Pre-Shared Keys(PSK) or Public Key Infrastructure (PKI) which the
CoAP server needs to know about.
please refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf) for more details.
If the URI is prefixed with coap+tcp://, then the CoAP will try to use TCP for the communication.
NOTE: coaps+tcp:// is not currently supported, even though both libcoap and MbedTLS support it.
The Constrained Application Protocol (CoAP) is a specialized web transfer protocol for use with
constrained nodes and constrained networks in the Internet of Things.
The protocol is designed for machine-to-machine (M2M) applications such as smart energy and
building automation.
Please refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf) for more details.
## How to use example
@ -19,16 +32,24 @@ please refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf)
idf.py menuconfig
```
* Set serial port under Serial Flasher config
* Set Target Uri under Example Configuration
* Set WiFi SSID under Example Configuration
* Set WiFi Password under Example Configuration
Example Connection Configuration --->
* Set WiFi SSID under Example Configuration
* Set WiFi Password under Example Configuration
Example CoAP Client Configuration --->
* Set CoAP Target Uri
* If PSK, Set CoAP Preshared Key to use in connection to the server
* If PSK, Set CoAP PSK Client identity (username)
Component config --->
CoAP Configuration --->
* Set encryption method definition, PSK (default) or PKI
* Enable CoAP debugging if required
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py build
idf.py -p PORT flash monitor
```
@ -72,9 +93,9 @@ published under EPL+EDL: http://www.eclipse.org/californium/
This can be found at https://libcoap.net/doc/reference/4.2.0/
## Troubleshooting
* Please make sure Target Url includes valid `host`, optional `port`, optional `path`, and begins
with `coap://` or `coap+tcp://` for a coap server that supports TCP
* Please make sure Target Url includes valid `host`, optional `port`,
optional `path`, and begins with `coap://`, `coaps://` or `coap+tcp://`
for a coap server that supports TCP
(not all do including coap+tcp://californium.eclipse.org).
* libcoap logging can be increased by changing `#define COAP_LOGGING_LEVEL 0`
to `#define COAP_LOGGING_LEVEL 9`
* CoAP logging can be enabled by running 'idf.py menuconfig -> Component config -> CoAP Configuration' and setting appropriate log level

View File

@ -1,2 +1,4 @@
# Embed CA, certificate & key directly into binary
idf_component_register(SRCS "coap_client_example_main.c"
INCLUDE_DIRS ".")
INCLUDE_DIRS "."
EMBED_TXTFILES certs/coap_ca.pem certs/coap_client.crt certs/coap_client.key)

View File

@ -1,9 +1,27 @@
menu "Example Configuration"
menu "Example CoAP Client Configuration"
config TARGET_DOMAIN_URI
config EXAMPLE_TARGET_DOMAIN_URI
string "Target Uri"
default "coap://californium.eclipse.org"
default "coaps://californium.eclipse.org"
help
Target uri for the example to use.
Target uri for the example to use. Use coaps:// prefix for encrypted traffic
using Pre-Shared Key (PSK) or Public Key Infrastructure (PKI).
config EXAMPLE_COAP_PSK_KEY
string "Preshared Key (PSK) to used in the connection to the CoAP server"
depends on COAP_MBEDTLS_PSK
default "sesame"
help
The Preshared Key to use to encrypt the communicatons. The same key must be
used at both ends of the CoAP connection, and the CoaP client must request
an URI prefixed with coaps:// instead of coap:// for DTLS to be used.
config EXAMPLE_COAP_PSK_IDENTITY
string "PSK Client identity (username)"
depends on COAP_MBEDTLS_PSK
default "password"
help
The identity (or username) to use to identify to the CoAP server which
PSK key to use.
endmenu

View File

@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID3DCCA0WgAwIBAgIJAMnlgL1czsmjMA0GCSqGSIb3DQEBCwUAMIGTMQswCQYD
VQQGEwJGUjEPMA0GA1UECAwGUmFkaXVzMRIwEAYDVQQHDAlTb21ld2hlcmUxFTAT
BgNVBAoMDEV4YW1wbGUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBs
ZS5jb20xJjAkBgNVBAMMHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4X
DTE3MDYwNzA4MDY0OVoXDTI3MDYwNTA4MDY0OVowgZMxCzAJBgNVBAYTAkZSMQ8w
DQYDVQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMGA1UECgwMRXhh
bXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLmNvbTEmMCQG
A1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwgZ8wDQYJKoZIhvcN
AQEBBQADgY0AMIGJAoGBALpWR23fn/TmHxsXsHdrydzPSd17fZkc71WsaicgQR66
1tIVYb22UWGfj9KPM8THMsV74ew4ZkaQ39qvU0iuQIRrKARFHFok+vbaecgWMeWe
vGIqdnmyB9gJYaFOKgtSkfXsu2ddsqdvLYwcDbczrq8X9yEXpN6mnxXeCcPG4F0p
AgMBAAGjggE0MIIBMDAdBgNVHQ4EFgQUgigpdAUpONoDq0pQ3yfxrslCSpcwgcgG
A1UdIwSBwDCBvYAUgigpdAUpONoDq0pQ3yfxrslCSpehgZmkgZYwgZMxCzAJBgNV
BAYTAkZSMQ8wDQYDVQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMG
A1UECgwMRXhhbXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxl
LmNvbTEmMCQGA1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCCQDJ
5YC9XM7JozAMBgNVHRMEBTADAQH/MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly93
d3cuZXhhbXBsZS5jb20vZXhhbXBsZV9jYS5jcmwwDQYJKoZIhvcNAQELBQADgYEA
euxOBPInSJRKAIseMxPmAabtAqKNslZSmpG4He3lkKt+HM3jfznUt3psmD7j1hFW
S4l7KXzzajvaGYybDq5N9MqrDjhGn3VXZqOLMUNDL7OQq96TzgqsTBT1dmVSbNlt
PQgiAeKAk3tmH4lRRi9MTBSyJ6I92JYcS5H6Bs4ZwCc=
-----END CERTIFICATE-----

View File

@ -0,0 +1,70 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 48 (0x30)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=FR, ST=Radius, L=Somewhere, O=Example Inc./emailAddress=admin@example.com, CN=Example Certificate Authority
Validity
Not Before: Jun 7 08:06:49 2017 GMT
Not After : Jun 5 08:06:49 2027 GMT
Subject: C=FR, ST=Radius, O=Example Inc., CN=user@example.com/emailAddress=user@example.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:d2:f6:be:72:a5:ab:2e:56:0c:dd:f2:3b:2c:7c:
e0:5d:05:40:af:0c:8c:f3:82:0c:d0:18:34:b4:e3:
7d:5f:8d:0a:3e:aa:79:02:f9:96:ad:10:00:ec:51:
e9:dc:3f:fb:ea:b0:57:eb:48:c7:ca:ef:e8:05:ab:
ee:3f:66:ba:5c:9e:7f:40:85:9f:25:a0:e0:e3:7c:
cf:b6:e6:31:f5:fd:24:03:c8:f4:fb:d8:a4:f3:92:
29:05:aa:55:43:80:f7:3e:13:10:43:3a:89:24:be:
d8:01:86:d1:69:73:44:7d:f8:b9:46:2b:6b:51:d0:
11:31:4b:06:ae:9f:45:fa:12:17:0c:ef:6a:fa:d0:
f7:36:46:eb:2e:db:4e:20:46:01:33:ac:b1:f7:4a:
e6:18:3d:53:22:dc:e8:4a:12:78:11:2f:e4:3b:92:
bd:d7:07:5a:c9:81:5d:48:58:c8:0f:9b:e9:a4:0f:
bb:89:b1:ad:38:07:6f:93:d0:a6:12:56:f9:07:48:
d2:23:2f:a3:a9:93:b0:11:0a:27:4c:48:0a:8d:70:
41:68:76:7a:dd:bc:54:c3:42:33:b0:7b:f6:ae:1f:
e7:95:5e:11:ca:f2:b4:4b:5c:ba:47:64:f0:f3:d7:
87:95:7f:93:06:a1:72:c9:81:12:a5:b7:8f:9d:7e:
d1:ef
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Extended Key Usage:
TLS Web Client Authentication
X509v3 CRL Distribution Points:
Full Name:
URI:http://www.example.com/example_ca.crl
Signature Algorithm: sha1WithRSAEncryption
2d:02:bc:7b:88:b8:5c:e1:07:b8:bb:ba:b2:f3:98:14:8f:cb:
b0:21:13:b5:e5:6f:05:4f:92:fa:ac:c0:53:a7:b0:cd:7e:ba:
87:36:85:25:d7:41:c5:29:84:22:74:af:bf:3e:34:36:d5:24:
7a:81:e2:1b:54:52:85:6f:76:de:dc:63:98:45:fc:2c:31:fa:
22:a4:72:3a:8d:d4:6a:2e:de:33:10:41:eb:94:1d:e3:59:cd:
b2:be:ab:f0:b6:20:86:9c:b8:46:ee:c5:64:ba:b6:6c:cc:53:
44:7a:80:12:77:7c:e7:51:67:91:32:2f:88:9d:93:a8:ef:d6:
cd:de
-----BEGIN CERTIFICATE-----
MIIDTjCCAregAwIBAgIBMDANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UEBhMCRlIx
DzANBgNVBAgMBlJhZGl1czESMBAGA1UEBwwJU29tZXdoZXJlMRUwEwYDVQQKDAxF
eGFtcGxlIEluYy4xIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUuY29tMSYw
JAYDVQQDDB1FeGFtcGxlIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNzA2MDcw
ODA2NDlaFw0yNzA2MDUwODA2NDlaMHExCzAJBgNVBAYTAkZSMQ8wDQYDVQQIDAZS
YWRpdXMxFTATBgNVBAoMDEV4YW1wbGUgSW5jLjEZMBcGA1UEAwwQdXNlckBleGFt
cGxlLmNvbTEfMB0GCSqGSIb3DQEJARYQdXNlckBleGFtcGxlLmNvbTCCASIwDQYJ
KoZIhvcNAQEBBQADggEPADCCAQoCggEBANL2vnKlqy5WDN3yOyx84F0FQK8MjPOC
DNAYNLTjfV+NCj6qeQL5lq0QAOxR6dw/++qwV+tIx8rv6AWr7j9mulyef0CFnyWg
4ON8z7bmMfX9JAPI9PvYpPOSKQWqVUOA9z4TEEM6iSS+2AGG0WlzRH34uUYra1HQ
ETFLBq6fRfoSFwzvavrQ9zZG6y7bTiBGATOssfdK5hg9UyLc6EoSeBEv5DuSvdcH
WsmBXUhYyA+b6aQPu4mxrTgHb5PQphJW+QdI0iMvo6mTsBEKJ0xICo1wQWh2et28
VMNCM7B79q4f55VeEcrytEtcukdk8PPXh5V/kwahcsmBEqW3j51+0e8CAwEAAaNP
ME0wEwYDVR0lBAwwCgYIKwYBBQUHAwIwNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDov
L3d3dy5leGFtcGxlLmNvbS9leGFtcGxlX2NhLmNybDANBgkqhkiG9w0BAQUFAAOB
gQAtArx7iLhc4Qe4u7qy85gUj8uwIRO15W8FT5L6rMBTp7DNfrqHNoUl10HFKYQi
dK+/PjQ21SR6geIbVFKFb3be3GOYRfwsMfoipHI6jdRqLt4zEEHrlB3jWc2yvqvw
tiCGnLhG7sVkurZszFNEeoASd3znUWeRMi+InZOo79bN3g==
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEA0va+cqWrLlYM3fI7LHzgXQVArwyM84IM0Bg0tON9X40KPqp5
AvmWrRAA7FHp3D/76rBX60jHyu/oBavuP2a6XJ5/QIWfJaDg43zPtuYx9f0kA8j0
+9ik85IpBapVQ4D3PhMQQzqJJL7YAYbRaXNEffi5RitrUdARMUsGrp9F+hIXDO9q
+tD3NkbrLttOIEYBM6yx90rmGD1TItzoShJ4ES/kO5K91wdayYFdSFjID5vppA+7
ibGtOAdvk9CmElb5B0jSIy+jqZOwEQonTEgKjXBBaHZ63bxUw0IzsHv2rh/nlV4R
yvK0S1y6R2Tw89eHlX+TBqFyyYESpbePnX7R7wIDAQABAoIBAQC5PncO3tBIeMEF
pu007FZq9/DLhP7D2B9+HrMxX0y4uXUUf8aQyS74ukPFP0xV3U1M0BnzfU4KscyQ
Jl+nBoKAT6C3vF15wiGXQAJ4vPuD4Ate03fjKWH2ixJAakhCZR01QbIXBnBkdrvf
401BBjlPUDcIGZo8FbLzEMlGTo84vE9v3Qmkbi+PzPCh2YC+NDmsOcIW1zpmwyYC
ZYCpoWgl4++kqXXn0NGhuaOgB0JLsJOBpx/hOOjBU/wXCKaXZ1vchYqfbvvx2gf2
WX4P0CiTH1z7MEAHanaZkcnNyxV/oF1EIMY5p0vDDzgrKtppvPOqspjydje03+CE
t0wKGPi5AoGBAPAG2Y4efgwLcoWdPjKZtsHLhDhLJnvxkqnNkzdPnLZojNi8pKkV
/Yu++pPemJZZa4YAp+OnqyEfhcha+HYqKMwRC8t3YrEVOlRQTfW/OoSrp059JIRV
jTvq/u7DdYGJRRgMLUJiEI+7xj1WbTc2EceJAgn0qfKvbvBtVJP0LH1TAoGBAOEA
xZB7SwyX+zDGRTugqMYg+sYobbQHJ7utLyoX+ckeG+sPEjEYLpQQfshET/gwF8ZK
4aILkACx/tna799xCjQdmyyc338NO9WULlY1xF+65WfeaxrtTAsqVikX3p19McRI
ijX8k7Msy3gYWJXev3MCtPT2+g68IgbL/W2wY+l1AoGAT7xGy0Jv5vpqid5pig+s
OYatHrJAT445hXUIQaiNy77Bg0JvhMgMWT8RKMwabl+4K2TOYP8TB0bcf2lQ/pgU
w22qOGYpf+AoZ1fh/hAPlYEcbCOAXQG6kDwJgjGmOGjsbgelhVbkX4smWLv8PgoV
L+7goYQIbNlAhlgbb6b+nIcCgYBB7Zr2Cdpkt0en9ACnRx0M6O7yDziNzqbqzAUM
3XeYYZUmnATlk8NaKTcs8S9JdrYQqTJR6/dm7MDTDt7IZvPpb19fhBvMu5DztPaa
1ihTMI01kStq+WsVvnL+mXrmRJ/HdsXgqcCReKep6eBTEbChP4LMYG3G0YNa4HzC
njO4XQKBgQDRnbqqg2CNTnS94BN2D3uzzELtwsIG6aVCtl09ZsLnGaBKVVDtP6BI
j2hGD7xw4g5JeSPIJU5J03nALTY3hz1JyI7AJCX7+JRtUTX2A8C4mlbeul7ilGaU
A7MFT8GqhjYYa84GzNcA1mK8ynlixpL8+yzTT/8lWInWRBa69SkktA==
-----END RSA PRIVATE KEY-----

View File

@ -7,9 +7,17 @@
CONDITIONS OF ANY KIND, either express or implied.
*/
/*
* WARNING
* libcoap is not multi-thread safe, so only this thread must make any coap_*()
* calls. Any external (to this thread) data transmitted in/out via libcoap
* therefore has to be passed in/out by xQueue*() via this thread.
*/
#include <string.h>
#include <sys/socket.h>
#include <netdb.h>
#include <sys/param.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
@ -23,20 +31,44 @@
#include "protocol_examples_common.h"
#if 1
/* Needed until coap_dtls.h becomes a part of libcoap proper */
#include "libcoap.h"
#include "coap_dtls.h"
#endif
#include "coap.h"
#define COAP_DEFAULT_TIME_SEC 5
/* Set this to 9 to get verbose logging from within libcoap */
#define COAP_LOGGING_LEVEL 0
/* The examples use simple Pre-Shared-Key configuration that you can set via
'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_COAP_PSK_KEY "some-agreed-preshared-key"
Note: PSK will only be used if the URI is prefixed with coaps://
instead of coap:// and the PSK must be one that the server supports
(potentially associated with the IDENTITY)
*/
#define EXAMPLE_COAP_PSK_KEY CONFIG_EXAMPLE_COAP_PSK_KEY
#define EXAMPLE_COAP_PSK_IDENTITY CONFIG_EXAMPLE_COAP_PSK_IDENTITY
/* The examples use uri Logging Level that
you can set via 'make menuconfig'.
If you'd rather not, just change the below entry to a value
that is between 0 and 7 with
the config you want - ie #define EXAMPLE_COAP_LOG_DEFAULT_LEVEL 7
*/
#define EXAMPLE_COAP_LOG_DEFAULT_LEVEL CONFIG_COAP_LOG_DEFAULT_LEVEL
/* The examples use uri "coap://californium.eclipse.org" that
you can set via the project configuration (idf.py menuconfig)
If you'd rather not, just change the below entries to strings with
the config you want - ie #define COAP_DEFAULT_DEMO_URI "coap://californium.eclipse.org"
the config you want - ie #define COAP_DEFAULT_DEMO_URI "coaps://californium.eclipse.org"
*/
#define COAP_DEFAULT_DEMO_URI CONFIG_TARGET_DOMAIN_URI
#define COAP_DEFAULT_DEMO_URI CONFIG_EXAMPLE_TARGET_DOMAIN_URI
const static char *TAG = "CoAP_client";
@ -44,11 +76,30 @@ static int resp_wait = 1;
static coap_optlist_t *optlist = NULL;
static int wait_ms;
#ifdef CONFIG_COAP_MBEDTLS_PKI
/* CA cert, taken from coap_ca.pem
Client cert, taken from coap_client.crt
Client key, taken from coap_client.key
The PEM, CRT and KEY file are examples taken from the wpa2 enterprise
example.
To embed it in the app binary, the PEM, CRT and KEY file is named
in the component.mk COMPONENT_EMBED_TXTFILES variable.
*/
extern uint8_t ca_pem_start[] asm("_binary_coap_ca_pem_start");
extern uint8_t ca_pem_end[] asm("_binary_coap_ca_pem_end");
extern uint8_t client_crt_start[] asm("_binary_coap_client_crt_start");
extern uint8_t client_crt_end[] asm("_binary_coap_client_crt_end");
extern uint8_t client_key_start[] asm("_binary_coap_client_key_start");
extern uint8_t client_key_end[] asm("_binary_coap_client_key_end");
#endif /* CONFIG_COAP_MBEDTLS_PKI */
static void message_handler(coap_context_t *ctx, coap_session_t *session,
coap_pdu_t *sent, coap_pdu_t *received,
const coap_tid_t id)
coap_pdu_t *sent, coap_pdu_t *received,
const coap_tid_t id)
{
unsigned char* data = NULL;
unsigned char *data = NULL;
size_t data_len;
coap_pdu_t *pdu = NULL;
coap_opt_t *block_opt;
@ -75,8 +126,8 @@ static void message_handler(coap_context_t *ctx, coap_session_t *session,
/* create pdu with request for next block */
pdu = coap_new_pdu(session);
if (!pdu) {
ESP_LOGE(TAG, "coap_new_pdu() failed");
goto clean_up;
ESP_LOGE(TAG, "coap_new_pdu() failed");
goto clean_up;
}
pdu->type = COAP_MESSAGE_CON;
pdu->tid = coap_new_message_id(session);
@ -90,7 +141,7 @@ static void message_handler(coap_context_t *ctx, coap_session_t *session,
case COAP_OPTION_URI_PATH :
case COAP_OPTION_URI_QUERY :
coap_add_option(pdu, option->number, option->length,
option->data);
option->data);
break;
default:
; /* skip other options */
@ -102,8 +153,8 @@ static void message_handler(coap_context_t *ctx, coap_session_t *session,
coap_add_option(pdu,
blktype,
coap_encode_var_safe(buf, sizeof(buf),
((coap_opt_block_num(block_opt) + 1) << 4) |
COAP_OPT_BLOCK_SZX(block_opt)), buf);
((coap_opt_block_num(block_opt) + 1) << 4) |
COAP_OPT_BLOCK_SZX(block_opt)), buf);
tid = coap_send(session, pdu);
@ -124,17 +175,34 @@ clean_up:
resp_wait = 0;
}
static void coap_example_task(void *p)
#ifdef CONFIG_COAP_MBEDTLS_PKI
static int
verify_cn_callback(const char *cn,
const uint8_t *asn1_public_cert,
size_t asn1_length,
coap_session_t *session,
unsigned depth,
int validated,
void *arg
)
{
coap_log(LOG_INFO, "CN '%s' presented by server (%s)\n",
cn, depth ? "CA" : "Certificate");
return 1;
}
#endif /* CONFIG_COAP_MBEDTLS_PKI */
static void coap_example_client(void *p)
{
struct hostent *hp;
struct ip4_addr *ip4_addr;
coap_address_t dst_addr, src_addr;
coap_address_t dst_addr;
static coap_uri_t uri;
const char* server_uri = COAP_DEFAULT_DEMO_URI;
char* phostname = NULL;
const char *server_uri = COAP_DEFAULT_DEMO_URI;
char *phostname = NULL;
coap_set_log_level(EXAMPLE_COAP_LOG_DEFAULT_LEVEL);
coap_set_log_level(COAP_LOGGING_LEVEL);
while (1) {
#define BUFSIZE 40
unsigned char _buf[BUFSIZE];
@ -151,17 +219,16 @@ static void coap_example_task(void *p)
break;
}
if ((uri.scheme==COAP_URI_SCHEME_COAPS && !coap_dtls_is_supported()) ||
(uri.scheme==COAP_URI_SCHEME_COAPS_TCP && !coap_tls_is_supported())) {
ESP_LOGE(TAG, "CoAP server uri scheme error");
if ((uri.scheme == COAP_URI_SCHEME_COAPS && !coap_dtls_is_supported()) ||
(uri.scheme == COAP_URI_SCHEME_COAPS_TCP && !coap_tls_is_supported())) {
ESP_LOGE(TAG, "CoAP server uri scheme is not supported");
break;
}
phostname = (char *)calloc(1, uri.host.length + 1);
if (phostname == NULL) {
ESP_LOGE(TAG, "calloc failed");
continue;
break;
}
memcpy(phostname, uri.host.s, uri.host.length);
@ -174,17 +241,27 @@ static void coap_example_task(void *p)
free(phostname);
continue;
}
/* Code to print the resolved IP.
Note: inet_ntoa is non-reentrant, look at ipaddr_ntoa_r for "real" code */
ip4_addr = (struct ip4_addr *)hp->h_addr;
ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", inet_ntoa(*ip4_addr));
coap_address_init(&src_addr);
src_addr.addr.sin.sin_family = AF_INET;
src_addr.addr.sin.sin_port = htons(0);
src_addr.addr.sin.sin_addr.s_addr = INADDR_ANY;
char tmpbuf[INET6_ADDRSTRLEN];
coap_address_init(&dst_addr);
switch (hp->h_addrtype) {
case AF_INET:
dst_addr.addr.sin.sin_family = AF_INET;
dst_addr.addr.sin.sin_port = htons(uri.port);
memcpy(&dst_addr.addr.sin.sin_addr, hp->h_addr, sizeof(dst_addr.addr.sin.sin_addr));
inet_ntop(AF_INET, &dst_addr.addr.sin.sin_addr, tmpbuf, sizeof(tmpbuf));
ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", tmpbuf);
break;
case AF_INET6:
dst_addr.addr.sin6.sin6_family = AF_INET6;
dst_addr.addr.sin6.sin6_port = htons(uri.port);
memcpy(&dst_addr.addr.sin6.sin6_addr, hp->h_addr, sizeof(dst_addr.addr.sin6.sin6_addr));
inet_ntop(AF_INET6, &dst_addr.addr.sin6.sin6_addr, tmpbuf, sizeof(tmpbuf));
ESP_LOGI(TAG, "DNS lookup succeeded. IP=%s", tmpbuf);
break;
default:
ESP_LOGE(TAG, "DNS lookup response failed");
goto clean_up;
}
if (uri.path.length) {
buflen = BUFSIZE;
@ -193,9 +270,9 @@ static void coap_example_task(void *p)
while (res--) {
coap_insert_optlist(&optlist,
coap_new_optlist(COAP_OPTION_URI_PATH,
coap_opt_length(buf),
coap_opt_value(buf)));
coap_new_optlist(COAP_OPTION_URI_PATH,
coap_opt_length(buf),
coap_opt_value(buf)));
buf += coap_opt_size(buf);
}
@ -208,9 +285,9 @@ static void coap_example_task(void *p)
while (res--) {
coap_insert_optlist(&optlist,
coap_new_optlist(COAP_OPTION_URI_QUERY,
coap_opt_length(buf),
coap_opt_value(buf)));
coap_new_optlist(COAP_OPTION_URI_QUERY,
coap_opt_length(buf),
coap_opt_value(buf)));
buf += coap_opt_size(buf);
}
@ -218,30 +295,97 @@ static void coap_example_task(void *p)
ctx = coap_new_context(NULL);
if (!ctx) {
ESP_LOGE(TAG, "coap_new_context() failed");
goto clean_up;
ESP_LOGE(TAG, "coap_new_context() failed");
goto clean_up;
}
coap_address_init(&dst_addr);
dst_addr.addr.sin.sin_family = AF_INET;
dst_addr.addr.sin.sin_port = htons(uri.port);
dst_addr.addr.sin.sin_addr.s_addr = ip4_addr->addr;
/*
* Note that if the URI starts with just coap:// (not coaps://) the
* session will still be plain text.
*
* coaps+tcp:// is NOT supported by the libcoap->mbedtls interface
* so COAP_URI_SCHEME_COAPS_TCP will have failed in a test above,
* but the code is left in for completeness.
*/
if (uri.scheme == COAP_URI_SCHEME_COAPS || uri.scheme == COAP_URI_SCHEME_COAPS_TCP) {
#ifdef CONFIG_COAP_MBEDTLS_PSK
session = coap_new_client_session_psk(ctx, NULL, &dst_addr,
uri.scheme == COAP_URI_SCHEME_COAPS ? COAP_PROTO_DTLS : COAP_PROTO_TLS,
EXAMPLE_COAP_PSK_IDENTITY,
(const uint8_t *)EXAMPLE_COAP_PSK_KEY,
sizeof(EXAMPLE_COAP_PSK_KEY) - 1);
#endif /* CONFIG_COAP_MBEDTLS_PSK */
session = coap_new_client_session(ctx, &src_addr, &dst_addr,
uri.scheme==COAP_URI_SCHEME_COAP_TCP ? COAP_PROTO_TCP :
uri.scheme==COAP_URI_SCHEME_COAPS_TCP ? COAP_PROTO_TLS :
uri.scheme==COAP_URI_SCHEME_COAPS ? COAP_PROTO_DTLS : COAP_PROTO_UDP);
#ifdef CONFIG_COAP_MBEDTLS_PKI
unsigned int ca_pem_bytes = ca_pem_end - ca_pem_start;
unsigned int client_crt_bytes = client_crt_end - client_crt_start;
unsigned int client_key_bytes = client_key_end - client_key_start;
coap_dtls_pki_t dtls_pki;
static char client_sni[256];
memset (&dtls_pki, 0, sizeof(dtls_pki));
dtls_pki.version = COAP_DTLS_PKI_SETUP_VERSION;
if (ca_pem_bytes) {
/*
* Add in additional certificate checking.
* This list of enabled can be tuned for the specific
* requirements - see 'man coap_encryption'.
*
* Note: A list of root ca file can be setup separately using
* coap_context_set_pki_root_cas(), but the below is used to
* define what checking actually takes place.
*/
dtls_pki.verify_peer_cert = 1;
dtls_pki.require_peer_cert = 1;
dtls_pki.allow_self_signed = 1;
dtls_pki.allow_expired_certs = 1;
dtls_pki.cert_chain_validation = 1;
dtls_pki.cert_chain_verify_depth = 2;
dtls_pki.check_cert_revocation = 1;
dtls_pki.allow_no_crl = 1;
dtls_pki.allow_expired_crl = 1;
dtls_pki.allow_bad_md_hash = 1;
dtls_pki.allow_short_rsa_length = 1;
dtls_pki.validate_cn_call_back = verify_cn_callback;
dtls_pki.cn_call_back_arg = NULL;
dtls_pki.validate_sni_call_back = NULL;
dtls_pki.sni_call_back_arg = NULL;
memset(client_sni, 0, sizeof(client_sni));
if (uri.host.length) {
memcpy(client_sni, uri.host.s, MIN(uri.host.length, sizeof(client_sni)));
} else {
memcpy(client_sni, "localhost", 9);
}
dtls_pki.client_sni = client_sni;
}
dtls_pki.pki_key.key_type = COAP_PKI_KEY_PEM_BUF;
dtls_pki.pki_key.key.pem_buf.public_cert = client_crt_start;
dtls_pki.pki_key.key.pem_buf.public_cert_len = client_crt_bytes;
dtls_pki.pki_key.key.pem_buf.private_key = client_key_start;
dtls_pki.pki_key.key.pem_buf.private_key_len = client_key_bytes;
dtls_pki.pki_key.key.pem_buf.ca_cert = ca_pem_start;
dtls_pki.pki_key.key.pem_buf.ca_cert_len = ca_pem_bytes;
session = coap_new_client_session_pki(ctx, NULL, &dst_addr,
uri.scheme == COAP_URI_SCHEME_COAPS ? COAP_PROTO_DTLS : COAP_PROTO_TLS,
&dtls_pki);
#endif /* CONFIG_COAP_MBEDTLS_PKI */
} else {
session = coap_new_client_session(ctx, NULL, &dst_addr,
uri.scheme == COAP_URI_SCHEME_COAP_TCP ? COAP_PROTO_TCP :
COAP_PROTO_UDP);
}
if (!session) {
ESP_LOGE(TAG, "coap_new_client_session() failed");
goto clean_up;
ESP_LOGE(TAG, "coap_new_client_session() failed");
goto clean_up;
}
coap_register_response_handler(ctx, message_handler);
request = coap_new_pdu(session);
if (!request) {
ESP_LOGE(TAG, "coap_new_pdu() failed");
goto clean_up;
ESP_LOGE(TAG, "coap_new_pdu() failed");
goto clean_up;
}
request->type = COAP_MESSAGE_CON;
request->tid = coap_new_message_id(session);
@ -256,12 +400,12 @@ static void coap_example_task(void *p)
while (resp_wait) {
int result = coap_run_once(ctx, wait_ms > 1000 ? 1000 : wait_ms);
if (result >= 0) {
if (result >= wait_ms) {
ESP_LOGE(TAG, "select timeout");
break;
} else {
wait_ms -= result;
}
if (result >= wait_ms) {
ESP_LOGE(TAG, "select timeout");
break;
} else {
wait_ms -= result;
}
}
}
clean_up:
@ -269,10 +413,17 @@ clean_up:
coap_delete_optlist(optlist);
optlist = NULL;
}
if (session) coap_session_release(session);
if (ctx) coap_free_context(ctx);
if (session) {
coap_session_release(session);
}
if (ctx) {
coap_free_context(ctx);
}
coap_cleanup();
/* Only send the request off once */
/*
* change the following line to something like sleep(2)
* if you want the request to continually be sent
*/
break;
}
@ -291,5 +442,5 @@ void app_main(void)
*/
ESP_ERROR_CHECK(example_connect());
xTaskCreate(coap_example_task, "coap", 5 * 1024, NULL, 5, NULL);
xTaskCreate(coap_example_client, "coap", 8 * 1024, NULL, 5, NULL);
}

View File

@ -3,3 +3,6 @@
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
# embed files from the "certs" directory as binary data symbols
# in the app
COMPONENT_EMBED_TXTFILES := certs/coap_ca.pem certs/coap_client.crt certs/coap_client.key

View File

@ -2,14 +2,26 @@
# CoAP server example
(See the README.md file in the upper level 'examples' directory for more information about examples.)
This CoAP server example is adaptation of one of the [libcoap](https://github.com/obgm/libcoap) example.
This CoAP server example is very simplified adaptation of one of the
[libcoap](https://github.com/obgm/libcoap) examples.
CoAP server example would startup a daemon task, receive data from CoAP client and transmit data to CoAP client.
CoAP server example will startup a daemon task, receive requests / data from CoAP client and transmit
data to CoAP client.
The Constrained Application Protocol (CoAP) is a specialized web transfer protocol for use with constrained nodes and constrained networks in the Internet of Things.
The protocol is designed for machine-to-machine (M2M) applications such as smart energy and building automation.
If the incoming request requests the use of DTLS (connecting to port 5684), then the CoAP server will
try to establish a DTLS session using the previously defined Pre-Shared Key (PSK) - which
must be the same as the one that the CoAP client is using, or Public Key Infrastructure (PKI) where
the PKI information must match as requested.
please refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf) for more details.
NOTE: Client sessions trying to use coaps+tcp:// are not currently supported, even though both
libcoap and MbedTLS support it.
The Constrained Application Protocol (CoAP) is a specialized web transfer protocol for use with
constrained nodes and constrained networks in the Internet of Things.
The protocol is designed for machine-to-machine (M2M) applications such as smart energy and
building automation.
Please refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf) for more details.
## How to use example
@ -19,15 +31,22 @@ please refer to [RFC7252](https://www.rfc-editor.org/rfc/pdfrfc/rfc7252.txt.pdf)
idf.py menuconfig
```
* Set default serial port under Serial Flasher config
* Set WiFi SSID under Example Configuration
* Set WiFi Password under Example Configuration
Example Connection Configuration --->
* Set WiFi SSID under Example Configuration
* Set WiFi Password under Example Configuration
Example CoAP Client Configuration --->
* If PSK, Set CoAP Preshared Key to use in connection to the server
Component config --->
CoAP Configuration --->
* Set encryption method definition, PSK (default) or PKI
* Enable CoAP debugging if required
### Build and Flash
Build the project and flash it to the board, then run monitor tool to view serial output:
```
idf.py build
idf.py -p PORT flash monitor
```
@ -54,8 +73,8 @@ I (2622) CoAP_server: Connected to AP
...
```
if a CoAP client query `/Espressif` resource, CoAP server would return `"no data"`
until a CoAP client does a PUT with some data.
If a CoAP client queries the `/Espressif` resource, CoAP server will return `"Hello World!"`
until a CoAP client does a PUT with different data.
## libcoap Documentation
This can be found at https://libcoap.net/doc/reference/4.2.0/
@ -64,5 +83,4 @@ This can be found at https://libcoap.net/doc/reference/4.2.0/
* Please make sure CoAP client fetchs or puts data under path: `/Espressif` or
fetches `/.well-known/core`
* libcoap logging can be increased by changing `#define COAP_LOGGING_LEVEL 0`
to `#define COAP_LOGGING_LEVEL 9`
* CoAP logging can be enabled by running 'idf.py menuconfig -> Component config -> CoAP Configuration' and setting appropriate log level

View File

@ -1,2 +1,3 @@
idf_component_register(SRCS "coap_server_example_main.c"
INCLUDE_DIRS ".")
INCLUDE_DIRS "."
EMBED_TXTFILES certs/coap_ca.pem certs/coap_server.crt certs/coap_server.key)

View File

@ -0,0 +1,11 @@
menu "Example CoAP Server Configuration"
config EXAMPLE_COAP_PSK_KEY
string "Preshared Key (PSK) to used in the connection from the CoAP client"
depends on COAP_MBEDTLS_PSK
default "secret-key"
help
The Preshared Key to use to encrypt the communicatons. The same key must be
used at both ends of the CoAP connection, and the CoaP client must request
an URI prefixed with coaps:// instead of coap:// for DTLS to be used.
endmenu

View File

@ -0,0 +1,23 @@
-----BEGIN CERTIFICATE-----
MIID3DCCA0WgAwIBAgIJAMnlgL1czsmjMA0GCSqGSIb3DQEBCwUAMIGTMQswCQYD
VQQGEwJGUjEPMA0GA1UECAwGUmFkaXVzMRIwEAYDVQQHDAlTb21ld2hlcmUxFTAT
BgNVBAoMDEV4YW1wbGUgSW5jLjEgMB4GCSqGSIb3DQEJARYRYWRtaW5AZXhhbXBs
ZS5jb20xJjAkBgNVBAMMHUV4YW1wbGUgQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4X
DTE3MDYwNzA4MDY0OVoXDTI3MDYwNTA4MDY0OVowgZMxCzAJBgNVBAYTAkZSMQ8w
DQYDVQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMGA1UECgwMRXhh
bXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxlLmNvbTEmMCQG
A1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwgZ8wDQYJKoZIhvcN
AQEBBQADgY0AMIGJAoGBALpWR23fn/TmHxsXsHdrydzPSd17fZkc71WsaicgQR66
1tIVYb22UWGfj9KPM8THMsV74ew4ZkaQ39qvU0iuQIRrKARFHFok+vbaecgWMeWe
vGIqdnmyB9gJYaFOKgtSkfXsu2ddsqdvLYwcDbczrq8X9yEXpN6mnxXeCcPG4F0p
AgMBAAGjggE0MIIBMDAdBgNVHQ4EFgQUgigpdAUpONoDq0pQ3yfxrslCSpcwgcgG
A1UdIwSBwDCBvYAUgigpdAUpONoDq0pQ3yfxrslCSpehgZmkgZYwgZMxCzAJBgNV
BAYTAkZSMQ8wDQYDVQQIDAZSYWRpdXMxEjAQBgNVBAcMCVNvbWV3aGVyZTEVMBMG
A1UECgwMRXhhbXBsZSBJbmMuMSAwHgYJKoZIhvcNAQkBFhFhZG1pbkBleGFtcGxl
LmNvbTEmMCQGA1UEAwwdRXhhbXBsZSBDZXJ0aWZpY2F0ZSBBdXRob3JpdHmCCQDJ
5YC9XM7JozAMBgNVHRMEBTADAQH/MDYGA1UdHwQvMC0wK6ApoCeGJWh0dHA6Ly93
d3cuZXhhbXBsZS5jb20vZXhhbXBsZV9jYS5jcmwwDQYJKoZIhvcNAQELBQADgYEA
euxOBPInSJRKAIseMxPmAabtAqKNslZSmpG4He3lkKt+HM3jfznUt3psmD7j1hFW
S4l7KXzzajvaGYybDq5N9MqrDjhGn3VXZqOLMUNDL7OQq96TzgqsTBT1dmVSbNlt
PQgiAeKAk3tmH4lRRi9MTBSyJ6I92JYcS5H6Bs4ZwCc=
-----END CERTIFICATE-----

View File

@ -0,0 +1,70 @@
Certificate:
Data:
Version: 3 (0x2)
Serial Number: 47 (0x2f)
Signature Algorithm: sha1WithRSAEncryption
Issuer: C=FR, ST=Radius, L=Somewhere, O=Example Inc./emailAddress=admin@example.com, CN=Example Certificate Authority
Validity
Not Before: Jun 7 08:06:49 2017 GMT
Not After : Jun 5 08:06:49 2027 GMT
Subject: C=FR, ST=Radius, O=Example Inc., CN=Example Server Certificate/emailAddress=admin@example.com
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
Public-Key: (2048 bit)
Modulus:
00:c9:d8:e2:e0:75:91:83:87:d8:c8:80:c6:20:4d:
e9:14:24:30:98:33:53:fa:56:0e:ec:9a:43:7f:87:
a9:22:94:26:06:c7:ac:b5:d9:ec:55:06:81:b7:0d:
c9:24:51:49:fa:47:fb:4b:4e:fc:ed:75:8a:e1:28:
32:bc:c5:e0:4c:45:c4:58:60:15:67:1e:6b:40:19:
3f:f0:ab:92:61:92:2d:71:10:2e:f2:eb:bc:81:2f:
5a:3b:74:ca:5f:fd:e0:ee:d1:d9:07:6a:6c:20:c0:
07:88:b4:8b:0f:ad:1e:c9:4f:7c:11:98:37:89:15:
de:24:b1:11:1a:7c:97:4a:cf:f3:c8:cb:79:9e:9c:
c3:71:da:a6:94:97:f5:95:fd:61:06:44:e2:3f:12:
43:0b:1d:33:48:91:d2:ce:4f:97:a1:ed:6a:30:c7:
5d:98:b5:6e:0a:b7:4f:d9:03:ec:80:76:09:b0:40:
a1:a1:af:ab:2a:59:c4:0f:56:22:bc:be:14:be:18:
df:10:7d:5d:22:bf:e5:04:77:7a:75:6b:3e:eb:6d:
20:a1:a7:60:d4:f1:87:9d:9f:60:b9:d3:db:2c:25:
f4:91:4a:f1:d2:40:e5:a1:10:88:a0:41:5a:98:40:
ca:15:d7:e3:e6:3e:c0:6a:d5:46:b2:b4:90:b4:ae:
3b:e3
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Extended Key Usage:
TLS Web Server Authentication
X509v3 CRL Distribution Points:
Full Name:
URI:http://www.example.com/example_ca.crl
Signature Algorithm: sha1WithRSAEncryption
a4:25:21:51:0b:22:6c:63:8d:a9:c1:4f:04:33:69:79:34:f0:
36:dd:8f:6a:27:5f:07:a2:1d:ef:8b:f0:96:e6:e7:a3:b8:3b:
85:5e:3f:26:43:8a:8e:95:58:9c:a6:db:9c:51:bf:ea:53:16:
3e:c1:a8:11:1a:c6:cf:0e:a1:17:18:64:d2:05:f1:c0:9c:a6:
2b:16:c4:29:54:03:d2:17:bd:15:74:d6:ad:8a:8f:2d:cc:27:
3b:88:88:f2:ea:d0:a2:cb:e9:42:57:df:26:9f:8a:a2:02:2f:
35:b6:19:1d:26:43:44:af:12:4b:bc:b9:84:50:02:fd:1d:fa:
50:e8
-----BEGIN CERTIFICATE-----
MIIDWTCCAsKgAwIBAgIBLzANBgkqhkiG9w0BAQUFADCBkzELMAkGA1UEBhMCRlIx
DzANBgNVBAgMBlJhZGl1czESMBAGA1UEBwwJU29tZXdoZXJlMRUwEwYDVQQKDAxF
eGFtcGxlIEluYy4xIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUuY29tMSYw
JAYDVQQDDB1FeGFtcGxlIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0xNzA2MDcw
ODA2NDlaFw0yNzA2MDUwODA2NDlaMHwxCzAJBgNVBAYTAkZSMQ8wDQYDVQQIDAZS
YWRpdXMxFTATBgNVBAoMDEV4YW1wbGUgSW5jLjEjMCEGA1UEAwwaRXhhbXBsZSBT
ZXJ2ZXIgQ2VydGlmaWNhdGUxIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUu
Y29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAydji4HWRg4fYyIDG
IE3pFCQwmDNT+lYO7JpDf4epIpQmBsestdnsVQaBtw3JJFFJ+kf7S0787XWK4Sgy
vMXgTEXEWGAVZx5rQBk/8KuSYZItcRAu8uu8gS9aO3TKX/3g7tHZB2psIMAHiLSL
D60eyU98EZg3iRXeJLERGnyXSs/zyMt5npzDcdqmlJf1lf1hBkTiPxJDCx0zSJHS
zk+Xoe1qMMddmLVuCrdP2QPsgHYJsEChoa+rKlnED1YivL4UvhjfEH1dIr/lBHd6
dWs+620goadg1PGHnZ9gudPbLCX0kUrx0kDloRCIoEFamEDKFdfj5j7AatVGsrSQ
tK474wIDAQABo08wTTATBgNVHSUEDDAKBggrBgEFBQcDATA2BgNVHR8ELzAtMCug
KaAnhiVodHRwOi8vd3d3LmV4YW1wbGUuY29tL2V4YW1wbGVfY2EuY3JsMA0GCSqG
SIb3DQEBBQUAA4GBAKQlIVELImxjjanBTwQzaXk08Dbdj2onXweiHe+L8Jbm56O4
O4VePyZDio6VWJym25xRv+pTFj7BqBEaxs8OoRcYZNIF8cCcpisWxClUA9IXvRV0
1q2Kjy3MJzuIiPLq0KLL6UJX3yafiqICLzW2GR0mQ0SvEku8uYRQAv0d+lDo
-----END CERTIFICATE-----

View File

@ -0,0 +1,27 @@
-----BEGIN RSA PRIVATE KEY-----
MIIEpAIBAAKCAQEAydji4HWRg4fYyIDGIE3pFCQwmDNT+lYO7JpDf4epIpQmBses
tdnsVQaBtw3JJFFJ+kf7S0787XWK4SgyvMXgTEXEWGAVZx5rQBk/8KuSYZItcRAu
8uu8gS9aO3TKX/3g7tHZB2psIMAHiLSLD60eyU98EZg3iRXeJLERGnyXSs/zyMt5
npzDcdqmlJf1lf1hBkTiPxJDCx0zSJHSzk+Xoe1qMMddmLVuCrdP2QPsgHYJsECh
oa+rKlnED1YivL4UvhjfEH1dIr/lBHd6dWs+620goadg1PGHnZ9gudPbLCX0kUrx
0kDloRCIoEFamEDKFdfj5j7AatVGsrSQtK474wIDAQABAoIBAQC2kGDEPBJdMSW2
VCLfXRiPixwYzXQLXIMrJWwfkQg9qlmqkDd6U50aWkRA2UswegW7RhfYSZ0i+cmf
VMhvTVpOIlwwwtcY6b5/v1bBy60eaySGuuh79xQMlFO8qynQIMStvUfbGTqrdIRb
9VBB4YeS9T12fILejtTZwv2BQ2dj1Y1SCay6Ri85UzJqSClRKgHISybvVdLNjPvP
0TRFBr57zyjL6WE8teKiKchzQko2u86No5uBCdKGsrAkrsdcR0YqlM/pZxd3VKNm
+eny0k+dZZlvcPxzkzP4hEp9+Rw5rP9/s3s/cCwvuuC5JO32ATBWKCbTvPv/XPDb
MdSJtOshAoGBAPzk0eswkcbFYtpnpBNmBAr1dtAdW1lfjUI2ucMMwt7Wns0P/tt+
gq6Hi1wTaGP0l/dIECgeHwjtWj31ZJjQtFJ1y/kafxo4o9cA8vCydpdvSZaldAfg
sbLlDTDYzEpelaDIbNQBBXFoC5U9JlBhBsIFCL5Z8ZuIeFPsb7t5wwuHAoGBAMxT
jyWfNm1uNxp1xgCnrRsLPQPVnURrSFAqcHrECqRu3F7sozTN7q/cZViemxPvVDGQ
p9c+9bHwaYvW4trO5qDHJ++gGwm5L52bMAY1VUfeTt67fqrey43XpdmzcTX1V9Uj
QWawPUCSDzFjL1MjfCIejtyYf5ash53vj+T8r/vFAoGAA/OPVB1uKazr3n3AEo2F
gqZTNO1AgCT+EArK3EFWyiSQVqPpV4SihheYFdg3yVgJB9QYbIgL9BfBUTaEW97m
8mLkzP+c/Mvlw3ZAVYJ0V+llPPVY2saoACOUES9SAdd4fwqiqK1baGo3xB0wfBEI
CgAKIu9E1ylKuAT5ufQtGAECgYEAtP/kU5h5N3El4QupTdU7VDSdZTMqsHw0v8cI
gsf9AXKvRmtrnBA8u46KPHmruHoO5CVXeSZtsaXdaaH+rYQQ6yXg67WxnehtFLlv
TmCaXiLBTS9cYvMf8FOyuGnsBLeEietEOTov2G5KhR5uwsAxa2wUc7endor5S9/2
YQuyvV0CgYALbiFpILd5l1ip65eE6JdA3hfttUbV2j2NSW12ej69vqbeOfaSgNse
uYCcXFsBbQPhNPwA+4d1oCe8SyXZg1f7gE812z2Tyr/3vdVnNZlitoxhsHmGiyS7
gZdaTYCb78l9z0EBdaCVvA16owEle4SR6f9eCwzSI0WPOUra+x/hrA==
-----END RSA PRIVATE KEY-----

View File

@ -7,6 +7,13 @@
CONDITIONS OF ANY KIND, either express or implied.
*/
/*
* WARNING
* libcoap is not multi-thread safe, so only this thread must make any coap_*()
* calls. Any external (to this thread) data transmitted in/out via libcoap
* therefore has to be passed in/out by xQueue*() via this thread.
*/
#include <string.h>
#include <sys/socket.h>
@ -22,14 +29,60 @@
#include "protocol_examples_common.h"
#if 1
/* Needed until coap_dtls.h becomes a part of libcoap proper */
#include "libcoap.h"
#include "coap_dtls.h"
#endif
#include "coap.h"
/* Set this to 9 to get verbose logging from within libcoap */
#define COAP_LOGGING_LEVEL 0
/* The examples use simple Pre-Shared-Key configuration that you can set via
'make menuconfig'.
If you'd rather not, just change the below entries to strings with
the config you want - ie #define EXAMPLE_COAP_PSK_KEY "some-agreed-preshared-key"
Note: PSK will only be used if the URI is prefixed with coaps://
instead of coap:// and the PSK must be one that the server supports
(potentially associated with the IDENTITY)
*/
#define EXAMPLE_COAP_PSK_KEY CONFIG_EXAMPLE_COAP_PSK_KEY
/* The examples use CoAP Logging Level that
you can set via 'make menuconfig'.
If you'd rather not, just change the below entry to a value
that is between 0 and 7 with
the config you want - ie #define EXAMPLE_COAP_LOG_DEFAULT_LEVEL 7
*/
#define EXAMPLE_COAP_LOG_DEFAULT_LEVEL CONFIG_COAP_LOG_DEFAULT_LEVEL
const static char *TAG = "CoAP_server";
static char espressif_data[100];
static int espressif_data_len = 0;
#ifdef CONFIG_COAP_MBEDTLS_PKI
/* CA cert, taken from coap_ca.pem
Server cert, taken from coap_server.crt
Server key, taken from coap_server.key
The PEM, CRT and KEY file are examples taken from the wpa2 enterprise
example.
To embed it in the app binary, the PEM, CRT and KEY file is named
in the component.mk COMPONENT_EMBED_TXTFILES variable.
*/
extern uint8_t ca_pem_start[] asm("_binary_coap_ca_pem_start");
extern uint8_t ca_pem_end[] asm("_binary_coap_ca_pem_end");
extern uint8_t server_crt_start[] asm("_binary_coap_server_crt_start");
extern uint8_t server_crt_end[] asm("_binary_coap_server_crt_end");
extern uint8_t server_key_start[] asm("_binary_coap_server_key_start");
extern uint8_t server_key_end[] asm("_binary_coap_server_key_end");
#endif /* CONFIG_COAP_MBEDTLS_PKI */
#define INITIAL_DATA "Hello World!"
/*
* The resource handler
*/
@ -59,10 +112,9 @@ hnd_espressif_put(coap_context_t *ctx,
coap_resource_notify_observers(resource, NULL);
if (strcmp (espressif_data, "no data") == 0) {
if (strcmp (espressif_data, INITIAL_DATA) == 0) {
response->code = COAP_RESPONSE_CODE(201);
}
else {
} else {
response->code = COAP_RESPONSE_CODE(204);
}
@ -70,7 +122,7 @@ hnd_espressif_put(coap_context_t *ctx,
(void)coap_get_data(request, &size, &data);
if (size == 0) { /* re-init */
snprintf(espressif_data, sizeof(espressif_data), "no data");
snprintf(espressif_data, sizeof(espressif_data), INITIAL_DATA);
espressif_data_len = strlen(espressif_data);
} else {
espressif_data_len = size > sizeof (espressif_data) ? sizeof (espressif_data) : size;
@ -88,23 +140,41 @@ hnd_espressif_delete(coap_context_t *ctx,
coap_pdu_t *response)
{
coap_resource_notify_observers(resource, NULL);
snprintf(espressif_data, sizeof(espressif_data), "no data");
snprintf(espressif_data, sizeof(espressif_data), INITIAL_DATA);
espressif_data_len = strlen(espressif_data);
response->code = COAP_RESPONSE_CODE(202);
}
static void coap_example_thread(void *p)
#ifdef CONFIG_COAP_MBEDTLS_PKI
static int
verify_cn_callback(const char *cn,
const uint8_t *asn1_public_cert,
size_t asn1_length,
coap_session_t *session,
unsigned depth,
int validated,
void *arg
)
{
coap_log(LOG_INFO, "CN '%s' presented by server (%s)\n",
cn, depth ? "CA" : "Certificate");
return 1;
}
#endif /* CONFIG_COAP_MBEDTLS_PKI */
static void coap_example_server(void *p)
{
coap_context_t *ctx = NULL;
coap_address_t serv_addr;
coap_address_t serv_addr;
coap_resource_t *resource = NULL;
snprintf(espressif_data, sizeof(espressif_data), "no data");
snprintf(espressif_data, sizeof(espressif_data), INITIAL_DATA);
espressif_data_len = strlen(espressif_data);
coap_set_log_level(COAP_LOGGING_LEVEL);
coap_set_log_level(EXAMPLE_COAP_LOG_DEFAULT_LEVEL);
while (1) {
coap_endpoint_t *ep_udp = NULL;
coap_endpoint_t *ep_tcp = NULL;
coap_endpoint_t *ep = NULL;
unsigned wait_ms;
/* Prepare the CoAP server socket */
@ -115,19 +185,85 @@ static void coap_example_thread(void *p)
ctx = coap_new_context(NULL);
if (!ctx) {
continue;
ESP_LOGE(TAG, "coap_new_context() failed");
continue;
}
ep_udp = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_UDP);
if (!ep_udp) {
goto clean_up;
#ifdef CONFIG_COAP_MBEDTLS_PSK
/* Need PSK setup before we set up endpoints */
coap_context_set_psk(ctx, "CoAP",
(const uint8_t *)EXAMPLE_COAP_PSK_KEY,
sizeof(EXAMPLE_COAP_PSK_KEY) - 1);
#endif /* CONFIG_COAP_MBEDTLS_PSK */
#ifdef CONFIG_COAP_MBEDTLS_PKI
unsigned int ca_pem_bytes = ca_pem_end - ca_pem_start;
unsigned int server_crt_bytes = server_crt_end - server_crt_start;
unsigned int server_key_bytes = server_key_end - server_key_start;
coap_dtls_pki_t dtls_pki;
memset (&dtls_pki, 0, sizeof(dtls_pki));
dtls_pki.version = COAP_DTLS_PKI_SETUP_VERSION;
if (ca_pem_bytes) {
/*
* Add in additional certificate checking.
* This list of enabled can be tuned for the specific
* requirements - see 'man coap_encryption'.
*
* Note: A list of root ca file can be setup separately using
* coap_context_set_pki_root_cas(), but the below is used to
* define what checking actually takes place.
*/
dtls_pki.verify_peer_cert = 1;
dtls_pki.require_peer_cert = 1;
dtls_pki.allow_self_signed = 1;
dtls_pki.allow_expired_certs = 1;
dtls_pki.cert_chain_validation = 1;
dtls_pki.cert_chain_verify_depth = 2;
dtls_pki.check_cert_revocation = 1;
dtls_pki.allow_no_crl = 1;
dtls_pki.allow_expired_crl = 1;
dtls_pki.allow_bad_md_hash = 1;
dtls_pki.allow_short_rsa_length = 1;
dtls_pki.validate_cn_call_back = verify_cn_callback;
dtls_pki.cn_call_back_arg = NULL;
dtls_pki.validate_sni_call_back = NULL;
dtls_pki.sni_call_back_arg = NULL;
}
ep_tcp = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_TCP);
if (!ep_tcp) {
goto clean_up;
dtls_pki.pki_key.key_type = COAP_PKI_KEY_PEM_BUF;
dtls_pki.pki_key.key.pem_buf.public_cert = server_crt_start;
dtls_pki.pki_key.key.pem_buf.public_cert_len = server_crt_bytes;
dtls_pki.pki_key.key.pem_buf.private_key = server_key_start;
dtls_pki.pki_key.key.pem_buf.private_key_len = server_key_bytes;
dtls_pki.pki_key.key.pem_buf.ca_cert = ca_pem_start;
dtls_pki.pki_key.key.pem_buf.ca_cert_len = ca_pem_bytes;
coap_context_set_pki(ctx, &dtls_pki);
#endif /* CONFIG_COAP_MBEDTLS_PKI */
ep = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_UDP);
if (!ep) {
ESP_LOGE(TAG, "udp: coap_new_endpoint() failed");
goto clean_up;
}
ep = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_TCP);
if (!ep) {
ESP_LOGE(TAG, "tcp: coap_new_endpoint() failed");
goto clean_up;
}
#if defined(CONFIG_COAP_MBEDTLS_PSK) || defined(CONFIG_COAP_MBEDTLS_PKI)
if (coap_dtls_is_supported()) {
serv_addr.addr.sin.sin_port = htons(COAPS_DEFAULT_PORT);
ep = coap_new_endpoint(ctx, &serv_addr, COAP_PROTO_DTLS);
if (!ep) {
ESP_LOGE(TAG, "dtls: coap_new_endpoint() failed");
goto clean_up;
}
}
#endif /* CONFIG_COAP_MBEDTLS_PSK CONFIG_COAP_MBEDTLS_PKI */
resource = coap_resource_init(coap_make_str_const("Espressif"), 0);
if (!resource) {
goto clean_up;
ESP_LOGE(TAG, "coap_resource_init() failed");
goto clean_up;
}
coap_register_handler(resource, COAP_REQUEST_GET, hnd_espressif_get);
coap_register_handler(resource, COAP_REQUEST_PUT, hnd_espressif_put);
@ -171,5 +307,5 @@ void app_main(void)
*/
ESP_ERROR_CHECK(example_connect());
xTaskCreate(coap_example_thread, "coap", 1024 * 5, NULL, 5, NULL);
xTaskCreate(coap_example_server, "coap", 8 * 1024, NULL, 5, NULL);
}

View File

@ -3,3 +3,6 @@
#
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
# embed files from the "certs" directory as binary data symbols
# in the app
COMPONENT_EMBED_TXTFILES := certs/coap_ca.pem certs/coap_server.crt certs/coap_server.key