Outstanding PKCS#11 issues

Douglas E Engert deengert at gmail.com
Thu Apr 19 22:22:21 AEST 2018



On 2/26/2018 12:00 PM, Jakub Jelen wrote:
> Hello everyone,
> 
> as you could have noticed over the years, there are several bugs for
> PKCS#11 improvement and integration which are slipping under the radar
> for several releases, but the most painful ones are constantly updated
> by community to build, work and make our lives better.
> 
> I wrote some of the patches, provided feedback to others, or offered
> other help here on mailing list, but did not get quite much any
> feedback, none of the patches (excluding some one-liners) are not
> incorporated, but usually not yet even reviewed or considered.
> 
> I believe using PKCS#11 as a store for private keys is a good practice
> and making OpenSSH work with it is a must. So again, I offering my help
>   in this area not limited to the following bugs (according to
> complexity and priority):
> 
> Bug 2430 - ssh-keygen should allow to login before reading public key
> from smart card
> Bug 2652 - PKCS11 login skipped if login required and no pin set
> Bug 2638 - Honor PKCS#11 CKA_ALWAYS_AUTHENTICATE attribute of the
> private objects
> Bug 2474 - Enabling ECDSA in PKCS#11 support for ssh-agent
> Bug 2817 - Add support for PKCS#11 URIs (RFC 7512)
> Bug 2472 - Add support to load additional certificates
> Bug 2075 - [PATCH] Enable key pair generation on a PCKS#11 device
> 
> Namely, the #2638 one will be a big problem after the release of OpenSC
> 0.18.0 [1], which is no longer allowing the workflow OpenSSH is using.
> 

In response to #2638, Attached are changes to 7.7p1 so the pin is used
for both the C_Login(CKU_USER) and C_Login(CKU_CONTEXT_SPECIFIC)
It can also work with a pin pad reader if [2] is applied but requires
user to enter pin twice.

Tested with NIST Demo card using AUTH key and SIGN Key.

PIV card enforces "PIN Always" for the SIGN key and OpenSC supports
this by returning CKA_ALWAYS_AUTHENTICATE=True for the SIGN key. The
Application requests this attribute and if True and does
C_Login(CKU_CONTEXT_SPECIFIC) just before the the C_Sign operation.






> 
> [1] https://github.com/OpenSC/OpenSC/pull/1256

[2] https://github.com/OpenSC/OpenSC/commit/dac9634d87e38ec899713d36a389816b0435b767


-- 

  Douglas E. Engert  <DEEngert at gmail.com>

-------------- next part --------------
From 981d0914d919afb56f452ba0507ddfaf7c99387a Mon Sep 17 00:00:00 2001
From: Doug Engert <deengert at gmail.com>
Date: Wed, 18 Apr 2018 09:09:05 -0500
Subject: [PATCH] PKCS11  Better C_Login to handle CKA_ALWAYS_AUTHENTICATE

 On branch pkcs11-c_login
 Changes to be committed:
	modified:   ssh-pkcs11.c
---
 ssh-pkcs11.c | 98 +++++++++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 68 insertions(+), 30 deletions(-)

diff --git a/ssh-pkcs11.c b/ssh-pkcs11.c
index 65a7b58..5b53f8e 100644
--- a/ssh-pkcs11.c
+++ b/ssh-pkcs11.c
@@ -216,6 +216,37 @@ pkcs11_find(struct pkcs11_provider *p, CK_ULONG slotidx, CK_ATTRIBUTE *attr,
 	return (ret);
 }
 
+/* read pin and do C_Login of type CKU_USER or CKU_CONTEXT_SPECIFIC */
+static int
+pkcs11_c_login(struct pkcs11_provider *provider, struct pkcs11_slotinfo *si, int cku, char **pin)
+{
+	CK_FUNCTION_LIST        *f;
+	CK_RV                   rv;
+	char			prompt[1041];
+
+	f = provider->function_list;
+	if (*pin == NULL) {
+		if (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
+			verbose("Deferring PIN entry to reader keypad.");
+		else {
+			snprintf(prompt, sizeof(prompt),
+			    "Enter%s PIN for '%s': ", cku==CKU_CONTEXT_SPECIFIC?" Context Specific":"", si->token.label);
+			*pin = read_passphrase(prompt, RP_ALLOW_EOF);
+			if (*pin == NULL)
+				return (-1);	/* bail out */
+		}
+	}
+	rv = f->C_Login(si->session, cku, (u_char *)*pin,
+	    (*pin != NULL) ? strlen(*pin) : 0);
+	    /* caller must zero out pin */
+	if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) {
+		error("C_Login failed: %lu", rv);
+		return (-1);
+	}
+	return 0;
+}
+
+
 /* openssl callback doing the actual signing operation */
 static int
 pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
@@ -237,7 +268,12 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
 		{CKA_ID, NULL, 0},
 		{CKA_SIGN, NULL, sizeof(true_val) }
 	};
-	char			*pin = NULL, prompt[1024];
+	CK_BBOOL		cka_always_authenticate = CK_FALSE;
+	CK_ATTRIBUTE		key_cka_always_authenticate[] = {
+		{CKA_ALWAYS_AUTHENTICATE, &cka_always_authenticate, sizeof(cka_always_authenticate) }
+	};
+		 
+	char			*pin = NULL;
 	int			rval = -1;
 
 	key_filter[0].pValue = &private_key_class;
@@ -260,25 +296,9 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
 			    " on reader keypad" : "");
 			return (-1);
 		}
-		if (si->token.flags & CKF_PROTECTED_AUTHENTICATION_PATH)
-			verbose("Deferring PIN entry to reader keypad.");
-		else {
-			snprintf(prompt, sizeof(prompt),
-			    "Enter PIN for '%s': ", si->token.label);
-			pin = read_passphrase(prompt, RP_ALLOW_EOF);
-			if (pin == NULL)
-				return (-1);	/* bail out */
-		}
-		rv = f->C_Login(si->session, CKU_USER, (u_char *)pin,
-		    (pin != NULL) ? strlen(pin) : 0);
-		if (pin != NULL) {
-			explicit_bzero(pin, strlen(pin));
-			free(pin);
-		}
-		if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) {
-			error("C_Login failed: %lu", rv);
-			return (-1);
-		}
+		rv = pkcs11_c_login(k11->provider, si, CKU_USER, &pin);
+		if (rv  != 0)
+		    return (-1);
 		si->logged_in = 1;
 	}
 	key_filter[1].pValue = k11->keyid;
@@ -287,16 +307,34 @@ pkcs11_rsa_private_encrypt(int flen, const u_char *from, u_char *to, RSA *rsa,
 	if (pkcs11_find(k11->provider, k11->slotidx, key_filter, 3, &obj) < 0 &&
 	    pkcs11_find(k11->provider, k11->slotidx, key_filter, 2, &obj) < 0) {
 		error("cannot find private key");
-	} else if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) {
-		error("C_SignInit failed: %lu", rv);
-	} else {
-		/* XXX handle CKR_BUFFER_TOO_SMALL */
-		tlen = RSA_size(rsa);
-		rv = f->C_Sign(si->session, (CK_BYTE *)from, flen, to, &tlen);
-		if (rv == CKR_OK) 
-			rval = tlen;
-		else 
-			error("C_Sign failed: %lu", rv);
+		goto fail;
+	}
+	/* If pkcs11 lib does support this, assume false get before C_SignInit */
+	f->C_GetAttributeValue(si->session, obj, key_cka_always_authenticate, 1);
+	if ((rv = f->C_SignInit(si->session, &mech, obj)) != CKR_OK) {
+			error("C_SignInit failed: %lu", rv);
+			goto fail;
+	}
+	if (cka_always_authenticate) {
+		/* if we have the PIN from above use it, or get it now */
+		rv = pkcs11_c_login(k11->provider, si, CKU_CONTEXT_SPECIFIC, &pin);
+		if (rv != CKR_OK && rv != CKR_USER_ALREADY_LOGGED_IN) {
+		    error("Context specific login failed %lu", rv);
+		    goto fail;
+		}
+	}
+	/* XXX handle CKR_BUFFER_TOO_SMALL */
+	tlen = RSA_size(rsa);
+	rv = f->C_Sign(si->session, (CK_BYTE *)from, flen, to, &tlen);
+	if (rv == CKR_OK)
+		rval = tlen;
+	else
+		error("C_Sign failed: %lu", rv);
+fail:
+	if (pin != NULL) {
+		explicit_bzero(pin, strlen(pin));
+		free(pin);
+		pin = NULL;
 	}
 	return (rval);
 }
-- 
2.7.4



More information about the openssh-unix-dev mailing list