Exemple #1
0
static int
gpk_read_rsa_key(sc_card_t *card, struct sc_pkcs15_pubkey_rsa *rsa)
{
	int	n, r;

	/* Read modulus and exponent */
	for (n = 2; ; n++) {
		sc_pkcs15_bignum_t *bn;
		u8		buffer[256];
		size_t		m;

		r = sc_read_record(card, n, buffer, sizeof(buffer),
				SC_RECORD_BY_REC_NR);
		if (r < 1)
			break;

		if (buffer[0] == 0x01)
			bn = &rsa->modulus;
		else if  (buffer[0] == 0x07)
			bn = &rsa->exponent;
		else
			continue;
		bn->len  = r - 1;
		bn->data = malloc(bn->len);
		for (m = 0; m < bn->len; m++)
			bn->data[m] = buffer[bn->len - m];
	}

	return 0;
}
static int do_update_record(int argc, char **argv)
{
	u8 buf[240];
	size_t buflen;
	int r, i, err = 1;
	int rec, offs;
	sc_path_t path;
	sc_file_t *file;

	if (argc != 4)
		return usage(do_update_record);
	if (arg_to_path(argv[0], &path, 0) != 0)
		return usage(do_update_record);
	rec  = strtol(argv[1],NULL,10);
	offs = strtol(argv[2],NULL,10);

	printf("in: %i; %i; %s\n", rec, offs, argv[3]);

	r = sc_select_file(card, &path, &file);
	if (r) {
		check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file);
		return -1;
	}

	if (file->ef_structure != SC_FILE_EF_LINEAR_VARIABLE)   {
		printf("EF structure should be SC_FILE_EF_LINEAR_VARIABLE\n");
		goto err;
	} else if (rec < 1 || rec > file->record_count)   {
		printf("Invalid record number %i\n", rec);
		goto err;
	}

	r = sc_read_record(card, rec, buf, sizeof(buf), SC_RECORD_BY_REC_NR);
	if (r<0)   {
		printf("Cannot read record %i; return %i\n", rec, r);
		goto err;;
	}

	buflen = sizeof(buf) - offs;
	i = parse_string_or_hexdata(argv[3], buf + offs, &buflen);
	if (!i) {
		printf("unable to parse data\n");
		goto err;
	}

	r = sc_update_record(card, rec, buf, r, SC_RECORD_BY_REC_NR);
	if (r<0)   {
		printf("Cannot update record %i; return %i\n", rec, r);
		goto err;
	}

	printf("Total of %d bytes written to record %i at %i offset.\n", 
	       i, rec, offs);

	err = 0;
err:
	sc_file_free(file);
	select_current_path_or_die();
	return -err;
}
Exemple #3
0
static int
gpk_pkfile_update_public(struct sc_profile *profile,
		sc_pkcs15_card_t *p15card, struct pkpart *part)
{
	struct sc_context *ctx = p15card->card->ctx;
	struct pkcomp	*pe;
	unsigned char	buffer[256];
	unsigned int	m, n, tag;
	int		r = 0, found;

	sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Updating public key elements\n");

	/* If we've been given a key with public parts, write them now */
	for (n = 2; n < 256; n++) {
		r = sc_read_record(p15card->card, n, buffer, sizeof(buffer),
				SC_RECORD_BY_REC_NR);
		if (r < 0) {
			r = 0;
			break;
		}

		/* Check for bad record */
		if (r < 2) {
			sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "key file format error: "
				"record %u too small (%u bytes)\n",
				n, r);
			return SC_ERROR_OBJECT_NOT_VALID;
		}

		tag = buffer[0];

		for (m = 0, found = 0; m < part->count; m++) {
			pe = part->components + m;
			if (pe->tag == tag) {
				r = sc_update_record(p15card->card, n,
						pe->data, pe->size,
						SC_RECORD_BY_REC_NR);
				if (r < 0)
					return r;
				pe->tag = 0; /* mark as stored */
				found++;
				break;
			}
		}

		if (!found)
			sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "GPK unknown PK tag %u\n", tag);
	}

	/* Write all remaining elements */
	for (m = 0; r >= 0 && m < part->count; m++) {
		pe = part->components + m;
		if (pe->tag != 0)
			r = sc_append_record(p15card->card, pe->data, pe->size, 0);
	}

	return r;
}
Exemple #4
0
static int mcrd_set_decipher_key_ref(sc_card_t * card, int key_reference)
{
	sc_apdu_t apdu;
	sc_path_t path;
	int r;
	u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
	u8 keyref_data[SC_ESTEID_KEYREF_FILE_RECLEN];
	assert(card != NULL);

	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xB8);
	/* track the active keypair  */
	sc_format_path("0033", &path);
	r = sc_select_file(card, &path, NULL);
	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Can't select keyref info file 0x0033");
	r = sc_read_record(card, 1, keyref_data,
			   SC_ESTEID_KEYREF_FILE_RECLEN, SC_RECORD_BY_REC_NR);
	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Can't read keyref info file!");

	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
		 "authkey reference 0x%02x%02x\n",
		 keyref_data[9], keyref_data[10]);

	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
		 "signkey reference 0x%02x%02x\n",
		 keyref_data[19], keyref_data[20]);

	sbuf[0] = 0x83;
	sbuf[1] = 0x03;
	sbuf[2] = 0x80;
	switch (key_reference) {
	case 1:
		sbuf[3] = keyref_data[9];
		sbuf[4] = keyref_data[10];
		break;
	case 2:
		sbuf[3] = keyref_data[19];
		sbuf[4] = keyref_data[20];
		break;
	}
	apdu.data = sbuf;
	apdu.lc = 5;
	apdu.datalen = 5;
	r = sc_transmit_apdu(card, &apdu);
	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
}
static int read_and_print_record_file(sc_file_t *file, unsigned char sfi)
{
	u8 buf[256];
	int rec, r;

	for (rec = 1; ; rec++) {
		r = sc_read_record(card, rec, buf, sizeof(buf),
			SC_RECORD_BY_REC_NR | sfi);
		if (r == SC_ERROR_RECORD_NOT_FOUND)
			return 0;
		if (r < 0) {
			check_ret(r, SC_AC_OP_READ, "read failed", file);
			return -1;
		}
		printf("Record %d:\n", rec);
		util_hex_dump_asc(stdout, buf, r, 0);
	}
}
Exemple #6
0
/*
 * Extract a key component from the public key file populated by
 * GENERATE KEY PAIR
 */
