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) {
114 ctx->
psk_key.data = (
unsigned char *)key;
115 ctx->
psk_key.size = key_length;
143 #define ITEM_SIZE (sizeof(struct queue_t) + data_length) 149 coap_debug(
"*** add %p to sendqueue of session %p\n", item, session);
152 memcpy(item->
data, data, data_length);
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;
248 local_interface->flags |= COAP_ENDPOINT_HAS_DATA;
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) {
289 assert(dtls_session->
ctx);
293 handle.fd, dtls_session->
ifindex);
295 assert(local_interface);
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);
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);
344 int fd = local_interface->handle.fd;
354 tv.tv_usec = (ms % 1000) * 1000;
356 ret = select(fd + 1, &rfds, NULL, NULL, &tv);
370 memset(session, 0, need);
372 session->
ifindex = local_interface->handle.fd;
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) {
429 if (gnutls_psk_set_client_credentials(credentials, dtls_context->
psk_identity, &dtls_context->
psk_key, GNUTLS_PSK_KEY_RAW) == GNUTLS_E_SUCCESS) {
430 gnutls_credentials_set(session->
dtls_session, GNUTLS_CRD_PSK, credentials);
442 if (gnutls_psk_allocate_server_credentials(&credentials) == GNUTLS_E_SUCCESS) {
443 gnutls_psk_set_server_credentials_function(credentials,
psk_callback);
444 gnutls_credentials_set(session->
dtls_session, GNUTLS_CRD_PSK, credentials);
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);
489 if ((session->
ifindex == local_interface->handle.fd) &&
502 assert(coap_context);
505 local_interface, dst);
511 local_interface, dst)) == NULL)) {
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,
573 local_interface, dst);
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");
599 local_interface, dst)) != NULL) {
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");
void coap_dtls_set_log_level(int level)
Sets the log level to the specified value.
void coap_dtls_free_session(struct coap_dtls_context_t *dtls_context, struct coap_dtls_session_t *session)
#define LL_FOREACH(head, el)
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.
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...
coap_endpoint_t * endpoint
the endpoints used for listening
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)
multi-purpose address abstraction
int coap_tid_t
coap_tid_t is used to store CoAP transaction id, i.e.
#define LL_PREPEND(head, add)
int coap_dtls_get_log_level(void)
Returns the current log level.
static int push_data_item(struct coap_dtls_session_t *session, coap_tid_t id, const unsigned char *data, size_t data_length)
static int psk_client_callback(gnutls_session_t session, char **username, gnutls_datum_t *key)
int coap_dtls_is_supported(void)
Returns 1 if support for DTLS is enabled, or 0 otherwise.
struct coap_dtls_session_t * sessions
enum CertificateFormat_ CertificateFormat
ssize_t coap_network_send(coap_socket_t *sock, const coap_session_t *session, const uint8_t *data, size_t datalen)
Abstraction of virtual endpoint that can be attached to coap_context_t.
struct coap_dtls_context_t coap_dtls_context_t
#define COAP_COPY_ADDRESS(DST, SRC)
int coap_dtls_send(struct coap_context_t *coap_context, struct coap_dtls_session_t *session, const coap_pdu_t *pdu)
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)
COAP_STATIC_INLINE void * coap_malloc(size_t size)
Wrapper function to coap_malloc_type() for backwards compatibility.
void dtls_set_psk(struct coap_dtls_context_t *ctx, const char *identity, const uint8_t *key, int key_length)
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)
coap_address_t network_address
structure for CoAP PDUs token, if any, follows the fixed size header, then options until payload mark...
static ssize_t decrypt_callback(gnutls_transport_ptr_t context, void *receive_buffer, size_t receive_buffer_length)
coap_endpoint_t * local_interface
Representation of network addresses.
const char * psk_identity
CredentialType credential_type
#define LL_APPEND(head, add)
static int psk_callback(gnutls_session_t session, const char *username, gnutls_datum_t *key)
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_address_equals(const coap_address_t *a, const coap_address_t *b)
Compares given address objects a and b.
static ssize_t dtls_send_to_peer(gnutls_transport_ptr_t context, const void *send_buffer, size_t send_buffer_length)
gnutls_priority_t priority_cache
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.
CertificateFormat certificateFormat
gnutls_certificate_credentials_t cert_credentials
void coap_dtls_free_context(struct coap_dtls_context_t *dtls_context)
Releases the storage allocated for dtls_context.
#define coap_log(level,...)
Logging function.
#define LL_SEARCH_SCALAR(head, out, field, val)
ssize_t coap_network_read(coap_socket_t *sock, coap_packet_t *packet)
Function interface for reading data.
uint8_t session_established
struct coap_dtls_session_t * next
gnutls_session_t dtls_session
The CoAP stack's global state is stored in a coap_context_t object.