kopia lustrzana https://github.com/solokeys/solo1
92 wiersze
3.6 KiB
C
92 wiersze
3.6 KiB
C
// 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);
|
|
|
|
bool migrate_from_FF_to_01(AuthenticatorState_0xFF* state_prev_0xff, AuthenticatorState_0x01* state_tmp_ptr){
|
|
// 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;
|
|
|
|
static_assert(sizeof(AuthenticatorState_0xFF) <= sizeof(AuthenticatorState_0x01), "New state structure is smaller, than current one, which is not handled");
|
|
|
|
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);
|
|
}
|
|
|
|
assert(state_tmp_ptr->_reserved == state_prev_0xff->pin_code_length);
|
|
state_tmp_ptr->_reserved = 0xFF;
|
|
state_tmp_ptr->data_version = 1;
|
|
|
|
check(is_initialized);
|
|
check(is_pin_set);
|
|
check(remaining_tries);
|
|
check(rk_stored);
|
|
check_buf(key_lens);
|
|
check_buf(key_space);
|
|
assert(state_tmp_ptr->data_version != 0xFF);
|
|
|
|
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");
|
|
bool success = migrate_from_FF_to_01((AuthenticatorState_0xFF *) &state_previous, &state_tmp);
|
|
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);
|
|
}
|
|
|
|
assert(state_current->data_version == STATE_VERSION);
|
|
|
|
return_cleanup:
|
|
memset(&state_tmp, 0, sizeof(AuthenticatorState));
|
|
memset(&state_previous, 0, sizeof(AuthenticatorState));
|
|
}
|