From 6cf43c0f7af8f34772d5cf6f1222dd4b47317f48 Mon Sep 17 00:00:00 2001 From: Achim Kraus Date: Fri, 29 Sep 2023 09:10:39 +0200 Subject: [PATCH 01/17] dtls.c: add check for valid handshake message type when version is 1.0. Fixes issue #209. Signed-off-by: Achim Kraus --- dtls.c | 36 ++++++++++++++++++++++++++---------- 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/dtls.c b/dtls.c index 33b352f4..7e91e9f1 100644 --- a/dtls.c +++ b/dtls.c @@ -82,11 +82,12 @@ memarray_t dtlscontext_storage; #define dtls_set_version(H,V) dtls_int_to_uint16((H)->version, (V)) #define dtls_set_content_type(H,V) ((H)->content_type = (V) & 0xff) -#define dtls_set_length(H,V) ((H)->length = (V)) +#define dtls_set_length(H,V) dtls_int_to_uint16(&((H)->length), (V)) #define dtls_get_content_type(H) ((H)->content_type & 0xff) #define dtls_get_version(H) dtls_uint16_to_int((H)->version) #define dtls_get_epoch(H) dtls_uint16_to_int((H)->epoch) +#define dtls_get_length(H) dtls_uint16_to_int((H)->length) #define dtls_get_sequence_number(H) dtls_uint48_to_ulong((H)->sequence_number) #define dtls_get_fragment_length(H) dtls_uint24_to_int((H)->fragment_length) @@ -563,15 +564,30 @@ is_record(uint8 *msg, size_t msglen) { unsigned int rlen = 0; if (msglen >= DTLS_RH_LENGTH) { /* FIXME allow empty records? */ - uint16_t version = dtls_uint16_to_int(msg + 1); - if ((((version == DTLS_VERSION) || (version == DTLS10_VERSION)) - && known_content_type(msg))) { - rlen = DTLS_RH_LENGTH + - dtls_uint16_to_int(DTLS_RECORD_HEADER(msg)->length); - - /* we do not accept wrong length field in record header */ - if (rlen > msglen) - rlen = 0; + uint16_t version = dtls_get_version(DTLS_RECORD_HEADER(msg)); + + if (DTLS_VERSION == version) { + if (!known_content_type(msg)) { + return 0; + } + } else if (DTLS10_VERSION == version) { + if (DTLS_CT_HANDSHAKE != msg[0] || DTLS_RH_LENGTH == msglen) { + return 0; + } else { + uint8_t handshake_type = msg[DTLS_RH_LENGTH]; + if (DTLS_HT_CLIENT_HELLO != handshake_type && + DTLS_HT_HELLO_VERIFY_REQUEST != handshake_type) { + return 0; + } + } + } else { + return 0; + } + rlen = DTLS_RH_LENGTH + dtls_uint16_to_int(DTLS_RECORD_HEADER(msg)->length); + + /* we do not accept wrong length field in record header */ + if (rlen > msglen) { + rlen = 0; } } From 0f1be3017eb894d144c1c124d3a4927781471c00 Mon Sep 17 00:00:00 2001 From: Achim Kraus Date: Thu, 7 Dec 2023 16:21:02 +0100 Subject: [PATCH 02/17] dtls_debug.h: explicitly cast macro parameter to size_t. Signed-off-by: Achim Kraus --- dtls_debug.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/dtls_debug.h b/dtls_debug.h index 37a4731d..a02cab4e 100644 --- a/dtls_debug.h +++ b/dtls_debug.h @@ -129,8 +129,8 @@ void dtls_dsrv_log_addr(log_t level, const char *name, const session_t *addr); #define dtls_notice(...) LOG_INF(__VA_ARGS__) #define dtls_info(...) LOG_INF(__VA_ARGS__) #define dtls_debug(...) LOG_DBG(__VA_ARGS__) -#define dtls_debug_hexdump(name, buf, length) { LOG_DBG("%s (%zu bytes):", name, length); LOG_HEXDUMP_DBG(buf, length, name); } -#define dtls_debug_dump(name, buf, length) { LOG_DBG("%s (%zu bytes):", name, length); LOG_HEXDUMP_DBG(buf, length, name); } +#define dtls_debug_hexdump(name, buf, length) { LOG_DBG("%s (%zu bytes):", name, (size_t)(length)); LOG_HEXDUMP_DBG(buf, length, name); } +#define dtls_debug_dump(name, buf, length) { LOG_DBG("%s (%zu bytes):", name, (size_t)(length)); LOG_HEXDUMP_DBG(buf, length, name); } #elif defined(RIOT_VERSION) #define dtls_emerg(...) LOG_ERROR(__VA_ARGS__) #define dtls_alert(...) LOG_ERROR(__VA_ARGS__) @@ -139,8 +139,8 @@ void dtls_dsrv_log_addr(log_t level, const char *name, const session_t *addr); #define dtls_notice(...) LOG_INFO(__VA_ARGS__) #define dtls_info(...) LOG_INFO(__VA_ARGS__) #define dtls_debug(...) LOG_DEBUG(__VA_ARGS__) -#define dtls_debug_hexdump(name, buf, length) { if (LOG_DEBUG <= LOG_LEVEL) { LOG_DEBUG("-= %s (%zu bytes) =-\n", name, length); od_hex_dump(buf, length, 0); }} -#define dtls_debug_dump(name, buf, length) { if (LOG_DEBUG <= LOG_LEVEL) { LOG_DEBUG("%s (%zu bytes):", name, length); od_hex_dump(buf, length, 0); }} +#define dtls_debug_hexdump(name, buf, length) { if (LOG_DEBUG <= LOG_LEVEL) { LOG_DEBUG("-= %s (%zu bytes) =-\n", name, (size_t)(length)); od_hex_dump(buf, length, 0); }} +#define dtls_debug_dump(name, buf, length) { if (LOG_DEBUG <= LOG_LEVEL) { LOG_DEBUG("%s (%zu bytes):", name, (size_t)(length)); od_hex_dump(buf, length, 0); }} #else /* neither RIOT nor Zephyr */ #define dtls_emerg(...) dsrv_log(DTLS_LOG_EMERG, __VA_ARGS__) #define dtls_alert(...) dsrv_log(DTLS_LOG_ALERT, __VA_ARGS__) From ff73600591dff6a49ab7bcb370903de02c7f32d7 Mon Sep 17 00:00:00 2001 From: Achim Kraus Date: Wed, 17 Jan 2024 16:49:35 +0100 Subject: [PATCH 03/17] dtls-server.c: check for left cli-arguments. Signed-off-by: Achim Kraus --- tests/dtls-server.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/tests/dtls-server.c b/tests/dtls-server.c index 1a471475..fa684d4d 100644 --- a/tests/dtls-server.c +++ b/tests/dtls-server.c @@ -308,7 +308,7 @@ usage(const char *program, const char *version) { program = ++p; fprintf(stderr, "%s v%s -- DTLS server implementation\n" - "(c) 2011-2014 Olaf Bergmann \n\n" + "(c) 2011-2024 Olaf Bergmann \n\n" "usage: %s [-A address] [-c cipher suites] [-e] [-p port] [-r] [-v num]\n" "\t-A address\t\tlisten on specified address (default is ::)\n", program, version, program); @@ -386,6 +386,11 @@ main(int argc, char **argv) { exit(1); } } + if (argc != optind) { + dtls_warn("no arguments supported!\n"); + usage(argv[0], dtls_package_version()); + exit(1); + } listen_addr.sin6_port = port; dtls_set_log_level(log_level); From 44eddf48c4e154b00de1ca153e663bf25e9687db Mon Sep 17 00:00:00 2001 From: Achim Kraus Date: Thu, 18 Jan 2024 08:39:58 +0100 Subject: [PATCH 04/17] dtls-client.c: accept options after arguments. Signed-off-by: Achim Kraus --- tests/dtls-client.c | 53 ++++++++++++++++++++++++++++++--------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/tests/dtls-client.c b/tests/dtls-client.c index bb27367b..95f4a9de 100644 --- a/tests/dtls-client.c +++ b/tests/dtls-client.c @@ -359,7 +359,7 @@ usage( const char *program, const char *version) { program = ++p; fprintf(stderr, "%s v%s -- DTLS client implementation\n" - "(c) 2011-2014 Olaf Bergmann \n\n" + "(c) 2011-2024 Olaf Bergmann \n\n" #ifdef DTLS_PSK "usage: %s [-c cipher suites] [-e] [-i file] [-k file] [-o file]\n" " %*s [-p port] [-r] [-v num] addr [port]\n", @@ -411,6 +411,7 @@ int main(int argc, char **argv) { fd_set rfds, wfds; struct timeval timeout; + unsigned short dst_port = 0; unsigned short port = DEFAULT_PORT; char port_str[NI_MAXSERV] = "0"; log_t log_level = DTLS_LOG_WARN; @@ -423,7 +424,7 @@ main(int argc, char **argv) { size_t len = 0; int buf_ready = 0; - + memset(&dst, 0, sizeof(session_t)); dtls_init(); snprintf(port_str, sizeof(port_str), "%d", port); @@ -434,7 +435,8 @@ main(int argc, char **argv) { memcpy(psk_key, PSK_DEFAULT_KEY, psk_key_length); #endif /* DTLS_PSK */ - while ((opt = getopt(argc, argv, "c:eo:p:rv:" PSK_OPTIONS)) != -1) { + while (optind < argc) { + opt = getopt(argc, argv, "c:eo:p:rv:z" PSK_OPTIONS); switch (opt) { #ifdef DTLS_PSK case 'i' : @@ -482,31 +484,48 @@ main(int argc, char **argv) { case 'v' : log_level = strtol(optarg, NULL, 10); break; + case -1 : + /* handle arguments */ + if (!dst.size) { + /* first argument: destination address */ + /* resolve destination address where server should be sent */ + res = resolve_address(argv[optind++], &dst.addr.sa); + if (res < 0) { + dtls_emerg("failed to resolve address\n"); + exit(-1); + } + dst.size = res; + } else if (!dst_port) { + /* second argument: destination port (optional) */ + dst_port = atoi(argv[optind++]); + } else { + dtls_warn("too many arguments!\n"); + usage(argv[0], dtls_package_version()); + exit(1); + } + break; default: usage(argv[0], dtls_package_version()); exit(1); } } - dtls_set_log_level(log_level); - - if (argc <= optind) { + if (!dst.size) { + dtls_warn("missing destination address!\n"); usage(argv[0], dtls_package_version()); exit(1); } - - memset(&dst, 0, sizeof(session_t)); - /* resolve destination address where server should be sent */ - res = resolve_address(argv[optind++], &dst.addr.sa); - if (res < 0) { - dtls_emerg("failed to resolve address\n"); - exit(-1); + if (!dst_port) { + /* destination port not provided, use default */ + dst_port = DEFAULT_PORT; + } + if (dst.addr.sa.sa_family == AF_INET6) { + dst.addr.sin6.sin6_port = htons(dst_port); + } else { + dst.addr.sin.sin_port = htons(dst_port); } - dst.size = res; - /* use port number from command line when specified or the listen - port, otherwise */ - dst.addr.sin.sin_port = htons(atoi(optind < argc ? argv[optind++] : port_str)); + dtls_set_log_level(log_level); /* init socket and set it to non-blocking */ fd = socket(dst.addr.sa.sa_family, SOCK_DGRAM, 0); From b306f276b34c64156ca60ce27c1a74c70e0d878b Mon Sep 17 00:00:00 2001 From: Achim Kraus Date: Thu, 18 Jan 2024 09:10:18 +0100 Subject: [PATCH 05/17] dtls-client.c: apply option for local port. The previous version ignores the option for the local port. That may be caused by issues using the same default local port for the server and client. This enables the use of an specific local port and changes the default to an ephemeral free port, similar to quite a lot of other UDP clients. The DEFAULT_PORT is therefore only used for the destination. Signed-off-by: Achim Kraus --- tests/dtls-client.c | 34 +++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/tests/dtls-client.c b/tests/dtls-client.c index 95f4a9de..c7fb016a 100644 --- a/tests/dtls-client.c +++ b/tests/dtls-client.c @@ -376,9 +376,11 @@ usage( const char *program, const char *version) { #endif /* DTLS_PSK */ "\t-o file\t\toutput received data to this file\n" "\t \t\t(use '-' for STDOUT)\n" - "\t-p port\t\tlisten on specified port (default is %d)\n" + "\t-p port\t\tlisten on specified port\n" + "\t \t\t(default is an ephemeral free port).\n" "\t-r\t\tforce renegotiation info (RFC5746)\n" - "\t-v num\t\tverbosity level (default: 3)\n", + "\t-v num\t\tverbosity level (default: 3)\n" + "\tDefault destination port: %d\n", DEFAULT_PORT); } @@ -412,21 +414,22 @@ main(int argc, char **argv) { fd_set rfds, wfds; struct timeval timeout; unsigned short dst_port = 0; - unsigned short port = DEFAULT_PORT; - char port_str[NI_MAXSERV] = "0"; + unsigned short local_port = 0; log_t log_level = DTLS_LOG_WARN; int fd; ssize_t result; int on = 1; int opt, res; session_t dst; + session_t listen; char buf[200]; size_t len = 0; int buf_ready = 0; memset(&dst, 0, sizeof(session_t)); + memset(&listen, 0, sizeof(session_t)); + dtls_init(); - snprintf(port_str, sizeof(port_str), "%d", port); #ifdef DTLS_PSK psk_id_length = strlen(PSK_DEFAULT_IDENTITY); @@ -475,8 +478,7 @@ main(int argc, char **argv) { } break; case 'p' : - strncpy(port_str, optarg, NI_MAXSERV-1); - port_str[NI_MAXSERV - 1] = '\0'; + local_port = atoi(optarg); break; case 'r' : force_renegotiation_info = 1; @@ -561,6 +563,24 @@ main(int argc, char **argv) { } } + if (local_port) { + listen.addr = dst.addr; + listen.size = dst.size; + if (listen.addr.sa.sa_family == AF_INET6) { + listen.addr.sin6.sin6_addr = in6addr_any; + listen.addr.sin6.sin6_port = htons(local_port); + dtls_info("bind to local IPv6 port %u\n", local_port); + } else { + listen.addr.sin.sin_addr.s_addr = INADDR_ANY; + listen.addr.sin.sin_port = htons(local_port); + dtls_info("bind to local IPv4 port %u\n", local_port); + } + if (bind(fd, (struct sockaddr *)&listen.addr.sa, listen.size) < 0) { + dtls_alert("bind: %s\n", strerror(errno)); + return EXIT_FAILURE; + } + } + if (signal(SIGINT, dtls_handle_signal) == SIG_ERR) { dtls_alert("An error occurred while setting a signal handler.\n"); return EXIT_FAILURE; From 92322710a76b05587aff32000e097ab4a825c7e2 Mon Sep 17 00:00:00 2001 From: Achim Kraus Date: Thu, 18 Nov 2021 21:50:52 +0100 Subject: [PATCH 06/17] Add client dtls connection ID. Simple client side implementation indicates support and uses the cid of the server, when negotiated by that. Signed-off-by: Achim Kraus --- crypto.h | 27 ++++++- dtls.c | 221 ++++++++++++++++++++++++++++++++++++++++++------------- dtls.h | 1 + global.h | 1 + 4 files changed, 198 insertions(+), 52 deletions(-) diff --git a/crypto.h b/crypto.h index 53547589..6df46ff7 100644 --- a/crypto.h +++ b/crypto.h @@ -110,6 +110,17 @@ typedef struct { uint64_t bitfield; } seqnum_t; +/* Maximum CID length. */ +#ifndef DTLS_MAX_CID_LENGTH +#define DTLS_MAX_CID_LENGTH 16 +#endif + +#if (DTLS_MAX_CID_LENGTH > 0) +#ifndef DTLS_USE_CID_DEFAULT +#define DTLS_USE_CID_DEFAULT 1 +#endif /* DTLS_USE_CID_DEFAULT */ +#endif /* DTLS_MAX_CID_LENGTH > 0 */ + typedef struct { dtls_compression_t compression; /**< compression method */ @@ -124,7 +135,12 @@ typedef struct { * access the components of the key block. */ uint8 key_block[MAX_KEYBLOCK_LENGTH]; - + +#if (DTLS_MAX_CID_LENGTH > 0) + uint8_t write_cid[DTLS_MAX_CID_LENGTH]; + uint8_t write_cid_length; +#endif /* DTLS_MAX_CID_LENGTH > 0 */ + seqnum_t cseq; /** 0) + unsigned int support_cid:1; /** indicate CID support (RFC9146) */ +#endif } dtls_user_parameters_t; typedef struct { @@ -158,6 +177,12 @@ typedef struct { dtls_compression_t compression; /**< compression method */ dtls_user_parameters_t user_parameters; /**< user parameters */ dtls_cipher_index_t cipher_index; /**< internal index for cipher_suite_params, DTLS_CIPHER_INDEX_NULL for TLS_NULL_WITH_NULL_NULL */ + +#if (DTLS_MAX_CID_LENGTH > 0) + uint8_t write_cid[DTLS_MAX_CID_LENGTH]; + uint8_t write_cid_length; +#endif /* DTLS_MAX_CID_LENGTH > 0 */ + unsigned int do_client_auth:1; unsigned int extended_master_secret:1; unsigned int renegotiation_info:1; diff --git a/dtls.c b/dtls.c index 7e91e9f1..97bc1e98 100644 --- a/dtls.c +++ b/dtls.c @@ -142,14 +142,15 @@ memarray_t dtlscontext_storage; * ec curves := 8 bytes * ec point format := 6 bytes => 26 * sign. and hash algos := 8 bytes - * extended master secret := 4 bytes => 12 + * extended master secret := 4 bytes + * connection id, empty := 5 bytes => 17 * * (The ClientHello uses TLS_EMPTY_RENEGOTIATION_INFO_SCSV * instead of renegotiation info) */ #define DTLS_CH_LENGTH sizeof(dtls_client_hello_t) /* no variable length fields! */ #define DTLS_COOKIE_LENGTH_MAX 32 -#define DTLS_CH_LENGTH_MAX DTLS_CH_LENGTH + DTLS_COOKIE_LENGTH_MAX + 10 + (2 * DTLS_MAX_CIPHER_SUITES) + 26 + 12 +#define DTLS_CH_LENGTH_MAX DTLS_CH_LENGTH + DTLS_COOKIE_LENGTH_MAX + 10 + (2 * DTLS_MAX_CIPHER_SUITES) + 26 + 17 #define DTLS_HV_LENGTH sizeof(dtls_hello_verify_t) /* * ServerHello: @@ -532,6 +533,7 @@ static char const content_types[] = { DTLS_CT_ALERT, DTLS_CT_HANDSHAKE, DTLS_CT_APPLICATION_DATA, + DTLS_CT_TLS12_CID, 0 /* end marker */ }; @@ -682,6 +684,9 @@ static const dtls_user_parameters_t default_user_parameters = { #endif /* DTLS_DEFAULT_CIPHER_SUITES */ .force_extended_master_secret = 1, .force_renegotiation_info = 1, +#if (DTLS_MAX_CID_LENGTH > 0) + .support_cid = DTLS_USE_CID_DEFAULT, +#endif /* DTLS_MAX_CID_LENGTH > 0 */ }; /** only one compression method is currently defined */ @@ -944,6 +949,8 @@ dtls_message_type_to_name(int type) { return "handshake"; case DTLS_CT_APPLICATION_DATA: return "application_data"; + case DTLS_CT_TLS12_CID: + return "connection_id"; default: return NULL; } @@ -1083,6 +1090,10 @@ calculate_key_block(dtls_context_t *ctx, security->cipher_index = handshake->cipher_index; security->compression = handshake->compression; security->rseq = 0; +#if (DTLS_MAX_CID_LENGTH > 0) + security->write_cid_length = handshake->write_cid_length; + memcpy(security->write_cid, handshake->write_cid, handshake->write_cid_length); +#endif /* DTLS_MAX_CID_LENGTH > 0 */ return 0; } @@ -1189,6 +1200,39 @@ static int verify_ext_sig_hash_algo(uint8 *data, size_t data_length) { return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); } +#if (DTLS_MAX_CID_LENGTH > 0) + +static int +get_ext_connection_id(dtls_handshake_parameters_t *handshake, uint8 *data, + size_t data_length) { + uint8_t i; + + if (sizeof(uint8) > data_length) { + dtls_warn("invalid length (%zu) for extension connection id\n", data_length); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + + /* length of the connection id */ + i = dtls_uint8_to_int(data); + data += sizeof(uint8); + if (i + sizeof(uint8) != data_length) { + dtls_warn("invalid connection id length (%d)\n", i); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + + if (DTLS_MAX_CID_LENGTH < i) { + dtls_warn("connection id length (%d) exceeds maximum (%d)!\n", i, DTLS_MAX_CID_LENGTH); + return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); + } + + handshake->write_cid_length = i; + memcpy(handshake->write_cid, data, i); + + return 0; +} + +#endif /* DTLS_MAX_CID_LENGTH > 0*/ + /* * Check for some TLS Extensions used by the ECDHE_ECDSA cipher. */ @@ -1282,6 +1326,16 @@ dtls_check_tls_extension(dtls_peer_t *peer, if (verify_ext_sig_hash_algo(data, j)) goto error; break; +#if (DTLS_MAX_CID_LENGTH > 0) + case TLS_EXT_CONNECTION_ID: + if (!is_client_hello && !peer->handshake_params->user_parameters.support_cid) { + dtls_warn("connection id was not sent by client!\n"); + goto error; + } + if (get_ext_connection_id(peer->handshake_params, data, j)) + goto error; + break; +#endif /* DTLS_MAX_CID_LENGTH */ case TLS_EXT_RENEGOTIATION_INFO: /* RFC 5746, minimal version, only empty info is supported */ if (j == 1 && *data == 0) { @@ -1659,9 +1713,10 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, uint8 *data_array[], size_t data_len_array[], size_t data_array_len, uint8 *sendbuf, size_t *rlen) { - uint8 *p, *start; + uint8 *p; int res; unsigned int i; + uint8_t cid_length = 0; if (*rlen < DTLS_RH_LENGTH) { dtls_alert("The sendbuf (%zu bytes) is too small\n", *rlen); @@ -1674,7 +1729,6 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, } p = dtls_set_record_header(type, security->epoch, &(security->rseq), sendbuf); - start = p; if (security->cipher_index == DTLS_CIPHER_INDEX_NULL) { /* no cipher suite */ @@ -1695,15 +1749,31 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 or TLS_ECDHE_ECDSA_WITH_AES_128_CCM */ /** + * RFC6347 * length of additional_data for the AEAD cipher which consists of * seq_num(2+6) + type(1) + version(2) + length(2) */ #define A_DATA_LEN 13 + +#if (DTLS_MAX_CID_LENGTH > 0) + /** + * RFC9146 + * length of extra additional_data for the AEAD cipher which consists of + * seq_num_placeholder(8) + type(1) + cid_length(1) + */ +#define A_DATA_CID_EXTRA_LEN 10 +#define A_DATA_MAX_LEN (A_DATA_LEN + A_DATA_CID_EXTRA_LEN + DTLS_MAX_CID_LENGTH) +#else +#define A_DATA_MAX_LEN A_DATA_LEN +#endif + + uint8 *start = p; unsigned char nonce[DTLS_CCM_BLOCKSIZE]; - unsigned char A_DATA[A_DATA_LEN]; + unsigned char A_DATA[A_DATA_MAX_LEN]; const uint8_t mac_len = get_cipher_suite_mac_len(security->cipher_index); const cipher_suite_key_exchange_algorithm_t key_exchange_algorithm = get_key_exchange_algorithm(security->cipher_index); + uint8_t a_data_len = A_DATA_LEN; /* For backwards-compatibility, dtls_encrypt_params is called with * M= and L=3. */ const dtls_ccm_params_t params = { nonce, mac_len, 3 }; @@ -1720,6 +1790,16 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, } } +#if (DTLS_MAX_CID_LENGTH > 0) + cid_length = security->write_cid_length; + if (cid_length > 0) { + /* add cid to record header */ + memcpy(p - sizeof(uint16_t), security->write_cid, cid_length); + p += cid_length; + start = p; + } +#endif /* DTLS_MAX_CID_LENGTH > 0 */ + /* set nonce from RFC 6655: The "nonce" input to the AEAD algorithm is exactly that of [RFC5288]: @@ -1785,31 +1865,62 @@ dtls_prepare_record(dtls_peer_t *peer, dtls_security_parameters_t *security, dtls_debug_dump("key:", dtls_kb_local_write_key(security, peer->role), dtls_kb_key_size(security, peer->role)); - /* re-use N to create additional data according to RFC 5246, Section 6.2.3.3: - * - * additional_data = seq_num + TLSCompressed.type + - * TLSCompressed.version + TLSCompressed.length; - */ - memcpy(A_DATA, &DTLS_RECORD_HEADER(sendbuf)->epoch, 8); /* epoch and seq_num */ - memcpy(A_DATA + 8, &DTLS_RECORD_HEADER(sendbuf)->content_type, 3); /* type and version */ - dtls_int_to_uint16(A_DATA + 11, res - 8); /* length */ +#if (DTLS_MAX_CID_LENGTH > 0) + if (cid_length > 0) { + /* RFC 9146 */ + + /* inner content type */ + *p = *sendbuf; + *sendbuf = DTLS_CT_TLS12_CID; + p += sizeof(uint8_t); + res += sizeof(uint8_t); + + /* seq_num_placeholder: 8x 0xff */ + memset(A_DATA, 0xff, 8); + /* tls_cid: 25 */ + A_DATA[8] = DTLS_CT_TLS12_CID; + /* cid length */ + A_DATA[9] = cid_length; + /* copy record header */ + memcpy(A_DATA + A_DATA_CID_EXTRA_LEN, sendbuf, A_DATA_LEN + cid_length); + dtls_int_to_uint16(A_DATA + A_DATA_CID_EXTRA_LEN + 11 + cid_length, res - 8); /* length */ + a_data_len = A_DATA_LEN + A_DATA_CID_EXTRA_LEN + cid_length; + + } else { +#endif /* DTLS_MAX_CID_LENGTH > 0 */ + /* RFC 6347 */ + /* re-use N to create additional data according to RFC 5246, Section 6.2.3.3: + * + * additional_data = seq_num + TLSCompressed.type + + * TLSCompressed.version + TLSCompressed.length; + */ + memcpy(A_DATA, &DTLS_RECORD_HEADER(sendbuf)->epoch, 8); /* epoch and seq_num */ + memcpy(A_DATA + 8, &DTLS_RECORD_HEADER(sendbuf)->content_type, 3); /* type and version */ + dtls_int_to_uint16(A_DATA + 11, res - 8); /* length */ + a_data_len = A_DATA_LEN; +#if (DTLS_MAX_CID_LENGTH > 0) + } +#endif /* DTLS_MAX_CID_LENGTH > 0 */ + + dtls_debug_dump("adata:", A_DATA, a_data_len); + dtls_debug_dump("message:", start, res); res = dtls_encrypt_params(¶ms, start + 8, res - 8, start + 8, dtls_kb_local_write_key(security, peer->role), dtls_kb_key_size(security, peer->role), - A_DATA, A_DATA_LEN); + A_DATA, a_data_len); if (res < 0) return res; res += 8; /* increment res by size of nonce_explicit */ - dtls_debug_dump("message:", start, res); + dtls_debug_dump("encrypted-message:", start, res); } /* fix length of fragment in sendbuf */ - dtls_int_to_uint16(sendbuf + 11, res); + dtls_int_to_uint16(sendbuf + 11 + cid_length, res); - *rlen = DTLS_RH_LENGTH + res; + *rlen = DTLS_RH_LENGTH + res + cid_length; return 0; } @@ -2481,15 +2592,12 @@ dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer) */ uint8 buf[DTLS_SH_LENGTH + 2 + 5 + 5 + 6 + 4 + 5]; uint8 *p; - uint8 extension_size; + uint8_t *p_extension_size = NULL; + uint16_t extension_size = 0; dtls_handshake_parameters_t * const handshake = peer->handshake_params; const dtls_cipher_t cipher_suite = get_cipher_suite(handshake->cipher_index); const int ecdsa = is_key_exchange_ecdhe_ecdsa(handshake->cipher_index); - extension_size = (handshake->extended_master_secret ? 4 : 0) + - (handshake->renegotiation_info ? 5 : 0) + - (ecdsa ? 5 + 5 + 6 : 0); - /* Handshake header */ p = buf; @@ -2503,7 +2611,8 @@ dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer) memcpy(p, handshake->tmp.random.server, DTLS_RANDOM_LENGTH); p += DTLS_RANDOM_LENGTH; - *p++ = 0; /* no session id */ + /* no session id */ + *p++ = 0; if (cipher_suite != TLS_NULL_WITH_NULL_NULL) { /* selected cipher suite */ @@ -2514,11 +2623,10 @@ dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer) *p++ = compression_methods[handshake->compression]; } - if (extension_size) { - /* length of the extensions */ - dtls_int_to_uint16(p, extension_size); - p += sizeof(uint16); - } + /* keep pointer to length of the extensions */ + p_extension_size = p; + /* skip length of extensions field */ + p += sizeof(uint16); if (ecdsa) { /* client certificate type extension, 5 bytes */ @@ -2582,6 +2690,10 @@ dtls_send_server_hello(dtls_context_t *ctx, dtls_peer_t *peer) *p++ = 0; } + /* length of the extensions */ + extension_size = (p - p_extension_size) - sizeof(uint16); + dtls_int_to_uint16(p_extension_size, extension_size); + assert((buf <= p) && ((unsigned int)(p - buf) <= sizeof(buf))); /* TODO use the same record sequence number as in the ClientHello, @@ -3085,10 +3197,9 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, uint8 cookie[], size_t cookie_length) { uint8 buf[DTLS_CH_LENGTH_MAX]; uint8_t *p = buf; - uint8_t *p_cipher_suites_size = NULL; + uint8_t *p_size = NULL; + uint16_t size = 0; uint8_t index = 0; - uint8_t cipher_suites_size = 0; - uint8_t extension_size = 4; /* extended master secret extension */ #ifdef DTLS_ECC uint8_t ecdsa = 0; #endif @@ -3128,7 +3239,7 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, } /* keep pointer to size of cipher suites */ - p_cipher_suites_size = p; + p_size = p; /* skip size of cipher suites field */ p += sizeof(uint16); @@ -3147,8 +3258,8 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, credentials callback is missing */ } - cipher_suites_size = (p - p_cipher_suites_size) - sizeof(uint16); - if (cipher_suites_size == 0) { + size = (p - p_size) - sizeof(uint16); + if (size == 0) { dtls_crit("no supported cipher suite provided!\n"); return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); } @@ -3156,23 +3267,10 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, /* RFC5746 add RENEGOTIATION_INFO_SCSV */ dtls_int_to_uint16(p, TLS_EMPTY_RENEGOTIATION_INFO_SCSV); p += sizeof(uint16); - cipher_suites_size += sizeof(uint16); + size += sizeof(uint16); /* set size of known cipher suites */ - dtls_int_to_uint16(p_cipher_suites_size, cipher_suites_size); - -#ifdef DTLS_ECC - if (ecdsa) { - /* - * client_cert_type := 6 bytes - * server_cert_type := 6 bytes - * ec curves := 8 bytes - * ec point format := 6 bytes - * sign. and hash algos := 8 bytes - */ - extension_size += 6 + 6 + 8 + 6 + 8; - } -#endif + dtls_int_to_uint16(p_size, size); /* compression method */ dtls_int_to_uint8(p, 1); @@ -3181,8 +3279,9 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, dtls_int_to_uint8(p, TLS_COMPRESSION_NULL); p += sizeof(uint8); - /* length of the extensions */ - dtls_int_to_uint16(p, extension_size); + /* keep pointer to length of the extensions */ + p_size = p; + /* skip length of extensions field */ p += sizeof(uint16); #ifdef DTLS_ECC @@ -3279,6 +3378,26 @@ dtls_send_client_hello(dtls_context_t *ctx, dtls_peer_t *peer, p += sizeof(uint16); handshake->extended_master_secret = 1; +#if (DTLS_MAX_CID_LENGTH > 0) + if (handshake->user_parameters.support_cid) { + /* connection id, empty to indicate support, 5 bytes */ + dtls_int_to_uint16(p, TLS_EXT_CONNECTION_ID); + p += sizeof(uint16); + + /* length of this extension type */ + dtls_int_to_uint16(p, sizeof(uint8)); + p += sizeof(uint16); + + /* empty cid, indicating support for cid extension */ + dtls_int_to_uint8(p, 0); + p += sizeof(uint8); + } +#endif /* DTLS_MAX_CID_LENGTH > 0 */ + + /* length of the extensions */ + size = (p - p_size) - sizeof(uint16); + dtls_int_to_uint16(p_size, size); + handshake->hs_state.read_epoch = dtls_security_params(peer)->epoch; assert((buf <= p) && ((unsigned int)(p - buf) <= sizeof(buf))); diff --git a/dtls.h b/dtls.h index 05f3385c..600e8edc 100644 --- a/dtls.h +++ b/dtls.h @@ -341,6 +341,7 @@ void dtls_check_retransmit(dtls_context_t *context, clock_time_t *next); #define DTLS_CT_ALERT 21 #define DTLS_CT_HANDSHAKE 22 #define DTLS_CT_APPLICATION_DATA 23 +#define DTLS_CT_TLS12_CID 25 #ifdef __GNUC__ #define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__)) diff --git a/global.h b/global.h index d915aed1..347c1c9e 100644 --- a/global.h +++ b/global.h @@ -93,6 +93,7 @@ typedef enum { #define TLS_EXT_SERVER_CERTIFICATE_TYPE 20 /* see RFC 7250 */ #define TLS_EXT_ENCRYPT_THEN_MAC 22 /* see RFC 7366 */ #define TLS_EXT_EXTENDED_MASTER_SECRET 23 /* see RFC 7627 */ +#define TLS_EXT_CONNECTION_ID 54 /* see RFC 9146 */ #define TLS_EXT_RENEGOTIATION_INFO 65281 /* see RFC 5746 */ #define TLS_CERT_TYPE_RAW_PUBLIC_KEY 2 /* see RFC 7250 */ From 0580b36337c7261aec1d689fa8458dc5b8a51e88 Mon Sep 17 00:00:00 2001 From: Achim Kraus Date: Tue, 24 Jan 2023 20:08:13 +0100 Subject: [PATCH 07/17] dtls-client.c: add support_cid option. Signed-off-by: Achim Kraus --- tests/dtls-client.c | 28 +++++++++++++++++++++++----- 1 file changed, 23 insertions(+), 5 deletions(-) diff --git a/tests/dtls-client.c b/tests/dtls-client.c index c7fb016a..4e95a5a2 100644 --- a/tests/dtls-client.c +++ b/tests/dtls-client.c @@ -69,7 +69,9 @@ static dtls_context_t *orig_dtls_context = NULL; static const dtls_cipher_t* ciphers = NULL; static unsigned int force_extended_master_secret = 0; static unsigned int force_renegotiation_info = 0; - +#if (DTLS_MAX_CID_LENGTH > 0) +static unsigned int support_cid = 0; +#endif #ifdef DTLS_ECC static const unsigned char ecdsa_priv_key[] = { @@ -246,6 +248,9 @@ get_user_parameters(struct dtls_context_t *ctx, (void) session; user_parameters->force_extended_master_secret = force_extended_master_secret; user_parameters->force_renegotiation_info = force_renegotiation_info; +#if (DTLS_MAX_CID_LENGTH > 0) + user_parameters->support_cid = support_cid; +#endif if (ciphers) { int i = 0; while (i < DTLS_MAX_CIPHER_SUITES) { @@ -360,13 +365,18 @@ usage( const char *program, const char *version) { fprintf(stderr, "%s v%s -- DTLS client implementation\n" "(c) 2011-2024 Olaf Bergmann \n\n" + "usage: %s [-c cipher suites] [-e] " #ifdef DTLS_PSK - "usage: %s [-c cipher suites] [-e] [-i file] [-k file] [-o file]\n" - " %*s [-p port] [-r] [-v num] addr [port]\n", + "[-i file] [-k file] [-o file]\n" + " %*s [-p port] [-r] [-v num]" #else /* DTLS_PSK */ - "usage: %s [-c cipher suites] [-e] [-o file] [-p port] [-r]\n" - " %*s [-v num] addr [port]\n", + "[-o file] [-p port] [-r]\n" + " %*s [-v num]" #endif /* DTLS_PSK */ +#if (DTLS_MAX_CID_LENGTH > 0) + " [-z]" +#endif /* DTLS_MAX_CID_LENGTH > 0*/ + " addr [port]\n", program, version, program, (int)strlen(program), ""); cipher_suites_usage(stderr, "\t"); fprintf(stderr, "\t-e\t\tforce extended master secret (RFC7627)\n" @@ -380,6 +390,9 @@ usage( const char *program, const char *version) { "\t \t\t(default is an ephemeral free port).\n" "\t-r\t\tforce renegotiation info (RFC5746)\n" "\t-v num\t\tverbosity level (default: 3)\n" +#if (DTLS_MAX_CID_LENGTH > 0) + "\t-z\t\tsupport CID (RFC9146)\n" +#endif /* DTLS_MAX_CID_LENGTH > 0*/ "\tDefault destination port: %d\n", DEFAULT_PORT); } @@ -486,6 +499,11 @@ main(int argc, char **argv) { case 'v' : log_level = strtol(optarg, NULL, 10); break; +#if (DTLS_MAX_CID_LENGTH > 0) + case 'z' : + support_cid = 1; + break; +#endif /* DTLS_MAX_CID_LENGTH > 0*/ case -1 : /* handle arguments */ if (!dst.size) { From 4c39d5cc8ce0f641bd105cc4913288bc985cae54 Mon Sep 17 00:00:00 2001 From: Jon Shallow Date: Tue, 6 Feb 2024 12:56:03 +0000 Subject: [PATCH 08/17] dtls.c: Handle DTLS1.3 ClientHello when calculating cookie Do not calculate the cookie using the Extensions as these are different between DTLS1.2 and DTLS1.3 https://datatracker.ietf.org/doc/html/rfc6347#section-4.2.1 When responding to a HelloVerifyRequest, the client MUST use the same parameter values (version, random, session_id, cipher_suites, compression_method) as it did in the original ClientHello. The server SHOULD use those values to generate its cookie and verify that they are correct upon cookie receipt. https://www.rfc-editor.org/rfc/rfc9147.html#section-5.3 The ClientHello up to, but not including the Extensions is the same for DTLS1.2 and DTLS1.3 Signed-off-by: Jon Shallow --- dtls.c | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/dtls.c b/dtls.c index 97bc1e98..b983b147 100644 --- a/dtls.c +++ b/dtls.c @@ -466,7 +466,7 @@ dtls_create_cookie(dtls_context_t *ctx, uint8 *msg, size_t msglen, uint8 *cookie, int *clen) { unsigned char buf[DTLS_HMAC_MAX]; - size_t e, fragment_length; + size_t e, compatability_length; int len; /* create cookie with HMAC-SHA256 over: @@ -506,14 +506,23 @@ dtls_create_cookie(dtls_context_t *ctx, e += dtls_uint8_to_int(msg + DTLS_HS_LENGTH + e); e += sizeof(uint8_t); - /* read fragment length and check for consistency */ - fragment_length = dtls_get_fragment_length(DTLS_HANDSHAKE_HEADER(msg)); - if ((fragment_length < e) || (e + DTLS_HS_LENGTH) > msglen) + /* + * Read in compatablility_length length and check for consistency + * The compatability_length is because a DTLS1.3 Client Hello may come in, + * and the re-transmit of the Client Hello with cookie may be different. + */ + /* Get the Cipher Suites length + value */ + compatability_length = dtls_uint16_to_int(msg + DTLS_HS_LENGTH + e) + 2; + /* Add in the Compression length byte + value */ + compatability_length += dtls_uint8_to_int(msg + DTLS_HS_LENGTH + e + + compatability_length) + 1; + + if (e + DTLS_HS_LENGTH + compatability_length > msglen) return dtls_alert_fatal_create(DTLS_ALERT_HANDSHAKE_FAILURE); dtls_hmac_update(&hmac_context, msg + DTLS_HS_LENGTH + e, - fragment_length - e); + compatability_length); len = dtls_hmac_finalize(&hmac_context, buf); From 3ce86c2522cb4d23ff2cd6d61a2281dc35967709 Mon Sep 17 00:00:00 2001 From: Olaf Bergmann Date: Wed, 14 Feb 2024 17:57:01 +0100 Subject: [PATCH 09/17] [Documentation] Update Doxyfile.in to version 1.9.8 To avoid doxygen warnings regarding outdated configuration options, this change updates the Doxyfile template to the current version 1.9.8. Change-Id: Ia60a20e4cb3da375cde48c9ae3ca234200bb8a10 --- doc/Doxyfile.in | 877 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 594 insertions(+), 283 deletions(-) diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index fc668a8d..33ea9627 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -1,4 +1,4 @@ -# Doxyfile 1.8.17 +# Doxyfile 1.10.0 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -12,6 +12,16 @@ # For lists, items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (\" \"). +# +# Note: +# +# Use doxygen to compare the used configuration file with the template +# configuration file: +# doxygen -x [configFile] +# Use doxygen to compare the used configuration file with the template +# configuration file without replacing the environment variables or CMake type +# replacement variables: +# doxygen -x_noenv [configFile] #--------------------------------------------------------------------------- # Project related configuration options @@ -53,6 +63,12 @@ PROJECT_BRIEF = PROJECT_LOGO = +# With the PROJECT_ICON tag one can specify an icon that is included in the tabs +# when the HTML document is shown. Doxygen will copy the logo to the output +# directory. + +PROJECT_ICON = + # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path # into which the generated documentation will be written. If a relative path is # entered, it will be relative to the location where doxygen was started. If @@ -60,16 +76,28 @@ PROJECT_LOGO = OUTPUT_DIRECTORY = -# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- -# directories (in 2 levels) under the output directory of each output format and -# will distribute the generated files over these directories. Enabling this +# If the CREATE_SUBDIRS tag is set to YES then doxygen will create up to 4096 +# sub-directories (in 2 levels) under the output directory of each output format +# and will distribute the generated files over these directories. Enabling this # option can be useful when feeding doxygen a huge amount of source files, where # putting all generated files in the same directory would otherwise causes -# performance problems for the file system. +# performance problems for the file system. Adapt CREATE_SUBDIRS_LEVEL to +# control the number of sub-directories. # The default value is: NO. CREATE_SUBDIRS = NO +# Controls the number of sub-directories that will be created when +# CREATE_SUBDIRS tag is set to YES. Level 0 represents 16 directories, and every +# level increment doubles the number of directories, resulting in 4096 +# directories at level 8 which is the default and also the maximum value. The +# sub-directories are organized in 2 levels, the first level always has a fixed +# number of 16 directories. +# Minimum value: 0, maximum value: 8, default value: 8. +# This tag requires that the tag CREATE_SUBDIRS is set to YES. + +CREATE_SUBDIRS_LEVEL = 8 + # If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII # characters to appear in the names of generated files. If set to NO, non-ASCII # characters will be escaped, for example _xE3_x81_x84 will be used for Unicode @@ -81,26 +109,18 @@ ALLOW_UNICODE_NAMES = NO # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. -# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese, -# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States), -# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian, -# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages), -# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian, -# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian, -# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish, -# Ukrainian and Vietnamese. +# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Bulgarian, +# Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch, English +# (United States), Esperanto, Farsi (Persian), Finnish, French, German, Greek, +# Hindi, Hungarian, Indonesian, Italian, Japanese, Japanese-en (Japanese with +# English messages), Korean, Korean-en (Korean with English messages), Latvian, +# Lithuanian, Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, +# Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, +# Swedish, Turkish, Ukrainian and Vietnamese. # The default value is: English. OUTPUT_LANGUAGE = English -# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all -# documentation generated by doxygen is written. Doxygen will use this -# information to generate all generated output in the proper direction. -# Possible values are: None, LTR, RTL and Context. -# The default value is: None. - -OUTPUT_TEXT_DIRECTION = None - # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. @@ -217,6 +237,14 @@ QT_AUTOBRIEF = NO MULTILINE_CPP_IS_BRIEF = NO +# By default Python docstrings are displayed as preformatted text and doxygen's +# special commands cannot be used. By setting PYTHON_DOCSTRING to NO the +# doxygen's special commands can be used and the contents of the docstring +# documentation blocks is shown as doxygen documentation. +# The default value is: YES. + +PYTHON_DOCSTRING = YES + # If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the # documentation from any documented member that it re-implements. # The default value is: YES. @@ -240,25 +268,19 @@ TAB_SIZE = 4 # the documentation. An alias has the form: # name=value # For example adding -# "sideeffect=@par Side Effects:\n" +# "sideeffect=@par Side Effects:^^" # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading -# "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines (in the resulting output). You can put ^^ in the value part of an -# alias to insert a newline as if a physical newline was in the original file. -# When you need a literal { or } or , in the value part of an alias you have to -# escape them by means of a backslash (\), this can lead to conflicts with the -# commands \{ and \} for these it is advised to use the version @{ and @} or use -# a double escape (\\{ and \\}) +# "Side Effects:". Note that you cannot put \n's in the value part of an alias +# to insert newlines (in the resulting output). You can put ^^ in the value part +# of an alias to insert a newline as if a physical newline was in the original +# file. When you need a literal { or } or , in the value part of an alias you +# have to escape them by means of a backslash (\), this can lead to conflicts +# with the commands \{ and \} for these it is advised to use the version @{ and +# @} or use a double escape (\\{ and \\}) ALIASES = -# This tag can be used to specify a number of word-keyword mappings (TCL only). -# A mapping has the form "name=value". For example adding "class=itcl::class" -# will allow you to use the command class in the itcl::class meaning. - -TCL_SUBST = - # Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources # only. Doxygen will then generate output that is more tailored for C. For # instance, some of the names that are used will be different. The list of all @@ -300,18 +322,21 @@ OPTIMIZE_OUTPUT_SLICE = NO # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, JavaScript, -# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, -# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# Csharp (C#), C, C++, Lex, D, PHP, md (Markdown), Objective-C, Python, Slice, +# VHDL, Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: # FortranFree, unknown formatted Fortran: Fortran. In the later case the parser # tries to guess whether the code is fixed or free formatted code, this is the -# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat -# .inc files as Fortran files (default is PHP), and .f files as C (default is -# Fortran), use: inc=Fortran f=C. +# default for Fortran type files). For instance to make doxygen treat .inc files +# as Fortran files (default is PHP), and .f files as C (default is Fortran), +# use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # # Note that for custom extensions you also need to set FILE_PATTERNS otherwise -# the files are not read by doxygen. +# the files are not read by doxygen. When specifying no_extension you should add +# * to the FILE_PATTERNS. +# +# Note see also the list of default file extension mappings. EXTENSION_MAPPING = @@ -334,6 +359,17 @@ MARKDOWN_SUPPORT = YES TOC_INCLUDE_HEADINGS = 5 +# The MARKDOWN_ID_STYLE tag can be used to specify the algorithm used to +# generate identifiers for the Markdown headings. Note: Every identifier is +# unique. +# Possible values are: DOXYGEN use a fixed 'autotoc_md' string followed by a +# sequence number starting at 0 and GITHUB use the lower case version of title +# with any whitespace replaced by '-' and punctuation characters removed. +# The default value is: DOXYGEN. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +MARKDOWN_ID_STYLE = DOXYGEN + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or @@ -445,6 +481,27 @@ TYPEDEF_HIDES_STRUCT = NO LOOKUP_CACHE_SIZE = 0 +# The NUM_PROC_THREADS specifies the number of threads doxygen is allowed to use +# during processing. When set to 0 doxygen will based this on the number of +# cores available in the system. You can set it explicitly to a value larger +# than 0 to get more control over the balance between CPU load and processing +# speed. At this moment only the input processing can be done using multiple +# threads. Since this is still an experimental feature the default is set to 1, +# which effectively disables parallel processing. Please report any issues you +# encounter. Generating dot graphs in parallel is controlled by the +# DOT_NUM_THREADS setting. +# Minimum value: 0, maximum value: 32, default value: 1. + +NUM_PROC_THREADS = 1 + +# If the TIMESTAMP tag is set different from NO then each generated page will +# contain the date or date and time when the page was generated. Setting this to +# NO can help when comparing the output of multiple runs. +# Possible values are: YES, NO, DATETIME and DATE. +# The default value is: NO. + +TIMESTAMP = YES + #--------------------------------------------------------------------------- # Build related configuration options #--------------------------------------------------------------------------- @@ -508,6 +565,13 @@ EXTRACT_LOCAL_METHODS = NO EXTRACT_ANON_NSPACES = NO +# If this flag is set to YES, the name of an unnamed parameter in a declaration +# will be determined by the corresponding definition. By default unnamed +# parameters remain unnamed in the output. +# The default value is: YES. + +RESOLVE_UNNAMED_PARAMS = YES + # If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all # undocumented members inside documented classes or files. If set to NO these # members will be included in the various overviews, but no documentation @@ -519,7 +583,8 @@ HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. If set # to NO, these classes will be included in the various overviews. This option -# has no effect if EXTRACT_ALL is enabled. +# will also hide undocumented C++ concepts if enabled. This option has no effect +# if EXTRACT_ALL is enabled. # The default value is: NO. HIDE_UNDOC_CLASSES = NO @@ -545,12 +610,20 @@ HIDE_IN_BODY_DOCS = NO INTERNAL_DOCS = NO -# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file -# names in lower-case letters. If set to YES, upper-case letters are also -# allowed. This is useful if you have classes or files whose names only differ -# in case and if your file system supports case sensitive file names. Windows -# (including Cygwin) ands Mac users are advised to set this option to NO. -# The default value is: system dependent. +# With the correct setting of option CASE_SENSE_NAMES doxygen will better be +# able to match the capabilities of the underlying filesystem. In case the +# filesystem is case sensitive (i.e. it supports files in the same directory +# whose names only differ in casing), the option must be set to YES to properly +# deal with such files in case they appear in the input. For filesystems that +# are not case sensitive the option should be set to NO to properly deal with +# output files written for symbols that only differ in casing, such as for two +# classes, one named CLASS and the other named Class, and to also support +# references to files without having to specify the exact matching casing. On +# Windows (including Cygwin) and MacOS, users should typically set this option +# to NO, whereas on Linux or other Unix flavors it should typically be set to +# YES. +# Possible values are: SYSTEM, NO and YES. +# The default value is: SYSTEM. CASE_SENSE_NAMES = YES @@ -568,6 +641,12 @@ HIDE_SCOPE_NAMES = NO HIDE_COMPOUND_REFERENCE= NO +# If the SHOW_HEADERFILE tag is set to YES then the documentation for a class +# will show which file needs to be included to use the class. +# The default value is: YES. + +SHOW_HEADERFILE = YES + # If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of # the files that are included by a file in the documentation of that file. # The default value is: YES. @@ -725,7 +804,8 @@ FILE_VERSION_FILTER = # output files in an output format independent way. To create the layout file # that represents doxygen's defaults, run doxygen with the -l option. You can # optionally specify a file name after the option, if omitted DoxygenLayout.xml -# will be used as the name of the layout file. +# will be used as the name of the layout file. See also section "Changing the +# layout of pages" for information. # # Note that if you run doxygen from a directory containing a file called # DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE @@ -771,24 +851,50 @@ WARNINGS = YES WARN_IF_UNDOCUMENTED = YES # If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for -# potential errors in the documentation, such as not documenting some parameters -# in a documented function, or documenting parameters that don't exist or using -# markup commands wrongly. +# potential errors in the documentation, such as documenting some parameters in +# a documented function twice, or documenting parameters that don't exist or +# using markup commands wrongly. # The default value is: YES. WARN_IF_DOC_ERROR = YES +# If WARN_IF_INCOMPLETE_DOC is set to YES, doxygen will warn about incomplete +# function parameter documentation. If set to NO, doxygen will accept that some +# parameters have no documentation without warning. +# The default value is: YES. + +WARN_IF_INCOMPLETE_DOC = YES + # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return -# value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. If -# EXTRACT_ALL is set to YES then this flag will automatically be disabled. +# value. If set to NO, doxygen will only warn about wrong parameter +# documentation, but not about the absence of documentation. If EXTRACT_ALL is +# set to YES then this flag will automatically be disabled. See also +# WARN_IF_INCOMPLETE_DOC # The default value is: NO. WARN_NO_PARAMDOC = NO +# If WARN_IF_UNDOC_ENUM_VAL option is set to YES, doxygen will warn about +# undocumented enumeration values. If set to NO, doxygen will accept +# undocumented enumeration values. If EXTRACT_ALL is set to YES then this flag +# will automatically be disabled. +# The default value is: NO. + +WARN_IF_UNDOC_ENUM_VAL = NO + # If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when -# a warning is encountered. +# a warning is encountered. If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS +# then doxygen will continue running as if WARN_AS_ERROR tag is set to NO, but +# at the end of the doxygen process doxygen will return with a non-zero status. +# If the WARN_AS_ERROR tag is set to FAIL_ON_WARNINGS_PRINT then doxygen behaves +# like FAIL_ON_WARNINGS but in case no WARN_LOGFILE is defined doxygen will not +# write the warning messages in between other messages but write them at the end +# of a run, in case a WARN_LOGFILE is defined the warning messages will be +# besides being in the defined file also be shown at the end of a run, unless +# the WARN_LOGFILE is defined as - i.e. standard output (stdout) in that case +# the behavior will remain as with the setting FAIL_ON_WARNINGS. +# Possible values are: NO, YES, FAIL_ON_WARNINGS and FAIL_ON_WARNINGS_PRINT. # The default value is: NO. WARN_AS_ERROR = YES @@ -799,13 +905,27 @@ WARN_AS_ERROR = YES # and the warning text. Optionally the format may contain $version, which will # be replaced by the version of the file (if it could be obtained via # FILE_VERSION_FILTER) +# See also: WARN_LINE_FORMAT # The default value is: $file:$line: $text. WARN_FORMAT = "$file:$line: $text" +# In the $text part of the WARN_FORMAT command it is possible that a reference +# to a more specific place is given. To make it easier to jump to this place +# (outside of doxygen) the user can define a custom "cut" / "paste" string. +# Example: +# WARN_LINE_FORMAT = "'vi $file +$line'" +# See also: WARN_FORMAT +# The default value is: at line $line of file $file. + +WARN_LINE_FORMAT = "at line $line of file $file" + # The WARN_LOGFILE tag can be used to specify a file to which warning and error # messages should be written. If left blank the output is written to standard -# error (stderr). +# error (stderr). In case the file specified cannot be opened for writing the +# warning and error messages are written to standard error. When as file - is +# specified the warning and error messages are written to standard output +# (stdout). WARN_LOGFILE = @@ -824,12 +944,23 @@ INPUT = .. # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: https://www.gnu.org/software/libiconv/) for the list of -# possible encodings. +# documentation (see: +# https://www.gnu.org/software/libiconv/) for the list of possible encodings. +# See also: INPUT_FILE_ENCODING # The default value is: UTF-8. INPUT_ENCODING = UTF-8 +# This tag can be used to specify the character encoding of the source files +# that doxygen parses The INPUT_FILE_ENCODING tag can be used to specify +# character encoding on a per file pattern basis. Doxygen will compare the file +# name with each pattern and apply the encoding instead of the default +# INPUT_ENCODING) if there is a match. The character encodings are a list of the +# form: pattern=encoding (like *.php=ISO-8859-1). See cfg_input_encoding +# "INPUT_ENCODING" for further information on supported encodings. + +INPUT_FILE_ENCODING = + # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and # *.h) to filter out the source-files in the directories. @@ -838,13 +969,15 @@ INPUT_ENCODING = UTF-8 # need to set EXTENSION_MAPPING for the extension otherwise the files are not # read by doxygen. # -# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, -# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, -# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, -# *.m, *.markdown, *.md, *.mm, *.dox (to be provided as doxygen C comment), -# *.doc (to be provided as doxygen C comment), *.txt (to be provided as doxygen -# C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, *.f, *.for, *.tcl, *.vhd, -# *.vhdl, *.ucf, *.qsf and *.ice. +# Note the list of default checked file patterns might differ from the list of +# default file extension mappings. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cxxm, +# *.cpp, *.cppm, *.ccm, *.c++, *.c++m, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, +# *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, *.h++, *.ixx, *.l, *.cs, *.d, +# *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, *.md, *.mm, *.dox (to +# be provided as doxygen C comment), *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f18, *.f, *.for, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. FILE_PATTERNS = @@ -861,7 +994,7 @@ RECURSIVE = NO # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = +EXCLUDE = ../ext # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -883,10 +1016,7 @@ EXCLUDE_PATTERNS = # (namespaces, classes, functions, etc.) that should be excluded from the # output. The symbol name can be a fully qualified name, a word, or if the # wildcard * is used, a substring. Examples: ANamespace, AClass, -# AClass::ANamespace, ANamespace::*Test -# -# Note that the wildcards are matched against the file with absolute path, so to -# exclude all test directories use the pattern */test/* +# ANamespace::AClass, ANamespace::*Test EXCLUDE_SYMBOLS = @@ -931,6 +1061,11 @@ IMAGE_PATH = # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. # +# Note that doxygen will use the data processed and written to standard output +# for further processing, therefore nothing else, like debug statements or used +# commands (so in case of a Windows batch file always use @echo OFF), should be +# written to standard output. +# # Note that for custom extensions or not directly supported extensions you also # need to set EXTENSION_MAPPING for the extension otherwise the files are not # properly processed by doxygen. @@ -972,6 +1107,15 @@ FILTER_SOURCE_PATTERNS = USE_MDFILE_AS_MAINPAGE = +# The Fortran standard specifies that for fixed formatted Fortran code all +# characters from position 72 are to be considered as comment. A common +# extension is to allow longer lines before the automatic comment starts. The +# setting FORTRAN_COMMENT_AFTER will also make it possible that longer lines can +# be processed before the automatic comment starts. +# Minimum value: 7, maximum value: 10000, default value: 72. + +FORTRAN_COMMENT_AFTER = 72 + #--------------------------------------------------------------------------- # Configuration options related to source browsing #--------------------------------------------------------------------------- @@ -986,7 +1130,8 @@ USE_MDFILE_AS_MAINPAGE = SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body of functions, -# classes and enums directly into the documentation. +# multi-line macros, enums or list initialized variables directly into the +# documentation. # The default value is: NO. INLINE_SOURCES = NO @@ -1059,16 +1204,24 @@ USE_HTAGS = NO VERBATIM_HEADERS = YES # If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the -# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the -# cost of reduced performance. This can be particularly helpful with template -# rich C++ code for which doxygen's built-in parser lacks the necessary type -# information. +# clang parser (see: +# http://clang.llvm.org/) for more accurate parsing at the cost of reduced +# performance. This can be particularly helpful with template rich C++ code for +# which doxygen's built-in parser lacks the necessary type information. # Note: The availability of this option depends on whether or not doxygen was # generated with the -Duse_libclang=ON option for CMake. # The default value is: NO. CLANG_ASSISTED_PARSING = NO +# If the CLANG_ASSISTED_PARSING tag is set to YES and the CLANG_ADD_INC_PATHS +# tag is set to YES then doxygen will add the directory of each input to the +# include path. +# The default value is: YES. +# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. + +CLANG_ADD_INC_PATHS = YES + # If clang assisted parsing is enabled you can provide the compiler with command # line options that you would normally use when invoking the compiler. Note that # the include paths will already be set by doxygen for the files and directories @@ -1078,10 +1231,13 @@ CLANG_ASSISTED_PARSING = NO CLANG_OPTIONS = # If clang assisted parsing is enabled you can provide the clang parser with the -# path to the compilation database (see: -# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) used when the files -# were built. This is equivalent to specifying the "-p" option to a clang tool, -# such as clang-check. These options will then be passed to the parser. +# path to the directory containing a file called compile_commands.json. This +# file is the compilation database (see: +# http://clang.llvm.org/docs/HowToSetupToolingForLLVM.html) containing the +# options used when the source files were built. This is equivalent to +# specifying the -p option to a clang tool, such as clang-check. These options +# will then be passed to the parser. Any options specified with CLANG_OPTIONS +# will be added as well. # Note: The availability of this option depends on whether or not doxygen was # generated with the -Duse_libclang=ON option for CMake. @@ -1098,17 +1254,11 @@ CLANG_DATABASE_PATH = ALPHABETICAL_INDEX = NO -# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in -# which the alphabetical index list will be split. -# Minimum value: 1, maximum value: 20, default value: 5. -# This tag requires that the tag ALPHABETICAL_INDEX is set to YES. - -COLS_IN_ALPHA_INDEX = 5 - -# In case all classes in a project start with a common prefix, all classes will -# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag -# can be used to specify a prefix (or a list of prefixes) that should be ignored -# while generating the index headers. +# The IGNORE_PREFIX tag can be used to specify a prefix (or a list of prefixes) +# that should be ignored while generating the index headers. The IGNORE_PREFIX +# tag works for classes, function and member names. The entity will be placed in +# the alphabetical list under the first letter of the entity name that remains +# after removing the prefix. # This tag requires that the tag ALPHABETICAL_INDEX is set to YES. IGNORE_PREFIX = @@ -1187,7 +1337,12 @@ HTML_STYLESHEET = # Doxygen will copy the style sheet files to the output directory. # Note: The order of the extra style sheet files is of importance (e.g. the last # style sheet in the list overrules the setting of the previous ones in the -# list). For an example see the documentation. +# list). +# Note: Since the styling of scrollbars can currently not be overruled in +# Webkit/Chromium, the styling will be left out of the default doxygen.css if +# one or more extra stylesheets have been specified. So if scrollbar +# customization is desired it has to be added explicitly. For an example see the +# documentation. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_EXTRA_STYLESHEET = @@ -1202,9 +1357,22 @@ HTML_EXTRA_STYLESHEET = HTML_EXTRA_FILES = +# The HTML_COLORSTYLE tag can be used to specify if the generated HTML output +# should be rendered with a dark or light theme. +# Possible values are: LIGHT always generate light mode output, DARK always +# generate dark mode output, AUTO_LIGHT automatically set the mode according to +# the user preference, use light mode if no preference is set (the default), +# AUTO_DARK automatically set the mode according to the user preference, use +# dark mode if no preference is set and TOGGLE allow to user to switch between +# light and dark mode via a button. +# The default value is: AUTO_LIGHT. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COLORSTYLE = AUTO_LIGHT + # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to -# this color. Hue is specified as an angle on a colorwheel, see +# this color. Hue is specified as an angle on a color-wheel, see # https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. @@ -1214,7 +1382,7 @@ HTML_EXTRA_FILES = HTML_COLORSTYLE_HUE = 220 # The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors -# in the HTML output. For a value of 0 the output will use grayscales only. A +# in the HTML output. For a value of 0 the output will use gray-scales only. A # value of 255 will produce the most vivid colors. # Minimum value: 0, maximum value: 255, default value: 100. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1232,15 +1400,6 @@ HTML_COLORSTYLE_SAT = 100 HTML_COLORSTYLE_GAMMA = 80 -# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML -# page will contain the date and time when the page was generated. Setting this -# to YES can help to show when doxygen was last run and thus if the -# documentation is up to date. -# The default value is: NO. -# This tag requires that the tag GENERATE_HTML is set to YES. - -HTML_TIMESTAMP = YES - # If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML # documentation will contain a main index with vertical navigation menus that # are dynamically created via JavaScript. If disabled, the navigation index will @@ -1260,6 +1419,33 @@ HTML_DYNAMIC_MENUS = YES HTML_DYNAMIC_SECTIONS = NO +# If the HTML_CODE_FOLDING tag is set to YES then classes and functions can be +# dynamically folded and expanded in the generated HTML source code. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_CODE_FOLDING = YES + +# If the HTML_COPY_CLIPBOARD tag is set to YES then doxygen will show an icon in +# the top right corner of code and text fragments that allows the user to copy +# its content to the clipboard. Note this only works if supported by the browser +# and the web page is served via a secure context (see: +# https://www.w3.org/TR/secure-contexts/), i.e. using the https: or file: +# protocol. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_COPY_CLIPBOARD = YES + +# Doxygen stores a couple of settings persistently in the browser (via e.g. +# cookies). By default these settings apply to all HTML pages generated by +# doxygen across all projects. The HTML_PROJECT_COOKIE tag can be used to store +# the settings under a project specific key, such that the user preferences will +# be stored separately. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_PROJECT_COOKIE = + # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand # and collapse entries dynamically later on. Doxygen will expand the tree to @@ -1275,10 +1461,11 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: https://developer.apple.com/xcode/), introduced with OSX -# 10.5 (Leopard). To create a documentation set, doxygen will generate a -# Makefile in the HTML output directory. Running make will produce the docset in -# that directory and running make install will install the docset in +# environment (see: +# https://developer.apple.com/xcode/), introduced with OSX 10.5 (Leopard). To +# create a documentation set, doxygen will generate a Makefile in the HTML +# output directory. Running make will produce the docset in that directory and +# running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at # startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy # genXcode/_index.html for more information. @@ -1295,6 +1482,13 @@ GENERATE_DOCSET = NO DOCSET_FEEDNAME = "Doxygen generated docs" +# This tag determines the URL of the docset feed. A documentation feed provides +# an umbrella under which multiple documentation sets from a single provider +# (such as a company or product suite) can be grouped. +# This tag requires that the tag GENERATE_DOCSET is set to YES. + +DOCSET_FEEDURL = + # This tag specifies a string that should uniquely identify the documentation # set bundle. This should be a reverse domain-name style string, e.g. # com.mycompany.MyDocSet. Doxygen will append .docset to the name. @@ -1320,8 +1514,12 @@ DOCSET_PUBLISHER_NAME = Publisher # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on -# Windows. +# on Windows. In the beginning of 2021 Microsoft took the original page, with +# a.o. the download links, offline the HTML help workshop was already many years +# in maintenance mode). You can download the HTML help workshop from the web +# archives at Installation executable (see: +# http://web.archive.org/web/20160201063255/http://download.microsoft.com/downlo +# ad/0/A/9/0A939EF6-E31C-430F-A3DF-DFAE7960D564/htmlhelp.exe). # # The HTML Help Workshop contains a compiler that can convert all HTML output # generated by doxygen into a single compiled HTML file (.chm). Compiled HTML @@ -1351,7 +1549,7 @@ CHM_FILE = HHC_LOCATION = # The GENERATE_CHI flag controls if a separate .chi index file is generated -# (YES) or that it should be included in the master .chm file (NO). +# (YES) or that it should be included in the main .chm file (NO). # The default value is: NO. # This tag requires that the tag GENERATE_HTMLHELP is set to YES. @@ -1378,6 +1576,16 @@ BINARY_TOC = NO TOC_EXPAND = NO +# The SITEMAP_URL tag is used to specify the full URL of the place where the +# generated documentation will be placed on the server by the user during the +# deployment of the documentation. The generated sitemap is called sitemap.xml +# and placed on the directory specified by HTML_OUTPUT. In case no SITEMAP_URL +# is specified no sitemap is generated. For information about the sitemap +# protocol see https://www.sitemaps.org +# This tag requires that the tag GENERATE_HTML is set to YES. + +SITEMAP_URL = + # If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and # QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that # can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help @@ -1396,7 +1604,8 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). +# (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1404,8 +1613,8 @@ QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- -# folders). +# Folders (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1413,16 +1622,16 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- -# filters). +# Filters (see: +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-filters). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_CUST_FILTER_ATTRS = @@ -1434,9 +1643,9 @@ QHP_CUST_FILTER_ATTRS = QHP_SECT_FILTER_ATTRS = -# The QHG_LOCATION tag can be used to specify the location of Qt's -# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the -# generated .qhp file. +# The QHG_LOCATION tag can be used to specify the location (absolute path +# including file name) of Qt's qhelpgenerator. If non-empty doxygen will try to +# run qhelpgenerator on the generated .qhp file. # This tag requires that the tag GENERATE_QHP is set to YES. QHG_LOCATION = @@ -1479,16 +1688,28 @@ DISABLE_INDEX = NO # to work a browser that supports JavaScript, DHTML, CSS and frames is required # (i.e. any modern browser). Windows users are probably better off using the # HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can -# further fine-tune the look of the index. As an example, the default style -# sheet generated by doxygen has an example that shows how to put an image at -# the root of the tree instead of the PROJECT_NAME. Since the tree basically has -# the same information as the tab index, you could consider setting -# DISABLE_INDEX to YES when enabling this option. +# further fine tune the look of the index (see "Fine-tuning the output"). As an +# example, the default style sheet generated by doxygen has an example that +# shows how to put an image at the root of the tree instead of the PROJECT_NAME. +# Since the tree basically has the same information as the tab index, you could +# consider setting DISABLE_INDEX to YES when enabling this option. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. GENERATE_TREEVIEW = NO +# When both GENERATE_TREEVIEW and DISABLE_INDEX are set to YES, then the +# FULL_SIDEBAR option determines if the side bar is limited to only the treeview +# area (value NO) or if it should extend to the full height of the window (value +# YES). Setting this to YES gives a layout similar to +# https://docs.readthedocs.io with more room for contents, but less room for the +# project logo, title, and description. If either GENERATE_TREEVIEW or +# DISABLE_INDEX is set to NO, this option has no effect. +# The default value is: NO. +# This tag requires that the tag GENERATE_HTML is set to YES. + +FULL_SIDEBAR = NO + # The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that # doxygen will group on one line in the generated HTML documentation. # @@ -1513,6 +1734,24 @@ TREEVIEW_WIDTH = 250 EXT_LINKS_IN_WINDOW = NO +# If the OBFUSCATE_EMAILS tag is set to YES, doxygen will obfuscate email +# addresses. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +OBFUSCATE_EMAILS = YES + +# If the HTML_FORMULA_FORMAT option is set to svg, doxygen will use the pdf2svg +# tool (see https://github.com/dawbarton/pdf2svg) or inkscape (see +# https://inkscape.org) to generate formulas as SVG images instead of PNGs for +# the HTML output. These images will generally look nicer at scaled resolutions. +# Possible values are: png (the default) and svg (looks nicer but requires the +# pdf2svg or inkscape tool). +# The default value is: png. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_FORMULA_FORMAT = png + # Use this tag to change the font size of LaTeX formulas included as images in # the HTML documentation. When you change the font size after a successful # doxygen run you need to manually remove any form_*.png images from the HTML @@ -1522,17 +1761,6 @@ EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANSPARENT tag to determine whether or not the images -# generated for formulas are transparent PNGs. Transparent PNGs are not -# supported properly for IE 6.0, but are supported on all modern browsers. -# -# Note that when changing this option you need to delete any form_*.png files in -# the HTML output directory before the changes have effect. -# The default value is: YES. -# This tag requires that the tag GENERATE_HTML is set to YES. - -FORMULA_TRANSPARENT = YES - # The FORMULA_MACROFILE can contain LaTeX \newcommand and \renewcommand commands # to create new LaTeX commands to be used in formulas as building blocks. See # the section "Including formulas" for details. @@ -1550,11 +1778,29 @@ FORMULA_MACROFILE = USE_MATHJAX = NO +# With MATHJAX_VERSION it is possible to specify the MathJax version to be used. +# Note that the different versions of MathJax have different requirements with +# regards to the different settings, so it is possible that also other MathJax +# settings have to be changed when switching between the different MathJax +# versions. +# Possible values are: MathJax_2 and MathJax_3. +# The default value is: MathJax_2. +# This tag requires that the tag USE_MATHJAX is set to YES. + +MATHJAX_VERSION = MathJax_2 + # When MathJax is enabled you can set the default output format to be used for -# the MathJax output. See the MathJax site (see: -# http://docs.mathjax.org/en/latest/output.html) for more details. +# the MathJax output. For more details about the output format see MathJax +# version 2 (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) and MathJax version 3 +# (see: +# http://docs.mathjax.org/en/latest/web/components/output.html). # Possible values are: HTML-CSS (which is slower, but has the best -# compatibility), NativeMML (i.e. MathML) and SVG. +# compatibility. This is the name for Mathjax version 2, for MathJax version 3 +# this will be translated into chtml), NativeMML (i.e. MathML. Only supported +# for NathJax 2. For MathJax version 3 chtml will be used instead.), chtml (This +# is the name for Mathjax version 3, for MathJax version 2 this will be +# translated into HTML-CSS) and SVG. # The default value is: HTML-CSS. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1567,22 +1813,29 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from https://www.mathjax.org before deployment. -# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. +# MathJax from https://www.mathjax.org before deployment. The default value is: +# - in case of MathJax version 2: https://cdn.jsdelivr.net/npm/mathjax@2 +# - in case of MathJax version 3: https://cdn.jsdelivr.net/npm/mathjax@3 # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/ # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example +# for MathJax version 2 (see +# https://docs.mathjax.org/en/v2.7-latest/tex.html#tex-and-latex-extensions): # MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols +# For example for MathJax version 3 (see +# http://docs.mathjax.org/en/latest/input/tex/extensions/index.html): +# MATHJAX_EXTENSIONS = ams # This tag requires that the tag USE_MATHJAX is set to YES. MATHJAX_EXTENSIONS = # The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces # of code that will be used on startup of the MathJax code. See the MathJax site -# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an +# (see: +# http://docs.mathjax.org/en/v2.7-latest/output.html) for more details. For an # example see the documentation. # This tag requires that the tag USE_MATHJAX is set to YES. @@ -1629,7 +1882,8 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: https://xapian.org/). +# Xapian (see: +# https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1642,8 +1896,9 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: https://xapian.org/). See the section "External Indexing and -# Searching" for details. +# Xapian (see: +# https://xapian.org/). See the section "External Indexing and Searching" for +# details. # This tag requires that the tag SEARCHENGINE is set to YES. SEARCHENGINE_URL = @@ -1738,7 +1993,7 @@ COMPACT_LATEX = NO # The default value is: a4. # This tag requires that the tag GENERATE_LATEX is set to YES. -PAPER_TYPE = a4wide +PAPER_TYPE = a4 # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names # that should be included in the LaTeX output. The package can be specified just @@ -1752,29 +2007,31 @@ PAPER_TYPE = a4wide EXTRA_PACKAGES = -# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the -# generated LaTeX document. The header should contain everything until the first -# chapter. If it is left blank doxygen will generate a standard header. See -# section "Doxygen usage" for information on how to let doxygen write the -# default header to a separate file. +# The LATEX_HEADER tag can be used to specify a user-defined LaTeX header for +# the generated LaTeX document. The header should contain everything until the +# first chapter. If it is left blank doxygen will generate a standard header. It +# is highly recommended to start with a default header using +# doxygen -w latex new_header.tex new_footer.tex new_stylesheet.sty +# and then modify the file new_header.tex. See also section "Doxygen usage" for +# information on how to generate the default header that doxygen normally uses. # -# Note: Only use a user-defined header if you know what you are doing! The -# following commands have a special meaning inside the header: $title, -# $datetime, $date, $doxygenversion, $projectname, $projectnumber, -# $projectbrief, $projectlogo. Doxygen will replace $title with the empty -# string, for the replacement values of the other commands the user is referred -# to HTML_HEADER. +# Note: Only use a user-defined header if you know what you are doing! +# Note: The header is subject to change so you typically have to regenerate the +# default header when upgrading to a newer version of doxygen. The following +# commands have a special meaning inside the header (and footer): For a +# description of the possible markers and block names see the documentation. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_HEADER = -# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the -# generated LaTeX document. The footer should contain everything after the last -# chapter. If it is left blank doxygen will generate a standard footer. See +# The LATEX_FOOTER tag can be used to specify a user-defined LaTeX footer for +# the generated LaTeX document. The footer should contain everything after the +# last chapter. If it is left blank doxygen will generate a standard footer. See # LATEX_HEADER for more information on how to generate a default footer and what -# special commands can be used inside the footer. -# -# Note: Only use a user-defined footer if you know what you are doing! +# special commands can be used inside the footer. See also section "Doxygen +# usage" for information on how to generate the default footer that doxygen +# normally uses. Note: Only use a user-defined footer if you know what you are +# doing! # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_FOOTER = @@ -1807,18 +2064,26 @@ LATEX_EXTRA_FILES = PDF_HYPERLINKS = YES -# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate -# the PDF file directly from the LaTeX files. Set this option to YES, to get a -# higher quality PDF documentation. +# If the USE_PDFLATEX tag is set to YES, doxygen will use the engine as +# specified with LATEX_CMD_NAME to generate the PDF file directly from the LaTeX +# files. Set this option to YES, to get a higher quality PDF documentation. +# +# See also section LATEX_CMD_NAME for selecting the engine. # The default value is: YES. # This tag requires that the tag GENERATE_LATEX is set to YES. USE_PDFLATEX = YES -# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode -# command to the generated LaTeX files. This will instruct LaTeX to keep running -# if errors occur, instead of asking the user for help. This option is also used -# when generating formulas in HTML. +# The LATEX_BATCHMODE tag signals the behavior of LaTeX in case of an error. +# Possible values are: NO same as ERROR_STOP, YES same as BATCH, BATCH In batch +# mode nothing is printed on the terminal, errors are scrolled as if is +# hit at every error; missing files that TeX tries to input or request from +# keyboard input (\read on a not open input stream) cause the job to abort, +# NON_STOP In nonstop mode the diagnostic message will appear on the terminal, +# but there is no possibility of user interaction just like in batch mode, +# SCROLL In scroll mode, TeX will stop only for missing files to input or if +# keyboard input is necessary and ERROR_STOP In errorstop mode, TeX will stop at +# each error, asking for user intervention. # The default value is: NO. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1831,16 +2096,6 @@ LATEX_BATCHMODE = NO LATEX_HIDE_INDICES = NO -# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source -# code with syntax highlighting in the LaTeX output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_SOURCE_CODE = NO - # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See # https://en.wikipedia.org/wiki/BibTeX and \cite for more info. @@ -1849,14 +2104,6 @@ LATEX_SOURCE_CODE = NO LATEX_BIB_STYLE = plain -# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated -# page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: NO. -# This tag requires that the tag GENERATE_LATEX is set to YES. - -LATEX_TIMESTAMP = NO - # The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) # path from which the emoji images will be read. If a relative path is entered, # it will be relative to the LATEX_OUTPUT directory. If left blank the @@ -1921,16 +2168,6 @@ RTF_STYLESHEET_FILE = RTF_EXTENSIONS_FILE = -# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code -# with syntax highlighting in the RTF output. -# -# Note that which sources are shown also depends on other settings such as -# SOURCE_BROWSER. -# The default value is: NO. -# This tag requires that the tag GENERATE_RTF is set to YES. - -RTF_SOURCE_CODE = NO - #--------------------------------------------------------------------------- # Configuration options related to the man page output #--------------------------------------------------------------------------- @@ -2027,27 +2264,44 @@ GENERATE_DOCBOOK = NO DOCBOOK_OUTPUT = docbook -# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the -# program listings (including syntax highlighting and cross-referencing -# information) to the DOCBOOK output. Note that enabling this will significantly -# increase the size of the DOCBOOK output. -# The default value is: NO. -# This tag requires that the tag GENERATE_DOCBOOK is set to YES. - -DOCBOOK_PROGRAMLISTING = NO - #--------------------------------------------------------------------------- # Configuration options for the AutoGen Definitions output #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# AutoGen Definitions (see https://autogen.sourceforge.net/) file that captures # the structure of the code including all documentation. Note that this feature # is still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO +#--------------------------------------------------------------------------- +# Configuration options related to Sqlite3 output +#--------------------------------------------------------------------------- + +# If the GENERATE_SQLITE3 tag is set to YES doxygen will generate a Sqlite3 +# database with symbols found by doxygen stored in tables. +# The default value is: NO. + +GENERATE_SQLITE3 = NO + +# The SQLITE3_OUTPUT tag is used to specify where the Sqlite3 database will be +# put. If a relative path is entered the value of OUTPUT_DIRECTORY will be put +# in front of it. +# The default directory is: sqlite3. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_OUTPUT = sqlite3 + +# The SQLITE3_RECREATE_DB tag is set to YES, the existing doxygen_sqlite3.db +# database file will be recreated with each doxygen run. If set to NO, doxygen +# will warn if a database file is already found and not modify it. +# The default value is: YES. +# This tag requires that the tag GENERATE_SQLITE3 is set to YES. + +SQLITE3_RECREATE_DB = YES + #--------------------------------------------------------------------------- # Configuration options related to the Perl module output #--------------------------------------------------------------------------- @@ -2122,7 +2376,8 @@ SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by the -# preprocessor. +# preprocessor. Note that the INCLUDE_PATH is not recursive, so the setting of +# RECURSIVE has no effect here. # This tag requires that the tag SEARCH_INCLUDES is set to YES. INCLUDE_PATH = @@ -2190,15 +2445,15 @@ TAGFILES = GENERATE_TAGFILE = -# If the ALLEXTERNALS tag is set to YES, all external class will be listed in -# the class index. If set to NO, only the inherited external classes will be -# listed. +# If the ALLEXTERNALS tag is set to YES, all external classes and namespaces +# will be listed in the class and namespace index. If set to NO, only the +# inherited external classes will be listed. # The default value is: NO. ALLEXTERNALS = NO # If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed -# in the modules index. If set to NO, only the current project's groups will be +# in the topic index. If set to NO, only the current project's groups will be # listed. # The default value is: YES. @@ -2212,25 +2467,9 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES #--------------------------------------------------------------------------- -# Configuration options related to the dot tool +# Configuration options related to diagram generator tools #--------------------------------------------------------------------------- -# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram -# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to -# NO turns the diagrams off. Note that this option also works with HAVE_DOT -# disabled, but it is recommended to install and use dot, since it yields more -# powerful graphs. -# The default value is: YES. - -CLASS_DIAGRAMS = NO - -# You can include diagrams made with dia in doxygen documentation. Doxygen will -# then run dia to produce the diagram and insert it in the documentation. The -# DIA_PATH tag allows you to specify the directory where the dia binary resides. -# If left empty dia is assumed to be found in the default search path. - -DIA_PATH = - # If set to YES the inheritance and collaboration graphs will hide inheritance # and usage relations if the target is undocumented or is not a class. # The default value is: YES. @@ -2239,10 +2478,10 @@ HIDE_UNDOC_RELATIONS = YES # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz (see: -# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent +# https://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent # Bell Labs. The other options in this section have no effect if this option is # set to NO -# The default value is: YES. +# The default value is: NO. HAVE_DOT = NO @@ -2256,49 +2495,77 @@ HAVE_DOT = NO DOT_NUM_THREADS = 0 -# When you want a differently looking font in the dot files that doxygen -# generates you can specify the font name using DOT_FONTNAME. You need to make -# sure dot is able to find the font, which can be done by putting it in a -# standard location or by setting the DOTFONTPATH environment variable or by -# setting DOT_FONTPATH to the directory containing the font. -# The default value is: Helvetica. +# DOT_COMMON_ATTR is common attributes for nodes, edges and labels of +# subgraphs. When you want a differently looking font in the dot files that +# doxygen generates you can specify fontname, fontcolor and fontsize attributes. +# For details please see Node, +# Edge and Graph Attributes specification You need to make sure dot is able +# to find the font, which can be done by putting it in a standard location or by +# setting the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the +# directory containing the font. Default graphviz fontsize is 14. +# The default value is: fontname=Helvetica,fontsize=10. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_COMMON_ATTR = "fontname=Helvetica,fontsize=10" + +# DOT_EDGE_ATTR is concatenated with DOT_COMMON_ATTR. For elegant style you can +# add 'arrowhead=open, arrowtail=open, arrowsize=0.5'. Complete documentation about +# arrows shapes. +# The default value is: labelfontname=Helvetica,labelfontsize=10. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTNAME = +DOT_EDGE_ATTR = "labelfontname=Helvetica,labelfontsize=10" -# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of -# dot graphs. -# Minimum value: 4, maximum value: 24, default value: 10. +# DOT_NODE_ATTR is concatenated with DOT_COMMON_ATTR. For view without boxes +# around nodes set 'shape=plain' or 'shape=plaintext' Shapes specification +# The default value is: shape=box,height=0.2,width=0.4. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_FONTSIZE = 10 +DOT_NODE_ATTR = "shape=box,height=0.2,width=0.4" -# By default doxygen will tell dot to use the default font as specified with -# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set -# the path where dot can find it using this tag. +# You can set the path where dot can find font specified with fontname in +# DOT_COMMON_ATTR and others dot attributes. # This tag requires that the tag HAVE_DOT is set to YES. DOT_FONTPATH = -# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for -# each documented class showing the direct and indirect inheritance relations. -# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO. +# If the CLASS_GRAPH tag is set to YES or GRAPH or BUILTIN then doxygen will +# generate a graph for each documented class showing the direct and indirect +# inheritance relations. In case the CLASS_GRAPH tag is set to YES or GRAPH and +# HAVE_DOT is enabled as well, then dot will be used to draw the graph. In case +# the CLASS_GRAPH tag is set to YES and HAVE_DOT is disabled or if the +# CLASS_GRAPH tag is set to BUILTIN, then the built-in generator will be used. +# If the CLASS_GRAPH tag is set to TEXT the direct and indirect inheritance +# relations will be shown as texts / links. Explicit enabling an inheritance +# graph or choosing a different representation for an inheritance graph of a +# specific class, can be accomplished by means of the command \inheritancegraph. +# Disabling an inheritance graph can be accomplished by means of the command +# \hideinheritancegraph. +# Possible values are: NO, YES, TEXT, GRAPH and BUILTIN. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. -CLASS_GRAPH = YES +CLASS_GRAPH = TEXT # If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a # graph for each documented class showing the direct and indirect implementation # dependencies (inheritance, containment, and class references variables) of the -# class with other documented classes. +# class with other documented classes. Explicit enabling a collaboration graph, +# when COLLABORATION_GRAPH is set to NO, can be accomplished by means of the +# command \collaborationgraph. Disabling a collaboration graph can be +# accomplished by means of the command \hidecollaborationgraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. COLLABORATION_GRAPH = YES # If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for -# groups, showing the direct groups dependencies. +# groups, showing the direct groups dependencies. Explicit enabling a group +# dependency graph, when GROUP_GRAPHS is set to NO, can be accomplished by means +# of the command \groupgraph. Disabling a directory graph can be accomplished by +# means of the command \hidegroupgraph. See also the chapter Grouping in the +# manual. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2321,10 +2588,32 @@ UML_LOOK = NO # but if the number exceeds 15, the total amount of fields shown is limited to # 10. # Minimum value: 0, maximum value: 100, default value: 10. -# This tag requires that the tag HAVE_DOT is set to YES. +# This tag requires that the tag UML_LOOK is set to YES. UML_LIMIT_NUM_FIELDS = 10 +# If the DOT_UML_DETAILS tag is set to NO, doxygen will show attributes and +# methods without types and arguments in the UML graphs. If the DOT_UML_DETAILS +# tag is set to YES, doxygen will add type and arguments for attributes and +# methods in the UML graphs. If the DOT_UML_DETAILS tag is set to NONE, doxygen +# will not generate fields with class member information in the UML graphs. The +# class diagrams will look similar to the default class diagrams but using UML +# notation for the relationships. +# Possible values are: NO, YES and NONE. +# The default value is: NO. +# This tag requires that the tag UML_LOOK is set to YES. + +DOT_UML_DETAILS = NO + +# The DOT_WRAP_THRESHOLD tag can be used to set the maximum number of characters +# to display on a single line. If the actual line length exceeds this threshold +# significantly it will be wrapped across multiple lines. Some heuristics are +# applied to avoid ugly line breaks. +# Minimum value: 0, maximum value: 1000, default value: 17. +# This tag requires that the tag HAVE_DOT is set to YES. + +DOT_WRAP_THRESHOLD = 17 + # If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and # collaboration graphs will show the relations between templates and their # instances. @@ -2336,7 +2625,9 @@ TEMPLATE_RELATIONS = NO # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to # YES then doxygen will generate a graph for each documented file showing the # direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an include graph, when INCLUDE_GRAPH is is set to NO, +# can be accomplished by means of the command \includegraph. Disabling an +# include graph can be accomplished by means of the command \hideincludegraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2345,7 +2636,10 @@ INCLUDE_GRAPH = YES # If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are # set to YES then doxygen will generate a graph for each documented file showing # the direct and indirect include dependencies of the file with other documented -# files. +# files. Explicit enabling an included by graph, when INCLUDED_BY_GRAPH is set +# to NO, can be accomplished by means of the command \includedbygraph. Disabling +# an included by graph can be accomplished by means of the command +# \hideincludedbygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2385,22 +2679,30 @@ GRAPHICAL_HIERARCHY = YES # If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the # dependencies a directory has on other directories in a graphical way. The # dependency relations are determined by the #include relations between the -# files in the directories. +# files in the directories. Explicit enabling a directory graph, when +# DIRECTORY_GRAPH is set to NO, can be accomplished by means of the command +# \directorygraph. Disabling a directory graph can be accomplished by means of +# the command \hidedirectorygraph. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. DIRECTORY_GRAPH = YES +# The DIR_GRAPH_MAX_DEPTH tag can be used to limit the maximum number of levels +# of child directories generated in directory dependency graphs by dot. +# Minimum value: 1, maximum value: 25, default value: 1. +# This tag requires that the tag DIRECTORY_GRAPH is set to YES. + +DIR_GRAPH_MAX_DEPTH = 1 + # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images # generated by dot. For an explanation of the image formats see the section # output formats in the documentation of the dot tool (Graphviz (see: -# http://www.graphviz.org/)). +# https://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). -# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd, -# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo, -# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo, +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, # png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and # png:gdiplus:gdiplus. # The default value is: png. @@ -2433,11 +2735,12 @@ DOT_PATH = DOTFILE_DIRS = -# The MSCFILE_DIRS tag can be used to specify one or more directories that -# contain msc files that are included in the documentation (see the \mscfile -# command). +# You can include diagrams made with dia in doxygen documentation. Doxygen will +# then run dia to produce the diagram and insert it in the documentation. The +# DIA_PATH tag allows you to specify the directory where the dia binary resides. +# If left empty dia is assumed to be found in the default search path. -MSCFILE_DIRS = +DIA_PATH = # The DIAFILE_DIRS tag can be used to specify one or more directories that # contain dia files that are included in the documentation (see the \diafile @@ -2446,10 +2749,10 @@ MSCFILE_DIRS = DIAFILE_DIRS = # When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the -# path where java can find the plantuml.jar file. If left blank, it is assumed -# PlantUML is not used or called during a preprocessing step. Doxygen will -# generate a warning when it encounters a \startuml command in this case and -# will not generate output for the diagram. +# path where java can find the plantuml.jar file or to the filename of jar file +# to be used. If left blank, it is assumed PlantUML is not used or called during +# a preprocessing step. Doxygen will generate a warning when it encounters a +# \startuml command in this case and will not generate output for the diagram. PLANTUML_JAR_PATH = @@ -2487,18 +2790,6 @@ DOT_GRAPH_MAX_NODES = 50 MAX_DOT_GRAPH_DEPTH = 0 -# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent -# background. This is disabled by default, because dot on Windows does not seem -# to support this out of the box. -# -# Warning: Depending on the platform used, enabling this option may lead to -# badly anti-aliased labels on the edges of a graph (i.e. they become hard to -# read). -# The default value is: NO. -# This tag requires that the tag HAVE_DOT is set to YES. - -DOT_TRANSPARENT = NO - # Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output # files in one run (i.e. multiple -o and -T options on the command line). This # makes dot run faster, but since only newer versions of dot (>1.8.10) support @@ -2511,14 +2802,34 @@ DOT_MULTI_TARGETS = YES # If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page # explaining the meaning of the various boxes and arrows in the dot generated # graphs. +# Note: This tag requires that UML_LOOK isn't set, i.e. the doxygen internal +# graphical representation for inheritance and collaboration diagrams is used. # The default value is: YES. # This tag requires that the tag HAVE_DOT is set to YES. GENERATE_LEGEND = YES -# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot +# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate # files that are used to generate the various graphs. +# +# Note: This setting is not only used for dot files but also for msc temporary +# files. # The default value is: YES. -# This tag requires that the tag HAVE_DOT is set to YES. DOT_CLEANUP = YES + +# You can define message sequence charts within doxygen comments using the \msc +# command. If the MSCGEN_TOOL tag is left empty (the default), then doxygen will +# use a built-in version of mscgen tool to produce the charts. Alternatively, +# the MSCGEN_TOOL tag can also specify the name an external tool. For instance, +# specifying prog as the value, doxygen will call the tool as prog -T +# -o . The external tool should support +# output file formats "png", "eps", "svg", and "ismap". + +MSCGEN_TOOL = + +# The MSCFILE_DIRS tag can be used to specify one or more directories that +# contain msc files that are included in the documentation (see the \mscfile +# command). + +MSCFILE_DIRS = From 86b6765cd442d04c1468348f87f3eca6232e898b Mon Sep 17 00:00:00 2001 From: Olaf Bergmann Date: Wed, 14 Feb 2024 21:15:47 +0100 Subject: [PATCH 10/17] Makefile.in: Remove SUB_OBJS rule to preserve CPPFLAGS The SUB_OBJS dependency rule invoked make -C on the target directory without passing important flags such as CPPFLAGS. This change removes this rule so that these objects are built with the all flags set in this Makefile. Change-Id: Ic673a881f18cbfa773860d722041a7a083f65d8e --- Makefile.in | 3 --- 1 file changed, 3 deletions(-) diff --git a/Makefile.in b/Makefile.in index 1866b44a..09501190 100644 --- a/Makefile.in +++ b/Makefile.in @@ -87,9 +87,6 @@ dirs: $(SUBDIRS) dtls_prng.o:: $(wildcard platform-specific/dtls_prng_*.c) -$(SUB_OBJECTS):: - $(MAKE) -C $(@D) $(@F) - $(LIB).so: $(OBJECTS) $(LINK.c) $(LDFLAGS) -shared $^ -o $@ From 121cad579b778887a9f5232d80f93cb4b0bc37cb Mon Sep 17 00:00:00 2001 From: Olaf Bergmann Date: Thu, 15 Feb 2024 15:42:26 +0100 Subject: [PATCH 11/17] configure.ac: Set flags for uECC if ECC support is enabled Sets OPT_OBJS and CPPFLAGS to build uECC with curve secp256r1 Change-Id: I3c4860fbc568a492082eeb08e4ee3abd6fbc3c6e --- configure.ac | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/configure.ac b/configure.ac index bce5a361..1286422e 100644 --- a/configure.ac +++ b/configure.ac @@ -72,7 +72,13 @@ AC_ARG_WITH(ecc, [AS_HELP_STRING([--without-ecc],[disable support for TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8])], [], [AC_DEFINE(DTLS_ECC, 1, [Define to 1 if building with ECC support.]) - OPT_OBJS="${OPT_OBJS} ecc/ecc.o" + OPT_OBJS="${OPT_OBJS} ext/micro-ecc/uECC.o" + dnl remove all ECC except for secp256r1 + AC_DEFINE([uECC_SUPPORTS_secp160r1], [0], [Define to 1 if building with uECC curve secp160r1]) + AC_DEFINE([uECC_SUPPORTS_secp192r1], [0], [Define to 1 if building with uECC curve secp192r1]) + AC_DEFINE([uECC_SUPPORTS_secp224r1], [0], [Define to 1 if building with uECC curve secp224r1]) + AC_DEFINE([uECC_SUPPORTS_secp256r1], [1], [Define to 1 if building with uECC curve secp256r1]) + AC_DEFINE([uECC_SUPPORTS_secp256k1], [0], [Define to 1 if building with uECC curve secp256k1]) DTLS_ECC=1]) AC_ARG_WITH(psk, @@ -116,7 +122,13 @@ AC_SUBST(NDEBUG) AC_SUBST(DTLS_ECC) AC_SUBST(DTLS_PSK) AC_SUBST(ENABLE_SHARED) -AC_SUBST(AR) +AC_SUBST(AC) + +AC_SUBST(uECC_SUPPORTS_secp160r1) +AC_SUBST(uECC_SUPPORTS_secp192r1) +AC_SUBST(uECC_SUPPORTS_secp224r1) +AC_SUBST(uECC_SUPPORTS_secp256r1) +AC_SUBST(uECC_SUPPORTS_secp256k1) # Checks for header files. AC_CHECK_HEADERS([assert.h arpa/inet.h fcntl.h inttypes.h netdb.h netinet/in.h stddef.h stdint.h stdlib.h string.h strings.h sys/param.h sys/socket.h unistd.h]) @@ -148,6 +160,5 @@ AC_CONFIG_FILES([Makefile platform-specific/Makefile tinydtls.pc sha2/Makefile - aes/Makefile - ecc/Makefile]) + aes/Makefile]) AC_OUTPUT From 61763fe7fef050473c4d3fdbf329d533845a9af8 Mon Sep 17 00:00:00 2001 From: Olaf Bergmann Date: Thu, 15 Feb 2024 15:46:13 +0100 Subject: [PATCH 12/17] dtls.c: Initialize PRNG function for micro-ecc When compiled with support for ECC, the pseudo-random number generator must be set for micro-ecc. As the function signature required by micro-ecc is different from dtls_prng(), a wrapper function is required to map the different size types. As dtls_prng's size type is larger, no other conversion is necessary. Change-Id: I2f0da18983256be3bc27f18079cf9a774049de33 --- dtls.c | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/dtls.c b/dtls.c index b983b147..5f4f6a5e 100644 --- a/dtls.c +++ b/dtls.c @@ -60,6 +60,10 @@ # include "hmac.h" #endif /* WITH_SHA256 */ +#ifdef DTLS_ECC +#include "ext/micro-ecc/uECC.h" +#endif /* DTLS_ECC */ + #ifdef WITH_ZEPHYR LOG_MODULE_DECLARE(TINYDTLS, CONFIG_TINYDTLS_LOG_LEVEL); #endif /* WITH_ZEPHYR */ @@ -326,6 +330,14 @@ free_context(dtls_context_t *context) { #endif /* WITH_POSIX */ +#ifdef DTLS_ECC +/* Define wrapper function for uECC_set_rng to map the size parameter + * from unsigned int to size_t. */ +static inline int uecc_rng_function(uint8_t *dest, unsigned int size) { + return dtls_prng(dest, size); +} +#endif /* DTLS_ECC */ + void dtls_init(void) { dtls_clock_init(); @@ -337,6 +349,9 @@ dtls_init(void) { memarray_init(&dtlscontext_storage, dtlscontext_storage_data, sizeof(dtls_context_t), DTLS_CONTEXT_MAX); #endif /* RIOT_VERSION */ +#ifdef DTLS_ECC + uECC_set_rng(uecc_rng_function); +#endif /* DTLS_ECC */ } /* Calls cb_alert() with given arguments if defined, otherwise an From f972a671013a531685874f0d53fba1e295cbef92 Mon Sep 17 00:00:00 2001 From: Olaf Bergmann Date: Fri, 16 Feb 2024 17:01:06 +0100 Subject: [PATCH 13/17] [Tests] Remove unit tests for internal ECC implementation As micro-ecc comes with its own unit tests, the tests for the internal ECC implementation are removed. Change-Id: I36826df4a99bd916659898587a94ea6d76af4a33 --- tests/Makefile.in | 4 ++-- tests/unit-tests/Makefile.in | 4 ++-- tests/unit-tests/testdriver.c | 2 -- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/Makefile.in b/tests/Makefile.in index f7ef52ec..efae2b1f 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -32,13 +32,13 @@ SOURCES:= dtls-server.c ccm-test.c \ #cbc_aes128-test.c #dsrv-test.c OBJECTS:= $(patsubst %.c, %.o, $(SOURCES)) PROGRAMS:= dtls-server dtls-client ccm-test -HEADERS:= +HEADERS:=dtls_ciphers_util.h CFLAGS:=-Wall -std=c99 @CFLAGS@ @WARNING_CFLAGS@ $(EXTRA_CFLAGS) -D_POSIX_C_SOURCE=200112L CPPFLAGS:=-I$(top_srcdir) @CPPFLAGS@ LDFLAGS:=-L$(top_builddir) @LDFLAGS@ LDLIBS:=$(top_srcdir)/libtinydtls.a @LIBS@ DISTDIR=$(top_builddir)/@PACKAGE_TARNAME@-@PACKAGE_VERSION@ -FILES:=Makefile.in $(SOURCES) ccm-testdata.c #cbc_aes128-testdata.c +FILES:=Makefile.in $(SOURCES) $(HEADERS) ccm-testdata.c .PHONY: all dirs clean distclean .gitignore doc install uninstall diff --git a/tests/unit-tests/Makefile.in b/tests/unit-tests/Makefile.in index 8c24c91c..756161cc 100644 --- a/tests/unit-tests/Makefile.in +++ b/tests/unit-tests/Makefile.in @@ -26,7 +26,7 @@ top_builddir = @top_builddir@ top_srcdir:= @top_srcdir@ # files and flags -UNITS= test_ccm.c test_ecc.c test_prf.c +UNITS= test_ccm.c test_prf.c SOURCES:= $(UNITS) PROGRAM:=testdriver OBJECTS:= $(patsubst %.c, %.o, $(SOURCES)) @@ -36,7 +36,7 @@ CPPFLAGS:=-I$(top_srcdir) @CPPFLAGS@ LDFLAGS:=-L$(top_builddir) @LDFLAGS@ LDLIBS:=$(top_srcdir)/libtinydtls.a @CUNIT_LIBS@ @LIBS@ DISTDIR=$(top_builddir)/@PACKAGE_TARNAME@-@PACKAGE_VERSION@ -FILES:=Makefile.in $(SOURCES) +FILES:=Makefile.in $(SOURCES) $(HEADERS) .PHONY: all dirs clean distclean check diff --git a/tests/unit-tests/testdriver.c b/tests/unit-tests/testdriver.c index 17be7533..998ab51b 100644 --- a/tests/unit-tests/testdriver.c +++ b/tests/unit-tests/testdriver.c @@ -4,7 +4,6 @@ #include #include "test_ccm.h" -#include "test_ecc.h" #include "test_prf.h" #include "tinydtls.h" @@ -18,7 +17,6 @@ int main(void) { } t_init_ccm_tests(); - t_init_ecc_tests(); t_init_prf_tests(); CU_basic_set_mode(run_mode); From 8014f05869c68d56a8dde5cd4ba7260cc002c57b Mon Sep 17 00:00:00 2001 From: Olaf Bergmann Date: Thu, 15 Feb 2024 15:47:13 +0100 Subject: [PATCH 14/17] crypto.c: Replace ECC functions with micro-ecc Change-Id: I85de2c3c88063dae35e81b2b3999bf7d76d04ce7 --- crypto.c | 92 +++++++++++++++++++++++++++----------------------------- 1 file changed, 44 insertions(+), 48 deletions(-) diff --git a/crypto.c b/crypto.c index 1937681d..bc07a8ac 100644 --- a/crypto.c +++ b/crypto.c @@ -31,7 +31,7 @@ #include "dtls.h" #include "crypto.h" #include "ccm.h" -#include "ecc/ecc.h" +#include "ecc/micro-ecc/uECC.h" #include "dtls_prng.h" #include "netq.h" @@ -438,24 +438,25 @@ int dtls_ecdh_pre_master_secret(unsigned char *priv_key, size_t key_size, unsigned char *result, size_t result_len) { - uint32_t priv[8]; - uint32_t pub_x[8]; - uint32_t pub_y[8]; - uint32_t result_x[8]; - uint32_t result_y[8]; + uint8_t pub_key[2 * DTLS_EC_KEY_SIZE]; + uint8_t priv[DTLS_EC_KEY_SIZE]; - assert(key_size == sizeof(priv)); if (result_len < key_size) { return -1; } - dtls_ec_key_to_uint32(priv_key, key_size, priv); - dtls_ec_key_to_uint32(pub_key_x, key_size, pub_x); - dtls_ec_key_to_uint32(pub_key_y, key_size, pub_y); + memcpy(priv, priv_key, DTLS_EC_KEY_SIZE); + memcpy(pub_key, pub_key_x, DTLS_EC_KEY_SIZE); + memcpy(pub_key + DTLS_EC_KEY_SIZE, pub_key_y, DTLS_EC_KEY_SIZE); + if (!uECC_valid_public_key(pub_key)) { + dtls_warn("invalid public key\n"); + } - ecc_ecdh(pub_x, pub_y, priv, result_x, result_y); + if (!uECC_shared_secret(pub_key, priv, result)) { + dtls_warn("cannot generate ECDH shared secret\n"); + return 0; + } - dtls_ec_key_from_uint32(result_x, key_size, result); return key_size; } @@ -464,19 +465,15 @@ dtls_ecdsa_generate_key(unsigned char *priv_key, unsigned char *pub_key_x, unsigned char *pub_key_y, size_t key_size) { - uint32_t priv[8]; - uint32_t pub_x[8]; - uint32_t pub_y[8]; - - do { - dtls_prng((unsigned char *)priv, key_size); - } while (!ecc_is_valid_key(priv)); + uint8_t pub_key[2 * DTLS_EC_KEY_SIZE]; - ecc_gen_pub_key(priv, pub_x, pub_y); - - dtls_ec_key_from_uint32(priv, key_size, priv_key); - dtls_ec_key_from_uint32(pub_x, key_size, pub_key_x); - dtls_ec_key_from_uint32(pub_y, key_size, pub_key_y); + assert(key_size == DTLS_EC_KEY_SIZE); + if (!uECC_make_key(pub_key, priv_key) + || !uECC_valid_public_key(pub_key)) { + dtls_crit("cannot generate ECC key pair\n"); + } + memcpy(pub_key_x, pub_key, key_size); + memcpy(pub_key_y, pub_key + key_size, key_size); } /* rfc4492#section-5.4 */ @@ -484,17 +481,15 @@ void dtls_ecdsa_create_sig_hash(const unsigned char *priv_key, size_t key_size, const unsigned char *sign_hash, size_t sign_hash_size, uint32_t point_r[9], uint32_t point_s[9]) { - int ret; - uint32_t priv[8]; - uint32_t hash[8]; - uint32_t randv[8]; - - dtls_ec_key_to_uint32(priv_key, key_size, priv); - dtls_ec_key_to_uint32(sign_hash, sign_hash_size, hash); - do { - dtls_prng((unsigned char *)randv, key_size); - ret = ecc_ecdsa_sign(priv, hash, randv, point_r, point_s); - } while (ret); + uint8_t sign[2 * DTLS_EC_KEY_SIZE]; + + assert(key_size == DTLS_EC_KEY_SIZE); + assert(sign_hash_size >= uECC_BYTES); + assert(sizeof(sign) >= 2 * uECC_BYTES); + uECC_sign(priv_key, sign_hash, sign); + + dtls_ec_key_to_uint32(sign, DTLS_EC_KEY_SIZE, point_r); + dtls_ec_key_to_uint32(sign + DTLS_EC_KEY_SIZE, DTLS_EC_KEY_SIZE, point_s); } void @@ -522,19 +517,20 @@ dtls_ecdsa_verify_sig_hash(const unsigned char *pub_key_x, const unsigned char *pub_key_y, size_t key_size, const unsigned char *sign_hash, size_t sign_hash_size, unsigned char *result_r, unsigned char *result_s) { - uint32_t pub_x[8]; - uint32_t pub_y[8]; - uint32_t hash[8]; - uint32_t point_r[8]; - uint32_t point_s[8]; - - dtls_ec_key_to_uint32(pub_key_x, key_size, pub_x); - dtls_ec_key_to_uint32(pub_key_y, key_size, pub_y); - dtls_ec_key_to_uint32(result_r, key_size, point_r); - dtls_ec_key_to_uint32(result_s, key_size, point_s); - dtls_ec_key_to_uint32(sign_hash, sign_hash_size, hash); - - return ecc_ecdsa_validate(pub_x, pub_y, hash, point_r, point_s); + uint8_t pub_key[2 * DTLS_EC_KEY_SIZE]; + uint8_t sign[2 * DTLS_EC_KEY_SIZE]; + (void)result_r; + (void)result_s; + + assert(key_size == DTLS_EC_KEY_SIZE); + assert(sign_hash_size >= uECC_BYTES); + assert(sizeof(sign) >= 2 * uECC_BYTES); + + /* clear sign to avoid maybe-unitialized warning */ + memset(sign, 0, sizeof(sign)); + memcpy(pub_key, pub_key_x, key_size); + memcpy(pub_key + key_size, pub_key_y, key_size); + return uECC_verify(pub_key, sign_hash, sign); } int From f8204f215c3ffd25b9ee653016483dd1c3fc237b Mon Sep 17 00:00:00 2001 From: Olaf Bergmann Date: Thu, 15 Feb 2024 16:28:57 +0100 Subject: [PATCH 15/17] [ECC] Add micro-ecc as submodule Add submodule ext/micro-ecc from https://github.com/kmackay/micro-ecc.git Change-Id: I17efa4c2fd9bd952b479bce32f0ebbb764301ca3 --- .gitmodules | 3 +++ ext/micro-ecc | 1 + 2 files changed, 4 insertions(+) create mode 100644 .gitmodules create mode 160000 ext/micro-ecc diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..c1d554b7 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "ext/micro-ecc"] + path = ext/micro-ecc + url = https://github.com/kmackay/micro-ecc.git diff --git a/ext/micro-ecc b/ext/micro-ecc new file mode 160000 index 00000000..fe8ed90a --- /dev/null +++ b/ext/micro-ecc @@ -0,0 +1 @@ +Subproject commit fe8ed90abc356347378eb25e2586e90df7be015a From 0e068ec031c76ce04d8f8d9ffa3e515340ac8534 Mon Sep 17 00:00:00 2001 From: Olaf Bergmann Date: Fri, 16 Feb 2024 16:59:48 +0100 Subject: [PATCH 16/17] Makefile.in: Add in micro-ecc dependencies Change-Id: I5bd1f510c162c5ef4432f5c9cb93836312706a74 --- Makefile.in | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Makefile.in b/Makefile.in index 09501190..3336c56c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -47,14 +47,16 @@ HEADERS:=dtls.h hmac.h dtls_debug.h dtls_config.h uthash.h numeric.h crypto.h gl netq.h alert.h utlist.h dtls_prng.h peer.h state.h dtls_time.h session.h \ tinydtls.h dtls_mutex.h PKG_CONFIG_FILES:=tinydtls.pc +__micro_ecc_path:=ext/micro-ecc +MICRO_ECC_FILES:=$(addprefix $(__micro_ecc_path)/, uECC.h uECC.c uECC_vli.h types.h) $(wildcard $(__micro_ecc_path)/*.inc) CFLAGS:=-Wall -pedantic -std=c99 -DSHA2_USE_INTTYPES_H @CFLAGS@ \ @WARNING_CFLAGS@ $(EXTRA_CFLAGS) CPPFLAGS:=@CPPFLAGS@ -DDTLS_CHECK_CONTENTTYPE -I$(top_srcdir) -SUBDIRS:=tests tests/unit-tests doc platform-specific sha2 aes ecc +SUBDIRS:=tests tests/unit-tests doc platform-specific sha2 aes DISTSUBDIRS:=$(SUBDIRS) DISTDIR=$(top_builddir)/$(package) FILES:=Makefile.in configure configure.ac dtls_config.h.in \ - Makefile.tinydtls $(SOURCES) $(HEADERS) + Makefile.tinydtls tinydtls.pc.in ar-lib $(SOURCES) $(HEADERS) $(MICRO_ECC_FILES) LIB:=libtinydtls LIBS:=$(LIB).a ifeq ("@ENABLE_SHARED@", "1") @@ -101,6 +103,9 @@ clean: done endif # WITH_CONTIKI +# Override several warnings for uECC.o +ext/micro-ecc/uECC.o:: CFLAGS+=-Wno-pedantic -Wno-unused-parameter -Wno-missing-prototypes -Wno-missing-declarations + doc: $(MAKE) -C doc @@ -110,7 +115,7 @@ distclean: clean dist: $(FILES) $(DISTSUBDIRS) test -d $(DISTDIR) || mkdir $(DISTDIR) - cp $(FILES) $(DISTDIR) + cp --parents $(FILES) $(DISTDIR) for dir in $(DISTSUBDIRS); do \ $(MAKE) -C $$dir dist; \ done From 3dc62b13038186f0e9201a476d42c9881601ceac Mon Sep 17 00:00:00 2001 From: Olaf Bergmann Date: Fri, 16 Feb 2024 17:03:41 +0100 Subject: [PATCH 17/17] crypto.[hc]: Use micro-ecc for ECC support This change provides support for the curve secp256r1 from micro-ecc. Change-Id: I2d272e2ddb498016a2d6e85af7af8247010768d8 --- crypto.c | 170 +++++++++++++++++++++++++++++++++++++++++++++---------- crypto.h | 78 ++++++++++++++++++++++++- 2 files changed, 215 insertions(+), 33 deletions(-) diff --git a/crypto.c b/crypto.c index bc07a8ac..1fe0807b 100644 --- a/crypto.c +++ b/crypto.c @@ -24,6 +24,7 @@ #else #define assert(x) #endif +#include #include "global.h" #include "dtls_debug.h" @@ -31,7 +32,9 @@ #include "dtls.h" #include "crypto.h" #include "ccm.h" -#include "ecc/micro-ecc/uECC.h" +#ifdef DTLS_ECC +#include "ext/micro-ecc/uECC.h" +#endif /* DTLS_ECC */ #include "dtls_prng.h" #include "netq.h" @@ -356,6 +359,10 @@ dtls_psk_pre_master_secret(unsigned char *key, size_t keylen, #endif /* DTLS_PSK */ #ifdef DTLS_ECC +#ifdef uECC_SUPPORTS_secp256r1 +const dtls_ecdh_curve default_curve = TLS_EXT_ELLIPTIC_CURVES_SECP256R1; +#endif /* uECC_SUPPORTS_secp256r1 */ + static void dtls_ec_key_to_uint32(const unsigned char *key, size_t key_size, uint32_t *result) { int i; @@ -432,32 +439,71 @@ int dtls_ec_key_asn1_from_uint32(const uint32_t *key, size_t key_size, return key_size + 2; } +static int get_uecc_curve(dtls_ecdh_curve curve, uECC_Curve *result) { + struct { + dtls_ecdh_curve curve; + uECC_Curve uecc_curve; + } known_curves[] = { +#if uECC_SUPPORTS_secp256r1 + { TLS_EXT_ELLIPTIC_CURVES_SECP256R1, uECC_secp256r1() }, +#endif /* uECC_SUPPORTS_secp256r1 */ + }; + unsigned int index; + + for (index = 0; index < sizeof(known_curves)/sizeof(known_curves[0]); index++) { + if (known_curves[index].curve == curve) { + *result = known_curves[index].uecc_curve; + return 1; + } + } + return 0; +} + +int dtls_ecdh_pre_master_secret2(const unsigned char *priv_key, + const unsigned char *pub_key, + size_t key_size, + dtls_ecdh_curve curve, + unsigned char *result, + size_t result_len) { + uECC_Curve uecc_curve; + if (!get_uecc_curve(curve, &uecc_curve)) { + dtls_warn("curve %" PRIu16 " not supported\n", curve); + return -1; + } + + if (result_len < key_size) { + return -1; + } + + if (!uECC_valid_public_key(pub_key, uecc_curve)) { + dtls_warn("invalid public key\n"); + } + + if (!uECC_shared_secret(pub_key, priv_key, result, uecc_curve)) { + dtls_warn("cannot generate ECDH shared secret\n"); + return 0; + } + + return key_size; +} + int dtls_ecdh_pre_master_secret(unsigned char *priv_key, unsigned char *pub_key_x, unsigned char *pub_key_y, size_t key_size, unsigned char *result, size_t result_len) { + const dtls_ecdh_curve curve = default_curve; uint8_t pub_key[2 * DTLS_EC_KEY_SIZE]; - uint8_t priv[DTLS_EC_KEY_SIZE]; if (result_len < key_size) { return -1; } - memcpy(priv, priv_key, DTLS_EC_KEY_SIZE); memcpy(pub_key, pub_key_x, DTLS_EC_KEY_SIZE); memcpy(pub_key + DTLS_EC_KEY_SIZE, pub_key_y, DTLS_EC_KEY_SIZE); - if (!uECC_valid_public_key(pub_key)) { - dtls_warn("invalid public key\n"); - } - - if (!uECC_shared_secret(pub_key, priv, result)) { - dtls_warn("cannot generate ECDH shared secret\n"); - return 0; - } - - return key_size; + return dtls_ecdh_pre_master_secret2(priv_key, pub_key, key_size, curve, + result, result_len); } void @@ -465,15 +511,36 @@ dtls_ecdsa_generate_key(unsigned char *priv_key, unsigned char *pub_key_x, unsigned char *pub_key_y, size_t key_size) { + const dtls_ecdh_curve curve = default_curve; uint8_t pub_key[2 * DTLS_EC_KEY_SIZE]; - assert(key_size == DTLS_EC_KEY_SIZE); - if (!uECC_make_key(pub_key, priv_key) - || !uECC_valid_public_key(pub_key)) { + int res = dtls_ecdsa_generate_key2(priv_key, pub_key, key_size, curve); + if (res > 0) { + memcpy(pub_key_x, pub_key, res); + memcpy(pub_key_y, pub_key + res, res); + } +} + +int +dtls_ecdsa_generate_key2(unsigned char *priv_key, + unsigned char *pub_key, + size_t key_size, + dtls_ecdh_curve curve) { + uECC_Curve uecc_curve; + if (!get_uecc_curve(curve, &uecc_curve)) { + dtls_warn("curve %" PRIu16 " not supported\n", curve); + return -1; + } + + assert(key_size >= (unsigned int)uECC_curve_private_key_size(uecc_curve)); + assert(2 * key_size >= (unsigned int)uECC_curve_public_key_size(uecc_curve)); + + if (!uECC_make_key(pub_key, priv_key, uecc_curve) + || !uECC_valid_public_key(pub_key, uecc_curve)) { dtls_crit("cannot generate ECC key pair\n"); + return 0; } - memcpy(pub_key_x, pub_key, key_size); - memcpy(pub_key_y, pub_key + key_size, key_size); + return uECC_curve_private_key_size(uecc_curve); } /* rfc4492#section-5.4 */ @@ -481,15 +548,39 @@ void dtls_ecdsa_create_sig_hash(const unsigned char *priv_key, size_t key_size, const unsigned char *sign_hash, size_t sign_hash_size, uint32_t point_r[9], uint32_t point_s[9]) { + const dtls_ecdh_curve curve = default_curve; + dtls_ecdsa_create_sig_hash2(priv_key, key_size, + sign_hash, sign_hash_size, + curve, point_r, point_s); + +} + +int +dtls_ecdsa_create_sig_hash2(const unsigned char *priv_key, size_t key_size, + const unsigned char *sign_hash, size_t sign_hash_size, + dtls_ecdh_curve curve, + uint32_t point_r[9], uint32_t point_s[9]) { uint8_t sign[2 * DTLS_EC_KEY_SIZE]; + uECC_Curve uecc_curve; + int curve_size; + if (!get_uecc_curve(curve, &uecc_curve)) { + dtls_warn("curve %" PRIu16 " not supported\n", curve); + return -1; + } + + curve_size = uECC_curve_private_key_size(uecc_curve); - assert(key_size == DTLS_EC_KEY_SIZE); - assert(sign_hash_size >= uECC_BYTES); - assert(sizeof(sign) >= 2 * uECC_BYTES); - uECC_sign(priv_key, sign_hash, sign); + assert(key_size >= (unsigned int)curve_size); + assert(sign_hash_size >= (unsigned int)curve_size); + assert(sizeof(sign) >= 2 * (unsigned int)curve_size); + if (!uECC_sign(priv_key, sign_hash, sign_hash_size, sign, uecc_curve)) { + dtls_warn("cannot create signature\n"); + return -1; + } - dtls_ec_key_to_uint32(sign, DTLS_EC_KEY_SIZE, point_r); - dtls_ec_key_to_uint32(sign + DTLS_EC_KEY_SIZE, DTLS_EC_KEY_SIZE, point_s); + dtls_ec_key_to_uint32(sign, curve_size, point_r); + dtls_ec_key_to_uint32(sign + curve_size, curve_size, point_s); + return 2 * curve_size; } void @@ -517,20 +608,39 @@ dtls_ecdsa_verify_sig_hash(const unsigned char *pub_key_x, const unsigned char *pub_key_y, size_t key_size, const unsigned char *sign_hash, size_t sign_hash_size, unsigned char *result_r, unsigned char *result_s) { + const dtls_ecdh_curve curve = default_curve; uint8_t pub_key[2 * DTLS_EC_KEY_SIZE]; + memcpy(pub_key, pub_key_x, key_size); + memcpy(pub_key + key_size, pub_key_y, key_size); + return dtls_ecdsa_verify_sig_hash2(pub_key, key_size, + sign_hash, sign_hash_size, + curve, + result_r, result_s); +} + +int +dtls_ecdsa_verify_sig_hash2(const unsigned char *pub_key, size_t key_size, + const unsigned char *sign_hash, size_t sign_hash_size, + dtls_ecdh_curve curve, + unsigned char *result_r, unsigned char *result_s) { uint8_t sign[2 * DTLS_EC_KEY_SIZE]; + uECC_Curve uecc_curve; + int curve_size; + if (!get_uecc_curve(curve, &uecc_curve)) { + dtls_warn("curve %" PRIu16 " not supported\n", curve); + return -1; + } (void)result_r; (void)result_s; - assert(key_size == DTLS_EC_KEY_SIZE); - assert(sign_hash_size >= uECC_BYTES); - assert(sizeof(sign) >= 2 * uECC_BYTES); + curve_size = uECC_curve_public_key_size(uecc_curve); + + assert(key_size == (unsigned int)curve_size); + assert(sizeof(sign) >= (unsigned int)curve_size); /* clear sign to avoid maybe-unitialized warning */ memset(sign, 0, sizeof(sign)); - memcpy(pub_key, pub_key_x, key_size); - memcpy(pub_key + key_size, pub_key_y, key_size); - return uECC_verify(pub_key, sign_hash, sign); + return uECC_verify(pub_key, sign_hash, sign_hash_size, sign, uecc_curve); } int diff --git a/crypto.h b/crypto.h index 6df46ff7..782f2331 100644 --- a/crypto.h +++ b/crypto.h @@ -60,9 +60,18 @@ typedef uint8_t dtls_cipher_index_t; typedef enum { AES128=0 } dtls_crypto_alg; -typedef enum { - DTLS_ECDH_CURVE_SECP256R1 -} dtls_ecdh_curve; +/** + * Curve type as specified in the TLS supported elliptic curves + * extension (@see [RFC 8422, Section 5.1.1](https://www.rfc-editor.org/rfc/rfc8422#section-5.1.1). + * + * The only supported value so far is TLS_EXT_ELLIPTIC_CURVES_SECP256R1 + */ +typedef uint16_t dtls_ecdh_curve; + +/** + * @deprecated {Defined for backwards compatibility.} + */ +#define DTLS_ECDH_CURVE_SECP256R1 TLS_EXT_ELLIPTIC_CURVES_SECP256R1 /** Crypto context for TLS_PSK_WITH_AES_128_CCM_8 cipher suite. */ typedef struct { @@ -454,15 +463,70 @@ int dtls_ecdh_pre_master_secret(unsigned char *priv_key, unsigned char *result, size_t result_len); +/** + * Generates the pre_master_sercet from given own private key @p + * priv_key and remote public key @p pub_key for the curve @p curve. + * This function returns the generated shared secret in @p result of + * size @p result_len. On success, the return value give the actual + * number of bytes written to @p result. The return @c 0 indicates + * an error. + * + * @param priv_key The own private key. The size of this key is + * defined by the selected @p curve and is passed + * in @p key_size. + * @param pub_key The remote public key. The size of this key is + * defined by the selected @p curve (usually twice + * @p key_size. + * @param key_size Length of @p priv_key in bytes. + * @param curve The elliptic curve to use. + * @param result The derived pre master secret. + * @param result_len The maximum length of the derived pre master secret. + * in @p result. + * @return The actual length of @p result or <= 0 on error. + */ +int dtls_ecdh_pre_master_secret2(const unsigned char *priv_key, + const unsigned char *pub_key, + size_t key_size, + dtls_ecdh_curve curve, + unsigned char *result, + size_t result_len); + void dtls_ecdsa_generate_key(unsigned char *priv_key, unsigned char *pub_key_x, unsigned char *pub_key_y, size_t key_size); +/** + * Generates a key pair for the given curve @p curve and stores the + * private part in @p priv_key and the public part in @p pub_key. The + * storage that must be provided for @p priv_key and @p pub_key is + * determined by @p curve. Usually, @p pub_key requires 2 * @p + * key_size. This function returns the actual number of bytes written + * into @p priv_key on success, or @c 0 otherwise. + * + * @param priv_key Storage for the generated private key. + * @param pub_key Storage for the generated public key. + * @param key_size The amount of storage for @p priv_key. + * @param curve Storage for the generated public key. + * @return The number of bytes written into @p priv_key, or @c 0 on error. + */ +int dtls_ecdsa_generate_key2(unsigned char *priv_key, + unsigned char *pub_key, + size_t key_size, + dtls_ecdh_curve curve); + void dtls_ecdsa_create_sig_hash(const unsigned char *priv_key, size_t key_size, const unsigned char *sign_hash, size_t sign_hash_size, uint32_t point_r[9], uint32_t point_s[9]); +/** + * FIXME: document function + */ +int dtls_ecdsa_create_sig_hash2(const unsigned char *priv_key, size_t key_size, + const unsigned char *sign_hash, size_t sign_hash_size, + dtls_ecdh_curve curve, + uint32_t point_r[9], uint32_t point_s[9]); + void dtls_ecdsa_create_sig(const unsigned char *priv_key, size_t key_size, const unsigned char *client_random, size_t client_random_size, const unsigned char *server_random, size_t server_random_size, @@ -474,6 +538,14 @@ int dtls_ecdsa_verify_sig_hash(const unsigned char *pub_key_x, const unsigned char *sign_hash, size_t sign_hash_size, unsigned char *result_r, unsigned char *result_s); +/** + * FIXME: document function + */ +int dtls_ecdsa_verify_sig_hash2(const unsigned char *pub_key, size_t key_size, + const unsigned char *sign_hash, size_t sign_hash_size, + dtls_ecdh_curve curve, + unsigned char *result_r, unsigned char *result_s); + int dtls_ecdsa_verify_sig(const unsigned char *pub_key_x, const unsigned char *pub_key_y, size_t key_size, const unsigned char *client_random, size_t client_random_size,