static int
incrypto34_extract_pubkey(sc_card_t *card, int nr, u8 tag,
			sc_pkcs15_bignum_t *bn)
{
	u8	buf[256];
	int	r, count;

	r = sc_read_record(card, nr, buf, sizeof(buf), SC_RECORD_BY_REC_NR);
	if (r < 0)
		return r;
	count = r - 4;
	if (count <= 0 || buf[0] != tag || buf[1] != count + 2
	 || buf[2] != count + 1 || buf[3] != 0)
		return SC_ERROR_INTERNAL;
	bn->len = count;
	bn->data = malloc(count);
	memcpy(bn->data, buf + 4, count);
	return 0;
}
static int read_and_print_record_file(sc_file_t *file)
{
	u8 buf[256];
	int rec, r;

	for (rec = 1; ; rec++) {
		ctx->suppress_errors++;
		r = sc_read_record(card, rec, buf, sizeof(buf), SC_RECORD_BY_REC_NR);
		ctx->suppress_errors--;
		if (r == SC_ERROR_RECORD_NOT_FOUND)
			return 0;
		if (r < 0) {
			check_ret(r, SC_AC_OP_READ, "read failed", file);
			return -1;
		}
		printf("Record %d:\n", rec);
		hex_dump_asc(stdout, buf, r, 0);
	}
}
static int
do_cardos_extract_pubkey(sc_card_t *card, int nr, u8 tag,
			sc_pkcs15_bignum_t *bn)
{
	u8	buf[256];
	int	r, count;

	r = sc_read_record(card, nr, buf, sizeof(buf), SC_RECORD_BY_REC_NR);
	if (r < 0)
		return r;
	count = r - 4;
	if (count <= 0 || buf[0] != tag || buf[1] != count + 2
	    || buf[2] != count + 1 || buf[3] != 0)
		return SC_ERROR_INTERNAL;
	bn->len = count;
	bn->data = (u8 *) malloc(count);
	if (bn->data == NULL)
		return SC_ERROR_OUT_OF_MEMORY;
	memcpy(bn->data, buf + 4, count);
	return SC_SUCCESS;
}
static int 
sc_oberthur_read_file(struct sc_pkcs15_card *p15card, const char *in_path, 
		unsigned char **out, size_t *out_len,
		int verify_pin)
{
	struct sc_context *ctx = p15card->card->ctx;
	struct sc_card *card = p15card->card;
	struct sc_file *file = NULL;
	struct sc_path path;
	size_t sz;
	int rv;

	SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
	if (!in_path || !out || !out_len)
		SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS, "Cannot read oberthur file");
		
	sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "read file '%s'; verify_pin:%i", in_path, verify_pin);
	
	*out = NULL;
	*out_len = 0;
	
	sc_format_path(in_path, &path);
	rv = sc_select_file(card, &path, &file);
	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannot select oberthur file to read");

	if (file->ef_structure == SC_FILE_EF_TRANSPARENT)
		sz = file->size;
	else
		sz = (file->record_length + 2) * file->record_count;
	
	*out = calloc(sz, 1);
	if (*out == NULL)
		SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_MEMORY_FAILURE, "Cannot read oberthur file");

	if (file->ef_structure == SC_FILE_EF_TRANSPARENT)   {
		rv = sc_read_binary(card, 0, *out, sz, 0);
	}
	else	{
		int rec;
		int offs = 0;
		int rec_len = file->record_length;
		
		for (rec = 1; ; rec++)   {
			rv = sc_read_record(card, rec, *out + offs + 2, rec_len, SC_RECORD_BY_REC_NR);
			if (rv == SC_ERROR_RECORD_NOT_FOUND)   {
				rv = 0;
				break;
			}
			else if (rv < 0)   {
				break;
			}

			rec_len = rv; 
				
			*(*out + offs) = 'R';
			*(*out + offs + 1) = rv;
			
			offs += rv + 2;
		}

		sz = offs;
	}

	sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "read oberthur file result %i", rv);
	if (verify_pin && rv == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED)   {
		struct sc_pkcs15_object *objs[0x10], *pin_obj = NULL;
		const struct sc_acl_entry *acl = sc_file_get_acl_entry(file, SC_AC_OP_READ);
		int ii;

		rv = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_AUTH_PIN, objs, 0x10);
		SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, rv, "Cannot read oberthur file: get AUTH objects error");

		for (ii=0; ii<rv; ii++)   {
			struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *) objs[ii]->data;
			sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "compare PIN/ACL refs:%i/%i, method:%i/%i", 
					auth_info->attrs.pin.reference, acl->key_ref, auth_info->auth_method, acl->method);
			if (auth_info->attrs.pin.reference == (int)acl->key_ref && auth_info->auth_method == (unsigned)acl->method)   {
				pin_obj = objs[ii];
				break;
			}
		}

		if (!pin_obj || !pin_obj->content.value)    {
			rv = SC_ERROR_SECURITY_STATUS_NOT_SATISFIED;
		}
		else    {
			rv = sc_pkcs15_verify_pin(p15card, pin_obj, pin_obj->content.value, pin_obj->content.len);
			if (!rv)
				rv = sc_oberthur_read_file(p15card, in_path, out, out_len, 0);
		}
	};
			
	sc_file_free(file);

	if (rv < 0)   {
		free(*out);
		*out = NULL;
		*out_len = 0;
	}

	*out_len = sz;

	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, rv);
}
Exemple #10
0
static int
sc_pkcs15emu_esteid_init (sc_pkcs15_card_t * p15card)
{
	sc_card_t *card = p15card->card;
	unsigned char buff[128];
	int r, i;
	sc_path_t tmppath;

	set_string (&p15card->tokeninfo->label, "ID-kaart");
	set_string (&p15card->tokeninfo->manufacturer_id, "AS Sertifitseerimiskeskus");

	/* Select application directory */
	sc_format_path ("3f00eeee5044", &tmppath);
	r = sc_select_file (card, &tmppath, NULL);
	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "select esteid PD failed");

	/* read the serial (document number) */	
	r = sc_read_record (card, SC_ESTEID_PD_DOCUMENT_NR, buff, sizeof(buff), SC_RECORD_BY_REC_NR);
	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "read document number failed");
	buff[r] = '\0';
	set_string (&p15card->tokeninfo->serial_number, (const char *) buff);

	p15card->tokeninfo->flags = SC_PKCS15_TOKEN_PRN_GENERATION
				  | SC_PKCS15_TOKEN_EID_COMPLIANT
				  | SC_PKCS15_TOKEN_READONLY;

	/* add certificates */
	for (i = 0; i < 2; i++) {
		static const char *esteid_cert_names[2] = {
			"Isikutuvastus",
			"Allkirjastamine"};
		static char const *esteid_cert_paths[2] = {
			"3f00eeeeaace",
			"3f00eeeeddce"};
		static int esteid_cert_ids[2] = {1, 2};
			
		struct sc_pkcs15_cert_info cert_info;
		struct sc_pkcs15_object cert_obj;
		
		memset(&cert_info, 0, sizeof(cert_info));
		memset(&cert_obj, 0, sizeof(cert_obj));

		cert_info.id.value[0] = esteid_cert_ids[i];
		cert_info.id.len = 1;
		sc_format_path(esteid_cert_paths[i], &cert_info.path);
		strlcpy(cert_obj.label, esteid_cert_names[i], sizeof(cert_obj.label));
		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
#ifdef ENABLE_OPENSSL
		if (i == 0) {
			BIO *mem = NULL;
			X509 *x509 = NULL;
			sc_pkcs15_cert_t *cert;
			char cardholder_name[64];
			unsigned char *tmp = NULL;
			r = sc_pkcs15_read_certificate(p15card, &cert_info, &cert);
			if (r == SC_SUCCESS) {
				mem = BIO_new_mem_buf(cert->data.value, cert->data.len);
				if (!mem) {
					sc_pkcs15_free_certificate(cert);
					return SC_ERROR_INTERNAL;
				}
				x509 = d2i_X509_bio(mem, NULL);
				BIO_free(mem);
				sc_pkcs15_free_certificate(cert);
				if (!x509)
					return SC_ERROR_INTERNAL;
				r = X509_NAME_get_index_by_NID(X509_get_subject_name(x509), NID_commonName, -1);
				if (r >= 0) {
					X509_NAME_ENTRY *ne;
					ASN1_STRING *a_str;
					ne = X509_NAME_get_entry(X509_get_subject_name(x509), r);
					if (!ne) {
						X509_free(x509);
						return SC_ERROR_INTERNAL;
					}
					a_str = X509_NAME_ENTRY_get_data(ne);
					if (!a_str) {
						X509_free(x509);
						return SC_ERROR_INTERNAL;
					}
					r = ASN1_STRING_to_UTF8(&tmp, a_str);
					if (r > 0) {
						if ((unsigned)r > sizeof(cardholder_name) - 1)
							r = sizeof(cardholder_name) -1;
						memcpy(cardholder_name, tmp, r);
						cardholder_name[r] = '\0';
						set_string(&p15card->tokeninfo->label, cardholder_name);
						OPENSSL_free(tmp);
					}
				}
				X509_free(x509);
			}
		}
#endif
	}

	/* the file with key pin info (tries left) */
	sc_format_path ("3f000016", &tmppath);
	r = sc_select_file (card, &tmppath, NULL);
	if (r < 0)
		return SC_ERROR_INTERNAL;

	/* add pins */
	for (i = 0; i < 3; i++) {
		unsigned char tries_left;
		static const char *esteid_pin_names[3] = {
			"PIN1",
			"PIN2",
			"PUK" };
			
		static const int esteid_pin_min[3] = {4, 5, 8};
		static const int esteid_pin_ref[3] = {1, 2, 0};
		static const int esteid_pin_authid[3] = {1, 2, 3};
		static const int esteid_pin_flags[3] = {0, 0, SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN};
		
		struct sc_pkcs15_auth_info pin_info;
		struct sc_pkcs15_object pin_obj;

		memset(&pin_info, 0, sizeof(pin_info));
		memset(&pin_obj, 0, sizeof(pin_obj));
		
		/* read the number of tries left for the PIN */
		r = sc_read_record (card, i + 1, buff, sizeof(buff), SC_RECORD_BY_REC_NR);
		if (r < 0)
			return SC_ERROR_INTERNAL;
		tries_left = buff[5];
		
		pin_info.auth_id.len = 1;
		pin_info.auth_id.value[0] = esteid_pin_authid[i];
		pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;	
		pin_info.attrs.pin.reference = esteid_pin_ref[i];
		pin_info.attrs.pin.flags = esteid_pin_flags[i];
		pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
		pin_info.attrs.pin.min_length = esteid_pin_min[i];
		pin_info.attrs.pin.stored_length = 12;
		pin_info.attrs.pin.max_length = 12;
		pin_info.attrs.pin.pad_char = '\0';
		pin_info.tries_left = (int)tries_left;
		pin_info.max_tries = 3;

		strlcpy(pin_obj.label, esteid_pin_names[i], sizeof(pin_obj.label));
		pin_obj.flags = esteid_pin_flags[i];

		/* Link normal PINs with PUK */
		if (i < 2) {
			pin_obj.auth_id.len = 1;
			pin_obj.auth_id.value[0] = 3;
		}

		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
	}
	
	/* add private keys */
	for (i = 0; i < 2; i++) {
		static int prkey_pin[2] = {1, 2};
		static int prkey_usage[2] = {
			SC_PKCS15_PRKEY_USAGE_ENCRYPT
			| SC_PKCS15_PRKEY_USAGE_DECRYPT
			| SC_PKCS15_PRKEY_USAGE_SIGN,
			SC_PKCS15_PRKEY_USAGE_NONREPUDIATION};
			
		static const char *prkey_name[2] = {
			"Isikutuvastus",
			"Allkirjastamine"};

		struct sc_pkcs15_prkey_info prkey_info;
		struct sc_pkcs15_object prkey_obj;

		memset(&prkey_info, 0, sizeof(prkey_info));
		memset(&prkey_obj, 0, sizeof(prkey_obj));
		
		prkey_info.id.len = 1;
		prkey_info.id.value[0] = prkey_pin[i];
		prkey_info.usage  = prkey_usage[i];
		prkey_info.native = 1;
		prkey_info.key_reference = i + 1;
		if (card->type == SC_CARD_TYPE_MCRD_ESTEID_V30)
			prkey_info.modulus_length = 2048;
		else
			prkey_info.modulus_length = 1024;	

		strlcpy(prkey_obj.label, prkey_name[i], sizeof(prkey_obj.label));
		prkey_obj.auth_id.len = 1;
		prkey_obj.auth_id.value[0] = prkey_pin[i];
		prkey_obj.user_consent = 0;
		prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;

		r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
	}

	return SC_SUCCESS;
}
Exemple #11
0
/*
 * Set up the public key record for a signature only public key
 */
static int
gpk_pkfile_init_public(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *file,
		unsigned int algo, unsigned int bits,
		unsigned int usage)
{
	struct sc_context *ctx = p15card->card->ctx;
	const sc_acl_entry_t *acl;
	sc_file_t	*tmp = NULL;
	u8		sysrec[7], buffer[256];
	unsigned int	n, npins;
	int		r, card_type;

	/* Find out what sort of GPK we're using */
	if ((r = sc_card_ctl(p15card->card, SC_CARDCTL_GPK_VARIANT, &card_type)) < 0)
		return r;

	/* Set up the system record */
	memset(sysrec, 0, sizeof(sysrec));

	/* Mapping keyUsage to sysrec[2]:
	 * 	0x00	sign & unwrap
	 * 	0x10	sign only
	 * 	0x20	unwrap only
	 * 	0x30	CA key
	 *
	 * We start with a value of 0x30.
	 * If the key allows decryption, clear the sign only bit.
	 * Likewise, if it allows signing, clear the unwrap only bit.
	 */
	sysrec[2] = 0x30;
	if (usage & (SC_PKCS15_PRKEY_USAGE_DECRYPT|SC_PKCS15_PRKEY_USAGE_UNWRAP))
		sysrec[2] &= ~0x10;
	if (usage & (SC_PKCS15_PRKEY_USAGE_SIGN|SC_PKCS15_PRKEY_USAGE_NONREPUDIATION))
		sysrec[2] &= ~0x20;
	if (sysrec[2] == 0x30) {
		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Key usage should specify at least one of sign or decipher");
		return SC_ERROR_INVALID_ARGUMENTS;
	}

	/* Set the key size and algorithm */
	if ((r = gpk_pkfile_keybits(bits, &sysrec[1])) < 0
	 || (r = gpk_pkfile_keyalgo(algo, &sysrec[5])) < 0)
		return r;

	/* Set PIN protection if requested.
	 * As the crypto ACLs are stored inside the file,
	 * we have to get them from the profile here. */
	r = sc_profile_get_file_by_path(profile, &file->path, &tmp);
	if (r < 0)
		return r;
	/* Fix up PIN references in file ACL */
	if ((r = sc_pkcs15init_fixup_file(profile, p15card, tmp)) < 0)
		goto out;

	acl = sc_file_get_acl_entry(tmp, SC_AC_OP_CRYPTO);
	for (npins = 0; acl; acl = acl->next) {
		if (acl->method == SC_AC_NONE
		 || acl->method == SC_AC_NEVER)
			continue;
		if (acl->method != SC_AC_CHV) {
			sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Authentication method not "
				"supported for private key files.\n");
			r = SC_ERROR_NOT_SUPPORTED;
			goto out;
		}
		if (++npins >= 2) {
			sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Too many pins for PrKEY file!\n");
			r = SC_ERROR_NOT_SUPPORTED;
			goto out;
		}
		sysrec[2] += 0x40;
		sysrec[3] >>= 4;
		sysrec[3] |= acl->key_ref << 4;
	}

	/* compute checksum - yet another slightly different
	 * checksum algorithm courtesy of Gemplus */
	if (card_type >= SC_CARD_TYPE_GPK_GPK8000) {
		/* This is according to the gpk reference manual */
		sysrec[6] = 0xA5;
	} else {
		/* And this is what you have to use for the GPK4000 */
		sysrec[6] = 0xFF;
	}
	for (n = 0; n < 6; n++)
		sysrec[6] ^= sysrec[n];

	r = sc_read_record(p15card->card, 1, buffer, sizeof(buffer),
			SC_RECORD_BY_REC_NR);
	if (r >= 0) {
		if (r != 7 || buffer[0] != 0) {
			sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "first record of public key file is not Lsys0");
			r = SC_ERROR_OBJECT_NOT_VALID;
			goto out;
		}

		r = sc_update_record(p15card->card, 1, sysrec, sizeof(sysrec),
				SC_RECORD_BY_REC_NR);
	} else {
		r = sc_append_record(p15card->card, sysrec, sizeof(sysrec), 0);
	}

