Exemple #1
0
/*
 * Get private and public key file
 */
static int cflex_get_keyfiles(sc_profile_t *profile, sc_card_t *card,
			const sc_path_t *df_path,
			sc_file_t **prkf, sc_file_t **pukf)
{
	sc_path_t	path = *df_path;
	int		r;

	/* Get the private key file */
	r = sc_profile_get_file_by_path(profile, &path, prkf);
	if (r < 0) {
		char pbuf[SC_MAX_PATH_STRING_SIZE];

		r = sc_path_print(pbuf, sizeof(pbuf), &path);
		if (r != SC_SUCCESS)
			pbuf[0] = '\0';

		sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Cannot find private key file info "
				"in profile (path=%s).", pbuf);
		return r;
	}

	/* Get the public key file */
	path.len -= 2;
	sc_append_file_id(&path, 0x1012);
	r = sc_profile_get_file_by_path(profile, &path, pukf);
	if (r < 0) {
		sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Cannot find public key file info in profile.");
		sc_file_free(*prkf);
		return r;
	}

	return 0;
}
static file_info *
sc_profile_instantiate_file(sc_profile_t *profile, file_info *ft,
		file_info *parent, unsigned int skew)
{
	struct file_info *fi;
	sc_card_t	*card = profile->card;

	fi = (file_info *) calloc(1, sizeof(*fi));
	if (fi == NULL)
		return NULL;
	fi->instance = fi;
	fi->parent = parent;
	fi->ident = strdup(ft->ident);
	if (fi->ident == NULL) {
		free(fi);
		return NULL;
	}
	sc_file_dup(&fi->file, ft->file);
	if (fi->file == NULL) {
		free(fi->ident);
		free(fi);
		return NULL;
	}
	fi->file->path = parent->file->path;
	fi->file->id += skew;
	sc_append_file_id(&fi->file->path, fi->file->id);

	append_file(profile, fi);

	ft->instance = fi;

	if (card->ctx->debug >= 2) {
		char pbuf[SC_MAX_PATH_STRING_SIZE];

		int r = sc_path_print(pbuf, sizeof(pbuf), &fi->file->path);
		if (r != SC_SUCCESS)
			pbuf[0] = '\0';

		sc_debug(card->ctx, "Instantiated %s at %s", ft->ident, pbuf);

		r = sc_path_print(pbuf, sizeof(pbuf), &parent->file->path);
		if (r != SC_SUCCESS)
			pbuf[0] = '\0';

		sc_debug(card->ctx, "  parent=%s@%s", parent->ident, pbuf);
	}

	return fi;
}
Exemple #3
0
/*
 * Create a new DF
 * This will usually be the application DF
 */
static int
gpk_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df)
{
	struct sc_file	*pinfile;
	int		r, locked;

	SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE);
	if (sc_card_ctl(p15card->card, SC_CARDCTL_GPK_IS_LOCKED, &locked) == 0
			&& locked) {
		sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL,
			"This card is already personalized, unable to "
			"create PKCS#15 structure.");
		return SC_ERROR_NOT_SUPPORTED;
	}

	/* Create the DF. */
	r = sc_pkcs15init_create_file(profile, p15card, df);
	if (r < 0)
		return r;

	/* See if there's a file called "pinfile" that resides within
	 * this DF. If so, create it */
	if (sc_profile_get_file(profile, "pinfile", &pinfile) >= 0) {
		/* Build the pin file's path from the DF path + its
		 * file ID */
		pinfile->path = df->path;
		sc_append_file_id(&pinfile->path, pinfile->id);

		r = gpk_init_pinfile(profile, p15card, pinfile);
		sc_file_free(pinfile);
		if (r < 0)
			return r;

		/* TODO: What for it was used ?
		for (i = 0; i < GPK_MAX_PINS; i++)
		*	sc_keycache_put_pin(&df->path, GPK_PIN_SCOPE|i, (const u8 *) "        ");
		*/
	}

	SC_FUNC_RETURN(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r);
}
Exemple #4
0
/*
 * Select a reference for a private key object
 */
static int rtecp_select_key_reference(sc_profile_t *profile,
		sc_pkcs15_card_t *p15card, sc_pkcs15_prkey_info_t *key_info)
{
	sc_file_t *df;
	int r;

	if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !key_info)
		return SC_ERROR_INVALID_ARGUMENTS;

	if (key_info->key_reference <= 0)
		key_info->key_reference = 1;
	else if (key_info->key_reference > 0xFF)
		return SC_ERROR_TOO_MANY_OBJECTS;

	r = sc_profile_get_file(profile, "PrKey-DF", &df);
	SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r, "Get PrKey-DF info failed");
	assert(df);
	key_info->path = df->path;
	sc_file_free(df);
	r = sc_append_file_id(&key_info->path, key_info->key_reference);
	return r;
}
/*
 * Create a new DF
 * This will usually be the application DF
 */
static int
gpk_create_dir(sc_profile_t *profile, sc_card_t *card, sc_file_t *df)
{
    struct sc_file	*pinfile;
    int		r, locked, i;

    if (sc_card_ctl(card, SC_CARDCTL_GPK_IS_LOCKED, &locked) == 0
            && locked) {
        sc_error(card->ctx,
                 "This card is already personalized, unable to "
                 "create PKCS#15 structure.");
        return SC_ERROR_NOT_SUPPORTED;
    }

    /* Create the DF. */
    r = sc_pkcs15init_create_file(profile, card, df);
    if (r < 0)
        return r;

    /* See if there's a file called "pinfile" that resides within
     * this DF. If so, create it */
    if (sc_profile_get_file(profile, "pinfile", &pinfile) >= 0) {
        /* Build the pin file's path from the DF path + its
         * file ID */
        pinfile->path = df->path;
        sc_append_file_id(&pinfile->path, pinfile->id);

        r = gpk_init_pinfile(profile, card, pinfile);
        sc_file_free(pinfile);
        if (r < 0)
            return r;

        for (i = 0; i < GPK_MAX_PINS; i++)
            sc_keycache_put_pin(&df->path, GPK_PIN_SCOPE|i, (const u8 *) "        ");
    }

    return r;
}
Exemple #6
0
/*
 * Delete object
 * 
 * Applied to private key: used to delete public part internal file
 */
static int rtecp_delete_object(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
		struct sc_pkcs15_object *obj, const struct sc_path *path)
{
	sc_context_t *ctx;
	sc_file_t *df;
	sc_path_t pubkey_path;
	int key_ref;
	int r;

	if (!profile || !p15card || !p15card->card || !p15card->card->ctx)
		return SC_ERROR_INVALID_ARGUMENTS;

	ctx = p15card->card->ctx;
	LOG_FUNC_CALLED(ctx);
	sc_log(ctx, "delete object: type %X, path %s", obj->type, sc_print_path(path));

	if ((obj->type & SC_PKCS15_TYPE_CLASS_MASK) != SC_PKCS15_TYPE_PRKEY)
		LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);

	key_ref = ((struct sc_pkcs15_prkey_info *)obj->data)->key_reference;
	sc_log(ctx, "key reference %04i", key_ref);

	r = sc_profile_get_file(profile, "PuKey-DF", &df);
	LOG_TEST_RET(ctx, r, "Get PuKey-DF info failed");
	pubkey_path = df->path;
	sc_file_free(df);

	r = sc_append_file_id(&pubkey_path, key_ref);
	LOG_TEST_RET(ctx, r, "Append ID to file failed");

	sc_log(ctx, "delete pubkey file %s", sc_print_path(&pubkey_path));
	r = sc_pkcs15init_delete_by_path(profile, p15card, &pubkey_path);
	if (r && r != SC_ERROR_FILE_NOT_FOUND)
		LOG_FUNC_RETURN(ctx, r);

	LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
}
Exemple #7
0
/*
 * Store a key on the card
 */
