pgp_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left)
{
	struct pgp_priv_data *priv = DRVDATA(card);

	LOG_FUNC_CALLED(card->ctx);

	if (data->pin_type != SC_AC_CHV)
		LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
				"invalid PIN type");

	/* In general, the PIN Reference is extracted from the key-id,
	 * for example, CHV0 -> Ref=0, CHV1 -> Ref=1.
	 * However, in the case of OpenGPG, the PIN Ref to compose APDU
	 * must be 81, 82, 83.
	 * So, if we receive Ref=1, Ref=2, we must convert to 81, 82...
	 * In OpenPGP v1, the PINs are named CHV1, CHV2, CHV3.
	 * In v2, they are named PW1, PW3 (PW1 operates in 2 modes).
	 *
	 * The PIN references (P2 in APDU) for "VERIFY" are the same in both versions:
	 * 81 (CHV1 or PW1), 82 (CHV2 or PW1-mode 2), 83 (CHV3 or PW3),
	 * On the other hand from version 2.0 "CHANGE REFERENCE DATA" and
	 * "RESET RETRY COUNTER" don't support PW1-mode 2 (82) and need this
	 * value changed to PW1 (81).
	 * Both of these commands also differ between card versions in that
	 * v1 cards can use only implicit old PIN or CHV3 test for both commands
	 * whereas v2 can use both implicit (for PW3) and explicit
	 * (for special "Resetting Code") PIN test for "RESET RETRY COUNTER"
	 * and only explicit test for "CHANGE REFERENCE DATA".
	 *
	 * Note that if this function is called from sc_pkcs15_verify_pin() in pkcs15-pin.c,
	 * the Ref is already 81, 82, 83.
	 */

	/* convert the PIN Reference if needed */
	data->pin_reference |= 0x80;

	/* check version-dependent constraints */
	if (data->cmd == SC_PIN_CMD_CHANGE || data->cmd == SC_PIN_CMD_UNBLOCK) {
		if (priv->bcd_version >= OPENPGP_CARD_2_0) {
			if (data->pin_reference == 0x82)
				data->pin_reference = 0x81;

			if (data->cmd == SC_PIN_CMD_CHANGE) {
				if (data->pin1.len == 0 &&
				    !(data->flags & SC_PIN_CMD_USE_PINPAD))
					LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
						     "v2 cards don't support implicit old PIN for PIN change.");

				data->flags &= ~SC_PIN_CMD_IMPLICIT_CHANGE;
			}
		} else {
			if (data->pin1.len != 0) {
				sc_log(card->ctx,
				       "v1 cards don't support explicit old or CHV3 PIN, PIN ignored.");
				sc_log(card->ctx,
				       "please make sure that you have verified the relevant PIN first.");
				data->pin1.len = 0;
			}

			data->flags |= SC_PIN_CMD_IMPLICIT_CHANGE;
		}
	}

	if (data->cmd == SC_PIN_CMD_UNBLOCK && data->pin2.len == 0 &&
	    !(data->flags & SC_PIN_CMD_USE_PINPAD))
		LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
			     "new PIN must be provided for unblock operation.");

	/* ensure pin_reference is 81, 82, 83 */
	if (!(data->pin_reference == 0x81 || data->pin_reference == 0x82 || data->pin_reference == 0x83)) {
		LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
					 "key-id should be 1, 2, 3.");
	}
	LOG_FUNC_RETURN(card->ctx, iso_ops->pin_cmd(card, data, tries_left));
}
pgp_pin_cmd(sc_card_t *card, struct sc_pin_cmd_data *data, int *tries_left)
{
	struct pgp_priv_data *priv = DRVDATA(card);

	LOG_FUNC_CALLED(card->ctx);

	if (data->pin_type != SC_AC_CHV)
		LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
				"invalid PIN type");

	 

	 
	data->pin_reference |= 0x80;

	 
	if (data->cmd == SC_PIN_CMD_CHANGE || data->cmd == SC_PIN_CMD_UNBLOCK) {
		if (priv->bcd_version >= OPENPGP_CARD_2_0) {
			if (data->pin_reference == 0x82)
				data->pin_reference = 0x81;

			if (data->cmd == SC_PIN_CMD_CHANGE) {
				if (data->pin1.len == 0 &&
				    !(data->flags & SC_PIN_CMD_USE_PINPAD))
					LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
						     "v2 cards don't support implicit old PIN for PIN change.");

				data->flags &= ~SC_PIN_CMD_IMPLICIT_CHANGE;
			}
		} else {
			if (data->pin1.len != 0) {
				sc_log(card->ctx,
				       "v1 cards don't support explicit old or CHV3 PIN, PIN ignored.");
				sc_log(card->ctx,
				       "please make sure that you have verified the relevant PIN first.");
				data->pin1.len = 0;
			}

			data->flags |= SC_PIN_CMD_IMPLICIT_CHANGE;
		}
	}

	if (data->cmd == SC_PIN_CMD_UNBLOCK && data->pin2.len == 0 &&
	    !(data->flags & SC_PIN_CMD_USE_PINPAD))
		LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
			     "new PIN must be provided for unblock operation.");

	 
	if (!(data->pin_reference == 0x81 || data->pin_reference == 0x82 || data->pin_reference == 0x83)) {
		LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_ARGUMENTS,
					 "key-id should be 1, 2, 3.");
	}
	LOG_FUNC_RETURN(card->ctx, iso_ops->pin_cmd(card, data, tries_left));
}