Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dispatch MAC operations through the driver interface #4247

Merged
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
675501d
Rename the PSA driver context structure headers to _primitives
stevew817 Apr 26, 2021
f4248f2
Remove inclusion of top-level crypto.h from the driver context header
stevew817 Apr 26, 2021
61398ec
Move the cipher operation structure declaration for grouping
stevew817 Apr 26, 2021
3c8dd63
Add include headers for composite operation contexts and move hmac
stevew817 Apr 26, 2021
d13a70f
Add boilerplate for dispatching MAC operations
stevew817 Mar 19, 2021
77e2cc5
Move the MAC operation structure into the driver headers
stevew817 Mar 19, 2021
82c66b6
Move internal HMAC implementation into internal MAC driver
stevew817 Mar 19, 2021
e680419
Migrate MAC setup/abort calls into the software driver
stevew817 Mar 19, 2021
6e7f291
Migrate MAC update call into the software driver
stevew817 Mar 19, 2021
a5b860a
Migrate MAC finish calls into the software driver
stevew817 Mar 19, 2021
7515e75
Add CMAC and HMAC driver testing to all.sh
stevew817 Mar 19, 2021
4fdf060
Complete, document and fully use internal HMAC API
stevew817 Mar 22, 2021
d1955af
Rename internal HMAC structure type to match convention
stevew817 Mar 22, 2021
939102e
Add CMAC to standard PSA config
stevew817 Mar 22, 2021
c7f0a57
Add testing of the MAC driver entry points
stevew817 Apr 29, 2021
02fc62a
Remove unused items from MAC operation context structure
stevew817 Apr 29, 2021
ba9a5bf
Code flow/readability improvements after review
stevew817 Apr 29, 2021
a4638e7
Remove redundant key_set from MAC operation structure
stevew817 Apr 29, 2021
36876a0
Make safer_memcmp available to all compile units under PSA
stevew817 Apr 29, 2021
dd1a915
Rename HMAC operation structure
stevew817 Apr 29, 2021
ac8d82a
Use the correct guards on the context structures for MAC/HKDF/PRF
stevew817 Apr 29, 2021
d1ed1d9
Make HKDF use the generic MAC API
stevew817 Apr 29, 2021
a6df604
Base the PSA implementation of TLS 1.2 PRF on the MAC API
stevew817 Apr 29, 2021
094a77e
Code flow and style improvements
stevew817 May 6, 2021
dcd0811
Remove superfluous length check
stevew817 May 6, 2021
8f37004
Remove unused variable from MAC driver structure
stevew817 May 6, 2021
3409b02
Remove superfluous check
stevew817 May 6, 2021
f45f071
Minor documentation and language fixes
stevew817 May 6, 2021
a2058a7
Convert mbedTLS to PSA dependencies for the driver wrapper tests
stevew817 May 6, 2021
c112315
Add PSA_ACCEL test dependencies in MAC driver wrappers tests
stevew817 May 6, 2021
72f736a
Move is_sign and mac_size checking back to PSA core scope
stevew817 May 7, 2021
2f60f20
Remove superfluous checking from MAC driver
stevew817 May 7, 2021
02865f5
Use the proper define guards in the MAC driver
stevew817 May 7, 2021
0c23965
Add sanity tests for CMAC-(3)DES through PSA Crypto
stevew817 May 7, 2021
b29902a
Correctly mark unused arguments when MAC algorithms are compiled out
stevew817 May 10, 2021
d1a68f1
Supply actual key bits to PSA_MAC_LENGTH during MAC setup
stevew817 May 10, 2021
ae3ec52
Apply mbedtls namespacing to MAC driver test hooks
stevew817 May 10, 2021
8af5c5c
Be explicit about why the zero-length check is there
stevew817 May 11, 2021
9e15fb7
Refactor out mac_sign_setup and mac_verify_setup
stevew817 May 11, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 1 addition & 3 deletions include/psa/crypto_builtin_composites.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,6 @@ typedef struct
typedef struct
{
psa_algorithm_t alg;
unsigned int is_sign : 1;
uint8_t mac_size;
union
{
unsigned dummy; /* Make the union non-empty even with no supported algorithms. */
Expand All @@ -76,7 +74,7 @@ typedef struct
} ctx;
} mbedtls_psa_mac_operation_t;

