pkcs11: ignore login error when traversing tokens
authorDaiki Ueno <dueno@redhat.com>
Wed, 19 Jun 2019 15:21:16 +0000 (17:21 +0200)
committerDaiki Ueno <dueno@redhat.com>
Thu, 11 Jul 2019 04:39:33 +0000 (06:39 +0200)
If a token is a general access device, it is expected that login
attempt to that token returns error:
https://github.com/p11-glue/p11-kit/blob/master/trust/module.c#L852

On the other hand, _pkcs11_traverse_tokens treats the error as fatal
and stops iteration.  This behavior prevents object search without
token specifier if such tokens are registered in the system.

Reported by Stanislav Zidek in
https://bugzilla.redhat.com/show_bug.cgi?id=1705478

Signed-off-by: Daiki Ueno <dueno@redhat.com>
.gitignore
lib/pkcs11.c
tests/Makefile.am
tests/p11-kit-load.sh
tests/pkcs11/list-objects.c [new file with mode: 0644]

index 85ae942f12003ffca50ef2b2dda18eb6b1c9435c..37f34bdcea15f19128975ef71116e739585b8f8b 100644 (file)
@@ -562,6 +562,7 @@ tests/pkcs11-privkey-safenet-always-auth
 tests/pkcs11-token-raw
 tests/pkcs11/gnutls_pcert_list_import_x509_file
 tests/pkcs11/gnutls_x509_crt_list_import_url
+tests/pkcs11/list-objects
 tests/pkcs11/pkcs11-chainverify
 tests/pkcs11/pkcs11-combo
 tests/pkcs11/pkcs11-ec-privkey-test
index de5309b2963fa2650332613942210b1e6f964409..2ef0e3e02524d030b57d969725d26da4c0d68c15 100644 (file)
@@ -1617,7 +1617,13 @@ _pkcs11_traverse_tokens(find_func_t find_func, void *input,
                                         info, flags);
                        if (ret < 0) {
                                gnutls_assert();
-                               return ret;
+                               pkcs11_close_session(&sinfo);
+
+                               /* treat the error as fatal only if
+                                * the token requires login */
+                               if (l_tinfo.flags & CKF_LOGIN_REQUIRED)
+                                       return ret;
+                               continue;
                        }
 
                        ret =
index a67f1549c23d5e8cfd5df8d947766f8c944c9108..7fe954f632e0185e62a34f21db23baf74e942147 100644 (file)
@@ -496,7 +496,7 @@ dist_check_SCRIPTS += p11-kit-trust.sh testpkcs11.sh certtool-pkcs11.sh
 if HAVE_PKCS11_TRUST_STORE
 if P11KIT_0_23_11_API
 dist_check_SCRIPTS += p11-kit-load.sh
-indirect_tests += pkcs11/list-tokens
+indirect_tests += pkcs11/list-tokens pkcs11/list-objects
 endif
 endif
 
index 3201a2c5fc694ffdb606c891dcd64fae0cb95ebd..419900f6a327bd98fca3222788a54a36aa5dc651 100755 (executable)
@@ -22,6 +22,7 @@
 srcdir="${srcdir:-.}"
 builddir="${builddir:-.}"
 CERTTOOL="${CERTTOOL:-../src/certtool${EXEEXT}}"
+P11TOOL="${P11TOOL:-../src/p11tool${EXEEXT}}"
 DIFF="${DIFF:-diff}"
 PKGCONFIG="${PKG_CONFIG:-$(which pkg-config)}"
 TMP_SOFTHSM_DIR="./softhsm-load.$$.tmp"
@@ -90,6 +91,12 @@ if test $? != 0; then
        exit 1
 fi
 
+GNUTLS_PIN="${PIN}" ${P11TOOL} --login --label GnuTLS-Test-RSA --generate-privkey rsa --provider "${SOFTHSM_MODULE}" pkcs11: --outfile /dev/null
+if test $? != 0; then
+       echo "failed to generate privkey"
+       exit 1
+fi
+
 FILTERTOKEN="sed s/token=.*//g"
 
 # Check whether both are listed
@@ -175,6 +182,22 @@ if test "$nr" != 2;then
        exit 1
 fi
 
+# Check whether public key and privkey are listed.
+nr=$(GNUTLS_PIN="${PIN}" ${builddir}/pkcs11/list-objects -o ${P11DIR} -t all pkcs11:token=GnuTLS-Test|sort -u|wc -l)
+if test "$nr" != 2;then
+       echo "Error in test 8: did not find all objects"
+       ${builddir}/pkcs11/list-objects -o ${P11DIR} -t all pkcs11:token=GnuTLS-Test
+       exit 1
+fi
+
+# Check whether all privkeys are listed even if trust module is registered.
+nr=$(GNUTLS_PIN="${PIN}" ${builddir}/pkcs11/list-objects -o ${P11DIR} -t privkey pkcs11:|sort -u|wc -l)
+if test "$nr" != 1;then
+       echo "Error in test 9: did not find privkey objects"
+       ${builddir}/pkcs11/list-objects -o ${P11DIR} -t privkey pkcs11:
+       exit 1
+fi
+
 rm -f ${P11DIR}/*
 rm -rf ${TMP_SOFTHSM_DIR}
 
diff --git a/tests/pkcs11/list-objects.c b/tests/pkcs11/list-objects.c
new file mode 100644 (file)
index 0000000..ab30cd5
--- /dev/null
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2016-2017 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 Lesser General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.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 <getopt.h>
+#define P11_KIT_FUTURE_UNSTABLE_API
+#include <p11-kit/p11-kit.h>
+#include "cert-common.h"
+
+/* lists the registered PKCS#11 modules by p11-kit.
+ */
+
+static void tls_log_func(int level, const char *str)
+{
+       fprintf(stderr, "|<%d>| %s", level, str);
+}
+
+static const char *opt_pin;
+
+static
+int pin_func(void* userdata, int attempt, const char* url, const char *label,
+            unsigned flags, char *pin, size_t pin_max)
+{
+       if (attempt == 0) {
+               strcpy(pin, opt_pin);
+               return 0;
+       }
+       return -1;
+}
+
+int main(int argc, char **argv)
+{
+       int ret;
+       unsigned i;
+       int opt;
+       char *url, *mod;
+       unsigned flags;
+       unsigned obj_flags = 0;
+       int attrs = GNUTLS_PKCS11_OBJ_ATTR_ALL;
+       gnutls_pkcs11_obj_t *crt_list;
+       unsigned int crt_list_size = 0;
+       const char *envvar;
+
+       ret = gnutls_global_init();
+       if (ret != 0) {
+               fprintf(stderr, "error at %d: %s\n", __LINE__, gnutls_strerror(ret));
+               exit(1);
+       }
+
+       gnutls_global_set_log_function(tls_log_func);
+
+       while((opt = getopt(argc, argv, "o:t:")) != -1) {
+               switch(opt) {
+                       case 'o':
+                               mod = strdup(optarg);
+                               p11_kit_override_system_files(NULL, NULL, mod, mod, NULL);
+                               break;
+                       case 't':
+                               /* specify the object type to list */
+                               if (strcmp(optarg, "all") == 0)
+                                       attrs = GNUTLS_PKCS11_OBJ_ATTR_ALL;
+                               else if (strcmp(optarg, "privkey") == 0)
+                                       attrs = GNUTLS_PKCS11_OBJ_ATTR_PRIVKEY;
+                               else {
+                                       fprintf(stderr, "Unknown object type %s\n", optarg);
+                                       exit(1);
+                               }
+                               break;
+                       default:
+                               fprintf(stderr, "Unknown option %c\n", (char)opt);
+                               exit(1);
+               }
+       }
+
+       if (optind == argc) {
+               fprintf(stderr, "specify URL\n");
+               exit(1);
+       }
+       url = argv[optind];
+
+       envvar = getenv("GNUTLS_PIN");
+       if (envvar && *envvar != '\0') {
+               opt_pin = envvar;
+               obj_flags |= GNUTLS_PKCS11_OBJ_FLAG_LOGIN;
+               gnutls_pkcs11_set_pin_function(pin_func, NULL);
+       }
+
+       ret = gnutls_pkcs11_token_get_flags(url, &flags);
+       if (ret < 0) {
+               flags = 0;
+       }
+
+       ret =
+           gnutls_pkcs11_obj_list_import_url2(&crt_list, &crt_list_size,
+                                              url, attrs, obj_flags);
+       if (ret != 0) {
+               fprintf(stderr, "error at %d: %s\n", __LINE__, gnutls_strerror(ret));
+               exit(1);
+       }
+
+       for (i = 0; i < crt_list_size; i++) {
+               char *output;
+
+               ret =
+                   gnutls_pkcs11_obj_export_url(crt_list[i], 0,
+                                                &output);
+               if (ret != 0) {
+                       fprintf(stderr, "error at %d: %s\n", __LINE__, gnutls_strerror(ret));
+                       exit(1);
+               }
+
+               fprintf(stdout, "%s\n", output);
+               gnutls_free(output);
+               gnutls_pkcs11_obj_deinit(crt_list[i]);
+       }
+       gnutls_free(crt_list);
+
+       gnutls_global_deinit();
+}