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
- #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;
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.
- 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
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
.
- void close_conn() {
- if ( app.socket != -1 ) {
- close( app.socket );
- app.socket = -1;
- }
- }
close_conn
ferme la connexion dont le socket est mémorisé dans app
.
- void init_ssl() {
- SSL_library_init();
- #if 1
- SSL_load_error_strings();
- #endif
- }
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
- void end_ssl() {
- EVP_cleanup();
- }
end_ssl
termine l'utilisation de la librairie SSL.
- 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
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
- 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
libère le contexte SSL et l'objet SSL mémorisés dans app
.
- void quit( int ret ) {
- close_conn();
- stop_ssl();
- end_ssl();
- exit( ret );
- }
quit
ferme la connexion avec le serveur, libère les ressources SSL puis termine le programme avec le code de retour 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
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.
- 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
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.
- 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
injecte les octets lus à partir du socket de l'application dans le moteur SSL.
- 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
écrit les octets extraits du moteur SSL dans le socket de l'application.
- void startup() {
- init_ssl();
- if ( !start_ssl() )
- exit( 1 );
- if ( !open_conn() )
- exit( 1 );
- }
startup
initialise l'utilisation de la librairie SSL, crée et configure l'objet SSL du programme et ouvre la connexion avec le serveur.
- void init() {
- app.host_ip = htonl( HOSTADDR );
- app.port_num = htons( PORTNUM );
- app.socket = -1;
- }
init
initialise 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
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.
- 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
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
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: /
- #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);
- }
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]
.
- #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)
Commentaires