diff options
Diffstat (limited to 'src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c')
-rw-r--r-- | src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c | 184 |
1 files changed, 133 insertions, 51 deletions
diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c index b4cc7a805..b616abc38 100644 --- a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c +++ b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c @@ -1,4 +1,7 @@ /* + * Copyright (C) 2011 Tobias Brunner + * Hochschule fuer Technik Rapperswil + * * Copyright (C) 2010 Martin Willi * Copyright (C) 2010 revosec AG * @@ -19,7 +22,6 @@ #include "pkcs11_manager.h" #include <debug.h> -#include <threading/mutex.h> typedef struct private_pkcs11_private_key_t private_pkcs11_private_key_t; @@ -39,14 +41,14 @@ struct private_pkcs11_private_key_t { pkcs11_library_t *lib; /** - * Token session + * Slot the token is in */ - CK_SESSION_HANDLE session; + CK_SLOT_ID slot; /** - * Mutex to lock session + * Token session */ - mutex_t *mutex; + CK_SESSION_HANDLE session; /** * Key object on the token @@ -72,12 +74,24 @@ struct private_pkcs11_private_key_t { * References to this key */ refcount_t ref; + + /** + * Type of this private key + */ + 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) { - return this->pubkey->get_type(this->pubkey); + return this->type; } METHOD(private_key_t, get_keysize, int, @@ -89,18 +103,45 @@ METHOD(private_key_t, get_keysize, int, /** * See header. */ -CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(signature_scheme_t scheme) +CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(signature_scheme_t scheme, + key_type_t type, size_t keylen, + hash_algorithm_t *hash) { static struct { signature_scheme_t scheme; CK_MECHANISM mechanism; + key_type_t type; + size_t keylen; + hash_algorithm_t hash; } mappings[] = { - {SIGN_RSA_EMSA_PKCS1_NULL, {CKM_RSA_PKCS, NULL, 0}}, - {SIGN_RSA_EMSA_PKCS1_SHA1, {CKM_SHA1_RSA_PKCS, NULL, 0}}, - {SIGN_RSA_EMSA_PKCS1_SHA256, {CKM_SHA256_RSA_PKCS, NULL, 0}}, - {SIGN_RSA_EMSA_PKCS1_SHA384, {CKM_SHA384_RSA_PKCS, NULL, 0}}, - {SIGN_RSA_EMSA_PKCS1_SHA512, {CKM_SHA512_RSA_PKCS, NULL, 0}}, - {SIGN_RSA_EMSA_PKCS1_MD5, {CKM_MD5_RSA_PKCS, NULL, 0}}, + {SIGN_RSA_EMSA_PKCS1_NULL, {CKM_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_UNKNOWN}, + {SIGN_RSA_EMSA_PKCS1_SHA1, {CKM_SHA1_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_UNKNOWN}, + {SIGN_RSA_EMSA_PKCS1_SHA256, {CKM_SHA256_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_UNKNOWN}, + {SIGN_RSA_EMSA_PKCS1_SHA384, {CKM_SHA384_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_UNKNOWN}, + {SIGN_RSA_EMSA_PKCS1_SHA512, {CKM_SHA512_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_UNKNOWN}, + {SIGN_RSA_EMSA_PKCS1_MD5, {CKM_MD5_RSA_PKCS, NULL, 0}, + KEY_RSA, 0, HASH_UNKNOWN}, + {SIGN_ECDSA_WITH_NULL, {CKM_ECDSA, NULL, 0}, + KEY_ECDSA, 0, HASH_UNKNOWN}, + {SIGN_ECDSA_WITH_SHA1_DER, {CKM_ECDSA_SHA1, NULL, 0}, + KEY_ECDSA, 0, HASH_UNKNOWN}, + {SIGN_ECDSA_WITH_SHA256_DER, {CKM_ECDSA, NULL, 0}, + KEY_ECDSA, 0, HASH_SHA256}, + {SIGN_ECDSA_WITH_SHA384_DER, {CKM_ECDSA, NULL, 0}, + KEY_ECDSA, 0, HASH_SHA384}, + {SIGN_ECDSA_WITH_SHA512_DER, {CKM_ECDSA, NULL, 0}, + KEY_ECDSA, 0, HASH_SHA512}, + {SIGN_ECDSA_256, {CKM_ECDSA, NULL, 0}, + KEY_ECDSA, 256, HASH_SHA256}, + {SIGN_ECDSA_384, {CKM_ECDSA, NULL, 0}, + KEY_ECDSA, 384, HASH_SHA384}, + {SIGN_ECDSA_521, {CKM_ECDSA, NULL, 0}, + KEY_ECDSA, 521, HASH_SHA512}, }; int i; @@ -108,6 +149,15 @@ CK_MECHANISM_PTR pkcs11_signature_scheme_to_mech(signature_scheme_t scheme) { if (mappings[i].scheme == scheme) { + size_t len = mappings[i].keylen; + if (mappings[i].type != type || (len && keylen != len)) + { + return NULL; + } + if (hash) + { + *hash = mappings[i].hash; + } return &mappings[i].mechanism; } } @@ -141,7 +191,8 @@ CK_MECHANISM_PTR pkcs11_encryption_scheme_to_mech(encryption_scheme_t scheme) /** * Reauthenticate to do a signature */ -static bool reauth(private_pkcs11_private_key_t *this) +static bool reauth(private_pkcs11_private_key_t *this, + CK_SESSION_HANDLE session) { enumerator_t *enumerator; shared_key_t *shared; @@ -155,7 +206,7 @@ static bool reauth(private_pkcs11_private_key_t *this) { found = TRUE; pin = shared->get_key(shared); - rv = this->lib->f->C_Login(this->session, CKU_CONTEXT_SPECIFIC, + rv = this->lib->f->C_Login(session, CKU_CONTEXT_SPECIFIC, pin.ptr, pin.len); if (rv == CKR_OK) { @@ -179,33 +230,61 @@ METHOD(private_key_t, sign, bool, chunk_t data, chunk_t *signature) { CK_MECHANISM_PTR mechanism; + CK_SESSION_HANDLE session; CK_BYTE_PTR buf; CK_ULONG len; CK_RV rv; + hash_algorithm_t hash_alg; + chunk_t hash = chunk_empty; - mechanism = pkcs11_signature_scheme_to_mech(scheme); + mechanism = pkcs11_signature_scheme_to_mech(scheme, this->type, + get_keysize(this), &hash_alg); if (!mechanism) { DBG1(DBG_LIB, "signature scheme %N not supported", signature_scheme_names, scheme); return FALSE; } - this->mutex->lock(this->mutex); - rv = this->lib->f->C_SignInit(this->session, mechanism, this->object); - if (this->reauth && !reauth(this)) + rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL, + &session); + if (rv != CKR_OK) { + DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv); + return FALSE; + } + rv = this->lib->f->C_SignInit(session, mechanism, this->object); + if (this->reauth && !reauth(this, session)) + { + this->lib->f->C_CloseSession(session); return FALSE; } if (rv != CKR_OK) { - this->mutex->unlock(this->mutex); + this->lib->f->C_CloseSession(session); DBG1(DBG_LIB, "C_SignInit() failed: %N", ck_rv_names, rv); return FALSE; } + if (hash_alg != HASH_UNKNOWN) + { + hasher_t *hasher = lib->crypto->create_hasher(lib->crypto, hash_alg); + if (!hasher) + { + this->lib->f->C_CloseSession(session); + return FALSE; + } + hasher->allocate_hash(hasher, data, &hash); + hasher->destroy(hasher); + data = hash; + } len = (get_keysize(this) + 7) / 8; + if (this->type == KEY_ECDSA) + { /* signature is twice the length of the base point order */ + len *= 2; + } buf = malloc(len); - rv = this->lib->f->C_Sign(this->session, data.ptr, data.len, buf, &len); - this->mutex->unlock(this->mutex); + rv = this->lib->f->C_Sign(session, data.ptr, data.len, buf, &len); + this->lib->f->C_CloseSession(session); + chunk_free(&hash); if (rv != CKR_OK) { DBG1(DBG_LIB, "C_Sign() failed: %N", ck_rv_names, rv); @@ -221,6 +300,7 @@ METHOD(private_key_t, decrypt, bool, chunk_t crypt, chunk_t *plain) { CK_MECHANISM_PTR mechanism; + CK_SESSION_HANDLE session; CK_BYTE_PTR buf; CK_ULONG len; CK_RV rv; @@ -232,22 +312,29 @@ METHOD(private_key_t, decrypt, bool, encryption_scheme_names, scheme); return FALSE; } - this->mutex->lock(this->mutex); - rv = this->lib->f->C_DecryptInit(this->session, mechanism, this->object); - if (this->reauth && !reauth(this)) + rv = this->lib->f->C_OpenSession(this->slot, CKF_SERIAL_SESSION, NULL, NULL, + &session); + if (rv != CKR_OK) { + DBG1(DBG_CFG, "opening PKCS#11 session failed: %N", ck_rv_names, rv); + return FALSE; + } + rv = this->lib->f->C_DecryptInit(session, mechanism, this->object); + if (this->reauth && !reauth(this, session)) + { + this->lib->f->C_CloseSession(session); return FALSE; } if (rv != CKR_OK) { - this->mutex->unlock(this->mutex); + this->lib->f->C_CloseSession(session); DBG1(DBG_LIB, "C_DecryptInit() failed: %N", ck_rv_names, rv); return FALSE; } len = (get_keysize(this) + 7) / 8; buf = malloc(len); - rv = this->lib->f->C_Decrypt(this->session, crypt.ptr, crypt.len, buf, &len); - this->mutex->unlock(this->mutex); + rv = this->lib->f->C_Decrypt(session, crypt.ptr, crypt.len, buf, &len); + this->lib->f->C_CloseSession(session); if (rv != CKR_OK) { DBG1(DBG_LIB, "C_Decrypt() failed: %N", ck_rv_names, rv); @@ -294,7 +381,6 @@ METHOD(private_key_t, destroy, void, { this->pubkey->destroy(this->pubkey); } - this->mutex->destroy(this->mutex); this->keyid->destroy(this->keyid); this->lib->f->C_CloseSession(this->session); free(this); @@ -311,7 +397,7 @@ static pkcs11_library_t* find_lib(char *module) pkcs11_library_t *p11, *found = NULL; CK_SLOT_ID slot; - manager = pkcs11_manager_get(); + manager = lib->get(lib, "pkcs11-manager"); if (!manager) { return NULL; @@ -339,7 +425,7 @@ static pkcs11_library_t* find_lib_by_keyid(chunk_t keyid, int *slot) pkcs11_library_t *p11, *found = NULL; CK_SLOT_ID current; - manager = pkcs11_manager_get(); + manager = lib->get(lib, "pkcs11-manager"); if (!manager) { return NULL; @@ -404,13 +490,11 @@ static bool find_key(private_pkcs11_private_key_t *this, chunk_t keyid) CK_BBOOL reauth = FALSE; CK_ATTRIBUTE attr[] = { {CKA_KEY_TYPE, &type, sizeof(type)}, - {CKA_MODULUS, NULL, 0}, - {CKA_PUBLIC_EXPONENT, NULL, 0}, {CKA_ALWAYS_AUTHENTICATE, &reauth, sizeof(reauth)}, }; enumerator_t *enumerator; - chunk_t modulus, pubexp; int count = countof(attr); + bool found = FALSE; /* do not use CKA_ALWAYS_AUTHENTICATE if not supported */ if (!(this->lib->get_features(this->lib) & PKCS11_ALWAYS_AUTH_KEYS)) @@ -421,26 +505,16 @@ static bool find_key(private_pkcs11_private_key_t *this, chunk_t keyid) this->session, tmpl, countof(tmpl), attr, count); if (enumerator->enumerate(enumerator, &object)) { + this->type = KEY_RSA; switch (type) { + case CKK_ECDSA: + this->type = KEY_ECDSA; + /* fall-through */ case CKK_RSA: - if (attr[1].ulValueLen == -1 || attr[2].ulValueLen == -1) - { - DBG1(DBG_CFG, "reading modulus/exponent from PKCS#1 failed"); - break; - } - modulus = chunk_create(attr[1].pValue, attr[1].ulValueLen); - pubexp = chunk_create(attr[2].pValue, attr[2].ulValueLen); - this->pubkey = lib->creds->create(lib->creds, CRED_PUBLIC_KEY, - KEY_RSA, BUILD_RSA_MODULUS, modulus, - BUILD_RSA_PUB_EXP, pubexp, BUILD_END); - if (!this->pubkey) - { - DBG1(DBG_CFG, "extracting public key from PKCS#11 RSA " - "private key failed"); - } this->reauth = reauth; this->object = object; + found = TRUE; break; default: DBG1(DBG_CFG, "PKCS#11 key type %d not supported", type); @@ -448,7 +522,7 @@ static bool find_key(private_pkcs11_private_key_t *this, chunk_t keyid) } } enumerator->destroy(enumerator); - return this->pubkey != NULL; + return found; } /** @@ -587,7 +661,7 @@ pkcs11_private_key_t *pkcs11_private_key_connect(key_type_t type, va_list args) return NULL; } - this->mutex = mutex_create(MUTEX_TYPE_DEFAULT); + this->slot = slot; this->keyid = identification_create_from_encoding(ID_KEY_ID, keyid); if (!login(this, slot)) @@ -602,5 +676,13 @@ 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); + return NULL; + } + return &this->public; } |