[prev in list] [next in list] [prev in thread] [next in thread] 

List:       strongswan-announce
Subject:    [strongSwan-dev] [PATCH] pkcs11: keyid alias
From:       Raphael Geissert <geissert () debian ! org>
Date:       2013-08-06 7:51:59
Message-ID: CAA7hUgHmR7hXjB9EQV13G_TKEoESYPeSu0fU9KPdQKRtZztMNw () mail ! gmail ! com
[Download RAW message or body]

Hi,

As briefly explained in IRC, the attached patches work around an issue
with charon-nm when the CKA_ID does not match the subject key
identifier. It is not pretty, I must admit, but it should work for
what I consider are "standard" users of the nm plugin: users with only
one token.

The first patch is just a bit of code refactoring. In the second patch
I'm using a 255 bytes buffer for the CKA_ID but now I think it is too
big. In any case, it is resized later on, so it shouldn't be a real
issue other than ("why 255?").

Please consider applying them.

Regards,
-- 
Raphael Geissert - Debian Developer
www.debian.org - get.debian.net

["0001-pkcs11-refactor-the-login-and-reauth-methods.patch" (application/octet-stream)]

From 3633d5efc5c192ca8b8ec76e2bf6ff0402df9bd6 Mon Sep 17 00:00:00 2001
From: Raphael Geissert <raphael-externe.geissert@edf.fr>
Date: Mon, 5 Aug 2013 16:05:15 +0200
Subject: [PATCH 1/2] pkcs11: refactor the login and reauth methods

Adds a generic_auth method to actually handle the login process.
---
 .../plugins/pkcs11/pkcs11_private_key.c            |   50 ++++++++------------
 1 file changed, 21 insertions(+), 29 deletions(-)

diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c \
b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c index bb9cc7a..a9d7017 100644
--- a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c
+++ b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c
@@ -184,10 +184,10 @@ CK_MECHANISM_PTR \
pkcs11_encryption_scheme_to_mech(encryption_scheme_t scheme)  }
 
 /**
- * Reauthenticate to do a signature
+ * Generic login, it takes the CKU
  */
-static bool reauth(private_pkcs11_private_key_t *this,
-				   CK_SESSION_HANDLE session)
+static bool generic_auth(private_pkcs11_private_key_t *this,
+				   CK_SESSION_HANDLE session, unsigned long type, identification_t *keyid)
 {
 	enumerator_t *enumerator;
 	shared_key_t *shared;
@@ -196,30 +196,41 @@ static bool reauth(private_pkcs11_private_key_t *this,
 	bool found = FALSE, success = FALSE;
 
 	enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
-												SHARED_PIN, this->keyid, NULL);
+												SHARED_PIN, keyid, NULL);
 	while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
 	{
 		found = TRUE;
 		pin = shared->get_key(shared);
-		rv = this->lib->f->C_Login(session, CKU_CONTEXT_SPECIFIC,
+		rv = this->lib->f->C_Login(session, type,
 								   pin.ptr, pin.len);
 		if (rv == CKR_OK)
 		{
 			success = TRUE;
 			break;
 		}
-		DBG1(DBG_CFG, "reauthentication login failed: %N", ck_rv_names, rv);
+		DBG1(DBG_CFG, "authentication login failed: %N", ck_rv_names, rv);
 	}
 	enumerator->destroy(enumerator);
 
 	if (!found)
 	{
-		DBG1(DBG_CFG, "private key requires reauthentication, but no PIN found");
+		DBG1(DBG_CFG, "private key requires authentication, but no PIN found for PKCS#11 \
key %Y", keyid);  return FALSE;
 	}
 	return success;
 }
 
+/**
+ * Reauthenticate to do a signature
+ */
+static bool reauth(private_pkcs11_private_key_t *this,
+				   CK_SESSION_HANDLE session)
+{
+	DBG1(DBG_CFG, "reauthentication in progress");
+
+	return generic_auth(this, session, CKU_CONTEXT_SPECIFIC, this->keyid);
+}
+
 METHOD(private_key_t, sign, bool,
 	private_pkcs11_private_key_t *this, signature_scheme_t scheme,
 	chunk_t data, chunk_t *signature)
@@ -527,12 +538,9 @@ static bool find_key(private_pkcs11_private_key_t *this, chunk_t \
                keyid)
  */
 static bool login(private_pkcs11_private_key_t *this, int slot)
 {
-	enumerator_t *enumerator;
-	shared_key_t *shared;
-	chunk_t pin;
 	CK_RV rv;
 	CK_SESSION_INFO info;
-	bool found = FALSE, success = FALSE;
+	bool success;
 
 	rv = this->lib->f->C_GetSessionInfo(this->session, &info);
 	if (rv != CKR_OK)
@@ -546,28 +554,12 @@ static bool login(private_pkcs11_private_key_t *this, int slot)
 		return TRUE;
 	}
 
-	enumerator = lib->credmgr->create_shared_enumerator(lib->credmgr,
-												SHARED_PIN, this->keyid, NULL);
-	while (enumerator->enumerate(enumerator, &shared, NULL, NULL))
+	success = generic_auth(this, this->session, CKU_USER, this->keyid);
+	if (!success)
 	{
-		found = TRUE;
-		pin = shared->get_key(shared);
-		rv = this->lib->f->C_Login(this->session, CKU_USER, pin.ptr, pin.len);
-		if (rv == CKR_OK)
-		{
-			success = TRUE;
-			break;
-		}
 		DBG1(DBG_CFG, "login to '%s':%d failed: %N",
 			 this->lib->get_name(this->lib), slot, ck_rv_names, rv);
 	}
-	enumerator->destroy(enumerator);
-
-	if (!found)
-	{
-		DBG1(DBG_CFG, "no PIN found for PKCS#11 key %Y", this->keyid);
-		return FALSE;
-	}
 	return success;
 }
 
-- 
1.7.10.4


["0002-pkcs11-allow-a-secondary-keyid-an-alias-to-be-used.patch" (application/octet-stream)]

From 27f975c05d1a4572889b2155b35ef9c572c2fd4a Mon Sep 17 00:00:00 2001
From: Raphael Geissert <raphael-externe.geissert@edf.fr>
Date: Mon, 5 Aug 2013 16:15:20 +0200
Subject: [PATCH 2/2] pkcs11: allow a secondary keyid (an "alias") to be used

This is mainly to workaround an issue with charon-nm when the CKA_ID
(objects) doesn't match the subject key id (x.509 certificate). When
the private key can not be found, charon-nm will now request the keyid
to be found - this is done by finding the first token where a pubkey/cert
is found. The CKA_ID of that object will then be used as an "alias" of
the original keyid.

This change should not affect anything else, as it requires a special,
negative, slot number to be passed to pkcs11_private_key_connect. Even
then, the alias is only tried *after* trying the original keyid.
---
 src/charon-nm/nm/nm_service.c                      |   10 ++
 .../plugins/pkcs11/pkcs11_private_key.c            |  153 ++++++++++++++++++--
 2 files changed, 152 insertions(+), 11 deletions(-)

