Commit message: oberthur: Correctly check for return values

Thanks oss-fuzz

https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=28843
CVE: None
Vulnerability description: None

Project: OpenSC
File: pkcs15-oberthur.c

sc_oberthur_parse_privateinfo (struct sc_pkcs15_card *p15card,
		unsigned char *buff, size_t len, int postpone_allowed)
{
	struct sc_context *ctx = p15card->card->ctx;
	size_t ii;
	int rv;
	int no_more_private_keys = 0, no_more_private_data = 0;

	LOG_FUNC_CALLED(ctx);

	for (ii=0; ii+5<=len; ii+=5)   {
		unsigned int file_id, size;

		if(*(buff+ii) != 0xFF)
			continue;

		file_id = 0x100 * *(buff+ii + 1) + *(buff+ii + 2);
		size = 0x100 * *(buff+ii + 3) + *(buff+ii + 4);
		sc_log(ctx, "add private object (file-id:%04X, size:%X)", file_id, size);

		switch (*(buff+ii + 1))   {
		case BASE_ID_PRV_RSA :
			if (no_more_private_keys)
				break;

			rv = sc_pkcs15emu_oberthur_add_prvkey(p15card, file_id, size);
			if (rv == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED && postpone_allowed)   {
				struct sc_path path;

				sc_log(ctx, "postpone adding of the private keys");
				sc_format_path("5011A5A5", &path);
				rv = sc_pkcs15_add_df(p15card, SC_PKCS15_PRKDF, &path);
				LOG_TEST_RET(ctx, rv, "Add PrkDF error");
				no_more_private_keys = 1;
			}
			LOG_TEST_RET(ctx, rv, "Cannot parse private key info");
			break;
		case BASE_ID_PRV_DES :
			break;
		case BASE_ID_PRV_DATA :
			sc_log(ctx, "*(buff+ii + 1):%X", *(buff+ii + 1));
			if (no_more_private_data)
				break;

			rv = sc_pkcs15emu_oberthur_add_data(p15card, file_id, size, 1);
			if (rv == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED && postpone_allowed)   {
				struct sc_path path;

				sc_log(ctx, "postpone adding of the private data");
				sc_format_path("5011A6A6", &path);
				rv = sc_pkcs15_add_df(p15card, SC_PKCS15_DODF, &path);
				LOG_TEST_RET(ctx, rv, "Add DODF error");
				no_more_private_data = 1;
			}
			LOG_TEST_RET(ctx, rv, "Cannot parse private data info");
			break;
		default:
			LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Private object parse error");
		}
	}

	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}

Project: OpenSC
File: pkcs15-oberthur.c

sc_awp_parse_df(struct sc_pkcs15_card *p15card, struct sc_pkcs15_df *df)
{
	struct sc_context *ctx = p15card->card->ctx;
	unsigned char *buf = NULL;
	size_t buf_len;
	int rv;

	LOG_FUNC_CALLED(ctx);
	if (df->type != SC_PKCS15_PRKDF && df->type != SC_PKCS15_DODF)
		LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);

	if (df->enumerated)
		LOG_FUNC_RETURN(ctx, SC_SUCCESS);

	rv = sc_oberthur_read_file(p15card, AWP_OBJECTS_LIST_PRV, &buf, &buf_len, 1);
	LOG_TEST_RET(ctx, rv, "Parse DF: read private objects info failed");

	rv = sc_oberthur_parse_privateinfo(p15card, buf, buf_len, 0);

	if (buf)
		free(buf);

	if (rv == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED)
		LOG_FUNC_RETURN(ctx, SC_SUCCESS);

	LOG_TEST_RET(ctx, rv, "Parse DF: private info parse error");
	df->enumerated = 1;

	LOG_FUNC_RETURN(ctx, rv);
}

Project: OpenSC
File: pkcs15-oberthur.c

sc_oberthur_parse_containers (struct sc_pkcs15_card *p15card,
		unsigned char *buff, size_t len, int postpone_allowed)
{
	struct sc_context *ctx = p15card->card->ctx;
	size_t offs;

	LOG_FUNC_CALLED(ctx);

	while (Containers)   {
		struct container *next = Containers->next;

		free (Containers);
		Containers = next;
	}

	for (offs=0; offs + 2 + 2+2+2 + 2+2+2 + 2+36 <= len;)  {
		struct container *cont;
		unsigned char *ptr =  buff + offs + 2;

		sc_log(ctx,
		       "parse contaniers offs:%"SC_FORMAT_LEN_SIZE_T"u, len:%"SC_FORMAT_LEN_SIZE_T"u",
		       offs, len);
		if (*(buff + offs) != 'R')
			return SC_ERROR_INVALID_DATA;

		cont = (struct container *)calloc(sizeof(struct container), 1);
		if (!cont)
			return SC_ERROR_OUT_OF_MEMORY;

		cont->exchange.id_pub = *ptr * 0x100 + *(ptr + 1);  ptr += 2;
		cont->exchange.id_prv = *ptr * 0x100 + *(ptr + 1);  ptr += 2;
		cont->exchange.id_cert = *ptr * 0x100 + *(ptr + 1); ptr += 2;

		cont->sign.id_pub = *ptr * 0x100 + *(ptr + 1);  ptr += 2;
		cont->sign.id_prv = *ptr * 0x100 + *(ptr + 1);  ptr += 2;
		cont->sign.id_cert = *ptr * 0x100 + *(ptr + 1); ptr += 2;

		memcpy(cont->uuid, ptr + 2, 36);
		sc_log(ctx, "UUID: %s; 0x%X, 0x%X, 0x%X", cont->uuid,
				cont->exchange.id_pub, cont->exchange.id_prv, cont->exchange.id_cert);

		if (!Containers)  {
			Containers = cont;
		}
		else   {
			cont->next = Containers;
			Containers->prev = (void *)cont;
			Containers = cont;
		}

		offs += *(buff + offs + 1) + 2;
	}

	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}

Project: OpenSC
File: pkcs15-oberthur.c

oberthur_detect_card(struct sc_pkcs15_card * p15card)
{
	struct sc_card *card = p15card->card;

	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
	if (p15card->card->type != SC_CARD_TYPE_OBERTHUR_64K)
		LOG_FUNC_RETURN(p15card->card->ctx, SC_ERROR_WRONG_CARD);
	LOG_FUNC_RETURN(p15card->card->ctx, SC_SUCCESS);
}

Project: OpenSC
File: pkcs15-oberthur.c

sc_oberthur_parse_publicinfo (struct sc_pkcs15_card *p15card,
		unsigned char *buff, size_t len, int postpone_allowed)
{
	struct sc_context *ctx = p15card->card->ctx;
	size_t ii;
	int rv;

	LOG_FUNC_CALLED(ctx);
	for (ii=0; ii+5<=len; ii+=5)   {
		unsigned int file_id, size;

		if(*(buff+ii) != 0xFF)
			continue;

		file_id = 0x100 * *(buff+ii + 1) + *(buff+ii + 2);
		size = 0x100 * *(buff+ii + 3) + *(buff+ii + 4);
		sc_log(ctx, "add public object(file-id:%04X,size:%X)", file_id, size);

		switch (*(buff+ii + 1))   {
		case BASE_ID_PUB_RSA :
			rv = sc_pkcs15emu_oberthur_add_pubkey(p15card, file_id, size);
			LOG_TEST_RET(ctx, rv, "Cannot parse public key info");
			break;
		case BASE_ID_CERT :
			rv = sc_pkcs15emu_oberthur_add_cert(p15card, file_id);
			LOG_TEST_RET(ctx, rv, "Cannot parse certificate info");
			break;
		case BASE_ID_PUB_DES :
			break;
		case BASE_ID_PUB_DATA :
			rv = sc_pkcs15emu_oberthur_add_data(p15card, file_id, size, 0);
			LOG_TEST_RET(ctx, rv, "Cannot parse data info");
			break;
		default:
			LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Public object parse error");
		}
	}

	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}

Project: OpenSC
File: pkcs15-oberthur.c

sc_oberthur_get_certificate_authority(struct sc_pkcs15_der *der, int *out_authority)
{
#ifdef ENABLE_OPENSSL
	X509	*x;
	BUF_MEM buf_mem;
	BIO *bio = NULL;
	BASIC_CONSTRAINTS *bs = NULL;

	if (!der)
		return SC_ERROR_INVALID_ARGUMENTS;

	buf_mem.data = malloc(der->len);
	if (!buf_mem.data)
		return SC_ERROR_OUT_OF_MEMORY;

	memcpy(buf_mem.data, der->value, der->len);
	buf_mem.max = buf_mem.length = der->len;

	bio = BIO_new(BIO_s_mem());
	if (!bio) {
		free(buf_mem.data);
		return SC_ERROR_OUT_OF_MEMORY;
	}

	BIO_set_mem_buf(bio, &buf_mem, BIO_NOCLOSE);
	x = d2i_X509_bio(bio, 0);
	BIO_free(bio);
	if (!x)
		return SC_ERROR_INVALID_DATA;

	bs = (BASIC_CONSTRAINTS *)X509_get_ext_d2i(x, NID_basic_constraints, NULL, NULL);
	if (out_authority)
		*out_authority = (bs && bs->ca);

	X509_free(x);

	return SC_SUCCESS;
#else
	return SC_ERROR_NOT_SUPPORTED;
#endif
}

Project: OpenSC
File: pkcs15-oberthur.c

sc_pkcs15emu_oberthur_add_data(struct sc_pkcs15_card *p15card,
		unsigned int file_id, unsigned int size, int private)
{
	struct sc_context *ctx = p15card->card->ctx;
	struct sc_pkcs15_data_info dinfo;
	struct sc_pkcs15_object dobj;
	unsigned flags;
	unsigned char *info_blob = NULL, *label = NULL, *app = NULL, *oid = NULL;
	size_t info_len, label_len, app_len, oid_len, offs;
	char ch_tmp[0x100];
	int rv;

	SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
	sc_log(ctx, "Add data(file-id:%04X,size:%i,is-private:%i)", file_id, size, private);
	memset(&dinfo, 0, sizeof(dinfo));
	memset(&dobj, 0, sizeof(dobj));

	snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", private ? AWP_OBJECTS_DF_PRV : AWP_OBJECTS_DF_PUB, file_id | 0x100);

	rv = sc_oberthur_read_file(p15card, ch_tmp, &info_blob, &info_len, 1);
	LOG_TEST_RET(ctx, rv, "Failed to add data: read oberthur file error");

	if (info_len < 2)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add certificate: no 'tag'");
	flags = *(info_blob + 0) * 0x100 + *(info_blob + 1);
	offs = 2;

	/* Label */
	if (offs > info_len)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add data: no 'label'");
	label = info_blob + offs + 2;
	label_len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100;
	if (label_len > sizeof(dobj.label) - 1)
		label_len = sizeof(dobj.label) - 1;
	offs += 2 + *(info_blob + offs + 1);

	/* Application */
	if (offs > info_len)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add data: no 'application'");
	app = info_blob + offs + 2;
	app_len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100;
	if (app_len > sizeof(dinfo.app_label) - 1)
		app_len = sizeof(dinfo.app_label) - 1;
	offs += 2 + app_len;

	/* OID encode like DER(ASN.1(oid)) */
	if (offs > info_len)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add data: no 'OID'");
	oid_len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100;
	if (oid_len)   {
		oid = info_blob + offs + 2;
		if (*oid != 0x06 || (*(oid + 1) != oid_len - 2))
			LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add data: invalid 'OID' format");
		oid += 2;
		oid_len -= 2;
	}

	snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", private ? AWP_OBJECTS_DF_PRV : AWP_OBJECTS_DF_PUB, file_id);

	sc_format_path(ch_tmp, &dinfo.path);

	memcpy(dobj.label, label, label_len);
	memcpy(dinfo.app_label, app, app_len);
	if (oid_len)
		sc_asn1_decode_object_id(oid, oid_len, &dinfo.app_oid);

	if (flags & OBERTHUR_ATTR_MODIFIABLE)
		dobj.flags |= SC_PKCS15_CO_FLAG_MODIFIABLE;

	if (private)   {
		dobj.auth_id.len = sizeof(PinDomainID) > sizeof(dobj.auth_id.value)
				? sizeof(dobj.auth_id.value) : sizeof(PinDomainID);
		memcpy(dobj.auth_id.value, PinDomainID, dobj.auth_id.len);

		dobj.flags |= SC_PKCS15_CO_FLAG_PRIVATE;
	}

	rv = sc_pkcs15emu_add_data_object(p15card, &dobj, &dinfo);

	LOG_FUNC_RETURN(p15card->card->ctx, rv);
}

Project: OpenSC
File: pkcs15-oberthur.c

sc_oberthur_read_file(struct sc_pkcs15_card *p15card, const char *in_path,
		unsigned char **out, size_t *out_len,
		int verify_pin)
{
	struct sc_context *ctx = p15card->card->ctx;
	struct sc_card *card = p15card->card;
	struct sc_file *file = NULL;
	struct sc_path path;
	size_t sz;
	int rv;

	LOG_FUNC_CALLED(ctx);
	if (!in_path || !out || !out_len)
		LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Cannot read oberthur file");

	sc_log(ctx, "read file '%s'; verify_pin:%i", in_path, verify_pin);

	*out = NULL;
	*out_len = 0;

	sc_format_path(in_path, &path);
	rv = sc_select_file(card, &path, &file);
	if (rv != SC_SUCCESS) {
		sc_file_free(file);
		LOG_TEST_RET(ctx, rv, "Cannot select oberthur file to read");
	}

	if (file->ef_structure == SC_FILE_EF_TRANSPARENT)
		sz = file->size;
	else
		sz = (file->record_length + 2) * file->record_count;

	*out = calloc(sz, 1);
	if (*out == NULL) {
		sc_file_free(file);
		LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot read oberthur file");
	}

	if (file->ef_structure == SC_FILE_EF_TRANSPARENT)   {
		rv = sc_read_binary(card, 0, *out, sz, 0);
	}
	else	{
		size_t rec;
		size_t offs = 0;
		size_t rec_len = file->record_length;

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

			rec_len = rv;

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

			offs += rv + 2;
		}

		sz = offs;
	}

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

		if (acl == NULL) {
			sc_file_free(file);
			free(*out);
			*out = NULL;
			LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
		}

		nobjs = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_AUTH_PIN, objs, 0x10);
		if (nobjs < 1) {
			sc_file_free(file);
			free(*out);
			*out = NULL;
			LOG_TEST_RET(ctx, SC_ERROR_DATA_OBJECT_NOT_FOUND,
				"Cannot read oberthur file: get AUTH objects error");
		}

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

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

	sc_file_free(file);

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

	*out_len = sz;

	LOG_FUNC_RETURN(ctx, rv);
}

Project: OpenSC
File: pkcs15-oberthur.c

sc_oberthur_decode_usage(unsigned flags)
{
	unsigned ret = 0;

	if (flags & OBERTHUR_ATTR_ENCRYPT)
		ret |= SC_PKCS15_PRKEY_USAGE_ENCRYPT;
	if (flags & OBERTHUR_ATTR_DECRYPT)
		ret |= SC_PKCS15_PRKEY_USAGE_DECRYPT;
	if (flags & OBERTHUR_ATTR_SIGN)
		ret |= SC_PKCS15_PRKEY_USAGE_SIGN;
	if (flags & OBERTHUR_ATTR_RSIGN)
		ret |= SC_PKCS15_PRKEY_USAGE_SIGNRECOVER;
	if (flags & OBERTHUR_ATTR_WRAP)
		ret |= SC_PKCS15_PRKEY_USAGE_WRAP;
	if (flags & OBERTHUR_ATTR_UNWRAP)
		ret |= SC_PKCS15_PRKEY_USAGE_UNWRAP;
	if (flags & OBERTHUR_ATTR_VERIFY)
		ret |= SC_PKCS15_PRKEY_USAGE_VERIFY;
	if (flags & OBERTHUR_ATTR_RVERIFY)
		ret |= SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER;
	if (flags & OBERTHUR_ATTR_DERIVE)
		ret |= SC_PKCS15_PRKEY_USAGE_DERIVE;
	return ret;
}

Project: OpenSC
File: pkcs15-oberthur.c

sc_pkcs15emu_oberthur_add_pubkey(struct sc_pkcs15_card *p15card,
		unsigned int file_id, unsigned int size)
{
	struct sc_context *ctx = p15card->card->ctx;
	struct sc_pkcs15_pubkey_info key_info;
	struct sc_pkcs15_object key_obj;
	char ch_tmp[0x100];
	unsigned char *info_blob;
	size_t len, info_len, offs;
	unsigned flags;
	int rv;

	LOG_FUNC_CALLED(ctx);
	sc_log(ctx, "public key(file-id:%04X,size:%X)", file_id, size);

	memset(&key_info, 0, sizeof(key_info));
	memset(&key_obj, 0, sizeof(key_obj));

	snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PUB, file_id | 0x100);
	rv = sc_oberthur_read_file(p15card, ch_tmp, &info_blob, &info_len, 1);
	LOG_TEST_RET(ctx, rv, "Failed to add public key: read oberthur file error");

	/* Flags */
	offs = 2;
	if (offs > info_len)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add public key: no 'tag'");
	flags = *(info_blob + 0) * 0x100 + *(info_blob + 1);
	key_info.usage = sc_oberthur_decode_usage(flags);
	if (flags & OBERTHUR_ATTR_MODIFIABLE)
		key_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE;
	sc_log(ctx, "Public key key-usage:%04X", key_info.usage);

	/* Label */
	if (offs + 2 > info_len)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add public key: no 'Label'");
	len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100;
	if (len)   {
		if (len > sizeof(key_obj.label) - 1)
			len = sizeof(key_obj.label) - 1;
		memcpy(key_obj.label, info_blob + offs + 2, len);
	}
	offs += 2 + len;

	/* ID */
	if (offs > info_len)
		LOG_TEST_RET(ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED, "Failed to add public key: no 'ID'");
	len = *(info_blob + offs + 1) + *(info_blob + offs) * 0x100;
	if (!len || len > sizeof(key_info.id.value))
		LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Failed to add public key: invalid 'ID' length");
	memcpy(key_info.id.value, info_blob + offs + 2, len);
	key_info.id.len = len;

	/* Ignore Start/End dates */

	snprintf(ch_tmp, sizeof(ch_tmp), "%s%04X", AWP_OBJECTS_DF_PUB, file_id);
	sc_format_path(ch_tmp, &key_info.path);

	key_info.native = 1;
	key_info.key_reference = file_id & 0xFF;
	key_info.modulus_length = size;

	rv = sc_pkcs15emu_add_rsa_pubkey(p15card, &key_obj, &key_info);

	LOG_FUNC_RETURN(ctx, rv);
}

Project: OpenSC
File: pkcs15-oberthur.c

sc_oberthur_get_friends (unsigned int id, struct crypto_container *ccont)
{
	struct container *cont;

	for (cont = Containers; cont; cont = cont->next)   {
		if (cont->exchange.id_pub == id || cont->exchange.id_prv == id || cont->exchange.id_cert == id)   {
			if (ccont)
				memcpy(ccont, &cont->exchange, sizeof(struct crypto_container));
			break;
		}

		if (cont->sign.id_pub == id || cont->sign.id_prv == id || cont->sign.id_cert == id)   {
			if (ccont)
				memcpy(ccont, &cont->sign, sizeof(struct crypto_container));
			break;
		}
	}

	return cont ? 0 : SC_ERROR_TEMPLATE_NOT_FOUND;
}

Project: OpenSC
File: pkcs15-oberthur.c

sc_pkcs15emu_oberthur_init_ex(struct sc_pkcs15_card * p15card, struct sc_aid *aid)
{
	int rv;

	LOG_FUNC_CALLED(p15card->card->ctx);
	rv = oberthur_detect_card(p15card);
	if (!rv)
		rv = sc_pkcs15emu_oberthur_init(p15card);

	LOG_FUNC_RETURN(p15card->card->ctx, rv);
}

Project: OpenSC
File: pkcs15-oberthur.c

sc_awp_clear(struct sc_pkcs15_card *p15card)
{
	LOG_FUNC_CALLED(p15card->card->ctx);
}

Project: OpenSC
File: pkcs15-oberthur.c

sc_oberthur_parse_tokeninfo (struct sc_pkcs15_card *p15card,
		unsigned char *buff, size_t len, int postpone_allowed)
{
	struct sc_context *ctx = p15card->card->ctx;
	char label[0x21];
	unsigned flags;
	int ii;

	LOG_FUNC_CALLED(ctx);
	if (!buff || len < 0x24)
		LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Cannot parse token info");

	memset(label, 0, sizeof(label));

	memcpy(label, buff, 0x20);
	ii = 0x20;
	while (*(label + --ii)==' ' && ii)
		;
	*(label + ii + 1) = '\0';

	flags = *(buff + 0x22) * 0x100 + *(buff + 0x23);

	set_string(&p15card->tokeninfo->label, label);
	set_string(&p15card->tokeninfo->manufacturer_id, "Oberthur/OpenSC");

	if (flags & 0x01)
		p15card->tokeninfo->flags |= SC_PKCS15_TOKEN_PRN_GENERATION;

	sc_log(ctx, "label %s", p15card->tokeninfo->label);
	sc_log(ctx, "manufacturer_id %s", p15card->tokeninfo->manufacturer_id);

	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}

Project: OpenSC
File: pkcs15-oberthur.c

sc_pkcs15emu_oberthur_init(struct sc_pkcs15_card * p15card)
{
	struct sc_context *ctx = p15card->card->ctx;
	struct sc_pkcs15_auth_info auth_info;
	struct sc_pkcs15_object   obj;
	struct sc_card *card = p15card->card;
	struct sc_path path;
	int rv, ii, tries_left;
	char serial[0x10];
	unsigned char sopin_reference = 0x04;

	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
	sc_bin_to_hex(card->serialnr.value, card->serialnr.len, serial, sizeof(serial), 0);
	set_string(&p15card->tokeninfo->serial_number, serial);

	p15card->ops.parse_df = sc_awp_parse_df;
	p15card->ops.clear = sc_awp_clear;

	sc_log(ctx, "Oberthur init: serial %s", p15card->tokeninfo->serial_number);

	sc_format_path(AWP_PIN_DF, &path);
	rv = sc_select_file(card, &path, NULL);
	LOG_TEST_RET(ctx, rv, "Oberthur init failed: cannot select PIN dir");

	tries_left = -1;
	rv = sc_verify(card, SC_AC_CHV, sopin_reference, (unsigned char *)"", 0, &tries_left);
	if (rv && rv != SC_ERROR_PIN_CODE_INCORRECT)   {
		sopin_reference = 0x84;
		rv = sc_verify(card, SC_AC_CHV, sopin_reference, (unsigned char *)"", 0, &tries_left);
	}
	if (rv && rv != SC_ERROR_PIN_CODE_INCORRECT)
		LOG_TEST_RET(ctx, rv, "Invalid state of SO-PIN");

	/* add PIN */
	memset(&auth_info, 0, sizeof(auth_info));
	memset(&obj,  0, sizeof(obj));

	auth_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
	auth_info.auth_method	= SC_AC_CHV;
	auth_info.auth_id.len = 1;
	auth_info.auth_id.value[0] = 0xFF;
	auth_info.attrs.pin.min_length		= 4;
	auth_info.attrs.pin.max_length		= 64;
	auth_info.attrs.pin.stored_length	= 64;
	auth_info.attrs.pin.type		= SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
	auth_info.attrs.pin.reference		= sopin_reference;
	auth_info.attrs.pin.pad_char		= 0xFF;
	auth_info.attrs.pin.flags		= SC_PKCS15_PIN_FLAG_CASE_SENSITIVE
				| SC_PKCS15_PIN_FLAG_INITIALIZED
				| SC_PKCS15_PIN_FLAG_NEEDS_PADDING
				| SC_PKCS15_PIN_FLAG_SO_PIN;
	auth_info.tries_left		= tries_left;
	auth_info.logged_in = SC_PIN_STATE_UNKNOWN;

	strncpy(obj.label, "SO PIN", SC_PKCS15_MAX_LABEL_SIZE-1);
	obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE;

	sc_log(ctx, "Add PIN(%s,auth_id:%s,reference:%i)", obj.label,
			sc_pkcs15_print_id(&auth_info.auth_id), auth_info.attrs.pin.reference);
	rv = sc_pkcs15emu_add_pin_obj(p15card, &obj, &auth_info);
	LOG_TEST_RET(ctx, rv, "Oberthur init failed: cannot add PIN object");

	tries_left = -1;
	rv = sc_verify(card, SC_AC_CHV, 0x81, (unsigned char *)"", 0, &tries_left);
	if (rv == SC_ERROR_PIN_CODE_INCORRECT)   {
		/* add PIN */
		memset(&auth_info, 0, sizeof(auth_info));
		memset(&obj,  0, sizeof(obj));

		auth_info.auth_id.len = sizeof(PinDomainID) > sizeof(auth_info.auth_id.value)
				? sizeof(auth_info.auth_id.value) : sizeof(PinDomainID);
		memcpy(auth_info.auth_id.value, PinDomainID, auth_info.auth_id.len);
		auth_info.auth_method	= SC_AC_CHV;

		auth_info.attrs.pin.min_length		= 4;
		auth_info.attrs.pin.max_length		= 64;
		auth_info.attrs.pin.stored_length	= 64;
		auth_info.attrs.pin.type		= SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
		auth_info.attrs.pin.reference		= 0x81;
		auth_info.attrs.pin.pad_char		= 0xFF;
		auth_info.attrs.pin.flags		= SC_PKCS15_PIN_FLAG_CASE_SENSITIVE
					| SC_PKCS15_PIN_FLAG_INITIALIZED
					| SC_PKCS15_PIN_FLAG_NEEDS_PADDING
					| SC_PKCS15_PIN_FLAG_LOCAL;
		auth_info.tries_left		= tries_left;

		strncpy(obj.label, PIN_DOMAIN_LABEL, SC_PKCS15_MAX_LABEL_SIZE-1);
		obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE;
		if (sopin_reference == 0x84) {
			/*
			 * auth_pin_reset_oberthur_style() in card-oberthur.c
			 * always uses PUK with reference 0x84 for
			 * unblocking of User PIN
			 */
			obj.auth_id.len = 1;
			obj.auth_id.value[0] = 0xFF;
		}

		sc_format_path(AWP_PIN_DF, &auth_info.path);
		auth_info.path.type = SC_PATH_TYPE_PATH;

		sc_log(ctx, "Add PIN(%s,auth_id:%s,reference:%i)", obj.label,
				sc_pkcs15_print_id(&auth_info.auth_id), auth_info.attrs.pin.reference);
		rv = sc_pkcs15emu_add_pin_obj(p15card, &obj, &auth_info);
		LOG_TEST_RET(ctx, rv, "Oberthur init failed: cannot add PIN object");
	}
	else if (rv != SC_ERROR_DATA_OBJECT_NOT_FOUND)    {
		LOG_TEST_RET(ctx, rv, "Oberthur init failed: cannot verify PIN");
	}

	for (ii=0; oberthur_infos[ii].name; ii++)   {
		sc_log(ctx, "Oberthur init: read %s file", oberthur_infos[ii].name);
		free(oberthur_infos[ii].content);
		rv = sc_oberthur_read_file(p15card, oberthur_infos[ii].path,
				&oberthur_infos[ii].content, &oberthur_infos[ii].len, 1);
		LOG_TEST_RET(ctx, rv, "Oberthur init failed: read oberthur file error");

		sc_log(ctx,
		       "Oberthur init: parse %s file, content length %"SC_FORMAT_LEN_SIZE_T"u",
		       oberthur_infos[ii].name, oberthur_infos[ii].len);
		rv = oberthur_infos[ii].parser(p15card, oberthur_infos[ii].content, oberthur_infos[ii].len,
				oberthur_infos[ii].postpone_allowed);
		LOG_TEST_RET(ctx, rv, "Oberthur init failed: parse error");
	}

	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}