static int rtecp_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
		sc_pkcs15_object_t *obj, sc_pkcs15_prkey_t *key)
{
	sc_card_t *card;
	sc_pkcs15_prkey_info_t *key_info;
	sc_file_t *pukey_df;
	sc_path_t path;
	unsigned char *buf;
	size_t buf_len, key_len, len, i;
	int r;

	if (!profile || !p15card || !p15card->card || !p15card->card->ctx
			|| !obj || !obj->data || !key)
		return SC_ERROR_INVALID_ARGUMENTS;

	card = p15card->card;
	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);

	if ((obj->type != SC_PKCS15_TYPE_PRKEY_RSA || key->algorithm != SC_ALGORITHM_RSA)
			&& (obj->type != SC_PKCS15_TYPE_PRKEY_GOSTR3410
				|| key->algorithm != SC_ALGORITHM_GOSTR3410))
		return SC_ERROR_NOT_SUPPORTED;

	key_info = (sc_pkcs15_prkey_info_t *)obj->data;
	assert(key_info);

	if (key->algorithm == SC_ALGORITHM_RSA)
	{
		assert(key_info->modulus_length % 128 == 0);
		len = key_info->modulus_length / 8 / 2;
		key_len = len * 5 + 8;
		buf_len = key_len;
	}
	else
	{
		assert(key_info->modulus_length == SC_PKCS15_GOSTR3410_KEYSIZE);
		len = key_info->modulus_length / 8;
		key_len = len;
		buf_len = len;
	}
	if (key->algorithm == SC_ALGORITHM_RSA && (!key->u.rsa.p.data
			|| !key->u.rsa.q.data || !key->u.rsa.iqmp.data
			|| !key->u.rsa.dmp1.data || !key->u.rsa.dmq1.data
			|| !key->u.rsa.modulus.data || !key->u.rsa.exponent.data
			|| key->u.rsa.p.len != len || key->u.rsa.q.len != len
			|| key->u.rsa.iqmp.len != len || key->u.rsa.dmp1.len != len
			|| key->u.rsa.dmq1.len != len || key->u.rsa.modulus.len != 2*len
			|| key->u.rsa.exponent.len > len || key->u.rsa.exponent.len == 0))
		return SC_ERROR_INVALID_ARGUMENTS;
	if (key->algorithm == SC_ALGORITHM_GOSTR3410 && (!key->u.gostr3410.d.data
			|| key->u.gostr3410.d.len != len))
		return SC_ERROR_INVALID_ARGUMENTS;
	buf = calloc(1, buf_len);
	if (!buf)
		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
	assert(key_len <= buf_len);
	if (key->algorithm == SC_ALGORITHM_RSA)
	{
		/* p */
		for (i = 0; i < len; ++i)
			buf[i] = key->u.rsa.p.data[len - 1 - i];
		/* q */
		for (i = 0; i < len; ++i)
			buf[len + 4 + i] = key->u.rsa.q.data[len - 1 - i];
		/* iqmp */
		for (i = 0; i < len; ++i)
			buf[len + 4 + len + 4 + i] = key->u.rsa.iqmp.data[len - 1 - i];
		/* dmp1 */
		for (i = 0; i < len; ++i)
			buf[len + 4 + len + 4 + len + i] =
				key->u.rsa.dmp1.data[len - 1 - i];
		/* dmq1 */
		for (i = 0; i < len; ++i)
			buf[len * 4 + 8 + i] = key->u.rsa.dmq1.data[len - 1 - i];
	}
	else
	{
		/* d */
		for (i = 0; i < len; ++i)
			buf[i] = key->u.gostr3410.d.data[len - 1 - i];
	}
	path = key_info->path;
	r = sc_select_file(card, &path, NULL);
	if (r == SC_SUCCESS)
		r = sc_change_reference_data(card, 0, 0, NULL, 0, buf, key_len, NULL);
	assert(buf);
	sc_mem_clear(buf, key_len);
	/* store public key */
	if (key->algorithm == SC_ALGORITHM_RSA)
		key_len = len * 3;
	else
		goto end;
	assert(key_len <= buf_len);
	if (key->algorithm == SC_ALGORITHM_RSA)
	{
		/* modulus */
		for (i = 0; i < 2*len; ++i)
			buf[i] = key->u.rsa.modulus.data[2*len - 1 - i];
		/* exponent */
		for (i = 0; i < key->u.rsa.exponent.len && i < len; ++i)
			buf[2 * len + i] = key->u.rsa.exponent.data[
				key->u.rsa.exponent.len - 1 - i];
	}
	if (r == SC_SUCCESS)
	{
		r = sc_profile_get_file(profile, "PuKey-DF", &pukey_df);
		if (r == SC_SUCCESS)
		{
			assert(pukey_df);
			path = pukey_df->path;
			r = sc_append_file_id(&path, key_info->key_reference);
			sc_file_free(pukey_df);
		}
		else if (card->ctx->debug >= 2)
			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "%s\n", "Get PuKey-DF info failed");
	}
	if (r == SC_SUCCESS)
	{
		r = sc_select_file(card, &path, NULL);
		if (r == SC_SUCCESS)
			r = sc_change_reference_data(card, 0, 0, NULL, 0,
					buf, key_len, NULL);
		if (r && card->ctx->debug >= 2)
			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "%s\n", "Store public key failed");
	}
