10 #include "coap_config.h"
15 #include "coap_keystore.h"
20 #include <gnutls/gnutls.h>
21 #include <gnutls/x509.h>
25 #define UNUSED __attribute__((unused))
89 #define COAP_COPY_ADDRESS(DST,SRC) do { \
90 (DST)->size = (SRC)->size; \
91 if ((SRC)->addr.sa.sa_family == AF_INET6) { \
92 (DST)->addr.sin6.sin6_family = (SRC)->addr.sin6.sin6_family; \
93 (DST)->addr.sin6.sin6_addr = (SRC)->addr.sin6.sin6_addr; \
94 (DST)->addr.sin6.sin6_port = (SRC)->addr.sin6.sin6_port; \
96 (DST)->addr.st = (SRC)->addr.st; \
101 #if GNUTLS_VERSION_MAJOR >= 3
103 certificate_verify(gnutls_session_t session) {
112 if (key_length > 0) {
113 ctx->psk_identity = identity;
114 ctx->psk_key.data = (
unsigned char *)key;
115 ctx->psk_key.size = key_length;
141 const unsigned char *data,
size_t data_length) {
143 #define ITEM_SIZE (sizeof(struct queue_t) + data_length)
149 coap_debug(
"*** add %p to sendqueue of session %p\n", item, session);
168 gnutls_global_init();
171 #define CONTEXT_SIZE (sizeof(struct coap_dtls_context_t))
176 context->
ctx = coap_context;
182 #if ((GNUTLS_VERSION_MAJOR > 3) || ((GNUTLS_VERSION_MAJOR == 3) && (GNUTLS_VERSION_MINOR >= 4)))
183 gnutls_priority_init(&context->
priority_cache,
"NONE:+VERS-ALL:+ECDHE-ECDSA:+ECDHE-PSK:+PSK:+CURVE-ALL:+AES-128-CCM-8:+AES-128-CBC:+MAC-ALL:-SHA1:+COMP-ALL:+SIGN-ALL:+CTYPE-X.509", NULL);
185 gnutls_priority_init(&context->
priority_cache,
"NONE:+VERS-TLS-ALL:+ECDHE-ECDSA:+ECDHE-PSK:+PSK:+CURVE-ALL:+AES-128-CBC:+MAC-ALL:-SHA1:+COMP-ALL:+SIGN-ALL:+CTYPE-X.509", NULL);
214 for (session = dtls_context->
sessions; session != NULL; ) {
216 session = session->
next;
226 gnutls_global_deinit();
232 decrypt_callback(gnutls_transport_ptr_t context,
void *receive_buffer,
size_t receive_buffer_length) {
238 assert(session->
ctx);
247 ssize_t bytes_read = 0;
252 if (bytes_read < 0) {
253 if (errno == EAGAIN) {
254 coap_log(COAP_LOG_DEBUG,
"eagain\n");
257 unsigned char* payload = 0;
259 memcpy(receive_buffer, payload, bytes_read);
265 if (receive_buffer_length < session->
buf_len) {
266 result = receive_buffer_length;
270 memcpy(receive_buffer, session->
buf, result);
272 session->
buf += result;
284 size_t send_buffer_length) {
298 if (result != (
int)send_buffer_length) {
299 coap_log(COAP_LOG_WARNING,
"coap_network_send failed\n");
311 (void)session; (void)username; (void)key;
318 psk_callback(gnutls_session_t session,
const char *username, gnutls_datum_t * key) {
321 key->data = gnutls_malloc(
dtls_session->ctx->dtls_context->psk_key.size);
322 key->size =
dtls_session->ctx->dtls_context->psk_key.size;
323 memcpy(key->data,
dtls_session->ctx->dtls_context->psk_key.data, key->size);
327 #if GNUTLS_VERSION_MAJOR >= 3
331 receive_timeout(gnutls_transport_ptr_t context,
unsigned int ms) {
338 assert(session->
ctx);
354 tv.tv_usec = (ms % 1000) * 1000;
356 ret = select(fd + 1, &rfds, NULL, NULL, &tv);
370 memset(session, 0, need);
373 assert(dtls_context->
ctx);
374 session->
ctx = dtls_context->
ctx;
377 #if GNUTLS_VERSION_MAJOR >= 3
379 flags = GNUTLS_CLIENT | GNUTLS_DATAGRAM | GNUTLS_NONBLOCK;
381 flags = GNUTLS_SERVER | GNUTLS_DATAGRAM | GNUTLS_NONBLOCK;
384 flags = GNUTLS_CLIENT;
386 flags = GNUTLS_SERVER;
389 assert(gnutls_init(&session->
dtls_session, flags) == GNUTLS_E_SUCCESS);
393 #if GNUTLS_VERSION_MAJOR >= 3
394 gnutls_transport_set_pull_timeout_function(session->
dtls_session, receive_timeout);
396 gnutls_transport_set_ptr(session->
dtls_session, session);
401 }
else if (gnutls_certificate_allocate_credentials(&dtls_context->
cert_credentials) == GNUTLS_E_SUCCESS) {
403 gnutls_datum_t certificateData;
406 int format = GNUTLS_X509_FMT_PEM;
408 format = GNUTLS_X509_FMT_DER;
412 gnutls_certificate_set_x509_key_mem(dtls_context->
cert_credentials, &certificateData, &certificateData, format);
414 #if GNUTLS_VERSION_MAJOR >= 3
415 gnutls_certificate_set_verify_function(dtls_context->
cert_credentials, certificate_verify);
419 gnutls_certificate_set_verify_flags(cert_credentials, GNUTLS_VERIFY_DISABLE_CA_SIGN);
425 if (dtls_context->
client) {
428 if (gnutls_psk_allocate_client_credentials(&
credentials) == GNUTLS_E_SUCCESS) {
442 if (gnutls_psk_allocate_server_credentials(&
credentials) == GNUTLS_E_SUCCESS) {
452 if (!dtls_context->
client) {
453 gnutls_certificate_server_set_request(session->
dtls_session, GNUTLS_CERT_REQUEST);
456 #if GNUTLS_VERSION_MAJOR >= 3
457 gnutls_handshake_set_timeout(session->
dtls_session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
473 gnutls_psk_free_client_credentials(session->
credentials);
475 gnutls_psk_free_server_credentials(session->
credentials);
502 assert(coap_context);
512 coap_log(COAP_LOG_WARNING,
"cannot create session object\n");
525 assert(coap_context && coap_context->
dtls_context && session);
527 coap_log(COAP_LOG_DEBUG,
"call dtls_write\n");
534 coap_log(COAP_LOG_WARNING,
"coap_dtls_send: cannot send PDU\n");
535 }
else if (res == 0) {
541 coap_log(COAP_LOG_DEBUG,
"cannot store %u bytes for deferred transmission\n",
555 coap_log(COAP_LOG_WARNING,
"session establish returned %d\n", r);
567 const unsigned char *data,
576 session->
buf = (
unsigned char*)data;
581 if ((decrypted_len <= 0) && new_session) {
584 ret = coap_handle_message(coap_context,
local_interface, dst, (
unsigned char*)data, decrypted_len);
589 coap_log(COAP_LOG_DEBUG,
"session established\n");
601 session->
buf = (
unsigned char*)data;
608 coap_log(COAP_LOG_WARNING,
"failed to establish session\n");
614 coap_log(COAP_LOG_WARNING,
"cannot allocate session, drop packet\n");
int coap_address_equals(const coap_address_t *a, const coap_address_t *b)
Compares given address objects a and b.
Representation of network addresses.
struct coap_dtls_session_t * coap_dtls_get_session(struct coap_context_t *coap_context, const coap_endpoint_t *local_interface, const coap_address_t *dst)
void coap_dtls_free_context(struct coap_dtls_context_t *dtls_context)
Releases the storage allocated for dtls_context.
int coap_dtls_handle_message(struct coap_context_t *coap_context, const coap_endpoint_t *local_interface, const coap_address_t *dst, const unsigned char *data, size_t data_len)
struct coap_dtls_session_t * coap_dtls_new_session(struct coap_dtls_context_t *dtls_context, const coap_endpoint_t *local_interface, const coap_address_t *remote)
static int psk_callback(gnutls_session_t session, const char *username, gnutls_datum_t *key)
struct coap_dtls_context_t coap_dtls_context_t
static int push_data_item(struct coap_dtls_session_t *session, coap_tid_t id, const unsigned char *data, size_t data_length)
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_dtls_send(struct coap_context_t *coap_context, struct coap_dtls_session_t *session, const coap_pdu_t *pdu)
void coap_dtls_free_session(struct coap_dtls_context_t *dtls_context, struct coap_dtls_session_t *session)
static ssize_t dtls_send_to_peer(gnutls_transport_ptr_t context, const void *send_buffer, size_t send_buffer_length)
@ CERTIFICATE_FORMAT_ASN1
@ CERTIFICATE_FORMAT_NONE
static int psk_client_callback(gnutls_session_t session, char **username, gnutls_datum_t *key)
void dtls_set_psk(struct coap_dtls_context_t *ctx, const char *identity, const uint8_t *key, int key_length)
static ssize_t decrypt_callback(gnutls_transport_ptr_t context, void *receive_buffer, size_t receive_buffer_length)
enum CertificateFormat_ CertificateFormat
@ CREDENTIAL_TYPE_NOT_SET
@ CREDENTIAL_TYPE_SERVER_PSK
@ CREDENTIAL_TYPE_CLIENT_PSK
#define COAP_COPY_ADDRESS(DST, SRC)
void coap_packet_get_memmapped(coap_packet_t *packet, unsigned char **address, size_t *length)
Given a packet, set msg and msg_len to an address and length of the packet's data in memory.
ssize_t coap_network_read(coap_socket_t *sock, coap_packet_t *packet)
Function interface for reading data.
ssize_t coap_network_send(coap_socket_t *sock, const coap_session_t *session, const uint8_t *data, size_t datalen)
struct coap_dtls_context_t * coap_dtls_new_context(struct coap_context_t *coap_context)
Creates a new DTLS context for the given coap_context.
int coap_dtls_is_supported(void)
Returns 1 if support for DTLS is enabled, or 0 otherwise.
void coap_dtls_set_log_level(int level)
Sets the log level to the specified value.
int coap_dtls_get_log_level(void)
Returns the current log level.
#define coap_log(level,...)
Logging function.
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.
COAP_STATIC_INLINE void * coap_malloc(size_t size)
Wrapper function to coap_malloc_type() for backwards compatibility.
COAP_STATIC_INLINE void coap_free(void *object)
Wrapper function to coap_free_type() for backwards compatibility.
int coap_tid_t
coap_tid_t is used to store CoAP transaction id, i.e.
multi-purpose address abstraction
The CoAP stack's global state is stored in a coap_context_t object.
coap_endpoint_t * endpoint
the endpoints used for listening
const char * psk_identity
CertificateFormat certificateFormat
gnutls_certificate_credentials_t cert_credentials
struct coap_dtls_session_t * sessions
gnutls_priority_t priority_cache
struct coap_dtls_session_t * next
gnutls_session_t dtls_session
CredentialType credential_type
uint8_t session_established
coap_endpoint_t * local_interface
struct queue_t * sendqueue
coap_address_t network_address
Abstraction of virtual endpoint that can be attached to coap_context_t.
structure for CoAP PDUs token, if any, follows the fixed size header, then options until payload mark...
#define LL_FOREACH(head, el)
#define LL_PREPEND(head, add)
#define LL_SEARCH_SCALAR(head, out, field, val)
#define LL_APPEND(head, add)