1
44

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;
  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. }
  1. void close_conn() {
  2.     if ( app.socket != -1 ) {
  3.         close( app.socket );
  4.         app.socket = -1;
  5.     }
  6. }
  1. void init_ssl() {
  2.     SSL_library_init();
  3. #if 1
  4.     SSL_load_error_strings();
  5. #endif
  6. }
  1. void end_ssl() {
  2.     EVP_cleanup();
  3. }
  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. }
  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. }
  1. void quit( int ret ) {
  2.     close_conn();
  3.  
  4.     stop_ssl();
  5.     end_ssl();
  6.  
  7.     exit( ret );
  8. }
  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. }
  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. }
  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. }
  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. }
  1. void startup() {
  2.     init_ssl();
  3.  
  4.     if ( !start_ssl() )
  5.         exit( 1 );
  6.  
  7.     if ( !open_conn() )
  8.         exit( 1 );
  9. }
  1. void init() {
  2.     app.host_ip = htonl( HOSTADDR );
  3.     app.port_num = htons( PORTNUM );
  4.     app.socket = -1;
  5. }
  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. }
  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. }

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 does display 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 */#endif
  64.  
  65. #if !NO_DH
  66.  
  67. /* openssl dhparam -C -noout 512 */
  68.  
  69. DH *get_dh512() {
  70.     static unsigned char dh512_p[] = {
  71.         0xFC, 0xFA, 0x8A, 0x3F, 0x8C, 0x50, 0xAA, 0x55, 0x01, 0xF2, 0x78,
  72.         0x27, 0x55, 0x5B, 0x5E, 0xD1, 0x9A, 0xF4, 0x56, 0x1E, 0x6F, 0x6B,
  73.         0xAC, 0x2B, 0x0B, 0x99, 0x1B, 0x89, 0x5B, 0x64, 0xCA, 0x11, 0xE8,
  74.         0x8F, 0x0B, 0x89, 0x67, 0x87, 0x5A, 0xF4, 0x16, 0xA8, 0x89, 0x2F,
  75.         0xAA, 0x4E, 0xE0, 0x03, 0x3C, 0x41, 0xE0, 0x48, 0xAE, 0x95, 0xD4,
  76.         0xFF, 0x07, 0xEF, 0x4B, 0xF0, 0xF4, 0x96, 0x02, 0x33
  77.     };
  78.     static unsigned char dh512_g[] = { 0x02, };
  79.     DH *dh;
  80.  
  81.     if ( (dh = DH_new()) == NULL )
  82.         return (NULL);
  83.     dh->p = BN_bin2bn( dh512_p, sizeof(dh512_p), NULL );
  84.     dh->g = BN_bin2bn( dh512_g, sizeof(dh512_g), NULL );
  85.     if ( (dh->p == NULL) || (dh->g == NULL) ) {
  86.         DH_free( dh );
  87.         return (NULL);
  88.     }
  89.     return (dh);
  90. }
  91.  
  92. /* openssl dhparam -C -noout -dsaparam 1024 */
  93.  
  94. DH *get_dh1024() {
  95.     static unsigned char dh1024_p[] = {
  96.         0xE8, 0xCD, 0xC3, 0xE8, 0x54, 0xA6, 0x14, 0x4C, 0x78, 0x58, 0x52,
  97.         0xC6, 0x6A, 0x2B, 0x3B, 0xC6, 0xC8, 0xAC, 0x16, 0x60, 0x76, 0x44,
  98.         0x62, 0x63, 0x3A, 0x3D, 0x32, 0xB4, 0x22, 0xBA, 0x1B, 0x34, 0x74,
  99.         0x23, 0x71, 0xE0, 0x1D, 0x7F, 0x51, 0x02, 0xEE, 0x9B, 0x2D, 0xD3,
  100.         0xA0, 0x66, 0x4B, 0x4F, 0x85, 0x59, 0xD4, 0x1A, 0x3A, 0xD4, 0x64,
  101.         0x28, 0x46, 0x55, 0xB4, 0xFD, 0x63, 0x32, 0x8E, 0x18, 0xCF, 0x65,
  102.         0x85, 0x21, 0xBF, 0xF9, 0xEE, 0x54, 0x48, 0x4C, 0x9C, 0x44, 0xAB,
  103.         0x26, 0xCA, 0x93, 0x85, 0x2A, 0xD1, 0x46, 0x6D, 0x3D, 0xED, 0xEE,
  104.         0x33, 0xF0, 0xFC, 0x3F, 0x98, 0x70, 0xA5, 0x19, 0x0B, 0x48, 0x6C,
  105.         0x0A, 0x7C, 0xCA, 0x53, 0xF4, 0x3B, 0xD5, 0x20, 0x3D, 0x58, 0xEA,
  106.         0x60, 0x5F, 0xFA, 0xA3, 0x05, 0xA1, 0x63, 0x20, 0xF6, 0x9A, 0xB7,
  107.         0xC1, 0x20, 0x77, 0x3A, 0xC9, 0x0E, 0x73
  108.     };
  109.     static unsigned char dh1024_g[] = {
  110.         0x95, 0xA5, 0x55, 0x32, 0x57, 0x13, 0xF7, 0xFA, 0x26, 0x13, 0x8E,
  111.         0x6C, 0xF9, 0x58, 0x7C, 0xA2, 0x59, 0xD2, 0x81, 0xD6, 0xC1, 0xC6,
  112.         0x33, 0xBE, 0x66, 0x14, 0xBC, 0x15, 0xE7, 0xFB, 0x2C, 0x35, 0xE1,
  113.         0x54, 0x11, 0x1C, 0xB2, 0x68, 0xFB, 0xF3, 0x7F, 0x62, 0x69, 0x42,
  114.         0x6D, 0xDE, 0x88, 0xD7, 0xAF, 0xE4, 0xAA, 0xED, 0xF4, 0x58, 0x44,
  115.         0x69, 0xBA, 0x51, 0x30, 0x6B, 0xF9, 0x48, 0x8D, 0x74, 0xDB, 0x64,
  116.         0xC3, 0x9A, 0xA2, 0x54, 0x86, 0xA2, 0xAA, 0x46, 0x0D, 0x5A, 0xE9,
  117.         0x15, 0x22, 0x36, 0xF5, 0x8B, 0xFF, 0xCD, 0xF9, 0xDA, 0x6C, 0x92,
  118.         0x5A, 0x1D, 0x5F, 0x2F, 0xA0, 0xED, 0x4A, 0x83, 0x2D, 0xAB, 0x07,
  119.         0x3B, 0x67, 0x8A, 0x3B, 0x35, 0xF1, 0xA6, 0xA3, 0x38, 0x16, 0x5A,
  120.         0x3D, 0xBB, 0x72, 0xBD, 0x1A, 0xFC, 0xA3, 0xB7, 0x04, 0x12, 0x8C,
  121.         0x40, 0x99, 0x08, 0x45, 0x68, 0x33, 0x7E
  122.     };
  123.     DH *dh;
  124.  
  125.     if ( (dh = DH_new()) == NULL )
  126.         return (NULL);
  127.     dh->p = BN_bin2bn( dh1024_p, sizeof(dh1024_p), NULL );
  128.     dh->g = BN_bin2bn( dh1024_g, sizeof(dh1024_g), NULL );
  129.     if ( (dh->p == NULL) || (dh->g == NULL) ) {
  130.         DH_free( dh );
  131.         return (NULL);
  132.     }
  133.     dh->length = 160;
  134.     return (dh);
  135. }
  136. #endif
  137.  
  138. struct {
  139.     SSL_CTX *s_ctx;
  140.     SSL *s_ssl;
  141.     int s_ready;
  142.     int s_failed;
  143.     SSL_CTX *c_ctx;
  144.     SSL *c_ssl;
  145.     int c_ready;
  146.     int c_failed;
  147. } app;
  148.  
  149. static void s_ssl_info_callback(const SSL *ssl, int where, int ret) {
  150.     if ( where & SSL_CB_ALERT ) {
  151.         fprintf( stdout, "[S] SSL_CB_ALERT %s %s\n", SSL_alert_type_string( ret ), SSL_alert_desc_string_long( ret ) );
  152.         app.s_failed = 1;
  153.     }
  154. }
  155.  
  156. static void c_ssl_info_callback(const SSL *ssl, int where, int ret) {
  157.     if ( where & SSL_CB_ALERT ) {
  158.         fprintf( stdout, "[C] SSL_CB_ALERT %s %s\n", SSL_alert_type_string( ret ), SSL_alert_desc_string_long( ret ) );
  159.         app.c_failed = 1;
  160.     }
  161. }
  162.  
  163. void init_ssl() {
  164.     SSL_library_init();
  165. #if 0
  166.     SSL_load_error_strings();
  167. #endif
  168. }
  169.  
  170. void end_ssl() {
  171.     EVP_cleanup();
  172. }
  173.  
  174. int start_ssl() {
  175.     SSL_CTX *s_ctx = 0;
  176.     SSL *s_ssl = 0;
  177.     BIO *s_bior = 0, *s_biow = 0;
  178.  
  179.     SSL_CTX *c_ctx = 0;
  180.     SSL *c_ssl = 0;
  181.     BIO *c_bior = 0, *c_biow = 0;
  182.  
  183.     char *cipher = CIPHER;
  184.  
  185.     if ( !(s_ctx = SSL_CTX_new( SSLv3_method() )) )
  186.         goto error;
  187.  
  188.     if ( !SSL_CTX_set_options( s_ctx, SSL_OP_NO_SSLv2 ) )
  189.         goto error;
  190.  
  191.     if ( !SSL_CTX_set_options( s_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE ) )
  192.         goto error;
  193.  
  194.     if ( cipher ) {
  195.         if ( !SSL_CTX_set_cipher_list( s_ctx, cipher ) )
  196.             goto error;
  197.     }
  198.  
  199. #if !NO_DH
  200. #if 0
  201.     DH *dh = get_dh512();
  202. #else
  203.     DH *dh = get_dh1024();
  204. #endif
  205.     SSL_CTX_set_tmp_dh(s_ctx,dh);
  206.     DH_free( dh );
  207.  
  208.     if ( ! SSL_CTX_set_options(s_ctx, SSL_OP_SINGLE_DH_USE) )
  209.         goto error;
  210. #endif
  211.  
  212. #if NO_FILE
  213.     if ( ! SSL_CTX_use_certificate_ASN1(s_ctx, sizeof (cert), cert) )
  214.         goto error;
  215. #else
  216.     if ( ! SSL_CTX_use_certificate_file(s_ctx, CERT_FILE, SSL_FILETYPE_PEM) )
  217.         goto error;
  218. #endif
  219.  
  220. #if NO_FILE
  221.     if ( ! SSL_CTX_use_RSAPrivateKey_ASN1(s_ctx, key, sizeof (key) ) )
  222.         goto error;
  223. #else
  224.     if ( ! SSL_CTX_use_PrivateKey_file(s_ctx, KEY_FILE, SSL_FILETYPE_PEM) )
  225.         goto error;
  226. #endif
  227.  
  228.     if ( ! SSL_CTX_check_private_key( s_ctx) )
  229.         goto error;
  230.  
  231.     SSL_CTX_set_info_callback( s_ctx, s_ssl_info_callback );
  232.  
  233.     if ( !(s_ssl = SSL_new( s_ctx )) )
  234.         goto error;
  235.  
  236.     s_bior = BIO_new( BIO_s_mem() );
  237.     s_biow = BIO_new( BIO_s_mem() );
  238.     SSL_set_bio( s_ssl, s_bior, s_biow );
  239.  
  240.     SSL_set_accept_state( s_ssl );
  241.  
  242.     if ( !(c_ctx = SSL_CTX_new( SSLv3_method() )) )
  243.         goto error;
  244.  
  245.     if ( !SSL_CTX_set_options( c_ctx, SSL_OP_NO_SSLv2 ) )
  246.         goto error;
  247.  
  248.     if ( cipher ) {
  249.         if ( !SSL_CTX_set_cipher_list( c_ctx, cipher ) )
  250.             goto error;
  251.     }
  252.  
  253. #if 0
  254.     if ( ! SSL_CTX_load_verify_locations( c_ctx, CERT_FILE, 0) )
  255.         goto error;
  256. #endif
  257.  
  258.     SSL_CTX_set_info_callback( c_ctx, c_ssl_info_callback );
  259.  
  260.     if ( !(c_ssl = SSL_new( c_ctx )) )
  261.         goto error;
  262.  
  263.     c_bior = BIO_new( BIO_s_mem() );
  264.     c_biow = BIO_new( BIO_s_mem() );
  265.     SSL_set_bio( c_ssl, c_bior, c_biow );
  266.  
  267.     SSL_set_connect_state( c_ssl );
  268.  
  269.     app.c_ctx = c_ctx;
  270.     app.c_ssl = c_ssl;
  271.     app.s_ctx = s_ctx;
  272.     app.s_ssl = s_ssl;
  273.  
  274.     return 1;
  275.  
  276. error:
  277.  
  278.     ERR_print_errors_fp( stderr );
  279.     if ( c_ctx )
  280.         SSL_CTX_free( c_ctx );
  281.     if ( c_ssl )
  282.         SSL_free( c_ssl );
  283.     if ( s_ctx )
  284.         SSL_CTX_free( s_ctx );
  285.     if ( s_ssl )
  286.         SSL_free( s_ssl );
  287.  
  288.     return 0;
  289. }
  290.  
  291. void stop_ssl() {
  292.     if ( app.s_ctx != 0 ) {
  293.         SSL_CTX_free( app.s_ctx );
  294.         app.s_ctx = 0;
  295.     }
  296.     if ( app.s_ssl != 0 ) {
  297.         SSL_free( app.s_ssl );
  298.         app.s_ssl = 0;
  299.     }
  300.  
  301.     if ( app.c_ctx != 0 ) {
  302.         SSL_CTX_free( app.c_ctx );
  303.         app.s_ctx = 0;
  304.     }
  305.     if ( app.c_ssl != 0 ) {
  306.         SSL_free( app.c_ssl );
  307.         app.c_ssl = 0;
  308.     }
  309. }
  310.  
  311. void quit(int ret) {
  312.     stop_ssl();
  313.     end_ssl();
  314.  
  315.     exit( ret );
  316. }
  317.  
  318. int read_ssl(SSL* ssl, unsigned char *buffer, unsigned buffer_size) {
  319.     fputs( "read_ssl\n", stdout );
  320.     int r;
  321.  
  322.     r = SSL_read( ssl, buffer, buffer_size );
  323.  
  324.     if ( r < 0 ) {
  325.         int err = SSL_get_error( ssl, r );
  326.  
  327.         if ( err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE )
  328.             r = 0;
  329.     }
  330.  
  331.     return r;
  332. }
  333.  
  334. int write_ssl(SSL* ssl, const unsigned char *buffer, unsigned buffer_size) {
  335.     fputs( "write_ssl\n", stdout );
  336.     int r;
  337.  
  338.     r = SSL_write( ssl, buffer, buffer_size );
  339.  
  340.     if ( r < 0 ) {
  341.         int err = SSL_get_error( ssl, r );
  342.  
  343.         if ( err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE )
  344.             r = 0;
  345.     }
  346.  
  347.     return r;
  348. }
  349.  
  350. int inject_ssl(const SSL* ssl, const unsigned char *buffer, unsigned buffer_size) {
  351.     fputs( "inject_ssl\n", stdout );
  352.     BIO * bior = SSL_get_rbio( ssl );
  353.  
  354.     return BIO_write( bior, buffer, buffer_size );
  355. }
  356.  
  357. int extract_ssl(const SSL* ssl, unsigned char *buffer, unsigned buffer_size) {
  358.     fputs( "extract_ssl\n", stdout );
  359.     BIO * biow = SSL_get_wbio( ssl );
  360.  
  361.     return BIO_read( biow, buffer, buffer_size );
  362. }
  363.  
  364. void server_read() {
  365.     fputs( "server read\n", stdout );
  366.     unsigned char buffer[1024];
  367.  
  368.     int r = extract_ssl( app.s_ssl, buffer, sizeof(buffer) );
  369.     fprintf( stderr, "r=%d\n", r );
  370.     if ( r > 0 ) {
  371.         DUMP( buffer, r, stdout );
  372.         r = inject_ssl( app.c_ssl, buffer, r );
  373.         fprintf( stderr, "r=%d\n", r );
  374.     }
  375. }
  376.  
  377. void client_read() {
  378.     fputs( "client read\n", stdout );
  379.     unsigned char buffer[1024];
  380.  
  381.     int r = extract_ssl( app.c_ssl, buffer, sizeof(buffer) );
  382.     fprintf( stderr, "r=%d\n", r );
  383.     if ( r > 0 ) {
  384.         DUMP( buffer, r, stdout );
  385.         r = inject_ssl( app.s_ssl, buffer, r );
  386.         fprintf( stderr, "r=%d\n", r );
  387.     }
  388. }
  389.  
  390. void process_bio(SSL *s_ssl, SSL *c_ssl) {
  391.     BIO * s_bior = SSL_get_rbio( s_ssl );
  392.     BIO * s_biow = SSL_get_wbio( s_ssl );
  393.  
  394.     BIO * c_bior = SSL_get_rbio( c_ssl );
  395.     BIO * c_biow = SSL_get_wbio( c_ssl );
  396.  
  397.     int s_bior_cnt, s_biow_cnt;
  398.     int c_bior_cnt, c_biow_cnt;
  399.  
  400.     s_biow_cnt = BIO_pending(s_biow);
  401.     s_bior_cnt = BIO_pending(s_bior);
  402.     c_biow_cnt = BIO_pending(c_biow);
  403.     c_bior_cnt = BIO_pending(c_bior);
  404.  
  405.     fprintf( stdout, "[S] biow=%d\n", s_biow_cnt );
  406.     fprintf( stdout, "[S] bior=%d\n", s_bior_cnt );
  407.     fprintf( stdout, "[C] biow=%d\n", c_biow_cnt );
  408.     fprintf( stdout, "[C] bior=%d\n", c_bior_cnt );
  409.  
  410.     if ( s_biow_cnt ) {
  411.         server_read();
  412.     }
  413.     if ( c_biow_cnt ) {
  414.         client_read();
  415.     }
  416. }
  417.  
  418. void blahblah() {
  419.     SSL *s_ssl = app.s_ssl;
  420.     SSL *c_ssl = app.c_ssl;
  421.  
  422.     char *msg = "HELLO";
  423.     unsigned msg_len = 5;
  424.     char *reply = "BYE";
  425.     unsigned reply_len = 3;
  426.  
  427.     unsigned char buffer[32];
  428.  
  429.     int r, w;
  430.  
  431.     fprintf( stderr, "msg=%s\n", msg );
  432.  
  433.     w = write_ssl( c_ssl, (const unsigned char *) msg, msg_len );
  434.     if ( w < 0 ) {
  435.         ERR_print_errors_fp( stderr );
  436.         quit( 3 );
  437.     }
  438.     if ( w == 0 )
  439.         return;
  440.  
  441.     process_bio( s_ssl, c_ssl );
  442.  
  443.     r = read_ssl( s_ssl, buffer, sizeof (buffer) - 1);
  444.     fprintf( stderr, "r=%d\n", r );
  445.     if ( r < 0 ) {
  446.         ERR_print_errors_fp( stderr );
  447.         quit( 3 );
  448.     }
  449.     if ( r == 0 )
  450.         return;
  451.  
  452.     buffer[ r ] = '\0';
  453.  
  454.     fprintf( stderr, "[S] %s\n", buffer );
  455.  
  456.     fprintf( stderr, "reply=%s\n", reply );
  457.  
  458.     w = write_ssl( s_ssl, (const unsigned char *) reply, reply_len );
  459.     if ( w < 0 ) {
  460.         ERR_print_errors_fp( stderr );
  461.         quit( 3 );
  462.     }
  463.     if ( w == 0 )
  464.         return;
  465.  
  466.     process_bio( s_ssl, c_ssl );
  467.  
  468.     r = read_ssl( c_ssl, buffer, sizeof (buffer) - 1);
  469.     fprintf( stderr, "r=%d\n", r );
  470.     if ( r < 0 ) {
  471.         ERR_print_errors_fp( stderr );
  472.         quit( 3 );
  473.     }
  474.     if ( r == 0 )
  475.         return;
  476.  
  477.     buffer[ r ] = '\0';
  478.  
  479.     fprintf( stderr, "[C] %s\n", buffer );
  480. }
  481.  
  482. void doit() {
  483.     SSL *s_ssl = app.s_ssl;
  484.     SSL *c_ssl = app.c_ssl;
  485.  
  486.     while ( !(app.s_ready && app.c_ready) && !(app.s_failed && app.c_failed) ) {
  487.         fprintf( stdout, "[S] %s\n", SSL_state_string( s_ssl ) );
  488.         fprintf( stdout, "[C] %s\n", SSL_state_string( c_ssl ) );
  489.  
  490.         if ( SSL_want_nothing(s_ssl) )
  491.             fputs( "[S] SSL_ERROR_WANT_NOTHING\n", stdout );
  492.         if ( SSL_want_read(s_ssl) )
  493.             fputs( "[S] SSL_ERROR_WANT_READ\n", stdout );
  494.         if ( SSL_want_write(s_ssl) )
  495.             fputs( "[S] SSL_ERROR_WANT_WRITE\n", stdout );
  496.         if ( SSL_want_x509_lookup(s_ssl) )
  497.             fputs( "[S] SSL_ERROR_WANT_X509_LOOKUP\n", stdout );
  498.  
  499.  
  500.         if ( SSL_want_nothing(c_ssl) )
  501.             fputs( "[C] SSL_ERROR_WANT_NOTHING\n", stdout );
  502.         if ( SSL_want_read(c_ssl) )
  503.             fputs( "[C] SSL_ERROR_WANT_READ\n", stdout );
  504.         if ( SSL_want_write(c_ssl) )
  505.             fputs( "[C] SSL_ERROR_WANT_WRITE\n", stdout );
  506.         if ( SSL_want_x509_lookup(c_ssl) )
  507.             fputs( "[C] SSL_ERROR_WANT_X509_LOOKUP\n", stdout );
  508.  
  509.         if ( !app.s_ready && !app.s_failed ) {
  510.             if ( SSL_in_before(s_ssl) )
  511.                 fputs( "[S] SSL_ST_BEFORE\n", stdout );
  512.             if ( SSL_in_init(s_ssl) )
  513.                 fputs( "[S] SSL_ST_INIT\n", stdout );
  514.             if ( SSL_in_connect_init(s_ssl) )
  515.                 fputs( "[S] SSL_ST_CONNECT_INIT\n", stdout );
  516.             if ( SSL_in_accept_init(s_ssl) )
  517.                 fputs( "[S] SSL_ST_ACCEPT_INIT\n", stdout );
  518.  
  519.             if ( SSL_in_init(s_ssl) ) {
  520.                 fputs( "[S] SSL_do_handshake\n", stdout );
  521.                 SSL_do_handshake( s_ssl );
  522.             }
  523.             if ( SSL_is_init_finished( s_ssl ) ) {
  524.                 app.s_ready = 1;
  525.                 fputs( "[S] *** ready ***\n", stdout );
  526.                 fprintf( stdout, "[S] %s\n", SSL_state_string( s_ssl ) );
  527.  
  528.                 SSL_SESSION *sess = SSL_get_session( s_ssl );
  529.                 if ( sess ) {
  530.                     fprintf( stdout, "sess->cipher->name=%s\n", sess->cipher->name );
  531.                 }
  532.             }
  533.         }
  534.  
  535.         if ( !app.c_ready && !app.c_failed ) {
  536.             if ( SSL_in_before(c_ssl) )
  537.                 fputs( "[C] SSL_ST_BEFORE\n", stdout );
  538.             if ( SSL_in_init(c_ssl) )
  539.                 fputs( "[C] SSL_ST_INIT\n", stdout );
  540.             if ( SSL_in_connect_init(c_ssl) )
  541.                 fputs( "[C] SSL_ST_CONNECT_INIT\n", stdout );
  542.             if ( SSL_in_accept_init(c_ssl) )
  543.                 fputs( "[C] SSL_ST_ACCEPT_INIT\n", stdout );
  544.  
  545.             if ( SSL_in_init(c_ssl) ) {
  546.                 fputs( "[C] SSL_do_handshake\n", stdout );
  547.                 SSL_do_handshake( c_ssl );
  548.             }
  549.             if ( SSL_is_init_finished( c_ssl ) ) {
  550.                 app.c_ready = 1;
  551.                 fputs( "[C] *** ready ***\n", stdout );
  552.                 fprintf( stdout, "[C] %s\n", SSL_state_string( c_ssl ) );
  553.  
  554.                 fprintf( stdout, "SSL_get_verify_result=%ld\n",
  555.                         SSL_get_verify_result( c_ssl ) );
  556.  
  557.                 X509 *cert = SSL_get_peer_certificate( c_ssl );
  558.                 if ( cert ) {
  559.                     fprintf( stdout, "cert->valid=%d\n", cert->valid );
  560.                     fprintf( stdout, "cert->name=%s\n", cert->name );
  561.  
  562.                     EVP_MD *digest;
  563.                     digest = (EVP_MD*) EVP_sha1();
  564.                     unsigned char data[EVP_MAX_MD_SIZE];
  565.                     unsigned int len;
  566.                     if ( X509_digest( cert, digest, data, &len ) > 0 ) {
  567.                         unsigned char *p;
  568.                         fputs( "cert->fingerprint=", stdout );
  569.                         for ( p = data; p < data + len; p++ )
  570.                             fprintf( stdout, p == data ? "%02x" : ":%02x", *p );
  571.                         fprintf( stdout, "\n" );
  572.                     }
  573.                 }
  574.                 SSL_SESSION *sess = SSL_get_session( c_ssl );
  575.                 if ( sess ) {
  576.                     fprintf( stdout, "sess->cipher->name=%s\n", sess->cipher->name );
  577.                 }
  578.             }
  579.         }
  580.  
  581.         process_bio( s_ssl, c_ssl );
  582.     }
  583.  
  584.     if ( !(app.s_ready && app.c_ready) )
  585.         return;
  586.  
  587.     blahblah();
  588. }
  589.  
  590. void startup() {
  591.     init_ssl();
  592.  
  593.     if ( !start_ssl() )
  594.         exit( 1 );
  595. }
  596.  
  597. void init() {
  598.     app.s_failed = 0;
  599.     app.s_ready = 0;
  600.     app.c_failed = 0;
  601.     app.c_ready = 0;
  602. }
  603.  
  604. int main(int argc, char **argv) {
  605.     init();
  606.  
  607.     startup();
  608.     doit();
  609.  
  610.     exit( 0 );
  611. }
  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

To add a comment, click here.