10 #include "coap_config.h" 15 #include "coap_keystore.h" 19 #define UNUSED __attribute__((unused)) 25 #ifdef HAVE_LIBTINYDTLS 43 session_t dtls_session;
51 dtls_context_t *dtls_context;
64 #define ITEM_SIZE (sizeof(struct queue_t) + data_length) 70 debug(
"*** add %p to sendqueue of session %p\n", item, session);
73 memcpy(item->
data,
data, data_length);
89 res = dtls_write(context->dtls_context, &session->
dtls_session,
93 debug(
"data not written\n");
97 debug(
"data truncated by dtls_write()\n");
111 session_t *session, uint8 *
data,
size_t len) {
120 if (!local_interface) {
130 dtls_application_data(
struct dtls_context_t *dtls_context,
131 session_t *session, uint8 *
data,
size_t len) {
141 if (!local_interface) {
142 debug(
"dropped message that was received on invalid interface\n");
146 return coap_handle_message(coap_context, local_interface,
148 (
unsigned char *)
data, len);
152 dtls_event(
struct dtls_context_t *dtls_context,
153 session_t *dtls_session,
154 dtls_alert_level_t level,
155 unsigned short code) {
164 if ((session->
dtls_session.ifindex == dtls_session->ifindex) &&
178 if (level == DTLS_ALERT_LEVEL_FATAL) {
189 case DTLS_ALERT_CLOSE_NOTIFY: {
193 case DTLS_EVENT_CONNECTED: {
198 case DTLS_EVENT_RENEGOTIATE: {
210 if (level == DTLS_ALERT_LEVEL_FATAL) {
221 get_psk_info(
struct dtls_context_t *dtls_context,
222 const session_t *session,
223 dtls_credentials_type_t type,
224 const unsigned char *
id,
size_t id_len,
225 unsigned char *result,
size_t result_length) {
227 coap_keystore_item_t *psk;
229 int fatal_error = DTLS_ALERT_INTERNAL_ERROR;
231 if(!coap_context || !coap_context->keystore) {
236 case DTLS_PSK_IDENTITY:
241 psk = coap_keystore_find_psk(coap_context->keystore,
id, id_len,
245 fatal_error = DTLS_ALERT_CLOSE_NOTIFY;
249 length = coap_psk_set_identity(psk, result, result_length);
257 psk = coap_keystore_find_psk(coap_context->keystore, NULL, 0,
261 fatal_error = DTLS_ALERT_HANDSHAKE_FAILURE;
265 length = coap_psk_set_key(psk, result, result_length);
281 return dtls_alert_fatal_create(fatal_error);
284 static dtls_handler_t cb = {
286 .read = dtls_application_data,
288 .get_psk_info = get_psk_info,
290 .get_ecdsa_key = NULL,
291 .verify_ecdsa_key = NULL
298 #define CONTEXT_SIZE (sizeof(struct coap_dtls_context_t)) 304 context->dtls_context = dtls_new_context(coap_context);
305 if (!context->dtls_context) {
309 dtls_set_handler(context->dtls_context, &cb);
324 dtls_free_context(dtls_context->dtls_context);
329 #define COAP_COPY_ADDRESS(DST,SRC) do { \ 330 (DST)->size = (SRC)->size; \ 331 if ((SRC)->addr.sa.sa_family == AF_INET6) { \ 332 (DST)->addr.sin6.sin6_family = (SRC)->addr.sin6.sin6_family; \ 333 (DST)->addr.sin6.sin6_addr = (SRC)->addr.sin6.sin6_addr; \ 334 (DST)->addr.sin6.sin6_port = (SRC)->addr.sin6.sin6_port; \ 336 (DST)->addr.st = (SRC)->addr.st; \ 352 memset(session, 0, need);
355 session->
dtls_session.ifindex = local_interface->handle.fd;
358 debug(
"*** new session %p\n", session);
374 debug(
"*** removed session %p\n", session);
386 if ((session->
dtls_session.ifindex == local_interface->handle.fd) &&
405 local_interface, dst);
409 local_interface, dst)) == NULL)) {
414 peer = dtls_get_peer(coap_context->
dtls_context->dtls_context,
421 if (dtls_connect(coap_context->
dtls_context->dtls_context,
424 peer = dtls_get_peer(coap_context->
dtls_context->dtls_context,
447 res = dtls_write(coap_context->
dtls_context->dtls_context,
449 (uint8 *)pdu->hdr, pdu->length);
453 }
else if (res == 0) {
457 if (!
push_data_item(session,
id, (uint8 *)pdu->hdr, pdu->length)) {
471 const unsigned char *
data,
size_t data_len) {
476 local_interface, dst);
480 local_interface, dst)) != NULL) {
491 dtls_handle_message(coap_context->
dtls_context->dtls_context,
494 if ((res < 0) && new_session) {
501 #elif defined(HAVE_GNUTLS) 502 #include <gnutls/gnutls.h> 503 #include <gnutls/dtls.h> 512 unsigned char data[];
515 typedef struct transport_t {
522 gnutls_session_t dtls_session;
535 gnutls_datum_t cookie_key;
544 return gnutls_check_version(
"3.3.0") != NULL;
548 get_psk(gnutls_session_t session __attribute__((unused)),
549 const char *identity,
550 gnutls_datum_t *key) {
551 #define PSK_IDENTITY "Client_identity" 552 #define PSK_IDENTITY_LENGTH (sizeof(PSK_IDENTITY) - 1) 553 #define PSK "secretPSK" 554 #define PSK_LENGTH (sizeof(PSK) - 1) 556 if ((strlen(identity) == PSK_IDENTITY_LENGTH) &&
557 (memcmp(identity, PSK_IDENTITY, PSK_IDENTITY_LENGTH) == 0)) {
558 key->data = gnutls_malloc(PSK_LENGTH);
560 if (key->data != NULL) {
561 key->size = PSK_LENGTH;
562 memcpy(key->data, PSK, PSK_LENGTH);
582 memset(session, 0, need);
585 session->coap_context = dtls_context->coap_context;
587 session->dst = *remote;
590 debug(
"*** new session %p\n", session);
607 if (gnutls_credentials_get(session->
dtls_session, GNUTLS_CRD_PSK,
609 == GNUTLS_E_SUCCESS) {
610 if (session->flags & GNUTLS_SERVER) {
611 gnutls_psk_free_server_credentials(
612 (gnutls_psk_server_credentials_t)credentials);
614 gnutls_psk_free_client_credentials(
615 (gnutls_psk_client_credentials_t)credentials);
619 debug(
"*** removed session %p\n", session);
628 #define ITEM_SIZE (sizeof(struct queue_t) + data_length) 634 debug(
"*** add %p to sendqueue of session %p\n", item, session);
637 memcpy(item->
data,
data, data_length);
656 res = dtls_write(coap_context->
dtls_context->dtls_context,
658 (uint8 *)pdu->hdr, pdu->length);
662 }
else if (res == 0) {
677 show_log(
int level,
const char *msg) {
684 #define CONTEXT_SIZE (sizeof(struct coap_dtls_context_t)) 689 context->coap_context = coap_context;
692 gnutls_global_set_log_function(show_log);
694 gnutls_key_generate(&context->cookie_key, GNUTLS_COOKIE_KEY_SIZE);
709 push_cookie(gnutls_transport_ptr_t tp,
const void *buf,
size_t len) {
710 transport_t *trans = (transport_t *)tp;
713 trans->dst, (
unsigned char *)buf, len);
717 push_func(gnutls_transport_ptr_t tp,
const void *buf,
size_t len) {
723 (
unsigned char *)buf,
734 if ((session->
local_interface.handle.fd == local_interface->handle.fd) &&
752 local_interface, dst);
756 local_interface, dst)) == NULL)) {
763 peer = dtls_get_peer(coap_context->
dtls_context->dtls_context,
770 if (dtls_connect(coap_context->
dtls_context->dtls_context,
773 peer = dtls_get_peer(coap_context->
dtls_context->dtls_context,
791 const unsigned char *
data,
size_t data_len) {
797 local_interface, dst);
800 gnutls_dtls_prestate_st prestate;
802 memset(&prestate, 0,
sizeof(prestate));
803 result = gnutls_dtls_cookie_verify(&coap_context->
dtls_context->cookie_key,
806 (
void *)
data, data_len, &prestate);
809 gnutls_dtls_cookie_send(&coap_context->
dtls_context->cookie_key,
810 (
void *)&dst->addr, dst->size, &prestate,
811 (gnutls_transport_ptr_t)&trans, push_cookie);
816 local_interface, dst)) != NULL) {
817 const char *error = NULL;
818 gnutls_psk_server_credentials_t cred;
822 #define TRY(stmt, dbgmsg) \ 825 if (result != GNUTLS_E_SUCCESS) { \ 831 session->flags = GNUTLS_SERVER;
833 GNUTLS_SERVER | GNUTLS_DATAGRAM ),
834 "cannot init GnuTLS session\n");
836 TRY(gnutls_psk_allocate_server_credentials(&cred),
837 "cannot create credentials\n");
839 gnutls_psk_set_server_credentials_function(cred, get_psk);
841 TRY(gnutls_credentials_set(session->
dtls_session, GNUTLS_CRD_PSK, cred),
842 "cannot set credentials");
845 "NONE:+VERS-DTLS1.2:+PSK:+AES-128-CCM:+SHA256:+COMP-NULL",
847 "cannot set cipher suite\n");
849 gnutls_dtls_prestate_set(session->
dtls_session, &prestate);
850 gnutls_transport_set_int(session->
dtls_session, local_interface->handle.fd);
859 }
while (result == GNUTLS_E_INTERRUPTED || result == GNUTLS_E_AGAIN);
863 gnutls_strerror(result));
867 debug(
"Handshake was completed\n");
881 if ((result < 0) && new_session) {
914 const unsigned char *
data UNUSED,
size_t data_len UNUSED) {
931 const unsigned char *
data UNUSED,
932 size_t data_len UNUSED) {
#define LL_FOREACH(head, el)
coap_endpoint_t * endpoint
the endpoints used for listening
multi-purpose address abstraction
#define COAP_EVENT_DTLS_RENEGOTIATE
int coap_tid_t
coap_tid_t is used to store CoAP transaction id, i.e.
#define LL_PREPEND(head, add)
static int push_data_item(struct coap_dtls_session_t *session, coap_tid_t id, const unsigned char *data, size_t data_length)
int coap_dtls_is_supported(void)
Check whether DTLS is available.
struct coap_dtls_session_t * sessions
ssize_t coap_network_send(coap_socket_t *sock, const coap_session_t *session, const uint8_t *data, size_t datalen)
void coap_dtls_free_session(coap_dtls_session_t *session UNUSED)
Abstraction of virtual endpoint that can be attached to coap_context_t.
struct coap_dtls_context_t coap_dtls_context_t
int coap_dtls_handle_message(struct coap_context_t *coap_context UNUSED, const coap_endpoint_t *local_interface UNUSED, const coap_address_t *dst UNUSED, const unsigned char *data UNUSED, size_t data_len UNUSED)
#define COAP_COPY_ADDRESS(DST, SRC)
COAP_STATIC_INLINE void * coap_malloc(size_t size)
Wrapper function to coap_malloc_type() for backwards compatibility.
struct coap_dtls_session_t * coap_dtls_get_session(struct coap_context_t *coap_context UNUSED, const coap_endpoint_t *local_interface UNUSED, const coap_address_t *dst UNUSED)
struct coap_dtls_session_t * coap_dtls_new_session(const coap_endpoint_t *local_interface UNUSED, const coap_address_t *remote UNUSED)
structure for CoAP PDUs token, if any, follows the fixed size header, then options until payload mark...
coap_endpoint_t * local_interface
Representation of network addresses.
#define COAP_EVENT_DTLS_CLOSED
(D)TLS events for COAP_PROTO_DTLS and COAP_PROTO_TLS
#define LL_APPEND(head, add)
COAP_STATIC_INLINE void coap_free(void *object)
Wrapper function to coap_free_type() for backwards compatibility.
static struct coap_dtls_session_t * coap_dtls_find_session(coap_dtls_context_t *dtls_context, const coap_endpoint_t *local_interface, const coap_address_t *dst)
int coap_remove_from_queue(coap_queue_t **queue, coap_session_t *session, coap_tid_t id, coap_queue_t **node)
This function removes the element with given id from the list given list.
#define COAP_EVENT_DTLS_ERROR
#define COAP_EVENT_DTLS_CONNECTED
int coap_address_equals(const coap_address_t *a, const coap_address_t *b)
Compares given address objects a and b.
int coap_handle_event(coap_context_t *context, coap_event_t event, coap_session_t *session)
Invokes the event handler of context for the given event and data.
static ssize_t dtls_send_to_peer(gnutls_transport_ptr_t context, const void *send_buffer, size_t send_buffer_length)
void coap_dtls_free_context(struct coap_dtls_context_t *dtls_context)
#define LL_FOREACH_SAFE(head, el, tmp)
struct coap_dtls_context_t * coap_dtls_new_context(struct coap_context_t *coap_context UNUSED)
struct queue_t * sendqueue
void * coap_malloc_type(coap_memory_tag_t type, size_t size)
Allocates a chunk of size bytes and returns a pointer to the newly allocated memory.
#define LL_DELETE(head, del)
coap_log_t coap_get_log_level(void)
Get the current logging level.
int coap_dtls_send(struct coap_context_t *coap_context UNUSED, struct coap_dtls_session_t *session UNUSED, const unsigned char *data UNUSED, size_t data_len UNUSED)
#define coap_log(level,...)
Logging function.
union coap_address_t::@0 addr
#define LL_SEARCH_SCALAR(head, out, field, val)
socklen_t size
size of addr
void coap_free_type(coap_memory_tag_t type, void *p)
Releases the memory that was allocated by coap_malloc_type().
gnutls_session_t dtls_session
The CoAP stack's global state is stored in a coap_context_t object.
int coap_delete_node(coap_queue_t *node)
Destroys specified node.