diff --git a/ChangeLog b/ChangeLog index a306201eea..06987cc783 100644 --- a/ChangeLog +++ b/ChangeLog @@ -5,6 +5,9 @@ Features * Added option parsing for host and port selection to ssl_client2 * Added support for GeneralizedTime in X509 parsing + * Added cert_app program to allow easy reading and + printing of X509 certificates from file or SSL + connection. Changes * Added const correctness for main code base diff --git a/programs/CMakeLists.txt b/programs/CMakeLists.txt index a11929a2a3..f73b645b3d 100644 --- a/programs/CMakeLists.txt +++ b/programs/CMakeLists.txt @@ -3,3 +3,4 @@ add_subdirectory(hash) add_subdirectory(pkey) add_subdirectory(ssl) add_subdirectory(test) +add_subdirectory(x509) diff --git a/programs/Makefile b/programs/Makefile index 8f3894ef1a..0e467e6982 100644 --- a/programs/Makefile +++ b/programs/Makefile @@ -7,15 +7,15 @@ OFLAGS = -O LDFLAGS = -L../library -lpolarssl APPS = aes/aescrypt2 hash/hello \ - hash/md5sum hash/sha1sum \ + hash/md5sum hash/sha1sum \ hash/sha2sum pkey/dh_client \ pkey/dh_genprime pkey/dh_server \ pkey/mpi_demo pkey/rsa_genkey \ pkey/rsa_sign pkey/rsa_verify \ ssl/ssl_client1 ssl/ssl_client2 \ ssl/ssl_server test/ssl_cert_test \ - test/benchmark \ - test/selftest test/ssl_test + test/benchmark test/selftest \ + test/ssl_test x509/cert_app .SILENT: @@ -97,6 +97,10 @@ test/ssl_test: test/ssl_test.c ../library/libpolarssl.a echo " CC test/ssl_test.c" $(CC) $(CFLAGS) $(OFLAGS) test/ssl_test.c $(LDFLAGS) -o $@ +x509/cert_app: x509/cert_app.c ../library/libpolarssl.a + echo " CC x509/cert_app.c" + $(CC) $(CFLAGS) $(OFLAGS) x509/cert_app.c $(LDFLAGS) -o $@ + clean: rm -f $(APPS) diff --git a/programs/x509/CMakeLists.txt b/programs/x509/CMakeLists.txt new file mode 100644 index 0000000000..3078fd5997 --- /dev/null +++ b/programs/x509/CMakeLists.txt @@ -0,0 +1,2 @@ +add_executable(cert_app cert_app.c) +target_link_libraries(cert_app polarssl) diff --git a/programs/x509/cert_app.c b/programs/x509/cert_app.c new file mode 100644 index 0000000000..1df51988ab --- /dev/null +++ b/programs/x509/cert_app.c @@ -0,0 +1,279 @@ +/* + * Certificate reading application + * + * Copyright (C) 2006-2009, Paul Bakker + * All rights reserved. + * + * Joined copyright on original XySSL code with: Christophe Devine + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + */ + +#ifndef _CRT_SECURE_NO_DEPRECATE +#define _CRT_SECURE_NO_DEPRECATE 1 +#endif + +#include +#include +#include + +#include "polarssl/havege.h" +#include "polarssl/net.h" +#include "polarssl/ssl.h" +#include "polarssl/x509.h" + +#define MODE_NONE 0 +#define MODE_FILE 1 +#define MODE_SSL 2 + +#define DFL_MODE MODE_NONE +#define DFL_FILENAME "cert.crt" +#define DFL_SERVER_NAME "localhost" +#define DFL_SERVER_PORT 4433 +#define DFL_DEBUG_LEVEL 0 + +/* + * global options + */ +struct options +{ + int mode; /* the mode to run the application in */ + char *filename; /* filename of the certificate file */ + char *server_name; /* hostname of the server (client only) */ + int server_port; /* port on which the ssl service runs */ + int debug_level; /* level of debugging */ +} opt; + +void my_debug( void *ctx, int level, const char *str ) +{ + if( level < opt.debug_level ) + { + fprintf( (FILE *) ctx, "%s", str ); + fflush( (FILE *) ctx ); + } +} + +#define USAGE \ + "\n usage: cert_app param=<>...\n" \ + "\n acceptable parameters:\n" \ + " mode=file|ssl default: none\n" \ + " filename=%%s default: cert.crt\n" \ + " server_name=%%s default: localhost\n" \ + " server_port=%%d default: 4433\n" \ + " debug_level=%%d default: 0 (disabled)\n" \ + "\n" + +int main( int argc, char *argv[] ) +{ + int ret = 0, server_fd; + unsigned char buf[1024]; + havege_state hs; + ssl_context ssl; + ssl_session ssn; + x509_cert clicert; + rsa_context rsa; + int i, j, n; + char *p, *q; + + if( argc == 0 ) + { + usage: + printf( USAGE ); + goto exit; + } + + opt.mode = DFL_MODE; + opt.filename = DFL_FILENAME; + opt.server_name = DFL_SERVER_NAME; + opt.server_port = DFL_SERVER_PORT; + opt.debug_level = DFL_DEBUG_LEVEL; + + for( i = 1; i < argc; i++ ) + { + n = strlen( argv[i] ); + + for( j = 0; j < n; j++ ) + { + if( argv[i][j] >= 'A' && argv[i][j] <= 'Z' ) + argv[i][j] |= 0x20; + } + + p = argv[i]; + if( ( q = strchr( p, '=' ) ) == NULL ) + goto usage; + *q++ = '\0'; + + if( strcmp( p, "mode" ) == 0 ) + { + if( strcmp( q, "file" ) == 0 ) + opt.mode = MODE_FILE; + else if( strcmp( q, "ssl" ) == 0 ) + opt.mode = MODE_SSL; + else + goto usage; + } + else if( strcmp( p, "filename" ) == 0 ) + opt.filename = q; + else if( strcmp( p, "server_name" ) == 0 ) + opt.server_name = q; + else if( strcmp( p, "server_port" ) == 0 ) + { + opt.server_port = atoi( q ); + if( opt.server_port < 1 || opt.server_port > 65535 ) + goto usage; + } + else if( strcmp( p, "debug_level" ) == 0 ) + { + opt.debug_level = atoi( q ); + if( opt.debug_level < 0 || opt.debug_level > 65535 ) + goto usage; + } + else + goto usage; + } + + if( opt.mode == MODE_FILE ) + { + x509_cert crt; + + memset( &crt, 0, sizeof( x509_cert ) ); + + /* + * 1.1. Load the certificate + */ + printf( "\n . Loading the certificate ..." ); + fflush( stdout ); + + ret = x509parse_crtfile( &crt, opt.filename ); + + if( ret != 0 ) + { + printf( " failed\n ! x509parse_crt returned %d\n\n", ret ); + x509_free( &crt ); + goto exit; + } + + printf( " ok\n" ); + + /* + * 1.2 Print the certificate + */ + printf( " . Peer certificate information ...\n" ); + ret = x509parse_cert_info( (char *) buf, sizeof( buf ) - 1, " ", &crt ); + if( ret == -1 ) + { + printf( " failed\n ! x509parse_cert_info returned %d\n\n", ret ); + x509_free( &crt ); + goto exit; + } + + printf( "%s\n", buf ); + + x509_free( &crt ); + } + else if( opt.mode == MODE_SSL ) + { + /* + * 1. Initialize the RNG and the session data + */ + havege_init( &hs ); + memset( &ssn, 0, sizeof( ssl_session ) ); + + /* + * 2. Start the connection + */ + printf( " . SSL connection to tcp/%s/%-4d...", opt.server_name, + opt.server_port ); + fflush( stdout ); + + if( ( ret = net_connect( &server_fd, opt.server_name, + opt.server_port ) ) != 0 ) + { + printf( " failed\n ! net_connect returned %d\n\n", ret ); + goto exit; + } + + /* + * 3. Setup stuff + */ + if( ( ret = ssl_init( &ssl ) ) != 0 ) + { + printf( " failed\n ! ssl_init returned %d\n\n", ret ); + goto exit; + } + + ssl_set_endpoint( &ssl, SSL_IS_CLIENT ); + ssl_set_authmode( &ssl, SSL_VERIFY_NONE ); + + ssl_set_rng( &ssl, havege_rand, &hs ); + ssl_set_dbg( &ssl, my_debug, stdout ); + ssl_set_bio( &ssl, net_recv, &server_fd, + net_send, &server_fd ); + + ssl_set_ciphers( &ssl, ssl_default_ciphers ); + ssl_set_session( &ssl, 1, 600, &ssn ); + + ssl_set_own_cert( &ssl, &clicert, &rsa ); + + ssl_set_hostname( &ssl, opt.server_name ); + + /* + * 4. Handshake + */ + while( ( ret = ssl_handshake( &ssl ) ) != 0 ) + { + if( ret != POLARSSL_ERR_NET_TRY_AGAIN ) + { + printf( " failed\n ! ssl_handshake returned %d\n\n", ret ); + goto exit; + } + } + + printf( " ok\n" ); + + /* + * 5. Print the certificate + */ + printf( " . Peer certificate information ...\n" ); + ret = x509parse_cert_info( (char *) buf, sizeof( buf ) - 1, " ", ssl.peer_cert ); + if( ret == -1 ) + { + printf( " failed\n ! x509parse_cert_info returned %d\n\n", ret ); + goto exit; + } + + printf( "%s\n", buf ); + + ssl_close_notify( &ssl ); + } + else + goto usage; + +exit: + + net_close( server_fd ); + x509_free( &clicert ); + rsa_free( &rsa ); + ssl_free( &ssl ); + + memset( &ssl, 0, sizeof( ssl ) ); + +#ifdef WIN32 + printf( " + Press Enter to exit this program.\n" ); + fflush( stdout ); getchar(); +#endif + + return( ret ); +}