2019-08-20 09:19:22 +00:00
// Copyright 2019 SoloKeys Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
// http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.
# include "data_migration.h"
# include "log.h"
# include "device.h"
# include "crypto.h"
// TODO move from macro to function/assert for better readability?
# define check(x) assert(state_prev_0xff->x == state_tmp_ptr->x);
# define check_buf(x) assert(memcmp(state_prev_0xff->x, state_tmp_ptr->x, sizeof(state_tmp_ptr->x)) == 0);
2019-08-20 09:57:32 +00:00
bool migrate_from_FF_to_01 ( AuthenticatorState_0xFF * state_prev_0xff , AuthenticatorState_0x01 * state_tmp_ptr ) {
2019-08-20 09:19:22 +00:00
// Calculate PIN hash, and replace PIN raw storage with it; add version to structure
// other ingredients do not change
if ( state_tmp_ptr - > data_version ! = 0xFF )
return false ;
2019-08-20 09:57:32 +00:00
static_assert ( sizeof ( AuthenticatorState_0xFF ) < = sizeof ( AuthenticatorState_0x01 ) , " New state structure is smaller, than current one, which is not handled " ) ;
2019-08-20 09:19:22 +00:00
if ( ctap_generate_rng ( state_tmp_ptr - > PIN_SALT , sizeof ( state_tmp_ptr - > PIN_SALT ) ) ! = 1 ) {
printf2 ( TAG_ERR , " Error, rng failed \n " ) ;
return false ;
}
if ( state_prev_0xff - > is_pin_set ) {
crypto_sha256_init ( ) ;
crypto_sha256_update ( state_prev_0xff - > pin_code , state_prev_0xff - > pin_code_length ) ;
uint8_t intermediateHash [ 32 ] ;
crypto_sha256_final ( intermediateHash ) ;
crypto_sha256_init ( ) ;
crypto_sha256_update ( intermediateHash , 16 ) ;
memset ( intermediateHash , 0 , sizeof ( intermediateHash ) ) ;
crypto_sha256_update ( state_tmp_ptr - > PIN_SALT , sizeof ( state_tmp_ptr - > PIN_SALT ) ) ;
crypto_sha256_final ( state_tmp_ptr - > PIN_CODE_HASH ) ;
}
state_tmp_ptr - > _reserved = 0xFF ;
state_tmp_ptr - > data_version = 1 ;
check ( is_pin_set ) ;
check ( rk_stored ) ;
check ( remaining_tries ) ;
check_buf ( key_lens ) ;
check_buf ( key_space ) ;
return true ;
}
void save_migrated_state ( AuthenticatorState * state_tmp_ptr ) {
memmove ( & STATE , state_tmp_ptr , sizeof ( AuthenticatorState ) ) ;
authenticator_write_state ( state_tmp_ptr , 0 ) ;
authenticator_write_state ( state_tmp_ptr , 1 ) ;
}
void do_migration_if_required ( AuthenticatorState * state_current ) {
// Currently handles only state structures with the same size, or bigger
// FIXME rework to raw buffers with fixed size to allow state structure size decrease
if ( ! state_current - > is_initialized )
return ;
AuthenticatorState state_tmp ;
AuthenticatorState state_previous ;
authenticator_read_state ( & state_previous ) ;
authenticator_read_state ( & state_tmp ) ;
if ( state_current - > data_version = = 0xFF ) {
printf2 ( TAG_ERR , " Running migration \n " ) ;
2019-08-20 09:57:32 +00:00
bool success = migrate_from_FF_to_01 ( ( AuthenticatorState_0xFF * ) & state_previous , & state_tmp ) ;
2019-08-20 09:19:22 +00:00
if ( ! success ) {
printf2 ( TAG_ERR , " Failed migration from 0xFF to 1 \n " ) ;
// FIXME discuss migration failure behavior
goto return_cleanup ;
}
dump_hex1 ( TAG_ERR , ( void * ) & state_tmp , sizeof ( state_tmp ) ) ;
dump_hex1 ( TAG_ERR , ( void * ) & state_previous , sizeof ( state_previous ) ) ;
save_migrated_state ( & state_tmp ) ;
}
2019-08-20 09:31:09 +00:00
assert ( state_current - > data_version = = STATE_VERSION ) ;
2019-08-20 09:19:22 +00:00
return_cleanup :
memset ( & state_tmp , 0 , sizeof ( AuthenticatorState ) ) ;
memset ( & state_previous , 0 , sizeof ( AuthenticatorState ) ) ;
}