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