From 736699c08c9929b87fe7e1a430489ba691367c92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 9 Jun 2014 11:29:50 +0200 Subject: [PATCH 01/13] Add a dhm_file option to ssl_server2 --- programs/ssl/ssl_server2.c | 47 +++++++++++++++++++++++++++++++++++--- 1 file changed, 44 insertions(+), 3 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 2b6e426b3..de7c0a8fb 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -91,6 +91,7 @@ #define DFL_CACHE_TIMEOUT -1 #define DFL_SNI NULL #define DFL_ALPN_STRING NULL +#define DFL_DHM_FILE 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" \ @@ -138,6 +139,7 @@ struct options int cache_timeout; /* expiration delay of session cache entries */ char *sni; /* string describing sni information */ const char *alpn_string; /* ALPN supported protocols */ + const char *dhm_file; /* the file with the DH parameters */ } opt; static void my_debug( void *ctx, int level, const char *str ) @@ -200,7 +202,9 @@ static int my_send( void *ctx, const unsigned char *buf, size_t len ) " default: see note after key_file2\n" \ " key_file2=%%s default: see note below\n" \ " note: if neither crt_file/key_file nor crt_file2/key_file2 are used,\n" \ - " preloaded certificate(s) and key(s) are used if available\n" + " preloaded certificate(s) and key(s) are used if available\n" \ + " dhm_file=%%s File containing Diffie-Hellman parameters\n" \ + " default: preloaded parameters\n" #else #define USAGE_IO \ "\n" \ @@ -452,6 +456,9 @@ int main( int argc, char *argv[] ) pk_context pkey2; int key_cert_init = 0, key_cert_init2 = 0; #endif +#if defined(POLARSSL_DHM_C) && defined(POLARSSL_FS_IO) + dhm_context dhm; +#endif #if defined(POLARSSL_SSL_CACHE_C) ssl_cache_context cache; #endif @@ -485,6 +492,9 @@ int main( int argc, char *argv[] ) x509_crt_init( &srvcert2 ); pk_init( &pkey2 ); #endif +#if defined(POLARSSL_DHM_C) && defined(POLARSSL_FS_IO) + memset( &dhm, 0, sizeof( dhm_context ) ); +#endif #if defined(POLARSSL_SSL_CACHE_C) ssl_cache_init( &cache ); #endif @@ -540,6 +550,7 @@ int main( int argc, char *argv[] ) opt.cache_timeout = DFL_CACHE_TIMEOUT; opt.sni = DFL_SNI; opt.alpn_string = DFL_ALPN_STRING; + opt.dhm_file = DFL_DHM_FILE; for( i = 1; i < argc; i++ ) { @@ -580,6 +591,8 @@ int main( int argc, char *argv[] ) opt.crt_file2 = q; else if( strcmp( p, "key_file2" ) == 0 ) opt.key_file2 = q; + else if( strcmp( p, "dhm_file" ) == 0 ) + opt.dhm_file = q; else if( strcmp( p, "psk" ) == 0 ) opt.psk = q; else if( strcmp( p, "psk_identity" ) == 0 ) @@ -988,6 +1001,23 @@ int main( int argc, char *argv[] ) printf( " ok\n" ); #endif /* POLARSSL_X509_CRT_PARSE_C */ +#if defined(POLARSSL_DHM_C) && defined(POLARSSL_FS_IO) + if( opt.dhm_file != NULL ) + { + printf( " . Loading DHM parameters..." ); + fflush( stdout ); + + if( ( ret = dhm_parse_dhmfile( &dhm, opt.dhm_file ) ) != 0 ) + { + printf( " failed\n ! dhm_parse_dhmfile returned -0x%04X\n\n", + -ret ); + goto exit; + } + + printf( " ok\n" ); + } +#endif + #if defined(POLARSSL_SNI) if( opt.sni != NULL ) { @@ -1096,8 +1126,19 @@ int main( int argc, char *argv[] ) /* * Use different group than default DHM group */ - ssl_set_dh_param( &ssl, POLARSSL_DHM_RFC5114_MODP_2048_P, - POLARSSL_DHM_RFC5114_MODP_2048_G ); +#if defined(POLARSSL_FS_IO) + if( opt.dhm_file != NULL ) + ret = ssl_set_dh_param_ctx( &ssl, &dhm ); + else +#endif + ret = ssl_set_dh_param( &ssl, POLARSSL_DHM_RFC5114_MODP_2048_P, + POLARSSL_DHM_RFC5114_MODP_2048_G ); + + if( ret != 0 ) + { + printf( " failed\n ssl_set_dh_param returned -0x%04X\n\n", - ret ); + goto exit; + } #endif if( opt.min_version != -1 ) From 0cc7e31ad157939b4d5454b36c7d963c77c50e22 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 9 Jun 2014 11:36:47 +0200 Subject: [PATCH 02/13] Add test for ssl_set_dh_param_ctx() --- tests/ssl-opt.sh | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index f4fbc019b..a9d6e4d17 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -1243,6 +1243,25 @@ run_test "extKeyUsage cli-auth #4b (codeSign -> fail (hard))" \ -s "bad certificate (usage extensions)" \ -s "Processing of the Certificate handshake message failed" +# Tests for DHM parameters loading + +run_test "DHM parameters #0 (reference)" \ + "$P_SRV" \ + "$P_CLI force_ciphersuite=TLS-DHE-RSA-WITH-AES-128-CBC-SHA \ + debug_level=3" \ + 0 \ + -c "value of 'DHM: P ' (2048 bits)" \ + -c "value of 'DHM: G ' (2048 bits)" + +run_test "DHM parameters #1 (other parameters)" \ + "$P_SRV dhm_file=data_files/dhparams.pem" \ + "$P_CLI force_ciphersuite=TLS-DHE-RSA-WITH-AES-128-CBC-SHA \ + debug_level=3" \ + 0 \ + -c "value of 'DHM: P ' (1024 bits)" \ + -c "value of 'DHM: G ' (2 bits)" + + # Final report echo "------------------------------------------------------------------------" From 9e27163acd8b89e997a1a5998b858bb657fa688a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Mon, 9 Jun 2014 19:06:00 +0200 Subject: [PATCH 03/13] Refactor PSK parsing in ssl_server2 --- programs/ssl/ssl_server2.c | 85 +++++++++++++++++++++----------------- 1 file changed, 46 insertions(+), 39 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index de7c0a8fb..c932d14b1 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -108,6 +108,8 @@ "

PolarSSL Test Server

\r\n" \ "

Successful connection using: %s

\r\n" // LONG_RESPONSE +#define MAX_PSK_LEN 256 + /* * global options */ @@ -433,6 +435,47 @@ int sni_callback( void *p_info, ssl_context *ssl, #endif /* POLARSSL_SNI */ +#if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED) + +#define HEX2NUM( c ) \ + if( c >= '0' && c <= '9' ) \ + c -= '0'; \ + else if( c >= 'a' && c <= 'f' ) \ + c -= 'a' - 10; \ + else if( c >= 'A' && c <= 'F' ) \ + c -= 'A' - 10; \ + else \ + return( -1 ); + +/* + * Convert a hex string to bytes. + * Return 0 on success, -1 on error. + */ +int unhexify( unsigned char *output, const char *input, size_t *olen ) +{ + unsigned char c; + size_t j; + + *olen = strlen( input ); + if( *olen % 2 != 0 || *olen / 2 > MAX_PSK_LEN ) + return( -1 ); + *olen /= 2; + + for( j = 0; j < *olen * 2; j += 2 ) + { + c = input[j]; + HEX2NUM( c ); + output[ j / 2 ] = c << 4; + + c = input[j + 1]; + HEX2NUM( c ); + output[ j / 2 ] |= c; + } + + return( 0 ); +} +#endif /* POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED */ + int main( int argc, char *argv[] ) { int ret = 0, len, written, frags; @@ -440,7 +483,7 @@ int main( int argc, char *argv[] ) int client_fd = -1; unsigned char buf[SSL_MAX_CONTENT_LEN + 1]; #if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED) - unsigned char psk[256]; + unsigned char psk[MAX_PSK_LEN]; size_t psk_len = 0; #endif const char *pers = "ssl_server2"; @@ -771,49 +814,13 @@ int main( int argc, char *argv[] ) /* * Unhexify the pre-shared key if any is given */ - if( strlen( opt.psk ) ) + if( opt.psk != NULL ) { - unsigned char c; - size_t j; - - if( strlen( opt.psk ) % 2 != 0 ) + if( unhexify( psk, opt.psk, &psk_len ) != 0 ) { printf("pre-shared key not valid hex\n"); goto exit; } - - psk_len = strlen( opt.psk ) / 2; - - for( j = 0; j < strlen( opt.psk ); j += 2 ) - { - c = opt.psk[j]; - if( c >= '0' && c <= '9' ) - c -= '0'; - else if( c >= 'a' && c <= 'f' ) - c -= 'a' - 10; - else if( c >= 'A' && c <= 'F' ) - c -= 'A' - 10; - else - { - printf("pre-shared key not valid hex\n"); - goto exit; - } - psk[ j / 2 ] = c << 4; - - c = opt.psk[j + 1]; - if( c >= '0' && c <= '9' ) - c -= '0'; - else if( c >= 'a' && c <= 'f' ) - c -= 'a' - 10; - else if( c >= 'A' && c <= 'F' ) - c -= 'A' - 10; - else - { - printf("pre-shared key not valid hex\n"); - goto exit; - } - psk[ j / 2 ] |= c; - } } #endif /* POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED */ From 80c8553a1a1075f81e424aa9c26f65d8e8225ee6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 10 Jun 2014 14:01:52 +0200 Subject: [PATCH 04/13] Add psk_list option to ssl_server2: PSK callback --- programs/ssl/ssl_server2.c | 113 +++++++++++++++++++++++++++++++++++-- 1 file changed, 109 insertions(+), 4 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index c932d14b1..e80038e87 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -77,6 +77,7 @@ #define DFL_KEY_FILE2 "" #define DFL_PSK "" #define DFL_PSK_IDENTITY "Client_identity" +#define DFL_PSK_LIST NULL #define DFL_FORCE_CIPHER 0 #define DFL_RENEGOTIATION SSL_RENEGOTIATION_DISABLED #define DFL_ALLOW_LEGACY SSL_LEGACY_NO_RENEGOTIATION @@ -127,6 +128,7 @@ struct options 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 */ + char *psk_list; /* list of PSK id/key pairs for callback */ int force_ciphersuite[2]; /* protocol/ciphersuite to use, or all */ int renegotiation; /* enable / disable renegotiation */ int allow_legacy; /* allow legacy renegotiation */ @@ -474,6 +476,97 @@ int unhexify( unsigned char *output, const char *input, size_t *olen ) return( 0 ); } + +typedef struct _psk_entry psk_entry; + +struct _psk_entry +{ + const char *name; + size_t key_len; + unsigned char key[MAX_PSK_LEN]; + psk_entry *next; +}; + +/* + * Parse a string of pairs name1,key1[,name2,key2[,...]] + * into a usable psk_entry list. + * + * Modifies the input string! This is not production quality! + * (leaks memory if parsing fails, no error reporting, ...) + */ +psk_entry *psk_parse( char *psk_string ) +{ + psk_entry *cur = NULL, *new = NULL; + char *p = psk_string; + char *end = p; + char *key_hex; + + while( *end != '\0' ) + ++end; + *end = ','; + + while( p <= end ) + { + if( ( new = polarssl_malloc( sizeof( psk_entry ) ) ) == NULL ) + return( NULL ); + + memset( new, 0, sizeof( psk_entry ) ); + + new->name = p; + while( *p != ',' ) if( ++p > end ) return( NULL ); + *p++ = '\0'; + + key_hex = p; + while( *p != ',' ) if( ++p > end ) return( NULL ); + *p++ = '\0'; + + if( unhexify( new->key, key_hex, &new->key_len ) != 0 ) + return( NULL ); + + new->next = cur; + cur = new; + } + + return( cur ); +} + +/* + * Free a list of psk_entry's + */ +void psk_free( psk_entry *head ) +{ + psk_entry *next; + + while( head != NULL ) + { + next = head->next; + polarssl_free( head ); + head = next; + } +} + +/* + * PSK callback + */ +int psk_callback( void *p_info, ssl_context *ssl, + const unsigned char *name, size_t name_len ) +{ + psk_entry *cur = (psk_entry *) p_info; + + while( cur != NULL ) + { + if( name_len == strlen( cur->name ) && + memcmp( name, cur->name, name_len ) == 0 ) + { + return( ssl_set_psk( ssl, cur->key, cur->key_len, + name, name_len ) ); + } + + cur = cur->next; + } + + return( -1 ); +} #endif /* POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED */ int main( int argc, char *argv[] ) @@ -485,6 +578,7 @@ int main( int argc, char *argv[] ) #if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED) unsigned char psk[MAX_PSK_LEN]; size_t psk_len = 0; + psk_entry *psk_info; #endif const char *pers = "ssl_server2"; @@ -579,6 +673,7 @@ int main( int argc, char *argv[] ) opt.key_file2 = DFL_KEY_FILE2; opt.psk = DFL_PSK; opt.psk_identity = DFL_PSK_IDENTITY; + opt.psk_list = DFL_PSK_LIST; opt.force_ciphersuite[0]= DFL_FORCE_CIPHER; opt.renegotiation = DFL_RENEGOTIATION; opt.allow_legacy = DFL_ALLOW_LEGACY; @@ -640,6 +735,8 @@ int main( int argc, char *argv[] ) opt.psk = q; else if( strcmp( p, "psk_identity" ) == 0 ) opt.psk_identity = q; + else if( strcmp( p, "psk_list" ) == 0 ) + opt.psk_list = q; else if( strcmp( p, "force_ciphersuite" ) == 0 ) { opt.force_ciphersuite[0] = -1; @@ -812,13 +909,19 @@ int main( int argc, char *argv[] ) #if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED) /* - * Unhexify the pre-shared key if any is given + * Unhexify the pre-shared key and parse the list if any given */ - if( opt.psk != NULL ) + if( unhexify( psk, opt.psk, &psk_len ) != 0 ) { - if( unhexify( psk, opt.psk, &psk_len ) != 0 ) + printf( "pre-shared key not valid hex\n" ); + goto exit; + } + + if( opt.psk_list != NULL ) + { + if( ( psk_info = psk_parse( opt.psk_list ) ) == NULL ) { - printf("pre-shared key not valid hex\n"); + printf( "psk_list invalid" ); goto exit; } } @@ -1127,6 +1230,8 @@ int main( int argc, char *argv[] ) #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 ) ); + if( opt.psk_list != NULL ) + ssl_set_psk_cb( &ssl, psk_callback, psk_info ); #endif #if defined(POLARSSL_DHM_C) From a6781c99ee1e93aa78dfd039c3060dfd6fa772ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 10 Jun 2014 15:00:46 +0200 Subject: [PATCH 05/13] Add tests for PSK callback --- tests/ssl-opt.sh | 49 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index a9d6e4d17..c11e26cca 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -1261,6 +1261,55 @@ run_test "DHM parameters #1 (other parameters)" \ -c "value of 'DHM: P ' (1024 bits)" \ -c "value of 'DHM: G ' (2 bits)" +# Tests for PSK callback + +run_test "PSK callback #0 (reference)" \ + "$P_SRV psk=abc123 psk_identity=foo" \ + "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ + psk_identity=foo psk=abc123" \ + 0 \ + -S "SSL - Unknown identity received" \ + -S "SSL - Verification of the message MAC failed" + +run_test "PSK callback #1 (callback overrides other settings)" \ + "$P_SRV psk=abc123 psk_identity=foo psk_list=abc,dead,def,beef" \ + "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ + psk_identity=foo psk=abc123" \ + 1 \ + -s "SSL - Unknown identity received" \ + -S "SSL - Verification of the message MAC failed" + +run_test "PSK callback #2 (first id matches)" \ + "$P_SRV psk_list=abc,dead,def,beef" \ + "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ + psk_identity=abc psk=dead" \ + 0 \ + -S "SSL - Unknown identity received" \ + -S "SSL - Verification of the message MAC failed" + +run_test "PSK callback #3 (second id matches)" \ + "$P_SRV psk_list=abc,dead,def,beef" \ + "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ + psk_identity=def psk=beef" \ + 0 \ + -S "SSL - Unknown identity received" \ + -S "SSL - Verification of the message MAC failed" + +run_test "PSK callback #4 (no match)" \ + "$P_SRV psk_list=abc,dead,def,beef" \ + "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ + psk_identity=ghi psk=beef" \ + 1 \ + -s "SSL - Unknown identity received" \ + -S "SSL - Verification of the message MAC failed" + +run_test "PSK callback #5 (wrong key)" \ + "$P_SRV psk_list=abc,dead,def,beef" \ + "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ + psk_identity=abc psk=beef" \ + 1 \ + -S "SSL - Unknown identity received" \ + -s "SSL - Verification of the message MAC failed" # Final report From fdee74b8d67f850eb4a03ac8405d8ba6faba85dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 10 Jun 2014 15:15:06 +0200 Subject: [PATCH 06/13] Simplify some option parsing code --- programs/ssl/ssl_server2.c | 56 +++++++++++++------------------------- 1 file changed, 19 insertions(+), 37 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index e80038e87..72e4975b5 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -314,6 +314,16 @@ int main( int argc, char *argv[] ) } #else +/* + * Used by sni_parse and psk_parse to handle coma-separated lists + */ +#define GET_ITEM( dst ) \ + dst = p; \ + while( *p != ',' ) \ + if( ++p > end ) \ + return( NULL ); \ + *p++ = '\0'; + #if defined(POLARSSL_SNI) typedef struct _sni_entry sni_entry; @@ -328,8 +338,8 @@ struct _sni_entry { * 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. + * Modifies the input string! This is not production quality! + * (leaks memory if parsing fails, no error reporting, ...) */ sni_entry *sni_parse( char *sni_string ) { @@ -351,44 +361,21 @@ sni_entry *sni_parse( char *sni_string ) if( ( new->cert = polarssl_malloc( sizeof( x509_crt ) ) ) == NULL || ( new->key = polarssl_malloc( sizeof( pk_context ) ) ) == NULL ) - { - cur = NULL; - goto exit; - } + return( NULL ); x509_crt_init( new->cert ); pk_init( new->key ); - new->name = p; - while( *p != ',' ) if( ++p > end ) { cur = NULL; goto exit; } - *p++ = '\0'; - - crt_file = p; - while( *p != ',' ) if( ++p > end ) { cur = NULL; goto exit; } - *p++ = '\0'; - - key_file = p; - while( *p != ',' ) if( ++p > end ) { cur = NULL; goto exit; } - *p++ = '\0'; + GET_ITEM( new->name ); + GET_ITEM( crt_file ); + GET_ITEM( key_file ); if( x509_crt_parse_file( new->cert, crt_file ) != 0 || pk_parse_keyfile( new->key, key_file, "" ) != 0 ) - { - cur = NULL; - goto exit; - } + return( NULL ); new->next = cur; cur = new; - new = NULL; - } - -exit: - if( new != NULL ) - { - x509_crt_free( new->cert); - pk_free( new->key ); - polarssl_free( new ); } return( cur ); @@ -512,13 +499,8 @@ psk_entry *psk_parse( char *psk_string ) memset( new, 0, sizeof( psk_entry ) ); - new->name = p; - while( *p != ',' ) if( ++p > end ) return( NULL ); - *p++ = '\0'; - - key_hex = p; - while( *p != ',' ) if( ++p > end ) return( NULL ); - *p++ = '\0'; + GET_ITEM( new->name ); + GET_ITEM( key_hex ); if( unhexify( new->key, key_hex, &new->key_len ) != 0 ) return( NULL ); From dc019b95590e64fdb51decf2907da8a65fc3b227 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 10 Jun 2014 15:24:51 +0200 Subject: [PATCH 07/13] Use ssl_set_psk() only when a psk is given --- programs/ssl/ssl_server2.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 72e4975b5..9d2733c93 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -1210,8 +1210,18 @@ int main( int argc, char *argv[] ) #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 ) ); + if( strlen( opt.psk ) != 0 && strlen( opt.psk_identity ) != 0 ) + { + ret = ssl_set_psk( &ssl, psk, psk_len, + (const unsigned char *) opt.psk_identity, + strlen( opt.psk_identity ) ); + if( ret != 0 ) + { + printf( " failed\n ssl_set_psk returned -0x%04X\n\n", - ret ); + goto exit; + } + } + if( opt.psk_list != NULL ) ssl_set_psk_cb( &ssl, psk_callback, psk_info ); #endif From 10c3c9fda897b89e02f6ce5f6c354e73614a6d5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Tue, 10 Jun 2014 15:28:52 +0200 Subject: [PATCH 08/13] Add test for PSK without a key --- tests/ssl-opt.sh | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index c11e26cca..b0393df98 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -1263,11 +1263,21 @@ run_test "DHM parameters #1 (other parameters)" \ # Tests for PSK callback -run_test "PSK callback #0 (reference)" \ +run_test "PSK callback #0a (psk, no callback)" \ "$P_SRV psk=abc123 psk_identity=foo" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ psk_identity=foo psk=abc123" \ 0 \ + -S "SSL - The server has no ciphersuites in common" \ + -S "SSL - Unknown identity received" \ + -S "SSL - Verification of the message MAC failed" + +run_test "PSK callback #0b (no psk, no callback)" \ + "$P_SRV" \ + "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ + psk_identity=foo psk=abc123" \ + 1 \ + -s "SSL - The server has no ciphersuites in common" \ -S "SSL - Unknown identity received" \ -S "SSL - Verification of the message MAC failed" @@ -1276,6 +1286,7 @@ run_test "PSK callback #1 (callback overrides other settings)" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ psk_identity=foo psk=abc123" \ 1 \ + -S "SSL - The server has no ciphersuites in common" \ -s "SSL - Unknown identity received" \ -S "SSL - Verification of the message MAC failed" @@ -1284,6 +1295,7 @@ run_test "PSK callback #2 (first id matches)" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ psk_identity=abc psk=dead" \ 0 \ + -S "SSL - The server has no ciphersuites in common" \ -S "SSL - Unknown identity received" \ -S "SSL - Verification of the message MAC failed" @@ -1292,6 +1304,7 @@ run_test "PSK callback #3 (second id matches)" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ psk_identity=def psk=beef" \ 0 \ + -S "SSL - The server has no ciphersuites in common" \ -S "SSL - Unknown identity received" \ -S "SSL - Verification of the message MAC failed" @@ -1300,6 +1313,7 @@ run_test "PSK callback #4 (no match)" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ psk_identity=ghi psk=beef" \ 1 \ + -S "SSL - The server has no ciphersuites in common" \ -s "SSL - Unknown identity received" \ -S "SSL - Verification of the message MAC failed" @@ -1308,6 +1322,7 @@ run_test "PSK callback #5 (wrong key)" \ "$P_CLI force_ciphersuite=TLS-PSK-WITH-AES-128-CBC-SHA \ psk_identity=abc psk=beef" \ 1 \ + -S "SSL - The server has no ciphersuites in common" \ -S "SSL - Unknown identity received" \ -s "SSL - Verification of the message MAC failed" From 6dc0781aba0e7f506c0cdafc501e7dafa1cafe36 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 11 Jun 2014 13:50:34 +0200 Subject: [PATCH 09/13] Add version_suites option to ssl_server2 --- programs/ssl/ssl_server2.c | 72 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 69 insertions(+), 3 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 9d2733c93..9e09e6f36 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -79,6 +79,7 @@ #define DFL_PSK_IDENTITY "Client_identity" #define DFL_PSK_LIST NULL #define DFL_FORCE_CIPHER 0 +#define DFL_VERSION_SUITES NULL #define DFL_RENEGOTIATION SSL_RENEGOTIATION_DISABLED #define DFL_ALLOW_LEGACY SSL_LEGACY_NO_RENEGOTIATION #define DFL_RENEGOTIATE 0 @@ -130,6 +131,7 @@ struct options const char *psk_identity; /* the pre-shared key identity */ char *psk_list; /* list of PSK id/key pairs for callback */ int force_ciphersuite[2]; /* protocol/ciphersuite to use, or all */ + const char *version_suites; /* per-version ciphersuites */ int renegotiation; /* enable / disable renegotiation */ int allow_legacy; /* allow legacy renegotiation */ int renegotiate; /* attempt renegotiation? */ @@ -294,9 +296,12 @@ static int my_send( void *ctx, const unsigned char *buf, size_t len ) " min_version=%%s default: \"ssl3\"\n" \ " max_version=%%s default: \"tls1_2\"\n" \ " force_version=%%s default: \"\" (none)\n" \ - " options: ssl3, tls1, tls1_1, tls1_2\n" \ - "\n" \ - " force_ciphersuite= default: all enabled\n"\ + " options: ssl3, tls1, tls1_1, tls1_2\n" \ + "\n" \ + " version_suites=a,b,c,d per-version ciphersuites\n" \ + " in order from ssl3 to tls1_2\n" \ + " default: all enabled\n" \ + " force_ciphersuite= default: all enabled\n" \ " acceptable ciphersuite names:\n" #if !defined(POLARSSL_ENTROPY_C) || \ @@ -556,6 +561,7 @@ int main( int argc, char *argv[] ) int ret = 0, len, written, frags; int listen_fd; int client_fd = -1; + int version_suites[4][2]; unsigned char buf[SSL_MAX_CONTENT_LEN + 1]; #if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED) unsigned char psk[MAX_PSK_LEN]; @@ -657,6 +663,7 @@ int main( int argc, char *argv[] ) opt.psk_identity = DFL_PSK_IDENTITY; opt.psk_list = DFL_PSK_LIST; opt.force_ciphersuite[0]= DFL_FORCE_CIPHER; + opt.version_suites = DFL_VERSION_SUITES; opt.renegotiation = DFL_RENEGOTIATION; opt.allow_legacy = DFL_ALLOW_LEGACY; opt.renegotiate = DFL_RENEGOTIATE; @@ -732,6 +739,8 @@ int main( int argc, char *argv[] ) } opt.force_ciphersuite[1] = 0; } + else if( strcmp( p, "version_suites" ) == 0 ) + opt.version_suites = q; else if( strcmp( p, "renegotiation" ) == 0 ) { opt.renegotiation = (atoi( q )) ? SSL_RENEGOTIATION_ENABLED : @@ -889,6 +898,47 @@ int main( int argc, char *argv[] ) opt.min_version = ciphersuite_info->min_minor_ver; } + if( opt.version_suites != NULL ) + { + const char *name[4] = { 0 }; + + /* Parse 4-element coma-separated list */ + for( i = 0, p = (char *) opt.version_suites; + i < 4 && *p != '\0'; + i++ ) + { + name[i] = p; + + /* Terminate the current string and move on to next one */ + while( *p != ',' && *p != '\0' ) + p++; + if( *p == ',' ) + *p++ = '\0'; + } + + if( i != 4 ) + { + printf( "too few values for version_suites\n" ); + ret = 1; + goto exit; + } + + memset( version_suites, 0, sizeof( version_suites ) ); + + /* Get the suites identifiers from their name */ + for( i = 0; i < 4; i++ ) + { + version_suites[i][0] = ssl_get_ciphersuite_id( name[i] ); + + if( version_suites[i][0] == 0 ) + { + printf( "unknown ciphersuite: '%s'\n", name[i] ); + ret = 2; + goto usage; + } + } + } + #if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED) /* * Unhexify the pre-shared key and parse the list if any given @@ -1189,6 +1239,22 @@ int main( int argc, char *argv[] ) if( opt.force_ciphersuite[0] != DFL_FORCE_CIPHER ) ssl_set_ciphersuites( &ssl, opt.force_ciphersuite ); + if( opt.version_suites != NULL ) + { + ssl_set_ciphersuites_for_version( &ssl, version_suites[0], + SSL_MAJOR_VERSION_3, + SSL_MINOR_VERSION_0 ); + ssl_set_ciphersuites_for_version( &ssl, version_suites[1], + SSL_MAJOR_VERSION_3, + SSL_MINOR_VERSION_1 ); + ssl_set_ciphersuites_for_version( &ssl, version_suites[2], + SSL_MAJOR_VERSION_3, + SSL_MINOR_VERSION_2 ); + ssl_set_ciphersuites_for_version( &ssl, version_suites[3], + SSL_MAJOR_VERSION_3, + SSL_MINOR_VERSION_3 ); + } + ssl_set_renegotiation( &ssl, opt.renegotiation ); ssl_legacy_renegotiation( &ssl, opt.allow_legacy ); From 90805a8d012e23b66f41acd8275c4edc943b8745 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 11 Jun 2014 14:06:01 +0200 Subject: [PATCH 10/13] Add test for ssl_set_ciphersuites_for_version() --- tests/ssl-opt.sh | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index b0393df98..724e2de25 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -1326,6 +1326,33 @@ run_test "PSK callback #5 (wrong key)" \ -S "SSL - Unknown identity received" \ -s "SSL - Verification of the message MAC failed" +# Tests for ciphersuites per version + +run_test "Per-version suites #1" \ + "$P_SRV version_suites=TLS-RSA-WITH-3DES-EDE-CBC-SHA,TLS-RSA-WITH-RC4-128-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \ + "$P_CLI force_version=ssl3" \ + 0 \ + -c "Ciphersuite is TLS-RSA-WITH-3DES-EDE-CBC-SHA" + +run_test "Per-version suites #2" \ + "$P_SRV version_suites=TLS-RSA-WITH-3DES-EDE-CBC-SHA,TLS-RSA-WITH-RC4-128-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \ + "$P_CLI force_version=tls1" \ + 0 \ + -c "Ciphersuite is TLS-RSA-WITH-RC4-128-SHA" + +run_test "Per-version suites #3" \ + "$P_SRV version_suites=TLS-RSA-WITH-3DES-EDE-CBC-SHA,TLS-RSA-WITH-RC4-128-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \ + "$P_CLI force_version=tls1_1" \ + 0 \ + -c "Ciphersuite is TLS-RSA-WITH-AES-128-CBC-SHA" + +run_test "Per-version suites #4" \ + "$P_SRV version_suites=TLS-RSA-WITH-3DES-EDE-CBC-SHA,TLS-RSA-WITH-RC4-128-SHA,TLS-RSA-WITH-AES-128-CBC-SHA,TLS-RSA-WITH-AES-128-GCM-SHA256" \ + "$P_CLI force_version=tls1_2" \ + 0 \ + -c "Ciphersuite is TLS-RSA-WITH-AES-128-GCM-SHA256" + + # Final report echo "------------------------------------------------------------------------" From e7a3b10dcc8449a0fbe506df018305d6fe4ba2b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 11 Jun 2014 18:21:20 +0200 Subject: [PATCH 11/13] Use ssl_get_bytes_avail() in ssl_server2. --- programs/ssl/ssl_server2.c | 49 ++++++++++++++++++++++++++++++++++---- 1 file changed, 45 insertions(+), 4 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 9e09e6f36..7f2041b51 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -112,6 +112,9 @@ #define MAX_PSK_LEN 256 +/* Size of the basic I/O buffer. Able to hold our default response. */ +#define IO_BUF_LEN 200 + /* * global options */ @@ -562,7 +565,7 @@ int main( int argc, char *argv[] ) int listen_fd; int client_fd = -1; int version_suites[4][2]; - unsigned char buf[SSL_MAX_CONTENT_LEN + 1]; + unsigned char buf[IO_BUF_LEN]; #if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED) unsigned char psk[MAX_PSK_LEN]; size_t psk_len = 0; @@ -1463,9 +1466,47 @@ reset: break; } - len = ret; - buf[len] = '\0'; - printf( " %d bytes read\n\n%s\n", len, (char *) buf ); + if( ssl_get_bytes_avail( &ssl ) == 0 ) + { + len = ret; + buf[len] = '\0'; + printf( " %d bytes read\n\n%s\n", len, (char *) buf ); + } + else + { + int extra_len, ori_len; + unsigned char *larger_buf; + + ori_len = ret; + extra_len = ssl_get_bytes_avail( &ssl ); + + larger_buf = polarssl_malloc( ori_len + extra_len + 1 ); + if( larger_buf == NULL ) + { + printf( " ! memory allocation failed\n" ); + ret = 1; + goto exit; + } + + memset( larger_buf, 0, ori_len + extra_len ); + memcpy( larger_buf, buf, ori_len ); + + /* This read should never fail */ + ret = ssl_read( &ssl, larger_buf + ori_len, extra_len ); + if( ret != extra_len ) + { + printf( " ! ssl_read failed on cached data\n" ); + ret = 1; + goto exit; + } + + larger_buf[ori_len + extra_len] = '\0'; + printf( " %u bytes read (%u + %u)\n\n%s\n", + ori_len + extra_len, ori_len, extra_len, (char *) buf ); + + polarssl_free( larger_buf ); + } + if( memcmp( buf, "SERVERQUIT", 10 ) == 0 ) { From 95c0a6302352161ad71857ed1c1a270102cc8a61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 11 Jun 2014 18:32:36 +0200 Subject: [PATCH 12/13] Add tests for ssl_get_bytes_avail() --- programs/ssl/ssl_server2.c | 12 +++++++++--- tests/ssl-opt.sh | 13 +++++++++++++ 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 7f2041b51..8af5f6429 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -112,7 +112,12 @@ #define MAX_PSK_LEN 256 -/* Size of the basic I/O buffer. Able to hold our default response. */ +/* + * Size of the basic I/O buffer. Able to hold our default response. + * + * You will need to adapt the ssl_get_bytes_avail() test in ssl-opt.sh + * if you change this value to something outside the range <= 100 or > 500 + */ #define IO_BUF_LEN 200 /* @@ -1491,9 +1496,10 @@ reset: memset( larger_buf, 0, ori_len + extra_len ); memcpy( larger_buf, buf, ori_len ); - /* This read should never fail */ + /* This read should never fail and get the whole cached data */ ret = ssl_read( &ssl, larger_buf + ori_len, extra_len ); - if( ret != extra_len ) + if( ret != extra_len || + ssl_get_bytes_avail( &ssl ) != 0 ) { printf( " ! ssl_read failed on cached data\n" ); ret = 1; diff --git a/tests/ssl-opt.sh b/tests/ssl-opt.sh index 724e2de25..9ec123c94 100755 --- a/tests/ssl-opt.sh +++ b/tests/ssl-opt.sh @@ -1352,6 +1352,19 @@ run_test "Per-version suites #4" \ 0 \ -c "Ciphersuite is TLS-RSA-WITH-AES-128-GCM-SHA256" +# Tests for ssl_get_bytes_avail() + +run_test "ssl_get_bytes_avail #1 (no extra data)" \ + "$P_SRV" \ + "$P_CLI request_size=100" \ + 0 \ + -s "Read from client: 100 bytes read$" + +run_test "ssl_get_bytes_avail #2 (extra data)" \ + "$P_SRV" \ + "$P_CLI request_size=500" \ + 0 \ + -s "Read from client: 500 bytes read (.*+.*)" # Final report From 8de259b9539d6936870780fd3ff6a768a749783d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Manuel=20P=C3=A9gouri=C3=A9-Gonnard?= Date: Wed, 11 Jun 2014 14:19:06 +0200 Subject: [PATCH 13/13] Minor code simplification in ssl programs --- programs/ssl/ssl_client2.c | 4 +--- programs/ssl/ssl_server2.c | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 06e4a16a4..8db6ddb77 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -458,11 +458,9 @@ int main( int argc, char *argv[] ) opt.psk_identity = q; else if( strcmp( p, "force_ciphersuite" ) == 0 ) { - opt.force_ciphersuite[0] = -1; - opt.force_ciphersuite[0] = ssl_get_ciphersuite_id( q ); - if( opt.force_ciphersuite[0] <= 0 ) + if( opt.force_ciphersuite[0] == 0 ) { ret = 2; goto usage; diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 8af5f6429..9f53ad287 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -736,11 +736,9 @@ int main( int argc, char *argv[] ) opt.psk_list = q; else if( strcmp( p, "force_ciphersuite" ) == 0 ) { - opt.force_ciphersuite[0] = -1; - opt.force_ciphersuite[0] = ssl_get_ciphersuite_id( q ); - if( opt.force_ciphersuite[0] <= 0 ) + if( opt.force_ciphersuite[0] == 0 ) { ret = 2; goto usage;