diff options
author | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2017-05-27 07:24:36 +0200 |
---|---|---|
committer | Nikos Mavrogiannopoulos <nmav@gnutls.org> | 2017-06-16 15:07:52 +0000 |
commit | 723a9c4366911710d66d29a8580ca5530f012907 (patch) | |
tree | 7b95dfad76f0cb32fd7e753e242dfb97d4c21cf8 /lib | |
parent | e798c51c992e0d780e000354c6c33fb7f3dea9b2 (diff) | |
download | gnutls-723a9c4366911710d66d29a8580ca5530f012907.tar.gz |
Handle specially safenet HSMs which cannot handle CKU_CONTEXT_SPECIFIC
These HSMs do not support CKA_ALWAYS_AUTHENTICATE, nor understand CKU_CONTEXT_SPECIFIC,
but rather return CKR_USER_NOT_LOGGED_IN on the first private key operation.
Try to discover that state by calling C_Login when CKR_USER_NOT_LOGGED_IN
is seen, and retrying with CKU_USER after CKU_CONTEXT_SPECIFIC login fails.
See discussion in https://github.com/OpenSC/libp11/issues/160
Signed-off-by: Nikos Mavrogiannopoulos <nmav@gnutls.org>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pkcs11.c | 13 | ||||
-rw-r--r-- | lib/pkcs11_privkey.c | 18 |
2 files changed, 26 insertions, 5 deletions
diff --git a/lib/pkcs11.c b/lib/pkcs11.c index 95b0cab13e..85954e72ad 100644 --- a/lib/pkcs11.c +++ b/lib/pkcs11.c @@ -2581,6 +2581,7 @@ pkcs11_login(struct pkcs11_session_info *sinfo, return 0; } + retry_login: /* For a token with a "protected" (out-of-band) authentication * path, calling login with a NULL username is all that is * required. */ @@ -2594,8 +2595,7 @@ pkcs11_login(struct pkcs11_session_info *sinfo, gnutls_assert(); _gnutls_debug_log ("p11: Protected login failed.\n"); - ret = GNUTLS_E_PKCS11_ERROR; - goto cleanup; + goto login_finished; } } @@ -2649,14 +2649,21 @@ pkcs11_login(struct pkcs11_session_info *sinfo, } while (rv == CKR_PIN_INCORRECT); + login_finished: _gnutls_debug_log("p11: Login result = %s (%lu)\n", (rv==0)?"ok":p11_kit_strerror(rv), rv); + if (rv == CKR_USER_TYPE_INVALID && user_type == CKU_CONTEXT_SPECIFIC) { + _gnutls_debug_log("p11: Retrying login with CKU_USER\n"); + /* PKCS#11 v2.10 don't know about CKU_CONTEXT_SPECIFIC */ + user_type = CKU_USER; + goto retry_login; + } 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 4bf907ee6a..d5772a0ae2 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 retried_login = 0; PKCS11_CHECK_INIT_PRIVKEY(key); @@ -312,7 +313,8 @@ _gnutls_pkcs11_privkey_sign_hash(gnutls_pkcs11_privkey_t key, goto cleanup; } - if (key->reauth) { + retry_login: + if (key->reauth || retried_login) { ret = pkcs11_login(&key->sinfo, &key->pin, key->uinfo, 0, 1); @@ -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 && retried_login == 0)) { + retried_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 retried_login = 0; PKCS11_CHECK_INIT_PRIVKEY(key); @@ -575,7 +583,8 @@ _gnutls_pkcs11_privkey_decrypt_data(gnutls_pkcs11_privkey_t key, goto cleanup; } - if (key->reauth) { + retry_login: + if (key->reauth || retried_login) { ret = pkcs11_login(&key->sinfo, &key->pin, key->uinfo, 0, 1); @@ -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 && retried_login == 0)) { + retried_login = 1; + goto retry_login; + } + if (rv != CKR_OK) { gnutls_assert(); ret = pkcs11_rv_to_err(rv); |