mirror of
https://github.com/trezor/trezor-firmware.git
synced 2024-12-19 04:48:12 +00:00
refactor(core): Clean up Optiga error handling.
[no changelog]
This commit is contained in:
parent
99c3d35e07
commit
fc09379877
@ -90,11 +90,12 @@ STATIC mp_obj_t mod_trezorcrypto_optiga_sign(mp_obj_t key_index,
|
|||||||
vstr_t sig = {0};
|
vstr_t sig = {0};
|
||||||
vstr_init_len(&sig, MAX_DER_SIGNATURE_SIZE);
|
vstr_init_len(&sig, MAX_DER_SIGNATURE_SIZE);
|
||||||
size_t sig_size = 0;
|
size_t sig_size = 0;
|
||||||
int ret = optiga_sign(idx, (const uint8_t *)dig.buf, dig.len,
|
optiga_sign_result ret =
|
||||||
((uint8_t *)sig.buf), sig.alloc, &sig_size);
|
optiga_sign(idx, (const uint8_t *)dig.buf, dig.len, ((uint8_t *)sig.buf),
|
||||||
if (ret != 0) {
|
sig.alloc, &sig_size);
|
||||||
|
if (ret != OPTIGA_SIGN_SUCCESS) {
|
||||||
vstr_clear(&sig);
|
vstr_clear(&sig);
|
||||||
if (ret == OPTIGA_ERR_ACCESS_COND_NOT_SAT) {
|
if (ret == OPTIGA_SIGN_INACCESSIBLE) {
|
||||||
mp_raise_msg(&mp_type_SigningInaccessible, "Signing inaccessible.");
|
mp_raise_msg(&mp_type_SigningInaccessible, "Signing inaccessible.");
|
||||||
} else {
|
} else {
|
||||||
mp_raise_msg(&mp_type_OptigaError, "Signing failed.");
|
mp_raise_msg(&mp_type_OptigaError, "Signing failed.");
|
||||||
|
@ -28,16 +28,20 @@
|
|||||||
|
|
||||||
#define OPTIGA_DEVICE_CERT_INDEX 1
|
#define OPTIGA_DEVICE_CERT_INDEX 1
|
||||||
#define OPTIGA_DEVICE_ECC_KEY_INDEX 0
|
#define OPTIGA_DEVICE_ECC_KEY_INDEX 0
|
||||||
#define OPTIGA_COMMAND_ERROR_OFFSET 0x100
|
|
||||||
|
|
||||||
// Error code 0x07: Access conditions not satisfied
|
typedef enum _optiga_pin_result {
|
||||||
#define OPTIGA_ERR_ACCESS_COND_NOT_SAT (OPTIGA_COMMAND_ERROR_OFFSET + 0x07)
|
OPTIGA_PIN_SUCCESS = 0, // The operation completed successfully.
|
||||||
|
OPTIGA_PIN_INVALID, // The PIN is invalid.
|
||||||
|
OPTIGA_PIN_COUNTER_EXCEEDED, // The PIN try counter limit was exceeded.
|
||||||
|
OPTIGA_PIN_ERROR, // Optiga processing or communication error.
|
||||||
|
} optiga_pin_result;
|
||||||
|
|
||||||
// Error code 0x0E: Counter threshold limit exceeded
|
typedef enum _optiga_sign_result {
|
||||||
#define OPTIGA_ERR_COUNTER_EXCEEDED (OPTIGA_COMMAND_ERROR_OFFSET + 0x0E)
|
OPTIGA_SIGN_SUCCESS = 0, // The operation completed successfully.
|
||||||
|
OPTIGA_SIGN_INACCESSIBLE, // The signing key is inaccessible.
|
||||||
// Error code 0x2F: Authorization failure
|
OPTIGA_SIGN_ERROR, // Invalid parameters or Optiga processing or
|
||||||
#define OPTIGA_ERR_AUTH_FAIL (OPTIGA_COMMAND_ERROR_OFFSET + 0x2F)
|
// communication error.
|
||||||
|
} optiga_sign_result;
|
||||||
|
|
||||||
// Size of secrets used in PIN processing, e.g. salted PIN, master secret etc.
|
// Size of secrets used in PIN processing, e.g. salted PIN, master secret etc.
|
||||||
#define OPTIGA_PIN_SECRET_SIZE 32
|
#define OPTIGA_PIN_SECRET_SIZE 32
|
||||||
@ -50,9 +54,9 @@
|
|||||||
|
|
||||||
typedef secbool (*OPTIGA_UI_PROGRESS)(uint32_t elapsed_ms);
|
typedef secbool (*OPTIGA_UI_PROGRESS)(uint32_t elapsed_ms);
|
||||||
|
|
||||||
int __wur optiga_sign(uint8_t index, const uint8_t *digest, size_t digest_size,
|
optiga_sign_result __wur optiga_sign(uint8_t index, const uint8_t *digest,
|
||||||
uint8_t *signature, size_t max_sig_size,
|
size_t digest_size, uint8_t *signature,
|
||||||
size_t *sig_size);
|
size_t max_sig_size, size_t *sig_size);
|
||||||
|
|
||||||
bool __wur optiga_cert_size(uint8_t index, size_t *cert_size);
|
bool __wur optiga_cert_size(uint8_t index, size_t *cert_size);
|
||||||
|
|
||||||
@ -63,15 +67,17 @@ bool __wur optiga_read_sec(uint8_t *sec);
|
|||||||
|
|
||||||
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,
|
bool __wur 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 __wur optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
optiga_pin_result __wur
|
||||||
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]);
|
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,
|
optiga_pin_result __wur
|
||||||
const uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE],
|
optiga_pin_verify_v4(OPTIGA_UI_PROGRESS ui_progress,
|
||||||
uint8_t out_secret[OPTIGA_PIN_SECRET_SIZE]);
|
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_v4(uint32_t *ctr);
|
||||||
|
|
||||||
|
@ -89,34 +89,36 @@ static const optiga_metadata_item ACCESS_PIN_HMAC_CTR =
|
|||||||
// Size of the CMAC/HMAC prefix returned by Optiga.
|
// Size of the CMAC/HMAC prefix returned by Optiga.
|
||||||
#define ENCRYPT_SYM_PREFIX_SIZE 3
|
#define ENCRYPT_SYM_PREFIX_SIZE 3
|
||||||
|
|
||||||
int optiga_sign(uint8_t index, const uint8_t *digest, size_t digest_size,
|
optiga_sign_result optiga_sign(uint8_t index, const uint8_t *digest,
|
||||||
uint8_t *signature, size_t max_sig_size, size_t *sig_size) {
|
size_t digest_size, uint8_t *signature,
|
||||||
|
size_t max_sig_size, size_t *sig_size) {
|
||||||
if (index >= OPTIGA_ECC_KEY_COUNT) {
|
if (index >= OPTIGA_ECC_KEY_COUNT) {
|
||||||
return OPTIGA_ERR_PARAM;
|
return OPTIGA_SIGN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
optiga_result ret =
|
optiga_result res =
|
||||||
optiga_calc_sign(OPTIGA_OID_ECC_KEY + index, digest, digest_size,
|
optiga_calc_sign(OPTIGA_OID_ECC_KEY + index, digest, digest_size,
|
||||||
&signature[2], max_sig_size - 2, sig_size);
|
&signature[2], max_sig_size - 2, sig_size);
|
||||||
if (ret == OPTIGA_ERR_CMD) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
uint8_t error_code = 0;
|
uint8_t error_code = 0;
|
||||||
(void)optiga_get_error_code(&error_code);
|
if (res == OPTIGA_ERR_CMD &&
|
||||||
return error_code + OPTIGA_COMMAND_ERROR_OFFSET;
|
optiga_get_error_code(&error_code) == OPTIGA_SUCCESS &&
|
||||||
}
|
error_code == OPTIGA_ERR_CODE_ACCESS_COND) {
|
||||||
|
return OPTIGA_SIGN_INACCESSIBLE;
|
||||||
if (ret != OPTIGA_SUCCESS) {
|
} else {
|
||||||
return ret;
|
return OPTIGA_SIGN_ERROR;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add sequence tag and length.
|
// Add sequence tag and length.
|
||||||
if (*sig_size >= 0x80) {
|
if (*sig_size >= 0x80) {
|
||||||
// Length not supported.
|
// Length not supported.
|
||||||
return OPTIGA_ERR_SIZE;
|
return OPTIGA_SIGN_ERROR;
|
||||||
}
|
}
|
||||||
signature[0] = 0x30;
|
signature[0] = 0x30;
|
||||||
signature[1] = *sig_size;
|
signature[1] = *sig_size;
|
||||||
*sig_size += 2;
|
*sig_size += 2;
|
||||||
return OPTIGA_SUCCESS;
|
return OPTIGA_SIGN_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool optiga_cert_size(uint8_t index, size_t *cert_size) {
|
bool optiga_cert_size(uint8_t index, size_t *cert_size) {
|
||||||
@ -188,28 +190,24 @@ bool optiga_random_buffer(uint8_t *dest, size_t size) {
|
|||||||
static bool read_metadata(uint16_t oid, optiga_metadata *metadata) {
|
static bool read_metadata(uint16_t oid, optiga_metadata *metadata) {
|
||||||
static uint8_t serialized[OPTIGA_MAX_METADATA_SIZE] = {0};
|
static uint8_t serialized[OPTIGA_MAX_METADATA_SIZE] = {0};
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
optiga_result ret =
|
if (optiga_get_data_object(oid, true, serialized, sizeof(serialized),
|
||||||
optiga_get_data_object(oid, true, serialized, sizeof(serialized), &size);
|
&size) != OPTIGA_SUCCESS) {
|
||||||
if (OPTIGA_SUCCESS != ret) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = optiga_parse_metadata(serialized, size, metadata);
|
return optiga_parse_metadata(serialized, size, metadata) == OPTIGA_SUCCESS;
|
||||||
return OPTIGA_SUCCESS == ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool write_metadata(uint16_t oid, const optiga_metadata *metadata) {
|
static bool write_metadata(uint16_t oid, const optiga_metadata *metadata) {
|
||||||
uint8_t serialized[OPTIGA_MAX_METADATA_SIZE] = {0};
|
uint8_t serialized[OPTIGA_MAX_METADATA_SIZE] = {0};
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
|
|
||||||
optiga_result ret = optiga_serialize_metadata(metadata, serialized,
|
if (optiga_serialize_metadata(metadata, serialized, sizeof(serialized),
|
||||||
sizeof(serialized), &size);
|
&size) != OPTIGA_SUCCESS) {
|
||||||
if (OPTIGA_SUCCESS != ret) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = optiga_set_data_object(oid, true, serialized, size);
|
return optiga_set_data_object(oid, true, serialized, size) == OPTIGA_SUCCESS;
|
||||||
return OPTIGA_SUCCESS == ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool optiga_set_metadata(uint16_t oid, const optiga_metadata *metadata) {
|
bool optiga_set_metadata(uint16_t oid, const optiga_metadata *metadata) {
|
||||||
@ -353,28 +351,22 @@ static bool optiga_pin_init_metadata(void) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int optiga_pin_init_stretch(void) {
|
static bool optiga_pin_init_stretch(void) {
|
||||||
// Generate a new key in OID_PIN_CMAC.
|
// Generate a new key in OID_PIN_CMAC.
|
||||||
optiga_result res =
|
if (optiga_gen_sym_key(OPTIGA_AES_256, OPTIGA_KEY_USAGE_ENC, OID_PIN_CMAC) !=
|
||||||
optiga_gen_sym_key(OPTIGA_AES_256, OPTIGA_KEY_USAGE_ENC, OID_PIN_CMAC);
|
OPTIGA_SUCCESS) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
return false;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate a new key in OID_PIN_ECDH.
|
// Generate a new key in OID_PIN_ECDH.
|
||||||
uint8_t public_key[6 + 65] = {0};
|
uint8_t public_key[6 + 65] = {0};
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
res =
|
return optiga_gen_key_pair(OPTIGA_CURVE_P256, OPTIGA_KEY_USAGE_KEYAGREE,
|
||||||
optiga_gen_key_pair(OPTIGA_CURVE_P256, OPTIGA_KEY_USAGE_KEYAGREE,
|
OID_PIN_ECDH, public_key, sizeof(public_key),
|
||||||
OID_PIN_ECDH, public_key, sizeof(public_key), &size);
|
&size) == OPTIGA_SUCCESS;
|
||||||
if (res != OPTIGA_SUCCESS) {
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
return OPTIGA_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int optiga_pin_stretch_common(
|
static bool 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], bool version4) {
|
const uint8_t input[OPTIGA_PIN_SECRET_SIZE], bool version4) {
|
||||||
// Implements the functionality that is common to
|
// Implements the functionality that is common to
|
||||||
@ -383,26 +375,25 @@ static int optiga_pin_stretch_common(
|
|||||||
|
|
||||||
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;
|
||||||
|
bool ret = true;
|
||||||
|
|
||||||
// Combine intermediate result with OID_PIN_CMAC.
|
// Combine intermediate result with OID_PIN_CMAC.
|
||||||
optiga_result res =
|
if (optiga_encrypt_sym(OPTIGA_SYM_MODE_CMAC, OID_PIN_CMAC, input,
|
||||||
optiga_encrypt_sym(OPTIGA_SYM_MODE_CMAC, OID_PIN_CMAC, input,
|
OPTIGA_PIN_SECRET_SIZE, buffer, sizeof(buffer),
|
||||||
OPTIGA_PIN_SECRET_SIZE, buffer, sizeof(buffer), &size);
|
&size) != OPTIGA_SUCCESS) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
ret = false;
|
||||||
memzero(buffer, sizeof(buffer));
|
goto end;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hmac_sha256_Update(ctx, buffer, size);
|
hmac_sha256_Update(ctx, buffer, size);
|
||||||
|
|
||||||
if (version4) {
|
if (version4) {
|
||||||
// Combine intermediate result with OID_PIN_HMAC
|
// Combine intermediate result with OID_PIN_HMAC
|
||||||
res = optiga_encrypt_sym(OPTIGA_SYM_MODE_HMAC_SHA256, OID_PIN_HMAC_V4,
|
if (optiga_encrypt_sym(OPTIGA_SYM_MODE_HMAC_SHA256, OID_PIN_HMAC_V4, input,
|
||||||
input, OPTIGA_PIN_SECRET_SIZE, buffer,
|
OPTIGA_PIN_SECRET_SIZE, buffer, sizeof(buffer),
|
||||||
sizeof(buffer), &size);
|
&size) != OPTIGA_SUCCESS) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
ret = false;
|
||||||
memzero(buffer, sizeof(buffer));
|
goto end;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hmac_sha256_Update(ctx, buffer, size);
|
hmac_sha256_Update(ctx, buffer, size);
|
||||||
@ -411,25 +402,28 @@ static int optiga_pin_stretch_common(
|
|||||||
// Combine intermediate result with OID_PIN_ECDH
|
// Combine intermediate result with OID_PIN_ECDH
|
||||||
uint8_t encoded_point[BIT_STRING_HEADER_SIZE + 65] = {0x03, 0x42, 0x00};
|
uint8_t encoded_point[BIT_STRING_HEADER_SIZE + 65] = {0x03, 0x42, 0x00};
|
||||||
if (!hash_to_curve_optiga(input, &encoded_point[BIT_STRING_HEADER_SIZE])) {
|
if (!hash_to_curve_optiga(input, &encoded_point[BIT_STRING_HEADER_SIZE])) {
|
||||||
memzero(buffer, sizeof(buffer));
|
ret = false;
|
||||||
return -1;
|
goto end;
|
||||||
}
|
}
|
||||||
res = optiga_calc_ssec(OPTIGA_CURVE_P256, OID_PIN_ECDH, encoded_point,
|
|
||||||
sizeof(encoded_point), buffer, sizeof(buffer), &size);
|
if (optiga_calc_ssec(OPTIGA_CURVE_P256, OID_PIN_ECDH, encoded_point,
|
||||||
memzero(encoded_point, sizeof(encoded_point));
|
sizeof(encoded_point), buffer, sizeof(buffer),
|
||||||
if (res != OPTIGA_SUCCESS) {
|
&size) != OPTIGA_SUCCESS) {
|
||||||
memzero(buffer, sizeof(buffer));
|
ret = false;
|
||||||
return res;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_progress(250);
|
ui_progress(250);
|
||||||
|
|
||||||
hmac_sha256_Update(ctx, buffer, size);
|
hmac_sha256_Update(ctx, buffer, size);
|
||||||
|
|
||||||
|
end:
|
||||||
|
memzero(encoded_point, sizeof(encoded_point));
|
||||||
memzero(buffer, sizeof(buffer));
|
memzero(buffer, sizeof(buffer));
|
||||||
return OPTIGA_SUCCESS;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int optiga_pin_stretch_secret_v4(
|
static bool optiga_pin_stretch_secret_v4(
|
||||||
OPTIGA_UI_PROGRESS ui_progress, uint8_t secret[OPTIGA_PIN_SECRET_SIZE]) {
|
OPTIGA_UI_PROGRESS ui_progress, uint8_t secret[OPTIGA_PIN_SECRET_SIZE]) {
|
||||||
// Legacy PIN verification method used in storage versions 3 and 4.
|
// Legacy PIN verification method used in storage versions 3 and 4.
|
||||||
|
|
||||||
@ -451,19 +445,16 @@ static int optiga_pin_stretch_secret_v4(
|
|||||||
HMAC_SHA256_CTX ctx = {0};
|
HMAC_SHA256_CTX ctx = {0};
|
||||||
hmac_sha256_Init(&ctx, secret, OPTIGA_PIN_SECRET_SIZE);
|
hmac_sha256_Init(&ctx, secret, OPTIGA_PIN_SECRET_SIZE);
|
||||||
|
|
||||||
optiga_result res =
|
bool ret = optiga_pin_stretch_common(ui_progress, &ctx, secret, true);
|
||||||
optiga_pin_stretch_common(ui_progress, &ctx, secret, true);
|
if (ret) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
hmac_sha256_Final(&ctx, secret);
|
||||||
memzero(&ctx, sizeof(ctx));
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hmac_sha256_Final(&ctx, secret);
|
|
||||||
memzero(&ctx, sizeof(ctx));
|
memzero(&ctx, sizeof(ctx));
|
||||||
return OPTIGA_SUCCESS;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int optiga_pin_stretch_cmac_ecdh(
|
static bool 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
|
||||||
@ -483,6 +474,7 @@ static int optiga_pin_stretch_cmac_ecdh(
|
|||||||
// ecdh_out = ECDH(OID_PIN_ECDH, digest)
|
// ecdh_out = ECDH(OID_PIN_ECDH, digest)
|
||||||
// stretched_pin = HMAC-SHA256(stretched_pin, cmac_out || ecdh_out)
|
// stretched_pin = HMAC-SHA256(stretched_pin, cmac_out || ecdh_out)
|
||||||
|
|
||||||
|
bool ret = true;
|
||||||
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};
|
||||||
for (int i = 0; i < PIN_STRETCH_ITERATIONS; ++i) {
|
for (int i = 0; i < PIN_STRETCH_ITERATIONS; ++i) {
|
||||||
@ -493,32 +485,25 @@ static int optiga_pin_stretch_cmac_ecdh(
|
|||||||
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 =
|
if (!optiga_pin_stretch_common(ui_progress, &ctx, digest, false)) {
|
||||||
optiga_pin_stretch_common(ui_progress, &ctx, digest, false);
|
ret = false;
|
||||||
if (res != OPTIGA_SUCCESS) {
|
goto end;
|
||||||
memzero(digest, sizeof(digest));
|
|
||||||
memzero(&ctx, sizeof(ctx));
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
hmac_sha256_Final(&ctx, stretched_pin);
|
hmac_sha256_Final(&ctx, stretched_pin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
end:
|
||||||
memzero(digest, sizeof(digest));
|
memzero(digest, sizeof(digest));
|
||||||
memzero(&ctx, sizeof(ctx));
|
memzero(&ctx, sizeof(ctx));
|
||||||
return OPTIGA_SUCCESS;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int optiga_pin_set(OPTIGA_UI_PROGRESS ui_progress,
|
bool 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;
|
bool ret = true;
|
||||||
if (!optiga_pin_init_metadata()) {
|
if (!optiga_pin_init_metadata() || !optiga_pin_init_stretch()) {
|
||||||
res = -1;
|
ret = false;
|
||||||
goto end;
|
|
||||||
}
|
|
||||||
|
|
||||||
res = optiga_pin_init_stretch();
|
|
||||||
if (res != OPTIGA_SUCCESS) {
|
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -528,38 +513,38 @@ 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_cmac_ecdh(ui_progress, stretched_pin);
|
if (!optiga_pin_stretch_cmac_ecdh(ui_progress, stretched_pin)) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
ret = false;
|
||||||
goto end;
|
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));
|
if (optiga_get_random(pin_secret, sizeof(pin_secret)) != OPTIGA_SUCCESS) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
ret = false;
|
||||||
goto end;
|
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,
|
if (optiga_set_data_object(OID_PIN_SECRET, false, pin_secret,
|
||||||
sizeof(pin_secret));
|
sizeof(pin_secret)) != OPTIGA_SUCCESS) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
ret = false;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Generate the key for the HMAC-SHA256 PIN stretching step.
|
// Generate the key for the HMAC-SHA256 PIN stretching step.
|
||||||
uint8_t pin_hmac[OPTIGA_PIN_SECRET_SIZE] = {0};
|
uint8_t pin_hmac[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||||
res = optiga_get_random(pin_hmac, sizeof(pin_hmac));
|
if (optiga_get_random(pin_hmac, sizeof(pin_hmac)) != OPTIGA_SUCCESS) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
ret = false;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
random_xor(pin_hmac, sizeof(pin_hmac));
|
random_xor(pin_hmac, sizeof(pin_hmac));
|
||||||
|
|
||||||
// Authorise using OID_PIN_SECRET so that we can write to OID_STRETCHED_PIN
|
// Authorise using OID_PIN_SECRET so that we can write to OID_STRETCHED_PIN
|
||||||
// and OID_STRETCHED_PIN_CTR.
|
// and OID_STRETCHED_PIN_CTR.
|
||||||
res = optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_PIN_SECRET,
|
if (optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_PIN_SECRET, pin_secret,
|
||||||
pin_secret, sizeof(pin_secret));
|
sizeof(pin_secret)) != OPTIGA_SUCCESS) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
ret = false;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -587,17 +572,17 @@ int optiga_pin_set(OPTIGA_UI_PROGRESS ui_progress,
|
|||||||
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 =
|
if (optiga_set_data_object(OID_STRETCHED_PIN, false, digest,
|
||||||
optiga_set_data_object(OID_STRETCHED_PIN, false, digest, sizeof(digest));
|
sizeof(digest)) != OPTIGA_SUCCESS) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
ret = false;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the counter which limits the guesses at OID_STRETCHED_PIN so
|
// Initialize the counter which limits the guesses at OID_STRETCHED_PIN so
|
||||||
// that we can authorise using OID_STRETCHED_PIN.
|
// that we can authorise using OID_STRETCHED_PIN.
|
||||||
res = optiga_set_data_object(OID_STRETCHED_PIN_CTR, false, COUNTER_RESET,
|
if (optiga_set_data_object(OID_STRETCHED_PIN_CTR, false, COUNTER_RESET,
|
||||||
sizeof(COUNTER_RESET));
|
sizeof(COUNTER_RESET)) != OPTIGA_SUCCESS) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
ret = false;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -605,31 +590,31 @@ int optiga_pin_set(OPTIGA_UI_PROGRESS ui_progress,
|
|||||||
|
|
||||||
// Authorise using OID_STRETCHED_PIN so that we can write to OID_PIN_HMAC and
|
// Authorise using OID_STRETCHED_PIN so that we can write to OID_PIN_HMAC and
|
||||||
// OID_PIN_HMAC_CTR.
|
// OID_PIN_HMAC_CTR.
|
||||||
res = optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_STRETCHED_PIN, digest,
|
if (optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_STRETCHED_PIN, digest,
|
||||||
sizeof(digest));
|
sizeof(digest)) != OPTIGA_SUCCESS) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
ret = false;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the key for HMAC-SHA256 PIN stretching.
|
// Initialize the key for HMAC-SHA256 PIN stretching.
|
||||||
res = optiga_set_data_object(OID_PIN_HMAC, false, pin_hmac, sizeof(pin_hmac));
|
if (optiga_set_data_object(OID_PIN_HMAC, false, pin_hmac, sizeof(pin_hmac)) !=
|
||||||
if (res != OPTIGA_SUCCESS) {
|
OPTIGA_SUCCESS) {
|
||||||
|
ret = false;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the counter which limits the guesses at OID_STRETCHED_PIN again,
|
// Initialize the counter which limits the guesses at OID_STRETCHED_PIN again,
|
||||||
// since we just depleted one attempt.
|
// since we just depleted one attempt.
|
||||||
res = optiga_set_data_object(OID_STRETCHED_PIN_CTR, false, COUNTER_RESET,
|
if (optiga_set_data_object(OID_STRETCHED_PIN_CTR, false, COUNTER_RESET,
|
||||||
sizeof(COUNTER_RESET));
|
sizeof(COUNTER_RESET)) != OPTIGA_SUCCESS) {
|
||||||
optiga_clear_auto_state(OID_PIN_SECRET);
|
ret = false;
|
||||||
if (res != OPTIGA_SUCCESS) {
|
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the PIN counter which limits the use of OID_PIN_HMAC.
|
// Initialize the PIN counter which limits the use of OID_PIN_HMAC.
|
||||||
res = optiga_set_data_object(OID_PIN_HMAC_CTR, false, COUNTER_RESET,
|
if (optiga_set_data_object(OID_PIN_HMAC_CTR, false, COUNTER_RESET,
|
||||||
sizeof(COUNTER_RESET));
|
sizeof(COUNTER_RESET)) != OPTIGA_SUCCESS) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
ret = false;
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -642,9 +627,6 @@ 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:
|
end:
|
||||||
memzero(hmac_buffer, sizeof(hmac_buffer));
|
memzero(hmac_buffer, sizeof(hmac_buffer));
|
||||||
@ -653,60 +635,69 @@ end:
|
|||||||
memzero(digest, sizeof(digest));
|
memzero(digest, sizeof(digest));
|
||||||
optiga_clear_auto_state(OID_PIN_SECRET);
|
optiga_clear_auto_state(OID_PIN_SECRET);
|
||||||
optiga_clear_auto_state(OID_STRETCHED_PIN);
|
optiga_clear_auto_state(OID_STRETCHED_PIN);
|
||||||
return res;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int optiga_pin_verify_v4(OPTIGA_UI_PROGRESS ui_progress,
|
optiga_pin_result optiga_pin_verify_v4(
|
||||||
const uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE],
|
OPTIGA_UI_PROGRESS ui_progress,
|
||||||
uint8_t out_secret[OPTIGA_PIN_SECRET_SIZE]) {
|
const uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE],
|
||||||
|
uint8_t out_secret[OPTIGA_PIN_SECRET_SIZE]) {
|
||||||
// Legacy PIN verification method used in storage version 3 and 4.
|
// Legacy PIN verification method used in storage version 3 and 4.
|
||||||
|
|
||||||
|
optiga_pin_result ret = OPTIGA_PIN_SUCCESS;
|
||||||
|
|
||||||
// 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_v4(ui_progress, stretched_pin);
|
if (!optiga_pin_stretch_secret_v4(ui_progress, stretched_pin)) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
ret = OPTIGA_PIN_ERROR;
|
||||||
memzero(stretched_pin, sizeof(stretched_pin));
|
goto end;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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.
|
||||||
res = optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_STRETCHED_PIN,
|
optiga_result res =
|
||||||
stretched_pin, sizeof(stretched_pin));
|
optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_STRETCHED_PIN,
|
||||||
memzero(stretched_pin, sizeof(stretched_pin));
|
stretched_pin, sizeof(stretched_pin));
|
||||||
if (res == OPTIGA_ERR_CMD) {
|
|
||||||
uint8_t error_code = 0;
|
|
||||||
(void)optiga_get_error_code(&error_code);
|
|
||||||
return error_code + OPTIGA_COMMAND_ERROR_OFFSET;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (res != OPTIGA_SUCCESS) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
return res;
|
uint8_t error_code = 0;
|
||||||
|
if (res != OPTIGA_ERR_CMD ||
|
||||||
|
optiga_get_error_code(&error_code) != OPTIGA_SUCCESS) {
|
||||||
|
ret = OPTIGA_PIN_ERROR;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (error_code) {
|
||||||
|
case OPTIGA_ERR_CODE_CTR_LIMIT:
|
||||||
|
ret = OPTIGA_PIN_COUNTER_EXCEEDED;
|
||||||
|
break;
|
||||||
|
case OPTIGA_ERR_CODE_AUTH_FAIL:
|
||||||
|
ret = OPTIGA_PIN_INVALID;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = OPTIGA_PIN_ERROR;
|
||||||
|
}
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read the master secret from OID_PIN_SECRET.
|
// Read the master secret from OID_PIN_SECRET.
|
||||||
size_t size = 0;
|
size_t size = 0;
|
||||||
res = optiga_get_data_object(OID_PIN_SECRET, false, out_secret,
|
if (optiga_get_data_object(OID_PIN_SECRET, false, out_secret,
|
||||||
OPTIGA_PIN_SECRET_SIZE, &size);
|
OPTIGA_PIN_SECRET_SIZE, &size) != OPTIGA_SUCCESS ||
|
||||||
optiga_clear_auto_state(OID_STRETCHED_PIN);
|
size != OPTIGA_PIN_SECRET_SIZE) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
ret = OPTIGA_PIN_ERROR;
|
||||||
return res;
|
goto end;
|
||||||
}
|
|
||||||
|
|
||||||
if (size != OPTIGA_PIN_SECRET_SIZE) {
|
|
||||||
return OPTIGA_ERR_SIZE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_progress(200);
|
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 write to OID_PIN_COUNTER.
|
||||||
res = optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_PIN_SECRET,
|
if (optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_PIN_SECRET, out_secret,
|
||||||
out_secret, OPTIGA_PIN_SECRET_SIZE);
|
OPTIGA_PIN_SECRET_SIZE) != OPTIGA_SUCCESS) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
ret = OPTIGA_PIN_ERROR;
|
||||||
return res;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_progress(200);
|
ui_progress(200);
|
||||||
@ -715,20 +706,26 @@ int optiga_pin_verify_v4(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_v4(ui_progress, out_secret);
|
if (!optiga_pin_stretch_secret_v4(ui_progress, out_secret)) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
ret = OPTIGA_PIN_ERROR;
|
||||||
return res;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Combine the stretched master secret with the PIN-derived secret to derive
|
// Combine the stretched master secret with the PIN-derived secret to derive
|
||||||
// the output secret.
|
// the output secret.
|
||||||
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);
|
||||||
return OPTIGA_SUCCESS;
|
|
||||||
|
end:
|
||||||
|
memzero(stretched_pin, sizeof(stretched_pin));
|
||||||
|
optiga_clear_auto_state(OID_STRETCHED_PIN);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int optiga_pin_stretch_hmac(
|
static optiga_pin_result optiga_pin_stretch_hmac(
|
||||||
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
||||||
|
optiga_pin_result ret = OPTIGA_PIN_SUCCESS;
|
||||||
|
|
||||||
// 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.
|
// Optiga.
|
||||||
uint8_t digest[OPTIGA_PIN_SECRET_SIZE] = {0};
|
uint8_t digest[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||||
@ -740,36 +737,42 @@ static int optiga_pin_stretch_hmac(
|
|||||||
optiga_result res = optiga_encrypt_sym(
|
optiga_result res = optiga_encrypt_sym(
|
||||||
OPTIGA_SYM_MODE_HMAC_SHA256, OID_PIN_HMAC, digest, sizeof(digest),
|
OPTIGA_SYM_MODE_HMAC_SHA256, OID_PIN_HMAC, digest, sizeof(digest),
|
||||||
hmac_buffer, sizeof(hmac_buffer), &size);
|
hmac_buffer, sizeof(hmac_buffer), &size);
|
||||||
memzero(digest, sizeof(digest));
|
|
||||||
if (res != OPTIGA_SUCCESS) {
|
if (res != OPTIGA_SUCCESS) {
|
||||||
uint8_t error_code = 0;
|
uint8_t error_code = 0;
|
||||||
(void)optiga_get_error_code(&error_code);
|
if (res == OPTIGA_ERR_CMD &&
|
||||||
if (error_code + OPTIGA_COMMAND_ERROR_OFFSET ==
|
optiga_get_error_code(&error_code) == OPTIGA_SUCCESS &&
|
||||||
OPTIGA_ERR_ACCESS_COND_NOT_SAT) {
|
error_code == OPTIGA_ERR_CODE_ACCESS_COND) {
|
||||||
return OPTIGA_ERR_COUNTER_EXCEEDED;
|
ret = OPTIGA_PIN_COUNTER_EXCEEDED;
|
||||||
} else {
|
} else {
|
||||||
return error_code + OPTIGA_COMMAND_ERROR_OFFSET;
|
ret = OPTIGA_PIN_ERROR;
|
||||||
}
|
}
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stretch the PIN with the result.
|
// Stretch the PIN with the result.
|
||||||
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, hmac_buffer, size,
|
hmac_sha256(stretched_pin, OPTIGA_PIN_SECRET_SIZE, hmac_buffer, size,
|
||||||
stretched_pin);
|
stretched_pin);
|
||||||
|
|
||||||
|
end:
|
||||||
|
memzero(digest, sizeof(digest));
|
||||||
memzero(hmac_buffer, sizeof(hmac_buffer));
|
memzero(hmac_buffer, sizeof(hmac_buffer));
|
||||||
return OPTIGA_SUCCESS;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
optiga_pin_result optiga_pin_verify(
|
||||||
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
OPTIGA_UI_PROGRESS ui_progress,
|
||||||
|
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
||||||
|
optiga_pin_result ret = OPTIGA_PIN_SUCCESS;
|
||||||
|
|
||||||
// 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_cmac_ecdh(ui_progress, stretched_pin);
|
if (!optiga_pin_stretch_cmac_ecdh(ui_progress, stretched_pin)) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
ret = OPTIGA_PIN_ERROR;
|
||||||
return res;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
res = optiga_pin_stretch_hmac(stretched_pin);
|
ret = optiga_pin_stretch_hmac(stretched_pin);
|
||||||
if (res != OPTIGA_SUCCESS) {
|
if (ret != OPTIGA_PIN_SUCCESS) {
|
||||||
return res;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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
|
||||||
@ -779,33 +782,45 @@ int optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
|||||||
|
|
||||||
// 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.
|
// and reset OID_PIN_HMAC_CTR.
|
||||||
res = optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_STRETCHED_PIN, digest,
|
optiga_result res = optiga_set_auto_state(
|
||||||
sizeof(digest));
|
OPTIGA_OID_SESSION_CTX, OID_STRETCHED_PIN, digest, sizeof(digest));
|
||||||
memzero(digest, sizeof(digest));
|
if (res != OPTIGA_SUCCESS) {
|
||||||
if (res == OPTIGA_ERR_CMD) {
|
|
||||||
uint8_t error_code = 0;
|
uint8_t error_code = 0;
|
||||||
(void)optiga_get_error_code(&error_code);
|
if (res != OPTIGA_ERR_CMD ||
|
||||||
return error_code + OPTIGA_COMMAND_ERROR_OFFSET;
|
optiga_get_error_code(&error_code) != OPTIGA_SUCCESS) {
|
||||||
|
ret = OPTIGA_PIN_ERROR;
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (error_code) {
|
||||||
|
case OPTIGA_ERR_CODE_CTR_LIMIT:
|
||||||
|
ret = OPTIGA_PIN_COUNTER_EXCEEDED;
|
||||||
|
break;
|
||||||
|
case OPTIGA_ERR_CODE_AUTH_FAIL:
|
||||||
|
ret = OPTIGA_PIN_INVALID;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
ret = OPTIGA_PIN_ERROR;
|
||||||
|
}
|
||||||
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_progress(200);
|
ui_progress(200);
|
||||||
|
|
||||||
// Reset the counter which limits the use of OID_PIN_HMAC.
|
// Reset the counter which limits the use of OID_PIN_HMAC.
|
||||||
res = optiga_set_data_object(OID_PIN_HMAC_CTR, false, COUNTER_RESET,
|
if (optiga_set_data_object(OID_PIN_HMAC_CTR, false, COUNTER_RESET,
|
||||||
sizeof(COUNTER_RESET));
|
sizeof(COUNTER_RESET)) != OPTIGA_SUCCESS) {
|
||||||
if (res != OPTIGA_SUCCESS) {
|
ret = OPTIGA_PIN_ERROR;
|
||||||
optiga_clear_auto_state(OID_STRETCHED_PIN);
|
goto end;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
||||||
res = optiga_get_data_object(OID_PIN_SECRET, false, pin_secret,
|
if (optiga_get_data_object(OID_PIN_SECRET, false, pin_secret,
|
||||||
OPTIGA_PIN_SECRET_SIZE, &size);
|
OPTIGA_PIN_SECRET_SIZE, &size) != OPTIGA_SUCCESS) {
|
||||||
optiga_clear_auto_state(OID_STRETCHED_PIN);
|
ret = OPTIGA_PIN_ERROR;
|
||||||
if (res != OPTIGA_SUCCESS) {
|
goto end;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Stretch the PIN more with the counter-protected PIN secret.
|
// Stretch the PIN more with the counter-protected PIN secret.
|
||||||
@ -813,24 +828,27 @@ int optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
|||||||
stretched_pin);
|
stretched_pin);
|
||||||
|
|
||||||
// Authorise using OID_PIN_SECRET so that we can reset OID_STRETCHED_PIN_CTR.
|
// 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,
|
if (optiga_set_auto_state(OPTIGA_OID_SESSION_CTX, OID_PIN_SECRET, pin_secret,
|
||||||
pin_secret, sizeof(pin_secret));
|
sizeof(pin_secret)) != OPTIGA_SUCCESS) {
|
||||||
memzero(pin_secret, sizeof(pin_secret));
|
ret = OPTIGA_PIN_ERROR;
|
||||||
if (res != OPTIGA_SUCCESS) {
|
goto end;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset the counter which limits the guesses at OID_STRETCHED_PIN.
|
// Reset the counter which limits the guesses at OID_STRETCHED_PIN.
|
||||||
res = optiga_set_data_object(OID_STRETCHED_PIN_CTR, false, COUNTER_RESET,
|
if (optiga_set_data_object(OID_STRETCHED_PIN_CTR, false, COUNTER_RESET,
|
||||||
sizeof(COUNTER_RESET));
|
sizeof(COUNTER_RESET)) != OPTIGA_SUCCESS) {
|
||||||
optiga_clear_auto_state(OID_PIN_SECRET);
|
ret = OPTIGA_PIN_ERROR;
|
||||||
if (res != OPTIGA_SUCCESS) {
|
goto end;
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_progress(200);
|
ui_progress(200);
|
||||||
|
|
||||||
return OPTIGA_SUCCESS;
|
end:
|
||||||
|
memzero(pin_secret, sizeof(pin_secret));
|
||||||
|
memzero(digest, sizeof(digest));
|
||||||
|
optiga_clear_auto_state(OID_STRETCHED_PIN);
|
||||||
|
optiga_clear_auto_state(OID_PIN_SECRET);
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int optiga_get_counter(uint16_t oid, uint32_t *ctr) {
|
static int optiga_get_counter(uint16_t oid, uint32_t *ctr) {
|
||||||
|
@ -113,6 +113,40 @@ typedef enum {
|
|||||||
OPTIGA_LCS_TE = 0x0f, // Termination state.
|
OPTIGA_LCS_TE = 0x0f, // Termination state.
|
||||||
} optiga_lcs;
|
} optiga_lcs;
|
||||||
|
|
||||||
|
// Error codes returned by optiga_get_error_code().
|
||||||
|
typedef enum {
|
||||||
|
OPTIGA_ERR_CODE_NONE = 0x00, // No Error.
|
||||||
|
OPTIGA_ERR_CODE_INVAL_OID = 0x01, // Invalid OID.
|
||||||
|
OPTIGA_ERR_CODE_INVAL_CMD_PARAM = 0x03, // Invalid param field in command.
|
||||||
|
OPTIGA_ERR_CODE_INVAL_CMD_LEN = 0x04, // Invalid length field in command.
|
||||||
|
OPTIGA_ERR_CODE_INVAL_CMD_DATA = 0x05, // Invalid parameter in command data.
|
||||||
|
OPTIGA_ERR_CODE_PROCESS = 0x06, // Internal process error.
|
||||||
|
OPTIGA_ERR_CODE_ACCESS_COND = 0x07, // Access conditions not satisfied.
|
||||||
|
OPTIGA_ERR_CODE_OBJ_BOUNDARY = 0x08, // Data object boundary exceeded.
|
||||||
|
OPTIGA_ERR_CODE_META_TRUNC = 0x09, // Metadata truncation error.
|
||||||
|
OPTIGA_ERR_CODE_INVAL_CMD_FIELD = 0x0A, // Invalid command field.
|
||||||
|
OPTIGA_ERR_CODE_CMD_SEQ = 0x0B, // Command out of sequence.
|
||||||
|
OPTIGA_ERR_CODE_CMD_UNAVAIL = 0x0C, // Command not available.
|
||||||
|
OPTIGA_ERR_CODE_MEMORY = 0x0D, // Insufficient memory to process the
|
||||||
|
// command.
|
||||||
|
OPTIGA_ERR_CODE_CTR_LIMIT = 0x0E, // Counter threshold limit exceeded.
|
||||||
|
OPTIGA_ERR_CODE_INVAL_MANIFEST = 0x0F, // Invalid manifest.
|
||||||
|
OPTIGA_ERR_CODE_PAYLOAD_VER = 0x10, // Wrong payload version.
|
||||||
|
OPTIGA_ERR_CODE_INVAL_OBJ_META = 0x11, // Invalid data object metadata.
|
||||||
|
OPTIGA_ERR_CODE_UNSUP_EXT_ID = 0x24, // Unsupported key usage, extension
|
||||||
|
// or algorithm identifier.
|
||||||
|
OPTIGA_ERR_CODE_UNSUP_PARAM = 0x25, // Unsupported parameters in
|
||||||
|
// handshake or command APDU InData.
|
||||||
|
OPTIGA_ERR_CODE_INVAL_CERT = 0x29, // Invalid certificate format or
|
||||||
|
// signature.
|
||||||
|
OPTIGA_ERR_CODE_UNSUP_CERT = 0x2A, // Unsupported certificate.
|
||||||
|
OPTIGA_ERR_CODE_SIG_FAIL = 0x2C, // Signature verification failure.
|
||||||
|
OPTIGA_ERR_CODE_INT_FAIL = 0x2D, // Message integrity validation failed
|
||||||
|
// (e.g. during CCM decryption).
|
||||||
|
OPTIGA_ERR_CODE_DECRYPT_FAIL = 0x2E, // Decryption failure
|
||||||
|
OPTIGA_ERR_CODE_AUTH_FAIL = 0x2F, // Authorization failure
|
||||||
|
} optiga_err_code;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const uint8_t *ptr;
|
const uint8_t *ptr;
|
||||||
uint16_t len;
|
uint16_t len;
|
||||||
|
@ -34,27 +34,28 @@
|
|||||||
#error "Cert chain for specified model is not available."
|
#error "Cert chain for specified model is not available."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int optiga_sign(uint8_t index, const uint8_t *digest, size_t digest_size,
|
optiga_sign_result optiga_sign(uint8_t index, const uint8_t *digest,
|
||||||
uint8_t *signature, size_t max_sig_size, size_t *sig_size) {
|
size_t digest_size, uint8_t *signature,
|
||||||
|
size_t max_sig_size, size_t *sig_size) {
|
||||||
const uint8_t DEVICE_PRIV_KEY[32] = {1};
|
const uint8_t DEVICE_PRIV_KEY[32] = {1};
|
||||||
|
|
||||||
if (index != OPTIGA_DEVICE_ECC_KEY_INDEX) {
|
if (index != OPTIGA_DEVICE_ECC_KEY_INDEX) {
|
||||||
return false;
|
return OPTIGA_SIGN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (max_sig_size < 72) {
|
if (max_sig_size < 72) {
|
||||||
return OPTIGA_ERR_SIZE;
|
return OPTIGA_SIGN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint8_t raw_signature[64] = {0};
|
uint8_t raw_signature[64] = {0};
|
||||||
int ret = ecdsa_sign_digest(&nist256p1, DEVICE_PRIV_KEY, digest,
|
int ret = ecdsa_sign_digest(&nist256p1, DEVICE_PRIV_KEY, digest,
|
||||||
raw_signature, NULL, NULL);
|
raw_signature, NULL, NULL);
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
return OPTIGA_ERR_CMD;
|
return OPTIGA_SIGN_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
*sig_size = ecdsa_sig_to_der(raw_signature, signature);
|
*sig_size = ecdsa_sig_to_der(raw_signature, signature);
|
||||||
return OPTIGA_SUCCESS;
|
return OPTIGA_SIGN_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool optiga_cert_size(uint8_t index, size_t *cert_size) {
|
bool optiga_cert_size(uint8_t index, size_t *cert_size) {
|
||||||
@ -91,24 +92,26 @@ bool optiga_random_buffer(uint8_t *dest, size_t size) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int optiga_pin_set(OPTIGA_UI_PROGRESS ui_progress,
|
bool optiga_pin_set(OPTIGA_UI_PROGRESS ui_progress,
|
||||||
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
||||||
ui_progress(OPTIGA_PIN_SET_MS);
|
ui_progress(OPTIGA_PIN_SET_MS);
|
||||||
return OPTIGA_SUCCESS;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int optiga_pin_verify_v4(OPTIGA_UI_PROGRESS ui_progress,
|
optiga_pin_result optiga_pin_verify_v4(
|
||||||
const uint8_t pin_secret[OPTIGA_PIN_SECRET_SIZE],
|
OPTIGA_UI_PROGRESS ui_progress,
|
||||||
uint8_t out_secret[OPTIGA_PIN_SECRET_SIZE]) {
|
const uint8_t pin_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);
|
||||||
ui_progress(OPTIGA_PIN_VERIFY_MS);
|
ui_progress(OPTIGA_PIN_VERIFY_MS);
|
||||||
return OPTIGA_SUCCESS;
|
return OPTIGA_PIN_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int optiga_pin_verify(OPTIGA_UI_PROGRESS ui_progress,
|
optiga_pin_result optiga_pin_verify(
|
||||||
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
OPTIGA_UI_PROGRESS ui_progress,
|
||||||
|
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE]) {
|
||||||
ui_progress(OPTIGA_PIN_VERIFY_MS);
|
ui_progress(OPTIGA_PIN_VERIFY_MS);
|
||||||
return OPTIGA_SUCCESS;
|
return OPTIGA_PIN_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
int optiga_pin_get_fails_v4(uint32_t *ctr) {
|
int optiga_pin_get_fails_v4(uint32_t *ctr) {
|
||||||
|
@ -609,7 +609,7 @@ static secbool __wur derive_kek_set(
|
|||||||
const uint8_t *ext_salt, uint8_t stretched_pin[SHA256_DIGEST_LENGTH]) {
|
const uint8_t *ext_salt, uint8_t stretched_pin[SHA256_DIGEST_LENGTH]) {
|
||||||
stretch_pin(pin, pin_len, storage_salt, ext_salt, stretched_pin);
|
stretch_pin(pin, pin_len, storage_salt, ext_salt, stretched_pin);
|
||||||
#if USE_OPTIGA
|
#if USE_OPTIGA
|
||||||
if (optiga_pin_set(ui_progress, stretched_pin) != OPTIGA_SUCCESS) {
|
if (!optiga_pin_set(ui_progress, stretched_pin)) {
|
||||||
memzero(stretched_pin, SHA256_DIGEST_LENGTH);
|
memzero(stretched_pin, SHA256_DIGEST_LENGTH);
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
@ -627,16 +627,17 @@ static secbool __wur derive_kek_unlock_v4(const uint8_t *pin, size_t pin_len,
|
|||||||
uint8_t optiga_secret[OPTIGA_PIN_SECRET_SIZE] = {0};
|
uint8_t optiga_secret[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||||
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE] = {0};
|
uint8_t stretched_pin[OPTIGA_PIN_SECRET_SIZE] = {0};
|
||||||
stretch_pin(pin, pin_len, storage_salt, ext_salt, stretched_pin);
|
stretch_pin(pin, pin_len, storage_salt, ext_salt, stretched_pin);
|
||||||
int ret = optiga_pin_verify_v4(ui_progress, stretched_pin, optiga_secret);
|
optiga_pin_result ret =
|
||||||
|
optiga_pin_verify_v4(ui_progress, stretched_pin, optiga_secret);
|
||||||
memzero(stretched_pin, sizeof(stretched_pin));
|
memzero(stretched_pin, sizeof(stretched_pin));
|
||||||
if (ret != OPTIGA_SUCCESS) {
|
if (ret != OPTIGA_PIN_SUCCESS) {
|
||||||
memzero(optiga_secret, sizeof(optiga_secret));
|
memzero(optiga_secret, sizeof(optiga_secret));
|
||||||
if (ret == OPTIGA_ERR_COUNTER_EXCEEDED) {
|
if (ret == OPTIGA_PIN_COUNTER_EXCEEDED) {
|
||||||
// Unreachable code. Wipe should have already been triggered in unlock().
|
// Unreachable code. Wipe should have already been triggered in unlock().
|
||||||
storage_wipe();
|
storage_wipe();
|
||||||
show_pin_too_many_screen();
|
show_pin_too_many_screen();
|
||||||
}
|
}
|
||||||
ensure(ret == OPTIGA_ERR_AUTH_FAIL ? sectrue : secfalse,
|
ensure(ret == OPTIGA_PIN_INVALID ? sectrue : secfalse,
|
||||||
"optiga_pin_verify failed");
|
"optiga_pin_verify failed");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
@ -653,16 +654,16 @@ static secbool __wur derive_kek_unlock(
|
|||||||
const uint8_t *ext_salt, uint8_t stretched_pin[SHA256_DIGEST_LENGTH]) {
|
const uint8_t *ext_salt, uint8_t stretched_pin[SHA256_DIGEST_LENGTH]) {
|
||||||
stretch_pin(pin, pin_len, storage_salt, ext_salt, stretched_pin);
|
stretch_pin(pin, pin_len, storage_salt, ext_salt, stretched_pin);
|
||||||
#if USE_OPTIGA
|
#if USE_OPTIGA
|
||||||
int ret = optiga_pin_verify(ui_progress, stretched_pin);
|
optiga_pin_result ret = optiga_pin_verify(ui_progress, stretched_pin);
|
||||||
if (ret != OPTIGA_SUCCESS) {
|
if (ret != OPTIGA_PIN_SUCCESS) {
|
||||||
memzero(stretched_pin, SHA256_DIGEST_LENGTH);
|
memzero(stretched_pin, SHA256_DIGEST_LENGTH);
|
||||||
|
|
||||||
if (ret == OPTIGA_ERR_COUNTER_EXCEEDED) {
|
if (ret == OPTIGA_PIN_COUNTER_EXCEEDED) {
|
||||||
// Unreachable code. Wipe should have already been triggered in unlock().
|
// Unreachable code. Wipe should have already been triggered in unlock().
|
||||||
storage_wipe();
|
storage_wipe();
|
||||||
show_pin_too_many_screen();
|
show_pin_too_many_screen();
|
||||||
}
|
}
|
||||||
ensure(ret == OPTIGA_ERR_AUTH_FAIL ? sectrue : secfalse,
|
ensure(ret == OPTIGA_PIN_INVALID ? sectrue : secfalse,
|
||||||
"optiga_pin_verify failed");
|
"optiga_pin_verify failed");
|
||||||
return secfalse;
|
return secfalse;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user