#define MBEDTLS_PSA_MAC_OPERATION_INIT {0, 0, 0, 0, {0}}
#define MBEDTLS_PSA_MAC_OPERATION_INIT {0, {0}}

/*
* BEYOND THIS POINT, TEST DRIVER DECLARATIONS ONLY.
Expand Down
4 changes: 3 additions & 1 deletion include/psa/crypto_struct.h
Original file line number Diff line number Diff line change
Expand Up @@ -137,10 +137,12 @@ struct psa_mac_operation_s
* ID value zero means the context is not valid or not assigned to
* any driver (i.e. none of the driver contexts are active). */
unsigned int id;
uint8_t mac_size;
unsigned int is_sign : 1;
psa_driver_mac_context_t ctx;
};

#define PSA_MAC_OPERATION_INIT {0, {0}}
#define PSA_MAC_OPERATION_INIT {0, 0, 0, {0}}
static inline struct psa_mac_operation_s psa_mac_operation_init( void )
{
const struct psa_mac_operation_s v = PSA_MAC_OPERATION_INIT;
Expand Down
72 changes: 55 additions & 17 deletions library/psa_crypto.c
Original file line number Diff line number Diff line change
Expand Up @@ -2240,6 +2240,8 @@ psa_status_t psa_mac_abort( psa_mac_operation_t *operation )
return( PSA_SUCCESS );

psa_status_t status = psa_driver_wrapper_mac_abort( operation );
operation->mac_size = 0;
operation->is_sign = 0;
operation->id = 0;

return( status );
Expand All @@ -2253,7 +2255,6 @@ static psa_status_t psa_mac_setup( psa_mac_operation_t *operation,
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_status_t unlock_status = PSA_ERROR_CORRUPTION_DETECTED;
psa_key_slot_t *slot;
size_t mac_size;

/* A context must be freshly initialized before it can be set up. */
if( operation->id != 0 )
Expand All @@ -2279,12 +2280,15 @@ static psa_status_t psa_mac_setup( psa_mac_operation_t *operation,
if( status != PSA_SUCCESS )
goto exit;

operation->is_sign = is_sign;

/* Get the output length for the algorithm and key combination. None of the
* currently supported algorithms have an output length dependent on actual
* key size, so setting it to a bogus value is currently OK. */
mac_size = PSA_MAC_LENGTH( psa_get_key_type( &attributes ), 0, alg );
operation->mac_size = PSA_MAC_LENGTH(
psa_get_key_type( &attributes ), 0, alg );
ronald-cron-arm marked this conversation as resolved.
Show resolved Hide resolved

if( mac_size < 4 )
if( operation->mac_size < 4 )
{
/* A very short MAC is too short for security since it can be
* brute-forced. Ancient protocols with 32-bit MACs do exist,
Expand All @@ -2294,8 +2298,9 @@ static psa_status_t psa_mac_setup( psa_mac_operation_t *operation,
goto exit;
}

if( mac_size > PSA_MAC_LENGTH( psa_get_key_type( &attributes ), 0,
PSA_ALG_FULL_LENGTH_MAC( alg ) ) )
if( operation->mac_size > PSA_MAC_LENGTH( psa_get_key_type( &attributes ),
0,
PSA_ALG_FULL_LENGTH_MAC( alg ) ) )
{
/* It's impossible to "truncate" to a larger length than the full length
* of the algorithm. */
Expand Down Expand Up @@ -2372,25 +2377,44 @@ psa_status_t psa_mac_sign_finish( psa_mac_operation_t *operation,
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;
psa_status_t abort_status = PSA_ERROR_CORRUPTION_DETECTED;

/* Set the output length and content to a safe default, such that in
* case the caller misses an error check, the output would be an
* unachievable MAC. */
*mac_length = mac_size;

if( operation->id == 0 )
return( PSA_ERROR_BAD_STATE );

/* Fill the output buffer with something that isn't a valid mac
* (barring an attack on the mac and deliberately-crafted input),
* in case the caller doesn't check the return status properly. */
*mac_length = mac_size;
/* If mac_size is 0 then mac may be NULL and then the
* call to memset would have undefined behavior. */
if( mac_size != 0 )
memset( mac, '!', mac_size );
if( ! operation->is_sign )
return( PSA_ERROR_BAD_STATE );

status = psa_driver_wrapper_mac_sign_finish( operation,
mac, mac_size, mac_length );
/* Sanity checks on output buffer length. */
if( mac_size == 0 || mac_size < operation->mac_size )
ronald-cron-arm marked this conversation as resolved.
Show resolved Hide resolved
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As Ronald noted in https://github.com/ARMmbed/mbedtls/pull/4247/files#r629107039, it's surprising to check for mac_size == 0 when we know that it would imply mac_size < operation->mac_size since the operation setup guarantees that operation->mac_size > 0. You make a good point that this avoids false positives from static analyzers about cases that can only happen if mac_size == 0. However, it still warrants a comment, otherwise the next person who works on the code might decide to remove this apparently superfluous check.

How about changing the code to this?

/* Sanity check. This will guarantee that mac_size != 0 (and so mac != NULL) once all the error checks are done. */
if( operation->mac_size == 0 )
    return( PSA_ERROR_BAD_STATE );
if( mac_size < operation->mac_size )
    return( PSA_ERROR_BUFFER_TOO_SMALL );

A static analyzer should be just as happy, a compiler will only have a couple of instructions more to generate, this adds a bit of robustness, and the code looks less surprising.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

return( PSA_ERROR_BUFFER_TOO_SMALL );

abort_status = psa_mac_abort( operation );
status = psa_driver_wrapper_mac_sign_finish( operation,
mac, operation->mac_size,
mac_length );

if( status != PSA_SUCCESS && mac_size > 0 )
if( status == PSA_SUCCESS )
{
/* Set the excess room in the output buffer to an invalid value, to
* avoid potentially leaking a longer MAC. */
ronald-cron-arm marked this conversation as resolved.
Show resolved Hide resolved
if( mac_size > operation->mac_size )
memset( &mac[operation->mac_size],
'!',
mac_size - operation->mac_size );
}
else
{
/* Set the output length and content to a safe default, such that in
* case the caller misses an error check, the output would be an
* unachievable MAC. */
*mac_length = mac_size;
memset( mac, '!', mac_size );
}

abort_status = psa_mac_abort( operation );

return( status == PSA_SUCCESS ? abort_status : status );
}
Expand All @@ -2405,8 +2429,19 @@ psa_status_t psa_mac_verify_finish( psa_mac_operation_t *operation,
if( operation->id == 0 )
return( PSA_ERROR_BAD_STATE );

if( operation->is_sign )
return( PSA_ERROR_BAD_STATE );

if( operation->mac_size != mac_length )
{
status = PSA_ERROR_INVALID_SIGNATURE;
goto cleanup;
}

status = psa_driver_wrapper_mac_verify_finish( operation,
mac, mac_length );

cleanup:
abort_status = psa_mac_abort( operation );

return( status == PSA_SUCCESS ? abort_status : status );
Expand Down Expand Up @@ -3199,6 +3234,9 @@ static psa_status_t psa_key_derivation_start_hmac(
psa_set_key_bits( &attributes, PSA_BYTES_TO_BITS( hmac_key_length ) );
psa_set_key_usage_flags( &attributes, PSA_KEY_USAGE_SIGN_HASH );

operation->is_sign = 1;
operation->mac_size = PSA_HASH_LENGTH( hash_alg );

status = psa_driver_wrapper_mac_sign_setup( operation,
&attributes,
hmac_key, hmac_key_length,
Expand Down
62 changes: 22 additions & 40 deletions library/psa_crypto_mac.c
Original file line number Diff line number Diff line change
Expand Up @@ -229,11 +229,10 @@ static psa_status_t mac_init(
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

operation->alg = PSA_ALG_FULL_LENGTH_MAC( alg );
operation->is_sign = 0;
operation->alg = alg;

#if defined(BUILTIN_ALG_CMAC)
if( operation->alg == PSA_ALG_CMAC )
if( PSA_ALG_FULL_LENGTH_MAC( operation->alg ) == PSA_ALG_CMAC )
{
mbedtls_cipher_init( &operation->ctx.cmac );
status = PSA_SUCCESS;
Expand Down Expand Up @@ -269,7 +268,7 @@ static psa_status_t mac_abort( mbedtls_psa_mac_operation_t *operation )
}
else
#if defined(BUILTIN_ALG_CMAC)
if( operation->alg == PSA_ALG_CMAC )
if( PSA_ALG_FULL_LENGTH_MAC( operation->alg ) == PSA_ALG_CMAC )
{
mbedtls_cipher_free( &operation->ctx.cmac );
}
Expand All @@ -289,7 +288,6 @@ static psa_status_t mac_abort( mbedtls_psa_mac_operation_t *operation )
}

operation->alg = 0;
operation->is_sign = 0;

return( PSA_SUCCESS );

Expand All @@ -306,8 +304,7 @@ static psa_status_t mac_setup( mbedtls_psa_mac_operation_t *operation,
const psa_key_attributes_t *attributes,
const uint8_t *key_buffer,
size_t key_buffer_size,
psa_algorithm_t alg,
int is_sign )
psa_algorithm_t alg )
{
psa_status_t status = PSA_ERROR_CORRUPTION_DETECTED;

Expand All @@ -318,13 +315,6 @@ static psa_status_t mac_setup( mbedtls_psa_mac_operation_t *operation,
status = mac_init( operation, alg );
if( status != PSA_SUCCESS )
return( status );
operation->is_sign = is_sign;

/* Get the output length for the algorithm and key combination. None of the
* currently supported algorithms have an output length dependent on actual
* key size, so setting it to a bogus value is currently OK. */
operation->mac_size =
PSA_MAC_LENGTH( psa_get_key_type( attributes ), 0, alg );

#if defined(BUILTIN_ALG_CMAC)
if( PSA_ALG_FULL_LENGTH_MAC( alg ) == PSA_ALG_CMAC )
Expand All @@ -340,7 +330,8 @@ static psa_status_t mac_setup( mbedtls_psa_mac_operation_t *operation,
if( PSA_ALG_IS_HMAC( alg ) )
{
/* Sanity check. This shouldn't fail on a valid configuration. */
if( operation->mac_size > sizeof( operation->ctx.hmac.opad ) )
if( PSA_MAC_LENGTH( psa_get_key_type( attributes ), 0, alg ) >
sizeof( operation->ctx.hmac.opad ) )
{
status = PSA_ERROR_NOT_SUPPORTED;
goto exit;
Expand All @@ -363,7 +354,6 @@ static psa_status_t mac_setup( mbedtls_psa_mac_operation_t *operation,
status = PSA_ERROR_NOT_SUPPORTED;
}

exit:
if( status != PSA_SUCCESS )
mac_abort( operation );

Expand Down Expand Up @@ -401,8 +391,8 @@ static psa_status_t mac_sign_setup(
size_t key_buffer_size,
psa_algorithm_t alg )
{
return( mac_setup( operation, attributes, key_buffer, key_buffer_size, alg,
1 ) );
return( mac_setup( operation,
attributes, key_buffer, key_buffer_size, alg ) );
}

static psa_status_t mac_verify_setup(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mac_verify_setup and mac_sign_setup are now identical. Why not call mac_setup directly?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Expand All @@ -412,8 +402,8 @@ static psa_status_t mac_verify_setup(
size_t key_buffer_size,
psa_algorithm_t alg )
{
return( mac_setup( operation, attributes, key_buffer, key_buffer_size, alg,
0 ) );
return( mac_setup( operation,
attributes, key_buffer, key_buffer_size, alg ) );
}

static psa_status_t mac_update(
Expand All @@ -425,7 +415,7 @@ static psa_status_t mac_update(
return( PSA_ERROR_BAD_STATE );

#if defined(BUILTIN_ALG_CMAC)
if( operation->alg == PSA_ALG_CMAC )
if( PSA_ALG_FULL_LENGTH_MAC( operation->alg ) == PSA_ALG_CMAC )
{
return( mbedtls_to_psa_error(
mbedtls_cipher_cmac_update( &operation->ctx.cmac,
Expand All @@ -452,16 +442,13 @@ static psa_status_t mac_finish_internal( mbedtls_psa_mac_operation_t *operation,
uint8_t *mac,
size_t mac_size )
{
if( mac_size < operation->mac_size )
return( PSA_ERROR_BUFFER_TOO_SMALL );

#if defined(BUILTIN_ALG_CMAC)
if( operation->alg == PSA_ALG_CMAC )
if( PSA_ALG_FULL_LENGTH_MAC( operation->alg ) == PSA_ALG_CMAC )
{
uint8_t tmp[PSA_BLOCK_CIPHER_BLOCK_MAX_SIZE];
int ret = mbedtls_cipher_cmac_finish( &operation->ctx.cmac, tmp );
if( ret == 0 )
memcpy( mac, tmp, operation->mac_size );
memcpy( mac, tmp, mac_size );
mbedtls_platform_zeroize( tmp, sizeof( tmp ) );
return( mbedtls_to_psa_error( ret ) );
}
Expand All @@ -471,13 +458,16 @@ static psa_status_t mac_finish_internal( mbedtls_psa_mac_operation_t *operation,
if( PSA_ALG_IS_HMAC( operation->alg ) )
{
return( psa_hmac_finish_internal( &operation->ctx.hmac,
mac, operation->mac_size ) );
mac, mac_size ) );
}
else
#endif /* BUILTIN_ALG_HMAC */
{
/* This shouldn't happen if `operation` was initialized by
* a setup function. */
(void) operation;
(void) mac;
(void) mac_size;
return( PSA_ERROR_BAD_STATE );
}
}
Expand All @@ -493,13 +483,10 @@ static psa_status_t mac_sign_finish(
if( operation->alg == 0 )
return( PSA_ERROR_BAD_STATE );

if( ! operation->is_sign )
return( PSA_ERROR_BAD_STATE );

status = mac_finish_internal( operation, mac, mac_size );

if( status == PSA_SUCCESS )
*mac_length = operation->mac_size;
*mac_length = mac_size;

return( status );
}
Expand All @@ -515,16 +502,11 @@ static psa_status_t mac_verify_finish(
if( operation->alg == 0 )
return( PSA_ERROR_BAD_STATE );

if( operation->is_sign )
return( PSA_ERROR_BAD_STATE );

if( operation->mac_size != mac_length )
{
status = PSA_ERROR_INVALID_SIGNATURE;
goto cleanup;
}
/* Consistency check: requested MAC length fits our local buffer */
if( mac_length > sizeof( actual_mac ) )
return( PSA_ERROR_INVALID_ARGUMENT );

status = mac_finish_internal( operation, actual_mac, sizeof( actual_mac ) );
status = mac_finish_internal( operation, actual_mac, mac_length );
if( status != PSA_SUCCESS )
goto cleanup;

Expand Down
21 changes: 13 additions & 8 deletions library/psa_crypto_mac.h
Original file line number Diff line number Diff line change
Expand Up @@ -182,13 +182,15 @@ psa_status_t mbedtls_psa_mac_update(
*
* \param[in,out] operation Active MAC operation.
* \param[out] mac Buffer where the MAC value is to be written.
* \param mac_size Size of the \p mac buffer in bytes.
* \param[out] mac_length On success, the number of bytes
* that make up the MAC value. This is always
* #PSA_MAC_LENGTH(\c key_type, \c key_bits, \c alg)
* where \c key_type and \c key_bits are the type and
* bit-size respectively of the key and \c alg is the
* MAC algorithm that is calculated.
* \param mac_size Output size requested for the MAC algorithm. The PSA
* core guarantees this is a valid MAC length for the
* algorithm and key combination passed to
* mbedtls_psa_mac_sign_setup(). It also guarantees the
* \p mac buffer is large enough to contain the
* requested output size.
* \param[out] mac_length On success, the number of bytes output to buffer
* \p mac, which will be equal to the requested length
* \p mac_size.
*
* \retval #PSA_SUCCESS
* Success.
Expand Down Expand Up @@ -226,7 +228,10 @@ psa_status_t mbedtls_psa_mac_sign_finish(
*
* \param[in,out] operation Active MAC operation.
* \param[in] mac Buffer containing the expected MAC value.
* \param mac_length Size of the \p mac buffer in bytes.
* \param mac_length Length in bytes of the expected MAC value. The PSA
* core guarantees that this length is a valid MAC
* length for the algorithm and key combination passed
* to mbedtls_psa_mac_verify_setup().
*
* \retval #PSA_SUCCESS
* The expected MAC is identical to the actual MAC of the message.
Expand Down