2
805

Programming the SSL library

Learn how to program in C the dialog in SSL between a client and a server. Write a first program which displays the digital fingerprint of the certificate of the server then a second program which sends a GET request to a server in HTTPS and displays the response. Finish with a program which shows how to organize the exchanges in SSL between a client and a server in memory.

Diagram

Install the development environment:

$ sudo apt-get install libssl-dev

Download sslfingerprint.c:

Compile sslfingerprint.c:

$ gcc -Wall -o sslfingerprint sslfingerprint.c -lssl

Display the fingerprint of the certificate of the server of frasq.org:

$ ./sslfingerprint -h frasq.org
51:56:f0:67:3a:9b:ed:56:b7:0c:a9:56:1d:48:13:bc:9d:51:a5:15

Try with the server of google.com:

$ ./sslfingerprint -h google.com -p 443
50:56:4e:3d:54:6d:a9:cf:4a:75:f9:33:a2:8c:c1:83:0f:00:e8:d0
  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <netinet/in.h>
  4. #include <netdb.h>
  5.  
  6. #include <stdio.h>
  7. #include <errno.h>
  8.  
  9. #include <unistd.h>
  10.  
  11. #include <openssl/ssl.h>
  12. #include <openssl/err.h>
  13.  
  14. #define HOSTADDR    INADDR_LOOPBACK             /* 0x7F000001U */
  15. #define PORTNUM     443
  16.  
  17. struct {
  18.     int host_ip;
  19.     int port_num;
  20.     int socket;
  21.     SSL_CTX *ctx;
  22.     SSL *ssl;
  23. } app;

Includes the definitions and the declarations used by the program. The global variable app contains the application object. This structure memorizes the IP address of the server and the port number of the remote program, the socket of the connection with the server, the SSL context and the SSL object. HOSTADDR is defined to the default address of the server, i.e. 127.0.0.1, PORTNUM to 443, the default port number of a HTTPS server.

  1. int open_conn() {
  2.     int sd = -1;
  3.     struct sockaddr_in sd_address;
  4.     int addrlen = sizeof(struct sockaddr_in);
  5.  
  6.     if ( (sd = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP )) == -1 )
  7.         goto error;
  8.  
  9.     sd_address.sin_family = AF_INET;
  10.     sd_address.sin_addr.s_addr = app.host_ip;   /* already in network order */
  11.     sd_address.sin_port = app.port_num;         /* see init */
  12.  
  13.     if ( connect( sd, (struct sockaddr *) &sd_address, addrlen ) == -1 )
  14.         goto error;
  15.  
  16.     app.socket = sd;
  17.  
  18.     return 1;
  19.  
  20. error:
  21.  
  22.     perror( 0 );
  23.     if ( sd != -1 )
  24.         close( sd );
  25.  
  26.     return 0;
  27. }

open_conn opens a connection with a remote program at the IP address and port number given in app. The number of the socket descriptor is saved in app.

  1. void close_conn() {
  2.     if ( app.socket != -1 ) {
  3.         close( app.socket );
  4.         app.socket = -1;
  5.     }
  6. }

close_conn closes the connection of the socket saved in app.

  1. void init_ssl() {
  2.     SSL_library_init();
  3. #if 1
  4.     SSL_load_error_strings();
  5. #endif
  6. }

init_ssl begins using the SSL library. SSL_load_error_strings loads the error messages.

NOTE: SSL_load_error_strings is only necessary if the program calls the function ERR_print_errors or a variation of it.

SSL_library_init SSL_load_error_strings ERR_print_errors

  1. void end_ssl() {
  2.     EVP_cleanup();
  3. }

end_ssl ends using the SSL library.

EVP_cleanup

  1. int start_ssl() {
  2.     SSL_CTX *ctx = 0;
  3.     SSL *ssl = 0;
  4.  
  5.     BIO *bior, *biow;
  6.  
  7.     /* create SSL context (only for v3) */
  8.     if ( (ctx = SSL_CTX_new( SSLv3_method() )) == 0 )
  9.         goto error;
  10.  
  11.     /* create SSL engine */
  12.     if ( (ssl = SSL_new( ctx )) == 0 )
  13.         goto error;
  14.  
  15.     /* connect SSL engine to r/w buffers in memory */
  16.     bior = BIO_new( BIO_s_mem() );
  17.     biow = BIO_new( BIO_s_mem() );
  18.     SSL_set_bio( ssl, bior, biow );
  19.  
  20.     /* be a client */
  21.     SSL_set_connect_state(ssl);
  22.  
  23.     app.ctx = ctx;
  24.     app.ssl = ssl;
  25.  
  26.     return 1;
  27.  
  28. error:
  29.  
  30.     ERR_print_errors_fp( stderr );
  31.     if ( ctx )
  32.         SSL_CTX_free( ctx );
  33.     if ( ssl )
  34.         SSL_free( ssl );
  35.  
  36.     return 0;
  37. }

start_ssl initializes the SSL context and the SSL object, creates the read and write buffers associated with the SSL object then sets the SSL object in client mode with SSL_set_connect_state. The addresses of the SSL context and the SSL object are saved in app.

In case of error, the code displays the SSL errors then frees if necessary the SSL context and the SSL object.

SSL_CTX_new SSL_new BIO_s_mem BIO_new SSL_set_bio SSL_set_connect_state ERR_print_errors

  1. void stop_ssl() {
  2.     if ( app.ctx != 0 ) {
  3.         SSL_CTX_free( app.ctx );
  4.         app.ctx = 0;
  5.     }
  6.     if ( app.ssl != 0 ) {
  7.         SSL_free( app.ssl );
  8.         app.ssl = 0;
  9.     }
  10. }

stop_ssl frees SSL context and the SSL object saved in app.

SSL_CTX_free SSL_free

  1. void quit( int ret ) {
  2.     close_conn();
  3.  
  4.     stop_ssl();
  5.     end_ssl();
  6.  
  7.     exit( ret );
  8. }

quit closes the connection with the server, frees the SSL resources then terminates the program with the return code ret.

  1. int inject_ssl( const SSL* ssl, const unsigned char *buffer, unsigned buffer_size ) {
  2.     BIO * bior = SSL_get_rbio( ssl );
  3.  
  4.     return BIO_write( bior, buffer, buffer_size );
  5. }

inject_ssl copies at most buffer_size bytes at the address buffer in the input buffer of the SSL engine ssl and returns the number of bytes actually copied or 0 or -1 in case of error.

SSL_get_rbio BIO_write

  1. int extract_ssl( const SSL* ssl, unsigned char *buffer, unsigned buffer_size ) {
  2.     BIO * biow = SSL_get_wbio( ssl );
  3.  
  4.     return BIO_read( biow, buffer, buffer_size );
  5. }

extract_ssl copies at most buffer_size bytes from the output buffer of the SSL engine ssl to the address buffer and returns the number of bytes actually copied or 0 or -1 in case of error.

SSL_get_wbio BIO_read

  1. int read_socket() {
  2.     unsigned char buffer[ 4*1024 ];
  3.  
  4.     /* pipe server data to SSL engine */
  5.     int r = read( app.socket, buffer, sizeof(buffer) );
  6.     if ( r == 0 ) {
  7.         return 0;
  8.     }
  9.  
  10.     inject_ssl( app.ssl, buffer, r );
  11.  
  12.     return 1;
  13. }

read_socket injects the bytes read from the socket of the application into the SSL engine.

  1. int write_socket() {
  2.     unsigned char buffer[ 4*1024 ];
  3.  
  4.     /* pipe SSL engine data to server socket */
  5.     int r = extract_ssl( app.ssl, buffer, sizeof(buffer) );
  6.  
  7.     if ( write( app.socket, buffer, r ) != r )
  8.         return 0;
  9.  
  10.     return 1;
  11. }

write_socket writes the bytes extracted from the SSL engine to the socket of the application.

  1. void startup() {
  2.     init_ssl();
  3.  
  4.     if ( !start_ssl() )
  5.         exit( 1 );
  6.  
  7.     if ( !open_conn() )
  8.         exit( 1 );
  9. }

startup begins using the SSL library, creates and configures the SSL object and opens the connection with the server.

  1. void init() {
  2.     app.host_ip = htonl( HOSTADDR );
  3.     app.port_num = htons( PORTNUM );
  4.     app.socket = -1;
  5. }

init initializes app.

  1. void doit() {
  2.     fd_set read_fds, write_fds;
  3.     int n_fds = FD_SETSIZE;
  4.  
  5.     SSL *ssl = app.ssl;
  6.     BIO * biow = SSL_get_wbio( ssl );
  7.  
  8.     for ( ;; ) {
  9.         FD_ZERO( &read_fds );
  10.         FD_ZERO( &write_fds );
  11.  
  12.         /* retry handshake until done (reads SSL bior) */
  13.         if ( SSL_in_init(ssl)) {
  14.             SSL_do_handshake( ssl );
  15.         }
  16.  
  17.         /* are we connected? (MUST be done after retrying handshake) */
  18.         if ( SSL_is_init_finished( ssl ) ) {
  19.             break;
  20.         }
  21.  
  22.         /* read input from server */
  23.         FD_SET( app.socket, &read_fds );
  24.  
  25.         /* write SSL engine output to server */
  26.         if ( BIO_pending(biow) ) {
  27.             FD_SET( app.socket, &write_fds );
  28.         }
  29.  
  30.         switch ( select( n_fds, &read_fds, &write_fds, 0, 0 ) ) {
  31.         case -1:    /* trouble */
  32.             if ( errno != EINTR ) {
  33.                 perror( 0 );
  34.                 quit( 1 );
  35.             }
  36.             break;
  37.         case 0:     /* time out */
  38.             break;
  39.         default:    /* event */
  40.             if ( FD_ISSET(app.socket, &read_fds) ) {
  41.                 if ( ! read_socket() ) {
  42.                     fputs( "read failed?\n", stderr );
  43.                     quit( 1 );
  44.                 }
  45.             }
  46.             if ( FD_ISSET(app.socket, &write_fds) ) {
  47.                 if ( ! write_socket() ) {
  48.                     fputs( "write failed?\n", stderr );
  49.                     quit( 1 );
  50.                 }
  51.             }
  52.             break;
  53.         }
  54.     }
  55.  
  56.     /* get certificate */
  57.     X509 *cert = SSL_get_peer_certificate( ssl );
  58.  
  59.     if ( ! cert ) {
  60.         fputs( "cert?\n", stderr );
  61.         quit( 1 );
  62.     }
  63.  
  64.     /* get certificate digest (SHA1) */
  65.     EVP_MD *digest = (EVP_MD*) EVP_sha1();
  66.  
  67.     unsigned char data[EVP_MAX_MD_SIZE];
  68.     unsigned int len;
  69.  
  70.     if ( ! (X509_digest(cert, digest, data, &len) > 0) ) {
  71.         fputs( "cert?\n", stderr );
  72.         quit( 1 );
  73.     }
  74.  
  75.     /* print certificate */
  76.     unsigned char *p;
  77.     for (p = data; p < data + len; p++)
  78.         fprintf(stdout, p == data ? "%02x" : ":%02x", *p);
  79.     fputs("\n", stdout);
  80. }

