#pragma module ssl$tcp_client_qio \ "V5.5-00" /* ** Copyright 2004 Hewlett-Packard Development Company, L.P. ** ** Confidential computer software. Valid license from HP and/or its ** subsidiaries required for possession, use, or copying. ** ** Consistent with FAR 12.211 and 12.212, Commercial Computer Software, ** Computer Software Documentation, and Technical Data for Commercial ** Items are licensed to the U.S. Government under vendor's standard ** commercial license. ** ** Neither HP nor any of its subsidiaries shall be liable for technical ** or editorial errors or omissions contained herein. The information ** in this document is provided "as is" without warranty of any kind ** and is subject to change without notice. The warranties for HP ** products are set forth in the express limited warranty statements ** accompanying such products. Nothing herein should be construed as ** constituting an additional warranty. ** **++ ** FACILITY: ** ** EXAMPLES ** ** ABSTRACT: ** ** This is an example of a TCP/IP IPv4 client using OpenVMS ** QIO system services to handle network I/O operations with SSL ** to secure the data with encryption. ** ** Refer to 'Build, Configuration, and Run Instructions' for ** details on how to build, configure, and run this program. ** ** ENVIRONMENT: (Minimal Versions) ** ** OpenVMS V7.2-2 Alpha, VAX V7.3 ** TCP/IP Services V5.3 ** SSL for OpenVMS V1.1-B ** ** AUTHOR: ** ** TCPIP Development Group, CREATION DATE: 23-May-1989 ** ** MODIFICATION HISTORY: ** ** OpenVMS Engineering - Security Group, ** ** V5.5-00 01-Dec-2003 Paul Mosteika ** Modified to use SSL to verify server certificate and encrypt data. ** **-- */ /* Build, Configuration, and Run Instructions */ /* * BUILD INSTRUCTIONS: * * To build this example program use commands of the form, * * * using the "DECC" compiler: * * To Create a 32-bit Application Using 32-bit SSL APIs * ---------------------------------------------------- * * $ CC /POINTER=32 /PREFIX=ALL SSL$TCP_CLIENT_QIO_SSL.C * $ LINK SSL$TCP_CLIENT_QIO_SSL.OBJ , SYS$INPUT:/OPT * SYS$LIBRARY:SSL$LIBCRYPTO_SHR32.EXE /SHARE * SYS$LIBRARY:SSL$LIBSSL_SHR32.EXE /SHARE * $ ^z * * Note: The source code would need to be modified for 64 bit support. * * CONFIGURATION INSTRUCTIONS: * * No special configuration required, although, TCPIP and SSL must be * installed and started. * * * RUN INSTRUCTIONS: * * To run this example program: * * 1) Start the client's server program as shown below: * * $ run SSL$TCP_SERVER_QIO_SSL * Waiting for a client connection on port: 5555 * * 2) After the server program blocks, start this client program, * entering the server host as shown below: * * $ run SSL$TCP_CLIENT_QIO_SSL * Enter remote host: * * Note: You can specify a server host by using either an IPv4 * address in dotted-decimal notation (e.g. 16.20.10.56) * or a host domain name (e.g. serverhost.hp.com). * * To eliminate user prompting for the Server node, define * SERVER_ADDR for the default Server node for the Client * connection, for example: * * #define SERVER_ADDR "TCPIP-Nodename" * * See SSL_EXAMPLES.H for more information and further debug * information and callbacks. * * 3) The client program then displays server connection information * and server data as show below: * * $ r SSL$TCP_CLIENT_QIO_SSL.EXE * Enter remote host: Node-10 * Initiated connection to host: 1.0.x.x, port: 5555 * * Info Callback state = 16, ret code = 1 * SSL_CB_HANDSHAKE_START * . * . * . * Message to be sent to the SSL server: * --- From SSL QIO Client, Hey, Hello Server --- * Received 39 chars:'This message is from the SSL QIO server' */ /* * INCLUDE FILES: */ #include /* define OpenVMS descriptors */ #include /* define 'EFN$C_ENF' event flag */ #include /* define internet related constants, */ /* functions, and structures */ #include /* define network address info */ #include /* define i/o function codes */ #include /* define network database library info */ #include /* define system service status codes */ #include /* define system service calls */ #include /* define standard i/o functions */ #include /* define standard library functions */ #include /* define string handling functions */ #include /* define condition value fields */ #include /* define tcp/ip network constants, */ /* structures, and functions */ /* ++ SSL ++ */ #include #include #define openssl "SSL$INCLUDE" #include #include #include #include "SSL$EXAMPLES:ssl_examples.h" /* SSL callbacks and error handling */ #undef openssl #define RSA_CLIENT_CERT "SSL$CERTS:client.crt" #define RSA_CLIENT_KEY "SSL$CERTS:client.key" #define RSA_CLIENT_CA_CERT "SSL$CERTS:client_ca.crt" #define ON 1 #define OFF 0 /* -- SSL -- */ /* * NAMED CONSTANTS: */ #define BUFSZ 1024 /* user input buffer size */ #define SERV_PORTNUM 5555 /* server port number */ /* * STRUCTURE DEFINITIONS: */ struct iosb { /* i/o status block */ unsigned short status; /* i/o completion status */ unsigned short bytcnt; /* bytes transferred if read/write */ void *details; /* address of buffer or parameter */ }; struct itemlst_2 { /* item-list 2 descriptor/element */ unsigned short length; /* length */ unsigned short type; /* parameter type */ void *address; /* address of item list */ }; struct sockchar { /* socket characteristics buffer */ unsigned short prot; /* protocol */ unsigned char type; /* type */ unsigned char af; /* address format */ }; /* ++ SSL ++ */ SSL *ssl; /* Global Pointer to SSL Object */ char buf[4096]; /* Global client data buffer */ /* -- SSL -- */ /* * FORWARD REFERENCES: */ int main( void ); /* client main */ void get_serv_addr( void * ); /* get server host address */ /* Client Main */ /* * FUNCTIONAL DESCRIPTION: * * This is the client's main-line code. It handles all the tasks of the * client including: socket creation, initiating server connections, * reading server connection data, and terminating server connections. * * This example program implements a typical TCP IPv4 client using QIO * system services to handle network i/o operations as shown below: * * 1) To create a socket: * * sys$assign() and sys$qiow(IO$_SETMODE) * * 2) To initiate a connection: * * sys$qiow(IO$_ACCESS) * * 3) To transfer data: * * sys$qiow(IO$_READVBLK) * * 4) To shutdown a socket: * * sys$qiow(IO$_DEACCESS|IO$M_SHUTDOWN) * * 5) To close and delete a socket: * * sys$qiow(IO$_DEACCESS) and sys$dassgn() * * This function is invoked by the DCL "RUN" command (see below); the * function's completion status is interpreted by DCL and if needed, * an error message is displayed. * * SYNOPSIS: * * int main( void ) * * FORMAL PARAMETERS: * * ** None ** * * IMPLICIT INPUTS: * * ** None ** * * IMPLICIT OUTPUTS: * * ** None ** * * FUNCTION VALUE: * * completion status * * SIDE EFFECTS: * * ** None ** * */ int main( void ) { /* ++ SSL ++ */ int err; int verify_client = OFF; /* To verify a client certificate, set ON */ int sock; struct sockaddr_in server_addr; char *str; char hello[80] = { " --- From SSL QIO Client, Hey, Hello Server --- " }; SSL_CTX *ctx; SSL *ssl; SSL_METHOD *meth; X509 *server_cert; EVP_PKEY *pkey; short int s_port = 5555; const char *s_ipaddr = "127.0.0.1"; /* -- SSL -- */ struct iosb iosb; /* i/o status block */ unsigned int status; /* system service return status */ unsigned short conn_channel; /* connect inet device i/o channel */ struct sockchar conn_sockchar; /* connect socket char buffer */ struct sockaddr_in serv_addr; /* server socket address structure */ struct itemlst_2 serv_itemlst; /* server item-list 2 descriptor */ $DESCRIPTOR( inet_device, /* string descriptor with logical */ "TCPIP$DEVICE:" ); /* name of internet pseudodevice */ /* ++ SSL ++ */ /* Load encryption & hashing algorithms for the SSL program */ SSL_library_init(); /* Load the error strings for SSL & CRYPTO APIs */ SSL_load_error_strings(); /* Create an SSL_METHOD structure (choose an SSL/TLS protocol version) */ meth = SSLv3_method(); /* Create an 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,"Error - Private key does not match the certificate public key\n"); exit(1); } } /* Load the RSA CA certificate into the SSL_CTX structure */ /* This will allow this client to verify the server's */ /* certificate. */ if (!SSL_CTX_load_verify_locations(ctx, RSA_CLIENT_CA_CERT, NULL)) { ERR_print_errors_fp(stderr); exit(1); } /* Set flag in context to require peer (server) certificate verification */ SSL_CTX_set_verify(ctx,SSL_VERIFY_PEER,NULL); SSL_CTX_set_verify_depth(ctx,1); /* -- SSL -- */ /* * init connection socket characteristics buffer */ conn_sockchar.prot = TCPIP$C_TCP; conn_sockchar.type = TCPIP$C_STREAM; conn_sockchar.af = TCPIP$C_AF_INET; /* * init server's item-list descriptor */ memset( &serv_itemlst, 0, sizeof(serv_itemlst) ); serv_itemlst.length = sizeof( serv_addr ); serv_itemlst.address = &serv_addr; /* * init server's socket address structure */ memset( &serv_addr, 0, sizeof(serv_addr) ); serv_addr.sin_family = TCPIP$C_AF_INET; serv_addr.sin_port = htons( SERV_PORTNUM ); get_serv_addr( &serv_addr.sin_addr ); /* * assign device socket */ status = sys$assign( &inet_device, /* device name */ &conn_channel, /* i/o channel */ 0, /* access mode */ 0 /* not used */ ); if ( !(status & STS$M_SUCCESS) ) { printf( "Error - Failed to assign i/o channel to TCPIP device\n" ); exit( status ); } /* * create (and bind) connection socket */ status = sys$qiow( EFN$C_ENF, /* event flag */ conn_channel, /* i/o channel */ IO$_SETMODE, /* i/o function code */ &iosb, /* i/o status block */ 0, /* ast service routine */ 0, /* ast parameter */ &conn_sockchar, /* p1 - socket char buffer */ 0, /* p2 */ 0, /* p3 */ 0, /* p4 */ 0, /* p5 */ 0 /* p6 */ ); if ( status & STS$M_SUCCESS ) { status = iosb.status; } if ( !(status & STS$M_SUCCESS) ) { printf( "Error - Failed to create socket\n" ); exit( status ); } /* * connect to specified host and port number */ printf( " Initiated connection to host: %s, port: %d\n", inet_ntoa(serv_addr.sin_addr), ntohs(serv_addr.sin_port) ); status = sys$qiow( EFN$C_ENF, /* event flag */ conn_channel, /* i/o channel */ IO$_ACCESS, /* i/o function code */ &iosb, /* i/o status block */ 0, /* ast service routine */ 0, /* ast parameter */ 0, /* p1 */ 0, /* p2 */ &serv_itemlst, /* p3 - remote socket name */ 0, /* p4 */ 0, /* p5 */ 0 /* p6 */ ); if ( status & STS$M_SUCCESS ) { status = iosb.status; } if ( !(status & STS$M_SUCCESS) ) { printf( "Error - Failed to connect to server\n" ); exit( status ); } /* ++ SSL ++ */ /* ----------------------------------------------- */ /* An SSL structure is created */ ssl = SSL_new (ctx); RETURN_NULL(ssl); /* Set informational callback routine */ SSL_set_info_callback( ssl , get_info ); /* Assign the socket channel into the SSL structure (SSL and socket without BIO) */ sock = decc$socket_fd ( conn_channel ); err = SSL_set_fd( ssl , sock ); if ( err == -1 ) check_error( ssl , err , \ "- ERROR - during CLIENT assigning socket to SSL object"); /* Perform SSL Handshake on the SSL client */ err = SSL_connect( ssl ); if ( err == -1 ) check_error( ssl , err , \ "- ERROR - during CLIENT connect to SERVER"); /* Informational output (optional) */ printf (" SSL connection using %s\n", SSL_get_cipher (ssl)); /* ** Get the server's certificate (optional) but, ** we do set the SSL_VERIFY_PEER flag. ** - see - SSL_CTX_set_verify() */ server_cert = SSL_get_peer_certificate (ssl); if (server_cert != NULL) { printf (" Server certificate:\n"); str = X509_NAME_oneline(X509_get_subject_name(server_cert),0,0); RETURN_NULL(str); printf ("\t subject: %s\n", str); free (str); str = X509_NAME_oneline(X509_get_issuer_name(server_cert),0,0); RETURN_NULL(str); printf ("\t issuer: %s\n", str); free(str); X509_free (server_cert); } else printf(" Error - The SSL server does not have certificate.\n"); /*--------------- DATA EXCHANGE - send message and receive reply. ---------------*/ /* ** Send data to the SSL server */ printf (" Message to be sent to the SSL server: \n\t %s \n" , hello ); err = SSL_write(ssl, hello, strlen(hello)); if ( err == -1 ) check_error( ssl , err , \ "- ERROR - during CLIENT write operation to SERVER"); /* ** Receive data from the SSL server */ err = SSL_read(ssl, buf, sizeof(buf)-1); if ( err == -1 ) check_error( ssl , err , \ "- ERROR - during CLIENT read operation from SERVER"); buf[err] = '\0'; printf (" Received %d chars:'%s'\n", err, buf); /*--------------- SSL closure ---------------*/ /* ** Shutdown the client side of the SSL connection */ err = SSL_shutdown(ssl); if ( err == -1 ) check_error( ssl , err , \ "- ERROR - during CLIENT shutting down SSL connection"); /* -- SSL -- */ /* * close connection socket */ status = sys$qiow( EFN$C_ENF, /* event flag */ conn_channel, /* i/o channel */ IO$_DEACCESS, /* i/o function code */ &iosb, /* i/o status block */ 0, /* ast service routine */ 0, /* ast parameter */ 0, /* p1 */ 0, /* p2 */ 0, /* p3 */ 0, /* p4 */ 0, /* p5 */ 0 /* p6 */ ); if ( status & STS$M_SUCCESS ) { status = iosb.status; } if ( !(status & STS$M_SUCCESS) ) { printf( "Error - Failed to close socket\n" ); exit( status ); } /* ++ SSL ++ */ /* ** Free the SSL structure */ SSL_free(ssl); /* ** Free the SSL_CTX structure */ SSL_CTX_free(ctx); /* -- SSL -- */ /* * deassign device socket */ status = sys$dassgn( conn_channel ); if ( !(status & STS$M_SUCCESS) ) { printf( "Error - Failed to deassign i/o channel to TCPIP device\n" ); exit( status ); } exit( EXIT_SUCCESS ); } /* End - Main() */