Make ssl ticket functions thread-safe
diff --git a/library/ssl_ticket.c b/library/ssl_ticket.c
index c1881b7..839e874 100644
--- a/library/ssl_ticket.c
+++ b/library/ssl_ticket.c
@@ -50,6 +50,10 @@
void mbedtls_ssl_ticket_init( mbedtls_ssl_ticket_context *ctx )
{
memset( ctx, 0, sizeof( mbedtls_ssl_ticket_context ) );
+
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_init( &ctx->mutex );
+#endif
}
/*
@@ -94,8 +98,6 @@
* 0 . n-1 session structure, n = sizeof(mbedtls_ssl_session)
* n . n+2 peer_cert length = m (0 if no certificate)
* n+3 . n+2+m peer cert ASN.1
- *
- * Assumes ticket is NULL (always true on server side).
*/
static int ssl_save_session( const mbedtls_ssl_session *session,
unsigned char *buf, size_t buf_len,
@@ -108,7 +110,7 @@
#endif /* MBEDTLS_X509_CRT_PARSE_C */
if( left < sizeof( mbedtls_ssl_session ) )
- return( -1 );
+ return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
memcpy( p, session, sizeof( mbedtls_ssl_session ) );
p += sizeof( mbedtls_ssl_session );
@@ -121,7 +123,7 @@
cert_len = session->peer_cert->raw.len;
if( left < 3 + cert_len )
- return( -1 );
+ return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
*p++ = (unsigned char)( cert_len >> 16 & 0xFF );
*p++ = (unsigned char)( cert_len >> 8 & 0xFF );
@@ -231,28 +233,36 @@
if( ctx == NULL )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
- *ticket_lifetime = ctx->ticket_lifetime;
-
/* We need at least 16 bytes for key_name, 16 for IV, 2 for len
* 16 for padding, 32 for MAC, in addition to session itself,
* that will be checked when writing it. */
if( end - start < 16 + 16 + 2 + 16 + 32 )
return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
+#if defined(MBEDTLS_THREADING_C)
+ if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
+ return( ret );
+#endif
+
+ *ticket_lifetime = ctx->ticket_lifetime;
+
/* Write key name */
memcpy( p, ctx->key_name, 16 );
p += 16;
/* Generate and write IV (with a copy for aes_crypt) */
if( ( ret = ctx->f_rng( ctx->p_rng, p, 16 ) ) != 0 )
- return( ret );
+ goto cleanup;
memcpy( iv, p, 16 );
p += 16;
/* Dump session state */
state = p + 2;
- if( ssl_save_session( session, state, end - state, &clear_len ) != 0 )
- return( MBEDTLS_ERR_SSL_BUFFER_TOO_SMALL );
+ if( ( ret = ssl_save_session( session,
+ state, end - state, &clear_len ) ) != 0 )
+ {
+ goto cleanup;
+ }
/* Apply PKCS padding */
pad_len = 16 - clear_len % 16;
@@ -264,7 +274,7 @@
if( ( ret = mbedtls_aes_crypt_cbc( &ctx->enc, MBEDTLS_AES_ENCRYPT,
enc_len, iv, state, state ) ) != 0 )
{
- return( ret );
+ goto cleanup;
}
/* Write length */
@@ -277,13 +287,19 @@
ctx->mac_key, 16,
start, p - start, p ) ) != 0 )
{
- return( ret );
+ goto cleanup;
}
p += 32;
*tlen = p - start;
- return( 0 );
+cleanup:
+#if defined(MBEDTLS_THREADING_C)
+ if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
+ return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
+#endif
+
+ return( ret );
}
/*
@@ -308,11 +324,19 @@
if( len < 34 || ctx == NULL )
return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+#if defined(MBEDTLS_THREADING_C)
+ if( ( ret = mbedtls_mutex_lock( &ctx->mutex ) ) != 0 )
+ return( ret );
+#endif
+
enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1];
mac = ticket + enc_len;
if( len != enc_len + 66 )
- return( MBEDTLS_ERR_SSL_BAD_INPUT_DATA );
+ {
+ ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
+ goto cleanup;
+ }
/* Check name, in constant time though it's not a big secret */
diff = 0;
@@ -325,7 +349,7 @@
ctx->mac_key, 16,
buf, len - 32, computed_mac ) ) != 0 )
{
- return( ret );
+ goto cleanup;
}
for( i = 0; i < 32; i++ )
@@ -334,13 +358,16 @@
/* Now return if ticket is not authentic, since we want to avoid
* decrypting arbitrary attacker-chosen data */
if( diff != 0 )
- return( MBEDTLS_ERR_SSL_INVALID_MAC );
+ {
+ ret = MBEDTLS_ERR_SSL_INVALID_MAC;
+ goto cleanup;
+ }
/* Decrypt */
if( ( ret = mbedtls_aes_crypt_cbc( &ctx->dec, MBEDTLS_AES_DECRYPT,
enc_len, iv, ticket, ticket ) ) != 0 )
{
- return( ret );
+ goto cleanup;
}
/* Check PKCS padding */
@@ -351,21 +378,30 @@
if( ticket[enc_len - i] != pad_len )
ret = MBEDTLS_ERR_SSL_BAD_INPUT_DATA;
if( ret != 0 )
- return( ret );
+ goto cleanup;
clear_len = enc_len - pad_len;
/* Actually load session */
if( ( ret = ssl_load_session( session, ticket, clear_len ) ) != 0 )
- return( ret );
+ goto cleanup;
#if defined(MBEDTLS_HAVE_TIME)
/* Check if still valid */
if( ( time( NULL) - session->start ) > ctx->ticket_lifetime )
- return( MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED );
+ {
+ ret = MBEDTLS_ERR_SSL_SESSION_TICKET_EXPIRED;
+ goto cleanup;
+ }
#endif
- return( 0 );
+cleanup:
+#if defined(MBEDTLS_THREADING_C)
+ if( mbedtls_mutex_unlock( &ctx->mutex ) != 0 )
+ return( MBEDTLS_ERR_THREADING_MUTEX_ERROR );
+#endif
+
+ return( ret );
}
/*
@@ -376,6 +412,10 @@
mbedtls_aes_free( &ctx->enc );
mbedtls_aes_free( &ctx->dec );
+#if defined(MBEDTLS_THREADING_C)
+ mbedtls_mutex_free( &ctx->mutex );
+#endif
+
mbedtls_zeroize( ctx, sizeof( mbedtls_ssl_ticket_context ) );
}