doit loops as long as the negotiation with the server in SSL isn't terminated, i.e. as long as the function SSL_is_init_finished returns 0. The negotiation is initalized with SSL_do_handshake if SSL_in_init returns 1. Once the negotiation is initialized, the code just keeps managing data exchanges between the SSL engine and the server. All the contents prepared by the SSL engine are sent to the server. Conversely, all the contents returned by the server are transmitted to the SSL engine. Once the SSL connection is established, doit gets the certificate of the server and displays it hexadecimal.

SSL_do_handshake

  1. int main( int argc, char **argv ) {
  2.     struct hostent *host;
  3.     int port_num;
  4.  
  5.     extern int opterr;
  6.     int c;
  7.  
  8.     init();
  9.  
  10.     opterr = 0;
  11.  
  12.     while ( (c = getopt( argc, argv, "h:p:" )) != -1 ) {
  13.         switch ( c ) {
  14.         case 'p':
  15.             if ( (port_num = atoi( optarg )) == 0 ) {
  16.                 fputs( "portnum?\n", stderr );
  17.                 exit( 1 );
  18.             }
  19.             app.port_num = htons( port_num );
  20.             break;
  21.         case 'h':
  22.             if ( (host = gethostbyname( optarg )) == 0 ) {
  23.                 fputs( "hostname?\n", stderr );
  24.                 exit( 1 );
  25.             }
  26.             app.host_ip = *((unsigned *) host->h_addr);
  27.             endhostent();
  28.             break;
  29.         case '?':
  30.         default:
  31. usage:      fprintf( stderr, "%s [-h host_name] [-p port_num]\n", argv[0] );
  32.             exit( 1 );
  33.         }
  34.     }
  35.  
  36.     switch ( argc - optind ) {
  37.     case 0:
  38.         break;
  39.     default:
  40.         goto usage;
  41.     }
  42.  
  43.     startup();
  44.     doit();
  45.  
  46.     exit(0);
  47. }

main initializes app with init then parses the arguments on the command-line. The option -h allows to specify a host name, the option -p a port number. In case of error on the command-line, the proper usage of the program is displayed and the program is terminated with the return code 1. If everything is in order, the program calls startup then doit and terminates itself with the return code 0.

Compile sslsock.c:

$ gcc -Wall -o sslsock sslsock.c -lssl -lcrypto
GET /robots.txt HTTP/1.1
Host: frasq.org

Run the program while specifying frasq.org as host and with req.txt as input flow:

$ ./sslsock -h frasq.org < req.txt
SSL_ERROR_WANT_NOTHING
biow=0
bior=0
pending=0
UNKWN 
SSL_ST_BEFORE
SSL_ST_INIT
SSL_ST_CONNECT_INIT
SSL_do_handshake
SSL_CB_LOOP UNKWN  before/connect initialization
SSL_CB_LOOP 3WCH_A SSLv3 write client hello A
SSL_CB_EXIT 3RSH_A SSLv3 read server hello A
biow=58
bior=0
pending=0
socket write
extract_ssl
r=58
SSL_ERROR_WANT_READ
biow=0
bior=0
pending=0
3RSH_A
SSL_ST_INIT
SSL_ST_CONNECT_INIT
SSL_do_handshake
SSL_CB_EXIT 3RSH_A SSLv3 read server hello A
biow=0
bior=0
pending=0
socket read
r=1024
inject_ssl
SSL_ERROR_WANT_READ
biow=0
bior=1024
pending=0
3RSH_A
SSL_ST_INIT
SSL_ST_CONNECT_INIT
SSL_do_handshake
SSL_CB_LOOP 3RSH_A SSLv3 read server hello A
SSL_CB_EXIT 3RSC_A SSLv3 read server certificate A
biow=0
bior=0
pending=0
socket read
r=416
inject_ssl
SSL_ERROR_WANT_READ
biow=0
bior=416
pending=0
3RSC_A
SSL_ST_INIT
SSL_ST_CONNECT_INIT
SSL_do_handshake
SSL_CB_EXIT 3RSC_A SSLv3 read server certificate A
biow=0
bior=0
pending=0
socket read
r=1024
inject_ssl
SSL_ERROR_WANT_READ
biow=0
bior=1024
pending=0
3RSC_A
SSL_ST_INIT
SSL_ST_CONNECT_INIT
SSL_do_handshake
SSL_CB_LOOP 3RSC_A SSLv3 read server certificate A
SSL_CB_EXIT 3RSKEA SSLv3 read server key exchange A
biow=0
bior=0
pending=0
socket read
r=718
inject_ssl
SSL_ERROR_WANT_READ
biow=0
bior=718
pending=0
3RSKEA
SSL_ST_INIT
SSL_ST_CONNECT_INIT
SSL_do_handshake
SSL_CB_LOOP 3RSKEA SSLv3 read server key exchange A
SSL_CB_LOOP 3RSD_A SSLv3 read server done A
SSL_CB_LOOP 3WCKEA SSLv3 write client key exchange A
SSL_CB_LOOP 3WCCSA SSLv3 write change cipher spec A
SSL_CB_LOOP 3WFINA SSLv3 write finished A
SSL_CB_LOOP 3FLUSH SSLv3 flush data
SSL_CB_EXIT 3RFINA SSLv3 read finished A
biow=342
bior=0
pending=0
socket write
extract_ssl
r=342
SSL_ERROR_WANT_READ
biow=0
bior=0
pending=0
3RFINA
SSL_ST_INIT
SSL_ST_CONNECT_INIT
SSL_do_handshake
SSL_CB_EXIT 3RFINA SSLv3 read finished A
biow=0
bior=0
pending=0
socket read
r=75
inject_ssl
SSL_ERROR_WANT_READ
biow=0
bior=75
pending=0
3RFINA
SSL_ST_INIT
SSL_ST_CONNECT_INIT
SSL_do_handshake
SSL_CB_LOOP 3RFINA SSLv3 read finished A
SSL_CB_EXIT SSLOK  SSL negotiation finished successfully
*** ready ***
SSL_get_verify_result=19
cert->valid=0
cert->name=/C=LU/ST=Luxembourg/O=mcPaLo/OU=Software/CN=kimsufi/emailAddress=webmaster@mcpalo.com
sess->cipher->name=DHE-RSA-AES256-SHA
biow=0
bior=0
pending=0
input read
r=42
write_ssl
SSL_ERROR_WANT_NOTHING
biow=106
bior=0
pending=0
biow=106
bior=0
pending=0
socket write
extract_ssl
r=106
input read
r=0
SSL_ERROR_WANT_NOTHING
biow=0
bior=0
pending=0
biow=0
bior=0
pending=0
socket read
r=346
inject_ssl
SSL_ERROR_WANT_NOTHING
biow=0
bior=346
pending=0
biow=0
bior=346
pending=0
output write
read_ssl
r=256
HTTP/1.1 200 OK
Date: Tue, 20 Oct 2015 22:52:01 GMT
Server: Apache/2.2.22 (Ubuntu)
Last-Modified: Tue, 20 Oct 2015 22:31:41 GMT
ETag: "2f1a-1a-52290d3680d40"
Accept-Ranges: bytes
Content-Length: 26
Vary: Accept-Encoding
Content-Type: text/plain


SSL_ERROR_WANT_NOTHING
biow=0
bior=53
pending=0
biow=0
bior=53
pending=0
output write
read_ssl
r=26
User-agent: *
Disallow: /

SSL_ERROR_WANT_NOTHING
biow=0
bior=0
pending=0
biow=0
bior=0
pending=0

The program displays the content of the file robots.txt:

User-agent: *
Disallow: /
  1. #include <sys/types.h>
  2. #include <sys/socket.h>
  3. #include <netinet/in.h>
  4. #include <netdb.h>
  5.  
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <strings.h>
  9. #include <errno.h>
  10. #include <string.h>
  11.  
  12. #include <unistd.h>
  13.  
  14. #include <openssl/ssl.h>
  15. #include <openssl/err.h>
  16.  
  17. #if 0
  18. extern void dump(unsigned char *buf, int size, FILE *fout);
  19. #define DUMP(buf, size, fout) dump(buf, size, fout);
  20. #else
  21. #define DUMP(buf, size, fout)
  22. #endif
  23.  
  24. #define HOSTADDR    INADDR_LOOPBACK             /* 0x7F000001U */
  25. #define PORTNUM     443
  26.  
  27. #define NO_FILE     1
  28.  
  29. #define CERT_FILE   "snakeoil.crt"
  30. #define CIPHER      "DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:AES256-SHA:AES128-SHA"
  31.  
  32. struct {
  33.     int host_ip;
  34.     int port_num;
  35.     int socket;
  36.     int input;
  37.     SSL_CTX *ctx;
  38.     SSL *ssl;
  39.     int ready;
  40.     int failed;
  41. } app;
  42.  
  43. int open_conn() {
  44.     int sd = -1;
  45.     struct sockaddr_in sd_address;
  46.     int addrlen = sizeof(struct sockaddr_in);
  47.  
  48.     if ( (sd = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP )) == -1 )
  49.         goto error;
  50.  
  51.     sd_address.sin_family = AF_INET;
  52.     sd_address.sin_addr.s_addr = app.host_ip;   /* already in network order */
  53.     sd_address.sin_port = app.port_num;         /* see init */
  54.  
  55.     if ( connect( sd, (struct sockaddr *) &sd_address, addrlen ) == -1 )
  56.         goto error;
  57.  
  58.     app.socket = sd;
  59.  
  60.     return 1;
  61.  
  62. error:
  63.  
  64.     perror( 0 );
  65.     if ( sd != -1 )
  66.         close( sd );
  67.  
  68.     return 0;
  69. }
  70.  
  71. void close_conn() {
  72.     if ( app.socket != -1 ) {
  73.         close( app.socket );
  74.         app.socket = -1;
  75.     }
  76. }
  77.  
  78. void ssl_info_callback(const SSL *ssl, int where, int ret) {
  79.     if ( where & SSL_CB_LOOP ) {
  80.         fprintf( stdout, "SSL_CB_LOOP %s %s\n",
  81.                 SSL_state_string( ssl ), SSL_state_string_long( ssl ) );
  82.     }
  83.     else if ( where & SSL_CB_EXIT ) {
  84.         fprintf( stdout, "SSL_CB_EXIT %s %s\n",
  85.                 SSL_state_string( ssl ), SSL_state_string_long( ssl ) );
  86.     }
  87.     else if ( where & SSL_CB_ALERT ) {
  88.         fprintf( stdout, "SSL_CB_ALERT %s %s\n",
  89.                 SSL_alert_type_string_long( ret ),
  90.                 SSL_alert_desc_string_long( ret ) );
  91.         app.failed = 1;
  92.     }
  93. }
  94.  
  95. void init_ssl() {
  96.     SSL_library_init();
  97. #if 0
  98.     SSL_load_error_strings();
  99.     OpenSSL_add_ssl_algorithms();
  100.     ERR_load_crypto_strings();
  101. #endif
  102. }
  103.  
  104. void end_ssl() {
  105.     EVP_cleanup();
  106. }
  107.  
  108. int start_ssl() {
  109.     SSL_CTX *ctx = 0;
  110.     SSL *ssl = 0;
  111.  
  112.     BIO *bior, *biow;
  113.  
  114.     char *cipher = CIPHER;
  115.  
  116.     if ( ! (ctx = SSL_CTX_new( SSLv3_client_method() )) )
  117.         goto error;
  118.  
  119.     if ( cipher ) {
  120.         if ( ! SSL_CTX_set_cipher_list( ctx, cipher ) )
  121.             goto error;
  122.     }
  123.  
  124. #if !NO_FILE
  125.     if ( ! SSL_CTX_load_verify_locations( ctx, CERT_FILE, 0) )
  126.         goto error;
  127. #endif
  128.  
  129.     SSL_CTX_set_info_callback( ctx, ssl_info_callback );
  130.  
  131.     if ( ! (ssl = SSL_new( ctx )) )
  132.         goto error;
  133.  
  134.     bior = BIO_new( BIO_s_mem() );
  135.     biow = BIO_new( BIO_s_mem() );
  136.     SSL_set_bio( ssl, bior, biow );
  137.  
  138.     SSL_set_connect_state(ssl);
  139.  
  140.     app.ctx = ctx;
  141.     app.ssl = ssl;
  142.  
  143.     return 1;
  144.  
  145. error:
  146.  
  147.     ERR_print_errors_fp( stderr );
  148.     if ( ctx )
  149.         SSL_CTX_free( ctx );
  150.     if ( ssl )
  151.         SSL_free( ssl );
  152.  
  153.     return 0;
  154. }
  155.  
  156. void stop_ssl() {
  157.     if ( app.ctx != 0 ) {
  158.         SSL_CTX_free( app.ctx );
  159.         app.ctx = 0;
  160.     }
  161.     if ( app.ssl != 0 ) {
  162.         SSL_free( app.ssl );
  163.         app.ssl = 0;
  164.     }
  165. }
  166.  
  167. void quit( int ret ) {
  168.     close_conn();
  169.  
  170.     stop_ssl();
  171.     end_ssl();
  172.  
  173.     exit( ret );
  174. }
  175.  
  176. /*
  177.  * input_read(C, strdin) -> write_ssl(C, ssl) -> extract_ssl(X, biow) -> socket_write(X, socket)
  178.  * socket_read(X, socket) -> inject_ssl(X, bior) -> read_ssl(C, ssl) -> output_write(C, stdout)
  179.  */
  180.  
  181. int read_ssl( SSL* ssl, unsigned char *buffer, unsigned buffer_size ) {
  182.     fputs( "read_ssl\n", stdout );
  183.     int r;
  184.  
  185.     r = SSL_read( ssl, buffer, buffer_size );
  186.  
  187.     if ( r < 0 ) {
  188.         int err = SSL_get_error( ssl, r );
  189.  
  190.         if ( err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE )
  191.             r = 0;
  192.     }
  193.  
  194.     return r;
  195. }
  196.  
  197. int write_ssl( SSL* ssl, const unsigned char *buffer, unsigned buffer_size ) {
  198.     fputs( "write_ssl\n", stdout );
  199.     int r;
  200.  
  201.     r = SSL_write( ssl, buffer, buffer_size );
  202.  
  203.     if ( r < 0 ) {
  204.         int err = SSL_get_error( ssl, r );
  205.  
  206.         if ( err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE )
  207.             r = 0;
  208.     }
  209.  
  210.     return r;
  211. }
  212.  
  213. void inject_ssl( const SSL* ssl, const unsigned char *buffer, unsigned buffer_size ) {
  214.     fputs( "inject_ssl\n", stdout );
  215.     BIO * bior = SSL_get_rbio( ssl );
  216.  
  217.     BIO_write( bior, buffer, buffer_size );
  218. }
  219.  
  220. int extract_ssl( const SSL* ssl, unsigned char *buffer, unsigned buffer_size ) {
  221.     fputs( "extract_ssl\n", stdout );
  222.     BIO * biow = SSL_get_wbio( ssl );
  223.  
  224.     return BIO_read( biow, buffer, buffer_size );
  225. }
  226.  
  227. void socket_read() {
  228.     fputs( "socket read\n", stdout );
  229.     unsigned char buffer[1024];
  230.  
  231.     int r = read( app.socket, buffer, sizeof(buffer) );
  232.     fprintf( stderr, "r=%d\n", r );
  233.     if ( r == 0 ) {
  234.         app.socket = -1;
  235.     }
  236.     else {
  237.         DUMP( buffer, r, stdout );
  238.         inject_ssl( app.ssl, buffer, r );
  239.     }
  240. }
  241.  
  242. void socket_write() {
  243.     fputs( "socket write\n", stdout );
  244.     unsigned char buffer[1024];
  245.  
  246.     int r = extract_ssl( app.ssl, buffer, sizeof(buffer) );
  247.     fprintf( stderr, "r=%d\n", r );
  248.     if ( r > 0 ) {
  249.         DUMP( buffer, r, stdout );
  250.         (void) write( app.socket, buffer, r );
  251.     }
  252. }
  253.  
  254. void output_write() {
  255.     fputs( "output write\n", stdout );
  256.     unsigned char buffer[1024];
  257.  
  258.     int r = read_ssl( app.ssl, buffer, sizeof (buffer) );
  259.     fprintf( stderr, "r=%d\n", r );
  260.     if ( r < 0 ) {
  261.         ERR_print_errors_fp( stderr );
  262.         quit( 3 );
  263.     }
  264.     if ( r == 0 )
  265.         return;
  266.  
  267.     write( 1, buffer, r );
  268.     write( 1, "\n", 1 );
  269. }
  270.  
  271. void input_read() {
  272.     fputs( "input read\n", stdout );
  273.     unsigned char buffer[1024];
  274.  
  275.     int r = read( 0, buffer, sizeof (buffer) );
  276.     fprintf( stderr, "r=%d\n", r );
  277.     if ( r == 0 ) {
  278.         app.input = 0;
  279.         return;
  280.     }
  281.  
  282.     DUMP( buffer, r, stdout );
  283.     int w = write_ssl( app.ssl, buffer, r );
  284.     if ( w < 0 ) {
  285.         ERR_print_errors_fp( stderr );
  286.         quit( 3 );
  287.     }
  288.     if ( w == 0 )
  289.         return;
  290. }
  291.  
  292. void startup() {
  293.     init_ssl();
  294.  
  295.     if ( !open_conn() )
  296.         exit( 1 );
  297.     if ( !start_ssl() )
  298.         exit( 1 );
  299. }
  300.  
  301. void init() {
  302.     app.host_ip = htonl( HOSTADDR );
  303.     app.port_num = htons( PORTNUM );
  304.     app.socket = -1;
  305.     app.input = 1;
  306.     app.ready = 0;
  307.     app.failed = 0;
  308. }
  309.  
  310. void main_loop() {
  311.     fd_set read_fds, write_fds;
  312.     int n_fds = FD_SETSIZE;
  313.  
  314.     SSL *ssl = app.ssl;
  315.     BIO * bior = SSL_get_rbio( ssl );
  316.     BIO * biow = SSL_get_wbio( ssl );
  317.  
  318.     for ( ;; ) { /* forever */
  319.         FD_ZERO( &read_fds );
  320.         FD_ZERO( &write_fds );
  321.  
  322.         if ( SSL_want_nothing(ssl) )
  323.             fputs( "SSL_ERROR_WANT_NOTHING\n", stdout );
  324.         if ( SSL_want_read(ssl) )
  325.             fputs( "SSL_ERROR_WANT_READ\n", stdout );
  326.         if ( SSL_want_write(ssl) )
  327.             fputs( "SSL_ERROR_WANT_WRITE\n", stdout );
  328.         if ( SSL_want_x509_lookup(ssl) )
  329.             fputs( "SSL_ERROR_WANT_X509_LOOKUP\n", stdout );
  330.  
  331.         fprintf( stdout, "biow=%d\n", BIO_pending(biow) );
  332.         fprintf( stdout, "bior=%d\n", BIO_pending(bior) );
  333.         fprintf( stdout, "pending=%d\n", SSL_pending( ssl ) );
  334.  
  335.         if ( !app.ready && !app.failed ) {
  336.             fprintf( stdout, "%s\n", SSL_state_string( ssl ) );
  337.  
  338.             if ( SSL_in_before(ssl) )
  339.                 fputs( "SSL_ST_BEFORE\n", stdout );
  340.             if ( SSL_in_init(ssl) )
  341.                 fputs( "SSL_ST_INIT\n", stdout );
  342.             if ( SSL_in_connect_init(ssl) )
  343.                 fputs( "SSL_ST_CONNECT_INIT\n", stdout );
  344.             if ( SSL_in_accept_init(ssl) )
  345.                 fputs( "SSL_ST_ACCEPT_INIT\n", stdout );
  346.  
  347.             if ( SSL_in_init(ssl)) {
  348.                 fputs( "SSL_do_handshake\n", stdout );
  349.                 SSL_do_handshake( ssl );
  350.             }
  351.             if ( SSL_is_init_finished( ssl ) ) {
  352.                 app.ready = 1;
  353.                 fputs( "*** ready ***\n", stdout );
  354.                 fprintf( stdout, "SSL_get_verify_result=%ld\n", SSL_get_verify_result( ssl ) );
  355.  
  356.                 X509 *cert = SSL_get_peer_certificate( ssl );
  357.                 if ( cert ) {
  358.                     fprintf( stdout, "cert->valid=%d\n", cert->valid );
  359.                     fprintf( stdout, "cert->name=%s\n", cert->name );
  360.                 }
  361.                 SSL_SESSION *sess = SSL_get_session( ssl );
  362.                 if ( sess ) {
  363.                     fprintf( stdout, "sess->cipher->name=%s\n", sess->cipher->name );
  364.                 }
  365.             }
  366.         }
  367.  
  368.         fprintf( stdout, "biow=%d\n", BIO_pending(biow) );
  369.         fprintf( stdout, "bior=%d\n", BIO_pending(bior) );
  370.         fprintf( stdout, "pending=%d\n", SSL_pending( ssl ) );
  371.  
  372.         /* socket? */
  373.         if ( app.socket != -1 ) {
  374.             FD_SET( app.socket, &read_fds );
  375.         }
  376.  
  377.         /* read input? */
  378.         if ( app.ready && app.input ) {
  379.             FD_SET( 0, &read_fds );
  380.         }
  381.  
  382.         if ( BIO_pending(biow) ) {
  383.             if ( app.socket != -1 )
  384.                 FD_SET( app.socket, &write_fds );
  385.         }
  386.         if ( BIO_pending(bior) ) {
  387.             FD_SET( 1, &write_fds );
  388.         }
  389.  
  390.         if ( SSL_pending( ssl ) ) {
  391.             FD_SET( 1, &write_fds );
  392.         }
  393.  
  394.         if ( !app.input && app.socket == -1 && !SSL_pending( ssl ) )
  395.             quit( 0 );
  396.  
  397.         switch ( select( n_fds, &read_fds, &write_fds, 0, 0 ) ) {
  398.         case -1: /* trouble */
  399.             if ( errno != EINTR ) {
  400.                 perror( 0 );
  401.                 quit( 1 );
  402.             }
  403.             break;
  404.         case 0: /* time out */
  405.             break;
  406.         default: /* event */
  407.             if ( app.socket != -1 && FD_ISSET(app.socket, &read_fds) ) {
  408.                 socket_read();
  409.             }
  410.             if ( FD_ISSET(1, &write_fds) ) {
  411.                 output_write();
  412.             }
  413.             if ( app.socket != -1 && FD_ISSET(app.socket, &write_fds) ) {
  414.                 socket_write();
  415.             }
  416.             if ( FD_ISSET( 0, &read_fds ) ) {
  417.                 input_read();
  418.             }
  419.             break;
  420.         }
  421.     }
  422. }
  423.  
  424. int main( int argc, char **argv ) {
  425.     struct hostent *host;
  426.     int port_num;
  427.  
  428.     extern int opterr;
  429.     int c;
  430.  
  431.     init();
  432.  
  433.     opterr = 0;
  434.  
  435.     while ( (c = getopt( argc, argv, "h:p:" )) != -1 )
  436.         switch ( c ) {
  437.         case 'p':
  438.             if ( (port_num = atoi( optarg )) == 0 ) {
  439.                 fputs( "portnum?\n", stderr );
  440.                 exit( 1 );
  441.             }
  442.             app.port_num = htons( port_num );
  443.             break;
  444.         case 'h':
  445.             if ( (host = gethostbyname( optarg )) == 0 ) {
  446.                 fputs( "hostname?\n", stderr );
  447.                 exit( 1 );
  448.             }
  449.             app.host_ip = *((unsigned *) host->h_addr);
  450.             endhostent();
  451.             break;
  452.         case '?':
  453.         default:
  454. usage:      fprintf( stderr, "%s [-h host_name] [-p port_num]\n", argv[0] );
  455.             exit( 1 );
  456.         }
  457.  
  458.     switch ( argc - optind ) {
  459.     case 0:
  460.         break;
  461.     default:
  462.         goto usage;
  463.     }
  464.  
  465.     setbuf( stdout, 0 );
  466.  
  467.     startup();
  468.     main_loop();
  469.  
  470.     exit(0);
  471. }

