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