mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-22 06:18:07 +00:00
feat(core): Rework Optiga PIN processing.
This commit is contained in:
parent
ecf31610b0
commit
7b636df35f
@ -60,10 +60,12 @@ bool __wur optiga_read_cert(uint8_t index, uint8_t *cert, size_t max_cert_size,
|
|||||||
bool __wur optiga_random_buffer(uint8_t *dest, size_t size);
|
bool __wur optiga_random_buffer(uint8_t *dest, size_t size);
|
||||||
|
|
||||||
int __wur optiga_pin_set(OPTIGA_UI_PROGRESS ui_progress,
|
int __wur optiga_pin_set(OPTIGA_UI_PROGRESS ui_progress,
|
||||||
const uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE],
|
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]);
|
||||||
uint8_t out_secret[OPTIGA_PIN_SECRET_SIZE]);
|
|
||||||
|
|
||||||
int __wur optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
int __wur optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
||||||
|
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]);
|
||||||
|
|
||||||
|
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]);
|
||||||
|
|
||||||
|
@ -47,8 +47,12 @@
|
|||||||
// 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.
|
// The number of times the stretching is repeated in each PIN processing phase
|
||||||
#define PIN_STRETCH_ITERATIONS 1
|
// 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.
|
// 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};
|
||||||
@ -363,8 +367,64 @@ static int optiga_pin_init_stretch(void) {
|
|||||||
return OPTIGA_SUCCESS;
|
return OPTIGA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int optiga_pin_stretch_secret(OPTIGA_UI_PROGRESS ui_progress,
|
static int optiga_pin_stretch_common(
|
||||||
uint8_t secret[OPTIGA_PIN_SECRET_SIZE]) {
|
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().
|
||||||
|
|
||||||
|
uint8_t buffer[ENCRYPT_SYM_PREFIX_SIZE + OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||||
|
size_t size = 0;
|
||||||
|
|
||||||
|
// Combine intermediate result with OID_PIN_CMAC.
|
||||||
|
optiga_result res =
|
||||||
|
optiga_encrypt_sym(OPTIGA_SYM_MODE_CMAC, OID_PIN_CMAC, 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);
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
if (res != OPTIGA_SUCCESS) {
|
||||||
|
memzero(buffer, sizeof(buffer));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
hmac_sha256_Update(ctx, buffer, size);
|
||||||
|
|
||||||
|
ui_progress(200);
|
||||||
|
|
||||||
|
// Combine intermediate result with OID_PIN_ECDH
|
||||||
|
uint8_t encoded_point[BIT_STRING_HEADER_SIZE + 65] = {0x03, 0x42, 0x00};
|
||||||
|
if (!hash_to_curve_optiga(input, &encoded_point[BIT_STRING_HEADER_SIZE])) {
|
||||||
|
memzero(buffer, sizeof(buffer));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
res = optiga_calc_ssec(OPTIGA_CURVE_P256, OID_PIN_ECDH, encoded_point,
|
||||||
|
sizeof(encoded_point), buffer, sizeof(buffer), &size);
|
||||||
|
memzero(encoded_point, sizeof(encoded_point));
|
||||||
|
if (res != OPTIGA_SUCCESS) {
|
||||||
|
memzero(buffer, sizeof(buffer));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_progress(200);
|
||||||
|
|
||||||
|
hmac_sha256_Update(ctx, buffer, size);
|
||||||
|
memzero(buffer, sizeof(buffer));
|
||||||
|
return OPTIGA_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int optiga_pin_stretch_secret_v4(
|
||||||
|
OPTIGA_UI_PROGRESS ui_progress, uint8_t secret[OPTIGA_PIN_SECRET_SIZE]) {
|
||||||
|
// Legacy PIN verification method used in storage versions 3 and 4.
|
||||||
|
|
||||||
// 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
|
||||||
// to extract the secret value of a data object in Optiga that has a
|
// to extract the secret value of a data object in Optiga that has a
|
||||||
// particular configuration, but does not allow secret extraction for other
|
// particular configuration, but does not allow secret extraction for other
|
||||||
@ -376,86 +436,85 @@ static int optiga_pin_stretch_secret(OPTIGA_UI_PROGRESS ui_progress,
|
|||||||
|
|
||||||
// Pseudocode for the stretching process:
|
// Pseudocode for the stretching process:
|
||||||
// result_0 = secret
|
// result_0 = secret
|
||||||
// for i in range(PIN_STRETCH_ITERATIONS):
|
// for i in range(PIN_STRETCH_ITERATIONS_V4):
|
||||||
// cmac_i = CMAC(optiga_cmac_key, result_i)
|
// cmac_i = CMAC(optiga_cmac_key, result_i)
|
||||||
// hmac_i = HMAC(optiga_hmac_key, result_i)
|
// hmac_i = HMAC(optiga_hmac_key, result_i)
|
||||||
// ecdh_i = ECDH(optiga_ecdh_key, result_i)
|
// ecdh_i = ECDH(optiga_ecdh_key, result_i)
|
||||||
// result_{i+1} = HMAC-SHA256(secret, cmac_i || hmac_i || ecdh_i)
|
// result_{i+1} = HMAC-SHA256(secret, cmac_i || hmac_i || ecdh_i)
|
||||||
// secret = result_{PIN_STRETCH_ITERATIONS}
|
// secret = result_{PIN_STRETCH_ITERATIONS_V4}
|
||||||
|
|
||||||
HMAC_SHA256_CTX ctx = {0};
|
HMAC_SHA256_CTX ctx = {0};
|
||||||
|
|
||||||
uint8_t result[OPTIGA_PIN_SECRET_SIZE] = {0};
|
uint8_t result[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||||
memcpy(result, secret, sizeof(result));
|
memcpy(result, secret, sizeof(result));
|
||||||
|
|
||||||
uint8_t buffer[ENCRYPT_SYM_PREFIX_SIZE + OPTIGA_PIN_SECRET_SIZE] = {0};
|
for (int i = 0; i < PIN_STRETCH_ITERATIONS_V4; ++i) {
|
||||||
size_t size = 0;
|
|
||||||
for (int i = 0; i < PIN_STRETCH_ITERATIONS; ++i) {
|
|
||||||
hmac_sha256_Init(&ctx, secret, OPTIGA_PIN_SECRET_SIZE);
|
hmac_sha256_Init(&ctx, secret, OPTIGA_PIN_SECRET_SIZE);
|
||||||
|
|
||||||
// Combine intermediate result with OID_PIN_CMAC.
|
optiga_result res = optiga_pin_stretch_common(ui_progress, &ctx, result);
|
||||||
optiga_result res =
|
|
||||||
optiga_encrypt_sym(OPTIGA_SYM_MODE_CMAC, OID_PIN_CMAC, result,
|
|
||||||
sizeof(result), buffer, sizeof(buffer), &size);
|
|
||||||
if (res != OPTIGA_SUCCESS) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
memzero(buffer, sizeof(buffer));
|
|
||||||
memzero(result, sizeof(result));
|
memzero(result, sizeof(result));
|
||||||
memzero(&ctx, sizeof(ctx));
|
memzero(&ctx, sizeof(ctx));
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
hmac_sha256_Update(&ctx, buffer, size);
|
|
||||||
|
|
||||||
// Combine intermediate result with OID_PIN_HMAC
|
|
||||||
res = optiga_encrypt_sym(OPTIGA_SYM_MODE_HMAC_SHA256, OID_PIN_HMAC, result,
|
|
||||||
sizeof(result), buffer, sizeof(buffer), &size);
|
|
||||||
if (res != OPTIGA_SUCCESS) {
|
|
||||||
memzero(buffer, sizeof(buffer));
|
|
||||||
memzero(result, sizeof(result));
|
|
||||||
memzero(&ctx, sizeof(ctx));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
hmac_sha256_Update(&ctx, buffer, size);
|
|
||||||
|
|
||||||
ui_progress(200);
|
|
||||||
|
|
||||||
// Combine intermediate result with OID_PIN_ECDH
|
|
||||||
uint8_t encoded_point[BIT_STRING_HEADER_SIZE + 65] = {0x03, 0x42, 0x00};
|
|
||||||
if (!hash_to_curve_optiga(result, &encoded_point[BIT_STRING_HEADER_SIZE])) {
|
|
||||||
memzero(buffer, sizeof(buffer));
|
|
||||||
memzero(result, sizeof(result));
|
|
||||||
memzero(&ctx, sizeof(ctx));
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
res =
|
|
||||||
optiga_calc_ssec(OPTIGA_CURVE_P256, OID_PIN_ECDH, encoded_point,
|
|
||||||
sizeof(encoded_point), buffer, sizeof(buffer), &size);
|
|
||||||
memzero(encoded_point, sizeof(encoded_point));
|
|
||||||
if (res != OPTIGA_SUCCESS) {
|
|
||||||
memzero(buffer, sizeof(buffer));
|
|
||||||
memzero(result, sizeof(result));
|
|
||||||
memzero(&ctx, sizeof(ctx));
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
hmac_sha256_Update(&ctx, buffer, size);
|
|
||||||
|
|
||||||
hmac_sha256_Final(&ctx, result);
|
hmac_sha256_Final(&ctx, result);
|
||||||
|
|
||||||
ui_progress(200);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(secret, result, sizeof(result));
|
memcpy(secret, result, sizeof(result));
|
||||||
memzero(buffer, sizeof(buffer));
|
|
||||||
memzero(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(
|
||||||
|
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
|
||||||
|
// to extract the secret value of a data object in Optiga that has a
|
||||||
|
// particular configuration, but does not allow secret extraction for other
|
||||||
|
// kinds of data objects. An attacker would need to be able to extract each of
|
||||||
|
// the secrets in the different data objects to conduct an offline brute-force
|
||||||
|
// 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.
|
||||||
|
|
||||||
|
// 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)
|
||||||
|
|
||||||
|
uint8_t digest[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||||
|
HMAC_SHA256_CTX ctx = {0};
|
||||||
|
for (int i = 0; i < PIN_STRETCH_ITERATIONS; ++i) {
|
||||||
|
// 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.
|
||||||
|
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);
|
||||||
|
if (res != OPTIGA_SUCCESS) {
|
||||||
|
memzero(digest, sizeof(digest));
|
||||||
|
memzero(&ctx, sizeof(ctx));
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
hmac_sha256_Final(&ctx, stretched_pin);
|
||||||
|
}
|
||||||
|
|
||||||
|
memzero(digest, sizeof(digest));
|
||||||
|
memzero(&ctx, sizeof(ctx));
|
||||||
|
return OPTIGA_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
int optiga_pin_set(OPTIGA_UI_PROGRESS ui_progress,
|
int optiga_pin_set(OPTIGA_UI_PROGRESS ui_progress,
|
||||||
const uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE],
|
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
||||||
uint8_t out_secret[OPTIGA_PIN_SECRET_SIZE]) {
|
|
||||||
if (!optiga_pin_init_metadata()) {
|
if (!optiga_pin_init_metadata()) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -467,50 +526,57 @@ int optiga_pin_set(OPTIGA_UI_PROGRESS ui_progress,
|
|||||||
|
|
||||||
ui_progress(200);
|
ui_progress(200);
|
||||||
|
|
||||||
// Process the PIN-derived secret using a one-way function before sending it
|
// Stretch the PIN more with stretching secrets from the Optiga. This step
|
||||||
// to the Optiga. This ensures that in the unlikely case of an attacker
|
// ensures that if an attacker extracts the value of OID_STRETCHED_PIN or
|
||||||
// recording communication between the MCU and Optiga, they will not gain
|
// OID_PIN_SECRET, then it cannot be used to conduct an offline brute-force
|
||||||
// knowledge of the PIN-derived secret.
|
// search for the PIN.
|
||||||
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE] = {0};
|
|
||||||
hmac_sha256(pin_secret, OPTIGA_PIN_SECRET_SIZE, NULL, 0, stretched_pin);
|
|
||||||
|
|
||||||
// Combine the result with stretching secrets from the Optiga. This step
|
|
||||||
// ensures that if an attacker extracts the value of OID_STRETCHED_PIN, 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_secret(ui_progress, stretched_pin);
|
||||||
if (res != OPTIGA_SUCCESS) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
memzero(stretched_pin, sizeof(stretched_pin));
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate and store the master secret / PIN counter reset key.
|
// Generate and store the counter-protected PIN secret.
|
||||||
res = optiga_get_random(out_secret, OPTIGA_PIN_SECRET_SIZE);
|
uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||||
|
res = optiga_get_random(pin_secret, sizeof(pin_secret));
|
||||||
if (res != OPTIGA_SUCCESS) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
memzero(stretched_pin, sizeof(stretched_pin));
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
random_xor(out_secret, OPTIGA_PIN_SECRET_SIZE);
|
random_xor(pin_secret, sizeof(pin_secret));
|
||||||
|
|
||||||
res = optiga_set_data_object(OID_PIN_SECRET, false, out_secret,
|
res = optiga_set_data_object(OID_PIN_SECRET, false, pin_secret,
|
||||||
OPTIGA_PIN_SECRET_SIZE);
|
sizeof(pin_secret));
|
||||||
if (res != OPTIGA_SUCCESS) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
memzero(stretched_pin, sizeof(stretched_pin));
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authorise using OID_PIN_SECRET so that we can write to OID_PIN_COUNTER and
|
// Authorise using OID_PIN_SECRET so that we can write to OID_PIN_COUNTER and
|
||||||
// OID_STRETCHED_PIN.
|
// OID_STRETCHED_PIN.
|
||||||
res = optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_PIN_SECRET,
|
res = optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_PIN_SECRET,
|
||||||
out_secret, OPTIGA_PIN_SECRET_SIZE);
|
pin_secret, sizeof(pin_secret));
|
||||||
if (res != OPTIGA_SUCCESS) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
memzero(stretched_pin, sizeof(stretched_pin));
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the stretched PIN.
|
// Process the stretched PIN using a one-way function before sending it to the
|
||||||
res = optiga_set_data_object(OID_STRETCHED_PIN, false, stretched_pin,
|
// Optiga. This ensures that in the unlikely case of an attacker recording
|
||||||
sizeof(stretched_pin));
|
// communication between the MCU and Optiga, they will not gain knowledge of
|
||||||
memzero(stretched_pin, sizeof(stretched_pin));
|
// 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));
|
||||||
|
|
||||||
|
// 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
|
||||||
|
// Optiga and its communication link is completely compromised, it will not
|
||||||
|
// reduce the security of their device any more than if the Optiga was not
|
||||||
|
// integrated into the device in the first place.
|
||||||
|
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, pin_secret,
|
||||||
|
sizeof(pin_secret), stretched_pin);
|
||||||
|
memzero(pin_secret, sizeof(pin_secret));
|
||||||
|
memzero(digest, sizeof(digest));
|
||||||
if (res != OPTIGA_SUCCESS) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
optiga_clear_auto_state(OID_PIN_SECRET);
|
optiga_clear_auto_state(OID_PIN_SECRET);
|
||||||
return res;
|
return res;
|
||||||
@ -526,47 +592,21 @@ int optiga_pin_set(OPTIGA_UI_PROGRESS ui_progress,
|
|||||||
|
|
||||||
ui_progress(200);
|
ui_progress(200);
|
||||||
|
|
||||||
// Combine the value of OID_PIN_SECRET with the PIN-derived secret and
|
|
||||||
// stretching secrets from the Optiga. This step ensures that if an attacker
|
|
||||||
// extracts the value of OID_PIN_SECRET, then it cannot be used to conduct an
|
|
||||||
// offline brute-force search for the PIN.
|
|
||||||
hmac_sha256(pin_secret, OPTIGA_PIN_SECRET_SIZE, out_secret,
|
|
||||||
OPTIGA_PIN_SECRET_SIZE, out_secret);
|
|
||||||
res = optiga_pin_stretch_secret(ui_progress, out_secret);
|
|
||||||
if (res != OPTIGA_SUCCESS) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Combine the stretched master secret with the PIN-derived secret to obtain
|
|
||||||
// the output secret. This ensures that in the unlikely case of an attacker
|
|
||||||
// recording communication between the MCU and Optiga, they cannot decrypt the
|
|
||||||
// storage without having to conduct a brute-force search for the PIN.
|
|
||||||
// NOTE: Considering how optiga_pin_stretch_secret() works internally and the
|
|
||||||
// fact that the PIN was already combined with the value of OID_PIN_SECRET,
|
|
||||||
// this step is not necessary. However, it is preferable to explicitly execute
|
|
||||||
// it, than to rely on the internals of optiga_pin_stretch_secret().
|
|
||||||
hmac_sha256(pin_secret, OPTIGA_PIN_SECRET_SIZE, out_secret,
|
|
||||||
OPTIGA_PIN_SECRET_SIZE, out_secret);
|
|
||||||
|
|
||||||
// Recombining the returned secret with the PIN-derived secret means that if
|
|
||||||
// the user chooses a high-entropy PIN, then even if the Optiga and its
|
|
||||||
// communication link is completely compromised, it will not reduce the
|
|
||||||
// security of their device any more than if the Optiga was not integrated
|
|
||||||
// into the device in the first place.
|
|
||||||
|
|
||||||
return OPTIGA_SUCCESS;
|
return OPTIGA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int optiga_pin_verify(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]) {
|
||||||
|
// Legacy PIN verification method used in storage version 3 and 4.
|
||||||
|
|
||||||
// Process the PIN-derived secret using a one-way function before sending it
|
// Process the PIN-derived secret using a one-way function before sending it
|
||||||
// to the Optiga.
|
// to the Optiga.
|
||||||
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE] = {0};
|
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||||
hmac_sha256(pin_secret, OPTIGA_PIN_SECRET_SIZE, NULL, 0, stretched_pin);
|
hmac_sha256(pin_secret, OPTIGA_PIN_SECRET_SIZE, NULL, 0, stretched_pin);
|
||||||
|
|
||||||
// Combine the result with stretching secrets from the Optiga.
|
// Combine the result with stretching secrets from the Optiga.
|
||||||
optiga_result res = optiga_pin_stretch_secret(ui_progress, stretched_pin);
|
optiga_result res = optiga_pin_stretch_secret_v4(ui_progress, stretched_pin);
|
||||||
if (res != OPTIGA_SUCCESS) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
memzero(stretched_pin, sizeof(stretched_pin));
|
memzero(stretched_pin, sizeof(stretched_pin));
|
||||||
return res;
|
return res;
|
||||||
@ -622,7 +662,7 @@ int optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
|||||||
// stretching secrets from the Optiga.
|
// stretching secrets from the Optiga.
|
||||||
hmac_sha256(pin_secret, OPTIGA_PIN_SECRET_SIZE, out_secret,
|
hmac_sha256(pin_secret, OPTIGA_PIN_SECRET_SIZE, out_secret,
|
||||||
OPTIGA_PIN_SECRET_SIZE, out_secret);
|
OPTIGA_PIN_SECRET_SIZE, out_secret);
|
||||||
res = optiga_pin_stretch_secret(ui_progress, out_secret);
|
res = optiga_pin_stretch_secret_v4(ui_progress, out_secret);
|
||||||
if (res != OPTIGA_SUCCESS) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
@ -634,6 +674,74 @@ int optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
|||||||
return OPTIGA_SUCCESS;
|
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);
|
||||||
|
if (res != OPTIGA_SUCCESS) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// Authorise using OID_STRETCHED_PIN so that we can read from OID_PIN_SECRET.
|
||||||
|
res = optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_STRETCHED_PIN, digest,
|
||||||
|
sizeof(digest));
|
||||||
|
memzero(digest, sizeof(digest));
|
||||||
|
if (res == OPTIGA_ERR_CMD) {
|
||||||
|
uint8_t error_code = 0;
|
||||||
|
optiga_get_error_code(&error_code);
|
||||||
|
return error_code + OPTIGA_COMMAND_ERROR_OFFSET;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res != OPTIGA_SUCCESS) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the counter-protected PIN secret from OID_PIN_SECRET.
|
||||||
|
uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||||
|
size_t size = 0;
|
||||||
|
res = optiga_get_data_object(OID_PIN_SECRET, false, pin_secret,
|
||||||
|
OPTIGA_PIN_SECRET_SIZE, &size);
|
||||||
|
optiga_clear_auto_state(OID_STRETCHED_PIN);
|
||||||
|
if (res != OPTIGA_SUCCESS) {
|
||||||
|
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);
|
||||||
|
|
||||||
|
ui_progress(200);
|
||||||
|
|
||||||
|
// 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,
|
||||||
|
pin_secret, OPTIGA_PIN_SECRET_SIZE);
|
||||||
|
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,
|
||||||
|
sizeof(COUNTER_RESET));
|
||||||
|
optiga_clear_auto_state(OID_PIN_SECRET);
|
||||||
|
if (res != OPTIGA_SUCCESS) {
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_progress(200);
|
||||||
|
|
||||||
|
return OPTIGA_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
static int optiga_get_counter(uint16_t oid, uint32_t *ctr) {
|
static int optiga_get_counter(uint16_t oid, uint32_t *ctr) {
|
||||||
uint8_t counter[8] = {0};
|
uint8_t counter[8] = {0};
|
||||||
size_t counter_size = 0;
|
size_t counter_size = 0;
|
||||||
|
@ -155,6 +155,12 @@ bool optiga_random_buffer(uint8_t *dest, size_t size) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
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]) {
|
||||||
|
ui_progress(OPTIGA_PIN_DERIVE_MS);
|
||||||
|
return OPTIGA_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
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]) {
|
||||||
memcpy(out_secret, pin_secret, OPTIGA_PIN_SECRET_SIZE);
|
memcpy(out_secret, pin_secret, OPTIGA_PIN_SECRET_SIZE);
|
||||||
@ -163,9 +169,7 @@ int optiga_pin_set(OPTIGA_UI_PROGRESS ui_progress,
|
|||||||
}
|
}
|
||||||
|
|
||||||
int optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
int optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
||||||
const uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE],
|
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
||||||
uint8_t out_secret[OPTIGA_PIN_SECRET_SIZE]) {
|
|
||||||
memcpy(out_secret, pin_secret, OPTIGA_PIN_SECRET_SIZE);
|
|
||||||
ui_progress(OPTIGA_PIN_DERIVE_MS);
|
ui_progress(OPTIGA_PIN_DERIVE_MS);
|
||||||
return OPTIGA_SUCCESS;
|
return OPTIGA_SUCCESS;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user