diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2017-05-27 07:24:36 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2017-06-16 22:14:01 +0200 |
commit | 724d23d43dc50563d3dadbdc895e2637cdfb895e (patch) | |
tree | 401dbadad7cd27352a650253dbf2148c3de368b7 /lib/pkcs11_privkey.c | |
parent | 438682a23b55b001e66ec4ba1bd81e2e67f2b37e (diff) | |
download | gnutls-724d23d43dc50563d3dadbdc895e2637cdfb895e.tar.gz |
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 <nmav@gnutls.org>
Diffstat (limited to 'lib/pkcs11_privkey.c')
-rw-r--r-- | lib/pkcs11_privkey.c | 22 |
1 files changed, 18 insertions, 4 deletions
diff --git a/lib/pkcs11_privkey.c b/lib/pkcs11_privkey.c index 4bf907ee6a..186662785c 100644 --- a/lib/pkcs11_privkey.c +++ b/lib/pkcs11_privkey.c @@ -290,6 +290,7 @@ _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); @@ -312,10 +313,11 @@ _gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key, goto cleanup; } - 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"); @@ -326,6 +328,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); @@ -552,6 +559,7 @@ _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); @@ -575,10 +583,11 @@ _gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key, goto cleanup; } - 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"); @@ -589,6 +598,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); |