1/* 2 * Simple DTLS client demonstration program 3 * 4 * Copyright The Mbed TLS Contributors 5 * SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 6 */ 7 8#include "mbedtls/build_info.h" 9 10#include "mbedtls/platform.h" 11 12#if !defined(MBEDTLS_SSL_CLI_C) || !defined(MBEDTLS_SSL_PROTO_DTLS) || \ 13 !defined(MBEDTLS_NET_C) || !defined(MBEDTLS_TIMING_C) || \ 14 !defined(MBEDTLS_ENTROPY_C) || !defined(MBEDTLS_CTR_DRBG_C) || \ 15 !defined(MBEDTLS_X509_CRT_PARSE_C) || !defined(MBEDTLS_RSA_C) || \ 16 !defined(MBEDTLS_PEM_PARSE_C) 17int main(void) 18{ 19 mbedtls_printf("MBEDTLS_SSL_CLI_C and/or MBEDTLS_SSL_PROTO_DTLS and/or " 20 "MBEDTLS_NET_C and/or MBEDTLS_TIMING_C and/or " 21 "MBEDTLS_ENTROPY_C and/or MBEDTLS_CTR_DRBG_C and/or " 22 "MBEDTLS_X509_CRT_PARSE_C and/or MBEDTLS_RSA_C and/or " 23 "MBEDTLS_PEM_PARSE_C not defined.\n"); 24 mbedtls_exit(0); 25} 26#else 27 28#include <string.h> 29 30#include "mbedtls/net_sockets.h" 31#include "mbedtls/debug.h" 32#include "mbedtls/ssl.h" 33#include "mbedtls/entropy.h" 34#include "mbedtls/ctr_drbg.h" 35#include "mbedtls/error.h" 36#include "mbedtls/timing.h" 37#include "test/certs.h" 38 39/* Uncomment out the following line to default to IPv4 and disable IPv6 */ 40//#define FORCE_IPV4 41 42#define SERVER_PORT "4433" 43#define SERVER_NAME "localhost" 44 45#ifdef FORCE_IPV4 46#define SERVER_ADDR "127.0.0.1" /* Forces IPv4 */ 47#else 48#define SERVER_ADDR "::1" 49#endif 50 51#define MESSAGE "Echo this" 52 53#define READ_TIMEOUT_MS 1000 54#define MAX_RETRY 5 55 56#define DEBUG_LEVEL 0 57 58 59static void my_debug(void *ctx, int level, 60 const char *file, int line, 61 const char *str) 62{ 63 ((void) level); 64 65 mbedtls_fprintf((FILE *) ctx, "%s:%04d: %s", file, line, str); 66 fflush((FILE *) ctx); 67} 68 69int main(int argc, char *argv[]) 70{ 71 int ret, len; 72 mbedtls_net_context server_fd; 73 uint32_t flags; 74 unsigned char buf[1024]; 75 const char *pers = "dtls_client"; 76 int retry_left = MAX_RETRY; 77 78 mbedtls_entropy_context entropy; 79 mbedtls_ctr_drbg_context ctr_drbg; 80 mbedtls_ssl_context ssl; 81 mbedtls_ssl_config conf; 82 mbedtls_x509_crt cacert; 83 mbedtls_timing_delay_context timer; 84 85 ((void) argc); 86 ((void) argv); 87 88#if defined(MBEDTLS_DEBUG_C) 89 mbedtls_debug_set_threshold(DEBUG_LEVEL); 90#endif 91 92 /* 93 * 0. Initialize the RNG and the session data 94 */ 95 mbedtls_net_init(&server_fd); 96 mbedtls_ssl_init(&ssl); 97 mbedtls_ssl_config_init(&conf); 98 mbedtls_x509_crt_init(&cacert); 99 mbedtls_ctr_drbg_init(&ctr_drbg); 100 mbedtls_entropy_init(&entropy); 101 102#if defined(MBEDTLS_USE_PSA_CRYPTO) 103 psa_status_t status = psa_crypto_init(); 104 if (status != PSA_SUCCESS) { 105 mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n", 106 (int) status); 107 ret = MBEDTLS_ERR_SSL_HW_ACCEL_FAILED; 108 goto exit; 109 } 110#endif /* MBEDTLS_USE_PSA_CRYPTO */ 111 112 mbedtls_printf("\n . Seeding the random number generator..."); 113 fflush(stdout); 114 115 if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, 116 (const unsigned char *) pers, 117 strlen(pers))) != 0) { 118 mbedtls_printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret); 119 goto exit; 120 } 121 122 mbedtls_printf(" ok\n"); 123 124 /* 125 * 0. Load certificates 126 */ 127 mbedtls_printf(" . Loading the CA root certificate ..."); 128 fflush(stdout); 129 130 ret = mbedtls_x509_crt_parse(&cacert, (const unsigned char *) mbedtls_test_cas_pem, 131 mbedtls_test_cas_pem_len); 132 if (ret < 0) { 133 mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", 134 (unsigned int) -ret); 135 goto exit; 136 } 137 138 mbedtls_printf(" ok (%d skipped)\n", ret); 139 140 /* 141 * 1. Start the connection 142 */ 143 mbedtls_printf(" . Connecting to udp/%s/%s...", SERVER_NAME, SERVER_PORT); 144 fflush(stdout); 145 146 if ((ret = mbedtls_net_connect(&server_fd, SERVER_ADDR, 147 SERVER_PORT, MBEDTLS_NET_PROTO_UDP)) != 0) { 148 mbedtls_printf(" failed\n ! mbedtls_net_connect returned %d\n\n", ret); 149 goto exit; 150 } 151 152 mbedtls_printf(" ok\n"); 153 154 /* 155 * 2. Setup stuff 156 */ 157 mbedtls_printf(" . Setting up the DTLS structure..."); 158 fflush(stdout); 159 160 if ((ret = mbedtls_ssl_config_defaults(&conf, 161 MBEDTLS_SSL_IS_CLIENT, 162 MBEDTLS_SSL_TRANSPORT_DATAGRAM, 163 MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { 164 mbedtls_printf(" failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret); 165 goto exit; 166 } 167 168 /* OPTIONAL is usually a bad choice for security, but makes interop easier 169 * in this simplified example, in which the ca chain is hardcoded. 170 * Production code should set a proper ca chain and use REQUIRED. */ 171 mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL); 172 mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL); 173 mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); 174 mbedtls_ssl_conf_dbg(&conf, my_debug, stdout); 175 mbedtls_ssl_conf_read_timeout(&conf, READ_TIMEOUT_MS); 176 177 if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) { 178 mbedtls_printf(" failed\n ! mbedtls_ssl_setup returned %d\n\n", ret); 179 goto exit; 180 } 181 182 if ((ret = mbedtls_ssl_set_hostname(&ssl, SERVER_NAME)) != 0) { 183 mbedtls_printf(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret); 184 goto exit; 185 } 186 187 mbedtls_ssl_set_bio(&ssl, &server_fd, 188 mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout); 189 190 mbedtls_ssl_set_timer_cb(&ssl, &timer, mbedtls_timing_set_delay, 191 mbedtls_timing_get_delay); 192 193 mbedtls_printf(" ok\n"); 194 195 /* 196 * 4. Handshake 197 */ 198 mbedtls_printf(" . Performing the DTLS handshake..."); 199 fflush(stdout); 200 201 do { 202 ret = mbedtls_ssl_handshake(&ssl); 203 } while (ret == MBEDTLS_ERR_SSL_WANT_READ || 204 ret == MBEDTLS_ERR_SSL_WANT_WRITE); 205 206 if (ret != 0) { 207 mbedtls_printf(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", 208 (unsigned int) -ret); 209 goto exit; 210 } 211 212 mbedtls_printf(" ok\n"); 213 214 /* 215 * 5. Verify the server certificate 216 */ 217 mbedtls_printf(" . Verifying peer X.509 certificate..."); 218 219 /* In real life, we would have used MBEDTLS_SSL_VERIFY_REQUIRED so that the 220 * handshake would not succeed if the peer's cert is bad. Even if we used 221 * MBEDTLS_SSL_VERIFY_OPTIONAL, we would bail out here if ret != 0 */ 222 if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) { 223#if !defined(MBEDTLS_X509_REMOVE_INFO) 224 char vrfy_buf[512]; 225#endif 226 227 mbedtls_printf(" failed\n"); 228 229#if !defined(MBEDTLS_X509_REMOVE_INFO) 230 mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags); 231 232 mbedtls_printf("%s\n", vrfy_buf); 233#endif 234 } else { 235 mbedtls_printf(" ok\n"); 236 } 237 238 /* 239 * 6. Write the echo request 240 */ 241send_request: 242 mbedtls_printf(" > Write to server:"); 243 fflush(stdout); 244 245 len = sizeof(MESSAGE) - 1; 246 247 do { 248 ret = mbedtls_ssl_write(&ssl, (unsigned char *) MESSAGE, len); 249 } while (ret == MBEDTLS_ERR_SSL_WANT_READ || 250 ret == MBEDTLS_ERR_SSL_WANT_WRITE); 251 252 if (ret < 0) { 253 mbedtls_printf(" failed\n ! mbedtls_ssl_write returned %d\n\n", ret); 254 goto exit; 255 } 256 257 len = ret; 258 mbedtls_printf(" %d bytes written\n\n%s\n\n", len, MESSAGE); 259 260 /* 261 * 7. Read the echo response 262 */ 263 mbedtls_printf(" < Read from server:"); 264 fflush(stdout); 265 266 len = sizeof(buf) - 1; 267 memset(buf, 0, sizeof(buf)); 268 269 do { 270 ret = mbedtls_ssl_read(&ssl, buf, len); 271 } while (ret == MBEDTLS_ERR_SSL_WANT_READ || 272 ret == MBEDTLS_ERR_SSL_WANT_WRITE); 273 274 if (ret <= 0) { 275 switch (ret) { 276 case MBEDTLS_ERR_SSL_TIMEOUT: 277 mbedtls_printf(" timeout\n\n"); 278 if (retry_left-- > 0) { 279 goto send_request; 280 } 281 goto exit; 282 283 case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: 284 mbedtls_printf(" connection was closed gracefully\n"); 285 goto close_notify; 286 287 default: 288 mbedtls_printf(" mbedtls_ssl_read returned -0x%x\n\n", (unsigned int) -ret); 289 goto exit; 290 } 291 } 292 293 len = ret; 294 mbedtls_printf(" %d bytes read\n\n%s\n\n", len, buf); 295 296 /* 297 * 8. Done, cleanly close the connection 298 */ 299close_notify: 300 mbedtls_printf(" . Closing the connection..."); 301 302 /* No error checking, the connection might be closed already */ 303 do { 304 ret = mbedtls_ssl_close_notify(&ssl); 305 } while (ret == MBEDTLS_ERR_SSL_WANT_WRITE); 306 ret = 0; 307 308 mbedtls_printf(" done\n"); 309 310 /* 311 * 9. Final clean-ups and exit 312 */ 313exit: 314 315#ifdef MBEDTLS_ERROR_C 316 if (ret != 0) { 317 char error_buf[100]; 318 mbedtls_strerror(ret, error_buf, 100); 319 mbedtls_printf("Last error was: %d - %s\n\n", ret, error_buf); 320 } 321#endif 322 323 mbedtls_net_free(&server_fd); 324 mbedtls_x509_crt_free(&cacert); 325 mbedtls_ssl_free(&ssl); 326 mbedtls_ssl_config_free(&conf); 327 mbedtls_ctr_drbg_free(&ctr_drbg); 328 mbedtls_entropy_free(&entropy); 329#if defined(MBEDTLS_USE_PSA_CRYPTO) 330 mbedtls_psa_crypto_free(); 331#endif /* MBEDTLS_USE_PSA_CRYPTO */ 332 333 /* Shell can not handle large exit numbers -> 1 for errors */ 334 if (ret < 0) { 335 ret = 1; 336 } 337 338 mbedtls_exit(ret); 339} 340#endif /* MBEDTLS_SSL_CLI_C && MBEDTLS_SSL_PROTO_DTLS && MBEDTLS_NET_C && 341 MBEDTLS_TIMING_C && MBEDTLS_ENTROPY_C && MBEDTLS_CTR_DRBG_C && 342 MBEDTLS_X509_CRT_PARSE_C && MBEDTLS_RSA_C && MBEDTLS_PEM_PARSE_C */ 343