#ifndef HEADER_SSL_EXAMPLES_H /* ** 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: ** ** SSL - EXAMPLES ** ** ABSTRACT: ** ** This header file provides common SSL error handling and callback ** routines used in various SSL example files located in the SYSHLP ** directory, SYS$COMMON:[SYSHLP.EXAMPLES.SSL] defined by the logical ** SSL$EXAMPLES logical name. ** ** Include this file within your application when compiling with: ** ** #include "SSL$EXAMPLES:SSL_EXAMPLES.H" ** ** or on the compilation command line with: ** ** cc /include=SSL$EXAMPLES:SSL_EXAMPLES.H ** ** 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 ** ** AUTHORS: ** ** OpenVMS Engineering, Security Group, CREATION DATE: 01-Dec-2003 ** ** MODIFICATION HISTORY: ** ** 13-Dec-2003 Paul Mosteika ** ** Modified to include SSL_set_info_callback() to provide SSL "state" ** information especially helpfull during connect/accept problems. ** ** -- */ /* ** ** INCLUDE FILES ** */ #include /* Internet related constants */ #include /* Network address info */ #include /* Network database library info */ #include #include #include #include #include #include "SSL$INCLUDE:BIO.H" #include "SSL$INCLUDE:ERR.H" #include "SSL$INCLUDE:SSL.H" /* ** Named Constants */ #define BUFSZ 1024 /* user input buffer size */ /* #define SERVER_ADDR "NodeName" */ /* Default Server node for Client connection */ #define SERVER_ADDR "" /* otherwise define as NULL */ /* #define BIO_DEBUG 1 */ /* Trace BIO R/W data flow */ /* #define BIO_DEBUG_FULL 1 */ /* Trace full BIO callback */ #define BIO_DEBUG 1 /* Trace BIO R/W data flow */ #define BIO_DEBUG_FULL 1 /* Trace full BIO callback */ /* ** ** MACRO DEFINITIONS ** */ /* Error Macros */ #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); } #define check_vms(status,string) \ if (status != SS$_NORMAL ) \ { \ printf("%s\n", string); lib$stop (status); \ } #define check_error(ssl,ret,msg) get_error((ssl),(ret),(msg),(__FILE__),(__LINE__)) /* ** ** Function Prototypes - Table of Contents ** */ long bio_cb(BIO *bio, int cmd, const char *argp, int argi, long argl, long ret); void get_error( SSL *ssl , int ret , const char *msg , const char *file , int lineno ); void get_info( const SSL *ssl , int state , int ret ); void get_serv_addr( void *addrptr ); int password_cb(char *buf, int num, int rwflag, void *ud_passwd); void print_it( char * message ); void print_stats(BIO *bio, SSL_CTX *ssl_ctx); /* ** Global (psect) Data */ char f_data[1024]; /* Formatted sprintf() data buffer */ /* ** Functions - Routines */ #if defined(BIO_DEBUG) || defined(BIO_DEBUG_FULL) long bio_cb(BIO *bio, int cmd, const char *argp, int argi, long argl, long ret) { /* ** SSL calls this bio_cb() routine with the BIO ptr, the command, and ** other parameters when attempting a BIO operation. This callback ** routine must first be set in the BIO, for example: ** ** BIO_set_callback(sbio,bio_cb); ** ** The command 'cmd' has a flag bit set 'BIO_CB_RETURN' when called after ** the operation. ** ** Define BIO_DEBUG to see BIO R/W callback or trace information. ** We use the stdio BIO to print the BIO callback information. ** BIO_DEBUG_FULL can be defined to see and trace all (and some ** uninteresting) verbose information. ** ** Also refer to SSL source code S_APPS.H , S_CLIENT.C , S_CB.C , BIO.H */ BIO *bio_c_out = NULL; bio_c_out = BIO_new_fp(stdout,BIO_NOCLOSE); /* Create output BIO */ if ( bio_c_out == NULL ) { printf(" \n\n\t ERROR ! BIO_new_fp() failed to create stdout BIO \n\n"); exit(1); } if (bio == NULL) return(ret); if (bio_c_out == NULL) return(ret); #if BIO_DEBUG_FULL printf("\n\t +++ Running BIO Callback bio_cb() +++ BIO = %3d %%X = %0X", bio , bio ); #endif switch ( cmd ) { case BIO_CB_FREE: #if defined(BIO_DEBUG) && !defined(BIO_DEBUG_FULL) printf("\n\t +++ Running BIO Callback bio_cb() +++ BIO = %3d %%X = %0X", bio , bio ); #endif printf("\n\t - Freeing BIO = %3d %%X = %0X", bio , bio ); #if defined(BIO_DEBUG) && !defined(BIO_DEBUG_FULL) printf("\n\t --- Ending BIO Callback bio_cb() --- BIO = %3d %%X = %0X\n", bio , bio ); #endif break; case BIO_CB_READ: #if BIO_DEBUG_FULL printf("\n\t - BIO_CB_READ - Called before READ"); #endif break; case BIO_CB_READ|BIO_CB_RETURN: #if defined(BIO_DEBUG) && !defined(BIO_DEBUG_FULL) printf("\n\t +++ Running BIO Callback bio_cb() +++ BIO = %3d %%X = %0X", bio , bio ); #endif printf("\n\t BIO_CB_READ|BIO_CB_RETURN"); /* ** Dump BIO info from callback parameter data and SSL BIO_dump() */ BIO_printf( bio_c_out ,"\n\t BIO Cmd = %%X %0X from BIO %08X [%08lX] (%d bytes => %ld (0x%X))\n", cmd , bio , argp , argi , ret , ret ); BIO_dump( bio_c_out , argp , (int)ret ); #if defined(BIO_DEBUG) && !defined(BIO_DEBUG_FULL) printf("\n\t --- Ending BIO Callback bio_cb() --- BIO = %3d %%X = %0X\n", bio , bio ); #endif break; case BIO_CB_WRITE: #if BIO_DEBUG_FULL printf("\n\t - BIO_CB_WRITE - Called before Write"); #endif break; case BIO_CB_WRITE|BIO_CB_RETURN: #if defined(BIO_DEBUG) && !defined(BIO_DEBUG_FULL) printf("\n\t +++ Running BIO Callback bio_cb() +++ BIO = %3d %%X = %0X", bio , bio ); #endif printf("\n\t BIO_CB_WRITE|BIO_CB_RETURN"); /* ** Dump BIO info from callback parameter data and SSL BIO_dump() */ BIO_printf( bio_c_out ,"\n\t BIO Cmd = %%X %0X from BIO %08X [%08lX] (%d bytes => %ld (0x%X))\n", cmd , bio , argp , argi , ret , ret ); BIO_dump( bio_c_out , argp , (int)ret ); #if defined(BIO_DEBUG) && !defined(BIO_DEBUG_FULL) printf("\n\t --- Ending BIO Callback bio_cb() --- BIO = %3d %%X = %0X\n", bio , bio ); #endif break; case BIO_CB_PUTS: #if BIO_DEBUG_FULL printf("\n\t BIO_CB_PUTS - Called before Puts"); #endif break; case BIO_CB_PUTS|BIO_CB_RETURN: #if BIO_DEBUG_FULL printf("\n\t BIO_CB_PUTS|BIO_CB_RETURN"); #endif break; case BIO_CB_GETS: #if BIO_DEBUG_FULL printf("\n\t BIO_CB_GETS - Called before Gets"); #endif break; case BIO_CB_GETS|BIO_CB_RETURN: #if BIO_DEBUG_FULL printf("\n\t BIO_CB_PUTS|BIO_CB_RETURN"); #endif break; case BIO_CB_CTRL: #if BIO_DEBUG_FULL printf("\n\t BIO_CB_CTRL - Called before Control"); #endif break; case BIO_CB_CTRL|BIO_CB_RETURN: #if BIO_DEBUG_FULL printf("\n\t BIO_CB_CTRL|BIO_CB_RETURN\n"); #endif break; default: printf("\n\t Unkown BIO Callback Operation = %d %%X = %0X", cmd , cmd ); } #if BIO_DEBUG_FULL printf("\n\t --- Ending BIO Callback bio_cb() --- BIO = %3d %%X = %0X\n", bio , bio ); #endif return(ret); } /* End - Routine bio_cb() */ #endif /* End - BIO_DEBUG or BIO_DEBUG_FULL */ /* ** FUNCTIONAL DESCRIPTION: ** ** get_error( SSL *ssl , int ret , const char *msg , ** const char *file , int lineno ) ** ** This routine handles fetching the errors from the SSL error ** queue, revealing problems with the client connection, server accept, ** or read write failures. ** ** A macro, check_error(), defines the get_error() function. When called: ** with an SSL pointer, the error code returned to be checked, and a ** message string (constant char pointer), ** ** check_error(ssl, ret, msg); ** ** The get_error() routine will print the source file name and line number ** where it was called and message. Then it will attempt to read the SSL ** error queue, fetching the earliest error first, and if it's a valid ** error code, it will pop all the errors off the queue (FIFO style). ** ** ** FORMAL PARAMETERS: ** ** SSL *ssl : Pointer to an SSL object (connection) ** int ret : Error code to be checked ** const char *msg : "String message associated with error code" ** const char *file: This file name __FILE__ ** int lineno : Line number __LINE__ where check_error occurred ** ** RETURN VALUE: ** ** void (none) ** ** SIDE EFFECTS: ** ** The SSL error message queue will be emptied. ** ** DESIGN: ** ** {@description or none@} ** ** CALLING SEQUENCE: ** ** As defined by macro definition, the file and line number are implied: ** ** check_error(ssl, ret, msg); ** ** ...implies the following ** ** __FILE__ : This file name ** __LINE__ : Line number where check_error occurred ** ** ... or ** ** get_error(ssl, ret, msg, __FILE__, __LINE__) ** */ void get_error( SSL *ssl , int ret , const char *msg , const char *file , int lineno ) { fprintf(stderr, "\n %s \n\t source: %s \n\t line number: %i \n", msg , file, lineno ); printf("\n\t SSL_get_error() returns earliest error in queue = "); /* ** SSL_get_error() pops (removes) earliest error from queue ** ** Note: ** ** check for new error codes when porting newer SSL versions ** --------------- */ switch( ret = SSL_get_error(ssl,ret) ) { case SSL_ERROR_NONE: printf("SSL_ERROR_NONE"); break; case SSL_ERROR_ZERO_RETURN: printf("SSL_ERROR_ZERO_RETURN"); break; case SSL_ERROR_WANT_READ: printf("SSL_ERROR_WANT_READ"); break; case SSL_ERROR_WANT_WRITE: printf("SSL_ERROR_WANT_WRITE"); break; case SSL_ERROR_WANT_CONNECT: printf("SSL_ERROR_WANT_CONNECT"); break; case SSL_ERROR_WANT_X509_LOOKUP: printf("SSL_ERROR_WANT_X509_LOOKUP"); break; case SSL_ERROR_SYSCALL: printf("SSL_ERROR_SYSCALL"); break; case SSL_ERROR_SSL: printf("SSL_ERROR_SSL"); break; default: printf("SSL_get_error() return code was not 0--7, \ check SSL source for new error codes."); } if ( ret != SSL_ERROR_NONE ) { printf("\n\t SSL error code %d encountered.", ret ); printf("\n\t . . . attempting to get next error queued . . .\n"); ERR_print_errors_fp(stderr); printf("\n\n Exiting . . .\n"); exit(SS$_NORMAL); } } /* End - Routine get_error() */ /* ** FUNCTIONAL DESCRIPTION: ** ** get_info( const SSL *ssl , int state, int ret ); ** ** This get_info() routine obtains SSL state information ** ** FORMAL PARAMETERS: ** ** SSL *ssl : Pointer to an SSL object (connection) ** int state : State bitmask to be checked ** int ret : If ret == 0, an error occurred. ** If an alert is handled, SSL_CB_ALERT is set ** and ret specifies the alert information. ** RETURN VALUE: ** ** void (none) ** ** SIDE EFFECTS: ** ** Prints information about the SSL connection, for example: ** ** " Info Callback state = 8193, ret code = 1 ** SSL_CB_ACCEPT_LOOP ** SSLv3 read client key exchange A " ** DESIGN: ** ** When get_info() is called back, 'state' holds the state to be checked. ** If ret == 0, then we have an error, else its an alert and ** ret specifies the alert error information (state == SSL_CB_ALERT). ** ** Note: ** ** check for new error codes when porting newer SSL versions. ** --------------- ** ** Refer to SSL [.APPS]S_CB.C and SSL.H source code for further ** details of callback information. ** ** ** CALLING SEQUENCE: ** ** This routine is an SSL callback function, called by SSL during the ** connection to provide state information. That is, once the application ** defines the callback routine with the following SSL function: ** ** SSL_set_info_callback( ssl , get_info ); ** ** ssl = a pointer to the SSL object ** get_info = a pointer to this routine */ void get_info( const SSL *ssl , int state , int ret ) { printf("\n Info Callback state = %d, ret code = %d", state , ret ); switch( state ) { case SSL_CB_LOOP: printf("\n\t SSL_CB_LOOP"); printf("\n\t %s \n\t", SSL_state_string_long(ssl) ); break; case SSL_CB_EXIT: printf("\n\t SSL_CB_EXIT \n"); if (ret == 0) { printf("\n\t !!! Failure !!! Failure code = %d , Failure = \n\t %s \n", state , SSL_state_string_long(ssl) ); } else if (ret < 0) { printf("\n\t !!! Error !!! Error code = %d , Error = \n\t %s \n", state , SSL_state_string_long(ssl) ); } break; case SSL_CB_READ: printf("\n\t SSL_CB_READ \n"); break; case SSL_CB_WRITE: printf("\n\t SSL_CB_WRITE \n"); break; case SSL_CB_ALERT: printf("\n\t SSL_CB_ALERT, Alert error code = %d", ret ); printf("\n\t SSL3 alert %s : %s \n", SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); break; case SSL_CB_READ_ALERT: printf("\n\t SSL_CB_READ_ALERT"); printf("\n\t Alert = %s:%s\n", SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); break; case SSL_CB_WRITE_ALERT: printf("\n\t SSL_CB_WRITE_ALERT"); printf("\n\t Alert = %s:%s\n", SSL_alert_type_string_long(ret), SSL_alert_desc_string_long(ret)); break; case SSL_CB_ACCEPT_LOOP: printf("\n\t SSL_CB_ACCEPT_LOOP"); printf("\n\t %s \n\t", SSL_state_string_long(ssl) ); break; case SSL_CB_ACCEPT_EXIT: printf("\n\t SSL_CB_ACCEPT_EXIT \n"); if (ret == 0) { printf("\n\t !!! Failure !!! Failure code = %d , Failure = \n\t %s \n", state , SSL_state_string_long(ssl) ); } else if (ret < 0) { printf("\n\t !!! Error !!! Error code = %d , Error = \n\t %s \n", state , SSL_state_string_long(ssl) ); } break; case SSL_CB_CONNECT_LOOP: printf("\n\t SSL_CB_CONNECT_LOOP"); printf("\n\t %s \n\t", SSL_state_string_long(ssl) ); break; case SSL_CB_CONNECT_EXIT: printf("\n\t SSL_CB_CONNECT_EXIT \n"); if (ret == 0) { printf("\n\t !!! Failure !!! Failure code = %d , Failure = \n\t %s \n", state , SSL_state_string_long(ssl) ); } else if (ret < 0) { printf("\n\t !!! Error !!! Error code = %d , Error = \n\t %s \n", state , SSL_state_string_long(ssl) ); } break; case SSL_CB_HANDSHAKE_START: printf("\n\t SSL_CB_HANDSHAKE_START \n"); break; case SSL_CB_HANDSHAKE_DONE: printf("\n\t SSL_CB_HANDSHAKE_DONE \n"); break; default: printf("\n\t Callback from SSL to get_info() code was not \ decoded. Check SSL source for new state information. \n"); } } /* End - Routine get_info() */ /* * FUNCTIONAL DESCRIPTION: get_serv_addr() * * This function gets the server host's address from the user and then * stores it in the server's socket address structure. Note that the * user can specify a server host by using either an IPv4 address in * dotted-decimal notation (e.g. 16.20.10.126) or a host domain name * (e.g. serverhost.hp.com). * * SYNOPSIS: * * void get_serv_addr( void *addrptr ) * * FORMAL PARAMETERS: * * addrptr - pointer to socket address structure's 'sin_addr' field * to store the specified network address * * IMPLICIT INPUTS: * * ** None ** * * IMPLICIT OUTPUTS: * * ** None ** * * FUNCTION VALUE: * * ** None ** * * SIDE EFFECTS: * * Program execution is terminated if unable to read user's input. * */ void get_serv_addr( void *addrptr ) { char buf[BUFSZ] = { 0 }; struct in_addr val; struct hostent *host; while ( TRUE ) { memmove( buf , SERVER_ADDR , sizeof(SERVER_ADDR) ); if ( buf[0] == 0 ) { printf( " Enter remote host: " ); if ( fgets(buf, sizeof(buf), stdin) == NULL ) { printf( "Failed to read user input\n" ); exit( EXIT_FAILURE ); } buf[strlen(buf)-1] = 0; } val.s_addr = inet_addr( buf ); if ( val.s_addr != INADDR_NONE ) { memcpy( addrptr, &val, sizeof(struct in_addr) ); break; } if ( (host = gethostbyname(buf)) ) { memcpy( addrptr, host->h_addr, sizeof(struct in_addr) ); break; } } } /* End - Routine get_serv_addr() */ /* This function is from p.413 of "Rescorla 2001" */ int password_cb(char *buf, int num, int rwflag, void *ud_passwd) { sprintf( f_data ,"----- Running password_cb() -----\n \t -- User data (password) = %s", (char *)ud_passwd); print_it( f_data ); if(num < strlen(ud_passwd) + 1){ return(0); } strcpy(buf,ud_passwd); return(strlen(ud_passwd)); } /* End - Routine password_cb() */ void print_it( char * message ) { /* ** Print a message, prefixed with a sequence number */ static int i = 0; printf(" %d. \t %s \n", ++i , message ); } /* End - Routine print_it() */ void print_stats(BIO *bio, SSL_CTX *ssl_ctx) { sprintf( f_data ,"----- Printing session statistics -----"); print_it( f_data ); BIO_printf(bio,"%4ld items in the session cache\n", SSL_CTX_sess_number(ssl_ctx)); BIO_printf(bio,"%4d client connects (SSL_connect())\n", SSL_CTX_sess_connect(ssl_ctx)); BIO_printf(bio,"%4d client renegotiates (SSL_connect())\n", SSL_CTX_sess_connect_renegotiate(ssl_ctx)); BIO_printf(bio,"%4d client connects that finished\n", SSL_CTX_sess_connect_good(ssl_ctx)); BIO_printf(bio,"%4d server accepts (SSL_accept())\n", SSL_CTX_sess_accept(ssl_ctx)); BIO_printf(bio,"%4d server renegotiates (SSL_accept())\n", SSL_CTX_sess_accept_renegotiate(ssl_ctx)); BIO_printf(bio,"%4d server accepts that finished\n", SSL_CTX_sess_accept_good(ssl_ctx)); BIO_printf(bio,"%4d session cache hits\n",SSL_CTX_sess_hits(ssl_ctx)); BIO_printf(bio,"%4d session cache misses\n",SSL_CTX_sess_misses(ssl_ctx)); BIO_printf(bio,"%4d session cache timeouts\n",SSL_CTX_sess_timeouts(ssl_ctx)); BIO_printf(bio,"%4d callback cache hits\n",SSL_CTX_sess_cb_hits(ssl_ctx)); BIO_printf(bio,"%4d cache full overflows (%d allowed)\n", SSL_CTX_sess_cache_full(ssl_ctx), SSL_CTX_sess_get_cache_size(ssl_ctx)); } /* End - Routine print_stats() */ #define HEADER_SSL_EXAMPLES_H #endif