1/* 2 * SSL 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_BIGNUM_C) || !defined(MBEDTLS_ENTROPY_C) || \ 13 !defined(MBEDTLS_SSL_TLS_C) || !defined(MBEDTLS_SSL_CLI_C) || \ 14 !defined(MBEDTLS_NET_C) || !defined(MBEDTLS_RSA_C) || \ 15 !defined(MBEDTLS_PEM_PARSE_C) || !defined(MBEDTLS_CTR_DRBG_C) || \ 16 !defined(MBEDTLS_X509_CRT_PARSE_C) 17int main(void) 18{ 19 mbedtls_printf("MBEDTLS_BIGNUM_C and/or MBEDTLS_ENTROPY_C and/or " 20 "MBEDTLS_SSL_TLS_C and/or MBEDTLS_SSL_CLI_C and/or " 21 "MBEDTLS_NET_C and/or MBEDTLS_RSA_C and/or " 22 "MBEDTLS_CTR_DRBG_C and/or MBEDTLS_X509_CRT_PARSE_C " 23 "not defined.\n"); 24 mbedtls_exit(0); 25} 26#else 27 28#include "mbedtls/net_sockets.h" 29#include "mbedtls/debug.h" 30#include "mbedtls/ssl.h" 31#include "mbedtls/entropy.h" 32#include "mbedtls/ctr_drbg.h" 33#include "mbedtls/error.h" 34#include "test/certs.h" 35 36#include <string.h> 37 38#define SERVER_PORT "4433" 39#define SERVER_NAME "localhost" 40#define GET_REQUEST "GET / HTTP/1.0\r\n\r\n" 41 42#define DEBUG_LEVEL 1 43 44 45static void my_debug(void *ctx, int level, 46 const char *file, int line, 47 const char *str) 48{ 49 ((void) level); 50 51 mbedtls_fprintf((FILE *) ctx, "%s:%04d: %s", file, line, str); 52 fflush((FILE *) ctx); 53} 54 55int main(void) 56{ 57 int ret = 1, len; 58 int exit_code = MBEDTLS_EXIT_FAILURE; 59 mbedtls_net_context server_fd; 60 uint32_t flags; 61 unsigned char buf[1024]; 62 const char *pers = "ssl_client1"; 63 64 mbedtls_entropy_context entropy; 65 mbedtls_ctr_drbg_context ctr_drbg; 66 mbedtls_ssl_context ssl; 67 mbedtls_ssl_config conf; 68 mbedtls_x509_crt cacert; 69 70#if defined(MBEDTLS_DEBUG_C) 71 mbedtls_debug_set_threshold(DEBUG_LEVEL); 72#endif 73 74 /* 75 * 0. Initialize the RNG and the session data 76 */ 77 mbedtls_net_init(&server_fd); 78 mbedtls_ssl_init(&ssl); 79 mbedtls_ssl_config_init(&conf); 80 mbedtls_x509_crt_init(&cacert); 81 mbedtls_ctr_drbg_init(&ctr_drbg); 82 mbedtls_entropy_init(&entropy); 83 84#if defined(MBEDTLS_USE_PSA_CRYPTO) 85 psa_status_t status = psa_crypto_init(); 86 if (status != PSA_SUCCESS) { 87 mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n", 88 (int) status); 89 goto exit; 90 } 91#endif /* MBEDTLS_USE_PSA_CRYPTO */ 92 93 mbedtls_printf("\n . Seeding the random number generator..."); 94 fflush(stdout); 95 96 97 if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, 98 (const unsigned char *) pers, 99 strlen(pers))) != 0) { 100 mbedtls_printf(" failed\n ! mbedtls_ctr_drbg_seed returned %d\n", ret); 101 goto exit; 102 } 103 104 mbedtls_printf(" ok\n"); 105 106 /* 107 * 0. Initialize certificates 108 */ 109 mbedtls_printf(" . Loading the CA root certificate ..."); 110 fflush(stdout); 111 112 ret = mbedtls_x509_crt_parse(&cacert, (const unsigned char *) mbedtls_test_cas_pem, 113 mbedtls_test_cas_pem_len); 114 if (ret < 0) { 115 mbedtls_printf(" failed\n ! mbedtls_x509_crt_parse returned -0x%x\n\n", 116 (unsigned int) -ret); 117 goto exit; 118 } 119 120 mbedtls_printf(" ok (%d skipped)\n", ret); 121 122 /* 123 * 1. Start the connection 124 */ 125 mbedtls_printf(" . Connecting to tcp/%s/%s...", SERVER_NAME, SERVER_PORT); 126 fflush(stdout); 127 128 if ((ret = mbedtls_net_connect(&server_fd, SERVER_NAME, 129 SERVER_PORT, MBEDTLS_NET_PROTO_TCP)) != 0) { 130 mbedtls_printf(" failed\n ! mbedtls_net_connect returned %d\n\n", ret); 131 goto exit; 132 } 133 134 mbedtls_printf(" ok\n"); 135 136 /* 137 * 2. Setup stuff 138 */ 139 mbedtls_printf(" . Setting up the SSL/TLS structure..."); 140 fflush(stdout); 141 142 if ((ret = mbedtls_ssl_config_defaults(&conf, 143 MBEDTLS_SSL_IS_CLIENT, 144 MBEDTLS_SSL_TRANSPORT_STREAM, 145 MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { 146 mbedtls_printf(" failed\n ! mbedtls_ssl_config_defaults returned %d\n\n", ret); 147 goto exit; 148 } 149 150 mbedtls_printf(" ok\n"); 151 152 /* OPTIONAL is not optimal for security, 153 * but makes interop easier in this simplified example */ 154 mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL); 155 mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL); 156 mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); 157 mbedtls_ssl_conf_dbg(&conf, my_debug, stdout); 158 159 if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) { 160 mbedtls_printf(" failed\n ! mbedtls_ssl_setup returned %d\n\n", ret); 161 goto exit; 162 } 163 164 if ((ret = mbedtls_ssl_set_hostname(&ssl, SERVER_NAME)) != 0) { 165 mbedtls_printf(" failed\n ! mbedtls_ssl_set_hostname returned %d\n\n", ret); 166 goto exit; 167 } 168 169 mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, NULL); 170 171 /* 172 * 4. Handshake 173 */ 174 mbedtls_printf(" . Performing the SSL/TLS handshake..."); 175 fflush(stdout); 176 177 while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) { 178 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { 179 mbedtls_printf(" failed\n ! mbedtls_ssl_handshake returned -0x%x\n\n", 180 (unsigned int) -ret); 181 goto exit; 182 } 183 } 184 185 mbedtls_printf(" ok\n"); 186 187 /* 188 * 5. Verify the server certificate 189 */ 190 mbedtls_printf(" . Verifying peer X.509 certificate..."); 191 192 /* In real life, we probably want to bail out when ret != 0 */ 193 if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) { 194#if !defined(MBEDTLS_X509_REMOVE_INFO) 195 char vrfy_buf[512]; 196#endif 197 198 mbedtls_printf(" failed\n"); 199 200#if !defined(MBEDTLS_X509_REMOVE_INFO) 201 mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), " ! ", flags); 202 203 mbedtls_printf("%s\n", vrfy_buf); 204#endif 205 } else { 206 mbedtls_printf(" ok\n"); 207 } 208 209 /* 210 * 3. Write the GET request 211 */ 212 mbedtls_printf(" > Write to server:"); 213 fflush(stdout); 214 215 len = sprintf((char *) buf, GET_REQUEST); 216 217 while ((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0) { 218 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { 219 mbedtls_printf(" failed\n ! mbedtls_ssl_write returned %d\n\n", ret); 220 goto exit; 221 } 222 } 223 224 len = ret; 225 mbedtls_printf(" %d bytes written\n\n%s", len, (char *) buf); 226 227 /* 228 * 7. Read the HTTP response 229 */ 230 mbedtls_printf(" < Read from server:"); 231 fflush(stdout); 232 233 do { 234 len = sizeof(buf) - 1; 235 memset(buf, 0, sizeof(buf)); 236 ret = mbedtls_ssl_read(&ssl, buf, len); 237 238 if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) { 239 continue; 240 } 241 242 if (ret == MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY) { 243 break; 244 } 245 246 if (ret < 0) { 247 mbedtls_printf("failed\n ! mbedtls_ssl_read returned %d\n\n", ret); 248 break; 249 } 250 251 if (ret == 0) { 252 mbedtls_printf("\n\nEOF\n\n"); 253 break; 254 } 255 256 len = ret; 257 mbedtls_printf(" %d bytes read\n\n%s", len, (char *) buf); 258 } while (1); 259 260 mbedtls_ssl_close_notify(&ssl); 261 262 exit_code = MBEDTLS_EXIT_SUCCESS; 263 264exit: 265 266#ifdef MBEDTLS_ERROR_C 267 if (exit_code != MBEDTLS_EXIT_SUCCESS) { 268 char error_buf[100]; 269 mbedtls_strerror(ret, error_buf, 100); 270 mbedtls_printf("Last error was: %d - %s\n\n", ret, error_buf); 271 } 272#endif 273 274 mbedtls_net_free(&server_fd); 275 mbedtls_x509_crt_free(&cacert); 276 mbedtls_ssl_free(&ssl); 277 mbedtls_ssl_config_free(&conf); 278 mbedtls_ctr_drbg_free(&ctr_drbg); 279 mbedtls_entropy_free(&entropy); 280#if defined(MBEDTLS_USE_PSA_CRYPTO) 281 mbedtls_psa_crypto_free(); 282#endif /* MBEDTLS_USE_PSA_CRYPTO */ 283 284 mbedtls_exit(exit_code); 285} 286#endif /* MBEDTLS_BIGNUM_C && MBEDTLS_ENTROPY_C && MBEDTLS_SSL_TLS_C && 287 MBEDTLS_SSL_CLI_C && MBEDTLS_NET_C && MBEDTLS_RSA_C && 288 MBEDTLS_PEM_PARSE_C && MBEDTLS_CTR_DRBG_C && MBEDTLS_X509_CRT_PARSE_C */ 289