Exemple #1
0
static int entersafe_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
								sc_file_t *df, sc_pkcs15_object_t *pin_obj,
								const unsigned char *pin, size_t pin_len,
								const unsigned char *puk, size_t puk_len)
{
	struct sc_card *card = p15card->card;
	int	r;
	sc_pkcs15_auth_info_t *auth_info = (sc_pkcs15_auth_info_t *) pin_obj->data;

	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);

	if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
		return SC_ERROR_OBJECT_NOT_VALID;

	{/*pin*/
		 sc_entersafe_wkey_data  data;

		 if (!pin || !pin_len || pin_len > 16)
			  return SC_ERROR_INVALID_ARGUMENTS;

		 data.key_id = auth_info->attrs.pin.reference;
		 data.usage=0x0B;
		 data.key_data.symmetric.EC=0x33;
		 data.key_data.symmetric.ver=0x00;
		 /* pad pin with 0 */
		 memset(data.key_data.symmetric.key_val, 0, sizeof(data.key_data.symmetric.key_val));
		 memcpy(data.key_data.symmetric.key_val, pin, pin_len);
		 data.key_data.symmetric.key_len=16;

		 r = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_WRITE_KEY, &data);

		 /* Cache new PIN value. */
		 sc_pkcs15_pincache_add(p15card, pin_obj, pin, pin_len);
	}

	{/*puk*/
		 sc_entersafe_wkey_data  data;

		 if (!puk || !puk_len || puk_len > 16)
			  return SC_ERROR_INVALID_ARGUMENTS;

		 data.key_id = auth_info->attrs.pin.reference+1;
		 data.usage=0x0B;
		 data.key_data.symmetric.EC=0x33;
		 data.key_data.symmetric.ver=0x00;
		 /* pad pin with 0 */
		 memset(data.key_data.symmetric.key_val, 0, sizeof(data.key_data.symmetric.key_val));
		 memcpy(data.key_data.symmetric.key_val, puk, puk_len);
		 data.key_data.symmetric.key_len=16;

		 r = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_WRITE_KEY, &data);
	}


	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,r);
}
Exemple #2
0
static int
cflex_create_pin_file(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
			sc_path_t *df_path, int ref,
			const u8 *pin, size_t pin_len, int pin_tries,
			const u8 *puk, size_t puk_len, int puk_tries,
			sc_file_t **file_ret, int unprotected)
{
	struct sc_context *ctx = p15card->card->ctx;
	struct sc_pkcs15_object *pin_obj = NULL;
	unsigned char	buffer[23];
	sc_path_t	path;
	sc_file_t	*dummies[2], *file;
	int		r, ndummies;

	SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL);
	if (file_ret)
		*file_ret = NULL;

	/* Build the CHV path */
	path = *df_path;
	path.value[path.len++] = ref - 1;
	path.value[path.len++] = 0;

	/* See if the CHV already exists */
	r = sc_select_file(p15card->card, &path, NULL);
	if (r >= 0)
		return SC_ERROR_FILE_ALREADY_EXISTS;

	/* Get the file definition from the profile */
	if (sc_profile_get_file_by_path(profile, &path, &file) < 0
			&& sc_profile_get_file(profile, (ref == 1)? "CHV1" : "CHV2", &file) < 0
			&& sc_profile_get_file(profile, "CHV", &file) < 0)
		SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_FILE_NOT_FOUND, "profile does not define pin file ACLs");

	file->path = path;
	file->size = 23;
	file->id = (ref == 1)? 0x0000 : 0x0100;

	if (unprotected)   {
		sc_file_add_acl_entry(file, SC_AC_OP_UPDATE,
				SC_AC_NONE, SC_AC_KEY_REF_NONE);
	}

	/* Build the contents of the file */
	buffer[0] = buffer[1] = buffer[2] = 0xFF;
	put_pin(profile, buffer + 3, pin, pin_len, pin_tries);
	put_pin(profile, buffer + 13, puk, puk_len, puk_tries);

	/* For updating the file, create a dummy CHV files if
	 * necessary */
	ndummies = cflex_create_dummy_chvs(profile, p15card,
				file, SC_AC_OP_UPDATE, dummies);
	SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, ndummies, "Unable to create dummy CHV file");

	if (!unprotected)   {
		struct sc_pin_cmd_data pin_cmd;

		memset(&pin_cmd, 0, sizeof(pin_cmd));
		pin_cmd.cmd = SC_PIN_CMD_VERIFY;
		pin_cmd.pin_type = SC_AC_CHV;
		pin_cmd.pin_reference = ref;
		pin_cmd.pin1.data = dummy_pin_value;
		pin_cmd.pin1.len = sizeof(dummy_pin_value);

		r = sc_pin_cmd(p15card->card, &pin_cmd, NULL);
		SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Cannot verify dummy PIN");

	};

	if (ref == 2)   {
		/* Cache dummy SOPIN value */
		r = sc_pkcs15_find_pin_by_type_and_reference(p15card, NULL, SC_AC_CHV, ref, &pin_obj);
		if (!r && pin_obj)
			sc_pkcs15_pincache_add(p15card, pin_obj, dummy_pin_value, sizeof(dummy_pin_value));
	}

	r = sc_pkcs15init_create_file(profile, p15card, file);
	SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Failed to create PIN file");

	r = sc_update_binary(p15card->card, 0, buffer, 23, 0);
	SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Failed to update PIN file");

	if (r < 0 || file_ret == NULL)
		sc_file_free(file);
	else
		*file_ret = file;

	/* Delete the dummy CHV files */
	cflex_delete_dummy_chvs(profile, p15card, ndummies, dummies);

	if (pin_obj)   {
		/* Cache new SOPIN value */
		sc_pkcs15_pincache_add(p15card, pin_obj, pin, pin_len);
	}

	SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
}
Exemple #3
0
/*
 * Unblock a PIN.
 */
int sc_pkcs15_unblock_pin(struct sc_pkcs15_card *p15card,
			 struct sc_pkcs15_object *pin_obj,
			 const u8 *puk, size_t puklen,
			 const u8 *newpin, size_t newpinlen)
{
	int r;
	sc_card_t *card;
	struct sc_pin_cmd_data data;
	struct sc_pkcs15_object *puk_obj;
	struct sc_pkcs15_pin_info *puk_info = NULL;
	struct sc_pkcs15_pin_info *pin_info = (struct sc_pkcs15_pin_info *)pin_obj->data;

	/* make sure the pins are in valid range */
	if ((r = _validate_pin(p15card, pin_info, newpinlen)) != SC_SUCCESS)
		return r;

	card = p15card->card;
	/* get pin_info object of the puk (this is a little bit complicated
	 * as we don't have the id of the puk (at least now))
	 * note: for compatibility reasons we give no error if no puk object
	 * is found */
	/* first step: try to get the pkcs15 object of the puk */
	r = sc_pkcs15_find_pin_by_auth_id(p15card, &pin_obj->auth_id, &puk_obj);
	if (r >= 0 && puk_obj) {
		/* second step:  get the pkcs15 info object of the puk */
		puk_info = (struct sc_pkcs15_pin_info *)puk_obj->data;
	}
	if (!puk_info) {
		sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unable to get puk object, using pin object instead!");
		puk_info = pin_info;
	}
	
	/* make sure the puk is in valid range */
	if ((r = _validate_pin(p15card, puk_info, puklen)) != SC_SUCCESS)
		return r;

	r = sc_lock(card);
	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "sc_lock() failed");
	/* the path in the pin object is optional */
	if (pin_info->path.len > 0) {
		r = sc_select_file(card, &pin_info->path, NULL);
		if (r)
			goto out;
	}

	/* set pin_cmd data */
	memset(&data, 0, sizeof(data));
	data.cmd             = SC_PIN_CMD_UNBLOCK;
	data.pin_type        = SC_AC_CHV;
	data.pin_reference   = pin_info->reference;
	data.pin1.data       = puk;
	data.pin1.len        = puklen;
	data.pin1.pad_char   = pin_info->pad_char;
	data.pin1.min_length = pin_info->min_length;
	data.pin1.max_length = pin_info->max_length;
	data.pin1.pad_length = pin_info->stored_length;
	data.pin2.data       = newpin;
	data.pin2.len        = newpinlen;
	data.pin2.pad_char   = puk_info->pad_char;
	data.pin2.min_length = puk_info->min_length;
	data.pin2.max_length = puk_info->max_length;
	data.pin2.pad_length = puk_info->stored_length;

	if (pin_info->flags & SC_PKCS15_PIN_FLAG_NEEDS_PADDING)
		data.flags |= SC_PIN_CMD_NEED_PADDING;

	switch (pin_info->type) {
	case SC_PKCS15_PIN_TYPE_BCD:
		data.pin1.encoding = SC_PIN_ENCODING_BCD;
		break;
	case SC_PKCS15_PIN_TYPE_ASCII_NUMERIC:
		data.pin1.encoding = SC_PIN_ENCODING_ASCII;
		break;
	}

	switch (puk_info->type) {
	case SC_PKCS15_PIN_TYPE_BCD:
		data.pin2.encoding = SC_PIN_ENCODING_BCD;
		break;
	case SC_PKCS15_PIN_TYPE_ASCII_NUMERIC:
		data.pin2.encoding = SC_PIN_ENCODING_ASCII;
		break;
	}
	
	if(p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) {
		data.flags |= SC_PIN_CMD_USE_PINPAD;
		if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
			data.pin1.prompt = "Please enter PUK";
			data.pin2.prompt = "Please enter new SO PIN";
		} else {
			data.pin1.prompt = "Please enter PUK";
			data.pin2.prompt = "Please enter new PIN";
		}
	}

	r = sc_pin_cmd(card, &data, &pin_info->tries_left);
	if (r == SC_SUCCESS)
		sc_pkcs15_pincache_add(p15card, pin_obj, newpin, newpinlen);

