2
210

Programmation de la librairie SSL

Apprenez à programmer en C le dialogue en SSL entre un client et un serveur. Écrivez un premier programme qui affiche l'empreinte numérique du certificat d'un serveur puis un second programme qui envoie une requête GET à un serveur en HTTPS et affiche la réponse. Terminez par un programme qui montre comment organiser des échanges en SSL entre un client et un serveur en mémoire.

Diagramme

Installez l'environnement de développement :

$ sudo apt-get install libssl-dev

Téléchargez sslfingerprint.c :

Compilez sslfingerprint.c :

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

Affichez l'empreinte du certificat du serveur de 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

Essayez avec le serveur de 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;

Inclut les définitions et les déclarations utilisées par le programme. La variable globale app contient l'objet de l'application. Cette structure mémorise l'adresse IP du serveur et le numéro de port du programme distant, le socket de la connexion avec le serveur, le contexte SSL et l'objet SSL. HOSTADDR est défini à l'adresse par défaut du serveur, i.e. 127.0.0.1, PORTNUM à 443, le numéro de port par défaut d'un serveur HTTPS.

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

open_conn ouvre une connexion avec un programme distant à l'adresse IP et au numéro de port indiqués dans app. Le numéro du descripteur du socket est mémorisé dans app.

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

close_conn ferme la connexion dont le socket est mémorisé dans app.

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

init_ssl initialise l'utilisation de la librairie SSL. SSL_load_error_strings charge les messages d'erreur.

NOTE : SSL_load_error_strings n'est nécessaire que si le programme appelle la fonction ERR_print_errors ou une de ses variantes.

SSL_library_init SSL_load_error_strings ERR_print_errors

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

end_ssl termine l'utilisation de la librairie SSL.

EVP_cleanup

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

start_ssl initialise le contexte SSL et l'objet SSL, crée les tampons de lecture et d'écriture associés à l'objet SSL puis place l'objet SSL en mode client avec SSL_set_connect_state. Les adresses du contexte SSL et de l'objet SSL sont mémorisés dans app.

En cas d'erreur, le code affiche la pile des erreurs SSL puis libère si nécessaire le contexte SSL et l'objet SSL.

SSL_CTX_new SSL_new BIO_s_mem BIO_new SSL_set_bio SSL_set_connect_state ERR_print_errors

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

stop_ssl libère le contexte SSL et l'objet SSL mémorisés dans app.

SSL_CTX_free SSL_free

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

quit ferme la connexion avec le serveur, libère les ressources SSL puis termine le programme avec le code de retour ret.

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

inject_ssl copie au plus buffer_size octets à l'adresse buffer dans le tampon d'entrée du moteur SSL ssl et retourne le nombre d'octets effectivement copiés ou 0 ou -1 en cas d'erreur.

SSL_get_rbio BIO_write

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

extract_ssl copie au plus buffer_size octets à partir du tampon de sortie du moteur SSL ssl à l'adresse buffer et retourne le nombre d'octets effectivement copiés ou 0 ou -1 en cas d'erreur.

SSL_get_wbio BIO_read

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

read_socket injecte les octets lus à partir du socket de l'application dans le moteur SSL.

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

write_socket écrit les octets extraits du moteur SSL dans le socket de l'application.

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

startup initialise l'utilisation de la librairie SSL, crée et configure l'objet SSL du programme et ouvre la connexion avec le serveur.

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

init initialise app.

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

doit boucle tant que la négociation avec le serveur en SSL n'est pas terminée, i.e. tant que la fonction SSL_is_init_finished retourne 0. La négociation est initialisée avec SSL_do_handshake si SSL_in_init retourne 1. Une fois la négociation initialisée, le code se contente d'assurer les échanges de données entre le moteur SSL et le serveur. Tout contenu préparé par le moteur SSL est envoyé au serveur. Réciproquement, tout contenu retourné par le serveur est transmis au moteur SSL. Une fois la connexion SSL établie, doit récupère le certificat du serveur et l'affiche en hexadécimal.

SSL_do_handshake

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

main initialise app avec init puis recherche des arguments sur la ligne de commande. L'option -h permet de spécifier un nom d'hôte, l'option -p un numéro de port. En cas d'erreur sur la ligne de commande, le bon usage du programme est affiché et le programme se termine avec le code de retour 1. Si tout est en ordre, le programme appelle startup puis doit et se termine avec le code de retour 0.

Compilez sslsock.c :

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

Exécutez le programme en spécifiant frasq.org comme hôte et avec req.txt comme flot d'entrée :

$ ./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

Le programme affiche le contenu du fichier 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. }

Compilez sslmem.c puis exécutez le programme :

$ 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

Les messages du serveur sont précédés par [S], ceux du client par [C].

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

Commentaires

Votre commentaire :
[p] [b] [i] [u] [s] [quote] [pre] [br] [code] [url] [email] strip aide 2000

Entrez un maximum de 2000 caractères.
Améliorez la présentation de votre texte avec les balises de formatage suivantes :
[p]paragraphe[/p], [b]gras[/b], [i]italique[/i], [u]souligné[/u], [s]barré[/s], [quote]citation[/quote], [pre]tel quel[/pre], [br]à la ligne,
[url]http://www.izend.org[/url], [url=http://www.izend.org]site[/url], [email]izend@izend.org[/email], [email=izend@izend.org]izend[/email],
[code]commande[/code], [code=langage]code source en c, java, php, html, javascript, xml, css, sql, bash, dos, make, etc.[/code].