50 #define MIN_GNUTLS_VERSION "3.3.0"
55 #include <gnutls/gnutls.h>
56 #include <gnutls/x509.h>
57 #include <gnutls/dtls.h>
58 #include <gnutls/pkcs11.h>
59 #include <gnutls/crypto.h>
60 #include <gnutls/abstract.h>
62 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
63 #define COAP_GNUTLS_KEY_RPK GNUTLS_KEY_DIGITAL_SIGNATURE | \
64 GNUTLS_KEY_NON_REPUDIATION | \
65 GNUTLS_KEY_KEY_ENCIPHERMENT | \
66 GNUTLS_KEY_DATA_ENCIPHERMENT | \
67 GNUTLS_KEY_KEY_AGREEMENT | \
68 GNUTLS_KEY_KEY_CERT_SIGN
72 #define strcasecmp _stricmp
75 typedef struct coap_ssl_t {
79 gnutls_datum_t cookie_key;
87 typedef struct coap_gnutls_env_t {
88 gnutls_session_t g_session;
89 gnutls_psk_client_credentials_t psk_cl_credentials;
90 gnutls_psk_server_credentials_t psk_sv_credentials;
91 gnutls_certificate_credentials_t pki_credentials;
92 coap_ssl_t coap_ssl_data;
95 int doing_dtls_timeout;
100 #define IS_PSK (1 << 0)
101 #define IS_PKI (1 << 1)
102 #define IS_CLIENT (1 << 6)
103 #define IS_SERVER (1 << 7)
105 typedef struct pki_sni_entry {
108 gnutls_certificate_credentials_t pki_credentials;
111 typedef struct psk_sni_entry {
114 gnutls_psk_server_credentials_t psk_credentials;
117 typedef struct coap_gnutls_context_t {
120 size_t pki_sni_count;
121 pki_sni_entry *pki_sni_entry_list;
122 size_t psk_sni_count;
123 psk_sni_entry *psk_sni_entry_list;
124 gnutls_datum_t alpn_proto;
127 gnutls_priority_t priority_cache;
128 } coap_gnutls_context_t;
130 typedef enum coap_free_bye_t {
131 COAP_FREE_BYE_AS_TCP,
132 COAP_FREE_BYE_AS_UDP,
136 #define VARIANTS_3_6_6 "NORMAL:+ECDHE-PSK:+PSK:+ECDHE-ECDSA:+AES-128-CCM-8:+CTYPE-CLI-ALL:+CTYPE-SRV-ALL:+SHA256"
137 #define VARIANTS_3_5_5 "NORMAL:+ECDHE-PSK:+PSK:+ECDHE-ECDSA:+AES-128-CCM-8"
138 #define VARIANTS_BASE "NORMAL:+ECDHE-PSK:+PSK"
140 #define VARIANTS_NO_TLS13_3_6_6 VARIANTS_3_6_6 ":-VERS-TLS1.3"
141 #define VARIANTS_NO_TLS13_3_6_4 VARIANTS_3_5_5 ":-VERS-TLS1.3"
143 #define G_ACTION(xx) do { \
145 } while (ret == GNUTLS_E_AGAIN || ret == GNUTLS_E_INTERRUPTED)
147 #define G_CHECK(xx,func) do { \
148 if ((ret = (xx)) < 0) { \
149 coap_log(LOG_WARNING, "%s: '%s'\n", func, gnutls_strerror(ret)); \
154 #define G_ACTION_CHECK(xx,func) do { \
161 static int post_client_hello_gnutls_pki(gnutls_session_t g_session);
162 static int post_client_hello_gnutls_psk(gnutls_session_t g_session);
163 static int psk_server_callback(gnutls_session_t g_session,
164 const char *identity,
165 gnutls_datum_t *key);
173 if (gnutls_check_version(MIN_GNUTLS_VERSION) == NULL) {
174 coap_log(
LOG_ERR,
"GnuTLS " MIN_GNUTLS_VERSION
" or later is required\n");
186 #if !COAP_DISABLE_TCP
187 if (gnutls_check_version(MIN_GNUTLS_VERSION) == NULL) {
188 coap_log(
LOG_ERR,
"GnuTLS " MIN_GNUTLS_VERSION
" or later is required\n");
200 const char *vers = gnutls_check_version(NULL);
206 sscanf (vers,
"%d.%d.%d", &p1, &p2, &p3);
207 version.
version = (p1 << 16) | (p2 << 8) | p3;
215 coap_gnutls_audit_log_func(gnutls_session_t g_session,
const char* text)
228 coap_gnutls_log_func(
int level,
const char* text)
245 coap_gnutls_context_t *g_context =
248 if (!g_context || !setup_data)
251 g_context->setup_data = *setup_data;
252 if (!g_context->setup_data.verify_peer_cert) {
254 g_context->setup_data.check_common_ca = 0;
255 if (g_context->setup_data.is_rpk_not_cert) {
257 g_context->setup_data.allow_self_signed = 0;
258 g_context->setup_data.allow_expired_certs = 0;
259 g_context->setup_data.cert_chain_validation = 0;
260 g_context->setup_data.cert_chain_verify_depth = 0;
261 g_context->setup_data.check_cert_revocation = 0;
262 g_context->setup_data.allow_no_crl = 0;
263 g_context->setup_data.allow_expired_crl = 0;
264 g_context->setup_data.allow_bad_md_hash = 0;
265 g_context->setup_data.allow_short_rsa_length = 0;
269 g_context->setup_data.allow_self_signed = 1;
270 g_context->setup_data.allow_expired_certs = 1;
271 g_context->setup_data.cert_chain_validation = 1;
272 g_context->setup_data.cert_chain_verify_depth = 10;
273 g_context->setup_data.check_cert_revocation = 1;
274 g_context->setup_data.allow_no_crl = 1;
275 g_context->setup_data.allow_expired_crl = 1;
276 g_context->setup_data.allow_bad_md_hash = 1;
277 g_context->setup_data.allow_short_rsa_length = 1;
280 g_context->psk_pki_enabled |= IS_PKI;
293 coap_gnutls_context_t *g_context =
297 "coap_context_set_pki_root_cas: (D)TLS environment "
302 if (ca_file == NULL && ca_path == NULL) {
304 "coap_context_set_pki_root_cas: ca_file and/or ca_path "
308 if (g_context->root_ca_file) {
309 gnutls_free(g_context->root_ca_file);
310 g_context->root_ca_file = NULL;
313 g_context->root_ca_file = gnutls_strdup(ca_file);
315 if (g_context->root_ca_path) {
316 gnutls_free(g_context->root_ca_path);
317 g_context->root_ca_path = NULL;
320 #if (GNUTLS_VERSION_NUMBER >= 0x030306)
321 g_context->root_ca_path = gnutls_strdup(ca_path);
337 coap_gnutls_context_t *g_context =
340 if (!g_context || !setup_data)
343 g_context->psk_pki_enabled |= IS_PSK;
355 coap_gnutls_context_t *g_context =
358 if (!g_context || !setup_data)
361 g_context->psk_pki_enabled |= IS_PSK;
372 coap_gnutls_context_t *g_context =
374 return g_context->psk_pki_enabled ? 1 : 0;
378 gnutls_global_set_audit_log_function(coap_gnutls_audit_log_func);
379 gnutls_global_set_log_function(coap_gnutls_log_func);
390 if (c_session && c_session->
tls) {
391 const coap_gnutls_env_t *g_env = (
const coap_gnutls_env_t *)c_session->
tls;
393 return g_env->g_session;
403 gnutls_global_set_log_level(2 + level -
LOG_DEBUG);
406 gnutls_global_set_log_level(0);
426 coap_gnutls_context_t *g_context =
427 (coap_gnutls_context_t *)
428 gnutls_malloc(
sizeof(coap_gnutls_context_t));
432 const char *priority;
434 G_CHECK(gnutls_global_init(),
"gnutls_global_init");
435 memset(g_context, 0,
sizeof(coap_gnutls_context_t));
436 g_context->alpn_proto.data = gnutls_malloc(4);
437 if (g_context->alpn_proto.data) {
438 memcpy(g_context->alpn_proto.data,
"coap", 4);
439 g_context->alpn_proto.size = 4;
442 if (tls_version->
version >= 0x030606) {
443 priority = VARIANTS_3_6_6;
445 else if (tls_version->
version >= 0x030505) {
446 priority = VARIANTS_3_5_5;
449 priority = VARIANTS_BASE;
451 ret = gnutls_priority_init(&g_context->priority_cache, priority, &err);
452 if (ret != GNUTLS_E_SUCCESS) {
453 if (ret == GNUTLS_E_INVALID_REQUEST)
455 "gnutls_priority_init: Syntax error at: %s\n", err);
458 "gnutls_priority_init: %s\n", gnutls_strerror(ret));
473 coap_gnutls_context_t *g_context = (coap_gnutls_context_t *)handle;
475 gnutls_free(g_context->alpn_proto.data);
476 gnutls_free(g_context->root_ca_file);
477 gnutls_free(g_context->root_ca_path);
478 for (i = 0; i < g_context->pki_sni_count; i++) {
479 gnutls_free(g_context->pki_sni_entry_list[i].sni);
480 gnutls_certificate_free_credentials(
481 g_context->pki_sni_entry_list[i].pki_credentials);
483 if (g_context->pki_sni_entry_list)
484 gnutls_free(g_context->pki_sni_entry_list);
486 for (i = 0; i < g_context->psk_sni_count; i++) {
487 gnutls_free(g_context->psk_sni_entry_list[i].sni);
489 gnutls_psk_free_server_credentials(
490 g_context->psk_sni_entry_list[i].psk_credentials);
492 if (g_context->psk_sni_entry_list)
493 gnutls_free(g_context->psk_sni_entry_list);
495 gnutls_priority_deinit(g_context->priority_cache);
497 gnutls_global_deinit();
498 gnutls_free(g_context);
509 psk_client_callback(gnutls_session_t g_session,
510 char **username, gnutls_datum_t *key) {
513 coap_gnutls_context_t *g_context;
515 uint8_t identity[64];
519 const char *hint = gnutls_psk_client_get_hint(g_session);
524 const size_t max_identity_len =
sizeof(identity) - 1;
530 if (c_session == NULL || c_session->
context == NULL ||
536 if (g_context == NULL)
542 hint_len = strlen(hint);
551 lhint.
s = (
const uint8_t*)hint;
557 if (psk_info == NULL)
561 if (*username == NULL)
566 key->data = gnutls_malloc(psk_info->
key.
length);
567 if (key->data == NULL) {
568 gnutls_free(*username);
585 assert(identity_len <
sizeof(identity));
589 *username = gnutls_malloc(identity_len+1);
590 if (*username == NULL)
592 memcpy(*username, identity, identity_len);
593 (*username)[identity_len] =
'\0';
595 key->data = gnutls_malloc(psk_len);
596 if (key->data == NULL) {
597 gnutls_free(*username);
601 memcpy(key->data, psk, psk_len);
608 gnutls_certificate_type_t certificate_type;
610 const gnutls_datum_t *cert_list;
611 unsigned int cert_list_size;
613 } coap_gnutls_certificate_info_t;
619 static gnutls_certificate_type_t get_san_or_cn(gnutls_session_t g_session,
620 coap_gnutls_certificate_info_t *cert_info)
622 gnutls_x509_crt_t cert;
629 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
630 cert_info->certificate_type = gnutls_certificate_type_get2(g_session,
633 cert_info->certificate_type = gnutls_certificate_type_get(g_session);
636 cert_info->san_or_cn = NULL;
638 cert_info->cert_list = gnutls_certificate_get_peers(g_session,
639 &cert_info->cert_list_size);
640 if (cert_info->cert_list_size == 0) {
641 return GNUTLS_CRT_UNKNOWN;
644 if (cert_info->certificate_type != GNUTLS_CRT_X509)
645 return cert_info->certificate_type;
647 G_CHECK(gnutls_x509_crt_init(&cert),
"gnutls_x509_crt_init");
650 G_CHECK(gnutls_x509_crt_import(cert, &cert_info->cert_list[0],
651 GNUTLS_X509_FMT_DER),
"gnutls_x509_crt_import");
653 cert_info->self_signed = gnutls_x509_crt_check_issuer(cert, cert);
655 size =
sizeof(dn) -1;
657 ret = gnutls_x509_crt_get_subject_alt_name(cert, 0, dn, &size, NULL);
660 gnutls_x509_crt_deinit(cert);
661 cert_info->san_or_cn = gnutls_strdup(dn);
662 return cert_info->certificate_type;
666 G_CHECK(gnutls_x509_crt_get_dn(cert, dn, &size),
"gnutls_x509_crt_get_dn");
668 gnutls_x509_crt_deinit(cert);
674 if (((cn[0] ==
'C') || (cn[0] ==
'c')) &&
675 ((cn[1] ==
'N') || (cn[1] ==
'n')) &&
684 char *ecn = strchr(cn,
',');
688 cert_info->san_or_cn = gnutls_strdup(cn);
689 return cert_info->certificate_type;
691 return GNUTLS_CRT_UNKNOWN;
694 return GNUTLS_CRT_UNKNOWN;
697 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
698 #define OUTPUT_CERT_NAME (cert_type == GNUTLS_CRT_X509 ? \
699 cert_info.san_or_cn : \
700 cert_type == GNUTLS_CRT_RAW ? \
701 COAP_DTLS_RPK_CERT_CN : "?")
703 #define OUTPUT_CERT_NAME (cert_type == GNUTLS_CRT_X509 ? \
704 cert_info.san_or_cn : "?")
707 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
709 check_rpk_cert(coap_gnutls_context_t *g_context,
710 coap_gnutls_certificate_info_t *cert_info,
714 if (g_context->setup_data.validate_cn_call_back) {
715 gnutls_pcert_st pcert;
719 G_CHECK(gnutls_pcert_import_rawpk_raw(&pcert, &cert_info->cert_list[0],
720 GNUTLS_X509_FMT_DER, 0, 0),
721 "gnutls_pcert_import_rawpk_raw");
724 G_CHECK(gnutls_pubkey_export(pcert.pubkey, GNUTLS_X509_FMT_DER, der, &size),
725 "gnutls_pubkey_export");
726 gnutls_pcert_deinit(&pcert);
733 g_context->setup_data.cn_call_back_arg)) {
747 static int cert_verify_gnutls(gnutls_session_t g_session)
749 unsigned int status = 0;
750 unsigned int fail = 0;
753 coap_gnutls_context_t *g_context =
755 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
756 int alert = GNUTLS_A_BAD_CERTIFICATE;
758 coap_gnutls_certificate_info_t cert_info;
759 gnutls_certificate_type_t cert_type;
761 memset(&cert_info, 0,
sizeof(cert_info));
762 cert_type = get_san_or_cn(g_session, &cert_info);
763 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
764 if (cert_type == GNUTLS_CRT_RAW) {
765 if (!check_rpk_cert(g_context, &cert_info, c_session)) {
766 alert = GNUTLS_A_ACCESS_DENIED;
773 if (cert_info.cert_list_size == 0 && !g_context->setup_data.verify_peer_cert)
776 G_CHECK(gnutls_certificate_verify_peers(g_session, NULL, 0, &status),
777 "gnutls_certificate_verify_peers");
780 status &= ~(GNUTLS_CERT_INVALID);
781 if (status & (GNUTLS_CERT_NOT_ACTIVATED|GNUTLS_CERT_EXPIRED)) {
782 status &= ~(GNUTLS_CERT_NOT_ACTIVATED|GNUTLS_CERT_EXPIRED);
783 if (g_context->setup_data.allow_expired_certs) {
785 " %s: %s: overridden: '%s'\n",
787 "The certificate has an invalid usage date",
795 "The certificate has an invalid usage date",
799 if (status & (GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED|
800 GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE)) {
801 status &= ~(GNUTLS_CERT_REVOCATION_DATA_SUPERSEDED|
802 GNUTLS_CERT_REVOCATION_DATA_ISSUED_IN_FUTURE);
803 if (g_context->setup_data.allow_expired_crl) {
805 " %s: %s: overridden: '%s'\n",
807 "The certificate's CRL entry has an invalid usage date",
815 "The certificate's CRL entry has an invalid usage date",
819 if (status & (GNUTLS_CERT_SIGNER_NOT_FOUND)) {
820 status &= ~(GNUTLS_CERT_SIGNER_NOT_FOUND);
821 if (cert_info.self_signed) {
822 if (g_context->setup_data.allow_self_signed &&
823 !g_context->setup_data.check_common_ca) {
825 " %s: %s: overridden: '%s'\n",
832 alert = GNUTLS_A_UNKNOWN_CA;
841 if (!g_context->setup_data.verify_peer_cert) {
843 " %s: %s: overridden: '%s'\n",
845 "The peer certificate's CA is unknown",
850 alert = GNUTLS_A_UNKNOWN_CA;
854 "The peer certificate's CA is unknown",
863 " %s: gnutls_certificate_verify_peers() status 0x%x: '%s'\n",
865 status, OUTPUT_CERT_NAME);
872 if (g_context->setup_data.validate_cn_call_back) {
873 gnutls_x509_crt_t cert;
878 const int cert_is_trusted = !status;
880 G_CHECK(gnutls_x509_crt_init(&cert),
"gnutls_x509_crt_init");
883 G_CHECK(gnutls_x509_crt_import(cert, &cert_info.cert_list[0],
884 GNUTLS_X509_FMT_DER),
"gnutls_x509_crt_import");
887 G_CHECK(gnutls_x509_crt_export(cert, GNUTLS_X509_FMT_DER, der, &size),
888 "gnutls_x509_crt_export");
889 gnutls_x509_crt_deinit(cert);
890 if (!g_context->setup_data.validate_cn_call_back(OUTPUT_CERT_NAME,
896 g_context->setup_data.cn_call_back_arg)) {
897 alert = GNUTLS_A_ACCESS_DENIED;
902 if (g_context->setup_data.additional_tls_setup_call_back) {
904 if (!g_context->setup_data.additional_tls_setup_call_back(g_session,
905 &g_context->setup_data)) {
911 if (cert_info.san_or_cn)
912 gnutls_free(cert_info.san_or_cn);
917 if (cert_info.san_or_cn)
918 gnutls_free(cert_info.san_or_cn);
920 if (!g_env->sent_alert) {
921 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL, alert));
922 g_env->sent_alert = 1;
935 static int cert_verify_callback_gnutls(gnutls_session_t g_session)
937 if (gnutls_auth_get_type(g_session) == GNUTLS_CRD_CERTIFICATE) {
938 if (cert_verify_gnutls(g_session) == 0) {
946 #define min(a,b) ((a) < (b) ? (a) : (b))
950 pin_callback(
void *user_data,
int attempt,
968 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
970 static const unsigned char cert_asn1_header1[] = {
974 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01,
979 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07,
981 static const unsigned char cert_asn1_header2[] = {
986 static gnutls_datum_t *
987 get_asn1_spki(
const uint8_t *data,
size_t size)
991 gnutls_datum_t *spki = NULL;
993 if (pub_key && prime) {
994 size_t header_size =
sizeof(cert_asn1_header1) +
997 sizeof(cert_asn1_header2);
998 uint8_t *tmp = gnutls_malloc(
sizeof(gnutls_datum_t) +
1003 spki = (gnutls_datum_t *)tmp;
1004 spki->data = &tmp[
sizeof(gnutls_datum_t)];
1005 memcpy(&spki->data[header_size], pub_key->
s, pub_key->
length);
1006 memcpy(spki->data, cert_asn1_header1,
sizeof(cert_asn1_header1));
1008 spki->data[
sizeof(cert_asn1_header1)+1] = prime->
length;
1009 memcpy(&spki->data[
sizeof(cert_asn1_header1)+2],
1011 memcpy(&spki->data[
sizeof(cert_asn1_header1)+2+prime->
length],
1012 cert_asn1_header2,
sizeof(cert_asn1_header2));
1013 spki->size = header_size + pub_key->
length;
1027 setup_pki_credentials(gnutls_certificate_credentials_t *pki_credentials,
1028 gnutls_session_t g_session,
1029 coap_gnutls_context_t *g_context,
1034 G_CHECK(gnutls_certificate_allocate_credentials(pki_credentials),
1035 "gnutls_certificate_allocate_credentials");
1045 "RPK keys cannot be in COAP_PKI_KEY_PEM format\n");
1046 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1049 G_CHECK(gnutls_certificate_set_x509_key_file(*pki_credentials,
1052 GNUTLS_X509_FMT_PEM),
1053 "gnutls_certificate_set_x509_key_file");
1058 "***setup_pki: (D)TLS: No %s Certificate + Private "
1061 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1065 ret = gnutls_certificate_set_x509_trust_file(*pki_credentials,
1067 GNUTLS_X509_FMT_PEM);
1070 "gnutls_certificate_set_x509_trust_file: No certificates found\n");
1074 "gnutls_certificate_set_x509_trust_file",
1075 gnutls_strerror(ret));
1086 gnutls_datum_t cert;
1088 int alloced_cert_memory = 0;
1089 int alloced_key_memory = 0;
1094 alloced_cert_memory = 1;
1095 cert.data = gnutls_malloc(cert.size + 1);
1098 return GNUTLS_E_MEMORY_ERROR;
1102 cert.data[cert.size] =
'\000';
1113 alloced_key_memory = 1;
1114 key.data = gnutls_malloc(key.size + 1);
1117 if (alloced_cert_memory) gnutls_free(cert.data);
1118 return GNUTLS_E_MEMORY_ERROR;
1121 key.data[key.size] =
'\000';
1130 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
1131 int have_done_key = 0;
1132 if (strstr ((
char*)key.data,
"-----BEGIN EC PRIVATE KEY-----")) {
1133 gnutls_datum_t der_private;
1135 if (gnutls_pem_base64_decode2(
"EC PRIVATE KEY", &key,
1136 &der_private) == 0) {
1137 gnutls_datum_t *spki = get_asn1_spki(der_private.data,
1141 ret = gnutls_certificate_set_rawpk_key_mem(*pki_credentials,
1144 GNUTLS_X509_FMT_DER, NULL,
1145 COAP_GNUTLS_KEY_RPK,
1152 gnutls_free(der_private.data);
1155 if (!have_done_key) {
1156 G_CHECK(gnutls_certificate_set_rawpk_key_mem(*pki_credentials,
1159 GNUTLS_X509_FMT_PEM, NULL,
1160 COAP_GNUTLS_KEY_RPK,
1162 "gnutls_certificate_set_rawpk_key_mem");
1166 "RPK Support not available (needs gnutls 3.6.6 or later)\n");
1167 if (alloced_cert_memory) gnutls_free(cert.data);
1168 if (alloced_key_memory) gnutls_free(key.data);
1169 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1173 G_CHECK(gnutls_certificate_set_x509_key_mem(*pki_credentials,
1176 GNUTLS_X509_FMT_PEM),
1177 "gnutls_certificate_set_x509_key_mem");
1179 if (alloced_cert_memory) gnutls_free(cert.data);
1180 if (alloced_key_memory) gnutls_free(key.data);
1184 "***setup_pki: (D)TLS: No Server Certificate + Private "
1186 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1191 int alloced_ca_memory = 0;
1196 alloced_ca_memory = 1;
1197 ca.data = gnutls_malloc(ca.size + 1);
1200 return GNUTLS_E_MEMORY_ERROR;
1203 ca.data[ca.size] =
'\000';
1211 ret = gnutls_certificate_set_x509_trust_mem(*pki_credentials,
1213 GNUTLS_X509_FMT_PEM);
1216 "gnutls_certificate_set_x509_trust_mem: No certificates found\n");
1220 "gnutls_certificate_set_x509_trust_mem",
1221 gnutls_strerror(ret));
1222 if (alloced_ca_memory) gnutls_free(ca.data);
1225 if (alloced_ca_memory) gnutls_free(ca.data);
1234 gnutls_datum_t cert;
1245 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
1246 int have_done_key = 0;
1249 gnutls_datum_t *spki = get_asn1_spki(key.data,
1253 ret = gnutls_certificate_set_rawpk_key_mem(*pki_credentials,
1256 GNUTLS_X509_FMT_DER, NULL,
1257 COAP_GNUTLS_KEY_RPK,
1265 if (!have_done_key) {
1266 G_CHECK(gnutls_certificate_set_rawpk_key_mem(*pki_credentials,
1269 GNUTLS_X509_FMT_DER, NULL,
1270 COAP_GNUTLS_KEY_RPK,
1272 "gnutls_certificate_set_rawpk_key_mem");
1276 "RPK Support not available (needs gnutls 3.6.6 or later)\n");
1277 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1281 G_CHECK(gnutls_certificate_set_x509_key_mem(*pki_credentials,
1284 GNUTLS_X509_FMT_DER),
1285 "gnutls_certificate_set_x509_key_mem");
1290 "***setup_pki: (D)TLS: No %s Certificate + Private "
1293 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1297 gnutls_datum_t ca_cert;
1301 sizeof(ca_cert.data));
1303 ret = gnutls_certificate_set_x509_trust_mem(*pki_credentials,
1305 GNUTLS_X509_FMT_DER);
1308 "gnutls_certificate_set_x509_trust_mem: No certificates found\n");
1312 "gnutls_certificate_set_x509_trust_mem",
1313 gnutls_strerror(ret));
1325 gnutls_pkcs11_set_pin_function(pin_callback, setup_data);
1327 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
1328 G_CHECK(gnutls_certificate_set_rawpk_key_file(*pki_credentials,
1331 GNUTLS_X509_FMT_PEM, NULL,
1332 COAP_GNUTLS_KEY_RPK,
1333 NULL, 0, GNUTLS_PKCS_PLAIN, 0),
1334 "gnutls_certificate_set_rawpk_key_file");
1337 "RPK Support not available (needs gnutls 3.6.6 or later)\n");
1338 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1342 G_CHECK(gnutls_certificate_set_x509_key_file(*pki_credentials,
1345 GNUTLS_X509_FMT_DER),
1346 "gnutls_certificate_set_x509_key_file");
1351 "***setup_pki: (D)TLS: No %s Certificate + Private "
1354 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1358 ret = gnutls_certificate_set_x509_trust_file(*pki_credentials,
1360 GNUTLS_X509_FMT_DER);
1363 "gnutls_certificate_set_x509_trust_file: No certificates found\n");
1367 "gnutls_certificate_set_x509_trust_file",
1368 gnutls_strerror(ret));
1376 "***setup_pki: (D)TLS: Unknown key type %d\n",
1378 return GNUTLS_E_INSUFFICIENT_CREDENTIALS;
1381 if (g_context->root_ca_file) {
1382 ret = gnutls_certificate_set_x509_trust_file(*pki_credentials,
1383 g_context->root_ca_file,
1384 GNUTLS_X509_FMT_PEM);
1387 "gnutls_certificate_set_x509_trust_file: Root CA: No certificates found\n");
1390 if (g_context->root_ca_path) {
1391 #if (GNUTLS_VERSION_NUMBER >= 0x030306)
1392 G_CHECK(gnutls_certificate_set_x509_trust_dir(*pki_credentials,
1393 g_context->root_ca_path,
1394 GNUTLS_X509_FMT_PEM),
1395 "gnutls_certificate_set_x509_trust_dir");
1398 gnutls_certificate_send_x509_rdn_sequence(g_session,
1400 if (!(g_context->psk_pki_enabled & IS_PKI)) {
1402 G_CHECK(gnutls_certificate_set_x509_system_trust(*pki_credentials),
1403 "gnutls_certificate_set_x509_system_trust");
1407 gnutls_certificate_set_verify_function(*pki_credentials,
1408 cert_verify_callback_gnutls);
1412 gnutls_certificate_set_verify_limits(*pki_credentials,
1421 gnutls_certificate_set_verify_flags(*pki_credentials,
1423 GNUTLS_VERIFY_DISABLE_CRL_CHECKS : 0)
1426 return GNUTLS_E_SUCCESS;
1437 setup_psk_credentials(gnutls_psk_server_credentials_t *psk_credentials,
1444 G_CHECK(gnutls_psk_allocate_server_credentials(psk_credentials),
1445 "gnutls_psk_allocate_server_credentials");
1446 gnutls_psk_set_server_credentials_function(*psk_credentials,
1447 psk_server_callback);
1451 G_CHECK(gnutls_psk_set_server_credentials_hint(*psk_credentials, hint),
1452 "gnutls_psk_set_server_credentials_hint");
1455 return GNUTLS_E_SUCCESS;
1467 post_client_hello_gnutls_psk(gnutls_session_t g_session)
1471 coap_gnutls_context_t *g_context =
1473 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1474 int ret = GNUTLS_E_SUCCESS;
1484 name = gnutls_malloc(len);
1486 return GNUTLS_E_MEMORY_ERROR;
1489 ret = gnutls_server_name_get(g_session, name, &len, &type, i);
1490 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
1492 new_name = gnutls_realloc(name, len);
1493 if (new_name == NULL) {
1494 ret = GNUTLS_E_MEMORY_ERROR;
1502 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1505 if (ret != GNUTLS_E_SUCCESS)
1508 if (type != GNUTLS_NAME_DNS)
1519 for (i = 0; i < g_context->psk_sni_count; i++) {
1520 if (strcasecmp(name, g_context->psk_sni_entry_list[i].sni) == 0) {
1524 if (i == g_context->psk_sni_count) {
1533 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
1534 GNUTLS_A_UNRECOGNIZED_NAME));
1535 g_env->sent_alert = 1;
1536 ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
1540 g_context->psk_sni_entry_list =
1541 gnutls_realloc(g_context->psk_sni_entry_list,
1542 (i+1)*
sizeof(psk_sni_entry));
1543 g_context->psk_sni_entry_list[i].sni = gnutls_strdup(name);
1544 g_context->psk_sni_entry_list[i].psk_info = *new_entry;
1546 sni_setup_data.
psk_info = *new_entry;
1547 if ((ret = setup_psk_credentials(
1548 &g_context->psk_sni_entry_list[i].psk_credentials,
1550 &sni_setup_data)) < 0) {
1552 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
1553 GNUTLS_A_BAD_CERTIFICATE));
1554 g_env->sent_alert = 1;
1558 g_context->psk_sni_count++;
1560 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_PSK,
1561 g_context->psk_sni_entry_list[i].psk_credentials),
1562 "gnutls_credentials_set");
1564 &g_context->psk_sni_entry_list[i].psk_info.hint);
1566 &g_context->psk_sni_entry_list[i].psk_info.key);
1582 post_client_hello_gnutls_pki(gnutls_session_t g_session)
1586 coap_gnutls_context_t *g_context =
1588 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1589 int ret = GNUTLS_E_SUCCESS;
1592 if (g_context->setup_data.validate_sni_call_back) {
1599 name = gnutls_malloc(len);
1601 return GNUTLS_E_MEMORY_ERROR;
1604 ret = gnutls_server_name_get(g_session, name, &len, &type, i);
1605 if (ret == GNUTLS_E_SHORT_MEMORY_BUFFER) {
1607 new_name = gnutls_realloc(name, len);
1608 if (new_name == NULL) {
1609 ret = GNUTLS_E_MEMORY_ERROR;
1617 if (ret == GNUTLS_E_REQUESTED_DATA_NOT_AVAILABLE)
1620 if (ret != GNUTLS_E_SUCCESS)
1623 if (type != GNUTLS_NAME_DNS)
1634 for (i = 0; i < g_context->pki_sni_count; i++) {
1635 if (strcasecmp(name, g_context->pki_sni_entry_list[i].sni) == 0) {
1639 if (i == g_context->pki_sni_count) {
1644 g_context->setup_data.validate_sni_call_back(name,
1645 g_context->setup_data.sni_call_back_arg);
1647 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
1648 GNUTLS_A_UNRECOGNIZED_NAME));
1649 g_env->sent_alert = 1;
1650 ret = GNUTLS_E_NO_CERTIFICATE_FOUND;
1654 g_context->pki_sni_entry_list = gnutls_realloc(
1655 g_context->pki_sni_entry_list,
1656 (i+1)*
sizeof(pki_sni_entry));
1657 g_context->pki_sni_entry_list[i].sni = gnutls_strdup(name);
1658 g_context->pki_sni_entry_list[i].pki_key = *new_entry;
1659 sni_setup_data = g_context->setup_data;
1660 sni_setup_data.
pki_key = *new_entry;
1661 if ((ret = setup_pki_credentials(
1662 &g_context->pki_sni_entry_list[i].pki_credentials,
1667 G_ACTION(gnutls_alert_send(g_session, GNUTLS_AL_FATAL,
1668 GNUTLS_A_BAD_CERTIFICATE));
1669 g_env->sent_alert = 1;
1673 g_context->pki_sni_count++;
1675 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
1676 g_context->pki_sni_entry_list[i].pki_credentials),
1677 "gnutls_credentials_set");
1693 setup_client_ssl_session(
coap_session_t *c_session, coap_gnutls_env_t *g_env)
1695 coap_gnutls_context_t *g_context =
1699 g_context->psk_pki_enabled |= IS_CLIENT;
1700 if (g_context->psk_pki_enabled & IS_PSK) {
1702 G_CHECK(gnutls_psk_allocate_client_credentials(&g_env->psk_cl_credentials),
1703 "gnutls_psk_allocate_client_credentials");
1704 gnutls_psk_set_client_credentials_function(g_env->psk_cl_credentials,
1705 psk_client_callback);
1706 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_PSK,
1707 g_env->psk_cl_credentials),
1708 "gnutls_credentials_set");
1711 G_CHECK(gnutls_server_name_set(g_env->g_session, GNUTLS_NAME_DNS,
1714 "gnutls_server_name_set");
1720 if (tls_version->
version >= 0x030604) {
1722 const char *priority;
1724 if (tls_version->
version >= 0x030606) {
1725 priority = VARIANTS_NO_TLS13_3_6_6;
1728 priority = VARIANTS_NO_TLS13_3_6_4;
1730 ret = gnutls_priority_set_direct(g_env->g_session,
1733 if (ret == GNUTLS_E_INVALID_REQUEST)
1735 "gnutls_priority_set_direct: Syntax error at: %s\n", err);
1738 "gnutls_priority_set_direct: %s\n", gnutls_strerror(ret));
1745 if ((g_context->psk_pki_enabled & IS_PKI) ||
1746 (g_context->psk_pki_enabled & (IS_PSK | IS_PKI)) == 0) {
1752 G_CHECK(setup_pki_credentials(&g_env->pki_credentials, g_env->g_session,
1753 g_context, setup_data,
1755 "setup_pki_credentials");
1757 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
1758 g_env->pki_credentials),
1759 "gnutls_credentials_set");
1762 G_CHECK(gnutls_alpn_set_protocols(g_env->g_session,
1763 &g_context->alpn_proto, 1, 0),
1764 "gnutls_alpn_set_protocols");
1768 G_CHECK(gnutls_server_name_set(g_env->g_session, GNUTLS_NAME_DNS,
1771 "gnutls_server_name_set");
1774 return GNUTLS_E_SUCCESS;
1788 psk_server_callback(gnutls_session_t g_session,
1789 const char *identity,
1790 gnutls_datum_t *key)
1794 coap_gnutls_context_t *g_context;
1796 size_t identity_len = 0;
1800 if (c_session == NULL || c_session->
context == NULL ||
1805 if (g_context == NULL)
1810 identity_len = strlen(identity);
1821 (
int)identity_len, identity);
1825 lidentity.
length = identity_len;
1826 lidentity.
s = (
const uint8_t*)identity;
1832 if (psk_key == NULL)
1834 key->data = gnutls_malloc(psk_key->
length);
1835 if (key->data == NULL)
1837 memcpy(key->data, psk_key->
s, psk_key->
length);
1838 key->size = psk_key->
length;
1844 (
const uint8_t*)identity,
1846 (uint8_t*)buf,
sizeof(buf));
1847 key->data = gnutls_malloc(psk_len);
1848 memcpy(key->data, buf, psk_len);
1849 key->size = psk_len;
1858 setup_server_ssl_session(
coap_session_t *c_session, coap_gnutls_env_t *g_env)
1860 coap_gnutls_context_t *g_context =
1862 int ret = GNUTLS_E_SUCCESS;
1864 g_context->psk_pki_enabled |= IS_SERVER;
1865 if (g_context->psk_pki_enabled & IS_PSK) {
1866 G_CHECK(setup_psk_credentials(
1867 &g_env->psk_sv_credentials,
1870 "setup_psk_credentials\n");
1871 G_CHECK(gnutls_credentials_set(g_env->g_session,
1873 g_env->psk_sv_credentials),
1874 "gnutls_credentials_set\n");
1875 gnutls_handshake_set_post_client_hello_function(g_env->g_session,
1876 post_client_hello_gnutls_psk);
1879 if (g_context->psk_pki_enabled & IS_PKI) {
1881 G_CHECK(setup_pki_credentials(&g_env->pki_credentials, g_env->g_session,
1882 g_context, setup_data,
1884 "setup_pki_credentials");
1887 gnutls_certificate_server_set_request(g_env->g_session,
1888 GNUTLS_CERT_REQUIRE);
1891 gnutls_certificate_server_set_request(g_env->g_session,
1892 GNUTLS_CERT_REQUEST);
1895 gnutls_certificate_server_set_request(g_env->g_session,
1896 GNUTLS_CERT_IGNORE);
1899 gnutls_handshake_set_post_client_hello_function(g_env->g_session,
1900 post_client_hello_gnutls_pki);
1902 G_CHECK(gnutls_credentials_set(g_env->g_session, GNUTLS_CRD_CERTIFICATE,
1903 g_env->pki_credentials),
1904 "gnutls_credentials_set\n");
1906 return GNUTLS_E_SUCCESS;
1918 coap_dgram_read(gnutls_transport_ptr_t context,
void *out,
size_t outl)
1924 if (!c_session->
tls) {
1928 data = &((coap_gnutls_env_t *)c_session->
tls)->coap_ssl_data;
1931 if (data != NULL && data->pdu_len > 0) {
1932 if (outl < data->pdu_len) {
1933 memcpy(out, data->pdu, outl);
1935 if (!data->peekmode) {
1937 data->pdu_len -= outl;
1940 memcpy(out, data->pdu, data->pdu_len);
1941 ret = data->pdu_len;
1942 if (!data->peekmode) {
1963 coap_dgram_write(gnutls_transport_ptr_t context,
const void *send_buffer,
1964 size_t send_buffer_length) {
1965 ssize_t result = -1;
1970 if (result != (
int)send_buffer_length) {
1986 receive_timeout(gnutls_transport_ptr_t context,
unsigned int ms
COAP_UNUSED) {
1990 fd_set readfds, writefds, exceptfds;
1992 int nfds = c_session->
sock.
fd +1;
1993 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
1997 g_env->coap_ssl_data.pdu_len > 0) {
2003 FD_ZERO(&exceptfds);
2004 FD_SET (c_session->
sock.
fd, &readfds);
2005 if (!(g_env && g_env->doing_dtls_timeout)) {
2006 FD_SET (c_session->
sock.
fd, &writefds);
2007 FD_SET (c_session->
sock.
fd, &exceptfds);
2013 return select(nfds, &readfds, &writefds, &exceptfds, &tv);
2018 static coap_gnutls_env_t *
2021 coap_gnutls_context_t *g_context =
2023 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
2024 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
2025 int flags = type | GNUTLS_DATAGRAM | GNUTLS_NONBLOCK | GNUTLS_ENABLE_RAWPK;
2027 int flags = type | GNUTLS_DATAGRAM | GNUTLS_NONBLOCK;
2034 g_env = gnutls_malloc(
sizeof(coap_gnutls_env_t));
2038 memset(g_env, 0,
sizeof(coap_gnutls_env_t));
2040 G_CHECK(gnutls_init(&g_env->g_session, flags),
"gnutls_init");
2042 gnutls_transport_set_pull_function(g_env->g_session, coap_dgram_read);
2043 gnutls_transport_set_push_function(g_env->g_session, coap_dgram_write);
2044 gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
2046 gnutls_transport_set_ptr(g_env->g_session, c_session);
2048 G_CHECK(gnutls_priority_set(g_env->g_session, g_context->priority_cache),
2049 "gnutls_priority_set");
2051 if (type == GNUTLS_SERVER) {
2052 G_CHECK(setup_server_ssl_session(c_session, g_env),
2053 "setup_server_ssl_session");
2056 G_CHECK(setup_client_ssl_session(c_session, g_env),
2057 "setup_client_ssl_session");
2060 gnutls_handshake_set_timeout(g_env->g_session,
2061 GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
2074 coap_dtls_free_gnutls_env(coap_gnutls_context_t *g_context,
2075 coap_gnutls_env_t *g_env,
2076 coap_free_bye_t free_bye)
2082 if (free_bye != COAP_FREE_BYE_NONE && !g_env->sent_alert) {
2084 gnutls_bye(g_env->g_session, free_bye == COAP_FREE_BYE_AS_UDP ?
2085 GNUTLS_SHUT_WR : GNUTLS_SHUT_RDWR);
2087 gnutls_deinit(g_env->g_session);
2088 g_env->g_session = NULL;
2089 if (g_context->psk_pki_enabled & IS_PSK) {
2090 if ((g_context->psk_pki_enabled & IS_CLIENT) &&
2091 g_env->psk_cl_credentials != NULL) {
2092 gnutls_psk_free_client_credentials(g_env->psk_cl_credentials);
2093 g_env->psk_cl_credentials = NULL;
2097 if (g_env->psk_sv_credentials != NULL)
2098 gnutls_psk_free_server_credentials(g_env->psk_sv_credentials);
2099 g_env->psk_sv_credentials = NULL;
2102 if ((g_context->psk_pki_enabled & IS_PKI) ||
2103 (g_context->psk_pki_enabled &
2104 (IS_PSK | IS_PKI | IS_CLIENT)) == IS_CLIENT) {
2105 gnutls_certificate_free_credentials(g_env->pki_credentials);
2106 g_env->pki_credentials = NULL;
2108 gnutls_free(g_env->coap_ssl_data.cookie_key.data);
2114 coap_gnutls_env_t *g_env =
2115 (coap_gnutls_env_t *)c_session->
tls;
2117 gnutls_transport_set_ptr(g_env->g_session, c_session);
2123 gnutls_session_t g_session) {
2124 int last_alert = gnutls_alert_get(g_session);
2126 if (last_alert == GNUTLS_A_CLOSE_NOTIFY)
2129 last_alert, gnutls_alert_get_name(last_alert));
2133 last_alert, gnutls_alert_get_name(last_alert));
2142 do_gnutls_handshake(
coap_session_t *c_session, coap_gnutls_env_t *g_env) {
2145 ret = gnutls_handshake(g_env->g_session);
2147 case GNUTLS_E_SUCCESS:
2148 g_env->established = 1;
2153 case GNUTLS_E_INTERRUPTED:
2157 case GNUTLS_E_AGAIN:
2161 case GNUTLS_E_INSUFFICIENT_CREDENTIALS:
2163 "Insufficient credentials provided.\n");
2166 case GNUTLS_E_FATAL_ALERT_RECEIVED:
2168 g_env->sent_alert = 1;
2169 log_last_alert(c_session, g_env->g_session);
2171 case GNUTLS_E_UNEXPECTED_HANDSHAKE_PACKET:
2175 case GNUTLS_E_WARNING_ALERT_RECEIVED:
2176 log_last_alert(c_session, g_env->g_session);
2180 case GNUTLS_E_NO_CERTIFICATE_FOUND:
2181 #if (GNUTLS_VERSION_NUMBER > 0x030606)
2182 case GNUTLS_E_CERTIFICATE_REQUIRED:
2185 "Client Certificate requested and required, but not provided\n"
2187 G_ACTION(gnutls_alert_send(g_env->g_session, GNUTLS_AL_FATAL,
2188 GNUTLS_A_BAD_CERTIFICATE));
2189 g_env->sent_alert = 1;
2193 case GNUTLS_E_DECRYPTION_FAILED:
2195 "do_gnutls_handshake: session establish "
2197 gnutls_strerror(ret));
2198 G_ACTION(gnutls_alert_send(g_env->g_session, GNUTLS_AL_FATAL,
2199 GNUTLS_A_DECRYPT_ERROR));
2200 g_env->sent_alert = 1;
2204 case GNUTLS_E_CERTIFICATE_ERROR:
2205 if (g_env->sent_alert) {
2211 case GNUTLS_E_UNKNOWN_CIPHER_SUITE:
2212 case GNUTLS_E_NO_CIPHER_SUITES:
2213 case GNUTLS_E_INVALID_SESSION:
2215 "do_gnutls_handshake: session establish "
2217 gnutls_strerror(ret));
2218 if (!g_env->sent_alert) {
2219 G_ACTION(gnutls_alert_send(g_env->g_session, GNUTLS_AL_FATAL,
2220 GNUTLS_A_HANDSHAKE_FAILURE));
2221 g_env->sent_alert = 1;
2226 case GNUTLS_E_SESSION_EOF:
2227 case GNUTLS_E_TIMEDOUT:
2228 case GNUTLS_E_PULL_ERROR:
2229 case GNUTLS_E_PUSH_ERROR:
2235 "do_gnutls_handshake: session establish "
2236 "returned %d: '%s'\n",
2237 ret, gnutls_strerror(ret));
2245 coap_gnutls_env_t *g_env = coap_dtls_new_gnutls_env(c_session, GNUTLS_CLIENT);
2249 ret = do_gnutls_handshake(c_session, g_env);
2254 COAP_FREE_BYE_AS_UDP : COAP_FREE_BYE_AS_TCP);
2262 if (c_session && c_session->
context && c_session->
tls) {
2266 COAP_FREE_BYE_AS_UDP : COAP_FREE_BYE_AS_TCP);
2267 c_session->
tls = NULL;
2273 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
2277 G_CHECK(gnutls_dtls_set_data_mtu(g_env->g_session,
2278 (
unsigned int)c_session->
mtu),
2279 "gnutls_dtls_set_data_mtu");
2290 const uint8_t *data,
size_t data_len) {
2292 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
2294 assert(g_env != NULL);
2297 if (g_env->established) {
2298 ret = gnutls_record_send(g_env->g_session, data, data_len);
2302 case GNUTLS_E_AGAIN:
2305 case GNUTLS_E_FATAL_ALERT_RECEIVED:
2307 g_env->sent_alert = 1;
2308 log_last_alert(c_session, g_env->g_session);
2314 "coap_dtls_send: gnutls_record_send "
2315 "returned %d: '%s'\n",
2316 ret, gnutls_strerror(ret));
2326 ret = do_gnutls_handshake(c_session, g_env);
2355 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
2358 if (g_env && g_env->g_session) {
2359 unsigned int rem_ms = gnutls_dtls_get_timeout(g_env->g_session);
2372 g_env->last_timeout = now;
2373 return now + rem_ms;
2380 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
2383 g_env->doing_dtls_timeout = 1;
2385 (do_gnutls_handshake(c_session, g_env) < 0)) {
2387 g_env->doing_dtls_timeout = 0;
2391 g_env->doing_dtls_timeout = 0;
2402 const uint8_t *data,
2405 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
2407 coap_ssl_t *ssl_data = &g_env->coap_ssl_data;
2411 assert(g_env != NULL);
2413 if (ssl_data->pdu_len)
2416 ssl_data->pdu = data;
2417 ssl_data->pdu_len = data_len;
2420 if (g_env->established) {
2424 gnutls_transport_set_ptr(g_env->g_session, c_session);
2427 ret = gnutls_record_recv(g_env->g_session, pdu, (
int)
sizeof(pdu));
2431 else if (ret == 0) {
2436 case GNUTLS_E_FATAL_ALERT_RECEIVED:
2438 g_env->sent_alert = 1;
2439 log_last_alert(c_session, g_env->g_session);
2443 case GNUTLS_E_WARNING_ALERT_RECEIVED:
2444 log_last_alert(c_session, g_env->g_session);
2450 "coap_dtls_receive: gnutls_record_recv returned %d\n", ret);
2457 ret = do_gnutls_handshake(c_session, g_env);
2463 if (ssl_data->pdu_len && !g_env->sent_alert) {
2465 ret = do_gnutls_handshake(c_session, g_env);
2485 if (ssl_data && ssl_data->pdu_len) {
2487 coap_log(
LOG_DEBUG,
"coap_dtls_receive: ret %d: remaining data %u\n", ret, ssl_data->pdu_len);
2488 ssl_data->pdu_len = 0;
2489 ssl_data->pdu = NULL;
2501 const uint8_t *data,
2504 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
2505 coap_ssl_t *ssl_data;
2509 g_env = coap_dtls_new_gnutls_env(c_session, GNUTLS_SERVER);
2511 c_session->
tls = g_env;
2512 gnutls_key_generate(&g_env->coap_ssl_data.cookie_key,
2513 GNUTLS_COOKIE_KEY_SIZE);
2521 gnutls_dtls_prestate_st prestate;
2524 memset(&prestate, 0,
sizeof(prestate));
2526 memcpy (&data_rw, &data,
sizeof(data_rw));
2527 ret = gnutls_dtls_cookie_verify(&g_env->coap_ssl_data.cookie_key,
2534 gnutls_dtls_cookie_send(&g_env->coap_ssl_data.cookie_key,
2542 gnutls_dtls_prestate_set(g_env->g_session, &prestate);
2545 ssl_data = &g_env->coap_ssl_data;
2546 ssl_data->pdu = data;
2547 ssl_data->pdu_len = data_len;
2549 ret = do_gnutls_handshake(c_session, g_env);
2555 coap_dtls_free_gnutls_env(
2557 g_env, COAP_FREE_BYE_NONE);
2558 c_session->
tls = NULL;
2567 if (ssl_data && ssl_data->pdu_len) {
2569 coap_log(
LOG_DEBUG,
"coap_dtls_hello: ret %d: remaining data %u\n", ret, ssl_data->pdu_len);
2570 ssl_data->pdu_len = 0;
2571 ssl_data->pdu = NULL;
2580 #if !COAP_DISABLE_TCP
2587 coap_sock_read(gnutls_transport_ptr_t context,
void *out,
size_t outl) {
2593 ret = recv(c_session->
sock.
fd, (
char *)out, (
int)outl, 0);
2595 ret = recv(c_session->
sock.
fd, out, outl, 0);
2600 }
else if (ret < 0 && errno != EAGAIN) {
2610 else if (ret < (ssize_t)outl)
2623 coap_sock_write(gnutls_transport_ptr_t context,
const void *in,
size_t inl) {
2631 }
else if (ret < 0) {
2634 (errno == EPIPE || errno == ECONNRESET)) {
2662 coap_gnutls_env_t *g_env = gnutls_malloc(
sizeof(coap_gnutls_env_t));
2663 coap_gnutls_context_t *g_context =
2665 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
2666 int flags = GNUTLS_CLIENT | GNUTLS_NONBLOCK | GNUTLS_ENABLE_RAWPK;
2668 int flags = GNUTLS_CLIENT | GNUTLS_NONBLOCK;
2675 memset(g_env, 0,
sizeof(coap_gnutls_env_t));
2678 G_CHECK(gnutls_init(&g_env->g_session, flags),
"gnutls_init");
2680 gnutls_transport_set_pull_function(g_env->g_session, coap_sock_read);
2681 gnutls_transport_set_push_function(g_env->g_session, coap_sock_write);
2682 gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
2684 gnutls_transport_set_ptr(g_env->g_session, c_session);
2686 gnutls_priority_set(g_env->g_session, g_context->priority_cache);
2687 setup_client_ssl_session(c_session, g_env);
2689 gnutls_handshake_set_timeout(g_env->g_session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
2691 c_session->
tls = g_env;
2692 ret = do_gnutls_handshake(c_session, g_env);
2707 coap_gnutls_env_t *g_env = gnutls_malloc(
sizeof(coap_gnutls_env_t));
2708 coap_gnutls_context_t *g_context =
2710 #if (GNUTLS_VERSION_NUMBER >= 0x030606)
2711 int flags = GNUTLS_SERVER | GNUTLS_NONBLOCK | GNUTLS_ENABLE_RAWPK;
2713 int flags = GNUTLS_SERVER | GNUTLS_NONBLOCK;
2719 memset(g_env, 0,
sizeof(coap_gnutls_env_t));
2722 G_CHECK(gnutls_init(&g_env->g_session, flags),
"gnutls_init");
2724 gnutls_transport_set_pull_function(g_env->g_session, coap_sock_read);
2725 gnutls_transport_set_push_function(g_env->g_session, coap_sock_write);
2726 gnutls_transport_set_pull_timeout_function(g_env->g_session, receive_timeout);
2728 gnutls_transport_set_ptr(g_env->g_session, c_session);
2730 setup_server_ssl_session(c_session, g_env);
2732 gnutls_priority_set(g_env->g_session, g_context->priority_cache);
2733 gnutls_handshake_set_timeout(g_env->g_session,
2734 GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);
2736 c_session->
tls = g_env;
2737 ret = do_gnutls_handshake(c_session, g_env);
2758 const uint8_t *data,
2762 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
2764 assert(g_env != NULL);
2767 if (g_env->established) {
2768 ret = gnutls_record_send(g_env->g_session, data, data_len);
2772 case GNUTLS_E_AGAIN:
2775 case GNUTLS_E_PUSH_ERROR:
2776 case GNUTLS_E_PULL_ERROR:
2777 case GNUTLS_E_PREMATURE_TERMINATION:
2781 case GNUTLS_E_FATAL_ALERT_RECEIVED:
2783 g_env->sent_alert = 1;
2784 log_last_alert(c_session, g_env->g_session);
2790 "coap_tls_write: gnutls_record_send "
2791 "returned %d: '%s'\n",
2792 ret, gnutls_strerror(ret));
2802 ret = do_gnutls_handshake(c_session, g_env);
2836 coap_gnutls_env_t *g_env = (coap_gnutls_env_t *)c_session->
tls;
2843 if (!g_env->established && !g_env->sent_alert) {
2844 ret = do_gnutls_handshake(c_session, g_env);
2852 ret = gnutls_record_recv(g_env->g_session, data, (
int)data_len);
2858 case GNUTLS_E_AGAIN:
2862 case GNUTLS_E_PULL_ERROR:
2865 case GNUTLS_E_FATAL_ALERT_RECEIVED:
2867 g_env->sent_alert = 1;
2868 log_last_alert(c_session, g_env->g_session);
2872 case GNUTLS_E_WARNING_ALERT_RECEIVED:
2873 log_last_alert(c_session, g_env->g_session);
2879 "coap_tls_read: gnutls_record_recv "
2880 "returned %d: '%s'\n",
2881 ret, gnutls_strerror(ret));
2904 gnutls_hash_hd_t digest_ctx;
2906 if (gnutls_hash_init(&digest_ctx, GNUTLS_DIG_SHA256)) {
2914 gnutls_hash_deinit(digest_ctx, NULL);
2919 const uint8_t *data,
2921 int ret = gnutls_hash(digest_ctx, data, data_len);
2929 gnutls_hash_output(digest_ctx, (uint8_t*)digest_buffer);
2941 #pragma GCC diagnostic ignored "-Wunused-function"
Pulls together all the internal only header files.
ssize_t coap_socket_write(coap_socket_t *sock, const uint8_t *data, size_t data_len)
const char * coap_socket_strerror(void)
#define COAP_RXBUFFER_SIZE
#define COAP_SOCKET_ERROR
#define COAP_SOCKET_CAN_READ
non blocking socket can now read without blocking
void * coap_dtls_new_server_session(coap_session_t *session COAP_UNUSED)
int coap_dtls_context_set_spsk(coap_context_t *ctx COAP_UNUSED, coap_dtls_spsk_t *setup_data COAP_UNUSED)
void coap_dtls_handle_timeout(coap_session_t *session COAP_UNUSED)
int coap_dtls_context_set_pki(coap_context_t *ctx COAP_UNUSED, const coap_dtls_pki_t *setup_data COAP_UNUSED, const coap_dtls_role_t role COAP_UNUSED)
coap_tick_t coap_dtls_get_timeout(coap_session_t *session COAP_UNUSED, coap_tick_t now COAP_UNUSED)
void * coap_dtls_new_context(coap_context_t *coap_context COAP_UNUSED)
int coap_dtls_send(coap_session_t *session COAP_UNUSED, const uint8_t *data COAP_UNUSED, size_t data_len COAP_UNUSED)
void * coap_dtls_new_client_session(coap_session_t *session COAP_UNUSED)
ssize_t coap_tls_read(coap_session_t *session COAP_UNUSED, uint8_t *data COAP_UNUSED, size_t data_len COAP_UNUSED)
coap_tick_t coap_dtls_get_context_timeout(void *dtls_context COAP_UNUSED)
int coap_dtls_receive(coap_session_t *session COAP_UNUSED, const uint8_t *data COAP_UNUSED, size_t data_len COAP_UNUSED)
unsigned int coap_dtls_get_overhead(coap_session_t *session COAP_UNUSED)
void * coap_tls_new_client_session(coap_session_t *session COAP_UNUSED, int *connected COAP_UNUSED)
void * coap_tls_new_server_session(coap_session_t *session COAP_UNUSED, int *connected COAP_UNUSED)
int coap_dtls_hello(coap_session_t *session COAP_UNUSED, const uint8_t *data COAP_UNUSED, size_t data_len COAP_UNUSED)
int coap_dtls_context_check_keys_enabled(coap_context_t *ctx COAP_UNUSED)
static int dtls_log_level
int coap_dtls_context_set_cpsk(coap_context_t *ctx COAP_UNUSED, coap_dtls_cpsk_t *setup_data COAP_UNUSED)
ssize_t coap_tls_write(coap_session_t *session COAP_UNUSED, const uint8_t *data COAP_UNUSED, size_t data_len COAP_UNUSED)
void coap_dtls_session_update_mtu(coap_session_t *session COAP_UNUSED)
int coap_dtls_context_set_pki_root_cas(coap_context_t *ctx COAP_UNUSED, const char *ca_file COAP_UNUSED, const char *ca_path COAP_UNUSED)
void coap_dtls_free_context(void *handle COAP_UNUSED)
void coap_dtls_free_session(coap_session_t *coap_session COAP_UNUSED)
void * coap_dtls_get_tls(const coap_session_t *c_session COAP_UNUSED, coap_tls_library_t *tls_lib)
void coap_tls_free_session(coap_session_t *coap_session COAP_UNUSED)
coap_binary_t * get_asn1_tag(coap_asn1_tag_t ltag, const uint8_t *ptr, size_t tlen, asn1_validate validate)
Get the asn1 tag and data from the current ptr.
void coap_digest_free(coap_digest_ctx_t *digest_ctx)
Free off coap_digest_ctx_t.
coap_digest_ctx_t * coap_digest_setup(void)
Initialize a coap_digest.
int coap_digest_final(coap_digest_ctx_t *digest_ctx, coap_digest_t *digest_buffer)
Finalize the coap_digest information into the provided digest_buffer.
int coap_digest_update(coap_digest_ctx_t *digest_ctx, const uint8_t *data, size_t data_len)
Update the coap_digest information with the next chunk of data.
uint64_t coap_tick_t
This data type represents internal timer ticks with COAP_TICKS_PER_SECOND resolution.
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_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_startup(void)
Initialize the underlying (D)TLS Library layer.
#define COAP_DTLS_RETRANSMIT_MS
int coap_dtls_is_context_timeout(void)
Check if timeout is handled per CoAP session or per CoAP context.
void coap_dtls_shutdown(void)
Close down the underlying (D)TLS Library layer.
#define COAP_DTLS_RETRANSMIT_COAP_TICKS
#define COAP_DTLS_RETRANSMIT_TOTAL_MS
#define COAP_DTLS_HINT_LENGTH
int coap_tls_is_supported(void)
Check whether TLS is available.
#define COAP_DTLS_RPK_CERT_CN
coap_tls_version_t * coap_get_tls_library_version(void)
Determine the type and version of the underlying (D)TLS library.
int coap_dtls_is_supported(void)
Check whether DTLS is available.
@ COAP_DTLS_ROLE_SERVER
Internal function invoked for server.
@ COAP_DTLS_ROLE_CLIENT
Internal function invoked for client.
@ COAP_PKI_KEY_PKCS11
The PKI key type is PKCS11 (DER)
@ COAP_PKI_KEY_PEM_BUF
The PKI key type is PEM buffer.
@ COAP_PKI_KEY_PEM
The PKI key type is PEM file.
@ COAP_PKI_KEY_ASN1
The PKI key type is ASN.1 (DER) buffer.
@ COAP_ASN1_PKEY_EC
EC type.
@ COAP_TLS_LIBRARY_GNUTLS
Using GnuTLS library.
#define COAP_EVENT_DTLS_ERROR
#define COAP_EVENT_DTLS_CLOSED
(D)TLS events for COAP_PROTO_DTLS and COAP_PROTO_TLS
#define COAP_EVENT_DTLS_CONNECTED
void coap_dtls_set_log_level(int level)
Sets the (D)TLS logging level to the specified level.
const char * coap_session_str(const coap_session_t *session)
Get session description.
int coap_dtls_get_log_level(void)
Get the current (D)TLS logging.
#define coap_log(level,...)
Logging function.
int coap_session_refresh_psk_hint(coap_session_t *session, const coap_bin_const_t *psk_hint)
Refresh the session's current Identity Hint (PSK).
void coap_session_send_csm(coap_session_t *session)
Notify session transport has just connected and CSM exchange can now start.
ssize_t coap_session_send(coap_session_t *session, const uint8_t *data, size_t datalen)
Function interface for datagram data transmission.
int coap_session_refresh_psk_key(coap_session_t *session, const coap_bin_const_t *psk_key)
Refresh the session's current pre-shared key (PSK).
void coap_session_connected(coap_session_t *session)
Notify session that it has just connected or reconnected.
#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.
@ COAP_SESSION_STATE_HANDSHAKE
@ COAP_SESSION_STATE_NONE
void coap_delete_bin_const(coap_bin_const_t *s)
Deletes the given const binary data and releases any memory allocated.
void coap_delete_binary(coap_binary_t *s)
Deletes the given coap_binary_t object and releases any memory allocated.
coap_bin_const_t * coap_new_bin_const(const uint8_t *data, size_t size)
Take the specified byte array (text) and create a coap_bin_const_t * Returns a new const binary objec...
CoAP binary data definition with const data.
size_t length
length of binary data
const uint8_t * s
read-only binary data
CoAP binary data definition.
size_t length
length of binary data
The CoAP stack's global state is stored in a coap_context_t object.
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)
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)
coap_dtls_spsk_t spsk_setup_data
Contains the initial PSK server setup data.
The structure that holds the Client PSK information.
coap_bin_const_t identity
The structure used for defining the Client PSK setup data to be used.
void * ih_call_back_arg
Passed in to the Identity Hint callback function.
char * client_sni
If not NULL, SNI to use in client TLS setup.
coap_dtls_ih_callback_t validate_ih_call_back
Identity Hint check callback function.
The structure that holds the PKI key information.
coap_pki_key_pem_t pem
for PEM file keys
coap_pki_key_pkcs11_t pkcs11
for PKCS11 keys
union coap_dtls_key_t::@2 key
coap_pki_key_pem_buf_t pem_buf
for PEM memory keys
coap_pki_key_t key_type
key format type
coap_pki_key_asn1_t asn1
for ASN.1 (DER) memory keys
The structure used for defining the PKI setup data to be used.
uint8_t cert_chain_validation
1 if to check cert_chain_verify_depth
uint8_t check_cert_revocation
1 if revocation checks wanted
uint8_t cert_chain_verify_depth
recommended depth is 3
uint8_t verify_peer_cert
Set to COAP_DTLS_PKI_SETUP_VERSION to support this version of the struct.
char * client_sni
If not NULL, SNI to use in client TLS setup.
uint8_t is_rpk_not_cert
1 is RPK instead of Public Certificate.
uint8_t check_common_ca
1 if peer cert is to be signed by the same CA as the local cert
coap_dtls_key_t pki_key
PKI key definition.
The structure that holds the Server Pre-Shared Key and Identity Hint information.
The structure used for defining the Server PSK setup data to be used.
coap_dtls_psk_sni_callback_t validate_sni_call_back
SNI check callback function.
coap_dtls_id_callback_t validate_id_call_back
Identity check callback function.
void * id_call_back_arg
Passed in to the Identity callback function.
void * sni_call_back_arg
Passed in to the SNI callback function.
coap_dtls_spsk_info_t psk_info
Server PSK definition.
const uint8_t * private_key
ASN1 (DER) Private Key.
coap_asn1_privatekey_type_t private_key_type
Private Key Type.
size_t public_cert_len
ASN1 Public Cert length.
size_t private_key_len
ASN1 Private Key length.
const uint8_t * ca_cert
ASN1 (DER) Common CA Cert.
size_t ca_cert_len
ASN1 CA Cert length.
const uint8_t * public_cert
ASN1 (DER) Public Cert, or Public Key if RPK.
size_t ca_cert_len
PEM buffer CA Cert length.
const uint8_t * ca_cert
PEM buffer Common CA Cert.
size_t private_key_len
PEM buffer Private Key length.
const uint8_t * private_key
PEM buffer Private Key If RPK and 'EC PRIVATE KEY' this can be used for both the public_cert and priv...
size_t public_cert_len
PEM buffer Public Cert length.
const uint8_t * public_cert
PEM buffer Public Cert, or Public Key if RPK.
const char * ca_file
File location of Common CA in PEM format.
const char * public_cert
File location of Public Cert.
const char * private_key
File location of Private Key in PEM format.
const char * private_key
pkcs11: URI for Private Key
const char * ca
pkcs11: URI for Common CA Certificate
const char * user_pin
User pin to access PKCS11.
const char * public_cert
pkcs11: URI for Public Cert
Abstraction of virtual session that can be attached to coap_context_t (client) or coap_endpoint_t (se...
unsigned int dtls_timeout_count
dtls setup retry counter
coap_socket_t sock
socket object for the session, if any
unsigned int max_retransmit
maximum re-transmit count (default 4)
coap_bin_const_t * psk_identity
If client, this field contains the current identity for server; When this field is NULL,...
coap_session_state_t state
current state of relationaship with peer
coap_addr_tuple_t addr_info
key: remote/local address info
coap_proto_t proto
protocol used
coap_dtls_cpsk_t cpsk_setup_data
client provided PSK initial setup data
size_t mtu
path or CSM mtu
int dtls_event
Tracking any (D)TLS events on this sesison.
void * tls
security parameters
coap_context_t * context
session's context
coap_socket_flags_t flags
CoAP string data definition with const data.
const uint8_t * s
read-only string data
size_t length
length of string
The structure used for returning the underlying (D)TLS library information.
uint64_t built_version
(D)TLS Built against Library Version
coap_tls_library_t type
Library type.
uint64_t version
(D)TLS runtime Library Version