out:
	sc_unlock(card);
	return r;
}
Exemple #4
0
/*
 * Change a PIN.
 */
int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card,
			 struct sc_pkcs15_object *pin_obj,
			 const u8 *oldpin, size_t oldpinlen,
			 const u8 *newpin, size_t newpinlen)
{
	int r;
	sc_card_t *card;
	struct sc_pin_cmd_data data;
	struct sc_pkcs15_pin_info *pin_info = (struct sc_pkcs15_pin_info *)pin_obj->data;
	
	/* make sure the pins are in valid range */
	if ((r = _validate_pin(p15card, pin_info, oldpinlen)) != SC_SUCCESS)
		return r;
	if ((r = _validate_pin(p15card, pin_info, newpinlen)) != SC_SUCCESS)
		return r;

	card = p15card->card;
	r = sc_lock(card);
	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "sc_lock() failed");
	/* the path in the pin object is optional */
	if (pin_info->path.len > 0) {
		r = sc_select_file(card, &pin_info->path, NULL);
		if (r)
			goto out;
	}

	/* set pin_cmd data */
	memset(&data, 0, sizeof(data));
	data.cmd             = SC_PIN_CMD_CHANGE;
	data.pin_type        = SC_AC_CHV;
	data.pin_reference   = pin_info->reference;
	data.pin1.data       = oldpin;
	data.pin1.len        = oldpinlen;
	data.pin1.pad_char   = pin_info->pad_char;
	data.pin1.min_length = pin_info->min_length;
	data.pin1.max_length = pin_info->max_length;
	data.pin1.pad_length = pin_info->stored_length;
	data.pin2.data       = newpin;
	data.pin2.len        = newpinlen;
	data.pin2.pad_char   = pin_info->pad_char;
	data.pin2.min_length = pin_info->min_length;
	data.pin2.max_length = pin_info->max_length;
	data.pin2.pad_length = pin_info->stored_length;

	if (pin_info->flags & SC_PKCS15_PIN_FLAG_NEEDS_PADDING)
		data.flags |= SC_PIN_CMD_NEED_PADDING;

	switch (pin_info->type) {
	case SC_PKCS15_PIN_TYPE_BCD:
		data.pin1.encoding = SC_PIN_ENCODING_BCD;
		data.pin2.encoding = SC_PIN_ENCODING_BCD;
		break;
	case SC_PKCS15_PIN_TYPE_ASCII_NUMERIC:
		data.pin1.encoding = SC_PIN_ENCODING_ASCII;
		data.pin2.encoding = SC_PIN_ENCODING_ASCII;
		break;
	}
	
	if((!oldpin || !newpin) 
			&& p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) {
		data.flags |= SC_PIN_CMD_USE_PINPAD;
		if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
			data.pin1.prompt = "Please enter SO PIN";
			data.pin2.prompt = "Please enter new SO PIN";
		} else {
			data.pin1.prompt = "Please enter PIN";
			data.pin2.prompt = "Please enter new PIN";
		}
	}

	r = sc_pin_cmd(card, &data, &pin_info->tries_left);
	if (r == SC_SUCCESS)
		sc_pkcs15_pincache_add(p15card, pin_obj, newpin, newpinlen);

out:
	sc_unlock(card);
	return r;
}
Exemple #5
0
/*
 * Verify a PIN.
 *
 * If the code given to us has zero length, this means we
 * should ask the card reader to obtain the PIN from the
 * reader's PIN pad
 */
int sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card,
			 struct sc_pkcs15_object *pin_obj,
			 const unsigned char *pincode, size_t pinlen)
{
	struct sc_context *ctx = p15card->card->ctx;
	struct sc_pkcs15_pin_info *pin_info = (struct sc_pkcs15_pin_info *)pin_obj->data;
	int r;
	sc_card_t *card;
	struct sc_pin_cmd_data data;

	SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL);
	sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "PIN(%p;len:%i)", pincode, pinlen);

	r = _validate_pin(p15card, pin_info, pinlen);
	SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "PIN value do not conforms the PIN policy");

	card = p15card->card;

	r = sc_lock(card);
	SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "sc_lock() failed");
	/* the path in the pin object is optional */
	if (pin_info->path.len > 0) {
		r = sc_select_file(card, &pin_info->path, NULL);
		if (r)
			goto out;
	}

	/* Initialize arguments */
	memset(&data, 0, sizeof(data));
	data.cmd = SC_PIN_CMD_VERIFY;
	data.pin_type = pin_info->auth_method;
	data.pin_reference = pin_info->reference;
	data.pin1.min_length = pin_info->min_length;
	data.pin1.max_length = pin_info->max_length;
	data.pin1.pad_length = pin_info->stored_length;
	data.pin1.pad_char = pin_info->pad_char;
	data.pin1.data = pincode;
	data.pin1.len = pinlen;

	if (pin_info->flags & SC_PKCS15_PIN_FLAG_NEEDS_PADDING)
		data.flags |= SC_PIN_CMD_NEED_PADDING;

	switch (pin_info->type) {
	case SC_PKCS15_PIN_TYPE_BCD:
		data.pin1.encoding = SC_PIN_ENCODING_BCD;
		break;
	case SC_PKCS15_PIN_TYPE_ASCII_NUMERIC:
		data.pin1.encoding = SC_PIN_ENCODING_ASCII;
		break;
	default:
		/* assume/hope the card driver knows how to encode the pin */
		data.pin1.encoding = 0;
	}

	if(p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) {
		if (!pincode && !pinlen)
			data.flags |= SC_PIN_CMD_USE_PINPAD;
		if (pin_info->flags & SC_PKCS15_PIN_FLAG_SO_PIN)
			data.pin1.prompt = "Please enter SO PIN";
		else
			data.pin1.prompt = "Please enter PIN";
	}

	r = sc_pin_cmd(card, &data, &pin_info->tries_left);
	if (r == SC_SUCCESS)
		sc_pkcs15_pincache_add(p15card, pin_obj, pincode, pinlen);
