| RSA BSAFE Micro Edition Suite |
Streamlined security for mobile and embedded devices |
 
![]() |
/* $Id: sock_server.c,v 1.46 2005/04/11 12:28:12 hfrancis Exp $ */ /* * Copyright (C) 1999-2003 RSA Security Inc. All rights reserved. * * This work contains proprietary information of RSA Security. * Distribution is limited to authorized licensees of RSA * Security. Any unauthorized reproduction, distribution or * modification of this work is strictly prohibited. */ /* * A source of pseudo random numbers is required for various aspects of the * security protocol and components included in this product. Failure to * appropriately seed the Pseudo Random Number Generator (PRNG) will * seriously impact the security provided. Your application should provide this * random seed. * * The exact requirements for this seeding process may depend upon your * application and the environment for which your application is designed. * See RFC 1750 - Randomness Recommendations for Security. */ #include "r_prod.h" #include "server_defaults.h" /* The default values for server samples */ #include "builtin_cert_pkey.h" /* The built-in certificate & private key */ #include "debug_cb.h" /* The BIO and SSL state dump callback */ #include "arguments.h" /* The program arguments processing */ BIO *bio_err; int main(int argc, char *argv[]) { int ret = R_ERROR_FAILED; /* The function return */ BIO *bio_in = NULL; /* The SSL input BIO */ BIO *bio_out = NULL; int bytes_read; /* The number of Bytes read from client */ int bytes_written; /* The number of Bytes written to client */ SIO_SOCK asock = INVALID_SOCKET; /* The accept socket listener */ SIO_SOCK acpt_sock; /* The accept socket connection */ int sock_fd; /* The socket file descriptor */ char *ip = NULL; /* The IP details string */ char *port = SSL_SERVER_PORT_DEFAULT; /* The default accept port 4433 */ char *ciphers = NULL; /* The cipher list. NULL means default */ static char buf[SSL_SERVER_DATA_BUFFER_LEN]; /* The SSL read buffer */ int debug = 0; /* Allow for extra debug output */ int state = 0; /* Print the SSL state */ int connections = SSL_SERVER_UNLIMITED_CONNECTIONS; /* connection count */ int extras = 0; /* The extra command line arguments */ int arg; /* The argument counter */ SSL *ssl = NULL; SSL_METHOD *meth=NULL; /* A pointer to the server SSL method */ SSL_CTX *ssl_ctx = NULL; /* A pointer to the SSL context */ R_LIB_CTX *lib_ctx = NULL; /* A pointer to the library context */ SSLCERT *server_cert = NULL; /* A pointer to the server certificate */ EVP_PKEY *pkey = NULL; /* A pointer to the server private key */ int off = 0; /* Additional options */ static unsigned char rand_seed[] = "A bad seed for software PRNG"; int mode = R_LIB_CTX_FIPS140_MODE; /* Library's default mode */ /* Create an output channel */ if ((bio_err = BIO_new_fp(stderr, BIO_NOCLOSE)) == NULL) { goto end; } BIO_set_flags(bio_err, BIO_FLAGS_FLUSH_ON_WRITE); /* Create an output channel */ if ((bio_out = BIO_new_fp(stdout, BIO_NOCLOSE)) == NULL) { goto end; } BIO_set_flags(bio_out, BIO_FLAGS_FLUSH_ON_WRITE); /* Parse the server arguments */ if (server_parse_arguments(argc, argv, bio_err, bio_out, &port, &connections, &debug, &state, &meth, &extras, &off, &ciphers, &mode) == 1) { server_usage(bio_err, argv[0]); goto end; } /* Extra command line arguments cause an error */ if (extras > 0) { /* Report the first command line problem */ for (arg = 1; arg < argc; arg++) { if (argv[arg] != NULL) { BIO_printf(bio_err, "\nUnknown argument : %s\n", argv[arg]); break; } } /* Report program usage and exit */ server_usage(bio_err, argv[0]); goto end; } /* Initialize the SSL library using the default resources */ if (PRODUCT_LIBRARY_NEW(PRODUCT_DEFAULT_RESOURCE_LIST(), R_RES_FLAG_DEF, &lib_ctx) != R_ERROR_NONE) { BIO_printf(bio_err, "Unable to create library context\n"); goto end; } /* * This demonstrates how to seed the software PRNG of the SSL library. * Seeding information gathered using software methods is not the best * source, so do not use the following example of application-specified * entropy in production. RNG hardware is considered the best source of * random information. */ if (R_rand_seed(R_rand_get_default(), rand_seed, sizeof(rand_seed)) == 0) { BIO_printf(bio_err, "Unable to seed the PRNG\n"); goto end; } #ifndef SSLC_SMALL_CODE SSL_load_error_strings(); #endif /* !SSLC_SMALL_CODE */ /* Set the server default method if it is not set */ if (meth == NULL) { /* * Select the protocol version in the following order: * - Use pure TLSv1 if it is the only protocol version available * - Use SSLv3 support optionally in an SSLv2 handshake * (for maximum compatibility) (if possible) * - Use pure SSLv3 * - Use pure SSLv2 */ #if defined(NO_SSL2) && defined(NO_SSL3) && !defined(NO_TLS1) meth = TLSv1_server_method(); BIO_printf(bio_out, "Doing TLSv1_server_method\n"); #elif (!defined(NO_SSL2) || defined(NO_SSL2IMPL)) && !defined(NO_SSL3) meth = SSLv23_server_method(); BIO_printf(bio_out, "Doing SSLv23_server_method\n"); #elif !defined(NO_SSL3) meth = SSLv3_server_method(); BIO_printf(bio_out, "Doing SSLv3_server_method\n"); #elif !defined(NO_SSL2) meth = SSLv2_server_method(); BIO_printf(bio_out, "Doing SSLv2_server_method\n"); #else BIO_printf(bio_err, "Unable to set default server method.\n"); goto end; #endif } /* Create an SSL context structure */ if ((ssl_ctx = SSL_CTX_new(meth)) == NULL) { BIO_printf(bio_err, "Unable to create SSL context\n"); goto end; } /* * Set the mode of operation of the context. * * Note this is only applicable to libraries that support FIPS/non-FIPS * modes of operations. */ (void)SSL_CTX_set_R_LIB_CTX(ssl_ctx, lib_ctx, mode); #ifndef SSLC_SMALL_CODE /* * Set the server temporary key generation mode. The temporary key * will be generated during the handshake. */ if (!SSL_CTX_set_tmp_key_mode(ssl_ctx, SSL_TMP_512_DH|SSL_TMP_1024_DH| SSL_TMP_512_RSA, SSL_TMP_GENERATE_LATER)) { BIO_printf(bio_err, "Unable to set temporary key mode\n"); goto end; } #endif /* !SSLC_SMALL_CODE */ /* Set the cipher list if specified. Otherwise use the default. */ if (ciphers != NULL) { SSL_CTX_set_cipher_list(ssl_ctx, ciphers); } /* Set the SSL information callback to print the SSL state */ if (state) { SSL_CTX_set_info_cb(ssl_ctx, ssl_state_info_cb); } /* Enable all vendor bug compatibility options */ SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | off); /* Load the built-in server certificate. */ BIO_printf(bio_out, "Server is using the built-in certificate\n"); server_cert = sslcert_get_certificate(); if (!SSL_CTX_use_certificate(ssl_ctx, server_cert)) { BIO_printf(bio_err, "Unable to load server certificate\n"); goto end; } /* Load the built-in server private key */ BIO_printf(bio_out, "Server is using the built-in RSA key\n"); pkey = get_rsa512_priv_server(); if (!SSL_CTX_use_PrivateKey(ssl_ctx, pkey)) { BIO_printf(bio_err, "Unable to load server private key\n"); goto end; } /* * Check that the certificate and private key match. This is a common error * which should be avoided before starting the server, as without a * certificate and matching private key the SSL handshake cannot be * completed. */ if (!SSL_CTX_check_private_key(ssl_ctx)) { BIO_printf(bio_err, "Private key check failed\n"); goto end; } /* * Create the SSL structure. Defaults are inherited from the SSL_CTX. * Options are usually set against the SSL_CTX with those requiring * modification set against the SSL. */ if ((ssl = SSL_new(ssl_ctx)) == NULL) { BIO_printf(bio_err, "Unable to create SSL structure\n"); goto end; } /* Enable anytime shutdown to handle https requests properly */ SSL_set_options(ssl, SSL_OP_ANYTIME_SHUTDOWN); /* Set up the listening accept socket and make it reuseable */ if ((asock = SIO_get_accept_socket(port, SIO_BIND_NORMAL | SIO_BIND_REUSEADDR)) == INVALID_SOCKET) { BIO_printf(bio_err, "No accept socket available\n"); goto end; } /* * Enter the SSL server loop. Allow for "connections" client connections * to the server unless an error condition forces an early close. */ while (connections != 0) { /* Decrement the number of connections by 1 */ connections--; BIO_printf(bio_out, "\nWaiting for new connection ...\n"); /* Reset the SSL for the next connection */ SSL_clear(ssl); /* Return a connection socket from the listening socket */ if ((acpt_sock = SIO_accept(asock, &ip)) <= 0) { BIO_printf(bio_err, "Socket accept failed\n"); goto end; } /* Output connection feedback for a successful connection */ if (ip != NULL) { /* Output the connecting client IP details */ BIO_printf(bio_out, "Connection received from %s\n", ip); /* * Do not free the IP string at this point. This memory can be * reused on the next connection loop. */ } /* * Embed the socket in a BIO that will not close the socket when the * BIO is freed. This requires that SIO_SOCK is an integer. */ bio_in = BIO_new_socket(acpt_sock, BIO_NOCLOSE); /* * In debug mode add a callback to the socket BIO to output * the data passing through to the error BIO */ if (debug) { BIO_set_cb(bio_in, bio_dump_cb); BIO_set_cb_arg(bio_in, (char *)bio_out); } /* * Add the socket BIO to the SSL. The bio_in is taken by SSL_set_bio(). * It does not need to be freed as the SSL clean up will do so. */ SSL_set_bio(ssl, bio_in, bio_in); /* * An SSL connection exists. Which side of the protocol is being * performed? If calling SSL_connect() or SSL_accept(), the side is * set. In this case only call SSL_do_handshake() which requires the * client/server flag to be set. */ SSL_set_accept_state(ssl); /* Read the client request in a single buffer */ bytes_read = SSL_read(ssl, buf, SSL_SERVER_DATA_BUFFER_LEN - 1); if (bytes_read > 0) { /* Data has been read from the client connection */ /* Display the received request to standard output */ buf[bytes_read] = '\0'; BIO_printf(bio_out, buf); /* Write the prepared response to the client */ bytes_written = SSL_write(ssl, SSL_SERVER_RESPONSE_DEFAULT, Strlen(SSL_SERVER_RESPONSE_DEFAULT)); /* Shut down the SSL protocol */ SSL_shutdown(ssl); /* * Now retrieve the socket file descriptor and close it because * SSL_shutdown() only shuts down the protocol and not the socket. * If it was useful the same socket could be reused after a call to * SSL_clear(). */ sock_fd = SSL_get_fd(ssl); closesocket(sock_fd); /* * An error on the blocking socket will close the server. Perform * this check after the socket for the SSL has been closed. */ if (bytes_written < 0) { BIO_printf(bio_err, "Server write response failed\n"); goto end; } BIO_printf(bio_out,"Done\n"); } else if (bytes_read == 0) { /* The connection to the client has broken */ BIO_printf(bio_out, "Client connection closed\n"); } else if (bytes_read < 0) { /* On error shut down the application */ BIO_printf(bio_err, "Server read request failed\n"); /* Exit immediately */ goto end; } } /* Set the program success code */ ret = R_ERROR_NONE; end: /* Display the error stack on error */ if ((ret != R_ERROR_NONE) && (bio_err != NULL)) { ERR_print_errors(bio_err); } /* Free an IP-details string */ if (ip != NULL) { Free(ip); } /* Free the accept sockets */ if (asock != INVALID_SOCKET) { /* Close the listener socket */ SIO_close(asock); } if (ssl != NULL) { SSL_free(ssl); } /* Free the server's private key */ if (pkey != NULL) { SSLCERT_PKEY_free(pkey); } /* Free the server certificate */ if (server_cert != NULL) { SSLCERT_free(server_cert); } if (ssl_ctx != NULL) { /* * Do not check the return code as no more memory freeing will be * performed */ SSL_CTX_free(ssl_ctx); } /* Free the SSL library context */ if (lib_ctx != NULL) { PRODUCT_LIBRARY_FREE(lib_ctx); } if (bio_out != NULL) { BIO_free(bio_out); } if (bio_err != NULL) { BIO_free(bio_err); bio_err = NULL; } return(R_ERROR_EXIT_CODE(ret)); }