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-17 14:28:18 +0200
commit847d8fe8b4cc7e829d6b1370f53735e546c6704c (patch)
treecbdbce21205d74b47ae0c69155bac7aae6ac2dfd
parent7ad3962153f75b49929c40e942f21c21be766800 (diff)
downloadgnutls-847d8fe8b4cc7e829d6b1370f53735e546c6704c.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>
-rw-r--r--lib/pkcs11.c3
-rw-r--r--lib/pkcs11_privkey.c22
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);