Add support for multiple server certificates

This commit is contained in:
Manuel Pégourié-Gonnard 2013-09-23 17:00:18 +02:00
parent 834ea8587f
commit 3ebb2cdb52
4 changed files with 114 additions and 50 deletions

View File

@ -492,6 +492,9 @@ struct _ssl_handshake_params
#if defined(POLARSSL_ECDH_C) || defined(POLARSSL_ECDSA_C) #if defined(POLARSSL_ECDH_C) || defined(POLARSSL_ECDSA_C)
int ec_curve; /*!< Selected elliptic curve */ int ec_curve; /*!< Selected elliptic curve */
#endif #endif
#if defined(POLARSSL_X509_CRT_PARSE_C)
ssl_key_cert *key_cert; /*!< Own key/cert in use */
#endif
/* /*
* Checksum contexts * Checksum contexts
@ -1517,12 +1520,14 @@ md_type_t ssl_md_alg_from_hash( unsigned char hash );
#if defined(POLARSSL_X509_CRT_PARSE_C) #if defined(POLARSSL_X509_CRT_PARSE_C)
static inline pk_context *ssl_own_key( ssl_context *ssl ) 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 ) 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 */ #endif /* POLARSSL_X509_CRT_PARSE_C */

View File

@ -1271,7 +1271,8 @@ static int ssl_parse_client_hello( ssl_context *ssl )
/* /*
* Search for a matching ciphersuite * 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]; ciphersuites = ssl->ciphersuite_list[ssl->minor_ver];
for( i = 0; ciphersuites[i] != 0; i++ ) for( i = 0; ciphersuites[i] != 0; i++ )
@ -1301,14 +1302,32 @@ static int ssl_parse_client_hello( ssl_context *ssl )
continue; continue;
#endif #endif
/* If ciphersuite requires us to have a private key of a #if defined(POLARSSL_X509_CRT_PARSE_C)
* certain type, make sure we do */ /*
#if defined(POLARSSL_PK_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 ); pk_alg = ssl_get_ciphersuite_sig_pk_alg( ciphersuite_info );
if( pk_alg != POLARSSL_PK_NONE && if( pk_alg != POLARSSL_PK_NONE )
( ssl_own_key( ssl ) == NULL || {
! pk_can_do( ssl_own_key( ssl ), pk_alg ) ) ) ssl_key_cert *good = NULL;
continue; 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 #endif
goto have_ciphersuite; goto have_ciphersuite;

View File

@ -3849,6 +3849,10 @@ int ssl_handshake( ssl_context *ssl )
SSL_DEBUG_MSG( 2, ( "=> handshake" ) ); 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 ) while( ssl->state != SSL_HANDSHAKE_OVER )
{ {
ret = ssl_handshake_step( ssl ); ret = ssl_handshake_step( ssl );

View File

@ -56,6 +56,8 @@
#define DFL_CA_PATH "" #define DFL_CA_PATH ""
#define DFL_CRT_FILE "" #define DFL_CRT_FILE ""
#define DFL_KEY_FILE "" #define DFL_KEY_FILE ""
#define DFL_CRT_FILE2 ""
#define DFL_KEY_FILE2 ""
#define DFL_PSK "" #define DFL_PSK ""
#define DFL_PSK_IDENTITY "Client_identity" #define DFL_PSK_IDENTITY "Client_identity"
#define DFL_FORCE_CIPHER 0 #define DFL_FORCE_CIPHER 0
@ -91,8 +93,10 @@ struct options
int debug_level; /* level of debugging */ int debug_level; /* level of debugging */
const char *ca_file; /* the file with the CA certificate(s) */ 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 *ca_path; /* the path with the CA certificate(s) reside */
const char *crt_file; /* the file with the client certificate */ const char *crt_file; /* the file with the server certificate */
const char *key_file; /* the file with the client key */ 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; /* the pre-shared key */
const char *psk_identity; /* the pre-shared key identity */ const char *psk_identity; /* the pre-shared key identity */
int force_ciphersuite[2]; /* protocol/ciphersuite to use, or all */ 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_X509_CRT_PARSE_C)
#if defined(POLARSSL_FS_IO) #if defined(POLARSSL_FS_IO)
#define USAGE_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" \ " 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" \ " crt_file=%%s Your own cert and chain (in bottom to top order, top may be omitted)\n" \
" default: \"\" (pre-loaded)\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 #else
#define USAGE_IO \ #define USAGE_IO \
"\n" \ "\n" \
@ -212,6 +269,8 @@ int main( int argc, char *argv[] )
x509_crt cacert; x509_crt cacert;
x509_crt srvcert; x509_crt srvcert;
pk_context pkey; pk_context pkey;
x509_crt srvcert2;
pk_context pkey2;
#endif #endif
#if defined(POLARSSL_SSL_CACHE_C) #if defined(POLARSSL_SSL_CACHE_C)
ssl_cache_context cache; ssl_cache_context cache;
@ -237,6 +296,8 @@ int main( int argc, char *argv[] )
x509_crt_init( &cacert ); x509_crt_init( &cacert );
x509_crt_init( &srvcert ); x509_crt_init( &srvcert );
pk_init( &pkey ); pk_init( &pkey );
x509_crt_init( &srvcert2 );
pk_init( &pkey2 );
#endif #endif
#if defined(POLARSSL_SSL_CACHE_C) #if defined(POLARSSL_SSL_CACHE_C)
ssl_cache_init( &cache ); ssl_cache_init( &cache );
@ -270,6 +331,8 @@ int main( int argc, char *argv[] )
opt.ca_path = DFL_CA_PATH; opt.ca_path = DFL_CA_PATH;
opt.crt_file = DFL_CRT_FILE; opt.crt_file = DFL_CRT_FILE;
opt.key_file = DFL_KEY_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 = DFL_PSK;
opt.psk_identity = DFL_PSK_IDENTITY; opt.psk_identity = DFL_PSK_IDENTITY;
opt.force_ciphersuite[0]= DFL_FORCE_CIPHER; opt.force_ciphersuite[0]= DFL_FORCE_CIPHER;
@ -308,6 +371,10 @@ int main( int argc, char *argv[] )
opt.crt_file = q; opt.crt_file = q;
else if( strcmp( p, "key_file" ) == 0 ) else if( strcmp( p, "key_file" ) == 0 )
opt.key_file = q; 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 ) else if( strcmp( p, "psk" ) == 0 )
opt.psk = q; opt.psk = q;
else if( strcmp( p, "psk_identity" ) == 0 ) else if( strcmp( p, "psk_identity" ) == 0 )
@ -550,45 +617,11 @@ int main( int argc, char *argv[] )
printf( " . Loading the server cert. and key..." ); printf( " . Loading the server cert. and key..." );
fflush( stdout ); fflush( stdout );
#if defined(POLARSSL_FS_IO) if( parse_cert_key( &srvcert, opt.crt_file, &pkey, opt.key_file ) != 0 )
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 );
goto exit; goto exit;
}
#if defined(POLARSSL_FS_IO) if( parse_cert_key( &srvcert2, opt.crt_file2, &pkey2, opt.key_file2 ) != 0 )
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 );
goto exit; goto exit;
}
printf( " ok\n" ); printf( " ok\n" );
#endif /* POLARSSL_X509_CRT_PARSE_C */ #endif /* POLARSSL_X509_CRT_PARSE_C */
@ -647,6 +680,7 @@ int main( int argc, char *argv[] )
#if defined(POLARSSL_X509_CRT_PARSE_C) #if defined(POLARSSL_X509_CRT_PARSE_C)
ssl_set_ca_chain( &ssl, &cacert, NULL, NULL ); ssl_set_ca_chain( &ssl, &cacert, NULL, NULL );
ssl_set_own_cert( &ssl, &srvcert, &pkey ); ssl_set_own_cert( &ssl, &srvcert, &pkey );
ssl_set_own_cert( &ssl, &srvcert2, &pkey2 );
#endif #endif
#if defined(POLARSSL_KEY_EXCHANGE_PSK_ENABLED) #if defined(POLARSSL_KEY_EXCHANGE_PSK_ENABLED)
@ -875,9 +909,11 @@ exit:
net_close( client_fd ); net_close( client_fd );
#if defined(POLARSSL_X509_CRT_PARSE_C) #if defined(POLARSSL_X509_CRT_PARSE_C)
x509_crt_free( &srvcert );
x509_crt_free( &cacert ); x509_crt_free( &cacert );
x509_crt_free( &srvcert );
pk_free( &pkey ); pk_free( &pkey );
x509_crt_free( &srvcert2 );
pk_free( &pkey2 );
#endif #endif
ssl_free( &ssl ); ssl_free( &ssl );