From f330e42e660eacbbf6d699005b2e9d5716384530 Mon Sep 17 00:00:00 2001 From: Achim Kraus Date: Mon, 28 Nov 2022 16:01:12 +0100 Subject: [PATCH] Add cipher suite selection to test applications. Signed-off-by: Achim Kraus --- tests/CMakeLists.txt | 4 +- tests/Makefile.in | 6 ++- tests/dtls-client.c | 49 +++++++++++++++++--- tests/dtls-server.c | 49 ++++++++++++++++---- tests/dtls_ciphers_util.c | 96 +++++++++++++++++++++++++++++++++++++++ tests/dtls_ciphers_util.h | 26 +++++++++++ 6 files changed, 211 insertions(+), 19 deletions(-) create mode 100644 tests/dtls_ciphers_util.c create mode 100644 tests/dtls_ciphers_util.h diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 06988ffd..5bf6f54a 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -23,7 +23,7 @@ cmake_minimum_required(VERSION 3.5) project(tinydtls-tests) -add_executable(dtls-server dtls-server.c) +add_executable(dtls-server dtls-server.c dtls_ciphers_util.c) target_link_libraries(dtls-server LINK_PUBLIC tinydtls) target_compile_options(dtls-server PUBLIC -Wall -DTEST_INCLUDE -DDTLSv12 -DWITH_SHA256) if(${WARNING_TO_ERROR}) @@ -37,7 +37,7 @@ if(${WARNING_TO_ERROR}) target_compile_options(ccm-test PUBLIC -Werror) endif() -add_executable(dtls-client dtls-client.c) +add_executable(dtls-client dtls-client.c dtls_ciphers_util.c) target_link_libraries(dtls-client LINK_PUBLIC tinydtls) target_compile_options(dtls-client PUBLIC -Wall -DTEST_INCLUDE -DDTLSv12 -DWITH_SHA256) if(${WARNING_TO_ERROR}) diff --git a/tests/Makefile.in b/tests/Makefile.in index a3097d92..f125db54 100644 --- a/tests/Makefile.in +++ b/tests/Makefile.in @@ -28,10 +28,10 @@ top_srcdir:= @top_srcdir@ # files and flags SOURCES:= dtls-server.c ccm-test.c \ - dtls-client.c + dtls-client.c dtls_ciphers_util.c #cbc_aes128-test.c #dsrv-test.c OBJECTS:= $(patsubst %.c, %.o, $(SOURCES)) -PROGRAMS:= $(patsubst %.c, %, $(SOURCES)) +PROGRAMS:= dtls-server dtls-client ccm-test HEADERS:= CFLAGS:=-Wall -std=c99 @CFLAGS@ @WARNING_CFLAGS@ $(EXTRA_CFLAGS) -D_GNU_SOURCE CPPFLAGS:=-I$(top_srcdir) @CPPFLAGS@ @@ -47,6 +47,8 @@ FILES:=Makefile.in $(SOURCES) ccm-testdata.c #cbc_aes128-testdata.c all: $(PROGRAMS) +dtls-client dtls-server:: dtls_ciphers_util.o + check: echo DISTDIR: $(DISTDIR) echo top_builddir: $(top_builddir) diff --git a/tests/dtls-client.c b/tests/dtls-client.c index e6a4c9c2..84c530c6 100644 --- a/tests/dtls-client.c +++ b/tests/dtls-client.c @@ -35,6 +35,7 @@ #include "global.h" #include "dtls_debug.h" +#include "dtls_ciphers_util.h" #include "dtls.h" #define DEFAULT_PORT 20220 @@ -59,6 +60,9 @@ static dtls_str output_file = { 0, NULL }; /* output file name */ static dtls_context_t *dtls_context = NULL; static dtls_context_t *orig_dtls_context = NULL; +static const dtls_cipher_t* ciphers = NULL; +static unsigned int force_extended_master_secret = 0; + #ifdef DTLS_ECC static const unsigned char ecdsa_priv_key[] = { @@ -228,6 +232,27 @@ send_to_peer(struct dtls_context_t *ctx, &session->addr.sa, session->size); } +static void +get_user_parameters(struct dtls_context_t *ctx, + session_t *session, dtls_user_parameters_t *user_parameters) { + (void) ctx; + (void) session; + user_parameters->force_extended_master_secret = force_extended_master_secret; + if (ciphers) { + int index = 0; + while (index < DTLS_MAX_CIPHER_SUITES) { + user_parameters->cipher_suites[index] = ciphers[index]; + if (ciphers[index] == TLS_NULL_WITH_NULL_NULL) { + break; + } + ++index; + } + if (index == DTLS_MAX_CIPHER_SUITES) { + user_parameters->cipher_suites[index] = TLS_NULL_WITH_NULL_NULL; + } + } +} + static int dtls_handle_read(struct dtls_context_t *ctx) { int fd; @@ -328,10 +353,13 @@ usage( const char *program, const char *version) { fprintf(stderr, "%s v%s -- DTLS client implementation\n" "(c) 2011-2014 Olaf Bergmann \n\n" #ifdef DTLS_PSK - "usage: %s [-i file] [-k file] [-o file] [-p port] [-v num] addr [port]\n" + "usage: %s [-c cipher suites] [-e] [-i file] [-k file] [-o file] [-p port] [-v num] addr [port]\n", #else /* DTLS_PSK */ - "usage: %s [-o file] [-p port] [-v num] addr [port]\n" + "usage: %s [-c cipher suites] [-e] [-o file] [-p port] [-v num] addr [port]\n", #endif /* DTLS_PSK */ + program, version, program); + cipher_suites_usage(stderr, "\t"); + fprintf(stderr, "\t-e\t\tforce extended master secret (RFC7627)\n" #ifdef DTLS_PSK "\t-i file\t\tread PSK identity from file\n" "\t-k file\t\tread pre-shared key from file\n" @@ -339,12 +367,13 @@ usage( const char *program, const char *version) { "\t-o file\t\toutput received data to this file (use '-' for STDOUT)\n" "\t-p port\t\tlisten on specified port (default is %d)\n" "\t-v num\t\tverbosity level (default: 3)\n", - program, version, program, DEFAULT_PORT); + DEFAULT_PORT); } static dtls_handler_t cb = { .write = send_to_peer, .read = read_from_peer, + .get_user_parameters = get_user_parameters, .event = NULL, #ifdef DTLS_PSK .get_psk_info = get_psk_info, @@ -393,7 +422,7 @@ main(int argc, char **argv) { memcpy(psk_key, PSK_DEFAULT_KEY, psk_key_length); #endif /* DTLS_PSK */ - while ((opt = getopt(argc, argv, "p:o:v:" PSK_OPTIONS)) != -1) { + while ((opt = getopt(argc, argv, "c:eo:p:v:" PSK_OPTIONS)) != -1) { switch (opt) { #ifdef DTLS_PSK case 'i' : @@ -413,9 +442,11 @@ main(int argc, char **argv) { } break; #endif /* DTLS_PSK */ - case 'p' : - strncpy(port_str, optarg, NI_MAXSERV-1); - port_str[NI_MAXSERV - 1] = '\0'; + case 'c' : + ciphers = init_cipher_suites(optarg); + break; + case 'e' : + force_extended_master_secret = 1; break; case 'o' : output_file.length = strlen(optarg); @@ -429,6 +460,10 @@ main(int argc, char **argv) { memcpy(output_file.s, optarg, output_file.length + 1); } break; + case 'p' : + strncpy(port_str, optarg, NI_MAXSERV-1); + port_str[NI_MAXSERV - 1] = '\0'; + break; case 'v' : log_level = strtol(optarg, NULL, 10); break; diff --git a/tests/dtls-server.c b/tests/dtls-server.c index 5a3c03c4..309f0b5c 100644 --- a/tests/dtls-server.c +++ b/tests/dtls-server.c @@ -27,8 +27,9 @@ #include #include "tinydtls.h" -#include "dtls.h" #include "dtls_debug.h" +#include "dtls_ciphers_util.h" +#include "dtls.h" #ifdef IS_WINDOWS #include @@ -44,6 +45,9 @@ #define DEFAULT_PORT 20220 static dtls_context_t *the_context = NULL; +static volatile int cmd_exit = 0; +static const dtls_cipher_t* ciphers = NULL; +static unsigned int force_extended_master_secret = 0; #ifdef DTLS_ECC static const unsigned char ecdsa_priv_key[] = { @@ -151,8 +155,6 @@ verify_ecdsa_key(struct dtls_context_t *ctx, #define DTLS_SERVER_CMD_CLOSE "server:close" #define DTLS_SERVER_CMD_EXIT "server:exit" -static volatile int cmd_exit = 0; - static int is_command(const char* cmd, const uint8 *data, size_t len) { size_t cmd_len = strlen(cmd); @@ -191,6 +193,27 @@ send_to_peer(struct dtls_context_t *ctx, &session->addr.sa, session->size); } +static void +get_user_parameters(struct dtls_context_t *ctx, + session_t *session, dtls_user_parameters_t *user_parameters) { + (void) ctx; + (void) session; + user_parameters->force_extended_master_secret = force_extended_master_secret; + if (ciphers) { + int index = 0; + while (index < DTLS_MAX_CIPHER_SUITES) { + user_parameters->cipher_suites[index] = ciphers[index]; + if (ciphers[index] == TLS_NULL_WITH_NULL_NULL) { + break; + } + ++index; + } + if (index == DTLS_MAX_CIPHER_SUITES) { + user_parameters->cipher_suites[index] = TLS_NULL_WITH_NULL_NULL; + } + } +} + static int dtls_handle_read(struct dtls_context_t *ctx) { int *fd; @@ -283,17 +306,21 @@ 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" - "usage: %s [-A address] [-p port] [-v num]\n" - "\t-A address\t\tlisten on specified address (default is ::)\n" + "(c) 2011-2014 Olaf Bergmann \n\n" + "usage: %s [-A address] [-c cipher suites] [-e] [-p port] [-v num]\n" + "\t-A address\t\tlisten on specified address (default is ::)\n", + program, version, program); + cipher_suites_usage(stderr, "\t"); + fprintf(stderr, "\t-e\t\tforce extended master secret (RFC7627)\n" "\t-p port\t\tlisten on specified port (default is %d)\n" "\t-v num\t\tverbosity level (default: 3)\n", - program, version, program, DEFAULT_PORT); + DEFAULT_PORT); } static dtls_handler_t cb = { .write = send_to_peer, .read = read_from_peer, + .get_user_parameters = get_user_parameters, .event = NULL, #ifdef DTLS_PSK .get_psk_info = get_psk_info, @@ -328,7 +355,7 @@ main(int argc, char **argv) { listen_addr.sin6_family = AF_INET6; listen_addr.sin6_addr = in6addr_any; - while ((opt = getopt(argc, argv, "A:p:v:")) != -1) { + while ((opt = getopt(argc, argv, "A:c:ep:v:")) != -1) { switch (opt) { case 'A' : if (resolve_address(optarg, (struct sockaddr *)&listen_addr) < 0) { @@ -336,6 +363,12 @@ main(int argc, char **argv) { exit(-1); } break; + case 'c' : + ciphers = init_cipher_suites(optarg); + break; + case 'e' : + force_extended_master_secret = 1; + break; case 'p' : port = htons(atoi(optarg)); break; diff --git a/tests/dtls_ciphers_util.c b/tests/dtls_ciphers_util.c new file mode 100644 index 00000000..d9d548df --- /dev/null +++ b/tests/dtls_ciphers_util.c @@ -0,0 +1,96 @@ +/******************************************************************************* + * + * Copyright (c) 2022 Contributors to the Eclipse Foundation. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. + * + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *******************************************************************************/ + +#include +#include + +#include "dtls_ciphers_util.h" + + +struct cipher_entry { + const char* name; + const dtls_cipher_t cipher; +}; + +#define CIPHER_ENTRY(X) { .name = #X, .cipher = X } +#define ARRAY_LENGTH (sizeof(map)/sizeof(struct cipher_entry)) +#define SEP ':' + +static const struct cipher_entry map[] = { +#ifdef DTLS_PSK + CIPHER_ENTRY(TLS_PSK_WITH_AES_128_CCM), + CIPHER_ENTRY(TLS_PSK_WITH_AES_128_CCM_8), +#endif /* DTLS_PSK */ +#ifdef DTLS_ECC + CIPHER_ENTRY(TLS_ECDHE_ECDSA_WITH_AES_128_CCM), + CIPHER_ENTRY(TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8), +#endif /* DTLS_ECC */ + { .name = NULL, .cipher = TLS_NULL_WITH_NULL_NULL} +}; + +static dtls_cipher_t ciphers_table[ARRAY_LENGTH] = { TLS_NULL_WITH_NULL_NULL }; + +static dtls_cipher_t find_cipher_suite(const char *arg) { + if (arg) { + size_t arg_len = strlen(arg); + for (size_t index=0; index < ARRAY_LENGTH - 1; ++index) { + size_t len = strlen(map[index].name); + if (len <= arg_len) { + if (strncmp(arg, map[index].name, len) == 0 && (arg[len] == 0 || arg[len] == SEP)) { + return map[index].cipher; + } + } + } + } + return TLS_NULL_WITH_NULL_NULL; +} + +static void add_cipher_suite(dtls_cipher_t cipher) { + for (size_t index=0; index < ARRAY_LENGTH - 1; ++index) { + if (ciphers_table[index] == cipher) { + return; + } + if (ciphers_table[index] == TLS_NULL_WITH_NULL_NULL) { + ciphers_table[index] = cipher; + ciphers_table[index + 1] = TLS_NULL_WITH_NULL_NULL; + return; + } + } +} + +const dtls_cipher_t* +init_cipher_suites(const char* arg) { + while (arg) { + dtls_cipher_t cipher = find_cipher_suite(arg); + if (cipher != TLS_NULL_WITH_NULL_NULL) { + add_cipher_suite(cipher); + } + arg = strchr(arg, SEP); + if (arg) { + ++arg; + } + } + return ciphers_table; +} + +void +cipher_suites_usage(FILE* file, const char* head) { + fprintf(file, "%s-c ciphers\tlist of cipher suites separated by ':'\n", head); + fprintf(file, "%s\t\t(default is %s", head, map[0].name); + for (int index = 1; map[index].name; ++index) { + fprintf(file, "\n%s\t\t :%s", head, map[index].name); + } + fprintf(file, ")\n"); +} + diff --git a/tests/dtls_ciphers_util.h b/tests/dtls_ciphers_util.h new file mode 100644 index 00000000..80f4c63f --- /dev/null +++ b/tests/dtls_ciphers_util.h @@ -0,0 +1,26 @@ +/******************************************************************************* + * + * Copyright (c) 2022 Contributors to the Eclipse Foundation. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * and Eclipse Distribution License v. 1.0 which accompanies this distribution. + * + * The Eclipse Public License is available at http://www.eclipse.org/legal/epl-v10.html + * and the Eclipse Distribution License is available at + * http://www.eclipse.org/org/documents/edl-v10.php. + * + *******************************************************************************/ + +#ifndef _DTLS_CIPHERS_UTIL_H_ +#define _DTLS_CIPHERS_UTIL_H_ + +#include + +#include "global.h" + +const dtls_cipher_t* init_cipher_suites(const char* arg); + +void cipher_suites_usage(FILE* file, const char* head); + +#endif /* _DTLS_CIPHERS_UTIL_H_ */