ssl_fork_server.c (11819B)
1 /* 2 * SSL server demonstration program using fork() for handling multiple clients 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_SRV_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_SRV_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 #elif defined(_WIN32) 24 int main(void) 25 { 26 mbedtls_printf("_WIN32 defined. This application requires fork() and signals " 27 "to work correctly.\n"); 28 mbedtls_exit(0); 29 } 30 #else 31 32 #include "mbedtls/entropy.h" 33 #include "mbedtls/ctr_drbg.h" 34 #include "test/certs.h" 35 #include "mbedtls/x509.h" 36 #include "mbedtls/ssl.h" 37 #include "mbedtls/net_sockets.h" 38 #include "mbedtls/timing.h" 39 40 #include <string.h> 41 #include <signal.h> 42 43 #if !defined(_MSC_VER) || defined(EFIX64) || defined(EFI32) 44 #include <unistd.h> 45 #endif 46 47 #define HTTP_RESPONSE \ 48 "HTTP/1.0 200 OK\r\nContent-Type: text/html\r\n\r\n" \ 49 "<h2>Mbed TLS Test Server</h2>\r\n" \ 50 "<p>Successful connection using: %s</p>\r\n" 51 52 #define DEBUG_LEVEL 0 53 54 55 static void my_debug(void *ctx, int level, 56 const char *file, int line, 57 const char *str) 58 { 59 ((void) level); 60 61 mbedtls_fprintf((FILE *) ctx, "%s:%04d: %s", file, line, str); 62 fflush((FILE *) ctx); 63 } 64 65 int main(void) 66 { 67 int ret = 1, len, cnt = 0, pid; 68 int exit_code = MBEDTLS_EXIT_FAILURE; 69 mbedtls_net_context listen_fd, client_fd; 70 unsigned char buf[1024]; 71 const char *pers = "ssl_fork_server"; 72 73 mbedtls_entropy_context entropy; 74 mbedtls_ctr_drbg_context ctr_drbg; 75 mbedtls_ssl_context ssl; 76 mbedtls_ssl_config conf; 77 mbedtls_x509_crt srvcert; 78 mbedtls_pk_context pkey; 79 80 mbedtls_net_init(&listen_fd); 81 mbedtls_net_init(&client_fd); 82 mbedtls_ssl_init(&ssl); 83 mbedtls_ssl_config_init(&conf); 84 mbedtls_entropy_init(&entropy); 85 mbedtls_pk_init(&pkey); 86 mbedtls_x509_crt_init(&srvcert); 87 mbedtls_ctr_drbg_init(&ctr_drbg); 88 89 #if defined(MBEDTLS_USE_PSA_CRYPTO) 90 psa_status_t status = psa_crypto_init(); 91 if (status != PSA_SUCCESS) { 92 mbedtls_fprintf(stderr, "Failed to initialize PSA Crypto implementation: %d\n", 93 (int) status); 94 goto exit; 95 } 96 #endif /* MBEDTLS_USE_PSA_CRYPTO */ 97 98 signal(SIGCHLD, SIG_IGN); 99 100 /* 101 * 0. Initial seeding of the RNG 102 */ 103 mbedtls_printf("\n . Initial seeding of the random generator..."); 104 fflush(stdout); 105 106 if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, 107 (const unsigned char *) pers, 108 strlen(pers))) != 0) { 109 mbedtls_printf(" failed! mbedtls_ctr_drbg_seed returned %d\n\n", ret); 110 goto exit; 111 } 112 113 mbedtls_printf(" ok\n"); 114 115 /* 116 * 1. Load the certificates and private RSA key 117 */ 118 mbedtls_printf(" . Loading the server cert. and key..."); 119 fflush(stdout); 120 121 /* 122 * This demonstration program uses embedded test certificates. 123 * Instead, you may want to use mbedtls_x509_crt_parse_file() to read the 124 * server and CA certificates, as well as mbedtls_pk_parse_keyfile(). 125 */ 126 ret = mbedtls_x509_crt_parse(&srvcert, (const unsigned char *) mbedtls_test_srv_crt, 127 mbedtls_test_srv_crt_len); 128 if (ret != 0) { 129 mbedtls_printf(" failed! mbedtls_x509_crt_parse returned %d\n\n", ret); 130 goto exit; 131 } 132 133 ret = mbedtls_x509_crt_parse(&srvcert, (const unsigned char *) mbedtls_test_cas_pem, 134 mbedtls_test_cas_pem_len); 135 if (ret != 0) { 136 mbedtls_printf(" failed! mbedtls_x509_crt_parse returned %d\n\n", ret); 137 goto exit; 138 } 139 140 ret = mbedtls_pk_parse_key(&pkey, (const unsigned char *) mbedtls_test_srv_key, 141 mbedtls_test_srv_key_len, NULL, 0, 142 mbedtls_ctr_drbg_random, &ctr_drbg); 143 if (ret != 0) { 144 mbedtls_printf(" failed! mbedtls_pk_parse_key returned %d\n\n", ret); 145 goto exit; 146 } 147 148 mbedtls_printf(" ok\n"); 149 150 /* 151 * 1b. Prepare SSL configuration 152 */ 153 mbedtls_printf(" . Configuring SSL..."); 154 fflush(stdout); 155 156 if ((ret = mbedtls_ssl_config_defaults(&conf, 157 MBEDTLS_SSL_IS_SERVER, 158 MBEDTLS_SSL_TRANSPORT_STREAM, 159 MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { 160 mbedtls_printf(" failed! mbedtls_ssl_config_defaults returned %d\n\n", ret); 161 goto exit; 162 } 163 164 mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); 165 mbedtls_ssl_conf_dbg(&conf, my_debug, stdout); 166 167 mbedtls_ssl_conf_ca_chain(&conf, srvcert.next, NULL); 168 if ((ret = mbedtls_ssl_conf_own_cert(&conf, &srvcert, &pkey)) != 0) { 169 mbedtls_printf(" failed! mbedtls_ssl_conf_own_cert returned %d\n\n", ret); 170 goto exit; 171 } 172 173 mbedtls_printf(" ok\n"); 174 175 /* 176 * 2. Setup the listening TCP socket 177 */ 178 mbedtls_printf(" . Bind on https://localhost:4433/ ..."); 179 fflush(stdout); 180 181 if ((ret = mbedtls_net_bind(&listen_fd, NULL, "4433", MBEDTLS_NET_PROTO_TCP)) != 0) { 182 mbedtls_printf(" failed! mbedtls_net_bind returned %d\n\n", ret); 183 goto exit; 184 } 185 186 mbedtls_printf(" ok\n"); 187 188 while (1) { 189 /* 190 * 3. Wait until a client connects 191 */ 192 mbedtls_net_init(&client_fd); 193 mbedtls_ssl_init(&ssl); 194 195 mbedtls_printf(" . Waiting for a remote connection ...\n"); 196 fflush(stdout); 197 198 if ((ret = mbedtls_net_accept(&listen_fd, &client_fd, 199 NULL, 0, NULL)) != 0) { 200 mbedtls_printf(" failed! mbedtls_net_accept returned %d\n\n", ret); 201 goto exit; 202 } 203 204 /* 205 * 3.5. Forking server thread 206 */ 207 208 mbedtls_printf(" . Forking to handle connection ..."); 209 fflush(stdout); 210 211 pid = fork(); 212 213 if (pid < 0) { 214 mbedtls_printf(" failed! fork returned %d\n\n", pid); 215 goto exit; 216 } 217 218 if (pid != 0) { 219 mbedtls_printf(" ok\n"); 220 mbedtls_net_close(&client_fd); 221 fflush(stdout); 222 223 if ((ret = mbedtls_ctr_drbg_reseed(&ctr_drbg, 224 (const unsigned char *) "parent", 225 6)) != 0) { 226 mbedtls_printf(" failed! mbedtls_ctr_drbg_reseed returned %d\n\n", ret); 227 goto exit; 228 } 229 230 continue; 231 } 232 233 mbedtls_net_close(&listen_fd); 234 235 pid = getpid(); 236 237 /* 238 * 4. Setup stuff 239 */ 240 mbedtls_printf("pid %d: Setting up the SSL data.\n", pid); 241 fflush(stdout); 242 243 if ((ret = mbedtls_ctr_drbg_reseed(&ctr_drbg, 244 (const unsigned char *) "child", 245 5)) != 0) { 246 mbedtls_printf( 247 "pid %d: SSL setup failed! mbedtls_ctr_drbg_reseed returned %d\n\n", 248 pid, ret); 249 goto exit; 250 } 251 252 if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) { 253 mbedtls_printf( 254 "pid %d: SSL setup failed! mbedtls_ssl_setup returned %d\n\n", 255 pid, ret); 256 goto exit; 257 } 258 259 mbedtls_ssl_set_bio(&ssl, &client_fd, mbedtls_net_send, mbedtls_net_recv, NULL); 260 261 mbedtls_printf("pid %d: SSL setup ok\n", pid); 262 263 /* 264 * 5. Handshake 265 */ 266 mbedtls_printf("pid %d: Performing the SSL/TLS handshake.\n", pid); 267 fflush(stdout); 268 269 while ((ret = mbedtls_ssl_handshake(&ssl)) != 0) { 270 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { 271 mbedtls_printf( 272 "pid %d: SSL handshake failed! mbedtls_ssl_handshake returned %d\n\n", 273 pid, ret); 274 goto exit; 275 } 276 } 277 278 mbedtls_printf("pid %d: SSL handshake ok\n", pid); 279 fflush(stdout); 280 281 /* 282 * 6. Read the HTTP Request 283 */ 284 mbedtls_printf("pid %d: Start reading from client.\n", pid); 285 fflush(stdout); 286 287 do { 288 len = sizeof(buf) - 1; 289 memset(buf, 0, sizeof(buf)); 290 ret = mbedtls_ssl_read(&ssl, buf, len); 291 292 if (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE) { 293 continue; 294 } 295 296 if (ret <= 0) { 297 switch (ret) { 298 case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: 299 mbedtls_printf("pid %d: connection was closed gracefully\n", pid); 300 break; 301 302 case MBEDTLS_ERR_NET_CONN_RESET: 303 mbedtls_printf("pid %d: connection was reset by peer\n", pid); 304 break; 305 306 default: 307 mbedtls_printf("pid %d: mbedtls_ssl_read returned %d\n", pid, ret); 308 break; 309 } 310 fflush(stdout); 311 312 break; 313 } 314 315 len = ret; 316 mbedtls_printf("pid %d: %d bytes read\n\n%s", pid, len, (char *) buf); 317 fflush(stdout); 318 319 if (ret > 0) { 320 break; 321 } 322 } while (1); 323 324 /* 325 * 7. Write the 200 Response 326 */ 327 mbedtls_printf("pid %d: Start writing to client.\n", pid); 328 fflush(stdout); 329 330 len = sprintf((char *) buf, HTTP_RESPONSE, 331 mbedtls_ssl_get_ciphersuite(&ssl)); 332 333 while (cnt++ < 10) { 334 while ((ret = mbedtls_ssl_write(&ssl, buf, len)) <= 0) { 335 if (ret == MBEDTLS_ERR_NET_CONN_RESET) { 336 mbedtls_printf( 337 "pid %d: Write failed! peer closed the connection\n\n", pid); 338 goto exit; 339 } 340 341 if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { 342 mbedtls_printf( 343 "pid %d: Write failed! mbedtls_ssl_write returned %d\n\n", 344 pid, ret); 345 goto exit; 346 } 347 } 348 len = ret; 349 mbedtls_printf("pid %d: %d bytes written (cnt=%d)\n\n%s\n", 350 pid, len, cnt, (char *) buf); 351 fflush(stdout); 352 353 mbedtls_net_usleep(1000000); 354 } 355 356 mbedtls_ssl_close_notify(&ssl); 357 mbedtls_printf("pid %d: shutting down\n", pid); 358 fflush(stdout); 359 goto exit; 360 } 361 362 exit: 363 mbedtls_net_free(&client_fd); 364 mbedtls_net_free(&listen_fd); 365 mbedtls_x509_crt_free(&srvcert); 366 mbedtls_pk_free(&pkey); 367 mbedtls_ssl_free(&ssl); 368 mbedtls_ssl_config_free(&conf); 369 mbedtls_ctr_drbg_free(&ctr_drbg); 370 mbedtls_entropy_free(&entropy); 371 #if defined(MBEDTLS_USE_PSA_CRYPTO) 372 mbedtls_psa_crypto_free(); 373 #endif /* MBEDTLS_USE_PSA_CRYPTO */ 374 375 mbedtls_exit(exit_code); 376 } 377 #endif /* MBEDTLS_BIGNUM_C && MBEDTLS_ENTROPY_C && 378 MBEDTLS_SSL_TLS_C && MBEDTLS_SSL_SRV_C && MBEDTLS_NET_C && 379 MBEDTLS_RSA_C && MBEDTLS_CTR_DRBG_C && MBEDTLS_PEM_PARSE_C && 380 ! _WIN32 */