Compile sslmem.c then run the program:

$ gcc -Wall -o sslmem sslmem.c -lssl -lcrypto
$ ./sslmem
[S] UNKWN 
[C] UNKWN 
[S] SSL_ERROR_WANT_NOTHING
[C] SSL_ERROR_WANT_NOTHING
[S] SSL_ST_BEFORE
[S] SSL_ST_INIT
[S] SSL_ST_ACCEPT_INIT
[S] SSL_do_handshake
[C] SSL_ST_BEFORE
[C] SSL_ST_INIT
[C] SSL_ST_CONNECT_INIT
[C] SSL_do_handshake
[S] biow=0
[S] bior=0
[C] biow=58
[C] bior=0
client read
extract_ssl
r=58
inject_ssl
r=58
[S] 3RCH_B
[C] 3RSH_A
[S] SSL_ERROR_WANT_READ
[C] SSL_ERROR_WANT_READ
[S] SSL_ST_INIT
[S] SSL_ST_ACCEPT_INIT
[S] SSL_do_handshake
[C] SSL_ST_INIT
[C] SSL_ST_CONNECT_INIT
[C] SSL_do_handshake
[S] biow=1052
[S] bior=0
[C] biow=0
[C] bior=0
server read
extract_ssl
r=1024
inject_ssl
r=1024
[S] 3RCC_A
[C] 3RSH_A
[S] SSL_ERROR_WANT_READ
[C] SSL_ERROR_WANT_READ
[S] SSL_ST_INIT
[S] SSL_ST_ACCEPT_INIT
[S] SSL_do_handshake
[C] SSL_ST_INIT
[C] SSL_ST_CONNECT_INIT
[C] SSL_do_handshake
[S] biow=28
[S] bior=0
[C] biow=0
[C] bior=0
server read
extract_ssl
r=28
inject_ssl
r=28
[S] 3RCC_A
[C] 3RSKEA
[S] SSL_ERROR_WANT_READ
[C] SSL_ERROR_WANT_READ
[S] SSL_ST_INIT
[S] SSL_ST_ACCEPT_INIT
[S] SSL_do_handshake
[C] SSL_ST_INIT
[C] SSL_ST_CONNECT_INIT
[C] SSL_do_handshake
[S] biow=0
[S] bior=0
[C] biow=214
[C] bior=0
client read
extract_ssl
r=214
inject_ssl
r=214
[S] 3RCC_A
[C] 3RFINA
[S] SSL_ERROR_WANT_READ
[C] SSL_ERROR_WANT_READ
[S] SSL_ST_INIT
[S] SSL_ST_ACCEPT_INIT
[S] SSL_do_handshake
[S] *** ready ***
[S] SSLOK 
sess->cipher->name=DHE-RSA-AES256-SHA
[C] SSL_ST_INIT
[C] SSL_ST_CONNECT_INIT
[C] SSL_do_handshake
[S] biow=75
[S] bior=0
[C] biow=0
[C] bior=0
server read
extract_ssl
r=75
inject_ssl
r=75
[S] SSLOK 
[C] 3RFINA
[S] SSL_ERROR_WANT_NOTHING
[C] SSL_ERROR_WANT_READ
[C] SSL_ST_INIT
[C] SSL_ST_CONNECT_INIT
[C] SSL_do_handshake
[C] *** ready ***
[C] SSLOK 
SSL_get_verify_result=18
cert->valid=0
cert->name=/CN=ubuntu
cert->fingerprint=fb:61:11:23:72:1b:a1:1f:11:c9:43:37:55:91:9a:99:a8:ae:f6:41
sess->cipher->name=DHE-RSA-AES256-SHA
[S] biow=0
[S] bior=0
[C] biow=0
[C] bior=0
msg=HELLO
write_ssl
[S] biow=0
[S] bior=0
[C] biow=74
[C] bior=0
client read
extract_ssl
r=74
inject_ssl
r=74
read_ssl
r=5
[S] HELLO
reply=BYE
write_ssl
[S] biow=74
[S] bior=0
[C] biow=0
[C] bior=0
server read
extract_ssl
r=74
inject_ssl
r=74
read_ssl
r=3
[C] BYE

