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

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

	append_file(profile, fi);

	ft->instance = fi;

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

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

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

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

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

	return fi;
}
Beispiel #2
0
int sc_create_file(sc_card_t *card, sc_file_t *file)
{
	int r;
	char pbuf[SC_MAX_PATH_STRING_SIZE];
	const sc_path_t *in_path;

	if (card == NULL || file == NULL) {
		return SC_ERROR_INVALID_ARGUMENTS;
	}

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

	sc_log(card->ctx,
	       "called; type=%d, path=%s, id=%04i, size=%"SC_FORMAT_LEN_SIZE_T"u",
	       in_path->type, pbuf, file->id, file->size);
	/* ISO 7816-4: "Number of data bytes in the file, including structural information if any"
	 * can not be bigger than two bytes */
	if (file->size > 0xFFFF)
		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);

	if (card->ops->create_file == NULL)
		LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);

	r = card->ops->create_file(card, file);
	LOG_FUNC_RETURN(card->ctx, r);
}
Beispiel #3
0
/*
 * Get private and public key file
 */
static int cflex_get_keyfiles(sc_profile_t *profile, sc_card_t *card,
			const sc_path_t *df_path,
			sc_file_t **prkf, sc_file_t **pukf)
{
	sc_path_t	path = *df_path;
	int		r;

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

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

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

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

	return 0;
}
int sc_pkcs15_add_unusedspace(struct sc_pkcs15_card *p15card,
		     const sc_path_t *path, const sc_pkcs15_id_t *auth_id)
{
	sc_pkcs15_unusedspace_t *p = p15card->unusedspace_list, *new_unusedspace;

	if (path->count == -1) {
		char pbuf[SC_MAX_PATH_STRING_SIZE];

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

		sc_error(p15card->card->ctx, "No offset and length present in path %s\n", pbuf);
		return SC_ERROR_INVALID_ARGUMENTS;
	}

	new_unusedspace = (sc_pkcs15_unusedspace_t *) calloc(1, sizeof(sc_pkcs15_unusedspace_t));
	if (new_unusedspace == NULL)
		return SC_ERROR_OUT_OF_MEMORY;
	new_unusedspace->path = *path;
	if (auth_id != NULL)
		new_unusedspace->auth_id = *auth_id;

	if (p15card->unusedspace_list == NULL) {
		p15card->unusedspace_list = new_unusedspace;
		return 0;
	}
	while (p->next != NULL)
 		p = p->next;
	p->next = new_unusedspace;
	new_unusedspace->prev = p;

	return 0;
}
Beispiel #5
0
static int entersafe_select_file(sc_card_t *card,
								 const sc_path_t *in_path,
								 sc_file_t **file_out)
{
	 int r;
	 char pbuf[SC_MAX_PATH_STRING_SIZE];
	 assert(card);
	 assert(in_path);
	 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);
	 
	 switch(in_path->type)
	 {
	 case SC_PATH_TYPE_FILE_ID:
		  if (in_path->len != 2)
			   SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_INVALID_ARGUMENTS);
		  return entersafe_select_fid(card,in_path->value[0],in_path->value[1], file_out);
	 case SC_PATH_TYPE_DF_NAME:
		  return entersafe_select_aid(card,in_path,file_out);
	 case SC_PATH_TYPE_PATH:
		  return entersafe_select_path(card,in_path->value,in_path->len,file_out);
	 default:
		  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
	 }
}
Beispiel #6
0
int sc_select_file(sc_card_t *card, const sc_path_t *in_path,  sc_file_t **file)
{
	int r;
	char pbuf[SC_MAX_PATH_STRING_SIZE];

	if (card == NULL || in_path == NULL) {
		return SC_ERROR_INVALID_ARGUMENTS;
	}

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

	/* FIXME We should be a bit less strict and let the upper layers do
	 * the initialization (including reuse of existing file objects). We
	 * implemented this here because we are lazy. */
	if (file != NULL)
		*file = NULL;

	sc_log(card->ctx, "called; type=%d, path=%s", in_path->type, pbuf);
	if (in_path->len > SC_MAX_PATH_SIZE)
		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);

	if (in_path->type == SC_PATH_TYPE_PATH) {
		/* Perform a sanity check */
		size_t i;

		if ((in_path->len & 1) != 0)
			LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);

		for (i = 0; i < in_path->len/2; i++) {
			u8 p1 = in_path->value[2*i],
			   p2 = in_path->value[2*i+1];

			if ((p1 == 0x3F && p2 == 0x00) && i != 0)
				LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
		}
	}
	if (card->ops->select_file == NULL)
		LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
	r = card->ops->select_file(card, in_path, file);
	LOG_TEST_RET(card->ctx, r, "'SELECT' error");

	if (file) {
		if (*file)
			/* Remember file path */
			(*file)->path = *in_path;
		else
			/* FIXME We should be a bit less strict and let the upper layers do
			 * the error checking. We implemented this here because we are
			 * lazy.  */
			r = SC_ERROR_INVALID_DATA;
	}

	LOG_FUNC_RETURN(card->ctx, r);
}
Beispiel #7
0
int sc_delete_file(sc_card_t *card, const sc_path_t *path)
{
	int r;
	char pbuf[SC_MAX_PATH_STRING_SIZE];

	assert(card != NULL);

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

	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "called; type=%d, path=%s", path->type, pbuf);
	if (card->ops->delete_file == NULL)
		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_NOT_SUPPORTED);
	r = card->ops->delete_file(card, path);
	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
}
Beispiel #8
0
int sc_delete_file(sc_card_t *card, const sc_path_t *path)
{
	int r;
	char pbuf[SC_MAX_PATH_STRING_SIZE];

	if (card == NULL) {
		return SC_ERROR_INVALID_ARGUMENTS;
	}

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

	sc_log(card->ctx, "called; type=%d, path=%s", path->type, pbuf);
	if (card->ops->delete_file == NULL)
		LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
	r = card->ops->delete_file(card, path);

	LOG_FUNC_RETURN(card->ctx, r);
}
Beispiel #9
0
int sc_create_file(sc_card_t *card, sc_file_t *file)
{
	int r;
	char pbuf[SC_MAX_PATH_STRING_SIZE];
	const sc_path_t *in_path = &file->path;

	assert(card != NULL);

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

	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,
		"called; type=%d, path=%s, size=%u\n",
		in_path->type, pbuf, file->size);
	if (card->ops->create_file == NULL)
		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_NOT_SUPPORTED);
	r = card->ops->create_file(card, file);
	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
}
Beispiel #10
0
int sc_select_file(sc_card_t *card, const sc_path_t *in_path,  sc_file_t **file)
{
	int r;
	char pbuf[SC_MAX_PATH_STRING_SIZE];

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

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

	sc_log(card->ctx, "called; type=%d, path=%s", in_path->type, pbuf);
	if (in_path->len > SC_MAX_PATH_SIZE)
		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);

	if (in_path->type == SC_PATH_TYPE_PATH) {
		/* Perform a sanity check */
		size_t i;

		if ((in_path->len & 1) != 0)
			LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);

		for (i = 0; i < in_path->len/2; i++) {
			u8 p1 = in_path->value[2*i],
			   p2 = in_path->value[2*i+1];

			if ((p1 == 0x3F && p2 == 0x00) && i != 0)
				LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
		}
	}
	if (card->ops->select_file == NULL)
		LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
	r = card->ops->select_file(card, in_path, file);
	LOG_TEST_RET(card->ctx, r, "'SELECT' error");

	/* Remember file path */
	if (file && *file)
		(*file)->path = *in_path;

	LOG_FUNC_RETURN(card->ctx, r);
}
Beispiel #11
0
int sc_create_file(sc_card_t *card, sc_file_t *file)
{
	int r;
	char pbuf[SC_MAX_PATH_STRING_SIZE];
	const sc_path_t *in_path = &file->path;

	assert(card != NULL);

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

	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "called; type=%d, path=%s, size=%u", 
			in_path->type, pbuf, file->size);
	/* ISO 7816-4: "Number of data bytes in the file, including structural information if any"
	 * can not be bigger than two bytes */
	if (file->size > 0xFFFF)
		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ARGUMENTS);
	if (card->ops->create_file == NULL)
		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_NOT_SUPPORTED);
	r = card->ops->create_file(card, file);
	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
}
/*
 * Instantiate template
 */
int
sc_profile_instantiate_template(sc_profile_t *profile,
		const char *template_name, const sc_path_t *base_path,
		const char *file_name, const sc_pkcs15_id_t *id,
		sc_file_t **ret)
{
	sc_card_t	*card = profile->card;
	sc_profile_t	*tmpl;
	sc_template_t	*info;
	unsigned int	idx;
	struct file_info *fi, *base_file, *match = NULL;

	for (info = profile->template_list; info; info = info->next) {
		if (!strcmp(info->name, template_name))
			break;
	}
	if (info == NULL)
		return SC_ERROR_TEMPLATE_NOT_FOUND;

	tmpl = info->data;
	idx = id->value[id->len-1];
	for (fi = profile->ef_list; fi; fi = fi->next) {
		if (fi->base_template == tmpl
		 && fi->inst_index == idx
		 && sc_compare_path(&fi->inst_path, base_path)
		 && !strcmp(fi->ident, file_name)) {
			sc_file_dup(ret, fi->file);
			if (*ret == NULL)
				return SC_ERROR_OUT_OF_MEMORY;
			return 0;
		}
	}

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

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

		sc_debug(profile->card->ctx,
			"Instantiating template %s at %s", template_name, pbuf);
	}

	base_file = sc_profile_find_file_by_path(profile, base_path);
	if (base_file == NULL) {
		char pbuf[SC_MAX_PATH_STRING_SIZE];

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

		sc_error(card->ctx, "Directory %s not defined in profile", pbuf);
		return SC_ERROR_OBJECT_NOT_FOUND;
	}

	/* This loop relies on the fact that new files are always
	 * appended to the list, after the parent files they refer to
	 */
	assert(base_file->instance);
	for (fi = tmpl->ef_list; fi; fi = fi->next) {
		file_info	*parent, *instance;
		unsigned int	skew = 0;

		fi->instance = NULL;
		if ((parent = fi->parent) == NULL) {
			parent = base_file;
			skew = idx;
		}
		parent = parent->instance;

		instance = sc_profile_instantiate_file(profile, fi, parent, skew);
		if (instance == NULL)
			return SC_ERROR_OUT_OF_MEMORY;
		instance->base_template = tmpl;
		instance->inst_index = idx;
		instance->inst_path = *base_path;

		if (!strcmp(instance->ident, file_name))
			match = instance;
	}

	if (match == NULL) {
		sc_error(card->ctx, "No file named \"%s\" in template \"%s\"",
				file_name, template_name);
		return SC_ERROR_OBJECT_NOT_FOUND;
	}
	sc_file_dup(ret, match->file);
	if (*ret == NULL)
		return SC_ERROR_OUT_OF_MEMORY;
	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;
}
/*
 * On-board key generation.
 */
static int
gpk_generate_key(sc_profile_t *profile, sc_card_t *card,
                 sc_pkcs15_object_t *obj,
                 sc_pkcs15_pubkey_t *pubkey)
{
    struct sc_cardctl_gpk_genkey args;
    sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
    unsigned int    keybits;
    sc_file_t	*keyfile;
    int             r, n;

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

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

        sc_debug(card->ctx, "path=%s, %d bits\n", pbuf,
                 key_info->modulus_length);
    }

    if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
        sc_error(card->ctx, "GPK supports generating only RSA keys.");
        return SC_ERROR_NOT_SUPPORTED;
    }

    /* The caller is supposed to have chosen a key file path for us */
    if (key_info->path.len == 0 || key_info->modulus_length == 0)
        return SC_ERROR_INVALID_ARGUMENTS;
    keybits = key_info->modulus_length;

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

#ifndef PK_INIT_IMMEDIATELY
    r = gpk_pkfile_init_public(profile, card, keyfile, SC_ALGORITHM_RSA,
                               keybits, key_info->usage);
    if (r < 0) {
        sc_file_free(keyfile);
        return r;
    }

    if ((r = gpk_pkfile_init_private(card, keyfile, 5 * ((3 + keybits / 16 + 7) & ~7UL))) < 0) {
        sc_file_free(keyfile);
        return r;
    }
#endif
    sc_file_free(keyfile);

    memset(&args, 0, sizeof(args));
    /*args.exponent = 0x10001;*/
    n = key_info->path.len;
    args.fid = (key_info->path.value[n-2] << 8) | key_info->path.value[n-1];
    args.privlen = keybits;

    r = sc_card_ctl(card, SC_CARDCTL_GPK_GENERATE_KEY, &args);
    if (r < 0)
        return r;

    /* This is fairly weird. The GENERATE RSA KEY command returns
     * immediately, but obviously it needs more time to complete.
     * This is why we sleep here. */
    sleep(20);

    pubkey->algorithm = SC_ALGORITHM_RSA;
    return gpk_read_rsa_key(card, &pubkey->u.rsa);
}
Beispiel #15
0
/*
 * Generate key
 */
static int westcos_pkcs15init_generate_key(sc_profile_t *profile,
						sc_pkcs15_card_t *p15card,
						sc_pkcs15_object_t *obj,
						sc_pkcs15_pubkey_t *pubkey)
{
#ifndef ENABLE_OPENSSL
	return SC_ERROR_NOT_SUPPORTED;
#else
	int r = SC_ERROR_UNKNOWN;
	long lg;
	u8 *p;
	sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
	RSA *rsa = NULL;
	BIGNUM *bn = NULL;
	BIO *mem = NULL;

	sc_file_t *prkf = NULL;

	if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
		return SC_ERROR_NOT_SUPPORTED;
	}

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

	if(rsa == NULL || bn == NULL || mem == NULL)
	{
		r = SC_ERROR_OUT_OF_MEMORY;
		goto out;
	}

	if(!BN_set_word(bn, RSA_F4) ||
		!RSA_generate_key_ex(rsa, key_info->modulus_length, bn, NULL))
#else
	mem = BIO_new(BIO_s_mem());

	if(mem == NULL)
	{
		r = SC_ERROR_OUT_OF_MEMORY;
		goto out;
	}

	rsa = RSA_generate_key(key_info->modulus_length, RSA_F4, NULL, NULL);
	if (!rsa)
#endif
	{
		r = SC_ERROR_UNKNOWN;
		goto out;
	}

	rsa->meth = RSA_PKCS1_SSLeay();

	if(pubkey != NULL)
	{
		if(!i2d_RSAPublicKey_bio(mem, rsa))
		{
			r = SC_ERROR_UNKNOWN;
			goto out;
		}

		lg = BIO_get_mem_data(mem, &p);

		pubkey->algorithm = SC_ALGORITHM_RSA;

		r = sc_pkcs15_decode_pubkey(p15card->card->ctx, pubkey, p, lg);
	}

	(void) BIO_reset(mem);

	if(!i2d_RSAPrivateKey_bio(mem, rsa))
	{
		r = SC_ERROR_UNKNOWN;
		goto out;
	}

	lg = BIO_get_mem_data(mem, &p);

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

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

		goto out;
	}

	prkf->size = lg;

	r = sc_pkcs15init_create_file(profile, p15card, prkf);
	if(r) goto out;

	r = sc_pkcs15init_update_file(profile, p15card, prkf, p, lg);
	if(r) goto out;

out:
	if(mem)
		BIO_free(mem);
	if(bn)
		BN_free(bn);
	if(rsa)
		RSA_free(rsa);
	if(prkf)
		sc_file_free(prkf);

	return r;
#endif
}
Beispiel #16
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);
}
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;
}