vishalmishra434 / rpms / openssh

Forked from rpms/openssh a month ago
Clone
Dmitry Belyavskiy 8f4d19
diff -up openssh-8.7p1/configure.ac.pkcs11-uri openssh-8.7p1/configure.ac
Dmitry Belyavskiy 8f4d19
--- openssh-8.7p1/configure.ac.pkcs11-uri	2021-08-30 13:07:43.646699953 +0200
Dmitry Belyavskiy 8f4d19
+++ openssh-8.7p1/configure.ac	2021-08-30 13:07:43.662700088 +0200
Dmitry Belyavskiy 8f4d19
@@ -1985,12 +1985,14 @@ AC_LINK_IFELSE(
Jakub Jelen def1de
 	[AC_DEFINE([HAVE_ISBLANK], [1], [Define if you have isblank(3C).])
Jakub Jelen def1de
 ])
Jakub Jelen def1de
 
Jakub Jelen def1de
+SCARD_MSG="yes"
Jakub Jelen def1de
 disable_pkcs11=
Jakub Jelen def1de
 AC_ARG_ENABLE([pkcs11],
Jakub Jelen def1de
 	[  --disable-pkcs11        disable PKCS#11 support code [no]],
Jakub Jelen def1de
 	[
Jakub Jelen def1de
 		if test "x$enableval" = "xno" ; then
Jakub Jelen def1de
 			disable_pkcs11=1
Jakub Jelen def1de
+			SCARD_MSG="no"
Jakub Jelen def1de
 		fi
Jakub Jelen def1de
 	]
Jakub Jelen def1de
 )
Dmitry Belyavskiy 8f4d19
@@ -2019,6 +2021,40 @@ AC_SEARCH_LIBS([dlopen], [dl])
Jakub Jelen 51f5c1
 AC_CHECK_FUNCS([dlopen])
Jakub Jelen 51f5c1
 AC_CHECK_DECL([RTLD_NOW], [], [], [#include <dlfcn.h>])
Jakub Jelen def1de
 
Jakub Jelen def1de
+# Check whether we have a p11-kit, we got default provider on command line
Jakub Jelen def1de
+DEFAULT_PKCS11_PROVIDER_MSG="no"
Jakub Jelen def1de
+AC_ARG_WITH([default-pkcs11-provider],
Jakub Jelen def1de
+	[  --with-default-pkcs11-provider[[=PATH]]   Use default pkcs11 provider (p11-kit detected by default)],
Jakub Jelen def1de
+	[ if test "x$withval" != "xno" && test "x$disable_pkcs11" = "x"; then
Jakub Jelen def1de
+		if test "x$withval" = "xyes" ; then
Jakub Jelen def1de
+			AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no])
Jakub Jelen def1de
+			if test "x$PKGCONFIG" != "xno"; then
Jakub Jelen def1de
+				AC_MSG_CHECKING([if $PKGCONFIG knows about p11-kit])
Jakub Jelen def1de
+				if "$PKGCONFIG" "p11-kit-1"; then
Jakub Jelen def1de
+					AC_MSG_RESULT([yes])
Jakub Jelen def1de
+					use_pkgconfig_for_p11kit=yes
Jakub Jelen def1de
+				else
Jakub Jelen def1de
+					AC_MSG_RESULT([no])
Jakub Jelen def1de
+				fi
Jakub Jelen def1de
+			fi
Jakub Jelen def1de
+		else
Jakub Jelen def1de
+			PKCS11_PATH="${withval}"
Jakub Jelen def1de
+		fi
Jakub Jelen def1de
+		if test "x$use_pkgconfig_for_p11kit" = "xyes"; then
Jakub Jelen def1de
+			PKCS11_PATH=`$PKGCONFIG --variable=proxy_module p11-kit-1`
Jakub Jelen def1de
+		fi
Jakub Jelen def1de
+		AC_CHECK_FILE("$PKCS11_PATH",
Jakub Jelen def1de
+			[ AC_DEFINE_UNQUOTED([PKCS11_DEFAULT_PROVIDER], ["$PKCS11_PATH"], [Path to default PKCS#11 provider (p11-kit proxy)])
Jakub Jelen def1de
+			  DEFAULT_PKCS11_PROVIDER_MSG="$PKCS11_PATH"
Jakub Jelen def1de
+			],
Jakub Jelen def1de
+			[ AC_MSG_ERROR([Requested PKCS11 provided not found]) ]
Jakub Jelen def1de
+		)
Jakub Jelen def1de
+	else
Jakub Jelen def1de
+		AC_MSG_WARN([Needs PKCS11 support to enable default pkcs11 provider])
Jakub Jelen def1de
+	fi ]
Jakub Jelen def1de
+)
Jakub Jelen def1de
+
Jakub Jelen def1de
+
Jakub Jelen def1de
 # IRIX has a const char return value for gai_strerror()
Jakub Jelen def1de
 AC_CHECK_FUNCS([gai_strerror], [
Jakub Jelen def1de
 	AC_DEFINE([HAVE_GAI_STRERROR])
Dmitry Belyavskiy 8f4d19
@@ -5624,6 +5660,7 @@ echo "                  BSD Auth support
Jakub Jelen def1de
 echo "              Random number source: $RAND_MSG"
Jakub Jelen def1de
 echo "             Privsep sandbox style: $SANDBOX_STYLE"
Jakub Jelen 51f5c1
 echo "                   PKCS#11 support: $enable_pkcs11"
Jakub Jelen def1de
+echo "          Default PKCS#11 provider: $DEFAULT_PKCS11_PROVIDER_MSG"
Jakub Jelen 51f5c1
 echo "                  U2F/FIDO support: $enable_sk"
Jakub Jelen def1de
 
Jakub Jelen def1de
 echo ""
Dmitry Belyavskiy 8f4d19
diff -up openssh-8.7p1/Makefile.in.pkcs11-uri openssh-8.7p1/Makefile.in
Dmitry Belyavskiy 8f4d19
--- openssh-8.7p1/Makefile.in.pkcs11-uri	2021-08-30 13:07:43.571699324 +0200
Dmitry Belyavskiy 8f4d19
+++ openssh-8.7p1/Makefile.in	2021-08-30 13:07:43.663700096 +0200
Dmitry Belyavskiy f32b84
@@ -103,7 +103,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
Dmitry Belyavskiy f32b84
 	monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-ecdsa-sk.o \
Dmitry Belyavskiy f32b84
 	ssh-ed25519-sk.o ssh-rsa.o dh.o \
Dmitry Belyavskiy f32b84
 	msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \
Dmitry Belyavskiy f32b84
-	ssh-pkcs11.o smult_curve25519_ref.o \
Dmitry Belyavskiy f32b84
+	ssh-pkcs11.o ssh-pkcs11-uri.o smult_curve25519_ref.o \
Dmitry Belyavskiy f32b84
 	poly1305.o chacha.o cipher-chachapoly.o cipher-chachapoly-libcrypto.o \
Dmitry Belyavskiy f32b84
 	ssh-ed25519.o digest-openssl.o digest-libc.o \
Dmitry Belyavskiy f32b84
 	hmac.o sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o \
Dmitry Belyavskiy 8f4d19
@@ -302,6 +302,8 @@ clean:	regressclean
Dmitry Belyavskiy f32b84
 	rm -f regress/unittests/sshsig/test_sshsig$(EXEEXT)
Dmitry Belyavskiy f32b84
 	rm -f regress/unittests/utf8/*.o
Dmitry Belyavskiy f32b84
 	rm -f regress/unittests/utf8/test_utf8$(EXEEXT)
Dmitry Belyavskiy f32b84
+	rm -f regress/unittests/pkcs11/*.o
Dmitry Belyavskiy f32b84
+	rm -f regress/unittests/pkcs11/test_pkcs11$(EXEEXT)
Dmitry Belyavskiy f32b84
 	rm -f regress/misc/sk-dummy/*.o
Dmitry Belyavskiy f32b84
 	rm -f regress/misc/sk-dummy/*.lo
Dmitry Belyavskiy f32b84
 	rm -f regress/misc/sk-dummy/sk-dummy.so
Dmitry Belyavskiy 8f4d19
@@ -339,6 +341,8 @@ distclean:	regressclean
Dmitry Belyavskiy f32b84
 	rm -f regress/unittests/sshsig/test_sshsig
Dmitry Belyavskiy f32b84
 	rm -f regress/unittests/utf8/*.o
Dmitry Belyavskiy f32b84
 	rm -f regress/unittests/utf8/test_utf8
Dmitry Belyavskiy f32b84
+	rm -f regress/unittests/pkcs11/*.o
Dmitry Belyavskiy f32b84
+	rm -f regress/unittests/pkcs11/test_pkcs11
Dmitry Belyavskiy 03150f
	rm -f regress/misc/sk-dummy/*.o
Dmitry Belyavskiy 03150f
	rm -f regress/misc/sk-dummy/*.lo
Dmitry Belyavskiy 03150f
	rm -f regress/misc/sk-dummy/sk-dummy.so
Dmitry Belyavskiy 8f4d19
@@ -513,6 +517,7 @@ regress-prep:
Dmitry Belyavskiy f32b84
 	$(MKDIR_P) `pwd`/regress/unittests/sshkey
Dmitry Belyavskiy f32b84
 	$(MKDIR_P) `pwd`/regress/unittests/sshsig
Dmitry Belyavskiy f32b84
 	$(MKDIR_P) `pwd`/regress/unittests/utf8
Dmitry Belyavskiy f32b84
+	$(MKDIR_P) `pwd`/regress/unittests/pkcs11
Dmitry Belyavskiy f32b84
 	$(MKDIR_P) `pwd`/regress/misc/sk-dummy
Dmitry Belyavskiy f32b84
 	[ -f `pwd`/regress/Makefile ] || \
Dmitry Belyavskiy f32b84
 	    ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile
Dmitry Belyavskiy 8f4d19
@@ -677,6 +682,16 @@ regress/unittests/utf8/test_utf8$(EXEEXT
Dmitry Belyavskiy f32b84
 	    regress/unittests/test_helper/libtest_helper.a \
Dmitry Belyavskiy f32b84
 	    -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
Dmitry Belyavskiy f32b84
 
Dmitry Belyavskiy f32b84
+UNITTESTS_TEST_PKCS11_OBJS=\
Dmitry Belyavskiy f32b84
+	regress/unittests/pkcs11/tests.o
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+regress/unittests/pkcs11/test_pkcs11$(EXEEXT): \
Dmitry Belyavskiy f32b84
+    ${UNITTESTS_TEST_PKCS11_OBJS} \
Dmitry Belyavskiy f32b84
+    regress/unittests/test_helper/libtest_helper.a libssh.a
Dmitry Belyavskiy f32b84
+	$(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_PKCS11_OBJS) \
Dmitry Belyavskiy f32b84
+	    regress/unittests/test_helper/libtest_helper.a \
Dmitry Belyavskiy f32b84
+	    -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
 # These all need to be compiled -fPIC, so they are treated differently.
Dmitry Belyavskiy f32b84
 SK_DUMMY_OBJS=\
Dmitry Belyavskiy f32b84
 	regress/misc/sk-dummy/sk-dummy.lo \
Dmitry Belyavskiy 8f4d19
@@ -711,7 +726,8 @@ regress-unit-binaries: regress-prep $(RE
Dmitry Belyavskiy 8f4d19
 	regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \
Dmitry Belyavskiy f32b84
 	regress/unittests/sshkey/test_sshkey$(EXEEXT) \
Dmitry Belyavskiy f32b84
 	regress/unittests/sshsig/test_sshsig$(EXEEXT) \
Dmitry Belyavskiy 8f4d19
-	regress/unittests/utf8/test_utf8$(EXEEXT)
Dmitry Belyavskiy 8f4d19
+	regress/unittests/utf8/test_utf8$(EXEEXT) \
Dmitry Belyavskiy f32b84
+	regress/unittests/pkcs11/test_pkcs11$(EXEEXT) \
Dmitry Belyavskiy f32b84
 
Dmitry Belyavskiy f32b84
 tests:	file-tests t-exec interop-tests unit
Dmitry Belyavskiy f32b84
 	echo all tests passed
Dmitry Belyavskiy 8f4d19
diff -up openssh-8.7p1/regress/agent-pkcs11.sh.pkcs11-uri openssh-8.7p1/regress/agent-pkcs11.sh
Dmitry Belyavskiy 8f4d19
--- openssh-8.7p1/regress/agent-pkcs11.sh.pkcs11-uri	2021-08-20 06:03:49.000000000 +0200
Dmitry Belyavskiy 8f4d19
+++ openssh-8.7p1/regress/agent-pkcs11.sh	2021-08-30 13:07:43.663700096 +0200
Dmitry Belyavskiy f32b84
@@ -113,7 +113,7 @@ else
Dmitry Belyavskiy f32b84
 	done
Dmitry Belyavskiy f32b84
 
Dmitry Belyavskiy f32b84
 	trace "remove pkcs11 keys"
Dmitry Belyavskiy f32b84
-	echo ${TEST_SSH_PIN} | notty ${SSHADD} -e ${TEST_SSH_PKCS11} > /dev/null 2>&1
Dmitry Belyavskiy f32b84
+	${SSHADD} -e ${TEST_SSH_PKCS11} > /dev/null 2>&1
Dmitry Belyavskiy f32b84
 	r=$?
Dmitry Belyavskiy f32b84
 	if [ $r -ne 0 ]; then
Dmitry Belyavskiy f32b84
 		fail "ssh-add -e failed: exit code $r"
Dmitry Belyavskiy 8f4d19
diff -up openssh-8.7p1/regress/Makefile.pkcs11-uri openssh-8.7p1/regress/Makefile
Dmitry Belyavskiy 8f4d19
--- openssh-8.7p1/regress/Makefile.pkcs11-uri	2021-08-20 06:03:49.000000000 +0200
Dmitry Belyavskiy 8f4d19
+++ openssh-8.7p1/regress/Makefile	2021-08-30 13:07:43.663700096 +0200
Dmitry Belyavskiy 8f4d19
@@ -122,7 +122,8 @@ CLEANFILES=	*.core actual agent-key.* au
Jakub Jelen def1de
 		known_hosts known_hosts-cert known_hosts.* krl-* ls.copy \
Jakub Jelen def1de
 		modpipe netcat no_identity_config \
Jakub Jelen 36fef5
 		pidfile putty.rsa2 ready regress.log remote_pid \
Jakub Jelen 36fef5
-		revoked-* rsa rsa-agent rsa-agent.pub rsa.pub rsa_ssh2_cr.prv \
Jakub Jelen 36fef5
+		revoked-* rsa rsa-agent rsa-agent.pub rsa-agent-cert.pub \
Jakub Jelen 36fef5
+		rsa.pub rsa_ssh2_cr.prv pkcs11*.crt pkcs11*.key pkcs11.info \
Jakub Jelen 36fef5
 		rsa_ssh2_crnl.prv scp-ssh-wrapper.exe \
Jakub Jelen def1de
 		scp-ssh-wrapper.scp setuid-allowed sftp-server.log \
Jakub Jelen def1de
 		sftp-server.sh sftp.log ssh-log-wrapper.sh ssh.log \
Dmitry Belyavskiy 8f4d19
@@ -252,8 +253,9 @@ unit:
Jakub Jelen def1de
 		V="" ; \
Jakub Jelen def1de
 		test "x${USE_VALGRIND}" = "x" || \
Jakub Jelen def1de
 		    V=${.CURDIR}/valgrind-unit.sh ; \
Dmitry Belyavskiy f32b84
-		 $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \
Dmitry Belyavskiy f32b84
-		 $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \
Jakub Jelen def1de
+		$$V ${.OBJDIR}/unittests/pkcs11/test_pkcs11 ; \
Dmitry Belyavskiy f32b84
+		$$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \
Dmitry Belyavskiy f32b84
+		$$V ${.OBJDIR}/unittests/sshkey/test_sshkey \
Jakub Jelen def1de
 			-d ${.CURDIR}/unittests/sshkey/testdata ; \
Dmitry Belyavskiy f32b84
 		$$V ${.OBJDIR}/unittests/sshsig/test_sshsig \
Dmitry Belyavskiy f32b84
 			-d ${.CURDIR}/unittests/sshsig/testdata ; \
Dmitry Belyavskiy 8f4d19
diff -up openssh-8.7p1/regress/pkcs11.sh.pkcs11-uri openssh-8.7p1/regress/pkcs11.sh
Dmitry Belyavskiy 8f4d19
--- openssh-8.7p1/regress/pkcs11.sh.pkcs11-uri	2021-08-30 13:07:43.663700096 +0200
Dmitry Belyavskiy 8f4d19
+++ openssh-8.7p1/regress/pkcs11.sh	2021-08-30 13:07:43.663700096 +0200
Jakub Jelen 51f5c1
@@ -0,0 +1,349 @@
Jakub Jelen def1de
+#
Jakub Jelen def1de
+#  Copyright (c) 2017 Red Hat
Jakub Jelen def1de
+#
Jakub Jelen def1de
+#  Authors: Jakub Jelen <jjelen@redhat.com>
Jakub Jelen def1de
+#
Jakub Jelen def1de
+#  Permission to use, copy, modify, and distribute this software for any
Jakub Jelen def1de
+#  purpose with or without fee is hereby granted, provided that the above
Jakub Jelen def1de
+#  copyright notice and this permission notice appear in all copies.
Jakub Jelen def1de
+#
Jakub Jelen def1de
+#  THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
Jakub Jelen def1de
+#  WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
Jakub Jelen def1de
+#  MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
Jakub Jelen def1de
+#  ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
Jakub Jelen def1de
+#  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
Jakub Jelen def1de
+#  ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Jakub Jelen def1de
+#  OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Jakub Jelen def1de
+
Jakub Jelen def1de
+tid="pkcs11 tests with soft token"
Jakub Jelen def1de
+
Jakub Jelen def1de
+try_token_libs() {
Jakub Jelen def1de
+	for _lib in "$@" ; do
Jakub Jelen def1de
+		if test -f "$_lib" ; then
Jakub Jelen def1de
+			verbose "Using token library $_lib"
Jakub Jelen def1de
+			TEST_SSH_PKCS11="$_lib"
Jakub Jelen def1de
+			return
Jakub Jelen def1de
+		fi
Jakub Jelen def1de
+	done
Jakub Jelen def1de
+	echo "skipped: Unable to find PKCS#11 token library"
Jakub Jelen def1de
+	exit 0
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+try_token_libs \
Jakub Jelen def1de
+	/usr/local/lib/softhsm/libsofthsm2.so \
Jakub Jelen def1de
+	/usr/lib64/pkcs11/libsofthsm2.so \
Jakub Jelen def1de
+	/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so
Jakub Jelen def1de
+
Jakub Jelen def1de
+TEST_SSH_PIN=1234
Jakub Jelen def1de
+TEST_SSH_SOPIN=12345678
Jakub Jelen def1de
+if [ "x$TEST_SSH_SSHPKCS11HELPER" != "x" ]; then
Jakub Jelen def1de
+	SSH_PKCS11_HELPER="${TEST_SSH_SSHPKCS11HELPER}"
Jakub Jelen def1de
+	export SSH_PKCS11_HELPER
Jakub Jelen def1de
+fi
Jakub Jelen def1de
+
Jakub Jelen def1de
+test -f "$TEST_SSH_PKCS11" || fatal "$TEST_SSH_PKCS11 does not exist"
Jakub Jelen def1de
+
Jakub Jelen def1de
+# setup environment for softhsm token
Jakub Jelen def1de
+DIR=$OBJ/SOFTHSM
Jakub Jelen def1de
+rm -rf $DIR
Jakub Jelen def1de
+TOKEN=$DIR/tokendir
Jakub Jelen def1de
+mkdir -p $TOKEN
Jakub Jelen def1de
+SOFTHSM2_CONF=$DIR/softhsm2.conf
Jakub Jelen def1de
+export SOFTHSM2_CONF
Jakub Jelen def1de
+cat > $SOFTHSM2_CONF << EOF
Jakub Jelen def1de
+# SoftHSM v2 configuration file
Jakub Jelen def1de
+directories.tokendir = ${TOKEN}
Jakub Jelen def1de
+objectstore.backend = file
Jakub Jelen def1de
+# ERROR, WARNING, INFO, DEBUG
Jakub Jelen def1de
+log.level = DEBUG
Jakub Jelen def1de
+# If CKF_REMOVABLE_DEVICE flag should be set
Jakub Jelen def1de
+slots.removable = false
Jakub Jelen def1de
+EOF
Jakub Jelen def1de
+out=$(softhsm2-util --init-token --free --label token-slot-0 --pin "$TEST_SSH_PIN" --so-pin "$TEST_SSH_SOPIN")
Jakub Jelen def1de
+slot=$(echo -- $out | sed 's/.* //')
Jakub Jelen def1de
+
Jakub Jelen def1de
+# prevent ssh-agent from calling ssh-askpass
Jakub Jelen def1de
+SSH_ASKPASS=/usr/bin/true
Jakub Jelen def1de
+export SSH_ASKPASS
Jakub Jelen def1de
+unset DISPLAY
Jakub Jelen def1de
+# We need interactive access to test PKCS# since it prompts for PIN
Jakub Jelen def1de
+sed -i 's/.*BatchMode.*//g' $OBJ/ssh_proxy
Jakub Jelen def1de
+
Jakub Jelen def1de
+# start command w/o tty, so ssh accepts pin from stdin (from agent-pkcs11.sh)
Jakub Jelen def1de
+notty() {
Jakub Jelen def1de
+	perl -e 'use POSIX; POSIX::setsid();
Jakub Jelen def1de
+	    if (fork) { wait; exit($? >> 8); } else { exec(@ARGV) }' "$@"
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+trace "generating keys"
Jakub Jelen def1de
+ID1="02"
Jakub Jelen def1de
+ID2="04"
Jakub Jelen def1de
+RSA=${DIR}/RSA
Jakub Jelen def1de
+EC=${DIR}/EC
Jakub Jelen def1de
+openssl genpkey -algorithm rsa > $RSA
Jakub Jelen def1de
+openssl pkcs8 -nocrypt -in $RSA |\
Jakub Jelen def1de
+    softhsm2-util --slot "$slot" --label "SSH RSA Key $ID1" --id $ID1 \
Jakub Jelen def1de
+	--pin "$TEST_SSH_PIN" --import /dev/stdin
Jakub Jelen def1de
+openssl genpkey \
Jakub Jelen def1de
+    -genparam \
Jakub Jelen def1de
+    -algorithm ec \
Jakub Jelen def1de
+    -pkeyopt ec_paramgen_curve:prime256v1 |\
Jakub Jelen def1de
+    openssl genpkey \
Jakub Jelen def1de
+    -paramfile /dev/stdin > $EC
Jakub Jelen def1de
+openssl pkcs8 -nocrypt -in $EC |\
Jakub Jelen def1de
+    softhsm2-util --slot "$slot" --label "SSH ECDSA Key $ID2" --id $ID2 \
Jakub Jelen def1de
+	--pin "$TEST_SSH_PIN" --import /dev/stdin
Jakub Jelen def1de
+
Jakub Jelen def1de
+trace "List the keys in the ssh-keygen with PKCS#11 URIs"
Jakub Jelen def1de
+${SSHKEYGEN} -D ${TEST_SSH_PKCS11} > $OBJ/token_keys
Jakub Jelen def1de
+if [ $? -ne 0 ]; then
Jakub Jelen 51f5c1
+	fail "FAIL: keygen fails to enumerate keys on PKCS#11 token"
Jakub Jelen def1de
+fi
Jakub Jelen def1de
+grep "pkcs11:" $OBJ/token_keys > /dev/null
Jakub Jelen def1de
+if [ $? -ne 0 ]; then
Jakub Jelen 51f5c1
+	fail "FAIL: The keys from ssh-keygen do not contain PKCS#11 URI as a comment"
Jakub Jelen def1de
+fi
Jakub Jelen 51f5c1
+
Jakub Jelen 51f5c1
+# Set the ECDSA key to authorized keys
Jakub Jelen 51f5c1
+grep "ECDSA" $OBJ/token_keys > $OBJ/authorized_keys_$USER
Jakub Jelen def1de
+
Jakub Jelen def1de
+trace "Simple connect with ssh (without PKCS#11 URI)"
Jakub Jelen def1de
+echo ${TEST_SSH_PIN} | notty ${SSH} -I ${TEST_SSH_PKCS11} \
Jakub Jelen def1de
+    -F $OBJ/ssh_proxy somehost exit 5
Jakub Jelen def1de
+r=$?
Jakub Jelen def1de
+if [ $r -ne 5 ]; then
Jakub Jelen 51f5c1
+	fail "FAIL: ssh connect with pkcs11 failed (exit code $r)"
Jakub Jelen def1de
+fi
Jakub Jelen def1de
+
Jakub Jelen def1de
+trace "Connect with PKCS#11 URI"
Jakub Jelen 51f5c1
+trace "  (ECDSA key should succeed)"
Jakub Jelen def1de
+echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
Jakub Jelen 51f5c1
+    -i "pkcs11:id=%${ID2}?module-path=${TEST_SSH_PKCS11}" somehost exit 5
Jakub Jelen def1de
+r=$?
Jakub Jelen def1de
+if [ $r -ne 5 ]; then
Jakub Jelen 51f5c1
+	fail "FAIL: ssh connect with PKCS#11 URI failed (exit code $r)"
Jakub Jelen def1de
+fi
Jakub Jelen def1de
+
Jakub Jelen 51f5c1
+trace "  (RSA key should fail)"
Jakub Jelen def1de
+echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
Jakub Jelen 51f5c1
+     -i "pkcs11:id=%${ID1}?module-path=${TEST_SSH_PKCS11}" somehost exit 5
Jakub Jelen def1de
+r=$?
Jakub Jelen def1de
+if [ $r -eq 5 ]; then
Jakub Jelen 51f5c1
+	fail "FAIL: ssh connect with PKCS#11 URI succeeded (should fail)"
Jakub Jelen def1de
+fi
Jakub Jelen def1de
+
Jakub Jelen def1de
+trace "Connect with PKCS#11 URI including PIN should not prompt"
Jakub Jelen 51f5c1
+trace "  (ECDSA key should succeed)"
Jakub Jelen def1de
+${SSH} -F $OBJ/ssh_proxy -i \
Jakub Jelen 51f5c1
+    "pkcs11:id=%${ID2}?module-path=${TEST_SSH_PKCS11}&pin-value=${TEST_SSH_PIN}" somehost exit 5
Jakub Jelen def1de
+r=$?
Jakub Jelen def1de
+if [ $r -ne 5 ]; then
Jakub Jelen 51f5c1
+	fail "FAIL: ssh connect with PKCS#11 URI failed (exit code $r)"
Jakub Jelen def1de
+fi
Jakub Jelen def1de
+
Jakub Jelen 51f5c1
+trace "  (RSA key should fail)"
Jakub Jelen def1de
+${SSH} -F $OBJ/ssh_proxy -i \
Jakub Jelen 51f5c1
+    "pkcs11:id=%${ID1}?module-path=${TEST_SSH_PKCS11}&pin-value=${TEST_SSH_PIN}" somehost exit 5
Jakub Jelen def1de
+r=$?
Jakub Jelen def1de
+if [ $r -eq 5 ]; then
Jakub Jelen 51f5c1
+	fail "FAIL: ssh connect with PKCS#11 URI succeeded (should fail)"
Jakub Jelen def1de
+fi
Jakub Jelen def1de
+
Jakub Jelen def1de
+trace "Connect with various filtering options in PKCS#11 URI"
Jakub Jelen 51f5c1
+trace "  (by object label, ECDSA should succeed)"
Jakub Jelen def1de
+echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
Jakub Jelen 51f5c1
+    -i "pkcs11:object=SSH%20ECDSA%20Key%2004?module-path=${TEST_SSH_PKCS11}" somehost exit 5
Jakub Jelen def1de
+r=$?
Jakub Jelen def1de
+if [ $r -ne 5 ]; then
Jakub Jelen 51f5c1
+	fail "FAIL: ssh connect with PKCS#11 URI failed (exit code $r)"
Jakub Jelen def1de
+fi
Jakub Jelen def1de
+
Jakub Jelen 51f5c1
+trace "  (by object label, RSA key should fail)"
Jakub Jelen def1de
+echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
Jakub Jelen 51f5c1
+     -i "pkcs11:object=SSH%20RSA%20Key%2002?module-path=${TEST_SSH_PKCS11}" somehost exit 5
Jakub Jelen def1de
+r=$?
Jakub Jelen def1de
+if [ $r -eq 5 ]; then
Jakub Jelen 51f5c1
+	fail "FAIL: ssh connect with PKCS#11 URI succeeded (should fail)"
Jakub Jelen def1de
+fi
Jakub Jelen def1de
+
Jakub Jelen 51f5c1
+trace "  (by token label, ECDSA key should succeed)"
Jakub Jelen def1de
+echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
Jakub Jelen 51f5c1
+    -i "pkcs11:id=%${ID2};token=token-slot-0?module-path=${TEST_SSH_PKCS11}" somehost exit 5
Jakub Jelen def1de
+r=$?
Jakub Jelen def1de
+if [ $r -ne 5 ]; then
Jakub Jelen 51f5c1
+	fail "FAIL: ssh connect with PKCS#11 URI failed (exit code $r)"
Jakub Jelen def1de
+fi
Jakub Jelen def1de
+
Jakub Jelen def1de
+trace "  (by wrong token label, should fail)"
Jakub Jelen def1de
+echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
Jakub Jelen 51f5c1
+     -i "pkcs11:token=token-slot-99?module-path=${TEST_SSH_PKCS11}" somehost exit 5
Jakub Jelen def1de
+r=$?
Jakub Jelen def1de
+if [ $r -eq 5 ]; then
Jakub Jelen 51f5c1
+	fail "FAIL: ssh connect with PKCS#11 URI succeeded (should fail)"
Jakub Jelen def1de
+fi
Jakub Jelen def1de
+
Jakub Jelen def1de
+
Jakub Jelen def1de
+
Jakub Jelen def1de
+
Jakub Jelen def1de
+trace "Test PKCS#11 URI specification in configuration files"
Jakub Jelen 51f5c1
+echo "IdentityFile \"pkcs11:id=%${ID2}?module-path=${TEST_SSH_PKCS11}\"" \
Jakub Jelen def1de
+    >> $OBJ/ssh_proxy
Jakub Jelen 51f5c1
+trace "  (ECDSA key should succeed)"
Jakub Jelen def1de
+echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy somehost exit 5
Jakub Jelen def1de
+r=$?
Jakub Jelen def1de
+if [ $r -ne 5 ]; then
Jakub Jelen 51f5c1
+	fail "FAIL: ssh connect with PKCS#11 URI in config failed (exit code $r)"
Jakub Jelen def1de
+fi
Jakub Jelen def1de
+
Jakub Jelen 51f5c1
+# Set the RSA key as authorized
Jakub Jelen 51f5c1
+grep "RSA" $OBJ/token_keys > $OBJ/authorized_keys_$USER
Jakub Jelen 51f5c1
+
Jakub Jelen 51f5c1
+trace "  (RSA key should fail)"
Jakub Jelen def1de
+echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy somehost exit 5
Jakub Jelen def1de
+r=$?
Jakub Jelen def1de
+if [ $r -eq 5 ]; then
Jakub Jelen 51f5c1
+	fail "FAIL: ssh connect with PKCS#11 URI in config succeeded (should fail)"
Jakub Jelen def1de
+fi
Jakub Jelen def1de
+sed -i -e "/IdentityFile/d" $OBJ/ssh_proxy
Jakub Jelen def1de
+
Jakub Jelen def1de
+trace "Test PKCS#11 URI specification in configuration files with bogus spaces"
Jakub Jelen 51f5c1
+echo "IdentityFile \"    pkcs11:?module-path=${TEST_SSH_PKCS11}    \"" \
Jakub Jelen def1de
+    >> $OBJ/ssh_proxy
Jakub Jelen def1de
+echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy somehost exit 5
Jakub Jelen def1de
+r=$?
Jakub Jelen def1de
+if [ $r -ne 5 ]; then
Jakub Jelen 51f5c1
+	fail "FAIL: ssh connect with PKCS#11 URI with bogus spaces in config failed" \
Jakub Jelen def1de
+	    "(exit code $r)"
Jakub Jelen def1de
+fi
Jakub Jelen def1de
+sed -i -e "/IdentityFile/d" $OBJ/ssh_proxy
Jakub Jelen def1de
+
Jakub Jelen def1de
+
Jakub Jelen def1de
+trace "Combination of PKCS11Provider and PKCS11URI on commandline"
Jakub Jelen 51f5c1
+trace "  (RSA key should succeed)"
Jakub Jelen def1de
+echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
Jakub Jelen 51f5c1
+    -i "pkcs11:id=%${ID1}" -I ${TEST_SSH_PKCS11} somehost exit 5
Jakub Jelen def1de
+r=$?
Jakub Jelen def1de
+if [ $r -ne 5 ]; then
Jakub Jelen 51f5c1
+	fail "FAIL: ssh connect with PKCS#11 URI and provider combination" \
Jakub Jelen def1de
+	    "failed (exit code $r)"
Jakub Jelen def1de
+fi
Jakub Jelen def1de
+
Jakub Jelen def1de
+trace "Regress: Missing provider in PKCS11URI option"
Jakub Jelen def1de
+${SSH} -F $OBJ/ssh_proxy \
Jakub Jelen def1de
+    -o IdentityFile=\"pkcs11:token=segfault\" somehost exit 5
Jakub Jelen def1de
+r=$?
Jakub Jelen def1de
+if [ $r -eq 139 ]; then
Jakub Jelen 51f5c1
+	fail "FAIL: ssh connect with missing provider_id from configuration option" \
Jakub Jelen def1de
+	    "crashed (exit code $r)"
Jakub Jelen def1de
+fi
Jakub Jelen def1de
+
Jakub Jelen def1de
+
Jakub Jelen def1de
+trace "SSH Agent can work with PKCS#11 URI"
Jakub Jelen def1de
+trace "start the agent"
Jakub Jelen 51f5c1
+eval `${SSHAGENT} -s` >  /dev/null
Jakub Jelen def1de
+
Jakub Jelen def1de
+r=$?
Jakub Jelen def1de
+if [ $r -ne 0 ]; then
Jakub Jelen def1de
+	fail "could not start ssh-agent: exit code $r"
Jakub Jelen def1de
+else
Jakub Jelen def1de
+	trace "add whole provider to agent"
Jakub Jelen def1de
+	echo ${TEST_SSH_PIN} | notty ${SSHADD} \
Jakub Jelen 51f5c1
+	    "pkcs11:?module-path=${TEST_SSH_PKCS11}" #> /dev/null 2>&1
Jakub Jelen def1de
+	r=$?
Jakub Jelen def1de
+	if [ $r -ne 0 ]; then
Jakub Jelen 51f5c1
+		fail "FAIL: ssh-add failed with whole provider: exit code $r"
Jakub Jelen def1de
+	fi
Jakub Jelen def1de
+
Jakub Jelen def1de
+	trace " pkcs11 list via agent (all keys)"
Jakub Jelen def1de
+	${SSHADD} -l > /dev/null 2>&1
Jakub Jelen def1de
+	r=$?
Jakub Jelen def1de
+	if [ $r -ne 0 ]; then
Jakub Jelen 51f5c1
+		fail "FAIL: ssh-add -l failed with whole provider: exit code $r"
Jakub Jelen def1de
+	fi
Jakub Jelen def1de
+
Jakub Jelen def1de
+	trace " pkcs11 connect via agent (all keys)"
Jakub Jelen def1de
+	${SSH} -F $OBJ/ssh_proxy somehost exit 5
Jakub Jelen def1de
+	r=$?
Jakub Jelen def1de
+	if [ $r -ne 5 ]; then
Jakub Jelen 51f5c1
+		fail "FAIL: ssh connect failed with whole provider (exit code $r)"
Jakub Jelen def1de
+	fi
Jakub Jelen def1de
+
Jakub Jelen def1de
+	trace " remove pkcs11 keys (all keys)"
Jakub Jelen def1de
+	${SSHADD} -d "pkcs11:?module-path=${TEST_SSH_PKCS11}" > /dev/null 2>&1
Jakub Jelen def1de
+	r=$?
Jakub Jelen def1de
+	if [ $r -ne 0 ]; then
Jakub Jelen 51f5c1
+		fail "FAIL: ssh-add -d failed with whole provider: exit code $r"
Jakub Jelen def1de
+	fi
Jakub Jelen def1de
+
Jakub Jelen 51f5c1
+	trace "add only RSA key to the agent"
Jakub Jelen def1de
+	echo ${TEST_SSH_PIN} | notty ${SSHADD} \
Jakub Jelen 51f5c1
+	    "pkcs11:id=%${ID1}?module-path=${TEST_SSH_PKCS11}" > /dev/null 2>&1
Jakub Jelen def1de
+	r=$?
Jakub Jelen def1de
+	if [ $r -ne 0 ]; then
Jakub Jelen 51f5c1
+		fail "FAIL ssh-add failed with RSA key: exit code $r"
Jakub Jelen def1de
+	fi
Jakub Jelen def1de
+
Jakub Jelen 51f5c1
+	trace " pkcs11 connect via agent (RSA key)"
Jakub Jelen def1de
+	${SSH} -F $OBJ/ssh_proxy somehost exit 5
Jakub Jelen def1de
+	r=$?
Jakub Jelen def1de
+	if [ $r -ne 5 ]; then
Jakub Jelen 51f5c1
+		fail "FAIL: ssh connect failed with RSA key (exit code $r)"
Jakub Jelen def1de
+	fi
Jakub Jelen def1de
+
Jakub Jelen 51f5c1
+	trace " remove RSA pkcs11 key"
Jakub Jelen 51f5c1
+	${SSHADD} -d "pkcs11:id=%${ID1}?module-path=${TEST_SSH_PKCS11}" \
Jakub Jelen def1de
+	    > /dev/null 2>&1
Jakub Jelen def1de
+	r=$?
Jakub Jelen def1de
+	if [ $r -ne 0 ]; then
Jakub Jelen 51f5c1
+		fail "FAIL: ssh-add -d failed with RSA key: exit code $r"
Jakub Jelen def1de
+	fi
Jakub Jelen def1de
+
Jakub Jelen 51f5c1
+	trace "add only ECDSA key to the agent"
Jakub Jelen def1de
+	echo ${TEST_SSH_PIN} | notty ${SSHADD} \
Jakub Jelen 51f5c1
+	    "pkcs11:id=%${ID2}?module-path=${TEST_SSH_PKCS11}" > /dev/null 2>&1
Jakub Jelen def1de
+	r=$?
Jakub Jelen def1de
+	if [ $r -ne 0 ]; then
Jakub Jelen 51f5c1
+		fail "FAIL: ssh-add failed with second key: exit code $r"
Jakub Jelen def1de
+	fi
Jakub Jelen def1de
+
Jakub Jelen 51f5c1
+	trace " pkcs11 connect via agent (ECDSA key should fail)"
Jakub Jelen def1de
+	${SSH} -F $OBJ/ssh_proxy somehost exit 5
Jakub Jelen def1de
+	r=$?
Jakub Jelen def1de
+	if [ $r -eq 5 ]; then
Jakub Jelen 51f5c1
+		fail "FAIL: ssh connect passed with ECDSA key (should fail)"
Jakub Jelen def1de
+	fi
Jakub Jelen def1de
+
Jakub Jelen 51f5c1
+	trace "add also the RSA key to the agent"
Jakub Jelen def1de
+	echo ${TEST_SSH_PIN} | notty ${SSHADD} \
Jakub Jelen 51f5c1
+	    "pkcs11:id=%${ID1}?module-path=${TEST_SSH_PKCS11}" > /dev/null 2>&1
Jakub Jelen def1de
+	r=$?
Jakub Jelen def1de
+	if [ $r -ne 0 ]; then
Jakub Jelen 51f5c1
+		fail "FAIL: ssh-add failed with first key: exit code $r"
Jakub Jelen def1de
+	fi
Jakub Jelen def1de
+
Jakub Jelen 51f5c1
+	trace " remove ECDSA pkcs11 key"
Jakub Jelen 51f5c1
+	${SSHADD} -d "pkcs11:id=%${ID2}?module-path=${TEST_SSH_PKCS11}" \
Jakub Jelen def1de
+	    > /dev/null 2>&1
Jakub Jelen def1de
+	r=$?
Jakub Jelen def1de
+	if [ $r -ne 0 ]; then
Jakub Jelen 51f5c1
+		fail "ssh-add -d failed with ECDSA key: exit code $r"
Jakub Jelen def1de
+	fi
Jakub Jelen def1de
+
Jakub Jelen def1de
+	trace " remove already-removed pkcs11 key should fail"
Jakub Jelen 51f5c1
+	${SSHADD} -d "pkcs11:id=%${ID2}?module-path=${TEST_SSH_PKCS11}" \
Jakub Jelen def1de
+	    > /dev/null 2>&1
Jakub Jelen def1de
+	r=$?
Jakub Jelen def1de
+	if [ $r -eq 0 ]; then
Jakub Jelen 51f5c1
+		fail "FAIL: ssh-add -d passed with non-existing key (should fail)"
Jakub Jelen def1de
+	fi
Jakub Jelen def1de
+
Jakub Jelen 51f5c1
+	trace " pkcs11 connect via agent (the RSA key should be still usable)"
Jakub Jelen def1de
+	${SSH} -F $OBJ/ssh_proxy somehost exit 5
Jakub Jelen def1de
+	r=$?
Jakub Jelen def1de
+	if [ $r -ne 5 ]; then
Jakub Jelen 51f5c1
+		fail "ssh connect failed with RSA key (after removing ECDSA): exit code $r"
Jakub Jelen def1de
+	fi
Jakub Jelen def1de
+
Jakub Jelen def1de
+	trace "kill agent"
Jakub Jelen def1de
+	${SSHAGENT} -k > /dev/null
Jakub Jelen def1de
+fi
Dmitry Belyavskiy 8f4d19
diff -up openssh-8.7p1/regress/unittests/Makefile.pkcs11-uri openssh-8.7p1/regress/unittests/Makefile
Dmitry Belyavskiy 8f4d19
--- openssh-8.7p1/regress/unittests/Makefile.pkcs11-uri	2021-08-20 06:03:49.000000000 +0200
Dmitry Belyavskiy 8f4d19
+++ openssh-8.7p1/regress/unittests/Makefile	2021-08-30 13:07:43.663700096 +0200
Jakub Jelen def1de
@@ -2,6 +2,6 @@
Jakub Jelen def1de
 
Jakub Jelen def1de
 REGRESS_FAIL_EARLY?=	yes
Jakub Jelen def1de
 SUBDIR=	test_helper sshbuf sshkey bitmap kex hostkeys utf8 match conversion
Jakub Jelen bd3516
-SUBDIR+=authopt misc sshsig
Jakub Jelen bd3516
+SUBDIR+=authopt misc sshsig pkcs11
Jakub Jelen def1de
 
Jakub Jelen def1de
 .include <bsd.subdir.mk>
Dmitry Belyavskiy 8f4d19
diff -up openssh-8.7p1/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh-8.7p1/regress/unittests/pkcs11/tests.c
Dmitry Belyavskiy 8f4d19
--- openssh-8.7p1/regress/unittests/pkcs11/tests.c.pkcs11-uri	2021-08-30 13:07:43.664700104 +0200
Dmitry Belyavskiy 8f4d19
+++ openssh-8.7p1/regress/unittests/pkcs11/tests.c	2021-08-30 13:07:43.664700104 +0200
Jakub Jelen def1de
@@ -0,0 +1,337 @@
Jakub Jelen def1de
+/*
Jakub Jelen def1de
+ * Copyright (c) 2017 Red Hat
Jakub Jelen def1de
+ *
Jakub Jelen def1de
+ * Authors: Jakub Jelen <jjelen@redhat.com>
Jakub Jelen def1de
+ *
Jakub Jelen def1de
+ * Permission to use, copy, modify, and distribute this software for any
Jakub Jelen def1de
+ * purpose with or without fee is hereby granted, provided that the above
Jakub Jelen def1de
+ * copyright notice and this permission notice appear in all copies.
Jakub Jelen def1de
+ *
Jakub Jelen def1de
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
Jakub Jelen def1de
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
Jakub Jelen def1de
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
Jakub Jelen def1de
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
Jakub Jelen def1de
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
Jakub Jelen def1de
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Jakub Jelen def1de
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Jakub Jelen def1de
+ */
Jakub Jelen def1de
+
Jakub Jelen def1de
+#include "includes.h"
Jakub Jelen def1de
+
Jakub Jelen def1de
+#include <locale.h>
Jakub Jelen def1de
+#include <string.h>
Jakub Jelen def1de
+
Jakub Jelen def1de
+#include "../test_helper/test_helper.h"
Jakub Jelen def1de
+
Jakub Jelen def1de
+#include "sshbuf.h"
Jakub Jelen def1de
+#include "ssh-pkcs11-uri.h"
Jakub Jelen def1de
+
Jakub Jelen def1de
+#define EMPTY_URI compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL, NULL)
Jakub Jelen def1de
+
Jakub Jelen def1de
+/* prototypes are not public -- specify them here internally for tests */
Jakub Jelen def1de
+struct sshbuf *percent_encode(const char *, size_t, char *);
Jakub Jelen def1de
+int percent_decode(char *, char **);
Jakub Jelen def1de
+
Jakub Jelen def1de
+void
Jakub Jelen def1de
+compare_uri(struct pkcs11_uri *a, struct pkcs11_uri *b)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	ASSERT_PTR_NE(a, NULL);
Jakub Jelen def1de
+	ASSERT_PTR_NE(b, NULL);
Jakub Jelen def1de
+	ASSERT_SIZE_T_EQ(a->id_len, b->id_len);
Jakub Jelen def1de
+	ASSERT_MEM_EQ(a->id, b->id, a->id_len);
Jakub Jelen def1de
+	if (b->object != NULL)
Jakub Jelen def1de
+		ASSERT_STRING_EQ(a->object, b->object);
Jakub Jelen def1de
+	else /* both should be null */
Jakub Jelen def1de
+		ASSERT_PTR_EQ(a->object, b->object);
Jakub Jelen def1de
+	if (b->module_path != NULL)
Jakub Jelen def1de
+		ASSERT_STRING_EQ(a->module_path, b->module_path);
Jakub Jelen def1de
+	else /* both should be null */
Jakub Jelen def1de
+		ASSERT_PTR_EQ(a->module_path, b->module_path);
Jakub Jelen def1de
+	if (b->token != NULL)
Jakub Jelen def1de
+		ASSERT_STRING_EQ(a->token, b->token);
Jakub Jelen def1de
+	else /* both should be null */
Jakub Jelen def1de
+		ASSERT_PTR_EQ(a->token, b->token);
Jakub Jelen def1de
+	if (b->manuf != NULL)
Jakub Jelen def1de
+		ASSERT_STRING_EQ(a->manuf, b->manuf);
Jakub Jelen def1de
+	else /* both should be null */
Jakub Jelen def1de
+		ASSERT_PTR_EQ(a->manuf, b->manuf);
Jakub Jelen def1de
+	if (b->lib_manuf != NULL)
Jakub Jelen def1de
+		ASSERT_STRING_EQ(a->lib_manuf, b->lib_manuf);
Jakub Jelen def1de
+	else /* both should be null */
Jakub Jelen def1de
+		ASSERT_PTR_EQ(a->lib_manuf, b->lib_manuf);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+void
Jakub Jelen def1de
+check_parse_rv(char *uri, struct pkcs11_uri *expect, int expect_rv)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	char *buf = NULL, *str;
Jakub Jelen def1de
+	struct pkcs11_uri *pkcs11uri = NULL;
Jakub Jelen def1de
+	int rv;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (expect_rv == 0)
Jakub Jelen def1de
+		str = "Valid";
Jakub Jelen def1de
+	else
Jakub Jelen def1de
+		str = "Invalid";
Jakub Jelen def1de
+	asprintf(&buf, "%s PKCS#11 URI parsing: %s", str, uri);
Jakub Jelen def1de
+	TEST_START(buf);
Jakub Jelen def1de
+	free(buf);
Jakub Jelen def1de
+	pkcs11uri = pkcs11_uri_init();
Jakub Jelen def1de
+	rv = pkcs11_uri_parse(uri, pkcs11uri);
Jakub Jelen def1de
+	ASSERT_INT_EQ(rv, expect_rv);
Jakub Jelen def1de
+	if (rv == 0) /* in case of failure result is undefined */
Jakub Jelen def1de
+		compare_uri(pkcs11uri, expect);
Jakub Jelen def1de
+	pkcs11_uri_cleanup(pkcs11uri);
Jakub Jelen def1de
+	free(expect);
Jakub Jelen def1de
+	TEST_DONE();
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+void
Jakub Jelen def1de
+check_parse(char *uri, struct pkcs11_uri *expect)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	check_parse_rv(uri, expect, 0);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+struct pkcs11_uri *
Jakub Jelen def1de
+compose_uri(unsigned char *id, size_t id_len, char *token, char *lib_manuf,
Jakub Jelen def1de
+    char *manuf, char *module_path, char *object, char *pin)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	struct pkcs11_uri *uri = pkcs11_uri_init();
Jakub Jelen def1de
+	if (id_len > 0) {
Jakub Jelen def1de
+		uri->id_len = id_len;
Jakub Jelen def1de
+		uri->id = id;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	uri->module_path = module_path;
Jakub Jelen def1de
+	uri->token = token;
Jakub Jelen def1de
+	uri->lib_manuf = lib_manuf;
Jakub Jelen def1de
+	uri->manuf = manuf;
Jakub Jelen def1de
+	uri->object = object;
Jakub Jelen def1de
+	uri->pin = pin;
Jakub Jelen def1de
+	return uri;
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+static void
Jakub Jelen def1de
+test_parse_valid(void)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	/* path arguments */
Jakub Jelen def1de
+	check_parse("pkcs11:id=%01",
Jakub Jelen def1de
+	    compose_uri("\x01", 1, NULL, NULL, NULL, NULL, NULL, NULL));
Jakub Jelen def1de
+	check_parse("pkcs11:id=%00%01",
Jakub Jelen def1de
+	    compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL, NULL, NULL));
Jakub Jelen def1de
+	check_parse("pkcs11:token=SSH%20Keys",
Jakub Jelen def1de
+	    compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL, NULL));
Jakub Jelen def1de
+	check_parse("pkcs11:library-manufacturer=OpenSC",
Jakub Jelen def1de
+	    compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL, NULL, NULL));
Jakub Jelen def1de
+	check_parse("pkcs11:manufacturer=piv_II",
Jakub Jelen def1de
+	    compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, NULL, NULL));
Jakub Jelen def1de
+	check_parse("pkcs11:object=SIGN%20Key",
Jakub Jelen def1de
+	    compose_uri(NULL, 0, NULL, NULL, NULL, NULL, "SIGN Key", NULL));
Jakub Jelen def1de
+	/* query arguments */
Jakub Jelen def1de
+	check_parse("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so",
Jakub Jelen def1de
+	    compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, NULL));
Jakub Jelen def1de
+	check_parse("pkcs11:?pin-value=123456",
Jakub Jelen def1de
+	    compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL, "123456"));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* combinations */
Jakub Jelen def1de
+	/* ID SHOULD be percent encoded */
Jakub Jelen def1de
+	check_parse("pkcs11:token=SSH%20Key;id=0",
Jakub Jelen def1de
+	    compose_uri("0", 1, "SSH Key", NULL, NULL, NULL, NULL, NULL));
Jakub Jelen def1de
+	check_parse(
Jakub Jelen def1de
+	    "pkcs11:manufacturer=CAC?module-path=/usr/lib64/p11-kit-proxy.so",
Jakub Jelen def1de
+	    compose_uri(NULL, 0, NULL, NULL, "CAC",
Jakub Jelen def1de
+	    "/usr/lib64/p11-kit-proxy.so", NULL, NULL));
Jakub Jelen def1de
+	check_parse(
Jakub Jelen def1de
+	    "pkcs11:object=RSA%20Key?module-path=/usr/lib64/pkcs11/opencryptoki.so",
Jakub Jelen def1de
+	    compose_uri(NULL, 0, NULL, NULL, NULL,
Jakub Jelen def1de
+	    "/usr/lib64/pkcs11/opencryptoki.so", "RSA Key", NULL));
Jakub Jelen def1de
+	check_parse("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so&pin-value=123456",
Jakub Jelen def1de
+	    compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, "123456"));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* empty path component matches everything */
Jakub Jelen def1de
+	check_parse("pkcs11:", EMPTY_URI);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* empty string is a valid to match against (and different from NULL) */
Jakub Jelen def1de
+	check_parse("pkcs11:token=",
Jakub Jelen def1de
+	    compose_uri(NULL, 0, "", NULL, NULL, NULL, NULL, NULL));
Jakub Jelen def1de
+	/* Percent character needs to be percent-encoded */
Jakub Jelen def1de
+	check_parse("pkcs11:token=%25",
Jakub Jelen def1de
+	     compose_uri(NULL, 0, "%", NULL, NULL, NULL, NULL, NULL));
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+static void
Jakub Jelen def1de
+test_parse_invalid(void)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	/* Invalid percent encoding */
Jakub Jelen def1de
+	check_parse_rv("pkcs11:id=%0", EMPTY_URI, -1);
Jakub Jelen def1de
+	/* Invalid percent encoding */
Jakub Jelen def1de
+	check_parse_rv("pkcs11:id=%ZZ", EMPTY_URI, -1);
Jakub Jelen def1de
+	/* Space MUST be percent encoded -- XXX not enforced yet */
Jakub Jelen def1de
+	check_parse("pkcs11:token=SSH Keys",
Jakub Jelen def1de
+	    compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL, NULL));
Jakub Jelen def1de
+	/* MUST NOT contain duplicate attributes of the same name */
Jakub Jelen def1de
+	check_parse_rv("pkcs11:id=%01;id=%02", EMPTY_URI, -1);
Jakub Jelen def1de
+	/* MUST NOT contain duplicate attributes of the same name */
Jakub Jelen def1de
+	check_parse_rv("pkcs11:?pin-value=111111&pin-value=123456", EMPTY_URI, -1);
Jakub Jelen def1de
+	/* Unrecognized attribute in path are ignored with log message */
Jakub Jelen def1de
+	check_parse("pkcs11:key_name=SSH", EMPTY_URI);
Jakub Jelen def1de
+	/* Unrecognized attribute in query SHOULD be ignored */
Jakub Jelen def1de
+	check_parse("pkcs11:?key_name=SSH", EMPTY_URI);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+void
Jakub Jelen def1de
+check_gen(char *expect, struct pkcs11_uri *uri)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	char *buf = NULL, *uri_str;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	asprintf(&buf, "Valid PKCS#11 URI generation: %s", expect);
Jakub Jelen def1de
+	TEST_START(buf);
Jakub Jelen def1de
+	free(buf);
Jakub Jelen def1de
+	uri_str = pkcs11_uri_get(uri);
Jakub Jelen def1de
+	ASSERT_PTR_NE(uri_str, NULL);
Jakub Jelen def1de
+	ASSERT_STRING_EQ(uri_str, expect);
Jakub Jelen def1de
+	free(uri_str);
Jakub Jelen def1de
+	TEST_DONE();
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+static void
Jakub Jelen def1de
+test_generate_valid(void)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	/* path arguments */
Jakub Jelen def1de
+	check_gen("pkcs11:id=%01",
Jakub Jelen def1de
+	    compose_uri("\x01", 1, NULL, NULL, NULL, NULL, NULL, NULL));
Jakub Jelen def1de
+	check_gen("pkcs11:id=%00%01",
Jakub Jelen def1de
+	    compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL, NULL, NULL));
Jakub Jelen def1de
+	check_gen("pkcs11:token=SSH%20Keys", /* space must be percent encoded */
Jakub Jelen def1de
+	    compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL, NULL));
Jakub Jelen def1de
+	/* library-manufacturer is not implmented now */
Jakub Jelen def1de
+	/*check_gen("pkcs11:library-manufacturer=OpenSC",
Jakub Jelen def1de
+	    compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL, NULL, NULL));*/
Jakub Jelen def1de
+	check_gen("pkcs11:manufacturer=piv_II",
Jakub Jelen def1de
+	    compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, NULL, NULL));
Jakub Jelen def1de
+	check_gen("pkcs11:object=RSA%20Key",
Jakub Jelen def1de
+	    compose_uri(NULL, 0, NULL, NULL, NULL, NULL, "RSA Key", NULL));
Jakub Jelen def1de
+	/* query arguments */
Jakub Jelen def1de
+	check_gen("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so",
Jakub Jelen def1de
+	    compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, NULL));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* combinations */
Jakub Jelen def1de
+	check_gen("pkcs11:id=%02;token=SSH%20Keys",
Jakub Jelen def1de
+	    compose_uri("\x02", 1, "SSH Keys", NULL, NULL, NULL, NULL, NULL));
Jakub Jelen def1de
+	check_gen("pkcs11:id=%EE%02?module-path=/usr/lib64/p11-kit-proxy.so",
Jakub Jelen def1de
+	    compose_uri("\xEE\x02", 2, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL, NULL));
Jakub Jelen def1de
+	check_gen("pkcs11:object=Encryption%20Key;manufacturer=piv_II",
Jakub Jelen def1de
+	    compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, "Encryption Key", NULL));
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* empty path component matches everything */
Jakub Jelen def1de
+	check_gen("pkcs11:", EMPTY_URI);
Jakub Jelen def1de
+
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+void
Jakub Jelen bd3516
+check_encode(char *source, size_t len, char *allow_list, char *expect)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	char *buf = NULL;
Jakub Jelen def1de
+	struct sshbuf *b;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	asprintf(&buf, "percent_encode: expected %s", expect);
Jakub Jelen def1de
+	TEST_START(buf);
Jakub Jelen def1de
+	free(buf);
Jakub Jelen def1de
+
Jakub Jelen bd3516
+	b = percent_encode(source, len, allow_list);
Jakub Jelen def1de
+	ASSERT_STRING_EQ(sshbuf_ptr(b), expect);
Jakub Jelen def1de
+	sshbuf_free(b);
Jakub Jelen def1de
+	TEST_DONE();
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+static void
Jakub Jelen def1de
+test_percent_encode_multibyte(void)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	/* SHOULD be encoded as octets according to the UTF-8 character encoding */
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* multi-byte characters are "for free" */
Jakub Jelen def1de
+	check_encode("$", 1, "", "%24");
Jakub Jelen def1de
+	check_encode("¢", 2, "", "%C2%A2");
Jakub Jelen def1de
+	check_encode("€", 3, "", "%E2%82%AC");
Jakub Jelen def1de
+	check_encode("𐍈", 4, "", "%F0%90%8D%88");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* CK_UTF8CHAR is unsigned char (1 byte) */
Jakub Jelen def1de
+	/* labels SHOULD be normalized to NFC [UAX15] */
Jakub Jelen def1de
+
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+static void
Jakub Jelen def1de
+test_percent_encode(void)
Jakub Jelen def1de
+{
Jakub Jelen bd3516
+	/* Without allow list encodes everything (for CKA_ID) */
Jakub Jelen def1de
+	check_encode("A*", 2, "", "%41%2A");
Jakub Jelen def1de
+	check_encode("\x00", 1, "", "%00");
Jakub Jelen def1de
+	check_encode("\x7F", 1, "", "%7F");
Jakub Jelen def1de
+	check_encode("\x80", 1, "", "%80");
Jakub Jelen def1de
+	check_encode("\xff", 1, "", "%FF");
Jakub Jelen def1de
+
Jakub Jelen bd3516
+	/* Default allow list encodes anything but safe letters */
Jakub Jelen def1de
+	check_encode("test" "\x00" "0alpha", 11, PKCS11_URI_WHITELIST,
Jakub Jelen def1de
+	    "test%000alpha");
Jakub Jelen def1de
+	check_encode(" ", 1, PKCS11_URI_WHITELIST,
Jakub Jelen def1de
+	    "%20"); /* Space MUST be percent encoded */
Jakub Jelen def1de
+	check_encode("/", 1, PKCS11_URI_WHITELIST,
Jakub Jelen def1de
+	    "%2F"); /* '/' delimiter MUST be percent encoded (in the path) */
Jakub Jelen def1de
+	check_encode("?", 1, PKCS11_URI_WHITELIST,
Jakub Jelen def1de
+	    "%3F"); /* delimiter '?' MUST be percent encoded (in the path) */
Jakub Jelen def1de
+	check_encode("#", 1, PKCS11_URI_WHITELIST,
Jakub Jelen def1de
+	    "%23"); /* '#' MUST be always percent encoded */
Jakub Jelen def1de
+	check_encode("key=value;separator?query&#anch", 35, PKCS11_URI_WHITELIST,
Jakub Jelen def1de
+	    "key%3Dvalue%3Bseparator%3Fquery%26amp%3B%23anch");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* Components in query can have '/' unencoded (useful for paths) */
Jakub Jelen def1de
+	check_encode("/path/to.file", 13, PKCS11_URI_WHITELIST "/",
Jakub Jelen def1de
+	    "/path/to.file");
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+void
Jakub Jelen def1de
+check_decode(char *source, char *expect, int expect_len)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	char *buf = NULL, *out = NULL;
Jakub Jelen def1de
+	int rv;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	asprintf(&buf, "percent_decode: %s", source);
Jakub Jelen def1de
+	TEST_START(buf);
Jakub Jelen def1de
+	free(buf);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	rv = percent_decode(source, &out;;
Jakub Jelen def1de
+	ASSERT_INT_EQ(rv, expect_len);
Jakub Jelen def1de
+	if (rv >= 0)
Jakub Jelen def1de
+		ASSERT_MEM_EQ(out, expect, expect_len);
Jakub Jelen def1de
+	free(out);
Jakub Jelen def1de
+	TEST_DONE();
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+static void
Jakub Jelen def1de
+test_percent_decode(void)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	/* simple valid cases */
Jakub Jelen def1de
+	check_decode("%00", "\x00", 1);
Jakub Jelen def1de
+	check_decode("%FF", "\xFF", 1);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* normal strings shold be kept intact */
Jakub Jelen def1de
+	check_decode("strings are left", "strings are left", 16);
Jakub Jelen def1de
+	check_decode("10%25 of trees", "10% of trees", 12);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* make sure no more than 2 bytes are parsed */
Jakub Jelen def1de
+	check_decode("%222", "\x22" "2", 2);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* invalid expects failure */
Jakub Jelen def1de
+	check_decode("%0", "", -1);
Jakub Jelen def1de
+	check_decode("%Z", "", -1);
Jakub Jelen def1de
+	check_decode("%FG", "", -1);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+void
Jakub Jelen def1de
+tests(void)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	test_percent_encode();
Jakub Jelen def1de
+	test_percent_encode_multibyte();
Jakub Jelen def1de
+	test_percent_decode();
Jakub Jelen def1de
+	test_parse_valid();
Jakub Jelen def1de
+	test_parse_invalid();
Jakub Jelen def1de
+	test_generate_valid();
Jakub Jelen def1de
+}
Dmitry Belyavskiy 8f4d19
diff -up openssh-8.7p1/ssh-add.c.pkcs11-uri openssh-8.7p1/ssh-add.c
Dmitry Belyavskiy 8f4d19
--- openssh-8.7p1/ssh-add.c.pkcs11-uri	2021-08-20 06:03:49.000000000 +0200
Dmitry Belyavskiy 8f4d19
+++ openssh-8.7p1/ssh-add.c	2021-08-30 13:07:43.664700104 +0200
Dmitry Belyavskiy f32b84
@@ -68,6 +68,7 @@
Jakub Jelen 51f5c1
 #include "ssh-sk.h"
Jakub Jelen bd3516
 #include "sk-api.h"
Dmitry Belyavskiy 03150f
 #include "hostfile.h"
Jakub Jelen def1de
+#include "ssh-pkcs11-uri.h"
Jakub Jelen def1de
 
Jakub Jelen def1de
 /* argv0 */
Jakub Jelen def1de
 extern char *__progname;
Dmitry Belyavskiy 03150f
@@ -229,6 +230,34 @@ delete_all(int agent_fd, int qflag)
Jakub Jelen def1de
 	return ret;
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
+#ifdef ENABLE_PKCS11
Dmitry Belyavskiy 03150f
+static int update_card(int, int, const char *, int, struct dest_constraint **, size_t, char *);
Jakub Jelen def1de
+
Jakub Jelen def1de
+int
Dmitry Belyavskiy 03150f
+update_pkcs11_uri(int agent_fd, int adding, const char *pkcs11_uri, int qflag,
Dmitry Belyavskiy 03150f
+    struct dest_constraint **dest_constraints, size_t ndest_constraints)
Jakub Jelen def1de
+{
Jakub Jelen 36fef5
+	char *pin = NULL;
Jakub Jelen def1de
+	struct pkcs11_uri *uri;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* dry-run parse to make sure the URI is valid and to report errors */
Jakub Jelen def1de
+	uri = pkcs11_uri_init();
Jakub Jelen def1de
+	if (pkcs11_uri_parse((char *) pkcs11_uri, uri) != 0)
Jakub Jelen def1de
+		fatal("Failed to parse PKCS#11 URI");
Jakub Jelen 36fef5
+	if (uri->pin != NULL) {
Jakub Jelen 36fef5
+		pin = strdup(uri->pin);
Jakub Jelen 36fef5
+		if (pin == NULL) {
Jakub Jelen 36fef5
+			fatal("Failed to dupplicate string");
Jakub Jelen 36fef5
+		}
Jakub Jelen 36fef5
+		/* pin is freed in the update_card() */
Jakub Jelen 36fef5
+	}
Jakub Jelen def1de
+	pkcs11_uri_cleanup(uri);
Jakub Jelen def1de
+
Dmitry Belyavskiy 03150f
+	return update_card(agent_fd, adding, pkcs11_uri, qflag, 
Dmitry Belyavskiy 03150f
+	           dest_constraints, ndest_constraints, pin);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
+
Jakub Jelen def1de
 static int
Jakub Jelen 51f5c1
 add_file(int agent_fd, const char *filename, int key_only, int qflag,
Dmitry Belyavskiy 03150f
     const char *skprovider, struct dest_constraint **dest_constraints,
Dmitry Belyavskiy f32b84
@@ -445,12 +472,11 @@ add_file(int agent_fd, const char *filen
Jakub Jelen 36fef5
 
Jakub Jelen 36fef5
 static int
Dmitry Belyavskiy 03150f
 update_card(int agent_fd, int add, const char *id, int qflag,
Dmitry Belyavskiy 03150f
-    struct dest_constraint **dest_constraints, size_t ndest_constraints)
Dmitry Belyavskiy 03150f
+    struct dest_constraint **dest_constraints, size_t ndest_constraints, char *pin)
Jakub Jelen 36fef5
 {
Jakub Jelen 36fef5
-	char *pin = NULL;
Jakub Jelen 36fef5
 	int r, ret = -1;
Jakub Jelen 36fef5
 
Jakub Jelen 36fef5
-	if (add) {
Jakub Jelen 36fef5
+	if (add && pin == NULL) {
Jakub Jelen 36fef5
 		if ((pin = read_passphrase("Enter passphrase for PKCS#11: ",
Jakub Jelen 36fef5
 		    RP_ALLOW_STDIN)) == NULL)
Jakub Jelen 36fef5
 			return -1;
Dmitry Belyavskiy 03150f
@@ -630,6 +656,14 @@ static int
Dmitry Belyavskiy 03150f
     const char *skprovider, struct dest_constraint **dest_constraints,
Dmitry Belyavskiy 03150f
     size_t ndest_constraints)
Jakub Jelen def1de
 {
Jakub Jelen def1de
+#ifdef ENABLE_PKCS11
Jakub Jelen def1de
+	if (strlen(file) >= strlen(PKCS11_URI_SCHEME) &&
Jakub Jelen def1de
+	    strncmp(file, PKCS11_URI_SCHEME,
Jakub Jelen def1de
+	    strlen(PKCS11_URI_SCHEME)) == 0) {
Dmitry Belyavskiy 03150f
+		return update_pkcs11_uri(agent_fd, !deleting, file, qflag,
Dmitry Belyavskiy 03150f
+                   dest_constraints, ndest_constraints);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
 	if (deleting) {
Jakub Jelen def1de
 		if (delete_file(agent_fd, file, key_only, qflag) == -1)
Jakub Jelen def1de
 			return -1;
Dmitry Belyavskiy f32b84
@@ -813,7 +846,7 @@ main(int argc, char **argv)
Jakub Jelen 36fef5
 	}
Jakub Jelen 36fef5
 	if (pkcs11provider != NULL) {
Jakub Jelen 36fef5
 		if (update_card(agent_fd, !deleting, pkcs11provider,
Dmitry Belyavskiy 03150f
-		    qflag, dest_constraints, ndest_constraints) == -1)
Dmitry Belyavskiy 03150f
+		    qflag, dest_constraints, ndest_constraints, NULL) == -1)
Jakub Jelen 36fef5
 			ret = 1;
Jakub Jelen 36fef5
 		goto done;
Jakub Jelen 36fef5
 	}
Dmitry Belyavskiy 8f4d19
diff -up openssh-8.7p1/ssh-agent.c.pkcs11-uri openssh-8.7p1/ssh-agent.c
Dmitry Belyavskiy 8f4d19
--- openssh-8.7p1/ssh-agent.c.pkcs11-uri	2021-08-20 06:03:49.000000000 +0200
Dmitry Belyavskiy 8f4d19
+++ openssh-8.7p1/ssh-agent.c	2021-08-30 13:07:43.664700104 +0200
Dmitry Belyavskiy f32b84
@@ -847,10 +847,72 @@ no_identities(SocketEntry *e)
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
 #ifdef ENABLE_PKCS11
Jakub Jelen def1de
+static char *
Jakub Jelen def1de
+sanitize_pkcs11_provider(const char *provider)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	struct pkcs11_uri *uri = NULL;
Jakub Jelen def1de
+	char *sane_uri, *module_path = NULL; /* default path */
Jakub Jelen def1de
+	char canonical_provider[PATH_MAX];
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (provider == NULL)
Jakub Jelen def1de
+		return NULL;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (strlen(provider) >= strlen(PKCS11_URI_SCHEME) &&
Jakub Jelen def1de
+	    strncmp(provider, PKCS11_URI_SCHEME,
Jakub Jelen def1de
+	    strlen(PKCS11_URI_SCHEME)) == 0) {
Jakub Jelen def1de
+		/* PKCS#11 URI */
Jakub Jelen def1de
+		uri = pkcs11_uri_init();
Jakub Jelen def1de
+		if (uri == NULL) {
Jakub Jelen 51f5c1
+			error("Failed to init PKCS#11 URI");
Jakub Jelen def1de
+			return NULL;
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+
Jakub Jelen def1de
+		if (pkcs11_uri_parse(provider, uri) != 0) {
Jakub Jelen def1de
+			error("Failed to parse PKCS#11 URI");
Jakub Jelen def1de
+			return NULL;
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+		/* validate also provider from URI */
Jakub Jelen def1de
+		if (uri->module_path)
Jakub Jelen def1de
+			module_path = strdup(uri->module_path);
Jakub Jelen def1de
+	} else
Jakub Jelen def1de
+		module_path = strdup(provider); /* simple path */
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (module_path != NULL) { /* do not validate default NULL path in URI */
Jakub Jelen def1de
+		if (realpath(module_path, canonical_provider) == NULL) {
Jakub Jelen def1de
+			verbose("failed PKCS#11 provider \"%.100s\": realpath: %s",
Jakub Jelen def1de
+			    module_path, strerror(errno));
Jakub Jelen def1de
+			free(module_path);
Jakub Jelen def1de
+			pkcs11_uri_cleanup(uri);
Jakub Jelen def1de
+			return NULL;
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+		free(module_path);
Jakub Jelen bd3516
+		if (match_pattern_list(canonical_provider, allowed_providers, 0) != 1) {
Jakub Jelen def1de
+			verbose("refusing PKCS#11 provider \"%.100s\": "
Jakub Jelen bd3516
+			    "not allowed", canonical_provider);
Jakub Jelen def1de
+			pkcs11_uri_cleanup(uri);
Jakub Jelen def1de
+			return NULL;
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+
Jakub Jelen def1de
+		/* copy verified and sanitized provider path back to the uri */
Jakub Jelen def1de
+		if (uri) {
Jakub Jelen def1de
+			free(uri->module_path);
Jakub Jelen def1de
+			uri->module_path = xstrdup(canonical_provider);
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (uri) {
Jakub Jelen def1de
+		sane_uri = pkcs11_uri_get(uri);
Jakub Jelen def1de
+		pkcs11_uri_cleanup(uri);
Jakub Jelen def1de
+		return sane_uri;
Jakub Jelen def1de
+	} else {
Jakub Jelen def1de
+		return xstrdup(canonical_provider); /* simple path */
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
 static void
Jakub Jelen def1de
 process_add_smartcard_key(SocketEntry *e)
Jakub Jelen def1de
 {
Jakub Jelen def1de
-	char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];
Jakub Jelen def1de
+	char *provider = NULL, *pin = NULL, *sane_uri = NULL;
Jakub Jelen 51f5c1
 	char **comments = NULL;
Jakub Jelen def1de
 	int r, i, count = 0, success = 0, confirm = 0;
Jakub Jelen 25c16c
 	u_int seconds = 0;
Dmitry Belyavskiy f32b84
@@ -869,33 +931,28 @@ process_add_smartcard_key(SocketEntry *e
Jakub Jelen 25c16c
 		error_f("failed to parse constraints");
Jakub Jelen 25c16c
 		goto send;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
-	if (realpath(provider, canonical_provider) == NULL) {
Jakub Jelen def1de
-		verbose("failed PKCS#11 add of \"%.100s\": realpath: %s",
Jakub Jelen def1de
-		    provider, strerror(errno));
Jakub Jelen def1de
-		goto send;
Jakub Jelen def1de
-	}
Jakub Jelen bd3516
-	if (match_pattern_list(canonical_provider, allowed_providers, 0) != 1) {
Jakub Jelen def1de
-		verbose("refusing PKCS#11 add of \"%.100s\": "
Jakub Jelen bd3516
-		    "provider not allowed", canonical_provider);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	sane_uri = sanitize_pkcs11_provider(provider);
Jakub Jelen def1de
+	if (sane_uri == NULL)
Jakub Jelen def1de
 		goto send;
Jakub Jelen def1de
-	}
Jakub Jelen 25c16c
-	debug_f("add %.100s", canonical_provider);
Jakub Jelen def1de
+
Jakub Jelen def1de
 	if (lifetime && !death)
Jakub Jelen def1de
 		death = monotime() + lifetime;
Jakub Jelen def1de
 
Jakub Jelen 51f5c1
-	count = pkcs11_add_provider(canonical_provider, pin, &keys, &comments);
Jakub Jelen 25c16c
+	debug_f("add %.100s", sane_uri);
Jakub Jelen 51f5c1
+	count = pkcs11_add_provider(sane_uri, pin, &keys, &comments);
Jakub Jelen def1de
 	for (i = 0; i < count; i++) {
Jakub Jelen def1de
 		k = keys[i];
Jakub Jelen def1de
 		if (lookup_identity(k) == NULL) {
Jakub Jelen def1de
 			id = xcalloc(1, sizeof(Identity));
Jakub Jelen def1de
 			id->key = k;
Jakub Jelen 51f5c1
 			keys[i] = NULL; /* transferred */
Jakub Jelen def1de
-			id->provider = xstrdup(canonical_provider);
Jakub Jelen def1de
+			id->provider = xstrdup(sane_uri);
Jakub Jelen 51f5c1
 			if (*comments[i] != '\0') {
Jakub Jelen 51f5c1
 				id->comment = comments[i];
Jakub Jelen 51f5c1
 				comments[i] = NULL; /* transferred */
Jakub Jelen 51f5c1
 			} else {
Jakub Jelen 51f5c1
-				id->comment = xstrdup(canonical_provider);
Jakub Jelen 51f5c1
+				id->comment = xstrdup(sane_uri);
Jakub Jelen 51f5c1
 			}
Jakub Jelen def1de
 			id->death = death;
Jakub Jelen def1de
 			id->confirm = confirm;
Dmitry Belyavskiy f32b84
@@ -910,6 +967,7 @@ process_add_smartcard_key(SocketEntry *e
Jakub Jelen def1de
 send:
Jakub Jelen def1de
 	free(pin);
Jakub Jelen def1de
 	free(provider);
Jakub Jelen def1de
+	free(sane_uri);
Jakub Jelen def1de
 	free(keys);
Jakub Jelen 51f5c1
 	free(comments);
Dmitry Belyavskiy 03150f
	free_dest_constraints(dest_constraints, ndest_constraints);
Dmitry Belyavskiy f32b84
@@ -918,7 +976,7 @@ send:
Jakub Jelen def1de
 static void
Jakub Jelen def1de
 process_remove_smartcard_key(SocketEntry *e)
Jakub Jelen def1de
 {
Jakub Jelen def1de
-	char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];
Jakub Jelen def1de
+	char *provider = NULL, *pin = NULL, *sane_uri = NULL;
Jakub Jelen def1de
 	int r, success = 0;
Jakub Jelen def1de
 	Identity *id, *nxt;
Jakub Jelen def1de
 
Dmitry Belyavskiy f32b84
@@ -930,30 +988,29 @@ process_remove_smartcard_key(SocketEntry
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 	free(pin);
Jakub Jelen def1de
 
Jakub Jelen def1de
-	if (realpath(provider, canonical_provider) == NULL) {
Jakub Jelen def1de
-		verbose("failed PKCS#11 add of \"%.100s\": realpath: %s",
Jakub Jelen def1de
-		    provider, strerror(errno));
Jakub Jelen def1de
+	sane_uri = sanitize_pkcs11_provider(provider);
Jakub Jelen def1de
+	if (sane_uri == NULL)
Jakub Jelen def1de
 		goto send;
Jakub Jelen def1de
-	}
Jakub Jelen def1de
 
Jakub Jelen 25c16c
-	debug_f("remove %.100s", canonical_provider);
Jakub Jelen 25c16c
+	debug_f("remove %.100s", sane_uri);
Jakub Jelen def1de
 	for (id = TAILQ_FIRST(&idtab->idlist); id; id = nxt) {
Jakub Jelen def1de
 		nxt = TAILQ_NEXT(id, next);
Jakub Jelen def1de
 		/* Skip file--based keys */
Jakub Jelen def1de
 		if (id->provider == NULL)
Jakub Jelen def1de
 			continue;
Jakub Jelen def1de
-		if (!strcmp(canonical_provider, id->provider)) {
Jakub Jelen def1de
+		if (!strcmp(sane_uri, id->provider)) {
Jakub Jelen def1de
 			TAILQ_REMOVE(&idtab->idlist, id, next);
Jakub Jelen def1de
 			free_identity(id);
Jakub Jelen def1de
 			idtab->nentries--;
Jakub Jelen def1de
 		}
Jakub Jelen def1de
 	}
Jakub Jelen def1de
-	if (pkcs11_del_provider(canonical_provider) == 0)
Jakub Jelen def1de
+	if (pkcs11_del_provider(sane_uri) == 0)
Jakub Jelen def1de
 		success = 1;
Jakub Jelen def1de
 	else
Jakub Jelen 25c16c
 		error_f("pkcs11_del_provider failed");
Jakub Jelen def1de
 send:
Jakub Jelen def1de
 	free(provider);
Jakub Jelen def1de
+	free(sane_uri);
Jakub Jelen def1de
 	send_status(e, success);
Jakub Jelen def1de
 }
Jakub Jelen def1de
 #endif /* ENABLE_PKCS11 */
Dmitry Belyavskiy 8f4d19
diff -up openssh-8.7p1/ssh_config.5.pkcs11-uri openssh-8.7p1/ssh_config.5
Dmitry Belyavskiy 8f4d19
--- openssh-8.7p1/ssh_config.5.pkcs11-uri	2021-08-30 13:07:43.578699383 +0200
Dmitry Belyavskiy 8f4d19
+++ openssh-8.7p1/ssh_config.5	2021-08-30 13:07:43.664700104 +0200
Dmitry Belyavskiy 8f4d19
@@ -1111,6 +1111,21 @@ may also be used in conjunction with
Dmitry Belyavskiy f32b84
 .Cm CertificateFile
Dmitry Belyavskiy f32b84
 in order to provide any certificate also needed for authentication with
Dmitry Belyavskiy f32b84
 the identity.
Dmitry Belyavskiy f32b84
+.Pp
Dmitry Belyavskiy f32b84
+The authentication identity can be also specified in a form of PKCS#11 URI
Dmitry Belyavskiy f32b84
+starting with a string
Dmitry Belyavskiy f32b84
+.Cm pkcs11: .
Dmitry Belyavskiy f32b84
+There is supported a subset of the PKCS#11 URI as defined
Dmitry Belyavskiy f32b84
+in RFC 7512 (implemented path arguments
Dmitry Belyavskiy f32b84
+.Cm id ,
Dmitry Belyavskiy f32b84
+.Cm manufacturer ,
Dmitry Belyavskiy f32b84
+.Cm object ,
Dmitry Belyavskiy f32b84
+.Cm token
Dmitry Belyavskiy f32b84
+and query arguments
Dmitry Belyavskiy f32b84
+.Cm module-path
Dmitry Belyavskiy f32b84
+and
Dmitry Belyavskiy f32b84
+.Cm pin-value
Dmitry Belyavskiy f32b84
+). The URI can not be in quotes.
Dmitry Belyavskiy f32b84
 .It Cm IgnoreUnknown
Dmitry Belyavskiy f32b84
 Specifies a pattern-list of unknown options to be ignored if they are
Dmitry Belyavskiy f32b84
 encountered in configuration parsing.
Dmitry Belyavskiy 8f4d19
diff -up openssh-8.7p1/ssh.c.pkcs11-uri openssh-8.7p1/ssh.c
Dmitry Belyavskiy 8f4d19
--- openssh-8.7p1/ssh.c.pkcs11-uri	2021-08-30 13:07:43.578699383 +0200
Dmitry Belyavskiy 8f4d19
+++ openssh-8.7p1/ssh.c	2021-08-30 13:07:43.666700121 +0200
Dmitry Belyavskiy 8f4d19
@@ -826,6 +826,14 @@ main(int ac, char **av)
Dmitry Belyavskiy f32b84
 			options.gss_deleg_creds = 1;
Dmitry Belyavskiy f32b84
 			break;
Dmitry Belyavskiy f32b84
 		case 'i':
Dmitry Belyavskiy f32b84
+#ifdef ENABLE_PKCS11
Dmitry Belyavskiy f32b84
+			if (strlen(optarg) >= strlen(PKCS11_URI_SCHEME) &&
Dmitry Belyavskiy f32b84
+			    strncmp(optarg, PKCS11_URI_SCHEME,
Dmitry Belyavskiy f32b84
+			    strlen(PKCS11_URI_SCHEME)) == 0) {
Dmitry Belyavskiy f32b84
+				add_identity_file(&options, NULL, optarg, 1);
Dmitry Belyavskiy f32b84
+				break;
Jakub Jelen 51f5c1
+			}
Dmitry Belyavskiy f32b84
+#endif
Dmitry Belyavskiy f32b84
 			p = tilde_expand_filename(optarg, getuid());
Dmitry Belyavskiy f32b84
 			if (stat(p, &st) == -1)
Dmitry Belyavskiy f32b84
 				fprintf(stderr, "Warning: Identity file %s "
Dmitry Belyavskiy 8f4d19
@@ -1681,6 +1689,7 @@ main(int ac, char **av)
Dmitry Belyavskiy f32b84
 #ifdef ENABLE_PKCS11
Dmitry Belyavskiy f32b84
 	(void)pkcs11_del_provider(options.pkcs11_provider);
Dmitry Belyavskiy f32b84
 #endif
Dmitry Belyavskiy f32b84
+	pkcs11_terminate();
Jakub Jelen def1de
 
Dmitry Belyavskiy f32b84
  skip_connect:
Dmitry Belyavskiy f32b84
 	exit_status = ssh_session2(ssh, cinfo);
Dmitry Belyavskiy 8f4d19
@@ -2197,6 +2206,45 @@ ssh_session2(struct ssh *ssh, const stru
Dmitry Belyavskiy f32b84
 	    options.escape_char : SSH_ESCAPECHAR_NONE, id);
Dmitry Belyavskiy f32b84
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
+#ifdef ENABLE_PKCS11
Dmitry Belyavskiy f32b84
+static void
Dmitry Belyavskiy f32b84
+load_pkcs11_identity(char *pkcs11_uri, char *identity_files[],
Dmitry Belyavskiy f32b84
+    struct sshkey *identity_keys[], int *n_ids)
Dmitry Belyavskiy f32b84
+{
Dmitry Belyavskiy f32b84
+	int nkeys, i;
Dmitry Belyavskiy f32b84
+	struct sshkey **keys;
Dmitry Belyavskiy f32b84
+	struct pkcs11_uri *uri;
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+	debug("identity file '%s' from pkcs#11", pkcs11_uri);
Dmitry Belyavskiy f32b84
+	uri = pkcs11_uri_init();
Dmitry Belyavskiy f32b84
+	if (uri == NULL)
Dmitry Belyavskiy f32b84
+		fatal("Failed to init PKCS#11 URI");
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+	if (pkcs11_uri_parse(pkcs11_uri, uri) != 0)
Dmitry Belyavskiy f32b84
+	fatal("Failed to parse PKCS#11 URI %s", pkcs11_uri);
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+	/* we need to merge URI and provider together */
Dmitry Belyavskiy f32b84
+	if (options.pkcs11_provider != NULL && uri->module_path == NULL)
Dmitry Belyavskiy f32b84
+		uri->module_path = strdup(options.pkcs11_provider);
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+	if (options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
Dmitry Belyavskiy f32b84
+	    (nkeys = pkcs11_add_provider_by_uri(uri, NULL, &keys, NULL)) > 0) {
Dmitry Belyavskiy f32b84
+		for (i = 0; i < nkeys; i++) {
Dmitry Belyavskiy f32b84
+			if (*n_ids >= SSH_MAX_IDENTITY_FILES) {
Dmitry Belyavskiy f32b84
+				sshkey_free(keys[i]);
Dmitry Belyavskiy f32b84
+				continue;
Dmitry Belyavskiy f32b84
+			}
Dmitry Belyavskiy f32b84
+			identity_keys[*n_ids] = keys[i];
Dmitry Belyavskiy f32b84
+			identity_files[*n_ids] = pkcs11_uri_get(uri);
Dmitry Belyavskiy f32b84
+			(*n_ids)++;
Dmitry Belyavskiy f32b84
+		}
Dmitry Belyavskiy f32b84
+		free(keys);
Dmitry Belyavskiy f32b84
+	}
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+	pkcs11_uri_cleanup(uri);
Dmitry Belyavskiy f32b84
+}
Dmitry Belyavskiy f32b84
+#endif /* ENABLE_PKCS11 */
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
 /* Loads all IdentityFile and CertificateFile keys */
Dmitry Belyavskiy f32b84
 static void
Dmitry Belyavskiy f32b84
 load_public_identity_files(const struct ssh_conn_info *cinfo)
Dmitry Belyavskiy 8f4d19
@@ -2211,11 +2259,6 @@ load_public_identity_files(const struct
Dmitry Belyavskiy f32b84
 	char *certificate_files[SSH_MAX_CERTIFICATE_FILES];
Dmitry Belyavskiy f32b84
 	struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES];
Dmitry Belyavskiy f32b84
 	int certificate_file_userprovided[SSH_MAX_CERTIFICATE_FILES];
Dmitry Belyavskiy f32b84
-#ifdef ENABLE_PKCS11
Dmitry Belyavskiy f32b84
-	struct sshkey **keys = NULL;
Dmitry Belyavskiy f32b84
-	char **comments = NULL;
Dmitry Belyavskiy f32b84
-	int nkeys;
Dmitry Belyavskiy f32b84
-#endif /* PKCS11 */
Dmitry Belyavskiy f32b84
 
Dmitry Belyavskiy f32b84
 	n_ids = n_certs = 0;
Dmitry Belyavskiy f32b84
 	memset(identity_files, 0, sizeof(identity_files));
Dmitry Belyavskiy 8f4d19
@@ -2228,33 +2271,46 @@ load_public_identity_files(const struct
Dmitry Belyavskiy f32b84
 	    sizeof(certificate_file_userprovided));
Dmitry Belyavskiy f32b84
 
Dmitry Belyavskiy f32b84
 #ifdef ENABLE_PKCS11
Dmitry Belyavskiy f32b84
-	if (options.pkcs11_provider != NULL &&
Dmitry Belyavskiy f32b84
-	    options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
Dmitry Belyavskiy f32b84
-	    (pkcs11_init(!options.batch_mode) == 0) &&
Dmitry Belyavskiy f32b84
-	    (nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL,
Dmitry Belyavskiy f32b84
-	    &keys, &comments)) > 0) {
Dmitry Belyavskiy f32b84
-		for (i = 0; i < nkeys; i++) {
Dmitry Belyavskiy f32b84
-			if (n_ids >= SSH_MAX_IDENTITY_FILES) {
Dmitry Belyavskiy f32b84
-				sshkey_free(keys[i]);
Dmitry Belyavskiy f32b84
-				free(comments[i]);
Dmitry Belyavskiy f32b84
-				continue;
Dmitry Belyavskiy f32b84
-			}
Dmitry Belyavskiy f32b84
-			identity_keys[n_ids] = keys[i];
Dmitry Belyavskiy f32b84
-			identity_files[n_ids] = comments[i]; /* transferred */
Dmitry Belyavskiy f32b84
-			n_ids++;
Dmitry Belyavskiy f32b84
-		}
Dmitry Belyavskiy f32b84
-		free(keys);
Dmitry Belyavskiy f32b84
-		free(comments);
Dmitry Belyavskiy f32b84
+	/* handle fallback from PKCS11Provider option */
Dmitry Belyavskiy f32b84
+	pkcs11_init(!options.batch_mode);
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+	if (options.pkcs11_provider != NULL) {
Dmitry Belyavskiy f32b84
+		struct pkcs11_uri *uri;
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+		uri = pkcs11_uri_init();
Dmitry Belyavskiy f32b84
+		if (uri == NULL)
Dmitry Belyavskiy f32b84
+			fatal("Failed to init PKCS#11 URI");
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+		/* Construct simple PKCS#11 URI to simplify access */
Dmitry Belyavskiy f32b84
+		uri->module_path = strdup(options.pkcs11_provider);
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+		/* Add it as any other IdentityFile */
Dmitry Belyavskiy f32b84
+		cp = pkcs11_uri_get(uri);
Dmitry Belyavskiy f32b84
+		add_identity_file(&options, NULL, cp, 1);
Dmitry Belyavskiy f32b84
+		free(cp);
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+		pkcs11_uri_cleanup(uri);
Dmitry Belyavskiy f32b84
 	}
Dmitry Belyavskiy f32b84
 #endif /* ENABLE_PKCS11 */
Dmitry Belyavskiy f32b84
 	for (i = 0; i < options.num_identity_files; i++) {
Dmitry Belyavskiy f32b84
+		char *name = options.identity_files[i];
Dmitry Belyavskiy f32b84
 		if (n_ids >= SSH_MAX_IDENTITY_FILES ||
Dmitry Belyavskiy f32b84
-		    strcasecmp(options.identity_files[i], "none") == 0) {
Dmitry Belyavskiy f32b84
+		    strcasecmp(name, "none") == 0) {
Dmitry Belyavskiy f32b84
 			free(options.identity_files[i]);
Dmitry Belyavskiy f32b84
 			options.identity_files[i] = NULL;
Dmitry Belyavskiy f32b84
 			continue;
Dmitry Belyavskiy f32b84
 		}
Dmitry Belyavskiy f32b84
-		cp = tilde_expand_filename(options.identity_files[i], getuid());
Dmitry Belyavskiy f32b84
+#ifdef ENABLE_PKCS11
Dmitry Belyavskiy f32b84
+		if (strlen(name) >= strlen(PKCS11_URI_SCHEME) &&
Dmitry Belyavskiy f32b84
+		    strncmp(name, PKCS11_URI_SCHEME,
Dmitry Belyavskiy f32b84
+		    strlen(PKCS11_URI_SCHEME)) == 0) {
Dmitry Belyavskiy f32b84
+			load_pkcs11_identity(name, identity_files,
Dmitry Belyavskiy f32b84
+			    identity_keys, &n_ids);
Dmitry Belyavskiy f32b84
+			free(options.identity_files[i]);
Dmitry Belyavskiy f32b84
+			continue;
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+#endif /* ENABLE_PKCS11 */
Dmitry Belyavskiy f32b84
+		cp = tilde_expand_filename(name, getuid());
Dmitry Belyavskiy f32b84
 		filename = default_client_percent_dollar_expand(cp, cinfo);
Dmitry Belyavskiy f32b84
 		free(cp);
Dmitry Belyavskiy f32b84
 		check_load(sshkey_load_public(filename, &public, NULL),
Dmitry Belyavskiy 8f4d19
diff -up openssh-8.7p1/ssh-keygen.c.pkcs11-uri openssh-8.7p1/ssh-keygen.c
Dmitry Belyavskiy 8f4d19
--- openssh-8.7p1/ssh-keygen.c.pkcs11-uri	2021-08-20 06:03:49.000000000 +0200
Dmitry Belyavskiy 8f4d19
+++ openssh-8.7p1/ssh-keygen.c	2021-08-30 13:07:43.666700121 +0200
Dmitry Belyavskiy f32b84
@@ -860,8 +860,11 @@ do_download(struct passwd *pw)
Dmitry Belyavskiy f32b84
 			free(fp);
Dmitry Belyavskiy f32b84
 		} else {
Dmitry Belyavskiy f32b84
 			(void) sshkey_write(keys[i], stdout); /* XXX check */
Dmitry Belyavskiy f32b84
-			fprintf(stdout, "%s%s\n",
Dmitry Belyavskiy f32b84
-			    *(comments[i]) == '\0' ? "" : " ", comments[i]);
Dmitry Belyavskiy f32b84
+			if (*(comments[i]) != '\0') {
Dmitry Belyavskiy f32b84
+				fprintf(stdout, " %s", comments[i]);
Dmitry Belyavskiy f32b84
+			}
Dmitry Belyavskiy f32b84
+			(void) pkcs11_uri_write(keys[i], stdout);
Dmitry Belyavskiy f32b84
+			fprintf(stdout, "\n");
Dmitry Belyavskiy f32b84
 		}
Dmitry Belyavskiy f32b84
 		free(comments[i]);
Dmitry Belyavskiy f32b84
 		sshkey_free(keys[i]);
Dmitry Belyavskiy 8f4d19
diff -up openssh-8.7p1/ssh-pkcs11-client.c.pkcs11-uri openssh-8.7p1/ssh-pkcs11-client.c
Dmitry Belyavskiy 8f4d19
--- openssh-8.7p1/ssh-pkcs11-client.c.pkcs11-uri	2021-08-20 06:03:49.000000000 +0200
Dmitry Belyavskiy 8f4d19
+++ openssh-8.7p1/ssh-pkcs11-client.c	2021-08-30 13:07:43.666700121 +0200
Dmitry Belyavskiy f32b84
@@ -323,6 +323,8 @@ pkcs11_add_provider(char *name, char *pi
Dmitry Belyavskiy f32b84
 	u_int nkeys, i;
Dmitry Belyavskiy f32b84
 	struct sshbuf *msg;
Dmitry Belyavskiy f32b84
 
Dmitry Belyavskiy f32b84
+	debug_f("called, name = %s", name);
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
 	if (fd < 0 && pkcs11_start_helper() < 0)
Dmitry Belyavskiy f32b84
 		return (-1);
Dmitry Belyavskiy f32b84
 
Dmitry Belyavskiy f32b84
@@ -342,6 +344,7 @@ pkcs11_add_provider(char *name, char *pi
Dmitry Belyavskiy f32b84
 		*keysp = xcalloc(nkeys, sizeof(struct sshkey *));
Dmitry Belyavskiy f32b84
 		if (labelsp)
Dmitry Belyavskiy f32b84
 			*labelsp = xcalloc(nkeys, sizeof(char *));
Dmitry Belyavskiy f32b84
+		debug_f("nkeys = %u", nkeys);
Dmitry Belyavskiy f32b84
 		for (i = 0; i < nkeys; i++) {
Dmitry Belyavskiy f32b84
 			/* XXX clean up properly instead of fatal() */
Dmitry Belyavskiy f32b84
 			if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 ||
Dmitry Belyavskiy 8f4d19
diff -up openssh-8.7p1/ssh-pkcs11.c.pkcs11-uri openssh-8.7p1/ssh-pkcs11.c
Dmitry Belyavskiy 8f4d19
--- openssh-8.7p1/ssh-pkcs11.c.pkcs11-uri	2021-08-20 06:03:49.000000000 +0200
Dmitry Belyavskiy 8f4d19
+++ openssh-8.7p1/ssh-pkcs11.c	2021-08-30 13:12:27.709084157 +0200
Dmitry Belyavskiy f32b84
@@ -55,8 +55,8 @@ struct pkcs11_slotinfo {
Jakub Jelen def1de
 	int			logged_in;
Jakub Jelen def1de
 };
Jakub Jelen def1de
 
Jakub Jelen def1de
-struct pkcs11_provider {
Jakub Jelen def1de
-	char			*name;
Jakub Jelen def1de
+struct pkcs11_module {
Jakub Jelen def1de
+	char			*module_path;
Jakub Jelen def1de
 	void			*handle;
Jakub Jelen def1de
 	CK_FUNCTION_LIST	*function_list;
Jakub Jelen def1de
 	CK_INFO			info;
Dmitry Belyavskiy f32b84
@@ -65,6 +65,13 @@ struct pkcs11_provider {
Jakub Jelen def1de
 	struct pkcs11_slotinfo	*slotinfo;
Jakub Jelen def1de
 	int			valid;
Jakub Jelen def1de
 	int			refcount;
Jakub Jelen def1de
+};
Jakub Jelen def1de
+
Jakub Jelen def1de
+struct pkcs11_provider {
Jakub Jelen def1de
+	char			*name;
Jakub Jelen def1de
+	struct pkcs11_module	*module; /* can be shared between various providers */
Jakub Jelen def1de
+	int			refcount;
Jakub Jelen def1de
+	int			valid;
Jakub Jelen def1de
 	TAILQ_ENTRY(pkcs11_provider) next;
Jakub Jelen def1de
 };
Jakub Jelen def1de
 
Dmitry Belyavskiy f32b84
@@ -75,6 +82,7 @@ struct pkcs11_key {
Jakub Jelen def1de
 	CK_ULONG		slotidx;
Jakub Jelen def1de
 	char			*keyid;
Jakub Jelen def1de
 	int			keyid_len;
Jakub Jelen def1de
+	char			*label;
Jakub Jelen def1de
 };
Jakub Jelen def1de
 
Jakub Jelen def1de
 int pkcs11_interactive = 0;
Jakub Jelen 25c16c
@@ -106,26 +114,61 @@ pkcs11_init(int interactive)
Jakub Jelen def1de
  * this is called when a provider gets unregistered.
Jakub Jelen def1de
  */
Jakub Jelen def1de
 static void
Jakub Jelen def1de
-pkcs11_provider_finalize(struct pkcs11_provider *p)
Jakub Jelen def1de
+pkcs11_module_finalize(struct pkcs11_module *m)
Jakub Jelen def1de
 {
Jakub Jelen def1de
 	CK_RV rv;
Jakub Jelen def1de
 	CK_ULONG i;
Jakub Jelen def1de
 
Dmitry Belyavskiy 8f4d19
-	debug_f("provider \"%s\" refcount %d valid %d",
Dmitry Belyavskiy 8f4d19
-	    p->name, p->refcount, p->valid);
Jakub Jelen def1de
-	if (!p->valid)
Jakub Jelen 25c16c
+	debug_f("%p refcount %d valid %d", m, m->refcount, m->valid);
Jakub Jelen def1de
+	if (!m->valid)
Jakub Jelen def1de
 		return;
Jakub Jelen def1de
-	for (i = 0; i < p->nslots; i++) {
Jakub Jelen def1de
-		if (p->slotinfo[i].session &&
Jakub Jelen def1de
-		    (rv = p->function_list->C_CloseSession(
Jakub Jelen def1de
-		    p->slotinfo[i].session)) != CKR_OK)
Jakub Jelen def1de
+	for (i = 0; i < m->nslots; i++) {
Jakub Jelen def1de
+		if (m->slotinfo[i].session &&
Jakub Jelen def1de
+		    (rv = m->function_list->C_CloseSession(
Jakub Jelen def1de
+		    m->slotinfo[i].session)) != CKR_OK)
Jakub Jelen def1de
 			error("C_CloseSession failed: %lu", rv);
Jakub Jelen def1de
 	}
Jakub Jelen def1de
-	if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK)
Jakub Jelen def1de
+	if ((rv = m->function_list->C_Finalize(NULL)) != CKR_OK)
Jakub Jelen def1de
 		error("C_Finalize failed: %lu", rv);
Jakub Jelen def1de
+	m->valid = 0;
Jakub Jelen def1de
+	m->function_list = NULL;
Jakub Jelen def1de
+	dlclose(m->handle);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+/*
Jakub Jelen def1de
+ * remove a reference to the pkcs11 module.
Jakub Jelen def1de
+ * called when a provider is unregistered.
Jakub Jelen def1de
+ */
Jakub Jelen def1de
+static void
Jakub Jelen def1de
+pkcs11_module_unref(struct pkcs11_module *m)
Jakub Jelen def1de
+{
Jakub Jelen 25c16c
+	debug_f("%p refcount %d", m, m->refcount);
Jakub Jelen def1de
+	if (--m->refcount <= 0) {
Jakub Jelen def1de
+		pkcs11_module_finalize(m);
Jakub Jelen def1de
+		if (m->valid)
Jakub Jelen 25c16c
+			error_f("%p still valid", m);
Jakub Jelen def1de
+		free(m->slotlist);
Jakub Jelen def1de
+		free(m->slotinfo);
Jakub Jelen def1de
+		free(m->module_path);
Jakub Jelen def1de
+		free(m);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+/*
Dmitry Belyavskiy 8f4d19
+ * finalize a provider shared library, it's no longer usable.
Jakub Jelen def1de
+ * however, there might still be keys referencing this provider,
Dmitry Belyavskiy 8f4d19
+ * so the actual freeing of memory is handled by pkcs11_provider_unref().
Jakub Jelen def1de
+ * this is called when a provider gets unregistered.
Jakub Jelen def1de
+ */
Jakub Jelen def1de
+static void
Jakub Jelen def1de
+pkcs11_provider_finalize(struct pkcs11_provider *p)
Jakub Jelen def1de
+{
Jakub Jelen 25c16c
+	debug_f("%p refcount %d valid %d", p, p->refcount, p->valid);
Jakub Jelen def1de
+	if (!p->valid)
Jakub Jelen def1de
+		return;
Jakub Jelen def1de
+	pkcs11_module_unref(p->module);
Jakub Jelen def1de
+	p->module = NULL;
Jakub Jelen def1de
 	p->valid = 0;
Jakub Jelen def1de
-	p->function_list = NULL;
Jakub Jelen def1de
-	dlclose(p->handle);
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
 /*
Dmitry Belyavskiy 8f4d19
@@ -137,11 +180,9 @@ pkcs11_provider_unref(struct pkcs11_prov
Jakub Jelen def1de
 {
Dmitry Belyavskiy 8f4d19
 	debug_f("provider \"%s\" refcount %d", p->name, p->refcount);
Jakub Jelen def1de
 	if (--p->refcount <= 0) {
Jakub Jelen def1de
-		if (p->valid)
Dmitry Belyavskiy 8f4d19
-			error_f("provider \"%s\" still valid", p->name);
Jakub Jelen def1de
 		free(p->name);
Jakub Jelen def1de
-		free(p->slotlist);
Jakub Jelen def1de
-		free(p->slotinfo);
Jakub Jelen def1de
+		if (p->module)
Jakub Jelen def1de
+			pkcs11_module_unref(p->module);
Jakub Jelen def1de
 		free(p);
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 }
Dmitry Belyavskiy f32b84
@@ -159,6 +200,20 @@ pkcs11_terminate(void)
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
+/* lookup provider by module path */
Jakub Jelen def1de
+static struct pkcs11_module *
Jakub Jelen def1de
+pkcs11_provider_lookup_module(char *module_path)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	struct pkcs11_provider *p;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	TAILQ_FOREACH(p, &pkcs11_providers, next) {
Jakub Jelen def1de
+		debug("check %p %s (%s)", p, p->name, p->module->module_path);
Jakub Jelen def1de
+		if (!strcmp(module_path, p->module->module_path))
Jakub Jelen def1de
+			return (p->module);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	return (NULL);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
 /* lookup provider by name */
Jakub Jelen def1de
 static struct pkcs11_provider *
Jakub Jelen def1de
 pkcs11_provider_lookup(char *provider_id)
Dmitry Belyavskiy f32b84
@@ -173,19 +228,55 @@ pkcs11_provider_lookup(char *provider_id
Jakub Jelen def1de
 	return (NULL);
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
+int pkcs11_del_provider_by_uri(struct pkcs11_uri *);
Jakub Jelen def1de
+
Jakub Jelen def1de
 /* unregister provider by name */
Jakub Jelen def1de
 int
Jakub Jelen def1de
 pkcs11_del_provider(char *provider_id)
Dmitry Belyavskiy f32b84
 {
Jakub Jelen def1de
+	int rv;
Jakub Jelen def1de
+	struct pkcs11_uri *uri;
Jakub Jelen def1de
+
Jakub Jelen 25c16c
+	debug_f("called, provider_id = %s", provider_id);
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+      if (provider_id == NULL)
Dmitry Belyavskiy f32b84
+          return 0;
Dmitry Belyavskiy f32b84
+
Jakub Jelen def1de
+	uri = pkcs11_uri_init();
Jakub Jelen def1de
+	if (uri == NULL)
Jakub Jelen 51f5c1
+		fatal("Failed to init PKCS#11 URI");
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) &&
Jakub Jelen def1de
+	    strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) {
Jakub Jelen def1de
+		if (pkcs11_uri_parse(provider_id, uri) != 0)
Jakub Jelen def1de
+			fatal("Failed to parse PKCS#11 URI");
Jakub Jelen def1de
+	} else {
Jakub Jelen def1de
+		uri->module_path = strdup(provider_id);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	rv = pkcs11_del_provider_by_uri(uri);
Jakub Jelen def1de
+	pkcs11_uri_cleanup(uri);
Jakub Jelen def1de
+	return rv;
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+/* unregister provider by PKCS#11 URI */
Jakub Jelen def1de
+int
Jakub Jelen def1de
+pkcs11_del_provider_by_uri(struct pkcs11_uri *uri)
Dmitry Belyavskiy f32b84
+{
Jakub Jelen def1de
 	struct pkcs11_provider *p;
Jakub Jelen def1de
+	int rv = -1;
Jakub Jelen def1de
+	char *provider_uri = pkcs11_uri_get(uri);
Jakub Jelen def1de
 
Jakub Jelen def1de
-	if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
Jakub Jelen 25c16c
+	debug3_f("called with provider %s", provider_uri);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((p = pkcs11_provider_lookup(provider_uri)) != NULL) {
Jakub Jelen def1de
 		TAILQ_REMOVE(&pkcs11_providers, p, next);
Jakub Jelen def1de
 		pkcs11_provider_finalize(p);
Jakub Jelen def1de
 		pkcs11_provider_unref(p);
Jakub Jelen def1de
-		return (0);
Jakub Jelen def1de
+		rv = 0;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
-	return (-1);
Jakub Jelen def1de
+	free(provider_uri);
Jakub Jelen def1de
+	return rv;
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
 static RSA_METHOD *rsa_method;
Dmitry Belyavskiy 8f4d19
@@ -195,6 +286,55 @@ static EC_KEY_METHOD *ec_key_method;
Jakub Jelen def1de
 static int ec_key_idx = 0;
Dmitry Belyavskiy 03150f
 #endif /* OPENSSL_HAS_ECC && HAVE_EC_KEY_METHOD_NEW */
Jakub Jelen def1de
 
Jakub Jelen def1de
+/*
Jakub Jelen def1de
+ * This can't be in the ssh-pkcs11-uri, becase we can not depend on
Jakub Jelen def1de
+ * PKCS#11 structures in ssh-agent (using client-helper communication)
Jakub Jelen def1de
+ */
Jakub Jelen def1de
+int
Jakub Jelen def1de
+pkcs11_uri_write(const struct sshkey *key, FILE *f)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	char *p = NULL;
Jakub Jelen def1de
+	struct pkcs11_uri uri;
Jakub Jelen def1de
+	struct pkcs11_key *k11;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* sanity - is it a RSA key with associated app_data? */
Jakub Jelen def1de
+	switch (key->type) {
Jakub Jelen def1de
+	case KEY_RSA:
Jakub Jelen def1de
+		k11 = RSA_get_ex_data(key->rsa, rsa_idx);
Jakub Jelen def1de
+		break;
Jakub Jelen def1de
+#ifdef HAVE_EC_KEY_METHOD_NEW
Jakub Jelen def1de
+	case KEY_ECDSA:
Jakub Jelen def1de
+		k11 = EC_KEY_get_ex_data(key->ecdsa, ec_key_idx);
Jakub Jelen def1de
+		break;
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
+	default:
Jakub Jelen def1de
+		error("Unknown key type %d", key->type);
Jakub Jelen def1de
+		return -1;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	if (k11 == NULL) {
Jakub Jelen def1de
+		error("Failed to get ex_data for key type %d", key->type);
Jakub Jelen def1de
+		return (-1);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* omit type -- we are looking for private-public or private-certificate pairs */
Jakub Jelen def1de
+	uri.id = k11->keyid;
Jakub Jelen def1de
+	uri.id_len = k11->keyid_len;
Jakub Jelen def1de
+	uri.token = k11->provider->module->slotinfo[k11->slotidx].token.label;
Jakub Jelen def1de
+	uri.object = k11->label;
Jakub Jelen def1de
+	uri.module_path = k11->provider->module->module_path;
Jakub Jelen def1de
+	uri.lib_manuf = k11->provider->module->info.manufacturerID;
Jakub Jelen def1de
+	uri.manuf = k11->provider->module->slotinfo[k11->slotidx].token.manufacturerID;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	p = pkcs11_uri_get(&uri);
Jakub Jelen def1de
+	/* do not cleanup -- we do not allocate here, only reference */
Jakub Jelen def1de
+	if (p == NULL)
Jakub Jelen def1de
+		return -1;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	fprintf(f, " %s", p);
Jakub Jelen def1de
+	free(p);
Jakub Jelen def1de
+	return 0;
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
 /* release a wrapped object */
Jakub Jelen def1de
 static void
Jakub Jelen def1de
 pkcs11_k11_free(void *parent, void *ptr, CRYPTO_EX_DATA *ad, int idx,
Dmitry Belyavskiy 8f4d19
@@ -208,6 +348,7 @@ pkcs11_k11_free(void *parent, void *ptr,
Jakub Jelen 36fef5
 	if (k11->provider)
Jakub Jelen 36fef5
 		pkcs11_provider_unref(k11->provider);
Jakub Jelen 36fef5
 	free(k11->keyid);
Jakub Jelen def1de
+	free(k11->label);
Jakub Jelen 36fef5
 	free(k11);
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Dmitry Belyavskiy 8f4d19
@@ -222,8 +363,8 @@ pkcs11_find(struct pkcs11_provider *p, C
Jakub Jelen def1de
 	CK_RV			rv;
Jakub Jelen def1de
 	int			ret = -1;
Jakub Jelen def1de
 
Jakub Jelen def1de
-	f = p->function_list;
Jakub Jelen def1de
-	session = p->slotinfo[slotidx].session;
Jakub Jelen def1de
+	f = p->module->function_list;
Jakub Jelen def1de
+	session = p->module->slotinfo[slotidx].session;
Jakub Jelen def1de
 	if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) {
Jakub Jelen def1de
 		error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv);
Jakub Jelen def1de
 		return (-1);
Dmitry Belyavskiy 8f4d19
@@ -262,12 +403,12 @@ pkcs11_login_slot(struct pkcs11_provider
Jakub Jelen 51f5c1
 	else {
Jakub Jelen 51f5c1
 		snprintf(prompt, sizeof(prompt), "Enter PIN for '%s': ",
Jakub Jelen 51f5c1
 		    si->token.label);
Jakub Jelen 51f5c1
-		if ((pin = read_passphrase(prompt, RP_ALLOW_EOF)) == NULL) {
Jakub Jelen 51f5c1
+		if ((pin = read_passphrase(prompt, RP_ALLOW_EOF|RP_ALLOW_STDIN)) == NULL) {
Jakub Jelen 25c16c
 			debug_f("no pin specified");
Jakub Jelen 36fef5
 			return (-1);	/* bail out */
Jakub Jelen 36fef5
 		}
Jakub Jelen 36fef5
 	}
Jakub Jelen 36fef5
-	rv = provider->function_list->C_Login(si->session, type, (u_char *)pin,
Jakub Jelen 36fef5
+	rv = provider->module->function_list->C_Login(si->session, type, (u_char *)pin,
Jakub Jelen 36fef5
 	    (pin != NULL) ? strlen(pin) : 0);
Jakub Jelen 36fef5
 	if (pin != NULL)
Jakub Jelen 36fef5
 		freezero(pin, strlen(pin));
Dmitry Belyavskiy 8f4d19
@@ -297,13 +438,14 @@ pkcs11_login_slot(struct pkcs11_provider
Jakub Jelen 36fef5
 static int
Jakub Jelen 36fef5
 pkcs11_login(struct pkcs11_key *k11, CK_USER_TYPE type)
Jakub Jelen 36fef5
 {
Jakub Jelen 36fef5
-	if (k11 == NULL || k11->provider == NULL || !k11->provider->valid) {
Jakub Jelen 36fef5
+	if (k11 == NULL || k11->provider == NULL || !k11->provider->valid ||
Jakub Jelen 36fef5
+	    k11->provider->module == NULL || !k11->provider->module->valid) {
Jakub Jelen 36fef5
 		error("no pkcs11 (valid) provider found");
Jakub Jelen def1de
 		return (-1);
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen 36fef5
 	return pkcs11_login_slot(k11->provider,
Jakub Jelen 36fef5
-	    &k11->provider->slotinfo[k11->slotidx], type);
Jakub Jelen 36fef5
+	    &k11->provider->module->slotinfo[k11->slotidx], type);
Jakub Jelen 36fef5
 }
Jakub Jelen 36fef5
 
Jakub Jelen 36fef5
 
Dmitry Belyavskiy 8f4d19
@@ -319,13 +461,14 @@ pkcs11_check_obj_bool_attrib(struct pkcs
Jakub Jelen def1de
 
Jakub Jelen 36fef5
 	*val = 0;
Jakub Jelen 36fef5
 
Jakub Jelen 36fef5
-	if (!k11->provider || !k11->provider->valid) {
Jakub Jelen 36fef5
+	if (!k11->provider || !k11->provider->valid ||
Jakub Jelen 36fef5
+	    !k11->provider->module || !k11->provider->module->valid) {
Jakub Jelen 36fef5
 		error("no pkcs11 (valid) provider found");
Jakub Jelen def1de
 		return (-1);
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
-	f = k11->provider->function_list;
Jakub Jelen def1de
-	si = &k11->provider->slotinfo[k11->slotidx];
Jakub Jelen def1de
+	f = k11->provider->module->function_list;
Jakub Jelen def1de
+	si = &k11->provider->module->slotinfo[k11->slotidx];
Jakub Jelen def1de
 
Jakub Jelen def1de
 	attr.type = type;
Jakub Jelen def1de
 	attr.pValue = &flag;
Dmitry Belyavskiy 8f4d19
@@ -356,13 +499,14 @@ pkcs11_get_key(struct pkcs11_key *k11, C
Jakub Jelen def1de
 	int			 always_auth = 0;
Jakub Jelen def1de
 	int			 did_login = 0;
Jakub Jelen def1de
 
Jakub Jelen def1de
-	if (!k11->provider || !k11->provider->valid) {
Jakub Jelen 36fef5
+	if (!k11->provider || !k11->provider->valid ||
Jakub Jelen 36fef5
+	    !k11->provider->module || !k11->provider->module->valid) {
Jakub Jelen def1de
 		error("no pkcs11 (valid) provider found");
Jakub Jelen def1de
 		return (-1);
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
-	f = k11->provider->function_list;
Jakub Jelen def1de
-	si = &k11->provider->slotinfo[k11->slotidx];
Jakub Jelen def1de
+	f = k11->provider->module->function_list;
Jakub Jelen def1de
+	si = &k11->provider->module->slotinfo[k11->slotidx];
Jakub Jelen def1de
 
Jakub Jelen def1de
 	if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) {
Jakub Jelen def1de
 		if (pkcs11_login(k11, CKU_USER) < 0) {
Dmitry Belyavskiy 8f4d19
@@ -439,8 +583,8 @@ pkcs11_rsa_private_encrypt(int flen, con
Jakub Jelen def1de
 		return (-1);
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
-	f = k11->provider->function_list;
Jakub Jelen def1de
-	si = &k11->provider->slotinfo[k11->slotidx];
Jakub Jelen def1de
+	f = k11->provider->module->function_list;
Jakub Jelen def1de
+	si = &k11->provider->module->slotinfo[k11->slotidx];
Jakub Jelen def1de
 	tlen = RSA_size(rsa);
Jakub Jelen def1de
 
Jakub Jelen def1de
 	/* XXX handle CKR_BUFFER_TOO_SMALL */
Dmitry Belyavskiy 8f4d19
@@ -484,7 +628,7 @@ pkcs11_rsa_start_wrapper(void)
Jakub Jelen def1de
 /* redirect private key operations for rsa key to pkcs11 token */
Jakub Jelen def1de
 static int
Jakub Jelen def1de
 pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
Jakub Jelen def1de
-    CK_ATTRIBUTE *keyid_attrib, RSA *rsa)
Jakub Jelen def1de
+    CK_ATTRIBUTE *keyid_attrib, CK_ATTRIBUTE *label_attrib, RSA *rsa)
Jakub Jelen def1de
 {
Jakub Jelen def1de
 	struct pkcs11_key	*k11;
Jakub Jelen def1de
 
Dmitry Belyavskiy 8f4d19
@@ -502,6 +646,12 @@ pkcs11_rsa_wrap(struct pkcs11_provider *
Jakub Jelen def1de
 		memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
+	if (label_attrib->ulValueLen > 0 ) {
Jakub Jelen def1de
+		k11->label = xmalloc(label_attrib->ulValueLen+1);
Jakub Jelen def1de
+		memcpy(k11->label, label_attrib->pValue, label_attrib->ulValueLen);
Jakub Jelen def1de
+		k11->label[label_attrib->ulValueLen] = 0;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
 	RSA_set_method(rsa, rsa_method);
Jakub Jelen def1de
 	RSA_set_ex_data(rsa, rsa_idx, k11);
Jakub Jelen def1de
 	return (0);
Dmitry Belyavskiy 8f4d19
@@ -532,8 +682,8 @@ ecdsa_do_sign(const unsigned char *dgst,
Jakub Jelen def1de
 		return (NULL);
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
-	f = k11->provider->function_list;
Jakub Jelen def1de
-	si = &k11->provider->slotinfo[k11->slotidx];
Jakub Jelen def1de
+	f = k11->provider->module->function_list;
Jakub Jelen def1de
+	si = &k11->provider->module->slotinfo[k11->slotidx];
Jakub Jelen def1de
 
Jakub Jelen def1de
 	siglen = ECDSA_size(ec);
Jakub Jelen def1de
 	sig = xmalloc(siglen);
Dmitry Belyavskiy 8f4d19
@@ -598,7 +748,7 @@ pkcs11_ecdsa_start_wrapper(void)
Jakub Jelen def1de
 
Jakub Jelen def1de
 static int
Jakub Jelen def1de
 pkcs11_ecdsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
Jakub Jelen def1de
-    CK_ATTRIBUTE *keyid_attrib, EC_KEY *ec)
Jakub Jelen def1de
+    CK_ATTRIBUTE *keyid_attrib, CK_ATTRIBUTE *label_attrib, EC_KEY *ec)
Jakub Jelen def1de
 {
Jakub Jelen def1de
 	struct pkcs11_key	*k11;
Jakub Jelen def1de
 
Dmitry Belyavskiy 8f4d19
@@ -614,6 +764,12 @@ pkcs11_ecdsa_wrap(struct pkcs11_provider
Dmitry Belyavskiy 03150f
 		k11->keyid = xmalloc(k11->keyid_len);
Dmitry Belyavskiy 03150f
 		memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
Dmitry Belyavskiy 03150f
	}
Jakub Jelen def1de
+	if (label_attrib->ulValueLen > 0 ) {
Jakub Jelen def1de
+		k11->label = xmalloc(label_attrib->ulValueLen+1);
Jakub Jelen def1de
+		memcpy(k11->label, label_attrib->pValue, label_attrib->ulValueLen);
Jakub Jelen def1de
+		k11->label[label_attrib->ulValueLen] = 0;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
 	EC_KEY_set_method(ec, ec_key_method);
Jakub Jelen def1de
 	EC_KEY_set_ex_data(ec, ec_key_idx, k11);
Jakub Jelen def1de
 
Dmitry Belyavskiy 8f4d19
@@ -650,8 +806,8 @@ pkcs11_open_session(struct pkcs11_provid
Jakub Jelen def1de
 	CK_SESSION_HANDLE	session;
Jakub Jelen 36fef5
 	int			login_required, ret;
Jakub Jelen def1de
 
Jakub Jelen def1de
-	f = p->function_list;
Jakub Jelen def1de
-	si = &p->slotinfo[slotidx];
Jakub Jelen def1de
+	f = p->module->function_list;
Jakub Jelen def1de
+	si = &p->module->slotinfo[slotidx];
Jakub Jelen def1de
 
Jakub Jelen def1de
 	login_required = si->token.flags & CKF_LOGIN_REQUIRED;
Jakub Jelen def1de
 
Dmitry Belyavskiy 8f4d19
@@ -661,9 +817,9 @@ pkcs11_open_session(struct pkcs11_provid
Jakub Jelen def1de
 		error("pin required");
Jakub Jelen def1de
 		return (-SSH_PKCS11_ERR_PIN_REQUIRED);
Jakub Jelen def1de
 	}
Jakub Jelen def1de
-	if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION|
Jakub Jelen def1de
+	if ((rv = f->C_OpenSession(p->module->slotlist[slotidx], CKF_RW_SESSION|
Jakub Jelen def1de
 	    CKF_SERIAL_SESSION, NULL, NULL, &session)) != CKR_OK) {
Jakub Jelen def1de
-		error("C_OpenSession failed: %lu", rv);
Jakub Jelen def1de
+		error("C_OpenSession failed for slot %lu: %lu", slotidx, rv);
Jakub Jelen def1de
 		return (-1);
Jakub Jelen def1de
 	}
Jakub Jelen 36fef5
 	if (login_required && pin != NULL && strlen(pin) != 0) {
Dmitry Belyavskiy 8f4d19
@@ -699,7 +855,8 @@ static struct sshkey *
Jakub Jelen def1de
 pkcs11_fetch_ecdsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
Jakub Jelen def1de
     CK_OBJECT_HANDLE *obj)
Jakub Jelen def1de
 {
Jakub Jelen def1de
-	CK_ATTRIBUTE		 key_attr[3];
Jakub Jelen def1de
+	CK_ATTRIBUTE		 key_attr[4];
Jakub Jelen def1de
+	int			 nattr = 4;
Jakub Jelen def1de
 	CK_SESSION_HANDLE	 session;
Jakub Jelen def1de
 	CK_FUNCTION_LIST	*f = NULL;
Jakub Jelen def1de
 	CK_RV			 rv;
Dmitry Belyavskiy 8f4d19
@@ -713,14 +870,15 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_
Jakub Jelen def1de
 
Jakub Jelen def1de
 	memset(&key_attr, 0, sizeof(key_attr));
Jakub Jelen def1de
 	key_attr[0].type = CKA_ID;
Jakub Jelen def1de
-	key_attr[1].type = CKA_EC_POINT;
Jakub Jelen def1de
-	key_attr[2].type = CKA_EC_PARAMS;
Jakub Jelen def1de
+	key_attr[1].type = CKA_LABEL;
Jakub Jelen def1de
+	key_attr[2].type = CKA_EC_POINT;
Jakub Jelen def1de
+	key_attr[3].type = CKA_EC_PARAMS;
Jakub Jelen def1de
 
Jakub Jelen def1de
-	session = p->slotinfo[slotidx].session;
Jakub Jelen def1de
-	f = p->function_list;
Jakub Jelen def1de
+	session = p->module->slotinfo[slotidx].session;
Jakub Jelen def1de
+	f = p->module->function_list;
Jakub Jelen def1de
 
Jakub Jelen def1de
 	/* figure out size of the attributes */
Jakub Jelen def1de
-	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
Jakub Jelen def1de
+	rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr);
Jakub Jelen def1de
 	if (rv != CKR_OK) {
Jakub Jelen def1de
 		error("C_GetAttributeValue failed: %lu", rv);
Jakub Jelen def1de
 		return (NULL);
Dmitry Belyavskiy 8f4d19
@@ -731,19 +889,19 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_
Jakub Jelen ee6f0f
 	 * ensure that none of the others are zero length.
Jakub Jelen def1de
 	 * XXX assumes CKA_ID is always first.
Jakub Jelen def1de
 	 */
Jakub Jelen ee6f0f
-	if (key_attr[1].ulValueLen == 0 ||
Jakub Jelen def1de
-	    key_attr[2].ulValueLen == 0) {
Jakub Jelen ee6f0f
+	if (key_attr[2].ulValueLen == 0 ||
Jakub Jelen def1de
+	    key_attr[3].ulValueLen == 0) {
Jakub Jelen def1de
 		error("invalid attribute length");
Jakub Jelen def1de
 		return (NULL);
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
 	/* allocate buffers for attributes */
Jakub Jelen def1de
-	for (i = 0; i < 3; i++)
Jakub Jelen def1de
+	for (i = 0; i < nattr; i++)
Jakub Jelen def1de
 		if (key_attr[i].ulValueLen > 0)
Jakub Jelen def1de
 			key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
Jakub Jelen def1de
 
Jakub Jelen def1de
 	/* retrieve ID, public point and curve parameters of EC key */
Jakub Jelen def1de
-	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
Jakub Jelen def1de
+	rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr);
Jakub Jelen def1de
 	if (rv != CKR_OK) {
Jakub Jelen def1de
 		error("C_GetAttributeValue failed: %lu", rv);
Jakub Jelen def1de
 		goto fail;
Dmitry Belyavskiy 8f4d19
@@ -755,8 +913,8 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_
Jakub Jelen def1de
 		goto fail;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
-	attrp = key_attr[2].pValue;
Jakub Jelen def1de
-	group = d2i_ECPKParameters(NULL, &attrp, key_attr[2].ulValueLen);
Jakub Jelen def1de
+	attrp = key_attr[3].pValue;
Jakub Jelen def1de
+	group = d2i_ECPKParameters(NULL, &attrp, key_attr[3].ulValueLen);
Jakub Jelen def1de
 	if (group == NULL) {
Jakub Jelen def1de
 		ossl_error("d2i_ECPKParameters failed");
Jakub Jelen def1de
 		goto fail;
Dmitry Belyavskiy 8f4d19
@@ -767,13 +925,13 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_
Jakub Jelen def1de
 		goto fail;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
-	if (key_attr[1].ulValueLen <= 2) {
Jakub Jelen def1de
+	if (key_attr[2].ulValueLen <= 2) {
Jakub Jelen def1de
 		error("CKA_EC_POINT too small");
Jakub Jelen def1de
 		goto fail;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
-	attrp = key_attr[1].pValue;
Jakub Jelen def1de
-	octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[1].ulValueLen);
Jakub Jelen def1de
+	attrp = key_attr[2].pValue;
Jakub Jelen def1de
+	octet = d2i_ASN1_OCTET_STRING(NULL, &attrp, key_attr[2].ulValueLen);
Jakub Jelen def1de
 	if (octet == NULL) {
Jakub Jelen def1de
 		ossl_error("d2i_ASN1_OCTET_STRING failed");
Jakub Jelen def1de
 		goto fail;
Dmitry Belyavskiy 8f4d19
@@ -790,7 +948,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_
Jakub Jelen def1de
 		goto fail;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
-	if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], ec))
Jakub Jelen def1de
+	if (pkcs11_ecdsa_wrap(p, slotidx, &key_attr[0], &key_attr[1], ec))
Jakub Jelen def1de
 		goto fail;
Jakub Jelen def1de
 
Jakub Jelen def1de
 	key = sshkey_new(KEY_UNSPEC);
Dmitry Belyavskiy 8f4d19
@@ -806,7 +964,7 @@ pkcs11_fetch_ecdsa_pubkey(struct pkcs11_
Jakub Jelen def1de
 	ec = NULL;	/* now owned by key */
Jakub Jelen def1de
 
Jakub Jelen def1de
 fail:
Jakub Jelen def1de
-	for (i = 0; i < 3; i++)
Jakub Jelen def1de
+	for (i = 0; i < nattr; i++)
Jakub Jelen def1de
 		free(key_attr[i].pValue);
Jakub Jelen def1de
 	if (ec)
Jakub Jelen def1de
 		EC_KEY_free(ec);
Dmitry Belyavskiy 8f4d19
@@ -823,7 +981,8 @@ static struct sshkey *
Jakub Jelen def1de
 pkcs11_fetch_rsa_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
Jakub Jelen def1de
     CK_OBJECT_HANDLE *obj)
Jakub Jelen def1de
 {
Jakub Jelen def1de
-	CK_ATTRIBUTE		 key_attr[3];
Jakub Jelen def1de
+	CK_ATTRIBUTE		 key_attr[4];
Jakub Jelen def1de
+	int			 nattr = 4;
Jakub Jelen def1de
 	CK_SESSION_HANDLE	 session;
Jakub Jelen def1de
 	CK_FUNCTION_LIST	*f = NULL;
Jakub Jelen def1de
 	CK_RV			 rv;
Dmitry Belyavskiy 8f4d19
@@ -834,14 +993,15 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr
Jakub Jelen def1de
 
Jakub Jelen def1de
 	memset(&key_attr, 0, sizeof(key_attr));
Jakub Jelen def1de
 	key_attr[0].type = CKA_ID;
Jakub Jelen def1de
-	key_attr[1].type = CKA_MODULUS;
Jakub Jelen def1de
-	key_attr[2].type = CKA_PUBLIC_EXPONENT;
Jakub Jelen def1de
+	key_attr[1].type = CKA_LABEL;
Jakub Jelen def1de
+	key_attr[2].type = CKA_MODULUS;
Jakub Jelen def1de
+	key_attr[3].type = CKA_PUBLIC_EXPONENT;
Jakub Jelen def1de
 
Jakub Jelen def1de
-	session = p->slotinfo[slotidx].session;
Jakub Jelen def1de
-	f = p->function_list;
Jakub Jelen def1de
+	session = p->module->slotinfo[slotidx].session;
Jakub Jelen def1de
+	f = p->module->function_list;
Jakub Jelen def1de
 
Jakub Jelen def1de
 	/* figure out size of the attributes */
Jakub Jelen def1de
-	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
Jakub Jelen def1de
+	rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr);
Jakub Jelen def1de
 	if (rv != CKR_OK) {
Jakub Jelen def1de
 		error("C_GetAttributeValue failed: %lu", rv);
Jakub Jelen def1de
 		return (NULL);
Dmitry Belyavskiy 8f4d19
@@ -852,19 +1012,19 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr
Jakub Jelen ee6f0f
 	 * ensure that none of the others are zero length.
Jakub Jelen def1de
 	 * XXX assumes CKA_ID is always first.
Jakub Jelen def1de
 	 */
Jakub Jelen ee6f0f
-	if (key_attr[1].ulValueLen == 0 ||
Jakub Jelen def1de
-	    key_attr[2].ulValueLen == 0) {
Jakub Jelen ee6f0f
+	if (key_attr[2].ulValueLen == 0 ||
Jakub Jelen def1de
+	    key_attr[3].ulValueLen == 0) {
Jakub Jelen def1de
 		error("invalid attribute length");
Jakub Jelen def1de
 		return (NULL);
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
 	/* allocate buffers for attributes */
Jakub Jelen def1de
-	for (i = 0; i < 3; i++)
Jakub Jelen def1de
+	for (i = 0; i < nattr; i++)
Jakub Jelen def1de
 		if (key_attr[i].ulValueLen > 0)
Jakub Jelen def1de
 			key_attr[i].pValue = xcalloc(1, key_attr[i].ulValueLen);
Jakub Jelen def1de
 
Jakub Jelen def1de
 	/* retrieve ID, modulus and public exponent of RSA key */
Jakub Jelen def1de
-	rv = f->C_GetAttributeValue(session, *obj, key_attr, 3);
Jakub Jelen def1de
+	rv = f->C_GetAttributeValue(session, *obj, key_attr, nattr);
Jakub Jelen def1de
 	if (rv != CKR_OK) {
Jakub Jelen def1de
 		error("C_GetAttributeValue failed: %lu", rv);
Jakub Jelen def1de
 		goto fail;
Dmitry Belyavskiy 8f4d19
@@ -876,8 +1036,8 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr
Jakub Jelen def1de
 		goto fail;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
-	rsa_n = BN_bin2bn(key_attr[1].pValue, key_attr[1].ulValueLen, NULL);
Jakub Jelen def1de
-	rsa_e = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL);
Jakub Jelen def1de
+	rsa_n = BN_bin2bn(key_attr[2].pValue, key_attr[2].ulValueLen, NULL);
Jakub Jelen def1de
+	rsa_e = BN_bin2bn(key_attr[3].pValue, key_attr[3].ulValueLen, NULL);
Jakub Jelen def1de
 	if (rsa_n == NULL || rsa_e == NULL) {
Jakub Jelen def1de
 		error("BN_bin2bn failed");
Jakub Jelen def1de
 		goto fail;
Dmitry Belyavskiy 8f4d19
@@ -886,7 +1046,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr
Jakub Jelen 25c16c
 		fatal_f("set key");
Jakub Jelen def1de
 	rsa_n = rsa_e = NULL; /* transferred */
Jakub Jelen def1de
 
Jakub Jelen def1de
-	if (pkcs11_rsa_wrap(p, slotidx, &key_attr[0], rsa))
Jakub Jelen def1de
+	if (pkcs11_rsa_wrap(p, slotidx, &key_attr[0], &key_attr[1], rsa))
Jakub Jelen def1de
 		goto fail;
Jakub Jelen def1de
 
Jakub Jelen def1de
 	key = sshkey_new(KEY_UNSPEC);
Dmitry Belyavskiy 8f4d19
@@ -901,7 +1061,7 @@ pkcs11_fetch_rsa_pubkey(struct pkcs11_pr
Jakub Jelen def1de
 	rsa = NULL;	/* now owned by key */
Jakub Jelen def1de
 
Jakub Jelen def1de
 fail:
Jakub Jelen def1de
-	for (i = 0; i < 3; i++)
Jakub Jelen def1de
+	for (i = 0; i < nattr; i++)
Jakub Jelen def1de
 		free(key_attr[i].pValue);
Jakub Jelen def1de
 	RSA_free(rsa);
Jakub Jelen def1de
 
Dmitry Belyavskiy 8f4d19
@@ -912,7 +1072,8 @@ static int
Jakub Jelen def1de
 pkcs11_fetch_x509_pubkey(struct pkcs11_provider *p, CK_ULONG slotidx,
Jakub Jelen 51f5c1
     CK_OBJECT_HANDLE *obj, struct sshkey **keyp, char **labelp)
Jakub Jelen def1de
 {
Jakub Jelen def1de
-	CK_ATTRIBUTE		 cert_attr[3];
Jakub Jelen def1de
+	CK_ATTRIBUTE		 cert_attr[4];
Jakub Jelen def1de
+	int			 nattr = 4;
Jakub Jelen def1de
 	CK_SESSION_HANDLE	 session;
Jakub Jelen def1de
 	CK_FUNCTION_LIST	*f = NULL;
Jakub Jelen def1de
 	CK_RV			 rv;
Dmitry Belyavskiy 8f4d19
@@ -936,14 +1097,15 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p
Jakub Jelen def1de
 
Jakub Jelen def1de
 	memset(&cert_attr, 0, sizeof(cert_attr));
Jakub Jelen def1de
 	cert_attr[0].type = CKA_ID;
Jakub Jelen def1de
-	cert_attr[1].type = CKA_SUBJECT;
Jakub Jelen def1de
-	cert_attr[2].type = CKA_VALUE;
Jakub Jelen def1de
+	cert_attr[1].type = CKA_LABEL;
Jakub Jelen def1de
+	cert_attr[2].type = CKA_SUBJECT;
Jakub Jelen def1de
+	cert_attr[3].type = CKA_VALUE;
Jakub Jelen def1de
 
Jakub Jelen def1de
-	session = p->slotinfo[slotidx].session;
Jakub Jelen def1de
-	f = p->function_list;
Jakub Jelen def1de
+	session = p->module->slotinfo[slotidx].session;
Jakub Jelen def1de
+	f = p->module->function_list;
Jakub Jelen def1de
 
Jakub Jelen def1de
 	/* figure out size of the attributes */
Jakub Jelen def1de
-	rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
Jakub Jelen def1de
+	rv = f->C_GetAttributeValue(session, *obj, cert_attr, nattr);
Jakub Jelen def1de
 	if (rv != CKR_OK) {
Jakub Jelen def1de
 		error("C_GetAttributeValue failed: %lu", rv);
Jakub Jelen 51f5c1
 		return -1;
Dmitry Belyavskiy 8f4d19
@@ -955,18 +1117,19 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p
Jakub Jelen def1de
 	 * XXX assumes CKA_ID is always first.
Jakub Jelen def1de
 	 */
Jakub Jelen def1de
 	if (cert_attr[1].ulValueLen == 0 ||
Jakub Jelen def1de
-	    cert_attr[2].ulValueLen == 0) {
Jakub Jelen def1de
+	    cert_attr[2].ulValueLen == 0 ||
Jakub Jelen def1de
+	    cert_attr[3].ulValueLen == 0) {
Jakub Jelen def1de
 		error("invalid attribute length");
Jakub Jelen 51f5c1
 		return -1;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 
Jakub Jelen def1de
 	/* allocate buffers for attributes */
Jakub Jelen def1de
-	for (i = 0; i < 3; i++)
Jakub Jelen def1de
+	for (i = 0; i < nattr; i++)
Jakub Jelen def1de
 		if (cert_attr[i].ulValueLen > 0)
Jakub Jelen def1de
 			cert_attr[i].pValue = xcalloc(1, cert_attr[i].ulValueLen);
Jakub Jelen def1de
 
Jakub Jelen def1de
 	/* retrieve ID, subject and value of certificate */
Jakub Jelen def1de
-	rv = f->C_GetAttributeValue(session, *obj, cert_attr, 3);
Jakub Jelen def1de
+	rv = f->C_GetAttributeValue(session, *obj, cert_attr, nattr);
Jakub Jelen def1de
 	if (rv != CKR_OK) {
Jakub Jelen def1de
 		error("C_GetAttributeValue failed: %lu", rv);
Jakub Jelen 51f5c1
 		goto out;
Dmitry Belyavskiy 8f4d19
@@ -980,8 +1143,8 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p
Jakub Jelen 51f5c1
 		subject = xstrdup("invalid subject");
Jakub Jelen 51f5c1
 	X509_NAME_free(x509_name);
Jakub Jelen def1de
 
Jakub Jelen def1de
-	cp = cert_attr[2].pValue;
Jakub Jelen 51f5c1
-	if ((x509 = d2i_X509(NULL, &cp, cert_attr[2].ulValueLen)) == NULL) {
Jakub Jelen def1de
+	cp = cert_attr[3].pValue;
Jakub Jelen 51f5c1
+	if ((x509 = d2i_X509(NULL, &cp, cert_attr[3].ulValueLen)) == NULL) {
Jakub Jelen def1de
 		error("d2i_x509 failed");
Jakub Jelen 51f5c1
 		goto out;
Jakub Jelen def1de
 	}
Dmitry Belyavskiy 8f4d19
@@ -1001,7 +1164,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p
Jakub Jelen 51f5c1
 			goto out;
Jakub Jelen def1de
 		}
Jakub Jelen def1de
 
Jakub Jelen def1de
-		if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], rsa))
Jakub Jelen def1de
+		if (pkcs11_rsa_wrap(p, slotidx, &cert_attr[0], &cert_attr[1], rsa))
Jakub Jelen 51f5c1
 			goto out;
Jakub Jelen def1de
 
Jakub Jelen def1de
 		key = sshkey_new(KEY_UNSPEC);
Dmitry Belyavskiy 8f4d19
@@ -1031,7 +1194,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p
Jakub Jelen 51f5c1
 			goto out;
Jakub Jelen def1de
 		}
Jakub Jelen def1de
 
Jakub Jelen def1de
-		if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], ec))
Jakub Jelen def1de
+		if (pkcs11_ecdsa_wrap(p, slotidx, &cert_attr[0], &cert_attr[1], ec))
Jakub Jelen 51f5c1
 			goto out;
Jakub Jelen def1de
 
Jakub Jelen def1de
 		key = sshkey_new(KEY_UNSPEC);
Dmitry Belyavskiy 8f4d19
@@ -1051,7 +1214,7 @@ pkcs11_fetch_x509_pubkey(struct pkcs11_p
Jakub Jelen 51f5c1
 		goto out;
Jakub Jelen 51f5c1
 	}
Jakub Jelen 51f5c1
  out:
Jakub Jelen def1de
-	for (i = 0; i < 3; i++)
Jakub Jelen def1de
+	for (i = 0; i < nattr; i++)
Jakub Jelen def1de
 		free(cert_attr[i].pValue);
Jakub Jelen def1de
 	X509_free(x509);
Jakub Jelen def1de
 	RSA_free(rsa);
Dmitry Belyavskiy 8f4d19
@@ -1102,11 +1265,12 @@ note_key(struct pkcs11_provider *p, CK_U
Jakub Jelen def1de
  */
Jakub Jelen def1de
 static int
Jakub Jelen def1de
 pkcs11_fetch_certs(struct pkcs11_provider *p, CK_ULONG slotidx,
Jakub Jelen 51f5c1
-    struct sshkey ***keysp, char ***labelsp, int *nkeys)
Jakub Jelen 51f5c1
+    struct sshkey ***keysp, char ***labelsp, int *nkeys, struct pkcs11_uri *uri)
Jakub Jelen def1de
 {
Jakub Jelen def1de
 	struct sshkey		*key = NULL;
Jakub Jelen def1de
 	CK_OBJECT_CLASS		 key_class;
Jakub Jelen def1de
-	CK_ATTRIBUTE		 key_attr[1];
Jakub Jelen def1de
+	CK_ATTRIBUTE		 key_attr[3];
Jakub Jelen def1de
+	int			 nattr = 1;
Jakub Jelen def1de
 	CK_SESSION_HANDLE	 session;
Jakub Jelen def1de
 	CK_FUNCTION_LIST	*f = NULL;
Jakub Jelen def1de
 	CK_RV			 rv;
Dmitry Belyavskiy 8f4d19
@@ -1123,10 +1287,23 @@ pkcs11_fetch_certs(struct pkcs11_provide
Jakub Jelen def1de
 	key_attr[0].pValue = &key_class;
Jakub Jelen def1de
 	key_attr[0].ulValueLen = sizeof(key_class);
Jakub Jelen def1de
 
Jakub Jelen def1de
-	session = p->slotinfo[slotidx].session;
Jakub Jelen def1de
-	f = p->function_list;
Jakub Jelen def1de
+	if (uri->id != NULL) {
Jakub Jelen def1de
+		key_attr[nattr].type = CKA_ID;
Jakub Jelen def1de
+		key_attr[nattr].pValue = uri->id;
Jakub Jelen def1de
+		key_attr[nattr].ulValueLen = uri->id_len;
Jakub Jelen def1de
+		nattr++;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	if (uri->object != NULL) {
Jakub Jelen def1de
+		key_attr[nattr].type = CKA_LABEL;
Jakub Jelen def1de
+		key_attr[nattr].pValue = uri->object;
Jakub Jelen def1de
+		key_attr[nattr].ulValueLen = strlen(uri->object);
Jakub Jelen def1de
+		nattr++;
Jakub Jelen def1de
+	}
Jakub Jelen 51f5c1
+
Jakub Jelen def1de
+	session = p->module->slotinfo[slotidx].session;
Jakub Jelen def1de
+	f = p->module->function_list;
Jakub Jelen 51f5c1
 
Jakub Jelen 51f5c1
-	rv = f->C_FindObjectsInit(session, key_attr, 1);
Jakub Jelen def1de
+	rv = f->C_FindObjectsInit(session, key_attr, nattr);
Jakub Jelen def1de
 	if (rv != CKR_OK) {
Jakub Jelen def1de
 		error("C_FindObjectsInit failed: %lu", rv);
Jakub Jelen def1de
 		goto fail;
Dmitry Belyavskiy 8f4d19
@@ -1207,11 +1384,12 @@ fail:
Jakub Jelen def1de
  */
Jakub Jelen def1de
 static int
Jakub Jelen def1de
 pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
Jakub Jelen 51f5c1
-    struct sshkey ***keysp, char ***labelsp, int *nkeys)
Jakub Jelen 51f5c1
+    struct sshkey ***keysp, char ***labelsp, int *nkeys, struct pkcs11_uri *uri)
Jakub Jelen def1de
 {
Jakub Jelen def1de
 	struct sshkey		*key = NULL;
Jakub Jelen def1de
 	CK_OBJECT_CLASS		 key_class;
Jakub Jelen 51f5c1
-	CK_ATTRIBUTE		 key_attr[2];
Jakub Jelen def1de
+	CK_ATTRIBUTE		 key_attr[3];
Jakub Jelen def1de
+	int			 nattr = 1;
Jakub Jelen def1de
 	CK_SESSION_HANDLE	 session;
Jakub Jelen def1de
 	CK_FUNCTION_LIST	*f = NULL;
Jakub Jelen def1de
 	CK_RV			 rv;
Dmitry Belyavskiy 8f4d19
@@ -1227,10 +1405,23 @@ pkcs11_fetch_keys(struct pkcs11_provider
Jakub Jelen def1de
 	key_attr[0].pValue = &key_class;
Jakub Jelen def1de
 	key_attr[0].ulValueLen = sizeof(key_class);
Jakub Jelen def1de
 
Jakub Jelen def1de
-	session = p->slotinfo[slotidx].session;
Jakub Jelen def1de
-	f = p->function_list;
Jakub Jelen def1de
+	if (uri->id != NULL) {
Jakub Jelen def1de
+		key_attr[nattr].type = CKA_ID;
Jakub Jelen def1de
+		key_attr[nattr].pValue = uri->id;
Jakub Jelen def1de
+		key_attr[nattr].ulValueLen = uri->id_len;
Jakub Jelen def1de
+		nattr++;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	if (uri->object != NULL) {
Jakub Jelen def1de
+		key_attr[nattr].type = CKA_LABEL;
Jakub Jelen def1de
+		key_attr[nattr].pValue = uri->object;
Jakub Jelen def1de
+		key_attr[nattr].ulValueLen = strlen(uri->object);
Jakub Jelen def1de
+		nattr++;
Jakub Jelen def1de
+	}
Jakub Jelen 51f5c1
 
Jakub Jelen 51f5c1
-	rv = f->C_FindObjectsInit(session, key_attr, 1);
Dmitry Belyavskiy 8f4d19
+	session = p->module->slotinfo[slotidx].session;
Dmitry Belyavskiy 8f4d19
+	f = p->module->function_list;
Dmitry Belyavskiy 8f4d19
+
Jakub Jelen def1de
+	rv = f->C_FindObjectsInit(session, key_attr, nattr);
Jakub Jelen def1de
 	if (rv != CKR_OK) {
Jakub Jelen def1de
 		error("C_FindObjectsInit failed: %lu", rv);
Jakub Jelen def1de
 		goto fail;
Dmitry Belyavskiy 8f4d19
@@ -1499,16 +1690,10 @@ pkcs11_ecdsa_generate_private_key(struct
Jakub Jelen def1de
 }
Jakub Jelen def1de
 #endif /* WITH_PKCS11_KEYGEN */
Jakub Jelen def1de
 
Jakub Jelen def1de
-/*
Jakub Jelen def1de
- * register a new provider, fails if provider already exists. if
Jakub Jelen def1de
- * keyp is provided, fetch keys.
Jakub Jelen def1de
- */
Jakub Jelen def1de
 static int
Jakub Jelen 51f5c1
-pkcs11_register_provider(char *provider_id, char *pin,
Jakub Jelen 51f5c1
-    struct sshkey ***keyp, char ***labelsp,
Jakub Jelen def1de
-    struct pkcs11_provider **providerp, CK_ULONG user)
Jakub Jelen def1de
+pkcs11_initialize_provider(struct pkcs11_uri *uri, struct pkcs11_provider **providerp)
Jakub Jelen def1de
 {
Jakub Jelen def1de
-	int nkeys, need_finalize = 0;
Jakub Jelen def1de
+	int need_finalize = 0;
Jakub Jelen def1de
 	int ret = -1;
Jakub Jelen def1de
 	struct pkcs11_provider *p = NULL;
Jakub Jelen def1de
 	void *handle = NULL;
Dmitry Belyavskiy 8f4d19
@@ -1517,164 +1702,298 @@ pkcs11_register_provider(char *provider_
Jakub Jelen def1de
 	CK_FUNCTION_LIST *f = NULL;
Jakub Jelen def1de
 	CK_TOKEN_INFO *token;
Jakub Jelen def1de
 	CK_ULONG i;
Jakub Jelen def1de
+	char *provider_module = NULL;
Jakub Jelen 66e988
+	struct pkcs11_module *m = NULL;
Dmitry Belyavskiy f32b84
 
Dmitry Belyavskiy f32b84
-	if (providerp == NULL)
Jakub Jelen def1de
+	/* if no provider specified, fallback to p11-kit */
Jakub Jelen def1de
+	if (uri->module_path == NULL) {
Jakub Jelen def1de
+#ifdef PKCS11_DEFAULT_PROVIDER
Jakub Jelen def1de
+		provider_module = strdup(PKCS11_DEFAULT_PROVIDER);
Jakub Jelen def1de
+#else
Dmitry Belyavskiy f32b84
+		error_f("No module path provided");
Dmitry Belyavskiy f32b84
 		goto fail;
Dmitry Belyavskiy f32b84
-	*providerp = NULL;
Jakub Jelen def1de
+#endif
Jakub Jelen def1de
+	} else {
Jakub Jelen def1de
+		provider_module = strdup(uri->module_path);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
 
Dmitry Belyavskiy f32b84
-	if (keyp != NULL)
Dmitry Belyavskiy f32b84
-		*keyp = NULL;
Dmitry Belyavskiy f32b84
-	if (labelsp != NULL)
Dmitry Belyavskiy f32b84
-		*labelsp = NULL;
Dmitry Belyavskiy f32b84
+	p = xcalloc(1, sizeof(*p));
Dmitry Belyavskiy f32b84
+	p->name = pkcs11_uri_get(uri);
Dmitry Belyavskiy f32b84
 
Jakub Jelen def1de
-	if (pkcs11_provider_lookup(provider_id) != NULL) {
Jakub Jelen 25c16c
-		debug_f("provider already registered: %s", provider_id);
Jakub Jelen def1de
-		goto fail;
Jakub Jelen def1de
+	if ((m = pkcs11_provider_lookup_module(provider_module)) != NULL
Jakub Jelen def1de
+	   && m->valid) {
Jakub Jelen 25c16c
+		debug_f("provider module already initialized: %s", provider_module);
Jakub Jelen def1de
+		free(provider_module);
Jakub Jelen def1de
+		/* Skip the initialization of PKCS#11 module */
Jakub Jelen def1de
+		m->refcount++;
Jakub Jelen def1de
+		p->module = m;
Jakub Jelen def1de
+		p->valid = 1;
Jakub Jelen def1de
+		TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
Jakub Jelen def1de
+		p->refcount++;	/* add to provider list */
Jakub Jelen def1de
+		*providerp = p;
Jakub Jelen def1de
+		return 0;
Jakub Jelen def1de
+	} else {
Jakub Jelen def1de
+		m = xcalloc(1, sizeof(*m));
Jakub Jelen def1de
+		p->module = m;
Jakub Jelen def1de
+		m->refcount++;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
+
Jakub Jelen def1de
 	/* open shared pkcs11-library */
Jakub Jelen def1de
-	if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) {
Jakub Jelen def1de
-		error("dlopen %s failed: %s", provider_id, dlerror());
Jakub Jelen def1de
+	if ((handle = dlopen(provider_module, RTLD_NOW)) == NULL) {
Jakub Jelen def1de
+		error("dlopen %s failed: %s", provider_module, dlerror());
Jakub Jelen def1de
 		goto fail;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 	if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) {
Jakub Jelen def1de
 		error("dlsym(C_GetFunctionList) failed: %s", dlerror());
Jakub Jelen def1de
 		goto fail;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
-	p = xcalloc(1, sizeof(*p));
Jakub Jelen def1de
-	p->name = xstrdup(provider_id);
Jakub Jelen def1de
-	p->handle = handle;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	p->module->handle = handle;
Jakub Jelen def1de
 	/* setup the pkcs11 callbacks */
Jakub Jelen def1de
 	if ((rv = (*getfunctionlist)(&f)) != CKR_OK) {
Jakub Jelen def1de
 		error("C_GetFunctionList for provider %s failed: %lu",
Jakub Jelen def1de
-		    provider_id, rv);
Jakub Jelen def1de
+		    provider_module, rv);
Jakub Jelen def1de
 		goto fail;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
-	p->function_list = f;
Jakub Jelen def1de
+	m->function_list = f;
Jakub Jelen def1de
 	if ((rv = f->C_Initialize(NULL)) != CKR_OK) {
Jakub Jelen def1de
 		error("C_Initialize for provider %s failed: %lu",
Jakub Jelen def1de
-		    provider_id, rv);
Jakub Jelen def1de
+		    provider_module, rv);
Jakub Jelen def1de
 		goto fail;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
 	need_finalize = 1;
Jakub Jelen def1de
-	if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) {
Jakub Jelen def1de
+	if ((rv = f->C_GetInfo(&m->info)) != CKR_OK) {
Jakub Jelen def1de
 		error("C_GetInfo for provider %s failed: %lu",
Jakub Jelen def1de
-		    provider_id, rv);
Jakub Jelen def1de
+		    provider_module, rv);
Dmitry Belyavskiy 8f4d19
+		goto fail;
Dmitry Belyavskiy 8f4d19
+	}
Jakub Jelen def1de
+	rmspace(m->info.manufacturerID, sizeof(m->info.manufacturerID));
Jakub Jelen def1de
+	if (uri->lib_manuf != NULL &&
Jakub Jelen def1de
+	    strcmp(uri->lib_manuf, m->info.manufacturerID)) {
Jakub Jelen 25c16c
+		debug_f("Skipping provider %s not matching library_manufacturer",
Jakub Jelen 25c16c
+		    m->info.manufacturerID);
Dmitry Belyavskiy 8f4d19
 		goto fail;
Dmitry Belyavskiy 8f4d19
 	}
Dmitry Belyavskiy 8f4d19
-	rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID));
Dmitry Belyavskiy 8f4d19
-	rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription));
Jakub Jelen def1de
+	rmspace(m->info.libraryDescription, sizeof(m->info.libraryDescription));
Jakub Jelen def1de
 	debug("provider %s: manufacturerID <%s> cryptokiVersion %d.%d"
Jakub Jelen def1de
 	    " libraryDescription <%s> libraryVersion %d.%d",
Jakub Jelen def1de
-	    provider_id,
Jakub Jelen def1de
-	    p->info.manufacturerID,
Jakub Jelen def1de
-	    p->info.cryptokiVersion.major,
Jakub Jelen def1de
-	    p->info.cryptokiVersion.minor,
Jakub Jelen def1de
-	    p->info.libraryDescription,
Jakub Jelen def1de
-	    p->info.libraryVersion.major,
Jakub Jelen def1de
-	    p->info.libraryVersion.minor);
Jakub Jelen def1de
-	if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) {
Jakub Jelen def1de
+	    provider_module,
Jakub Jelen def1de
+	    m->info.manufacturerID,
Jakub Jelen def1de
+	    m->info.cryptokiVersion.major,
Jakub Jelen def1de
+	    m->info.cryptokiVersion.minor,
Jakub Jelen def1de
+	    m->info.libraryDescription,
Jakub Jelen def1de
+	    m->info.libraryVersion.major,
Jakub Jelen def1de
+	    m->info.libraryVersion.minor);
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &m->nslots)) != CKR_OK) {
Jakub Jelen def1de
 		error("C_GetSlotList failed: %lu", rv);
Jakub Jelen def1de
 		goto fail;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
-	if (p->nslots == 0) {
Jakub Jelen 25c16c
-		debug_f("provider %s returned no slots", provider_id);
Dmitry Belyavskiy f32b84
+	if (m->nslots == 0) {
Jakub Jelen 25c16c
+		debug_f("provider %s returned no slots", provider_module);
Jakub Jelen def1de
 		ret = -SSH_PKCS11_ERR_NO_SLOTS;
Jakub Jelen def1de
 		goto fail;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
-	p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
Jakub Jelen def1de
-	if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots))
Jakub Jelen def1de
+	m->slotlist = xcalloc(m->nslots, sizeof(CK_SLOT_ID));
Jakub Jelen def1de
+	if ((rv = f->C_GetSlotList(CK_TRUE, m->slotlist, &m->nslots))
Jakub Jelen def1de
 	    != CKR_OK) {
Jakub Jelen def1de
 		error("C_GetSlotList for provider %s failed: %lu",
Jakub Jelen def1de
-		    provider_id, rv);
Jakub Jelen def1de
+		    provider_module, rv);
Jakub Jelen def1de
 		goto fail;
Jakub Jelen def1de
 	}
Jakub Jelen def1de
-	p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo));
Jakub Jelen def1de
 	p->valid = 1;
Jakub Jelen def1de
-	nkeys = 0;
Jakub Jelen def1de
-	for (i = 0; i < p->nslots; i++) {
Jakub Jelen def1de
-		token = &p->slotinfo[i].token;
Jakub Jelen def1de
-		if ((rv = f->C_GetTokenInfo(p->slotlist[i], token))
Jakub Jelen def1de
+	m->slotinfo = xcalloc(m->nslots, sizeof(struct pkcs11_slotinfo));
Jakub Jelen def1de
+	m->valid = 1;
Jakub Jelen def1de
+	for (i = 0; i < m->nslots; i++) {
Jakub Jelen def1de
+		token = &m->slotinfo[i].token;
Jakub Jelen def1de
+		if ((rv = f->C_GetTokenInfo(m->slotlist[i], token))
Jakub Jelen def1de
 		    != CKR_OK) {
Jakub Jelen def1de
 			error("C_GetTokenInfo for provider %s slot %lu "
Jakub Jelen 25c16c
-			    "failed: %lu", provider_id, (u_long)i, rv);
Dmitry Belyavskiy f32b84
-			continue;
Dmitry Belyavskiy f32b84
-		}
Dmitry Belyavskiy f32b84
-		if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
Dmitry Belyavskiy f32b84
-			debug2_f("ignoring uninitialised token in "
Dmitry Belyavskiy f32b84
-			    "provider %s slot %lu", provider_id, (u_long)i);
Jakub Jelen 25c16c
+			    "failed: %lu", provider_module, (u_long)i, rv);
Jakub Jelen def1de
+			token->flags = 0;
Jakub Jelen def1de
 			continue;
Jakub Jelen def1de
 		}
Dmitry Belyavskiy f32b84
 		rmspace(token->label, sizeof(token->label));
Dmitry Belyavskiy f32b84
 		rmspace(token->manufacturerID, sizeof(token->manufacturerID));
Dmitry Belyavskiy f32b84
 		rmspace(token->model, sizeof(token->model));
Dmitry Belyavskiy f32b84
 		rmspace(token->serialNumber, sizeof(token->serialNumber));
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	m->module_path = provider_module;
Jakub Jelen def1de
+	provider_module = NULL;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	/* insert unconditionally -- remove if there will be no keys later */
Jakub Jelen def1de
+	TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
Jakub Jelen def1de
+	p->refcount++;	/* add to provider list */
Jakub Jelen def1de
+	*providerp = p;
Jakub Jelen def1de
+	return 0;
Jakub Jelen def1de
+
Jakub Jelen def1de
+fail:
Jakub Jelen def1de
+	if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
Jakub Jelen def1de
+		error("C_Finalize for provider %s failed: %lu",
Jakub Jelen def1de
+		    provider_module, rv);
Jakub Jelen def1de
+	free(provider_module);
Jakub Jelen def1de
+	if (m) {
Jakub Jelen def1de
+		free(m->slotlist);
Jakub Jelen def1de
+		free(m);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	if (p) {
Jakub Jelen def1de
+		free(p->name);
Jakub Jelen def1de
+		free(p);
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+	if (handle)
Jakub Jelen def1de
+		dlclose(handle);
Jakub Jelen def1de
+	return ret;
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+/*
Jakub Jelen def1de
+ * register a new provider, fails if provider already exists. if
Jakub Jelen def1de
+ * keyp is provided, fetch keys.
Jakub Jelen def1de
+ */
Jakub Jelen def1de
+static int
Jakub Jelen def1de
+pkcs11_register_provider_by_uri(struct pkcs11_uri *uri, char *pin,
Jakub Jelen 51f5c1
+    struct sshkey ***keyp, char ***labelsp, struct pkcs11_provider **providerp,
Jakub Jelen 51f5c1
+    CK_ULONG user)
Jakub Jelen def1de
+{
Jakub Jelen def1de
+	int nkeys;
Jakub Jelen def1de
+	int ret = -1;
Jakub Jelen def1de
+	struct pkcs11_provider *p = NULL;
Jakub Jelen def1de
+	CK_ULONG i;
Jakub Jelen def1de
+	CK_TOKEN_INFO *token;
Jakub Jelen def1de
+	char *provider_uri = NULL;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (providerp == NULL)
Jakub Jelen def1de
+		goto fail;
Jakub Jelen def1de
+	*providerp = NULL;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if (keyp != NULL)
Jakub Jelen def1de
+		*keyp = NULL;
Jakub Jelen def1de
+
Jakub Jelen def1de
+	if ((ret = pkcs11_initialize_provider(uri, &p)) != 0) {
Jakub Jelen def1de
+		goto fail;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Jakub Jelen def1de
+	provider_uri = pkcs11_uri_get(uri);
Jakub Jelen ed59cb
+	if (pin == NULL && uri->pin != NULL) {
Jakub Jelen ed59cb
+		pin = uri->pin;
Jakub Jelen ed59cb
+	}
Jakub Jelen def1de
+	nkeys = 0;
Jakub Jelen def1de
+	for (i = 0; i < p->module->nslots; i++) {
Jakub Jelen def1de
+		token = &p->module->slotinfo[i].token;
Dmitry Belyavskiy f32b84
+		if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
Dmitry Belyavskiy f32b84
+			debug2_f("ignoring uninitialised token in "
Jakub Jelen 25c16c
+			    "provider %s slot %lu", provider_uri, (u_long)i);
Jakub Jelen def1de
+			continue;
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+		if (uri->token != NULL &&
Jakub Jelen def1de
+		    strcmp(token->label, uri->token) != 0) {
Jakub Jelen 25c16c
+			debug2_f("ignoring token not matching label (%s) "
Jakub Jelen 25c16c
+			    "specified by PKCS#11 URI in slot %lu",
Jakub Jelen def1de
+			    token->label, (unsigned long)i);
Jakub Jelen def1de
+			continue;
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+		if (uri->manuf != NULL &&
Jakub Jelen def1de
+		    strcmp(token->manufacturerID, uri->manuf) != 0) {
Jakub Jelen 25c16c
+			debug2_f("ignoring token not matching requrested "
Jakub Jelen def1de
+			    "manufacturerID (%s) specified by PKCS#11 URI in "
Jakub Jelen 25c16c
+			    "slot %lu", token->manufacturerID, (unsigned long)i);
Dmitry Belyavskiy f32b84
+			continue;
Dmitry Belyavskiy f32b84
+		}
Jakub Jelen def1de
 		debug("provider %s slot %lu: label <%s> manufacturerID <%s> "
Jakub Jelen def1de
 		    "model <%s> serial <%s> flags 0x%lx",
Jakub Jelen def1de
-		    provider_id, (unsigned long)i,
Jakub Jelen def1de
+		    provider_uri, (unsigned long)i,
Jakub Jelen def1de
 		    token->label, token->manufacturerID, token->model,
Jakub Jelen def1de
 		    token->serialNumber, token->flags);
Jakub Jelen def1de
 		/*
Jakub Jelen def1de
-		 * open session, login with pin and retrieve public
Jakub Jelen def1de
-		 * keys (if keyp is provided)
Jakub Jelen def1de
+		 * open session if not yet openend, login with pin and
Jakub Jelen def1de
+		 * retrieve public keys (if keyp is provided)
Jakub Jelen def1de
 		 */
Jakub Jelen 36fef5
-		if ((ret = pkcs11_open_session(p, i, pin, user)) != 0 ||
Jakub Jelen 36fef5
+		if ((p->module->slotinfo[i].session != 0 ||
Jakub Jelen 36fef5
+		    (ret = pkcs11_open_session(p, i, pin, user)) != 0) && /* ??? */
Jakub Jelen 36fef5
 		    keyp == NULL)
Jakub Jelen 36fef5
 			continue;
Jakub Jelen 51f5c1
-		pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
Jakub Jelen 51f5c1
-		pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
Jakub Jelen 36fef5
-		if (nkeys == 0 && !p->slotinfo[i].logged_in &&
Jakub Jelen 51f5c1
+		pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys, uri);
Jakub Jelen 51f5c1
+		pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys, uri);
Jakub Jelen 36fef5
+		if (nkeys == 0 && !p->module->slotinfo[i].logged_in &&
Jakub Jelen 36fef5
 		    pkcs11_interactive) {
Jakub Jelen 36fef5
 			/*
Jakub Jelen 36fef5
 			 * Some tokens require login before they will
Jakub Jelen 36fef5
 			 * expose keys.
Jakub Jelen 36fef5
 			 */
Jakub Jelen 36fef5
-			if (pkcs11_login_slot(p, &p->slotinfo[i],
Jakub Jelen 25c16c
+			debug3_f("Trying to login as there were no keys found");
Jakub Jelen 36fef5
+			if (pkcs11_login_slot(p, &p->module->slotinfo[i],
Jakub Jelen 36fef5
 			    CKU_USER) < 0) {
Jakub Jelen 36fef5
 				error("login failed");
Jakub Jelen def1de
 				continue;
Jakub Jelen 36fef5
 			}
Jakub Jelen 51f5c1
-			pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys);
Jakub Jelen 51f5c1
-			pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys);
Jakub Jelen 51f5c1
+			pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys, uri);
Jakub Jelen 51f5c1
+			pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys, uri);
Jakub Jelen 51f5c1
+		}
Jakub Jelen 36fef5
+		if (nkeys == 0 && uri->object != NULL) {
Jakub Jelen 25c16c
+			debug3_f("No keys found. Retrying without label (%s) ",
Jakub Jelen 25c16c
+			    uri->object);
Jakub Jelen 36fef5
+			/* Try once more without the label filter */
Jakub Jelen 36fef5
+			char *label = uri->object;
Jakub Jelen 36fef5
+			uri->object = NULL; /* XXX clone uri? */
Jakub Jelen 51f5c1
+			pkcs11_fetch_keys(p, i, keyp, labelsp, &nkeys, uri);
Jakub Jelen 51f5c1
+			pkcs11_fetch_certs(p, i, keyp, labelsp, &nkeys, uri);
Jakub Jelen 36fef5
+			uri->object = label;
Jakub Jelen 51f5c1
 		}
Jakub Jelen def1de
 	}
Jakub Jelen ed59cb
+	pin = NULL; /* Will be cleaned up with URI */
Jakub Jelen def1de
 
Jakub Jelen def1de
 	/* now owned by caller */
Jakub Jelen def1de
 	*providerp = p;
Jakub Jelen def1de
 
Jakub Jelen def1de
-	TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
Jakub Jelen def1de
-	p->refcount++;	/* add to provider list */
Jakub Jelen def1de
-
Jakub Jelen def1de
+	free(provider_uri);
Jakub Jelen def1de
 	return (nkeys);
Jakub Jelen def1de
 fail:
Jakub Jelen def1de
-	if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
Jakub Jelen def1de
-		error("C_Finalize for provider %s failed: %lu",
Jakub Jelen def1de
-		    provider_id, rv);
Jakub Jelen def1de
 	if (p) {
Jakub Jelen def1de
-		free(p->name);
Jakub Jelen def1de
-		free(p->slotlist);
Jakub Jelen def1de
-		free(p->slotinfo);
Jakub Jelen def1de
-		free(p);
Jakub Jelen def1de
+ 		TAILQ_REMOVE(&pkcs11_providers, p, next);
Jakub Jelen def1de
+		pkcs11_provider_unref(p);
Jakub Jelen def1de
 	}
Jakub Jelen def1de
-	if (handle)
Jakub Jelen def1de
-		dlclose(handle);
Jakub Jelen 5cd955
 	if (ret > 0)
Jakub Jelen 5cd955
 		ret = -1;
Jakub Jelen def1de
 	return (ret);
Jakub Jelen def1de
 }
Jakub Jelen def1de
 
Jakub Jelen def1de
-/*
Jakub Jelen def1de
- * register a new provider and get number of keys hold by the token,
Jakub Jelen def1de
- * fails if provider already exists
Jakub Jelen def1de
- */
Jakub Jelen def1de
+static int
Jakub Jelen def1de
+pkcs11_register_provider(char *provider_id, char *pin, struct sshkey ***keyp,
Jakub Jelen 51f5c1
+    char ***labelsp, struct pkcs11_provider **providerp, CK_ULONG user)
Jakub Jelen def1de
+{
Dmitry Belyavskiy f32b84
+	struct pkcs11_uri *uri = NULL;
Dmitry Belyavskiy f32b84
+	int r;
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	debug_f("called, provider_id = %s", provider_id);
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	uri = pkcs11_uri_init();
Dmitry Belyavskiy f32b84
+	if (uri == NULL)
Dmitry Belyavskiy f32b84
+		fatal("failed to init PKCS#11 URI");
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) &&
Dmitry Belyavskiy f32b84
+	    strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) {
Dmitry Belyavskiy f32b84
+		if (pkcs11_uri_parse(provider_id, uri) != 0)
Dmitry Belyavskiy f32b84
+			fatal("Failed to parse PKCS#11 URI");
Dmitry Belyavskiy f32b84
+	} else {
Dmitry Belyavskiy f32b84
+		uri->module_path = strdup(provider_id);
Dmitry Belyavskiy f32b84
+	}
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	r = pkcs11_register_provider_by_uri(uri, pin, keyp, labelsp, providerp, user);
Dmitry Belyavskiy f32b84
+	pkcs11_uri_cleanup(uri);
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	return r;
Dmitry Belyavskiy f32b84
+}
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
 int
Dmitry Belyavskiy f32b84
-pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp,
Dmitry Belyavskiy f32b84
-    char ***labelsp)
Dmitry Belyavskiy f32b84
+pkcs11_add_provider_by_uri(struct pkcs11_uri *uri, char *pin,
Dmitry Belyavskiy f32b84
+    struct sshkey ***keyp, char ***labelsp)
Dmitry Belyavskiy f32b84
 {
Dmitry Belyavskiy f32b84
 	struct pkcs11_provider *p = NULL;
Dmitry Belyavskiy f32b84
 	int nkeys;
Dmitry Belyavskiy f32b84
+	char *provider_uri = pkcs11_uri_get(uri);
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	debug_f("called, provider_uri = %s", provider_uri);
Dmitry Belyavskiy f32b84
 
Dmitry Belyavskiy f32b84
-	nkeys = pkcs11_register_provider(provider_id, pin, keyp, labelsp,
Dmitry Belyavskiy f32b84
-	    &p, CKU_USER);
Dmitry Belyavskiy f32b84
+	nkeys = pkcs11_register_provider_by_uri(uri, pin, keyp, labelsp, &p, CKU_USER);
Dmitry Belyavskiy f32b84
 
Dmitry Belyavskiy f32b84
 	/* no keys found or some other error, de-register provider */
Dmitry Belyavskiy f32b84
 	if (nkeys <= 0 && p != NULL) {
Dmitry Belyavskiy 8f4d19
@@ -1683,7 +2002,37 @@ pkcs11_add_provider(char *provider_id, c
Dmitry Belyavskiy f32b84
 		pkcs11_provider_unref(p);
Dmitry Belyavskiy f32b84
 	}
Dmitry Belyavskiy f32b84
 	if (nkeys == 0)
Dmitry Belyavskiy f32b84
-		debug_f("provider %s returned no keys", provider_id);
Dmitry Belyavskiy f32b84
+		debug_f("provider %s returned no keys", provider_uri);
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	free(provider_uri);
Dmitry Belyavskiy f32b84
+	return nkeys;
Dmitry Belyavskiy f32b84
+}
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+/*
Dmitry Belyavskiy f32b84
+ * register a new provider and get number of keys hold by the token,
Dmitry Belyavskiy f32b84
+ * fails if provider already exists
Dmitry Belyavskiy f32b84
+ */
Dmitry Belyavskiy f32b84
+int
Dmitry Belyavskiy f32b84
+pkcs11_add_provider(char *provider_id, char *pin,
Dmitry Belyavskiy f32b84
+    struct sshkey ***keyp, char ***labelsp)
Dmitry Belyavskiy f32b84
+{
Dmitry Belyavskiy f32b84
+	struct pkcs11_uri *uri;
Dmitry Belyavskiy f32b84
+	int nkeys;
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	uri = pkcs11_uri_init();
Dmitry Belyavskiy f32b84
+	if (uri == NULL)
Dmitry Belyavskiy f32b84
+		fatal("Failed to init PKCS#11 URI");
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) &&
Dmitry Belyavskiy f32b84
+	    strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) {
Dmitry Belyavskiy f32b84
+		if (pkcs11_uri_parse(provider_id, uri) != 0)
Dmitry Belyavskiy f32b84
+			fatal("Failed to parse PKCS#11 URI");
Dmitry Belyavskiy f32b84
+	} else {
Dmitry Belyavskiy f32b84
+		uri->module_path = strdup(provider_id);
Dmitry Belyavskiy f32b84
+	}
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	nkeys = pkcs11_add_provider_by_uri(uri, pin, keyp, labelsp);
Dmitry Belyavskiy f32b84
+	pkcs11_uri_cleanup(uri);
Dmitry Belyavskiy f32b84
 
Dmitry Belyavskiy f32b84
 	return (nkeys);
Dmitry Belyavskiy f32b84
 }
Dmitry Belyavskiy 8f4d19
diff -up openssh-8.7p1/ssh-pkcs11.h.pkcs11-uri openssh-8.7p1/ssh-pkcs11.h
Dmitry Belyavskiy 8f4d19
--- openssh-8.7p1/ssh-pkcs11.h.pkcs11-uri	2021-08-20 06:03:49.000000000 +0200
Dmitry Belyavskiy 8f4d19
+++ openssh-8.7p1/ssh-pkcs11.h	2021-08-30 13:07:43.666700121 +0200
Dmitry Belyavskiy f32b84
@@ -22,10 +22,14 @@
Dmitry Belyavskiy f32b84
 #define	SSH_PKCS11_ERR_PIN_REQUIRED		4
Dmitry Belyavskiy f32b84
 #define	SSH_PKCS11_ERR_PIN_LOCKED		5
Dmitry Belyavskiy f32b84
 
Dmitry Belyavskiy f32b84
+#include "ssh-pkcs11-uri.h"
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
 int	pkcs11_init(int);
Dmitry Belyavskiy f32b84
 void	pkcs11_terminate(void);
Dmitry Belyavskiy f32b84
 int	pkcs11_add_provider(char *, char *, struct sshkey ***, char ***);
Dmitry Belyavskiy f32b84
+int	pkcs11_add_provider_by_uri(struct pkcs11_uri *, char *, struct sshkey ***, char ***);
Dmitry Belyavskiy f32b84
 int	pkcs11_del_provider(char *);
Dmitry Belyavskiy f32b84
+int	pkcs11_uri_write(const struct sshkey *, FILE *);
Dmitry Belyavskiy f32b84
 #ifdef WITH_PKCS11_KEYGEN
Dmitry Belyavskiy f32b84
 struct sshkey *
Dmitry Belyavskiy f32b84
 	pkcs11_gakp(char *, char *, unsigned int, char *, unsigned int,
Dmitry Belyavskiy 8f4d19
diff -up openssh-8.7p1/ssh-pkcs11-uri.c.pkcs11-uri openssh-8.7p1/ssh-pkcs11-uri.c
Dmitry Belyavskiy 8f4d19
--- openssh-8.7p1/ssh-pkcs11-uri.c.pkcs11-uri	2021-08-30 13:07:43.667700130 +0200
Dmitry Belyavskiy 8f4d19
+++ openssh-8.7p1/ssh-pkcs11-uri.c	2021-08-30 13:07:43.667700130 +0200
Dmitry Belyavskiy f32b84
@@ -0,0 +1,419 @@
Dmitry Belyavskiy f32b84
+/*
Dmitry Belyavskiy f32b84
+ * Copyright (c) 2017 Red Hat
Dmitry Belyavskiy f32b84
+ *
Dmitry Belyavskiy f32b84
+ * Authors: Jakub Jelen <jjelen@redhat.com>
Dmitry Belyavskiy f32b84
+ *
Dmitry Belyavskiy f32b84
+ * Permission to use, copy, modify, and distribute this software for any
Dmitry Belyavskiy f32b84
+ * purpose with or without fee is hereby granted, provided that the above
Dmitry Belyavskiy f32b84
+ * copyright notice and this permission notice appear in all copies.
Dmitry Belyavskiy f32b84
+ *
Dmitry Belyavskiy f32b84
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
Dmitry Belyavskiy f32b84
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
Dmitry Belyavskiy f32b84
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
Dmitry Belyavskiy f32b84
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
Dmitry Belyavskiy f32b84
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
Dmitry Belyavskiy f32b84
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Dmitry Belyavskiy f32b84
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Dmitry Belyavskiy f32b84
+ */
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+#include "includes.h"
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+#ifdef ENABLE_PKCS11
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+#include <stdio.h>
Dmitry Belyavskiy f32b84
+#include <string.h>
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+#include "sshkey.h"
Dmitry Belyavskiy f32b84
+#include "sshbuf.h"
Dmitry Belyavskiy f32b84
+#include "log.h"
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+#define CRYPTOKI_COMPAT
Dmitry Belyavskiy f32b84
+#include "pkcs11.h"
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+#include "ssh-pkcs11-uri.h"
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+#define PKCS11_URI_PATH_SEPARATOR ";"
Dmitry Belyavskiy f32b84
+#define PKCS11_URI_QUERY_SEPARATOR "&"
Dmitry Belyavskiy f32b84
+#define PKCS11_URI_VALUE_SEPARATOR "="
Dmitry Belyavskiy f32b84
+#define PKCS11_URI_ID "id"
Dmitry Belyavskiy f32b84
+#define PKCS11_URI_TOKEN "token"
Dmitry Belyavskiy f32b84
+#define PKCS11_URI_OBJECT "object"
Dmitry Belyavskiy f32b84
+#define PKCS11_URI_LIB_MANUF "library-manufacturer"
Dmitry Belyavskiy f32b84
+#define PKCS11_URI_MANUF "manufacturer"
Dmitry Belyavskiy f32b84
+#define PKCS11_URI_MODULE_PATH "module-path"
Dmitry Belyavskiy f32b84
+#define PKCS11_URI_PIN_VALUE "pin-value"
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+/* Keyword tokens. */
Dmitry Belyavskiy f32b84
+typedef enum {
Dmitry Belyavskiy f32b84
+	pId, pToken, pObject, pLibraryManufacturer, pManufacturer, pModulePath,
Dmitry Belyavskiy f32b84
+	pPinValue, pBadOption
Dmitry Belyavskiy f32b84
+} pkcs11uriOpCodes;
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+/* Textual representation of the tokens. */
Dmitry Belyavskiy f32b84
+static struct {
Dmitry Belyavskiy f32b84
+	const char *name;
Dmitry Belyavskiy f32b84
+	pkcs11uriOpCodes opcode;
Dmitry Belyavskiy f32b84
+} keywords[] = {
Dmitry Belyavskiy f32b84
+	{ PKCS11_URI_ID, pId },
Dmitry Belyavskiy f32b84
+	{ PKCS11_URI_TOKEN, pToken },
Dmitry Belyavskiy f32b84
+	{ PKCS11_URI_OBJECT, pObject },
Dmitry Belyavskiy f32b84
+	{ PKCS11_URI_LIB_MANUF, pLibraryManufacturer },
Dmitry Belyavskiy f32b84
+	{ PKCS11_URI_MANUF, pManufacturer },
Dmitry Belyavskiy f32b84
+	{ PKCS11_URI_MODULE_PATH, pModulePath },
Dmitry Belyavskiy f32b84
+	{ PKCS11_URI_PIN_VALUE, pPinValue },
Dmitry Belyavskiy f32b84
+	{ NULL, pBadOption }
Dmitry Belyavskiy f32b84
+};
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+static pkcs11uriOpCodes
Dmitry Belyavskiy f32b84
+parse_token(const char *cp)
Dmitry Belyavskiy f32b84
+{
Dmitry Belyavskiy f32b84
+	u_int i;
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	for (i = 0; keywords[i].name; i++)
Dmitry Belyavskiy f32b84
+		if (strncasecmp(cp, keywords[i].name,
Dmitry Belyavskiy f32b84
+		    strlen(keywords[i].name)) == 0)
Dmitry Belyavskiy f32b84
+			return keywords[i].opcode;
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	return pBadOption;
Dmitry Belyavskiy f32b84
+}
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+int
Dmitry Belyavskiy f32b84
+percent_decode(char *data, char **outp)
Dmitry Belyavskiy f32b84
+{
Dmitry Belyavskiy f32b84
+	char tmp[3];
Dmitry Belyavskiy f32b84
+	char *out, *tmp_end;
Dmitry Belyavskiy f32b84
+	char *p = data;
Dmitry Belyavskiy f32b84
+	long value;
Dmitry Belyavskiy f32b84
+	size_t outlen = 0;
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	out = malloc(strlen(data)+1); /* upper bound */
Dmitry Belyavskiy f32b84
+	if (out == NULL)
Dmitry Belyavskiy f32b84
+		return -1;
Dmitry Belyavskiy f32b84
+	while (*p != '\0') {
Dmitry Belyavskiy f32b84
+		switch (*p) {
Dmitry Belyavskiy f32b84
+		case '%':
Dmitry Belyavskiy f32b84
+			p++;
Dmitry Belyavskiy f32b84
+			if (*p == '\0')
Dmitry Belyavskiy f32b84
+				goto fail;
Dmitry Belyavskiy f32b84
+			tmp[0] = *p++;
Dmitry Belyavskiy f32b84
+			if (*p == '\0')
Dmitry Belyavskiy f32b84
+				goto fail;
Dmitry Belyavskiy f32b84
+			tmp[1] = *p++;
Dmitry Belyavskiy f32b84
+			tmp[2] = '\0';
Dmitry Belyavskiy f32b84
+			tmp_end = NULL;
Dmitry Belyavskiy f32b84
+			value = strtol(tmp, &tmp_end, 16);
Dmitry Belyavskiy f32b84
+			if (tmp_end != tmp+2)
Dmitry Belyavskiy f32b84
+				goto fail;
Dmitry Belyavskiy f32b84
+			else
Dmitry Belyavskiy f32b84
+				out[outlen++] = (char) value;
Dmitry Belyavskiy f32b84
+			break;
Dmitry Belyavskiy f32b84
+		default:
Dmitry Belyavskiy f32b84
+			out[outlen++] = *p++;
Dmitry Belyavskiy f32b84
+			break;
Dmitry Belyavskiy f32b84
+		}
Dmitry Belyavskiy f32b84
+	}
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	/* zero terminate */
Dmitry Belyavskiy f32b84
+	out[outlen] = '\0';
Dmitry Belyavskiy f32b84
+	*outp = out;
Dmitry Belyavskiy f32b84
+	return outlen;
Dmitry Belyavskiy f32b84
+fail:
Dmitry Belyavskiy f32b84
+	free(out);
Dmitry Belyavskiy f32b84
+	return -1;
Dmitry Belyavskiy f32b84
+}
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+struct sshbuf *
Dmitry Belyavskiy f32b84
+percent_encode(const char *data, size_t length, const char *allow_list)
Dmitry Belyavskiy f32b84
+{
Dmitry Belyavskiy f32b84
+	struct sshbuf *b = NULL;
Dmitry Belyavskiy f32b84
+	char tmp[4], *cp;
Dmitry Belyavskiy f32b84
+	size_t i;
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	if ((b = sshbuf_new()) == NULL)
Dmitry Belyavskiy f32b84
+		return NULL;
Dmitry Belyavskiy f32b84
+	for (i = 0; i < length; i++) {
Dmitry Belyavskiy f32b84
+		cp = strchr(allow_list, data[i]);
Dmitry Belyavskiy f32b84
+		/* if c is specified as '\0' pointer to terminator is returned !! */
Dmitry Belyavskiy f32b84
+		if (cp != NULL && *cp != '\0') {
Dmitry Belyavskiy f32b84
+			if (sshbuf_put(b, &data[i], 1) != 0)
Dmitry Belyavskiy f32b84
+				goto err;
Dmitry Belyavskiy f32b84
+		} else
Dmitry Belyavskiy f32b84
+			if (snprintf(tmp, 4, "%%%02X", (unsigned char) data[i]) < 3
Dmitry Belyavskiy f32b84
+			    || sshbuf_put(b, tmp, 3) != 0)
Dmitry Belyavskiy f32b84
+				goto err;
Dmitry Belyavskiy f32b84
+	}
Dmitry Belyavskiy f32b84
+	if (sshbuf_put(b, "\0", 1) == 0)
Dmitry Belyavskiy f32b84
+		return b;
Dmitry Belyavskiy f32b84
+err:
Dmitry Belyavskiy f32b84
+	sshbuf_free(b);
Dmitry Belyavskiy f32b84
+	return NULL;
Dmitry Belyavskiy f32b84
+}
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+char *
Dmitry Belyavskiy f32b84
+pkcs11_uri_append(char *part, const char *separator, const char *key,
Dmitry Belyavskiy f32b84
+    struct sshbuf *value)
Dmitry Belyavskiy f32b84
+{
Dmitry Belyavskiy f32b84
+	char *new_part;
Dmitry Belyavskiy f32b84
+	size_t size = 0;
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+	if (value == NULL)
Dmitry Belyavskiy f32b84
+		return NULL;
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+	size = asprintf(&new_part,
Dmitry Belyavskiy f32b84
+	    "%s%s%s"  PKCS11_URI_VALUE_SEPARATOR "%s",
Dmitry Belyavskiy f32b84
+	    (part != NULL ? part : ""),
Dmitry Belyavskiy f32b84
+	    (part != NULL ? separator : ""),
Dmitry Belyavskiy f32b84
+	    key, sshbuf_ptr(value));
Dmitry Belyavskiy f32b84
+	sshbuf_free(value);
Dmitry Belyavskiy f32b84
+	free(part);
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+	if (size <= 0)
Dmitry Belyavskiy f32b84
+		return NULL;
Dmitry Belyavskiy f32b84
+	return new_part;
Dmitry Belyavskiy f32b84
+}
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+char *
Dmitry Belyavskiy f32b84
+pkcs11_uri_get(struct pkcs11_uri *uri)
Dmitry Belyavskiy f32b84
+{
Dmitry Belyavskiy f32b84
+	size_t size = 0;
Dmitry Belyavskiy f32b84
+	char *p = NULL, *path = NULL, *query = NULL;
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	/* compose a percent-encoded ID */
Dmitry Belyavskiy f32b84
+	if (uri->id_len > 0) {
Dmitry Belyavskiy f32b84
+		struct sshbuf *key_id = percent_encode(uri->id, uri->id_len, "");
Dmitry Belyavskiy f32b84
+		path = pkcs11_uri_append(path, PKCS11_URI_PATH_SEPARATOR,
Dmitry Belyavskiy f32b84
+		    PKCS11_URI_ID, key_id);
Dmitry Belyavskiy f32b84
+		if (path == NULL)
Dmitry Belyavskiy f32b84
+			goto err;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+	/* Write object label */
Dmitry Belyavskiy f32b84
+	if (uri->object) {
Dmitry Belyavskiy f32b84
+		struct sshbuf *label = percent_encode(uri->object, strlen(uri->object),
Dmitry Belyavskiy f32b84
+		    PKCS11_URI_WHITELIST);
Dmitry Belyavskiy f32b84
+		path = pkcs11_uri_append(path, PKCS11_URI_PATH_SEPARATOR,
Dmitry Belyavskiy f32b84
+		    PKCS11_URI_OBJECT, label);
Dmitry Belyavskiy f32b84
+		if (path == NULL)
Dmitry Belyavskiy f32b84
+			goto err;
Dmitry Belyavskiy f32b84
+	}
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+	/* Write token label */
Dmitry Belyavskiy f32b84
+	if (uri->token) {
Dmitry Belyavskiy f32b84
+		struct sshbuf *label = percent_encode(uri->token, strlen(uri->token),
Dmitry Belyavskiy f32b84
+		    PKCS11_URI_WHITELIST);
Dmitry Belyavskiy f32b84
+		path = pkcs11_uri_append(path, PKCS11_URI_PATH_SEPARATOR,
Dmitry Belyavskiy f32b84
+		    PKCS11_URI_TOKEN, label);
Dmitry Belyavskiy f32b84
+		if (path == NULL)
Dmitry Belyavskiy f32b84
+			goto err;
Dmitry Belyavskiy f32b84
+	}
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	/* Write manufacturer */
Dmitry Belyavskiy f32b84
+	if (uri->manuf) {
Dmitry Belyavskiy f32b84
+		struct sshbuf *manuf = percent_encode(uri->manuf,
Dmitry Belyavskiy f32b84
+		    strlen(uri->manuf), PKCS11_URI_WHITELIST);
Dmitry Belyavskiy f32b84
+		path = pkcs11_uri_append(path, PKCS11_URI_PATH_SEPARATOR,
Dmitry Belyavskiy f32b84
+		    PKCS11_URI_MANUF, manuf);
Dmitry Belyavskiy f32b84
+		if (path == NULL)
Dmitry Belyavskiy f32b84
+			goto err;
Dmitry Belyavskiy f32b84
+	}
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	/* Write module_path */
Dmitry Belyavskiy f32b84
+	if (uri->module_path) {
Dmitry Belyavskiy f32b84
+		struct sshbuf *module = percent_encode(uri->module_path,
Dmitry Belyavskiy f32b84
+		    strlen(uri->module_path), PKCS11_URI_WHITELIST "/");
Dmitry Belyavskiy f32b84
+		query = pkcs11_uri_append(query, PKCS11_URI_QUERY_SEPARATOR,
Dmitry Belyavskiy f32b84
+		    PKCS11_URI_MODULE_PATH, module);
Dmitry Belyavskiy f32b84
+		if (query == NULL)
Dmitry Belyavskiy f32b84
+			goto err;
Dmitry Belyavskiy f32b84
+	}
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	size = asprintf(&p, PKCS11_URI_SCHEME "%s%s%s",
Dmitry Belyavskiy f32b84
+	    path != NULL ? path : "",
Dmitry Belyavskiy f32b84
+	    query != NULL ? "?" : "",
Dmitry Belyavskiy f32b84
+	    query != NULL ? query : "");
Dmitry Belyavskiy f32b84
+err:
Dmitry Belyavskiy f32b84
+	free(query);
Dmitry Belyavskiy f32b84
+	free(path);
Dmitry Belyavskiy f32b84
+	if (size <= 0)
Dmitry Belyavskiy f32b84
+		return NULL;
Dmitry Belyavskiy f32b84
+	return p;
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+struct pkcs11_uri *
Dmitry Belyavskiy f32b84
+pkcs11_uri_init()
Dmitry Belyavskiy f32b84
+{
Dmitry Belyavskiy f32b84
+	struct pkcs11_uri *d = calloc(1, sizeof(struct pkcs11_uri));
Dmitry Belyavskiy f32b84
+	return d;
Dmitry Belyavskiy f32b84
+}
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+void
Dmitry Belyavskiy f32b84
+pkcs11_uri_cleanup(struct pkcs11_uri *pkcs11)
Dmitry Belyavskiy f32b84
+{
Dmitry Belyavskiy f32b84
+	if (pkcs11 == NULL) {
Dmitry Belyavskiy f32b84
+		return;
Dmitry Belyavskiy f32b84
+	}
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+	free(pkcs11->id);
Dmitry Belyavskiy f32b84
+	free(pkcs11->module_path);
Dmitry Belyavskiy f32b84
+	free(pkcs11->token);
Dmitry Belyavskiy f32b84
+	free(pkcs11->object);
Dmitry Belyavskiy f32b84
+	free(pkcs11->lib_manuf);
Dmitry Belyavskiy f32b84
+	free(pkcs11->manuf);
Dmitry Belyavskiy f32b84
+	if (pkcs11->pin)
Dmitry Belyavskiy f32b84
+		freezero(pkcs11->pin, strlen(pkcs11->pin));
Dmitry Belyavskiy f32b84
+	free(pkcs11);
Jakub Jelen def1de
+}
Jakub Jelen def1de
+
Jakub Jelen def1de
+int
Dmitry Belyavskiy f32b84
+pkcs11_uri_parse(const char *uri, struct pkcs11_uri *pkcs11)
Jakub Jelen def1de
+{
Dmitry Belyavskiy f32b84
+	char *saveptr1, *saveptr2, *str1, *str2, *tok;
Dmitry Belyavskiy f32b84
+	int rv = 0, len;
Dmitry Belyavskiy f32b84
+	char *p = NULL;
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+	size_t scheme_len = strlen(PKCS11_URI_SCHEME);
Dmitry Belyavskiy f32b84
+	if (strlen(uri) < scheme_len || /* empty URI matches everything */
Dmitry Belyavskiy f32b84
+	    strncmp(uri, PKCS11_URI_SCHEME, scheme_len) != 0) {
Dmitry Belyavskiy f32b84
+		error_f("The '%s' does not look like PKCS#11 URI", uri);
Dmitry Belyavskiy f32b84
+		return -1;
Dmitry Belyavskiy f32b84
+	}
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+	if (pkcs11 == NULL) {
Dmitry Belyavskiy f32b84
+		error_f("Bad arguments. The pkcs11 can't be null");
Dmitry Belyavskiy f32b84
+		return -1;
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+	/* skip URI schema name */
Dmitry Belyavskiy f32b84
+	p = strdup(uri);
Dmitry Belyavskiy f32b84
+	str1 = p;
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+	/* everything before ? */
Dmitry Belyavskiy f32b84
+	tok = strtok_r(str1, "?", &saveptr1);
Dmitry Belyavskiy f32b84
+	if (tok == NULL) {
Dmitry Belyavskiy f32b84
+		error_f("pk11-path expected, got EOF");
Dmitry Belyavskiy f32b84
+		rv = -1;
Dmitry Belyavskiy f32b84
+		goto out;
Dmitry Belyavskiy f32b84
+	}
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	/* skip URI schema name:
Dmitry Belyavskiy f32b84
+	 * the scheme ensures that there is at least something before "?"
Dmitry Belyavskiy f32b84
+	 * allowing empty pk11-path. Resulting token at worst pointing to
Dmitry Belyavskiy f32b84
+	 * \0 byte */
Dmitry Belyavskiy f32b84
+	tok = tok + scheme_len;
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+	/* parse pk11-path */
Dmitry Belyavskiy f32b84
+	for (str2 = tok; ; str2 = NULL) {
Dmitry Belyavskiy f32b84
+		char **charptr, *arg = NULL;
Dmitry Belyavskiy f32b84
+		pkcs11uriOpCodes opcode;
Dmitry Belyavskiy f32b84
+		tok = strtok_r(str2, PKCS11_URI_PATH_SEPARATOR, &saveptr2);
Dmitry Belyavskiy f32b84
+		if (tok == NULL)
Dmitry Belyavskiy f32b84
+			break;
Dmitry Belyavskiy f32b84
+		opcode = parse_token(tok);
Dmitry Belyavskiy f32b84
+		if (opcode != pBadOption)
Dmitry Belyavskiy f32b84
+			arg = tok + strlen(keywords[opcode].name) + 1; /* separator "=" */
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+		switch (opcode) {
Dmitry Belyavskiy f32b84
+		case pId:
Dmitry Belyavskiy f32b84
+			/* CKA_ID */
Dmitry Belyavskiy f32b84
+			if (pkcs11->id != NULL) {
Dmitry Belyavskiy f32b84
+				verbose_f("The id already set in the PKCS#11 URI");
Dmitry Belyavskiy f32b84
+				rv = -1;
Dmitry Belyavskiy f32b84
+				goto out;
Dmitry Belyavskiy f32b84
+			}
Dmitry Belyavskiy f32b84
+			len = percent_decode(arg, &pkcs11->id);
Dmitry Belyavskiy f32b84
+			if (len <= 0) {
Dmitry Belyavskiy f32b84
+				verbose_f("Failed to percent-decode CKA_ID: %s", arg);
Dmitry Belyavskiy f32b84
+				rv = -1;
Dmitry Belyavskiy f32b84
+				goto out;
Dmitry Belyavskiy f32b84
+			} else
Dmitry Belyavskiy f32b84
+				pkcs11->id_len = len;
Dmitry Belyavskiy f32b84
+			debug3_f("Setting CKA_ID = %s from PKCS#11 URI", arg);
Dmitry Belyavskiy f32b84
+			break;
Dmitry Belyavskiy f32b84
+		case pToken:
Dmitry Belyavskiy f32b84
+			/* CK_TOKEN_INFO -> label */
Dmitry Belyavskiy f32b84
+			charptr = &pkcs11->token;
Dmitry Belyavskiy f32b84
+ parse_string:
Dmitry Belyavskiy f32b84
+			if (*charptr != NULL) {
Dmitry Belyavskiy f32b84
+				verbose_f("The %s already set in the PKCS#11 URI",
Dmitry Belyavskiy f32b84
+				    keywords[opcode].name);
Dmitry Belyavskiy f32b84
+				rv = -1;
Dmitry Belyavskiy f32b84
+				goto out;
Jakub Jelen def1de
+			}
Dmitry Belyavskiy f32b84
+			percent_decode(arg, charptr);
Dmitry Belyavskiy f32b84
+			debug3_f("Setting %s = %s from PKCS#11 URI",
Dmitry Belyavskiy f32b84
+			    keywords[opcode].name, *charptr);
Dmitry Belyavskiy f32b84
+			break;
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+		case pObject:
Dmitry Belyavskiy f32b84
+			/* CK_TOKEN_INFO -> manufacturerID */
Dmitry Belyavskiy f32b84
+			charptr = &pkcs11->object;
Dmitry Belyavskiy f32b84
+			goto parse_string;
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+		case pManufacturer:
Dmitry Belyavskiy f32b84
+			/* CK_TOKEN_INFO -> manufacturerID */
Dmitry Belyavskiy f32b84
+			charptr = &pkcs11->manuf;
Dmitry Belyavskiy f32b84
+			goto parse_string;
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+		case pLibraryManufacturer:
Dmitry Belyavskiy f32b84
+			/* CK_INFO -> manufacturerID */
Dmitry Belyavskiy f32b84
+			charptr = &pkcs11->lib_manuf;
Dmitry Belyavskiy f32b84
+			goto parse_string;
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+		default:
Dmitry Belyavskiy f32b84
+			/* Unrecognized attribute in the URI path SHOULD be error */
Dmitry Belyavskiy f32b84
+			verbose_f("Unknown part of path in PKCS#11 URI: %s", tok);
Jakub Jelen def1de
+		}
Jakub Jelen def1de
+	}
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+	tok = strtok_r(NULL, "?", &saveptr1);
Dmitry Belyavskiy f32b84
+	if (tok == NULL) {
Dmitry Belyavskiy f32b84
+		goto out;
Dmitry Belyavskiy f32b84
+	}
Dmitry Belyavskiy f32b84
+	/* parse pk11-query (optional) */
Dmitry Belyavskiy f32b84
+	for (str2 = tok; ; str2 = NULL) {
Dmitry Belyavskiy f32b84
+		char *arg;
Dmitry Belyavskiy f32b84
+		pkcs11uriOpCodes opcode;
Dmitry Belyavskiy f32b84
+		tok = strtok_r(str2, PKCS11_URI_QUERY_SEPARATOR, &saveptr2);
Dmitry Belyavskiy f32b84
+		if (tok == NULL)
Dmitry Belyavskiy f32b84
+			break;
Dmitry Belyavskiy f32b84
+		opcode = parse_token(tok);
Dmitry Belyavskiy f32b84
+		if (opcode != pBadOption)
Dmitry Belyavskiy f32b84
+			arg = tok + strlen(keywords[opcode].name) + 1; /* separator "=" */
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+		switch (opcode) {
Dmitry Belyavskiy f32b84
+		case pModulePath:
Dmitry Belyavskiy f32b84
+			/* module-path is PKCS11Provider */
Dmitry Belyavskiy f32b84
+			if (pkcs11->module_path != NULL) {
Dmitry Belyavskiy f32b84
+				verbose_f("Multiple module-path attributes are"
Dmitry Belyavskiy f32b84
+				    "not supported the PKCS#11 URI");
Dmitry Belyavskiy f32b84
+				rv = -1;
Dmitry Belyavskiy f32b84
+				goto out;
Dmitry Belyavskiy f32b84
+			}
Dmitry Belyavskiy f32b84
+			percent_decode(arg, &pkcs11->module_path);
Dmitry Belyavskiy f32b84
+			debug3_f("Setting PKCS11Provider = %s from PKCS#11 URI",
Dmitry Belyavskiy f32b84
+			    pkcs11->module_path);
Dmitry Belyavskiy f32b84
+			break;
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+		case pPinValue:
Dmitry Belyavskiy f32b84
+			/* pin-value */
Dmitry Belyavskiy f32b84
+			if (pkcs11->pin != NULL) {
Dmitry Belyavskiy f32b84
+				verbose_f("Multiple pin-value attributes are"
Dmitry Belyavskiy f32b84
+				    "not supported the PKCS#11 URI");
Dmitry Belyavskiy f32b84
+				rv = -1;
Dmitry Belyavskiy f32b84
+				goto out;
Dmitry Belyavskiy f32b84
+			}
Dmitry Belyavskiy f32b84
+			percent_decode(arg, &pkcs11->pin);
Dmitry Belyavskiy f32b84
+			debug3_f("Setting PIN from PKCS#11 URI");
Dmitry Belyavskiy f32b84
+			break;
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+		default:
Dmitry Belyavskiy f32b84
+			/* Unrecognized attribute in the URI query SHOULD be ignored */
Dmitry Belyavskiy f32b84
+			verbose_f("Unknown part of query in PKCS#11 URI: %s", tok);
Dmitry Belyavskiy f32b84
+		}
Dmitry Belyavskiy f32b84
+	}
Dmitry Belyavskiy f32b84
+out:
Dmitry Belyavskiy f32b84
+	free(p);
Dmitry Belyavskiy f32b84
+	return rv;
Dmitry Belyavskiy f32b84
+}
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+#endif /* ENABLE_PKCS11 */
Dmitry Belyavskiy 8f4d19
diff -up openssh-8.7p1/ssh-pkcs11-uri.h.pkcs11-uri openssh-8.7p1/ssh-pkcs11-uri.h
Dmitry Belyavskiy 8f4d19
--- openssh-8.7p1/ssh-pkcs11-uri.h.pkcs11-uri	2021-08-30 13:07:43.667700130 +0200
Dmitry Belyavskiy 8f4d19
+++ openssh-8.7p1/ssh-pkcs11-uri.h	2021-08-30 13:07:43.667700130 +0200
Dmitry Belyavskiy f32b84
@@ -0,0 +1,42 @@
Dmitry Belyavskiy f32b84
+/*
Dmitry Belyavskiy f32b84
+ * Copyright (c) 2017 Red Hat
Dmitry Belyavskiy f32b84
+ *
Dmitry Belyavskiy f32b84
+ * Authors: Jakub Jelen <jjelen@redhat.com>
Dmitry Belyavskiy f32b84
+ *
Dmitry Belyavskiy f32b84
+ * Permission to use, copy, modify, and distribute this software for any
Dmitry Belyavskiy f32b84
+ * purpose with or without fee is hereby granted, provided that the above
Dmitry Belyavskiy f32b84
+ * copyright notice and this permission notice appear in all copies.
Dmitry Belyavskiy f32b84
+ *
Dmitry Belyavskiy f32b84
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
Dmitry Belyavskiy f32b84
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
Dmitry Belyavskiy f32b84
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
Dmitry Belyavskiy f32b84
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
Dmitry Belyavskiy f32b84
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
Dmitry Belyavskiy f32b84
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
Dmitry Belyavskiy f32b84
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
Dmitry Belyavskiy f32b84
+ */
Jakub Jelen def1de
+
Dmitry Belyavskiy f32b84
+#define PKCS11_URI_SCHEME "pkcs11:"
Dmitry Belyavskiy f32b84
+#define PKCS11_URI_WHITELIST	"abcdefghijklmnopqrstuvwxyz" \
Dmitry Belyavskiy f32b84
+				"ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
Dmitry Belyavskiy f32b84
+				"0123456789_-.()"
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+struct pkcs11_uri {
Dmitry Belyavskiy f32b84
+	/* path */
Dmitry Belyavskiy f32b84
+	char *id;
Dmitry Belyavskiy f32b84
+	size_t id_len;
Dmitry Belyavskiy f32b84
+	char *token;
Dmitry Belyavskiy f32b84
+	char *object;
Dmitry Belyavskiy f32b84
+	char *lib_manuf;
Dmitry Belyavskiy f32b84
+	char *manuf;
Dmitry Belyavskiy f32b84
+	/* query */
Dmitry Belyavskiy f32b84
+	char *module_path;
Dmitry Belyavskiy f32b84
+	char *pin; /* Only parsed, but not printed */
Dmitry Belyavskiy f32b84
+};
Dmitry Belyavskiy f32b84
+
Dmitry Belyavskiy f32b84
+struct	 pkcs11_uri *pkcs11_uri_init();
Dmitry Belyavskiy f32b84
+void	 pkcs11_uri_cleanup(struct pkcs11_uri *);
Dmitry Belyavskiy f32b84
+int	 pkcs11_uri_parse(const char *, struct pkcs11_uri *);
Dmitry Belyavskiy f32b84
+struct	 pkcs11_uri *pkcs11_uri_init();
Dmitry Belyavskiy f32b84
+char	*pkcs11_uri_get(struct pkcs11_uri *uri);
Jakub Jelen def1de
+