The messages from the server are preceded by [S], the messages from the client by [C].

  1. #include <unistd.h>
  2.  
  3. #include <openssl/ssl.h>
  4. #include <openssl/err.h>
  5.  
  6. #if 0
  7. extern void dump(unsigned char *buf, int size, FILE *fout);
  8. #define DUMP(buf, size, fout) dump( buf, size, fout );
  9. #else
  10. #define DUMP(buf, size, fout)
  11. #endif
  12.  
  13. #define NO_DH       0
  14. #define NO_FILE     1
  15.  
  16. #define CERT_FILE   "snakeoil.crt"
  17. #define KEY_FILE    "snakeoil.key"
  18.  
  19. #define CIPHER      "DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:AES256-SHA:AES128-SHA"   /* DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA && NO_DH 1 fails handshake */
  20.  
  21. #if NO_FILE
  22.  
  23. /* openssl x509 -in snakeoil.crt -outform DER | xxd -i */
  24.  
  25. static unsigned char cert[] = {
  26.     0x30, 0x82, 0x01, 0x99, 0x30, 0x82, 0x01, 0x02, 0x02, 0x09, 0x00, 0x80,
  27.     0xb5, 0x35, 0x11, 0x35, 0xab, 0x15, 0x82, 0x30, 0x0d, 0x06, 0x09, 0x2a,
  28.     0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x11,
  29.     0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x06, 0x75,
  30.     0x62, 0x75, 0x6e, 0x74, 0x75, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30,
  31.     0x35, 0x32, 0x30, 0x30, 0x39, 0x33, 0x34, 0x35, 0x31, 0x5a, 0x17, 0x0d,
  32.     0x32, 0x30, 0x30, 0x35, 0x31, 0x37, 0x30, 0x39, 0x33, 0x34, 0x35, 0x31,
  33.     0x5a, 0x30, 0x11, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03,
  34.     0x13, 0x06, 0x75, 0x62, 0x75, 0x6e, 0x74, 0x75, 0x30, 0x81, 0x9f, 0x30,
  35.     0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
  36.     0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81,
  37.     0x00, 0xd3, 0xb5, 0x48, 0x6c, 0x4b, 0x18, 0x80, 0xb0, 0x14, 0xbe, 0x9f,
  38.     0x1e, 0x99, 0x03, 0xff, 0x5b, 0x47, 0x1a, 0xde, 0x54, 0x2e, 0x5e, 0x86,
  39.     0xff, 0xaa, 0x7a, 0xb7, 0x04, 0x76, 0x77, 0xd2, 0x9c, 0xc8, 0xd8, 0x8c,
  40.     0xbe, 0x1a, 0x86, 0x3d, 0x7a, 0xb3, 0xbb, 0x89, 0x2b, 0x16, 0xb9, 0xac,
  41.     0xd8, 0xe4, 0x8d, 0x66, 0x82, 0xb3, 0xd0, 0x38, 0x3d, 0xd6, 0xce, 0xd2,
  42.     0x9d, 0x2a, 0x6c, 0x39, 0x95, 0x57, 0x9a, 0xde, 0x8b, 0x5a, 0xd9, 0x35,
  43.     0xa2, 0x2c, 0x60, 0x69, 0xe9, 0x73, 0xfe, 0x15, 0x76, 0x5a, 0xb6, 0x56,
  44.     0x38, 0x47, 0x1e, 0xf9, 0x51, 0xba, 0x2c, 0x1b, 0xe4, 0x63, 0x9e, 0x6f,
  45.     0xfc, 0xac, 0xb8, 0x0a, 0x07, 0xac, 0x72, 0x9f, 0xb7, 0x0a, 0x64, 0x57,
  46.     0xf2, 0x53, 0x8a, 0xdf, 0x3a, 0x1e, 0x0f, 0x65, 0x2f, 0xa4, 0x92, 0x92,
  47.     0x30, 0x5c, 0x6c, 0x3e, 0x04, 0x49, 0x99, 0x58, 0xef, 0x02, 0x03, 0x01,
  48.     0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
  49.     0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x2e, 0x94, 0x77,
  50.     0xfb, 0x45, 0x59, 0x71, 0x75, 0x74, 0x88, 0x78, 0x05, 0x24, 0x6f, 0x18,
  51.     0xf9, 0x3f, 0x3d, 0xd8, 0x52, 0x2e, 0x01, 0xc4, 0x41, 0x95, 0xe3, 0x62,
  52.     0x7d, 0x6a, 0x1e, 0x73, 0x96, 0x79, 0xa9, 0x48, 0x1a, 0xfc, 0x98, 0xc9,
  53.     0x55, 0x11, 0x95, 0x4c, 0x91, 0x31, 0x98, 0xe6, 0x9f, 0x1b, 0xc6, 0x57,
  54.     0x82, 0xdd, 0x49, 0x69, 0x37, 0x31, 0xd8, 0x08, 0x05, 0x89, 0xd4, 0xc0,
  55.     0xbb, 0x95, 0xe9, 0xc6, 0x81, 0xca, 0x79, 0x6d, 0x14, 0x07, 0x69, 0x29,
  56.     0xf6, 0xb0, 0x96, 0x03, 0x81, 0xef, 0x0c, 0x3e, 0x3f, 0x05, 0x5b, 0xd3,
  57.     0xd1, 0xdf, 0x64, 0xbc, 0xf3, 0x47, 0xb9, 0xbb, 0xf5, 0x62, 0xa3, 0x2f,
  58.     0xf9, 0xa2, 0x54, 0xfb, 0xd3, 0x6b, 0xff, 0xbc, 0x65, 0xf7, 0xda, 0x46,
  59.     0xef, 0x3b, 0xdc, 0x17, 0xf2, 0xcf, 0x8a, 0x43, 0x3e, 0xb8, 0xb1, 0xe9,
  60.     0xb2, 0x4d, 0xe1, 0x17, 0x24
  61. };
  62.  
  63. /* openssl rsa -in snakeoil.key -outform DER | xxd -i */
  64.  
  65. static unsigned char key[] = {
  66.     0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xd3,
  67.     0xb5, 0x48, 0x6c, 0x4b, 0x18, 0x80, 0xb0, 0x14, 0xbe, 0x9f, 0x1e, 0x99,
  68.     0x03, 0xff, 0x5b, 0x47, 0x1a, 0xde, 0x54, 0x2e, 0x5e, 0x86, 0xff, 0xaa,
  69.     0x7a, 0xb7, 0x04, 0x76, 0x77, 0xd2, 0x9c, 0xc8, 0xd8, 0x8c, 0xbe, 0x1a,
  70.     0x86, 0x3d, 0x7a, 0xb3, 0xbb, 0x89, 0x2b, 0x16, 0xb9, 0xac, 0xd8, 0xe4,
  71.     0x8d, 0x66, 0x82, 0xb3, 0xd0, 0x38, 0x3d, 0xd6, 0xce, 0xd2, 0x9d, 0x2a,
  72.     0x6c, 0x39, 0x95, 0x57, 0x9a, 0xde, 0x8b, 0x5a, 0xd9, 0x35, 0xa2, 0x2c,
  73.     0x60, 0x69, 0xe9, 0x73, 0xfe, 0x15, 0x76, 0x5a, 0xb6, 0x56, 0x38, 0x47,
  74.     0x1e, 0xf9, 0x51, 0xba, 0x2c, 0x1b, 0xe4, 0x63, 0x9e, 0x6f, 0xfc, 0xac,
  75.     0xb8, 0x0a, 0x07, 0xac, 0x72, 0x9f, 0xb7, 0x0a, 0x64, 0x57, 0xf2, 0x53,
  76.     0x8a, 0xdf, 0x3a, 0x1e, 0x0f, 0x65, 0x2f, 0xa4, 0x92, 0x92, 0x30, 0x5c,
  77.     0x6c, 0x3e, 0x04, 0x49, 0x99, 0x58, 0xef, 0x02, 0x03, 0x01, 0x00, 0x01,
  78.     0x02, 0x81, 0x80, 0x5a, 0x32, 0xb8, 0x62, 0x7b, 0x34, 0x3b, 0x4f, 0xc9,
  79.     0xe6, 0xd5, 0x40, 0x62, 0x0d, 0x13, 0xf4, 0xbd, 0xbc, 0xb2, 0xd0, 0xc6,
  80.     0xd8, 0xbb, 0x47, 0x9e, 0x48, 0x9e, 0x45, 0x26, 0x7c, 0x32, 0x9d, 0x5d,
  81.     0xec, 0xf5, 0x39, 0xe1, 0x6f, 0x24, 0x2e, 0x6c, 0xf9, 0x0f, 0x9d, 0xee,
  82.     0x16, 0xb9, 0x8f, 0xc7, 0x00, 0x7f, 0x96, 0x5c, 0x29, 0xf0, 0x6c, 0x58,
  83.     0x62, 0xd1, 0xd4, 0xe8, 0x48, 0x27, 0xd7, 0xb3, 0xf6, 0xb1, 0xfb, 0xcf,
  84.     0xf2, 0xe8, 0x34, 0xf3, 0x68, 0x62, 0x1e, 0x9a, 0xd6, 0x2a, 0x6c, 0x59,
  85.     0x63, 0x6b, 0x79, 0x84, 0xec, 0xbf, 0xdd, 0xb0, 0xb3, 0x6f, 0x60, 0x77,
  86.     0xbe, 0x02, 0x02, 0x4c, 0x3a, 0xba, 0x30, 0xc9, 0x37, 0xb4, 0x2d, 0x24,
  87.     0xbb, 0xeb, 0xa8, 0x95, 0xce, 0xd2, 0xc3, 0xb7, 0x60, 0xd6, 0x97, 0x6e,
  88.     0xbb, 0xdc, 0xdb, 0xf0, 0x72, 0x55, 0x88, 0x0c, 0xf1, 0x2b, 0x91, 0x02,
  89.     0x41, 0x00, 0xfb, 0xf6, 0x26, 0xeb, 0xf3, 0xcc, 0x7b, 0xdf, 0x95, 0x02,
  90.     0xe6, 0x3b, 0x28, 0x46, 0x52, 0xc4, 0x66, 0x79, 0x11, 0xa0, 0x2b, 0x72,
  91.     0x00, 0x2e, 0x34, 0xdf, 0x2a, 0xf9, 0x2b, 0x9d, 0x46, 0x51, 0xb8, 0x19,
  92.     0x50, 0x4f, 0xc4, 0x77, 0x45, 0xaa, 0x22, 0xa9, 0xf6, 0x93, 0x17, 0x8d,
  93.     0xf6, 0x5e, 0x54, 0x01, 0xb9, 0xf6, 0xdf, 0x63, 0x02, 0x8d, 0x73, 0x33,
  94.     0x23, 0x4d, 0x12, 0x94, 0x57, 0x63, 0x02, 0x41, 0x00, 0xd7, 0x19, 0xf6,
  95.     0x96, 0x29, 0x52, 0x4b, 0x43, 0x8e, 0xb7, 0x67, 0xda, 0xd8, 0x6d, 0x64,
  96.     0xad, 0x7b, 0x4a, 0xbc, 0xd1, 0xe6, 0xeb, 0x12, 0x9a, 0xc2, 0x7a, 0xe9,
  97.     0x25, 0x19, 0x07, 0x82, 0x73, 0xa6, 0x4b, 0x4e, 0xba, 0x46, 0xec, 0xdf,
  98.     0x0a, 0x17, 0x60, 0x28, 0xe3, 0xd9, 0xd6, 0x23, 0xef, 0x4c, 0x5e, 0x2f,
  99.     0x9c, 0x66, 0x76, 0xe0, 0x69, 0x69, 0xc7, 0xa2, 0xef, 0xab, 0x69, 0x0c,
  100.     0x05, 0x02, 0x40, 0x55, 0x51, 0x94, 0xfc, 0x71, 0x21, 0xdd, 0x10, 0x68,
  101.     0xb5, 0x02, 0xa1, 0x25, 0x92, 0x2a, 0x94, 0xb6, 0xde, 0x68, 0x49, 0x84,
  102.     0x6c, 0xa6, 0x02, 0xff, 0x84, 0x52, 0x58, 0xed, 0x9b, 0xe4, 0x23, 0xe7,
  103.     0xe3, 0x2a, 0x7e, 0xd8, 0x58, 0x4b, 0x0e, 0xc1, 0x8e, 0x2c, 0x20, 0xc2,
  104.     0xe9, 0x1f, 0x73, 0xf1, 0x9e, 0x64, 0x0a, 0x64, 0xba, 0x72, 0x32, 0xd3,
  105.     0xbf, 0x8d, 0x44, 0x9b, 0xf5, 0xff, 0x61, 0x02, 0x40, 0x11, 0x8a, 0x2c,
  106.     0x71, 0x52, 0x2d, 0x43, 0xb5, 0xde, 0x8d, 0x56, 0x0a, 0xa2, 0x5b, 0x49,
  107.     0x3a, 0x5c, 0x33, 0x5b, 0xf2, 0x41, 0xc2, 0x29, 0x62, 0x35, 0x39, 0x90,
  108.     0x89, 0x55, 0xe1, 0x26, 0xe2, 0x07, 0x4d, 0x5c, 0xbe, 0x13, 0xca, 0x7c,
  109.     0xe5, 0x75, 0xc2, 0x81, 0x93, 0x12, 0xd0, 0x43, 0x5d, 0xdf, 0xfc, 0x4e,
  110.     0x25, 0x92, 0xb5, 0x5e, 0xd7, 0x39, 0xa8, 0xed, 0xc0, 0x5d, 0x59, 0xd3,
  111.     0x81, 0x02, 0x41, 0x00, 0xd0, 0x16, 0xe4, 0xa0, 0xb0, 0x58, 0xaa, 0x5e,
  112.     0x28, 0xc2, 0x82, 0xc5, 0x43, 0x7c, 0xfd, 0x29, 0x22, 0x39, 0x3d, 0x73,
  113.     0xf3, 0xc0, 0x58, 0x1b, 0x03, 0x6c, 0xf3, 0x44, 0x66, 0x67, 0xe1, 0x72,
  114.     0xf8, 0x75, 0x9e, 0x1b, 0x77, 0xbe, 0xb3, 0xc0, 0x14, 0xfd, 0x44, 0xcc,
  115.     0xba, 0x97, 0xc2, 0x7a, 0xc2, 0xdb, 0x2d, 0x07, 0x25, 0x13, 0x12, 0xcb,
  116.     0x2c, 0xbf, 0x95, 0x0f, 0x1b, 0xfd, 0xe3, 0xe4
  117. };
  118. #endif
  119.  
  120. #if !NO_DH
  121.  
  122. /* openssl dhparam -C -noout 512 */
  123.  
  124. DH *get_dh512() {
  125.     static unsigned char dh512_p[] = {
  126.         0xFC, 0xFA, 0x8A, 0x3F, 0x8C, 0x50, 0xAA, 0x55, 0x01, 0xF2, 0x78,
  127.         0x27, 0x55, 0x5B, 0x5E, 0xD1, 0x9A, 0xF4, 0x56, 0x1E, 0x6F, 0x6B,
  128.         0xAC, 0x2B, 0x0B, 0x99, 0x1B, 0x89, 0x5B, 0x64, 0xCA, 0x11, 0xE8,
  129.         0x8F, 0x0B, 0x89, 0x67, 0x87, 0x5A, 0xF4, 0x16, 0xA8, 0x89, 0x2F,
  130.         0xAA, 0x4E, 0xE0, 0x03, 0x3C, 0x41, 0xE0, 0x48, 0xAE, 0x95, 0xD4,
  131.         0xFF, 0x07, 0xEF, 0x4B, 0xF0, 0xF4, 0x96, 0x02, 0x33
  132.     };
  133.     static unsigned char dh512_g[] = { 0x02, };
  134.     DH *dh;
  135.  
  136.     if ( (dh = DH_new()) == NULL )
  137.         return (NULL);
  138.     dh->p = BN_bin2bn( dh512_p, sizeof(dh512_p), NULL );
  139.     dh->g = BN_bin2bn( dh512_g, sizeof(dh512_g), NULL );
  140.     if ( (dh->p == NULL) || (dh->g == NULL) ) {
  141.         DH_free( dh );
  142.         return (NULL);
  143.     }
  144.     return (dh);
  145. }
  146.  
  147. /* openssl dhparam -C -noout -dsaparam 1024 */
  148.  
  149. DH *get_dh1024() {
  150.     static unsigned char dh1024_p[] = {
  151.         0xE8, 0xCD, 0xC3, 0xE8, 0x54, 0xA6, 0x14, 0x4C, 0x78, 0x58, 0x52,
  152.         0xC6, 0x6A, 0x2B, 0x3B, 0xC6, 0xC8, 0xAC, 0x16, 0x60, 0x76, 0x44,
  153.         0x62, 0x63, 0x3A, 0x3D, 0x32, 0xB4, 0x22, 0xBA, 0x1B, 0x34, 0x74,
  154.         0x23, 0x71, 0xE0, 0x1D, 0x7F, 0x51, 0x02, 0xEE, 0x9B, 0x2D, 0xD3,
  155.         0xA0, 0x66, 0x4B, 0x4F, 0x85, 0x59, 0xD4, 0x1A, 0x3A, 0xD4, 0x64,
  156.         0x28, 0x46, 0x55, 0xB4, 0xFD, 0x63, 0x32, 0x8E, 0x18, 0xCF, 0x65,
  157.         0x85, 0x21, 0xBF, 0xF9, 0xEE, 0x54, 0x48, 0x4C, 0x9C, 0x44, 0xAB,
  158.         0x26, 0xCA, 0x93, 0x85, 0x2A, 0xD1, 0x46, 0x6D, 0x3D, 0xED, 0xEE,
  159.         0x33, 0xF0, 0xFC, 0x3F, 0x98, 0x70, 0xA5, 0x19, 0x0B, 0x48, 0x6C,
  160.         0x0A, 0x7C, 0xCA, 0x53, 0xF4, 0x3B, 0xD5, 0x20, 0x3D, 0x58, 0xEA,
  161.         0x60, 0x5F, 0xFA, 0xA3, 0x05, 0xA1, 0x63, 0x20, 0xF6, 0x9A, 0xB7,
  162.         0xC1, 0x20, 0x77, 0x3A, 0xC9, 0x0E, 0x73
  163.     };
  164.     static unsigned char dh1024_g[] = {
  165.         0x95, 0xA5, 0x55, 0x32, 0x57, 0x13, 0xF7, 0xFA, 0x26, 0x13, 0x8E,
  166.         0x6C, 0xF9, 0x58, 0x7C, 0xA2, 0x59, 0xD2, 0x81, 0xD6, 0xC1, 0xC6,
  167.         0x33, 0xBE, 0x66, 0x14, 0xBC, 0x15, 0xE7, 0xFB, 0x2C, 0x35, 0xE1,
  168.         0x54, 0x11, 0x1C, 0xB2, 0x68, 0xFB, 0xF3, 0x7F, 0x62, 0x69, 0x42,
  169.         0x6D, 0xDE, 0x88, 0xD7, 0xAF, 0xE4, 0xAA, 0xED, 0xF4, 0x58, 0x44,
  170.         0x69, 0xBA, 0x51, 0x30, 0x6B, 0xF9, 0x48, 0x8D, 0x74, 0xDB, 0x64,
  171.         0xC3, 0x9A, 0xA2, 0x54, 0x86, 0xA2, 0xAA, 0x46, 0x0D, 0x5A, 0xE9,
  172.         0x15, 0x22, 0x36, 0xF5, 0x8B, 0xFF, 0xCD, 0xF9, 0xDA, 0x6C, 0x92,
  173.         0x5A, 0x1D, 0x5F, 0x2F, 0xA0, 0xED, 0x4A, 0x83, 0x2D, 0xAB, 0x07,
  174.         0x3B, 0x67, 0x8A, 0x3B, 0x35, 0xF1, 0xA6, 0xA3, 0x38, 0x16, 0x5A,
  175.         0x3D, 0xBB, 0x72, 0xBD, 0x1A, 0xFC, 0xA3, 0xB7, 0x04, 0x12, 0x8C,
  176.         0x40, 0x99, 0x08, 0x45, 0x68, 0x33, 0x7E
  177.     };
  178.     DH *dh;
  179.  
  180.     if ( (dh = DH_new()) == NULL )
  181.         return (NULL);
  182.     dh->p = BN_bin2bn( dh1024_p, sizeof(dh1024_p), NULL );
  183.     dh->g = BN_bin2bn( dh1024_g, sizeof(dh1024_g), NULL );
  184.     if ( (dh->p == NULL) || (dh->g == NULL) ) {
  185.         DH_free( dh );
  186.         return (NULL);
  187.     }
  188.     dh->length = 160;
  189.     return (dh);
  190. }
  191. #endif
  192.  
  193. struct {
  194.     SSL_CTX *s_ctx;
  195.     SSL *s_ssl;
  196.     int s_ready;
  197.     int s_failed;
  198.     SSL_CTX *c_ctx;
  199.     SSL *c_ssl;
  200.     int c_ready;
  201.     int c_failed;
  202. } app;
  203.  
  204. static void s_ssl_info_callback(const SSL *ssl, int where, int ret) {
  205.     if ( where & SSL_CB_ALERT ) {
  206.         fprintf( stdout, "[S] SSL_CB_ALERT %s %s\n", SSL_alert_type_string( ret ), SSL_alert_desc_string_long( ret ) );
  207.         app.s_failed = 1;
  208.     }
  209. }
  210.  
  211. static void c_ssl_info_callback(const SSL *ssl, int where, int ret) {
  212.     if ( where & SSL_CB_ALERT ) {
  213.         fprintf( stdout, "[C] SSL_CB_ALERT %s %s\n", SSL_alert_type_string( ret ), SSL_alert_desc_string_long( ret ) );
  214.         app.c_failed = 1;
  215.     }
  216. }
  217.  
  218. void init_ssl() {
  219.     SSL_library_init();
  220. #if 0
  221.     SSL_load_error_strings();
  222. #endif
  223. }
  224.  
  225. void end_ssl() {
  226.     EVP_cleanup();
  227. }
  228.  
  229. int start_ssl() {
  230.     SSL_CTX *s_ctx = 0;
  231.     SSL *s_ssl = 0;
  232.     BIO *s_bior = 0, *s_biow = 0;
  233.  
  234.     SSL_CTX *c_ctx = 0;
  235.     SSL *c_ssl = 0;
  236.     BIO *c_bior = 0, *c_biow = 0;
  237.  
  238.     char *cipher = CIPHER;
  239.  
  240.     if ( !(s_ctx = SSL_CTX_new( SSLv3_method() )) )
  241.         goto error;
  242.  
  243.     if ( !SSL_CTX_set_options( s_ctx, SSL_OP_NO_SSLv2 ) )
  244.         goto error;
  245.  
  246.     if ( !SSL_CTX_set_options( s_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE ) )
  247.         goto error;
  248.  
  249.     if ( cipher ) {
  250.         if ( !SSL_CTX_set_cipher_list( s_ctx, cipher ) )
  251.             goto error;
  252.     }
  253.  
  254. #if !NO_DH
  255. #if 0
  256.     DH *dh = get_dh512();
  257. #else
  258.     DH *dh = get_dh1024();
  259. #endif
  260.     SSL_CTX_set_tmp_dh(s_ctx,dh);
  261.     DH_free( dh );
  262.  
  263.     if ( ! SSL_CTX_set_options(s_ctx, SSL_OP_SINGLE_DH_USE) )
  264.         goto error;
  265. #endif
  266.  
  267. #if NO_FILE
  268.     if ( ! SSL_CTX_use_certificate_ASN1(s_ctx, sizeof (cert), cert) )
  269.         goto error;
  270. #else
  271.     if ( ! SSL_CTX_use_certificate_file(s_ctx, CERT_FILE, SSL_FILETYPE_PEM) )
  272.         goto error;
  273. #endif
  274.  
  275. #if NO_FILE
  276.     if ( ! SSL_CTX_use_RSAPrivateKey_ASN1(s_ctx, key, sizeof (key) ) )
  277.         goto error;
  278. #else
  279.     if ( ! SSL_CTX_use_PrivateKey_file(s_ctx, KEY_FILE, SSL_FILETYPE_PEM) )
  280.         goto error;
  281. #endif
  282.  
  283.     if ( ! SSL_CTX_check_private_key( s_ctx) )
  284.         goto error;
  285.  
  286.     SSL_CTX_set_info_callback( s_ctx, s_ssl_info_callback );
  287.  
  288.     if ( !(s_ssl = SSL_new( s_ctx )) )
  289.         goto error;
  290.  
  291.     s_bior = BIO_new( BIO_s_mem() );
  292.     s_biow = BIO_new( BIO_s_mem() );
  293.     SSL_set_bio( s_ssl, s_bior, s_biow );
  294.  
  295.     SSL_set_accept_state( s_ssl );
  296.  
  297.     if ( !(c_ctx = SSL_CTX_new( SSLv3_method() )) )
  298.         goto error;
  299.  
  300.     if ( !SSL_CTX_set_options( c_ctx, SSL_OP_NO_SSLv2 ) )
  301.         goto error;
  302.  
  303.     if ( cipher ) {
  304.         if ( !SSL_CTX_set_cipher_list( c_ctx, cipher ) )
  305.             goto error;
  306.     }
  307.  
  308. #if 0
  309.     if ( ! SSL_CTX_load_verify_locations( c_ctx, CERT_FILE, 0) )
  310.         goto error;
  311. #endif
  312.  
  313.     SSL_CTX_set_info_callback( c_ctx, c_ssl_info_callback );
  314.  
  315.     if ( !(c_ssl = SSL_new( c_ctx )) )
  316.         goto error;
  317.  
  318.     c_bior = BIO_new( BIO_s_mem() );
  319.     c_biow = BIO_new( BIO_s_mem() );
  320.     SSL_set_bio( c_ssl, c_bior, c_biow );
  321.  
  322.     SSL_set_connect_state( c_ssl );
  323.  
  324.     app.c_ctx = c_ctx;
  325.     app.c_ssl = c_ssl;
  326.     app.s_ctx = s_ctx;
  327.     app.s_ssl = s_ssl;
  328.  
  329.     return 1;
  330.  
  331. error:
  332.  
  333.     ERR_print_errors_fp( stderr );
  334.     if ( c_ctx )
  335.         SSL_CTX_free( c_ctx );
  336.     if ( c_ssl )
  337.         SSL_free( c_ssl );
  338.     if ( s_ctx )
  339.         SSL_CTX_free( s_ctx );
  340.     if ( s_ssl )
  341.         SSL_free( s_ssl );
  342.  
  343.     return 0;
  344. }
  345.  
  346. void stop_ssl() {
  347.     if ( app.s_ctx != 0 ) {
  348.         SSL_CTX_free( app.s_ctx );
  349.         app.s_ctx = 0;
  350.     }
  351.     if ( app.s_ssl != 0 ) {
  352.         SSL_free( app.s_ssl );
  353.         app.s_ssl = 0;
  354.     }
  355.  
  356.     if ( app.c_ctx != 0 ) {
  357.         SSL_CTX_free( app.c_ctx );
  358.         app.s_ctx = 0;
  359.     }
  360.     if ( app.c_ssl != 0 ) {
  361.         SSL_free( app.c_ssl );
  362.         app.c_ssl = 0;
  363.     }
  364. }
  365.  
  366. void quit(int ret) {
  367.     stop_ssl();
  368.     end_ssl();
  369.  
  370.     exit( ret );
  371. }
  372.  
  373. int read_ssl(SSL* ssl, unsigned char *buffer, unsigned buffer_size) {
  374.     fputs( "read_ssl\n", stdout );
  375.     int r;
  376.  
  377.     r = SSL_read( ssl, buffer, buffer_size );
  378.  
  379.     if ( r < 0 ) {
  380.         int err = SSL_get_error( ssl, r );
  381.  
  382.         if ( err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE )
  383.             r = 0;
  384.     }
  385.  
  386.     return r;
  387. }
  388.  
  389. int write_ssl(SSL* ssl, const unsigned char *buffer, unsigned buffer_size) {
  390.     fputs( "write_ssl\n", stdout );
  391.     int r;
  392.  
  393.     r = SSL_write( ssl, buffer, buffer_size );
  394.  
  395.     if ( r < 0 ) {
  396.         int err = SSL_get_error( ssl, r );
  397.  
  398.         if ( err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE )
  399.             r = 0;
  400.     }
  401.  
  402.     return r;
  403. }
  404.  
  405. int inject_ssl(const SSL* ssl, const unsigned char *buffer, unsigned buffer_size) {
  406.     fputs( "inject_ssl\n", stdout );
  407.     BIO * bior = SSL_get_rbio( ssl );
  408.  
  409.     return BIO_write( bior, buffer, buffer_size );
  410. }
  411.  
  412. int extract_ssl(const SSL* ssl, unsigned char *buffer, unsigned buffer_size) {
  413.     fputs( "extract_ssl\n", stdout );
  414.     BIO * biow = SSL_get_wbio( ssl );
  415.  
  416.     return BIO_read( biow, buffer, buffer_size );
  417. }
  418.  
  419. void server_read() {
  420.     fputs( "server read\n", stdout );
  421.     unsigned char buffer[1024];
  422.  
  423.     int r = extract_ssl( app.s_ssl, buffer, sizeof(buffer) );
  424.     fprintf( stderr, "r=%d\n", r );
  425.     if ( r > 0 ) {
  426.         DUMP( buffer, r, stdout );
  427.         r = inject_ssl( app.c_ssl, buffer, r );
  428.         fprintf( stderr, "r=%d\n", r );
  429.     }
  430. }
  431.  
  432. void client_read() {
  433.     fputs( "client read\n", stdout );
  434.     unsigned char buffer[1024];
  435.  
  436.     int r = extract_ssl( app.c_ssl, buffer, sizeof(buffer) );
  437.     fprintf( stderr, "r=%d\n", r );
  438.     if ( r > 0 ) {
  439.         DUMP( buffer, r, stdout );
  440.         r = inject_ssl( app.s_ssl, buffer, r );
  441.         fprintf( stderr, "r=%d\n", r );
  442.     }
  443. }
  444.  
  445. void process_bio(SSL *s_ssl, SSL *c_ssl) {
  446.     BIO * s_bior = SSL_get_rbio( s_ssl );
  447.     BIO * s_biow = SSL_get_wbio( s_ssl );
  448.  
  449.     BIO * c_bior = SSL_get_rbio( c_ssl );
  450.     BIO * c_biow = SSL_get_wbio( c_ssl );
  451.  
  452.     int s_bior_cnt, s_biow_cnt;
  453.     int c_bior_cnt, c_biow_cnt;
  454.  
  455.     s_biow_cnt = BIO_pending(s_biow);
  456.     s_bior_cnt = BIO_pending(s_bior);
  457.     c_biow_cnt = BIO_pending(c_biow);
  458.     c_bior_cnt = BIO_pending(c_bior);
  459.  
  460.     fprintf( stdout, "[S] biow=%d\n", s_biow_cnt );
  461.     fprintf( stdout, "[S] bior=%d\n", s_bior_cnt );
  462.     fprintf( stdout, "[C] biow=%d\n", c_biow_cnt );
  463.     fprintf( stdout, "[C] bior=%d\n", c_bior_cnt );
  464.  
  465.     if ( s_biow_cnt ) {
  466.         server_read();
  467.     }
  468.     if ( c_biow_cnt ) {
  469.         client_read();
  470.     }
  471. }
  472.  
  473. void blahblah() {
  474.     SSL *s_ssl = app.s_ssl;
  475.     SSL *c_ssl = app.c_ssl;
  476.  
  477.     char *msg = "HELLO";
  478.     unsigned msg_len = 5;
  479.     char *reply = "BYE";
  480.     unsigned reply_len = 3;
  481.  
  482.     unsigned char buffer[32];
  483.  
  484.     int r, w;
  485.  
  486.     fprintf( stderr, "msg=%s\n", msg );
  487.  
  488.     w = write_ssl( c_ssl, (const unsigned char *) msg, msg_len );
  489.     if ( w < 0 ) {
  490.         ERR_print_errors_fp( stderr );
  491.         quit( 3 );
  492.     }
  493.     if ( w == 0 )
  494.         return;
  495.  
  496.     process_bio( s_ssl, c_ssl );
  497.  
  498.     r = read_ssl( s_ssl, buffer, sizeof (buffer) - 1);
  499.     fprintf( stderr, "r=%d\n", r );
  500.     if ( r < 0 ) {
  501.         ERR_print_errors_fp( stderr );
  502.         quit( 3 );
  503.     }
  504.     if ( r == 0 )
  505.         return;
  506.  
  507.     buffer[ r ] = '\0';
  508.  
  509.     fprintf( stderr, "[S] %s\n", buffer );
  510.  
  511.     fprintf( stderr, "reply=%s\n", reply );
  512.  
  513.     w = write_ssl( s_ssl, (const unsigned char *) reply, reply_len );
  514.     if ( w < 0 ) {
  515.         ERR_print_errors_fp( stderr );
  516.         quit( 3 );
  517.     }
  518.     if ( w == 0 )
  519.         return;
  520.  
  521.     process_bio( s_ssl, c_ssl );
  522.  
  523.     r = read_ssl( c_ssl, buffer, sizeof (buffer) - 1);
  524.     fprintf( stderr, "r=%d\n", r );
  525.     if ( r < 0 ) {
  526.         ERR_print_errors_fp( stderr );
  527.         quit( 3 );
  528.     }
  529.     if ( r == 0 )
  530.         return;
  531.  
  532.     buffer[ r ] = '\0';
  533.  
  534.     fprintf( stderr, "[C] %s\n", buffer );
  535. }
  536.  
  537. void doit() {
  538.     SSL *s_ssl = app.s_ssl;
  539.     SSL *c_ssl = app.c_ssl;
  540.  
  541.     while ( !(app.s_ready && app.c_ready) && !(app.s_failed && app.c_failed) ) {
  542.         fprintf( stdout, "[S] %s\n", SSL_state_string( s_ssl ) );
  543.         fprintf( stdout, "[C] %s\n", SSL_state_string( c_ssl ) );
  544.  
  545.         if ( SSL_want_nothing(s_ssl) )
  546.             fputs( "[S] SSL_ERROR_WANT_NOTHING\n", stdout );
  547.         if ( SSL_want_read(s_ssl) )
  548.             fputs( "[S] SSL_ERROR_WANT_READ\n", stdout );
  549.         if ( SSL_want_write(s_ssl) )
  550.             fputs( "[S] SSL_ERROR_WANT_WRITE\n", stdout );
  551.         if ( SSL_want_x509_lookup(s_ssl) )
  552.             fputs( "[S] SSL_ERROR_WANT_X509_LOOKUP\n", stdout );
  553.  
  554.  
  555.         if ( SSL_want_nothing(c_ssl) )
  556.             fputs( "[C] SSL_ERROR_WANT_NOTHING\n", stdout );
  557.         if ( SSL_want_read(c_ssl) )
  558.             fputs( "[C] SSL_ERROR_WANT_READ\n", stdout );
  559.         if ( SSL_want_write(c_ssl) )
  560.             fputs( "[C] SSL_ERROR_WANT_WRITE\n", stdout );
  561.         if ( SSL_want_x509_lookup(c_ssl) )
  562.             fputs( "[C] SSL_ERROR_WANT_X509_LOOKUP\n", stdout );
  563.  
  564.         if ( !app.s_ready && !app.s_failed ) {
  565.             if ( SSL_in_before(s_ssl) )
  566.                 fputs( "[S] SSL_ST_BEFORE\n", stdout );
  567.             if ( SSL_in_init(s_ssl) )
  568.                 fputs( "[S] SSL_ST_INIT\n", stdout );
  569.             if ( SSL_in_connect_init(s_ssl) )
  570.                 fputs( "[S] SSL_ST_CONNECT_INIT\n", stdout );
  571.             if ( SSL_in_accept_init(s_ssl) )
  572.                 fputs( "[S] SSL_ST_ACCEPT_INIT\n", stdout );
  573.  
  574.             if ( SSL_in_init(s_ssl) ) {
  575.                 fputs( "[S] SSL_do_handshake\n", stdout );
  576.                 SSL_do_handshake( s_ssl );
  577.             }
  578.             if ( SSL_is_init_finished( s_ssl ) ) {
  579.                 app.s_ready = 1;
  580.                 fputs( "[S] *** ready ***\n", stdout );
  581.                 fprintf( stdout, "[S] %s\n", SSL_state_string( s_ssl ) );
  582.  
  583.                 SSL_SESSION *sess = SSL_get_session( s_ssl );
  584.                 if ( sess ) {
  585.                     fprintf( stdout, "sess->cipher->name=%s\n", sess->cipher->name );
  586.                 }
  587.             }
  588.         }
  589.  
  590.         if ( !app.c_ready && !app.c_failed ) {
  591.             if ( SSL_in_before(c_ssl) )
  592.                 fputs( "[C] SSL_ST_BEFORE\n", stdout );
  593.             if ( SSL_in_init(c_ssl) )
  594.                 fputs( "[C] SSL_ST_INIT\n", stdout );
  595.             if ( SSL_in_connect_init(c_ssl) )
  596.                 fputs( "[C] SSL_ST_CONNECT_INIT\n", stdout );
  597.             if ( SSL_in_accept_init(c_ssl) )
  598.                 fputs( "[C] SSL_ST_ACCEPT_INIT\n", stdout );
  599.  
  600.             if ( SSL_in_init(c_ssl) ) {
  601.                 fputs( "[C] SSL_do_handshake\n", stdout );
  602.                 SSL_do_handshake( c_ssl );
  603.             }
  604.             if ( SSL_is_init_finished( c_ssl ) ) {
  605.                 app.c_ready = 1;
  606.                 fputs( "[C] *** ready ***\n", stdout );
  607.                 fprintf( stdout, "[C] %s\n", SSL_state_string( c_ssl ) );
  608.  
  609.                 fprintf( stdout, "SSL_get_verify_result=%ld\n",
  610.                         SSL_get_verify_result( c_ssl ) );
  611.  
  612.                 X509 *cert = SSL_get_peer_certificate( c_ssl );
  613.                 if ( cert ) {
  614.                     fprintf( stdout, "cert->valid=%d\n", cert->valid );
  615.                     fprintf( stdout, "cert->name=%s\n", cert->name );
  616.  
  617.                     EVP_MD *digest;
  618.                     digest = (EVP_MD*) EVP_sha1();
  619.                     unsigned char data[EVP_MAX_MD_SIZE];
  620.                     unsigned int len;
  621.                     if ( X509_digest( cert, digest, data, &len ) > 0 ) {
  622.                         unsigned char *p;
  623.                         fputs( "cert->fingerprint=", stdout );
  624.                         for ( p = data; p < data + len; p++ )
  625.                             fprintf( stdout, p == data ? "%02x" : ":%02x", *p );
  626.                         fprintf( stdout, "\n" );
  627.                     }
  628.                 }
  629.                 SSL_SESSION *sess = SSL_get_session( c_ssl );
  630.                 if ( sess ) {
  631.                     fprintf( stdout, "sess->cipher->name=%s\n", sess->cipher->name );
  632.                 }
  633.             }
  634.         }
  635.  
  636.         process_bio( s_ssl, c_ssl );
  637.     }
  638.  
  639.     if ( !(app.s_ready && app.c_ready) )
  640.         return;
  641.  
  642.     blahblah();
  643. }
  644.  
  645. void startup() {
  646.     init_ssl();
  647.  
  648.     if ( !start_ssl() )
  649.         exit( 1 );
  650. }
  651.  
  652. void init() {
  653.     app.s_failed = 0;
  654.     app.s_ready = 0;
  655.     app.c_failed = 0;
  656.     app.c_ready = 0;
  657. }
  658.  
  659. int main(int argc, char **argv) {
  660.     init();
  661.  
  662.     startup();
  663.     doit();
  664.  
  665.     exit( 0 );
  666. }
  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include <unistd.h>
  4.  
  5. void dump( unsigned char *buf, int size, FILE *fout ) {
  6.     register int n, i, col = 0;
  7.  
  8.     const int ncols = 16;
  9.     unsigned char c[ 16 ];
  10.  
  11.     for( n = 0; n < size; n++ ) {
  12.         fprintf( fout, "%02x ", buf[ n ] );
  13.         c[ col ] = buf[ n ];
  14.         col++;
  15.         if( col == ncols / 2 )
  16.             fprintf( fout, " " );
  17.         else if( col == ncols ) {
  18.             for( i = 0; i < col; i++ )
  19.                 fprintf( fout, "%c", isprint(c[ i ] ) ? c[ i ] : '.' );
  20.             fprintf( fout, "\n" );
  21.             col = 0;
  22.         }
  23.     }
  24.     if( col != 0 ) {
  25.         for( i = ncols - col; i > 0; i-- )
  26.             fprintf( fout, "   " );
  27.         if( col < ncols / 2 )
  28.             fprintf( fout, " " );
  29.         for( i = 0; i < col; i++ )
  30.             fprintf( fout, "%c", isprint( c[ i ] ) ? c[ i ] : '.' );
  31.         fprintf( fout, "\n" );
  32.     }
  33. }
  34.  
  35. #if defined( STANDALONE )
  36.  
  37. #if 0
  38. #include <io.h>
  39. #endif
  40.  
  41. #include <fcntl.h>
  42. #include <errno.h>
  43. #include <string.h>
  44. #include <stdlib.h>
  45.  
  46. int main( int argc, char *argv[] ) {
  47.     unsigned char buf[ 4096 ];
  48.     int n;
  49.  
  50.     int fd = 0; /* default to stdin */
  51.  
  52.     switch( argc ) {
  53.         case 1:
  54.             break;
  55.         case 2:
  56.             fd = open( argv[ 1 ], O_RDONLY );
  57.             if ( fd == -1) {
  58.                 fprintf( stderr, "%s\n", strerror( errno ) );
  59.                 exit( 2 );
  60.             }
  61.             break;
  62.         default:
  63.             fprintf( stderr, "%s [file]\n", argv[0] );
  64.             exit(1);
  65.     }
  66.  
  67.     while ( (n = read( fd, buf, sizeof( buf ))) != 0 )
  68.         dump( buf, n, stdout );
  69.     exit( 0 );
  70. }
  71.  
  72. #endif
