]> git.ipfire.org Git - thirdparty/gnutls.git/commitdiff
tests: added test for CKA_ALWAYS_AUTHENTICATE handling in PKCS#11
authorNikos Mavrogiannopoulos <nmav@redhat.com>
Mon, 3 Oct 2016 08:29:29 +0000 (10:29 +0200)
committerNikos Mavrogiannopoulos <nmav@redhat.com>
Mon, 3 Oct 2016 09:33:31 +0000 (11:33 +0200)
This checks whether GnuTLS properly calls login prior to any sign
operations when the object is marked as CKA_ALWAYS_AUTHENTICATE.

.gitignore
tests/Makefile.am
tests/pkcs11/pkcs11-mock-ext.h
tests/pkcs11/pkcs11-mock.c
tests/pkcs11/pkcs11-privkey-always-auth.c [new file with mode: 0644]

index 1eff3ec617caa1e8804455d50982556661b69cae..dd17b9895462b1143e3cb7a0ec8f7fd7157cf533 100644 (file)
@@ -879,6 +879,7 @@ tests/pkcs11/pkcs11-is-known
 tests/pkcs11/pkcs11-privkey
 tests/pkcs11/pkcs11-pubkey-import-ecdsa
 tests/pkcs11/pkcs11-pubkey-import-rsa
+tests/pkcs11/pkcs11-privkey-always-auth
 tests/softhsm-*.db/
 tests/status-request-missing
 tests/slow/cipher-openssl-compat
index f0b4885d3cf14fcb9198c7077e763bf563365806..7c070bc2276030d53343f08b9ff11f766b50a236 100644 (file)
@@ -179,10 +179,15 @@ pkcs11_privkey_fork_SOURCES = pkcs11/pkcs11-privkey-fork.c
 pkcs11_privkey_fork_DEPENDENCIES = libpkcs11mock1.la libutils.la
 pkcs11_privkey_fork_LDADD = $(LDADD) $(LIBDL)
 
+pkcs11_privkey_always_auth_SOURCES = pkcs11/pkcs11-privkey-always-auth.c
+pkcs11_privkey_always_auth_DEPENDENCIES = libpkcs11mock1.la libutils.la
+pkcs11_privkey_always_auth_LDADD = $(LDADD) $(LIBDL)
+
 ctests += pkcs11-cert-import-url-exts pkcs11-get-exts pkcs11-get-raw-issuer-exts \
        pkcs11-cert-import-url4-exts pkcs11/pkcs11-chainverify pkcs11/pkcs11-get-issuer pkcs11/pkcs11-is-known \
        pkcs11/pkcs11-combo pkcs11/pkcs11-privkey pkcs11/pkcs11-pubkey-import-rsa pkcs11/pkcs11-pubkey-import-ecdsa \
-       pkcs11-import-url-privkey pkcs11-privkey-fork pkcs11/pkcs11-ec-privkey-test
+       pkcs11-import-url-privkey pkcs11-privkey-fork pkcs11/pkcs11-ec-privkey-test \
+       pkcs11/pkcs11-privkey-always-auth
 
 
 endif
index 8b66b189bceb0d0603aa7553d6fd603b575f3abc..c2267e86b2d4a49d6e99c45bc5583ce88bff4f85 100644 (file)
@@ -26,5 +26,6 @@
 /* This flag instructs the module to return CKR_OK on sensitive
  * objects */
 #define MOCK_FLAG_BROKEN_GET_ATTRIBUTES 1
+#define MOCK_FLAG_ALWAYS_AUTH (1<<1)
 
 #endif
index 2cb11c41c82dc7b9facc292e604c8f682e584789..6bf63baed05923184df131043d91517f71e8b25c 100644 (file)
@@ -116,6 +116,7 @@ const char mock_pubkey[] =
 
 CK_BBOOL pkcs11_mock_initialized = CK_FALSE;
 CK_BBOOL pkcs11_mock_session_opened = CK_FALSE;
+CK_BBOOL pkcs11_mock_session_reauth = CK_FALSE;
 
 static session_ptr_st *mock_session = NULL;
 
@@ -702,8 +703,12 @@ CK_DEFINE_FUNCTION(CK_RV, C_Login)(CK_SESSION_HANDLE hSession, CK_USER_TYPE user
        if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession))
                return CKR_SESSION_HANDLE_INVALID;
 
-       if ((CKU_SO != userType) && (CKU_USER != userType))
+       if (pkcs11_mock_flags & MOCK_FLAG_ALWAYS_AUTH) {
+               if ((CKU_CONTEXT_SPECIFIC != userType) && (CKU_SO != userType) && (CKU_USER != userType))
+                       return CKR_USER_TYPE_INVALID;
+       } else if ((CKU_SO != userType) && (CKU_USER != userType)) {
                return CKR_USER_TYPE_INVALID;
+       }
 
        if (NULL == pPin)
                return CKR_ARGUMENTS_BAD;
@@ -742,6 +747,11 @@ CK_DEFINE_FUNCTION(CK_RV, C_Login)(CK_SESSION_HANDLE hSession, CK_USER_TYPE user
                        break;
        }
 
+       if (pkcs11_mock_flags & MOCK_FLAG_ALWAYS_AUTH && rv == CKR_USER_ALREADY_LOGGED_IN) {
+               rv = 0;
+       }
+
+       pkcs11_mock_session_reauth = 1;
        return rv;
 }
 
@@ -930,6 +940,19 @@ CK_DEFINE_FUNCTION(CK_RV, C_GetAttributeValue)(CK_SESSION_HANDLE hSession, CK_OB
                        t = CKK_RSA;
                        memcpy(pTemplate[i].pValue, &t, sizeof(CK_KEY_TYPE));
                }
+               else if (CKA_ALWAYS_AUTHENTICATE == pTemplate[i].type)
+               {
+                       CK_BBOOL t;
+                       if (pTemplate[i].ulValueLen != sizeof(CK_BBOOL))
+                               return CKR_ARGUMENTS_BAD;
+
+                       if (!(pkcs11_mock_flags & MOCK_FLAG_ALWAYS_AUTH)) {
+                               t = CK_FALSE;
+                       } else {
+                               t = CK_TRUE;
+                       }
+                       memcpy(pTemplate[i].pValue, &t, sizeof(CK_BBOOL));
+               }
                else if (CKA_ID == pTemplate[i].type)
                {
                        if (NULL != pTemplate[i].pValue)
@@ -1445,6 +1468,13 @@ CK_DEFINE_FUNCTION(CK_RV, C_DecryptInit)(CK_SESSION_HANDLE hSession, CK_MECHANIS
        if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession))
                return CKR_SESSION_HANDLE_INVALID;
 
+       if (pkcs11_mock_flags & MOCK_FLAG_ALWAYS_AUTH) {
+               if (!pkcs11_mock_session_reauth) {
+                       return CKR_USER_NOT_LOGGED_IN;
+               }
+               pkcs11_mock_session_reauth = 0;
+       }
+
        if (NULL == pMechanism)
                return CKR_ARGUMENTS_BAD;
 
