mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-19 12:58:13 +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],
|
const uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE],
|
||||||
uint8_t out_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_get_fails(uint32_t *ctr);
|
||||||
|
|
||||||
|
int __wur optiga_pin_fails_increase_v4(uint32_t count);
|
||||||
|
|
||||||
int __wur optiga_pin_fails_increase(uint32_t count);
|
int __wur optiga_pin_fails_increase(uint32_t count);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -26,20 +26,29 @@
|
|||||||
#include "rand.h"
|
#include "rand.h"
|
||||||
#include "storage.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)
|
#define OID_PIN_SECRET (OPTIGA_OID_DATA + 0)
|
||||||
|
|
||||||
// PIN counter (OID 0xE120).
|
// Digest of the stretched PIN (OID 0xF1D4).
|
||||||
#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).
|
|
||||||
#define OID_STRETCHED_PIN (OPTIGA_OID_DATA + 4)
|
#define OID_STRETCHED_PIN (OPTIGA_OID_DATA + 4)
|
||||||
|
|
||||||
// Key for HMAC-SHA256 PIN stretching step (OID 0xF1D1).
|
// Counter-protected key for HMAC-SHA256 PIN stretching step (OID 0xF1D5).
|
||||||
#define OID_PIN_HMAC (OPTIGA_OID_DATA + 1)
|
#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).
|
// Key for AES-CMAC PIN stretching step (OID 0xE200).
|
||||||
#define OID_PIN_CMAC OPTIGA_OID_SYM_KEY
|
#define OID_PIN_CMAC OPTIGA_OID_SYM_KEY
|
||||||
@ -47,20 +56,17 @@
|
|||||||
// Key for ECDH PIN stretching step (OID 0xE0F3).
|
// Key for ECDH PIN stretching step (OID 0xE0F3).
|
||||||
#define OID_PIN_ECDH (OPTIGA_OID_ECC_KEY + 3)
|
#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.
|
// The number of times that PIN stretching is repeated.
|
||||||
#define PIN_STRETCH_ITERATIONS 2
|
#define PIN_STRETCH_ITERATIONS 2
|
||||||
|
|
||||||
// Value of the PIN counter when it is reset.
|
// 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};
|
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
|
// Initial value of the counter which limits the total number of PIN stretching
|
||||||
// 600000 stretching operations, which equates to
|
// operations. The limit is 600000 stretching operations, which equates to
|
||||||
// 100000 / PIN_STRETCH_ITERATIONS unlock operations.
|
// 300000 / PIN_STRETCH_ITERATIONS unlock operations over the lifetime of the
|
||||||
static const uint8_t STRETCH_COUNTER_INIT[] = {0, 0, 0, 0, 0, 0x09, 0x27, 0xC0};
|
// device.
|
||||||
|
static const uint8_t PIN_TOTAL_CTR_INIT[] = {0, 0, 0, 0, 0, 0x09, 0x27, 0xC0};
|
||||||
|
|
||||||
static const optiga_metadata_item TYPE_AUTOREF =
|
static const optiga_metadata_item TYPE_AUTOREF =
|
||||||
OPTIGA_META_VALUE(OPTIGA_DATA_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);
|
OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_AUTO, OID_STRETCHED_PIN);
|
||||||
static const optiga_metadata_item ACCESS_PIN_SECRET =
|
static const optiga_metadata_item ACCESS_PIN_SECRET =
|
||||||
OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_AUTO, OID_PIN_SECRET);
|
OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_AUTO, OID_PIN_SECRET);
|
||||||
static const optiga_metadata_item ACCESS_PIN_COUNTER =
|
static const optiga_metadata_item ACCESS_STRETCHED_PIN_CTR =
|
||||||
OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_LUC, OID_PIN_COUNTER);
|
OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_LUC, OID_STRETCHED_PIN_CTR);
|
||||||
static const optiga_metadata_item ACCESS_PIN_STRETCH_COUNTER =
|
static const optiga_metadata_item ACCESS_PIN_TOTAL_CTR =
|
||||||
OPTIGA_ACCESS_CONDITION(OPTIGA_ACCESS_COND_LUC, OID_PIN_STRETCH_COUNTER);
|
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().
|
// Size of the DER BIT STRING header required for inputs to optiga_calc_ssec().
|
||||||
#define BIT_STRING_HEADER_SIZE 3
|
#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) {
|
static bool optiga_pin_init_metadata(void) {
|
||||||
optiga_metadata metadata = {0};
|
optiga_metadata metadata = {0};
|
||||||
|
|
||||||
// Set metadata for PIN counter reset key / Master secret.
|
// Set metadata for counter-protected PIN secret.
|
||||||
memzero(&metadata, sizeof(metadata));
|
memzero(&metadata, sizeof(metadata));
|
||||||
metadata.change = OPTIGA_META_ACCESS_ALWAYS;
|
metadata.change = OPTIGA_META_ACCESS_ALWAYS;
|
||||||
metadata.read = ACCESS_STRETCHED_PIN;
|
metadata.read = ACCESS_STRETCHED_PIN;
|
||||||
@ -254,43 +262,64 @@ static bool optiga_pin_init_metadata(void) {
|
|||||||
return false;
|
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));
|
memzero(&metadata, sizeof(metadata));
|
||||||
metadata.change = ACCESS_PIN_SECRET;
|
metadata.change = ACCESS_PIN_SECRET;
|
||||||
metadata.read = OPTIGA_META_ACCESS_ALWAYS;
|
metadata.read = OPTIGA_META_ACCESS_ALWAYS;
|
||||||
metadata.execute = 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;
|
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));
|
memzero(&metadata, sizeof(metadata));
|
||||||
metadata.change = OPTIGA_META_ACCESS_ALWAYS;
|
metadata.change = OPTIGA_META_ACCESS_ALWAYS;
|
||||||
if (write_metadata(OID_PIN_STRETCH_COUNTER, &metadata)) {
|
if (write_metadata(OID_PIN_TOTAL_CTR, &metadata)) {
|
||||||
optiga_result res = optiga_set_data_object(OID_PIN_STRETCH_COUNTER, false,
|
optiga_result res =
|
||||||
STRETCH_COUNTER_INIT,
|
optiga_set_data_object(OID_PIN_TOTAL_CTR, false, PIN_TOTAL_CTR_INIT,
|
||||||
sizeof(STRETCH_COUNTER_INIT));
|
sizeof(PIN_TOTAL_CTR_INIT));
|
||||||
if (res != OPTIGA_SUCCESS) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
return false;
|
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));
|
memzero(&metadata, sizeof(metadata));
|
||||||
metadata.change = OPTIGA_META_ACCESS_NEVER;
|
metadata.change = OPTIGA_META_ACCESS_NEVER;
|
||||||
metadata.read = OPTIGA_META_ACCESS_ALWAYS;
|
metadata.read = OPTIGA_META_ACCESS_ALWAYS;
|
||||||
metadata.execute = OPTIGA_META_ACCESS_ALWAYS;
|
metadata.execute = OPTIGA_META_ACCESS_ALWAYS;
|
||||||
if (!optiga_set_metadata(OID_PIN_STRETCH_COUNTER, &metadata)) {
|
if (!optiga_set_metadata(OID_PIN_TOTAL_CTR, &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)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -298,7 +327,7 @@ static bool optiga_pin_init_metadata(void) {
|
|||||||
memzero(&metadata, sizeof(metadata));
|
memzero(&metadata, sizeof(metadata));
|
||||||
metadata.change = OPTIGA_META_ACCESS_ALWAYS;
|
metadata.change = OPTIGA_META_ACCESS_ALWAYS;
|
||||||
metadata.read = OPTIGA_META_ACCESS_NEVER;
|
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;
|
metadata.key_usage = OPTIGA_META_KEY_USE_ENC;
|
||||||
if (!optiga_set_metadata(OID_PIN_CMAC, &metadata)) {
|
if (!optiga_set_metadata(OID_PIN_CMAC, &metadata)) {
|
||||||
return false;
|
return false;
|
||||||
@ -308,41 +337,12 @@ static bool optiga_pin_init_metadata(void) {
|
|||||||
memzero(&metadata, sizeof(metadata));
|
memzero(&metadata, sizeof(metadata));
|
||||||
metadata.change = OPTIGA_META_ACCESS_ALWAYS;
|
metadata.change = OPTIGA_META_ACCESS_ALWAYS;
|
||||||
metadata.read = OPTIGA_META_ACCESS_NEVER;
|
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;
|
metadata.key_usage = OPTIGA_META_KEY_USE_KEYAGREE;
|
||||||
if (!optiga_set_metadata(OID_PIN_ECDH, &metadata)) {
|
if (!optiga_set_metadata(OID_PIN_ECDH, &metadata)) {
|
||||||
return false;
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -369,9 +369,10 @@ static int optiga_pin_init_stretch(void) {
|
|||||||
|
|
||||||
static int optiga_pin_stretch_common(
|
static int optiga_pin_stretch_common(
|
||||||
OPTIGA_UI_PROGRESS ui_progress, HMAC_SHA256_CTX *ctx,
|
OPTIGA_UI_PROGRESS ui_progress, HMAC_SHA256_CTX *ctx,
|
||||||
const uint8_t input[OPTIGA_PIN_SECRET_SIZE]) {
|
const uint8_t input[OPTIGA_PIN_SECRET_SIZE], bool version4) {
|
||||||
// Implements the functionality that is common to optiga_pin_stretch_secret()
|
// Implements the functionality that is common to
|
||||||
// and the legacy function optiga_pin_stretch_secret_v4().
|
// 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};
|
uint8_t buffer[ENCRYPT_SYM_PREFIX_SIZE + OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
@ -387,16 +388,18 @@ static int optiga_pin_stretch_common(
|
|||||||
|
|
||||||
hmac_sha256_Update(ctx, buffer, size);
|
hmac_sha256_Update(ctx, buffer, size);
|
||||||
|
|
||||||
|
if (version4) {
|
||||||
// Combine intermediate result with OID_PIN_HMAC
|
// Combine intermediate result with OID_PIN_HMAC
|
||||||
res =
|
res = optiga_encrypt_sym(OPTIGA_SYM_MODE_HMAC_SHA256, OID_PIN_HMAC_V4,
|
||||||
optiga_encrypt_sym(OPTIGA_SYM_MODE_HMAC_SHA256, OID_PIN_HMAC, input,
|
input, OPTIGA_PIN_SECRET_SIZE, buffer,
|
||||||
OPTIGA_PIN_SECRET_SIZE, buffer, sizeof(buffer), &size);
|
sizeof(buffer), &size);
|
||||||
if (res != OPTIGA_SUCCESS) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
memzero(buffer, sizeof(buffer));
|
memzero(buffer, sizeof(buffer));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
hmac_sha256_Update(ctx, buffer, size);
|
hmac_sha256_Update(ctx, buffer, size);
|
||||||
|
}
|
||||||
|
|
||||||
ui_progress(200);
|
ui_progress(200);
|
||||||
|
|
||||||
@ -435,39 +438,27 @@ static int optiga_pin_stretch_secret_v4(
|
|||||||
// in each attempt.
|
// in each attempt.
|
||||||
|
|
||||||
// Pseudocode for the stretching process:
|
// Pseudocode for the stretching process:
|
||||||
// result_0 = secret
|
// cmac_out = CMAC(OID_PIN_CMAC, secret)
|
||||||
// for i in range(PIN_STRETCH_ITERATIONS_V4):
|
// hmac_out = HMAC(OID_PIN_HMAC_V4, secret)
|
||||||
// cmac_i = CMAC(optiga_cmac_key, result_i)
|
// ecdh_out = ECDH(OID_PIN_ECDH, secret)
|
||||||
// hmac_i = HMAC(optiga_hmac_key, result_i)
|
// secret = HMAC-SHA256(secret, cmac_out || hmac_out || ecdh_out)
|
||||||
// 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}
|
|
||||||
|
|
||||||
HMAC_SHA256_CTX ctx = {0};
|
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);
|
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) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
memzero(result, sizeof(result));
|
|
||||||
memzero(&ctx, sizeof(ctx));
|
memzero(&ctx, sizeof(ctx));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
hmac_sha256_Final(&ctx, result);
|
hmac_sha256_Final(&ctx, secret);
|
||||||
}
|
|
||||||
|
|
||||||
memcpy(secret, result, sizeof(result));
|
|
||||||
memzero(result, sizeof(result));
|
|
||||||
memzero(&ctx, sizeof(ctx));
|
memzero(&ctx, sizeof(ctx));
|
||||||
return OPTIGA_SUCCESS;
|
return OPTIGA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int optiga_pin_stretch_secret(
|
static int optiga_pin_stretch_cmac_ecdh(
|
||||||
OPTIGA_UI_PROGRESS ui_progress,
|
OPTIGA_UI_PROGRESS ui_progress,
|
||||||
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
||||||
// This step hardens the PIN verification process in case an attacker is able
|
// 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
|
// 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
|
// 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
|
// in each attempt, and restricts the overall number of attempts using
|
||||||
// OID_PIN_STRETCH_COUNTER.
|
// OID_PIN_TOTAL_CTR.
|
||||||
|
|
||||||
// Pseudocode for the stretching process:
|
// Pseudocode for the stretching process:
|
||||||
// for i in range(PIN_STRETCH_ITERATIONS):
|
// for _ in range(PIN_STRETCH_ITERATIONS):
|
||||||
// digest = HMAC(secret, "")
|
// digest = HMAC-SHA256(stretched_pin, "")
|
||||||
// cmac_i = CMAC(optiga_cmac_key, digest)
|
// cmac_out = CMAC(OID_PIN_CMAC, digest)
|
||||||
// hmac_i = HMAC(optiga_hmac_key, digest)
|
// ecdh_out = ECDH(OID_PIN_ECDH, digest)
|
||||||
// ecdh_i = ECDH(optiga_ecdh_key, digest)
|
// stretched_pin = HMAC-SHA256(stretched_pin, cmac_out || ecdh_out)
|
||||||
// secret = HMAC-SHA256(secret, cmac_i || hmac_i || ecdh_i)
|
|
||||||
|
|
||||||
uint8_t digest[OPTIGA_PIN_SECRET_SIZE] = {0};
|
uint8_t digest[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||||
HMAC_SHA256_CTX ctx = {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(stretched_pin, OPTIGA_PIN_SECRET_SIZE, NULL, 0, digest);
|
||||||
hmac_sha256_Init(&ctx, stretched_pin, OPTIGA_PIN_SECRET_SIZE);
|
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) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
memzero(digest, sizeof(digest));
|
memzero(digest, sizeof(digest));
|
||||||
memzero(&ctx, sizeof(ctx));
|
memzero(&ctx, sizeof(ctx));
|
||||||
@ -515,13 +506,15 @@ static int optiga_pin_stretch_secret(
|
|||||||
|
|
||||||
int optiga_pin_set(OPTIGA_UI_PROGRESS ui_progress,
|
int optiga_pin_set(OPTIGA_UI_PROGRESS ui_progress,
|
||||||
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
||||||
|
int res = OPTIGA_SUCCESS;
|
||||||
if (!optiga_pin_init_metadata()) {
|
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) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
return res;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_progress(200);
|
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
|
// 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
|
// OID_PIN_SECRET, then it cannot be used to conduct an offline brute-force
|
||||||
// search for the PIN.
|
// 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) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
return res;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate and store the counter-protected PIN secret.
|
// Generate and store the counter-protected PIN secret.
|
||||||
uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE] = {0};
|
uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||||
res = optiga_get_random(pin_secret, sizeof(pin_secret));
|
res = optiga_get_random(pin_secret, sizeof(pin_secret));
|
||||||
if (res != OPTIGA_SUCCESS) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
return res;
|
goto end;
|
||||||
}
|
}
|
||||||
random_xor(pin_secret, sizeof(pin_secret));
|
random_xor(pin_secret, sizeof(pin_secret));
|
||||||
|
|
||||||
res = optiga_set_data_object(OID_PIN_SECRET, false, pin_secret,
|
res = optiga_set_data_object(OID_PIN_SECRET, false, pin_secret,
|
||||||
sizeof(pin_secret));
|
sizeof(pin_secret));
|
||||||
if (res != OPTIGA_SUCCESS) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
return res;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authorise using OID_PIN_SECRET so that we can write to OID_PIN_COUNTER and
|
// Generate the key for the HMAC-SHA256 PIN stretching step.
|
||||||
// OID_STRETCHED_PIN.
|
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,
|
res = optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_PIN_SECRET,
|
||||||
pin_secret, sizeof(pin_secret));
|
pin_secret, sizeof(pin_secret));
|
||||||
if (res != OPTIGA_SUCCESS) {
|
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
|
// 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
|
// Optiga. This ensures that in the unlikely case of an attacker recording
|
||||||
// communication between the MCU and Optiga, they will not gain knowledge of
|
// communication between the MCU and Optiga, they will not gain knowledge of
|
||||||
// the stretched PIN.
|
// the stretched PIN.
|
||||||
uint8_t digest[OPTIGA_PIN_SECRET_SIZE] = {0};
|
|
||||||
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, NULL, 0, digest);
|
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, NULL, 0, digest);
|
||||||
|
|
||||||
// Store the digest of the stretched PIN in OID_STRETCHED_PIN.
|
// Store the digest of the stretched PIN in OID_STRETCHED_PIN.
|
||||||
res =
|
res =
|
||||||
optiga_set_data_object(OID_STRETCHED_PIN, false, digest, sizeof(digest));
|
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
|
// 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
|
// 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.
|
// integrated into the device in the first place.
|
||||||
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, pin_secret,
|
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, pin_secret,
|
||||||
sizeof(pin_secret), stretched_pin);
|
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(pin_secret, sizeof(pin_secret));
|
||||||
memzero(digest, sizeof(digest));
|
memzero(digest, sizeof(digest));
|
||||||
if (res != OPTIGA_SUCCESS) {
|
|
||||||
optiga_clear_auto_state(OID_PIN_SECRET);
|
optiga_clear_auto_state(OID_PIN_SECRET);
|
||||||
|
optiga_clear_auto_state(OID_STRETCHED_PIN);
|
||||||
return res;
|
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,
|
int optiga_pin_verify_v4(OPTIGA_UI_PROGRESS ui_progress,
|
||||||
const uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE],
|
const uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE],
|
||||||
uint8_t out_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;
|
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);
|
ui_progress(200);
|
||||||
|
|
||||||
// Combine the value of OID_PIN_SECRET with the PIN-derived secret and
|
// 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;
|
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,
|
int optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
||||||
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
||||||
// Stretch the PIN more with stretching secrets from the Optiga.
|
// 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) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -687,7 +770,8 @@ int optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
|||||||
uint8_t digest[OPTIGA_PIN_SECRET_SIZE] = {0};
|
uint8_t digest[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||||
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, NULL, 0, digest);
|
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,
|
res = optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_STRETCHED_PIN, digest,
|
||||||
sizeof(digest));
|
sizeof(digest));
|
||||||
memzero(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;
|
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) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
|
optiga_clear_auto_state(OID_STRETCHED_PIN);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ui_progress(200);
|
||||||
|
|
||||||
// Read the counter-protected PIN secret from OID_PIN_SECRET.
|
// Read the counter-protected PIN secret from OID_PIN_SECRET.
|
||||||
uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE] = {0};
|
uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
@ -711,26 +801,20 @@ int optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (size != OPTIGA_PIN_SECRET_SIZE) {
|
|
||||||
return OPTIGA_ERR_SIZE;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stretch the PIN more with the counter-protected PIN secret.
|
// Stretch the PIN more with the counter-protected PIN secret.
|
||||||
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, pin_secret,
|
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, pin_secret, size,
|
||||||
OPTIGA_PIN_SECRET_SIZE, stretched_pin);
|
stretched_pin);
|
||||||
|
|
||||||
ui_progress(200);
|
// Authorise using OID_PIN_SECRET so that we can reset OID_STRETCHED_PIN_CTR.
|
||||||
|
|
||||||
// Authorise using OID_PIN_SECRET so that we can write to OID_PIN_COUNTER.
|
|
||||||
res = optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_PIN_SECRET,
|
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));
|
memzero(pin_secret, sizeof(pin_secret));
|
||||||
if (res != OPTIGA_SUCCESS) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the PIN counter.
|
// Reset the counter which limits the guesses at OID_STRETCHED_PIN.
|
||||||
res = optiga_set_data_object(OID_PIN_COUNTER, false, COUNTER_RESET,
|
res = optiga_set_data_object(OID_STRETCHED_PIN_CTR, false, COUNTER_RESET,
|
||||||
sizeof(COUNTER_RESET));
|
sizeof(COUNTER_RESET));
|
||||||
optiga_clear_auto_state(OID_PIN_SECRET);
|
optiga_clear_auto_state(OID_PIN_SECRET);
|
||||||
if (res != OPTIGA_SUCCESS) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
@ -763,8 +847,43 @@ static int optiga_get_counter(uint16_t oid, uint32_t *ctr) {
|
|||||||
return OPTIGA_SUCCESS;
|
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) {
|
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) {
|
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_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;
|
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) {
|
int optiga_pin_get_fails(uint32_t *ctr) {
|
||||||
*ctr = 0;
|
*ctr = 0;
|
||||||
return OPTIGA_SUCCESS;
|
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; }
|
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
|
#if USE_OPTIGA
|
||||||
// Synchronize counters in case they diverged.
|
// Synchronize counters in case they diverged.
|
||||||
uint32_t ctr_optiga = 0;
|
uint32_t ctr_optiga = 0;
|
||||||
ensure(
|
optiga_result ret = OPTIGA_SUCCESS;
|
||||||
optiga_pin_get_fails(&ctr_optiga) == OPTIGA_SUCCESS ? sectrue : secfalse,
|
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");
|
"optiga_pin_get_fails failed");
|
||||||
|
|
||||||
while (ctr_mcu < ctr_optiga) {
|
while (ctr_mcu < ctr_optiga) {
|
||||||
@ -1285,9 +1290,12 @@ uint32_t storage_get_pin_rem(void) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (ctr_optiga < ctr_mcu) {
|
if (ctr_optiga < ctr_mcu) {
|
||||||
ensure(optiga_pin_fails_increase(ctr_mcu - ctr_optiga) == OPTIGA_SUCCESS
|
if (get_lock_version() >= 5) {
|
||||||
? sectrue
|
ret = optiga_pin_fails_increase(ctr_mcu - ctr_optiga);
|
||||||
: secfalse,
|
} else {
|
||||||
|
ret = optiga_pin_fails_increase_v4(ctr_mcu - ctr_optiga);
|
||||||
|
}
|
||||||
|
ensure(ret == OPTIGA_SUCCESS ? sectrue : secfalse,
|
||||||
"optiga_pin_fails_increase failed");
|
"optiga_pin_fails_increase failed");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user