mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-27 08:38:07 +00:00
legacy: new passphrase redesign draft
This commit is contained in:
parent
569068044e
commit
041a95f738
@ -122,6 +122,9 @@ be added to the storage u2f_counter to get the real counter value.
|
||||
static secbool sessionSeedCached, sessionSeedUsesPassphrase;
|
||||
static uint8_t CONFIDENTIAL sessionSeed[64];
|
||||
|
||||
static secbool sessionIdCached;
|
||||
static uint8_t sessionId[32];
|
||||
|
||||
static secbool sessionPassphraseCached = secfalse;
|
||||
static char CONFIDENTIAL sessionPassphrase[51];
|
||||
|
||||
@ -409,6 +412,8 @@ void session_clear(bool lock) {
|
||||
memzero(&sessionSeed, sizeof(sessionSeed));
|
||||
sessionPassphraseCached = secfalse;
|
||||
memzero(&sessionPassphrase, sizeof(sessionPassphrase));
|
||||
sessionIdCached = secfalse;
|
||||
memzero(&sessionId, sizeof(sessionId));
|
||||
if (lock) {
|
||||
storage_lock();
|
||||
}
|
||||
@ -527,8 +532,6 @@ void config_setLanguage(const char *lang) {
|
||||
}
|
||||
|
||||
void config_setPassphraseProtection(bool passphrase_protection) {
|
||||
sessionSeedCached = secfalse;
|
||||
sessionPassphraseCached = secfalse;
|
||||
config_set_bool(KEY_PASSPHRASE_PROTECTION, passphrase_protection);
|
||||
}
|
||||
|
||||
@ -552,6 +555,7 @@ static void get_root_node_callback(uint32_t iter, uint32_t total) {
|
||||
|
||||
const uint8_t *config_getSeed(bool usePassphrase) {
|
||||
// root node is properly cached
|
||||
// TODO: investigate
|
||||
if (usePassphrase == (sectrue == sessionSeedUsesPassphrase) &&
|
||||
sectrue == sessionSeedCached) {
|
||||
return sessionSeed;
|
||||
@ -820,31 +824,12 @@ bool session_isPassphraseCached(void) {
|
||||
return sectrue == sessionPassphraseCached;
|
||||
}
|
||||
|
||||
bool session_getState(const uint8_t *salt, uint8_t *state,
|
||||
const char *passphrase) {
|
||||
if (!passphrase && sectrue != sessionPassphraseCached) {
|
||||
return false;
|
||||
} else {
|
||||
passphrase = sessionPassphrase;
|
||||
const uint8_t *session_getSessionId(void) {
|
||||
if (!sessionIdCached) {
|
||||
random_buffer(sessionId, 32);
|
||||
}
|
||||
if (!salt) {
|
||||
// if salt is not provided fill the first half of the state with random data
|
||||
random_buffer(state, 32);
|
||||
} else {
|
||||
// if salt is provided fill the first half of the state with salt
|
||||
memcpy(state, salt, 32);
|
||||
}
|
||||
// state[0:32] = salt
|
||||
// state[32:64] = HMAC(passphrase, salt || device_id)
|
||||
HMAC_SHA256_CTX ctx = {0};
|
||||
hmac_sha256_Init(&ctx, (const uint8_t *)passphrase, strlen(passphrase));
|
||||
hmac_sha256_Update(&ctx, state, 32);
|
||||
hmac_sha256_Update(&ctx, (const uint8_t *)config_uuid, sizeof(config_uuid));
|
||||
hmac_sha256_Final(&ctx, state + 32);
|
||||
|
||||
memzero(&ctx, sizeof(ctx));
|
||||
|
||||
return true;
|
||||
sessionIdCached = sectrue;
|
||||
return sessionId;
|
||||
}
|
||||
|
||||
bool session_isUnlocked(void) { return sectrue == storage_is_unlocked(); }
|
||||
|
@ -110,8 +110,7 @@ void config_setHomescreen(const uint8_t *data, uint32_t size);
|
||||
|
||||
void session_cachePassphrase(const char *passphrase);
|
||||
bool session_isPassphraseCached(void);
|
||||
bool session_getState(const uint8_t *salt, uint8_t *state,
|
||||
const char *passphrase);
|
||||
const uint8_t *session_getSessionId(void);
|
||||
|
||||
bool config_setMnemonic(const char *mnemonic);
|
||||
bool config_containsMnemonic(const char *mnemonic);
|
||||
|
@ -20,17 +20,13 @@
|
||||
void fsm_msgInitialize(const Initialize *msg) {
|
||||
recovery_abort();
|
||||
signing_abort();
|
||||
if (msg && msg->has_state && msg->state.size == 64) {
|
||||
uint8_t i_state[64];
|
||||
if (!session_getState(msg->state.bytes, i_state, NULL)) {
|
||||
session_clear(false); // do not clear PIN
|
||||
} else {
|
||||
if (0 != memcmp(msg->state.bytes, i_state, 64)) {
|
||||
session_clear(false); // do not clear PIN
|
||||
}
|
||||
if (msg && msg->has_session_id && msg->session_id.size == 32) {
|
||||
if (0 != memcmp(session_getSessionId(), msg->session_id.bytes, 32)) {
|
||||
session_clear(false); // do not lock
|
||||
}
|
||||
} else {
|
||||
session_clear(false); // do not clear PIN
|
||||
// If session id was not specified -> clear the cache.
|
||||
session_clear(false); // do not lock
|
||||
}
|
||||
layoutHome();
|
||||
fsm_msgGetFeatures(0);
|
||||
@ -39,6 +35,12 @@ void fsm_msgInitialize(const Initialize *msg) {
|
||||
void fsm_msgGetFeatures(const GetFeatures *msg) {
|
||||
(void)msg;
|
||||
RESP_INIT(Features);
|
||||
|
||||
resp->has_session_id = true;
|
||||
memcpy(resp->session_id.bytes, session_getSessionId(),
|
||||
sizeof(resp->session_id.bytes));
|
||||
resp->session_id.size = sizeof(resp->session_id.bytes);
|
||||
|
||||
resp->has_vendor = true;
|
||||
strlcpy(resp->vendor, "trezor.io", sizeof(resp->vendor));
|
||||
resp->has_major_version = true;
|
||||
@ -359,6 +361,10 @@ void fsm_msgClearSession(const ClearSession *msg) {
|
||||
}
|
||||
|
||||
void fsm_msgApplySettings(const ApplySettings *msg) {
|
||||
CHECK_PARAM(
|
||||
!msg->has_passphrase_always_on_device,
|
||||
_("This firmware is incapable of passphrase entry on the device."));
|
||||
|
||||
CHECK_PARAM(msg->has_label || msg->has_language || msg->has_use_passphrase ||
|
||||
msg->has_homescreen || msg->has_auto_lock_delay_ms,
|
||||
_("No setting provided"));
|
||||
|
@ -354,6 +354,7 @@ bool protectPassphrase(void) {
|
||||
bool passphrase_protection = false;
|
||||
config_getPassphraseProtection(&passphrase_protection);
|
||||
if (!passphrase_protection || session_isPassphraseCached()) {
|
||||
session_cachePassphrase("");
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -369,11 +370,15 @@ bool protectPassphrase(void) {
|
||||
bool result;
|
||||
for (;;) {
|
||||
usbPoll();
|
||||
// TODO: correctly process PassphraseAck with state field set (mismatch =>
|
||||
// Failure)
|
||||
if (msg_tiny_id == MessageType_MessageType_PassphraseAck) {
|
||||
msg_tiny_id = 0xFFFF;
|
||||
PassphraseAck *ppa = (PassphraseAck *)msg_tiny;
|
||||
if (ppa->has_on_device && ppa->on_device == true) {
|
||||
fsm_sendFailure(
|
||||
FailureType_Failure_DataError,
|
||||
_("This firmware is incapable of passphrase entry on the device."));
|
||||
// TODO: write test
|
||||
}
|
||||
session_cachePassphrase(ppa->has_passphrase ? ppa->passphrase : "");
|
||||
result = true;
|
||||
break;
|
||||
|
@ -5,9 +5,6 @@ Failure.message max_size:256
|
||||
PinMatrixAck.pin max_size:10
|
||||
|
||||
PassphraseAck.passphrase max_size:51
|
||||
PassphraseAck.state max_size:64
|
||||
|
||||
PassphraseStateRequest.state max_size:64
|
||||
|
||||
HDNodeType.chain_code max_size:32
|
||||
HDNodeType.private_key max_size:32
|
||||
|
@ -1,4 +1,4 @@
|
||||
Initialize.state max_size:64
|
||||
Initialize.session_id max_size:32
|
||||
|
||||
Features.vendor max_size:33
|
||||
Features.device_id max_size:25
|
||||
@ -10,6 +10,7 @@ Features.model max_size:17
|
||||
Features.fw_vendor max_size:256
|
||||
Features.fw_vendor_keys max_size:32
|
||||
Features.capabilities max_count:32
|
||||
Features.session_id max_size:32
|
||||
|
||||
ApplySettings.language max_size:17
|
||||
ApplySettings.label max_size:33
|
||||
|
@ -39,7 +39,6 @@ def _enable_passphrase(client):
|
||||
assert isinstance(response, messages.Success)
|
||||
|
||||
|
||||
@pytest.mark.skip_t1 # TODO
|
||||
@pytest.mark.skip_ui
|
||||
@pytest.mark.setup_client()
|
||||
def test_session_with_passphrase(client):
|
||||
@ -91,7 +90,6 @@ def test_session_with_passphrase(client):
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skip_t1 # TODO
|
||||
@pytest.mark.skip_ui
|
||||
@pytest.mark.setup_client()
|
||||
def test_session_enable_passphrase(client):
|
||||
@ -132,7 +130,6 @@ def test_session_enable_passphrase(client):
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.skip_t1
|
||||
@pytest.mark.skip_ui
|
||||
@pytest.mark.setup_client()
|
||||
def test_passphrase_always_on_device(client):
|
||||
@ -146,6 +143,12 @@ def test_passphrase_always_on_device(client):
|
||||
|
||||
# Force passphrase entry on Trezor.
|
||||
response = client.call_raw(messages.ApplySettings(passphrase_always_on_device=True))
|
||||
|
||||
if client.features.model == "1":
|
||||
assert isinstance(response, messages.Failure)
|
||||
assert response.code == 3 # DataError
|
||||
return
|
||||
|
||||
assert isinstance(response, messages.ButtonRequest) # confirm dialog
|
||||
client.debug.press_yes()
|
||||
response = client.call_raw(messages.ButtonAck())
|
||||
|
Loading…
Reference in New Issue
Block a user