@@ -1822,6 +1852,13 @@ CK_DEFINE_FUNCTION(CK_RV, C_SignInit)(CK_SESSION_HANDLE hSession, CK_MECHANISM_P
        if ((CK_FALSE == pkcs11_mock_session_opened) || (PKCS11_MOCK_CK_SESSION_ID != hSession))
                return CKR_SESSION_HANDLE_INVALID;
 
+       if (pkcs11_mock_flags & MOCK_FLAG_ALWAYS_AUTH) {
+               if (!pkcs11_mock_session_reauth) {
+                       return CKR_USER_NOT_LOGGED_IN;
+               }
+               pkcs11_mock_session_reauth = 0;
+       }
+
        if (NULL == pMechanism)
                return CKR_ARGUMENTS_BAD;
 
diff --git a/tests/pkcs11/pkcs11-privkey-always-auth.c b/tests/pkcs11/pkcs11-privkey-always-auth.c
new file mode 100644 (file)
index 0000000..3561c41
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2016 Red Hat, Inc.
+ *
+ * Author: Nikos Mavrogiannopoulos
+ *
+ * This file is part of GnuTLS.
+ *
+ * GnuTLS is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * GnuTLS is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with GnuTLS; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+#include <gnutls/abstract.h>
+#include <gnutls/pkcs11.h>
+
+#ifdef _WIN32
+
+void doit(void)
+{
+       exit(77);
+}
+
+#else
+
+# include "utils.h"
+# include "pkcs11-mock-ext.h"
+
+/* Tests whether a gnutls_privkey_t will work properly with a key marked
+ * as always authenticate */
+
+static unsigned pin_called = 0;
+static const char *_pin = "1234";
+
+# include <dlfcn.h>
+# define P11LIB "libpkcs11mock1.so"
+
+
+static void tls_log_func(int level, const char *str)
+{
+       fprintf(stderr, "|<%d>| %s", level, str);
+}
+
+static
+int pin_func(void* userdata, int attempt, const char* url, const char *label,
+               unsigned flags, char *pin, size_t pin_max)
+{
+       if (_pin == NULL)
+               return -1;
+
+       strcpy(pin, _pin);
+       pin_called++;
+       return 0;
+}
+
+void doit(void)
+{
+       int ret;
+       const char *lib;
+       gnutls_privkey_t key;
+       gnutls_pkcs11_obj_t obj;
+       gnutls_datum_t sig = {NULL, 0}, data;
+       unsigned flags = 0;
+
+       lib = getenv("P11MOCKLIB1");
+       if (lib == NULL)
+               lib = P11LIB;
+
+       {
+               void *dl;
+               unsigned int *pflags;
+
+               dl = dlopen(lib, RTLD_NOW);
+               if (dl == NULL) {
+                       fail("could not dlopen %s\n", lib);
+                       exit(1);
+               }
+
+               pflags = dlsym(dl, "pkcs11_mock_flags");
+               if (pflags == NULL) {
+                       fail("could find pkcs11_mock_flags\n");
+                       exit(1);
+               }
+
+               *pflags = MOCK_FLAG_ALWAYS_AUTH;
+       }
+
+       data.data = (void*)"\x38\x17\x0c\x08\xcb\x45\x8f\xd4\x87\x9c\x34\xb6\xf6\x08\x29\x4c\x50\x31\x2b\xbb";
+       data.size = 20;
+
+       ret = global_init();
+       if (ret != 0) {
+               fail("%d: %s\n", ret, gnutls_strerror(ret));
+               exit(1);
+       }
+
+       gnutls_global_set_log_function(tls_log_func);
+       if (debug)
+               gnutls_global_set_log_level(4711);
+
+       ret = gnutls_pkcs11_init(GNUTLS_PKCS11_FLAG_MANUAL, NULL);
+       if (ret != 0) {
+               fail("%d: %s\n", ret, gnutls_strerror(ret));
+               exit(1);
+       }
+
+       ret = gnutls_pkcs11_add_provider(lib, NULL);
+       if (ret != 0) {
+               fail("%d: %s\n", ret, gnutls_strerror(ret));
+               exit(1);
+       }
+
+       ret = gnutls_pkcs11_obj_init(&obj);
+       assert(ret>=0);
+
+       gnutls_pkcs11_obj_set_pin_function(obj, pin_func, NULL);
+
+       ret = gnutls_pkcs11_obj_import_url(obj, "pkcs11:object=test;type=private", GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
+       assert(ret>=0);
+
+       ret = gnutls_pkcs11_obj_get_flags(obj, &flags);
+       assert(ret>=0);
+
+       if (!(flags & GNUTLS_PKCS11_OBJ_FLAG_MARK_ALWAYS_AUTH)) {
+               fail("key object doesn't have the always authenticate flag\n");
+       }
+       gnutls_pkcs11_obj_deinit(obj);
+
+
+       ret = gnutls_privkey_init(&key);
+       assert(ret>=0);
+
+       gnutls_privkey_set_pin_function(key, pin_func, NULL);
+
+       ret = gnutls_privkey_import_url(key, "pkcs11:object=test", GNUTLS_PKCS11_OBJ_FLAG_LOGIN);
+       if (ret < 0) {
+               fail("%d: %s\n", ret, gnutls_strerror(ret));
+               exit(1);
+       }
+
+       pin_called = 0;
+
+       ret = gnutls_privkey_sign_hash(key, GNUTLS_DIG_SHA1, 0, &data, &sig);
+       if (ret < 0) {
+               fail("%d: %s\n", ret, gnutls_strerror(ret));
+               exit(1);
+       }
+
+       if (pin_called == 0) {
+               fail("PIN function wasn't called!\n");
+       }
+       pin_called = 0;
+
+       gnutls_free(sig.data);
+       sig.data = NULL;
+
+       /* call again - should re-authenticate */
+       ret = gnutls_privkey_sign_hash(key, GNUTLS_DIG_SHA1, 0, &data, &sig);
+       if (ret < 0) {
+               fail("%d: %s\n", ret, gnutls_strerror(ret));
+               exit(1);
+       }
+
+       if (pin_called == 0) {
+               fail("PIN function wasn't called twice!\n");
+       }
+       pin_called = 0;
+
+       gnutls_free(sig.data);
+       sig.data = NULL;
+
+       if (debug)
+               printf("done\n\n\n");
+
+       gnutls_privkey_deinit(key);
+       gnutls_pkcs11_deinit();
+       gnutls_global_deinit();
+}
+#endif