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:
@@ -81,6 +81,13 @@ struct private_pkcs11_private_key_t {
|
|||||||
key_type_t type;
|
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,
|
METHOD(private_key_t, get_type, key_type_t,
|
||||||
private_pkcs11_private_key_t *this)
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this->pubkey = pkcs11_public_key_connect(this->lib, slot, this->type,
|
||||||
|
keyid);
|
||||||
if (!this->pubkey)
|
if (!this->pubkey)
|
||||||
{
|
{
|
||||||
destroy(this);
|
destroy(this);
|
||||||
|
|||||||
@@ -772,3 +772,119 @@ pkcs11_public_key_t *pkcs11_public_key_load(key_type_t type, va_list args)
|
|||||||
return NULL;
|
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;
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user