/* * ++ * FACILITY: * * SSL$SERV_SESS_REUSE_CLI_VER.C * * Simplest SSL Server + "Socket BIO" + "client certificate verification" * + "Session Reuse (Resumption)" * * ABSTRACT: * * This is an example of a SSL server with minimum functionality * with the client certificate verification (using Socket BIO). * The socket APIs are used to handle TCP/IP operations. This SSL * server loads its own certificate and key, but it does not verify * the certificate of the SSL client. * * * This SSL server also demonstrates how to implement SSL Session Reuse * (Resumption) in the server using SSL V3 protocol on port = 5555 and * ipaddr = 127.0.0.1 * * ENVIRONMENT: * * OpenVMS Alpha V7.2-2 * TCP/IP Services V5.0A or higher * * AUTHOR: * * Taka Shinagawa, OpenVMS Security Group * * CREATION DATE: * * 1-Jan-2002 * * MODIFICATION HISTORY: * * 11-July-2003 Paul Mosteika * * Changed loop to include multiple (150) session resumptions * with a forced session cache miss (server flush) every 50th iteration. * Certificates use the SSL$CERTS logical. Also some document changes, * and print output was sequenced. * -- */ /* Assumptions, Build, Configuration, and Execution Instructions */ /* * ASSUMPTIONS: * * The following are assumed to be true for the * execution of this program to succeed: * * - SSL is installed and started on this system. * * - this server program, and its accompanying client * program are run on the same system, but in different * processes. * * - the certificate and keys referenced by this program * reside in the same directory as this program. There * is a command procedure, SSL$EXAMPLES_SETUP.COM, to * help set up the certificates and keys. * * BUILD INSTRUCTIONS: * * To build this example program use commands of the form, * * For 32-bit SSL applications, use the following commands: * ----------------------------------------------------------------- * $ CC /POINTER_SIZE=32 /PREFIX_LIBRARY_ENTRIES=ALL_ENTRIES - * SSL$SERV_SESS_REUSE_CLI_VER * $ LINK SSL$SERV_SESS_REUSE_CLI_VER , VMS_DECC_OPTIONS.OPT/OPT * ----------------------------------------------------------------- * VMS_DECC_OPTIONS.OPT should include the following lines. * ------------------------------------------------- * SYS$LIBRARY:SSL$LIBCRYPTO_SHR32.EXE/SHARE * SYS$LIBRARY:SSL$LIBSSL_SHR32.EXE/SHARE * ------------------------------------------------- * * Create 64-bit SSL application with the following commands: * ----------------------------------------------------------------- * $ CC /POINTER_SIZE=64 /PREFIX_LIBRARY_ENTRIES=ALL_ENTRIES - * SSL$SERV_SESS_REUSE_CLI_VER * $ LINK SSL$SERV_SESS_REUSE_CLI_VER , VMS_DECC_OPTIONS-64.OPT/OPT * ----------------------------------------------------------------- * VMS_DECC_OPTIONS.OPT should include the following lines. * ------------------------------------------------- * SYS$LIBRARY:SSL$LIBCRYPTO_SHR.EXE/SHARE * SYS$LIBRARY:SSL$LIBSSL_SHR.EXE/SHARE * ------------------------------------------------- * * * CONFIGURATION INSTRUCTIONS: * * * RUN INSTRUCTIONS: * * To run this example program: * * 1) Start the server program, * * $ run server * * 2) Start the client program on this same system, * * $ run client * */ #include #include #include #include #include #include #ifdef __VMS #include #include #include #include #else #include #include #include #include #endif #include #include #include #define RSA_SERVER_CERT "ssl$certs:server.crt" #define RSA_SERVER_KEY "ssl$certs:server.key" #define RSA_SERVER_CA_CERT "ssl$certs:server_ca.crt" #define RSA_SERVER_CA_PATH "sys$common:[syshlp.examples.ssl]" #define ON 1 #define OFF 0 #define RETURN_NULL(x) if ((x)==NULL) exit(1) #define RETURN_ERR(err,s) if ((err)==-1) { perror(s); exit(1); } #define RETURN_SSL(err) if ((err)==-1) { ERR_print_errors_fp(stderr); exit(1); } /* Function Prototypes */ void print_it( char * message ); /* Print string formatted buffer, prepends a sequence number */ /* Global */ char r_buf[4096]; /* SSL Read data buffer */ char f_data[1024]; /* Formatted sprintf() data buffer */ void main () { int err, i, flush; int verify_client = ON; /* To verify a client certificate, set ON */ int listen_sock; int sock; int on = ON; struct sockaddr_in sa_serv; struct sockaddr_in sa_cli; size_t client_len; char *str1, *str2; SSL_CTX *ctx; SSL *ssl; SSL_METHOD *meth; X509 *client_cert = NULL; BIO *sbio = NULL; short int s_port = 5555; const unsigned char sid_ctx[] = {"Our Session ID"}; unsigned int sid_ctx_len = sizeof(sid_ctx); /* SSL_MAX_SSL_SESSION_ID_LENGTH = 32 */ /*-----------------------------------------------------------------------------------------*/ /* Load encryption & hashing algorithms for the SSL program */ SSL_library_init(); /* Load the error strings for SSL & CRYPTO APIs */ SSL_load_error_strings(); /* Create a SSL_METHOD structure (choose a SSL/TLS protocol version) */ meth = SSLv3_method(); /* Create a SSL_CTX structure */ ctx = SSL_CTX_new(meth); if (!ctx) { ERR_print_errors_fp(stderr); exit(1); } /* Load the server certificate into the SSL_CTX structure */ if (SSL_CTX_use_certificate_file(ctx, RSA_SERVER_CERT, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); exit(1); } /* Load the private-key corresponding to the server certificate */ if (SSL_CTX_use_PrivateKey_file(ctx, RSA_SERVER_KEY, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); exit(1); } /* Check if the server certificate and private-key matches */ if (!SSL_CTX_check_private_key(ctx)) { fprintf(stderr,"!!!!! Private key does not match the certificate public key failure !!!!!\n"); exit(1); } if(verify_client == ON) { /* Load the RSA CA certificate into the SSL_CTX structure */ if (!SSL_CTX_load_verify_locations(ctx, RSA_SERVER_CA_CERT, NULL)) { ERR_print_errors_fp(stderr); exit(1); } /* Set to require peer (client) certificate verification */ SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); /* Set the verification depth to 1 */ SSL_CTX_set_verify_depth(ctx,1); /* For session resumption */ if( ! SSL_CTX_set_session_id_context( ctx , sid_ctx , sid_ctx_len ) ) { printf(" !!!!! SSL_CTX_set_session_id_context() failed !!!!! \n"); exit(1); } sprintf( f_data , "Session Cache size = %ld", SSL_CTX_sess_get_cache_size(ctx)); print_it( f_data ); sprintf( f_data , "Session ID timeout value = %ld", SSL_CTX_get_timeout(ctx)); print_it( f_data ); } /* ----------------------------------------------- */ /* Set up a TCP socket */ listen_sock = socket(PF_INET, SOCK_STREAM, IPPROTO_TCP); RETURN_ERR(listen_sock, "socket"); memset (&sa_serv, '\0', sizeof(sa_serv)); sa_serv.sin_family = AF_INET; sa_serv.sin_addr.s_addr = INADDR_ANY; sa_serv.sin_port = htons (s_port); /* Server Port number */ /* Set the socket options so that the socket can be reused */ err = setsockopt (listen_sock, SOL_SOCKET, SO_REUSEADDR, (void *)&on, sizeof(on)); RETURN_ERR(err, "setsockopt"); err = bind(listen_sock, (struct sockaddr*)&sa_serv,sizeof(sa_serv)); RETURN_ERR(err, "bind"); /* Wait for an incoming TCP connection. */ err = listen(listen_sock, 5); RETURN_ERR(err, "listen"); client_len = sizeof(sa_cli); /* ** Loop at least 154 times. Minus initial connection and 3 misses = ** 150 reconnects/session resumptions: ** 0 = Initial connection, full handshake ** 1..50..52.. = Session resumed, partial handshake (change_cipher, data...) ** 51, 101, 151 = Session Cache miss, full handshake */ for( i=0 , flush=0; i < 154; i++, flush++ ) { /* Socket for a TCP/IP connection is created */ sock = accept(listen_sock, (struct sockaddr*)&sa_cli, &client_len); RETURN_ERR(sock, "accept"); sprintf( f_data , "Received Connection %d on Server from Client: %s, port: %d", i , inet_ntoa(sa_cli.sin_addr) , ntohs(sa_cli.sin_port) ); print_it( f_data ); /* ----------------------------------------------- */ /* TCP connection is ready. */ /* A SSL structure is created */ ssl = SSL_new(ctx); RETURN_NULL(ssl); /* Use a socket BIO between the socket and SSL structure */ /* Create a socket BIO */ sbio = BIO_new_socket(sock, BIO_NOCLOSE); /* Assign the socket BIO to the SSL structure*/ SSL_set_bio(ssl, sbio, sbio); /* Perform SSL Handshake on the SSL server */ err = SSL_accept(ssl); RETURN_SSL(err); /* Informational output (optional) */ sprintf( f_data , "SSL connection using %s", SSL_get_cipher (ssl)); print_it( f_data ); /* Get the client's certificate (optional) */ client_cert = SSL_get_peer_certificate(ssl); if (client_cert != NULL) { str1 = X509_NAME_oneline(X509_get_subject_name(client_cert), 0, 0); RETURN_NULL(str1); str2 = X509_NAME_oneline(X509_get_issuer_name(client_cert), 0, 0); RETURN_NULL(str2); sprintf( f_data , "Client certificate: \n\t - subject: %s \n\t - issuer: %s", str1 , str2 ); print_it( f_data ); free (str1); free (str2); X509_free(client_cert); } else print_it("The SSL client does not have certificate.\n"); /*--------------- DATA EXCHANGE - Receive message and send reply. ---------------*/ /* Receive data from the SSL client */ err = SSL_read(ssl, r_buf, sizeof(r_buf) - 1); RETURN_SSL(err); r_buf[err] = '\0'; sprintf( f_data , "Received %d chars:'%s'", err, r_buf); print_it( f_data ); /* Send data to the SSL client */ err = SSL_write(ssl, "This message is from the SSL server", strlen("This message is from the SSL server")); RETURN_SSL(err); /* SSL_CTX_sess_* are MACRO's for the SSL_CTX_ctrl API */ print_it("Server (CTX) Internal Session Cache Statistics"); printf("\t Current number of cached sessions == %d\n", SSL_CTX_sess_number(ctx)); printf("\t Number of started SSLv3 handshakes == %d\n", SSL_CTX_sess_connect(ctx)); printf("\t Number of successfully established SSLv3 sessions == %d\n", SSL_CTX_sess_connect_good(ctx)); printf("\t Number of start renegotiations == %d\n", SSL_CTX_sess_connect_renegotiate(ctx)); printf("\t Number of successfully reused sessions == %d\n", SSL_CTX_sess_hits(ctx)); printf("\t SSL_CTX_sess_misses == %d\n", SSL_CTX_sess_misses(ctx)); printf("\t SSL_CTX_sess_timeouts == %d\n", SSL_CTX_sess_timeouts(ctx)); printf("\t SSL_CTX_sess_cache_full == %d\n", SSL_CTX_sess_cache_full(ctx)); printf("\t SSL_CTX_get_session_cache_mode == "); switch(SSL_CTX_get_session_cache_mode(ctx)) { case SSL_SESS_CACHE_OFF: printf("SSL_SESS_CACHE_OFF\n"); break; case SSL_SESS_CACHE_CLIENT: printf("SSL_SESS_CACHE_CLIENT\n"); break; case SSL_SESS_CACHE_SERVER: printf("SSL_SESS_CACHE_SERVER\n"); break; case SSL_SESS_CACHE_BOTH: printf("SSL_SESS_CACHE_BOTH\n"); break; case SSL_SESS_CACHE_NO_AUTO_CLEAR: printf("SSL_SESS_CACHE_NO_AUTO_CLEAR\n"); break; case SSL_SESS_CACHE_NO_INTERNAL_LOOKUP: printf("SSL_SESS_CACHE_NO_INTERNAL_LOOKUP\n"); break; #if 0 /* 0.9.6h */ case SSL_SESS_CACHE_NO_INTERNAL_STORE: printf("SSL_SESS_CACHE_NO_INTERNAL_STORE\n"); break; case SSL_SESS_CACHE_NO_INTERNAL: printf("SSL_SESS_CACHE_NO_INTERNAL\n"); break; /* End 0.9.6h */ #endif } /* End - Switch */ printf("\n"); /* Separate each connection */ /*--------------- SSL closure ---------------*/ /* Shutdown this side of the SSL connection */ err = SSL_shutdown(ssl); RETURN_SSL(err); /* Terminate communication on a socket */ err = close(sock); RETURN_ERR(err, "close"); /* ** Flush the cache every 50 re-connects/resumes ** Note: forces cache miss */ if ( 50 == flush ) { flush = 0; SSL_CTX_flush_sessions( ctx , 0); } } /* End - For */ err = close(listen_sock); RETURN_ERR(err, "close"); /* Free the SSL structure */ SSL_free(ssl); /* Free the SSL_CTX structure */ SSL_CTX_free(ctx); } /* ** Print a message, prepending a sequence number */ void print_it( char * message ) { static int i = 0; printf(" %d \t %s \n", ++i , message ); }