/* * ++ * FACILITY: * * SSL1$CLI_SESS_REUSE_CLI_VER.C * * Simplest SSL Server + "Socket BIO" + "client certificate verification" * + "Session Reuse (Resumption)" * * ABSTRACT: * * This is an example of a SSL client with minimum functionality. * This client uses Socket BIO. * The socket APIs are used to handle TCP/IP operations. * * This SSL client verifies the server's certificate against the CA * certificate loaded in the client. * * This SSL client loads its own certificate and key for the * client certificate verification on the SSL server. * * This SSL client also demonstrates how to implement SSL Session Reuse * (Resumption) in the client 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 SSL1$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, SSL1$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 - * SSL1$CLI_SESS_REUSE_CLI_VER * $ LINK SSL1$CLI_SESS_REUSE_CLI_VER , VMS_DECC_OPTIONS.OPT/OPT * ----------------------------------------------------------------- * VMS_DECC_OPTIONS.OPT should include the following lines. * ------------------------------------------------- * SYS$LIBRARY:SSL1$LIBCRYPTO_SHR32.EXE/SHARE * SYS$LIBRARY:SSL1$LIBSSL_SHR32.EXE/SHARE * ------------------------------------------------- * * Create a 64-bit SSL application with the following commands: * ----------------------------------------------------------------- * $ CC /POINTER_SIZE=64 /PREFIX_LIBRARY_ENTRIES=ALL_ENTRIES - * SSL1$CLI_SESS_REUSE_CLI_VER * $ LINK SSL1$CLI_SESS_REUSE_CLI_VER , VMS_DECC_OPTIONS-64.OPT/OPT * ----------------------------------------------------------------- * VMS_DECC_OPTIONS.OPT should include the following lines. * ------------------------------------------------- * SYS$LIBRARY:SSL1$LIBCRYPTO_SHR.EXE/SHARE * SYS$LIBRARY:SSL1$LIBSSL_SHR.EXE/SHARE * ------------------------------------------------- * * * CONFIGURATION INSTRUCTIONS: * * * RUN INSTRUCTIONS: * * To run this example program: * * 1) Start the server program on this system, * * $ run server * * 2) Start the client program on this same system, * * $ run client * */ #include #include #include #include #include #ifdef __VMS # include # include # include #else # include # include # include # include #endif #include #include #include #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); } static int verify_callback(int ok, X509_STORE_CTX *ctx); #define RSA_CLIENT_CERT "ssl1$certs:client.crt" #define RSA_CLIENT_KEY "ssl1$certs:client.key" #define RSA_CLIENT_CA_CERT "ssl1$certs:client_ca.crt" #define RSA_CLIENT_CA_PATH "sys$common:[syshlp.examples.ssl1]" #define ON 1 #define OFF 0 /* 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; int verify_client = ON; /* To verify a client certificate, set ON */ int sock; struct sockaddr_in server_addr; char *str1, *str2; char hello[80]; SSL_CTX *ctx; SSL *ssl; const SSL_METHOD *meth; X509 *server_cert; BIO *sbio = NULL; SSL_SESSION *sess; EVP_PKEY *pkey; short int s_port = 5555; const char *s_ipaddr = "127.0.0.1"; const char *c_data = " !!! Hello Server... this is SSLv3 Client ... !!! "; /*----------------------------------------------------------*/ sprintf( f_data , "Message to be sent to the SSL server: %s", c_data ); print_it( f_data ); /* 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 const SSL_METHOD structure (choose a SSL/TLS protocol version) */ meth = SSLv3_method(); /* Create a SSL_CTX structure */ ctx = SSL_CTX_new(meth); RETURN_NULL(ctx); /*-------------------------------------------------------------------------*/ if(verify_client == ON) { /* Load the client certificate into the SSL_CTX structure */ if (SSL_CTX_use_certificate_file(ctx, RSA_CLIENT_CERT, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); exit(1); } /* Load the private-key corresponding to the client certificate */ if (SSL_CTX_use_PrivateKey_file(ctx, RSA_CLIENT_KEY, SSL_FILETYPE_PEM) <= 0) { ERR_print_errors_fp(stderr); exit(1); } /* Check if the client certificate and private-key matches */ if (!SSL_CTX_check_private_key(ctx)) { fprintf(stderr,"Private key does not match the certificate public key\n"); exit(1); } } /* Load the RSA CA certificate into the SSL_CTX structure */ if (!SSL_CTX_load_verify_locations(ctx, RSA_CLIENT_CA_CERT, NULL)) { ERR_print_errors_fp(stderr); exit(1); } /* Set to require peer (server) certificate verification */ SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); SSL_CTX_set_verify_depth(ctx,1); /* ** 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; i<154; i++) { /* ----------------------------------------------------------------- */ /* Set up a TCP socket */ sock = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP); RETURN_ERR(sock, "socket"); memset (&server_addr, '\0', sizeof(server_addr)); server_addr.sin_family = AF_INET; server_addr.sin_port = htons(s_port); /* TCP/IP Port number */ server_addr.sin_addr.s_addr = inet_addr(s_ipaddr); /* TCP/IP IP */ /* Establish a TCP/IP connection to the SSL client */ err = connect(sock, (struct sockaddr*) &server_addr, sizeof(server_addr)); RETURN_ERR(err, "connect"); /* ----------------------------------------------- */ /* 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); /* ** We could have assigned the socket into the SSL structure ** with SSL_set_fd(ssl, sock). However, this creates a new BIO ** as does SSL_set_bio(). So use one or the other, but not both. */ if( i > 0 ) { /* Attach new session to new SSL object */ SSL_set_session(ssl,sess); SSL_SESSION_free(sess); } /* Perform SSL Handshake on the SSL client */ sprintf( f_data , "Initiating Connection %d from Client to Server: %s, port: %d", i , inet_ntoa(server_addr.sin_addr), ntohs(server_addr.sin_port) ); print_it( f_data ); err = SSL_connect(ssl); RETURN_SSL(err); /* Informational output (optional) */ sprintf( f_data , "SSL connection %d using cipher: %s", i , SSL_get_cipher (ssl)); print_it( f_data ); /* Get the server's certificate (optional) */ server_cert = SSL_get_peer_certificate (ssl); if (server_cert != NULL ) { if ( i == 0 ) /* Print Server Cert. once */ { str1 = X509_NAME_oneline(X509_get_subject_name(server_cert),0,0); RETURN_NULL(str1); str2 = X509_NAME_oneline(X509_get_issuer_name(server_cert),0,0); RETURN_NULL(str2); sprintf( f_data , "Server certificate: \n\t - subject: %s \n\t - issuer: %s", str1 , str2 ); print_it( f_data ); free(str1); free(str2); X509_free (server_cert); } } else print_it("The SSL server does not have certificate.\n"); /*--------------- DATA EXCHANGE - send message and receive reply. ---------------*/ /* Send data to the SSL server */ err = SSL_write( ssl , c_data , strlen(c_data)); RETURN_SSL(err); /* 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 ); /* ** ---------- Save the SSL session (for SSL session resumption) ---------- ** ** SSL_get1_session() will increment the SSL session reference ** count, as SSL_get_session() and SSL_get0_session() do not ** increment the reference count. ** ** Note: ** If the reference count is not incremented, the ** cached session pointer can become invalid at any time ** due to a free or flush operation. ** ** SSL_SESSION_free() must be used to free the cached ** session when SSL_get1_session() is explicitly used. */ sess = SSL_get1_session(ssl); RETURN_NULL(sess); /*--------------- 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"); /* No need to call BIO_free() */ /* as this is freed with SSL_free() */ sprintf( f_data , "SSL_session_reused() == %d\n",SSL_session_reused(ssl)); print_it( f_data ); } /* End - For */ SSL_SESSION_free(sess); /* Terminate communication on a socket */ /* err = close(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 ); }