static int parse_ddo(struct sc_pkcs15_card *p15card, const u8 * buf, size_t buflen)
{
	struct sc_asn1_entry asn1_ddo[5];
	sc_path_t odf_path, ti_path, us_path;
	int r;

	sc_copy_asn1_entry(c_asn1_ddo, asn1_ddo);
	sc_format_asn1_entry(asn1_ddo + 1, &odf_path, NULL, 0);
	sc_format_asn1_entry(asn1_ddo + 2, &ti_path, NULL, 0);
	sc_format_asn1_entry(asn1_ddo + 3, &us_path, NULL, 0);

	r = sc_asn1_decode(p15card->card->ctx, asn1_ddo, buf, buflen, NULL, NULL);
	if (r) {
		sc_error(p15card->card->ctx, "DDO parsing failed: %s\n",
		      sc_strerror(r));
		return r;
	}
	if (asn1_ddo[1].flags & SC_ASN1_PRESENT) {
		p15card->file_odf = sc_file_new();
		if (p15card->file_odf == NULL)
			goto mem_err;
		p15card->file_odf->path = odf_path;
	}
	if (asn1_ddo[2].flags & SC_ASN1_PRESENT) {
		p15card->file_tokeninfo = sc_file_new();
		if (p15card->file_tokeninfo == NULL)
			goto mem_err;
		p15card->file_tokeninfo->path = ti_path;
	}
	if (asn1_ddo[3].flags & SC_ASN1_PRESENT) {
		p15card->file_unusedspace = sc_file_new();
		if (p15card->file_unusedspace == NULL)
			goto mem_err;
		p15card->file_unusedspace->path = us_path;
	}
	return 0;
mem_err:
	if (p15card->file_odf != NULL) {
		sc_file_free(p15card->file_odf);
		p15card->file_odf = NULL;
	}
	if (p15card->file_tokeninfo != NULL) {
		sc_file_free(p15card->file_tokeninfo);
		p15card->file_tokeninfo = NULL;
	}
	if (p15card->file_unusedspace != NULL) {
		sc_file_free(p15card->file_unusedspace);
		p15card->file_unusedspace = NULL;
	}
	return SC_ERROR_OUT_OF_MEMORY;
}
Exemple #2
0
static sc_pkcs15_df_t * sc_pkcs15emu_get_df(sc_pkcs15_card_t *p15card,
	unsigned int type)
{
	sc_pkcs15_df_t	*df;
	sc_file_t	*file;
	int		created = 0;

	while (1) {
		for (df = p15card->df_list; df; df = df->next) {
			if (df->type == type) {
				if (created)
					df->enumerated = 1;
				return df;
			}
		}

		assert(created == 0);

		file = sc_file_new();
		if (!file)
			return NULL;
		sc_format_path("11001101", &file->path);
		sc_pkcs15_add_df(p15card, type, &file->path);
		sc_file_free(file);
		created++;
	}
}
static int do_create(int argc, char **argv)
{
	sc_path_t path;
	sc_file_t *file;
	unsigned int size;
	int r, op;

	if (argc != 2)
		return usage(do_create);
	if (arg_to_path(argv[0], &path, 1) != 0)
		return usage(do_create);
	/* %z isn't supported everywhere */
	if (sscanf(argv[1], "%u", &size) != 1)
		return usage(do_create);
	file = sc_file_new();
	file->id = (path.value[0] << 8) | path.value[1];
	file->type = SC_FILE_TYPE_WORKING_EF;
	file->ef_structure = SC_FILE_EF_TRANSPARENT;
	file->size = (size_t) size;
	file->status = SC_FILE_STATUS_ACTIVATED;
	for (op = 0; op < SC_MAX_AC_OPS; op++)
		sc_file_add_acl_entry(file, op, SC_AC_NONE, 0);

	r = create_file(file);
	sc_file_free(file);
	return r;
}
static int do_mkdir(int argc, char **argv)
{
	sc_path_t path;
	sc_file_t *file;
	unsigned int size;
	int r, op;

	if (argc != 2)
		return usage(do_mkdir);
	if (arg_to_path(argv[0], &path, 1) != 0)
		return usage(do_mkdir);
	if (sscanf(argv[1], "%u", &size) != 1)
		return usage(do_mkdir);
	file = sc_file_new();
	file->id = (path.value[0] << 8) | path.value[1];
	file->type = SC_FILE_TYPE_DF;
	file->size = size;
	file->status = SC_FILE_STATUS_ACTIVATED;
	for (op = 0; op < SC_MAX_AC_OPS; op++)
		sc_file_add_acl_entry(file, op, SC_AC_NONE, 0);

	r = create_file(file);
	sc_file_free(file);
	return r;
}
Exemple #5
0
static int create_file_cert(sc_card_t *card)
{
	int r;
	int size = 0;
	sc_path_t path;
	sc_file_t *file = NULL;

	sc_format_path("3F00", &path);
	r = sc_select_file(card, &path, &file);
	if(r) goto out;

	if(file)
	{
		size = (file->size) - 32;
		sc_file_free(file);
		file = NULL;
	} else {
		size = 2048;
	}

	sc_format_path("0002", &path);
	r = sc_select_file(card, &path, NULL);
	if(r)
	{
		if(r != SC_ERROR_FILE_NOT_FOUND) goto out;

		file = sc_file_new();
		if(file == NULL)
		{
			printf("Memory error.\n");
			goto out;
		}

		file->type = SC_FILE_TYPE_WORKING_EF;
		file->ef_structure = SC_FILE_EF_TRANSPARENT;
		file->shareable = 0;

		file->size = size;

		r = sc_file_add_acl_entry(file, SC_AC_OP_READ, SC_AC_NONE, 0);
		if(r) goto out;
		r = sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_CHV, 0);
		if(r) goto out;
		r = sc_file_add_acl_entry(file, SC_AC_OP_ERASE, SC_AC_CHV, 0);
		if(r) goto out;

		file->path = path;
		r = sc_create_file(card, file);
		if(r) goto out;
	}

out:
	if(file)
		sc_file_free(file);

	return r;
}
Exemple #6
0
static int belpic_select_file(sc_card_t *card,
			      const sc_path_t *in_path, sc_file_t **file_out)
{
	sc_context_t *ctx;
	sc_apdu_t apdu;
	u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
	int r, pathlen;
	sc_file_t *file = NULL;

	assert(card != NULL && in_path != NULL);
	ctx = card->ctx;
	memcpy(path, in_path->value, in_path->len);
	pathlen = in_path->len;

	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x08, 0x0C);

	apdu.lc = pathlen;
	apdu.data = path;
	apdu.datalen = pathlen;

	apdu.resplen = 0;
	apdu.le = 0;

	r = sc_transmit_apdu(card, &apdu);

	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Select File APDU transmit failed");

	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
	if (r)
		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);

	next_idx = (size_t)-1;		/* reset */

	if (file_out != NULL) {
		file = sc_file_new();
		file->path = *in_path;
		if (pathlen >= 2)
			file->id = (in_path->value[pathlen - 2] << 8) | in_path->value[pathlen - 1];
		file->size = BELPIC_MAX_FILE_SIZE;
		file->shareable = 1;
		file->ef_structure = SC_FILE_EF_TRANSPARENT;
		if (pathlen == 2 && memcmp("\x3F\x00", in_path->value, 2) == 0)
			file->type = SC_FILE_TYPE_DF;
		else
			file->type = SC_FILE_TYPE_WORKING_EF;
		*file_out = file;
	}

	return 0;
}
static sc_file_t *
init_file(unsigned int type)
{
	struct sc_file	*file;
	unsigned int	op;

	file = sc_file_new();
	for (op = 0; op < SC_MAX_AC_OPS; op++) {
		sc_file_add_acl_entry(file, op, SC_AC_NONE, 0);
	}
	file->type = type;
	file->status = SC_FILE_STATUS_ACTIVATED;
	if (file->type != SC_FILE_TYPE_DF)
		file->ef_structure = SC_FILE_EF_TRANSPARENT;
	return file;
}
Exemple #8
0
static
int dump_ef(sc_card_t * card, const char *path, u8 * buf, size_t * buf_len)
{
	int rv;
	sc_file_t *file = sc_file_new();
	sc_format_path(path, &file->path);
	sc_select_file(card, &file->path, &file);
	if (file->size > *buf_len)
		return SC_ERROR_BUFFER_TOO_SMALL;
	rv = sc_read_binary(card, 0, buf, file->size, 0);
	if (rv < 0)
		return rv;
	*buf_len = rv;

	return SC_SUCCESS;
}
Exemple #9
0
static int starcos_select_aid(sc_card_t *card,
                              u8 aid[16], size_t len,
                              sc_file_t **file_out)
{
    sc_apdu_t apdu;
    int r;
    size_t i = 0;

    sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x04, 0x0C);
    apdu.lc = len;
    apdu.data = (u8*)aid;
    apdu.datalen = len;
    apdu.resplen = 0;
    apdu.le = 0;
    r = sc_transmit_apdu(card, &apdu);
    SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");

    /* check return value */
    if (!(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) && apdu.sw1 != 0x61 )
        SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));

    /* update cache */
    card->cache.current_path.type = SC_PATH_TYPE_DF_NAME;
    card->cache.current_path.len = len;
    memcpy(card->cache.current_path.value, aid, len);

    if (file_out) {
        sc_file_t *file = sc_file_new();
        if (!file)
            SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
        file->type = SC_FILE_TYPE_DF;
        file->ef_structure = SC_FILE_EF_UNKNOWN;
        file->path.len = 0;
        file->size = 0;
        /* AID */
        for (i = 0; i < len; i++)
            file->name[i] = aid[i];
        file->namelen = len;
        file->id = 0x0000;
        file->magic = SC_FILE_MAGIC;
        *file_out = file;
    }
    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
}
Exemple #10
0
static int
jpki_init(struct sc_card *card)
{
	struct jpki_private_data *drvdata;
	sc_file_t *mf;
	int flags;

	LOG_FUNC_CALLED(card->ctx);

	drvdata = malloc(sizeof (struct jpki_private_data));
	if (!drvdata)
		LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);

	memset(drvdata, 0, sizeof (struct jpki_private_data));

	/* create virtual MF */
	mf = sc_file_new();
	if (!mf) {
		free(drvdata);
		LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
	}
	sc_format_path("3f00", &mf->path);
	mf->type = SC_FILE_TYPE_DF;
	mf->shareable = 0;
	mf->ef_structure = SC_FILE_EF_UNKNOWN;
	mf->size = 0;
	mf->id = 0x3f00;
	mf->status = SC_FILE_STATUS_ACTIVATED;
	sc_file_add_acl_entry(mf, SC_AC_OP_SELECT, SC_AC_NONE, 0);
	sc_file_add_acl_entry(mf, SC_AC_OP_LIST_FILES, SC_AC_NONE, 0);
	sc_file_add_acl_entry(mf, SC_AC_OP_LOCK, SC_AC_NEVER, 0);
	sc_file_add_acl_entry(mf, SC_AC_OP_DELETE, SC_AC_NEVER, 0);
	sc_file_add_acl_entry(mf, SC_AC_OP_CREATE, SC_AC_NEVER, 0);
	drvdata->mf = mf;
	drvdata->selected = SELECT_MF;

	card->name = "jpki";
	card->drv_data = drvdata;

	flags = SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_PAD_PKCS1;
	_sc_card_add_rsa_alg(card, 2048, flags, 0);

	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
Exemple #11
0
static int entersafe_select_aid(sc_card_t *card,
								const sc_path_t *in_path,
								sc_file_t **file_out)
{
	int r = 0;

	if (card->cache.valid 
		&& card->cache.current_path.type == SC_PATH_TYPE_DF_NAME
		&& card->cache.current_path.len == in_path->len
		&& memcmp(card->cache.current_path.value, in_path->value, in_path->len)==0 )
	{
		 if(file_out)
		 {
			  *file_out = sc_file_new();
			  if(!file_out)
				   SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
		 }
	}
	else
	{
		 r = iso_ops->select_file(card,in_path,file_out);
		 SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");

		 /* update cache */
		 card->cache.current_path.type = SC_PATH_TYPE_DF_NAME;
		 card->cache.current_path.len = in_path->len;
		 memcpy(card->cache.current_path.value,in_path->value,in_path->len);
	}
	if (file_out) {
		 sc_file_t *file = *file_out;
		 assert(file);

		 file->type = SC_FILE_TYPE_DF;
		 file->ef_structure = SC_FILE_EF_UNKNOWN;
		 file->path.len = 0;
		 file->size = 0;
		 /* AID */
		 memcpy(file->name,in_path->value,in_path->len);
		 file->namelen = in_path->len;
		 file->id = 0x0000;
	}
	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
}
Exemple #12
0
static int esteid_select_file(struct sc_card *card, const struct sc_path *in_path, struct sc_file **file_out) {
	unsigned char pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
	size_t pathlen;
	struct sc_file *file = NULL;

	LOG_FUNC_CALLED(card->ctx);

	// Only support full paths
	if (in_path->type != SC_PATH_TYPE_PATH) {
		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
	}

	memcpy(path, in_path->value, in_path->len);
	pathlen = in_path->len;

	while (pathlen >= 2) {
		if (memcmp(path, "\x3F\x00", 2) == 0) {
			LOG_TEST_RET(card->ctx, esteid_select(card, 0x00, 0x3F, 0x00), "MF select failed");
		} else if (path[0] == 0xAD) {
			LOG_TEST_RET(card->ctx, esteid_select(card, 0x01, path[0], path[1]), "DF select failed");
		} else if (pathlen == 2) {
			LOG_TEST_RET(card->ctx, esteid_select(card, 0x02, path[0], path[1]), "EF select failed");

			if (file_out != NULL) // Just make a dummy file
			{
				file = sc_file_new();
				if (file == NULL)
					LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
				file->path = *in_path;
				file->size = 1536; // Dummy size, to be above 1024

				*file_out = file;
			}
		}
		path += 2;
		pathlen -= 2;
	}
	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
Exemple #13
0
static int sc_hsm_update_ef(sc_pkcs15_card_t *p15card, u8 prefix, u8 id, int erase, u8 *buf, size_t buflen)
{
	sc_card_t *card = p15card->card;
	sc_file_t *file = NULL;
	sc_file_t newfile;
	sc_path_t path;
	u8 fid[2];
	int r;

	fid[0] = prefix;
	fid[1] = id;

	sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, 2, 0, -1);

	r = sc_select_file(card, &path, NULL);

	if ((r == SC_SUCCESS) && erase) {
		r = sc_delete_file(card, &path);
		LOG_TEST_RET(card->ctx, r, "Could not delete file");
		r = SC_ERROR_FILE_NOT_FOUND;
	}

	if (r == SC_ERROR_FILE_NOT_FOUND) {
		file = sc_file_new();
		file->id = (path.value[0] << 8) | path.value[1];
		file->type = SC_FILE_TYPE_WORKING_EF;
		file->ef_structure = SC_FILE_EF_TRANSPARENT;
		file->size = (size_t) 0;
		file->status = SC_FILE_STATUS_ACTIVATED;
		r = sc_create_file(card, file);
		sc_file_free(file);
		LOG_TEST_RET(card->ctx, r, "Could not create file");
	}

	r = sc_update_binary(card, 0, buf, buflen, 0);
	LOG_FUNC_RETURN(card->ctx, r);
}
Exemple #14
0
static int update_ef(sc_card_t *card, u8 prefix, u8 id, int erase, const u8 *buf, size_t buflen)
{
	sc_file_t *file = NULL;
	sc_file_t newfile;
	sc_path_t path;
	u8 fid[2];
	int r;

	fid[0] = prefix;
	fid[1] = id;

	sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, 2, 0, -1);

	r = sc_select_file(card, &path, NULL);

	if ((r == SC_SUCCESS) && erase) {
		r = sc_delete_file(card, &path);
		r = SC_ERROR_FILE_NOT_FOUND;
	}

	if (r == SC_ERROR_FILE_NOT_FOUND) {
		file = sc_file_new();
		file->id = (path.value[0] << 8) | path.value[1];
		file->type = SC_FILE_TYPE_WORKING_EF;
		file->ef_structure = SC_FILE_EF_TRANSPARENT;
		file->size = (size_t) 0;
		file->status = SC_FILE_STATUS_ACTIVATED;
		r = sc_create_file(card, file);
		sc_file_free(file);
		if (r < 0) {
			return r;
		}
	}

	r = sc_update_binary(card, 0, buf, buflen, 0);
	return r;
}
static int sc_pkcs15_bind_internal(sc_pkcs15_card_t *p15card)
{
	unsigned char *buf = NULL;
	int    err, ok = 0;
	size_t len;
	sc_path_t tmppath;
	sc_card_t    *card = p15card->card;
	sc_context_t *ctx  = card->ctx;
	sc_pkcs15_tokeninfo_t tokeninfo;

	if (ctx->debug > 4)
		sc_debug(ctx, "trying normal pkcs15 processing\n");

	/* Enumerate apps now */
	if (card->app_count < 0) {
		err = sc_enum_apps(card);
		if (err < 0 && err != SC_ERROR_FILE_NOT_FOUND) {
			sc_error(ctx, "unable to enumerate apps: %s\n", sc_strerror(err));
			goto end;
		}
	}
	p15card->file_app = sc_file_new();
	if (p15card->file_app == NULL) {
		err = SC_ERROR_OUT_OF_MEMORY;
		goto end;
	}
	sc_format_path("3F005015", &p15card->file_app->path);
	if (card->app_count > 0) {
		const sc_app_info_t *info;
		
		info = sc_find_pkcs15_app(card);
		if (info != NULL) {
			if (info->path.len)
				p15card->file_app->path = info->path;
			if (info->ddo != NULL)
				parse_ddo(p15card, info->ddo, info->ddo_len);
		}
	}

	/* Check if pkcs15 directory exists */
	sc_ctx_suppress_errors_on(card->ctx);
	err = sc_select_file(card, &p15card->file_app->path, NULL);
#if 1
	/* If the above test failed on cards without EF(DIR),
	 * try to continue read ODF from 3F005031. -aet
	 */
	if ((err == SC_ERROR_FILE_NOT_FOUND) &&
	    (card->app_count < 1)) {
		sc_format_path("3F00", &p15card->file_app->path);
		err = SC_NO_ERROR;
	}
#endif
	sc_ctx_suppress_errors_off(card->ctx);
	if (err < 0)
		goto end;

	if (p15card->file_odf == NULL) {
		/* check if an ODF is present; suppress errors as we
		 * don't know yet whether we have a pkcs15 card */
		tmppath = p15card->file_app->path;
		sc_append_path_id(&tmppath, (const u8 *) "\x50\x31", 2);
		sc_ctx_suppress_errors_on(card->ctx);
		err = sc_select_file(card, &tmppath, &p15card->file_odf);
		sc_ctx_suppress_errors_off(card->ctx);
		
	} else {
		tmppath = p15card->file_odf->path;
		sc_file_free(p15card->file_odf);
		p15card->file_odf = NULL;
		err = sc_select_file(card, &tmppath, &p15card->file_odf);
	}
	if (err != SC_SUCCESS) {
		char pbuf[SC_MAX_PATH_STRING_SIZE];

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

		sc_debug(ctx, "EF(ODF) not found in '%s'\n", pbuf);
		goto end;
	}

	if ((len = p15card->file_odf->size) == 0) {
		sc_error(card->ctx, "EF(ODF) is empty\n");
		goto end;
	}
	buf = malloc(len);
	if(buf == NULL)
		return SC_ERROR_OUT_OF_MEMORY;
	err = sc_read_binary(card, 0, buf, len, 0);
	if (err < 0)
		goto end;
	if (err < 2) {
		err = SC_ERROR_PKCS15_APP_NOT_FOUND;
		goto end;
	}
	len = err;
	if (parse_odf(buf, len, p15card)) {
		err = SC_ERROR_PKCS15_APP_NOT_FOUND;
		sc_error(card->ctx, "Unable to parse ODF\n");
		goto end;
	}
	free(buf);
	buf = NULL;

	if (card->ctx->debug) {
		sc_pkcs15_df_t *df;

		sc_debug(card->ctx, "The following DFs were found:\n");
		for (df = p15card->df_list; df; df = df->next) {
			char pbuf[SC_MAX_PATH_STRING_SIZE];

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

			sc_debug(card->ctx,
				"  DF type %u, path %s, index %u, count %d\n",
				df->type, pbuf, df->path.index, df->path.count);
		}
	}

	if (p15card->file_tokeninfo == NULL) {
		tmppath = p15card->file_app->path;
		sc_append_path_id(&tmppath, (const u8 *) "\x50\x32", 2);
	} else {
		tmppath = p15card->file_tokeninfo->path;
		sc_file_free(p15card->file_tokeninfo);
		p15card->file_tokeninfo = NULL;
	}
	err = sc_select_file(card, &tmppath, &p15card->file_tokeninfo);
	if (err)
		goto end;

	if ((len = p15card->file_tokeninfo->size) == 0) {
		sc_error(card->ctx, "EF(TokenInfo) is empty\n");
		goto end;
	}
	buf = malloc(len);
	if(buf == NULL)
		return SC_ERROR_OUT_OF_MEMORY;
	err = sc_read_binary(card, 0, buf, len, 0);
	if (err < 0)
		goto end;
	if (err <= 2) {
		err = SC_ERROR_PKCS15_APP_NOT_FOUND;
		goto end;
	}

	memset(&tokeninfo, 0, sizeof(tokeninfo));
	err = sc_pkcs15_parse_tokeninfo(ctx, &tokeninfo, buf, (size_t)err);
	if (err != SC_SUCCESS)
		goto end;
	p15card->version         = tokeninfo.version;
	p15card->label           = tokeninfo.label;
	p15card->serial_number   = tokeninfo.serial_number;
	p15card->manufacturer_id = tokeninfo.manufacturer_id;
	p15card->last_update     = tokeninfo.last_update;
	p15card->flags           = tokeninfo.flags;
	p15card->preferred_language = tokeninfo.preferred_language;
	p15card->seInfo          = tokeninfo.seInfo;
	p15card->num_seInfo      = tokeninfo.num_seInfo;

	/* for cardos cards initialized by Siemens: sign with decrypt */
	if (strcmp(p15card->card->driver->short_name,"cardos") == 0
                && ( strcmp(p15card->manufacturer_id,"Siemens AG (C)") == 0
			|| strcmp(p15card->manufacturer_id,"Prime") == 0 ))
		p15card->flags |= SC_PKCS15_CARD_FLAG_SIGN_WITH_DECRYPT;

	ok = 1;
end:
	if(buf != NULL)
		free(buf);
	if (!ok) {
		sc_pkcs15_card_clear(p15card);
		return err;
	}

	return SC_SUCCESS;
}
Exemple #16
0
int main(int argc, char *argv[])
{
	int r, c, long_optind = 0;
	sc_context_param_t ctx_param;
	sc_card_t *card = NULL;
	sc_context_t *ctx = NULL;
	sc_file_t *file = NULL;
	sc_path_t path;
	RSA	*rsa = NULL;
	BIGNUM	*bn = NULL;
	BIO	*mem = NULL;
	static const char *pin = NULL;
	static const char *puk = NULL;

	while (1)
	{
		c = getopt_long(argc, argv, "r:wgol:ix:y:nut:fj:k:hv", \
			options, &long_optind);
		if (c == -1)
			break;
		if (c == '?' || c == 'h')
			util_print_usage_and_die(app_name, options, option_help, NULL);
		switch (c)
		{
			case 'r':
				opt_reader = optarg;
				break;
			case 'w':
				opt_wait = 1;
				break;
			case 'g':
				if(keylen == 0) keylen = 1536;
				break;
			case 'o':
				overwrite = 1;
				break;
			case 'l':
				keylen = atoi(optarg);
				break;
			case 'i':
				install_pin = 1;
				break;
			case 'x':
				util_get_pin(optarg, &pin);
				break;
			case 'y':
				util_get_pin(optarg, &puk);
				break;
			case 'n':
				new_pin = 1;
				break;
			case 'u':
				unlock = 1;
				break;
			case 't':
				cert = optarg;
				break;
			case 'f':
				finalize = 1;
				break;
			case 'j':
				get_filename = optarg;
				break;
			case 'k':
				put_filename = optarg;
				break;
			case 'v':
				verbose++;
				break;
		}
	}

	memset(&ctx_param, 0, sizeof(ctx_param));
	ctx_param.ver      = 0;
	ctx_param.app_name = argv[0];

	r = sc_context_create(&ctx, &ctx_param);
	if (r)
	{
		printf("Failed to establish context: %s\n", sc_strerror(r));
		return 1;
	}

	if (verbose > 1) {
		ctx->debug = verbose;
		sc_ctx_log_to_file(ctx, "stderr");
	}

	if (opt_driver != NULL)
	{
		r = sc_set_card_driver(ctx, opt_driver);
		if (r)
		{
			printf("Driver '%s' not found!\n", opt_driver);
			goto out;
		}
	}

	r = util_connect_card(ctx, &card, opt_reader, opt_wait, 0);
	if (r)
		goto out;

	sc_format_path("3F00", &path);
	r = sc_select_file(card, &path, NULL);
	if(r) goto out;

	if(install_pin)
	{
		sc_format_path("AAAA", &path);
		r = sc_select_file(card, &path, NULL);
		if(r)
		{
			if(r != SC_ERROR_FILE_NOT_FOUND) goto out;

			file = sc_file_new();
			if(file == NULL)
			{
				printf("Not enougth memory.\n");
				goto out;
			}

			file->type = SC_FILE_TYPE_INTERNAL_EF;
			file->ef_structure = SC_FILE_EF_TRANSPARENT;
			file->shareable = 0;

			file->id = 0xAAAA;
			file->size = 37;

			r = sc_file_add_acl_entry(file, SC_AC_OP_READ, SC_AC_NONE, 0);
			if(r) goto out;
			r = sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_NONE, 0);
			if(r) goto out;
			r = sc_file_add_acl_entry(file, SC_AC_OP_ERASE, SC_AC_NONE, 0);
			if(r) goto out;

			/* sc_format_path("3F00AAAA", &(file->path)); */
			file->path = path;
			r = sc_create_file(card, file);
			if(r) goto out;
		}

		if(pin != NULL)
		{
			sc_changekey_t ck;
			struct sc_pin_cmd_pin pin_cmd;
			int ret;

			memset(&pin_cmd, 0, sizeof(pin_cmd));
			memset(&ck, 0, sizeof(ck));

			memcpy(ck.key_template, "\x1e\x00\x00\x10", 4);

			pin_cmd.encoding = SC_PIN_ENCODING_GLP;
			pin_cmd.len = strlen(pin);
			pin_cmd.data = (u8*)pin;
			pin_cmd.max_length = 8;

			ret = sc_build_pin(ck.new_key.key_value,
				sizeof(ck.new_key.key_value), &pin_cmd, 1);
			if(ret < 0)
				goto out;

			ck.new_key.key_len = ret;
			r = sc_card_ctl(card, SC_CARDCTL_WESTCOS_CHANGE_KEY, &ck);
			if(r) goto out;
		}

		if(puk != NULL)
		{
			sc_changekey_t ck;
			struct sc_pin_cmd_pin puk_cmd;
			int ret;

			memset(&puk_cmd, 0, sizeof(puk_cmd));
			memset(&ck, 0, sizeof(ck));

			memcpy(ck.key_template, "\x1e\x00\x00\x20", 4);

			puk_cmd.encoding = SC_PIN_ENCODING_GLP;
			puk_cmd.len = strlen(puk);
			puk_cmd.data = (u8*)puk;
			puk_cmd.max_length = 8;

			ret = sc_build_pin(ck.new_key.key_value,
				sizeof(ck.new_key.key_value), &puk_cmd, 1);
			if(ret < 0)
				goto out;

			ck.new_key.key_len = ret;
			r = sc_card_ctl(card, SC_CARDCTL_WESTCOS_CHANGE_KEY, &ck);
			if(r) goto out;
		}
	}

	if(new_pin)
	{
		if(change_pin(card, 0, pin, puk))
			printf("Wrong pin.\n");
		goto out;
	}

	if(unlock)
	{
		if(unlock_pin(card, 0, puk, pin))
			printf("Error unblocking pin.\n");
		goto out;
	}

	printf("verify pin.\n");
	{
		if(verify_pin(card, 0, pin))
		{
			printf("Wrong pin.\n");
			goto out;
		}
	}

	if(keylen)
	{
		size_t lg;
		struct sc_pkcs15_pubkey key;
		struct sc_pkcs15_pubkey_rsa *dst = &(key.u.rsa);
		u8 *pdata;

		memset(&key, 0, sizeof(key));
		key.algorithm = SC_ALGORITHM_RSA;

		printf("Generate key of length %d.\n", keylen);

#if OPENSSL_VERSION_NUMBER>=0x00908000L
		rsa = RSA_new();
		bn = BN_new();
		mem = BIO_new(BIO_s_mem());

		if(rsa == NULL || bn == NULL || mem == NULL)
		{
			printf("Not enougth memory.\n");
			goto out;
		}

		if(!BN_set_word(bn, RSA_F4) ||
			!RSA_generate_key_ex(rsa, keylen, bn, NULL))
#else
		rsa = RSA_generate_key(keylen, RSA_F4, NULL, NULL);
		mem = BIO_new(BIO_s_mem());

		if(mem == NULL)
		{
			printf("Not enougth memory.\n");
			goto out;
		}

		if (!rsa)
#endif
		{
			printf("RSA_generate_key_ex return %ld\n", ERR_get_error());
			goto out;
		}

		RSA_set_method(rsa, RSA_PKCS1_OpenSSL());

		if(!i2d_RSAPrivateKey_bio(mem, rsa))
		{
			printf("i2d_RSAPrivateKey_bio return %ld\n", ERR_get_error());
			goto out;
		}

		lg = BIO_get_mem_data(mem, &pdata);

		sc_format_path("0001", &path);
		r = sc_select_file(card, &path, NULL);
		if(r)
		{
			if(r != SC_ERROR_FILE_NOT_FOUND) goto out;

			file = sc_file_new();
			if(file == NULL)
			{
				printf("Not enougth memory.\n");
				goto out;
			}

			file->type = SC_FILE_TYPE_WORKING_EF;
			file->ef_structure = SC_FILE_EF_TRANSPARENT;
			file->shareable = 0;

			file->size = ((lg/4)+1)*4;

			r = sc_file_add_acl_entry(file, SC_AC_OP_READ, SC_AC_CHV, 0);
			if(r) goto out;
			r = sc_file_add_acl_entry(file, SC_AC_OP_UPDATE, SC_AC_CHV, 0);
			if(r) goto out;
			r = sc_file_add_acl_entry(file, SC_AC_OP_ERASE, SC_AC_CHV, 0);
			if(r) goto out;

			file->path = path;

			printf("File key creation %s, size %"SC_FORMAT_LEN_SIZE_T"d.\n",
			       file->path.value,
			       file->size);

			r = sc_create_file(card, file);
			if(r) goto out;
		}
		else
		{
			if(!overwrite)
			{
				printf("Key file already exist,"\
						" use -o to replace it.\n");
				goto out;
			}
		}

		printf("Private key length is %"SC_FORMAT_LEN_SIZE_T"d\n", lg);

		printf("Write private key.\n");
		r = sc_update_binary(card,0,pdata,lg,0);
		if(r<0) goto out;
		printf("Private key correctly written.\n");

		r = create_file_cert(card);
		if(r) goto out;

		{
			const BIGNUM *rsa_n, *rsa_e;

			RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);

			if (!do_convert_bignum(&dst->modulus, rsa_n)
			 || !do_convert_bignum(&dst->exponent, rsa_e))
				goto out;

		}

		r = sc_pkcs15_encode_pubkey(ctx, &key, &pdata, &lg);
		if(r) goto out;

		printf("Public key length %"SC_FORMAT_LEN_SIZE_T"d\n", lg);

		sc_format_path("3F000002", &path);
		r = sc_select_file(card, &path, NULL);
		if(r) goto out;

		printf("Write public key.\n");
		r = sc_update_binary(card,0,pdata,lg,0);
		if(r<0) goto out;
		printf("Public key correctly written.\n");

	}

	if(cert)
	{
		BIO *bio;
		X509 *xp;
		u8 *pdata;

		bio = BIO_new(BIO_s_file());
		if (BIO_read_filename(bio, cert) <= 0)
		{
			BIO_free(bio);
			printf("Can't open file %s.\n", cert);
			goto out;
		}
		xp = PEM_read_bio_X509(bio, NULL, NULL, NULL);
		BIO_free(bio);
		if (xp == NULL)
		{
			print_openssl_error();
			goto out;
		}
		else
		{
			int lg = cert2der(xp, &pdata);

			sc_format_path("0002", &path);
			r = sc_select_file(card, &path, NULL);
			if(r) goto out;

			/* FIXME: verify if the file has a compatible size... */
			printf("Write certificate %s.\n", cert);

			r = sc_update_binary(card,0,pdata,lg,0);
			if(r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED)
			{
				if(verify_pin(card, 0, pin))
				{
					printf("Wrong pin.\n");
				}
				else
				{
					r = sc_update_binary(card,0,pdata,lg,0);
				}
			}
			if(r<0)
			{
				if(pdata) free(pdata);
				goto out;
			}
			if(xp) X509_free(xp);
			if(pdata) free(pdata);

			printf("Certificate correctly written.\n");
		}
	}

	if(finalize)
	{
		int mode = SC_CARDCTRL_LIFECYCLE_USER;

		if(card->atr.value[10] != 0x82)
		{
			sc_format_path("0001", &path);
			r = sc_select_file(card, &path, NULL);
			if(r)
			{
				printf("This card don't have private key"\
					" and can't be finalize.\n");
				goto out;
			}
			printf("Finalize card...\n");
			if(sc_card_ctl(card, SC_CARDCTL_WESTCOS_AUT_KEY, NULL) ||
				sc_card_ctl(card, SC_CARDCTL_LIFECYCLE_SET, &mode))
			{
				printf("Error finalizing card,"\
					" card isn't secure.\n");
				goto out;
			}
		}
		printf("Card correctly finalized.\n");
	}

	if(get_filename)
	{
		FILE *fp;
		u8 *b;

		if(file)
		{
			sc_file_free(file);
			file = NULL;
		}

		sc_format_path(get_filename, &path);
		r = sc_select_file(card, &path, &file);
		if(r)
		{
				printf("Error file not found.\n");
				goto out;
		}

		b = malloc(file->size);
		if(b == NULL)
		{
				printf("Not enougth memory.\n");
				goto out;
		}

		r = sc_read_binary(card, 0, b, file->size, 0);
		if(r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED)
		{
			if(verify_pin(card, 0, pin))
			{
				printf("Wrong pin.\n");
				goto out;
			}
			r = sc_read_binary(card, 0, b, file->size, 0);
		}

		if(r<0)
		{
				printf("Error reading file.\n");
				goto out;
		}

		fp = fopen(get_filename, "wb");
		fwrite(b, 1, file->size, fp);
		fclose(fp);

		free(b);
	}

	if(put_filename)
	{
		FILE *fp;
		u8 *b;

		if(file)
		{
			sc_file_free(file);
			file = NULL;
		}

		sc_format_path(put_filename, &path);
		r = sc_select_file(card, &path, &file);
		if(r)
		{
				printf("File not found.\n");
				goto out;
		}

		b = malloc(file->size);
		if(b == NULL)
		{
				printf("Not enougth memory.\n");
				goto out;
		}

		memset(b, 0, file->size);

		fp = fopen(put_filename, "rb");
		fread(b, 1, file->size, fp);
		fclose(fp);

		r = sc_update_binary(card, 0, b, file->size, 0);
		if(r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED)
		{
			if(verify_pin(card, 0, pin))
			{
				printf("Wrong pin.\n");
			}
			else
			{
				r = sc_update_binary(card, 0, b, file->size, 0);
			}
		}
		if(r<0)
		{
				free(b);
				printf("Error writing file.\n");
				goto out;
		}

		free(b);
	}

out:

	if(mem)
		BIO_free(mem);
	if(bn)
		BN_free(bn);
	if(rsa)
		RSA_free(rsa);

	if(file)
		sc_file_free(file);

	if (card)
	{
		sc_unlock(card);
		sc_disconnect_card(card);
	}

	sc_release_context(ctx);

	return EXIT_SUCCESS;
}
Exemple #17
0
/*
 * Create an empty key object
 */
static int rtecp_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
		sc_pkcs15_object_t *obj)
{
	sc_context_t *ctx;
	/*                              RSA_PRkey/ Adds Miller-
	 *                              RSA_PUBkey Rabin tests    Attempts Reserve */
	const unsigned char prkey_prop[]  = { 0x23,          0, 0,    0xAA, 0, 0 };
	const unsigned char pbkey_prop[]  = { 0x33,          0, 0,    0xAA, 0, 0 };
	/*                  GOSTR3410_PRkey/
	 *                  GOSTR3410_PUBkey  paramset    Attempts Reserve */
	unsigned char prgkey_prop[] = { 0x03,      '?', 0,    0xAA, 0, 0 };
	unsigned char pbgkey_prop[] = { 0x13,      '?', 0,    0xAA, 0, 0 };
	/*                        AccessMode  - Update  Use  -  -  - Delete */
	unsigned char prkey_sec[15] = { 0x46, 0,   '?', '?', 0, 0, 0,   '?' };
	unsigned char pbkey_sec[15] = { 0x46, 0,   '?',   0, 0, 0, 0,   '?' };
	unsigned char auth_id, paramset;
	sc_pkcs15_prkey_info_t *key_info;
	sc_file_t *file;
	int r;

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

	ctx = p15card->card->ctx;
	SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
	if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA
			&& obj->type != SC_PKCS15_TYPE_PRKEY_GOSTR3410)
		return SC_ERROR_NOT_SUPPORTED;
	if (obj->auth_id.len != 1)
		return SC_ERROR_INVALID_ARGUMENTS;
	auth_id = obj->auth_id.value[0];

	key_info = (sc_pkcs15_prkey_info_t *)obj->data;
	assert(key_info);
	if ((obj->type == SC_PKCS15_TYPE_PRKEY_RSA
				&& key_info->modulus_length % 128 != 0)
			|| (obj->type == SC_PKCS15_TYPE_PRKEY_GOSTR3410
				&& key_info->modulus_length
				!= SC_PKCS15_GOSTR3410_KEYSIZE))
	{
		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Unsupported key size %u\n", key_info->modulus_length);
		return SC_ERROR_INVALID_ARGUMENTS;
	}
	if (obj->type == SC_PKCS15_TYPE_PRKEY_GOSTR3410)
	{
		if (key_info->params.len < sizeof(int))
			return SC_ERROR_INVALID_ARGUMENTS;
		if (((int*)key_info->params.data)[0] < 1
				|| ((int*)key_info->params.data)[0] > 3)
			return SC_ERROR_INVALID_ARGUMENTS;
		paramset = ((unsigned int*)key_info->params.data)[0] & 0x03;
		assert(sizeof(prgkey_prop)/sizeof(prgkey_prop[0]) > 1);
		assert(sizeof(pbgkey_prop)/sizeof(pbgkey_prop[0]) > 1);
		prgkey_prop[1] = 0x10 + (paramset << 4);
		pbgkey_prop[1] = prgkey_prop[1];
	}

	r = sc_profile_get_file(profile, "PKCS15-AppDF", &file);
	SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Get PKCS15-AppDF info failed");
	r = sc_file_add_acl_entry(file, SC_AC_OP_CREATE, SC_AC_CHV, auth_id);
	if (r == SC_SUCCESS)
		r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_CREATE);
	assert(file);
	sc_file_free(file);
	SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Authenticate failed");

	file = sc_file_new();
	if (!file)
		SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
	file->id = key_info->key_reference;
	r = sc_file_set_type_attr(file, (const u8*)"\x10\x00", 2);

	/* private key file */
	if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA)
		file->size = key_info->modulus_length / 8 / 2 * 5 + 8;
	else
		file->size = key_info->modulus_length / 8;
	if (r == SC_SUCCESS)
	{
		assert(sizeof(prkey_sec)/sizeof(prkey_sec[0]) > 7);
		prkey_sec[2] = auth_id;
		prkey_sec[3] = auth_id;
		prkey_sec[7] = auth_id;
		r = sc_file_set_sec_attr(file, prkey_sec, sizeof(prkey_sec));
	}
	if (r == SC_SUCCESS)
	{
		if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA)
			r = sc_file_set_prop_attr(file, prkey_prop, sizeof(prkey_prop));
		else
			r = sc_file_set_prop_attr(file, prgkey_prop,sizeof(prgkey_prop));
	}
	if (r == SC_SUCCESS)  {
		sc_log(ctx, "create private key file id:%04i", file->id);
		r = sc_create_file(p15card->card, file);
	}
	/* public key file */
	if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA)
		file->size = key_info->modulus_length / 8 / 2 * 3;
	else
		file->size = key_info->modulus_length / 8 * 2;
	if (r == SC_SUCCESS)
	{
		assert(sizeof(pbkey_sec)/sizeof(pbkey_sec[0]) > 7);
		pbkey_sec[2] = auth_id;
		pbkey_sec[7] = auth_id;
		r = sc_file_set_sec_attr(file, pbkey_sec, sizeof(pbkey_sec));
	}
	if (r == SC_SUCCESS)
	{
		if (obj->type == SC_PKCS15_TYPE_PRKEY_RSA)
			r = sc_file_set_prop_attr(file, pbkey_prop, sizeof(pbkey_prop));
		else
			r = sc_file_set_prop_attr(file, pbgkey_prop,sizeof(pbgkey_prop));
	}
	if (r == SC_SUCCESS)   {
		sc_log(ctx, "create public key file id:%04i", file->id);
		r = sc_create_file(p15card->card, file);
	}
	assert(file);
	sc_file_free(file);
	SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, r);
}
Exemple #18
0
/*
 * Create a PIN object within the given DF
 */
static int rtecp_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)
{
	sc_context_t *ctx;
	sc_pkcs15_auth_info_t *auth_info;
	sc_file_t *file = NULL;
	/*                        GCHV min-length Flags Attempts  Reserve */
	unsigned char prop[]  = { 0x01,       '?', 0x01,     '?', 0, 0 };
	/*                  AccessMode Unblock Change             Delete */
	unsigned char sec[15] = { 0x43,    '?',   '?', 0, 0, 0, 0,  0xFF };
	char pin_sname[0x10];
	int r, reset_by_sopin = 0;

	(void)puk; /* no warning */
	if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !df
			|| !pin_obj || !pin_obj->data || !pin || !pin_len)
		return SC_ERROR_INVALID_ARGUMENTS;

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

	if (puk_len != 0)
	{
		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Do not enter User unblocking PIN (PUK): %s\n",
				sc_strerror(SC_ERROR_NOT_SUPPORTED));
		return SC_ERROR_NOT_SUPPORTED;
	}

	auth_info = (sc_pkcs15_auth_info_t *)pin_obj->data;
	if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
		return SC_ERROR_OBJECT_NOT_VALID;

	if (auth_info->attrs.pin.reference != RTECP_SO_PIN_REF
			&& auth_info->attrs.pin.reference != RTECP_USER_PIN_REF)
	{
		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "PIN reference %i not found in standard"
				" (Rutoken ECP) PINs\n", auth_info->attrs.pin.reference);
		return SC_ERROR_NOT_SUPPORTED;
	}

	snprintf(pin_sname, sizeof(pin_sname), "CHV%i", auth_info->attrs.pin.reference);
	if (auth_info->attrs.pin.reference == RTECP_USER_PIN_REF)   {
		r = sc_profile_get_file(profile, pin_sname, &file);
		if (!r)   {
			const struct sc_acl_entry *acl = NULL;

			r = sc_pkcs15init_fixup_file(profile, p15card, file);
			if (r < 0)
				sc_file_free(file);
			SC_TEST_RET(p15card->card->ctx, SC_LOG_DEBUG_NORMAL, r, "Cannot fixup the ACLs of PIN file");

			acl = sc_file_get_acl_entry(file, SC_AC_OP_PIN_RESET);
			if (acl && acl->method == SC_AC_CHV && acl->key_ref == RTECP_SO_PIN_REF)   {
				sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Allow reset of User PIN with SoPIN\n");
				reset_by_sopin = 1;
			}
			sc_file_free(file);
		}
	}

	file = sc_file_new();
	if (!file)
		SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
	file->id = auth_info->attrs.pin.reference;
	file->size = pin_len;
	assert(sizeof(sec)/sizeof(sec[0]) > 2);
	sec[1] = (auth_info->attrs.pin.reference == RTECP_SO_PIN_REF) ? 0xFF : RTECP_SO_PIN_REF;
	sec[2] = (unsigned char)auth_info->attrs.pin.reference | (reset_by_sopin ? RTECP_SO_PIN_REF : 0);
	r = sc_file_set_sec_attr(file, sec, sizeof(sec));
	if (r == SC_SUCCESS)
	{
		assert(sizeof(prop)/sizeof(prop[0]) > 3);
		prop[1] = (unsigned char)auth_info->attrs.pin.min_length;
		prop[3] = 0x11 * (unsigned char)(auth_info->tries_left & 0x0F);
		r = sc_file_set_prop_attr(file, prop, sizeof(prop));
	}
	if (r == SC_SUCCESS)
		r = sc_file_set_type_attr(file, (const u8*)"\x10\x00", 2);
	if (r == SC_SUCCESS)
		r = sc_create_file(p15card->card, file);
	sc_file_free(file);

	if (r == SC_SUCCESS)
		r = sc_change_reference_data(p15card->card, SC_AC_CHV,
				auth_info->attrs.pin.reference, NULL, 0, pin, pin_len, NULL);
	SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, r);
}
Exemple #19
0
static int sc_pkcs15emu_dnie_init(sc_pkcs15_card_t * p15card)
{
	u8 buf[1024];
	sc_pkcs15_df_t *df;
	sc_pkcs15_object_t *p15_obj;
	size_t len = sizeof(buf);
	int rv;

	sc_context_t *ctx = p15card->card->ctx;
	LOG_FUNC_CALLED(ctx);

	/* Check for correct card driver (i.e. iso7816) */
	if (strcmp(p15card->card->driver->short_name, "dnie") != 0)
		return SC_ERROR_WRONG_CARD;

	/* Check for correct card atr */
	if (dnie_match_card(p15card->card) != 1)
		return SC_ERROR_WRONG_CARD;

	/* Set root path of this application */
	p15card->file_app = sc_file_new();
	sc_format_path("3F00", &p15card->file_app->path);

	/* Load TokenInfo */
	rv = dump_ef(p15card->card, "3F0050155032", buf, &len);
	if (rv != SC_SUCCESS) {
		sc_log(ctx, "Reading of EF.TOKENINFO failed: %d", rv);
		LOG_FUNC_RETURN(ctx, rv);
	}
	rv = sc_pkcs15_parse_tokeninfo(p15card->card->ctx, p15card->tokeninfo,
				       buf, len);
	if (rv != SC_SUCCESS) {
		sc_log(ctx, "Decoding of EF.TOKENINFO failed: %d", rv);
		LOG_FUNC_RETURN(ctx, rv);
	}

	/* Only accept the original stuff */
	if (strcmp(p15card->tokeninfo->manufacturer_id, "DGP-FNMT") != 0)
		LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_CARD);

	/* Load ODF */
	rv = dump_ef(p15card->card, "3F0050155031", buf, &len);
	if (rv != SC_SUCCESS) {
		sc_log(ctx, "Reading of ODF failed: %d", rv);
		LOG_FUNC_RETURN(ctx, rv);
	}
	rv = parse_odf(buf, len, p15card);
	if (rv != SC_SUCCESS) {
		sc_log(ctx, "Decoding of ODF failed: %d", rv);
		LOG_FUNC_RETURN(ctx, rv);
	}

	/* Decode EF.PrKDF, EF.PuKDF and EF.CDF */
	for (df = p15card->df_list; df != NULL; df = df->next) {
		if (df->type == SC_PKCS15_PRKDF) {
			rv = sc_pkcs15_parse_df(p15card, df);
			if (rv != SC_SUCCESS) {
				sc_log(ctx,
				       "Decoding of EF.PrKDF (%s) failed: %d",
				       sc_print_path(&df->path), rv);
			}
		}
		if (df->type == SC_PKCS15_PUKDF) {
			rv = sc_pkcs15_parse_df(p15card, df);
			if (rv != SC_SUCCESS) {
				sc_log(ctx,
				       "Decoding of EF.PuKDF (%s) failed: %d",
				       sc_print_path(&df->path), rv);
			}
		}
		if (df->type == SC_PKCS15_CDF) {
			rv = sc_pkcs15_parse_df(p15card, df);
			if (rv != SC_SUCCESS) {
				sc_log(ctx,
				       "Decoding of EF.CDF (%s) failed: %d",
				       sc_print_path(&df->path), rv);
			}
		}
		if (df->type == SC_PKCS15_DODF) {
			rv = sc_pkcs15_parse_df(p15card, df);
			if (rv != SC_SUCCESS) {
				sc_log(ctx,
				       "Decoding of EF.DODF (%s) failed: %d",
				       sc_print_path(&df->path), rv);
			}
		}
	}

	/* Perform required fixes */
	p15_obj = p15card->obj_list;
	while (p15_obj != NULL) {
		/* Add missing 'auth_id' to private objects */
		if ((p15_obj->flags & SC_PKCS15_CO_FLAG_PRIVATE)
		    && (p15_obj->auth_id.len == 0)) {
			p15_obj->auth_id.value[0] = 0x01;
			p15_obj->auth_id.len = 1;
		}
		/* Remove found public keys as cannot be read_binary()'d */
		if ( p15_obj->df && (p15_obj->df->type == SC_PKCS15_PUKDF) ) {
			sc_pkcs15_object_t *puk = p15_obj;
			p15_obj = p15_obj->next;
			sc_pkcs15_remove_object(p15card, puk);
			sc_pkcs15_free_object(puk);
                } else {
			p15_obj = p15_obj->next;
		}
	}
	
	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
int card_sync_card_to_virtual_fs_any_df( sc_card_t *card, struct _virtual_file_t *virtual_file, virtual_fs_t *virtual_fs, int type )
{
  int r = SC_SUCCESS;
  unsigned char *encoded_pkcs15 = NULL;
  size_t encoded_pkcs15_size = 0;
  sc_pkcs15_card_t *temp_pkcs15_card  = NULL;
  sc_pkcs15_object_t *obj = NULL;
  unsigned char *card_data = NULL;
  size_t card_data_length = 0;  
  
  SC_FUNC_CALLED(card->ctx, 1);

  if(!card || !virtual_file)
    return SC_ERROR_INVALID_ARGUMENTS;

  /* get file */
  r = card_helper_read_file(card, &virtual_file->path, &card_data, &card_data_length);
  if(r < 0)
    goto end;

  /* create a new pkcs15_card structure */
  temp_pkcs15_card = sc_pkcs15_card_new();
  if(!temp_pkcs15_card) {
    r = SC_ERROR_OUT_OF_MEMORY;
    goto end;
  }

  /* we set some important fields */
  temp_pkcs15_card->card = card;
  temp_pkcs15_card->file_app = sc_file_new();
  if (!temp_pkcs15_card->file_app) {
    r = SC_ERROR_OUT_OF_MEMORY;
    goto end;
  }
  sc_format_path("3F00", &temp_pkcs15_card->file_app->path);
  temp_pkcs15_card->tokeninfo->flags=SC_PKCS15_TOKEN_PRN_GENERATION | SC_PKCS15_TOKEN_EID_COMPLIANT;

  /* Convert card df read to a list of same type of pkcs15 objects. 
     This function uses our internal card decoding parser.
  */
  r = sc_pkcs15_parse_card_df( temp_pkcs15_card, 
			       type, 
			       card_data, 
			       card_data_length
                               );
  if(r != SC_SUCCESS) {
    sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Card parsing failed\n"); 
    goto end;
  }

  /* we need to correct some PKCS#15 data */
  for(obj = temp_pkcs15_card->obj_list; obj != NULL; obj = obj->next) {
    switch(obj->type & SC_PKCS15_TYPE_CLASS_MASK) {
    case SC_PKCS15_TYPE_CERT:
      r = card_sync_card_to_virtual_fs_filter_cert(card, virtual_file, virtual_fs, obj);
      break;

    case SC_PKCS15_TYPE_PRKEY:
      r = card_sync_card_to_virtual_fs_filter_prkey(card, virtual_file, virtual_fs, obj);
      break;
      
    case SC_PKCS15_TYPE_PUBKEY:
      r = card_sync_card_to_virtual_fs_filter_pukey(card, virtual_file, virtual_fs, obj);
      break;

    case SC_PKCS15_TYPE_AUTH:
      if(obj->data) {
	sc_pkcs15_pin_info_t * pin=obj->data;
	/* remove security officer pin */
	pin->flags &= (~SC_PKCS15_PIN_FLAG_SO_PIN);
	sc_format_path("3F00", &pin->path);		
	pin->stored_length= (pin->max_length>pin->stored_length) ? pin->max_length : pin->stored_length;
      }
      break;

    case SC_PKCS15_TYPE_DATA_OBJECT:
      r = card_sync_card_to_virtual_fs_filter_data_object(card, virtual_file, virtual_fs, obj);
      break;

    default:
      /* ignore this object */
      break;
    }
  }
  if(r != SC_SUCCESS) {
    sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Object filtering failed\n");
    goto end;
  }
 

  /* generate pkcs#15 stream for the appropiate object type */
  r = sc_standard_pkcs15_encode_any_df( card->ctx, 
					temp_pkcs15_card, 
					type, /* encode only specific objects type */
					&encoded_pkcs15,
					&encoded_pkcs15_size
                                        );
  if(r != SC_SUCCESS) {
    sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Standard PKCS#15 encoding failed\n"); 
    goto end;
  }
    
  r = virtual_file_data_update(virtual_file, 0, encoded_pkcs15, encoded_pkcs15_size);
  if(r == SC_SUCCESS) {
    /* add a trailing 0 */
    r = virtual_file_data_update(virtual_file, encoded_pkcs15_size, (const unsigned char *)"\0", 1);
  }

 end:
  if(card_data) {
    free(card_data);
    card_data = NULL;
  }

  if(temp_pkcs15_card) { 
    /* set to NULL without freeing because we reused structure */
    temp_pkcs15_card->card = NULL;
    
    /* now free temp structure */
    sc_pkcs15_card_free(temp_pkcs15_card);
    temp_pkcs15_card = NULL;
  }  

  if(encoded_pkcs15) {
    free(encoded_pkcs15);
    encoded_pkcs15 = NULL;
  }
  SC_FUNC_RETURN(card->ctx, 1, r);
}
Exemple #21
0
static int
jpki_select_file(struct sc_card *card,
		 const struct sc_path *path, struct sc_file **file_out)
{
	struct jpki_private_data *drvdata = JPKI_DRVDATA(card);
	int rc;
	sc_apdu_t apdu;
	struct sc_file *file = NULL;

	LOG_FUNC_CALLED(card->ctx);
	sc_log(card->ctx,
	       "jpki_select_file: path=%s, len=%"SC_FORMAT_LEN_SIZE_T"u",
	       sc_print_path(path), path->len);
	if (path->len == 2 && memcmp(path->value, "\x3F\x00", 2) == 0) {
		drvdata->selected = SELECT_MF;
		if (file_out) {
			sc_file_dup(file_out, drvdata->mf);
			if (*file_out == NULL) {
				LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
			}
		}
		return 0;
	}

	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0, 0);
	switch (path->type) {
	case SC_PATH_TYPE_FILE_ID:
		apdu.p1 = 2;
		break;
	case SC_PATH_TYPE_DF_NAME:
		apdu.p1 = 4;
		break;
	default:
		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
	}
	apdu.p2 = 0x0C;
	apdu.data = path->value;
	apdu.datalen = path->len;
	apdu.lc = path->len;

	rc = sc_transmit_apdu(card, &apdu);
	LOG_TEST_RET(card->ctx, rc, "APDU transmit failed");
	rc = sc_check_sw(card, apdu.sw1, apdu.sw2);
	LOG_TEST_RET(card->ctx, rc, "SW Check failed");
	if (!file_out) {
		LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
	}

	/* read certificate file size */
	if (path->len == 2 && (
		    memcmp(path->value, "\x00\x0A", 2) == 0 ||
		    memcmp(path->value, "\x00\x01", 2) == 0 ||
		    memcmp(path->value, "\x00\x0B", 2) == 0 ||
		    memcmp(path->value, "\x00\x02", 2) == 0 )
		) {
		u8 buf[4];
		rc = sc_read_binary(card, 0, buf, 4, 0);
		LOG_TEST_RET(card->ctx, rc, "SW Check failed");
		file = sc_file_new();
		if (!file) {
			LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
		}
		file->path = *path;
		file->size = (buf[2] << 8 | buf[3]) + 4;
		*file_out = file;
	}
	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}
Exemple #22
0
static int sc_pkcs15emu_dnie_init(sc_pkcs15_card_t * p15card)
{
	u8 buf[1024];
	sc_pkcs15_df_t *df;
	sc_pkcs15_object_t *p15_obj;
	size_t len = sizeof(buf);
	int rv;
	struct sc_pkcs15_cert_info *p15_info = NULL;

	sc_context_t *ctx = p15card->card->ctx;
	LOG_FUNC_CALLED(ctx);

	/* Check for correct card driver (i.e. iso7816) */
	if (strcmp(p15card->card->driver->short_name, "dnie") != 0)
		return SC_ERROR_WRONG_CARD;

	/* Check for correct card atr */
	if (dnie_match_card(p15card->card) != 1)
		return SC_ERROR_WRONG_CARD;

#ifdef ENABLE_OPENSSL
	/* The two keys inside DNIe 3.0 needs login before performing any signature.
	 * They are CKA_ALWAYS_AUTHENTICATE although they are not tagged like that.
	 * For the moment caching is forced if 3.0 is detected to make it work properly. */
	if (p15card->card->atr.value[15] >= DNIE_30_VERSION) {
		p15card->opts.use_pin_cache = 1;
		p15card->opts.pin_cache_counter = DNIE_30_CACHE_COUNTER;
		sc_log(ctx, "DNIe 3.0 detected - PKCS#15 options reset: use_file_cache=%d use_pin_cache=%d pin_cache_counter=%d pin_cache_ignore_user_consent=%d",
			p15card->opts.use_file_cache,
			p15card->opts.use_pin_cache,
			p15card->opts.pin_cache_counter,
			p15card->opts.pin_cache_ignore_user_consent);
        }
#endif

	/* Set root path of this application */
	p15card->file_app = sc_file_new();
	sc_format_path("3F00", &p15card->file_app->path);

	/* Load TokenInfo */
	rv = dump_ef(p15card->card, "3F0050155032", buf, &len);
	if (rv != SC_SUCCESS) {
		sc_log(ctx, "Reading of EF.TOKENINFO failed: %d", rv);
		LOG_FUNC_RETURN(ctx, rv);
	}
	rv = sc_pkcs15_parse_tokeninfo(p15card->card->ctx, p15card->tokeninfo,
				       buf, len);
	if (rv != SC_SUCCESS) {
		sc_log(ctx, "Decoding of EF.TOKENINFO failed: %d", rv);
		LOG_FUNC_RETURN(ctx, rv);
	}

	/* Only accept the original stuff */
	if (strcmp(p15card->tokeninfo->manufacturer_id, "DGP-FNMT") != 0)
		LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_CARD);

	/* Load ODF */
	rv = dump_ef(p15card->card, "3F0050155031", buf, &len);
	if (rv != SC_SUCCESS) {
		sc_log(ctx, "Reading of ODF failed: %d", rv);
		LOG_FUNC_RETURN(ctx, rv);
	}
	rv = parse_odf(buf, len, p15card);
	if (rv != SC_SUCCESS) {
		sc_log(ctx, "Decoding of ODF failed: %d", rv);
		LOG_FUNC_RETURN(ctx, rv);
	}

	/* Decode EF.PrKDF, EF.PuKDF and EF.CDF */
	for (df = p15card->df_list; df != NULL; df = df->next) {
		if (df->type == SC_PKCS15_PRKDF) {
			rv = sc_pkcs15_parse_df(p15card, df);
			if (rv != SC_SUCCESS) {
				sc_log(ctx,
				       "Decoding of EF.PrKDF (%s) failed: %d",
				       sc_print_path(&df->path), rv);
			}
		}
		if (df->type == SC_PKCS15_PUKDF) {
			rv = sc_pkcs15_parse_df(p15card, df);
			if (rv != SC_SUCCESS) {
				sc_log(ctx,
				       "Decoding of EF.PuKDF (%s) failed: %d",
				       sc_print_path(&df->path), rv);
			}
		}
		if (df->type == SC_PKCS15_CDF) {
			rv = sc_pkcs15_parse_df(p15card, df);
			if (rv != SC_SUCCESS) {
				sc_log(ctx,
				       "Decoding of EF.CDF (%s) failed: %d",
				       sc_print_path(&df->path), rv);
			}
		}
		if (df->type == SC_PKCS15_DODF) {
			rv = sc_pkcs15_parse_df(p15card, df);
			if (rv != SC_SUCCESS) {
				sc_log(ctx,
				       "Decoding of EF.DODF (%s) failed: %d",
				       sc_print_path(&df->path), rv);
			}
		}
	}

	/* Perform required fixes */
	p15_obj = p15card->obj_list;
	while (p15_obj != NULL) {
		/* Add missing 'auth_id' to private objects */
		if ((p15_obj->flags & SC_PKCS15_CO_FLAG_PRIVATE)
		    && (p15_obj->auth_id.len == 0)) {
			p15_obj->auth_id.value[0] = 0x01;
			p15_obj->auth_id.len = 1;
		};
		/* Set path count to -1 for public certificates, as they
		   will need to be decompressed and read_binary()'d, so
		   we make sure we end up reading the file->size and not the
		   path->count which is the compressed size on newer
                   DNIe versions  */
		if ( p15_obj->df && (p15_obj->df->type == SC_PKCS15_CDF) ) {
                    p15_info = (struct sc_pkcs15_cert_info *) p15_obj ->data;
		    p15_info ->path.count = -1;
		}
		/* Remove found public keys as cannot be read_binary()'d */
		if ( p15_obj->df && (p15_obj->df->type == SC_PKCS15_PUKDF) ) {
			sc_pkcs15_object_t *puk = p15_obj;
			p15_obj = p15_obj->next;
			sc_pkcs15_remove_object(p15card, puk);
			sc_pkcs15_free_object(puk);
                } else {
			p15_obj = p15_obj->next;
		}
	}
	
	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
Exemple #23
0
static int starcos_select_fid(sc_card_t *card,
                              unsigned int id_hi, unsigned int id_lo,
                              sc_file_t **file_out)
{
    sc_apdu_t apdu;
    u8 data[] = {id_hi & 0xff, id_lo & 0xff};
    u8 resp[SC_MAX_APDU_BUFFER_SIZE];
    int bIsDF = 0, r;

    /* request FCI to distinguish between EFs and DFs */
    sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0x00, 0x00);
    apdu.p2   = 0x00;
    apdu.resp = (u8*)resp;
    apdu.resplen = SC_MAX_APDU_BUFFER_SIZE;
    apdu.le = 256;
    apdu.lc = 2;
    apdu.data = (u8*)data;
    apdu.datalen = 2;

    r = sc_transmit_apdu(card, &apdu);
    SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");

    if (apdu.p2 == 0x00 && apdu.sw1 == 0x62 && apdu.sw2 == 0x84 ) {
        /* no FCI => we have a DF (see comment in process_fci()) */
        bIsDF = 1;
        apdu.p2 = 0x0C;
        apdu.cse = SC_APDU_CASE_3_SHORT;
        apdu.resplen = 0;
        apdu.le = 0;
        r = sc_transmit_apdu(card, &apdu);
        SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU re-transmit failed");
    } else if (apdu.sw1 == 0x61 || (apdu.sw1 == 0x90 && apdu.sw2 == 0x00)) {
        /* SELECT returned some data (possible FCI) =>
         * try a READ BINARY to see if a EF is selected */
        sc_apdu_t apdu2;
        u8 resp2[2];
        sc_format_apdu(card, &apdu2, SC_APDU_CASE_2_SHORT, 0xB0, 0, 0);
        apdu2.resp = (u8*)resp2;
        apdu2.resplen = 2;
        apdu2.le = 1;
        apdu2.lc = 0;
        r = sc_transmit_apdu(card, &apdu2);
        SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
        if (apdu2.sw1 == 0x69 && apdu2.sw2 == 0x86)
            /* no current EF is selected => we have a DF */
            bIsDF = 1;
    }

    if (apdu.sw1 != 0x61 && (apdu.sw1 != 0x90 || apdu.sw2 != 0x00))
        SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));

    /* update cache */
    if (bIsDF) {
        card->cache.current_path.type = SC_PATH_TYPE_PATH;
        card->cache.current_path.value[0] = 0x3f;
        card->cache.current_path.value[1] = 0x00;
        if (id_hi == 0x3f && id_lo == 0x00)
            card->cache.current_path.len = 2;
        else {
            card->cache.current_path.len = 4;
            card->cache.current_path.value[2] = id_hi;
            card->cache.current_path.value[3] = id_lo;
        }
    }

    if (file_out) {
        sc_file_t *file = sc_file_new();
        if (!file)
            SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
        file->id   = (id_hi << 8) + id_lo;
        file->path = card->cache.current_path;

        if (bIsDF) {
            /* we have a DF */
            file->type = SC_FILE_TYPE_DF;
            file->ef_structure = SC_FILE_EF_UNKNOWN;
            file->size = 0;
            file->namelen = 0;
            file->magic = SC_FILE_MAGIC;
            *file_out = file;
        } else {
            /* ok, assume we have a EF */
            r = process_fci(card->ctx, file, apdu.resp,
                            apdu.resplen);
            if (r != SC_SUCCESS) {
                sc_file_free(file);
                return r;
            }

            *file_out = file;
        }
    }

    SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
}
Exemple #24
0
static int ias_select_file(sc_card_t *card, const sc_path_t *in_path,
		sc_file_t **file_out)
{
	int 			r, pathlen, stripped_len;
	u8 				buf[SC_MAX_APDU_BUFFER_SIZE];
	u8 				pathbuf[SC_MAX_PATH_SIZE], *path;
	sc_apdu_t 		apdu;
	sc_file_t 		*file;

	stripped_len = 0;
	path = pathbuf;
	file = NULL;

	assert(card != NULL && in_path != NULL);

	if (in_path->len > SC_MAX_PATH_SIZE)
		return SC_ERROR_INVALID_ARGUMENTS;
	memcpy(path, in_path->value, in_path->len);
	pathlen = in_path->len;

	sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0xA4, 0, 0);
	apdu.p2 = 0; /* First record, return FCI */

	switch (in_path->type) {
	case SC_PATH_TYPE_FILE_ID:
		apdu.p1 = 2;
		if (pathlen != 2)
			return SC_ERROR_INVALID_ARGUMENTS;
		break;
	case SC_PATH_TYPE_DF_NAME:
		apdu.p1 = 4;
		break;
	case SC_PATH_TYPE_PATH:
		apdu.p1 = 9;
		/* Strip the MF */
		if (pathlen >= 2 && memcmp(path, "\x3f\x00", 2) == 0) {
			if (pathlen == 2) { /* Only 3f00 provided */
				apdu.p1 = 0;
				break;
			}
			path += 2;
			pathlen -= 2;
		}
		/* Optimization based on the normal Portuguese eID usage pattern:
		 * paths with len >= 4 shall be stripped - this avoids unnecessary
		 * "file not found" errors. Other cards may benefit from this also.
		 *
		 * This works perfectly for the Portuguese eID card, but if you
		 * are adapting this driver to another card, "false positives" may
		 * occur depending, of course, on the file structure of the card.
		 *
		 * Please have this in mind if adapting this driver to another card.
		 */
		if (pathlen >= 4) {
			stripped_len = pathlen - 2;
			path += stripped_len;
			pathlen = 2;
		} else if (pathlen == 2) {
			apdu.p1 = 0;
		}
		break;
	case SC_PATH_TYPE_FROM_CURRENT:
		apdu.p1 = 9;
		break;
	case SC_PATH_TYPE_PARENT:
		apdu.p1 = 3;
		apdu.p2 = 0x0C;
		pathlen = 0;
		apdu.cse = SC_APDU_CASE_2_SHORT;
		break;
	default:
		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
	}

	apdu.lc = pathlen;
	apdu.data = path;
	apdu.datalen = pathlen;

	if (file_out != NULL) {
		apdu.resp = buf;
		apdu.resplen = sizeof(buf);
		apdu.le = 256;
	} else {
		apdu.p2 = 0x0C;
		apdu.cse = (apdu.lc == 0) ? SC_APDU_CASE_1 : SC_APDU_CASE_3_SHORT;
	}

	r = sc_transmit_apdu(card, &apdu);
	SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
	if (file_out == NULL) {
		if (apdu.sw1 == 0x61)
			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, 0);
		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
	}

	/* A "file not found" error was received, this can mean two things:
	 * 1) the file does not exist
	 * 2) the current DF may be incorrect due to the optimization applied
	 *    earlier. If the path was previously stripped, select the first DF
	 *    and try to re-select the path with the full value.
	 */
	if (stripped_len > 0 && apdu.sw1 == 0x6A && apdu.sw2 == 0x82) {
		sc_path_t tpath;

		/* Restore original path value */
		path -= stripped_len;
		pathlen += stripped_len;

		memset(&tpath, 0, sizeof(sc_path_t));
		tpath.type = SC_PATH_TYPE_PATH;
		tpath.len = 2;
		tpath.value[0] = path[0];
		tpath.value[1] = path[1];

		/* Go up in the hierarchy to the correct DF */
		r = ias_select_file(card, &tpath, NULL);
		SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "Error selecting parent.");

		/* We're now in the right place, reconstruct the APDU and retry */
		path += 2;
		pathlen -= 2;
		apdu.lc = pathlen;
		apdu.data = path;
		apdu.datalen = pathlen;

		if (file_out != NULL)
			apdu.resplen = sizeof(buf);

		r = sc_transmit_apdu(card, &apdu);
		SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "APDU transmit failed");
		if (file_out == NULL) {
			if (apdu.sw1 == 0x61)
				SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, 0);
			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
		}
	}

	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
	if (r)
		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);

	if (apdu.resplen < 2)
		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_UNKNOWN_DATA_RECEIVED);
	switch (apdu.resp[0]) {
	case 0x6F:
		file = sc_file_new();
		if (file == NULL)
			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
		file->path = *in_path;
		if (card->ops->process_fci == NULL) {
			sc_file_free(file);
			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
		}
		if ((size_t)apdu.resp[1] + 2 <= apdu.resplen)
			card->ops->process_fci(card, file, apdu.resp+2, apdu.resp[1]);
		*file_out = file;
		break;
	case 0x00:	/* proprietary coding */
		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_UNKNOWN_DATA_RECEIVED);
	default:
		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_UNKNOWN_DATA_RECEIVED);
	}

	return SC_SUCCESS;
}
Exemple #25
0
static int entersafe_select_path(sc_card_t *card,
								const u8 pathbuf[16], const size_t len,
								sc_file_t **file_out)
{
	 u8 n_pathbuf[SC_MAX_PATH_SIZE];
	 const u8 *path=pathbuf;
	 size_t pathlen=len;
	 int bMatch = -1;
	 unsigned int i;
	 int r;

	 if (pathlen%2 != 0 || pathlen > 6 || pathlen <= 0)
		  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);

	 /* if pathlen == 6 then the first FID must be MF (== 3F00) */
	 if (pathlen == 6 && ( path[0] != 0x3f || path[1] != 0x00 ))
		  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);

	 /* unify path (the first FID should be MF) */
	 if (path[0] != 0x3f || path[1] != 0x00)
	 {
		  n_pathbuf[0] = 0x3f;
		  n_pathbuf[1] = 0x00;
		  for (i=0; i< pathlen; i++)
			   n_pathbuf[i+2] = pathbuf[i];
		  path = n_pathbuf;
		  pathlen += 2; 
	 }
	
	 /* check current working directory */
	 if (card->cache.valid 
		 && card->cache.current_path.type == SC_PATH_TYPE_PATH
		 && card->cache.current_path.len >= 2
		 && card->cache.current_path.len <= pathlen )
	 {
		  bMatch = 0;
		  for (i=0; i < card->cache.current_path.len; i+=2)
			   if (card->cache.current_path.value[i] == path[i] 
				   && card->cache.current_path.value[i+1] == path[i+1] )
					bMatch += 2;
	 }

	 if ( card->cache.valid && bMatch > 2 )
	 {
		  if ( pathlen - bMatch == 2 )
		  {
			   /* we are in the rigth directory */
			   return entersafe_select_fid(card, path[bMatch], path[bMatch+1], file_out);
		  }
		  else if ( pathlen - bMatch > 2 )
		  {
			   /* two more steps to go */
			   sc_path_t new_path;
	
			   /* first step: change directory */
			   r = entersafe_select_fid(card, path[bMatch], path[bMatch+1], NULL);
			   SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "SELECT FILE (DF-ID) failed");
	
		   	   memset(&new_path, 0, sizeof(sc_path_t));

			   new_path.type = SC_PATH_TYPE_PATH;
			   new_path.len  = pathlen - bMatch-2;
			   memcpy(new_path.value, &(path[bMatch+2]), new_path.len);
			   /* final step: select file */
			   return entersafe_select_file(card, &new_path, file_out);
		  }
		  else /* if (bMatch - pathlen == 0) */
		  {
			   /* done: we are already in the
				* requested directory */
			   sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
				"cache hit\n");
			   /* copy file info (if necessary) */
			   if (file_out) {
					sc_file_t *file = sc_file_new();
					if (!file)
						 SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
					file->id = (path[pathlen-2] << 8) +
						 path[pathlen-1];
					file->path = card->cache.current_path;
					file->type = SC_FILE_TYPE_DF;
					file->ef_structure = SC_FILE_EF_UNKNOWN;
					file->size = 0;
					file->namelen = 0;
					file->magic = SC_FILE_MAGIC;
					*file_out = file;
			   }
			   /* nothing left to do */
			   return SC_SUCCESS;
		  }
	 }
	 else
	 {
		  /* no usable cache */
		  for ( i=0; i<pathlen-2; i+=2 )
		  {
			   r = entersafe_select_fid(card, path[i], path[i+1], NULL);
			   SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "SELECT FILE (DF-ID) failed");
		  }
		  return entersafe_select_fid(card, path[pathlen-2], path[pathlen-1], file_out);
	 }
}
Exemple #26
0
static int starcos_select_file(sc_card_t *card,
                               const sc_path_t *in_path,
                               sc_file_t **file_out)
{
    u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
    int    r;
    size_t i, pathlen;
    char pbuf[SC_MAX_PATH_STRING_SIZE];

    SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);

    r = sc_path_print(pbuf, sizeof(pbuf), &card->cache.current_path);
    if (r != SC_SUCCESS)
        pbuf[0] = '\0';

    sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
             "current path (%s, %s): %s (len: %u)\n",
             (card->cache.current_path.type==SC_PATH_TYPE_DF_NAME?"aid":"path"),
             (card->cache.valid?"valid":"invalid"), pbuf,
             card->cache.current_path.len);

    memcpy(path, in_path->value, in_path->len);
    pathlen = in_path->len;

    if (in_path->type == SC_PATH_TYPE_FILE_ID)
    {   /* SELECT EF/DF with ID */
        /* Select with 2byte File-ID */
        if (pathlen != 2)
            SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_INVALID_ARGUMENTS);
        return starcos_select_fid(card, path[0], path[1], file_out);
    }
    else if (in_path->type == SC_PATH_TYPE_DF_NAME)
    {   /* SELECT DF with AID */
        /* Select with 1-16byte Application-ID */
        if (card->cache.valid
                && card->cache.current_path.type == SC_PATH_TYPE_DF_NAME
                && card->cache.current_path.len == pathlen
                && memcmp(card->cache.current_path.value, pathbuf, pathlen) == 0 )
        {
            sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "cache hit\n");
            SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
        }
        else
            return starcos_select_aid(card, pathbuf, pathlen, file_out);
    }
    else if (in_path->type == SC_PATH_TYPE_PATH)
    {
        u8 n_pathbuf[SC_MAX_PATH_SIZE];
        int bMatch = -1;

        /* Select with path (sequence of File-IDs) */
        /* Starcos (S 2.1 and SPK 2.3) only supports one
         * level of subdirectories, therefore a path is
         * at most 3 FID long (the last one being the FID
         * of a EF) => pathlen must be even and less than 6
         */
        if (pathlen%2 != 0 || pathlen > 6 || pathlen <= 0)
            SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
        /* if pathlen == 6 then the first FID must be MF (== 3F00) */
        if (pathlen == 6 && ( path[0] != 0x3f || path[1] != 0x00 ))
            SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);

        /* unify path (the first FID should be MF) */
        if (path[0] != 0x3f || path[1] != 0x00)
        {
            n_pathbuf[0] = 0x3f;
            n_pathbuf[1] = 0x00;
            for (i=0; i< pathlen; i++)
                n_pathbuf[i+2] = pathbuf[i];
            path = n_pathbuf;
            pathlen += 2;
        }

        /* check current working directory */
        if (card->cache.valid
                && card->cache.current_path.type == SC_PATH_TYPE_PATH
                && card->cache.current_path.len >= 2
                && card->cache.current_path.len <= pathlen )
        {
            bMatch = 0;
            for (i=0; i < card->cache.current_path.len; i+=2)
                if (card->cache.current_path.value[i] == path[i]
                        && card->cache.current_path.value[i+1] == path[i+1] )
                    bMatch += 2;
        }

        if ( card->cache.valid && bMatch >= 0 )
        {
            if ( pathlen - bMatch == 2 )
                /* we are in the rigth directory */
                return starcos_select_fid(card, path[bMatch], path[bMatch+1], file_out);
            else if ( pathlen - bMatch > 2 )
            {
                /* two more steps to go */
                sc_path_t new_path;

                /* first step: change directory */
                r = starcos_select_fid(card, path[bMatch], path[bMatch+1], NULL);
                SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "SELECT FILE (DF-ID) failed");

                memset(&new_path, 0, sizeof(sc_path_t));
                new_path.type = SC_PATH_TYPE_PATH;
                new_path.len  = pathlen - bMatch-2;
                memcpy(new_path.value, &(path[bMatch+2]), new_path.len);
                /* final step: select file */
                return starcos_select_file(card, &new_path, file_out);
            }
            else /* if (bMatch - pathlen == 0) */
            {
                /* done: we are already in the
                 * requested directory */
                sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
                         "cache hit\n");
                /* copy file info (if necessary) */
                if (file_out) {
                    sc_file_t *file = sc_file_new();
                    if (!file)
                        SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
                    file->id = (path[pathlen-2] << 8) +
                               path[pathlen-1];
                    file->path = card->cache.current_path;
                    file->type = SC_FILE_TYPE_DF;
                    file->ef_structure = SC_FILE_EF_UNKNOWN;
                    file->size = 0;
                    file->namelen = 0;
                    file->magic = SC_FILE_MAGIC;
                    *file_out = file;
                }
                /* nothing left to do */
                return SC_SUCCESS;
            }
        }
        else
        {
            /* no usable cache */
            for ( i=0; i<pathlen-2; i+=2 )
            {
                r = starcos_select_fid(card, path[i], path[i+1], NULL);
                SC_TEST_RET(card->ctx, SC_LOG_DEBUG_NORMAL, r, "SELECT FILE (DF-ID) failed");
            }
            return starcos_select_fid(card, path[pathlen-2], path[pathlen-1], file_out);
        }
    }
    else
        SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
}
Exemple #27
0
/*
 * Create a PIN object within the given DF
 */
static int rtecp_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)
{
	sc_context_t *ctx;
	sc_pkcs15_pin_info_t *pin_info;
	sc_file_t *file;
	/*                        GCHV min-length Flags Attempts  Reserve */
	unsigned char prop[]  = { 0x01,       '?', 0x01,     '?', 0, 0 };
	/*                  AccessMode Unblock Change             Delete */
	unsigned char sec[15] = { 0x43,    '?',   '?', 0, 0, 0, 0,  0xFF };
	int r;

	(void)puk; /* no warning */
	if (!profile || !p15card || !p15card->card || !p15card->card->ctx || !df 
			|| !pin_obj || !pin_obj->data || !pin || !pin_len)
		return SC_ERROR_INVALID_ARGUMENTS;

	ctx = p15card->card->ctx;
	SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
	if (puk_len != 0)
	{
		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "Do not enter User unblocking PIN (PUK): %s\n",
				sc_strerror(SC_ERROR_NOT_SUPPORTED));
		return SC_ERROR_NOT_SUPPORTED;
	}
	pin_info = (sc_pkcs15_pin_info_t *)pin_obj->data;
	if (pin_info->reference != RTECP_SO_PIN_REF
			&& pin_info->reference != RTECP_USER_PIN_REF)
	{
		sc_debug(ctx, SC_LOG_DEBUG_NORMAL, "PIN reference %i not found in standard"
				" (Rutoken ECP) PINs\n", pin_info->reference);
		return SC_ERROR_NOT_SUPPORTED;
	}
	file = sc_file_new();
	if (!file)
		SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
	file->id = pin_info->reference;
	file->size = pin_len;
	assert(sizeof(sec)/sizeof(sec[0]) > 2);
	sec[1] = (pin_info->reference == RTECP_SO_PIN_REF) ? 0xFF : RTECP_SO_PIN_REF;
	sec[2] = (unsigned char)pin_info->reference;
	r = sc_file_set_sec_attr(file, sec, sizeof(sec));
	if (r == SC_SUCCESS)
	{
		assert(sizeof(prop)/sizeof(prop[0]) > 3);
		prop[1] = (unsigned char)pin_info->min_length;
		prop[3] = 0x11 * (unsigned char)(pin_info->tries_left & 0x0F);
		r = sc_file_set_prop_attr(file, prop, sizeof(prop));
	}
	if (r == SC_SUCCESS)
		r = sc_file_set_type_attr(file, (const u8*)"\x10\x00", 2);
	if (r == SC_SUCCESS)
		r = sc_create_file(p15card->card, file);
	sc_file_free(file);

	if (r == SC_SUCCESS)
		r = sc_change_reference_data(p15card->card, SC_AC_CHV,
				pin_info->reference, NULL, 0, pin, pin_len, NULL);
	SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, r);
}