1
0
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:
Andrew Kozlik 2024-06-13 18:24:09 +02:00 committed by Andrew Kozlik
parent 9c50e15cf7
commit 509e291118
4 changed files with 316 additions and 173 deletions

View File

@ -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

View File

@ -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;
}

View File

@ -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; }

View File

@ -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