out:	if (tmp)
		sc_file_free(tmp);
	return r;
}
Exemple #12
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;
}
Exemple #13
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 #14
0
static void do_esteid(sc_card_t *card)
{
	sc_path_t path;
	int r, i;
	unsigned char buff[512];

	if (stats) {
		int key_used[4];
		sc_format_path("3f00eeee0013", &path);
		r = sc_select_file(card, &path, NULL);
		if (r) {
			fprintf(stderr, "Failed to select key counters: %s\n", sc_strerror(r));
			goto out;
		}
	
		/* print the counters */
		for (i = 1; i <= 4; i++) {
			r = sc_read_record(card, i, buff, 128, SC_RECORD_BY_REC_NR);
			key_used[i - 1] = 0xffffff - ((unsigned char) buff[0xc] * 65536
									+ (unsigned char) buff[0xd] * 256
									+ (unsigned char) buff[0xe]);
		}
		for (i = 0; i < 2; i++) {
			printf("Key generation #%d usage:\n\tsign: %d\n\tauth: %d\n",
					 i, key_used[i], key_used[i + 2]);
		}
		exit_status = EXIT_SUCCESS;
		goto out;
	}
	
	/* Or just read the datafile */
	sc_format_path("3f00eeee5044", &path);
	r = sc_select_file(card, &path, NULL);
	if (r) {
		fprintf(stderr, "Failed to select DF: %s\n", sc_strerror(r));
		goto out;
	}

	for (i = 0; esteid_data[i].recno != 0; i++) {
		r = sc_read_record(card, esteid_data[i].recno, buff, 50, SC_RECORD_BY_REC_NR);
		if (r < 0) {
			fprintf (stderr, "Failed to read record %d from card: %s\n",
						esteid_data[i].recno, sc_strerror (r));
			goto out;
		} 
		buff[r] = '\0';
		if (exec_program) {
			unsigned char * cp;
			cp = malloc(strlen(esteid_data[i].env_name) + 
				strlen((char *) buff) + 2);
			if (cp) { 
				strcpy((char *) cp,esteid_data[i].env_name);
				strcat((char *) cp,"=");
				strcat((char *) cp,(char *) buff);
				putenv((char *) cp);
			}
		} else {
			printf("%s: %s\n", esteid_data[i].name, buff);
		}
	}
	
	exit_status = EXIT_SUCCESS;

out:
	return;
}
static int do_update_record(int argc, char **argv)
{
	u8 buf[240];
	int r, i, err = 1;
	int rec, offs;
	sc_path_t path;
	sc_file_t *file;
	char *in_str;
	
	if (argc < 3 || argc > 4)
		goto usage;
	if (arg_to_path(argv[0], &path, 0) != 0)
		goto usage;
	rec  = strtol(argv[1],NULL,10);
	offs = strtol(argv[2],NULL,10);

	in_str = argv[3];
	printf("in: %i; %i; %s\n", rec, offs, in_str);

	r = sc_select_file(card, &path, &file);
	if (r) {
		check_ret(r, SC_AC_OP_SELECT, "unable to select file", current_file);
		return -1;
	}

	if (file->ef_structure != SC_FILE_EF_LINEAR_VARIABLE)   {
		printf("EF structure should be SC_FILE_EF_LINEAR_VARIABLE\n");
		goto err;
	} else if (rec < 1 || rec > file->record_count)   {
		printf("Invalid record number %i\n", rec);
		goto err;
	}
	
	r = sc_read_record(card, rec, buf, sizeof(buf), SC_RECORD_BY_REC_NR);
	if (r<0)   {
		printf("Cannot read record %i; return %i\n", rec, r);
		goto err;;
	}

	i = hex2binary(buf + offs, sizeof(buf) - offs, in_str);
	if (!i) {
		printf("unable to parse hex value\n");
		goto err;
	}

	r = sc_update_record(card, rec, buf, r, SC_RECORD_BY_REC_NR);
	if (r<0)   {
		printf("Cannot update record %i; return %i\n", rec, r);
		goto err;
	}

	printf("Total of %d bytes written to record %i at %i offset.\n", 
	       i, rec, offs);
	err = 0;

err:
	sc_file_free(file);
	select_current_path_or_die();
	return -err;
usage:
	printf("Usage: update_record <file id> rec_nr rec_offs <hex value>\n");
	return -1;
}
Exemple #16
0
/* Load the rule and keyd file into our private data.
   Return 0 on success */
