From 847d8fe8b4cc7e829d6b1370f53735e546c6704c Mon Sep 17 00:00:00 2001 From: Nikos Mavrogiannopoulos Date: Sat, 27 May 2017 07:24:36 +0200 Subject: Handle specially safenet HSMs which request explicit authentication These HSMs return CKR_USER_NOT_LOGGED_IN on the first private key operation, instead of using CKA_ALWAYS_AUTHENTICATE or similar. Detect that state and retry login with CKU_USER. See discussion in https://github.com/OpenSC/libp11/issues/160 Signed-off-by: Nikos Mavrogiannopoulos --- lib/pkcs11.c | 3 +-- lib/pkcs11_privkey.c | 22 ++++++++++++++++++---- 2 files changed, 19 insertions(+), 6 deletions(-) diff --git a/lib/pkcs11.c b/lib/pkcs11.c index 26d88e51a8..9ca9863b43 100644 --- a/lib/pkcs11.c +++ b/lib/pkcs11.c @@ -2508,12 +2508,11 @@ pkcs11_login(struct pkcs11_session_info *sinfo, _gnutls_debug_log("p11: Login result = %lu\n", rv); - ret = (rv == CKR_OK || rv == CKR_USER_ALREADY_LOGGED_IN) ? 0 : pkcs11_rv_to_err(rv); - cleanup: + cleanup: return ret; } diff --git a/lib/pkcs11_privkey.c b/lib/pkcs11_privkey.c index dcffe5ff52..a97a7f5591 100644 --- a/lib/pkcs11_privkey.c +++ b/lib/pkcs11_privkey.c @@ -231,13 +231,15 @@ _gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key, gnutls_datum_t tmp = { NULL, 0 }; unsigned long siglen; struct pkcs11_session_info *sinfo; + unsigned req_login = 0; PKCS11_CHECK_INIT_PRIVKEY(key); - if (key->reauth) { + retry_login: + if (key->reauth || req_login) { ret = pkcs11_login(&key->sinfo, &key->pin, - key->uinfo, 0, 1); + key->uinfo, 0, 1-req_login); if (ret < 0) { gnutls_assert(); _gnutls_debug_log("PKCS #11 login failed, trying operation anyway\n"); @@ -263,6 +265,11 @@ _gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key, /* Work out how long the signature must be: */ rv = pkcs11_sign(sinfo->module, sinfo->pks, hash->data, hash->size, NULL, &siglen); + if (unlikely(rv == CKR_USER_NOT_LOGGED_IN && req_login == 0)) { + req_login = 1; + goto retry_login; + } + if (rv != CKR_OK) { gnutls_assert(); ret = pkcs11_rv_to_err(rv); @@ -474,16 +481,18 @@ _gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key, int ret; struct ck_mechanism mech; unsigned long siglen; + unsigned req_login = 0; PKCS11_CHECK_INIT_PRIVKEY(key); if (key->pk_algorithm != GNUTLS_PK_RSA) return gnutls_assert_val(GNUTLS_E_INVALID_REQUEST); - if (key->reauth) { + retry_login: + if (key->reauth || req_login) { ret = pkcs11_login(&key->sinfo, &key->pin, - key->uinfo, 0, 1); + key->uinfo, 0, 1-req_login); if (ret < 0) { gnutls_assert(); _gnutls_debug_log("PKCS #11 login failed, trying operation anyway\n"); @@ -507,6 +516,11 @@ _gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key, /* Work out how long the plaintext must be: */ rv = pkcs11_decrypt(key->sinfo.module, key->sinfo.pks, ciphertext->data, ciphertext->size, NULL, &siglen); + if (unlikely(rv == CKR_USER_NOT_LOGGED_IN && req_login == 0)) { + req_login = 1; + goto retry_login; + } + if (rv != CKR_OK) { gnutls_assert(); ret = pkcs11_rv_to_err(rv); -- cgit v1.2.1