Require fixed-size reference change bodies

Signed-off-by: Pol Henarejos <pol.henarejos@cttc.es>
This commit is contained in:
Pol Henarejos
2026-08-14 23:34:32 +02:00
parent d6362c6083
commit b686df8684
2 changed files with 29 additions and 8 deletions
+24 -8
View File
@@ -56,6 +56,7 @@
#define PINPOLICY_ONCE 2
#define PINPOLICY_ALWAYS 3
#define MGM_PIN_POLICY PINPOLICY_DEFAULT
#define PIV_PIN_WIRE_SIZE 8u
#define TOUCHPOLICY_DEFAULT 0
#define TOUCHPOLICY_NEVER 1
@@ -99,6 +100,15 @@ static uint8_t piv_default_pin_policy(uint8_t key_ref) {
return PINPOLICY_ONCE;
}
static bool piv_reference_pair(const uint8_t **old_ref, const uint8_t **new_ref) {
if (apdu.nc != 2u * PIV_PIN_WIRE_SIZE) {
return false;
}
*old_ref = apdu.data;
*new_ref = apdu.data + PIV_PIN_WIRE_SIZE;
return true;
}
uint8_t piv_aid[] = {
5,
0xA0, 0x00, 0x00, 0x03, 0x8,
@@ -1291,20 +1301,23 @@ static int cmd_piv_change_pin(void) {
if (P1(apdu) != 0x0 || (pin_ref != 0x80 && pin_ref != 0x81)) {
return SW_REFERENCE_NOT_FOUND();
}
const uint8_t *old_pin = NULL, *new_pin = NULL;
if (!piv_reference_pair(&old_pin, &new_pin)) {
return SW_INCORRECT_PARAMS();
}
file_t *ef = file_search_by_fid(pin_ref == 0x80 ? EF_PIV_PIN : EF_PIV_PUK, NULL, SPECIFY_ANY);
if (!ef) {
return SW_MEMORY_FAILURE();
}
uint8_t *pin_data = file_get_data(ef), pin_len = apdu.nc - pin_data[0];
uint16_t ret = check_pin(ef, apdu.data, pin_data[0]);
uint16_t ret = check_pin(ef, old_pin, PIV_PIN_WIRE_SIZE);
if (ret != 0x9000) {
return ret;
}
uint8_t dhash[34];
dhash[0] = pin_len;
dhash[0] = PIV_PIN_WIRE_SIZE;
dhash[1] = 0x1; // Format
pin_derive_verifier(CONST_BYTE_ARRAY(apdu.data + pin_data[0], pin_len), dhash + 2);
pin_derive_verifier(CONST_BYTE_ARRAY(new_pin, PIV_PIN_WIRE_SIZE), dhash + 2);
file_put_data(ef, CONST_BYTE_ARRAY(dhash, sizeof(dhash)));
flash_commit();
return SW_OK();
@@ -1314,19 +1327,22 @@ static int cmd_piv_reset_retry(void) {
if (P1(apdu) != 0x0 || P2(apdu) != 0x80) {
return SW_REFERENCE_NOT_FOUND();
}
const uint8_t *old_puk = NULL, *new_pin = NULL;
if (!piv_reference_pair(&old_puk, &new_pin)) {
return SW_INCORRECT_PARAMS();
}
file_t *ef = file_search_by_fid(EF_PIV_PUK, NULL, SPECIFY_ANY);
if (!ef) {
return SW_MEMORY_FAILURE();
}
uint8_t *puk_data = file_get_data(ef), pin_len = apdu.nc - puk_data[0];
uint16_t ret = check_pin(ef, apdu.data, puk_data[0]);
uint16_t ret = check_pin(ef, old_puk, PIV_PIN_WIRE_SIZE);
if (ret != 0x9000) {
return ret;
}
uint8_t dhash[34];
dhash[0] = pin_len;
dhash[0] = PIV_PIN_WIRE_SIZE;
dhash[1] = 0x1; // Format
pin_derive_verifier(CONST_BYTE_ARRAY(apdu.data + puk_data[0], pin_len), dhash + 2);
pin_derive_verifier(CONST_BYTE_ARRAY(new_pin, PIV_PIN_WIRE_SIZE), dhash + 2);
ef = file_search_by_fid(EF_PIV_PIN, NULL, SPECIFY_ANY);
file_put_data(ef, CONST_BYTE_ARRAY(dhash, sizeof(dhash)));
pin_reset_retries(ef, true);
+5
View File
@@ -124,6 +124,11 @@ def test_piv_ec_import_requires_the_field_length(managed_piv):
delete_key(managed_piv, slot)
@pytest.mark.parametrize(("instruction", "p2"), ((0x24, 0x80), (0x24, 0x81), (0x2C, 0x80)))
def test_piv_reference_changes_require_two_wire_blocks(piv, instruction, p2):
assert_apdu_error(lambda: piv.protocol.send_apdu(0, instruction, 0, p2, b"12345678"), SW.INCORRECT_PARAMETERS)
def test_piv_card_authentication_key_is_pin_free_by_default(managed_piv):
slot = SLOT.CARD_AUTH
try: