コード例 #1
0
ファイル: pkcs15-prkey.c プロジェクト: andyvand/OpenSC
int
sc_pkcs15_prkey_attrs_from_cert(struct sc_pkcs15_card *p15card, struct sc_pkcs15_object *cert_object,
		struct sc_pkcs15_object **out_key_object)
{
	struct sc_context *ctx = p15card->card->ctx;
#ifdef ENABLE_OPENSSL
	struct sc_pkcs15_object *key_object = NULL;
	struct sc_pkcs15_prkey_info *key_info = NULL;
	X509 *x = NULL;
	BIO *mem = NULL;
	unsigned char *buff = NULL, *ptr = NULL;
	int rv;

	LOG_FUNC_CALLED(ctx);
	if (out_key_object)
		*out_key_object = NULL;

	rv = sc_pkcs15_find_prkey_by_id(p15card, &((struct sc_pkcs15_cert_info *)cert_object->data)->id, &key_object);
	if (rv == SC_ERROR_OBJECT_NOT_FOUND)
		LOG_FUNC_RETURN(ctx, SC_SUCCESS);
	LOG_TEST_RET(ctx, rv, "Find private key error");

	key_info = (struct sc_pkcs15_prkey_info *) key_object->data;

	ERR_load_ERR_strings();
	ERR_load_crypto_strings();

	sc_log(ctx, "CertValue(%i) %p", cert_object->content.len, cert_object->content.value);
	mem = BIO_new_mem_buf(cert_object->content.value, cert_object->content.len);
	if (!mem)
		LOG_TEST_RET(ctx, SC_ERROR_INTERNAL, "MEM buffer allocation error");

	x = d2i_X509_bio(mem, NULL);
	if (!x)
		LOG_TEST_RET(ctx, SC_ERROR_INTERNAL, "x509 parse error");

	buff = OPENSSL_malloc(i2d_X509(x,NULL) + EVP_MAX_MD_SIZE);
	if (!buff)
		LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "OpenSSL allocation error");

	ptr = buff;
	rv = i2d_X509_NAME(X509_get_subject_name(x), &ptr);
	if (rv <= 0)
		LOG_TEST_RET(ctx, SC_ERROR_INTERNAL, "Get subject name error");

	key_info->subject.value = malloc(rv);
	if (!key_info->subject.value)
		LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Subject allocation error");

	memcpy(key_info->subject.value, buff, rv);
	key_info->subject.len = rv;

	strlcpy(key_object->label, cert_object->label, sizeof(key_object->label));

	rv = 0;

	if (x)
		X509_free(x);
	if (mem)
		BIO_free(mem);
	if (buff)
		OPENSSL_free(buff);

	ERR_clear_error();
	ERR_free_strings();

	if (out_key_object)
		*out_key_object = key_object;

	sc_log(ctx, "Subject %s", sc_dump_hex(key_info->subject.value, key_info->subject.len));
	LOG_FUNC_RETURN(ctx, rv);
#else
	LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
#endif
}
コード例 #2
0
ファイル: iasecc-sdo.c プロジェクト: CardContact/OpenSC
int
iasecc_sdo_convert_acl(struct sc_card *card, struct iasecc_sdo *sdo,
		unsigned char op, unsigned *out_method, unsigned *out_ref)
{
	struct sc_context *ctx = card->ctx;
	struct acl_op {
		unsigned char op;
		unsigned char mask;
	} ops[] = {
		{SC_AC_OP_PSO_COMPUTE_SIGNATURE,IASECC_ACL_PSO_SIGNATURE},
		{SC_AC_OP_INTERNAL_AUTHENTICATE,IASECC_ACL_INTERNAL_AUTHENTICATE},
		{SC_AC_OP_PSO_DECRYPT,	IASECC_ACL_PSO_DECIPHER},
		{SC_AC_OP_GENERATE,	IASECC_ACL_GENERATE_KEY},
		{SC_AC_OP_UPDATE,	IASECC_ACL_PUT_DATA},
		{SC_AC_OP_READ,		IASECC_ACL_GET_DATA},
		{0x00, 0x00}
	};
	unsigned char mask = 0x80, op_mask = 0;
	int ii;

	LOG_FUNC_CALLED(ctx);

	for (ii=0; ops[ii].mask; ii++)   {
		if (op == ops[ii].op)   {
			op_mask = ops[ii].mask;
			break;
		}
	}
	if (op_mask == 0)
		LOG_FUNC_RETURN(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);

	sc_log(ctx, "OP:%i, mask:0x%X", op, op_mask);
	sc_log(ctx, "AMB:%X, scbs:%s", sdo->docp.amb, sc_dump_hex(sdo->docp.scbs, IASECC_MAX_SCBS));
	sc_log(ctx, "docp.acls_contact:%s", sc_dump_hex(sdo->docp.acls_contact.value, sdo->docp.acls_contact.size));

	if (!sdo->docp.amb && sdo->docp.acls_contact.size)   {
		int rv = iasecc_parse_acls(card, &sdo->docp, 0);
		LOG_TEST_RET(ctx, rv, "Cannot parse ACLs in DOCP");
	}

	*out_method = SC_AC_NEVER;
	*out_ref = SC_AC_NEVER;

	for (ii=0; ii<7; ii++)   {
		mask >>= 1;
		if (sdo->docp.amb & mask)   {
			if (op_mask == mask)   {
				unsigned char scb = sdo->docp.scbs[ii];
				sc_log(ctx, "ii:%i, scb:0x%X", ii, scb);

				*out_ref = scb & 0x0F;
				if (scb == 0)
					*out_method = SC_AC_NONE;
				else if (scb == 0xFF)
					*out_method = SC_AC_NEVER;
				else if ((scb & IASECC_SCB_METHOD_MASK) == IASECC_SCB_METHOD_USER_AUTH)
					*out_method = SC_AC_SEN;
				else if ((scb & IASECC_SCB_METHOD_MASK) == IASECC_SCB_METHOD_EXT_AUTH)
					*out_method = SC_AC_AUT;
				else if ((scb & IASECC_SCB_METHOD_MASK) == IASECC_SCB_METHOD_SM)
					*out_method = SC_AC_PRO;
				else
					*out_method = SC_AC_SCB, *out_ref = scb;

				break;
			}
		}
	}

	sc_log(ctx, "returns method %X; ref %X", *out_method, *out_ref);
	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
コード例 #3
0
ファイル: sm-cwa14890.c プロジェクト: AktivCo/OpenSC
int
sm_cwa_securize_apdu(struct sc_context *ctx, struct sm_info *sm_info, struct sc_remote_apdu *rapdu)
{
	struct sm_cwa_session *session_data = &sm_info->session.cwa;
	struct sc_apdu *apdu = &rapdu->apdu;
	unsigned char sbuf[0x400];
	DES_cblock cblock, icv;
	unsigned char *encrypted = NULL, edfb_data[0x200], mac_data[0x200];
	size_t encrypted_len, edfb_len = 0, mac_len = 0, offs;
	int rv;

	LOG_FUNC_CALLED(ctx);
	sc_debug(ctx, SC_LOG_DEBUG_SM,
	       "securize APDU (cla:%X,ins:%X,p1:%X,p2:%X,data(%"SC_FORMAT_LEN_SIZE_T"u):%p)",
	       apdu->cla, apdu->ins, apdu->p1, apdu->p2, apdu->datalen,
	       apdu->data);

	sm_incr_ssc(session_data->ssc, sizeof(session_data->ssc));

	rv = sm_encrypt_des_cbc3(ctx, session_data->session_enc, apdu->data, apdu->datalen, &encrypted, &encrypted_len, 0);
	LOG_TEST_RET(ctx, rv, "securize APDU: DES CBC3 encryption failed");
	sc_debug(ctx, SC_LOG_DEBUG_SM, "encrypted data (len:%"SC_FORMAT_LEN_SIZE_T"u, %s)",
	       encrypted_len, sc_dump_hex(encrypted, encrypted_len));

	offs = 0;
	if (apdu->ins & 0x01)   {
		edfb_data[offs++] = IASECC_SM_DO_TAG_TCG_ODD_INS;
		if (encrypted_len + 1 > 0x7F)
			edfb_data[offs++] = 0x81;
		edfb_data[offs++] = encrypted_len;
	}
	else   {
		edfb_data[offs++] = IASECC_SM_DO_TAG_TCG_EVEN_INS;
		if (encrypted_len + 1 > 0x7F)
			edfb_data[offs++] = 0x81;
		edfb_data[offs++] = encrypted_len + 1;
		edfb_data[offs++] = 0x01;
	}
	memcpy(edfb_data + offs, encrypted, encrypted_len);
	offs += encrypted_len;
	edfb_len = offs;
	sc_debug(ctx, SC_LOG_DEBUG_SM, "securize APDU: EDFB(len:%"SC_FORMAT_LEN_SIZE_T"u,%s)",
	       edfb_len, sc_dump_hex(edfb_data, edfb_len));

	free(encrypted);
	encrypted = NULL;

	offs = 0;
	memcpy(mac_data + offs, session_data->ssc, 8);
	offs += 8;
	mac_data[offs++] = apdu->cla | 0x0C;
	mac_data[offs++] = apdu->ins;
	mac_data[offs++] = apdu->p1;
	mac_data[offs++] = apdu->p2;
	mac_data[offs++] = 0x80;
	mac_data[offs++] = 0x00;
	mac_data[offs++] = 0x00;
	mac_data[offs++] = 0x00;

	memcpy(mac_data + offs, edfb_data, edfb_len);
	offs += edfb_len;

	/* if (apdu->le)   { */
		mac_data[offs++] = IASECC_SM_DO_TAG_TLE;
		mac_data[offs++] = 1;
		mac_data[offs++] = apdu->le;
	/* } */

	mac_len = offs;
	sc_debug(ctx, SC_LOG_DEBUG_SM, "securize APDU: MAC data(len:%"SC_FORMAT_LEN_SIZE_T"u,%s)",
	       mac_len, sc_dump_hex(mac_data, mac_len));

	memset(icv, 0, sizeof(icv));
	rv = sm_cwa_get_mac(ctx, session_data->session_mac, &icv, mac_data, mac_len, &cblock, 0);
	LOG_TEST_RET(ctx, rv, "securize APDU: MAC calculation error");
	sc_debug(ctx, SC_LOG_DEBUG_SM, "securize APDU: MAC:%s", sc_dump_hex(cblock, sizeof(cblock)));

	offs = 0;
	if (edfb_len)   {
		memcpy(sbuf + offs, edfb_data, edfb_len);
		offs += edfb_len;
	}

	/* if (apdu->le)   { */
		sbuf[offs++] = IASECC_SM_DO_TAG_TLE;
		sbuf[offs++] = 1;
		sbuf[offs++] = apdu->le;
	/* } */

	sbuf[offs++] = IASECC_SM_DO_TAG_TCC;
	sbuf[offs++] = 8;
	memcpy(sbuf + offs, cblock, 8);
	offs += 8;
	sc_debug(ctx, SC_LOG_DEBUG_SM, "securize APDU: SM data(len:%"SC_FORMAT_LEN_SIZE_T"u,%s)",
	       offs, sc_dump_hex(sbuf, offs));

	if (offs > sizeof(rapdu->sbuf))
		LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "securize APDU: buffer too small for encrypted data");

	apdu->cse = SC_APDU_CASE_4_SHORT;
	apdu->cla |= 0x0C;
	apdu->lc = offs;
	apdu->datalen = offs;
	memcpy((unsigned char *)apdu->data, sbuf, offs);

	sm_incr_ssc(session_data->ssc, sizeof(session_data->ssc));

	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
コード例 #4
0
ファイル: pkcs15-prkey.c プロジェクト: andyvand/OpenSC
int sc_pkcs15_decode_prkdf_entry(struct sc_pkcs15_card *p15card,
				 struct sc_pkcs15_object *obj,
				 const u8 ** buf, size_t *buflen)
{
	sc_context_t *ctx = p15card->card->ctx;
	struct sc_pkcs15_prkey_info info;
	int r, i, gostr3410_params[3];
	struct sc_pkcs15_keyinfo_gostparams *keyinfo_gostparams;
	size_t usage_len = sizeof(info.usage);
	size_t af_len = sizeof(info.access_flags);
	struct sc_asn1_entry asn1_com_key_attr[C_ASN1_COM_KEY_ATTR_SIZE];
	struct sc_asn1_entry asn1_com_prkey_attr[C_ASN1_COM_PRKEY_ATTR_SIZE];
	struct sc_asn1_entry asn1_rsakey_attr[C_ASN1_RSAKEY_ATTR_SIZE];
	struct sc_asn1_entry asn1_prk_rsa_attr[C_ASN1_PRK_RSA_ATTR_SIZE];
	struct sc_asn1_entry asn1_dsakey_attr[C_ASN1_DSAKEY_ATTR_SIZE];
	struct sc_asn1_entry asn1_prk_dsa_attr[C_ASN1_PRK_DSA_ATTR_SIZE];
	struct sc_asn1_entry asn1_dsakey_i_p_attr[C_ASN1_DSAKEY_I_P_ATTR_SIZE];
	struct sc_asn1_entry asn1_dsakey_value_attr[C_ASN1_DSAKEY_VALUE_ATTR_SIZE];
	struct sc_asn1_entry asn1_gostr3410key_attr[C_ASN1_GOSTR3410KEY_ATTR_SIZE];
	struct sc_asn1_entry asn1_prk_gostr3410_attr[C_ASN1_PRK_GOSTR3410_ATTR_SIZE];
	struct sc_asn1_entry asn1_ecckey_attr[C_ASN1_ECCKEY_ATTR];
	struct sc_asn1_entry asn1_prk_ecc_attr[C_ASN1_PRK_ECC_ATTR];
	struct sc_asn1_entry asn1_prkey[C_ASN1_PRKEY_SIZE];
	struct sc_asn1_entry asn1_supported_algorithms[C_ASN1_SUPPORTED_ALGORITHMS_SIZE];
	struct sc_asn1_pkcs15_object rsa_prkey_obj = {obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_rsa_attr};
	struct sc_asn1_pkcs15_object dsa_prkey_obj = {obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_dsa_attr};
	struct sc_asn1_pkcs15_object gostr3410_prkey_obj = {obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_gostr3410_attr};
	struct sc_asn1_pkcs15_object ecc_prkey_obj = { obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_ecc_attr };

	sc_copy_asn1_entry(c_asn1_prkey, asn1_prkey);
	sc_copy_asn1_entry(c_asn1_supported_algorithms, asn1_supported_algorithms);

	sc_copy_asn1_entry(c_asn1_prk_rsa_attr, asn1_prk_rsa_attr);
	sc_copy_asn1_entry(c_asn1_rsakey_attr, asn1_rsakey_attr);
	sc_copy_asn1_entry(c_asn1_prk_dsa_attr, asn1_prk_dsa_attr);
	sc_copy_asn1_entry(c_asn1_dsakey_attr, asn1_dsakey_attr);
	sc_copy_asn1_entry(c_asn1_dsakey_value_attr, asn1_dsakey_value_attr);
	sc_copy_asn1_entry(c_asn1_dsakey_i_p_attr, asn1_dsakey_i_p_attr);
	sc_copy_asn1_entry(c_asn1_prk_gostr3410_attr, asn1_prk_gostr3410_attr);
	sc_copy_asn1_entry(c_asn1_gostr3410key_attr, asn1_gostr3410key_attr);
	sc_copy_asn1_entry(c_asn1_prk_ecc_attr, asn1_prk_ecc_attr);
	sc_copy_asn1_entry(c_asn1_ecckey_attr, asn1_ecckey_attr);

	sc_copy_asn1_entry(c_asn1_com_prkey_attr, asn1_com_prkey_attr);
	sc_copy_asn1_entry(c_asn1_com_key_attr, asn1_com_key_attr);

	sc_format_asn1_entry(asn1_prkey + 0, &rsa_prkey_obj, NULL, 0);
	sc_format_asn1_entry(asn1_prkey + 1, &ecc_prkey_obj, NULL, 0);
	sc_format_asn1_entry(asn1_prkey + 2, &dsa_prkey_obj, NULL, 0);
	sc_format_asn1_entry(asn1_prkey + 3, &gostr3410_prkey_obj, NULL, 0);

	sc_format_asn1_entry(asn1_prk_rsa_attr + 0, asn1_rsakey_attr, NULL, 0);
	sc_format_asn1_entry(asn1_prk_dsa_attr + 0, asn1_dsakey_attr, NULL, 0);
	sc_format_asn1_entry(asn1_prk_gostr3410_attr + 0, asn1_gostr3410key_attr, NULL, 0);
	sc_format_asn1_entry(asn1_prk_ecc_attr + 0, asn1_ecckey_attr, NULL, 0);

	sc_format_asn1_entry(asn1_rsakey_attr + 0, &info.path, NULL, 0);
	sc_format_asn1_entry(asn1_rsakey_attr + 1, &info.modulus_length, NULL, 0);

	sc_format_asn1_entry(asn1_dsakey_attr + 0, asn1_dsakey_value_attr, NULL, 0);
	sc_format_asn1_entry(asn1_dsakey_value_attr + 0, &info.path, NULL, 0);
	sc_format_asn1_entry(asn1_dsakey_value_attr + 1, asn1_dsakey_i_p_attr, NULL, 0);
	sc_format_asn1_entry(asn1_dsakey_i_p_attr + 0, &info.path, NULL, 0);

	sc_format_asn1_entry(asn1_gostr3410key_attr + 0, &info.path, NULL, 0);
	sc_format_asn1_entry(asn1_gostr3410key_attr + 1, &gostr3410_params[0], NULL, 0);
	sc_format_asn1_entry(asn1_gostr3410key_attr + 2, &gostr3410_params[1], NULL, 0);
	sc_format_asn1_entry(asn1_gostr3410key_attr + 3, &gostr3410_params[2], NULL, 0);

	sc_format_asn1_entry(asn1_ecckey_attr + 0, &info.path, NULL, 0);
	sc_format_asn1_entry(asn1_ecckey_attr + 1, &info.field_length, NULL, 0);

	sc_format_asn1_entry(asn1_com_key_attr + 0, &info.id, NULL, 0);
	sc_format_asn1_entry(asn1_com_key_attr + 1, &info.usage, &usage_len, 0);
	sc_format_asn1_entry(asn1_com_key_attr + 2, &info.native, NULL, 0);
	sc_format_asn1_entry(asn1_com_key_attr + 3, &info.access_flags, &af_len, 0);
	sc_format_asn1_entry(asn1_com_key_attr + 4, &info.key_reference, NULL, 0);

	for (i=0; i<SC_MAX_SUPPORTED_ALGORITHMS && (asn1_supported_algorithms + i)->name; i++)
		sc_format_asn1_entry(asn1_supported_algorithms + i, &info.algo_refs[i], NULL, 0);
	sc_format_asn1_entry(asn1_com_key_attr + 5, asn1_supported_algorithms, NULL, 0);

	sc_format_asn1_entry(asn1_com_prkey_attr + 0, &info.subject.value, &info.subject.len, 0);

	/* Fill in defaults */
	memset(&info, 0, sizeof(info));
	info.key_reference = -1;
	info.native = 1;
	memset(gostr3410_params, 0, sizeof(gostr3410_params));

	r = sc_asn1_decode_choice(ctx, asn1_prkey, *buf, *buflen, buf, buflen);
	if (r == SC_ERROR_ASN1_END_OF_CONTENTS)
		return r;
	LOG_TEST_RET(ctx, r, "PrKey DF ASN.1 decoding failed");
	if (asn1_prkey[0].flags & SC_ASN1_PRESENT) {
		obj->type = SC_PKCS15_TYPE_PRKEY_RSA;
	}
	else if (asn1_prkey[1].flags & SC_ASN1_PRESENT) {
		obj->type = SC_PKCS15_TYPE_PRKEY_EC;
	}
	else if (asn1_prkey[2].flags & SC_ASN1_PRESENT) {
		obj->type = SC_PKCS15_TYPE_PRKEY_DSA;
		/* If the value was indirect-protected, mark the path */
		if (asn1_dsakey_i_p_attr[0].flags & SC_ASN1_PRESENT)
			info.path.type = SC_PATH_TYPE_PATH_PROT;
	}
	else if (asn1_prkey[3].flags & SC_ASN1_PRESENT) {
		obj->type = SC_PKCS15_TYPE_PRKEY_GOSTR3410;
		assert(info.modulus_length == 0);
		info.modulus_length = SC_PKCS15_GOSTR3410_KEYSIZE;
		assert(info.params.len == 0);
		info.params.len = sizeof(struct sc_pkcs15_keyinfo_gostparams);
		info.params.data = malloc(info.params.len);
		if (info.params.data == NULL)
			LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
		assert(sizeof(*keyinfo_gostparams) == info.params.len);
		keyinfo_gostparams = info.params.data;
		keyinfo_gostparams->gostr3410 = gostr3410_params[0];
		keyinfo_gostparams->gostr3411 = gostr3410_params[1];
		keyinfo_gostparams->gost28147 = gostr3410_params[2];
	}
	else {
		sc_log(ctx, "Neither RSA or DSA or GOSTR3410 or ECC key in PrKDF entry.");
		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ASN1_OBJECT);
	}

	if (!p15card->app || !p15card->app->ddo.aid.len)   {
		r = sc_pkcs15_make_absolute_path(&p15card->file_app->path, &info.path);
		if (r < 0) {
			sc_pkcs15_free_key_params(&info.params);
			return r;
		}
	}
	else   {
		info.path.aid = p15card->app->ddo.aid;
	}
	sc_log(ctx, "PrivKey path '%s'", sc_print_path(&info.path));

	/* OpenSC 0.11.4 and older encoded "keyReference" as a negative value.
	 * Fixed in 0.11.5 we need to add a hack, so old cards continue to work. */
	if (info.key_reference < -1)
		info.key_reference += 256;

	/* Check the auth_id - if not present, try and find it in access rules */
	if ((obj->flags & SC_PKCS15_CO_FLAG_PRIVATE) && (obj->auth_id.len == 0)) {
		sc_log(ctx, "Private key %s has no auth ID - checking AccessControlRules",
				sc_pkcs15_print_id(&info.id));

		/* Search in the access_rules for an appropriate auth ID */
		for (i = 0; i < SC_PKCS15_MAX_ACCESS_RULES; i++) {
			/* If access_mode is one of the private key usage modes */
			if (obj->access_rules[i].access_mode &
					(SC_PKCS15_ACCESS_RULE_MODE_EXECUTE |
					 SC_PKCS15_ACCESS_RULE_MODE_PSO_CDS |
					 SC_PKCS15_ACCESS_RULE_MODE_PSO_DECRYPT |
					 SC_PKCS15_ACCESS_RULE_MODE_INT_AUTH)) {
				if (obj->access_rules[i].auth_id.len != 0) {
					/* Found an auth ID to use for private key access */
					obj->auth_id = obj->access_rules[i].auth_id;
					sc_log(ctx, "Auth ID found - %s",
						 sc_pkcs15_print_id(&obj->auth_id));
					break;
				}
			}
		}

		/* No auth ID found */
		if (i == SC_PKCS15_MAX_ACCESS_RULES)
			sc_log(ctx, "Warning: No auth ID found");
	}

	obj->data = malloc(sizeof(info));
	if (obj->data == NULL) {
		sc_pkcs15_free_key_params(&info.params);
		LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
	}
	memcpy(obj->data, &info, sizeof(info));

	sc_log(ctx, "Key Subject %s", sc_dump_hex(info.subject.value, info.subject.len));
	sc_log(ctx, "Key path %s", sc_print_path(&info.path));
	return 0;
}
コード例 #5
0
ファイル: pkcs15-openpgp.c プロジェクト: PhoenixBaymax/OpenSC
static int openpgp_store_data(struct sc_pkcs15_card *p15card, struct sc_profile *profile,
                              struct sc_pkcs15_object *obj, struct sc_pkcs15_der *content,
                              struct sc_path *path)
{
	sc_card_t *card = p15card->card;
	sc_context_t *ctx = card->ctx;
	sc_file_t *file;
	sc_pkcs15_cert_info_t *cinfo;
	sc_pkcs15_id_t *cid;
	sc_pkcs15_data_info_t *dinfo;
	u8 buf[254];
	int r;

	LOG_FUNC_CALLED(card->ctx);

	switch (obj->type & SC_PKCS15_TYPE_CLASS_MASK) {
	case SC_PKCS15_TYPE_PRKEY:
	case SC_PKCS15_TYPE_PUBKEY:
		/* For these two type, store_data just don't need to do anything.
		 * All have been done already before this function is called */
		r = SC_SUCCESS;
		break;

	case SC_PKCS15_TYPE_CERT:
		cinfo = (sc_pkcs15_cert_info_t *) obj->data;
		cid = &(cinfo->id);

		if (cid->len != 1) {
			sc_log(card->ctx, "ID=%s is not valid.", sc_dump_hex(cid->value, cid->len));
			LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
		}

		/* OpenPGP card v.2 contains only 1 certificate */
		if (cid->value[0] != 3) {
			sc_log(card->ctx,
			       "This version does not support certificate ID = %d (only ID=3 is supported).",
			       cid->value[0]);
			LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
		}
		/* Just update the certificate DO */
		sc_format_path("7F21", path);
		r = sc_select_file(card, path, &file);
		LOG_TEST_RET(card->ctx, r, "Cannot select cert file");
		r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE);
		sc_log(card->ctx, "Data to write is %d long", content->len);
		if (r >= 0 && content->len)
			r = sc_put_data(p15card->card, 0x7F21, (const unsigned char *) content->value, content->len);
		break;

	case SC_PKCS15_TYPE_DATA_OBJECT:
		dinfo = (sc_pkcs15_data_info_t *) obj->data;
		/* dinfo->app_label contains filename */
		sc_log(ctx, "===== App label %s", dinfo->app_label);
		/* Currently, we only support DO 0101. The reason is that when initializing this
		 * pkcs15 emulation, PIN authentication is not applied and we can expose only this DO,
		 * which is "read always".
		 * If we support other DOs, they will not be exposed, and not helpful to user.
		 * I haven't found a way to refresh the list of exposed DOs after verifying PIN yet.
		 * http://sourceforge.net/mailarchive/message.php?msg_id=30646373
		 **/
		sc_log(ctx, "About to write to DO 0101");
		sc_format_path("0101", path);
		r = sc_select_file(card, path, &file);
		LOG_TEST_RET(card->ctx, r, "Cannot select private DO");
		r = sc_read_binary(card, 0, buf, sizeof(buf), 0);
		if (r < 0) {
			sc_log(ctx, "Cannot read DO 0101");
			break;
		}
		if (r > 0) {
			sc_log(ctx, "DO 0101 is full.");
			r = SC_ERROR_NOT_ENOUGH_MEMORY;
			break;
		}
		r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE);
		if (r >= 0 && content->len) {
			r = sc_update_binary(p15card->card, 0,
			                     (const unsigned char *) content->value,
			                     content->len, 0);
		}
		break;

	default:
		r = SC_ERROR_NOT_IMPLEMENTED;
	}

	LOG_FUNC_RETURN(card->ctx, r);
}
コード例 #6
0
ファイル: sm-cwa14890.c プロジェクト: AktivCo/OpenSC
int
sm_cwa_initialize(struct sc_context *ctx, struct sm_info *sm_info, struct sc_remote_data *rdata)
{
	struct sm_cwa_session *cwa_session = &sm_info->session.cwa;
	struct sm_cwa_keyset *cwa_keyset = &sm_info->session.cwa.cwa_keyset;
	struct sc_serial_number sn = sm_info->serialnr;
	size_t icc_sn_len = sizeof(cwa_session->icc.sn);
	struct sc_remote_apdu *new_rapdu = NULL;
	struct sc_apdu *apdu = NULL;
	unsigned char buf[0x100], *encrypted;
	size_t encrypted_len;
	DES_cblock icv = {0, 0, 0, 0, 0, 0, 0, 0}, cblock;
	int rv, offs;

	LOG_FUNC_CALLED(ctx);
	sc_debug(ctx, SC_LOG_DEBUG_SM, "SM IAS/ECC initialize: serial %s", sc_dump_hex(sm_info->serialnr.value, sm_info->serialnr.len));
	sc_debug(ctx, SC_LOG_DEBUG_SM, "SM IAS/ECC initialize: card challenge %s", sc_dump_hex(cwa_session->card_challenge, 8));
	sc_debug(ctx, SC_LOG_DEBUG_SM, "SM IAS/ECC initialize: current_df_path %s", sc_print_path(&sm_info->current_path_df));
	sc_debug(ctx, SC_LOG_DEBUG_SM, "SM IAS/ECC initialize: CRT_AT reference 0x%X", cwa_session->params.crt_at.refs[0]);

	if (!rdata || !rdata->alloc)
		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);

	rv = rdata->alloc(rdata, &new_rapdu);
	LOG_TEST_RET(ctx, rv, "SM GP decode card answer: cannot allocate remote APDU");
	apdu = &new_rapdu->apdu;

	memcpy(&cwa_session->icc.rnd[0], cwa_session->card_challenge, 8);

	if (sn.len > icc_sn_len)
		memcpy(&cwa_session->icc.sn[0], &sn.value[sn.len - icc_sn_len], icc_sn_len);
	else
		memcpy(&cwa_session->icc.sn[icc_sn_len - sn.len], &sn.value[0], sn.len);

	if (sm_info->cmd == SM_CMD_EXTERNAL_AUTH)   {
		offs = sm_cwa_encode_external_auth_data(ctx, cwa_session, buf, sizeof(buf));
		if (offs != 0x10)
			LOG_FUNC_RETURN(ctx, offs);
	}
	else   {
		offs = sm_cwa_encode_mutual_auth_data(ctx, cwa_session, buf, sizeof(buf));
		if (offs != 0x40)
			LOG_FUNC_RETURN(ctx, offs);
	}

	sc_debug(ctx, SC_LOG_DEBUG_SM, "S(%i) %s", offs, sc_dump_hex(buf, offs));

	rv = sm_encrypt_des_cbc3(ctx, cwa_keyset->enc, buf, offs, &encrypted, &encrypted_len, 1);
	LOG_TEST_RET(ctx, rv, "_encrypt_des_cbc3() failed");

	sc_debug(ctx, SC_LOG_DEBUG_SM, "ENCed(%"SC_FORMAT_LEN_SIZE_T"u) %s", encrypted_len,
	       sc_dump_hex(encrypted, encrypted_len));

	memcpy(buf, encrypted, encrypted_len);
	offs = encrypted_len;

	rv = sm_cwa_get_mac(ctx, cwa_keyset->mac, &icv, buf, offs, &cblock, 1);
	LOG_TEST_RET(ctx, rv, "sm_ecc_get_mac() failed");
	sc_debug(ctx, SC_LOG_DEBUG_SM, "MACed(%"SC_FORMAT_LEN_SIZE_T"u) %s", sizeof(cblock),
	       sc_dump_hex(cblock, sizeof(cblock)));

	apdu->cse = SC_APDU_CASE_4_SHORT;
	apdu->cla = 0x00;
	apdu->ins = 0x82;
	apdu->p1 =  0x00;
	apdu->p2 =  0x00;
	apdu->lc =  encrypted_len + sizeof(cblock);
	apdu->le = encrypted_len + sizeof(cblock);
	apdu->datalen = encrypted_len + sizeof(cblock);
	memcpy(new_rapdu->sbuf, encrypted, encrypted_len);
	memcpy(new_rapdu->sbuf + encrypted_len, cblock, sizeof(cblock));

	free(encrypted);
	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
コード例 #7
0
ファイル: pkcs15-openpgp.c プロジェクト: PhoenixBaymax/OpenSC
/**
 * Generates a new (RSA) key pair using an existing key file.
 * @param  profile  IN profile information for this card
 * @param  card     IN sc_card_t object to use
 * @param  obj      IN sc_pkcs15_object_t object with pkcs15 information
 * @param  pukkey   OUT the newly created public key
 * @return SC_SUCCESS on success and an error code otherwise
 **/
static int openpgp_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
	sc_pkcs15_object_t *obj, sc_pkcs15_pubkey_t *pubkey)
{
	sc_card_t *card = p15card->card;
	sc_context_t *ctx = card->ctx;
	sc_cardctl_openpgp_keygen_info_t key_info;
	sc_pkcs15_prkey_info_t *required = (sc_pkcs15_prkey_info_t *)obj->data;
	sc_pkcs15_id_t *kid = &(required->id);
	int r;

	LOG_FUNC_CALLED(ctx);
	memset(&key_info, 0, sizeof(key_info));
	sc_log(ctx, "Key ID to be generated: %s", sc_dump_hex(kid->value, kid->len));

	/* Accept KeyID = 45, which is default value set by pkcs15init */
	if (kid->len == 1 && kid->value[0] == 0x45) {
		/* Default key is authentication key. We choose this because the common use
		 * is to generate from PKCS#11 (Firefox/Thunderbird) */
		sc_log(ctx, "Authentication key is to be generated.");
		key_info.keytype = 3;
	}
	if (!key_info.keytype && (kid->len > 1 || kid->value[0] > 3)) {
		sc_log(ctx, "Key ID must be 1, 2 or 3!");
		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
	}

	if (!key_info.keytype)
		key_info.keytype = kid->value[0];

	/* Prepare buffer */
	key_info.modulus_len = required->modulus_length;
	key_info.modulus = calloc(required->modulus_length >> 3, 1);
	if (key_info.modulus == NULL)
		LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY);

	/* The OpenPGP supports only 32-bit exponent. */
	key_info.exponent_len = 32;
	key_info.exponent = calloc(key_info.exponent_len>>3, 1); /* 1/8 */
	if (key_info.exponent == NULL)
		LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY);

	r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_GENERATE_KEY, &key_info);
	if (r < 0)
		goto out;

	sc_log(ctx, "Set output modulus info");
	pubkey->u.rsa.modulus.len = key_info.modulus_len;
	pubkey->u.rsa.modulus.data = calloc(key_info.modulus_len, 1);
	if (pubkey->u.rsa.modulus.data == NULL)
		goto out;
	memcpy(pubkey->u.rsa.modulus.data, key_info.modulus, key_info.modulus_len);

	sc_log(ctx, "Set output exponent info");
	pubkey->u.rsa.exponent.len = key_info.exponent_len;
	pubkey->u.rsa.exponent.data = calloc(key_info.exponent_len>>3, 1); /* 1/8 */
	if (pubkey->u.rsa.exponent.data == NULL)
		goto out;
	memcpy(pubkey->u.rsa.exponent.data, key_info.exponent, key_info.exponent_len>>3); /* 1/8 */

out:
	if (key_info.modulus)
		free(key_info.modulus);
	if (key_info.exponent)
		free(key_info.exponent);
	LOG_FUNC_RETURN(ctx, r);
}
コード例 #8
0
ファイル: sm-card-iasecc.c プロジェクト: Hubitronic/OpenSC
int
sm_iasecc_decode_card_data(struct sc_context *ctx, struct sm_info *sm_info, struct sc_remote_data *rdata,
		unsigned char *out, size_t out_len)
{
	struct sm_cwa_session *session_data = &sm_info->session.cwa;
	struct sc_asn1_entry asn1_iasecc_sm_data_object[4];
	struct sc_remote_apdu *rapdu = NULL;
	int rv, offs = 0;

	LOG_FUNC_CALLED(ctx);

	sc_log(ctx, "IAS/ECC decode answer() rdata length %i, out length %i", rdata->length, out_len);
        for (rapdu = rdata->data; rapdu; rapdu = rapdu->next)   {
                unsigned char *decrypted;
                size_t decrypted_len;
		unsigned char resp_data[SC_MAX_APDU_BUFFER_SIZE];
		size_t resp_len = sizeof(resp_data);
		unsigned char status[2] = {0, 0};
		size_t status_len = sizeof(status);
		unsigned char ticket[8];
		size_t ticket_len = sizeof(ticket);

		sc_log(ctx, "IAS/ECC decode response(%i) %s", rapdu->apdu.resplen, sc_dump_hex(rapdu->apdu.resp, rapdu->apdu.resplen));

		sc_copy_asn1_entry(c_asn1_iasecc_sm_data_object, asn1_iasecc_sm_data_object);
		sc_format_asn1_entry(asn1_iasecc_sm_data_object + 0, resp_data, &resp_len, 0);
		sc_format_asn1_entry(asn1_iasecc_sm_data_object + 1, status, &status_len, 0);
		sc_format_asn1_entry(asn1_iasecc_sm_data_object + 2, ticket, &ticket_len, 0);

        	rv = sc_asn1_decode(ctx, asn1_iasecc_sm_data_object, rapdu->apdu.resp, rapdu->apdu.resplen, NULL, NULL);
		LOG_TEST_RET(ctx, rv, "IAS/ECC decode answer(s): ASN1 decode error");

		sc_log(ctx, "IAS/ECC decode response() SW:%02X%02X, MAC:%s", status[0], status[1], sc_dump_hex(ticket, ticket_len));
		if (status[0] != 0x90 || status[1] != 0x00)
			continue;

		if (asn1_iasecc_sm_data_object[0].flags & SC_ASN1_PRESENT)   {
			sc_log(ctx, "IAS/ECC decode answer() object present");
			if (resp_data[0] != 0x01)
				LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "IAS/ECC decode answer(s): invalid encrypted data format");

			decrypted_len = sizeof(decrypted);
			rv = sm_decrypt_des_cbc3(ctx, session_data->session_enc, &resp_data[1], resp_len - 1,
					&decrypted, &decrypted_len);
			LOG_TEST_RET(ctx, rv, "IAS/ECC decode answer(s): cannot decrypt card answer data");

			sc_log(ctx, "IAS/ECC decrypted data(%i) %s", decrypted_len, sc_dump_hex(decrypted, decrypted_len));
			while(*(decrypted + decrypted_len - 1) == 0x00)
			       decrypted_len--;
			if (*(decrypted + decrypted_len - 1) != 0x80)
				LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "IAS/ECC decode answer(s): invalid card data padding ");
			decrypted_len--;

			if (out && out_len)   {
				if (out_len < offs + decrypted_len)
					LOG_TEST_RET(ctx, SC_ERROR_BUFFER_TOO_SMALL, "IAS/ECC decode answer(s): unsufficient output buffer size");

				memcpy(out + offs, decrypted, decrypted_len);

				offs += decrypted_len;
				sc_log(ctx, "IAS/ECC decode card answer(s): out_len/offs %i/%i", out_len, offs);
			}

			free(decrypted);
		}
	}

	LOG_FUNC_RETURN(ctx, offs);
}
コード例 #9
0
ファイル: sm-card-iasecc.c プロジェクト: Hubitronic/OpenSC
int
sm_iasecc_get_apdus(struct sc_context *ctx, struct sm_info *sm_info,
	       unsigned char *init_data, size_t init_len, struct sc_remote_data *rdata, int release_sm)
{
	struct sm_cwa_session *cwa_session = &sm_info->session.cwa;
	struct sm_cwa_keyset *cwa_keyset = &sm_info->session.cwa.cwa_keyset;
	int rv;

	LOG_FUNC_CALLED(ctx);
	if (!sm_info)
		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);

	sc_log(ctx, "SM IAS/ECC get APDUs: init_len:%i", init_len);
	sc_log(ctx, "SM IAS/ECC get APDUs: rdata:%p", rdata);
	sc_log(ctx, "SM IAS/ECC get APDUs: serial %s", sc_dump_hex(sm_info->serialnr.value, sm_info->serialnr.len));

	rv = sm_cwa_decode_authentication_data(ctx, cwa_keyset, cwa_session, init_data);
	LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: decode authentication data error");

	rv = sm_cwa_init_session_keys(ctx, cwa_session, cwa_session->params.crt_at.algo);
	LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: cannot get session keys");

	sc_log(ctx, "SKENC %s", sc_dump_hex(cwa_session->session_enc, sizeof(cwa_session->session_enc)));
	sc_log(ctx, "SKMAC %s", sc_dump_hex(cwa_session->session_mac, sizeof(cwa_session->session_mac)));
	sc_log(ctx, "SSC   %s", sc_dump_hex(cwa_session->ssc, sizeof(cwa_session->ssc)));

	switch (sm_info->cmd)  {
	case SM_CMD_FILE_READ:
		rv = sm_iasecc_get_apdu_read_binary(ctx, sm_info, rdata);
		LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: 'READ BINARY' failed");
		break;
	case SM_CMD_FILE_UPDATE:
		rv = sm_iasecc_get_apdu_update_binary(ctx, sm_info, rdata);
		LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: 'UPDATE BINARY' failed");
		break;
	case SM_CMD_FILE_CREATE:
		rv = sm_iasecc_get_apdu_create_file(ctx, sm_info, rdata);
		LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: 'CREATE FILE' failed");
		break;
	case SM_CMD_FILE_DELETE:
		rv = sm_iasecc_get_apdu_delete_file(ctx, sm_info, rdata);
		LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: 'DELETE FILE' failed");
		break;
	case SM_CMD_PIN_RESET:
		rv = sm_iasecc_get_apdu_reset_pin(ctx, sm_info, rdata);
		LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: 'RESET PIN' failed");
		break;
	case SM_CMD_RSA_GENERATE:
		rv = sm_iasecc_get_apdu_generate_rsa(ctx, sm_info, rdata);
		LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: 'GENERATE RSA' failed");
		break;
	case SM_CMD_RSA_UPDATE:
		rv = sm_iasecc_get_apdu_update_rsa(ctx, sm_info, rdata);
		LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: 'UPDATE RSA' failed");
		break;
	case SM_CMD_SDO_UPDATE:
		rv = sm_iasecc_get_apdu_sdo_update(ctx, sm_info, rdata);
		LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: 'SDO UPDATE' failed");
		break;
	case SM_CMD_PIN_VERIFY:
		rv = sm_iasecc_get_apdu_verify_pin(ctx, sm_info, rdata);
		LOG_TEST_RET(ctx, rv, "SM IAS/ECC get APDUs: 'RAW APDU' failed");
		break;
	default:
		LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "unsupported SM command");
	}

	if (release_sm)   {
		/* Apparently useless for this card */
	}

	LOG_FUNC_RETURN(ctx, rv);
}
コード例 #10
0
ファイル: sm-card-iasecc.c プロジェクト: Hubitronic/OpenSC
static int
sm_iasecc_get_apdu_update_rsa(struct sc_context *ctx, struct sm_info *sm_info, struct sc_remote_data *rdata)
{
	struct iasecc_sdo_rsa_update *cmd_data = (struct iasecc_sdo_rsa_update *)sm_info->cmd_data;
	struct iasecc_sdo_update *to_update[2] = {NULL, NULL};
	int rv = 0, ii = 0, jj = 0;

	LOG_FUNC_CALLED(ctx);
	if (cmd_data->update_prv.sdo_class)   {
		to_update[ii++] = &cmd_data->update_prv;
		sc_log(ctx, "SM get 'UPDATE RSA' APDU: SDO(class:%X,ref:%X)", cmd_data->update_prv.sdo_class, cmd_data->update_prv.sdo_ref);
	}

	if (cmd_data->update_pub.sdo_class)   {
		to_update[ii++] = &cmd_data->update_pub;
		sc_log(ctx, "SM get 'UPDATE RSA' APDU: SDO(class:%X,ref:%X)", cmd_data->update_pub.sdo_class, cmd_data->update_pub.sdo_ref);
	}

	for (jj=0;jj<2 && to_update[jj];jj++)   {
		for (ii=0; to_update[jj]->fields[ii].tag && ii < IASECC_SDO_TAGS_UPDATE_MAX; ii++)   {
			unsigned char *encoded = NULL;
			size_t encoded_len, offs;

			sc_log(ctx, "SM IAS/ECC get APDUs: component(num %i:%i) class:%X, ref:%X", jj, ii,
					to_update[jj]->sdo_class, to_update[jj]->sdo_ref);

			encoded_len = iasecc_sdo_encode_update_field(ctx, to_update[jj]->sdo_class, to_update[jj]->sdo_ref,
						&to_update[jj]->fields[ii], &encoded);
			LOG_TEST_RET(ctx, encoded_len, "SM get 'UPDATE RSA' APDU: cannot encode key component");

			sc_log(ctx, "SM IAS/ECC get APDUs: component encoded %s", sc_dump_hex(encoded, encoded_len));

			for (offs = 0; offs < encoded_len; )   {
				int len = (encoded_len - offs) > SM_MAX_DATA_SIZE ? SM_MAX_DATA_SIZE : (encoded_len - offs);
				struct sc_remote_apdu *rapdu = NULL;

		 		rv = rdata->alloc(rdata, &rapdu);
	        		LOG_TEST_RET(ctx, rv, "SM get 'UPDATE RSA' APDUs: cannot allocate remote APDU");

				rapdu->apdu.cse = SC_APDU_CASE_3_SHORT;
				rapdu->apdu.cla = len + offs < encoded_len ? 0x10 : 0x00;
				rapdu->apdu.ins = 0xDB;
				rapdu->apdu.p1 = 0x3F;
				rapdu->apdu.p2 = 0xFF;
				memcpy((unsigned char *)rapdu->apdu.data, encoded + offs, len);
				rapdu->apdu.datalen = len;
				rapdu->apdu.lc = len;

				/** 99 02 SW   8E 08 MAC **/
				rapdu->apdu.le = 0x0E;

				rv = sm_cwa_securize_apdu(ctx, sm_info, rapdu);
		                LOG_TEST_RET(ctx, rv, "SM get 'UPDATE RSA' APDUs: securize APDU error");

				rapdu->flags |= SC_REMOTE_APDU_FLAG_RETURN_ANSWER;

				offs += len;
			}
			free(encoded);
		}
	}

	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
コード例 #11
0
ファイル: pkcs15-algo.c プロジェクト: PhoenixBaymax/OpenSC
int
sc_asn1_encode_algorithm_id(struct sc_context *ctx, u8 **buf, size_t *len,
			    const struct sc_algorithm_id *id,
			    int depth)
{
	struct sc_asn1_pkcs15_algorithm_info *alg_info;
	struct sc_algorithm_id temp_id;
	struct sc_asn1_entry asn1_alg_id[3];
	u8 *obj = NULL;
	size_t obj_len = 0;
	int r;
	u8 *tmp;

	LOG_FUNC_CALLED(ctx);
        sc_log(ctx, "type of algorithm to encode: %i", id->algorithm);
	alg_info = sc_asn1_get_algorithm_info(id);
	if (alg_info == NULL) {
		sc_log(ctx, "Cannot encode unknown algorithm %u", id->algorithm);
		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
	}

	/* Set the oid if not yet given */
	if (!sc_valid_oid(&id->oid)) {
		temp_id = *id;
		temp_id.oid = alg_info->oid;
		id = &temp_id;
	}

        sc_log(ctx, "encode algo %s", sc_dump_oid(&(id->oid)));
	sc_copy_asn1_entry(c_asn1_alg_id, asn1_alg_id);
	sc_format_asn1_entry(asn1_alg_id + 0, (void *) &id->oid, NULL, 1);

	/* no parameters, write NULL tag */
	if (!id->params || !alg_info->encode)
		asn1_alg_id[1].flags |= SC_ASN1_PRESENT;

	r = _sc_asn1_encode(ctx, asn1_alg_id, buf, len, depth + 1);
	LOG_TEST_RET(ctx, r, "ASN.1 encode of algorithm failed");

	/* Encode any parameters */
	if (id->params && alg_info->encode) {
		r = alg_info->encode(ctx, id->params, &obj, &obj_len, depth+1);
		if (r < 0) {
			if (obj)
				free(obj);
			LOG_FUNC_RETURN(ctx, r);
		}
	}

	if (obj_len) {
		tmp = (u8 *) realloc(*buf, *len + obj_len);
		if (!tmp) {
			free(*buf);
			*buf = NULL;
			free(obj);
			LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
		}
		*buf = tmp;
		memcpy(*buf + *len, obj, obj_len);
		*len += obj_len;
		free(obj);
	}

	sc_log(ctx, "return encoded algorithm ID: %s", sc_dump_hex(*buf, *len));
	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}