pkcs11: Lookup the public key of a private key by CKA_ID.

Currently this only works if a public key object with the same ID is
available, if there isn't one we could search for a certificate with the
same ID and extract the key from there.
This commit is contained in:
Tobias Brunner
2011-11-02 20:27:55 +01:00
parent 5d2fccf439
commit 30a3ede8ce
2 changed files with 125 additions and 0 deletions
@@ -81,6 +81,13 @@ struct private_pkcs11_private_key_t {
key_type_t type;
};
/**
* Implemented in pkcs11_public_key.c
*/
public_key_t *pkcs11_public_key_connect(pkcs11_library_t *p11,
int slot, key_type_t type, chunk_t keyid);
METHOD(private_key_t, get_type, key_type_t,
private_pkcs11_private_key_t *this)
{
@@ -613,6 +620,8 @@ pkcs11_private_key_t *pkcs11_private_key_connect(key_type_t type, va_list args)
return NULL;
}
this->pubkey = pkcs11_public_key_connect(this->lib, slot, this->type,
keyid);
if (!this->pubkey)
{
destroy(this);
@@ -772,3 +772,119 @@ pkcs11_public_key_t *pkcs11_public_key_load(key_type_t type, va_list args)
return NULL;
}
static private_pkcs11_public_key_t *find_key_by_keyid(pkcs11_library_t *p11,
int slot, key_type_t key_type,
chunk_t keyid)
{
CK_OBJECT_CLASS class = CKO_PUBLIC_KEY;
CK_KEY_TYPE type;
CK_ATTRIBUTE tmpl[] = {
{CKA_CLASS, &class, sizeof(class)},
{CKA_ID, keyid.ptr, keyid.len},
{CKA_KEY_TYPE, &type, sizeof(type)},
};
CK_OBJECT_HANDLE object;
CK_ATTRIBUTE attr[] = {
{CKA_KEY_TYPE, &type, sizeof(type)},
};
CK_SESSION_HANDLE session;
CK_RV rv;
enumerator_t *enumerator;
int count = countof(tmpl);
bool found = FALSE;
size_t keylen;
switch (type)
{
case KEY_RSA:
type = CKK_RSA;
break;
case KEY_ECDSA:
type = CKK_ECDSA;
break;
default:
/* don't specify key type on KEY_ANY */
count--;
break;
}
rv = p11->f->C_OpenSession(slot, CKF_SERIAL_SESSION, NULL, NULL, &session);
if (rv != CKR_OK)
{
DBG1(DBG_CFG, "opening public key session on '%s':%d failed: %N",
p11->get_name(p11), slot, ck_rv_names, rv);
return NULL;
}
enumerator = p11->create_object_enumerator(p11, session, tmpl, count, attr,
countof(attr));
if (enumerator->enumerate(enumerator, &object))
{
switch (type)
{
case CKK_ECDSA:
{
chunk_t ecparams;
if (p11->get_ck_attribute(p11, session, object, CKA_EC_PARAMS,
&ecparams) &&
keylen_from_ecparams(ecparams, &keylen))
{
chunk_free(&ecparams);
key_type = KEY_ECDSA;
found = TRUE;
}
break;
}
case CKK_RSA:
{
chunk_t n;
if (p11->get_ck_attribute(p11, session, object, CKA_MODULUS,
&n) && n.len > 0)
{
keylen = n.len * 8;
chunk_free(&n);
key_type = KEY_RSA;
found = TRUE;
}
break;
}
default:
DBG1(DBG_CFG, "PKCS#11 key type %d not supported", type);
break;
}
}
enumerator->destroy(enumerator);
if (found)
{
return create(key_type, keylen, p11, slot, session, object);
}
p11->f->C_CloseSession(session);
return NULL;
}
/**
* Find a public key on the given token with a specific keyid.
*
* Used by pkcs11_private_key_t.
*
* TODO: if no public key is found, we should perhaps search for a certificate
* with the given keyid and extract the key from there
*
* @param p11 PKCS#11 module
* @param slot slot id
* @param type type of the key
* @param keyid key id
*/
pkcs11_public_key_t *pkcs11_public_key_connect(pkcs11_library_t *p11,
int slot, key_type_t type, chunk_t keyid)
{
private_pkcs11_public_key_t *this;
this = find_key_by_keyid(p11, slot, type, keyid);
if (!this)
{
return NULL;
}
return &this->public;
}