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@xxxxxxxxx>
From 981d0914d919afb56f452ba0507ddfaf7c99387a Mon Sep 17 00:00:00 2001 From: Doug Engert <deengert@xxxxxxxxx> 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
_______________________________________________ openssh-unix-dev mailing list openssh-unix-dev@xxxxxxxxxxx https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev