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 #define VARIANTS "NORMAL:+ECDHE-PSK:+PSK" 93 #define G_ACTION(xx) do { \ 95 } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED) 97 #define G_CHECK(xx,func) do { \ 98 if ((ret = (xx)) < 0) { \ 99 coap_log(LOG_WARNING, "%s: '%s'\n", func, gnutls_strerror(ret)); \ 104 #define G_ACTION_CHECK(xx,func) do { \ 111 static int post_client_hello_gnutls_pki(gnutls_session_t g_session);
112 static int post_client_hello_gnutls_psk(gnutls_session_t g_session);
120 if (gnutls_check_version(MIN_GNUTLS_VERSION) == NULL) {
121 coap_log(
LOG_ERR,
"GnuTLS " MIN_GNUTLS_VERSION
" or later is required\n");
133 if (gnutls_check_version(MIN_GNUTLS_VERSION) == NULL) {
134 coap_log(
LOG_ERR,
"GnuTLS " MIN_GNUTLS_VERSION
" or later is required\n");
143 const char *vers = gnutls_check_version(NULL);
149 sscanf (vers,
"%d.%d.%d", &p1, &p2, &p3);
150 version.
version = (p1 << 16) | (p2 << 8) | p3;
158 coap_gnutls_audit_log_func(gnutls_session_t g_session,
const char* text)
166 coap_gnutls_log_func(
int level,
const char* text)
183 coap_gnutls_context_t *g_context =
186 if (!g_context || !setup_data)
189 g_context->setup_data = *setup_data;
190 g_context->psk_pki_enabled |= IS_PKI;
203 coap_gnutls_context_t *g_context =
207 "coap_context_set_pki_root_cas: (D)TLS environment " 212 if (ca_file == NULL && ca_path == NULL) {
214 "coap_context_set_pki_root_cas: ca_file and/or ca_path " 218 if (g_context->root_ca_file) {
219 gnutls_free(g_context->root_ca_file);
220 g_context->root_ca_file = NULL;
223 g_context->root_ca_file = gnutls_strdup(ca_file);
225 if (g_context->root_ca_path) {
226 gnutls_free(g_context->root_ca_path);
227 g_context->root_ca_path = NULL;
230 #if (GNUTLS_VERSION_NUMBER >= 0x030306) 231 g_context->root_ca_path = gnutls_strdup(ca_path);
245 const char *identity_hint UNUSED,
248 coap_gnutls_context_t *g_context =
251 g_context->psk_pki_enabled |= IS_PSK;
262 coap_gnutls_context_t *g_context =
264 return g_context->psk_pki_enabled ? 1 : 0;
268 gnutls_global_set_audit_log_function(coap_gnutls_audit_log_func);
269 gnutls_global_set_log_function(coap_gnutls_log_func);
277 gnutls_global_set_log_level(2 + level -
LOG_DEBUG);
280 gnutls_global_set_log_level(0);
300 struct coap_gnutls_context_t *g_context =
301 (
struct coap_gnutls_context_t *)
302 gnutls_malloc(
sizeof(coap_gnutls_context_t));
305 G_CHECK(gnutls_global_init(),
"gnutls_global_init");
306 memset(g_context, 0,
sizeof(
struct coap_gnutls_context_t));
307 g_context->alpn_proto.data = gnutls_malloc(4);
308 if (g_context->alpn_proto.data) {
309 memcpy(g_context->alpn_proto.data,
"coap", 4);
310 g_context->alpn_proto.size = 4;
312 G_CHECK(gnutls_priority_init(&g_context->priority_cache, VARIANTS, &err),
313 "gnutls_priority_init");
326 coap_gnutls_context_t *g_context = (coap_gnutls_context_t *)handle;
328 gnutls_free(g_context->alpn_proto.data);
329 gnutls_free(g_context->root_ca_file);
330 gnutls_free(g_context->root_ca_path);
331 for (i = 0; i < g_context->sni_count; i++) {
332 gnutls_free(g_context->sni_entry_list[i].sni);
333 if (g_context->psk_pki_enabled & IS_PKI) {
334 gnutls_certificate_free_credentials(
335 g_context->sni_entry_list[i].pki_credentials);
338 if (g_context->sni_count)
339 gnutls_free(g_context->sni_entry_list);
341 gnutls_priority_deinit(g_context->priority_cache);
343 gnutls_global_deinit();
344 gnutls_free(g_context);
355 psk_client_callback(gnutls_session_t g_session,
356 char **username, gnutls_datum_t *key) {
364 if (c_session == NULL || c_session->
context == NULL ||
374 sizeof (identity) - 1,
377 if (identity_len <
sizeof (identity))
378 identity[identity_len] = 0;
380 *username = gnutls_malloc(identity_len+1);
381 memcpy(*username, identity, identity_len+1);
383 key->data = gnutls_malloc(psk_len);
384 memcpy(key->data, psk_key, psk_len);
394 static char* get_san_or_cn(gnutls_session_t g_session)
396 unsigned int cert_list_size = 0;
397 const gnutls_datum_t *cert_list;
398 gnutls_x509_crt_t cert;
405 if (gnutls_certificate_type_get(g_session) != GNUTLS_CRT_X509)
408 cert_list = gnutls_certificate_get_peers(g_session, &cert_list_size);
409 if (cert_list_size == 0) {
413 G_CHECK(gnutls_x509_crt_init(&cert),
"gnutls_x509_crt_init");
416 G_CHECK(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER),
417 "gnutls_x509_crt_import");
419 size =
sizeof(dn) -1;
421 ret = gnutls_x509_crt_get_subject_alt_name(cert, 0, dn, &size, NULL);
424 gnutls_x509_crt_deinit(cert);
425 return gnutls_strdup(dn);
429 G_CHECK(gnutls_x509_crt_get_dn(cert, dn, &size),
"gnutls_x509_crt_get_dn");
431 gnutls_x509_crt_deinit(cert);
437 if (((cn[0] ==
'C') || (cn[0] ==
'c')) &&
438 ((cn[1] ==
'N') || (cn[1] ==
'n')) &&
447 char *ecn = strchr(cn,
',');
451 return gnutls_strdup(cn);
463 static int cert_verify_gnutls(gnutls_session_t g_session)
465 unsigned int status = 0;
468 coap_gnutls_context_t *g_context =
471 int alert = GNUTLS_A_BAD_CERTIFICATE;
474 G_CHECK(gnutls_certificate_verify_peers(g_session, NULL, 0, &status),
475 "gnutls_certificate_verify_peers");
477 cn = get_san_or_cn(g_session);
480 status &= ~(GNUTLS_CERT_INVALID);
481 if (status & (GNUTLS_CERT_NOT_ACTIVATED|GNUTLS_CERT_EXPIRED)) {
482 if (g_context->setup_data.allow_expired_certs) {
483 status &= ~(GNUTLS_CERT_NOT_ACTIVATED|GNUTLS_CERT_EXPIRED);
485 " %s: %s: overridden: '%s'\n",
487 "The certificate has an invalid usage date", cn ? cn :
"?");
490 if (status & (GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED|
491 GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE)) {
492 if (g_context->setup_data.allow_expired_crl) {
493 status &= ~(GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED|
494 GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE);
496 " %s: %s: overridden: '%s'\n",
498 "The certificate's CRL entry has an invalid usage date",
505 " %s: status 0x%x: '%s'\n",
507 status, cn ? cn :
"?");
514 if (g_context->setup_data.validate_cn_call_back) {
515 unsigned int cert_list_size = 0;
516 const gnutls_datum_t *cert_list;
517 gnutls_x509_crt_t cert;
521 cert_list = gnutls_certificate_get_peers(g_session, &cert_list_size);
522 if (cert_list_size == 0) {
527 G_CHECK(gnutls_x509_crt_init(&cert),
"gnutls_x509_crt_init");
530 G_CHECK(gnutls_x509_crt_import(cert, &cert_list[0], GNUTLS_X509_FMT_DER),
531 "gnutls_x509_crt_import");
534 G_CHECK(gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, der, &size),
535 "gnutls_x509_crt_export");
536 gnutls_x509_crt_deinit(cert);
537 if (!g_context->setup_data.validate_cn_call_back(cn,
543 g_context->setup_data.cn_call_back_arg)) {
544 alert = GNUTLS_A_ACCESS_DENIED;
549 if (g_context->setup_data.additional_tls_setup_call_back) {
551 if (!g_context->setup_data.additional_tls_setup_call_back(g_session,
552 &g_context->setup_data)) {
566 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL, alert));
577 static int cert_verify_callback_gnutls(gnutls_session_t g_session)
581 if (gnutls_auth_get_type(g_session) == GNUTLS_CRD_CERTIFICATE) {
582 if (cert_verify_gnutls(g_session) == 0) {
583 G_ACTION(gnutls_alert_send(g_session,
585 GNUTLS_A_ACCESS_DENIED));
597 setup_pki_credentials(gnutls_certificate_credentials_t *pki_credentials,
598 coap_gnutls_context_t *g_context,
609 G_CHECK(gnutls_certificate_allocate_credentials(pki_credentials),
610 "gnutls_certificate_allocate_credentials");
612 G_CHECK(gnutls_certificate_set_x509_key_file(*pki_credentials,
615 GNUTLS_X509_FMT_PEM),
616 "gnutls_certificate_set_x509_key_file");
620 "***setup_pki: (D)TLS: No Client Certificate + Private " 622 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
626 G_CHECK(gnutls_certificate_set_x509_trust_file(*pki_credentials,
628 GNUTLS_X509_FMT_PEM),
629 "gnutls_certificate_set_x509_trust_file");
648 G_CHECK(gnutls_certificate_set_x509_key_mem(*pki_credentials,
651 GNUTLS_X509_FMT_DER),
652 "gnutls_certificate_set_x509_key_mem");
656 "***setup_pki: (D)TLS: No Client Certificate + Private " 658 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
662 gnutls_datum_t ca_cert;
666 sizeof(ca_cert.data));
668 G_CHECK(gnutls_certificate_set_x509_trust_mem(*pki_credentials,
670 GNUTLS_X509_FMT_DER),
671 "gnutls_certificate_set_x509_trust_mem");
676 "***setup_pki: (D)TLS: Unknown key type %d\n",
678 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
681 if (g_context->root_ca_file) {
682 G_CHECK(gnutls_certificate_set_x509_trust_file(*pki_credentials,
683 g_context->root_ca_file,
684 GNUTLS_X509_FMT_PEM),
685 "gnutls_certificate_set_x509_trust_file");
687 if (g_context->root_ca_path) {
688 #if (GNUTLS_VERSION_NUMBER >= 0x030306) 689 G_CHECK(gnutls_certificate_set_x509_trust_dir(*pki_credentials,
690 g_context->root_ca_path,
691 GNUTLS_X509_FMT_PEM),
692 "gnutls_certificate_set_x509_trust_dir");
698 gnutls_certificate_set_verify_function(*pki_credentials,
699 cert_verify_callback_gnutls);
704 gnutls_certificate_set_verify_limits(*pki_credentials,
710 gnutls_certificate_set_verify_flags(*pki_credentials,
711 GNUTLS_VERIFY_DO_NOT_ALLOW_SAME);
715 gnutls_certificate_set_verify_flags(*pki_credentials,
716 GNUTLS_VERIFY_DO_NOT_ALLOW_SAME |
717 GNUTLS_VERIFY_DISABLE_CRL_CHECKS);
720 return GNUTLS_E_SUCCESS;
731 post_client_hello_gnutls_pki(gnutls_session_t g_session)
735 coap_gnutls_context_t *g_context =
737 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
738 int ret = GNUTLS_E_SUCCESS;
741 g_env->seen_client_hello = 1;
743 if (g_context->setup_data.validate_sni_call_back) {
750 name = gnutls_malloc(len);
752 return GNUTLS_E_MEMORY_ERROR;
755 ret = gnutls_server_name_get(g_session, name, &len, &type, i);
756 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
758 new_name = gnutls_realloc(name, len);
759 if (new_name == NULL) {
760 ret = GNUTLS_E_MEMORY_ERROR;
768 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
771 if (ret != GNUTLS_E_SUCCESS)
774 if (type != GNUTLS_NAME_DNS)
785 for (i = 0; i < g_context->sni_count; i++) {
786 if (strcmp(name, g_context->sni_entry_list[i].sni) == 0) {
790 if (i == g_context->sni_count) {
795 g_context->setup_data.validate_sni_call_back(name,
796 g_context->setup_data.sni_call_back_arg);
798 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
799 GNUTLS_A_UNRECOGNIZED_NAME));
800 ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
804 g_context->sni_entry_list = gnutls_realloc(g_context->sni_entry_list,
805 (i+1)*
sizeof(sni_entry));
806 g_context->sni_entry_list[i].sni = gnutls_strdup(name);
807 g_context->sni_entry_list[i].pki_key = *new_entry;
808 sni_setup_data = g_context->setup_data;
809 sni_setup_data.
pki_key = *new_entry;
810 if ((ret = setup_pki_credentials(
811 &g_context->sni_entry_list[i].pki_credentials,
813 &sni_setup_data)) < 0) {
815 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
816 GNUTLS_A_BAD_CERTIFICATE));
820 g_context->sni_count++;
822 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
823 g_context->sni_entry_list[i].pki_credentials),
824 "gnutls_credentials_set");
840 post_client_hello_gnutls_psk(gnutls_session_t g_session)
844 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
846 g_env->seen_client_hello = 1;
847 return GNUTLS_E_SUCCESS;
855 setup_client_ssl_session(
coap_session_t *c_session, coap_gnutls_env_t *g_env)
857 coap_gnutls_context_t *g_context =
861 g_context->psk_pki_enabled |= IS_CLIENT;
862 if (g_context->psk_pki_enabled & IS_PSK) {
863 char *identity = NULL;
864 gnutls_datum_t psk_key;
866 G_CHECK(gnutls_psk_allocate_client_credentials(&g_env->psk_cl_credentials),
867 "gnutls_psk_allocate_client_credentials");
868 psk_client_callback(g_env->g_session, &identity, &psk_key);
869 G_CHECK(gnutls_psk_set_client_credentials(g_env->psk_cl_credentials,
873 "gnutls_psk_set_client_credentials");
874 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_PSK,
875 g_env->psk_cl_credentials),
876 "gnutls_credentials_set");
877 gnutls_free(identity);
878 gnutls_free(psk_key.data);
881 if (g_context->psk_pki_enabled & IS_PKI) {
883 G_CHECK(setup_pki_credentials(&g_env->pki_credentials, g_context,
885 "setup_pki_credentials");
887 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
888 g_env->pki_credentials),
889 "gnutls_credentials_set");
892 G_CHECK(gnutls_alpn_set_protocols(g_env->g_session,
893 &g_context->alpn_proto, 1, 0),
894 "gnutls_alpn_set_protocols");
898 G_CHECK(gnutls_server_name_set(g_env->g_session, GNUTLS_NAME_DNS,
901 "gnutls_server_name_set");
904 return GNUTLS_E_SUCCESS;
918 psk_server_callback(gnutls_session_t g_session,
919 const char *identity,
924 size_t identity_len = 0;
929 identity_len = strlen(identity);
934 (
int)identity_len, identity);
936 if (c_session == NULL || c_session->
context == NULL ||
944 key->data = gnutls_malloc(psk_len);
945 memcpy(key->data, buf, psk_len);
955 setup_server_ssl_session(
coap_session_t *c_session, coap_gnutls_env_t *g_env)
957 coap_gnutls_context_t *g_context =
959 int ret = GNUTLS_E_SUCCESS;
961 g_context->psk_pki_enabled |= IS_SERVER;
962 if (g_context->psk_pki_enabled & IS_PSK) {
963 G_CHECK(gnutls_psk_allocate_server_credentials(&g_env->psk_sv_credentials),
964 "gnutls_psk_allocate_server_credentials");
965 gnutls_psk_set_server_credentials_function(g_env->psk_sv_credentials,
966 psk_server_callback);
968 gnutls_handshake_set_post_client_hello_function(g_env->g_session,
969 post_client_hello_gnutls_psk);
971 G_CHECK(gnutls_credentials_set(g_env->g_session,
973 g_env->psk_sv_credentials),
974 "gnutls_credentials_set\n");
977 if (g_context->psk_pki_enabled & IS_PKI) {
979 G_CHECK(setup_pki_credentials(&g_env->pki_credentials, g_context,
981 "setup_pki_credentials");
984 gnutls_certificate_server_set_request(g_env->g_session,
985 GNUTLS_CERT_REQUIRE);
988 gnutls_certificate_server_set_request(g_env->g_session, GNUTLS_CERT_IGNORE);
991 gnutls_handshake_set_post_client_hello_function(g_env->g_session,
992 post_client_hello_gnutls_pki);
994 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
995 g_env->pki_credentials),
996 "gnutls_credentials_set\n");
998 return GNUTLS_E_SUCCESS;
1010 coap_dgram_read(gnutls_transport_ptr_t context,
void *out,
size_t outl)
1014 coap_ssl_t *data = &((coap_gnutls_env_t *)c_session->
tls)->coap_ssl_data;
1016 if (!c_session->
tls) {
1022 if (data != NULL && data->pdu_len > 0) {
1023 if (outl < data->pdu_len) {
1024 memcpy(out, data->pdu, outl);
1027 data->pdu_len -= outl;
1029 memcpy(out, data->pdu, data->pdu_len);
1030 ret = data->pdu_len;
1031 if (!data->peekmode) {
1052 coap_dgram_write(gnutls_transport_ptr_t context,
const void *send_buffer,
1053 size_t send_buffer_length) {
1054 ssize_t result = -1;
1059 if (result != (
int)send_buffer_length) {
1075 receive_timeout(gnutls_transport_ptr_t context,
unsigned int ms UNUSED) {
1079 fd_set readfds, writefds, exceptfds;
1081 int nfds = c_session->
sock.
fd +1;
1085 FD_ZERO(&exceptfds);
1086 FD_SET (c_session->
sock.
fd, &readfds);
1087 FD_SET (c_session->
sock.
fd, &writefds);
1088 FD_SET (c_session->
sock.
fd, &exceptfds);
1093 return select(nfds, &readfds, &writefds, &exceptfds, &tv);
1098 static coap_gnutls_env_t *
1101 coap_gnutls_context_t *g_context =
1103 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1104 int flags = type | GNUTLS_DATAGRAM | GNUTLS_NONBLOCK;
1110 g_env = gnutls_malloc(
sizeof(coap_gnutls_env_t));
1114 memset(g_env, 0,
sizeof(
struct coap_gnutls_env_t));
1116 G_CHECK(gnutls_init(&g_env->g_session, flags),
"gnutls_init");
1118 gnutls_transport_set_pull_function(g_env->g_session, coap_dgram_read);
1119 gnutls_transport_set_push_function(g_env->g_session, coap_dgram_write);
1120 gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
1122 gnutls_transport_set_ptr(g_env->g_session, c_session);
1124 if (type == GNUTLS_SERVER) {
1125 G_CHECK(setup_server_ssl_session(c_session, g_env),
1126 "setup_server_ssl_session");
1129 G_CHECK(setup_client_ssl_session(c_session, g_env),
1130 "setup_client_ssl_session");
1133 G_CHECK(gnutls_priority_set(g_env->g_session, g_context->priority_cache),
1134 "gnutls_priority_set");
1135 gnutls_handshake_set_timeout(g_env->g_session,
1136 GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
1147 coap_dtls_free_gnutls_env(coap_gnutls_context_t *g_context,
1148 coap_gnutls_env_t *g_env,
1155 gnutls_bye(g_env->g_session, unreliable ?
1156 GNUTLS_SHUT_WR : GNUTLS_SHUT_RDWR);
1157 gnutls_deinit(g_env->g_session);
1158 g_env->g_session = NULL;
1159 if (g_context->psk_pki_enabled & IS_PSK) {
1160 if (g_context->psk_pki_enabled & IS_CLIENT) {
1161 gnutls_psk_free_client_credentials(g_env->psk_cl_credentials);
1164 gnutls_psk_free_server_credentials(g_env->psk_sv_credentials);
1167 if (g_context->psk_pki_enabled & IS_PKI) {
1168 gnutls_certificate_free_credentials(g_env->pki_credentials);
1175 coap_gnutls_env_t *g_env =
1178 gnutls_transport_set_ptr(g_env->g_session, c_session);
1185 static void log_last_alert(gnutls_session_t g_session) {
1186 int last_alert = gnutls_alert_get(g_session);
1189 last_alert, gnutls_alert_get_name(last_alert));
1198 do_gnutls_handshake(
coap_session_t *c_session, coap_gnutls_env_t *g_env) {
1201 ret = gnutls_handshake(g_env->g_session);
1203 case GNUTLS_E_SUCCESS:
1204 g_env->established = 1;
1209 case GNUTLS_E_INTERRUPTED:
1213 case GNUTLS_E_AGAIN:
1217 case GNUTLS_E_INSUFFICIENT_CREDENTIALS:
1219 "Insufficient credentials provided.\n");
1222 case GNUTLS_E_FATAL_ALERT_RECEIVED:
1223 log_last_alert(g_env->g_session);
1227 case GNUTLS_E_WARNING_ALERT_RECEIVED:
1228 log_last_alert(g_env->g_session);
1232 case GNUTLS_E_DECRYPTION_FAILED:
1234 "do_gnutls_handshake: session establish " 1235 "returned %d: '%s'\n",
1236 ret, gnutls_strerror(ret));
1237 G_ACTION(gnutls_alert_send(g_env->g_session, GNUTLS_AL_FATAL,
1238 GNUTLS_A_DECRYPT_ERROR));
1242 case GNUTLS_E_UNKNOWN_CIPHER_SUITE:
1244 case GNUTLS_E_TIMEDOUT:
1250 "do_gnutls_handshake: session establish " 1251 "returned %d: '%s'\n",
1252 ret, gnutls_strerror(ret));
1260 coap_gnutls_env_t *g_env = coap_dtls_new_gnutls_env(c_session, GNUTLS_CLIENT);
1264 ret = do_gnutls_handshake(c_session, g_env);
1276 if (c_session && c_session->
context) {
1279 c_session->
tls = NULL;
1284 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1288 G_CHECK(gnutls_dtls_set_data_mtu(g_env->g_session, c_session->
mtu),
1289 "gnutls_dtls_set_data_mtu");
1300 const uint8_t *data,
size_t data_len) {
1302 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1307 if (g_env->established) {
1308 ret = gnutls_record_send(g_env->g_session, data, data_len);
1312 case GNUTLS_E_AGAIN:
1315 case GNUTLS_E_FATAL_ALERT_RECEIVED:
1316 log_last_alert(g_env->g_session);
1330 ret = do_gnutls_handshake(c_session, g_env);
1375 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1377 coap_ssl_t *ssl_data = &g_env->coap_ssl_data;
1383 if (ssl_data->pdu_len)
1386 ssl_data->pdu = data;
1387 ssl_data->pdu_len = (unsigned)data_len;
1390 if (g_env->established) {
1394 gnutls_transport_set_ptr(g_env->g_session, c_session);
1397 ret = gnutls_record_recv(g_env->g_session, pdu, (
int)
sizeof(pdu));
1401 else if (ret == 0) {
1406 "coap_dtls_receive: gnutls_record_recv returned %d\n", ret);
1411 ret = do_gnutls_handshake(c_session, g_env);
1441 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1442 coap_ssl_t *ssl_data = g_env ? &g_env->coap_ssl_data : NULL;
1446 g_env = coap_dtls_new_gnutls_env(c_session, GNUTLS_SERVER);
1448 c_session->
tls = g_env;
1449 ssl_data = &g_env->coap_ssl_data;
1450 ssl_data->pdu = data;
1451 ssl_data->pdu_len = (unsigned)data_len;
1452 gnutls_dtls_set_data_mtu(g_env->g_session, c_session->
mtu);
1453 ret = do_gnutls_handshake(c_session, g_env);
1454 if (ret == 1 || g_env->seen_client_hello) {
1460 g_env->seen_client_hello = 0;
1467 ssl_data->pdu = data;
1468 ssl_data->pdu_len = (unsigned)data_len;
1470 ret = do_gnutls_handshake(c_session, g_env);
1471 if (ret == 1 || g_env->seen_client_hello) {
1477 g_env->seen_client_hello = 0;
1493 coap_sock_read(gnutls_transport_ptr_t context,
void *out,
size_t outl) {
1513 coap_sock_write(gnutls_transport_ptr_t context,
const void *in,
size_t inl) {
1526 coap_gnutls_env_t *g_env = gnutls_malloc(
sizeof(coap_gnutls_env_t));
1527 coap_gnutls_context_t *g_context =
1529 int flags = GNUTLS_CLIENT;
1535 memset(g_env, 0,
sizeof(
struct coap_gnutls_env_t));
1538 G_CHECK(gnutls_init(&g_env->g_session, flags),
"gnutls_init");
1540 gnutls_transport_set_pull_function(g_env->g_session, coap_sock_read);
1541 gnutls_transport_set_push_function(g_env->g_session, coap_sock_write);
1542 gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
1544 gnutls_transport_set_ptr(g_env->g_session, c_session);
1546 setup_client_ssl_session(c_session, g_env);
1548 gnutls_priority_set(g_env->g_session, g_context->priority_cache);
1549 gnutls_handshake_set_timeout(g_env->g_session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
1551 ret = do_gnutls_handshake(c_session, g_env);
1566 coap_gnutls_env_t *g_env = gnutls_malloc(
sizeof(coap_gnutls_env_t));
1567 coap_gnutls_context_t *g_context =
1569 int flags = GNUTLS_SERVER;
1574 memset(g_env, 0,
sizeof(
struct coap_gnutls_env_t));
1577 G_CHECK(gnutls_init(&g_env->g_session, flags),
"gnutls_init");
1579 gnutls_transport_set_pull_function(g_env->g_session, coap_sock_read);
1580 gnutls_transport_set_push_function(g_env->g_session, coap_sock_write);
1581 gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
1583 gnutls_transport_set_ptr(g_env->g_session, c_session);
1585 setup_server_ssl_session(c_session, g_env);
1587 gnutls_priority_set(g_env->g_session, g_context->priority_cache);
1588 gnutls_handshake_set_timeout(g_env->g_session,
1589 GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
1591 c_session->
tls = g_env;
1592 ret = do_gnutls_handshake(c_session, g_env);
1617 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1622 if (g_env->established) {
1623 ret = gnutls_record_send(g_env->g_session, data, data_len);
1627 case GNUTLS_E_AGAIN:
1630 case GNUTLS_E_FATAL_ALERT_RECEIVED:
1631 log_last_alert(g_env->g_session);
1637 "coap_tls_write: gnutls_record_send " 1638 "returned %d: '%s'\n",
1639 ret, gnutls_strerror(ret));
1649 ret = do_gnutls_handshake(c_session, g_env);
1681 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1688 if (!g_env->established) {
1689 ret = do_gnutls_handshake(c_session, g_env);
1696 if (g_env->established) {
1697 ret = gnutls_record_recv(g_env->g_session, data, (
int)data_len);
1703 case GNUTLS_E_AGAIN:
1709 "coap_tls_read: gnutls_record_recv " 1710 "returned %d: '%s'\n",
1711 ret, gnutls_strerror(ret));
1735 #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