$ gcc -DSTANDALONE -o dump dump.c
./dump < dump.c
23 69 6e 63 6c 75 64 65  20 3c 73 74 64 69 6f 2e #include <stdio.
68 3e 0a 23 69 6e 63 6c  75 64 65 20 3c 63 74 79 h>.#include <cty
70 65 2e 68 3e 0a 23 69  6e 63 6c 75 64 65 20 3c pe.h>.#include <
75 6e 69 73 74 64 2e 68  3e 0a 0a 76 6f 69 64 20 unistd.h>..void 
64 75 6d 70 28 20 75 6e  73 69 67 6e 65 64 20 63 dump( unsigned c
...
  1. #
  2.  
  3. ALL = sslfingerprint sslsock sslmem
  4.  
  5. CC = gcc
  6.  
  7. CFLAGS = -Wall -g #-O
  8. #CFLAGS = -Wall -g -I../openssl/include
  9. #CFLAGS = -Wall -O -fstrength-reduce -finline-functions -fomit-frame-pointer
  10.  
  11. SRCS = sslfingerprint.c sslsock.c sslmem.c dump.c
  12. OBJS = $(SRCS:.c=.o)
  13.  
  14. LDFLAGS = -lssl -lcrypto
  15. #LDFLAGS = -L../openssl -lssl -lcrypto
  16. #LDFLAGS = -L/usr/local/ssl/lib -lssl -lcrypto
  17.  
  18. #.SILENT:
  19.  
  20. all:    $(ALL)
  21.  
  22. sslsock:    sslsock.o dump.o
  23.     $(CC) $^ -o $@ $(LDFLAGS)
  24.  
  25. sslmem:     sslmem.o dump.o
  26.     $(CC) $^ -o $@ $(LDFLAGS)
  27.  
  28. sslfingerprint: sslfingerprint.o
  29.     $(CC) $^ -o $@ $(LDFLAGS)
  30.  
  31. test:   all
  32.     ./sslmem && ./sslsock < req.txt
  33.  
  34. clean:
  35.     rm -f $(OBJS)
  36.  
  37. wipe:   clean
  38.     rm -f $(ALL)

Comments

Your comment:
[p] [b] [i] [u] [s] [quote] [pre] [br] [code] [url] [email] strip help 2000

Enter a maximum of 2000 characters.
Improve the presentation of your text with the following formatting tags:
[p]paragraph[/p], [b]bold[/b], [i]italics[/i], [u]underline[/u], [s]strike[/s], [quote]citation[/quote], [pre]as is[/pre], [br]line break,
[url]http://www.izend.org[/url], [url=http://www.izend.org]site[/url], [email]izend@izend.org[/email], [email=izend@izend.org]izend[/email],
[code]command[/code], [code=language]source code in c, java, php, html, javascript, xml, css, sql, bash, dos, make, etc.[/code].