diff --git a/src/openpgp/openpgp.h b/src/openpgp/openpgp.h index e068736..be5126c 100644 --- a/src/openpgp/openpgp.h +++ b/src/openpgp/openpgp.h @@ -46,6 +46,7 @@ extern int rsa_sign(mbedtls_rsa_context *ctx, size_t *out_len); extern int load_private_key_rsa(mbedtls_rsa_context *ctx, file_t *fkey, bool use_dek); extern int load_private_key_ecdsa(mbedtls_ecdsa_context *ctx, file_t *fkey, bool use_dek); +extern int pin_reset_retries(const file_t *pin, bool force); #define ALGO_RSA 0x01 #define ALGO_ECDH 0x12 diff --git a/src/openpgp/piv.c b/src/openpgp/piv.c index eed3803..01beece 100644 --- a/src/openpgp/piv.c +++ b/src/openpgp/piv.c @@ -775,6 +775,25 @@ static int cmd_move_key() { return SW_OK(); } +static int cmd_change_pin() { + uint8_t pin_ref = P2(apdu); + if (P1(apdu) != 0x0 || (pin_ref != 0x80 && pin_ref != 0x81)) { + return SW_INCORRECT_P1P2(); + } + file_t *ef = search_by_fid(pin_ref == 0x80 ? EF_PIV_PIN : EF_PIV_PUK, NULL, SPECIFY_ANY); + uint8_t *pin_data = file_get_data(ef), pin_len = apdu.nc - pin_data[0]; + uint8_t dhash[33]; + double_hash_pin(apdu.data, pin_data[0], dhash + 1); + if (memcmp(dhash, file_get_data(ef) + 1, pin_len) != 0) { + return SW_SECURITY_STATUS_NOT_SATISFIED(); + } + dhash[0] = pin_len; + double_hash_pin(apdu.data + pin_data[0], pin_len, dhash + 1); + flash_write_data_to_file(ef, dhash, sizeof(dhash)); + pin_reset_retries(ef, true); + return SW_OK(); +} + #define INS_VERIFY 0x20 #define INS_VERSION 0xFD #define INS_SELECT 0xA4 @@ -787,6 +806,7 @@ static int cmd_move_key() { #define INS_PUT_DATA 0xDB #define INS_SET_MGMKEY 0xFF #define INS_MOVE_KEY 0xF6 +#define INS_CHANGE_PIN 0x24 static const cmd_t cmds[] = { { INS_VERSION, cmd_version }, @@ -800,6 +820,7 @@ static const cmd_t cmds[] = { { INS_PUT_DATA, cmd_put_data }, { INS_SET_MGMKEY, cmd_set_mgmkey }, { INS_MOVE_KEY, cmd_move_key }, + { INS_CHANGE_PIN, cmd_change_pin }, { 0x00, 0x0 } };