summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikos Mavrogiannopoulos <nmav@gnutls.org>2017-05-27 07:24:36 +0200
committerNikos Mavrogiannopoulos <nmav@gnutls.org>2017-06-16 15:07:52 +0000
commit723a9c4366911710d66d29a8580ca5530f012907 (patch)
tree7b95dfad76f0cb32fd7e753e242dfb97d4c21cf8
parente798c51c992e0d780e000354c6c33fb7f3dea9b2 (diff)
downloadgnutls-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>
-rw-r--r--lib/pkcs11.c13
-rw-r--r--lib/pkcs11_privkey.c18
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);