mirror of
https://github.com/yuzu-emu/mbedtls.git
synced 2024-11-30 02:44:20 +01:00
Move mbedtls_cf_rsaes_pkcs1_v15_unpadding function to the constant-time module
Signed-off-by: Gabor Mezei <gabor.mezei@arm.com>
This commit is contained in:
parent
c2aee6fc0b
commit
f52941ef73
@ -29,6 +29,7 @@
|
|||||||
#include "mbedtls/ssl_internal.h"
|
#include "mbedtls/ssl_internal.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
/* constant-time buffer comparison */
|
/* constant-time buffer comparison */
|
||||||
int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n )
|
int mbedtls_ssl_safer_memcmp( const void *a, const void *b, size_t n )
|
||||||
@ -710,3 +711,152 @@ int mbedtls_mpi_lt_mpi_ct( const mbedtls_mpi *X, const mbedtls_mpi *Y,
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endif /* MBEDTLS_BIGNUM_C */
|
#endif /* MBEDTLS_BIGNUM_C */
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
|
||||||
|
|
||||||
|
int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode,
|
||||||
|
size_t ilen,
|
||||||
|
size_t *olen,
|
||||||
|
unsigned char *output,
|
||||||
|
size_t output_max_len,
|
||||||
|
unsigned char *buf )
|
||||||
|
{
|
||||||
|
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
||||||
|
size_t i, plaintext_max_size;
|
||||||
|
|
||||||
|
/* The following variables take sensitive values: their value must
|
||||||
|
* not leak into the observable behavior of the function other than
|
||||||
|
* the designated outputs (output, olen, return value). Otherwise
|
||||||
|
* this would open the execution of the function to
|
||||||
|
* side-channel-based variants of the Bleichenbacher padding oracle
|
||||||
|
* attack. Potential side channels include overall timing, memory
|
||||||
|
* access patterns (especially visible to an adversary who has access
|
||||||
|
* to a shared memory cache), and branches (especially visible to
|
||||||
|
* an adversary who has access to a shared code cache or to a shared
|
||||||
|
* branch predictor). */
|
||||||
|
size_t pad_count = 0;
|
||||||
|
unsigned bad = 0;
|
||||||
|
unsigned char pad_done = 0;
|
||||||
|
size_t plaintext_size = 0;
|
||||||
|
unsigned output_too_large;
|
||||||
|
|
||||||
|
plaintext_max_size = mbedtls_cf_size_if( output_max_len > ilen - 11,
|
||||||
|
ilen - 11,
|
||||||
|
output_max_len );
|
||||||
|
|
||||||
|
/* Check and get padding length in constant time and constant
|
||||||
|
* memory trace. The first byte must be 0. */
|
||||||
|
bad |= buf[0];
|
||||||
|
|
||||||
|
if( mode == MBEDTLS_RSA_PRIVATE )
|
||||||
|
{
|
||||||
|
/* Decode EME-PKCS1-v1_5 padding: 0x00 || 0x02 || PS || 0x00
|
||||||
|
* where PS must be at least 8 nonzero bytes. */
|
||||||
|
bad |= buf[1] ^ MBEDTLS_RSA_CRYPT;
|
||||||
|
|
||||||
|
/* Read the whole buffer. Set pad_done to nonzero if we find
|
||||||
|
* the 0x00 byte and remember the padding length in pad_count. */
|
||||||
|
for( i = 2; i < ilen; i++ )
|
||||||
|
{
|
||||||
|
pad_done |= ((buf[i] | (unsigned char)-buf[i]) >> 7) ^ 1;
|
||||||
|
pad_count += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Decode EMSA-PKCS1-v1_5 padding: 0x00 || 0x01 || PS || 0x00
|
||||||
|
* where PS must be at least 8 bytes with the value 0xFF. */
|
||||||
|
bad |= buf[1] ^ MBEDTLS_RSA_SIGN;
|
||||||
|
|
||||||
|
/* Read the whole buffer. Set pad_done to nonzero if we find
|
||||||
|
* the 0x00 byte and remember the padding length in pad_count.
|
||||||
|
* If there's a non-0xff byte in the padding, the padding is bad. */
|
||||||
|
for( i = 2; i < ilen; i++ )
|
||||||
|
{
|
||||||
|
pad_done |= mbedtls_cf_uint_if( buf[i], 0, 1 );
|
||||||
|
pad_count += mbedtls_cf_uint_if( pad_done, 0, 1 );
|
||||||
|
bad |= mbedtls_cf_uint_if( pad_done, 0, buf[i] ^ 0xFF );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If pad_done is still zero, there's no data, only unfinished padding. */
|
||||||
|
bad |= mbedtls_cf_uint_if( pad_done, 0, 1 );
|
||||||
|
|
||||||
|
/* There must be at least 8 bytes of padding. */
|
||||||
|
bad |= mbedtls_cf_size_gt( 8, pad_count );
|
||||||
|
|
||||||
|
/* If the padding is valid, set plaintext_size to the number of
|
||||||
|
* remaining bytes after stripping the padding. If the padding
|
||||||
|
* is invalid, avoid leaking this fact through the size of the
|
||||||
|
* output: use the maximum message size that fits in the output
|
||||||
|
* buffer. Do it without branches to avoid leaking the padding
|
||||||
|
* validity through timing. RSA keys are small enough that all the
|
||||||
|
* size_t values involved fit in unsigned int. */
|
||||||
|
plaintext_size = mbedtls_cf_uint_if(
|
||||||
|
bad, (unsigned) plaintext_max_size,
|
||||||
|
(unsigned) ( ilen - pad_count - 3 ) );
|
||||||
|
|
||||||
|
/* Set output_too_large to 0 if the plaintext fits in the output
|
||||||
|
* buffer and to 1 otherwise. */
|
||||||
|
output_too_large = mbedtls_cf_size_gt( plaintext_size,
|
||||||
|
plaintext_max_size );
|
||||||
|
|
||||||
|
/* Set ret without branches to avoid timing attacks. Return:
|
||||||
|
* - INVALID_PADDING if the padding is bad (bad != 0).
|
||||||
|
* - OUTPUT_TOO_LARGE if the padding is good but the decrypted
|
||||||
|
* plaintext does not fit in the output buffer.
|
||||||
|
* - 0 if the padding is correct. */
|
||||||
|
ret = - (int) mbedtls_cf_uint_if(
|
||||||
|
bad, - MBEDTLS_ERR_RSA_INVALID_PADDING,
|
||||||
|
mbedtls_cf_uint_if( output_too_large,
|
||||||
|
- MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE,
|
||||||
|
0 ) );
|
||||||
|
|
||||||
|
/* If the padding is bad or the plaintext is too large, zero the
|
||||||
|
* data that we're about to copy to the output buffer.
|
||||||
|
* We need to copy the same amount of data
|
||||||
|
* from the same buffer whether the padding is good or not to
|
||||||
|
* avoid leaking the padding validity through overall timing or
|
||||||
|
* through memory or cache access patterns. */
|
||||||
|
bad = mbedtls_cf_uint_mask( bad | output_too_large );
|
||||||
|
for( i = 11; i < ilen; i++ )
|
||||||
|
buf[i] &= ~bad;
|
||||||
|
|
||||||
|
/* If the plaintext is too large, truncate it to the buffer size.
|
||||||
|
* Copy anyway to avoid revealing the length through timing, because
|
||||||
|
* revealing the length is as bad as revealing the padding validity
|
||||||
|
* for a Bleichenbacher attack. */
|
||||||
|
plaintext_size = mbedtls_cf_uint_if( output_too_large,
|
||||||
|
(unsigned) plaintext_max_size,
|
||||||
|
(unsigned) plaintext_size );
|
||||||
|
|
||||||
|
/* Move the plaintext to the leftmost position where it can start in
|
||||||
|
* the working buffer, i.e. make it start plaintext_max_size from
|
||||||
|
* the end of the buffer. Do this with a memory access trace that
|
||||||
|
* does not depend on the plaintext size. After this move, the
|
||||||
|
* starting location of the plaintext is no longer sensitive
|
||||||
|
* information. */
|
||||||
|
mbedtls_cf_mem_move_to_left( buf + ilen - plaintext_max_size,
|
||||||
|
plaintext_max_size,
|
||||||
|
plaintext_max_size - plaintext_size );
|
||||||
|
|
||||||
|
/* Finally copy the decrypted plaintext plus trailing zeros into the output
|
||||||
|
* buffer. If output_max_len is 0, then output may be an invalid pointer
|
||||||
|
* and the result of memcpy() would be undefined; prevent undefined
|
||||||
|
* behavior making sure to depend only on output_max_len (the size of the
|
||||||
|
* user-provided output buffer), which is independent from plaintext
|
||||||
|
* length, validity of padding, success of the decryption, and other
|
||||||
|
* secrets. */
|
||||||
|
if( output_max_len != 0 )
|
||||||
|
memcpy( output, buf + ilen - plaintext_max_size, plaintext_max_size );
|
||||||
|
|
||||||
|
/* Report the amount of data we copied to the output buffer. In case
|
||||||
|
* of errors (bad padding or output too large), the value of *olen
|
||||||
|
* when this function returns is not specified. Making it equivalent
|
||||||
|
* to the good case limits the risks of leaking the padding validity. */
|
||||||
|
*olen = plaintext_size;
|
||||||
|
|
||||||
|
return( ret );
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */
|
||||||
|
@ -148,3 +148,14 @@ int mbedtls_ssl_cf_hmac(
|
|||||||
unsigned char *output );
|
unsigned char *output );
|
||||||
|
|
||||||
#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
|
#endif /* MBEDTLS_SSL_SOME_SUITES_USE_TLS_CBC */
|
||||||
|
|
||||||
|
#if defined(MBEDTLS_PKCS1_V15) && defined(MBEDTLS_RSA_C) && !defined(MBEDTLS_RSA_ALT)
|
||||||
|
|
||||||
|
int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode,
|
||||||
|
size_t ilen,
|
||||||
|
size_t *olen,
|
||||||
|
unsigned char *output,
|
||||||
|
size_t output_max_len,
|
||||||
|
unsigned char *buf );
|
||||||
|
|
||||||
|
#endif /* MBEDTLS_PKCS1_V15 && MBEDTLS_RSA_C && ! MBEDTLS_RSA_ALT */
|
||||||
|
145
library/rsa.c
145
library/rsa.c
@ -1479,151 +1479,6 @@ cleanup:
|
|||||||
#endif /* MBEDTLS_PKCS1_V21 */
|
#endif /* MBEDTLS_PKCS1_V21 */
|
||||||
|
|
||||||
#if defined(MBEDTLS_PKCS1_V15)
|
#if defined(MBEDTLS_PKCS1_V15)
|
||||||
int mbedtls_cf_rsaes_pkcs1_v15_unpadding( int mode,
|
|
||||||
size_t ilen,
|
|
||||||
size_t *olen,
|
|
||||||
unsigned char *output,
|
|
||||||
size_t output_max_len,
|
|
||||||
unsigned char *buf )
|
|
||||||
{
|
|
||||||
int ret = MBEDTLS_ERR_ERROR_CORRUPTION_DETECTED;
|
|
||||||
size_t i, plaintext_max_size;
|
|
||||||
|
|
||||||
/* The following variables take sensitive values: their value must
|
|
||||||
* not leak into the observable behavior of the function other than
|
|
||||||
* the designated outputs (output, olen, return value). Otherwise
|
|
||||||
* this would open the execution of the function to
|
|
||||||
* side-channel-based variants of the Bleichenbacher padding oracle
|
|
||||||
* attack. Potential side channels include overall timing, memory
|
|
||||||
* access patterns (especially visible to an adversary who has access
|
|
||||||
* to a shared memory cache), and branches (especially visible to
|
|
||||||
* an adversary who has access to a shared code cache or to a shared
|
|
||||||
* branch predictor). */
|
|
||||||
size_t pad_count = 0;
|
|
||||||
unsigned bad = 0;
|
|
||||||
unsigned char pad_done = 0;
|
|
||||||
size_t plaintext_size = 0;
|
|
||||||
unsigned output_too_large;
|
|
||||||
|
|
||||||
plaintext_max_size = mbedtls_cf_size_if( output_max_len > ilen - 11,
|
|
||||||
ilen - 11,
|
|
||||||
output_max_len );
|
|
||||||
|
|
||||||
/* Check and get padding length in constant time and constant
|
|
||||||
* memory trace. The first byte must be 0. */
|
|
||||||
bad |= buf[0];
|
|
||||||
|
|
||||||
if( mode == MBEDTLS_RSA_PRIVATE )
|
|
||||||
{
|
|
||||||
/* Decode EME-PKCS1-v1_5 padding: 0x00 || 0x02 || PS || 0x00
|
|
||||||
* where PS must be at least 8 nonzero bytes. */
|
|
||||||
bad |= buf[1] ^ MBEDTLS_RSA_CRYPT;
|
|
||||||
|
|
||||||
/* Read the whole buffer. Set pad_done to nonzero if we find
|
|
||||||
* the 0x00 byte and remember the padding length in pad_count. */
|
|
||||||
for( i = 2; i < ilen; i++ )
|
|
||||||
{
|
|
||||||
pad_done |= ((buf[i] | (unsigned char)-buf[i]) >> 7) ^ 1;
|
|
||||||
pad_count += ((pad_done | (unsigned char)-pad_done) >> 7) ^ 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
/* Decode EMSA-PKCS1-v1_5 padding: 0x00 || 0x01 || PS || 0x00
|
|
||||||
* where PS must be at least 8 bytes with the value 0xFF. */
|
|
||||||
bad |= buf[1] ^ MBEDTLS_RSA_SIGN;
|
|
||||||
|
|
||||||
/* Read the whole buffer. Set pad_done to nonzero if we find
|
|
||||||
* the 0x00 byte and remember the padding length in pad_count.
|
|
||||||
* If there's a non-0xff byte in the padding, the padding is bad. */
|
|
||||||
for( i = 2; i < ilen; i++ )
|
|
||||||
{
|
|
||||||
pad_done |= mbedtls_cf_uint_if( buf[i], 0, 1 );
|
|
||||||
pad_count += mbedtls_cf_uint_if( pad_done, 0, 1 );
|
|
||||||
bad |= mbedtls_cf_uint_if( pad_done, 0, buf[i] ^ 0xFF );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If pad_done is still zero, there's no data, only unfinished padding. */
|
|
||||||
bad |= mbedtls_cf_uint_if( pad_done, 0, 1 );
|
|
||||||
|
|
||||||
/* There must be at least 8 bytes of padding. */
|
|
||||||
bad |= mbedtls_cf_size_gt( 8, pad_count );
|
|
||||||
|
|
||||||
/* If the padding is valid, set plaintext_size to the number of
|
|
||||||
* remaining bytes after stripping the padding. If the padding
|
|
||||||
* is invalid, avoid leaking this fact through the size of the
|
|
||||||
* output: use the maximum message size that fits in the output
|
|
||||||
* buffer. Do it without branches to avoid leaking the padding
|
|
||||||
* validity through timing. RSA keys are small enough that all the
|
|
||||||
* size_t values involved fit in unsigned int. */
|
|
||||||
plaintext_size = mbedtls_cf_uint_if(
|
|
||||||
bad, (unsigned) plaintext_max_size,
|
|
||||||
(unsigned) ( ilen - pad_count - 3 ) );
|
|
||||||
|
|
||||||
/* Set output_too_large to 0 if the plaintext fits in the output
|
|
||||||
* buffer and to 1 otherwise. */
|
|
||||||
output_too_large = mbedtls_cf_size_gt( plaintext_size,
|
|
||||||
plaintext_max_size );
|
|
||||||
|
|
||||||
/* Set ret without branches to avoid timing attacks. Return:
|
|
||||||
* - INVALID_PADDING if the padding is bad (bad != 0).
|
|
||||||
* - OUTPUT_TOO_LARGE if the padding is good but the decrypted
|
|
||||||
* plaintext does not fit in the output buffer.
|
|
||||||
* - 0 if the padding is correct. */
|
|
||||||
ret = - (int) mbedtls_cf_uint_if(
|
|
||||||
bad, - MBEDTLS_ERR_RSA_INVALID_PADDING,
|
|
||||||
mbedtls_cf_uint_if( output_too_large,
|
|
||||||
- MBEDTLS_ERR_RSA_OUTPUT_TOO_LARGE,
|
|
||||||
0 ) );
|
|
||||||
|
|
||||||
/* If the padding is bad or the plaintext is too large, zero the
|
|
||||||
* data that we're about to copy to the output buffer.
|
|
||||||
* We need to copy the same amount of data
|
|
||||||
* from the same buffer whether the padding is good or not to
|
|
||||||
* avoid leaking the padding validity through overall timing or
|
|
||||||
* through memory or cache access patterns. */
|
|
||||||
bad = mbedtls_cf_uint_mask( bad | output_too_large );
|
|
||||||
for( i = 11; i < ilen; i++ )
|
|
||||||
buf[i] &= ~bad;
|
|
||||||
|
|
||||||
/* If the plaintext is too large, truncate it to the buffer size.
|
|
||||||
* Copy anyway to avoid revealing the length through timing, because
|
|
||||||
* revealing the length is as bad as revealing the padding validity
|
|
||||||
* for a Bleichenbacher attack. */
|
|
||||||
plaintext_size = mbedtls_cf_uint_if( output_too_large,
|
|
||||||
(unsigned) plaintext_max_size,
|
|
||||||
(unsigned) plaintext_size );
|
|
||||||
|
|
||||||
/* Move the plaintext to the leftmost position where it can start in
|
|
||||||
* the working buffer, i.e. make it start plaintext_max_size from
|
|
||||||
* the end of the buffer. Do this with a memory access trace that
|
|
||||||
* does not depend on the plaintext size. After this move, the
|
|
||||||
* starting location of the plaintext is no longer sensitive
|
|
||||||
* information. */
|
|
||||||
mbedtls_cf_mem_move_to_left( buf + ilen - plaintext_max_size,
|
|
||||||
plaintext_max_size,
|
|
||||||
plaintext_max_size - plaintext_size );
|
|
||||||
|
|
||||||
/* Finally copy the decrypted plaintext plus trailing zeros into the output
|
|
||||||
* buffer. If output_max_len is 0, then output may be an invalid pointer
|
|
||||||
* and the result of memcpy() would be undefined; prevent undefined
|
|
||||||
* behavior making sure to depend only on output_max_len (the size of the
|
|
||||||
* user-provided output buffer), which is independent from plaintext
|
|
||||||
* length, validity of padding, success of the decryption, and other
|
|
||||||
* secrets. */
|
|
||||||
if( output_max_len != 0 )
|
|
||||||
memcpy( output, buf + ilen - plaintext_max_size, plaintext_max_size );
|
|
||||||
|
|
||||||
/* Report the amount of data we copied to the output buffer. In case
|
|
||||||
* of errors (bad padding or output too large), the value of *olen
|
|
||||||
* when this function returns is not specified. Making it equivalent
|
|
||||||
* to the good case limits the risks of leaking the padding validity. */
|
|
||||||
*olen = plaintext_size;
|
|
||||||
|
|
||||||
return( ret );
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function
|
* Implementation of the PKCS#1 v2.1 RSAES-PKCS1-V1_5-DECRYPT function
|
||||||
*/
|
*/
|
||||||
|
Loading…
Reference in New Issue
Block a user