From 5d917ff6a8c699265274c030bea94771cdd2269b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Fri, 21 Feb 2014 16:52:06 +0100 Subject: [PATCH] Add a 'sni' option to ssl_server2 --- include/polarssl/config.h | 5 ++ programs/ssl/ssl_server2.c | 164 +++++++++++++++++++++++++++++++++++++ 2 files changed, 169 insertions(+) diff --git a/include/polarssl/config.h b/include/polarssl/config.h index 74e8189483..c070df2aca 100644 --- a/include/polarssl/config.h +++ b/include/polarssl/config.h @@ -2273,6 +2273,11 @@ #error "POLARSSL_SSL_SESSION_TICKETS_C defined, but not all prerequisites" #endif +#if defined(POLARSSL_SSL_SERVER_NAME_INDICATION) && \ + !defined(POLARSSL_X509_CRT_PARSE_C) +#error "POLARSSL_SSL_SERVER_NAME_INDICATION defined, but not all prerequisites" +#endif + #if defined(POLARSSL_THREADING_PTHREAD) #if !defined(POLARSSL_THREADING_C) || defined(POLARSSL_THREADING_IMPL) #error "POLARSSL_THREADING_PTHREAD defined, but not all prerequisites" diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 81027a638d..052e56d0d2 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -25,6 +25,17 @@ #include "polarssl/config.h" +#if defined(POLARSSL_SSL_SERVER_NAME_INDICATION) && defined(POLARSSL_FS_IO) +#define POLARSSL_SNI +#endif + +#if defined(POLARSSL_PLATFORM_C) +#include "polarssl/platform.h" +#else +#define polarssl_malloc malloc +#define polarssl_free free +#endif + #if defined(_WIN32) #include #endif @@ -72,6 +83,7 @@ #define DFL_TICKET_TIMEOUT -1 #define DFL_CACHE_MAX -1 #define DFL_CACHE_TIMEOUT -1 +#define DFL_SNI NULL #define LONG_RESPONSE "

01-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \ "02-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah-blah\r\n" \ @@ -116,6 +128,7 @@ struct options int ticket_timeout; /* session ticket lifetime */ int cache_max; /* max number of session cache entries */ int cache_timeout; /* expiration delay of session cache entries */ + char *sni; /* string decribing sni information */ } opt; static void my_debug( void *ctx, int level, const char *str ) @@ -177,6 +190,14 @@ static void my_debug( void *ctx, int level, const char *str ) #define USAGE_CACHE "" #endif /* POLARSSL_SSL_CACHE_C */ +#if defined(POLARSSL_SNI) +#define USAGE_SNI \ + " sni=%%s name1,cert1,key1[,name2,cert2,key2[,...]]\n" \ + " default: disabled\n" +#else +#define USAGE_SNI "" +#endif /* POLARSSL_SNI */ + #if defined(POLARSSL_SSL_MAX_FRAGMENT_LENGTH) #define USAGE_MAX_FRAG_LEN \ " max_frag_len=%%d default: 16384 (tls default)\n" \ @@ -195,6 +216,7 @@ static void my_debug( void *ctx, int level, const char *str ) " auth_mode=%%s default: \"optional\"\n" \ " options: none, optional, required\n" \ USAGE_IO \ + USAGE_SNI \ "\n" \ USAGE_PSK \ "\n" \ @@ -227,6 +249,116 @@ int main( int argc, char *argv[] ) return( 0 ); } #else + +#if defined(POLARSSL_SNI) +typedef struct _sni_entry sni_entry; + +struct _sni_entry { + const char *name; + x509_crt *cert; + pk_context *key; + sni_entry *next; +}; + +/* + * Parse a string of triplets name1,crt1,key1[,name2,crt2,key2[,...]] + * into a usable sni_entry list. + * + * Note: this is not production quality: leaks memory if parsing fails, + * and error reporting is poor. + */ +sni_entry *sni_parse( char *sni_string ) +{ + sni_entry *cur = NULL, *new = NULL; + char *p = sni_string; + char *end = p; + char *crt_file, *key_file; + + while( *end != '\0' ) + ++end; + *end = ','; + + while( p <= end ) + { + if( ( new = polarssl_malloc( sizeof( sni_entry ) ) ) == NULL ) + return( NULL ); + + memset( new, 0, sizeof( sni_entry ) ); + + if( ( new->cert = polarssl_malloc( sizeof( x509_crt ) ) ) == NULL || + ( new->key = polarssl_malloc( sizeof( pk_context ) ) ) == NULL ) + return( NULL ); + + x509_crt_init( new->cert ); + pk_init( new->key ); + + new->name = p; + while( *p != ',' ) if( ++p > end ) return( NULL ); + *p++ = '\0'; + + crt_file = p; + while( *p != ',' ) if( ++p > end ) return( NULL ); + *p++ = '\0'; + + key_file = p; + while( *p != ',' ) if( ++p > end ) return( NULL ); + *p++ = '\0'; + + if( x509_crt_parse_file( new->cert, crt_file ) != 0 || + pk_parse_keyfile( new->key, key_file, "" ) != 0 ) + return( NULL ); + + new->next = cur; + cur = new; + + } + + return( cur ); +} + +void sni_free( sni_entry *head ) +{ + sni_entry *cur = head, *next; + + while( cur != NULL ) + { + x509_crt_free( cur->cert ); + polarssl_free( cur->cert ); + + pk_free( cur->key ); + polarssl_free( cur->key ); + + next = cur->next; + polarssl_free( cur ); + cur = next; + } +} + +/* + * SNI callback. + */ +int sni_callback( void *p_info, ssl_context *ssl, + const unsigned char *name, size_t name_len ) +{ + sni_entry *cur = (sni_entry *) p_info; + + while( cur != NULL ) + { + if( name_len == strlen( cur->name ) && + memcmp( name, cur->name, name_len ) == 0 ) + { + ssl_set_own_cert( ssl, cur->cert, cur->key ); + return( 0 ); + } + + cur = cur->next; + } + + return( -1 ); +} + +#endif /* POLARSSL_SNI */ + int main( int argc, char *argv[] ) { int ret = 0, len, written, frags; @@ -253,6 +385,9 @@ int main( int argc, char *argv[] ) #if defined(POLARSSL_SSL_CACHE_C) ssl_cache_context cache; #endif +#if defined(POLARSSL_SNI) + sni_entry *sni_info = NULL; +#endif #if defined(POLARSSL_MEMORY_BUFFER_ALLOC_C) unsigned char alloc_buf[100000]; #endif @@ -326,6 +461,7 @@ int main( int argc, char *argv[] ) opt.ticket_timeout = DFL_TICKET_TIMEOUT; opt.cache_max = DFL_CACHE_MAX; opt.cache_timeout = DFL_CACHE_TIMEOUT; + opt.sni = DFL_SNI; for( i = 1; i < argc; i++ ) { @@ -493,6 +629,10 @@ int main( int argc, char *argv[] ) if( opt.cache_timeout < 0 ) goto usage; } + else if( strcmp( p, "sni" ) == 0 ) + { + opt.sni = q; + } else goto usage; } @@ -725,6 +865,22 @@ int main( int argc, char *argv[] ) printf( " ok\n" ); #endif /* POLARSSL_X509_CRT_PARSE_C */ +#if defined(POLARSSL_SNI) + if( opt.sni != NULL ) + { + printf( " . Setting up SNI information..." ); + fflush( stdout ); + + if( ( sni_info = sni_parse( opt.sni ) ) == NULL ) + { + printf( " failed\n" ); + goto exit; + } + + printf( " ok\n" ); + } +#endif /* POLARSSL_SNI */ + /* * 2. Setup the listening TCP socket */ @@ -794,6 +950,11 @@ int main( int argc, char *argv[] ) ssl_set_own_cert( &ssl, &srvcert2, &pkey2 ); #endif +#if defined(POLARSSL_SNI) + if( opt.sni != NULL ) + ssl_set_sni( &ssl, sni_callback, sni_info ); +#endif + #if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED) ssl_set_psk( &ssl, psk, psk_len, (const unsigned char *) opt.psk_identity, strlen( opt.psk_identity ) ); @@ -1047,6 +1208,9 @@ exit: x509_crt_free( &srvcert2 ); pk_free( &pkey2 ); #endif +#if defined(POLARSSL_SNI) + sni_free( sni_info ); +#endif ssl_free( &ssl ); entropy_free( &entropy );