From: Tobias Brunner Date: Wed, 2 Nov 2011 18:11:46 +0000 (+0100) Subject: pkcs11: Lookup the public key of a private key by CKA_ID. X-Git-Tag: 4.6.0~25 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=30a3ede8cee48adb16ef73c9eddda1b7418d263f;p=thirdparty%2Fstrongswan.git 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. --- diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c index fd50d02871..fda6ae3925 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c @@ -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); diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c b/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c index 8be4a2b2f0..0be7b05091 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_public_key.c @@ -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; +}