Example #1
0
int
sc_pkcs15_read_data_object(struct sc_pkcs15_card *p15card,
		const struct sc_pkcs15_data_info *info,
		struct sc_pkcs15_data **data_object_out)
{
        struct sc_context *ctx = p15card->card->ctx;
	struct sc_pkcs15_data *data_object;
	struct sc_pkcs15_der der;
	int r;

	LOG_FUNC_CALLED(ctx);
	if (!info || !data_object_out)
		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);

	if (!info->data.value)   {
		r = sc_pkcs15_read_file(p15card, &info->path, &info->data.value, &info->data.len);
		LOG_TEST_RET(ctx, r, "Cannot get DATA object data");
	}

	sc_der_copy(&der, &info->data);
	data_object = calloc(sizeof(struct sc_pkcs15_data), 1);
	if (!data_object && !der.value)
		LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate memory for data object");

	data_object->data = der.value;
	data_object->data_len = der.len;
	*data_object_out = data_object;

	LOG_FUNC_RETURN(ctx,SC_SUCCESS);
}
Example #2
0
LIBOPENSC_API int sc_pkcs15_read_data_object(struct sc_pkcs15_card *p15card,
			       const struct sc_pkcs15_data_info *info,
			       struct sc_pkcs15_data **data_object_out)
{
	int r;
	struct sc_pkcs15_data *data_object;
	u8 *data = NULL;
	size_t len;

	if (p15card == NULL || info == NULL || data_object_out == NULL)
		return SC_ERROR_INVALID_ARGUMENTS;
	SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE);

	r = sc_pkcs15_read_file(p15card, &info->path, &data, &len);
	if (r)
		return r;
	data_object = malloc(sizeof(struct sc_pkcs15_data));
	if (data_object == NULL) {
		free(data);
		return SC_ERROR_OUT_OF_MEMORY;
	}
	memset(data_object, 0, sizeof(struct sc_pkcs15_data));

	data_object->data = data;
	data_object->data_len = len;
	*data_object_out = data_object;
	return SC_SUCCESS;
}
static int dump_unusedspace(void)
{
	u8 *buf = NULL;
	size_t buf_len;
	sc_path_t path;
	sc_pkcs15_unusedspace_t *us;
	int r;

	if (p15card->file_unusedspace != NULL)
		path = p15card->file_unusedspace->path;
	else {
		path = p15card->file_app->path;
		sc_append_path_id(&path, (const u8 *) "\x50\x33", 2);
	}
	path.count = -1;

	sc_ctx_suppress_errors_on(p15card->card->ctx);
	r = sc_pkcs15_read_file(p15card, &path, &buf, &buf_len, NULL);
	sc_ctx_suppress_errors_off(p15card->card->ctx);
	if (r < 0) {
		if (r == SC_ERROR_FILE_NOT_FOUND) {
			printf("\nNo EF(UnusedSpace) file\n");
			r = 0;
		}
		else
			printf("\nError reading file \"%s\": %s\n",
				sc_print_path(&path), sc_strerror(r));
		goto err;
	}

	r = sc_pkcs15_parse_unusedspace(buf, buf_len, p15card);
	if (r != 0) {
		printf("\nError parsing EF(UnusedSpace): %s\n", sc_strerror(r));
		goto err;
	}

	if (p15card->unusedspace_list == NULL)
		printf("\nEF(UnusedSpace) file is empty\n");
	else {
		printf("\nContents of EF(UnusedSpace):\n");
		for (us = p15card->unusedspace_list; us != NULL; us = us->next)
		printf("  - path=%s, index=%d, length=%d  -- auth_id = %s\n",
			sc_print_path(&us->path), us->path.index, us->path.count,
			us->auth_id.len == 0 ? "<empty>" : sc_pkcs15_print_id(&us->auth_id));
	}

err:
	if (buf != NULL)
		free(buf);
	return r;
}
Example #4
0
int
sc_pkcs15_read_certificate(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_cert_info *info,
                           struct sc_pkcs15_cert **cert_out)
{
    struct sc_context *ctx = NULL;
    struct sc_pkcs15_cert *cert = NULL;
    struct sc_pkcs15_der der;
    int r;

    assert(p15card != NULL && info != NULL && cert_out != NULL);
    ctx = p15card->card->ctx;
    LOG_FUNC_CALLED(ctx);

    if (info->value.len && info->value.value)   {
        sc_der_copy(&der, &info->value);
    }
    else if (info->path.len) {
        r = sc_pkcs15_read_file(p15card, &info->path, &der.value, &der.len);
        LOG_TEST_RET(ctx, r, "Unable to read certificate file.");
    }
    else   {
        LOG_FUNC_RETURN(ctx, SC_ERROR_OBJECT_NOT_FOUND);
    }

    cert = malloc(sizeof(struct sc_pkcs15_cert));
    if (cert == NULL) {
        free(der.value);
        LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
    }
    memset(cert, 0, sizeof(struct sc_pkcs15_cert));
    if (parse_x509_cert(ctx, &der, cert)) {
        free(der.value);
        sc_pkcs15_free_certificate(cert);
        LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ASN1_OBJECT);
    }
    free(der.value);

    *cert_out = cert;
    LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
Example #5
0
int
sc_pkcs15_read_certificate(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_cert_info *info,
		struct sc_pkcs15_cert **cert_out)
{
	struct sc_pkcs15_cert *cert;
	struct sc_pkcs15_der der;
	int r;

	assert(p15card != NULL && info != NULL && cert_out != NULL);
	LOG_FUNC_CALLED(p15card->card->ctx);

	if (info->value.len && info->value.value)   {
		sc_der_copy(&der, &info->value);
	}
	else if (info->path.len) {
		r = sc_pkcs15_read_file(p15card, &info->path, &der.value, &der.len);
		if (r)
			return r;
	}
	else   {
		return SC_ERROR_OBJECT_NOT_FOUND;
	}


	cert = malloc(sizeof(struct sc_pkcs15_cert));
	if (cert == NULL) {
		free(der.value);
		return SC_ERROR_OUT_OF_MEMORY;
	}
	memset(cert, 0, sizeof(struct sc_pkcs15_cert));
	if (parse_x509_cert(p15card->card->ctx, der.value, der.len, cert)) {
		free(der.value);
		sc_pkcs15_free_certificate(cert);
		return SC_ERROR_INVALID_ASN1_OBJECT;
	}

	cert->data = der;
	*cert_out = cert;
	return SC_SUCCESS;
}
Example #6
0
int sc_pkcs15_read_certificate(struct sc_pkcs15_card *p15card,
                               const struct sc_pkcs15_cert_info *info,
                               struct sc_pkcs15_cert **cert_out)
{
    int r;
    struct sc_pkcs15_cert *cert;
    u8 *data = NULL;
    size_t len;

    assert(p15card != NULL && info != NULL && cert_out != NULL);
    SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE);

    if (info->path.len) {
        r = sc_pkcs15_read_file(p15card, &info->path, &data, &len, NULL);
        if (r)
            return r;
    } else {
        sc_pkcs15_der_t copy;

        sc_der_copy(&copy, &info->value);
        data = copy.value;
        len = copy.len;
    }

    cert = malloc(sizeof(struct sc_pkcs15_cert));
    if (cert == NULL) {
        free(data);
        return SC_ERROR_OUT_OF_MEMORY;
    }
    memset(cert, 0, sizeof(struct sc_pkcs15_cert));
    if (parse_x509_cert(p15card->card->ctx, data, len, cert)) {
        free(data);
        sc_pkcs15_free_certificate(cert);
        return SC_ERROR_INVALID_ASN1_OBJECT;
    }
    cert->data = data;
    *cert_out = cert;
    return 0;
}
Example #7
0
/*
 * Read public key.
 */
int
sc_pkcs15_read_pubkey(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_object *obj,
		struct sc_pkcs15_pubkey **out)
{
	struct sc_context *ctx = p15card->card->ctx;
	const struct sc_pkcs15_pubkey_info *info = NULL;
	struct sc_pkcs15_pubkey *pubkey = NULL;
	unsigned char *data = NULL;
	size_t	len;
	int	algorithm, r;

	assert(p15card != NULL && obj != NULL && out != NULL);
	LOG_FUNC_CALLED(ctx);

	switch (obj->type) {
	case SC_PKCS15_TYPE_PUBKEY_RSA:
		algorithm = SC_ALGORITHM_RSA;
		break;
	case SC_PKCS15_TYPE_PUBKEY_DSA:
		algorithm = SC_ALGORITHM_DSA;
		break;
	case SC_PKCS15_TYPE_PUBKEY_GOSTR3410:
		algorithm = SC_ALGORITHM_GOSTR3410;
		break;
	case SC_PKCS15_TYPE_PUBKEY_EC:
		algorithm = SC_ALGORITHM_EC;
		break;
	default:
		LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported public key type.");
	}
	info = (const struct sc_pkcs15_pubkey_info *) obj->data;

	sc_log(ctx, "Content (%p, %i)", obj->content.value, obj->content.len);
	if (obj->content.value && obj->content.len)   {
		/* public key data is present as 'direct' value of pkcs#15 object */
		data = calloc(1, obj->content.len);
		if (!data)
			LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
		memcpy(data, obj->content.value, obj->content.len);
		len = obj->content.len;
	}
	else if (p15card->card->ops->read_public_key)   {
		r = p15card->card->ops->read_public_key(p15card->card, algorithm,
				&info->path, info->key_reference, info->modulus_length,
				&data, &len);
		LOG_TEST_RET(ctx, r, "Card specific 'read-public' procedure failed.");
	}
	else if (info->path.len)   {
		r = sc_pkcs15_read_file(p15card, &info->path, &data, &len);
		LOG_TEST_RET(ctx, r, "Failed to read public key file.");
	}
	else    {
		LOG_TEST_RET(ctx, SC_ERROR_NOT_IMPLEMENTED, "No way to get public key");
	}

	if (!data || !len)
		LOG_FUNC_RETURN(ctx, SC_ERROR_OBJECT_NOT_VALID);

	pubkey = calloc(1, sizeof(struct sc_pkcs15_pubkey));
	if (pubkey == NULL) {
		free(data);
		LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
	}
	pubkey->algorithm = algorithm;
	pubkey->data.value = data;
	pubkey->data.len = len;
	if (sc_pkcs15_decode_pubkey(ctx, pubkey, data, len)) {
		free(data);
		free(pubkey);
		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ASN1_OBJECT);
	}

	*out = pubkey;
	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
}
/*
 * Read public key.
 */
int
sc_pkcs15_read_pubkey(struct sc_pkcs15_card *p15card,
			const struct sc_pkcs15_object *obj,
			struct sc_pkcs15_pubkey **out)
{
	struct sc_context *ctx = p15card->card->ctx;
	const struct sc_pkcs15_pubkey_info *info;
	struct sc_pkcs15_pubkey *pubkey;
	u8	*data;
	size_t	len;
	int	algorithm, r;

	assert(p15card != NULL && obj != NULL && out != NULL);
	SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL);

	switch (obj->type) {
	case SC_PKCS15_TYPE_PUBKEY_RSA:
		algorithm = SC_ALGORITHM_RSA;
		break;
	case SC_PKCS15_TYPE_PUBKEY_DSA:
		algorithm = SC_ALGORITHM_DSA;
		break;
	case SC_PKCS15_TYPE_PUBKEY_GOSTR3410:
		algorithm = SC_ALGORITHM_GOSTR3410;
		break;
	case SC_PKCS15_TYPE_PUBKEY_EC:
		algorithm = SC_ALGORITHM_EC;
		break;
	default:
		SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_NOT_SUPPORTED, "Unsupported public key type.");
	}
	info = (const struct sc_pkcs15_pubkey_info *) obj->data;

	if (obj->content.value && obj->content.len)   {
		/* public key data is present as 'direct' value of pkcs#15 object */
		data = calloc(1, obj->content.len);
		if (!data)
			SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
		memcpy(data, obj->content.value, obj->content.len);
		len = obj->content.len;
	}
        else   {
		r = sc_pkcs15_read_file(p15card, &info->path, &data, &len);
		SC_TEST_RET(ctx, SC_LOG_DEBUG_NORMAL, r, "Failed to read public key file.");
	}

	pubkey = calloc(1, sizeof(struct sc_pkcs15_pubkey));
	if (pubkey == NULL) {
		free(data);
		SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_OUT_OF_MEMORY);
	}
	pubkey->algorithm = algorithm;
	pubkey->data.value = data;
	pubkey->data.len = len;
	if (sc_pkcs15_decode_pubkey(ctx, pubkey, data, len)) {
		free(data);
		free(pubkey);
		SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_INVALID_ASN1_OBJECT);
	}

	*out = pubkey;
	SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_SUCCESS);
}
int sc_pkcs15_parse_df(struct sc_pkcs15_card *p15card,
		       struct sc_pkcs15_df *df)
{
	sc_context_t *ctx = p15card->card->ctx;
	u8 *buf;
	const u8 *p;
	size_t bufsize;
	int r;
	struct sc_pkcs15_object *obj = NULL;
	int (* func)(struct sc_pkcs15_card *, struct sc_pkcs15_object *,
		     const u8 **nbuf, size_t *nbufsize) = NULL;

	switch (df->type) {
	case SC_PKCS15_PRKDF:
		func = sc_pkcs15_decode_prkdf_entry;
		break;
	case SC_PKCS15_PUKDF:
		func = sc_pkcs15_decode_pukdf_entry;
		break;
	case SC_PKCS15_CDF:
	case SC_PKCS15_CDF_TRUSTED:
	case SC_PKCS15_CDF_USEFUL:
		func = sc_pkcs15_decode_cdf_entry;
		break;
	case SC_PKCS15_DODF:
		func = sc_pkcs15_decode_dodf_entry;
		break;
	case SC_PKCS15_AODF:
		func = sc_pkcs15_decode_aodf_entry;
		break;
	}
	if (func == NULL) {
		sc_error(ctx, "unknown DF type: %d\n", df->type);
		return SC_ERROR_INVALID_ARGUMENTS;
	}
	if (df->file != NULL)
		r = sc_pkcs15_read_file(p15card, &df->path,
					&buf, &bufsize, NULL);
	else
		r = sc_pkcs15_read_file(p15card, &df->path,
					&buf, &bufsize, &df->file);
	if (r < 0)
		return r;

	p = buf;
	while (bufsize && *p != 0x00) {
		const u8 *oldp;
		size_t obj_len;
		
		obj = (struct sc_pkcs15_object *) calloc(1, sizeof(struct sc_pkcs15_object));
		if (obj == NULL) {
			r = SC_ERROR_OUT_OF_MEMORY;
			goto ret;
		}
		oldp = p;
		r = func(p15card, obj, &p, &bufsize);
		if (r) {
			free(obj);
			if (r == SC_ERROR_ASN1_END_OF_CONTENTS) {
				r = 0;
				break;
			}
			sc_perror(ctx, r, "Error decoding DF entry");
			goto ret;
		}
		obj_len = p - oldp;

		obj->der.value = (u8 *) malloc(obj_len);
		if (obj->der.value == NULL) {
			r = SC_ERROR_OUT_OF_MEMORY;
			goto ret;
		}
		memcpy(obj->der.value, oldp, obj_len);
		obj->der.len = obj_len;

		obj->df = df;
		r = sc_pkcs15_add_object(p15card, obj);
		if (r) {
			if (obj->data)
				free(obj->data);
			free(obj);
			sc_perror(ctx, r, "Error adding object");
			goto ret;
		}
	};
ret:
	free(buf);
	return r;
}
int
sc_pkcs15_read_prkey(struct sc_pkcs15_card *p15card,
		const struct sc_pkcs15_object *obj,
		const char *passphrase,
		struct sc_pkcs15_prkey **out)
{
	sc_context_t *ctx = p15card->card->ctx;
	struct sc_pkcs15_prkey_info *info;
	struct sc_pkcs15_prkey key;
	sc_path_t path;
	u8 *data = NULL;
	size_t len;
	int r;

	memset(&key, 0, sizeof(key));
	switch (obj->type) {
	case SC_PKCS15_TYPE_PRKEY_RSA:
		key.algorithm = SC_ALGORITHM_RSA;
		break;
	case SC_PKCS15_TYPE_PRKEY_DSA:
		key.algorithm = SC_ALGORITHM_DSA;
		break;
	default:
		sc_error(ctx, "Unsupported object type.\n");
		return SC_ERROR_NOT_SUPPORTED;
	}
	info = (struct sc_pkcs15_prkey_info *) obj->data;
	if (info->native) {
		sc_error(ctx, "Private key is native, will not read.");
		return SC_ERROR_NOT_ALLOWED;
	}

	path = info->path;
	if (path.type == SC_PATH_TYPE_PATH_PROT)
		path.type = SC_PATH_TYPE_PATH;

	r = sc_pkcs15_read_file(p15card, &path, &data, &len, NULL);
	if (r < 0) {
		sc_error(ctx, "Unable to read private key file.\n");
		return r;
	}

	/* Is this a protected file? */
	if (info->path.type == SC_PATH_TYPE_PATH_PROT) {
		u8 *clear;
		size_t clear_len;

		if (passphrase == NULL) {
			r = SC_ERROR_PASSPHRASE_REQUIRED;
			goto fail;
		}
		r = sc_pkcs15_unwrap_data(ctx,
				passphrase,
				data, len,
				&clear, &clear_len);
		if (r < 0)  {
			sc_error(ctx, "Failed to unwrap privat key.");
			goto fail;
		}
		free(data);
		data = clear;
		len = clear_len;
	}

	r = sc_pkcs15_decode_prkey(ctx, &key, data, len);
	if (r < 0) {
		sc_error(ctx, "Unable to decode private key");
		goto fail;
	}

	*out = (struct sc_pkcs15_prkey *) malloc(sizeof(key));
	if (*out == NULL) {
		r = SC_ERROR_OUT_OF_MEMORY;
		goto fail;
	}

	**out = key;
	free(data);
	return 0;

fail:	if (data)
		free(data);
	return r;
}
Example #11
0
static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
{

	/* The cert objects will return all the data */
	/* Note: pkcs11 objects do not have CK_ID values */

	static const objdata objects[] = {
	{"1", "Card Capability Container", 
			"2.16.840.1.101.3.7.1.219.0", NULL, "DB00", 0},
	{"2", "Card Holder Unique Identifier",
			"2.16.840.1.101.3.7.2.48.0", NULL, "3000", 0},
	{"3", "Unsigned Card Holder Unique Identifier",
			"2.16.840.1.101.3.7.2.48.2", NULL, "3010", 0},
	{"4", "X.509 Certificate for PIV Authentication",
			"2.16.840.1.101.3.7.2.1.1", NULL, "0101", 0},
	{"5", "Cardholder Fingerprints",
			"2.16.840.1.101.3.7.2.96.16", "1", "6010", SC_PKCS15_CO_FLAG_PRIVATE},
	{"6", "Printed Information",
			"2.16.840.1.101.3.7.2.48.1", "1", "3001", SC_PKCS15_CO_FLAG_PRIVATE},
	{"7", "Cardholder Facial Image", 
			"2.16.840.1.101.3.7.2.96.48", "1", "6030", SC_PKCS15_CO_FLAG_PRIVATE},
	{"8", "X.509 Certificate for Digital Signature",
			"2.16.840.1.101.3.7.2.1.0",  NULL, "0100", 0},
	{"9", "X.509 Certificate for Key Management", 
			"2.16.840.1.101.3.7.2.1.2", NULL, "0102", 0},
	{"10","X.509 Certificate for Card Authentication",
			"2.16.840.1.101.3.7.2.5.0", NULL, "0500", 0},
	{"11", "Security Object",
			"2.16.840.1.101.3.7.2.144.0", NULL, "9000", 0},
	{"12", "Discovery Object",
			"2.16.840.1.101.3.7.2.96.80", NULL, "6050", 0},
	{"13", "Key History Object",
			"2.16.840.1.101.3.7.2.96.96", NULL, "6060", 0},
	{"14", "Cardholder Iris Image",
			"2.16.840.1.101.3.7.2.16.21", NULL, "1015", SC_PKCS15_CO_FLAG_PRIVATE},

	{"15", "Retired X.509 Certificate for Key Management 1", 
			"2.16.840.1.101.3.7.2.16.1", NULL, "1001", 0},
	{"16", "Retired X.509 Certificate for Key Management 2", 
			"2.16.840.1.101.3.7.2.16.2", NULL, "1002", 0},
	{"17", "Retired X.509 Certificate for Key Management 3", 
			"2.16.840.1.101.3.7.2.16.3", NULL, "1003", 0},
	{"18", "Retired X.509 Certificate for Key Management 4", 
			"2.16.840.1.101.3.7.2.16.4", NULL, "1004", 0},
	{"19", "Retired X.509 Certificate for Key Management 5", 
			"2.16.840.1.101.3.7.2.16.5", NULL, "1005", 0},
	{"20", "Retired X.509 Certificate for Key Management 6", 
			"2.16.840.1.101.3.7.2.16.6", NULL, "1006", 0},
	{"21", "Retired X.509 Certificate for Key Management 7", 
			"2.16.840.1.101.3.7.2.16.7", NULL, "1007", 0},
	{"22", "Retired X.509 Certificate for Key Management 8", 
			"2.16.840.1.101.3.7.2.16.8", NULL, "1008", 0},
	{"23", "Retired X.509 Certificate for Key Management 9", 
			"2.16.840.1.101.3.7.2.16.9", NULL, "1009", 0},
	{"24", "Retired X.509 Certificate for Key Management 10", 
			"2.16.840.1.101.3.7.2.16.10", NULL, "100A", 0},
	{"25", "Retired X.509 Certificate for Key Management 11", 
			"2.16.840.1.101.3.7.2.16.11", NULL, "100B", 0},
	{"26", "Retired X.509 Certificate for Key Management 12", 
			"2.16.840.1.101.3.7.2.16.12", NULL, "100C", 0},
	{"27", "Retired X.509 Certificate for Key Management 13", 
			"2.16.840.1.101.3.7.2.16.13", NULL, "100D", 0},
	{"28", "Retired X.509 Certificate for Key Management 14", 
			"2.16.840.1.101.3.7.2.16.14", NULL, "100E", 0},
	{"29", "Retired X.509 Certificate for Key Management 15", 
			"2.16.840.1.101.3.7.2.16.15", NULL, "100F", 0},
	{"30", "Retired X.509 Certificate for Key Management 16", 
			"2.16.840.1.101.3.7.2.16.16", NULL, "1010", 0},
	{"31", "Retired X.509 Certificate for Key Management 17", 
			"2.16.840.1.101.3.7.2.16.17", NULL, "1011", 0},
	{"32", "Retired X.509 Certificate for Key Management 18", 
			"2.16.840.1.101.3.7.2.16.18", NULL, "1012", 0},
	{"33", "Retired X.509 Certificate for Key Management 19", 
			"2.16.840.1.101.3.7.2.16.19", NULL, "1013", 0},
	{"34", "Retired X.509 Certificate for Key Management 20", 
			"2.16.840.1.101.3.7.2.16.20", NULL, "1014", 0},
	{NULL, NULL, NULL, NULL, NULL, 0}
};
	/* 
	 * NIST 800-73-1 lifted the restriction on 
	 * requering pin protected certs. Thus the default is to   
	 * not require this.
	 */
	/* certs will be pulled out from the cert objects */
	/* the number of cert, pubkey and prkey triplets */

#define PIV_NUM_CERTS_AND_KEYS 24

	static const cdata certs[PIV_NUM_CERTS_AND_KEYS] = {
		{"1", "Certificate for PIV Authentication", 0, "0101cece", 0},
		{"2", "Certificate for Digital Signature", 0, "0100cece", 0},
		{"3", "Certificate for Key Management", 0, "0102cece", 0},
		{"4", "Certificate for Card Authentication", 0, "0500cece", 0},
		{"5", "Retired Certificate for Key Management 1", 0, "1001cece", 0},
		{"6", "Retired Certificate for Key Management 2", 0, "1002cece", 0},
		{"7", "Retired Certificate for Key Management 3", 0, "1003cece", 0},
		{"8", "Retired Certificate for Key Management 4", 0, "1004cece", 0},
		{"9", "Retired Certificate for Key Management 5", 0, "1005cece", 0},
		{"10", "Retired Certificate for Key Management 6", 0, "1006cece", 0},
		{"11", "Retired Certificate for Key Management 7", 0, "1007cece", 0},
		{"12", "Retired Certificate for Key Management 8", 0, "1008cece", 0},
		{"13", "Retired Certificate for Key Management 9", 0, "1009cece", 0},
		{"14", "Retired Certificate for Key Management 10", 0, "100Acece", 0},
		{"15", "Retired Certificate for Key Management 11", 0, "100Bcece", 0},
		{"16", "Retired Certificate for Key Management 12", 0, "100Ccece", 0},
		{"17", "Retired Certificate for Key Management 13", 0, "100Dcece", 0},
		{"18", "Retired Certificate for Key Management 14", 0, "100Ecece", 0},
		{"19", "Retired Certificate for Key Management 15", 0, "100Fcece", 0},
		{"20", "Retired Certificate for Key Management 16", 0, "1010cece", 0},
		{"21", "Retired Certificate for Key Management 17", 0, "1011cece", 0},
		{"22", "Retired Certificate for Key Management 18", 0, "1012cece", 0},
		{"23", "Retired Certificate for Key Management 19", 0, "1013cece", 0},
		{"24", "Retired Certificate for Key Management 20", 0, "1014cece", 0}
	};

	static const pindata pins[] = {
		{ "1", "PIV Card Holder pin", "", 0x80,
		  /* label and ref will change if using global pin */
		  SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
		  8, 4, 8, 
		  SC_PKCS15_PIN_FLAG_NEEDS_PADDING |
		  SC_PKCS15_PIN_FLAG_LOCAL, 
		  -1, 0xFF,
		  SC_PKCS15_CO_FLAG_PRIVATE },
		{ "2", "PIV PUK", "", 0x81, 
		  SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
		  8, 4, 8, 
		  SC_PKCS15_PIN_FLAG_NEEDS_PADDING |
		  SC_PKCS15_PIN_FLAG_LOCAL | SC_PKCS15_PIN_FLAG_SO_PIN |
		  SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN, 
		  -1, 0xFF, 
		  SC_PKCS15_CO_FLAG_PRIVATE },
		{ NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0}
	};


	/*
	 * The size of the key or the algid is not really known
	 * but can be derived from the certificates. 
	 * the cert, pubkey and privkey are a set. 
	 * Key usages bits taken from pkcs15v1_1 Table 2
	 * RSA and EC hav differents set of usage 
	 */
	static const pubdata pubkeys[PIV_NUM_CERTS_AND_KEYS] = {

		{ "1", "PIV AUTH pubkey", 
			 	/*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT |
			 		SC_PKCS15_PRKEY_USAGE_WRAP |
					SC_PKCS15_PRKEY_USAGE_VERIFY |
					SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER,
				/*EC*/SC_PKCS15_PRKEY_USAGE_VERIFY,
			"9A06", 0x9A, "1", 0, "PIV_9A_KEY"},
		{ "2", "SIGN pubkey", 
				/*RSA*/SC_PKCS15_PRKEY_USAGE_ENCRYPT |
					SC_PKCS15_PRKEY_USAGE_VERIFY |
					SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER |
					SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
				/*EC*/SC_PKCS15_PRKEY_USAGE_VERIFY |
					SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
			"9C06", 0x9C, "1", 0, "PIV_9C_KEY"},
		{ "3", "KEY MAN pubkey", 
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"9D06", 0x9D, "1", 0, "PIV_9D_KEY"},
		{ "4", "CARD AUTH pubkey", 
				/*RSA*/SC_PKCS15_PRKEY_USAGE_VERIFY |
					SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER, 
				/*EC*/SC_PKCS15_PRKEY_USAGE_VERIFY,
			"9E06", 0x9E, "0", 0, "PIV_9E_KEY"},  /* no pin, and avail in contactless */

		{ "5", "Retired KEY MAN 1",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8206", 0x82, "1", 0, NULL},
		{ "6", "Retired KEY MAN 2",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8306", 0x83, "1", 0, NULL},
		{ "7", "Retired KEY MAN 3",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8406", 0x84, "1", 0, NULL},
		{ "8", "Retired KEY MAN 4",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8506", 0x85, "1", 0, NULL},
		{ "9", "Retired KEY MAN 5",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8606", 0x86, "1", 0, NULL},
		{ "10", "Retired KEY MAN 6",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8706", 0x87, "1", 0, NULL},
		{ "11", "Retired KEY MAN 7",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8806", 0x88, "1", 0, NULL},
		{ "12", "Retired KEY MAN 8",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8906", 0x89, "1", 0, NULL},
		{ "13", "Retired KEY MAN 9",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8A06", 0x8A, "1", 0, NULL},
		{ "14", "Retired KEY MAN 10",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8B06", 0x8B, "1", 0, NULL},
		{ "15", "Retired KEY MAN 11",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8C06", 0x8C, "1", 0, NULL},
		{ "16", "Retired KEY MAN 12",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8D06", 0x8D, "1", 0, NULL},
		{ "17", "Retired KEY MAN 13",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8E06", 0x8E, "1", 0, NULL},
		{ "18", "Retired KEY MAN 14",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "8F06", 0x8F, "1", 0, NULL},
		{ "19", "Retired KEY MAN 15",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "9006", 0x90, "1", 0, NULL},
		{ "20", "Retired KEY MAN 16",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "9106", 0x91, "1", 0, NULL},
		{ "21", "Retired KEY MAN 17",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "9206", 0x92, "1", 0, NULL},
		{ "22", "Retired KEY MAN 18",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "9306", 0x93, "1", 0, NULL},
		{ "23", "Retired KEY MAN 19",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "9406", 0x94, "1", 0, NULL},
		{ "24", "Retired KEY MAN 20",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_WRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			 "9506", 0x95, "1", 0, NULL} };

/*
 * note some of the SC_PKCS15_PRKEY values are dependent
 * on the key algorithm, and will be reset. 
 */
	static const prdata prkeys[PIV_NUM_CERTS_AND_KEYS] = {
		{ "1", "PIV AUTH key", 
				/*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT |
					SC_PKCS15_PRKEY_USAGE_UNWRAP |
					SC_PKCS15_PRKEY_USAGE_SIGN |
					SC_PKCS15_PRKEY_USAGE_SIGNRECOVER,
				/*EC*/SC_PKCS15_PRKEY_USAGE_SIGN,
			"", 0x9A, "1", SC_PKCS15_CO_FLAG_PRIVATE, 0},
		{ "2", "SIGN key", 
				/*RSA*/SC_PKCS15_PRKEY_USAGE_DECRYPT |
					SC_PKCS15_PRKEY_USAGE_SIGN |
					SC_PKCS15_PRKEY_USAGE_SIGNRECOVER |
					SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
				/*EC*/SC_PKCS15_PRKEY_USAGE_SIGN | 
					SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
			"", 0x9C, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "3", "KEY MAN key", 
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x9D, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "4", "CARD AUTH key", 
				/*RSA*/SC_PKCS15_PRKEY_USAGE_SIGN |
				SC_PKCS15_PRKEY_USAGE_SIGNRECOVER,
				/*EC*/SC_PKCS15_PRKEY_USAGE_SIGN,
			"", 0x9E, NULL, 0, 0}, /* no PIN needed, works with wireless */
		{ "5", "Retired KEY MAN 1",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x82, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "6", "Retired KEY MAN 2",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x83, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "7", "Retired KEY MAN 3",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x84, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "8", "Retired KEY MAN 4",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x85, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "9", "Retired KEY MAN 5",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x86, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "10", "Retired KEY MAN 6",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x87, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "11", "Retired KEY MAN 7",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x88, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "12", "Retired KEY MAN 8",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x89, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "13", "Retired KEY MAN 9",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x8A, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "14", "Retired KEY MAN 10",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x8B, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "15", "Retired KEY MAN 11",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x8C, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "16", "Retired KEY MAN 12",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x8D, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "17", "Retired KEY MAN 13",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x8E, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "18", "Retired KEY MAN 14",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x8F, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "19", "Retired KEY MAN 15",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x90, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "20", "Retired KEY MAN 16",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x91, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "21", "Retired KEY MAN 17",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x92, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "22", "Retired KEY MAN 18",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x93, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "23", "Retired KEY MAN 19",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x94, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1},
		{ "24", "Retired KEY MAN 20",
				/*RSA*/SC_PKCS15_PRKEY_USAGE_UNWRAP,
				/*EC*/SC_PKCS15_PRKEY_USAGE_DERIVE,
			"", 0x95, "1", SC_PKCS15_CO_FLAG_PRIVATE, 1}
	};

	int    r, i;
	sc_card_t *card = p15card->card;
	sc_file_t *file_out = NULL;
	int exposed_cert[PIV_NUM_CERTS_AND_KEYS] = {1, 0, 0, 0};
	sc_serial_number_t serial;
	char buf[SC_MAX_SERIALNR * 2 + 1];
	common_key_info ckis[PIV_NUM_CERTS_AND_KEYS];


	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);

	/* could read this off card if needed */

	/* CSP does not like a - in the name */
	p15card->tokeninfo->label = strdup("PIV_II");
	p15card->tokeninfo->manufacturer_id = strdup(MANU_ID);

	/*
	 * get serial number 
	 * We will use the FASC-N from the CHUID
	 * Note we are not verifying CHUID, belongs to this card
	 * but need serial number for Mac tokend 
	 */

	r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
	if (r < 0) {
		sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"sc_card_ctl rc=%d",r);
		p15card->tokeninfo->serial_number = strdup("00000000");
	} else {
		sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0);
		p15card->tokeninfo->serial_number = strdup(buf);
	}

	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "PIV-II adding objects...");

	/* set other objects */
	for (i = 0; objects[i].label; i++) {
		struct sc_pkcs15_data_info obj_info;
		struct sc_pkcs15_object    obj_obj;

		memset(&obj_info, 0, sizeof(obj_info));
		memset(&obj_obj, 0, sizeof(obj_obj));
		sc_pkcs15_format_id(objects[i].id, &obj_info.id);
		sc_format_path(objects[i].path, &obj_info.path);

		/* See if the object can not be present on the card */
		r = (card->ops->card_ctl)(card, SC_CARDCTL_PIV_OBJECT_PRESENT, &obj_info.path);
		if (r == 1)
			continue; /* Not on card, do not define the object */
			
		strncpy(obj_info.app_label, objects[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		r = sc_format_oid(&obj_info.app_oid, objects[i].aoid);
		if (r != SC_SUCCESS)
			return r;

		if (objects[i].auth_id)
			sc_pkcs15_format_id(objects[i].auth_id, &obj_obj.auth_id);

		strncpy(obj_obj.label, objects[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		obj_obj.flags = objects[i].obj_flags;
		
		r = sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_DATA_OBJECT, 
			&obj_obj, &obj_info); 
		if (r < 0)
			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
/* TODO
 * PIV keys 9C and 9D require the pin verify be done just befor any
 * crypto operation using these keys. 
 * 
 * Nss 3.12.7 does not check the CKA_ALWAYS_AUTHENTICATE attribute of a key
 * and will do a C_FindObjects with only CKA_VALUE looking for a certificate
 * it had found earlier after c_Login. The template does not add CKA_TYPE=cert.
 * This will cause the card-piv to read all the objects and will reset
 * the security status for the 9C and 9D keys.
 * Mozilla Bug 457025 
 * 
 * We can not read all the objects, as some need the PIN!
 */  
	}

	/*
	 * certs, pubkeys and priv keys are related and we assume
	 * they are in order 
	 * We need to read the cert, get modulus and keylen 
	 * We use those for the pubkey, and priv key objects. 
	 * If no cert, then see if pubkey (i.e. we are initilizing,
	 * and the pubkey is in a file,) then add pubkey and privkey
	 * If no cert and no pubkey, skip adding them. 
 
	 */
	/* set certs */
	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "PIV-II adding certs...");
	for (i = 0; i < PIV_NUM_CERTS_AND_KEYS; i++) {
		struct sc_pkcs15_cert_info cert_info;
		struct sc_pkcs15_object    cert_obj;
		sc_pkcs15_der_t   cert_der;
		sc_pkcs15_cert_t *cert_out;
		
		ckis[i].cert_found = 0;
		ckis[i].key_alg = -1;
		ckis[i].pubkey_found = 0;
		ckis[i].pubkey_len = 0;

		if ((card->flags & 0x20) &&  (exposed_cert[i] == 0))
			continue;

		memset(&cert_info, 0, sizeof(cert_info));
		memset(&cert_obj,  0, sizeof(cert_obj));
	
		sc_pkcs15_format_id(certs[i].id, &cert_info.id);
		cert_info.authority = certs[i].authority;
		sc_format_path(certs[i].path, &cert_info.path);

		strncpy(cert_obj.label, certs[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		cert_obj.flags = certs[i].obj_flags;

		/* See if the cert might be present or not. */
		r = (card->ops->card_ctl)(card, SC_CARDCTL_PIV_OBJECT_PRESENT, &cert_info.path);
		if (r == 1) {
			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Cert can not be present,i=%d", i);
			continue;
		}

		/* use a &file_out so card-piv.c will read cert if present */
		r = sc_pkcs15_read_file(p15card, &cert_info.path, 
				&cert_der.value, &cert_der.len, &file_out);
		if (file_out) {
			sc_file_free(file_out);
			file_out = NULL;
		}

		if (r) { 
			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "No cert found,i=%d", i);
			continue;
		}

		ckis[i].cert_found = 1;
		/* cache it using the PKCS15 emulation objects */
		/* as it does not change */
               	if (cert_der.value) {
               	 	cert_info.value.value = cert_der.value;
                       	cert_info.value.len = cert_der.len;
                       	cert_info.path.len = 0; /* use in mem cert from now on */
               	}
		/* following will find the cached cert in cert_info */
		r =  sc_pkcs15_read_certificate(p15card, &cert_info, &cert_out);
		if (r < 0 || cert_out->key == NULL) {
			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Failed to read/parse the certificate r=%d",r);
			continue;
		}
		ckis[i].key_alg = cert_out->key->algorithm;
		switch (cert_out->key->algorithm) {
			case SC_ALGORITHM_RSA:
				/* save pubkey_len for pub and priv */
				ckis[i].pubkey_len = cert_out->key->u.rsa.modulus.len * 8;
				break;
			case SC_ALGORITHM_EC:
				ckis[i].pubkey_len = cert_out->key->u.ec.field_length;
				break;
			default:
				sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unsuported key.algorithm %d", cert_out->key->algorithm);
				ckis[i].pubkey_len = 0; /* set some value for now */
		}
		sc_pkcs15_free_certificate(cert_out);

		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
		if (r < 0) {
			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, " Failed to add cert obj r=%d",r);
			continue;
		}
	}

	/* set pins */
	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "PIV-II adding pins...");
	for (i = 0; pins[i].label; i++) {
		struct sc_pkcs15_pin_info pin_info;
		struct sc_pkcs15_object   pin_obj;
		const char * label;
		int pin_ref;

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

		sc_pkcs15_format_id(pins[i].id, &pin_info.auth_id);
		pin_info.reference     = pins[i].ref;
		pin_info.flags         = pins[i].flags;
		pin_info.type          = pins[i].type;
		pin_info.min_length    = pins[i].minlen;
		pin_info.stored_length = pins[i].storedlen;
		pin_info.max_length    = pins[i].maxlen;
		pin_info.pad_char      = pins[i].pad_char;
		sc_format_path(pins[i].path, &pin_info.path);
		pin_info.tries_left    = -1;

		label = pins[i].label;
		if (i == 0 &&
			(card->ops->card_ctl)(card, SC_CARDCTL_PIV_PIN_PREFERENCE,
					&pin_ref) == 0 &&
				pin_ref == 0x00) { /* must be 80 for PIV pin, or 00 for Global PIN */
			pin_info.reference = pin_ref;
			label = "Global PIN";
		} 
sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "DEE Adding pin %d label=%s",i, label);
		strncpy(pin_obj.label, label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		pin_obj.flags = pins[i].obj_flags;

		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
		if (r < 0)
			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
	}



	/* set public keys */
	/* We may only need this during initialzation when genkey
	 * gets the pubkey, but it can not be read from the card 
	 * at a later time. The piv-tool can stach  pubkey in file 
	 */ 
	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "PIV-II adding pub keys...");
	for (i = 0; i < PIV_NUM_CERTS_AND_KEYS; i++) {
		struct sc_pkcs15_pubkey_info pubkey_info;
		struct sc_pkcs15_object     pubkey_obj;
		struct sc_pkcs15_pubkey *p15_key;

		if ((card->flags & 0x20) &&  (exposed_cert[i] == 0))
			continue;

		memset(&pubkey_info, 0, sizeof(pubkey_info));
		memset(&pubkey_obj,  0, sizeof(pubkey_obj));


		sc_pkcs15_format_id(pubkeys[i].id, &pubkey_info.id);
		pubkey_info.native        = 1;
		pubkey_info.key_reference = pubkeys[i].ref;

//		sc_format_path(pubkeys[i].path, &pubkey_info.path);

		strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);

		pubkey_obj.flags = pubkeys[i].obj_flags;
		

		if (pubkeys[i].auth_id)
			sc_pkcs15_format_id(pubkeys[i].auth_id, &pubkey_obj.auth_id);

		/* If no cert found, piv-tool may have stached the pubkey 
		 * so we can use it when generating a certificate request
		 * The file is a OpenSSL DER EVP_KEY, which looks like 
		 * a certificate subjectPublicKeyInfo.
		 *
		 */
		if (ckis[i].cert_found == 0 ) { /*  no cert found */
			char * filename = NULL;
			
			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"No cert for this pub key i=%d",i);
			
			/* 
			 * If we used the piv-tool to generate a key,
			 * we would have saved the public key as a file.
			 * This code is only used while signing a request
			 * After the certificate is loaded on the card,
			 * the public key is extracted from the certificate.
			 */
	
			
			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"DEE look for env %s", 
					pubkeys[i].getenvname?pubkeys[i].getenvname:"NULL");

			if (pubkeys[i].getenvname == NULL) 
				continue;

			filename = getenv(pubkeys[i].getenvname); 
			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"DEE look for file %s", filename?filename:"NULL");
			if (filename == NULL)  
				continue;
			
			sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"Adding pubkey from file %s",filename);

			r = sc_pkcs15_pubkey_from_spki_filename(card->ctx, 
						filename,
						&p15_key);
			if (r < 0) 
				continue;
			
			/* Only get here if no cert, and the the above found the
			 * pub key file (actually the SPKI version). This only 
			 * happens when trying initializing a card and have set 
			 * env PIV_9A_KEY or 9C, 9D, 9E to point at the file. 
			 *
			 * We will cache it using the PKCS15 emulation objects
			 */

			pubkey_info.path.len = 0;
			
			ckis[i].key_alg = p15_key->algorithm; 
			switch (p15_key->algorithm) {
				case SC_ALGORITHM_RSA:
					/* save pubkey_len in pub and priv */
					ckis[i].pubkey_len = p15_key->u.rsa.modulus.len * 8;
					ckis[i].pubkey_found = 1;
					break;
				case SC_ALGORITHM_EC:
					ckis[i].key_alg = SC_ALGORITHM_EC;
					ckis[i].pubkey_len = p15_key->u.ec.field_length;
					ckis[i].pubkey_found = 1;
					break;
				default:
					sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"Unsupported key_alg %d",p15_key->algorithm);
					continue;
			}
			pubkey_obj.emulated = p15_key;
			p15_key = NULL;
		}

		sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"adding pubkey for %d keyalg=%d",i, ckis[i].key_alg);
		switch (ckis[i].key_alg) {
			case SC_ALGORITHM_RSA:
				pubkey_info.usage = pubkeys[i].usage_rsa;
				pubkey_info.modulus_length = ckis[i].pubkey_len;
				strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);

				r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
				if (r < 0)
					SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); /* should not fail */

				ckis[i].pubkey_found = 1;
				break;
			case SC_ALGORITHM_EC:
				pubkey_info.usage = pubkeys[i].usage_ec;
				pubkey_info.field_length = ckis[i].pubkey_len; 
				strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);

				r = sc_pkcs15emu_add_ec_pubkey(p15card, &pubkey_obj, &pubkey_info);
				if (r < 0) 
					SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r); /* should not fail */
				ckis[i].pubkey_found = 1;
				break;
			default:
				sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL,"key_alg %d not supported", ckis[i].key_alg);
				continue;
		}
	}


	/* set private keys */
	sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "PIV-II adding private keys...");
	for (i = 0; i < PIV_NUM_CERTS_AND_KEYS; i++) {
		struct sc_pkcs15_prkey_info prkey_info;
		struct sc_pkcs15_object     prkey_obj;

		if ((card->flags & 0x20) &&  (exposed_cert[i] == 0))
			continue;

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

		if (ckis[i].cert_found == 0 && ckis[i].pubkey_found == 0)
			continue; /* i.e. no cert or pubkey */
		
		sc_pkcs15_format_id(prkeys[i].id, &prkey_info.id);
		prkey_info.native        = 1;
		prkey_info.key_reference = prkeys[i].ref;
		sc_format_path(prkeys[i].path, &prkey_info.path);

		strncpy(prkey_obj.label, prkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		prkey_obj.flags = prkeys[i].obj_flags;
		prkey_obj.user_consent = prkeys[i].user_consent;

		if (prkeys[i].auth_id)
			sc_pkcs15_format_id(prkeys[i].auth_id, &prkey_obj.auth_id);

		switch (ckis[i].key_alg) {
			case SC_ALGORITHM_RSA: 
				prkey_info.usage         = prkeys[i].usage_rsa;
				prkey_info.modulus_length= ckis[i].pubkey_len;
				r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
				break;
		 	case SC_ALGORITHM_EC: 
				prkey_info.usage         = prkeys[i].usage_ec;
				prkey_info.field_length = ckis[i].pubkey_len;
				sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "DEE added key_alg %2.2x prkey_obj.flags %8.8x",
					 ckis[i].key_alg, prkey_obj.flags);
				r = sc_pkcs15emu_add_ec_prkey(p15card, &prkey_obj, &prkey_info);
				break;
			default:
				sc_debug(card->ctx, SC_LOG_DEBUG_NORMAL, "Unsupported key_alg %d", ckis[i].key_alg);
				r = 0; /* we just skip this one */
		}
		if (r < 0)
			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, r);
	}

	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_NORMAL, SC_SUCCESS);
}
static int sc_pkcs15emu_piv_init(sc_pkcs15_card_t *p15card)
{

	/* The cert objects will return all the data */
const objdata objects[] = {
	{"1", "Card Capability Container", 
			"2.16.840.1.101.3.7.1.219.0", NULL, "DB00", 0},
	{"2", "Card Holder Unique Identifier",
			"2.16.840.1.101.3.7.2.48.0", NULL, "3000", 0},
	{"3", "Unsigned Card Holder Unique Identifier",
			"2.16.840.1.101.3.7.2.48.2", NULL, "3010", 0},
	{"4", "X.509 Certificate for PIV Authentication",
			"2.16.840.1.101.3.7.2.1.1", NULL, "0101", 0},
	{"5", "Card Holder Fingerprints",
			"2.16.840.1.101.3.7.2.96.16", "1", "6010", SC_PKCS15_CO_FLAG_PRIVATE},
	{"6", "Printed Information",
			"2.16.840.1.101.3.7.2.48.1", "1", "3001", SC_PKCS15_CO_FLAG_PRIVATE},
	{"7", "Card Holder Facial Image", 
			"2.16.840.1.101.3.7.2.96.48", "1", "6030", SC_PKCS15_CO_FLAG_PRIVATE},
	{"8", "X.509 Certificate for Digital Signature",
			"2.16.840.1.101.3.7.2.1.0",  NULL, "0100", 0},
	{"9", "X.509 Certificate for Key Management", 
			"2.16.840.1.101.3.7.2.1.2", NULL, "0102", 0},
	{"10","X.509 Certificate for Card Authentication",
			"2.16.840.1.101.3.7.2.5.0", NULL, "0500", 0},
	{"11", "Security Object",
			"2.16.840.1.101.3.7.2.144.0", NULL, "9000", 0},
	{NULL, NULL, NULL, NULL, NULL, 0}
};
	/* 
	 * NIST 800-73-1 is proposing to lift the restriction on 
	 * requering pin protected certs. Thus the default will be to 
	 * not require this. But there are a number of test cards 
	 * that do enforce it. Code later on will allow SC_PKCS15_CO_FLAG_PRIVATE
	 * to be set. 
	 */
	/* certs will be pulled out from the cert objects */
	cdata certs[] = {
		{"1", "Certificate for PIV Authentication", 0, "0101cece", 0, 0},

		{"2", "Certificate for Digital Signature", 0, "0100cece", 0, 0},
		{"3", "Certificate for Key Management", 0, "0102cece", 0, 0},
		{"4", "Certificate for Card Authentication", 0, "0500cece", 0, 0},
		{NULL, NULL, 0, NULL, 0, 0}
	};

	const pindata pins[] = {
		{ "1", "PIV Card Holder pin", "", 0x80,
		  SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
		  8, 4, 8, 
		  SC_PKCS15_PIN_FLAG_NEEDS_PADDING |
		  SC_PKCS15_PIN_FLAG_LOCAL, 
		  -1, 0xFF,
		  SC_PKCS15_CO_FLAG_PRIVATE },
		{ "2", "PIV PUK", "", 0x81, 
		  SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
		  8, 4, 8, 
		  SC_PKCS15_PIN_FLAG_NEEDS_PADDING |
		  SC_PKCS15_PIN_FLAG_LOCAL | SC_PKCS15_PIN_FLAG_SO_PIN |
		  SC_PKCS15_PIN_FLAG_UNBLOCKING_PIN, 
		  -1, 0xFF, 
		  SC_PKCS15_CO_FLAG_PRIVATE },
		/* there are some more key, but dont need for now */
		/* The admin 9b might fall in here */
		{ NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0}
	};


	/*
	 * The size of the key or the algid is not really known
	 * but can be derived from the certificates. 
	 * the cert, pubkey and privkey are a set. 
	 * Key usages bits taken from pkcs15v1_1 Table 2
	 */
	pubdata pubkeys[] = {

		{ "1", "PIV AUTH pubkey", 0000, 
			 	SC_PKCS15_PRKEY_USAGE_ENCRYPT |
			 	SC_PKCS15_PRKEY_USAGE_WRAP |
				SC_PKCS15_PRKEY_USAGE_VERIFY |
				SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER,
			"9A06", 0x9A, "1", 0, 0},
		{ "2", "SIGN pubkey", 0000, 
				SC_PKCS15_PRKEY_USAGE_ENCRYPT |
				SC_PKCS15_PRKEY_USAGE_VERIFY |
				SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER |
				SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
			"9C06", 0x9C, "1", 0, 0},
		{ "3", "KEY MAN pubkey", 0000, 
				SC_PKCS15_PRKEY_USAGE_WRAP,
			"9D06", 0x9D, "1", 0, 0},
		{ "4", "CARD AUTH pubkey", 0000, 
				SC_PKCS15_PRKEY_USAGE_VERIFY |
				SC_PKCS15_PRKEY_USAGE_VERIFYRECOVER, 
			"9E06", 0x9E, "0", 0, 0},  /* no pin, and avail in contactless */
		{ NULL, NULL, 0, 0, NULL, 0, NULL, 0, 0}
		
	};

	prdata prkeys[] = {
		{ "1", "PIV AUTH key", 0000, 
				SC_PKCS15_PRKEY_USAGE_DECRYPT |
				SC_PKCS15_PRKEY_USAGE_UNWRAP |
				SC_PKCS15_PRKEY_USAGE_SIGN |
				SC_PKCS15_PRKEY_USAGE_SIGNRECOVER,
			"", 0x9A, "1", 0},
		{ "2", "SIGN key", 0000, 
				SC_PKCS15_PRKEY_USAGE_DECRYPT |
				SC_PKCS15_PRKEY_USAGE_SIGN |
				SC_PKCS15_PRKEY_USAGE_SIGNRECOVER |
				SC_PKCS15_PRKEY_USAGE_NONREPUDIATION,
			"", 0x9C, "1", 0},
		{ "3", "KEY MAN key", 0000, 
				SC_PKCS15_PRKEY_USAGE_UNWRAP,
			"", 0x9D, "1", 0},
		{ "4", "CARD AUTH key", 0000, 
				SC_PKCS15_PRKEY_USAGE_SIGN |
				SC_PKCS15_PRKEY_USAGE_SIGNRECOVER,
			"", 0x9E, NULL, 0}, /* no PIN needed, works with wireless */
		{ NULL, NULL, 0, 0, NULL, 0, NULL, 0}
	};

	int    r, i;
	sc_card_t *card = p15card->card;
	sc_file_t *file_out = NULL;
	int exposed_cert[4] = {1, 0, 0, 0};
	sc_serial_number_t serial;
	char buf[SC_MAX_SERIALNR * 2 + 1];

	SC_FUNC_CALLED(card->ctx, 1);

	/* could read this off card if needed */

	/* CSP does not like a - in the name */
	p15card->label = strdup("PIV_II");
	p15card->manufacturer_id = strdup(MANU_ID);

	/*
	 * get serial number 
	 * We will use the FASC-N from the CHUID
	 * Note we are not verifying CHUID, belongs to this card
	 * but need serial number for Mac tokend 
	 */

	sc_ctx_suppress_errors_on(card->ctx);
	r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
	sc_ctx_suppress_errors_off(card->ctx);
	if (r < 0) {
		sc_debug(card->ctx,"sc_card_ctl rc=%d",r);
		p15card->serial_number = strdup("00000000");
	} else {
		sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0);
		p15card->serial_number = strdup(buf);
	}

	sc_debug(card->ctx, "PIV-II adding objects...");

	/* set other objects */
	for (i = 0; objects[i].label; i++) {
		struct sc_pkcs15_data_info obj_info;
		struct sc_pkcs15_object    obj_obj;

		memset(&obj_info, 0, sizeof(obj_info));
		memset(&obj_obj, 0, sizeof(obj_obj));
		sc_pkcs15_format_id(objects[i].id, &obj_info.id);
		sc_format_path(objects[i].path, &obj_info.path);

		/* We could make sure the object is on the card */
		/* But really don't need to do this now */
//		sc_ctx_suppress_errors_on(card->ctx);
//		r = sc_select_file(card, &obj_info.path, NULL);
//		sc_ctx_suppress_errors_off(card->ctx);
//		if (r == SC_ERROR_FILE_NOT_FOUND)
//			continue; 
			
		strncpy(obj_info.app_label, objects[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		r = sc_format_oid(&obj_info.app_oid, objects[i].aoid);
		if (r != SC_SUCCESS)
			return r;

		if (objects[i].auth_id)
			sc_pkcs15_format_id(objects[i].auth_id, &obj_obj.auth_id);

		strncpy(obj_obj.label, objects[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		obj_obj.flags = objects[i].obj_flags;
		
		r = sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_DATA_OBJECT, 
			&obj_obj, &obj_info); 
		if (r < 0)
			SC_FUNC_RETURN(card->ctx, 1, r);
	}

	/*
	 * certs, pubkeys and priv keys are related and we assume
	 * they are in order 
	 * We need to read the cert, get modulus and keylen 
	 * We use those for the pubkey, and priv key objects. 
	 * If no cert, then see if pubkey (i.e. we are initilizing,
	 * and the pubkey is in a file,) then add pubkey and privkey
	 * If no cert and no pubkey, skip adding them. 
 
	 */
	/* set certs */
	sc_debug(card->ctx, "PIV-II adding certs...");
	for (i = 0; certs[i].label; i++) {
		struct sc_pkcs15_cert_info cert_info;
		struct sc_pkcs15_object    cert_obj;
		sc_pkcs15_der_t   cert_der;
		sc_pkcs15_cert_t *cert_out;
		
		if ((card->flags & 0x20) &&  (exposed_cert[i] == 0))
			continue;

		memset(&cert_info, 0, sizeof(cert_info));
		memset(&cert_obj,  0, sizeof(cert_obj));
	
		sc_pkcs15_format_id(certs[i].id, &cert_info.id);
		cert_info.authority = certs[i].authority;
		sc_format_path(certs[i].path, &cert_info.path);

		strncpy(cert_obj.label, certs[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		cert_obj.flags = certs[i].obj_flags;

		/* see if we have a cert */

		/* use a &file_out so card-piv will read cert if present */
		sc_ctx_suppress_errors_on(card->ctx);
		r = sc_pkcs15_read_file(p15card, &cert_info.path, 
				&cert_der.value, &cert_der.len, &file_out);
		sc_ctx_suppress_errors_off(card->ctx);
		if (file_out) {
			sc_file_free(file_out);
			file_out = NULL;
		}

		if (r) { 
			sc_debug(card->ctx, "No cert found,i=%d", i);
			continue;
		}

		certs[i].found = 1;
		/* cache it using the PKCS15 emulation objects */
		/* as it does not change */
               	if (cert_der.value) {
               	 	cert_info.value.value = cert_der.value;
                       	cert_info.value.len = cert_der.len;
                       	cert_info.path.len = 0; /* use in mem cert from now on */
               	}
		/* following will find the cached cert in cert_info */
		r =  sc_pkcs15_read_certificate(p15card, &cert_info, &cert_out);
		if (r < 0) {
			sc_debug(card->ctx, "Failed to read/parse the certificate r=%d",r);
			continue;
		}
		/* TODO support DSA keys */
		if (cert_out->key.algorithm == SC_ALGORITHM_RSA) {
			/* save modulus_len in pub and priv */
			pubkeys[i].modulus_len = cert_out->key.u.rsa.modulus.len * 8;
			prkeys[i].modulus_len = cert_out->key.u.rsa.modulus.len * 8;
		}
		sc_pkcs15_free_certificate(cert_out);

		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
		if (r < 0) {
			sc_error(card->ctx, " Failed to add cert obj r=%d",r);
			continue;
		}
	}

	/* set pins */
	sc_debug(card->ctx, "PIV-II adding pins...");
	for (i = 0; pins[i].label; i++) {
		struct sc_pkcs15_pin_info pin_info;
		struct sc_pkcs15_object   pin_obj;

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

		sc_pkcs15_format_id(pins[i].id, &pin_info.auth_id);
		pin_info.reference     = pins[i].ref;
		pin_info.flags         = pins[i].flags;
		pin_info.type          = pins[i].type;
		pin_info.min_length    = pins[i].minlen;
		pin_info.stored_length = pins[i].storedlen;
		pin_info.max_length    = pins[i].maxlen;
		pin_info.pad_char      = pins[i].pad_char;
		sc_format_path(pins[i].path, &pin_info.path);
		pin_info.tries_left    = -1;

		strncpy(pin_obj.label, pins[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		pin_obj.flags = pins[i].obj_flags;

		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
		if (r < 0)
			SC_FUNC_RETURN(card->ctx, 1, r);
	}



	/* set public keys */
	/* We may only need this during initialzation when genkey
	 * gets the pubkey, but it can not be read from the card 
	 * at a later time. The piv-tool can stach in file 
	 */ 
	sc_debug(card->ctx, "PIV-II adding pub keys...");
	for (i = 0; pubkeys[i].label; i++) {
		struct sc_pkcs15_pubkey_info pubkey_info;
		struct sc_pkcs15_object     pubkey_obj;
		struct sc_pkcs15_pubkey *p15_key;

		if ((card->flags & 0x20) &&  (exposed_cert[i] == 0))
			continue;

		memset(&pubkey_info, 0, sizeof(pubkey_info));
		memset(&pubkey_obj,  0, sizeof(pubkey_obj));


		sc_pkcs15_format_id(pubkeys[i].id, &pubkey_info.id);
		pubkey_info.usage         = pubkeys[i].usage;
		pubkey_info.native        = 1;
		pubkey_info.key_reference = pubkeys[i].ref;

		sc_format_path(pubkeys[i].path, &pubkey_info.path);

		strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);

		pubkey_obj.flags = pubkeys[i].obj_flags;
		

		if (pubkeys[i].auth_id)
			sc_pkcs15_format_id(pubkeys[i].auth_id, &pubkey_obj.auth_id);

		if (certs[i].found == 0) { /*  no cert found */
			sc_debug(card->ctx,"No cert for this pub key i=%d",i);
			/* TODO DSA */
			pubkey_obj.type = SC_PKCS15_TYPE_PUBKEY_RSA;
			pubkey_obj.data = &pubkey_info;
			sc_ctx_suppress_errors_on(card->ctx);
			r = sc_pkcs15_read_pubkey(p15card, &pubkey_obj, &p15_key);
			sc_ctx_suppress_errors_off(card->ctx);
				pubkey_obj.data = NULL;
				sc_debug(card->ctx," READING PUB KEY r=%d",r);
			if (r < 0 ) {
				continue;
			}
			/* Only get here if no cert, and the card-piv.c found 
			 * there is a pub key file. This only happens when trying
			 * initializing a card and have set env to point at file  
			 */
			if (p15_key->algorithm == SC_ALGORITHM_RSA) {
			/* save modulus_len in pub and priv */
			pubkeys[i].modulus_len = p15_key->u.rsa.modulus.len * 8;
			prkeys[i].modulus_len = p15_key->u.rsa.modulus.len * 8;
			pubkeys[i].found = 1;
			}

		}
		pubkey_info.modulus_length = pubkeys[i].modulus_len;
		strncpy(pubkey_obj.label, pubkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);

		/* TODO DSA keys */
		r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
		if (r < 0)
			SC_FUNC_RETURN(card->ctx, 1, r); /* should not fail */

		pubkeys[i].found = 1;
	}


	/* set private keys */
	sc_debug(card->ctx, "PIV-II adding private keys...");
	for (i = 0; prkeys[i].label; i++) {
		struct sc_pkcs15_prkey_info prkey_info;
		struct sc_pkcs15_object     prkey_obj;

		if ((card->flags & 0x20) &&  (exposed_cert[i] == 0))
			continue;

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

		if (certs[i].found == 0 && pubkeys[i].found == 0)
			continue; /* i.e. no cert or pubkey */
		
		sc_pkcs15_format_id(prkeys[i].id, &prkey_info.id);
		prkey_info.usage         = prkeys[i].usage;
		prkey_info.native        = 1;
		prkey_info.key_reference = prkeys[i].ref;
		prkey_info.modulus_length= prkeys[i].modulus_len;
		/* The cert or pubkey should have filled modulus_len */
		/* TODO DSA keys */
		sc_format_path(prkeys[i].path, &prkey_info.path);

		strncpy(prkey_obj.label, prkeys[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);

		prkey_obj.flags = prkeys[i].obj_flags;

		if (prkeys[i].auth_id)
			sc_pkcs15_format_id(prkeys[i].auth_id, &prkey_obj.auth_id);

		r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
		if (r < 0)
			SC_FUNC_RETURN(card->ctx, 1, r);
	}

	SC_FUNC_RETURN(card->ctx, 1, SC_SUCCESS);
}
Example #13
0
static int sc_pkcs15emu_cac_init(sc_pkcs15_card_t *p15card)
{
	static const pindata pins[] = {
		{ "1", "PIN", "", 0x00,
		  SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
		  8, 4, 8,
		  SC_PKCS15_PIN_FLAG_NEEDS_PADDING |
		  SC_PKCS15_PIN_FLAG_INITIALIZED ,
		  -1, 0xFF,
		  SC_PKCS15_CO_FLAG_PRIVATE },
		{ NULL, NULL, NULL, 0, 0, 0, 0, 0, 0, 0, 0, 0}
	};
	/* oid for key usage */
	static const struct sc_object_id usage_type = {{ 2, 5, 29, 15, -1 }};
	unsigned int usage;


	/*
	 * The size of the key or the algid is not really known
	 * but can be derived from the certificates.
	 * the cert, pubkey and privkey are a set.
	 * Key usages bits taken from certificate key usage extension.
	 */

	int    r, i;
	sc_card_t *card = p15card->card;
	sc_serial_number_t serial;
	char buf[SC_MAX_SERIALNR * 2 + 1];
	int count;
	char *token_name = NULL;


	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);

	memset(&serial, 0, sizeof(serial));

	/* could read this off card if needed */

	p15card->tokeninfo->label = strdup(cac_get_name(card->type));
	p15card->tokeninfo->manufacturer_id = strdup(MANU_ID);

	/*
	 * get serial number
	 */
	r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
	if (r < 0) {
		sc_log(card->ctx, "sc_card_ctl rc=%d",r);
		p15card->tokeninfo->serial_number = strdup("00000000");
	} else {
		sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0);
		p15card->tokeninfo->serial_number = strdup(buf);
	}

	/* set pins */
	/* TODO we should not create PIN objects if it is not initialized
	 * (opensc-tool -s 0020000000 returns 0x6A 0x88)
	 */
	sc_log(card->ctx,  "CAC adding pins...");
	for (i = 0; pins[i].id; i++) {
		struct sc_pkcs15_auth_info pin_info;
		struct sc_pkcs15_object   pin_obj;
		const char * label;

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

		pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
		sc_pkcs15_format_id(pins[i].id, &pin_info.auth_id);
		pin_info.attrs.pin.reference     = pins[i].ref;
		pin_info.attrs.pin.flags         = pins[i].flags;
		pin_info.attrs.pin.type          = pins[i].type;
		pin_info.attrs.pin.min_length    = pins[i].minlen;
		pin_info.attrs.pin.stored_length = pins[i].storedlen;
		pin_info.attrs.pin.max_length    = pins[i].maxlen;
		pin_info.attrs.pin.pad_char      = pins[i].pad_char;
		sc_format_path(pins[i].path, &pin_info.path);
		pin_info.tries_left    = -1;

		label = pins[i].label;
		sc_log(card->ctx,  "CAC Adding pin %d label=%s",i, label);
		strncpy(pin_obj.label, label, SC_PKCS15_MAX_LABEL_SIZE - 1);
		pin_obj.flags = pins[i].obj_flags;

		/* get the ACA path in case it needs to be selected before PIN verify */
		r = sc_card_ctl(card, SC_CARDCTL_CAC_GET_ACA_PATH, &pin_info.path);
		if (r < 0) {
			LOG_FUNC_RETURN(card->ctx, r);
		}

		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
		if (r < 0)
			LOG_FUNC_RETURN(card->ctx, r);
	}

	/* set other objects */
	r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_INIT_GET_GENERIC_OBJECTS, &count);
	LOG_TEST_RET(card->ctx, r, "Can not initiate generic objects.");

	for (i = 0; i < count; i++) {
		struct sc_pkcs15_data_info obj_info;
		struct sc_pkcs15_object    obj_obj;

		r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_GET_NEXT_GENERIC_OBJECT, &obj_info);
		if (r < 0)
			LOG_FUNC_RETURN(card->ctx, r);
		memset(&obj_obj, 0, sizeof(obj_obj));
		memcpy(obj_obj.label, obj_info.app_label, sizeof(obj_obj.label));

		r = sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_DATA_OBJECT,
			&obj_obj, &obj_info);
		if (r < 0)
			LOG_FUNC_RETURN(card->ctx, r);
	}
	r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_FINAL_GET_GENERIC_OBJECTS, &count);
	LOG_TEST_RET(card->ctx, r, "Can not finalize generic objects.");

	/*
	 * certs, pubkeys and priv keys are related and we assume
	 * they are in order
	 * We need to read the cert, get modulus and keylen
	 * We use those for the pubkey, and priv key objects.
	 */
	sc_log(card->ctx,  "CAC adding certs, pub and priv keys...");
	r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_INIT_GET_CERT_OBJECTS, &count);
	LOG_TEST_RET(card->ctx, r, "Can not initiate cert objects.");

	for (i = 0; i < count; i++) {
		struct sc_pkcs15_data_info obj_info;
		struct sc_pkcs15_cert_info cert_info;
		struct sc_pkcs15_pubkey_info pubkey_info;
		struct sc_pkcs15_prkey_info prkey_info;
		struct sc_pkcs15_object cert_obj;
		struct sc_pkcs15_object pubkey_obj;
		struct sc_pkcs15_object prkey_obj;
		sc_pkcs15_der_t   cert_der;
		sc_pkcs15_cert_t *cert_out = NULL;

		r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_GET_NEXT_CERT_OBJECT, &obj_info);
		LOG_TEST_RET(card->ctx, r, "Can not get next object");

		memset(&cert_info, 0, sizeof(cert_info));
		memset(&pubkey_info, 0, sizeof(pubkey_info));
		memset(&prkey_info, 0, sizeof(prkey_info));
		memset(&cert_obj,  0, sizeof(cert_obj));
		memset(&pubkey_obj,  0, sizeof(pubkey_obj));
		memset(&prkey_obj,  0, sizeof(prkey_obj));

		cert_info.id = obj_info.id;
		pubkey_info.id = obj_info.id;
		prkey_info.id = obj_info.id;
		cert_info.path = obj_info.path;
		prkey_info.path = obj_info.path;
		/* Add 0x3f00 to the front of prkey_info.path to make sc_key_file happy */
		/* only do this if our path.len is 1 or 2 */
		if (prkey_info.path.len && prkey_info.path.len <= 2) {
			prkey_info.path.value[2] = prkey_info.path.value[0];
			prkey_info.path.value[3] = prkey_info.path.value[1];
			prkey_info.path.value[0] = 0x3f;
			prkey_info.path.value[1] = 0x00;
			prkey_info.path.len += 2;
		}
		pubkey_info.native        = 1;
		pubkey_info.key_reference = ((int)obj_info.id.value[0]) << 8 | obj_info.id.value[1];
		prkey_info.key_reference = ((int)obj_info.id.value[0]) << 8 | obj_info.id.value[1];
		prkey_info.native        = 1;

		memcpy(cert_obj.label, obj_info.app_label, sizeof(obj_info.app_label));
		memcpy(pubkey_obj.label, obj_info.app_label, sizeof(obj_info.app_label));
		memcpy(prkey_obj.label, obj_info.app_label, sizeof(obj_info.app_label));
		prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
		sc_pkcs15_format_id(pins[0].id, &prkey_obj.auth_id);

		r = sc_pkcs15_read_file(p15card, &cert_info.path, &cert_der.value, &cert_der.len);

		if (r) {
			sc_log(card->ctx,  "No cert found,i=%d", i);
			continue;
		}
		cert_info.path.count = cert_der.len;

		sc_log(card->ctx, 
			 "cert len=%"SC_FORMAT_LEN_SIZE_T"u, cert_info.path.count=%d r=%d\n",
			 cert_der.len, cert_info.path.count, r);
		sc_log_hex(card->ctx, "cert", cert_der.value, cert_der.len);

		/* cache it using the PKCS15 emulation objects */
		/* as it does not change */
		if (cert_der.value) {
			cert_info.value.value = cert_der.value;
			cert_info.value.len = cert_der.len;
			cert_info.path.len = 0; /* use in mem cert from now on */
		}

		/* following will find the cached cert in cert_info */
		r =  sc_pkcs15_read_certificate(p15card, &cert_info, &cert_out);
		if (r < 0 || cert_out->key == NULL) {
			sc_log(card->ctx,  "Failed to read/parse the certificate r=%d",r);
			if (cert_out != NULL)
				sc_pkcs15_free_certificate(cert_out);
			continue;
		}

		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
		if (r < 0) {
			sc_log(card->ctx,  " Failed to add cert obj r=%d",r);
			sc_pkcs15_free_certificate(cert_out);
			continue;
		}
		/* set the token name to the name of the CN of the first certificate */
		if (!token_name) {
			u8 * cn_name = NULL;
			size_t cn_len = 0;
			static const struct sc_object_id cn_oid = {{ 2, 5, 4, 3, -1 }};
			r = sc_pkcs15_get_name_from_dn(card->ctx, cert_out->subject,
				cert_out->subject_len, &cn_oid, &cn_name, &cn_len);
			if (r == SC_SUCCESS) {
				token_name = malloc (cn_len+1);
				if (!token_name) {
					free(cn_name);
					r = SC_ERROR_OUT_OF_MEMORY;
					goto fail;
				}
				memcpy(token_name, cn_name, cn_len);
				free(cn_name);
				token_name[cn_len] = 0;
				free(p15card->tokeninfo->label);
				p15card->tokeninfo->label = token_name;
			}
		}


		r = sc_pkcs15_encode_pubkey_as_spki(card->ctx, cert_out->key, &pubkey_info.direct.spki.value, &pubkey_info.direct.spki.len);
		if (r < 0)
			goto fail;
		pubkey_obj.emulated = cert_out->key;

		r = sc_pkcs15_get_bitstring_extension(card->ctx, cert_out, &usage_type, &usage, NULL);
		if (r < 0) {
			usage = 0xd9ULL; /* basic default usage */
		}
		cac_map_usage(usage, cert_out->key->algorithm, &pubkey_info.usage, &prkey_info.usage, 1);
		sc_log(card->ctx,   "cert %s: cert_usage=0x%x, pub_usage=0x%x priv_usage=0x%x\n",
				sc_dump_hex(cert_info.id.value, cert_info.id.len),
				 usage, pubkey_info.usage, prkey_info.usage);
		if (cert_out->key->algorithm != SC_ALGORITHM_RSA) {
			sc_log(card->ctx, "unsupported key.algorithm %d", cert_out->key->algorithm);
			sc_pkcs15_free_certificate(cert_out);
			continue;
		} else {
			pubkey_info.modulus_length = cert_out->key->u.rsa.modulus.len * 8;
			prkey_info.modulus_length = cert_out->key->u.rsa.modulus.len * 8;
			r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
			sc_log(card->ctx,  "adding rsa public key r=%d usage=%x",r, pubkey_info.usage);
			if (r < 0)
				goto fail;
			r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
			sc_log(card->ctx,  "adding rsa private key r=%d usage=%x",r, prkey_info.usage);
		}

		cert_out->key = NULL;
fail:
		sc_pkcs15_free_certificate(cert_out);
		if (r < 0)
			LOG_FUNC_RETURN(card->ctx, r); /* should not fail */

	}
	r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_FINAL_GET_CERT_OBJECTS, &count);
	LOG_TEST_RET(card->ctx, r, "Can not finalize cert objects.");

	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
}