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
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #include <stdio.h>
- #include <errno.h>
- #include <unistd.h>
- #include <openssl/ssl.h>
- #include <openssl/err.h>
- #define HOSTADDR INADDR_LOOPBACK /* 0x7F000001U */
- #define PORTNUM 443
- struct {
- int host_ip;
- int port_num;
- int socket;
- SSL_CTX *ctx;
- SSL *ssl;
- } 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.
- int open_conn() {
- int sd = -1;
- struct sockaddr_in sd_address;
- int addrlen = sizeof(struct sockaddr_in);
- if ( (sd = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP )) == -1 )
- goto error;
- sd_address.sin_family = AF_INET;
- sd_address.sin_addr.s_addr = app.host_ip; /* already in network order */
- sd_address.sin_port = app.port_num; /* see init */
- if ( connect( sd, (struct sockaddr *) &sd_address, addrlen ) == -1 )
- goto error;
- app.socket = sd;
- return 1;
- error:
- perror( 0 );
- if ( sd != -1 )
- close( sd );
- return 0;
- }
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
.
- void close_conn() {
- if ( app.socket != -1 ) {
- close( app.socket );
- app.socket = -1;
- }
- }
close_conn
closes the connection of the socket saved in app
.
- void init_ssl() {
- SSL_library_init();
- #if 1
- SSL_load_error_strings();
- #endif
- }
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
- void end_ssl() {
- EVP_cleanup();
- }
end_ssl
ends using the SSL library.
- int start_ssl() {
- SSL_CTX *ctx = 0;
- SSL *ssl = 0;
- BIO *bior, *biow;
- /* create SSL context (only for v3) */
- if ( (ctx = SSL_CTX_new( SSLv3_method() )) == 0 )
- goto error;
- /* create SSL engine */
- if ( (ssl = SSL_new( ctx )) == 0 )
- goto error;
- /* connect SSL engine to r/w buffers in memory */
- bior = BIO_new( BIO_s_mem() );
- biow = BIO_new( BIO_s_mem() );
- SSL_set_bio( ssl, bior, biow );
- /* be a client */
- SSL_set_connect_state(ssl);
- app.ctx = ctx;
- app.ssl = ssl;
- return 1;
- error:
- ERR_print_errors_fp( stderr );
- if ( ctx )
- SSL_CTX_free( ctx );
- if ( ssl )
- SSL_free( ssl );
- return 0;
- }
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
- void stop_ssl() {
- if ( app.ctx != 0 ) {
- SSL_CTX_free( app.ctx );
- app.ctx = 0;
- }
- if ( app.ssl != 0 ) {
- SSL_free( app.ssl );
- app.ssl = 0;
- }
- }
stop_ssl
frees SSL context and the SSL object saved in app
.
- void quit( int ret ) {
- close_conn();
- stop_ssl();
- end_ssl();
- exit( ret );
- }
quit
closes the connection with the server, frees the SSL resources then terminates the program with the return code ret
.
- int inject_ssl( const SSL* ssl, const unsigned char *buffer, unsigned buffer_size ) {
- BIO * bior = SSL_get_rbio( ssl );
- return BIO_write( bior, buffer, buffer_size );
- }
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.
- int extract_ssl( const SSL* ssl, unsigned char *buffer, unsigned buffer_size ) {
- BIO * biow = SSL_get_wbio( ssl );
- return BIO_read( biow, buffer, buffer_size );
- }
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.
- int read_socket() {
- unsigned char buffer[ 4*1024 ];
- /* pipe server data to SSL engine */
- int r = read( app.socket, buffer, sizeof(buffer) );
- if ( r == 0 ) {
- return 0;
- }
- inject_ssl( app.ssl, buffer, r );
- return 1;
- }
read_socket
injects the bytes read from the socket of the application into the SSL engine.
- int write_socket() {
- unsigned char buffer[ 4*1024 ];
- /* pipe SSL engine data to server socket */
- int r = extract_ssl( app.ssl, buffer, sizeof(buffer) );
- if ( write( app.socket, buffer, r ) != r )
- return 0;
- return 1;
- }
write_socket
writes the bytes extracted from the SSL engine to the socket of the application.
- void startup() {
- init_ssl();
- if ( !start_ssl() )
- exit( 1 );
- if ( !open_conn() )
- exit( 1 );
- }
startup
begins using the SSL library, creates and configures the SSL object and opens the connection with the server.
- void init() {
- app.host_ip = htonl( HOSTADDR );
- app.port_num = htons( PORTNUM );
- app.socket = -1;
- }
init
initializes app
.
- void doit() {
- fd_set read_fds, write_fds;
- int n_fds = FD_SETSIZE;
- SSL *ssl = app.ssl;
- BIO * biow = SSL_get_wbio( ssl );
- for ( ;; ) {
- FD_ZERO( &read_fds );
- FD_ZERO( &write_fds );
- /* retry handshake until done (reads SSL bior) */
- if ( SSL_in_init(ssl)) {
- SSL_do_handshake( ssl );
- }
- /* are we connected? (MUST be done after retrying handshake) */
- if ( SSL_is_init_finished( ssl ) ) {
- break;
- }
- /* read input from server */
- FD_SET( app.socket, &read_fds );
- /* write SSL engine output to server */
- if ( BIO_pending(biow) ) {
- FD_SET( app.socket, &write_fds );
- }
- switch ( select( n_fds, &read_fds, &write_fds, 0, 0 ) ) {
- case -1: /* trouble */
- if ( errno != EINTR ) {
- perror( 0 );
- quit( 1 );
- }
- break;
- case 0: /* time out */
- break;
- default: /* event */
- if ( FD_ISSET(app.socket, &read_fds) ) {
- if ( ! read_socket() ) {
- fputs( "read failed?\n", stderr );
- quit( 1 );
- }
- }
- if ( FD_ISSET(app.socket, &write_fds) ) {
- if ( ! write_socket() ) {
- fputs( "write failed?\n", stderr );
- quit( 1 );
- }
- }
- break;
- }
- }
- /* get certificate */
- X509 *cert = SSL_get_peer_certificate( ssl );
- if ( ! cert ) {
- fputs( "cert?\n", stderr );
- quit( 1 );
- }
- /* get certificate digest (SHA1) */
- EVP_MD *digest = (EVP_MD*) EVP_sha1();
- unsigned char data[EVP_MAX_MD_SIZE];
- unsigned int len;
- if ( ! (X509_digest(cert, digest, data, &len) > 0) ) {
- fputs( "cert?\n", stderr );
- quit( 1 );
- }
- /* print certificate */
- unsigned char *p;
- for (p = data; p < data + len; p++)
- fprintf(stdout, p == data ? "%02x" : ":%02x", *p);
- fputs("\n", stdout);
- }
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.
- int main( int argc, char **argv ) {
- struct hostent *host;
- int port_num;
- extern int opterr;
- int c;
- init();
- opterr = 0;
- while ( (c = getopt( argc, argv, "h:p:" )) != -1 ) {
- switch ( c ) {
- case 'p':
- if ( (port_num = atoi( optarg )) == 0 ) {
- fputs( "portnum?\n", stderr );
- exit( 1 );
- }
- app.port_num = htons( port_num );
- break;
- case 'h':
- if ( (host = gethostbyname( optarg )) == 0 ) {
- fputs( "hostname?\n", stderr );
- exit( 1 );
- }
- app.host_ip = *((unsigned *) host->h_addr);
- endhostent();
- break;
- case '?':
- default:
- usage: fprintf( stderr, "%s [-h host_name] [-p port_num]\n", argv[0] );
- exit( 1 );
- }
- }
- switch ( argc - optind ) {
- case 0:
- break;
- default:
- goto usage;
- }
- startup();
- doit();
- exit(0);
- }
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
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: /
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <strings.h>
- #include <errno.h>
- #include <string.h>
- #include <unistd.h>
- #include <openssl/ssl.h>
- #include <openssl/err.h>
- #if 0
- extern void dump(unsigned char *buf, int size, FILE *fout);
- #define DUMP(buf, size, fout) dump(buf, size, fout);
- #else
- #define DUMP(buf, size, fout)
- #endif
- #define HOSTADDR INADDR_LOOPBACK /* 0x7F000001U */
- #define PORTNUM 443
- #define NO_FILE 1
- #define CERT_FILE "snakeoil.crt"
- #define CIPHER "DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:AES256-SHA:AES128-SHA"
- struct {
- int host_ip;
- int port_num;
- int socket;
- int input;
- SSL_CTX *ctx;
- SSL *ssl;
- int ready;
- int failed;
- } app;
- int open_conn() {
- int sd = -1;
- struct sockaddr_in sd_address;
- int addrlen = sizeof(struct sockaddr_in);
- if ( (sd = socket( PF_INET, SOCK_STREAM, IPPROTO_TCP )) == -1 )
- goto error;
- sd_address.sin_family = AF_INET;
- sd_address.sin_addr.s_addr = app.host_ip; /* already in network order */
- sd_address.sin_port = app.port_num; /* see init */
- if ( connect( sd, (struct sockaddr *) &sd_address, addrlen ) == -1 )
- goto error;
- app.socket = sd;
- return 1;
- error:
- perror( 0 );
- if ( sd != -1 )
- close( sd );
- return 0;
- }
- void close_conn() {
- if ( app.socket != -1 ) {
- close( app.socket );
- app.socket = -1;
- }
- }
- void ssl_info_callback(const SSL *ssl, int where, int ret) {
- if ( where & SSL_CB_LOOP ) {
- fprintf( stdout, "SSL_CB_LOOP %s %s\n",
- SSL_state_string( ssl ), SSL_state_string_long( ssl ) );
- }
- else if ( where & SSL_CB_EXIT ) {
- fprintf( stdout, "SSL_CB_EXIT %s %s\n",
- SSL_state_string( ssl ), SSL_state_string_long( ssl ) );
- }
- else if ( where & SSL_CB_ALERT ) {
- fprintf( stdout, "SSL_CB_ALERT %s %s\n",
- SSL_alert_type_string_long( ret ),
- SSL_alert_desc_string_long( ret ) );
- app.failed = 1;
- }
- }
- void init_ssl() {
- SSL_library_init();
- #if 0
- SSL_load_error_strings();
- OpenSSL_add_ssl_algorithms();
- ERR_load_crypto_strings();
- #endif
- }
- void end_ssl() {
- EVP_cleanup();
- }
- int start_ssl() {
- SSL_CTX *ctx = 0;
- SSL *ssl = 0;
- BIO *bior, *biow;
- char *cipher = CIPHER;
- if ( ! (ctx = SSL_CTX_new( SSLv3_client_method() )) )
- goto error;
- if ( cipher ) {
- if ( ! SSL_CTX_set_cipher_list( ctx, cipher ) )
- goto error;
- }
- #if !NO_FILE
- if ( ! SSL_CTX_load_verify_locations( ctx, CERT_FILE, 0) )
- goto error;
- #endif
- SSL_CTX_set_info_callback( ctx, ssl_info_callback );
- if ( ! (ssl = SSL_new( ctx )) )
- goto error;
- bior = BIO_new( BIO_s_mem() );
- biow = BIO_new( BIO_s_mem() );
- SSL_set_bio( ssl, bior, biow );
- SSL_set_connect_state(ssl);
- app.ctx = ctx;
- app.ssl = ssl;
- return 1;
- error:
- ERR_print_errors_fp( stderr );
- if ( ctx )
- SSL_CTX_free( ctx );
- if ( ssl )
- SSL_free( ssl );
- return 0;
- }
- void stop_ssl() {
- if ( app.ctx != 0 ) {
- SSL_CTX_free( app.ctx );
- app.ctx = 0;
- }
- if ( app.ssl != 0 ) {
- SSL_free( app.ssl );
- app.ssl = 0;
- }
- }
- void quit( int ret ) {
- close_conn();
- stop_ssl();
- end_ssl();
- exit( ret );
- }
- /*
- * input_read(C, strdin) -> write_ssl(C, ssl) -> extract_ssl(X, biow) -> socket_write(X, socket)
- * socket_read(X, socket) -> inject_ssl(X, bior) -> read_ssl(C, ssl) -> output_write(C, stdout)
- */
- int read_ssl( SSL* ssl, unsigned char *buffer, unsigned buffer_size ) {
- fputs( "read_ssl\n", stdout );
- int r;
- r = SSL_read( ssl, buffer, buffer_size );
- if ( r < 0 ) {
- int err = SSL_get_error( ssl, r );
- if ( err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE )
- r = 0;
- }
- return r;
- }
- int write_ssl( SSL* ssl, const unsigned char *buffer, unsigned buffer_size ) {
- fputs( "write_ssl\n", stdout );
- int r;
- r = SSL_write( ssl, buffer, buffer_size );
- if ( r < 0 ) {
- int err = SSL_get_error( ssl, r );
- if ( err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE )
- r = 0;
- }
- return r;
- }
- void inject_ssl( const SSL* ssl, const unsigned char *buffer, unsigned buffer_size ) {
- fputs( "inject_ssl\n", stdout );
- BIO * bior = SSL_get_rbio( ssl );
- BIO_write( bior, buffer, buffer_size );
- }
- int extract_ssl( const SSL* ssl, unsigned char *buffer, unsigned buffer_size ) {
- fputs( "extract_ssl\n", stdout );
- BIO * biow = SSL_get_wbio( ssl );
- return BIO_read( biow, buffer, buffer_size );
- }
- void socket_read() {
- fputs( "socket read\n", stdout );
- unsigned char buffer[1024];
- int r = read( app.socket, buffer, sizeof(buffer) );
- fprintf( stderr, "r=%d\n", r );
- if ( r == 0 ) {
- app.socket = -1;
- }
- else {
- DUMP( buffer, r, stdout );
- inject_ssl( app.ssl, buffer, r );
- }
- }
- void socket_write() {
- fputs( "socket write\n", stdout );
- unsigned char buffer[1024];
- int r = extract_ssl( app.ssl, buffer, sizeof(buffer) );
- fprintf( stderr, "r=%d\n", r );
- if ( r > 0 ) {
- DUMP( buffer, r, stdout );
- (void) write( app.socket, buffer, r );
- }
- }
- void output_write() {
- fputs( "output write\n", stdout );
- unsigned char buffer[1024];
- int r = read_ssl( app.ssl, buffer, sizeof (buffer) );
- fprintf( stderr, "r=%d\n", r );
- if ( r < 0 ) {
- ERR_print_errors_fp( stderr );
- quit( 3 );
- }
- if ( r == 0 )
- return;
- write( 1, buffer, r );
- write( 1, "\n", 1 );
- }
- void input_read() {
- fputs( "input read\n", stdout );
- unsigned char buffer[1024];
- int r = read( 0, buffer, sizeof (buffer) );
- fprintf( stderr, "r=%d\n", r );
- if ( r == 0 ) {
- app.input = 0;
- return;
- }
- DUMP( buffer, r, stdout );
- int w = write_ssl( app.ssl, buffer, r );
- if ( w < 0 ) {
- ERR_print_errors_fp( stderr );
- quit( 3 );
- }
- if ( w == 0 )
- return;
- }
- void startup() {
- init_ssl();
- if ( !open_conn() )
- exit( 1 );
- if ( !start_ssl() )
- exit( 1 );
- }
- void init() {
- app.host_ip = htonl( HOSTADDR );
- app.port_num = htons( PORTNUM );
- app.socket = -1;
- app.input = 1;
- app.ready = 0;
- app.failed = 0;
- }
- void main_loop() {
- fd_set read_fds, write_fds;
- int n_fds = FD_SETSIZE;
- SSL *ssl = app.ssl;
- BIO * bior = SSL_get_rbio( ssl );
- BIO * biow = SSL_get_wbio( ssl );
- for ( ;; ) { /* forever */
- FD_ZERO( &read_fds );
- FD_ZERO( &write_fds );
- if ( SSL_want_nothing(ssl) )
- fputs( "SSL_ERROR_WANT_NOTHING\n", stdout );
- if ( SSL_want_read(ssl) )
- fputs( "SSL_ERROR_WANT_READ\n", stdout );
- if ( SSL_want_write(ssl) )
- fputs( "SSL_ERROR_WANT_WRITE\n", stdout );
- if ( SSL_want_x509_lookup(ssl) )
- fputs( "SSL_ERROR_WANT_X509_LOOKUP\n", stdout );
- fprintf( stdout, "biow=%d\n", BIO_pending(biow) );
- fprintf( stdout, "bior=%d\n", BIO_pending(bior) );
- fprintf( stdout, "pending=%d\n", SSL_pending( ssl ) );
- if ( !app.ready && !app.failed ) {
- fprintf( stdout, "%s\n", SSL_state_string( ssl ) );
- if ( SSL_in_before(ssl) )
- fputs( "SSL_ST_BEFORE\n", stdout );
- if ( SSL_in_init(ssl) )
- fputs( "SSL_ST_INIT\n", stdout );
- if ( SSL_in_connect_init(ssl) )
- fputs( "SSL_ST_CONNECT_INIT\n", stdout );
- if ( SSL_in_accept_init(ssl) )
- fputs( "SSL_ST_ACCEPT_INIT\n", stdout );
- if ( SSL_in_init(ssl)) {
- fputs( "SSL_do_handshake\n", stdout );
- SSL_do_handshake( ssl );
- }
- if ( SSL_is_init_finished( ssl ) ) {
- app.ready = 1;
- fputs( "*** ready ***\n", stdout );
- fprintf( stdout, "SSL_get_verify_result=%ld\n", SSL_get_verify_result( ssl ) );
- X509 *cert = SSL_get_peer_certificate( ssl );
- if ( cert ) {
- fprintf( stdout, "cert->valid=%d\n", cert->valid );
- fprintf( stdout, "cert->name=%s\n", cert->name );
- }
- SSL_SESSION *sess = SSL_get_session( ssl );
- if ( sess ) {
- fprintf( stdout, "sess->cipher->name=%s\n", sess->cipher->name );
- }
- }
- }
- fprintf( stdout, "biow=%d\n", BIO_pending(biow) );
- fprintf( stdout, "bior=%d\n", BIO_pending(bior) );
- fprintf( stdout, "pending=%d\n", SSL_pending( ssl ) );
- /* socket? */
- if ( app.socket != -1 ) {
- FD_SET( app.socket, &read_fds );
- }
- /* read input? */
- if ( app.ready && app.input ) {
- FD_SET( 0, &read_fds );
- }
- if ( BIO_pending(biow) ) {
- if ( app.socket != -1 )
- FD_SET( app.socket, &write_fds );
- }
- if ( BIO_pending(bior) ) {
- FD_SET( 1, &write_fds );
- }
- if ( SSL_pending( ssl ) ) {
- FD_SET( 1, &write_fds );
- }
- if ( !app.input && app.socket == -1 && !SSL_pending( ssl ) )
- quit( 0 );
- switch ( select( n_fds, &read_fds, &write_fds, 0, 0 ) ) {
- case -1: /* trouble */
- if ( errno != EINTR ) {
- perror( 0 );
- quit( 1 );
- }
- break;
- case 0: /* time out */
- break;
- default: /* event */
- if ( app.socket != -1 && FD_ISSET(app.socket, &read_fds) ) {
- socket_read();
- }
- if ( FD_ISSET(1, &write_fds) ) {
- output_write();
- }
- if ( app.socket != -1 && FD_ISSET(app.socket, &write_fds) ) {
- socket_write();
- }
- if ( FD_ISSET( 0, &read_fds ) ) {
- input_read();
- }
- break;
- }
- }
- }
- int main( int argc, char **argv ) {
- struct hostent *host;
- int port_num;
- extern int opterr;
- int c;
- init();
- opterr = 0;
- while ( (c = getopt( argc, argv, "h:p:" )) != -1 )
- switch ( c ) {
- case 'p':
- if ( (port_num = atoi( optarg )) == 0 ) {
- fputs( "portnum?\n", stderr );
- exit( 1 );
- }
- app.port_num = htons( port_num );
- break;
- case 'h':
- if ( (host = gethostbyname( optarg )) == 0 ) {
- fputs( "hostname?\n", stderr );
- exit( 1 );
- }
- app.host_ip = *((unsigned *) host->h_addr);
- endhostent();
- break;
- case '?':
- default:
- usage: fprintf( stderr, "%s [-h host_name] [-p port_num]\n", argv[0] );
- exit( 1 );
- }
- switch ( argc - optind ) {
- case 0:
- break;
- default:
- goto usage;
- }
- setbuf( stdout, 0 );
- startup();
- main_loop();
- exit(0);
- }
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]
.
- #include <unistd.h>
- #include <openssl/ssl.h>
- #include <openssl/err.h>
- #if 0
- extern void dump(unsigned char *buf, int size, FILE *fout);
- #define DUMP(buf, size, fout) dump( buf, size, fout );
- #else
- #define DUMP(buf, size, fout)
- #endif
- #define NO_DH 0
- #define NO_FILE 1
- #define CERT_FILE "snakeoil.crt"
- #define KEY_FILE "snakeoil.key"
- #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 */
- #if NO_FILE
- /* openssl x509 -in snakeoil.crt -outform DER | xxd -i */
- static unsigned char cert[] = {
- 0x30, 0x82, 0x01, 0x99, 0x30, 0x82, 0x01, 0x02, 0x02, 0x09, 0x00, 0x80,
- 0xb5, 0x35, 0x11, 0x35, 0xab, 0x15, 0x82, 0x30, 0x0d, 0x06, 0x09, 0x2a,
- 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x05, 0x05, 0x00, 0x30, 0x11,
- 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x06, 0x75,
- 0x62, 0x75, 0x6e, 0x74, 0x75, 0x30, 0x1e, 0x17, 0x0d, 0x31, 0x30, 0x30,
- 0x35, 0x32, 0x30, 0x30, 0x39, 0x33, 0x34, 0x35, 0x31, 0x5a, 0x17, 0x0d,
- 0x32, 0x30, 0x30, 0x35, 0x31, 0x37, 0x30, 0x39, 0x33, 0x34, 0x35, 0x31,
- 0x5a, 0x30, 0x11, 0x31, 0x0f, 0x30, 0x0d, 0x06, 0x03, 0x55, 0x04, 0x03,
- 0x13, 0x06, 0x75, 0x62, 0x75, 0x6e, 0x74, 0x75, 0x30, 0x81, 0x9f, 0x30,
- 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01,
- 0x05, 0x00, 0x03, 0x81, 0x8d, 0x00, 0x30, 0x81, 0x89, 0x02, 0x81, 0x81,
- 0x00, 0xd3, 0xb5, 0x48, 0x6c, 0x4b, 0x18, 0x80, 0xb0, 0x14, 0xbe, 0x9f,
- 0x1e, 0x99, 0x03, 0xff, 0x5b, 0x47, 0x1a, 0xde, 0x54, 0x2e, 0x5e, 0x86,
- 0xff, 0xaa, 0x7a, 0xb7, 0x04, 0x76, 0x77, 0xd2, 0x9c, 0xc8, 0xd8, 0x8c,
- 0xbe, 0x1a, 0x86, 0x3d, 0x7a, 0xb3, 0xbb, 0x89, 0x2b, 0x16, 0xb9, 0xac,
- 0xd8, 0xe4, 0x8d, 0x66, 0x82, 0xb3, 0xd0, 0x38, 0x3d, 0xd6, 0xce, 0xd2,
- 0x9d, 0x2a, 0x6c, 0x39, 0x95, 0x57, 0x9a, 0xde, 0x8b, 0x5a, 0xd9, 0x35,
- 0xa2, 0x2c, 0x60, 0x69, 0xe9, 0x73, 0xfe, 0x15, 0x76, 0x5a, 0xb6, 0x56,
- 0x38, 0x47, 0x1e, 0xf9, 0x51, 0xba, 0x2c, 0x1b, 0xe4, 0x63, 0x9e, 0x6f,
- 0xfc, 0xac, 0xb8, 0x0a, 0x07, 0xac, 0x72, 0x9f, 0xb7, 0x0a, 0x64, 0x57,
- 0xf2, 0x53, 0x8a, 0xdf, 0x3a, 0x1e, 0x0f, 0x65, 0x2f, 0xa4, 0x92, 0x92,
- 0x30, 0x5c, 0x6c, 0x3e, 0x04, 0x49, 0x99, 0x58, 0xef, 0x02, 0x03, 0x01,
- 0x00, 0x01, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d,
- 0x01, 0x01, 0x05, 0x05, 0x00, 0x03, 0x81, 0x81, 0x00, 0x2e, 0x94, 0x77,
- 0xfb, 0x45, 0x59, 0x71, 0x75, 0x74, 0x88, 0x78, 0x05, 0x24, 0x6f, 0x18,
- 0xf9, 0x3f, 0x3d, 0xd8, 0x52, 0x2e, 0x01, 0xc4, 0x41, 0x95, 0xe3, 0x62,
- 0x7d, 0x6a, 0x1e, 0x73, 0x96, 0x79, 0xa9, 0x48, 0x1a, 0xfc, 0x98, 0xc9,
- 0x55, 0x11, 0x95, 0x4c, 0x91, 0x31, 0x98, 0xe6, 0x9f, 0x1b, 0xc6, 0x57,
- 0x82, 0xdd, 0x49, 0x69, 0x37, 0x31, 0xd8, 0x08, 0x05, 0x89, 0xd4, 0xc0,
- 0xbb, 0x95, 0xe9, 0xc6, 0x81, 0xca, 0x79, 0x6d, 0x14, 0x07, 0x69, 0x29,
- 0xf6, 0xb0, 0x96, 0x03, 0x81, 0xef, 0x0c, 0x3e, 0x3f, 0x05, 0x5b, 0xd3,
- 0xd1, 0xdf, 0x64, 0xbc, 0xf3, 0x47, 0xb9, 0xbb, 0xf5, 0x62, 0xa3, 0x2f,
- 0xf9, 0xa2, 0x54, 0xfb, 0xd3, 0x6b, 0xff, 0xbc, 0x65, 0xf7, 0xda, 0x46,
- 0xef, 0x3b, 0xdc, 0x17, 0xf2, 0xcf, 0x8a, 0x43, 0x3e, 0xb8, 0xb1, 0xe9,
- 0xb2, 0x4d, 0xe1, 0x17, 0x24
- };
- /* openssl rsa -in snakeoil.key -outform DER | xxd -i */
- static unsigned char key[] = {
- 0x30, 0x82, 0x02, 0x5c, 0x02, 0x01, 0x00, 0x02, 0x81, 0x81, 0x00, 0xd3,
- 0xb5, 0x48, 0x6c, 0x4b, 0x18, 0x80, 0xb0, 0x14, 0xbe, 0x9f, 0x1e, 0x99,
- 0x03, 0xff, 0x5b, 0x47, 0x1a, 0xde, 0x54, 0x2e, 0x5e, 0x86, 0xff, 0xaa,
- 0x7a, 0xb7, 0x04, 0x76, 0x77, 0xd2, 0x9c, 0xc8, 0xd8, 0x8c, 0xbe, 0x1a,
- 0x86, 0x3d, 0x7a, 0xb3, 0xbb, 0x89, 0x2b, 0x16, 0xb9, 0xac, 0xd8, 0xe4,
- 0x8d, 0x66, 0x82, 0xb3, 0xd0, 0x38, 0x3d, 0xd6, 0xce, 0xd2, 0x9d, 0x2a,
- 0x6c, 0x39, 0x95, 0x57, 0x9a, 0xde, 0x8b, 0x5a, 0xd9, 0x35, 0xa2, 0x2c,
- 0x60, 0x69, 0xe9, 0x73, 0xfe, 0x15, 0x76, 0x5a, 0xb6, 0x56, 0x38, 0x47,
- 0x1e, 0xf9, 0x51, 0xba, 0x2c, 0x1b, 0xe4, 0x63, 0x9e, 0x6f, 0xfc, 0xac,
- 0xb8, 0x0a, 0x07, 0xac, 0x72, 0x9f, 0xb7, 0x0a, 0x64, 0x57, 0xf2, 0x53,
- 0x8a, 0xdf, 0x3a, 0x1e, 0x0f, 0x65, 0x2f, 0xa4, 0x92, 0x92, 0x30, 0x5c,
- 0x6c, 0x3e, 0x04, 0x49, 0x99, 0x58, 0xef, 0x02, 0x03, 0x01, 0x00, 0x01,
- 0x02, 0x81, 0x80, 0x5a, 0x32, 0xb8, 0x62, 0x7b, 0x34, 0x3b, 0x4f, 0xc9,
- 0xe6, 0xd5, 0x40, 0x62, 0x0d, 0x13, 0xf4, 0xbd, 0xbc, 0xb2, 0xd0, 0xc6,
- 0xd8, 0xbb, 0x47, 0x9e, 0x48, 0x9e, 0x45, 0x26, 0x7c, 0x32, 0x9d, 0x5d,
- 0xec, 0xf5, 0x39, 0xe1, 0x6f, 0x24, 0x2e, 0x6c, 0xf9, 0x0f, 0x9d, 0xee,
- 0x16, 0xb9, 0x8f, 0xc7, 0x00, 0x7f, 0x96, 0x5c, 0x29, 0xf0, 0x6c, 0x58,
- 0x62, 0xd1, 0xd4, 0xe8, 0x48, 0x27, 0xd7, 0xb3, 0xf6, 0xb1, 0xfb, 0xcf,
- 0xf2, 0xe8, 0x34, 0xf3, 0x68, 0x62, 0x1e, 0x9a, 0xd6, 0x2a, 0x6c, 0x59,
- 0x63, 0x6b, 0x79, 0x84, 0xec, 0xbf, 0xdd, 0xb0, 0xb3, 0x6f, 0x60, 0x77,
- 0xbe, 0x02, 0x02, 0x4c, 0x3a, 0xba, 0x30, 0xc9, 0x37, 0xb4, 0x2d, 0x24,
- 0xbb, 0xeb, 0xa8, 0x95, 0xce, 0xd2, 0xc3, 0xb7, 0x60, 0xd6, 0x97, 0x6e,
- 0xbb, 0xdc, 0xdb, 0xf0, 0x72, 0x55, 0x88, 0x0c, 0xf1, 0x2b, 0x91, 0x02,
- 0x41, 0x00, 0xfb, 0xf6, 0x26, 0xeb, 0xf3, 0xcc, 0x7b, 0xdf, 0x95, 0x02,
- 0xe6, 0x3b, 0x28, 0x46, 0x52, 0xc4, 0x66, 0x79, 0x11, 0xa0, 0x2b, 0x72,
- 0x00, 0x2e, 0x34, 0xdf, 0x2a, 0xf9, 0x2b, 0x9d, 0x46, 0x51, 0xb8, 0x19,
- 0x50, 0x4f, 0xc4, 0x77, 0x45, 0xaa, 0x22, 0xa9, 0xf6, 0x93, 0x17, 0x8d,
- 0xf6, 0x5e, 0x54, 0x01, 0xb9, 0xf6, 0xdf, 0x63, 0x02, 0x8d, 0x73, 0x33,
- 0x23, 0x4d, 0x12, 0x94, 0x57, 0x63, 0x02, 0x41, 0x00, 0xd7, 0x19, 0xf6,
- 0x96, 0x29, 0x52, 0x4b, 0x43, 0x8e, 0xb7, 0x67, 0xda, 0xd8, 0x6d, 0x64,
- 0xad, 0x7b, 0x4a, 0xbc, 0xd1, 0xe6, 0xeb, 0x12, 0x9a, 0xc2, 0x7a, 0xe9,
- 0x25, 0x19, 0x07, 0x82, 0x73, 0xa6, 0x4b, 0x4e, 0xba, 0x46, 0xec, 0xdf,
- 0x0a, 0x17, 0x60, 0x28, 0xe3, 0xd9, 0xd6, 0x23, 0xef, 0x4c, 0x5e, 0x2f,
- 0x9c, 0x66, 0x76, 0xe0, 0x69, 0x69, 0xc7, 0xa2, 0xef, 0xab, 0x69, 0x0c,
- 0x05, 0x02, 0x40, 0x55, 0x51, 0x94, 0xfc, 0x71, 0x21, 0xdd, 0x10, 0x68,
- 0xb5, 0x02, 0xa1, 0x25, 0x92, 0x2a, 0x94, 0xb6, 0xde, 0x68, 0x49, 0x84,
- 0x6c, 0xa6, 0x02, 0xff, 0x84, 0x52, 0x58, 0xed, 0x9b, 0xe4, 0x23, 0xe7,
- 0xe3, 0x2a, 0x7e, 0xd8, 0x58, 0x4b, 0x0e, 0xc1, 0x8e, 0x2c, 0x20, 0xc2,
- 0xe9, 0x1f, 0x73, 0xf1, 0x9e, 0x64, 0x0a, 0x64, 0xba, 0x72, 0x32, 0xd3,
- 0xbf, 0x8d, 0x44, 0x9b, 0xf5, 0xff, 0x61, 0x02, 0x40, 0x11, 0x8a, 0x2c,
- 0x71, 0x52, 0x2d, 0x43, 0xb5, 0xde, 0x8d, 0x56, 0x0a, 0xa2, 0x5b, 0x49,
- 0x3a, 0x5c, 0x33, 0x5b, 0xf2, 0x41, 0xc2, 0x29, 0x62, 0x35, 0x39, 0x90,
- 0x89, 0x55, 0xe1, 0x26, 0xe2, 0x07, 0x4d, 0x5c, 0xbe, 0x13, 0xca, 0x7c,
- 0xe5, 0x75, 0xc2, 0x81, 0x93, 0x12, 0xd0, 0x43, 0x5d, 0xdf, 0xfc, 0x4e,
- 0x25, 0x92, 0xb5, 0x5e, 0xd7, 0x39, 0xa8, 0xed, 0xc0, 0x5d, 0x59, 0xd3,
- 0x81, 0x02, 0x41, 0x00, 0xd0, 0x16, 0xe4, 0xa0, 0xb0, 0x58, 0xaa, 0x5e,
- 0x28, 0xc2, 0x82, 0xc5, 0x43, 0x7c, 0xfd, 0x29, 0x22, 0x39, 0x3d, 0x73,
- 0xf3, 0xc0, 0x58, 0x1b, 0x03, 0x6c, 0xf3, 0x44, 0x66, 0x67, 0xe1, 0x72,
- 0xf8, 0x75, 0x9e, 0x1b, 0x77, 0xbe, 0xb3, 0xc0, 0x14, 0xfd, 0x44, 0xcc,
- 0xba, 0x97, 0xc2, 0x7a, 0xc2, 0xdb, 0x2d, 0x07, 0x25, 0x13, 0x12, 0xcb,
- 0x2c, 0xbf, 0x95, 0x0f, 0x1b, 0xfd, 0xe3, 0xe4
- };
- #endif
- #if !NO_DH
- /* openssl dhparam -C -noout 512 */
- DH *get_dh512() {
- static unsigned char dh512_p[] = {
- 0xFC, 0xFA, 0x8A, 0x3F, 0x8C, 0x50, 0xAA, 0x55, 0x01, 0xF2, 0x78,
- 0x27, 0x55, 0x5B, 0x5E, 0xD1, 0x9A, 0xF4, 0x56, 0x1E, 0x6F, 0x6B,
- 0xAC, 0x2B, 0x0B, 0x99, 0x1B, 0x89, 0x5B, 0x64, 0xCA, 0x11, 0xE8,
- 0x8F, 0x0B, 0x89, 0x67, 0x87, 0x5A, 0xF4, 0x16, 0xA8, 0x89, 0x2F,
- 0xAA, 0x4E, 0xE0, 0x03, 0x3C, 0x41, 0xE0, 0x48, 0xAE, 0x95, 0xD4,
- 0xFF, 0x07, 0xEF, 0x4B, 0xF0, 0xF4, 0x96, 0x02, 0x33
- };
- static unsigned char dh512_g[] = { 0x02, };
- DH *dh;
- if ( (dh = DH_new()) == NULL )
- return (NULL);
- dh->p = BN_bin2bn( dh512_p, sizeof(dh512_p), NULL );
- dh->g = BN_bin2bn( dh512_g, sizeof(dh512_g), NULL );
- if ( (dh->p == NULL) || (dh->g == NULL) ) {
- DH_free( dh );
- return (NULL);
- }
- return (dh);
- }
- /* openssl dhparam -C -noout -dsaparam 1024 */
- DH *get_dh1024() {
- static unsigned char dh1024_p[] = {
- 0xE8, 0xCD, 0xC3, 0xE8, 0x54, 0xA6, 0x14, 0x4C, 0x78, 0x58, 0x52,
- 0xC6, 0x6A, 0x2B, 0x3B, 0xC6, 0xC8, 0xAC, 0x16, 0x60, 0x76, 0x44,
- 0x62, 0x63, 0x3A, 0x3D, 0x32, 0xB4, 0x22, 0xBA, 0x1B, 0x34, 0x74,
- 0x23, 0x71, 0xE0, 0x1D, 0x7F, 0x51, 0x02, 0xEE, 0x9B, 0x2D, 0xD3,
- 0xA0, 0x66, 0x4B, 0x4F, 0x85, 0x59, 0xD4, 0x1A, 0x3A, 0xD4, 0x64,
- 0x28, 0x46, 0x55, 0xB4, 0xFD, 0x63, 0x32, 0x8E, 0x18, 0xCF, 0x65,
- 0x85, 0x21, 0xBF, 0xF9, 0xEE, 0x54, 0x48, 0x4C, 0x9C, 0x44, 0xAB,
- 0x26, 0xCA, 0x93, 0x85, 0x2A, 0xD1, 0x46, 0x6D, 0x3D, 0xED, 0xEE,
- 0x33, 0xF0, 0xFC, 0x3F, 0x98, 0x70, 0xA5, 0x19, 0x0B, 0x48, 0x6C,
- 0x0A, 0x7C, 0xCA, 0x53, 0xF4, 0x3B, 0xD5, 0x20, 0x3D, 0x58, 0xEA,
- 0x60, 0x5F, 0xFA, 0xA3, 0x05, 0xA1, 0x63, 0x20, 0xF6, 0x9A, 0xB7,
- 0xC1, 0x20, 0x77, 0x3A, 0xC9, 0x0E, 0x73
- };
- static unsigned char dh1024_g[] = {
- 0x95, 0xA5, 0x55, 0x32, 0x57, 0x13, 0xF7, 0xFA, 0x26, 0x13, 0x8E,
- 0x6C, 0xF9, 0x58, 0x7C, 0xA2, 0x59, 0xD2, 0x81, 0xD6, 0xC1, 0xC6,
- 0x33, 0xBE, 0x66, 0x14, 0xBC, 0x15, 0xE7, 0xFB, 0x2C, 0x35, 0xE1,
- 0x54, 0x11, 0x1C, 0xB2, 0x68, 0xFB, 0xF3, 0x7F, 0x62, 0x69, 0x42,
- 0x6D, 0xDE, 0x88, 0xD7, 0xAF, 0xE4, 0xAA, 0xED, 0xF4, 0x58, 0x44,
- 0x69, 0xBA, 0x51, 0x30, 0x6B, 0xF9, 0x48, 0x8D, 0x74, 0xDB, 0x64,
- 0xC3, 0x9A, 0xA2, 0x54, 0x86, 0xA2, 0xAA, 0x46, 0x0D, 0x5A, 0xE9,
- 0x15, 0x22, 0x36, 0xF5, 0x8B, 0xFF, 0xCD, 0xF9, 0xDA, 0x6C, 0x92,
- 0x5A, 0x1D, 0x5F, 0x2F, 0xA0, 0xED, 0x4A, 0x83, 0x2D, 0xAB, 0x07,
- 0x3B, 0x67, 0x8A, 0x3B, 0x35, 0xF1, 0xA6, 0xA3, 0x38, 0x16, 0x5A,
- 0x3D, 0xBB, 0x72, 0xBD, 0x1A, 0xFC, 0xA3, 0xB7, 0x04, 0x12, 0x8C,
- 0x40, 0x99, 0x08, 0x45, 0x68, 0x33, 0x7E
- };
- DH *dh;
- if ( (dh = DH_new()) == NULL )
- return (NULL);
- dh->p = BN_bin2bn( dh1024_p, sizeof(dh1024_p), NULL );
- dh->g = BN_bin2bn( dh1024_g, sizeof(dh1024_g), NULL );
- if ( (dh->p == NULL) || (dh->g == NULL) ) {
- DH_free( dh );
- return (NULL);
- }
- dh->length = 160;
- return (dh);
- }
- #endif
- struct {
- SSL_CTX *s_ctx;
- SSL *s_ssl;
- int s_ready;
- int s_failed;
- SSL_CTX *c_ctx;
- SSL *c_ssl;
- int c_ready;
- int c_failed;
- } app;
- static void s_ssl_info_callback(const SSL *ssl, int where, int ret) {
- if ( where & SSL_CB_ALERT ) {
- fprintf( stdout, "[S] SSL_CB_ALERT %s %s\n", SSL_alert_type_string( ret ), SSL_alert_desc_string_long( ret ) );
- app.s_failed = 1;
- }
- }
- static void c_ssl_info_callback(const SSL *ssl, int where, int ret) {
- if ( where & SSL_CB_ALERT ) {
- fprintf( stdout, "[C] SSL_CB_ALERT %s %s\n", SSL_alert_type_string( ret ), SSL_alert_desc_string_long( ret ) );
- app.c_failed = 1;
- }
- }
- void init_ssl() {
- SSL_library_init();
- #if 0
- SSL_load_error_strings();
- #endif
- }
- void end_ssl() {
- EVP_cleanup();
- }
- int start_ssl() {
- SSL_CTX *s_ctx = 0;
- SSL *s_ssl = 0;
- BIO *s_bior = 0, *s_biow = 0;
- SSL_CTX *c_ctx = 0;
- SSL *c_ssl = 0;
- BIO *c_bior = 0, *c_biow = 0;
- char *cipher = CIPHER;
- if ( !(s_ctx = SSL_CTX_new( SSLv3_method() )) )
- goto error;
- if ( !SSL_CTX_set_options( s_ctx, SSL_OP_NO_SSLv2 ) )
- goto error;
- if ( !SSL_CTX_set_options( s_ctx, SSL_OP_CIPHER_SERVER_PREFERENCE ) )
- goto error;
- if ( cipher ) {
- if ( !SSL_CTX_set_cipher_list( s_ctx, cipher ) )
- goto error;
- }
- #if !NO_DH
- #if 0
- DH *dh = get_dh512();
- #else
- DH *dh = get_dh1024();
- #endif
- SSL_CTX_set_tmp_dh(s_ctx,dh);
- DH_free( dh );
- if ( ! SSL_CTX_set_options(s_ctx, SSL_OP_SINGLE_DH_USE) )
- goto error;
- #endif
- #if NO_FILE
- if ( ! SSL_CTX_use_certificate_ASN1(s_ctx, sizeof (cert), cert) )
- goto error;
- #else
- if ( ! SSL_CTX_use_certificate_file(s_ctx, CERT_FILE, SSL_FILETYPE_PEM) )
- goto error;
- #endif
- #if NO_FILE
- if ( ! SSL_CTX_use_RSAPrivateKey_ASN1(s_ctx, key, sizeof (key) ) )
- goto error;
- #else
- if ( ! SSL_CTX_use_PrivateKey_file(s_ctx, KEY_FILE, SSL_FILETYPE_PEM) )
- goto error;
- #endif
- if ( ! SSL_CTX_check_private_key( s_ctx) )
- goto error;
- SSL_CTX_set_info_callback( s_ctx, s_ssl_info_callback );
- if ( !(s_ssl = SSL_new( s_ctx )) )
- goto error;
- s_bior = BIO_new( BIO_s_mem() );
- s_biow = BIO_new( BIO_s_mem() );
- SSL_set_bio( s_ssl, s_bior, s_biow );
- SSL_set_accept_state( s_ssl );
- if ( !(c_ctx = SSL_CTX_new( SSLv3_method() )) )
- goto error;
- if ( !SSL_CTX_set_options( c_ctx, SSL_OP_NO_SSLv2 ) )
- goto error;
- if ( cipher ) {
- if ( !SSL_CTX_set_cipher_list( c_ctx, cipher ) )
- goto error;
- }
- #if 0
- if ( ! SSL_CTX_load_verify_locations( c_ctx, CERT_FILE, 0) )
- goto error;
- #endif
- SSL_CTX_set_info_callback( c_ctx, c_ssl_info_callback );
- if ( !(c_ssl = SSL_new( c_ctx )) )
- goto error;
- c_bior = BIO_new( BIO_s_mem() );
- c_biow = BIO_new( BIO_s_mem() );
- SSL_set_bio( c_ssl, c_bior, c_biow );
- SSL_set_connect_state( c_ssl );
- app.c_ctx = c_ctx;
- app.c_ssl = c_ssl;
- app.s_ctx = s_ctx;
- app.s_ssl = s_ssl;
- return 1;
- error:
- ERR_print_errors_fp( stderr );
- if ( c_ctx )
- SSL_CTX_free( c_ctx );
- if ( c_ssl )
- SSL_free( c_ssl );
- if ( s_ctx )
- SSL_CTX_free( s_ctx );
- if ( s_ssl )
- SSL_free( s_ssl );
- return 0;
- }
- void stop_ssl() {
- if ( app.s_ctx != 0 ) {
- SSL_CTX_free( app.s_ctx );
- app.s_ctx = 0;
- }
- if ( app.s_ssl != 0 ) {
- SSL_free( app.s_ssl );
- app.s_ssl = 0;
- }
- if ( app.c_ctx != 0 ) {
- SSL_CTX_free( app.c_ctx );
- app.s_ctx = 0;
- }
- if ( app.c_ssl != 0 ) {
- SSL_free( app.c_ssl );
- app.c_ssl = 0;
- }
- }
- void quit(int ret) {
- stop_ssl();
- end_ssl();
- exit( ret );
- }
- int read_ssl(SSL* ssl, unsigned char *buffer, unsigned buffer_size) {
- fputs( "read_ssl\n", stdout );
- int r;
- r = SSL_read( ssl, buffer, buffer_size );
- if ( r < 0 ) {
- int err = SSL_get_error( ssl, r );
- if ( err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE )
- r = 0;
- }
- return r;
- }
- int write_ssl(SSL* ssl, const unsigned char *buffer, unsigned buffer_size) {
- fputs( "write_ssl\n", stdout );
- int r;
- r = SSL_write( ssl, buffer, buffer_size );
- if ( r < 0 ) {
- int err = SSL_get_error( ssl, r );
- if ( err == SSL_ERROR_WANT_READ || err == SSL_ERROR_WANT_WRITE )
- r = 0;
- }
- return r;
- }
- int inject_ssl(const SSL* ssl, const unsigned char *buffer, unsigned buffer_size) {
- fputs( "inject_ssl\n", stdout );
- BIO * bior = SSL_get_rbio( ssl );
- return BIO_write( bior, buffer, buffer_size );
- }
- int extract_ssl(const SSL* ssl, unsigned char *buffer, unsigned buffer_size) {
- fputs( "extract_ssl\n", stdout );
- BIO * biow = SSL_get_wbio( ssl );
- return BIO_read( biow, buffer, buffer_size );
- }
- void server_read() {
- fputs( "server read\n", stdout );
- unsigned char buffer[1024];
- int r = extract_ssl( app.s_ssl, buffer, sizeof(buffer) );
- fprintf( stderr, "r=%d\n", r );
- if ( r > 0 ) {
- DUMP( buffer, r, stdout );
- r = inject_ssl( app.c_ssl, buffer, r );
- fprintf( stderr, "r=%d\n", r );
- }
- }
- void client_read() {
- fputs( "client read\n", stdout );
- unsigned char buffer[1024];
- int r = extract_ssl( app.c_ssl, buffer, sizeof(buffer) );
- fprintf( stderr, "r=%d\n", r );
- if ( r > 0 ) {
- DUMP( buffer, r, stdout );
- r = inject_ssl( app.s_ssl, buffer, r );
- fprintf( stderr, "r=%d\n", r );
- }
- }
- void process_bio(SSL *s_ssl, SSL *c_ssl) {
- BIO * s_bior = SSL_get_rbio( s_ssl );
- BIO * s_biow = SSL_get_wbio( s_ssl );
- BIO * c_bior = SSL_get_rbio( c_ssl );
- BIO * c_biow = SSL_get_wbio( c_ssl );
- int s_bior_cnt, s_biow_cnt;
- int c_bior_cnt, c_biow_cnt;
- s_biow_cnt = BIO_pending(s_biow);
- s_bior_cnt = BIO_pending(s_bior);
- c_biow_cnt = BIO_pending(c_biow);
- c_bior_cnt = BIO_pending(c_bior);
- fprintf( stdout, "[S] biow=%d\n", s_biow_cnt );
- fprintf( stdout, "[S] bior=%d\n", s_bior_cnt );
- fprintf( stdout, "[C] biow=%d\n", c_biow_cnt );
- fprintf( stdout, "[C] bior=%d\n", c_bior_cnt );
- if ( s_biow_cnt ) {
- server_read();
- }
- if ( c_biow_cnt ) {
- client_read();
- }
- }
- void blahblah() {
- SSL *s_ssl = app.s_ssl;
- SSL *c_ssl = app.c_ssl;
- char *msg = "HELLO";
- unsigned msg_len = 5;
- char *reply = "BYE";
- unsigned reply_len = 3;
- unsigned char buffer[32];
- int r, w;
- fprintf( stderr, "msg=%s\n", msg );
- w = write_ssl( c_ssl, (const unsigned char *) msg, msg_len );
- if ( w < 0 ) {
- ERR_print_errors_fp( stderr );
- quit( 3 );
- }
- if ( w == 0 )
- return;
- process_bio( s_ssl, c_ssl );
- r = read_ssl( s_ssl, buffer, sizeof (buffer) - 1);
- fprintf( stderr, "r=%d\n", r );
- if ( r < 0 ) {
- ERR_print_errors_fp( stderr );
- quit( 3 );
- }
- if ( r == 0 )
- return;
- buffer[ r ] = '\0';
- fprintf( stderr, "[S] %s\n", buffer );
- fprintf( stderr, "reply=%s\n", reply );
- w = write_ssl( s_ssl, (const unsigned char *) reply, reply_len );
- if ( w < 0 ) {
- ERR_print_errors_fp( stderr );
- quit( 3 );
- }
- if ( w == 0 )
- return;
- process_bio( s_ssl, c_ssl );
- r = read_ssl( c_ssl, buffer, sizeof (buffer) - 1);
- fprintf( stderr, "r=%d\n", r );
- if ( r < 0 ) {
- ERR_print_errors_fp( stderr );
- quit( 3 );
- }
- if ( r == 0 )
- return;
- buffer[ r ] = '\0';
- fprintf( stderr, "[C] %s\n", buffer );
- }
- void doit() {
- SSL *s_ssl = app.s_ssl;
- SSL *c_ssl = app.c_ssl;
- while ( !(app.s_ready && app.c_ready) && !(app.s_failed && app.c_failed) ) {
- fprintf( stdout, "[S] %s\n", SSL_state_string( s_ssl ) );
- fprintf( stdout, "[C] %s\n", SSL_state_string( c_ssl ) );
- if ( SSL_want_nothing(s_ssl) )
- fputs( "[S] SSL_ERROR_WANT_NOTHING\n", stdout );
- if ( SSL_want_read(s_ssl) )
- fputs( "[S] SSL_ERROR_WANT_READ\n", stdout );
- if ( SSL_want_write(s_ssl) )
- fputs( "[S] SSL_ERROR_WANT_WRITE\n", stdout );
- if ( SSL_want_x509_lookup(s_ssl) )
- fputs( "[S] SSL_ERROR_WANT_X509_LOOKUP\n", stdout );
- if ( SSL_want_nothing(c_ssl) )
- fputs( "[C] SSL_ERROR_WANT_NOTHING\n", stdout );
- if ( SSL_want_read(c_ssl) )
- fputs( "[C] SSL_ERROR_WANT_READ\n", stdout );
- if ( SSL_want_write(c_ssl) )
- fputs( "[C] SSL_ERROR_WANT_WRITE\n", stdout );
- if ( SSL_want_x509_lookup(c_ssl) )
- fputs( "[C] SSL_ERROR_WANT_X509_LOOKUP\n", stdout );
- if ( !app.s_ready && !app.s_failed ) {
- if ( SSL_in_before(s_ssl) )
- fputs( "[S] SSL_ST_BEFORE\n", stdout );
- if ( SSL_in_init(s_ssl) )
- fputs( "[S] SSL_ST_INIT\n", stdout );
- if ( SSL_in_connect_init(s_ssl) )
- fputs( "[S] SSL_ST_CONNECT_INIT\n", stdout );
- if ( SSL_in_accept_init(s_ssl) )
- fputs( "[S] SSL_ST_ACCEPT_INIT\n", stdout );
- if ( SSL_in_init(s_ssl) ) {
- fputs( "[S] SSL_do_handshake\n", stdout );
- SSL_do_handshake( s_ssl );
- }
- if ( SSL_is_init_finished( s_ssl ) ) {
- app.s_ready = 1;
- fputs( "[S] *** ready ***\n", stdout );
- fprintf( stdout, "[S] %s\n", SSL_state_string( s_ssl ) );
- SSL_SESSION *sess = SSL_get_session( s_ssl );
- if ( sess ) {
- fprintf( stdout, "sess->cipher->name=%s\n", sess->cipher->name );
- }
- }
- }
- if ( !app.c_ready && !app.c_failed ) {
- if ( SSL_in_before(c_ssl) )
- fputs( "[C] SSL_ST_BEFORE\n", stdout );
- if ( SSL_in_init(c_ssl) )
- fputs( "[C] SSL_ST_INIT\n", stdout );
- if ( SSL_in_connect_init(c_ssl) )
- fputs( "[C] SSL_ST_CONNECT_INIT\n", stdout );
- if ( SSL_in_accept_init(c_ssl) )
- fputs( "[C] SSL_ST_ACCEPT_INIT\n", stdout );
- if ( SSL_in_init(c_ssl) ) {
- fputs( "[C] SSL_do_handshake\n", stdout );
- SSL_do_handshake( c_ssl );
- }
- if ( SSL_is_init_finished( c_ssl ) ) {
- app.c_ready = 1;
- fputs( "[C] *** ready ***\n", stdout );
- fprintf( stdout, "[C] %s\n", SSL_state_string( c_ssl ) );
- fprintf( stdout, "SSL_get_verify_result=%ld\n",
- SSL_get_verify_result( c_ssl ) );
- X509 *cert = SSL_get_peer_certificate( c_ssl );
- if ( cert ) {
- fprintf( stdout, "cert->valid=%d\n", cert->valid );
- fprintf( stdout, "cert->name=%s\n", cert->name );
- EVP_MD *digest;
- digest = (EVP_MD*) EVP_sha1();
- unsigned char data[EVP_MAX_MD_SIZE];
- unsigned int len;
- if ( X509_digest( cert, digest, data, &len ) > 0 ) {
- unsigned char *p;
- fputs( "cert->fingerprint=", stdout );
- for ( p = data; p < data + len; p++ )
- fprintf( stdout, p == data ? "%02x" : ":%02x", *p );
- fprintf( stdout, "\n" );
- }
- }
- SSL_SESSION *sess = SSL_get_session( c_ssl );
- if ( sess ) {
- fprintf( stdout, "sess->cipher->name=%s\n", sess->cipher->name );
- }
- }
- }
- process_bio( s_ssl, c_ssl );
- }
- if ( !(app.s_ready && app.c_ready) )
- return;
- blahblah();
- }
- void startup() {
- init_ssl();
- if ( !start_ssl() )
- exit( 1 );
- }
- void init() {
- app.s_failed = 0;
- app.s_ready = 0;
- app.c_failed = 0;
- app.c_ready = 0;
- }
- int main(int argc, char **argv) {
- init();
- startup();
- doit();
- exit( 0 );
- }
- #include <stdio.h>
- #include <ctype.h>
- #include <unistd.h>
- void dump( unsigned char *buf, int size, FILE *fout ) {
- register int n, i, col = 0;
- const int ncols = 16;
- unsigned char c[ 16 ];
- for( n = 0; n < size; n++ ) {
- fprintf( fout, "%02x ", buf[ n ] );
- c[ col ] = buf[ n ];
- col++;
- if( col == ncols / 2 )
- fprintf( fout, " " );
- else if( col == ncols ) {
- for( i = 0; i < col; i++ )
- fprintf( fout, "%c", isprint(c[ i ] ) ? c[ i ] : '.' );
- fprintf( fout, "\n" );
- col = 0;
- }
- }
- if( col != 0 ) {
- for( i = ncols - col; i > 0; i-- )
- fprintf( fout, " " );
- if( col < ncols / 2 )
- fprintf( fout, " " );
- for( i = 0; i < col; i++ )
- fprintf( fout, "%c", isprint( c[ i ] ) ? c[ i ] : '.' );
- fprintf( fout, "\n" );
- }
- }
- #if defined( STANDALONE )
- #if 0
- #include <io.h>
- #endif
- #include <fcntl.h>
- #include <errno.h>
- #include <string.h>
- #include <stdlib.h>
- int main( int argc, char *argv[] ) {
- unsigned char buf[ 4096 ];
- int n;
- int fd = 0; /* default to stdin */
- switch( argc ) {
- case 1:
- break;
- case 2:
- fd = open( argv[ 1 ], O_RDONLY );
- if ( fd == -1) {
- fprintf( stderr, "%s\n", strerror( errno ) );
- exit( 2 );
- }
- break;
- default:
- fprintf( stderr, "%s [file]\n", argv[0] );
- exit(1);
- }
- while ( (n = read( fd, buf, sizeof( buf ))) != 0 )
- dump( buf, n, stdout );
- exit( 0 );
- }
- #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
...
- #
- ALL = sslfingerprint sslsock sslmem
- CC = gcc
- CFLAGS = -Wall -g #-O
- #CFLAGS = -Wall -g -I../openssl/include
- #CFLAGS = -Wall -O -fstrength-reduce -finline-functions -fomit-frame-pointer
- SRCS = sslfingerprint.c sslsock.c sslmem.c dump.c
- OBJS = $(SRCS:.c=.o)
- LDFLAGS = -lssl -lcrypto
- #LDFLAGS = -L../openssl -lssl -lcrypto
- #LDFLAGS = -L/usr/local/ssl/lib -lssl -lcrypto
- #.SILENT:
- all: $(ALL)
- sslsock: sslsock.o dump.o
- $(CC) $^ -o $@ $(LDFLAGS)
- sslmem: sslmem.o dump.o
- $(CC) $^ -o $@ $(LDFLAGS)
- sslfingerprint: sslfingerprint.o
- $(CC) $^ -o $@ $(LDFLAGS)
- test: all
- ./sslmem && ./sslsock < req.txt
- clean:
- rm -f $(OBJS)
- wipe: clean
- rm -f $(ALL)
Comments