diff --git a/src/charon-nm/nm/nm_service.c b/src/charon-nm/nm/nm_service.c
index 901abd3..17945ca 100644
--- a/src/charon-nm/nm/nm_service.c
+++ b/src/charon-nm/nm/nm_service.c
@@ -255,6 +255,16 @@ static identification_t \
*find_smartcard_key(NMStrongswanPluginPrivate *priv,  \
priv->creds->set_pin(priv->creds, keyid, pin);  key = lib->creds->create(lib->creds, \
CRED_PRIVATE_KEY,  KEY_ANY, BUILD_PKCS11_KEYID, keyid, BUILD_END);
+				if (!key)
+				{
+					DBG1(DBG_CFG, "Building the private key with keyid %#B failed", &keyid);
+					key = lib->creds->create(lib->creds, CRED_PRIVATE_KEY,
+								KEY_ANY, BUILD_PKCS11_KEYID, keyid, BUILD_PKCS11_SLOT, -0x1057, BUILD_END);
+					if (!key)
+					{
+						DBG1(DBG_CFG, "building by slot didn't work either");
+					}
+				}
 				if (key)
 				{
 					/* prefer a more convenient subjectAltName */
diff --git a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c \
b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c index a9d7017..29da98f 100644
--- a/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c
+++ b/src/libstrongswan/plugins/pkcs11/pkcs11_private_key.c
@@ -67,6 +67,11 @@ struct private_pkcs11_private_key_t {
 	identification_t *keyid;
 
 	/**
+	 * Keyid (alias) of the key we use
+	 */
+	identification_t *keyid_alias;
+
+	/**
 	 * Associated public key
 	 */
 	public_key_t *pubkey;
@@ -228,7 +233,15 @@ static bool reauth(private_pkcs11_private_key_t *this,
 {
 	DBG1(DBG_CFG, "reauthentication in progress");
 
-	return generic_auth(this, session, CKU_CONTEXT_SPECIFIC, this->keyid);
+	if (generic_auth(this, session, CKU_CONTEXT_SPECIFIC, this->keyid))
+	{
+		return TRUE;
+	}
+	else if (this->keyid_alias)
+	{
+		return generic_auth(this, session, CKU_CONTEXT_SPECIFIC, this->keyid_alias);
+	}
+	return FALSE;
 }
 
 METHOD(private_key_t, sign, bool,
@@ -390,6 +403,10 @@ METHOD(private_key_t, destroy, void,
 			this->pubkey->destroy(this->pubkey);
 		}
 		this->keyid->destroy(this->keyid);
+		if (this->keyid_alias)
+		{
+			this->keyid_alias->destroy(this->keyid_alias);
+		}
 		this->lib->f->C_CloseSession(this->session);
 		free(this);
 	}
@@ -484,6 +501,81 @@ static pkcs11_library_t* find_lib_by_keyid(chunk_t keyid, int \
*slot,  }
 
 /**
+ * Find the PKCS#11 lib having an object of the given class, yeah, wild-guess
+ */
+static pkcs11_library_t* find_lib_and_keyid(chunk_t *keyid, int *slot,
+										   CK_OBJECT_CLASS class)
+{
+	pkcs11_manager_t *manager;
+	enumerator_t *enumerator;
+	pkcs11_library_t *p11, *found = NULL;
+	CK_SLOT_ID current;
+	chunk_t keyid_read = chunk_alloc(255);
+	CK_ATTRIBUTE attr[] = {
+		{CKA_ID, keyid_read.ptr, keyid_read.len},
+	};
+	memset(keyid_read.ptr, '\0', keyid_read.len);
+
+	manager = pkcs11_manager_get();
+	if (!manager)
+	{
+		return NULL;
+	}
+	enumerator = manager->create_token_enumerator(manager);
+	while (enumerator->enumerate(enumerator, &p11, &current))
+	{
+		/* look for a pubkey/cert, it is usually readable without login */
+		CK_ATTRIBUTE tmpl[] = {
+			{CKA_CLASS, &class, sizeof(class)},
+		};
+		CK_OBJECT_HANDLE object;
+		CK_SESSION_HANDLE session;
+		CK_RV rv;
+		enumerator_t *keys;
+
+		rv = p11->f->C_OpenSession(current, CKF_SERIAL_SESSION, NULL, NULL,
+								   &session);
+		if (rv != CKR_OK)
+		{
+			DBG1(DBG_CFG, "opening PKCS#11 session failed: %N",
+				 ck_rv_names, rv);
+			continue;
+		}
+		keys = p11->create_object_enumerator(p11, session,
+											 tmpl, countof(tmpl), attr, countof(attr));
+		if (keys->enumerate(keys, &object))
+		{
+			u_char *ptr_to_nul;
+			DBG1(DBG_CFG, "found key on PKCS#11 token '%s':%d",
+				 p11->get_name(p11), current);
+			ptr_to_nul = memchr(keyid_read.ptr, '\0', keyid_read.len);
+			if (!ptr_to_nul)
+			{
+				DBG1(DBG_CFG, "huh? no NUL in '%#B'? ", keyid_read);
+				chunk_free(&keyid_read);
+			}
+			else
+			{
+				keyid_read.len = (ptr_to_nul - keyid_read.ptr);
+				keyid_read.ptr = realloc(keyid_read.ptr, keyid_read.len);
+				DBG1(DBG_CFG, "Hope the correct CKA_ID is '%#B'", &keyid_read);
+				*keyid = keyid_read;
+			}
+			found = p11;
+			*slot = current;
+		}
+		keys->destroy(keys);
+		p11->f->C_CloseSession(session);
+		if (found)
+		{
+			break;
+		}
+	}
+	enumerator->destroy(enumerator);
+	return found;
+}
+
+/**
  * Find the key on the token
  */
 static bool find_key(private_pkcs11_private_key_t *this, chunk_t keyid)
@@ -536,7 +628,7 @@ static bool find_key(private_pkcs11_private_key_t *this, chunk_t \
keyid)  /**
  * Find a PIN and try to log in
  */
-static bool login(private_pkcs11_private_key_t *this, int slot)
+static bool login(private_pkcs11_private_key_t *this, int slot, identification_t \
*keyid)  {
 	CK_RV rv;
 	CK_SESSION_INFO info;
@@ -554,7 +646,7 @@ static bool login(private_pkcs11_private_key_t *this, int slot)
 		return TRUE;
 	}
 
-	success = generic_auth(this, this->session, CKU_USER, this->keyid);
+	success = generic_auth(this, this->session, CKU_USER, keyid);
 	if (!success)
 	{
 		DBG1(DBG_CFG, "login to '%s':%d failed: %N",
@@ -614,7 +706,7 @@ pkcs11_private_key_t *pkcs11_private_key_connect(key_type_t type, \
va_list args)  {
 	private_pkcs11_private_key_t *this;
 	char *module = NULL;
-	chunk_t keyid = chunk_empty;
+	chunk_t keyid = chunk_empty, keyid_alias = chunk_empty;
 	int slot = -1;
 	CK_RV rv;
 
@@ -673,6 +765,25 @@ pkcs11_private_key_t *pkcs11_private_key_connect(key_type_t \
type, va_list args)  return NULL;
 		}
 	}
+	else if (slot == -0x1057)
+	{
+		keyid_alias = chunk_clone(keyid);
+		this->lib = find_lib_and_keyid(&keyid_alias, &slot, CKO_PUBLIC_KEY);
+		if (!this->lib)
+		{
+			this->lib = find_lib_and_keyid(&keyid_alias, &slot, CKO_CERTIFICATE);
+		}
+		if (!this->lib)
+		{
+			DBG1(DBG_CFG, "no PKCS#11 module found having a keyid %#B", &keyid);
+			free(this);
+			return NULL;
+		}
+		else
+		{
+			DBG1(DBG_CFG, "found a PKCS#11 module in slot %d having a keyid %#B", slot, \
&keyid_alias); +		}
+	}
 	else
 	{
 		this->lib = find_lib_by_keyid(keyid, &slot, CKO_PUBLIC_KEY);
@@ -700,11 +811,19 @@ pkcs11_private_key_t *pkcs11_private_key_connect(key_type_t \
type, va_list args)  
 	this->slot = slot;
 	this->keyid = identification_create_from_encoding(ID_KEY_ID, keyid);
+	this->keyid_alias = NULL;
+	if (keyid_alias.ptr)
+	{
+		this->keyid_alias = identification_create_from_encoding(ID_KEY_ID, keyid_alias);
+	}
 
-	if (!login(this, slot))
+	if (!login(this, slot, this->keyid))
 	{
-		destroy(this);
-		return NULL;
+		if (this->keyid_alias && !login(this, slot, this->keyid_alias))
+		{
+			destroy(this);
+			return NULL;
+		}
 	}
 
 	if (!find_key(this, keyid))
@@ -719,10 +838,22 @@ pkcs11_private_key_t *pkcs11_private_key_connect(key_type_t \
type, va_list args)  this->pubkey = find_pubkey_in_certs(this, keyid);
 		if (!this->pubkey)
 		{
-			DBG1(DBG_CFG, "no public key or certificate found for private key "
-				 "on '%s':%d", module, slot);
-			destroy(this);
-			return NULL;
+			DBG1(DBG_CFG, "no public key or certificate found for private key (keyid '%#B') "
+				 "on '%s':%d", &keyid, module, slot);
+			if (!keyid_alias.ptr || !find_key(this, keyid_alias))
+			{
+				if (keyid_alias.ptr)
+				{
+					this->pubkey = find_pubkey_in_certs(this, keyid_alias);
+				}
+				if (!this->pubkey)
+				{
+					DBG1(DBG_CFG, "no public key or certificate found for private key (keyid '%#B') \
" +						 "on '%s':%d", &keyid_alias, module, slot);
+					destroy(this);
+					return NULL;
+				}
+			}
 		}
 	}
 
-- 
1.7.10.4



_______________________________________________
Dev mailing list
Dev@lists.strongswan.org
https://lists.strongswan.org/mailman/listinfo/dev

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic