Add generator API
Add an API for byte generators: psa_crypto_generator_t, PSA_CRYPTO_GENERATOR_INIT, psa_crypto_generator_init, psa_get_generator_capacity, psa_generator_read, psa_generator_import_key, psa_generator_abort. This commit does not yet implement any generator algorithm, it only provides the framework. This code may not compile with -Wunused.
This commit is contained in:
parent
9aa369eafb
commit
eab56e4159
3 changed files with 296 additions and 2 deletions
|
@ -285,12 +285,18 @@ typedef int32_t psa_status_t;
|
|||
* depend on the validity of the padding. */
|
||||
#define PSA_ERROR_INVALID_PADDING ((psa_status_t)16)
|
||||
|
||||
/** The generator has insufficient capacity left.
|
||||
*
|
||||
* Once a function returns this error, attempts to read from the
|
||||
* generator will always return this error. */
|
||||
#define PSA_ERROR_INSUFFICIENT_CAPACITY ((psa_status_t)17)
|
||||
|
||||
/** An error occurred that does not correspond to any defined
|
||||
* failure cause.
|
||||
*
|
||||
* Implementations may use this error code if none of the other standard
|
||||
* error codes are applicable. */
|
||||
#define PSA_ERROR_UNKNOWN_ERROR ((psa_status_t)17)
|
||||
#define PSA_ERROR_UNKNOWN_ERROR ((psa_status_t)18)
|
||||
|
||||
/**
|
||||
* \brief Library initialization.
|
||||
|
@ -2440,6 +2446,175 @@ psa_status_t psa_asymmetric_decrypt(psa_key_slot_t key,
|
|||
|
||||
/**@}*/
|
||||
|
||||
/** \defgroup generation Generators
|
||||
* @{
|
||||
*/
|
||||
|
||||
/** The type of the state data structure for generators.
|
||||
*
|
||||
* Before calling any function on a generator, the application must
|
||||
* initialize it by any of the following means:
|
||||
* - Set the structure to all-bits-zero, for example:
|
||||
* \code
|
||||
* psa_crypto_generator_t generator;
|
||||
* memset(&generator, 0, sizeof(generator));
|
||||
* \endcode
|
||||
* - Initialize the structure to logical zero values, for example:
|
||||
* \code
|
||||
* psa_crypto_generator_t generator = {0};
|
||||
* \endcode
|
||||
* - Initialize the structure to the initializer #PSA_CRYPTO_GENERATOR_INIT,
|
||||
* for example:
|
||||
* \code
|
||||
* psa_crypto_generator_t generator = PSA_CRYPTO_GENERATOR_INIT;
|
||||
* \endcode
|
||||
* - Assign the result of the function psa_crypto_generator_init()
|
||||
* to the structure, for example:
|
||||
* \code
|
||||
* psa_crypto_generator_t generator;
|
||||
* generator = psa_crypto_generator_init();
|
||||
* \endcode
|
||||
*
|
||||
* This is an implementation-defined \c struct. Applications should not
|
||||
* make any assumptions about the content of this structure except
|
||||
* as directed by the documentation of a specific implementation.
|
||||
*/
|
||||
typedef struct psa_crypto_generator_s psa_crypto_generator_t;
|
||||
|
||||
/** \def PSA_CRYPTO_GENERATOR_INIT
|
||||
*
|
||||
* This macro returns a suitable initializer for a generator object
|
||||
* of type #psa_crypto_generator_t.
|
||||
*/
|
||||
#ifdef __DOXYGEN_ONLY__
|
||||
/* This is an example definition for documentation purposes.
|
||||
* Implementations should define a suitable value in `crypto_struct.h`.
|
||||
*/
|
||||
#define PSA_CRYPTO_GENERATOR_INIT {0}
|
||||
#endif
|
||||
|
||||
/** Return an initial value for a generator object.
|
||||
*/
|
||||
static psa_crypto_generator_t psa_crypto_generator_init(void);
|
||||
|
||||
/** Retrieve the current capacity of a generator.
|
||||
*
|
||||
* The capacity of a generator is the maximum number of bytes that it can
|
||||
* return. Reading *N* bytes from a generator reduces its capacity by *N*.
|
||||
*
|
||||
* \param[in] generator The generator to query.
|
||||
* \param[out] capacity On success, the capacity of the generator.
|
||||
*
|
||||
* \retval PSA_SUCCESS
|
||||
* \retval PSA_ERROR_BAD_STATE
|
||||
* \retval PSA_ERROR_COMMUNICATION_FAILURE
|
||||
*/
|
||||
psa_status_t psa_get_generator_capacity(const psa_crypto_generator_t *generator,
|
||||
size_t *capacity);
|
||||
|
||||
/** Read some data from a generator.
|
||||
*
|
||||
* This function reads and returns a sequence of bytes from a generator.
|
||||
* The data that is read is discarded from the generator. The generator's
|
||||
* capacity is decreased by the number of bytes read.
|
||||
*
|
||||
* \param[in,out] generator The generator object to read from.
|
||||
* \param[out] output Buffer where the generator output will be
|
||||
* written.
|
||||
* \param output_length Number of bytes to output.
|
||||
*
|
||||
* \retval PSA_SUCCESS
|
||||
* \retval PSA_ERROR_INSUFFICIENT_CAPACITY
|
||||
* There were fewer than \p output_length bytes
|
||||
* in the generator. Note that in this case, no
|
||||
* output is written to the output buffer.
|
||||
* The generator's capacity is set to 0, thus
|
||||
* subsequent calls to this function will not
|
||||
* succeed, even with a smaller output buffer.
|
||||
* \retval PSA_ERROR_BAD_STATE
|
||||
* \retval PSA_ERROR_INSUFFICIENT_MEMORY
|
||||
* \retval PSA_ERROR_COMMUNICATION_FAILURE
|
||||
* \retval PSA_ERROR_HARDWARE_FAILURE
|
||||
* \retval PSA_ERROR_TAMPERING_DETECTED
|
||||
*/
|
||||
psa_status_t psa_generator_read(psa_crypto_generator_t *generator,
|
||||
uint8_t *output,
|
||||
size_t output_length);
|
||||
|
||||
/** Create a symmetric key from data read from a generator.
|
||||
*
|
||||
* This function reads a sequence of bytes from a generator and imports
|
||||
* these bytes as a key.
|
||||
* The data that is read is discarded from the generator. The generator's
|
||||
* capacity is decreased by the number of bytes read.
|
||||
*
|
||||
* This function is equivalent to calling #psa_generator_read and
|
||||
* passing the resulting output to #psa_import_key, but
|
||||
* if the implementation provides an isolation boundary then
|
||||
* the key material is not exposed outside the isolation boundary.
|
||||
*
|
||||
* \param key Slot where the key will be stored. This must be a
|
||||
* valid slot for a key of the chosen type. It must
|
||||
* be unoccupied.
|
||||
* \param type Key type (a \c PSA_KEY_TYPE_XXX value).
|
||||
* This must be a symmetric key type.
|
||||
* \param bits Key size in bits.
|
||||
* \param[in,out] generator The generator object to read from.
|
||||
*
|
||||
* \retval PSA_SUCCESS
|
||||
* Success.
|
||||
* \retval PSA_ERROR_INSUFFICIENT_CAPACITY
|
||||
* There were fewer than \p output_length bytes
|
||||
* in the generator. Note that in this case, no
|
||||
* output is written to the output buffer.
|
||||
* The generator's capacity is set to 0, thus
|
||||
* subsequent calls to this function will not
|
||||
* succeed, even with a smaller output buffer.
|
||||
* \retval PSA_ERROR_NOT_SUPPORTED
|
||||
* The key type or key size is not supported, either by the
|
||||
* implementation in general or in this particular slot.
|
||||
* \retval PSA_ERROR_BAD_STATE
|
||||
* \retval PSA_ERROR_INVALID_ARGUMENT
|
||||
* The key slot is invalid.
|
||||
* \retval PSA_ERROR_OCCUPIED_SLOT
|
||||
* There is already a key in the specified slot.
|
||||
* \retval PSA_ERROR_INSUFFICIENT_MEMORY
|
||||
* \retval PSA_ERROR_INSUFFICIENT_STORAGE
|
||||
* \retval PSA_ERROR_COMMUNICATION_FAILURE
|
||||
* \retval PSA_ERROR_HARDWARE_FAILURE
|
||||
* \retval PSA_ERROR_TAMPERING_DETECTED
|
||||
*/
|
||||
psa_status_t psa_generator_import_key(psa_key_slot_t key,
|
||||
psa_key_type_t type,
|
||||
size_t bits,
|
||||
psa_crypto_generator_t *generator);
|
||||
|
||||
/** Abort a generator.
|
||||
*
|
||||
* Once a generator has been aborted, its capacity is zero.
|
||||
* Aborting a generator frees all associated resources except for the
|
||||
* \c generator structure itself.
|
||||
*
|
||||
* This function may be called at any time as long as the generator
|
||||
* object has been initialized to #PSA_CRYPTO_GENERATOR_INIT, to
|
||||
* psa_crypto_generator_init() or a zero value. In particular, it is valid
|
||||
* to call psa_generator_abort() twice, or to call psa_generator_abort()
|
||||
* on a generator that has not been set up.
|
||||
*
|
||||
* Once aborted, the generator object may be called.
|
||||
*
|
||||
* \param[in,out] generator The generator to abort.
|
||||
*
|
||||
* \retval PSA_SUCCESS
|
||||
* \retval PSA_ERROR_BAD_STATE
|
||||
* \retval PSA_ERROR_COMMUNICATION_FAILURE
|
||||
* \retval PSA_ERROR_HARDWARE_FAILURE
|
||||
* \retval PSA_ERROR_TAMPERING_DETECTED
|
||||
*/
|
||||
psa_status_t psa_generator_abort(psa_crypto_generator_t *generator);
|
||||
|
||||
/**@}*/
|
||||
|
||||
/** \defgroup generation Key generation
|
||||
* @{
|
||||
*/
|
||||
|
|
|
@ -130,6 +130,27 @@ struct psa_cipher_operation_s
|
|||
} ctx;
|
||||
};
|
||||
|
||||
struct psa_crypto_generator_s
|
||||
{
|
||||
psa_algorithm_t alg;
|
||||
size_t capacity;
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
uint8_t *data;
|
||||
size_t size;
|
||||
} buffer;
|
||||
} ctx;
|
||||
};
|
||||
|
||||
#define PSA_CRYPTO_GENERATOR_INIT {0, 0, {{0, 0}}}
|
||||
static inline struct psa_crypto_generator_s psa_crypto_generator_init( void )
|
||||
{
|
||||
const struct psa_crypto_generator_s v = PSA_CRYPTO_GENERATOR_INIT;
|
||||
return( v );
|
||||
}
|
||||
|
||||
struct psa_key_policy_s
|
||||
{
|
||||
psa_key_usage_t usage;
|
||||
|
|
|
@ -2988,7 +2988,105 @@ psa_status_t psa_aead_decrypt( psa_key_slot_t key,
|
|||
|
||||
|
||||
/****************************************************************/
|
||||
/* Key generation */
|
||||
/* Generators */
|
||||
/****************************************************************/
|
||||
|
||||
psa_status_t psa_generator_abort( psa_crypto_generator_t *generator )
|
||||
{
|
||||
psa_status_t status = PSA_SUCCESS;
|
||||
if( generator->alg == 0 )
|
||||
{
|
||||
/* The object has (apparently) been initialized but it is not
|
||||
* in use. It's ok to call abort on such an object, and there's
|
||||
* nothing to do. */
|
||||
}
|
||||
else
|
||||
{
|
||||
status = PSA_ERROR_BAD_STATE;
|
||||
}
|
||||
memset( generator, 0, sizeof( *generator ) );
|
||||
return( status );
|
||||
}
|
||||
|
||||
|
||||
psa_status_t psa_get_generator_capacity(const psa_crypto_generator_t *generator,
|
||||
size_t *capacity)
|
||||
{
|
||||
*capacity = generator->capacity;
|
||||
return( PSA_SUCCESS );
|
||||
}
|
||||
|
||||
psa_status_t psa_generator_read( psa_crypto_generator_t *generator,
|
||||
uint8_t *output,
|
||||
size_t output_length )
|
||||
{
|
||||
psa_status_t status;
|
||||
|
||||
if( output_length > generator->capacity )
|
||||
{
|
||||
generator->capacity = 0;
|
||||
/* Go through the error path to wipe all confidential data now
|
||||
* that the generator object is useless. */
|
||||
status = PSA_ERROR_INSUFFICIENT_CAPACITY;
|
||||
goto exit;
|
||||
}
|
||||
if( output_length == 0 &&
|
||||
generator->capacity == 0 && generator->alg == 0 )
|
||||
{
|
||||
/* Edge case: this is a blank or finished generator, and 0
|
||||
* bytes were requested. The right error in this case could
|
||||
* be either INSUFFICIENT_CAPACITY or BAD_STATE. Return
|
||||
* INSUFFICIENT_CAPACITY, which is right for a finished
|
||||
* generator, for consistency with the case when
|
||||
* output_length > 0. */
|
||||
return( PSA_ERROR_INSUFFICIENT_CAPACITY );
|
||||
}
|
||||
generator->capacity -= output_length;
|
||||
|
||||
{
|
||||
return( PSA_ERROR_BAD_STATE );
|
||||
}
|
||||
|
||||
exit:
|
||||
if( status != PSA_SUCCESS )
|
||||
{
|
||||
psa_generator_abort( generator );
|
||||
memset( output, '!', output_length );
|
||||
}
|
||||
return( status );
|
||||
}
|
||||
|
||||
psa_status_t psa_generator_import_key( psa_key_slot_t key,
|
||||
psa_key_type_t type,
|
||||
size_t bits,
|
||||
psa_crypto_generator_t *generator )
|
||||
{
|
||||
uint8_t *data = NULL;
|
||||
size_t bytes = PSA_BITS_TO_BYTES( bits );
|
||||
psa_status_t status;
|
||||
|
||||
if( ! key_type_is_raw_bytes( type ) )
|
||||
return( PSA_ERROR_INVALID_ARGUMENT );
|
||||
if( bits % 8 != 0 )
|
||||
return( PSA_ERROR_INVALID_ARGUMENT );
|
||||
data = mbedtls_calloc( 1, bytes );
|
||||
if( data == NULL )
|
||||
return( PSA_ERROR_INSUFFICIENT_MEMORY );
|
||||
|
||||
status = psa_generator_read( generator, data, bytes );
|
||||
if( status != PSA_SUCCESS )
|
||||
goto exit;
|
||||
status = psa_import_key( key, type, data, bytes );
|
||||
|
||||
exit:
|
||||
mbedtls_free( data );
|
||||
return( status );
|
||||
}
|
||||
|
||||
|
||||
|
||||
/****************************************************************/
|
||||
/* Random generation */
|
||||
/****************************************************************/
|
||||
|
||||
psa_status_t psa_generate_random( uint8_t *output,
|
||||
|
|
Loading…
Reference in a new issue