out:
	sc_unlock(card);
	return r;
}
Exemple #6
0
/*
 * Change a PIN.
 */
int sc_pkcs15_change_pin(struct sc_pkcs15_card *p15card,
			 struct sc_pkcs15_object *pin_obj,
			 const u8 *oldpin, size_t oldpinlen,
			 const u8 *newpin, size_t newpinlen)
{
	struct sc_context *ctx = p15card->card->ctx;
	struct sc_pin_cmd_data data;
	struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *)pin_obj->data;
	struct sc_card *card = p15card->card;
	int r;

	LOG_FUNC_CALLED(ctx);
	if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
		LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);

	/* make sure the pins are in valid range */
	r = _validate_pin(p15card, auth_info, oldpinlen);
	LOG_TEST_RET(ctx, r, "Old PIN value do not conform PIN policy");

	r = _validate_pin(p15card, auth_info, newpinlen);
	LOG_TEST_RET(ctx, r, "New PIN value do not conform PIN policy");

	card = p15card->card;
	r = sc_lock(card);
	LOG_TEST_RET(ctx, r, "sc_lock() failed");
	/* the path in the pin object is optional */
	if ((auth_info->path.len > 0) || ((auth_info->path.aid.len > 0))) {
		r = sc_select_file(card, &auth_info->path, NULL);
		if (r)
			goto out;
	}

	/* set pin_cmd data */
	memset(&data, 0, sizeof(data));
	data.cmd             = SC_PIN_CMD_CHANGE;
	data.pin_type        = SC_AC_CHV;
	data.pin_reference   = auth_info->attrs.pin.reference;
	data.pin1.data       = oldpin;
	data.pin1.len        = oldpinlen;
	data.pin1.pad_char   = auth_info->attrs.pin.pad_char;
	data.pin1.min_length = auth_info->attrs.pin.min_length;
	data.pin1.max_length = auth_info->attrs.pin.max_length;
	data.pin1.pad_length = auth_info->attrs.pin.stored_length;
	data.pin2.data       = newpin;
	data.pin2.len        = newpinlen;
	data.pin2.pad_char   = auth_info->attrs.pin.pad_char;
	data.pin2.min_length = auth_info->attrs.pin.min_length;
	data.pin2.max_length = auth_info->attrs.pin.max_length;
	data.pin2.pad_length = auth_info->attrs.pin.stored_length;

	if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_NEEDS_PADDING)
		data.flags |= SC_PIN_CMD_NEED_PADDING;

	switch (auth_info->attrs.pin.type) {
	case SC_PKCS15_PIN_TYPE_BCD:
		data.pin1.encoding = SC_PIN_ENCODING_BCD;
		data.pin2.encoding = SC_PIN_ENCODING_BCD;
		break;
	case SC_PKCS15_PIN_TYPE_ASCII_NUMERIC:
		data.pin1.encoding = SC_PIN_ENCODING_ASCII;
		data.pin2.encoding = SC_PIN_ENCODING_ASCII;
		break;
	}

	if((!oldpin || !newpin)
			&& p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) {
		data.flags |= SC_PIN_CMD_USE_PINPAD;
		if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
			data.pin1.prompt = "Please enter SO PIN";
			data.pin2.prompt = "Please enter new SO PIN";
		}
		else {
			data.pin1.prompt = "Please enter PIN";
			data.pin2.prompt = "Please enter new PIN";
		}
	}

	r = sc_pin_cmd(card, &data, &auth_info->tries_left);
	if (r == SC_SUCCESS)
		sc_pkcs15_pincache_add(p15card, pin_obj, newpin, newpinlen);

out:
	sc_unlock(card);
	return r;
}
Exemple #7
0
/*
 * Verify a PIN.
 *
 * If the code given to us has zero length, this means we
 * should ask the card reader to obtain the PIN from the
 * reader's PIN pad
 */
