22 #include "coap_config.h" 26 #define MIN_GNUTLS_VERSION "3.3.0" 35 #include <gnutls/gnutls.h> 36 #include <gnutls/x509.h> 37 #include <gnutls/dtls.h> 41 #define UNUSED __attribute__((unused)) 46 typedef struct coap_ssl_t {
58 typedef struct coap_gnutls_env_t {
59 gnutls_session_t g_session;
60 gnutls_psk_client_credentials_t psk_cl_credentials;
61 gnutls_psk_server_credentials_t psk_sv_credentials;
62 gnutls_certificate_credentials_t pki_credentials;
63 coap_ssl_t coap_ssl_data;
66 int seen_client_hello;
69 #define IS_PSK (1 << 0) 70 #define IS_PKI (1 << 1) 71 #define IS_CLIENT (1 << 6) 72 #define IS_SERVER (1 << 7) 74 typedef struct sni_entry {
77 gnutls_certificate_credentials_t pki_credentials;
80 typedef struct coap_gnutls_context_t {
84 sni_entry *sni_entry_list;
85 gnutls_datum_t alpn_proto;
88 gnutls_priority_t priority_cache;
89 } coap_gnutls_context_t;
91 typedef enum coap_free_bye_t {
97 #if (GNUTLS_VERSION_NUMBER >= 0x030505) 98 #define VARIANTS "NORMAL:+ECDHE-PSK:+PSK:+ECDHE-ECDSA:+AES-128-CCM-8" 100 #define VARIANTS "NORMAL:+ECDHE-PSK:+PSK" 103 #define G_ACTION(xx) do { \ 105 } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) 107 #define G_CHECK(xx,func) do { \ 108 if ((ret = (xx)) < 0) { \ 109 coap_log(LOG_WARNING, "%s: '%s'\n", func, gnutls_strerror(ret)); \ 114 #define G_ACTION_CHECK(xx,func) do { \ 121 static int post_client_hello_gnutls_pki(gnutls_session_t g_session);
122 static int post_client_hello_gnutls_psk(gnutls_session_t g_session);
130 if (gnutls_check_version(MIN_GNUTLS_VERSION) == NULL) {
131 coap_log(
LOG_ERR,
"GnuTLS " MIN_GNUTLS_VERSION
" or later is required\n");
143 if (gnutls_check_version(MIN_GNUTLS_VERSION) == NULL) {
144 coap_log(
LOG_ERR,
"GnuTLS " MIN_GNUTLS_VERSION
" or later is required\n");
153 const char *vers = gnutls_check_version(NULL);
159 sscanf (vers,
"%d.%d.%d", &p1, &p2, &p3);
160 version.
version = (p1 << 16) | (p2 << 8) | p3;
168 coap_gnutls_audit_log_func(gnutls_session_t g_session,
const char* text)
181 coap_gnutls_log_func(
int level,
const char* text)
198 coap_gnutls_context_t *g_context =
201 if (!g_context || !setup_data)
204 g_context->setup_data = *setup_data;
205 g_context->psk_pki_enabled |= IS_PKI;
218 coap_gnutls_context_t *g_context =
222 "coap_context_set_pki_root_cas: (D)TLS environment " 227 if (ca_file == NULL && ca_path == NULL) {
229 "coap_context_set_pki_root_cas: ca_file and/or ca_path " 233 if (g_context->root_ca_file) {
234 gnutls_free(g_context->root_ca_file);
235 g_context->root_ca_file = NULL;
238 g_context->root_ca_file = gnutls_strdup(ca_file);
240 if (g_context->root_ca_path) {
241 gnutls_free(g_context->root_ca_path);
242 g_context->root_ca_path = NULL;
245 #if (GNUTLS_VERSION_NUMBER >= 0x030306) 246 g_context->root_ca_path = gnutls_strdup(ca_path);
260 const char *identity_hint UNUSED,
263 coap_gnutls_context_t *g_context =
266 g_context->psk_pki_enabled |= IS_PSK;
277 coap_gnutls_context_t *g_context =
279 return g_context->psk_pki_enabled ? 1 : 0;
283 gnutls_global_set_audit_log_function(coap_gnutls_audit_log_func);
284 gnutls_global_set_log_function(coap_gnutls_log_func);
292 gnutls_global_set_log_level(2 + level -
LOG_DEBUG);
295 gnutls_global_set_log_level(0);
315 struct coap_gnutls_context_t *g_context =
316 (
struct coap_gnutls_context_t *)
317 gnutls_malloc(
sizeof(coap_gnutls_context_t));
320 G_CHECK(gnutls_global_init(),
"gnutls_global_init");
321 memset(g_context, 0,
sizeof(
struct coap_gnutls_context_t));
322 g_context->alpn_proto.data = gnutls_malloc(4);
323 if (g_context->alpn_proto.data) {
324 memcpy(g_context->alpn_proto.data,
"coap", 4);
325 g_context->alpn_proto.size = 4;
327 G_CHECK(gnutls_priority_init(&g_context->priority_cache, VARIANTS, &err),
328 "gnutls_priority_init");
341 coap_gnutls_context_t *g_context = (coap_gnutls_context_t *)handle;
343 gnutls_free(g_context->alpn_proto.data);
344 gnutls_free(g_context->root_ca_file);
345 gnutls_free(g_context->root_ca_path);
346 for (i = 0; i < g_context->sni_count; i++) {
347 gnutls_free(g_context->sni_entry_list[i].sni);
348 if (g_context->psk_pki_enabled & IS_PKI) {
349 gnutls_certificate_free_credentials(
350 g_context->sni_entry_list[i].pki_credentials);
353 if (g_context->sni_count)
354 gnutls_free(g_context->sni_entry_list);
356 gnutls_priority_deinit(g_context->priority_cache);
358 gnutls_global_deinit();
359 gnutls_free(g_context);
371 char **username, gnutls_datum_t *key) {
381 const size_t max_identity_len =
sizeof(identity) - 1;
387 if (c_session == NULL || c_session->
context == NULL ||
400 assert(identity_len <
sizeof(identity));
404 *username = gnutls_malloc(identity_len+1);
406 memcpy(*username, identity, identity_len);
407 *username[identity_len] =
'\0';
410 key->data = gnutls_malloc(psk_len);
412 memcpy(key->data, psk_key, psk_len);
416 return (*username && key->data) ? 0 : -1;
423 static char* get_san_or_cn(gnutls_session_t g_session)
425 unsigned int cert_list_size = 0;
426 const gnutls_datum_t *cert_list;
427 gnutls_x509_crt_t cert;
434 if (gnutls_certificate_type_get(g_session) != GNUTLS_CRT_X509)
437 cert_list = gnutls_certificate_get_peers(g_session, &cert_list_size);
438 if (cert_list_size == 0) {
442 G_CHECK(gnutls_x509_crt_init(&cert),
"gnutls_x509_crt_init");
445 G_CHECK(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER),
446 "gnutls_x509_crt_import");
448 size =
sizeof(dn) -1;
450 ret = gnutls_x509_crt_get_subject_alt_name(cert, 0, dn, &size, NULL);
453 gnutls_x509_crt_deinit(cert);
454 return gnutls_strdup(dn);
458 G_CHECK(gnutls_x509_crt_get_dn(cert, dn, &size),
"gnutls_x509_crt_get_dn");
460 gnutls_x509_crt_deinit(cert);
466 if (((cn[0] ==
'C') || (cn[0] ==
'c')) &&
467 ((cn[1] ==
'N') || (cn[1] ==
'n')) &&
476 char *ecn = strchr(cn,
',');
480 return gnutls_strdup(cn);
492 static int cert_verify_gnutls(gnutls_session_t g_session)
494 unsigned int status = 0;
497 coap_gnutls_context_t *g_context =
500 int alert = GNUTLS_A_BAD_CERTIFICATE;
503 G_CHECK(gnutls_certificate_verify_peers(g_session, NULL, 0, &status),
504 "gnutls_certificate_verify_peers");
506 cn = get_san_or_cn(g_session);
509 status &= ~(GNUTLS_CERT_INVALID);
510 if (status & (GNUTLS_CERT_NOT_ACTIVATED|GNUTLS_CERT_EXPIRED)) {
511 if (g_context->setup_data.allow_expired_certs) {
512 status &= ~(GNUTLS_CERT_NOT_ACTIVATED|GNUTLS_CERT_EXPIRED);
514 " %s: %s: overridden: '%s'\n",
516 "The certificate has an invalid usage date", cn ? cn :
"?");
519 if (status & (GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED|
520 GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE)) {
521 if (g_context->setup_data.allow_expired_crl) {
522 status &= ~(GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED|
523 GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE);
525 " %s: %s: overridden: '%s'\n",
527 "The certificate's CRL entry has an invalid usage date",
534 " %s: status 0x%x: '%s'\n",
536 status, cn ? cn :
"?");
543 if (g_context->setup_data.validate_cn_call_back) {
544 unsigned int cert_list_size = 0;
545 const gnutls_datum_t *cert_list;
546 gnutls_x509_crt_t cert;
551 const int cert_is_trusted = !status;
553 cert_list = gnutls_certificate_get_peers(g_session, &cert_list_size);
554 if (cert_list_size == 0) {
559 G_CHECK(gnutls_x509_crt_init(&cert),
"gnutls_x509_crt_init");
562 G_CHECK(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER),
563 "gnutls_x509_crt_import");
566 G_CHECK(gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, der, &size),
567 "gnutls_x509_crt_export");
568 gnutls_x509_crt_deinit(cert);
569 if (!g_context->setup_data.validate_cn_call_back(cn,
575 g_context->setup_data.cn_call_back_arg)) {
576 alert = GNUTLS_A_ACCESS_DENIED;
581 if (g_context->setup_data.additional_tls_setup_call_back) {
583 if (!g_context->setup_data.additional_tls_setup_call_back(g_session,
584 &g_context->setup_data)) {
598 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL, alert));
609 static int cert_verify_callback_gnutls(gnutls_session_t g_session)
613 if (gnutls_auth_get_type(g_session) == GNUTLS_CRD_CERTIFICATE) {
614 if (cert_verify_gnutls(g_session) == 0) {
615 G_ACTION(gnutls_alert_send(g_session,
617 GNUTLS_A_ACCESS_DENIED));
629 setup_pki_credentials(gnutls_certificate_credentials_t *pki_credentials,
630 coap_gnutls_context_t *g_context,
635 G_CHECK(gnutls_certificate_allocate_credentials(pki_credentials),
636 "gnutls_certificate_allocate_credentials");
644 G_CHECK(gnutls_certificate_set_x509_key_file(*pki_credentials,
647 GNUTLS_X509_FMT_PEM),
648 "gnutls_certificate_set_x509_key_file");
652 "***setup_pki: (D)TLS: No %s Certificate + Private " 655 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
659 G_CHECK(gnutls_certificate_set_x509_trust_file(*pki_credentials,
661 GNUTLS_X509_FMT_PEM),
662 "gnutls_certificate_set_x509_trust_file");
681 G_CHECK(gnutls_certificate_set_x509_key_mem(*pki_credentials,
684 GNUTLS_X509_FMT_DER),
685 "gnutls_certificate_set_x509_key_mem");
689 "***setup_pki: (D)TLS: No %s Certificate + Private " 692 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
696 gnutls_datum_t ca_cert;
700 sizeof(ca_cert.data));
702 G_CHECK(gnutls_certificate_set_x509_trust_mem(*pki_credentials,
704 GNUTLS_X509_FMT_DER),
705 "gnutls_certificate_set_x509_trust_mem");
710 "***setup_pki: (D)TLS: Unknown key type %d\n",
712 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
715 if (g_context->root_ca_file) {
716 G_CHECK(gnutls_certificate_set_x509_trust_file(*pki_credentials,
717 g_context->root_ca_file,
718 GNUTLS_X509_FMT_PEM),
719 "gnutls_certificate_set_x509_trust_file");
721 if (g_context->root_ca_path) {
722 #if (GNUTLS_VERSION_NUMBER >= 0x030306) 723 G_CHECK(gnutls_certificate_set_x509_trust_dir(*pki_credentials,
724 g_context->root_ca_path,
725 GNUTLS_X509_FMT_PEM),
726 "gnutls_certificate_set_x509_trust_dir");
729 if (!(g_context->psk_pki_enabled & IS_PKI)) {
731 G_CHECK(gnutls_certificate_set_x509_system_trust(*pki_credentials),
732 "gnutls_certificate_set_x509_system_trust");
737 gnutls_certificate_set_verify_function(*pki_credentials,
738 cert_verify_callback_gnutls);
743 gnutls_certificate_set_verify_limits(*pki_credentials,
749 gnutls_certificate_set_verify_flags(*pki_credentials,
750 GNUTLS_VERIFY_DO_NOT_ALLOW_SAME);
754 gnutls_certificate_set_verify_flags(*pki_credentials,
755 GNUTLS_VERIFY_DO_NOT_ALLOW_SAME |
756 GNUTLS_VERIFY_DISABLE_CRL_CHECKS);
759 return GNUTLS_E_SUCCESS;
770 post_client_hello_gnutls_pki(gnutls_session_t g_session)
774 coap_gnutls_context_t *g_context =
776 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
777 int ret = GNUTLS_E_SUCCESS;
780 g_env->seen_client_hello = 1;
782 if (g_context->setup_data.validate_sni_call_back) {
789 name = gnutls_malloc(len);
791 return GNUTLS_E_MEMORY_ERROR;
794 ret = gnutls_server_name_get(g_session, name, &len, &type, i);
795 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
797 new_name = gnutls_realloc(name, len);
798 if (new_name == NULL) {
799 ret = GNUTLS_E_MEMORY_ERROR;
807 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
810 if (ret != GNUTLS_E_SUCCESS)
813 if (type != GNUTLS_NAME_DNS)
824 for (i = 0; i < g_context->sni_count; i++) {
825 if (strcmp(name, g_context->sni_entry_list[i].sni) == 0) {
829 if (i == g_context->sni_count) {
834 g_context->setup_data.validate_sni_call_back(name,
835 g_context->setup_data.sni_call_back_arg);
837 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
838 GNUTLS_A_UNRECOGNIZED_NAME));
839 ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
843 g_context->sni_entry_list = gnutls_realloc(g_context->sni_entry_list,
844 (i+1)*
sizeof(sni_entry));
845 g_context->sni_entry_list[i].sni = gnutls_strdup(name);
846 g_context->sni_entry_list[i].pki_key = *new_entry;
847 sni_setup_data = g_context->setup_data;
848 sni_setup_data.
pki_key = *new_entry;
849 if ((ret = setup_pki_credentials(
850 &g_context->sni_entry_list[i].pki_credentials,
854 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
855 GNUTLS_A_BAD_CERTIFICATE));
859 g_context->sni_count++;
861 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
862 g_context->sni_entry_list[i].pki_credentials),
863 "gnutls_credentials_set");
879 post_client_hello_gnutls_psk(gnutls_session_t g_session)
883 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
885 g_env->seen_client_hello = 1;
886 return GNUTLS_E_SUCCESS;
894 setup_client_ssl_session(
coap_session_t *c_session, coap_gnutls_env_t *g_env)
896 coap_gnutls_context_t *g_context =
900 g_context->psk_pki_enabled |= IS_CLIENT;
901 if (g_context->psk_pki_enabled & IS_PSK) {
902 char *identity = NULL;
903 gnutls_datum_t psk_key;
905 G_CHECK(gnutls_psk_allocate_client_credentials(&g_env->psk_cl_credentials),
906 "gnutls_psk_allocate_client_credentials");
908 G_CHECK(gnutls_psk_set_client_credentials(g_env->psk_cl_credentials,
912 "gnutls_psk_set_client_credentials");
913 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_PSK,
914 g_env->psk_cl_credentials),
915 "gnutls_credentials_set");
916 gnutls_free(identity);
917 gnutls_free(psk_key.data);
920 if ((g_context->psk_pki_enabled & IS_PKI) ||
921 (g_context->psk_pki_enabled & (IS_PSK | IS_PKI)) == 0) {
927 G_CHECK(setup_pki_credentials(&g_env->pki_credentials, g_context,
929 "setup_pki_credentials");
931 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
932 g_env->pki_credentials),
933 "gnutls_credentials_set");
936 G_CHECK(gnutls_alpn_set_protocols(g_env->g_session,
937 &g_context->alpn_proto, 1, 0),
938 "gnutls_alpn_set_protocols");
942 G_CHECK(gnutls_server_name_set(g_env->g_session, GNUTLS_NAME_DNS,
945 "gnutls_server_name_set");
948 return GNUTLS_E_SUCCESS;
962 psk_server_callback(gnutls_session_t g_session,
963 const char *identity,
968 size_t identity_len = 0;
973 identity_len = strlen(identity);
978 (
int)identity_len, identity);
980 if (c_session == NULL || c_session->
context == NULL ||
988 key->data = gnutls_malloc(psk_len);
989 memcpy(key->data, buf, psk_len);
999 setup_server_ssl_session(
coap_session_t *c_session, coap_gnutls_env_t *g_env)
1001 coap_gnutls_context_t *g_context =
1003 int ret = GNUTLS_E_SUCCESS;
1005 g_context->psk_pki_enabled |= IS_SERVER;
1006 if (g_context->psk_pki_enabled & IS_PSK) {
1007 G_CHECK(gnutls_psk_allocate_server_credentials(&g_env->psk_sv_credentials),
1008 "gnutls_psk_allocate_server_credentials");
1009 gnutls_psk_set_server_credentials_function(g_env->psk_sv_credentials,
1010 psk_server_callback);
1012 gnutls_handshake_set_post_client_hello_function(g_env->g_session,
1013 post_client_hello_gnutls_psk);
1015 G_CHECK(gnutls_credentials_set(g_env->g_session,
1017 g_env->psk_sv_credentials),
1018 "gnutls_credentials_set\n");
1021 if (g_context->psk_pki_enabled & IS_PKI) {
1023 G_CHECK(setup_pki_credentials(&g_env->pki_credentials, g_context,
1025 "setup_pki_credentials");
1028 gnutls_certificate_server_set_request(g_env->g_session,
1029 GNUTLS_CERT_REQUIRE);
1032 gnutls_certificate_server_set_request(g_env->g_session, GNUTLS_CERT_IGNORE);
1035 gnutls_handshake_set_post_client_hello_function(g_env->g_session,
1036 post_client_hello_gnutls_pki);
1038 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
1039 g_env->pki_credentials),
1040 "gnutls_credentials_set\n");
1042 return GNUTLS_E_SUCCESS;
1054 coap_dgram_read(gnutls_transport_ptr_t context,
void *out,
size_t outl)
1058 coap_ssl_t *data = &((coap_gnutls_env_t *)c_session->
tls)->coap_ssl_data;
1060 if (!c_session->
tls) {
1066 if (data != NULL && data->pdu_len > 0) {
1067 if (outl < data->pdu_len) {
1068 memcpy(out, data->pdu, outl);
1071 data->pdu_len -= outl;
1073 memcpy(out, data->pdu, data->pdu_len);
1074 ret = data->pdu_len;
1075 if (!data->peekmode) {
1096 coap_dgram_write(gnutls_transport_ptr_t context,
const void *send_buffer,
1097 size_t send_buffer_length) {
1098 ssize_t result = -1;
1103 if (result != (
int)send_buffer_length) {
1119 receive_timeout(gnutls_transport_ptr_t context,
unsigned int ms UNUSED) {
1123 fd_set readfds, writefds, exceptfds;
1125 int nfds = c_session->
sock.
fd +1;
1129 FD_ZERO(&exceptfds);
1130 FD_SET (c_session->
sock.
fd, &readfds);
1131 FD_SET (c_session->
sock.
fd, &writefds);
1132 FD_SET (c_session->
sock.
fd, &exceptfds);
1137 return select(nfds, &readfds, &writefds, &exceptfds, &tv);
1142 static coap_gnutls_env_t *
1145 coap_gnutls_context_t *g_context =
1147 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1148 int flags = type | GNUTLS_DATAGRAM | GNUTLS_NONBLOCK;
1154 g_env = gnutls_malloc(
sizeof(coap_gnutls_env_t));
1158 memset(g_env, 0,
sizeof(
struct coap_gnutls_env_t));
1160 G_CHECK(gnutls_init(&g_env->g_session, flags),
"gnutls_init");
1162 gnutls_transport_set_pull_function(g_env->g_session, coap_dgram_read);
1163 gnutls_transport_set_push_function(g_env->g_session, coap_dgram_write);
1164 gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
1166 gnutls_transport_set_ptr(g_env->g_session, c_session);
1168 if (type == GNUTLS_SERVER) {
1169 G_CHECK(setup_server_ssl_session(c_session, g_env),
1170 "setup_server_ssl_session");
1173 G_CHECK(setup_client_ssl_session(c_session, g_env),
1174 "setup_client_ssl_session");
1177 G_CHECK(gnutls_priority_set(g_env->g_session, g_context->priority_cache),
1178 "gnutls_priority_set");
1179 gnutls_handshake_set_timeout(g_env->g_session,
1180 GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
1191 coap_dtls_free_gnutls_env(coap_gnutls_context_t *g_context,
1192 coap_gnutls_env_t *g_env,
1193 coap_free_bye_t free_bye)
1199 if (free_bye != COAP_FREE_BYE_NONE) {
1201 gnutls_bye(g_env->g_session, free_bye == COAP_FREE_BYE_AS_UDP ?
1202 GNUTLS_SHUT_WR : GNUTLS_SHUT_RDWR);
1204 gnutls_deinit(g_env->g_session);
1205 g_env->g_session = NULL;
1206 if (g_context->psk_pki_enabled & IS_PSK) {
1207 if (g_context->psk_pki_enabled & IS_CLIENT) {
1208 gnutls_psk_free_client_credentials(g_env->psk_cl_credentials);
1209 g_env->psk_cl_credentials = NULL;
1212 gnutls_psk_free_server_credentials(g_env->psk_sv_credentials);
1213 g_env->psk_sv_credentials = NULL;
1216 if (g_context->psk_pki_enabled & IS_PKI) {
1217 gnutls_certificate_free_credentials(g_env->pki_credentials);
1218 g_env->pki_credentials = NULL;
1225 coap_gnutls_env_t *g_env =
1228 gnutls_transport_set_ptr(g_env->g_session, c_session);
1235 static void log_last_alert(gnutls_session_t g_session) {
1236 int last_alert = gnutls_alert_get(g_session);
1239 last_alert, gnutls_alert_get_name(last_alert));
1248 do_gnutls_handshake(
coap_session_t *c_session, coap_gnutls_env_t *g_env) {
1251 ret = gnutls_handshake(g_env->g_session);
1253 case GNUTLS_E_SUCCESS:
1254 g_env->established = 1;
1259 case GNUTLS_E_INTERRUPTED:
1263 case GNUTLS_E_AGAIN:
1267 case GNUTLS_E_INSUFFICIENT_CREDENTIALS:
1269 "Insufficient credentials provided.\n");
1272 case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET:
1273 case GNUTLS_E_FATAL_ALERT_RECEIVED:
1274 log_last_alert(g_env->g_session);
1278 case GNUTLS_E_WARNING_ALERT_RECEIVED:
1279 log_last_alert(g_env->g_session);
1283 case GNUTLS_E_NO_CERTIFICATE_FOUND:
1285 "Client Certificate requested and required, but not provided\n" 1287 G_ACTION(gnutls_alert_send(g_env->g_session, GNUTLS_AL_FATAL,
1288 GNUTLS_A_BAD_CERTIFICATE));
1292 case GNUTLS_E_DECRYPTION_FAILED:
1294 "do_gnutls_handshake: session establish " 1295 "returned %d: '%s'\n",
1296 ret, gnutls_strerror(ret));
1297 G_ACTION(gnutls_alert_send(g_env->g_session, GNUTLS_AL_FATAL,
1298 GNUTLS_A_DECRYPT_ERROR));
1302 case GNUTLS_E_UNKNOWN_CIPHER_SUITE:
1304 case GNUTLS_E_TIMEDOUT:
1310 "do_gnutls_handshake: session establish " 1311 "returned %d: '%s'\n",
1312 ret, gnutls_strerror(ret));
1320 coap_gnutls_env_t *g_env = coap_dtls_new_gnutls_env(c_session, GNUTLS_CLIENT);
1324 ret = do_gnutls_handshake(c_session, g_env);
1329 COAP_FREE_BYE_AS_UDP : COAP_FREE_BYE_AS_TCP);
1337 if (c_session && c_session->
context) {
1341 COAP_FREE_BYE_AS_UDP : COAP_FREE_BYE_AS_TCP);
1342 c_session->
tls = NULL;
1347 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1351 G_CHECK(gnutls_dtls_set_data_mtu(g_env->g_session, c_session->
mtu),
1352 "gnutls_dtls_set_data_mtu");
1363 const uint8_t *data,
size_t data_len) {
1365 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1370 if (g_env->established) {
1371 ret = gnutls_record_send(g_env->g_session, data, data_len);
1375 case GNUTLS_E_AGAIN:
1378 case GNUTLS_E_FATAL_ALERT_RECEIVED:
1379 log_last_alert(g_env->g_session);
1393 ret = do_gnutls_handshake(c_session, g_env);
1438 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1440 coap_ssl_t *ssl_data = &g_env->coap_ssl_data;
1446 if (ssl_data->pdu_len)
1449 ssl_data->pdu = data;
1450 ssl_data->pdu_len = (unsigned)data_len;
1453 if (g_env->established) {
1457 gnutls_transport_set_ptr(g_env->g_session, c_session);
1460 ret = gnutls_record_recv(g_env->g_session, pdu, (
int)
sizeof(pdu));
1464 else if (ret == 0) {
1469 "coap_dtls_receive: gnutls_record_recv returned %d\n", ret);
1474 ret = do_gnutls_handshake(c_session, g_env);
1495 #define DTLS_CT_HANDSHAKE 22 1496 #define DTLS_HT_CLIENT_HELLO 1 1499 typedef struct __attribute__((__packed__)) {
1506 } dtls_record_handshake_t;
1508 #define OFF_CONTENT_TYPE 0 1509 #define OFF_HANDSHAKE_TYPE 13 1520 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1521 coap_ssl_t *ssl_data = g_env ? &g_env->coap_ssl_data : NULL;
1529 if (data_len < (OFF_HANDSHAKE_TYPE + 1)) {
1531 "coap_dtls_hello: ContentType %d Short Packet (%ld < %d) dropped\n",
1532 data[OFF_CONTENT_TYPE], data_len, OFF_HANDSHAKE_TYPE + 1);
1535 if (data[OFF_CONTENT_TYPE] != DTLS_CT_HANDSHAKE ||
1536 data[OFF_HANDSHAKE_TYPE] != DTLS_HT_CLIENT_HELLO) {
1538 "coap_dtls_hello: ContentType %d Handshake %d dropped\n",
1539 data[OFF_CONTENT_TYPE], data[OFF_HANDSHAKE_TYPE]);
1543 g_env = coap_dtls_new_gnutls_env(c_session, GNUTLS_SERVER);
1545 c_session->
tls = g_env;
1546 ssl_data = &g_env->coap_ssl_data;
1547 ssl_data->pdu = data;
1548 ssl_data->pdu_len = (unsigned)data_len;
1549 gnutls_dtls_set_data_mtu(g_env->g_session, c_session->
mtu);
1550 ret = do_gnutls_handshake(c_session, g_env);
1551 if (ret == 1 || g_env->seen_client_hello) {
1557 g_env->seen_client_hello = 0;
1564 coap_dtls_free_gnutls_env(
1566 g_env, COAP_FREE_BYE_NONE);
1567 c_session->
tls = NULL;
1572 ssl_data->pdu = data;
1573 ssl_data->pdu_len = (unsigned)data_len;
1575 ret = do_gnutls_handshake(c_session, g_env);
1576 if (ret == 1 || g_env->seen_client_hello) {
1582 g_env->seen_client_hello = 0;
1598 coap_sock_read(gnutls_transport_ptr_t context,
void *out,
size_t outl) {
1604 ret = recv(c_session->
sock.
fd, (
char *)out, (
int)outl, 0);
1606 ret = recv(c_session->
sock.
fd, out, outl, 0);
1614 else if (ret < (ssize_t)outl)
1627 coap_sock_write(gnutls_transport_ptr_t context,
const void *in,
size_t inl) {
1640 coap_gnutls_env_t *g_env = gnutls_malloc(
sizeof(coap_gnutls_env_t));
1641 coap_gnutls_context_t *g_context =
1643 int flags = GNUTLS_CLIENT;
1649 memset(g_env, 0,
sizeof(
struct coap_gnutls_env_t));
1652 G_CHECK(gnutls_init(&g_env->g_session, flags),
"gnutls_init");
1654 gnutls_transport_set_pull_function(g_env->g_session, coap_sock_read);
1655 gnutls_transport_set_push_function(g_env->g_session, coap_sock_write);
1656 gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
1658 gnutls_transport_set_ptr(g_env->g_session, c_session);
1660 setup_client_ssl_session(c_session, g_env);
1662 gnutls_priority_set(g_env->g_session, g_context->priority_cache);
1663 gnutls_handshake_set_timeout(g_env->g_session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
1665 ret = do_gnutls_handshake(c_session, g_env);
1680 coap_gnutls_env_t *g_env = gnutls_malloc(
sizeof(coap_gnutls_env_t));
1681 coap_gnutls_context_t *g_context =
1683 int flags = GNUTLS_SERVER;
1688 memset(g_env, 0,
sizeof(
struct coap_gnutls_env_t));
1691 G_CHECK(gnutls_init(&g_env->g_session, flags),
"gnutls_init");
1693 gnutls_transport_set_pull_function(g_env->g_session, coap_sock_read);
1694 gnutls_transport_set_push_function(g_env->g_session, coap_sock_write);
1695 gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
1697 gnutls_transport_set_ptr(g_env->g_session, c_session);
1699 setup_server_ssl_session(c_session, g_env);
1701 gnutls_priority_set(g_env->g_session, g_context->priority_cache);
1702 gnutls_handshake_set_timeout(g_env->g_session,
1703 GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
1705 c_session->
tls = g_env;
1706 ret = do_gnutls_handshake(c_session, g_env);
1731 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1736 if (g_env->established) {
1737 ret = gnutls_record_send(g_env->g_session, data, data_len);
1741 case GNUTLS_E_AGAIN:
1744 case GNUTLS_E_FATAL_ALERT_RECEIVED:
1745 log_last_alert(g_env->g_session);
1751 "coap_tls_write: gnutls_record_send " 1752 "returned %d: '%s'\n",
1753 ret, gnutls_strerror(ret));
1763 ret = do_gnutls_handshake(c_session, g_env);
1795 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1802 if (!g_env->established) {
1803 ret = do_gnutls_handshake(c_session, g_env);
1810 if (g_env->established) {
1811 ret = gnutls_record_recv(g_env->g_session, data, (
int)data_len);
1817 case GNUTLS_E_AGAIN:
1821 case GNUTLS_E_PULL_ERROR:
1826 "coap_tls_read: gnutls_record_recv " 1827 "returned %d: '%s'\n",
1828 ret, gnutls_strerror(ret));
1852 #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_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)
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)
Check whether DTLS is available.
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_dtls_free_session(coap_dtls_session_t *session UNUSED)
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.
int coap_tls_is_supported(void)
Check whether TLS is available.
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.
coap_session_t hello
special session of DTLS hello messages
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_TLS_LIBRARY_GNUTLS
Using GnuTLS library.
#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.
void coap_dtls_free_context(struct coap_dtls_context_t *dtls_context)
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)
struct coap_dtls_context_t * coap_dtls_new_context(struct coap_context_t *coap_context UNUSED)
uint8_t cert_chain_verify_depth
recommended depth is 3
coap_tick_t coap_dtls_get_timeout(coap_session_t *session UNUSED)
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.
#define COAP_PROTO_NOT_RELIABLE(p)
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)
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.
struct coap_endpoint_t * endpoint
session's endpoint
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)
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.
coap_pki_key_asn1_t asn1
for ASN.1 (DER) keys