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 #if (GNUTLS_VERSION_NUMBER >= 0x030505) 92 #define VARIANTS "NORMAL:+ECDHE-PSK:+PSK:+ECDHE-ECDSA:+AES-128-CCM-8" 94 #define VARIANTS "NORMAL:+ECDHE-PSK:+PSK" 97 #define G_ACTION(xx) do { \ 99 } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) 101 #define G_CHECK(xx,func) do { \ 102 if ((ret = (xx)) < 0) { \ 103 coap_log(LOG_WARNING, "%s: '%s'\n", func, gnutls_strerror(ret)); \ 108 #define G_ACTION_CHECK(xx,func) do { \ 115 static int post_client_hello_gnutls_pki(gnutls_session_t g_session);
116 static int post_client_hello_gnutls_psk(gnutls_session_t g_session);
124 if (gnutls_check_version(MIN_GNUTLS_VERSION) == NULL) {
125 coap_log(
LOG_ERR,
"GnuTLS " MIN_GNUTLS_VERSION
" or later is required\n");
137 if (gnutls_check_version(MIN_GNUTLS_VERSION) == NULL) {
138 coap_log(
LOG_ERR,
"GnuTLS " MIN_GNUTLS_VERSION
" or later is required\n");
147 const char *vers = gnutls_check_version(NULL);
153 sscanf (vers,
"%d.%d.%d", &p1, &p2, &p3);
154 version.
version = (p1 << 16) | (p2 << 8) | p3;
162 coap_gnutls_audit_log_func(gnutls_session_t g_session,
const char* text)
170 coap_gnutls_log_func(
int level,
const char* text)
187 coap_gnutls_context_t *g_context =
190 if (!g_context || !setup_data)
193 g_context->setup_data = *setup_data;
194 g_context->psk_pki_enabled |= IS_PKI;
207 coap_gnutls_context_t *g_context =
211 "coap_context_set_pki_root_cas: (D)TLS environment " 216 if (ca_file == NULL && ca_path == NULL) {
218 "coap_context_set_pki_root_cas: ca_file and/or ca_path " 222 if (g_context->root_ca_file) {
223 gnutls_free(g_context->root_ca_file);
224 g_context->root_ca_file = NULL;
227 g_context->root_ca_file = gnutls_strdup(ca_file);
229 if (g_context->root_ca_path) {
230 gnutls_free(g_context->root_ca_path);
231 g_context->root_ca_path = NULL;
234 #if (GNUTLS_VERSION_NUMBER >= 0x030306) 235 g_context->root_ca_path = gnutls_strdup(ca_path);
249 const char *identity_hint UNUSED,
252 coap_gnutls_context_t *g_context =
255 g_context->psk_pki_enabled |= IS_PSK;
266 coap_gnutls_context_t *g_context =
268 return g_context->psk_pki_enabled ? 1 : 0;
272 gnutls_global_set_audit_log_function(coap_gnutls_audit_log_func);
273 gnutls_global_set_log_function(coap_gnutls_log_func);
281 gnutls_global_set_log_level(2 + level -
LOG_DEBUG);
284 gnutls_global_set_log_level(0);
304 struct coap_gnutls_context_t *g_context =
305 (
struct coap_gnutls_context_t *)
306 gnutls_malloc(
sizeof(coap_gnutls_context_t));
309 G_CHECK(gnutls_global_init(),
"gnutls_global_init");
310 memset(g_context, 0,
sizeof(
struct coap_gnutls_context_t));
311 g_context->alpn_proto.data = gnutls_malloc(4);
312 if (g_context->alpn_proto.data) {
313 memcpy(g_context->alpn_proto.data,
"coap", 4);
314 g_context->alpn_proto.size = 4;
316 G_CHECK(gnutls_priority_init(&g_context->priority_cache, VARIANTS, &err),
317 "gnutls_priority_init");
330 coap_gnutls_context_t *g_context = (coap_gnutls_context_t *)handle;
332 gnutls_free(g_context->alpn_proto.data);
333 gnutls_free(g_context->root_ca_file);
334 gnutls_free(g_context->root_ca_path);
335 for (i = 0; i < g_context->sni_count; i++) {
336 gnutls_free(g_context->sni_entry_list[i].sni);
337 if (g_context->psk_pki_enabled & IS_PKI) {
338 gnutls_certificate_free_credentials(
339 g_context->sni_entry_list[i].pki_credentials);
342 if (g_context->sni_count)
343 gnutls_free(g_context->sni_entry_list);
345 gnutls_priority_deinit(g_context->priority_cache);
347 gnutls_global_deinit();
348 gnutls_free(g_context);
359 psk_client_callback(gnutls_session_t g_session,
360 char **username, gnutls_datum_t *key) {
368 if (c_session == NULL || c_session->
context == NULL ||
378 sizeof (identity) - 1,
381 if (identity_len <
sizeof (identity))
382 identity[identity_len] = 0;
384 *username = gnutls_malloc(identity_len+1);
385 memcpy(*username, identity, identity_len+1);
387 key->data = gnutls_malloc(psk_len);
388 memcpy(key->data, psk_key, psk_len);
398 static char* get_san_or_cn(gnutls_session_t g_session)
400 unsigned int cert_list_size = 0;
401 const gnutls_datum_t *cert_list;
402 gnutls_x509_crt_t cert;
409 if (gnutls_certificate_type_get(g_session) != GNUTLS_CRT_X509)
412 cert_list = gnutls_certificate_get_peers(g_session, &cert_list_size);
413 if (cert_list_size == 0) {
417 G_CHECK(gnutls_x509_crt_init(&cert),
"gnutls_x509_crt_init");
420 G_CHECK(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER),
421 "gnutls_x509_crt_import");
423 size =
sizeof(dn) -1;
425 ret = gnutls_x509_crt_get_subject_alt_name(cert, 0, dn, &size, NULL);
428 gnutls_x509_crt_deinit(cert);
429 return gnutls_strdup(dn);
433 G_CHECK(gnutls_x509_crt_get_dn(cert, dn, &size),
"gnutls_x509_crt_get_dn");
435 gnutls_x509_crt_deinit(cert);
441 if (((cn[0] ==
'C') || (cn[0] ==
'c')) &&
442 ((cn[1] ==
'N') || (cn[1] ==
'n')) &&
451 char *ecn = strchr(cn,
',');
455 return gnutls_strdup(cn);
467 static int cert_verify_gnutls(gnutls_session_t g_session)
469 unsigned int status = 0;
472 coap_gnutls_context_t *g_context =
475 int alert = GNUTLS_A_BAD_CERTIFICATE;
478 G_CHECK(gnutls_certificate_verify_peers(g_session, NULL, 0, &status),
479 "gnutls_certificate_verify_peers");
481 cn = get_san_or_cn(g_session);
484 status &= ~(GNUTLS_CERT_INVALID);
485 if (status & (GNUTLS_CERT_NOT_ACTIVATED|GNUTLS_CERT_EXPIRED)) {
486 if (g_context->setup_data.allow_expired_certs) {
487 status &= ~(GNUTLS_CERT_NOT_ACTIVATED|GNUTLS_CERT_EXPIRED);
489 " %s: %s: overridden: '%s'\n",
491 "The certificate has an invalid usage date", cn ? cn :
"?");
494 if (status & (GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED|
495 GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE)) {
496 if (g_context->setup_data.allow_expired_crl) {
497 status &= ~(GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED|
498 GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE);
500 " %s: %s: overridden: '%s'\n",
502 "The certificate's CRL entry has an invalid usage date",
509 " %s: status 0x%x: '%s'\n",
511 status, cn ? cn :
"?");
518 if (g_context->setup_data.validate_cn_call_back) {
519 unsigned int cert_list_size = 0;
520 const gnutls_datum_t *cert_list;
521 gnutls_x509_crt_t cert;
525 cert_list = gnutls_certificate_get_peers(g_session, &cert_list_size);
526 if (cert_list_size == 0) {
531 G_CHECK(gnutls_x509_crt_init(&cert),
"gnutls_x509_crt_init");
534 G_CHECK(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER),
535 "gnutls_x509_crt_import");
538 G_CHECK(gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, der, &size),
539 "gnutls_x509_crt_export");
540 gnutls_x509_crt_deinit(cert);
541 if (!g_context->setup_data.validate_cn_call_back(cn,
547 g_context->setup_data.cn_call_back_arg)) {
548 alert = GNUTLS_A_ACCESS_DENIED;
553 if (g_context->setup_data.additional_tls_setup_call_back) {
555 if (!g_context->setup_data.additional_tls_setup_call_back(g_session,
556 &g_context->setup_data)) {
570 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL, alert));
581 static int cert_verify_callback_gnutls(gnutls_session_t g_session)
585 if (gnutls_auth_get_type(g_session) == GNUTLS_CRD_CERTIFICATE) {
586 if (cert_verify_gnutls(g_session) == 0) {
587 G_ACTION(gnutls_alert_send(g_session,
589 GNUTLS_A_ACCESS_DENIED));
601 setup_pki_credentials(gnutls_certificate_credentials_t *pki_credentials,
602 coap_gnutls_context_t *g_context,
613 G_CHECK(gnutls_certificate_allocate_credentials(pki_credentials),
614 "gnutls_certificate_allocate_credentials");
616 G_CHECK(gnutls_certificate_set_x509_key_file(*pki_credentials,
619 GNUTLS_X509_FMT_PEM),
620 "gnutls_certificate_set_x509_key_file");
624 "***setup_pki: (D)TLS: No Client Certificate + Private " 626 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
630 G_CHECK(gnutls_certificate_set_x509_trust_file(*pki_credentials,
632 GNUTLS_X509_FMT_PEM),
633 "gnutls_certificate_set_x509_trust_file");
652 G_CHECK(gnutls_certificate_set_x509_key_mem(*pki_credentials,
655 GNUTLS_X509_FMT_DER),
656 "gnutls_certificate_set_x509_key_mem");
660 "***setup_pki: (D)TLS: No Client Certificate + Private " 662 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
666 gnutls_datum_t ca_cert;
670 sizeof(ca_cert.data));
672 G_CHECK(gnutls_certificate_set_x509_trust_mem(*pki_credentials,
674 GNUTLS_X509_FMT_DER),
675 "gnutls_certificate_set_x509_trust_mem");
680 "***setup_pki: (D)TLS: Unknown key type %d\n",
682 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
685 if (g_context->root_ca_file) {
686 G_CHECK(gnutls_certificate_set_x509_trust_file(*pki_credentials,
687 g_context->root_ca_file,
688 GNUTLS_X509_FMT_PEM),
689 "gnutls_certificate_set_x509_trust_file");
691 if (g_context->root_ca_path) {
692 #if (GNUTLS_VERSION_NUMBER >= 0x030306) 693 G_CHECK(gnutls_certificate_set_x509_trust_dir(*pki_credentials,
694 g_context->root_ca_path,
695 GNUTLS_X509_FMT_PEM),
696 "gnutls_certificate_set_x509_trust_dir");
702 gnutls_certificate_set_verify_function(*pki_credentials,
703 cert_verify_callback_gnutls);
708 gnutls_certificate_set_verify_limits(*pki_credentials,
714 gnutls_certificate_set_verify_flags(*pki_credentials,
715 GNUTLS_VERIFY_DO_NOT_ALLOW_SAME);
719 gnutls_certificate_set_verify_flags(*pki_credentials,
720 GNUTLS_VERIFY_DO_NOT_ALLOW_SAME |
721 GNUTLS_VERIFY_DISABLE_CRL_CHECKS);
724 return GNUTLS_E_SUCCESS;
735 post_client_hello_gnutls_pki(gnutls_session_t g_session)
739 coap_gnutls_context_t *g_context =
741 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
742 int ret = GNUTLS_E_SUCCESS;
745 g_env->seen_client_hello = 1;
747 if (g_context->setup_data.validate_sni_call_back) {
754 name = gnutls_malloc(len);
756 return GNUTLS_E_MEMORY_ERROR;
759 ret = gnutls_server_name_get(g_session, name, &len, &type, i);
760 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
762 new_name = gnutls_realloc(name, len);
763 if (new_name == NULL) {
764 ret = GNUTLS_E_MEMORY_ERROR;
772 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
775 if (ret != GNUTLS_E_SUCCESS)
778 if (type != GNUTLS_NAME_DNS)
789 for (i = 0; i < g_context->sni_count; i++) {
790 if (strcmp(name, g_context->sni_entry_list[i].sni) == 0) {
794 if (i == g_context->sni_count) {
799 g_context->setup_data.validate_sni_call_back(name,
800 g_context->setup_data.sni_call_back_arg);
802 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
803 GNUTLS_A_UNRECOGNIZED_NAME));
804 ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
808 g_context->sni_entry_list = gnutls_realloc(g_context->sni_entry_list,
809 (i+1)*
sizeof(sni_entry));
810 g_context->sni_entry_list[i].sni = gnutls_strdup(name);
811 g_context->sni_entry_list[i].pki_key = *new_entry;
812 sni_setup_data = g_context->setup_data;
813 sni_setup_data.
pki_key = *new_entry;
814 if ((ret = setup_pki_credentials(
815 &g_context->sni_entry_list[i].pki_credentials,
817 &sni_setup_data)) < 0) {
819 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
820 GNUTLS_A_BAD_CERTIFICATE));
824 g_context->sni_count++;
826 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
827 g_context->sni_entry_list[i].pki_credentials),
828 "gnutls_credentials_set");
844 post_client_hello_gnutls_psk(gnutls_session_t g_session)
848 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
850 g_env->seen_client_hello = 1;
851 return GNUTLS_E_SUCCESS;
859 setup_client_ssl_session(
coap_session_t *c_session, coap_gnutls_env_t *g_env)
861 coap_gnutls_context_t *g_context =
865 g_context->psk_pki_enabled |= IS_CLIENT;
866 if (g_context->psk_pki_enabled & IS_PSK) {
867 char *identity = NULL;
868 gnutls_datum_t psk_key;
870 G_CHECK(gnutls_psk_allocate_client_credentials(&g_env->psk_cl_credentials),
871 "gnutls_psk_allocate_client_credentials");
872 psk_client_callback(g_env->g_session, &identity, &psk_key);
873 G_CHECK(gnutls_psk_set_client_credentials(g_env->psk_cl_credentials,
877 "gnutls_psk_set_client_credentials");
878 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_PSK,
879 g_env->psk_cl_credentials),
880 "gnutls_credentials_set");
881 gnutls_free(identity);
882 gnutls_free(psk_key.data);
885 if (g_context->psk_pki_enabled & IS_PKI) {
887 G_CHECK(setup_pki_credentials(&g_env->pki_credentials, g_context,
889 "setup_pki_credentials");
891 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
892 g_env->pki_credentials),
893 "gnutls_credentials_set");
896 G_CHECK(gnutls_alpn_set_protocols(g_env->g_session,
897 &g_context->alpn_proto, 1, 0),
898 "gnutls_alpn_set_protocols");
902 G_CHECK(gnutls_server_name_set(g_env->g_session, GNUTLS_NAME_DNS,
905 "gnutls_server_name_set");
908 return GNUTLS_E_SUCCESS;
922 psk_server_callback(gnutls_session_t g_session,
923 const char *identity,
928 size_t identity_len = 0;
933 identity_len = strlen(identity);
938 (
int)identity_len, identity);
940 if (c_session == NULL || c_session->
context == NULL ||
948 key->data = gnutls_malloc(psk_len);
949 memcpy(key->data, buf, psk_len);
959 setup_server_ssl_session(
coap_session_t *c_session, coap_gnutls_env_t *g_env)
961 coap_gnutls_context_t *g_context =
963 int ret = GNUTLS_E_SUCCESS;
965 g_context->psk_pki_enabled |= IS_SERVER;
966 if (g_context->psk_pki_enabled & IS_PSK) {
967 G_CHECK(gnutls_psk_allocate_server_credentials(&g_env->psk_sv_credentials),
968 "gnutls_psk_allocate_server_credentials");
969 gnutls_psk_set_server_credentials_function(g_env->psk_sv_credentials,
970 psk_server_callback);
972 gnutls_handshake_set_post_client_hello_function(g_env->g_session,
973 post_client_hello_gnutls_psk);
975 G_CHECK(gnutls_credentials_set(g_env->g_session,
977 g_env->psk_sv_credentials),
978 "gnutls_credentials_set\n");
981 if (g_context->psk_pki_enabled & IS_PKI) {
983 G_CHECK(setup_pki_credentials(&g_env->pki_credentials, g_context,
985 "setup_pki_credentials");
988 gnutls_certificate_server_set_request(g_env->g_session,
989 GNUTLS_CERT_REQUIRE);
992 gnutls_certificate_server_set_request(g_env->g_session, GNUTLS_CERT_IGNORE);
995 gnutls_handshake_set_post_client_hello_function(g_env->g_session,
996 post_client_hello_gnutls_pki);
998 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
999 g_env->pki_credentials),
1000 "gnutls_credentials_set\n");
1002 return GNUTLS_E_SUCCESS;
1014 coap_dgram_read(gnutls_transport_ptr_t context,
void *out,
size_t outl)
1018 coap_ssl_t *data = &((coap_gnutls_env_t *)c_session->
tls)->coap_ssl_data;
1020 if (!c_session->
tls) {
1026 if (data != NULL && data->pdu_len > 0) {
1027 if (outl < data->pdu_len) {
1028 memcpy(out, data->pdu, outl);
1031 data->pdu_len -= outl;
1033 memcpy(out, data->pdu, data->pdu_len);
1034 ret = data->pdu_len;
1035 if (!data->peekmode) {
1056 coap_dgram_write(gnutls_transport_ptr_t context,
const void *send_buffer,
1057 size_t send_buffer_length) {
1058 ssize_t result = -1;
1063 if (result != (
int)send_buffer_length) {
1079 receive_timeout(gnutls_transport_ptr_t context,
unsigned int ms UNUSED) {
1083 fd_set readfds, writefds, exceptfds;
1085 int nfds = c_session->
sock.
fd +1;
1089 FD_ZERO(&exceptfds);
1090 FD_SET (c_session->
sock.
fd, &readfds);
1091 FD_SET (c_session->
sock.
fd, &writefds);
1092 FD_SET (c_session->
sock.
fd, &exceptfds);
1097 return select(nfds, &readfds, &writefds, &exceptfds, &tv);
1102 static coap_gnutls_env_t *
1105 coap_gnutls_context_t *g_context =
1107 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1108 int flags = type | GNUTLS_DATAGRAM | GNUTLS_NONBLOCK;
1114 g_env = gnutls_malloc(
sizeof(coap_gnutls_env_t));
1118 memset(g_env, 0,
sizeof(
struct coap_gnutls_env_t));
1120 G_CHECK(gnutls_init(&g_env->g_session, flags),
"gnutls_init");
1122 gnutls_transport_set_pull_function(g_env->g_session, coap_dgram_read);
1123 gnutls_transport_set_push_function(g_env->g_session, coap_dgram_write);
1124 gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
1126 gnutls_transport_set_ptr(g_env->g_session, c_session);
1128 if (type == GNUTLS_SERVER) {
1129 G_CHECK(setup_server_ssl_session(c_session, g_env),
1130 "setup_server_ssl_session");
1133 G_CHECK(setup_client_ssl_session(c_session, g_env),
1134 "setup_client_ssl_session");
1137 G_CHECK(gnutls_priority_set(g_env->g_session, g_context->priority_cache),
1138 "gnutls_priority_set");
1139 gnutls_handshake_set_timeout(g_env->g_session,
1140 GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
1151 coap_dtls_free_gnutls_env(coap_gnutls_context_t *g_context,
1152 coap_gnutls_env_t *g_env,
1159 gnutls_bye(g_env->g_session, unreliable ?
1160 GNUTLS_SHUT_WR : GNUTLS_SHUT_RDWR);
1161 gnutls_deinit(g_env->g_session);
1162 g_env->g_session = NULL;
1163 if (g_context->psk_pki_enabled & IS_PSK) {
1164 if (g_context->psk_pki_enabled & IS_CLIENT) {
1165 gnutls_psk_free_client_credentials(g_env->psk_cl_credentials);
1168 gnutls_psk_free_server_credentials(g_env->psk_sv_credentials);
1171 if (g_context->psk_pki_enabled & IS_PKI) {
1172 gnutls_certificate_free_credentials(g_env->pki_credentials);
1179 coap_gnutls_env_t *g_env =
1182 gnutls_transport_set_ptr(g_env->g_session, c_session);
1189 static void log_last_alert(gnutls_session_t g_session) {
1190 int last_alert = gnutls_alert_get(g_session);
1193 last_alert, gnutls_alert_get_name(last_alert));
1202 do_gnutls_handshake(
coap_session_t *c_session, coap_gnutls_env_t *g_env) {
1205 ret = gnutls_handshake(g_env->g_session);
1207 case GNUTLS_E_SUCCESS:
1208 g_env->established = 1;
1213 case GNUTLS_E_INTERRUPTED:
1217 case GNUTLS_E_AGAIN:
1221 case GNUTLS_E_INSUFFICIENT_CREDENTIALS:
1223 "Insufficient credentials provided.\n");
1226 case GNUTLS_E_FATAL_ALERT_RECEIVED:
1227 log_last_alert(g_env->g_session);
1231 case GNUTLS_E_WARNING_ALERT_RECEIVED:
1232 log_last_alert(g_env->g_session);
1236 case GNUTLS_E_DECRYPTION_FAILED:
1238 "do_gnutls_handshake: session establish " 1239 "returned %d: '%s'\n",
1240 ret, gnutls_strerror(ret));
1241 G_ACTION(gnutls_alert_send(g_env->g_session, GNUTLS_AL_FATAL,
1242 GNUTLS_A_DECRYPT_ERROR));
1246 case GNUTLS_E_UNKNOWN_CIPHER_SUITE:
1248 case GNUTLS_E_TIMEDOUT:
1254 "do_gnutls_handshake: session establish " 1255 "returned %d: '%s'\n",
1256 ret, gnutls_strerror(ret));
1264 coap_gnutls_env_t *g_env = coap_dtls_new_gnutls_env(c_session, GNUTLS_CLIENT);
1268 ret = do_gnutls_handshake(c_session, g_env);
1280 if (c_session && c_session->
context) {
1283 c_session->
tls = NULL;
1288 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1292 G_CHECK(gnutls_dtls_set_data_mtu(g_env->g_session, c_session->
mtu),
1293 "gnutls_dtls_set_data_mtu");
1304 const uint8_t *data,
size_t data_len) {
1306 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1311 if (g_env->established) {
1312 ret = gnutls_record_send(g_env->g_session, data, data_len);
1316 case GNUTLS_E_AGAIN:
1319 case GNUTLS_E_FATAL_ALERT_RECEIVED:
1320 log_last_alert(g_env->g_session);
1334 ret = do_gnutls_handshake(c_session, g_env);
1379 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1381 coap_ssl_t *ssl_data = &g_env->coap_ssl_data;
1387 if (ssl_data->pdu_len)
1390 ssl_data->pdu = data;
1391 ssl_data->pdu_len = (unsigned)data_len;
1394 if (g_env->established) {
1398 gnutls_transport_set_ptr(g_env->g_session, c_session);
1401 ret = gnutls_record_recv(g_env->g_session, pdu, (
int)
sizeof(pdu));
1405 else if (ret == 0) {
1410 "coap_dtls_receive: gnutls_record_recv returned %d\n", ret);
1415 ret = do_gnutls_handshake(c_session, g_env);
1445 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1446 coap_ssl_t *ssl_data = g_env ? &g_env->coap_ssl_data : NULL;
1450 g_env = coap_dtls_new_gnutls_env(c_session, GNUTLS_SERVER);
1452 c_session->
tls = g_env;
1453 ssl_data = &g_env->coap_ssl_data;
1454 ssl_data->pdu = data;
1455 ssl_data->pdu_len = (unsigned)data_len;
1456 gnutls_dtls_set_data_mtu(g_env->g_session, c_session->
mtu);
1457 ret = do_gnutls_handshake(c_session, g_env);
1458 if (ret == 1 || g_env->seen_client_hello) {
1464 g_env->seen_client_hello = 0;
1471 ssl_data->pdu = data;
1472 ssl_data->pdu_len = (unsigned)data_len;
1474 ret = do_gnutls_handshake(c_session, g_env);
1475 if (ret == 1 || g_env->seen_client_hello) {
1481 g_env->seen_client_hello = 0;
1497 coap_sock_read(gnutls_transport_ptr_t context,
void *out,
size_t outl) {
1517 coap_sock_write(gnutls_transport_ptr_t context,
const void *in,
size_t inl) {
1530 coap_gnutls_env_t *g_env = gnutls_malloc(
sizeof(coap_gnutls_env_t));
1531 coap_gnutls_context_t *g_context =
1533 int flags = GNUTLS_CLIENT;
1539 memset(g_env, 0,
sizeof(
struct coap_gnutls_env_t));
1542 G_CHECK(gnutls_init(&g_env->g_session, flags),
"gnutls_init");
1544 gnutls_transport_set_pull_function(g_env->g_session, coap_sock_read);
1545 gnutls_transport_set_push_function(g_env->g_session, coap_sock_write);
1546 gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
1548 gnutls_transport_set_ptr(g_env->g_session, c_session);
1550 setup_client_ssl_session(c_session, g_env);
1552 gnutls_priority_set(g_env->g_session, g_context->priority_cache);
1553 gnutls_handshake_set_timeout(g_env->g_session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
1555 ret = do_gnutls_handshake(c_session, g_env);
1570 coap_gnutls_env_t *g_env = gnutls_malloc(
sizeof(coap_gnutls_env_t));
1571 coap_gnutls_context_t *g_context =
1573 int flags = GNUTLS_SERVER;
1578 memset(g_env, 0,
sizeof(
struct coap_gnutls_env_t));
1581 G_CHECK(gnutls_init(&g_env->g_session, flags),
"gnutls_init");
1583 gnutls_transport_set_pull_function(g_env->g_session, coap_sock_read);
1584 gnutls_transport_set_push_function(g_env->g_session, coap_sock_write);
1585 gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
1587 gnutls_transport_set_ptr(g_env->g_session, c_session);
1589 setup_server_ssl_session(c_session, g_env);
1591 gnutls_priority_set(g_env->g_session, g_context->priority_cache);
1592 gnutls_handshake_set_timeout(g_env->g_session,
1593 GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
1595 c_session->
tls = g_env;
1596 ret = do_gnutls_handshake(c_session, g_env);
1621 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1626 if (g_env->established) {
1627 ret = gnutls_record_send(g_env->g_session, data, data_len);
1631 case GNUTLS_E_AGAIN:
1634 case GNUTLS_E_FATAL_ALERT_RECEIVED:
1635 log_last_alert(g_env->g_session);
1641 "coap_tls_write: gnutls_record_send " 1642 "returned %d: '%s'\n",
1643 ret, gnutls_strerror(ret));
1653 ret = do_gnutls_handshake(c_session, g_env);
1685 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1692 if (!g_env->established) {
1693 ret = do_gnutls_handshake(c_session, g_env);
1700 if (g_env->established) {
1701 ret = gnutls_record_recv(g_env->g_session, data, (
int)data_len);
1707 case GNUTLS_E_AGAIN:
1713 "coap_tls_read: gnutls_record_recv " 1714 "returned %d: '%s'\n",
1715 ret, gnutls_strerror(ret));
1739 #pragma GCC diagnostic ignored "-Wunused-function" unsigned mtu
path or CSM mtu
void coap_dtls_set_log_level(int level)
Sets the (D)TLS logging level to the specified level.
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)
Get the current (D)TLS logging.
void * coap_dtls_new_client_session(coap_session_t *session UNUSED)
int coap_dtls_is_supported(void)
Check whether DTLS is available.
void coap_dtls_free_context(void *handle 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)
ssize_t coap_socket_read(coap_socket_t *sock, uint8_t *data, size_t data_len)
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.
int coap_tls_is_supported(void)
Check whether TLS is available.
int coap_dtls_context_set_pki(coap_context_t *ctx UNUSED, coap_dtls_pki_t *setup_data UNUSED, int server UNUSED)
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
int coap_dtls_context_set_psk(coap_context_t *ctx UNUSED, const char *hint UNUSED, int server UNUSED)
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.
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
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.
void coap_dtls_free_session(coap_session_t *coap_session UNUSED)
#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)
int coap_dtls_send(coap_session_t *session UNUSED, const uint8_t *data UNUSED, size_t data_len 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)
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)
void * coap_dtls_new_context(struct coap_context_t *coap_context 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