Merge pull request #781 from mpg/cipher-auth-crypt-restricted
Fix buffer overflow with NIST-KW in cipher layer
This commit is contained in:
commit
3aae5d4ed7
6 changed files with 830 additions and 177 deletions
204
library/cipher.c
204
library/cipher.c
|
@ -1288,23 +1288,16 @@ int mbedtls_cipher_crypt( mbedtls_cipher_context_t *ctx,
|
|||
|
||||
#if defined(MBEDTLS_CIPHER_MODE_AEAD)
|
||||
/*
|
||||
* Packet-oriented encryption for AEAD modes
|
||||
* Packet-oriented encryption for AEAD modes: internal function shared by
|
||||
* mbedtls_cipher_auth_encrypt() and mbedtls_cipher_auth_encrypt_ext().
|
||||
*/
|
||||
int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx,
|
||||
static int mbedtls_cipher_aead_encrypt( mbedtls_cipher_context_t *ctx,
|
||||
const unsigned char *iv, size_t iv_len,
|
||||
const unsigned char *ad, size_t ad_len,
|
||||
const unsigned char *input, size_t ilen,
|
||||
unsigned char *output, size_t *olen,
|
||||
unsigned char *tag, size_t tag_len )
|
||||
{
|
||||
CIPHER_VALIDATE_RET( ctx != NULL );
|
||||
CIPHER_VALIDATE_RET( iv != NULL );
|
||||
CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL );
|
||||
CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
|
||||
CIPHER_VALIDATE_RET( output != NULL );
|
||||
CIPHER_VALIDATE_RET( olen != NULL );
|
||||
CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL );
|
||||
|
||||
#if defined(MBEDTLS_USE_PSA_CRYPTO)
|
||||
if( ctx->psa_enabled == 1 )
|
||||
{
|
||||
|
@ -1320,7 +1313,7 @@ int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx,
|
|||
|
||||
/* PSA Crypto API always writes the authentication tag
|
||||
* at the end of the encrypted message. */
|
||||
if( tag != output + ilen )
|
||||
if( output == NULL || tag != output + ilen )
|
||||
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
|
||||
|
||||
status = psa_aead_encrypt( cipher_psa->slot,
|
||||
|
@ -1370,44 +1363,21 @@ int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx,
|
|||
ilen, iv, ad, ad_len, input, output, tag ) );
|
||||
}
|
||||
#endif /* MBEDTLS_CHACHAPOLY_C */
|
||||
#if defined(MBEDTLS_NIST_KW_C)
|
||||
if( MBEDTLS_MODE_KW == ctx->cipher_info->mode ||
|
||||
MBEDTLS_MODE_KWP == ctx->cipher_info->mode )
|
||||
{
|
||||
mbedtls_nist_kw_mode_t mode = ( MBEDTLS_MODE_KW == ctx->cipher_info->mode ) ?
|
||||
MBEDTLS_KW_MODE_KW : MBEDTLS_KW_MODE_KWP;
|
||||
|
||||
/* There is no iv, tag or ad associated with KW and KWP, these length should be 0 */
|
||||
if( iv_len != 0 || tag_len != 0 || ad_len != 0 )
|
||||
{
|
||||
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
|
||||
}
|
||||
|
||||
return( mbedtls_nist_kw_wrap( ctx->cipher_ctx, mode, input, ilen, output, olen, SIZE_MAX ) );
|
||||
}
|
||||
#endif /* MBEDTLS_NIST_KW_C */
|
||||
|
||||
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
|
||||
}
|
||||
|
||||
/*
|
||||
* Packet-oriented decryption for AEAD modes
|
||||
* Packet-oriented encryption for AEAD modes: internal function shared by
|
||||
* mbedtls_cipher_auth_encrypt() and mbedtls_cipher_auth_encrypt_ext().
|
||||
*/
|
||||
int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx,
|
||||
static int mbedtls_cipher_aead_decrypt( mbedtls_cipher_context_t *ctx,
|
||||
const unsigned char *iv, size_t iv_len,
|
||||
const unsigned char *ad, size_t ad_len,
|
||||
const unsigned char *input, size_t ilen,
|
||||
unsigned char *output, size_t *olen,
|
||||
const unsigned char *tag, size_t tag_len )
|
||||
{
|
||||
CIPHER_VALIDATE_RET( ctx != NULL );
|
||||
CIPHER_VALIDATE_RET( iv != NULL );
|
||||
CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL );
|
||||
CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
|
||||
CIPHER_VALIDATE_RET( output != NULL );
|
||||
CIPHER_VALIDATE_RET( olen != NULL );
|
||||
CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL );
|
||||
|
||||
#if defined(MBEDTLS_USE_PSA_CRYPTO)
|
||||
if( ctx->psa_enabled == 1 )
|
||||
{
|
||||
|
@ -1423,7 +1393,7 @@ int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx,
|
|||
|
||||
/* PSA Crypto API always writes the authentication tag
|
||||
* at the end of the encrypted message. */
|
||||
if( tag != input + ilen )
|
||||
if( input == NULL || tag != input + ilen )
|
||||
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
|
||||
|
||||
status = psa_aead_decrypt( cipher_psa->slot,
|
||||
|
@ -1495,25 +1465,169 @@ int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx,
|
|||
return( ret );
|
||||
}
|
||||
#endif /* MBEDTLS_CHACHAPOLY_C */
|
||||
|
||||
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
|
||||
}
|
||||
|
||||
#if !defined(MBEDTLS_DEPRECATED_REMOVED)
|
||||
/*
|
||||
* Packet-oriented encryption for AEAD modes: public legacy function.
|
||||
*/
|
||||
int mbedtls_cipher_auth_encrypt( mbedtls_cipher_context_t *ctx,
|
||||
const unsigned char *iv, size_t iv_len,
|
||||
const unsigned char *ad, size_t ad_len,
|
||||
const unsigned char *input, size_t ilen,
|
||||
unsigned char *output, size_t *olen,
|
||||
unsigned char *tag, size_t tag_len )
|
||||
{
|
||||
CIPHER_VALIDATE_RET( ctx != NULL );
|
||||
CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL );
|
||||
CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL );
|
||||
CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
|
||||
CIPHER_VALIDATE_RET( ilen == 0 || output != NULL );
|
||||
CIPHER_VALIDATE_RET( olen != NULL );
|
||||
CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL );
|
||||
|
||||
return( mbedtls_cipher_aead_encrypt( ctx, iv, iv_len, ad, ad_len,
|
||||
input, ilen, output, olen,
|
||||
tag, tag_len ) );
|
||||
}
|
||||
|
||||
/*
|
||||
* Packet-oriented decryption for AEAD modes: public legacy function.
|
||||
*/
|
||||
int mbedtls_cipher_auth_decrypt( mbedtls_cipher_context_t *ctx,
|
||||
const unsigned char *iv, size_t iv_len,
|
||||
const unsigned char *ad, size_t ad_len,
|
||||
const unsigned char *input, size_t ilen,
|
||||
unsigned char *output, size_t *olen,
|
||||
const unsigned char *tag, size_t tag_len )
|
||||
{
|
||||
CIPHER_VALIDATE_RET( ctx != NULL );
|
||||
CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL );
|
||||
CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL );
|
||||
CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
|
||||
CIPHER_VALIDATE_RET( ilen == 0 || output != NULL );
|
||||
CIPHER_VALIDATE_RET( olen != NULL );
|
||||
CIPHER_VALIDATE_RET( tag_len == 0 || tag != NULL );
|
||||
|
||||
return( mbedtls_cipher_aead_decrypt( ctx, iv, iv_len, ad, ad_len,
|
||||
input, ilen, output, olen,
|
||||
tag, tag_len ) );
|
||||
}
|
||||
#endif /* !MBEDTLS_DEPRECATED_REMOVED */
|
||||
#endif /* MBEDTLS_CIPHER_MODE_AEAD */
|
||||
|
||||
#if defined(MBEDTLS_CIPHER_MODE_AEAD) || defined(MBEDTLS_NIST_KW_C)
|
||||
/*
|
||||
* Packet-oriented encryption for AEAD/NIST_KW: public function.
|
||||
*/
|
||||
int mbedtls_cipher_auth_encrypt_ext( mbedtls_cipher_context_t *ctx,
|
||||
const unsigned char *iv, size_t iv_len,
|
||||
const unsigned char *ad, size_t ad_len,
|
||||
const unsigned char *input, size_t ilen,
|
||||
unsigned char *output, size_t output_len,
|
||||
size_t *olen, size_t tag_len )
|
||||
{
|
||||
CIPHER_VALIDATE_RET( ctx != NULL );
|
||||
CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL );
|
||||
CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL );
|
||||
CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
|
||||
CIPHER_VALIDATE_RET( output != NULL );
|
||||
CIPHER_VALIDATE_RET( olen != NULL );
|
||||
|
||||
#if defined(MBEDTLS_NIST_KW_C)
|
||||
if( MBEDTLS_MODE_KW == ctx->cipher_info->mode ||
|
||||
MBEDTLS_MODE_KWP == ctx->cipher_info->mode )
|
||||
if(
|
||||
#if defined(MBEDTLS_USE_PSA_CRYPTO)
|
||||
ctx->psa_enabled == 0 &&
|
||||
#endif
|
||||
( MBEDTLS_MODE_KW == ctx->cipher_info->mode ||
|
||||
MBEDTLS_MODE_KWP == ctx->cipher_info->mode ) )
|
||||
{
|
||||
mbedtls_nist_kw_mode_t mode = ( MBEDTLS_MODE_KW == ctx->cipher_info->mode ) ?
|
||||
MBEDTLS_KW_MODE_KW : MBEDTLS_KW_MODE_KWP;
|
||||
|
||||
/* There is no iv, tag or ad associated with KW and KWP, these length should be 0 */
|
||||
/* There is no iv, tag or ad associated with KW and KWP,
|
||||
* so these length should be 0 as documented. */
|
||||
if( iv_len != 0 || tag_len != 0 || ad_len != 0 )
|
||||
{
|
||||
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
|
||||
}
|
||||
|
||||
return( mbedtls_nist_kw_unwrap( ctx->cipher_ctx, mode, input, ilen, output, olen, SIZE_MAX ) );
|
||||
(void) iv;
|
||||
(void) ad;
|
||||
|
||||
return( mbedtls_nist_kw_wrap( ctx->cipher_ctx, mode, input, ilen,
|
||||
output, olen, output_len ) );
|
||||
}
|
||||
#endif /* MBEDTLS_NIST_KW_C */
|
||||
|
||||
#if defined(MBEDTLS_CIPHER_MODE_AEAD)
|
||||
/* AEAD case: check length before passing on to shared function */
|
||||
if( output_len < ilen + tag_len )
|
||||
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
|
||||
|
||||
int ret = mbedtls_cipher_aead_encrypt( ctx, iv, iv_len, ad, ad_len,
|
||||
input, ilen, output, olen,
|
||||
output + ilen, tag_len );
|
||||
*olen += tag_len;
|
||||
return( ret );
|
||||
#else
|
||||
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
|
||||
}
|
||||
#endif /* MBEDTLS_CIPHER_MODE_AEAD */
|
||||
}
|
||||
|
||||
/*
|
||||
* Packet-oriented decryption for AEAD/NIST_KW: public function.
|
||||
*/
|
||||
int mbedtls_cipher_auth_decrypt_ext( mbedtls_cipher_context_t *ctx,
|
||||
const unsigned char *iv, size_t iv_len,
|
||||
const unsigned char *ad, size_t ad_len,
|
||||
const unsigned char *input, size_t ilen,
|
||||
unsigned char *output, size_t output_len,
|
||||
size_t *olen, size_t tag_len )
|
||||
{
|
||||
CIPHER_VALIDATE_RET( ctx != NULL );
|
||||
CIPHER_VALIDATE_RET( iv_len == 0 || iv != NULL );
|
||||
CIPHER_VALIDATE_RET( ad_len == 0 || ad != NULL );
|
||||
CIPHER_VALIDATE_RET( ilen == 0 || input != NULL );
|
||||
CIPHER_VALIDATE_RET( output_len == 0 || output != NULL );
|
||||
CIPHER_VALIDATE_RET( olen != NULL );
|
||||
|
||||
#if defined(MBEDTLS_NIST_KW_C)
|
||||
if(
|
||||
#if defined(MBEDTLS_USE_PSA_CRYPTO)
|
||||
ctx->psa_enabled == 0 &&
|
||||
#endif
|
||||
( MBEDTLS_MODE_KW == ctx->cipher_info->mode ||
|
||||
MBEDTLS_MODE_KWP == ctx->cipher_info->mode ) )
|
||||
{
|
||||
mbedtls_nist_kw_mode_t mode = ( MBEDTLS_MODE_KW == ctx->cipher_info->mode ) ?
|
||||
MBEDTLS_KW_MODE_KW : MBEDTLS_KW_MODE_KWP;
|
||||
|
||||
/* There is no iv, tag or ad associated with KW and KWP,
|
||||
* so these length should be 0 as documented. */
|
||||
if( iv_len != 0 || tag_len != 0 || ad_len != 0 )
|
||||
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
|
||||
|
||||
(void) iv;
|
||||
(void) ad;
|
||||
|
||||
return( mbedtls_nist_kw_unwrap( ctx->cipher_ctx, mode, input, ilen,
|
||||
output, olen, output_len ) );
|
||||
}
|
||||
#endif /* MBEDTLS_NIST_KW_C */
|
||||
|
||||
#if defined(MBEDTLS_CIPHER_MODE_AEAD)
|
||||
/* AEAD case: check length before passing on to shared function */
|
||||
if( ilen < tag_len || output_len < ilen - tag_len )
|
||||
return( MBEDTLS_ERR_CIPHER_BAD_INPUT_DATA );
|
||||
|
||||
return( mbedtls_cipher_aead_decrypt( ctx, iv, iv_len, ad, ad_len,
|
||||
input, ilen - tag_len, output, olen,
|
||||
input + ilen - tag_len, tag_len ) );
|
||||
#else
|
||||
return( MBEDTLS_ERR_CIPHER_FEATURE_UNAVAILABLE );
|
||||
#endif /* MBEDTLS_CIPHER_MODE_AEAD */
|
||||
}
|
||||
#endif /* MBEDTLS_CIPHER_MODE_AEAD || MBEDTLS_NIST_KW_C */
|
||||
|
||||
#endif /* MBEDTLS_CIPHER_C */
|
||||
|
|
|
@ -850,20 +850,21 @@ int mbedtls_ssl_encrypt_buf( mbedtls_ssl_context *ssl,
|
|||
* Encrypt and authenticate
|
||||
*/
|
||||
|
||||
if( ( ret = mbedtls_cipher_auth_encrypt( &transform->cipher_ctx_enc,
|
||||
if( ( ret = mbedtls_cipher_auth_encrypt_ext( &transform->cipher_ctx_enc,
|
||||
iv, transform->ivlen,
|
||||
add_data, add_data_len, /* add data */
|
||||
data, rec->data_len, /* source */
|
||||
data, &rec->data_len, /* destination */
|
||||
data + rec->data_len, transform->taglen ) ) != 0 )
|
||||
add_data, add_data_len,
|
||||
data, rec->data_len, /* src */
|
||||
data, rec->buf_len - (data - rec->buf), /* dst */
|
||||
&rec->data_len,
|
||||
transform->taglen ) ) != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_auth_encrypt", ret );
|
||||
return( ret );
|
||||
}
|
||||
MBEDTLS_SSL_DEBUG_BUF( 4, "after encrypt: tag",
|
||||
data + rec->data_len, transform->taglen );
|
||||
data + rec->data_len - transform->taglen,
|
||||
transform->taglen );
|
||||
/* Account for authentication tag. */
|
||||
rec->data_len += transform->taglen;
|
||||
post_avail -= transform->taglen;
|
||||
|
||||
/*
|
||||
|
@ -1422,12 +1423,11 @@ int mbedtls_ssl_decrypt_buf( mbedtls_ssl_context const *ssl,
|
|||
/*
|
||||
* Decrypt and authenticate
|
||||
*/
|
||||
if( ( ret = mbedtls_cipher_auth_decrypt( &transform->cipher_ctx_dec,
|
||||
if( ( ret = mbedtls_cipher_auth_decrypt_ext( &transform->cipher_ctx_dec,
|
||||
iv, transform->ivlen,
|
||||
add_data, add_data_len,
|
||||
data, rec->data_len,
|
||||
data, &olen,
|
||||
data + rec->data_len,
|
||||
data, rec->data_len + transform->taglen, /* src */
|
||||
data, rec->buf_len - (data - rec->buf), &olen, /* dst */
|
||||
transform->taglen ) ) != 0 )
|
||||
{
|
||||
MBEDTLS_SSL_DEBUG_RET( 1, "mbedtls_cipher_auth_decrypt", ret );
|
||||
|
|
|
@ -209,7 +209,6 @@ int mbedtls_ssl_ticket_write( void *p_ticket,
|
|||
unsigned char *iv = start + TICKET_KEY_NAME_BYTES;
|
||||
unsigned char *state_len_bytes = iv + TICKET_IV_BYTES;
|
||||
unsigned char *state = state_len_bytes + TICKET_CRYPT_LEN_BYTES;
|
||||
unsigned char *tag;
|
||||
size_t clear_len, ciph_len;
|
||||
|
||||
*tlen = 0;
|
||||
|
@ -250,23 +249,23 @@ int mbedtls_ssl_ticket_write( void *p_ticket,
|
|||
state_len_bytes[1] = ( clear_len ) & 0xff;
|
||||
|
||||
/* Encrypt and authenticate */
|
||||
tag = state + clear_len;
|
||||
if( ( ret = mbedtls_cipher_auth_encrypt( &key->ctx,
|
||||
if( ( ret = mbedtls_cipher_auth_encrypt_ext( &key->ctx,
|
||||
iv, TICKET_IV_BYTES,
|
||||
/* Additional data: key name, IV and length */
|
||||
key_name, TICKET_ADD_DATA_LEN,
|
||||
state, clear_len, state, &ciph_len,
|
||||
tag, TICKET_AUTH_TAG_BYTES ) ) != 0 )
|
||||
state, clear_len,
|
||||
state, end - state, &ciph_len,
|
||||
TICKET_AUTH_TAG_BYTES ) ) != 0 )
|
||||
{
|
||||
goto cleanup;
|
||||
}
|
||||
if( ciph_len != clear_len )
|
||||
if( ciph_len != clear_len + TICKET_AUTH_TAG_BYTES )
|
||||
{
|
||||
ret = MBEDTLS_ERR_SSL_INTERNAL_ERROR;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
*tlen = TICKET_MIN_LEN + ciph_len;
|
||||
*tlen = TICKET_MIN_LEN + ciph_len - TICKET_AUTH_TAG_BYTES;
|
||||
|
||||
cleanup:
|
||||
#if defined(MBEDTLS_THREADING_C)
|
||||
|
@ -308,7 +307,6 @@ int mbedtls_ssl_ticket_parse( void *p_ticket,
|
|||
unsigned char *iv = buf + TICKET_KEY_NAME_BYTES;
|
||||
unsigned char *enc_len_p = iv + TICKET_IV_BYTES;
|
||||
unsigned char *ticket = enc_len_p + TICKET_CRYPT_LEN_BYTES;
|
||||
unsigned char *tag;
|
||||
size_t enc_len, clear_len;
|
||||
|
||||
if( ctx == NULL || ctx->f_rng == NULL )
|
||||
|
@ -326,7 +324,6 @@ int mbedtls_ssl_ticket_parse( void *p_ticket,
|
|||
goto cleanup;
|
||||
|
||||
enc_len = ( enc_len_p[0] << 8 ) | enc_len_p[1];
|
||||
tag = ticket + enc_len;
|
||||
|
||||
if( len != TICKET_MIN_LEN + enc_len )
|
||||
{
|
||||
|
@ -344,13 +341,13 @@ int mbedtls_ssl_ticket_parse( void *p_ticket,
|
|||
}
|
||||
|
||||
/* Decrypt and authenticate */
|
||||
if( ( ret = mbedtls_cipher_auth_decrypt( &key->ctx,
|
||||
if( ( ret = mbedtls_cipher_auth_decrypt_ext( &key->ctx,
|
||||
iv, TICKET_IV_BYTES,
|
||||
/* Additional data: key name, IV and length */
|
||||
key_name, TICKET_ADD_DATA_LEN,
|
||||
ticket, enc_len,
|
||||
ticket, &clear_len,
|
||||
tag, TICKET_AUTH_TAG_BYTES ) ) != 0 )
|
||||
ticket, enc_len + TICKET_AUTH_TAG_BYTES,
|
||||
ticket, enc_len, &clear_len,
|
||||
TICKET_AUTH_TAG_BYTES ) ) != 0 )
|
||||
{
|
||||
if( ret == MBEDTLS_ERR_CIPHER_AUTH_FAILED )
|
||||
ret = MBEDTLS_ERR_SSL_INVALID_MAC;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue