Blame src/p11_key.c

Packit 6b81fa
/* libp11, a simple layer on to of PKCS#11 API
Packit 6b81fa
 * Copyright (C) 2005 Olaf Kirch <okir@lst.de>
Packit 6b81fa
 * Copyright (C) 2016-2018 MichaƂ Trojnara <Michal.Trojnara@stunnel.org>
Packit 6b81fa
 *
Packit 6b81fa
 *  This library is free software; you can redistribute it and/or
Packit 6b81fa
 *  modify it under the terms of the GNU Lesser General Public
Packit 6b81fa
 *  License as published by the Free Software Foundation; either
Packit 6b81fa
 *  version 2.1 of the License, or (at your option) any later version.
Packit 6b81fa
 *
Packit 6b81fa
 *  This library is distributed in the hope that it will be useful,
Packit 6b81fa
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6b81fa
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6b81fa
 *  Lesser General Public License for more details.
Packit 6b81fa
 *
Packit 6b81fa
 *  You should have received a copy of the GNU Lesser General Public
Packit 6b81fa
 *  License along with this library; if not, write to the Free Software
Packit 6b81fa
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
Packit 6b81fa
 */
Packit 6b81fa
Packit 6b81fa
#include "libp11-int.h"
Packit 6b81fa
#include <string.h>
Packit 6b81fa
#include <openssl/ui.h>
Packit 6b81fa
#include <openssl/bn.h>
Packit 6b81fa
Packit 6b81fa
#ifdef _WIN32
Packit 6b81fa
#define strncasecmp strnicmp
Packit 6b81fa
#endif
Packit 6b81fa
Packit 6b81fa
/* The maximum length of PIN */
Packit 6b81fa
#define MAX_PIN_LENGTH   32
Packit 6b81fa
Packit 6b81fa
static int pkcs11_find_keys(PKCS11_TOKEN *, unsigned int);
Packit 6b81fa
static int pkcs11_next_key(PKCS11_CTX *ctx, PKCS11_TOKEN *token,
Packit 6b81fa
	CK_SESSION_HANDLE session, CK_OBJECT_CLASS type);
Packit 6b81fa
static int pkcs11_init_key(PKCS11_CTX *ctx, PKCS11_TOKEN *token,
Packit 6b81fa
	CK_SESSION_HANDLE session, CK_OBJECT_HANDLE o,
Packit 6b81fa
	CK_OBJECT_CLASS type, PKCS11_KEY **);
Packit 6b81fa
static int pkcs11_store_key(PKCS11_TOKEN *, EVP_PKEY *, unsigned int,
Packit 6b81fa
	char *, unsigned char *, size_t, PKCS11_KEY **);
Packit 6b81fa
Packit 6b81fa
/* Set UI method to allow retrieving CKU_CONTEXT_SPECIFIC PINs interactively */
Packit 6b81fa
int pkcs11_set_ui_method(PKCS11_CTX *ctx,
Packit 6b81fa
		UI_METHOD *ui_method, void *ui_user_data)
Packit 6b81fa
{
Packit 6b81fa
	PKCS11_CTX_private *cpriv = PRIVCTX(ctx);
Packit 6b81fa
	if (cpriv == NULL)
Packit 6b81fa
		return -1;
Packit 6b81fa
	cpriv->ui_method = ui_method;
Packit 6b81fa
	cpriv->ui_user_data = ui_user_data;
Packit 6b81fa
	return 0;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
/*
Packit 6b81fa
 * Find private key matching a certificate
Packit 6b81fa
 */
Packit 6b81fa
PKCS11_KEY *pkcs11_find_key(PKCS11_CERT *cert)
Packit 6b81fa
{
Packit 6b81fa
	PKCS11_CERT_private *cpriv = PRIVCERT(cert);
Packit 6b81fa
	PKCS11_KEY *keys;
Packit 6b81fa
	unsigned int n, count;
Packit 6b81fa
Packit 6b81fa
	if (pkcs11_enumerate_keys(CERT2TOKEN(cert), CKO_PRIVATE_KEY, &keys, &count))
Packit 6b81fa
		return NULL;
Packit 6b81fa
	for (n = 0; n < count; n++) {
Packit 6b81fa
		PKCS11_KEY_private *kpriv = PRIVKEY(&keys[n]);
Packit 6b81fa
		if (kpriv && cpriv->id_len == kpriv->id_len
Packit 6b81fa
				&& !memcmp(cpriv->id, kpriv->id, cpriv->id_len))
Packit 6b81fa
			return &keys[n];
Packit 6b81fa
	}
Packit 6b81fa
	return NULL;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
/*
Packit 6b81fa
 * Find key matching a key of the other type (public vs private)
Packit 6b81fa
 */
Packit 6b81fa
PKCS11_KEY *pkcs11_find_key_from_key(PKCS11_KEY *keyin)
Packit 6b81fa
{
Packit 6b81fa
	PKCS11_KEY_private *kinpriv = PRIVKEY(keyin);
Packit 6b81fa
	PKCS11_KEY *keys;
Packit 6b81fa
	unsigned int n, count, type =
Packit 6b81fa
		keyin->isPrivate ? CKO_PUBLIC_KEY : CKO_PRIVATE_KEY;
Packit 6b81fa
Packit 6b81fa
	if (pkcs11_enumerate_keys(KEY2TOKEN(keyin), type, &keys, &count))
Packit 6b81fa
		return NULL;
Packit 6b81fa
	for (n = 0; n < count; n++) {
Packit 6b81fa
		PKCS11_KEY_private *kpriv = PRIVKEY(&keys[n]);
Packit 6b81fa
		if (kpriv && kinpriv->id_len == kpriv->id_len
Packit 6b81fa
				&& !memcmp(kinpriv->id, kpriv->id, kinpriv->id_len))
Packit 6b81fa
			return &keys[n];
Packit 6b81fa
	}
Packit 6b81fa
	return NULL;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
/*
Packit 6b81fa
 * Reopens the object associated with the key
Packit 6b81fa
 */
Packit 6b81fa
int pkcs11_reload_key(PKCS11_KEY *key)
Packit 6b81fa
{
Packit 6b81fa
	PKCS11_KEY_private *kpriv = PRIVKEY(key);
Packit 6b81fa
	PKCS11_SLOT *slot = KEY2SLOT(key);
Packit 6b81fa
	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
Packit 6b81fa
	PKCS11_CTX *ctx = SLOT2CTX(slot);
Packit 6b81fa
	CK_OBJECT_CLASS key_search_class =
Packit 6b81fa
		key->isPrivate ? CKO_PRIVATE_KEY : CKO_PUBLIC_KEY;
Packit 6b81fa
	CK_ATTRIBUTE key_search_attrs[2] = {
Packit 6b81fa
		{CKA_CLASS, &key_search_class, sizeof(key_search_class)},
Packit 6b81fa
		{CKA_ID, kpriv->id, kpriv->id_len},
Packit 6b81fa
	};
Packit 6b81fa
	CK_ULONG count;
Packit 6b81fa
	int rv;
Packit 6b81fa
Packit 6b81fa
	/* this is already covered with a per-ctx lock */
Packit 6b81fa
Packit 6b81fa
	rv = CRYPTOKI_call(ctx,
Packit 6b81fa
		C_FindObjectsInit(spriv->session, key_search_attrs, 2));
Packit 6b81fa
	CRYPTOKI_checkerr(CKR_F_PKCS11_RELOAD_KEY, rv);
Packit 6b81fa
Packit 6b81fa
	rv = CRYPTOKI_call(ctx,
Packit 6b81fa
		C_FindObjects(spriv->session, &kpriv->object, 1, &count));
Packit 6b81fa
	CRYPTOKI_checkerr(CKR_F_PKCS11_RELOAD_KEY, rv);
Packit 6b81fa
Packit 6b81fa
	CRYPTOKI_call(ctx, C_FindObjectsFinal(spriv->session));
Packit 6b81fa
Packit 6b81fa
	return 0;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
/**
Packit 6b81fa
 * Generate a keyPair directly on token
Packit 6b81fa
 */
Packit 6b81fa
int pkcs11_generate_key(PKCS11_TOKEN *token, int algorithm, unsigned int bits,
Packit 6b81fa
		char *label, unsigned char* id, size_t id_len) {
Packit 6b81fa
Packit 6b81fa
	PKCS11_SLOT *slot = TOKEN2SLOT(token);
Packit 6b81fa
	PKCS11_CTX *ctx = TOKEN2CTX(token);
Packit 6b81fa
	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
Packit 6b81fa
Packit 6b81fa
	CK_ATTRIBUTE pubkey_attrs[32];
Packit 6b81fa
	CK_ATTRIBUTE privkey_attrs[32];
Packit 6b81fa
	unsigned int n_pub = 0, n_priv = 0;
Packit 6b81fa
	CK_MECHANISM mechanism = {
Packit 6b81fa
		CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
Packit 6b81fa
	};
Packit 6b81fa
	CK_BYTE public_exponent[] = { 1, 0, 1 };
Packit 6b81fa
	CK_OBJECT_HANDLE pub_key_obj, priv_key_obj;
Packit 6b81fa
	int rv;
Packit 6b81fa
Packit 6b81fa
	(void)algorithm; /* squash the unused parameter warning */
Packit 6b81fa
Packit 6b81fa
	/* make sure we have a session */
Packit 6b81fa
	if (!spriv->haveSession && PKCS11_open_session(slot, 1))
Packit 6b81fa
		return -1;
Packit 6b81fa
Packit 6b81fa
	/* pubkey attributes */
Packit 6b81fa
	pkcs11_addattr(pubkey_attrs + n_pub++, CKA_ID, id, id_len);
Packit 6b81fa
	if (label)
Packit 6b81fa
		pkcs11_addattr_s(pubkey_attrs + n_pub++, CKA_LABEL, label);
Packit 6b81fa
	pkcs11_addattr_bool(pubkey_attrs + n_pub++, CKA_TOKEN, TRUE);
Packit 6b81fa
Packit 6b81fa
	pkcs11_addattr_bool(pubkey_attrs + n_pub++, CKA_ENCRYPT, TRUE);
Packit 6b81fa
	pkcs11_addattr_bool(pubkey_attrs + n_pub++, CKA_VERIFY, TRUE);
Packit 6b81fa
	pkcs11_addattr_bool(pubkey_attrs + n_pub++, CKA_WRAP, TRUE);
Packit 6b81fa
	pkcs11_addattr_int(pubkey_attrs + n_pub++, CKA_MODULUS_BITS, bits);
Packit 6b81fa
	pkcs11_addattr(pubkey_attrs + n_pub++, CKA_PUBLIC_EXPONENT, public_exponent, 3);
Packit 6b81fa
Packit 6b81fa
	/* privkey attributes */
Packit 6b81fa
	pkcs11_addattr(privkey_attrs + n_priv++, CKA_ID, id, id_len);
Packit 6b81fa
	if (label)
Packit 6b81fa
		pkcs11_addattr_s(privkey_attrs + n_priv++, CKA_LABEL, label);
Packit 6b81fa
	pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_TOKEN, TRUE);
Packit 6b81fa
	pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_PRIVATE, TRUE);
Packit 6b81fa
	pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_SENSITIVE, TRUE);
Packit 6b81fa
	pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_DECRYPT, TRUE);
Packit 6b81fa
	pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_SIGN, TRUE);
Packit 6b81fa
	pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_UNWRAP, TRUE);
Packit 6b81fa
Packit 6b81fa
	/* call the pkcs11 module to create the key pair */
Packit 6b81fa
	rv = CRYPTOKI_call(ctx, C_GenerateKeyPair(
Packit 6b81fa
		spriv->session,
Packit 6b81fa
		&mechanism,
Packit 6b81fa
		pubkey_attrs,
Packit 6b81fa
		n_pub,
Packit 6b81fa
		privkey_attrs,
Packit 6b81fa
		n_priv,
Packit 6b81fa
		&pub_key_obj,
Packit 6b81fa
		&priv_key_obj
Packit 6b81fa
	));
Packit 6b81fa
Packit 6b81fa
	/* zap all memory allocated when building the template */
Packit 6b81fa
	pkcs11_zap_attrs(privkey_attrs, n_priv);
Packit 6b81fa
	pkcs11_zap_attrs(pubkey_attrs, n_pub);
Packit 6b81fa
Packit 6b81fa
	CRYPTOKI_checkerr(CKR_F_PKCS11_GENERATE_KEY, rv);
Packit 6b81fa
Packit 6b81fa
	return 0;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
/*
Packit 6b81fa
 * Store a private key on the token
Packit 6b81fa
 */
Packit 6b81fa
int pkcs11_store_private_key(PKCS11_TOKEN *token, EVP_PKEY *pk,
Packit 6b81fa
		char *label, unsigned char *id, size_t id_len)
Packit 6b81fa
{
Packit 6b81fa
	if (pkcs11_store_key(token, pk, CKO_PRIVATE_KEY, label, id, id_len, NULL))
Packit 6b81fa
		return -1;
Packit 6b81fa
	return 0;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
int pkcs11_store_public_key(PKCS11_TOKEN *token, EVP_PKEY *pk,
Packit 6b81fa
		char *label, unsigned char *id, size_t id_len)
Packit 6b81fa
{
Packit 6b81fa
	if (pkcs11_store_key(token, pk, CKO_PUBLIC_KEY, label, id, id_len, NULL))
Packit 6b81fa
		return -1;
Packit 6b81fa
	return 0;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
/*
Packit 6b81fa
 * Store private key
Packit 6b81fa
 */
Packit 6b81fa
static int pkcs11_store_key(PKCS11_TOKEN *token, EVP_PKEY *pk,
Packit 6b81fa
		unsigned int type, char *label, unsigned char *id, size_t id_len,
Packit 6b81fa
		PKCS11_KEY ** ret_key)
Packit 6b81fa
{
Packit 6b81fa
	PKCS11_SLOT *slot = TOKEN2SLOT(token);
Packit 6b81fa
	PKCS11_CTX *ctx = TOKEN2CTX(token);
Packit 6b81fa
	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
Packit 6b81fa
	CK_OBJECT_HANDLE object;
Packit 6b81fa
	CK_ATTRIBUTE attrs[32];
Packit 6b81fa
	unsigned int n = 0;
Packit 6b81fa
	int rv;
Packit 6b81fa
	const BIGNUM *rsa_n, *rsa_e, *rsa_d, *rsa_p, *rsa_q, *rsa_dmp1, *rsa_dmq1, *rsa_iqmp;
Packit 6b81fa
Packit 6b81fa
	/* First, make sure we have a session */
Packit 6b81fa
	if (!spriv->haveSession && PKCS11_open_session(slot, 1))
Packit 6b81fa
		return -1;
Packit 6b81fa
Packit 6b81fa
	/* Now build the key attrs */
Packit 6b81fa
	pkcs11_addattr_int(attrs + n++, CKA_CLASS, type);
Packit 6b81fa
	if (label)
Packit 6b81fa
		pkcs11_addattr_s(attrs + n++, CKA_LABEL, label);
Packit 6b81fa
	if (id && id_len)
Packit 6b81fa
		pkcs11_addattr(attrs + n++, CKA_ID, id, id_len);
Packit 6b81fa
	pkcs11_addattr_bool(attrs + n++, CKA_TOKEN, TRUE);
Packit 6b81fa
	if (type == CKO_PRIVATE_KEY) {
Packit 6b81fa
		pkcs11_addattr_bool(attrs + n++, CKA_PRIVATE, TRUE);
Packit 6b81fa
		pkcs11_addattr_bool(attrs + n++, CKA_SENSITIVE, TRUE);
Packit 6b81fa
		pkcs11_addattr_bool(attrs + n++, CKA_DECRYPT, TRUE);
Packit 6b81fa
		pkcs11_addattr_bool(attrs + n++, CKA_SIGN, TRUE);
Packit 6b81fa
		pkcs11_addattr_bool(attrs + n++, CKA_UNWRAP, TRUE);
Packit 6b81fa
	} else { /* CKO_PUBLIC_KEY */
Packit 6b81fa
		pkcs11_addattr_bool(attrs + n++, CKA_ENCRYPT, TRUE);
Packit 6b81fa
		pkcs11_addattr_bool(attrs + n++, CKA_VERIFY, TRUE);
Packit 6b81fa
		pkcs11_addattr_bool(attrs + n++, CKA_WRAP, TRUE);
Packit 6b81fa
	}
Packit 6b81fa
#if OPENSSL_VERSION_NUMBER >= 0x10100003L && !defined(LIBRESSL_VERSION_NUMBER)
Packit 6b81fa
	if (EVP_PKEY_base_id(pk) == EVP_PKEY_RSA) {
Packit 6b81fa
		RSA *rsa = EVP_PKEY_get1_RSA(pk);
Packit 6b81fa
		pkcs11_addattr_int(attrs + n++, CKA_KEY_TYPE, CKK_RSA);
Packit 6b81fa
		RSA_get0_key(rsa, &rsa_n, &rsa_e, &rsa_d);
Packit 6b81fa
		RSA_get0_factors(rsa, &rsa_p, &rsa_q);
Packit 6b81fa
		RSA_get0_crt_params(rsa, &rsa_dmp1, &rsa_dmq1, &rsa_iqmp);
Packit 6b81fa
		RSA_free(rsa);
Packit 6b81fa
#else
Packit 6b81fa
	if (pk->type == EVP_PKEY_RSA) {
Packit 6b81fa
		RSA *rsa = pk->pkey.rsa;
Packit 6b81fa
		pkcs11_addattr_int(attrs + n++, CKA_KEY_TYPE, CKK_RSA);
Packit 6b81fa
		rsa_n=rsa->n;
Packit 6b81fa
		rsa_e=rsa->e;
Packit 6b81fa
		rsa_d=rsa->d;
Packit 6b81fa
		rsa_p=rsa->p;
Packit 6b81fa
		rsa_q=rsa->q;
Packit 6b81fa
		rsa_dmp1=rsa->dmp1;
Packit 6b81fa
		rsa_dmq1=rsa->dmq1;
Packit 6b81fa
		rsa_iqmp=rsa->iqmp;
Packit 6b81fa
#endif
Packit 6b81fa
		pkcs11_addattr_bn(attrs + n++, CKA_MODULUS, rsa_n);
Packit 6b81fa
		pkcs11_addattr_bn(attrs + n++, CKA_PUBLIC_EXPONENT, rsa_e);
Packit 6b81fa
		if (type == CKO_PRIVATE_KEY) {
Packit 6b81fa
			pkcs11_addattr_bn(attrs + n++, CKA_PRIVATE_EXPONENT, rsa_d);
Packit 6b81fa
			pkcs11_addattr_bn(attrs + n++, CKA_PRIME_1, rsa_p);
Packit 6b81fa
			pkcs11_addattr_bn(attrs + n++, CKA_PRIME_2, rsa_q);
Packit 6b81fa
			if (rsa_dmp1)
Packit 6b81fa
				pkcs11_addattr_bn(attrs + n++, CKA_EXPONENT_1, rsa_dmp1);
Packit 6b81fa
			if (rsa_dmq1)
Packit 6b81fa
				pkcs11_addattr_bn(attrs + n++, CKA_EXPONENT_2, rsa_dmq1);
Packit 6b81fa
			if (rsa_iqmp)
Packit 6b81fa
				pkcs11_addattr_bn(attrs + n++, CKA_COEFFICIENT, rsa_iqmp);
Packit 6b81fa
		}
Packit 6b81fa
	} else {
Packit 6b81fa
		pkcs11_zap_attrs(attrs, n);
Packit 6b81fa
		P11err(P11_F_PKCS11_STORE_KEY, P11_R_NOT_SUPPORTED);
Packit 6b81fa
		return -1;
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	/* Now call the pkcs11 module to create the object */
Packit 6b81fa
	rv = CRYPTOKI_call(ctx, C_CreateObject(spriv->session, attrs, n, &object));
Packit 6b81fa
Packit 6b81fa
	/* Zap all memory allocated when building the template */
Packit 6b81fa
	pkcs11_zap_attrs(attrs, n);
Packit 6b81fa
Packit 6b81fa
	CRYPTOKI_checkerr(CKR_F_PKCS11_STORE_KEY, rv);
Packit 6b81fa
Packit 6b81fa
	/* Gobble the key object */
Packit 6b81fa
	return pkcs11_init_key(ctx, token, spriv->session, object, type, ret_key);
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
/*
Packit 6b81fa
 * Get the key type
Packit 6b81fa
 */
Packit 6b81fa
int pkcs11_get_key_type(PKCS11_KEY *key)
Packit 6b81fa
{
Packit 6b81fa
	PKCS11_KEY_private *kpriv = PRIVKEY(key);
Packit 6b81fa
Packit 6b81fa
	return kpriv->ops->type;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
/*
Packit 6b81fa
 * Create an EVP_PKEY OpenSSL object for a given key
Packit 6b81fa
 * Returns private or public key depending on isPrivate
Packit 6b81fa
 */
Packit 6b81fa
EVP_PKEY *pkcs11_get_key(PKCS11_KEY *key, int isPrivate)
Packit 6b81fa
{
Packit 6b81fa
	if (key->isPrivate != isPrivate)
Packit 6b81fa
		key = pkcs11_find_key_from_key(key);
Packit 6b81fa
	if (key == NULL)
Packit 6b81fa
		return NULL;
Packit 6b81fa
	if (key->evp_key == NULL) {
Packit 6b81fa
		PKCS11_KEY_private *kpriv = PRIVKEY(key);
Packit 6b81fa
		key->evp_key = kpriv->ops->get_evp_key(key);
Packit 6b81fa
		if (key->evp_key == NULL)
Packit 6b81fa
			return NULL;
Packit 6b81fa
		kpriv->always_authenticate = CK_FALSE;
Packit 6b81fa
		if (isPrivate && key_getattr_val(key, CKA_ALWAYS_AUTHENTICATE,
Packit 6b81fa
				&kpriv->always_authenticate, sizeof(CK_BBOOL))) {
Packit 6b81fa
#ifdef DEBUG
Packit 6b81fa
			fprintf(stderr, "Missing CKA_ALWAYS_AUTHENTICATE attribute\n");
Packit 6b81fa
#endif
Packit 6b81fa
		}
Packit 6b81fa
	}
Packit 6b81fa
#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
Packit 6b81fa
	EVP_PKEY_up_ref(key->evp_key);
Packit 6b81fa
#else
Packit 6b81fa
	CRYPTO_add(&key->evp_key->references, 1, CRYPTO_LOCK_EVP_PKEY);
Packit 6b81fa
#endif
Packit 6b81fa
	return key->evp_key;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
/*
Packit 6b81fa
 * Authenticate a private the key operation if needed
Packit 6b81fa
 * This function *only* handles CKU_CONTEXT_SPECIFIC logins.
Packit 6b81fa
 */
Packit 6b81fa
int pkcs11_authenticate(PKCS11_KEY *key)
Packit 6b81fa
{
Packit 6b81fa
	PKCS11_TOKEN *token = KEY2TOKEN(key);
Packit 6b81fa
	PKCS11_SLOT *slot = TOKEN2SLOT(token);
Packit 6b81fa
	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
Packit 6b81fa
	PKCS11_CTX *ctx = SLOT2CTX(slot);
Packit 6b81fa
	PKCS11_CTX_private *cpriv = PRIVCTX(ctx);
Packit 6b81fa
	char pin[MAX_PIN_LENGTH+1];
Packit 6b81fa
	char* prompt;
Packit 6b81fa
	UI *ui;
Packit 6b81fa
	int rv;
Packit 6b81fa
Packit 6b81fa
	/* Handle CKF_PROTECTED_AUTHENTICATION_PATH */
Packit 6b81fa
	if (token->secureLogin) {
Packit 6b81fa
		rv = CRYPTOKI_call(ctx,
Packit 6b81fa
			C_Login(spriv->session, CKU_CONTEXT_SPECIFIC, NULL, 0));
Packit 6b81fa
		return rv == CKR_USER_ALREADY_LOGGED_IN ? 0 : rv;
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	/* Call UI to ask for a PIN */
Packit 6b81fa
	ui = UI_new_method(cpriv->ui_method);
Packit 6b81fa
	if (ui == NULL)
Packit 6b81fa
		return P11_R_UI_FAILED;
Packit 6b81fa
	if (cpriv->ui_user_data != NULL)
Packit 6b81fa
		UI_add_user_data(ui, cpriv->ui_user_data);
Packit 6b81fa
	memset(pin, 0, MAX_PIN_LENGTH+1);
Packit 6b81fa
	prompt = UI_construct_prompt(ui, "PKCS#11 key PIN", key->label);
Packit 6b81fa
	if (!prompt) {
Packit 6b81fa
		return P11_R_UI_FAILED;
Packit 6b81fa
	}
Packit 6b81fa
	if (!UI_dup_input_string(ui, prompt,
Packit 6b81fa
			UI_INPUT_FLAG_DEFAULT_PWD, pin, 4, MAX_PIN_LENGTH)) {
Packit 6b81fa
		UI_free(ui);
Packit 6b81fa
		OPENSSL_free(prompt);
Packit 6b81fa
		return P11_R_UI_FAILED;
Packit 6b81fa
	}
Packit 6b81fa
	OPENSSL_free(prompt);
Packit 6b81fa
Packit 6b81fa
	if (UI_process(ui)) {
Packit 6b81fa
		UI_free(ui);
Packit 6b81fa
		return P11_R_UI_FAILED;
Packit 6b81fa
	}
Packit 6b81fa
	UI_free(ui);
Packit 6b81fa
Packit 6b81fa
	/* Login with the PIN */
Packit 6b81fa
	rv = CRYPTOKI_call(ctx,
Packit 6b81fa
		C_Login(spriv->session, CKU_CONTEXT_SPECIFIC,
Packit 6b81fa
			(CK_UTF8CHAR *)pin, strlen(pin)));
Packit 6b81fa
	OPENSSL_cleanse(pin, MAX_PIN_LENGTH+1);
Packit 6b81fa
	return rv == CKR_USER_ALREADY_LOGGED_IN ? 0 : rv;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
/*
Packit 6b81fa
 * Return keys of a given type (public or private)
Packit 6b81fa
 * Use the cached values if available
Packit 6b81fa
 */
Packit 6b81fa
int pkcs11_enumerate_keys(PKCS11_TOKEN *token, unsigned int type,
Packit 6b81fa
		PKCS11_KEY ** keyp, unsigned int *countp)
Packit 6b81fa
{
Packit 6b81fa
	PKCS11_SLOT *slot = TOKEN2SLOT(token);
Packit 6b81fa
	PKCS11_CTX *ctx = TOKEN2CTX(token);
Packit 6b81fa
	PKCS11_TOKEN_private *tpriv = PRIVTOKEN(token);
Packit 6b81fa
	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
Packit 6b81fa
	PKCS11_CTX_private *cpriv = PRIVCTX(ctx);
Packit 6b81fa
	PKCS11_keys *keys = (type == CKO_PRIVATE_KEY) ? &tpriv->prv : &tpriv->pub;
Packit 6b81fa
	PKCS11_KEY *first_key_prev = keys->keys;
Packit 6b81fa
	int rv;
Packit 6b81fa
	int i;
Packit 6b81fa
Packit 6b81fa
	/* Make sure we have a session */
Packit 6b81fa
	if (!spriv->haveSession && PKCS11_open_session(slot, 0))
Packit 6b81fa
		return -1;
Packit 6b81fa
Packit 6b81fa
	CRYPTO_THREAD_write_lock(cpriv->rwlock);
Packit 6b81fa
	rv = pkcs11_find_keys(token, type);
Packit 6b81fa
	CRYPTO_THREAD_unlock(cpriv->rwlock);
Packit 6b81fa
	if (rv < 0) {
Packit 6b81fa
		pkcs11_destroy_keys(token, type);
Packit 6b81fa
		return -1;
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	/* Always update key references if the keys pointer changed */
Packit 6b81fa
	if (first_key_prev != NULL && first_key_prev != keys->keys) {
Packit 6b81fa
		for (i = 0; i < keys->num; ++i) {
Packit 6b81fa
			PKCS11_KEY *key = keys->keys + i;
Packit 6b81fa
			PKCS11_KEY_private *kpriv = PRIVKEY(key);
Packit 6b81fa
			kpriv->ops->update_ex_data(key);
Packit 6b81fa
		}
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	if (keyp)
Packit 6b81fa
		*keyp = keys->keys;
Packit 6b81fa
	if (countp)
Packit 6b81fa
		*countp = keys->num;
Packit 6b81fa
	return 0;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
/**
Packit 6b81fa
 * Remove a key from the associated token
Packit 6b81fa
 */
Packit 6b81fa
int pkcs11_remove_key(PKCS11_KEY *key) {
Packit 6b81fa
	PKCS11_SLOT *slot = KEY2SLOT(key);
Packit 6b81fa
	PKCS11_CTX *ctx = KEY2CTX(key);
Packit 6b81fa
	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
Packit 6b81fa
	CK_OBJECT_HANDLE obj;
Packit 6b81fa
	CK_ULONG count;
Packit 6b81fa
	CK_ATTRIBUTE search_parameters[32];
Packit 6b81fa
	unsigned int n = 0;
Packit 6b81fa
	int rv;
Packit 6b81fa
Packit 6b81fa
	/* First, make sure we have a session */
Packit 6b81fa
	if (!spriv->haveSession && PKCS11_open_session(slot, 1))
Packit 6b81fa
		return -1;
Packit 6b81fa
	if (key->isPrivate)
Packit 6b81fa
		pkcs11_addattr_int(search_parameters + n++, CKA_CLASS, CKO_PRIVATE_KEY);
Packit 6b81fa
	else
Packit 6b81fa
		pkcs11_addattr_int(search_parameters + n++, CKA_CLASS, CKO_PUBLIC_KEY);
Packit 6b81fa
	if (key->id && key->id_len)
Packit 6b81fa
		pkcs11_addattr(search_parameters + n++, CKA_ID, key->id, key->id_len);
Packit 6b81fa
	if (key->label)
Packit 6b81fa
	 	pkcs11_addattr_s(search_parameters + n++, CKA_LABEL, key->label);
Packit 6b81fa
Packit 6b81fa
	rv = CRYPTOKI_call(ctx,
Packit 6b81fa
		C_FindObjectsInit(spriv->session, search_parameters, n));
Packit 6b81fa
	CRYPTOKI_checkerr(CKR_F_PKCS11_REMOVE_KEY, rv);
Packit 6b81fa
Packit 6b81fa
	rv = CRYPTOKI_call(ctx, C_FindObjects(spriv->session, &obj, 1, &count));
Packit 6b81fa
	CRYPTOKI_checkerr(CKR_F_PKCS11_REMOVE_KEY, rv);
Packit 6b81fa
Packit 6b81fa
	CRYPTOKI_call(ctx, C_FindObjectsFinal(spriv->session));
Packit 6b81fa
	if (count!=1) {
Packit 6b81fa
		pkcs11_zap_attrs(search_parameters, n);
Packit 6b81fa
		return -1;
Packit 6b81fa
	}
Packit 6b81fa
	rv = CRYPTOKI_call(ctx, C_DestroyObject(spriv->session, obj));
Packit 6b81fa
	if (rv != CKR_OK) {
Packit 6b81fa
		pkcs11_zap_attrs(search_parameters, n);
Packit 6b81fa
		return -1;
Packit 6b81fa
	}
Packit 6b81fa
	pkcs11_zap_attrs(search_parameters, n);
Packit 6b81fa
	return 0;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
/*
Packit 6b81fa
 * Find all keys of a given type (public or private)
Packit 6b81fa
 */
Packit 6b81fa
static int pkcs11_find_keys(PKCS11_TOKEN *token, unsigned int type)
Packit 6b81fa
{
Packit 6b81fa
	PKCS11_SLOT *slot = TOKEN2SLOT(token);
Packit 6b81fa
	PKCS11_CTX *ctx = TOKEN2CTX(token);
Packit 6b81fa
	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
Packit 6b81fa
	CK_OBJECT_CLASS key_search_class;
Packit 6b81fa
	CK_ATTRIBUTE key_search_attrs[1] = {
Packit 6b81fa
		{CKA_CLASS, &key_search_class, sizeof(key_search_class)},
Packit 6b81fa
	};
Packit 6b81fa
	int rv, res = -1;
Packit 6b81fa
Packit 6b81fa
	/* Tell the PKCS11 lib to enumerate all matching objects */
Packit 6b81fa
	key_search_class = type;
Packit 6b81fa
	rv = CRYPTOKI_call(ctx,
Packit 6b81fa
		C_FindObjectsInit(spriv->session, key_search_attrs, 1));
Packit 6b81fa
	CRYPTOKI_checkerr(CKR_F_PKCS11_FIND_KEYS, rv);
Packit 6b81fa
Packit 6b81fa
	do {
Packit 6b81fa
		res = pkcs11_next_key(ctx, token, spriv->session, type);
Packit 6b81fa
	} while (res == 0);
Packit 6b81fa
Packit 6b81fa
	CRYPTOKI_call(ctx, C_FindObjectsFinal(spriv->session));
Packit 6b81fa
Packit 6b81fa
	return (res < 0) ? -1 : 0;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
static int pkcs11_next_key(PKCS11_CTX *ctx, PKCS11_TOKEN *token,
Packit 6b81fa
		CK_SESSION_HANDLE session, CK_OBJECT_CLASS type)
Packit 6b81fa
{
Packit 6b81fa
	CK_OBJECT_HANDLE obj;
Packit 6b81fa
	CK_ULONG count;
Packit 6b81fa
	int rv;
Packit 6b81fa
Packit 6b81fa
	/* Get the next matching object */
Packit 6b81fa
	rv = CRYPTOKI_call(ctx, C_FindObjects(session, &obj, 1, &count));
Packit 6b81fa
	CRYPTOKI_checkerr(CKR_F_PKCS11_NEXT_KEY, rv);
Packit 6b81fa
Packit 6b81fa
	if (count == 0)
Packit 6b81fa
		return 1;
Packit 6b81fa
Packit 6b81fa
	if (pkcs11_init_key(ctx, token, session, obj, type, NULL))
Packit 6b81fa
		return -1;
Packit 6b81fa
Packit 6b81fa
	return 0;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
static int pkcs11_init_key(PKCS11_CTX *ctx, PKCS11_TOKEN *token,
Packit 6b81fa
		CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj,
Packit 6b81fa
		CK_OBJECT_CLASS type, PKCS11_KEY ** ret)
Packit 6b81fa
{
Packit 6b81fa
	PKCS11_TOKEN_private *tpriv = PRIVTOKEN(token);
Packit 6b81fa
	PKCS11_keys *keys = (type == CKO_PRIVATE_KEY) ? &tpriv->prv : &tpriv->pub;
Packit 6b81fa
	PKCS11_KEY_private *kpriv;
Packit 6b81fa
	PKCS11_KEY *key, *tmp;
Packit 6b81fa
	CK_KEY_TYPE key_type;
Packit 6b81fa
	PKCS11_KEY_ops *ops;
Packit 6b81fa
	size_t size;
Packit 6b81fa
	int i;
Packit 6b81fa
Packit 6b81fa
	(void)ctx;
Packit 6b81fa
	(void)session;
Packit 6b81fa
Packit 6b81fa
	/* Ignore unknown key types */
Packit 6b81fa
	size = sizeof(CK_KEY_TYPE);
Packit 6b81fa
	if (pkcs11_getattr_var(token, obj, CKA_KEY_TYPE, (CK_BYTE *)&key_type, &size))
Packit 6b81fa
		return -1;
Packit 6b81fa
	switch (key_type) {
Packit 6b81fa
	case CKK_RSA:
Packit 6b81fa
		ops = &pkcs11_rsa_ops;
Packit 6b81fa
		break;
Packit 6b81fa
	case CKK_EC:
Packit 6b81fa
		ops = pkcs11_ec_ops;
Packit 6b81fa
		if (ops == NULL)
Packit 6b81fa
			return 0; /* not supported */
Packit 6b81fa
		break;
Packit 6b81fa
	default:
Packit 6b81fa
		/* Ignore any keys we don't understand */
Packit 6b81fa
		return 0;
Packit 6b81fa
	}
Packit 6b81fa
Packit 6b81fa
	/* Prevent re-adding existing PKCS#11 object handles */
Packit 6b81fa
	/* TODO: Rewrite the O(n) algorithm as O(log n),
Packit 6b81fa
	 * or it may be too slow with a large number of keys */
Packit 6b81fa
	for (i=0; i < keys->num; ++i)
Packit 6b81fa
		if (PRIVKEY(keys->keys + i)->object == obj)
Packit 6b81fa
			return 0;
Packit 6b81fa
Packit 6b81fa
	/* Allocate memory */
Packit 6b81fa
	kpriv = OPENSSL_malloc(sizeof(PKCS11_KEY_private));
Packit 6b81fa
	if (kpriv == NULL)
Packit 6b81fa
		return -1;
Packit 6b81fa
	memset(kpriv, 0, sizeof(PKCS11_KEY_private));
Packit 6b81fa
	tmp = OPENSSL_realloc(keys->keys, (keys->num + 1) * sizeof(PKCS11_KEY));
Packit 6b81fa
	if (tmp == NULL)
Packit 6b81fa
		return -1;
Packit 6b81fa
	keys->keys = tmp;
Packit 6b81fa
	key = keys->keys + keys->num++;
Packit 6b81fa
	memset(key, 0, sizeof(PKCS11_KEY));
Packit 6b81fa
Packit 6b81fa
	/* Fill public properties */
Packit 6b81fa
	pkcs11_getattr_alloc(token, obj, CKA_LABEL, (CK_BYTE **)&key->label, NULL);
Packit 6b81fa
	key->id_len = 0;
Packit 6b81fa
	pkcs11_getattr_alloc(token, obj, CKA_ID, &key->id, &key->id_len);
Packit 6b81fa
	key->isPrivate = (type == CKO_PRIVATE_KEY);
Packit 6b81fa
Packit 6b81fa
	/* Fill private properties */
Packit 6b81fa
	key->_private = kpriv;
Packit 6b81fa
	kpriv->object = obj;
Packit 6b81fa
	kpriv->parent = token;
Packit 6b81fa
	kpriv->id_len = sizeof kpriv->id;
Packit 6b81fa
	if (pkcs11_getattr_var(token, obj, CKA_ID, kpriv->id, &kpriv->id_len))
Packit 6b81fa
		kpriv->id_len = 0;
Packit 6b81fa
	kpriv->ops = ops;
Packit 6b81fa
	kpriv->forkid = get_forkid();
Packit 6b81fa
Packit 6b81fa
	if (ret)
Packit 6b81fa
		*ret = key;
Packit 6b81fa
	return 0;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
/*
Packit 6b81fa
 * Destroy all keys of a given type (public or private)
Packit 6b81fa
 */
Packit 6b81fa
void pkcs11_destroy_keys(PKCS11_TOKEN *token, unsigned int type)
Packit 6b81fa
{
Packit 6b81fa
	PKCS11_TOKEN_private *tpriv = PRIVTOKEN(token);
Packit 6b81fa
	PKCS11_keys *keys = (type == CKO_PRIVATE_KEY) ? &tpriv->prv : &tpriv->pub;
Packit 6b81fa
Packit 6b81fa
	while (keys->num > 0) {
Packit 6b81fa
		PKCS11_KEY *key = &keys->keys[--(keys->num)];
Packit 6b81fa
Packit 6b81fa
		if (key->evp_key)
Packit 6b81fa
			EVP_PKEY_free(key->evp_key);
Packit 6b81fa
		OPENSSL_free(key->label);
Packit 6b81fa
		if (key->id)
Packit 6b81fa
			OPENSSL_free(key->id);
Packit 6b81fa
		if (key->_private != NULL)
Packit 6b81fa
			OPENSSL_free(key->_private);
Packit 6b81fa
	}
Packit 6b81fa
	if (keys->keys)
Packit 6b81fa
		OPENSSL_free(keys->keys);
Packit 6b81fa
	keys->keys = NULL;
Packit 6b81fa
	keys->num = 0;
Packit 6b81fa
}
Packit 6b81fa
Packit 6b81fa
/* vim: set noexpandtab: */