diff --git a/include/polarssl/ssl.h b/include/polarssl/ssl.h index b51cc876c..6b5124db4 100644 --- a/include/polarssl/ssl.h +++ b/include/polarssl/ssl.h @@ -35,6 +35,7 @@ #include "sha1.h" #include "sha256.h" #include "sha512.h" +#include "aes.h" #include "ssl_ciphersuites.h" @@ -452,6 +453,8 @@ struct _ssl_handshake_params struct _ssl_ticket_keys { unsigned char key_name[16]; /*!< name to quickly discard bad tickets */ + aes_context enc; /*!< encryption context */ + aes_context dec; /*!< decryption context */ }; struct _ssl_context diff --git a/library/ssl_srv.c b/library/ssl_srv.c index 117830980..cbec7952b 100644 --- a/library/ssl_srv.c +++ b/library/ssl_srv.c @@ -161,36 +161,56 @@ static int ssl_load_session( ssl_session *session, */ static int ssl_write_ticket( ssl_context *ssl, size_t *tlen ) { + int ret; unsigned char * const start = ssl->out_msg + 10; unsigned char *p = start; - size_t clear_len, enc_len; + unsigned char *state; + unsigned char iv[16]; + size_t clear_len, enc_len, pad_len, i; if( ssl->ticket_keys == NULL ) return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); + /* Write key name */ memcpy( p, ssl->ticket_keys->key_name, 16 ); p += 16; - memset( p, 0, 16 ); // TODO: iv + /* Generate and write IV (with a copy for aes_crypt) */ + if( ( ret = ssl->f_rng( ssl->p_rng, p, 16 ) ) != 0 ) + return( ret ); + memcpy( iv, p, 16 ); p += 16; - ssl_save_session( ssl->session_negotiate, p + 2, &clear_len ); - SSL_DEBUG_BUF( 4, "session ticket cleartext", p, clear_len ); + /* Dump session state */ + state = p + 2; + ssl_save_session( ssl->session_negotiate, state, &clear_len ); + SSL_DEBUG_BUF( 3, "session ticket cleartext", state, clear_len ); - // TODO: encrypt ticket - enc_len = clear_len; - (void) enc_len; + /* Apply PKCS padding */ + pad_len = 16 - clear_len % 16; + enc_len = clear_len + pad_len; + for( i = clear_len; i < enc_len; i++ ) + state[i] = (unsigned char) pad_len; - *p++ = (unsigned char)( ( clear_len >> 8 ) & 0xFF ); - *p++ = (unsigned char)( ( clear_len ) & 0xFF ); - p += clear_len; + /* Encrypt */ + if( ( ret = aes_crypt_cbc( &ssl->ticket_keys->enc, AES_ENCRYPT, + enc_len, iv, state, state ) ) != 0 ) + { + return( ret ); + } - memset( p, 0, 32 ); // TODO: mac + /* Write length */ + *p++ = (unsigned char)( ( enc_len >> 8 ) & 0xFF ); + *p++ = (unsigned char)( ( enc_len ) & 0xFF ); + p = state + enc_len; + + /* Compute and write MAC */ + memset( p, 0, 32 ); p += 32; *tlen = p - start; - SSL_DEBUG_BUF( 4, "final session ticket", start, *tlen ); + SSL_DEBUG_BUF( 3, "session ticket structure", start, *tlen ); return( 0 ); } @@ -199,17 +219,20 @@ static int ssl_write_ticket( ssl_context *ssl, size_t *tlen ) * Load session ticket (see ssl_write_ticket for structure) */ static int ssl_parse_ticket( ssl_context *ssl, - const unsigned char *buf, + unsigned char *buf, size_t len ) { int ret; ssl_session session; - const unsigned char *key_name = buf; - const unsigned char *iv = buf + 16; - const unsigned char *enc_len_p = iv + 16; - const unsigned char *ticket = enc_len_p + 2; - const unsigned char *mac; - size_t enc_len, clear_len; + unsigned char *key_name = buf; + unsigned char *iv = buf + 16; + unsigned char *enc_len_p = iv + 16; + unsigned char *ticket = enc_len_p + 2; + unsigned char *mac; + size_t enc_len, clear_len, i; + unsigned char pad_len; + + SSL_DEBUG_BUF( 3, "session ticket structure", buf, len ); if( len < 34 || ssl->ticket_keys == NULL ) return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); @@ -220,15 +243,35 @@ static int ssl_parse_ticket( ssl_context *ssl, if( len != enc_len + 66 ) return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); + /* Check name */ if( memcmp( key_name, ssl->ticket_keys->key_name, 16 ) != 0 ) return( POLARSSL_ERR_SSL_BAD_INPUT_DATA ); // TODO: check hmac (void) mac; - // TODO: decrypt ticket - clear_len = enc_len; + /* Decrypt */ + if( ( ret = aes_crypt_cbc( &ssl->ticket_keys->dec, AES_DECRYPT, + enc_len, iv, ticket, ticket ) ) != 0 ) + { + return( ret ); + } + /* Check PKCS padding */ + pad_len = ticket[enc_len - 1]; + + ret = 0; + for( i = 2; i < pad_len; i++ ) + if( ticket[enc_len - i] != pad_len ) + ret = POLARSSL_ERR_SSL_BAD_INPUT_DATA; + if( ret != 0 ) + return( ret ); + + clear_len = enc_len - pad_len; + + SSL_DEBUG_BUF( 3, "session ticket cleartext", ticket, clear_len ); + + /* Actually load session */ if( ( ret = ssl_load_session( &session, ticket, clear_len ) ) != 0 ) { SSL_DEBUG_MSG( 1, ( "failed to parse ticket content" ) ); @@ -534,9 +577,11 @@ static int ssl_parse_truncated_hmac_ext( ssl_context *ssl, } static int ssl_parse_session_ticket_ext( ssl_context *ssl, - const unsigned char *buf, + unsigned char *buf, size_t len ) { + int ret; + if( ssl->session_tickets == SSL_SESSION_TICKETS_DISABLED ) return( 0 ); @@ -557,8 +602,11 @@ static int ssl_parse_session_ticket_ext( ssl_context *ssl, /* * Failures are ok: just ignore the ticket and proceed. */ - if( ssl_parse_ticket( ssl, buf, len ) != 0 ) + if( ( ret = ssl_parse_ticket( ssl, buf, len ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_parse_ticket", ret ); return( 0 ); + } SSL_DEBUG_MSG( 3, ( "session successfully restored from ticket" ) ); @@ -2438,7 +2486,11 @@ static int ssl_write_new_session_ticket( ssl_context *ssl ) ssl->out_msg[6] = 0x00; ssl->out_msg[7] = 0x00; - ssl_write_ticket( ssl, &tlen ); + if( ( ret = ssl_write_ticket( ssl, &tlen ) ) != 0 ) + { + SSL_DEBUG_RET( 1, "ssl_write_ticket", ret ); + tlen = 0; + } ssl->out_msg[8] = (unsigned char)( ( tlen >> 8 ) & 0xFF ); ssl->out_msg[9] = (unsigned char)( ( tlen ) & 0xFF ); diff --git a/library/ssl_tls.c b/library/ssl_tls.c index f4d6e2489..fb01c6c5a 100644 --- a/library/ssl_tls.c +++ b/library/ssl_tls.c @@ -2979,6 +2979,7 @@ static int ssl_ticket_keys_init( ssl_context *ssl ) { int ret; ssl_ticket_keys *tkeys; + unsigned char buf[32]; if( ssl->ticket_keys != NULL ) return( 0 ); @@ -2989,6 +2990,13 @@ static int ssl_ticket_keys_init( ssl_context *ssl ) if( ( ret = ssl->f_rng( ssl->p_rng, tkeys->key_name, 16 ) ) != 0 ) return( ret ); + if( ( ret = ssl->f_rng( ssl->p_rng, buf, 16 ) ) != 0 || + ( ret = aes_setkey_enc( &tkeys->enc, buf, 128 ) ) != 0 || + ( ret = aes_setkey_dec( &tkeys->dec, buf, 128 ) ) != 0 ) + { + return( ret ); + } + ssl->ticket_keys = tkeys; return( 0 );