mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-19 04:48:12 +00:00
feat(core): Rework Optiga PIN slot configuration.
This commit is contained in:
parent
9c50e15cf7
commit
509e291118
@ -69,8 +69,12 @@ int __wur optiga_pin_verify_v4(OPTIGA_UI_PROGRESS ui_progress,
|
||||
const uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE],
|
||||
uint8_t out_secret[OPTIGA_PIN_SECRET_SIZE]);
|
||||
|
||||
int __wur optiga_pin_get_fails_v4(uint32_t *ctr);
|
||||
|
||||
int __wur optiga_pin_get_fails(uint32_t *ctr);
|
||||
|
||||
int __wur optiga_pin_fails_increase_v4(uint32_t count);
|
||||
|
||||
int __wur optiga_pin_fails_increase(uint32_t count);
|
||||
|
||||
#endif
|
||||
|
@ -26,20 +26,29 @@
|
||||
#include "rand.h"
|
||||
#include "storage.h"
|
||||
|
||||
// PIN counter reset key / Master secret (OID 0xF1D0).
|
||||
// Counter-protected PIN secret and reset key for OID_STRETCHED_PIN_CTR (OID
|
||||
// 0xF1D0).
|
||||
#define OID_PIN_SECRET (OPTIGA_OID_DATA + 0)
|
||||
|
||||
// PIN counter (OID 0xE120).
|
||||
#define OID_PIN_COUNTER (OPTIGA_OID_COUNTER + 0)
|
||||
|
||||
// PIN stretching counter (OID 0xE121).
|
||||
#define OID_PIN_STRETCH_COUNTER (OPTIGA_OID_COUNTER + 1)
|
||||
|
||||
// Stretched PIN (OID 0xF1D4).
|
||||
// Digest of the stretched PIN (OID 0xF1D4).
|
||||
#define OID_STRETCHED_PIN (OPTIGA_OID_DATA + 4)
|
||||
|
||||
// Key for HMAC-SHA256 PIN stretching step (OID 0xF1D1).
|
||||
#define OID_PIN_HMAC (OPTIGA_OID_DATA + 1)
|
||||
// Counter-protected key for HMAC-SHA256 PIN stretching step (OID 0xF1D5).
|
||||
#define OID_PIN_HMAC (OPTIGA_OID_DATA + 8)
|
||||
|
||||
// Counter which limits the guesses at OID_STRETCHED_PIN (OID 0xE120).
|
||||
#define OID_STRETCHED_PIN_CTR (OPTIGA_OID_COUNTER + 0)
|
||||
|
||||
// Counter which limits the use of OID_PIN_HMAC (OID 0xE122).
|
||||
#define OID_PIN_HMAC_CTR (OPTIGA_OID_COUNTER + 2)
|
||||
|
||||
// Counter which limits the total number of PIN stretching operations over the
|
||||
// lifetime of the device (OID 0xE121).
|
||||
#define OID_PIN_TOTAL_CTR (OPTIGA_OID_COUNTER + 1)
|
||||
|
||||
// Key for HMAC-SHA256 PIN stretching step used in storage version 3 and 4 (OID
|
||||
// 0xF1D1).
|
||||
#define OID_PIN_HMAC_V4 (OPTIGA_OID_DATA + 1)
|
||||
|
||||
// Key for AES-CMAC PIN stretching step (OID 0xE200).
|
||||
#define OID_PIN_CMAC OPTIGA_OID_SYM_KEY
|
||||
@ -47,20 +56,17 @@
|
||||
// Key for ECDH PIN stretching step (OID 0xE0F3).
|
||||
#define OID_PIN_ECDH (OPTIGA_OID_ECC_KEY + 3)
|
||||
|
||||
// The number of times the stretching is repeated in each PIN processing phase
|
||||
// for legacy storage version 3 and 4.
|
||||
#define PIN_STRETCH_ITERATIONS_V4 1
|
||||
|
||||
// The number of times that PIN stretching is repeated.
|
||||
#define PIN_STRETCH_ITERATIONS 2
|
||||
|
||||
// Value of the PIN counter when it is reset.
|
||||
static const uint8_t COUNTER_RESET[] = {0, 0, 0, 0, 0, 0, 0, PIN_MAX_TRIES};
|
||||
|
||||
// Value of the PIN stretching counter when it is initialized. The limit is
|
||||
// 600000 stretching operations, which equates to
|
||||
// 100000 / PIN_STRETCH_ITERATIONS unlock operations.
|
||||
static const uint8_t STRETCH_COUNTER_INIT[] = {0, 0, 0, 0, 0, 0x09, 0x27, 0xC0};
|
||||
// Initial value of the counter which limits the total number of PIN stretching
|
||||
// operations. The limit is 600000 stretching operations, which equates to
|
||||
// 300000 / PIN_STRETCH_ITERATIONS unlock operations over the lifetime of the
|
||||
// device.
|
||||
static const uint8_t PIN_TOTAL_CTR_INIT[] = {0, 0, 0, 0, 0, 0x09, 0x27, 0xC0};
|
||||
|
||||
static const optiga_metadata_item TYPE_AUTOREF =
|
||||
OPTIGA_META_VALUE(OPTIGA_DATA_TYPE_AUTOREF);
|
||||
@ -70,10 +76,12 @@ static const optiga_metadata_item ACCESS_STRETCHED_PIN =
|
||||
OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_AUTO, OID_STRETCHED_PIN);
|
||||
static const optiga_metadata_item ACCESS_PIN_SECRET =
|
||||
OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_AUTO, OID_PIN_SECRET);
|
||||
static const optiga_metadata_item ACCESS_PIN_COUNTER =
|
||||
OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_LUC, OID_PIN_COUNTER);
|
||||
static const optiga_metadata_item ACCESS_PIN_STRETCH_COUNTER =
|
||||
OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_LUC, OID_PIN_STRETCH_COUNTER);
|
||||
static const optiga_metadata_item ACCESS_STRETCHED_PIN_CTR =
|
||||
OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_LUC, OID_STRETCHED_PIN_CTR);
|
||||
static const optiga_metadata_item ACCESS_PIN_TOTAL_CTR =
|
||||
OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_LUC, OID_PIN_TOTAL_CTR);
|
||||
static const optiga_metadata_item ACCESS_PIN_HMAC_CTR =
|
||||
OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_LUC, OID_PIN_HMAC_CTR);
|
||||
|
||||
// Size of the DER BIT STRING header required for inputs to optiga_calc_ssec().
|
||||
#define BIT_STRING_HEADER_SIZE 3
|
||||
@ -244,7 +252,7 @@ bool optiga_set_metadata(uint16_t oid, const optiga_metadata *metadata) {
|
||||
static bool optiga_pin_init_metadata(void) {
|
||||
optiga_metadata metadata = {0};
|
||||
|
||||
// Set metadata for PIN counter reset key / Master secret.
|
||||
// Set metadata for counter-protected PIN secret.
|
||||
memzero(&metadata, sizeof(metadata));
|
||||
metadata.change = OPTIGA_META_ACCESS_ALWAYS;
|
||||
metadata.read = ACCESS_STRETCHED_PIN;
|
||||
@ -254,43 +262,64 @@ static bool optiga_pin_init_metadata(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set metadata for PIN counter.
|
||||
// Set metadata for stretched PIN.
|
||||
memzero(&metadata, sizeof(metadata));
|
||||
metadata.change = ACCESS_PIN_SECRET;
|
||||
metadata.read = OPTIGA_META_ACCESS_NEVER;
|
||||
metadata.execute = ACCESS_STRETCHED_PIN_CTR;
|
||||
metadata.data_type = TYPE_AUTOREF;
|
||||
if (!optiga_set_metadata(OID_STRETCHED_PIN, &metadata)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set metadata for HMAC-SHA256 PIN stretching secret.
|
||||
memzero(&metadata, sizeof(metadata));
|
||||
metadata.change = ACCESS_STRETCHED_PIN;
|
||||
metadata.read = OPTIGA_META_ACCESS_NEVER;
|
||||
metadata.execute = ACCESS_PIN_HMAC_CTR;
|
||||
metadata.data_type = TYPE_PRESSEC;
|
||||
if (!optiga_set_metadata(OID_PIN_HMAC, &metadata)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set metadata for the counter of guesses at OID_STRETCHED_PIN.
|
||||
memzero(&metadata, sizeof(metadata));
|
||||
metadata.change = ACCESS_PIN_SECRET;
|
||||
metadata.read = OPTIGA_META_ACCESS_ALWAYS;
|
||||
metadata.execute = OPTIGA_META_ACCESS_ALWAYS;
|
||||
if (!optiga_set_metadata(OID_PIN_COUNTER, &metadata)) {
|
||||
if (!optiga_set_metadata(OID_STRETCHED_PIN_CTR, &metadata)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize the PIN stretching counter if write access is possible.
|
||||
// Set metadata for the counter of OID_PIN_HMAC uses.
|
||||
memzero(&metadata, sizeof(metadata));
|
||||
metadata.change = ACCESS_STRETCHED_PIN;
|
||||
metadata.read = OPTIGA_META_ACCESS_ALWAYS;
|
||||
metadata.execute = OPTIGA_META_ACCESS_ALWAYS;
|
||||
if (!optiga_set_metadata(OID_PIN_HMAC_CTR, &metadata)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Initialize the counter of the total number of PIN stretching operations, if
|
||||
// write access is possible.
|
||||
memzero(&metadata, sizeof(metadata));
|
||||
metadata.change = OPTIGA_META_ACCESS_ALWAYS;
|
||||
if (write_metadata(OID_PIN_STRETCH_COUNTER, &metadata)) {
|
||||
optiga_result res = optiga_set_data_object(OID_PIN_STRETCH_COUNTER, false,
|
||||
STRETCH_COUNTER_INIT,
|
||||
sizeof(STRETCH_COUNTER_INIT));
|
||||
if (write_metadata(OID_PIN_TOTAL_CTR, &metadata)) {
|
||||
optiga_result res =
|
||||
optiga_set_data_object(OID_PIN_TOTAL_CTR, false, PIN_TOTAL_CTR_INIT,
|
||||
sizeof(PIN_TOTAL_CTR_INIT));
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Set metadata for PIN stretching counter.
|
||||
// Set metadata for the counter of the total number of PIN stretching
|
||||
// operations.
|
||||
memzero(&metadata, sizeof(metadata));
|
||||
metadata.change = OPTIGA_META_ACCESS_NEVER;
|
||||
metadata.read = OPTIGA_META_ACCESS_ALWAYS;
|
||||
metadata.execute = OPTIGA_META_ACCESS_ALWAYS;
|
||||
if (!optiga_set_metadata(OID_PIN_STRETCH_COUNTER, &metadata)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set metadata for stretched PIN.
|
||||
memzero(&metadata, sizeof(metadata));
|
||||
metadata.change = ACCESS_PIN_SECRET;
|
||||
metadata.read = OPTIGA_META_ACCESS_NEVER;
|
||||
metadata.execute = ACCESS_PIN_COUNTER;
|
||||
metadata.data_type = TYPE_AUTOREF;
|
||||
if (!optiga_set_metadata(OID_STRETCHED_PIN, &metadata)) {
|
||||
if (!optiga_set_metadata(OID_PIN_TOTAL_CTR, &metadata)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -298,7 +327,7 @@ static bool optiga_pin_init_metadata(void) {
|
||||
memzero(&metadata, sizeof(metadata));
|
||||
metadata.change = OPTIGA_META_ACCESS_ALWAYS;
|
||||
metadata.read = OPTIGA_META_ACCESS_NEVER;
|
||||
metadata.execute = ACCESS_PIN_STRETCH_COUNTER;
|
||||
metadata.execute = ACCESS_PIN_TOTAL_CTR;
|
||||
metadata.key_usage = OPTIGA_META_KEY_USE_ENC;
|
||||
if (!optiga_set_metadata(OID_PIN_CMAC, &metadata)) {
|
||||
return false;
|
||||
@ -308,41 +337,12 @@ static bool optiga_pin_init_metadata(void) {
|
||||
memzero(&metadata, sizeof(metadata));
|
||||
metadata.change = OPTIGA_META_ACCESS_ALWAYS;
|
||||
metadata.read = OPTIGA_META_ACCESS_NEVER;
|
||||
metadata.execute = ACCESS_PIN_STRETCH_COUNTER;
|
||||
metadata.execute = ACCESS_PIN_TOTAL_CTR;
|
||||
metadata.key_usage = OPTIGA_META_KEY_USE_KEYAGREE;
|
||||
if (!optiga_set_metadata(OID_PIN_ECDH, &metadata)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generate and store the HMAC PIN stretching secret in OID_PIN_HMAC, if write
|
||||
// access is possible.
|
||||
memzero(&metadata, sizeof(metadata));
|
||||
metadata.change = OPTIGA_META_ACCESS_ALWAYS;
|
||||
if (write_metadata(OID_PIN_HMAC, &metadata)) {
|
||||
uint8_t secret[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||
optiga_result res = optiga_get_random(secret, sizeof(secret));
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
random_xor(secret, sizeof(secret));
|
||||
|
||||
res = optiga_set_data_object(OID_PIN_HMAC, false, secret, sizeof(secret));
|
||||
memzero(secret, sizeof(secret));
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Set metadata for HMAC-SHA256 PIN stretching secret.
|
||||
memzero(&metadata, sizeof(metadata));
|
||||
metadata.change = OPTIGA_META_ACCESS_NEVER;
|
||||
metadata.read = OPTIGA_META_ACCESS_NEVER;
|
||||
metadata.execute = ACCESS_PIN_STRETCH_COUNTER;
|
||||
metadata.data_type = TYPE_PRESSEC;
|
||||
if (!optiga_set_metadata(OID_PIN_HMAC, &metadata)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -369,9 +369,10 @@ static int optiga_pin_init_stretch(void) {
|
||||
|
||||
static int optiga_pin_stretch_common(
|
||||
OPTIGA_UI_PROGRESS ui_progress, HMAC_SHA256_CTX *ctx,
|
||||
const uint8_t input[OPTIGA_PIN_SECRET_SIZE]) {
|
||||
// Implements the functionality that is common to optiga_pin_stretch_secret()
|
||||
// and the legacy function optiga_pin_stretch_secret_v4().
|
||||
const uint8_t input[OPTIGA_PIN_SECRET_SIZE], bool version4) {
|
||||
// Implements the functionality that is common to
|
||||
// optiga_pin_stretch_cmac_ecdh() and the legacy function
|
||||
// optiga_pin_stretch_secret_v4().
|
||||
|
||||
uint8_t buffer[ENCRYPT_SYM_PREFIX_SIZE + OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||
size_t size = 0;
|
||||
@ -387,16 +388,18 @@ static int optiga_pin_stretch_common(
|
||||
|
||||
hmac_sha256_Update(ctx, buffer, size);
|
||||
|
||||
if (version4) {
|
||||
// Combine intermediate result with OID_PIN_HMAC
|
||||
res =
|
||||
optiga_encrypt_sym(OPTIGA_SYM_MODE_HMAC_SHA256, OID_PIN_HMAC, input,
|
||||
OPTIGA_PIN_SECRET_SIZE, buffer, sizeof(buffer), &size);
|
||||
res = optiga_encrypt_sym(OPTIGA_SYM_MODE_HMAC_SHA256, OID_PIN_HMAC_V4,
|
||||
input, OPTIGA_PIN_SECRET_SIZE, buffer,
|
||||
sizeof(buffer), &size);
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
memzero(buffer, sizeof(buffer));
|
||||
return res;
|
||||
}
|
||||
|
||||
hmac_sha256_Update(ctx, buffer, size);
|
||||
}
|
||||
|
||||
ui_progress(200);
|
||||
|
||||
@ -435,39 +438,27 @@ static int optiga_pin_stretch_secret_v4(
|
||||
// in each attempt.
|
||||
|
||||
// Pseudocode for the stretching process:
|
||||
// result_0 = secret
|
||||
// for i in range(PIN_STRETCH_ITERATIONS_V4):
|
||||
// cmac_i = CMAC(optiga_cmac_key, result_i)
|
||||
// hmac_i = HMAC(optiga_hmac_key, result_i)
|
||||
// ecdh_i = ECDH(optiga_ecdh_key, result_i)
|
||||
// result_{i+1} = HMAC-SHA256(secret, cmac_i || hmac_i || ecdh_i)
|
||||
// secret = result_{PIN_STRETCH_ITERATIONS_V4}
|
||||
// cmac_out = CMAC(OID_PIN_CMAC, secret)
|
||||
// hmac_out = HMAC(OID_PIN_HMAC_V4, secret)
|
||||
// ecdh_out = ECDH(OID_PIN_ECDH, secret)
|
||||
// secret = HMAC-SHA256(secret, cmac_out || hmac_out || ecdh_out)
|
||||
|
||||
HMAC_SHA256_CTX ctx = {0};
|
||||
|
||||
uint8_t result[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||
memcpy(result, secret, sizeof(result));
|
||||
|
||||
for (int i = 0; i < PIN_STRETCH_ITERATIONS_V4; ++i) {
|
||||
hmac_sha256_Init(&ctx, secret, OPTIGA_PIN_SECRET_SIZE);
|
||||
|
||||
optiga_result res = optiga_pin_stretch_common(ui_progress, &ctx, result);
|
||||
optiga_result res =
|
||||
optiga_pin_stretch_common(ui_progress, &ctx, secret, true);
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
memzero(result, sizeof(result));
|
||||
memzero(&ctx, sizeof(ctx));
|
||||
return res;
|
||||
}
|
||||
|
||||
hmac_sha256_Final(&ctx, result);
|
||||
}
|
||||
|
||||
memcpy(secret, result, sizeof(result));
|
||||
memzero(result, sizeof(result));
|
||||
hmac_sha256_Final(&ctx, secret);
|
||||
memzero(&ctx, sizeof(ctx));
|
||||
return OPTIGA_SUCCESS;
|
||||
}
|
||||
|
||||
static int optiga_pin_stretch_secret(
|
||||
static int optiga_pin_stretch_cmac_ecdh(
|
||||
OPTIGA_UI_PROGRESS ui_progress,
|
||||
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
||||
// This step hardens the PIN verification process in case an attacker is able
|
||||
@ -478,15 +469,14 @@ static int optiga_pin_stretch_secret(
|
||||
// search for the PIN. Thus it reduces the number of PIN values that the
|
||||
// attacker can test in a unit of time by forcing them to involve the Optiga
|
||||
// in each attempt, and restricts the overall number of attempts using
|
||||
// OID_PIN_STRETCH_COUNTER.
|
||||
// OID_PIN_TOTAL_CTR.
|
||||
|
||||
// Pseudocode for the stretching process:
|
||||
// for i in range(PIN_STRETCH_ITERATIONS):
|
||||
// digest = HMAC(secret, "")
|
||||
// cmac_i = CMAC(optiga_cmac_key, digest)
|
||||
// hmac_i = HMAC(optiga_hmac_key, digest)
|
||||
// ecdh_i = ECDH(optiga_ecdh_key, digest)
|
||||
// secret = HMAC-SHA256(secret, cmac_i || hmac_i || ecdh_i)
|
||||
// for _ in range(PIN_STRETCH_ITERATIONS):
|
||||
// digest = HMAC-SHA256(stretched_pin, "")
|
||||
// cmac_out = CMAC(OID_PIN_CMAC, digest)
|
||||
// ecdh_out = ECDH(OID_PIN_ECDH, digest)
|
||||
// stretched_pin = HMAC-SHA256(stretched_pin, cmac_out || ecdh_out)
|
||||
|
||||
uint8_t digest[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||
HMAC_SHA256_CTX ctx = {0};
|
||||
@ -498,7 +488,8 @@ static int optiga_pin_stretch_secret(
|
||||
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, NULL, 0, digest);
|
||||
hmac_sha256_Init(&ctx, stretched_pin, OPTIGA_PIN_SECRET_SIZE);
|
||||
|
||||
optiga_result res = optiga_pin_stretch_common(ui_progress, &ctx, digest);
|
||||
optiga_result res =
|
||||
optiga_pin_stretch_common(ui_progress, &ctx, digest, false);
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
memzero(digest, sizeof(digest));
|
||||
memzero(&ctx, sizeof(ctx));
|
||||
@ -515,13 +506,15 @@ static int optiga_pin_stretch_secret(
|
||||
|
||||
int optiga_pin_set(OPTIGA_UI_PROGRESS ui_progress,
|
||||
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
||||
int res = OPTIGA_SUCCESS;
|
||||
if (!optiga_pin_init_metadata()) {
|
||||
return -1;
|
||||
res = -1;
|
||||
goto end;
|
||||
}
|
||||
|
||||
optiga_result res = optiga_pin_init_stretch();
|
||||
res = optiga_pin_init_stretch();
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
return res;
|
||||
goto end;
|
||||
}
|
||||
|
||||
ui_progress(200);
|
||||
@ -530,43 +523,110 @@ int optiga_pin_set(OPTIGA_UI_PROGRESS ui_progress,
|
||||
// ensures that if an attacker extracts the value of OID_STRETCHED_PIN or
|
||||
// OID_PIN_SECRET, then it cannot be used to conduct an offline brute-force
|
||||
// search for the PIN.
|
||||
res = optiga_pin_stretch_secret(ui_progress, stretched_pin);
|
||||
res = optiga_pin_stretch_cmac_ecdh(ui_progress, stretched_pin);
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
return res;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Generate and store the counter-protected PIN secret.
|
||||
uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||
res = optiga_get_random(pin_secret, sizeof(pin_secret));
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
return res;
|
||||
goto end;
|
||||
}
|
||||
random_xor(pin_secret, sizeof(pin_secret));
|
||||
|
||||
res = optiga_set_data_object(OID_PIN_SECRET, false, pin_secret,
|
||||
sizeof(pin_secret));
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
return res;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Authorise using OID_PIN_SECRET so that we can write to OID_PIN_COUNTER and
|
||||
// OID_STRETCHED_PIN.
|
||||
// Generate the key for the HMAC-SHA256 PIN stretching step.
|
||||
uint8_t pin_hmac[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||
res = optiga_get_random(pin_hmac, sizeof(pin_hmac));
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
goto end;
|
||||
}
|
||||
random_xor(pin_hmac, sizeof(pin_hmac));
|
||||
|
||||
// Authorise using OID_PIN_SECRET so that we can write to OID_STRETCHED_PIN
|
||||
// and OID_STRETCHED_PIN_CTR.
|
||||
res = optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_PIN_SECRET,
|
||||
pin_secret, sizeof(pin_secret));
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
return res;
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Process the stretched PIN using a one-way function before using it in the
|
||||
// operation that will be executed in Optiga during verification. This ensures
|
||||
// that in the unlikely case of an attacker recording communication between
|
||||
// the MCU and Optiga, they will not gain knowledge of the stretched PIN.
|
||||
uint8_t digest[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, NULL, 0, digest);
|
||||
|
||||
// Compute the operation that will be executed in Optiga during verification.
|
||||
uint8_t hmac_buffer[ENCRYPT_SYM_PREFIX_SIZE + OPTIGA_PIN_SECRET_SIZE] = {
|
||||
0x61, 0x00, 0x20};
|
||||
hmac_sha256(pin_hmac, sizeof(pin_hmac), digest, sizeof(digest),
|
||||
&hmac_buffer[ENCRYPT_SYM_PREFIX_SIZE]);
|
||||
|
||||
// Stretch the PIN with the result.
|
||||
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, hmac_buffer,
|
||||
sizeof(hmac_buffer), stretched_pin);
|
||||
|
||||
// Process the stretched PIN using a one-way function before sending it to the
|
||||
// Optiga. This ensures that in the unlikely case of an attacker recording
|
||||
// communication between the MCU and Optiga, they will not gain knowledge of
|
||||
// the stretched PIN.
|
||||
uint8_t digest[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, NULL, 0, digest);
|
||||
|
||||
// Store the digest of the stretched PIN in OID_STRETCHED_PIN.
|
||||
res =
|
||||
optiga_set_data_object(OID_STRETCHED_PIN, false, digest, sizeof(digest));
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Initialize the counter which limits the guesses at OID_STRETCHED_PIN so
|
||||
// that we can authorise using OID_STRETCHED_PIN.
|
||||
res = optiga_set_data_object(OID_STRETCHED_PIN_CTR, false, COUNTER_RESET,
|
||||
sizeof(COUNTER_RESET));
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Authorise using OID_STRETCHED_PIN so that we can write to OID_PIN_HMAC and
|
||||
// OID_PIN_HMAC_CTR.
|
||||
res = optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_STRETCHED_PIN, digest,
|
||||
sizeof(digest));
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Initialize the key for HMAC-SHA256 PIN stretching.
|
||||
res = optiga_set_data_object(OID_PIN_HMAC, false, pin_hmac, sizeof(pin_hmac));
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Initialize the counter which limits the guesses at OID_STRETCHED_PIN again,
|
||||
// since we just depleted one attempt.
|
||||
res = optiga_set_data_object(OID_STRETCHED_PIN_CTR, false, COUNTER_RESET,
|
||||
sizeof(COUNTER_RESET));
|
||||
optiga_clear_auto_state(OID_PIN_SECRET);
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
// Initialize the PIN counter which limits the use of OID_PIN_HMAC.
|
||||
res = optiga_set_data_object(OID_PIN_HMAC_CTR, false, COUNTER_RESET,
|
||||
sizeof(COUNTER_RESET));
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
ui_progress(200);
|
||||
|
||||
// Stretch the PIN more with the counter-protected PIN secret. This method
|
||||
// ensures that if the user chooses a high-entropy PIN, then even if the
|
||||
@ -575,26 +635,20 @@ int optiga_pin_set(OPTIGA_UI_PROGRESS ui_progress,
|
||||
// integrated into the device in the first place.
|
||||
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, pin_secret,
|
||||
sizeof(pin_secret), stretched_pin);
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
end:
|
||||
memzero(hmac_buffer, sizeof(hmac_buffer));
|
||||
memzero(pin_hmac, sizeof(pin_hmac));
|
||||
memzero(pin_secret, sizeof(pin_secret));
|
||||
memzero(digest, sizeof(digest));
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
optiga_clear_auto_state(OID_PIN_SECRET);
|
||||
optiga_clear_auto_state(OID_STRETCHED_PIN);
|
||||
return res;
|
||||
}
|
||||
|
||||
// Initialize the PIN counter.
|
||||
res = optiga_set_data_object(OID_PIN_COUNTER, false, COUNTER_RESET,
|
||||
sizeof(COUNTER_RESET));
|
||||
optiga_clear_auto_state(OID_PIN_SECRET);
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
ui_progress(200);
|
||||
|
||||
return OPTIGA_SUCCESS;
|
||||
}
|
||||
|
||||
int optiga_pin_verify_v4(OPTIGA_UI_PROGRESS ui_progress,
|
||||
const uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE],
|
||||
uint8_t out_secret[OPTIGA_PIN_SECRET_SIZE]) {
|
||||
@ -648,14 +702,6 @@ int optiga_pin_verify_v4(OPTIGA_UI_PROGRESS ui_progress,
|
||||
return res;
|
||||
}
|
||||
|
||||
// Reset the PIN counter.
|
||||
res = optiga_set_data_object(OID_PIN_COUNTER, false, COUNTER_RESET,
|
||||
sizeof(COUNTER_RESET));
|
||||
optiga_clear_auto_state(OID_PIN_SECRET);
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
ui_progress(200);
|
||||
|
||||
// Combine the value of OID_PIN_SECRET with the PIN-derived secret and
|
||||
@ -674,10 +720,47 @@ int optiga_pin_verify_v4(OPTIGA_UI_PROGRESS ui_progress,
|
||||
return OPTIGA_SUCCESS;
|
||||
}
|
||||
|
||||
static int optiga_pin_stretch_hmac(
|
||||
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
||||
// Process the stretched PIN using a one-way function before sending it to the
|
||||
// Optiga.
|
||||
uint8_t digest[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, NULL, 0, digest);
|
||||
|
||||
// HMAC the digest with the key in OID_PIN_HMAC.
|
||||
uint8_t hmac_buffer[ENCRYPT_SYM_PREFIX_SIZE + OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||
size_t size = 0;
|
||||
optiga_result res = optiga_encrypt_sym(
|
||||
OPTIGA_SYM_MODE_HMAC_SHA256, OID_PIN_HMAC, digest, sizeof(digest),
|
||||
hmac_buffer, sizeof(hmac_buffer), &size);
|
||||
memzero(digest, sizeof(digest));
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
uint8_t error_code = 0;
|
||||
optiga_get_error_code(&error_code);
|
||||
if (error_code + OPTIGA_COMMAND_ERROR_OFFSET ==
|
||||
OPTIGA_ERR_ACCESS_COND_NOT_SAT) {
|
||||
return OPTIGA_ERR_COUNTER_EXCEEDED;
|
||||
} else {
|
||||
return error_code + OPTIGA_COMMAND_ERROR_OFFSET;
|
||||
}
|
||||
}
|
||||
|
||||
// Stretch the PIN with the result.
|
||||
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, hmac_buffer, size,
|
||||
stretched_pin);
|
||||
memzero(hmac_buffer, sizeof(hmac_buffer));
|
||||
return OPTIGA_SUCCESS;
|
||||
}
|
||||
|
||||
int optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
||||
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
||||
// Stretch the PIN more with stretching secrets from the Optiga.
|
||||
optiga_result res = optiga_pin_stretch_secret(ui_progress, stretched_pin);
|
||||
optiga_result res = optiga_pin_stretch_cmac_ecdh(ui_progress, stretched_pin);
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
res = optiga_pin_stretch_hmac(stretched_pin);
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
@ -687,7 +770,8 @@ int optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
||||
uint8_t digest[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, NULL, 0, digest);
|
||||
|
||||
// Authorise using OID_STRETCHED_PIN so that we can read from OID_PIN_SECRET.
|
||||
// Authorise using OID_STRETCHED_PIN so that we can read from OID_PIN_SECRET
|
||||
// and reset OID_PIN_HMAC_CTR.
|
||||
res = optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_STRETCHED_PIN, digest,
|
||||
sizeof(digest));
|
||||
memzero(digest, sizeof(digest));
|
||||
@ -697,10 +781,16 @@ int optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
||||
return error_code + OPTIGA_COMMAND_ERROR_OFFSET;
|
||||
}
|
||||
|
||||
// Reset the counter which limits the use of OID_PIN_HMAC.
|
||||
res = optiga_set_data_object(OID_PIN_HMAC_CTR, false, COUNTER_RESET,
|
||||
sizeof(COUNTER_RESET));
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
optiga_clear_auto_state(OID_STRETCHED_PIN);
|
||||
return res;
|
||||
}
|
||||
|
||||
ui_progress(200);
|
||||
|
||||
// Read the counter-protected PIN secret from OID_PIN_SECRET.
|
||||
uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||
size_t size = 0;
|
||||
@ -711,26 +801,20 @@ int optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
||||
return res;
|
||||
}
|
||||
|
||||
if (size != OPTIGA_PIN_SECRET_SIZE) {
|
||||
return OPTIGA_ERR_SIZE;
|
||||
}
|
||||
|
||||
// Stretch the PIN more with the counter-protected PIN secret.
|
||||
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, pin_secret,
|
||||
OPTIGA_PIN_SECRET_SIZE, stretched_pin);
|
||||
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, pin_secret, size,
|
||||
stretched_pin);
|
||||
|
||||
ui_progress(200);
|
||||
|
||||
// Authorise using OID_PIN_SECRET so that we can write to OID_PIN_COUNTER.
|
||||
// Authorise using OID_PIN_SECRET so that we can reset OID_STRETCHED_PIN_CTR.
|
||||
res = optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_PIN_SECRET,
|
||||
pin_secret, OPTIGA_PIN_SECRET_SIZE);
|
||||
pin_secret, sizeof(pin_secret));
|
||||
memzero(pin_secret, sizeof(pin_secret));
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Reset the PIN counter.
|
||||
res = optiga_set_data_object(OID_PIN_COUNTER, false, COUNTER_RESET,
|
||||
// Reset the counter which limits the guesses at OID_STRETCHED_PIN.
|
||||
res = optiga_set_data_object(OID_STRETCHED_PIN_CTR, false, COUNTER_RESET,
|
||||
sizeof(COUNTER_RESET));
|
||||
optiga_clear_auto_state(OID_PIN_SECRET);
|
||||
if (res != OPTIGA_SUCCESS) {
|
||||
@ -763,8 +847,43 @@ static int optiga_get_counter(uint16_t oid, uint32_t *ctr) {
|
||||
return OPTIGA_SUCCESS;
|
||||
}
|
||||
|
||||
int optiga_pin_get_fails_v4(uint32_t *ctr) {
|
||||
return optiga_get_counter(OID_STRETCHED_PIN_CTR, ctr);
|
||||
}
|
||||
|
||||
int optiga_pin_get_fails(uint32_t *ctr) {
|
||||
return optiga_get_counter(OID_PIN_COUNTER, ctr);
|
||||
uint32_t ctr1 = 0;
|
||||
uint32_t ctr2 = 0;
|
||||
if (optiga_get_counter(OID_PIN_HMAC_CTR, &ctr1) != OPTIGA_SUCCESS ||
|
||||
optiga_get_counter(OID_STRETCHED_PIN_CTR, &ctr2) != OPTIGA_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Ensure that the counters are in sync.
|
||||
if (ctr1 > ctr2) {
|
||||
if (optiga_count_data_object(OID_STRETCHED_PIN_CTR, ctr1 - ctr2) !=
|
||||
OPTIGA_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
*ctr = ctr1;
|
||||
} else if (ctr2 > ctr1) {
|
||||
if (optiga_count_data_object(OID_PIN_HMAC_CTR, ctr2 - ctr1) !=
|
||||
OPTIGA_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
*ctr = ctr2;
|
||||
} else {
|
||||
*ctr = ctr2;
|
||||
}
|
||||
return OPTIGA_SUCCESS;
|
||||
}
|
||||
|
||||
int optiga_pin_fails_increase_v4(uint32_t count) {
|
||||
if (count > 0xff) {
|
||||
return OPTIGA_ERR_PARAM;
|
||||
}
|
||||
|
||||
return optiga_count_data_object(OID_STRETCHED_PIN_CTR, count);
|
||||
}
|
||||
|
||||
int optiga_pin_fails_increase(uint32_t count) {
|
||||
@ -772,5 +891,10 @@ int optiga_pin_fails_increase(uint32_t count) {
|
||||
return OPTIGA_ERR_PARAM;
|
||||
}
|
||||
|
||||
return optiga_count_data_object(OID_PIN_COUNTER, count);
|
||||
if (optiga_count_data_object(OID_PIN_HMAC_CTR, count) != OPTIGA_SUCCESS ||
|
||||
optiga_count_data_object(OID_STRETCHED_PIN_CTR, count) !=
|
||||
OPTIGA_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
return OPTIGA_SUCCESS;
|
||||
}
|
||||
|
@ -174,9 +174,16 @@ int optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
||||
return OPTIGA_SUCCESS;
|
||||
}
|
||||
|
||||
int optiga_pin_get_fails_v4(uint32_t *ctr) {
|
||||
*ctr = 0;
|
||||
return OPTIGA_SUCCESS;
|
||||
}
|
||||
|
||||
int optiga_pin_get_fails(uint32_t *ctr) {
|
||||
*ctr = 0;
|
||||
return OPTIGA_SUCCESS;
|
||||
}
|
||||
|
||||
int optiga_pin_fails_increase_v4(uint32_t count) { return OPTIGA_SUCCESS; }
|
||||
|
||||
int optiga_pin_fails_increase(uint32_t count) { return OPTIGA_SUCCESS; }
|
||||
|
@ -1275,8 +1275,13 @@ uint32_t storage_get_pin_rem(void) {
|
||||
#if USE_OPTIGA
|
||||
// Synchronize counters in case they diverged.
|
||||
uint32_t ctr_optiga = 0;
|
||||
ensure(
|
||||
optiga_pin_get_fails(&ctr_optiga) == OPTIGA_SUCCESS ? sectrue : secfalse,
|
||||
optiga_result ret = OPTIGA_SUCCESS;
|
||||
if (get_lock_version() >= 5) {
|
||||
ret = optiga_pin_get_fails(&ctr_optiga);
|
||||
} else {
|
||||
ret = optiga_pin_get_fails_v4(&ctr_optiga);
|
||||
}
|
||||
ensure(ret == OPTIGA_SUCCESS ? sectrue : secfalse,
|
||||
"optiga_pin_get_fails failed");
|
||||
|
||||
while (ctr_mcu < ctr_optiga) {
|
||||
@ -1285,9 +1290,12 @@ uint32_t storage_get_pin_rem(void) {
|
||||
}
|
||||
|
||||
if (ctr_optiga < ctr_mcu) {
|
||||
ensure(optiga_pin_fails_increase(ctr_mcu - ctr_optiga) == OPTIGA_SUCCESS
|
||||
? sectrue
|
||||
: secfalse,
|
||||
if (get_lock_version() >= 5) {
|
||||
ret = optiga_pin_fails_increase(ctr_mcu - ctr_optiga);
|
||||
} else {
|
||||
ret = optiga_pin_fails_increase_v4(ctr_mcu - ctr_optiga);
|
||||
}
|
||||
ensure(ret == OPTIGA_SUCCESS ? sectrue : secfalse,
|
||||
"optiga_pin_fails_increase failed");
|
||||
}
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user