summaryrefslogtreecommitdiff
path: root/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c')
-rw-r--r--src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c184
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;
}