26 #define MIN_GNUTLS_VERSION "3.3.0" 31 #include <gnutls/gnutls.h> 32 #include <gnutls/x509.h> 33 #include <gnutls/dtls.h> 37 #define UNUSED __attribute__((unused)) 42 typedef struct coap_ssl_t {
54 typedef struct coap_gnutls_env_t {
55 gnutls_session_t g_session;
56 gnutls_psk_client_credentials_t psk_cl_credentials;
57 gnutls_psk_server_credentials_t psk_sv_credentials;
58 gnutls_certificate_credentials_t pki_credentials;
59 coap_ssl_t coap_ssl_data;
62 int seen_client_hello;
63 int doing_dtls_timeout;
66 #define IS_PSK (1 << 0) 67 #define IS_PKI (1 << 1) 68 #define IS_CLIENT (1 << 6) 69 #define IS_SERVER (1 << 7) 71 typedef struct sni_entry {
74 gnutls_certificate_credentials_t pki_credentials;
77 typedef struct coap_gnutls_context_t {
81 sni_entry *sni_entry_list;
82 gnutls_datum_t alpn_proto;
85 gnutls_priority_t priority_cache;
86 } coap_gnutls_context_t;
88 typedef enum coap_free_bye_t {
94 #if (GNUTLS_VERSION_NUMBER >= 0x030505) 95 #define VARIANTS "NORMAL:+ECDHE-PSK:+PSK:+ECDHE-ECDSA:+AES-128-CCM-8" 97 #define VARIANTS "NORMAL:+ECDHE-PSK:+PSK" 100 #define G_ACTION(xx) do { \ 102 } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) 104 #define G_CHECK(xx,func) do { \ 105 if ((ret = (xx)) < 0) { \ 106 coap_log(LOG_WARNING, "%s: '%s'\n", func, gnutls_strerror(ret)); \ 111 #define G_ACTION_CHECK(xx,func) do { \ 118 static int post_client_hello_gnutls_pki(gnutls_session_t g_session);
119 static int post_client_hello_gnutls_psk(gnutls_session_t g_session);
127 if (gnutls_check_version(MIN_GNUTLS_VERSION) == NULL) {
128 coap_log(
LOG_ERR,
"GnuTLS " MIN_GNUTLS_VERSION
" or later is required\n");
140 if (gnutls_check_version(MIN_GNUTLS_VERSION) == NULL) {
141 coap_log(
LOG_ERR,
"GnuTLS " MIN_GNUTLS_VERSION
" or later is required\n");
150 const char *vers = gnutls_check_version(NULL);
156 sscanf (vers,
"%d.%d.%d", &p1, &p2, &p3);
157 version.
version = (p1 << 16) | (p2 << 8) | p3;
165 coap_gnutls_audit_log_func(gnutls_session_t g_session,
const char* text)
178 coap_gnutls_log_func(
int level,
const char* text)
195 coap_gnutls_context_t *g_context =
198 if (!g_context || !setup_data)
201 g_context->setup_data = *setup_data;
202 g_context->psk_pki_enabled |= IS_PKI;
215 coap_gnutls_context_t *g_context =
219 "coap_context_set_pki_root_cas: (D)TLS environment " 224 if (ca_file == NULL && ca_path == NULL) {
226 "coap_context_set_pki_root_cas: ca_file and/or ca_path " 230 if (g_context->root_ca_file) {
231 gnutls_free(g_context->root_ca_file);
232 g_context->root_ca_file = NULL;
235 g_context->root_ca_file = gnutls_strdup(ca_file);
237 if (g_context->root_ca_path) {
238 gnutls_free(g_context->root_ca_path);
239 g_context->root_ca_path = NULL;
242 #if (GNUTLS_VERSION_NUMBER >= 0x030306) 243 g_context->root_ca_path = gnutls_strdup(ca_path);
257 const char *identity_hint UNUSED,
260 coap_gnutls_context_t *g_context =
263 g_context->psk_pki_enabled |= IS_PSK;
274 coap_gnutls_context_t *g_context =
276 return g_context->psk_pki_enabled ? 1 : 0;
280 gnutls_global_set_audit_log_function(coap_gnutls_audit_log_func);
281 gnutls_global_set_log_function(coap_gnutls_log_func);
289 gnutls_global_set_log_level(2 + level -
LOG_DEBUG);
292 gnutls_global_set_log_level(0);
312 struct coap_gnutls_context_t *g_context =
313 (
struct coap_gnutls_context_t *)
314 gnutls_malloc(
sizeof(coap_gnutls_context_t));
317 G_CHECK(gnutls_global_init(),
"gnutls_global_init");
318 memset(g_context, 0,
sizeof(
struct coap_gnutls_context_t));
319 g_context->alpn_proto.data = gnutls_malloc(4);
320 if (g_context->alpn_proto.data) {
321 memcpy(g_context->alpn_proto.data,
"coap", 4);
322 g_context->alpn_proto.size = 4;
324 G_CHECK(gnutls_priority_init(&g_context->priority_cache, VARIANTS, &err),
325 "gnutls_priority_init");
338 coap_gnutls_context_t *g_context = (coap_gnutls_context_t *)handle;
340 gnutls_free(g_context->alpn_proto.data);
341 gnutls_free(g_context->root_ca_file);
342 gnutls_free(g_context->root_ca_path);
343 for (i = 0; i < g_context->sni_count; i++) {
344 gnutls_free(g_context->sni_entry_list[i].sni);
345 if (g_context->psk_pki_enabled & IS_PKI) {
346 gnutls_certificate_free_credentials(
347 g_context->sni_entry_list[i].pki_credentials);
350 if (g_context->sni_count)
351 gnutls_free(g_context->sni_entry_list);
353 gnutls_priority_deinit(g_context->priority_cache);
355 gnutls_global_deinit();
356 gnutls_free(g_context);
368 char **username, gnutls_datum_t *key) {
378 const size_t max_identity_len =
sizeof(identity) - 1;
384 if (c_session == NULL || c_session->
context == NULL ||
397 assert(identity_len <
sizeof(identity));
401 *username = gnutls_malloc(identity_len+1);
403 memcpy(*username, identity, identity_len);
404 (*username)[identity_len] =
'\0';
407 key->data = gnutls_malloc(psk_len);
409 memcpy(key->data, psk_key, psk_len);
413 return (*username && key->data) ? 0 : -1;
420 static char* get_san_or_cn(gnutls_session_t g_session)
422 unsigned int cert_list_size = 0;
423 const gnutls_datum_t *cert_list;
424 gnutls_x509_crt_t cert;
431 if (gnutls_certificate_type_get(g_session) != GNUTLS_CRT_X509)
434 cert_list = gnutls_certificate_get_peers(g_session, &cert_list_size);
435 if (cert_list_size == 0) {
439 G_CHECK(gnutls_x509_crt_init(&cert),
"gnutls_x509_crt_init");
442 G_CHECK(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER),
443 "gnutls_x509_crt_import");
445 size =
sizeof(dn) -1;
447 ret = gnutls_x509_crt_get_subject_alt_name(cert, 0, dn, &size, NULL);
450 gnutls_x509_crt_deinit(cert);
451 return gnutls_strdup(dn);
455 G_CHECK(gnutls_x509_crt_get_dn(cert, dn, &size),
"gnutls_x509_crt_get_dn");
457 gnutls_x509_crt_deinit(cert);
463 if (((cn[0] ==
'C') || (cn[0] ==
'c')) &&
464 ((cn[1] ==
'N') || (cn[1] ==
'n')) &&
473 char *ecn = strchr(cn,
',');
477 return gnutls_strdup(cn);
489 static int cert_verify_gnutls(gnutls_session_t g_session)
491 unsigned int status = 0;
494 coap_gnutls_context_t *g_context =
497 int alert = GNUTLS_A_BAD_CERTIFICATE;
500 G_CHECK(gnutls_certificate_verify_peers(g_session, NULL, 0, &status),
501 "gnutls_certificate_verify_peers");
503 cn = get_san_or_cn(g_session);
506 status &= ~(GNUTLS_CERT_INVALID);
507 if (status & (GNUTLS_CERT_NOT_ACTIVATED|GNUTLS_CERT_EXPIRED)) {
508 if (g_context->setup_data.allow_expired_certs) {
509 status &= ~(GNUTLS_CERT_NOT_ACTIVATED|GNUTLS_CERT_EXPIRED);
511 " %s: %s: overridden: '%s'\n",
513 "The certificate has an invalid usage date", cn ? cn :
"?");
516 if (status & (GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED|
517 GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE)) {
518 if (g_context->setup_data.allow_expired_crl) {
519 status &= ~(GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED|
520 GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE);
522 " %s: %s: overridden: '%s'\n",
524 "The certificate's CRL entry has an invalid usage date",
531 " %s: status 0x%x: '%s'\n",
533 status, cn ? cn :
"?");
540 if (g_context->setup_data.validate_cn_call_back) {
541 unsigned int cert_list_size = 0;
542 const gnutls_datum_t *cert_list;
543 gnutls_x509_crt_t cert;
548 const int cert_is_trusted = !status;
550 cert_list = gnutls_certificate_get_peers(g_session, &cert_list_size);
551 if (cert_list_size == 0) {
556 G_CHECK(gnutls_x509_crt_init(&cert),
"gnutls_x509_crt_init");
559 G_CHECK(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER),
560 "gnutls_x509_crt_import");
563 G_CHECK(gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, der, &size),
564 "gnutls_x509_crt_export");
565 gnutls_x509_crt_deinit(cert);
566 if (!g_context->setup_data.validate_cn_call_back(cn,
572 g_context->setup_data.cn_call_back_arg)) {
573 alert = GNUTLS_A_ACCESS_DENIED;
578 if (g_context->setup_data.additional_tls_setup_call_back) {
580 if (!g_context->setup_data.additional_tls_setup_call_back(g_session,
581 &g_context->setup_data)) {
595 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL, alert));
606 static int cert_verify_callback_gnutls(gnutls_session_t g_session)
610 if (gnutls_auth_get_type(g_session) == GNUTLS_CRD_CERTIFICATE) {
611 if (cert_verify_gnutls(g_session) == 0) {
612 G_ACTION(gnutls_alert_send(g_session,
614 GNUTLS_A_ACCESS_DENIED));
626 setup_pki_credentials(gnutls_certificate_credentials_t *pki_credentials,
627 coap_gnutls_context_t *g_context,
632 G_CHECK(gnutls_certificate_allocate_credentials(pki_credentials),
633 "gnutls_certificate_allocate_credentials");
641 G_CHECK(gnutls_certificate_set_x509_key_file(*pki_credentials,
644 GNUTLS_X509_FMT_PEM),
645 "gnutls_certificate_set_x509_key_file");
649 "***setup_pki: (D)TLS: No %s Certificate + Private " 652 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
656 G_CHECK(gnutls_certificate_set_x509_trust_file(*pki_credentials,
658 GNUTLS_X509_FMT_PEM),
659 "gnutls_certificate_set_x509_trust_file");
678 G_CHECK(gnutls_certificate_set_x509_key_mem(*pki_credentials,
681 GNUTLS_X509_FMT_DER),
682 "gnutls_certificate_set_x509_key_mem");
686 "***setup_pki: (D)TLS: No %s Certificate + Private " 689 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
693 gnutls_datum_t ca_cert;
697 sizeof(ca_cert.data));
699 G_CHECK(gnutls_certificate_set_x509_trust_mem(*pki_credentials,
701 GNUTLS_X509_FMT_DER),
702 "gnutls_certificate_set_x509_trust_mem");
707 "***setup_pki: (D)TLS: Unknown key type %d\n",
709 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
712 if (g_context->root_ca_file) {
713 G_CHECK(gnutls_certificate_set_x509_trust_file(*pki_credentials,
714 g_context->root_ca_file,
715 GNUTLS_X509_FMT_PEM),
716 "gnutls_certificate_set_x509_trust_file");
718 if (g_context->root_ca_path) {
719 #if (GNUTLS_VERSION_NUMBER >= 0x030306) 720 G_CHECK(gnutls_certificate_set_x509_trust_dir(*pki_credentials,
721 g_context->root_ca_path,
722 GNUTLS_X509_FMT_PEM),
723 "gnutls_certificate_set_x509_trust_dir");
726 if (!(g_context->psk_pki_enabled & IS_PKI)) {
728 G_CHECK(gnutls_certificate_set_x509_system_trust(*pki_credentials),
729 "gnutls_certificate_set_x509_system_trust");
734 gnutls_certificate_set_verify_function(*pki_credentials,
735 cert_verify_callback_gnutls);
740 gnutls_certificate_set_verify_limits(*pki_credentials,
746 gnutls_certificate_set_verify_flags(*pki_credentials,
747 GNUTLS_VERIFY_DO_NOT_ALLOW_SAME);
751 gnutls_certificate_set_verify_flags(*pki_credentials,
752 GNUTLS_VERIFY_DO_NOT_ALLOW_SAME |
753 GNUTLS_VERIFY_DISABLE_CRL_CHECKS);
756 return GNUTLS_E_SUCCESS;
767 post_client_hello_gnutls_pki(gnutls_session_t g_session)
771 coap_gnutls_context_t *g_context =
773 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
774 int ret = GNUTLS_E_SUCCESS;
777 g_env->seen_client_hello = 1;
779 if (g_context->setup_data.validate_sni_call_back) {
786 name = gnutls_malloc(len);
788 return GNUTLS_E_MEMORY_ERROR;
791 ret = gnutls_server_name_get(g_session, name, &len, &type, i);
792 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
794 new_name = gnutls_realloc(name, len);
795 if (new_name == NULL) {
796 ret = GNUTLS_E_MEMORY_ERROR;
804 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
807 if (ret != GNUTLS_E_SUCCESS)
810 if (type != GNUTLS_NAME_DNS)
821 for (i = 0; i < g_context->sni_count; i++) {
822 if (strcmp(name, g_context->sni_entry_list[i].sni) == 0) {
826 if (i == g_context->sni_count) {
831 g_context->setup_data.validate_sni_call_back(name,
832 g_context->setup_data.sni_call_back_arg);
834 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
835 GNUTLS_A_UNRECOGNIZED_NAME));
836 ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
840 g_context->sni_entry_list = gnutls_realloc(g_context->sni_entry_list,
841 (i+1)*
sizeof(sni_entry));
842 g_context->sni_entry_list[i].sni = gnutls_strdup(name);
843 g_context->sni_entry_list[i].pki_key = *new_entry;
844 sni_setup_data = g_context->setup_data;
845 sni_setup_data.
pki_key = *new_entry;
846 if ((ret = setup_pki_credentials(
847 &g_context->sni_entry_list[i].pki_credentials,
851 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
852 GNUTLS_A_BAD_CERTIFICATE));
856 g_context->sni_count++;
858 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
859 g_context->sni_entry_list[i].pki_credentials),
860 "gnutls_credentials_set");
876 post_client_hello_gnutls_psk(gnutls_session_t g_session)
880 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
882 g_env->seen_client_hello = 1;
883 return GNUTLS_E_SUCCESS;
891 setup_client_ssl_session(
coap_session_t *c_session, coap_gnutls_env_t *g_env)
893 coap_gnutls_context_t *g_context =
897 g_context->psk_pki_enabled |= IS_CLIENT;
898 if (g_context->psk_pki_enabled & IS_PSK) {
899 char *identity = NULL;
900 gnutls_datum_t psk_key;
902 G_CHECK(gnutls_psk_allocate_client_credentials(&g_env->psk_cl_credentials),
903 "gnutls_psk_allocate_client_credentials");
905 G_CHECK(gnutls_psk_set_client_credentials(g_env->psk_cl_credentials,
909 "gnutls_psk_set_client_credentials");
910 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_PSK,
911 g_env->psk_cl_credentials),
912 "gnutls_credentials_set");
913 gnutls_free(identity);
914 gnutls_free(psk_key.data);
917 if ((g_context->psk_pki_enabled & IS_PKI) ||
918 (g_context->psk_pki_enabled & (IS_PSK | IS_PKI)) == 0) {
924 G_CHECK(setup_pki_credentials(&g_env->pki_credentials, g_context,
926 "setup_pki_credentials");
928 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
929 g_env->pki_credentials),
930 "gnutls_credentials_set");
933 G_CHECK(gnutls_alpn_set_protocols(g_env->g_session,
934 &g_context->alpn_proto, 1, 0),
935 "gnutls_alpn_set_protocols");
939 G_CHECK(gnutls_server_name_set(g_env->g_session, GNUTLS_NAME_DNS,
942 "gnutls_server_name_set");
945 return GNUTLS_E_SUCCESS;
959 psk_server_callback(gnutls_session_t g_session,
960 const char *identity,
965 size_t identity_len = 0;
970 identity_len = strlen(identity);
975 (
int)identity_len, identity);
977 if (c_session == NULL || c_session->
context == NULL ||
985 key->data = gnutls_malloc(psk_len);
986 memcpy(key->data, buf, psk_len);
996 setup_server_ssl_session(
coap_session_t *c_session, coap_gnutls_env_t *g_env)
998 coap_gnutls_context_t *g_context =
1000 int ret = GNUTLS_E_SUCCESS;
1002 g_context->psk_pki_enabled |= IS_SERVER;
1003 if (g_context->psk_pki_enabled & IS_PSK) {
1004 G_CHECK(gnutls_psk_allocate_server_credentials(&g_env->psk_sv_credentials),
1005 "gnutls_psk_allocate_server_credentials");
1006 gnutls_psk_set_server_credentials_function(g_env->psk_sv_credentials,
1007 psk_server_callback);
1009 gnutls_handshake_set_post_client_hello_function(g_env->g_session,
1010 post_client_hello_gnutls_psk);
1012 G_CHECK(gnutls_credentials_set(g_env->g_session,
1014 g_env->psk_sv_credentials),
1015 "gnutls_credentials_set\n");
1018 if (g_context->psk_pki_enabled & IS_PKI) {
1020 G_CHECK(setup_pki_credentials(&g_env->pki_credentials, g_context,
1022 "setup_pki_credentials");
1025 gnutls_certificate_server_set_request(g_env->g_session,
1026 GNUTLS_CERT_REQUIRE);
1029 gnutls_certificate_server_set_request(g_env->g_session, GNUTLS_CERT_IGNORE);
1032 gnutls_handshake_set_post_client_hello_function(g_env->g_session,
1033 post_client_hello_gnutls_pki);
1035 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
1036 g_env->pki_credentials),
1037 "gnutls_credentials_set\n");
1039 return GNUTLS_E_SUCCESS;
1051 coap_dgram_read(gnutls_transport_ptr_t context,
void *out,
size_t outl)
1055 coap_ssl_t *data = &((coap_gnutls_env_t *)c_session->
tls)->coap_ssl_data;
1057 if (!c_session->
tls) {
1063 if (data != NULL && data->pdu_len > 0) {
1064 if (outl < data->pdu_len) {
1065 memcpy(out, data->pdu, outl);
1068 data->pdu_len -= outl;
1070 memcpy(out, data->pdu, data->pdu_len);
1071 ret = data->pdu_len;
1072 if (!data->peekmode) {
1093 coap_dgram_write(gnutls_transport_ptr_t context,
const void *send_buffer,
1094 size_t send_buffer_length) {
1095 ssize_t result = -1;
1100 if (result != (
int)send_buffer_length) {
1116 receive_timeout(gnutls_transport_ptr_t context,
unsigned int ms UNUSED) {
1120 fd_set readfds, writefds, exceptfds;
1122 int nfds = c_session->
sock.
fd +1;
1123 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1127 g_env->coap_ssl_data.pdu_len > 0) {
1133 FD_ZERO(&exceptfds);
1134 FD_SET (c_session->
sock.
fd, &readfds);
1135 if (!(g_env && g_env->doing_dtls_timeout)) {
1136 FD_SET (c_session->
sock.
fd, &writefds);
1137 FD_SET (c_session->
sock.
fd, &exceptfds);
1143 return select(nfds, &readfds, &writefds, &exceptfds, &tv);
1148 static coap_gnutls_env_t *
1151 coap_gnutls_context_t *g_context =
1153 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1154 int flags = type | GNUTLS_DATAGRAM | GNUTLS_NONBLOCK;
1160 g_env = gnutls_malloc(
sizeof(coap_gnutls_env_t));
1164 memset(g_env, 0,
sizeof(
struct coap_gnutls_env_t));
1166 G_CHECK(gnutls_init(&g_env->g_session, flags),
"gnutls_init");
1168 gnutls_transport_set_pull_function(g_env->g_session, coap_dgram_read);
1169 gnutls_transport_set_push_function(g_env->g_session, coap_dgram_write);
1170 gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
1172 gnutls_transport_set_ptr(g_env->g_session, c_session);
1174 if (type == GNUTLS_SERVER) {
1175 G_CHECK(setup_server_ssl_session(c_session, g_env),
1176 "setup_server_ssl_session");
1179 G_CHECK(setup_client_ssl_session(c_session, g_env),
1180 "setup_client_ssl_session");
1183 G_CHECK(gnutls_priority_set(g_env->g_session, g_context->priority_cache),
1184 "gnutls_priority_set");
1185 gnutls_handshake_set_timeout(g_env->g_session,
1186 GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
1187 gnutls_dtls_set_timeouts(g_env->g_session, 5000, 60000);
1198 coap_dtls_free_gnutls_env(coap_gnutls_context_t *g_context,
1199 coap_gnutls_env_t *g_env,
1200 coap_free_bye_t free_bye)
1206 if (free_bye != COAP_FREE_BYE_NONE) {
1208 gnutls_bye(g_env->g_session, free_bye == COAP_FREE_BYE_AS_UDP ?
1209 GNUTLS_SHUT_WR : GNUTLS_SHUT_RDWR);
1211 gnutls_deinit(g_env->g_session);
1212 g_env->g_session = NULL;
1213 if (g_context->psk_pki_enabled & IS_PSK) {
1214 if (g_context->psk_pki_enabled & IS_CLIENT) {
1215 gnutls_psk_free_client_credentials(g_env->psk_cl_credentials);
1216 g_env->psk_cl_credentials = NULL;
1219 gnutls_psk_free_server_credentials(g_env->psk_sv_credentials);
1220 g_env->psk_sv_credentials = NULL;
1223 if ((g_context->psk_pki_enabled & IS_PKI) ||
1224 (g_context->psk_pki_enabled &
1225 (IS_PSK | IS_PKI | IS_CLIENT)) == IS_CLIENT) {
1226 gnutls_certificate_free_credentials(g_env->pki_credentials);
1227 g_env->pki_credentials = NULL;
1234 coap_gnutls_env_t *g_env =
1235 (coap_gnutls_env_t *)c_session->
tls;
1237 gnutls_transport_set_ptr(g_env->g_session, c_session);
1242 static void log_last_alert(gnutls_session_t g_session) {
1243 int last_alert = gnutls_alert_get(g_session);
1246 last_alert, gnutls_alert_get_name(last_alert));
1255 do_gnutls_handshake(
coap_session_t *c_session, coap_gnutls_env_t *g_env) {
1258 ret = gnutls_handshake(g_env->g_session);
1260 case GNUTLS_E_SUCCESS:
1261 g_env->established = 1;
1266 case GNUTLS_E_INTERRUPTED:
1270 case GNUTLS_E_AGAIN:
1274 case GNUTLS_E_INSUFFICIENT_CREDENTIALS:
1276 "Insufficient credentials provided.\n");
1279 case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET:
1280 case GNUTLS_E_FATAL_ALERT_RECEIVED:
1281 log_last_alert(g_env->g_session);
1285 case GNUTLS_E_WARNING_ALERT_RECEIVED:
1286 log_last_alert(g_env->g_session);
1290 case GNUTLS_E_NO_CERTIFICATE_FOUND:
1292 "Client Certificate requested and required, but not provided\n" 1294 G_ACTION(gnutls_alert_send(g_env->g_session, GNUTLS_AL_FATAL,
1295 GNUTLS_A_BAD_CERTIFICATE));
1299 case GNUTLS_E_DECRYPTION_FAILED:
1301 "do_gnutls_handshake: session establish " 1302 "returned %d: '%s'\n",
1303 ret, gnutls_strerror(ret));
1304 G_ACTION(gnutls_alert_send(g_env->g_session, GNUTLS_AL_FATAL,
1305 GNUTLS_A_DECRYPT_ERROR));
1309 case GNUTLS_E_UNKNOWN_CIPHER_SUITE:
1311 case GNUTLS_E_TIMEDOUT:
1317 "do_gnutls_handshake: session establish " 1318 "returned %d: '%s'\n",
1319 ret, gnutls_strerror(ret));
1327 coap_gnutls_env_t *g_env = coap_dtls_new_gnutls_env(c_session, GNUTLS_CLIENT);
1331 ret = do_gnutls_handshake(c_session, g_env);
1336 COAP_FREE_BYE_AS_UDP : COAP_FREE_BYE_AS_TCP);
1344 if (c_session && c_session->
context) {
1348 COAP_FREE_BYE_AS_UDP : COAP_FREE_BYE_AS_TCP);
1349 c_session->
tls = NULL;
1355 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1359 G_CHECK(gnutls_dtls_set_data_mtu(g_env->g_session, c_session->
mtu),
1360 "gnutls_dtls_set_data_mtu");
1371 const uint8_t *data,
size_t data_len) {
1373 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1375 assert(g_env != NULL);
1378 if (g_env->established) {
1379 ret = gnutls_record_send(g_env->g_session, data, data_len);
1383 case GNUTLS_E_AGAIN:
1386 case GNUTLS_E_FATAL_ALERT_RECEIVED:
1387 log_last_alert(g_env->g_session);
1401 ret = do_gnutls_handshake(c_session, g_env);
1430 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1432 if (g_env && g_env->g_session) {
1433 unsigned int rem_ms = gnutls_dtls_get_timeout(g_env->g_session);
1435 return now + rem_ms;
1442 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1444 assert(g_env != NULL);
1445 g_env->doing_dtls_timeout = 1;
1448 (do_gnutls_handshake(c_session, g_env) < 0)) {
1450 g_env->doing_dtls_timeout = 0;
1454 g_env->doing_dtls_timeout = 0;
1468 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1470 coap_ssl_t *ssl_data = &g_env->coap_ssl_data;
1474 assert(g_env != NULL);
1476 if (ssl_data->pdu_len)
1479 ssl_data->pdu = data;
1480 ssl_data->pdu_len = (unsigned)data_len;
1483 if (g_env->established) {
1487 gnutls_transport_set_ptr(g_env->g_session, c_session);
1490 ret = gnutls_record_recv(g_env->g_session, pdu, (
int)
sizeof(pdu));
1494 else if (ret == 0) {
1499 "coap_dtls_receive: gnutls_record_recv returned %d\n", ret);
1504 ret = do_gnutls_handshake(c_session, g_env);
1534 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1535 coap_ssl_t *ssl_data = g_env ? &g_env->coap_ssl_data : NULL;
1539 g_env = coap_dtls_new_gnutls_env(c_session, GNUTLS_SERVER);
1541 c_session->
tls = g_env;
1542 ssl_data = &g_env->coap_ssl_data;
1543 ssl_data->pdu = data;
1544 ssl_data->pdu_len = (unsigned)data_len;
1545 gnutls_dtls_set_data_mtu(g_env->g_session, c_session->
mtu);
1546 ret = do_gnutls_handshake(c_session, g_env);
1547 if (ret == 1 || g_env->seen_client_hello) {
1553 g_env->seen_client_hello = 0;
1560 coap_dtls_free_gnutls_env(
1562 g_env, COAP_FREE_BYE_NONE);
1563 c_session->
tls = NULL;
1568 ssl_data->pdu = data;
1569 ssl_data->pdu_len = (unsigned)data_len;
1571 ret = do_gnutls_handshake(c_session, g_env);
1572 if (ret == 1 || g_env->seen_client_hello) {
1578 g_env->seen_client_hello = 0;
1594 coap_sock_read(gnutls_transport_ptr_t context,
void *out,
size_t outl) {
1600 ret = recv(c_session->
sock.
fd, (
char *)out, (
int)outl, 0);
1602 ret = recv(c_session->
sock.
fd, out, outl, 0);
1607 }
else if (ret < 0 && errno != EAGAIN) {
1617 else if (ret < (ssize_t)outl)
1630 coap_sock_write(gnutls_transport_ptr_t context,
const void *in,
size_t inl) {
1638 }
else if (ret < 0) {
1650 coap_gnutls_env_t *g_env = gnutls_malloc(
sizeof(coap_gnutls_env_t));
1651 coap_gnutls_context_t *g_context =
1653 int flags = GNUTLS_CLIENT;
1659 memset(g_env, 0,
sizeof(
struct coap_gnutls_env_t));
1662 G_CHECK(gnutls_init(&g_env->g_session, flags),
"gnutls_init");
1664 gnutls_transport_set_pull_function(g_env->g_session, coap_sock_read);
1665 gnutls_transport_set_push_function(g_env->g_session, coap_sock_write);
1666 gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
1668 gnutls_transport_set_ptr(g_env->g_session, c_session);
1670 setup_client_ssl_session(c_session, g_env);
1672 gnutls_priority_set(g_env->g_session, g_context->priority_cache);
1673 gnutls_handshake_set_timeout(g_env->g_session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
1675 ret = do_gnutls_handshake(c_session, g_env);
1690 coap_gnutls_env_t *g_env = gnutls_malloc(
sizeof(coap_gnutls_env_t));
1691 coap_gnutls_context_t *g_context =
1693 int flags = GNUTLS_SERVER;
1698 memset(g_env, 0,
sizeof(
struct coap_gnutls_env_t));
1701 G_CHECK(gnutls_init(&g_env->g_session, flags),
"gnutls_init");
1703 gnutls_transport_set_pull_function(g_env->g_session, coap_sock_read);
1704 gnutls_transport_set_push_function(g_env->g_session, coap_sock_write);
1705 gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
1707 gnutls_transport_set_ptr(g_env->g_session, c_session);
1709 setup_server_ssl_session(c_session, g_env);
1711 gnutls_priority_set(g_env->g_session, g_context->priority_cache);
1712 gnutls_handshake_set_timeout(g_env->g_session,
1713 GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
1715 c_session->
tls = g_env;
1716 ret = do_gnutls_handshake(c_session, g_env);
1741 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1743 assert(g_env != NULL);
1746 if (g_env->established) {
1747 ret = gnutls_record_send(g_env->g_session, data, data_len);
1751 case GNUTLS_E_AGAIN:
1754 case GNUTLS_E_FATAL_ALERT_RECEIVED:
1755 log_last_alert(g_env->g_session);
1761 "coap_tls_write: gnutls_record_send " 1762 "returned %d: '%s'\n",
1763 ret, gnutls_strerror(ret));
1773 ret = do_gnutls_handshake(c_session, g_env);
1807 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1814 if (!g_env->established) {
1815 ret = do_gnutls_handshake(c_session, g_env);
1822 if (g_env->established) {
1823 ret = gnutls_record_recv(g_env->g_session, data, (
int)data_len);
1829 case GNUTLS_E_AGAIN:
1833 case GNUTLS_E_PULL_ERROR:
1838 "coap_tls_read: gnutls_record_recv " 1839 "returned %d: '%s'\n",
1840 ret, gnutls_strerror(ret));
1866 #pragma GCC diagnostic ignored "-Wunused-function" unsigned mtu
path or CSM mtu
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)
void coap_session_send_csm(coap_session_t *session)
Notify session transport has just connected and CSM exchange can now start.
int coap_dtls_hello(coap_session_t *session UNUSED, const uint8_t *data UNUSED, size_t data_len UNUSED)
#define COAP_RXBUFFER_SIZE
void coap_tls_free_session(coap_session_t *coap_session UNUSED)
struct coap_context_t * context
session's context
The PKI key type is ASN.1 (DER)
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 * tls
security parameters
coap_pki_key_t key_type
key format type
#define COAP_SESSION_STATE_HANDSHAKE
int coap_dtls_receive(coap_session_t *session UNUSED, const uint8_t *data UNUSED, size_t data_len UNUSED)
int coap_dtls_context_check_keys_enabled(coap_context_t *ctx UNUSED)
ssize_t coap_tls_read(coap_session_t *session UNUSED, uint8_t *data UNUSED, size_t data_len UNUSED)
int coap_dtls_get_log_level(void)
Returns the current log level.
void * coap_dtls_new_client_session(coap_session_t *session UNUSED)
Internal function invoked for server.
#define COAP_SOCKET_ERROR
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.
int coap_dtls_context_set_pki(coap_context_t *ctx UNUSED, coap_dtls_pki_t *setup_data UNUSED, coap_dtls_role_t role UNUSED)
void * coap_tls_new_server_session(coap_session_t *session UNUSED, int *connected UNUSED)
ssize_t coap_tls_write(coap_session_t *session UNUSED, const uint8_t *data UNUSED, size_t data_len UNUSED)
#define COAP_SOCKET_CAN_READ
non blocking socket can now read without blocking
ssize_t coap_session_send(coap_session_t *session, const uint8_t *data, size_t datalen)
Function interface for datagram data transmission.
int dtls_event
Tracking any (D)TLS events on this sesison.
uint8_t verify_peer_cert
Set to 1 to support this version of the struct.
uint64_t version
(D)TLS runtime Library Version
size_t(* get_client_psk)(const coap_session_t *session, const uint8_t *hint, size_t hint_len, uint8_t *identity, size_t *identity_len, size_t max_identity_len, uint8_t *psk, size_t max_psk_len)
void * coap_tls_new_client_session(coap_session_t *session UNUSED, int *connected UNUSED)
const char * coap_session_str(const coap_session_t *session)
Get session description.
const char * coap_socket_strerror(void)
unsigned int max_retransmit
maximum re-transmit count (default 4)
int coap_dtls_send(struct coap_context_t *coap_context, struct coap_dtls_session_t *session, const coap_pdu_t *pdu)
int coap_tls_is_supported(void)
Check whether TLS is available.
coap_tls_library_t type
Library type.
coap_tls_version_t * coap_get_tls_library_version(void)
Determine the type and version of the underlying (D)TLS library.
const char * private_key
File location of Private Key in PEM format.
uint8_t require_peer_cert
1 if peer cert is required
coap_proto_t proto
protocol used
coap_dtls_key_t pki_key
PKI key definition.
coap_pki_key_pem_t pem
for PEM keys
char * client_sni
If not NULL, SNI to use in client TLS setup.
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
The structure that holds the PKI key information.
unsigned int coap_dtls_get_overhead(coap_session_t *session UNUSED)
const uint8_t * public_cert
ASN1 (DER) Public Cert.
const char * ca_file
File location of Common CA in PEM format.
size_t ca_cert_len
ASN1 CA Cert length.
coap_socket_t sock
socket object for the session, if any
ssize_t coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len)
static int dtls_log_level
The structure used for returning the underlying (D)TLS library information.
#define COAP_EVENT_DTLS_CLOSED
(D)TLS events for COAP_PROTO_DTLS and COAP_PROTO_TLS
int coap_handle_dgram(coap_context_t *ctx, coap_session_t *session, uint8_t *msg, size_t msg_len)
Parses and interprets a CoAP datagram with context ctx.
int coap_dtls_context_set_psk(coap_context_t *ctx UNUSED, const char *hint UNUSED, coap_dtls_role_t role UNUSED)
uint8_t cert_chain_validation
1 if to check cert_chain_verify_depth
union coap_dtls_key_t::@1 key
coap_session_state_t state
current state of relationaship with peer
Internal function invoked for client.
const uint8_t * private_key
ASN1 (DER) Private Key.
uint8_t check_cert_revocation
1 if revocation checks wanted
#define COAP_EVENT_DTLS_ERROR
#define COAP_EVENT_DTLS_CONNECTED
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.
void * coap_dtls_new_server_session(coap_session_t *session UNUSED)
void coap_session_connected(coap_session_t *session)
Notify session that it has just connected or reconnected.
The structure used for defining the PKI setup data to be used.
int coap_dtls_context_set_pki_root_cas(struct coap_context_t *ctx UNUSED, const char *ca_file UNUSED, const char *ca_path UNUSED)
uint8_t cert_chain_verify_depth
recommended depth is 3
size_t(* get_server_psk)(const coap_session_t *session, const uint8_t *identity, size_t identity_len, uint8_t *psk, size_t max_psk_len)
void coap_dtls_handle_timeout(coap_session_t *session UNUSED)
const char * public_cert
File location of Public Cert in PEM format.
void coap_dtls_startup(void)
Initialize the underlying (D)TLS Library layer.
coap_tick_t coap_dtls_get_timeout(coap_session_t *session UNUSED, coap_tick_t now UNUSED)
#define COAP_PROTO_NOT_RELIABLE(p)
void coap_dtls_free_context(struct coap_dtls_context_t *dtls_context)
Releases the storage allocated for dtls_context.
coap_socket_flags_t flags
void coap_session_disconnected(coap_session_t *session, coap_nack_reason_t reason)
Notify session that it has failed.
#define coap_log(level,...)
Logging function.
const uint8_t * ca_cert
ASN1 (DER) Common CA Cert.
size_t public_cert_len
ASN1 Public Cert length.
coap_tick_t coap_dtls_get_context_timeout(void *dtls_context UNUSED)
uint64_t built_version
(D)TLS Built against Library Version
void coap_dtls_session_update_mtu(coap_session_t *session UNUSED)
unsigned int dtls_timeout_count
dtls setup retry counter
The CoAP stack's global state is stored in a coap_context_t object.
int coap_dtls_is_context_timeout(void)
Check if timeout is handled per CoAP session or per CoAP context.
size_t private_key_len
ASN1 Private Key length.
Pulls together all the internal only header files.
coap_pki_key_asn1_t asn1
for ASN.1 (DER) keys