int sc_pkcs15_verify_pin(struct sc_pkcs15_card *p15card,
			 struct sc_pkcs15_object *pin_obj,
			 const unsigned char *pincode, size_t pinlen)
{
	struct sc_context *ctx = p15card->card->ctx;
	struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *)pin_obj->data;
	int r;
	sc_card_t *card;
	struct sc_pin_cmd_data data;

	LOG_FUNC_CALLED(ctx);
	sc_log(ctx, "PIN(type:%X;method:%X;len:)", auth_info->auth_type, auth_info->auth_method, pinlen);

	if (pinlen > SC_MAX_PIN_SIZE)
		LOG_TEST_RET(ctx, SC_ERROR_INVALID_PIN_LENGTH, "Invalid PIN size");

	card = p15card->card;

	/* Initialize arguments */
	memset(&data, 0, sizeof(data));
	data.cmd = SC_PIN_CMD_VERIFY;
	data.pin_type = auth_info->auth_method;

	if (auth_info->auth_type == SC_PKCS15_PIN_AUTH_TYPE_PIN)   {
		data.pin_reference = auth_info->attrs.pin.reference;
		data.pin1.min_length = auth_info->attrs.pin.min_length;
		data.pin1.max_length = auth_info->attrs.pin.max_length;
		data.pin1.pad_length = auth_info->attrs.pin.stored_length;
		data.pin1.pad_char = auth_info->attrs.pin.pad_char;
		data.pin1.data = pincode;
		data.pin1.len = pinlen;

		if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_NEEDS_PADDING)
			data.flags |= SC_PIN_CMD_NEED_PADDING;

		switch (auth_info->attrs.pin.type) {
		case SC_PKCS15_PIN_TYPE_BCD:
			data.pin1.encoding = SC_PIN_ENCODING_BCD;
			break;
		case SC_PKCS15_PIN_TYPE_ASCII_NUMERIC:
			data.pin1.encoding = SC_PIN_ENCODING_ASCII;
			break;
		default:
			/* assume/hope the card driver knows how to encode the pin */
			data.pin1.encoding = 0;
		}
	}
	else if (auth_info->auth_type == SC_PKCS15_PIN_AUTH_TYPE_AUTH_KEY)   {
		struct sc_pkcs15_object *skey_obj = NULL;
		struct sc_pkcs15_id *skey_id =  &auth_info->attrs.authkey.skey_id;
		struct sc_pkcs15_skey_info *skey_info = NULL;

		r = sc_pkcs15_find_skey_by_id(p15card, skey_id, &skey_obj);
		if (r)   {
			sc_log(ctx, "cannot find secret key with id:%s", sc_pkcs15_print_id(skey_id));
			LOG_FUNC_RETURN(ctx, r);
		}
		skey_info = (struct sc_pkcs15_skey_info *)skey_obj->data;

		sc_log(ctx, "found secret key '%s'", skey_obj->label);
		data.pin_reference = skey_info->key_reference;
	}

	if(p15card->card->reader->capabilities & SC_READER_CAP_PIN_PAD) {
		if (!pincode && !pinlen)
			data.flags |= SC_PIN_CMD_USE_PINPAD;
		if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN)
			data.pin1.prompt = "Please enter SO PIN";
		else
			data.pin1.prompt = "Please enter PIN";
	}

	r = sc_lock(card);
	LOG_TEST_RET(ctx, r, "sc_lock() failed");

	/* the path in the pin object is optional */
	if ((auth_info->path.len > 0) || ((auth_info->path.aid.len > 0))) {
		r = sc_select_file(card, &auth_info->path, NULL);
		if (r)
			goto out;
	}

	r = sc_pin_cmd(card, &data, &auth_info->tries_left);
	sc_log(ctx, "PIN cmd result %i", r);
	if (r == SC_SUCCESS)
		sc_pkcs15_pincache_add(p15card, pin_obj, pincode, pinlen);
out:
	sc_unlock(card);
	LOG_FUNC_RETURN(ctx, r);
}