static int load_special_files(sc_card_t * card)
{
	sc_context_t *ctx = card->ctx;
	int r, recno;
	struct df_info_s *dfi;
	struct rule_record_s *rule;
	struct keyd_record_s *keyd;

	/* First check whether we already cached it. */
	dfi = get_df_info(card);
	if (dfi && dfi->rule_file)
		return 0;	/* yes. */
	clear_special_files(dfi);
	if (!dfi)
		SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INTERNAL);

	/* Read rule file. Note that we bypass our cache here. */
	r = select_part(card, MCRD_SEL_EF, EF_Rule, NULL);
	SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "selecting EF_Rule failed");

	for (recno = 1;; recno++) {
		u8 recbuf[256];
		r = sc_read_record(card, recno, recbuf, sizeof(recbuf),
				   SC_RECORD_BY_REC_NR);

		if (r == SC_ERROR_RECORD_NOT_FOUND)
			break;
		else if (r < 0) {
			SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
		} else {
			rule = malloc(sizeof *rule + r);
			if (!rule)
				SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
			rule->recno = recno;
			rule->datalen = r;
			memcpy(rule->data, recbuf, r);
			rule->next = dfi->rule_file;
			dfi->rule_file = rule;
		}
	}

	sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "new EF_Rule file loaded (%d records)\n", recno - 1);

	/* Read the KeyD file. Note that we bypass our cache here. */
	r = select_part(card, MCRD_SEL_EF, EF_KeyD, NULL);
	if (r == SC_ERROR_FILE_NOT_FOUND) {
		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "no EF_KeyD file available\n");
		return 0;	/* That is okay. */
	}
	SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "selecting EF_KeyD failed");

	for (recno = 1;; recno++) {
		u8 recbuf[256];
		r = sc_read_record(card, recno, recbuf, sizeof(recbuf),
				   SC_RECORD_BY_REC_NR);

		if (r == SC_ERROR_RECORD_NOT_FOUND)
			break;
		else if (r < 0) {
			SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_VERBOSE, r);
		} else {
			keyd = malloc(sizeof *keyd + r);
			if (!keyd)
				SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
			keyd->recno = recno;
			keyd->datalen = r;
			memcpy(keyd->data, recbuf, r);
			keyd->next = dfi->keyd_file;
			dfi->keyd_file = keyd;
		}
	}

	sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "new EF_KeyD file loaded (%d records)\n", recno - 1);
	/* FIXME: Do we need to restore the current DF?  I guess it is
	   not required, but we could try to do so by selecting 3fff?  */
	return 0;
}
int sc_pkcs15_read_file(struct sc_pkcs15_card *p15card,
			const sc_path_t *in_path,
			u8 **buf, size_t *buflen,
			sc_file_t **file_out)
{
	sc_file_t *file = NULL;
	u8	*data = NULL;
	size_t	len = 0, offset = 0;
	int	r;

	assert(p15card != NULL && in_path != NULL && buf != NULL);

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

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

		sc_debug(p15card->card->ctx, "called, path=%s, index=%u, count=%d\n",
			pbuf, in_path->index, in_path->count);
	}

	r = -1; /* file state: not in cache */
	if (p15card->opts.use_cache) {
		r = sc_pkcs15_read_cached_file(p15card, in_path, &data, &len);
	}
	if (r) {
		r = sc_lock(p15card->card);
		SC_TEST_RET(p15card->card->ctx, r, "sc_lock() failed");
		r = sc_select_file(p15card->card, in_path, &file);
		if (r)
			goto fail_unlock;

		/* Handle the case where the ASN.1 Path object specified
		 * index and length values */
		if (in_path->count < 0) {
			len = file->size;
			offset = 0;
		} else {
			offset = in_path->index;
			len = in_path->count;
			/* Make sure we're within proper bounds */
			if (offset >= file->size
			 || offset + len > file->size) {
				r = SC_ERROR_INVALID_ASN1_OBJECT;
				goto fail_unlock;
			}
		}
		data = (u8 *) malloc(len);
		if (data == NULL) {
			r = SC_ERROR_OUT_OF_MEMORY;
			goto fail_unlock;
		}
		if (file->ef_structure == SC_FILE_EF_LINEAR_VARIABLE_TLV) {
			int i;
			size_t l, record_len;
			unsigned char *head;

			head = data;
			for (i=1;  ; i++) {
				l = len - (head - data);
				if (l > 256) { l = 256; }
				p15card->card->ctx->suppress_errors++;
				r = sc_read_record(p15card->card, i, head, l,
						SC_RECORD_BY_REC_NR);
				p15card->card->ctx->suppress_errors--;
				if (r == SC_ERROR_RECORD_NOT_FOUND)
					break;
				if (r < 0) {
					free(data);
					goto fail_unlock;
				}
				if (r < 2)
					break;
				record_len = head[1];
				if (record_len != 0xff) {
					memmove(head,head+2,r-2);
					head += (r-2);
				} else {
					if (r < 4)
						break;
					record_len = head[2] * 256 + head[3];
					memmove(head,head+4,r-4);
					head += (r-4);
				}
			}
			len = head-data;
			r = len;
		} else {
			r = sc_read_binary(p15card->card, offset, data, len, 0);
			if (r < 0) {
				free(data);
				goto fail_unlock;
			}
			/* sc_read_binary may return less than requested */
			len = r;
		} 
		sc_unlock(p15card->card);

		/* Return of release file */
		if (file_out != NULL)
			*file_out = file;
		else
			sc_file_free(file);
	}
	*buf = data;
	*buflen = len;
	return 0;

