From 3ebb2cdb523e6d8708f8ca74d3cdac15e74ae185 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 23 Sep 2013 17:00:18 +0200 Subject: [PATCH] Add support for multiple server certificates --- include/polarssl/ssl.h | 9 ++- library/ssl_srv.c | 35 ++++++++--- library/ssl_tls.c | 4 ++ programs/ssl/ssl_server2.c | 116 ++++++++++++++++++++++++------------- 4 files changed, 114 insertions(+), 50 deletions(-) diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h index c764961d0..f357b4624 100644 --- a/include/polarssl/ssl.h +++ b/include/polarssl/ssl.h @@ -492,6 +492,9 @@ struct _ssl_handshake_params #if defined(POLARSSL_ECDH_C) || defined(POLARSSL_ECDSA_C) int ec_curve; /*!< Selected elliptic curve */ #endif +#if defined(POLARSSL_X509_CRT_PARSE_C) + ssl_key_cert *key_cert; /*!< Own key/cert in use */ +#endif /* * Checksum contexts @@ -1517,12 +1520,14 @@ md_type_t ssl_md_alg_from_hash( unsigned char hash ); #if defined(POLARSSL_X509_CRT_PARSE_C) static inline pk_context *ssl_own_key( ssl_context *ssl ) { - return( ssl->key_cert == NULL ? NULL : ssl->key_cert->key ); + return( ssl->handshake->key_cert == NULL ? NULL + : ssl->handshake->key_cert->key ); } static inline x509_crt *ssl_own_cert( ssl_context *ssl ) { - return( ssl->key_cert == NULL ? NULL : ssl->key_cert->cert ); + return( ssl->handshake->key_cert == NULL ? NULL + : ssl->handshake->key_cert->cert ); } #endif /* POLARSSL_X509_CRT_PARSE_C */ diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 47e3e272c..d1d5ec7fc 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -1271,7 +1271,8 @@ static int ssl_parse_client_hello( ssl_context *ssl ) /* * Search for a matching ciphersuite - * (At the end because we need information from the EC-based extensions) + * (At the end because we need information from the EC-based extensions + * and certificate from the SNI callback triggered by the SNI extension.) */ ciphersuites = ssl->ciphersuite_list[ssl->minor_ver]; for( i = 0; ciphersuites[i] != 0; i++ ) @@ -1301,14 +1302,32 @@ static int ssl_parse_client_hello( ssl_context *ssl ) continue; #endif - /* If ciphersuite requires us to have a private key of a - * certain type, make sure we do */ -#if defined(POLARSSL_PK_C) +#if defined(POLARSSL_X509_CRT_PARSE_C) + /* + * Final check: if ciphersuite requires us to have a + * certificate/key of a particular type: + * - select the appropriate certificate if we have one, or + * - try the next ciphersuite if we don't + * This must be done last since we modify the key_cert list. + */ pk_alg = ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info ); - if( pk_alg != POLARSSL_PK_NONE && - ( ssl_own_key( ssl ) == NULL || - ! pk_can_do( ssl_own_key( ssl ), pk_alg ) ) ) - continue; + if( pk_alg != POLARSSL_PK_NONE ) + { + ssl_key_cert *good = NULL; + ssl_key_cert *cur = ssl->key_cert; + + while( cur != NULL && good == NULL ) + { + if( pk_can_do( cur->key, pk_alg ) ) + good = cur; + cur = cur->next; + } + + if( good == NULL ) + continue; + else + ssl->handshake->key_cert = good; + } #endif goto have_ciphersuite; diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 7f5ea76bd..86c2953d4 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -3849,6 +3849,10 @@ int ssl_handshake( ssl_context *ssl ) SSL_DEBUG_MSG( 2, ( "=> handshake" ) ); +#if defined(POLARSSL_X509_CRT_PARSE_C) + ssl->handshake->key_cert = ssl->key_cert; +#endif + while( ssl->state != SSL_HANDSHAKE_OVER ) { ret = ssl_handshake_step( ssl ); diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 69b005a52..e73a0b598 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -56,6 +56,8 @@ #define DFL_CA_PATH "" #define DFL_CRT_FILE "" #define DFL_KEY_FILE "" +#define DFL_CRT_FILE2 "" +#define DFL_KEY_FILE2 "" #define DFL_PSK "" #define DFL_PSK_IDENTITY "Client_identity" #define DFL_FORCE_CIPHER 0 @@ -91,8 +93,10 @@ struct options int debug_level; /* level of debugging */ const char *ca_file; /* the file with the CA certificate(s) */ const char *ca_path; /* the path with the CA certificate(s) reside */ - const char *crt_file; /* the file with the client certificate */ - const char *key_file; /* the file with the client key */ + const char *crt_file; /* the file with the server certificate */ + const char *key_file; /* the file with the server key */ + const char *crt_file2; /* the file with the 2nd server certificate */ + const char *key_file2; /* the file with the 2nd server key */ const char *psk; /* the pre-shared key */ const char *psk_identity; /* the pre-shared key identity */ int force_ciphersuite[2]; /* protocol/ciphersuite to use, or all */ @@ -114,6 +118,56 @@ static void my_debug( void *ctx, int level, const char *str ) } } +#if defined(POLARSSL_X509_CRT_PARSE_C) +static int parse_cert_key( x509_crt *crt, const char *crt_file, + pk_context *key, const char *key_file ) +{ + int ret; + +#if defined(POLARSSL_FS_IO) + if( strlen( crt_file ) ) + ret = x509_crt_parse_file( crt, crt_file ); + else +#endif +#if defined(POLARSSL_CERTS_C) + ret = x509_crt_parse( crt, (const unsigned char *) test_srv_crt, + strlen( test_srv_crt ) ); +#else + { + ret = 1; + printf("POLARSSL_CERTS_C not defined."); + } +#endif + if( ret != 0 ) + { + printf( " failed\n ! x509_crt_parse returned -0x%x\n\n", -ret ); + return( ret ); + } + +#if defined(POLARSSL_FS_IO) + if( strlen( key_file ) ) + ret = pk_parse_keyfile( key, key_file, "" ); + else +#endif +#if defined(POLARSSL_CERTS_C) + ret = pk_parse_key( key, (const unsigned char *) test_srv_key, + strlen( test_srv_key ), NULL, 0 ); +#else + { + ret = 1; + printf("POLARSSL_CERTS_C not defined."); + } +#endif + if( ret != 0 ) + { + printf( " failed\n ! pk_parse_key returned -0x%x\n\n", -ret ); + return( ret ); + } + + return( 0 ); +} +#endif /* POLARSSL_X509_CRT_PARSE_C */ + #if defined(POLARSSL_X509_CRT_PARSE_C) #if defined(POLARSSL_FS_IO) #define USAGE_IO \ @@ -123,7 +177,10 @@ static void my_debug( void *ctx, int level, const char *str ) " default: \"\" (pre-loaded) (overrides ca_file)\n" \ " crt_file=%%s Your own cert and chain (in bottom to top order, top may be omitted)\n" \ " default: \"\" (pre-loaded)\n" \ - " key_file=%%s default: \"\" (pre-loaded)\n" + " key_file=%%s default: \"\" (pre-loaded)\n" \ + " crt_file2=%%s Your second cert and chain (in bottom to top order, top may be omitted)\n" \ + " default: \"\" (pre-loaded)\n" \ + " key_file2=%%s default: \"\" (pre-loaded)\n" #else #define USAGE_IO \ "\n" \ @@ -212,6 +269,8 @@ int main( int argc, char *argv[] ) x509_crt cacert; x509_crt srvcert; pk_context pkey; + x509_crt srvcert2; + pk_context pkey2; #endif #if defined(POLARSSL_SSL_CACHE_C) ssl_cache_context cache; @@ -237,6 +296,8 @@ int main( int argc, char *argv[] ) x509_crt_init( &cacert ); x509_crt_init( &srvcert ); pk_init( &pkey ); + x509_crt_init( &srvcert2 ); + pk_init( &pkey2 ); #endif #if defined(POLARSSL_SSL_CACHE_C) ssl_cache_init( &cache ); @@ -270,6 +331,8 @@ int main( int argc, char *argv[] ) opt.ca_path = DFL_CA_PATH; opt.crt_file = DFL_CRT_FILE; opt.key_file = DFL_KEY_FILE; + opt.crt_file2 = DFL_CRT_FILE2; + opt.key_file2 = DFL_KEY_FILE2; opt.psk = DFL_PSK; opt.psk_identity = DFL_PSK_IDENTITY; opt.force_ciphersuite[0]= DFL_FORCE_CIPHER; @@ -308,6 +371,10 @@ int main( int argc, char *argv[] ) opt.crt_file = q; else if( strcmp( p, "key_file" ) == 0 ) opt.key_file = q; + else if( strcmp( p, "crt_file2" ) == 0 ) + opt.crt_file2 = q; + else if( strcmp( p, "key_file2" ) == 0 ) + opt.key_file2 = q; else if( strcmp( p, "psk" ) == 0 ) opt.psk = q; else if( strcmp( p, "psk_identity" ) == 0 ) @@ -550,45 +617,11 @@ int main( int argc, char *argv[] ) printf( " . Loading the server cert. and key..." ); fflush( stdout ); -#if defined(POLARSSL_FS_IO) - if( strlen( opt.crt_file ) ) - ret = x509_crt_parse_file( &srvcert, opt.crt_file ); - else -#endif -#if defined(POLARSSL_CERTS_C) - ret = x509_crt_parse( &srvcert, (const unsigned char *) test_srv_crt, - strlen( test_srv_crt ) ); -#else - { - ret = 1; - printf("POLARSSL_CERTS_C not defined."); - } -#endif - if( ret != 0 ) - { - printf( " failed\n ! x509_crt_parse returned -0x%x\n\n", -ret ); + if( parse_cert_key( &srvcert, opt.crt_file, &pkey, opt.key_file ) != 0 ) goto exit; - } -#if defined(POLARSSL_FS_IO) - if( strlen( opt.key_file ) ) - ret = pk_parse_keyfile( &pkey, opt.key_file, "" ); - else -#endif -#if defined(POLARSSL_CERTS_C) - ret = pk_parse_key( &pkey, (const unsigned char *) test_srv_key, - strlen( test_srv_key ), NULL, 0 ); -#else - { - ret = 1; - printf("POLARSSL_CERTS_C not defined."); - } -#endif - if( ret != 0 ) - { - printf( " failed\n ! pk_parse_key returned -0x%x\n\n", -ret ); + if( parse_cert_key( &srvcert2, opt.crt_file2, &pkey2, opt.key_file2 ) != 0 ) goto exit; - } printf( " ok\n" ); #endif /* POLARSSL_X509_CRT_PARSE_C */ @@ -647,6 +680,7 @@ int main( int argc, char *argv[] ) #if defined(POLARSSL_X509_CRT_PARSE_C) ssl_set_ca_chain( &ssl, &cacert, NULL, NULL ); ssl_set_own_cert( &ssl, &srvcert, &pkey ); + ssl_set_own_cert( &ssl, &srvcert2, &pkey2 ); #endif #if defined(POLARSSL_KEY_EXCHANGE_PSK_ENABLED) @@ -875,9 +909,11 @@ exit: net_close( client_fd ); #if defined(POLARSSL_X509_CRT_PARSE_C) - x509_crt_free( &srvcert ); x509_crt_free( &cacert ); + x509_crt_free( &srvcert ); pk_free( &pkey ); + x509_crt_free( &srvcert2 ); + pk_free( &pkey2 ); #endif ssl_free( &ssl );