end:
	assert(buf);
	free(buf);
	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
}
Exemple #8
0
/*
 * Generate a keypair
 */
static int
jcop_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
		  sc_pkcs15_object_t *obj,
		  sc_pkcs15_pubkey_t *pubkey)
{
     sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
     struct sc_cardctl_jcop_genkey args;
     sc_file_t       *temppubfile=NULL, *keyfile=NULL;
     unsigned char   *keybuf=NULL;
     size_t          mod_len, exp_len, pub_len, keybits;
     int             r,delete_ok=0;

     if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
	  sc_debug(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, "JCOP supports only RSA keys.");
	  return SC_ERROR_NOT_SUPPORTED;
     }

     r=sc_profile_get_file(profile, "temp-pubkey", &temppubfile);
     if (r < 0)
	  goto out;

     r = sc_select_file(p15card->card, &key_info->path, &keyfile);
     if (r < 0)
	  goto out;

     mod_len = key_info->modulus_length / 8;
     exp_len = 4;
     pub_len = 2 + mod_len + exp_len;
     temppubfile->size = pub_len;

     r = sc_pkcs15init_fixup_file(profile, p15card, temppubfile);
     if (r < 0)
	  goto out;

     r = sc_pkcs15init_create_file(profile, p15card, temppubfile);
     if (r < 0)
	  goto out;

     delete_ok=1;
     r = sc_pkcs15init_authenticate(profile, p15card, temppubfile, SC_AC_OP_UPDATE);
     if (r < 0)
	  goto out;
     r = sc_pkcs15init_authenticate(profile, p15card, keyfile, SC_AC_OP_UPDATE);
     if (r < 0)
	  goto out;

     keybits = key_info->modulus_length;

     /* generate key */
     /* keysize is _not_ passed to the card at any point. it appears to
	infer it from the file size */
     memset(&args, 0, sizeof(args));
     args.exponent = 0x10001;
     sc_append_file_id(&args.pub_file_ref, temppubfile->id);
     sc_append_file_id(&args.pri_file_ref, keyfile->id);
     keybuf = malloc(keybits / 8);
     if (!keybuf) {
	  r=SC_ERROR_OUT_OF_MEMORY;
	  goto out;
     }
     args.pubkey = keybuf;
     args.pubkey_len = keybits / 8;

     r = sc_card_ctl(p15card->card, SC_CARDCTL_JCOP_GENERATE_KEY, (void *)&args);
     if (r < 0)
	  goto out;

     /* extract public key */
     pubkey->algorithm = SC_ALGORITHM_RSA;
     pubkey->u.rsa.modulus.len   = keybits / 8;
     pubkey->u.rsa.modulus.data  = keybuf;
     pubkey->u.rsa.exponent.len  = 3;
     pubkey->u.rsa.exponent.data = malloc(3);
     if (!pubkey->u.rsa.exponent.data) {
	  pubkey->u.rsa.modulus.data = NULL;
	  r=SC_ERROR_OUT_OF_MEMORY;
	  goto out;
     }
     memcpy(pubkey->u.rsa.exponent.data, "\x01\x00\x01", 3);

 out:
     if (r < 0 && keybuf)
	  free(keybuf);
     if (delete_ok)
	  sc_pkcs15init_rmdir(p15card, profile, temppubfile);
     if (keyfile)
	  sc_file_free(keyfile);
     if (temppubfile)
	  sc_file_free(temppubfile);
     return r;
}
Exemple #9
0
static int insert_key(
	sc_pkcs15_card_t *p15card,
	const char       *path,
	unsigned char     id,
	unsigned char     key_reference,
	int               key_length,
	unsigned char     auth_id,
	const char       *label
){
	sc_card_t *card=p15card->card;
	sc_context_t *ctx=p15card->card->ctx;
	sc_file_t *f;
	struct sc_pkcs15_prkey_info prkey_info;
	struct sc_pkcs15_object prkey_obj;
	int r, can_sign, can_crypt;

	memset(&prkey_info, 0, sizeof(prkey_info));
	prkey_info.id.len         = 1;
	prkey_info.id.value[0]    = id;
	prkey_info.native         = 1;
	prkey_info.key_reference  = key_reference;
	prkey_info.modulus_length = key_length;
	sc_format_path(path, &prkey_info.path);

	memset(&prkey_obj, 0, sizeof(prkey_obj));
	strlcpy(prkey_obj.label, label, sizeof(prkey_obj.label));
	prkey_obj.flags            = SC_PKCS15_CO_FLAG_PRIVATE;
	prkey_obj.auth_id.len      = 1;
	prkey_obj.auth_id.value[0] = auth_id;

	can_sign=can_crypt=0;
	if(card->type==SC_CARD_TYPE_TCOS_V3){
		unsigned char buf[256];
		int i, rec_no=0;
		if(prkey_info.path.len>=2) prkey_info.path.len-=2;
		sc_append_file_id(&prkey_info.path, 0x5349);
		if(sc_select_file(card, &prkey_info.path, NULL)!=SC_SUCCESS){
			sc_debug(ctx, SC_LOG_DEBUG_NORMAL,
				"Select(%s) failed\n",
				sc_print_path(&prkey_info.path));
			return 1;
		}
		sc_debug(ctx, SC_LOG_DEBUG_NORMAL,
			"Searching for Key-Ref %02X\n", key_reference);
		while((r=sc_read_record(card, ++rec_no, buf, sizeof(buf), SC_RECORD_BY_REC_NR))>0){
			int found=0;
			if(buf[0]!=0xA0) continue;
			for(i=2;i<buf[1]+2;i+=2+buf[i+1]){
				if(buf[i]==0x83 && buf[i+1]==1 && buf[i+2]==key_reference) ++found;
			}
			if(found) break;
		}
		if(r<=0){
			sc_debug(ctx, SC_LOG_DEBUG_NORMAL,"No EF_KEYD-Record found\n");
			return 1;
		}
		for(i=0;i<r;i+=2+buf[i+1]){
			if(buf[i]==0xB6) can_sign++;
			if(buf[i]==0xB8) can_crypt++;
		}
	} else {
		if(sc_select_file(card, &prkey_info.path, &f)!=SC_SUCCESS){
			sc_debug(ctx, SC_LOG_DEBUG_NORMAL,
				"Select(%s) failed\n",
				sc_print_path(&prkey_info.path));
			return 1;
		}
		if (f->prop_attr[1] & 0x04) can_crypt=1;
		if (f->prop_attr[1] & 0x08) can_sign=1;
		sc_file_free(f);
	}
	prkey_info.usage= SC_PKCS15_PRKEY_USAGE_SIGN;
	if(can_crypt) prkey_info.usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT|SC_PKCS15_PRKEY_USAGE_DECRYPT;
	if(can_sign) prkey_info.usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;

	r=sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
	if(r!=SC_SUCCESS){
		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "sc_pkcs15emu_add_rsa_prkey(%s) failed\n", path);
		return 4;
	}
	sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "%s: OK%s%s\n", path, can_sign ? ", Sign" : "", can_crypt ? ", Crypt" : "");
	return 0;
}
Exemple #10
0
static int insert_pin(
	sc_pkcs15_card_t *p15card,
	const char       *path,
	unsigned char     id,
	unsigned char     auth_id,
	unsigned char     pin_reference,
	int               min_length,
	const char       *label,
	int               pin_flags
){
	sc_card_t *card=p15card->card;
	sc_context_t *ctx=p15card->card->ctx;
	sc_file_t *f;
	struct sc_pkcs15_auth_info pin_info;
	struct sc_pkcs15_object pin_obj;
	int r;

	memset(&pin_info, 0, sizeof(pin_info));
	pin_info.auth_id.len      = 1;
	pin_info.auth_id.value[0] = id;
	pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
	pin_info.attrs.pin.reference        = pin_reference;
	pin_info.attrs.pin.flags            = pin_flags;
	pin_info.attrs.pin.type             = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
	pin_info.attrs.pin.min_length       = min_length;
	pin_info.attrs.pin.stored_length    = 16;
	pin_info.attrs.pin.max_length       = 16;
	pin_info.attrs.pin.pad_char         = '\0';
	sc_format_path(path, &pin_info.path);

	memset(&pin_obj, 0, sizeof(pin_obj));
	strlcpy(pin_obj.label, label, sizeof(pin_obj.label));
	pin_obj.flags            = SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE;
	pin_obj.auth_id.len      = auth_id ? 0 : 1;
	pin_obj.auth_id.value[0] = auth_id;

	if(card->type==SC_CARD_TYPE_TCOS_V3){
		unsigned char buf[256];
		int i, rec_no=0;
		if(pin_info.path.len>=2) pin_info.path.len-=2;
		sc_append_file_id(&pin_info.path, 0x5049);
		if(sc_select_file(card, &pin_info.path, NULL)!=SC_SUCCESS){
			sc_debug(ctx, SC_LOG_DEBUG_NORMAL,
				"Select(%s) failed\n",
				sc_print_path(&pin_info.path));
			return 1;
		}
		sc_debug(ctx, SC_LOG_DEBUG_NORMAL,
			"Searching for PIN-Ref %02X\n", pin_reference);
		while((r=sc_read_record(card, ++rec_no, buf, sizeof(buf), SC_RECORD_BY_REC_NR))>0){
			int found=0, fbz=-1;
			if(buf[0]!=0xA0) continue;
			for(i=2;i<buf[1]+2;i+=2+buf[i+1]){
				if(buf[i]==0x83 && buf[i+1]==1 && buf[i+2]==pin_reference) ++found;
				if(buf[i]==0x90) fbz=buf[i+1+buf[i+1]];
			}
			if(found) pin_info.tries_left=fbz;
			if(found) break;
		}
		if(r<=0){
			sc_debug(ctx, SC_LOG_DEBUG_NORMAL,"No EF_PWDD-Record found\n");
			return 1;
		}
	} else {
		if(sc_select_file(card, &pin_info.path, &f)!=SC_SUCCESS){
			sc_debug(ctx, SC_LOG_DEBUG_NORMAL,"Select(%s) failed\n", path);
			return 1;
		}
		pin_info.tries_left=f->prop_attr[3];
		sc_file_free(f);
	}

	r=sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
	if(r!=SC_SUCCESS){
		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "sc_pkcs15emu_add_pin_obj(%s) failed\n", path);
		return 4;
	}
	sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "%s: OK, FBZ=%d\n", path, pin_info.tries_left);
	return 0;
}