fail_unlock:
	if (file)
		sc_file_free(file);
	sc_unlock(p15card->card);
	return r;
}
Exemple #18
0
int sc_enum_apps(sc_card_t *card)
{
	struct sc_context *ctx = card->ctx;
	sc_path_t path;
	int ef_structure;
	size_t file_size, jj;
	int r, ii, idx;

	LOG_FUNC_CALLED(ctx);
	if (card->app_count < 0)
		card->app_count = 0;

	sc_format_path("3F002F00", &path);
	sc_file_free(card->ef_dir);
	card->ef_dir = NULL;
	r = sc_select_file(card, &path, &card->ef_dir);
	LOG_TEST_RET(ctx, r, "Cannot select EF.DIR file");

	if (card->ef_dir->type != SC_FILE_TYPE_WORKING_EF) {
		sc_file_free(card->ef_dir);
		card->ef_dir = NULL;
		LOG_TEST_RET(ctx, SC_ERROR_INVALID_CARD, "EF(DIR) is not a working EF.");
	}

	ef_structure = card->ef_dir->ef_structure;
	if (ef_structure == SC_FILE_EF_TRANSPARENT) {
		u8 *buf = NULL, *p;
		size_t bufsize;

		file_size = card->ef_dir->size;
		if (file_size == 0)
			LOG_FUNC_RETURN(ctx, 0);

		buf = malloc(file_size);
		if (buf == NULL)
			LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
		p = buf;
		r = sc_read_binary(card, 0, buf, file_size, 0);
		if (r < 0) {
			free(buf);
			LOG_TEST_RET(ctx, r, "sc_read_binary() failed");
		}
		bufsize = r;
		while (bufsize > 0) {
			if (card->app_count == SC_MAX_CARD_APPS) {
				sc_log(ctx, "Too many applications on card");
				break;
			}
			r = parse_dir_record(card, &p, &bufsize, -1);
			if (r)
				break;
		}
		if (buf)
			free(buf);

	}
	else {	/* record structure */
		unsigned char buf[256], *p;
		unsigned int rec_nr;
		size_t rec_size;

		/* Arbitrary set '16' as maximal number of records to check out:
		 * to avoid endless loop because of some incomplete cards/drivers */
		for (rec_nr = 1; rec_nr < 16; rec_nr++) {
			r = sc_read_record(card, rec_nr, buf, sizeof(buf), SC_RECORD_BY_REC_NR);
			if (r == SC_ERROR_RECORD_NOT_FOUND)
				break;
			LOG_TEST_RET(ctx, r, "read_record() failed");

			if (card->app_count == SC_MAX_CARD_APPS) {
				sc_log(ctx, "Too many applications on card");
				break;
			}

			rec_size = r;
			p = buf;
			parse_dir_record(card, &p, &rec_size, (int)rec_nr);
		}
	}

	/* Move known PKCS#15 applications to the head of the list */
	for (ii=0, idx=0; ii<card->app_count; ii++)   {
		for (jj=0; jj < sizeof(apps)/sizeof(apps[0]); jj++) {
			if (apps[jj].aid_len != card->app[ii]->aid.len)
				continue;
			if (memcmp(apps[jj].aid, card->app[ii]->aid.value, apps[jj].aid_len))
				continue;
			break;
		}

		if (ii != idx && jj < sizeof(apps)/sizeof(apps[0]))   {
			struct sc_app_info *tmp = card->app[idx];

			card->app[idx] = card->app[ii];
			card->app[ii] = tmp;
			idx++;
		}
	}

	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
Exemple #19
0
static int
sc_pkcs15emu_esteid_init (sc_pkcs15_card_t * p15card)
{
	sc_card_t *card = p15card->card;
	unsigned char buff[128];
	int r, i;
	size_t field_length = 0, modulus_length = 0;
	sc_path_t tmppath;

	set_string (&p15card->tokeninfo->label, "ID-kaart");
	set_string (&p15card->tokeninfo->manufacturer_id, "AS Sertifitseerimiskeskus");

	/* Select application directory */
	sc_format_path ("3f00eeee5044", &tmppath);
	r = sc_select_file (card, &tmppath, NULL);
	LOG_TEST_RET(card->ctx, r, "select esteid PD failed");

	/* read the serial (document number) */
	r = sc_read_record (card, SC_ESTEID_PD_DOCUMENT_NR, buff, sizeof(buff), SC_RECORD_BY_REC_NR);
	LOG_TEST_RET(card->ctx, r, "read document number failed");
	buff[MIN((size_t) r, (sizeof buff)-1)] = '\0';
	set_string (&p15card->tokeninfo->serial_number, (const char *) buff);

	p15card->tokeninfo->flags = SC_PKCS15_TOKEN_PRN_GENERATION
				  | SC_PKCS15_TOKEN_EID_COMPLIANT
				  | SC_PKCS15_TOKEN_READONLY;

	/* add certificates */
	for (i = 0; i < 2; i++) {
		static const char *esteid_cert_names[2] = {
			"Isikutuvastus",
			"Allkirjastamine"};
		static char const *esteid_cert_paths[2] = {
			"3f00eeeeaace",
			"3f00eeeeddce"};
		static int esteid_cert_ids[2] = {1, 2};

		struct sc_pkcs15_cert_info cert_info;
		struct sc_pkcs15_object cert_obj;

		memset(&cert_info, 0, sizeof(cert_info));
		memset(&cert_obj, 0, sizeof(cert_obj));

		cert_info.id.value[0] = esteid_cert_ids[i];
		cert_info.id.len = 1;
		sc_format_path(esteid_cert_paths[i], &cert_info.path);
		strlcpy(cert_obj.label, esteid_cert_names[i], sizeof(cert_obj.label));
		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
		if (i != 0)
			continue;

		sc_pkcs15_cert_t *cert = NULL;
		r = sc_pkcs15_read_certificate(p15card, &cert_info, &cert);
		if (r < 0)
			return SC_ERROR_INTERNAL;
		if (cert->key->algorithm == SC_ALGORITHM_EC)
			field_length = cert->key->u.ec.params.field_length;
		else
			modulus_length = cert->key->u.rsa.modulus.len * 8;
		static const struct sc_object_id cn_oid = {{ 2, 5, 4, 3, -1 }};
		u8 *cn_name = NULL;
		size_t cn_len = 0;
		sc_pkcs15_get_name_from_dn(card->ctx, cert->subject,
			cert->subject_len, &cn_oid, &cn_name, &cn_len);
		if (cn_len > 0) {
			char *token_name = malloc(cn_len+1);
			if (token_name) {
				memcpy(token_name, cn_name, cn_len);
				token_name[cn_len] = '\0';
				set_string(&p15card->tokeninfo->label, (const char*)token_name);
				free(token_name);
			}
		}
		free(cn_name);
		sc_pkcs15_free_certificate(cert);
	}

	/* the file with key pin info (tries left) */
	sc_format_path ("3f000016", &tmppath);
	r = sc_select_file (card, &tmppath, NULL);
	if (r < 0)
		return SC_ERROR_INTERNAL;

	/* add pins */
	for (i = 0; i < 3; i++) {
		unsigned char tries_left;
		static const char *esteid_pin_names[3] = {
			"PIN1",
			"PIN2",
			"PUK" };
			
		static const int esteid_pin_min[3] = {4, 5, 8};
		static const int esteid_pin_ref[3] = {1, 2, 0};
		static const int esteid_pin_authid[3] = {1, 2, 3};
		static const int esteid_pin_flags[3] = {0, 0, SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN};
		
		struct sc_pkcs15_auth_info pin_info;
		struct sc_pkcs15_object pin_obj;

		memset(&pin_info, 0, sizeof(pin_info));
		memset(&pin_obj, 0, sizeof(pin_obj));

		/* read the number of tries left for the PIN */
		r = sc_read_record (card, i + 1, buff, sizeof(buff), SC_RECORD_BY_REC_NR);
		if (r < 0)
			return SC_ERROR_INTERNAL;
		tries_left = buff[5];

		pin_info.auth_id.len = 1;
		pin_info.auth_id.value[0] = esteid_pin_authid[i];
		pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
		pin_info.attrs.pin.reference = esteid_pin_ref[i];
		pin_info.attrs.pin.flags = esteid_pin_flags[i];
		pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
		pin_info.attrs.pin.min_length = esteid_pin_min[i];
		pin_info.attrs.pin.stored_length = 12;
		pin_info.attrs.pin.max_length = 12;
		pin_info.attrs.pin.pad_char = '\0';
		pin_info.tries_left = (int)tries_left;
		pin_info.max_tries = 3;

		strlcpy(pin_obj.label, esteid_pin_names[i], sizeof(pin_obj.label));
		pin_obj.flags = esteid_pin_flags[i];

		/* Link normal PINs with PUK */
		if (i < 2) {
			pin_obj.auth_id.len = 1;
			pin_obj.auth_id.value[0] = 3;
		}

		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
	}

	/* add private keys */
	for (i = 0; i < 2; i++) {
		static int prkey_pin[2] = {1, 2};

		static const char *prkey_name[2] = {
			"Isikutuvastus",
			"Allkirjastamine"};

		struct sc_pkcs15_prkey_info prkey_info;
		struct sc_pkcs15_object prkey_obj;

		memset(&prkey_info, 0, sizeof(prkey_info));
		memset(&prkey_obj, 0, sizeof(prkey_obj));

		prkey_info.id.len = 1;
		prkey_info.id.value[0] = prkey_pin[i];
		prkey_info.native = 1;
		prkey_info.key_reference = i + 1;
		prkey_info.field_length = field_length;
		prkey_info.modulus_length = modulus_length;
		if (i == 1)
			prkey_info.usage = SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
		else if(field_length > 0) // ECC has sign and derive usage
			prkey_info.usage = SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_DERIVE;
		else
			prkey_info.usage = SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_DECRYPT;

		strlcpy(prkey_obj.label, prkey_name[i], sizeof(prkey_obj.label));
		prkey_obj.auth_id.len = 1;
		prkey_obj.auth_id.value[0] = prkey_pin[i];
		prkey_obj.user_consent = 0;
		prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;

		if(field_length > 0)
			r = sc_pkcs15emu_add_ec_prkey(p15card, &prkey_obj, &prkey_info);
		else
			r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
		if (r < 0)
			return SC_ERROR_INTERNAL;
	}

	return SC_SUCCESS;
}
static int print_file(sc_card_t *in_card, const sc_file_t *file,
	const sc_path_t *path, int depth)
{
	int r;
	const char *tmps;
	const char *ac_ops_df[] = {
		"select", "lock", "delete", "create", "rehab", "inval",
		"list"
	};
	const char *ac_ops_ef[] = {
		"read", "update", "write", "erase", "rehab", "inval"
	};
	
	for (r = 0; r < depth; r++)
		printf("  ");
	printf("%s ", sc_print_path(path));
	if (file->namelen) {
		printf("[");
		print_binary(stdout, file->name, file->namelen);
		printf("] ");
	}
	switch (file->type) {
	case SC_FILE_TYPE_WORKING_EF:
		tmps = "wEF";
		break;
	case SC_FILE_TYPE_INTERNAL_EF:
		tmps = "iEF";
		break;
	case SC_FILE_TYPE_DF:
		tmps = " DF";
		break;
	default:
		tmps = "unknown";
		break;
	}
	printf("type: %-3s, ", tmps);
	if (file->type != SC_FILE_TYPE_DF) {
		const char *structs[] = {
			"unknown", "transpnt", "linrfix", "linrfix(TLV)",
			"linvar", "linvar(TLV)", "lincyc", "lincyc(TLV)"
		};
		int ef_type = file->ef_structure;
		if (ef_type < 0 || ef_type > 7)
			ef_type = 0;	/* invalid or unknow ef type */
		printf("ef structure: %s, ", structs[ef_type]);
	}
	printf("size: %lu\n", (unsigned long) file->size);
	for (r = 0; r < depth; r++)
		printf("  ");
	if (file->type == SC_FILE_TYPE_DF)
		for (r = 0; r < (int) (sizeof(ac_ops_df)/sizeof(ac_ops_df[0])); r++)
			printf("%s[%s] ", ac_ops_df[r], acl_to_str(sc_file_get_acl_entry(file, r)));
	else
		for (r = 0; r < (int) (sizeof(ac_ops_ef)/sizeof(ac_ops_ef[0])); r++)
			printf("%s[%s] ", ac_ops_ef[r], acl_to_str(sc_file_get_acl_entry(file, r)));

	if (file->sec_attr_len) {
		printf("sec: ");
		/* Octets are as follows:
		 *   DF: select, lock, delete, create, rehab, inval
		 *   EF: read, update, write, erase, rehab, inval
		 * 4 MSB's of the octet mean:			 
		 *  0 = ALW, 1 = PIN1, 2 = PIN2, 4 = SYS,
		 * 15 = NEV */
		hex_dump(stdout, file->sec_attr, file->sec_attr_len, ":");
	}
	if (file->prop_attr_len) {
		printf("\n");
		for (r = 0; r < depth; r++)
			printf("  ");
		printf("prop: ");
		hex_dump(stdout, file->prop_attr, file->prop_attr_len, ":");
	}
	printf("\n\n");

	if (file->type == SC_FILE_TYPE_DF)
		return 0;

	if (file->ef_structure == SC_FILE_EF_TRANSPARENT) {
		unsigned char *buf;
		
		if (!(buf = (unsigned char *) malloc(file->size))) {
			fprintf(stderr, "out of memory");
			return 1;
		}

		r = sc_read_binary(in_card, 0, buf, file->size, 0);
		if (r > 0)
			hex_dump_asc(stdout, buf, r, 0);
		free(buf);
	} else {
		unsigned char buf[256];
		int i;

		for (i=0; i < file->record_count; i++) {
			printf("Record %d\n", i);
			r = sc_read_record(in_card, i, buf, 256, 0);
			if (r > 0)
				hex_dump_asc(stdout, buf, r, 0);
		}
	}
	return 0;
}