diff --git a/ChangeLog b/ChangeLog index 070e55eb2..dc008f8fb 100644 --- a/ChangeLog +++ b/ChangeLog @@ -22,6 +22,8 @@ Features from the default list (inactive by default). * Add server-side enforcement of sent renegotiation requests (ssl_set_renegotiation_enforced()) + * Add SSL_CIPHERSUITES config.h flag to allow specifying a list of + ciphersuites to use and save some memory if the list is small. Changes * Add LINK_WITH_PTHREAD option in CMake for explicit linking that is diff --git a/configs/config-ccm-psk-tls1_2.h b/configs/config-ccm-psk-tls1_2.h index f425391d0..1da9f6a6b 100644 --- a/configs/config-ccm-psk-tls1_2.h +++ b/configs/config-ccm-psk-tls1_2.h @@ -3,7 +3,7 @@ * Distinguishing features: * - no bignum, no PK, no X509 * - fully modern and secure (provided the pre-shared keys have high entropy) - * - very low record overhead if using the CCM-8 suites + * - very low record overhead with CCM-8 * - optimized for low RAM usage * * See README.txt for usage instructions. @@ -13,7 +13,7 @@ /* System support */ //#define POLARSSL_HAVE_IPV6 /* Optional */ -//#define POLARSSL_HAVE_TIME /* Optionnaly used in Hello messages */ +//#define POLARSSL_HAVE_TIME /* Optionally used in Hello messages */ /* Other POLARSSL_HAVE_XXX flags irrelevant for this configuration */ /* PolarSSL feature support */ @@ -36,6 +36,9 @@ /* Save RAM at the expense of ROM */ #define POLARSSL_AES_ROM_TABLES +/* Save some RAM by adjusting to your exact needs */ +#define POLARSSL_PSK_MAX_LEN 16 /* 128-bits keys are generally enough */ + /* * You should adjust this to the exact number of sources you're using: default * is the "platform_entropy_poll" source, but you may want to add other ones @@ -43,9 +46,17 @@ */ #define ENTROPY_MAX_SOURCES 2 +/* + * Use only CCM_8 ciphersuites, and + * save ROM and a few bytes of RAM by specifying our own ciphersuite list + */ +#define SSL_CIPHERSUITES \ + TLS_PSK_WITH_AES_256_CCM_8, \ + TLS_PSK_WITH_AES_128_CCM_8 + /* * Save RAM at the expense of interoperability: do this only if you control - * both ends of the connection! (See coments in "polarssl/ssl.h".) + * both ends of the connection! (See comments in "polarssl/ssl.h".) * The optimal size here depends on the typical size of records. */ #define SSL_MAX_CONTENT_LEN 512 diff --git a/configs/config-suite-b.h b/configs/config-suite-b.h index d10cf6320..cd38f3334 100644 --- a/configs/config-suite-b.h +++ b/configs/config-suite-b.h @@ -77,6 +77,11 @@ */ #define ENTROPY_MAX_SOURCES 2 +/* Save ROM and a few bytes of RAM by specifying our own ciphersuite list */ +#define SSL_CIPHERSUITES \ + TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, \ + TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 + /* * Save RAM at the expense of interoperability: do this only if you control * both ends of the connection! (See coments in "polarssl/ssl.h".) diff --git a/include/polarssl/config.h b/include/polarssl/config.h index bfd68c401..d43365ff5 100644 --- a/include/polarssl/config.h +++ b/include/polarssl/config.h @@ -2154,6 +2154,21 @@ /* SSL options */ //#define SSL_MAX_CONTENT_LEN 16384 /**< Size of the input / output buffer */ //#define SSL_DEFAULT_TICKET_LIFETIME 86400 /**< Lifetime of session tickets (if enabled) */ +//#define POLARSSL_PSK_MAX_LEN 32 /**< Max size of TLS pre-shared keys, in bytes (default 256 bits) */ + +/** + * Complete list of ciphersuites to use, in order of preference. + * + * \warning No dependency checking is done on that field! This option can only + * be used to restrict the set of available ciphersuites. It is your + * responsibility to make sure the needed modules are active. + * + * Use this to save a few hundred bytes of ROM (default ordering of all + * available ciphersuites) and a few to a few hundred bytes of RAM. + * + * The value below is only an example, not the default. + */ +//#define SSL_CIPHERSUITES TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 /* Debug options */ //#define POLARSSL_DEBUG_DFL_MODE POLARSSL_DEBUG_LOG_FULL /**< Default log: Full or Raw */ diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h index b90b232a5..730dc3937 100644 --- a/include/polarssl/ssl.h +++ b/include/polarssl/ssl.h @@ -34,6 +34,7 @@ #endif #include "net.h" #include "bignum.h" +#include "ecp.h" #include "ssl_ciphersuites.h" @@ -252,7 +253,9 @@ * Note: the RFC defines the default size of SSL / TLS messages. If you * change the value here, other clients / servers may not be able to * communicate with you anymore. Only change this value if you control - * both sides of the connection and have it reduced at both sides! + * both sides of the connection and have it reduced at both sides, or + * if you're using the Max Fragment Length extension and you know all your + * peers are using it too! */ #if !defined(SSL_MAX_CONTENT_LEN) #define SSL_MAX_CONTENT_LEN 16384 /**< Size of the input / output buffer */ @@ -261,8 +264,8 @@ /* \} name SECTION: Module settings */ /* - * Allow an extra 301 bytes for the record header and encryption overhead: - * counter (8) + header (5) + IV(16) + MAC (48) + padding (256) + * Allow extra bytes for record, authentication and encryption overhead: + * counter (8) + header (5) + IV(16) + MAC (16-48) + padding (0-256) * and allow for a maximum of 1024 of compression expansion if * enabled. */ @@ -272,8 +275,36 @@ #define SSL_COMPRESSION_ADD 0 #endif -#define SSL_BUFFER_LEN (SSL_MAX_CONTENT_LEN + SSL_COMPRESSION_ADD + 333) +#if defined(POLARSSL_RC4_C) || defined(POLARSSL_CIPHER_MODE_CBC) +/* Ciphersuites using HMAC */ +#if defined(POLARSSL_SHA512_C) +#define SSL_MAC_ADD 48 /* SHA-384 used for HMAC */ +#elif defined(POLARSSL_SHA256_C) +#define SSL_MAC_ADD 32 /* SHA-256 used for HMAC */ +#else +#define SSL_MAC_ADD 20 /* SHA-1 used for HMAC */ +#endif +#else +/* AEAD ciphersuites: GCM and CCM use a 128 bits tag */ +#define SSL_MAC_ADD 16 +#endif +#if defined(POLARSSL_CIPHER_MODE_CBC) +#define SSL_PADDING_ADD 256 +#else +#define SSL_PADDING_ADD 0 +#endif + +#define SSL_BUFFER_LEN ( SSL_MAX_CONTENT_LEN \ + + SSL_COMPRESSION_ADD \ + + 29 /* counter + header + IV */ \ + + SSL_MAC_ADD \ + + SSL_PADDING_ADD \ + ) + +/* + * Signaling ciphersuite values (SCSV) + */ #define SSL_EMPTY_RENEGOTIATION_INFO 0xFF /**< renegotiation info ext */ /* @@ -382,12 +413,43 @@ /* * Size defines */ -#if !defined(POLARSSL_MPI_MAX_SIZE) -#define POLARSSL_PREMASTER_SIZE 512 -#else -#define POLARSSL_PREMASTER_SIZE POLARSSL_MPI_MAX_SIZE +#if !defined(POLARSSL_PSK_MAX_LEN) +#define POLARSSL_PSK_MAX_LEN 32 /* 256 bits */ #endif +/* Dummy type used only for its size */ +union _ssl_premaster_secret +{ +#if defined(POLARSSL_KEY_EXCHANGE_RSA_ENABLED) + unsigned char _pms_rsa[48]; /* RFC 5246 8.1.1 */ +#endif +#if defined(POLARSSL_KEY_EXCHANGE_DHE_RSA_ENABLED) + unsigned char _pms_dhm[POLARSSL_MPI_MAX_SIZE]; /* RFC 5246 8.1.2 */ +#endif +#if defined(POLARSSL_KEY_EXCHANGE_ECDHE_RSA_ENABLED) || \ + defined(POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) || \ + defined(POLARSSL_KEY_EXCHANGE_ECDH_RSA_ENABLED) || \ + defined(POLARSSL_KEY_EXCHANGE_ECDH_ECDSA_ENABLED) + unsigned char _pms_ecdh[POLARSSL_ECP_MAX_BYTES]; /* RFC 4492 5.10 */ +#endif +#if defined(POLARSSL_KEY_EXCHANGE_PSK_ENABLED) + unsigned char _pms_psk[4 + 2 * POLARSSL_PSK_MAX_LEN]; /* RFC 4279 2 */ +#endif +#if defined(POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED) + unsigned char _pms_dhe_psk[4 + POLARSSL_MPI_MAX_SIZE + + POLARSSL_PSK_MAX_LEN]; /* RFC 4279 3 */ +#endif +#if defined(POLARSSL_KEY_EXCHANGE_RSA_PSK_ENABLED) + unsigned char _pms_rsa_psk[52 + POLARSSL_PSK_MAX_LEN]; /* RFC 4279 4 */ +#endif +#if defined(POLARSSL_KEY_EXCHANGE_DHE_PSK_ENABLED) + unsigned char _pms_ecdhe_psk[4 + POLARSSL_ECP_MAX_BYTES + + POLARSSL_PSK_MAX_LEN]; /* RFC 5489 2 */ +#endif +}; + +#define POLARSSL_PREMASTER_SIZE sizeof( union _ssl_premaster_secret ) + #ifdef __cplusplus extern "C" { #endif diff --git a/include/polarssl/ssl_ciphersuites.h b/include/polarssl/ssl_ciphersuites.h index 5ecd5febd..c4f1ffe64 100644 --- a/include/polarssl/ssl_ciphersuites.h +++ b/include/polarssl/ssl_ciphersuites.h @@ -233,6 +233,7 @@ extern "C" { #define TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 0xC0AE /**< TLS 1.2 */ #define TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 0xC0AF /**< TLS 1.2 */ +/* Reminder: update _ssl_premaster_secret when adding a new key exchange */ typedef enum { POLARSSL_KEY_EXCHANGE_NONE = 0, POLARSSL_KEY_EXCHANGE_RSA, diff --git a/library/ssl_ciphersuites.c b/library/ssl_ciphersuites.c index 608e26d2f..df838e260 100644 --- a/library/ssl_ciphersuites.c +++ b/library/ssl_ciphersuites.c @@ -57,6 +57,9 @@ */ static const int ciphersuite_preference[] = { +#if defined(SSL_CIPHERSUITES) + SSL_CIPHERSUITES, +#else /* All AES-256 ephemeral suites */ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, @@ -257,13 +260,10 @@ static const int ciphersuite_preference[] = TLS_PSK_WITH_NULL_SHA256, TLS_PSK_WITH_NULL_SHA, +#endif 0 }; -#define MAX_CIPHERSUITES 176 -static int supported_ciphersuites[MAX_CIPHERSUITES]; -static int supported_init = 0; - static const ssl_ciphersuite_t ciphersuite_definitions[] = { #if defined(POLARSSL_KEY_EXCHANGE_ECDHE_ECDSA_ENABLED) @@ -1679,6 +1679,17 @@ static const ssl_ciphersuite_t ciphersuite_definitions[] = { 0, "", 0, 0, 0, 0, 0, 0, 0, 0 } }; +#if defined(SSL_CIPHERSUITES) +const int *ssl_list_ciphersuites( void ) +{ + return( ciphersuite_preference ); +} +#else +#define MAX_CIPHERSUITES sizeof( ciphersuite_definitions ) / \ + sizeof( ciphersuite_definitions[0] ) +static int supported_ciphersuites[MAX_CIPHERSUITES]; +static int supported_init = 0; + const int *ssl_list_ciphersuites( void ) { /* @@ -1687,21 +1698,21 @@ const int *ssl_list_ciphersuites( void ) */ if( supported_init == 0 ) { - const int *p = ciphersuite_preference; - int *q = supported_ciphersuites; - size_t i; - size_t max = sizeof(supported_ciphersuites) / sizeof(int); + const int *p; + int *q; - for( i = 0; i < max - 1 && p[i] != 0; i++ ) + for( p = ciphersuite_preference, q = supported_ciphersuites; + *p != 0 && q < supported_ciphersuites + MAX_CIPHERSUITES - 1; + p++ ) { #if defined(POLARSSL_REMOVE_ARC4_CIPHERSUITES) const ssl_ciphersuite_t *cs_info; - if( ( cs_info = ssl_ciphersuite_from_id( p[i] ) ) != NULL && + if( ( cs_info = ssl_ciphersuite_from_id( *p ) ) != NULL && cs_info->cipher != POLARSSL_CIPHER_ARC4_128 ) #else - if( ssl_ciphersuite_from_id( p[i] ) != NULL ) + if( ssl_ciphersuite_from_id( *p ) != NULL ) #endif - *(q++) = p[i]; + *(q++) = *p; } *q = 0; @@ -1710,6 +1721,7 @@ const int *ssl_list_ciphersuites( void ) return( supported_ciphersuites ); }; +#endif /* SSL_CIPHERSUITES */ const ssl_ciphersuite_t *ssl_ciphersuite_from_string( const char *ciphersuite_name ) diff --git a/library/ssl_tls.c b/library/ssl_tls.c index 7c8f3064b..8040f9092 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -3747,12 +3747,7 @@ int ssl_set_psk( ssl_context *ssl, const unsigned char *psk, size_t psk_len, if( psk == NULL || psk_identity == NULL ) return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); - /* - * The length will be check later anyway, but in case it is obviously - * too large, better abort now. The PMS is as follows: - * other_len (2 bytes) + other + psk_len (2 bytes) + psk - */ - if( psk_len + 4 > POLARSSL_PREMASTER_SIZE ) + if( psk_len > POLARSSL_PSK_MAX_LEN ) return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); if( ssl->psk != NULL ) diff --git a/programs/ssl/ssl_client2.c b/programs/ssl/ssl_client2.c index 3af54f904..4682ee5bc 100644 --- a/programs/ssl/ssl_client2.c +++ b/programs/ssl/ssl_client2.c @@ -325,7 +325,7 @@ int main( int argc, char *argv[] ) int ret = 0, len, server_fd, i, written, frags; unsigned char buf[SSL_MAX_CONTENT_LEN + 1]; #if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED) - unsigned char psk[256]; + unsigned char psk[POLARSSL_PSK_MAX_LEN]; size_t psk_len = 0; #endif #if defined(POLARSSL_SSL_ALPN) diff --git a/programs/ssl/ssl_server2.c b/programs/ssl/ssl_server2.c index 9cb742b3f..c470363b4 100644 --- a/programs/ssl/ssl_server2.c +++ b/programs/ssl/ssl_server2.c @@ -127,8 +127,6 @@ int main( int argc, char *argv[] ) "
Successful connection using: %s
\r\n" // LONG_RESPONSE -#define MAX_PSK_LEN 256 - /* * Size of the basic I/O buffer. Able to hold our default response. * @@ -462,7 +460,7 @@ int unhexify( unsigned char *output, const char *input, size_t *olen ) size_t j; *olen = strlen( input ); - if( *olen % 2 != 0 || *olen / 2 > MAX_PSK_LEN ) + if( *olen % 2 != 0 || *olen / 2 > POLARSSL_PSK_MAX_LEN ) return( -1 ); *olen /= 2; @@ -486,7 +484,7 @@ struct _psk_entry { const char *name; size_t key_len; - unsigned char key[MAX_PSK_LEN]; + unsigned char key[POLARSSL_PSK_MAX_LEN]; psk_entry *next; }; @@ -575,7 +573,7 @@ int main( int argc, char *argv[] ) int version_suites[4][2]; unsigned char buf[IO_BUF_LEN]; #if defined(POLARSSL_KEY_EXCHANGE__SOME__PSK_ENABLED) - unsigned char psk[MAX_PSK_LEN]; + unsigned char psk[POLARSSL_PSK_MAX_LEN]; size_t psk_len = 0; psk_entry *psk_info = NULL; #endif diff --git a/tests/scripts/test-ref-configs.pl b/tests/scripts/test-ref-configs.pl index 9b09e3464..6546b05af 100755 --- a/tests/scripts/test-ref-configs.pl +++ b/tests/scripts/test-ref-configs.pl @@ -20,7 +20,7 @@ my %configs = ( 'config-picocoin.h' => 0, 'config-ccm-psk-tls1_2.h' - => '-m tls1_2 -f \'TLS-PSK.*AES.*CCM\'', + => '-m tls1_2 -f \'^TLS-PSK-WITH-AES-...-CCM-8\'', ); # If no config-name is provided, use all known configs.