| |
@@ -1,4760 +0,0 @@
|
| |
- diff -up openssh/authfd.c.pkcs11-uri openssh/authfd.c
|
| |
- --- openssh/authfd.c.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200
|
| |
- +++ openssh/authfd.c 2018-10-12 13:52:55.450191401 +0200
|
| |
- @@ -312,6 +312,8 @@ ssh_free_identitylist(struct ssh_identit
|
| |
- if (idl->comments != NULL)
|
| |
- free(idl->comments[i]);
|
| |
- }
|
| |
- + free(idl->keys);
|
| |
- + free(idl->comments);
|
| |
- free(idl);
|
| |
- }
|
| |
-
|
| |
- diff -up openssh/configure.ac.pkcs11-uri openssh/configure.ac
|
| |
- --- openssh/configure.ac.pkcs11-uri 2018-10-12 13:52:55.430191235 +0200
|
| |
- +++ openssh/configure.ac 2018-10-12 13:52:55.451191409 +0200
|
| |
- @@ -1987,12 +1987,14 @@ AC_LINK_IFELSE(
|
| |
- [AC_DEFINE([HAVE_ISBLANK], [1], [Define if you have isblank(3C).])
|
| |
- ])
|
| |
-
|
| |
- +SCARD_MSG="yes"
|
| |
- disable_pkcs11=
|
| |
- AC_ARG_ENABLE([pkcs11],
|
| |
- [ --disable-pkcs11 disable PKCS#11 support code [no]],
|
| |
- [
|
| |
- if test "x$enableval" = "xno" ; then
|
| |
- disable_pkcs11=1
|
| |
- + SCARD_MSG="no"
|
| |
- fi
|
| |
- ]
|
| |
- )
|
| |
- @@ -2008,6 +2010,40 @@ if test "x$openssl" = "xyes" && test "x$
|
| |
- )
|
| |
- fi
|
| |
-
|
| |
- +# Check whether we have a p11-kit, we got default provider on command line
|
| |
- +DEFAULT_PKCS11_PROVIDER_MSG="no"
|
| |
- +AC_ARG_WITH([default-pkcs11-provider],
|
| |
- + [ --with-default-pkcs11-provider[[=PATH]] Use default pkcs11 provider (p11-kit detected by default)],
|
| |
- + [ if test "x$withval" != "xno" && test "x$disable_pkcs11" = "x"; then
|
| |
- + if test "x$withval" = "xyes" ; then
|
| |
- + AC_PATH_TOOL([PKGCONFIG], [pkg-config], [no])
|
| |
- + if test "x$PKGCONFIG" != "xno"; then
|
| |
- + AC_MSG_CHECKING([if $PKGCONFIG knows about p11-kit])
|
| |
- + if "$PKGCONFIG" "p11-kit-1"; then
|
| |
- + AC_MSG_RESULT([yes])
|
| |
- + use_pkgconfig_for_p11kit=yes
|
| |
- + else
|
| |
- + AC_MSG_RESULT([no])
|
| |
- + fi
|
| |
- + fi
|
| |
- + else
|
| |
- + PKCS11_PATH="${withval}"
|
| |
- + fi
|
| |
- + if test "x$use_pkgconfig_for_p11kit" = "xyes"; then
|
| |
- + PKCS11_PATH=`$PKGCONFIG --variable=proxy_module p11-kit-1`
|
| |
- + fi
|
| |
- + AC_CHECK_FILE("$PKCS11_PATH",
|
| |
- + [ AC_DEFINE_UNQUOTED([PKCS11_DEFAULT_PROVIDER], ["$PKCS11_PATH"], [Path to default PKCS#11 provider (p11-kit proxy)])
|
| |
- + DEFAULT_PKCS11_PROVIDER_MSG="$PKCS11_PATH"
|
| |
- + ],
|
| |
- + [ AC_MSG_ERROR([Requested PKCS11 provided not found]) ]
|
| |
- + )
|
| |
- + else
|
| |
- + AC_MSG_WARN([Needs PKCS11 support to enable default pkcs11 provider])
|
| |
- + fi ]
|
| |
- +)
|
| |
- +
|
| |
- +
|
| |
- # IRIX has a const char return value for gai_strerror()
|
| |
- AC_CHECK_FUNCS([gai_strerror], [
|
| |
- AC_DEFINE([HAVE_GAI_STRERROR])
|
| |
- @@ -5458,6 +5494,7 @@ echo " BSD Auth support
|
| |
- echo " Random number source: $RAND_MSG"
|
| |
- echo " Privsep sandbox style: $SANDBOX_STYLE"
|
| |
- echo " Vendor patch level: $SSH_VENDOR_PATCHLEVEL"
|
| |
- +echo " Default PKCS#11 provider: $DEFAULT_PKCS11_PROVIDER_MSG"
|
| |
-
|
| |
- echo ""
|
| |
-
|
| |
- diff -up openssh/Makefile.in.pkcs11-uri openssh/Makefile.in
|
| |
- --- openssh/Makefile.in.pkcs11-uri 2018-10-12 13:52:55.366190704 +0200
|
| |
- +++ openssh/Makefile.in 2018-10-12 13:52:55.450191401 +0200
|
| |
- @@ -102,7 +102,7 @@ LIBSSH_OBJS=${LIBOPENSSH_OBJS} \
|
| |
- monitor_fdpass.o rijndael.o ssh-dss.o ssh-ecdsa.o ssh-rsa.o dh.o \
|
| |
- kexgssc.o \
|
| |
- msg.o progressmeter.o dns.o entropy.o gss-genr.o umac.o umac128.o \
|
| |
- - ssh-pkcs11.o smult_curve25519_ref.o \
|
| |
- + ssh-pkcs11.o ssh-pkcs11-uri.o smult_curve25519_ref.o \
|
| |
- poly1305.o chacha.o cipher-chachapoly.o \
|
| |
- ssh-ed25519.o digest-openssl.o digest-libc.o hmac.o \
|
| |
- sc25519.o ge25519.o fe25519.o ed25519.o verify.o hash.o \
|
| |
- @@ -270,6 +270,8 @@ clean: regressclean
|
| |
- rm -f regress/unittests/match/test_match$(EXEEXT)
|
| |
- rm -f regress/unittests/utf8/*.o
|
| |
- rm -f regress/unittests/utf8/test_utf8$(EXEEXT)
|
| |
- + rm -f regress/unittests/pkcs11/*.o
|
| |
- + rm -f regress/unittests/pkcs11/test_pkcs11$(EXEEXT)
|
| |
- rm -f regress/misc/kexfuzz/*.o
|
| |
- rm -f regress/misc/kexfuzz/kexfuzz$(EXEEXT)
|
| |
- (cd openbsd-compat && $(MAKE) clean)
|
| |
- @@ -300,6 +302,8 @@ distclean: regressclean
|
| |
- rm -f regress/unittests/match/test_match
|
| |
- rm -f regress/unittests/utf8/*.o
|
| |
- rm -f regress/unittests/utf8/test_utf8
|
| |
- + rm -f regress/unittests/pkcs11/*.o
|
| |
- + rm -f regress/unittests/pkcs11/test_pkcs11
|
| |
- rm -f regress/misc/kexfuzz/*.o
|
| |
- rm -f regress/misc/kexfuzz/kexfuzz$(EXEEXT)
|
| |
- (cd openbsd-compat && $(MAKE) distclean)
|
| |
- @@ -484,6 +488,7 @@ regress-prep:
|
| |
- $(MKDIR_P) `pwd`/regress/unittests/kex
|
| |
- $(MKDIR_P) `pwd`/regress/unittests/match
|
| |
- $(MKDIR_P) `pwd`/regress/unittests/utf8
|
| |
- + $(MKDIR_P) `pwd`/regress/unittests/pkcs11
|
| |
- $(MKDIR_P) `pwd`/regress/misc/kexfuzz
|
| |
- [ -f `pwd`/regress/Makefile ] || \
|
| |
- ln -s `cd $(srcdir) && pwd`/regress/Makefile `pwd`/regress/Makefile
|
| |
- @@ -502,6 +507,11 @@ regress/netcat$(EXEEXT): $(srcdir)/regre
|
| |
- $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/netcat.c \
|
| |
- $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
|
| |
-
|
| |
- +regress/soft-pkcs11.so: $(srcdir)/regress/soft-pkcs11.c $(REGRESSLIBS)
|
| |
- + $(CC) $(CFLAGS) $(CPPFLAGS) -fpic -c $(srcdir)/regress/soft-pkcs11.c \
|
| |
- + -o $(srcdir)/regress/soft-pkcs11.o
|
| |
- + $(CC) -shared -o $@ $(srcdir)/regress/soft-pkcs11.o
|
| |
- +
|
| |
- regress/check-perm$(EXEEXT): $(srcdir)/regress/check-perm.c $(REGRESSLIBS)
|
| |
- $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $(srcdir)/regress/check-perm.c \
|
| |
- $(LDFLAGS) -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
|
| |
- @@ -607,6 +617,16 @@ regress/unittests/utf8/test_utf8$(EXEEXT
|
| |
- regress/unittests/test_helper/libtest_helper.a \
|
| |
- -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
|
| |
-
|
| |
- +UNITTESTS_TEST_PKCS11_OBJS=\
|
| |
- + regress/unittests/pkcs11/tests.o
|
| |
- +
|
| |
- +regress/unittests/pkcs11/test_pkcs11$(EXEEXT): \
|
| |
- + ${UNITTESTS_TEST_PKCS11_OBJS} \
|
| |
- + regress/unittests/test_helper/libtest_helper.a libssh.a
|
| |
- + $(LD) -o $@ $(LDFLAGS) $(UNITTESTS_TEST_PKCS11_OBJS) \
|
| |
- + regress/unittests/test_helper/libtest_helper.a \
|
| |
- + -lssh -lopenbsd-compat -lssh -lopenbsd-compat $(LIBS)
|
| |
- +
|
| |
- MISC_KEX_FUZZ_OBJS=\
|
| |
- regress/misc/kexfuzz/kexfuzz.o
|
| |
-
|
| |
- @@ -617,6 +637,7 @@ regress/misc/kexfuzz/kexfuzz$(EXEEXT): $
|
| |
- regress-binaries: regress/modpipe$(EXEEXT) \
|
| |
- regress/setuid-allowed$(EXEEXT) \
|
| |
- regress/netcat$(EXEEXT) \
|
| |
- + regress/soft-pkcs11.so \
|
| |
- regress/check-perm$(EXEEXT) \
|
| |
- regress/mkdtemp$(EXEEXT) \
|
| |
- regress/unittests/sshbuf/test_sshbuf$(EXEEXT) \
|
| |
- @@ -627,6 +648,7 @@ regress-binaries: regress/modpipe$(EXEEX
|
| |
- regress/unittests/kex/test_kex$(EXEEXT) \
|
| |
- regress/unittests/match/test_match$(EXEEXT) \
|
| |
- regress/unittests/utf8/test_utf8$(EXEEXT) \
|
| |
- + regress/unittests/pkcs11/test_pkcs11$(EXEEXT) \
|
| |
- regress/misc/kexfuzz/kexfuzz$(EXEEXT)
|
| |
-
|
| |
- tests interop-tests t-exec unit: regress-prep regress-binaries $(TARGETS)
|
| |
- diff -up openssh/regress/agent-pkcs11.sh.pkcs11-uri openssh/regress/agent-pkcs11.sh
|
| |
- --- openssh/regress/agent-pkcs11.sh.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200
|
| |
- +++ openssh/regress/agent-pkcs11.sh 2018-10-12 13:52:55.451191409 +0200
|
| |
- @@ -4,10 +4,17 @@
|
| |
- tid="pkcs11 agent test"
|
| |
-
|
| |
- TEST_SSH_PIN=""
|
| |
- -TEST_SSH_PKCS11=/usr/local/lib/soft-pkcs11.so.0.0
|
| |
- +TEST_SSH_PKCS11=$OBJ/soft-pkcs11.so
|
| |
-
|
| |
- test -f "$TEST_SSH_PKCS11" || fatal "$TEST_SSH_PKCS11 does not exist"
|
| |
-
|
| |
- +# requires ssh-agent built with correct path to ssh-pkcs11-helper
|
| |
- +# otherwise it fails to start the helper
|
| |
- +strings ${TEST_SSH_SSHAGENT} | grep "$TEST_SSH_SSHPKCS11HELPER"
|
| |
- +if [ $? -ne 0 ]; then
|
| |
- + fatal "Needs to reconfigure with --libexecdir=\`pwd\` or so"
|
| |
- +fi
|
| |
- +
|
| |
- # setup environment for soft-pkcs11 token
|
| |
- SOFTPKCS11RC=$OBJ/pkcs11.info
|
| |
- export SOFTPKCS11RC
|
| |
- @@ -23,7 +30,7 @@ notty() {
|
| |
- }
|
| |
-
|
| |
- trace "start agent"
|
| |
- -eval `${SSHAGENT} -s` > /dev/null
|
| |
- +eval `${SSHAGENT} -s -P "${OBJ}/*"` > /dev/null
|
| |
- r=$?
|
| |
- if [ $r -ne 0 ]; then
|
| |
- fail "could not start ssh-agent: exit code $r"
|
| |
- @@ -60,7 +67,7 @@ else
|
| |
- fi
|
| |
-
|
| |
- trace "remove pkcs11 keys"
|
| |
- - echo ${TEST_SSH_PIN} | notty ${SSHADD} -e ${TEST_SSH_PKCS11} > /dev/null 2>&1
|
| |
- + ${SSHADD} -e ${TEST_SSH_PKCS11} > /dev/null 2>&1
|
| |
- r=$?
|
| |
- if [ $r -ne 0 ]; then
|
| |
- fail "ssh-add -e failed: exit code $r"
|
| |
- diff -up openssh/regress/locl.h.pkcs11-uri openssh/regress/locl.h
|
| |
- --- openssh/regress/locl.h.pkcs11-uri 2018-10-12 13:52:55.451191409 +0200
|
| |
- +++ openssh/regress/locl.h 2018-10-12 13:52:55.451191409 +0200
|
| |
- @@ -0,0 +1,78 @@
|
| |
- +/*
|
| |
- + * Copyright (c) 2004, Stockholms universitet
|
| |
- + * (Stockholm University, Stockholm Sweden)
|
| |
- + * All rights reserved.
|
| |
- + *
|
| |
- + * Redistribution and use in source and binary forms, with or without
|
| |
- + * modification, are permitted provided that the following conditions
|
| |
- + * are met:
|
| |
- + *
|
| |
- + * 1. Redistributions of source code must retain the above copyright
|
| |
- + * notice, this list of conditions and the following disclaimer.
|
| |
- + *
|
| |
- + * 2. Redistributions in binary form must reproduce the above copyright
|
| |
- + * notice, this list of conditions and the following disclaimer in the
|
| |
- + * documentation and/or other materials provided with the distribution.
|
| |
- + *
|
| |
- + * 3. Neither the name of the university nor the names of its contributors
|
| |
- + * may be used to endorse or promote products derived from this software
|
| |
- + * without specific prior written permission.
|
| |
- + *
|
| |
- + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| |
- + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| |
- + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| |
- + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| |
- + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| |
- + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| |
- + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| |
- + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| |
- + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| |
- + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| |
- + * POSSIBILITY OF SUCH DAMAGE.
|
| |
- + */
|
| |
- +
|
| |
- +/* $Id: locl.h,v 1.5 2005/08/28 15:30:31 lha Exp $ */
|
| |
- +
|
| |
- +#ifdef HAVE_CONFIG_H
|
| |
- +#include <config.h>
|
| |
- +#endif
|
| |
- +
|
| |
- +#include <openssl/err.h>
|
| |
- +#include <openssl/evp.h>
|
| |
- +#include <openssl/pem.h>
|
| |
- +#include <openssl/rand.h>
|
| |
- +#include <openssl/x509.h>
|
| |
- +
|
| |
- +#include <ctype.h>
|
| |
- +#include <errno.h>
|
| |
- +#include <pwd.h>
|
| |
- +#include <stdarg.h>
|
| |
- +#define _GNU_SOURCE
|
| |
- +#include <stdio.h>
|
| |
- +#include <stdlib.h>
|
| |
- +#include <string.h>
|
| |
- +#include <unistd.h>
|
| |
- +
|
| |
- +#include "../pkcs11.h"
|
| |
- +
|
| |
- +#define OPENSSL_ASN1_MALLOC_ENCODE(T, B, BL, S, R) \
|
| |
- +{ \
|
| |
- + unsigned char *p; \
|
| |
- + (BL) = i2d_##T((S), NULL); \
|
| |
- + if ((BL) <= 0) { \
|
| |
- + (R) = EINVAL; \
|
| |
- + } else { \
|
| |
- + (B) = malloc((BL)); \
|
| |
- + if ((B) == NULL) { \
|
| |
- + (R) = ENOMEM; \
|
| |
- + } else { \
|
| |
- + p = (B); \
|
| |
- + (R) = 0; \
|
| |
- + (BL) = i2d_##T((S), &p); \
|
| |
- + if ((BL) <= 0) { \
|
| |
- + free((B)); \
|
| |
- + (R) = EINVAL; \
|
| |
- + } \
|
| |
- + } \
|
| |
- + } \
|
| |
- +}
|
| |
- diff -up openssh/regress/Makefile.pkcs11-uri openssh/regress/Makefile
|
| |
- --- openssh/regress/Makefile.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200
|
| |
- +++ openssh/regress/Makefile 2018-10-12 13:52:55.451191409 +0200
|
| |
- @@ -109,9 +109,11 @@ CLEANFILES= *.core actual agent-key.* au
|
| |
- known_hosts known_hosts-cert known_hosts.* krl-* ls.copy \
|
| |
- modpipe netcat no_identity_config \
|
| |
- pidfile putty.rsa2 ready regress.log \
|
| |
- - remote_pid revoked-* rsa rsa-agent rsa-agent.pub rsa.pub \
|
| |
- + remote_pid revoked-* rsa rsa-agent rsa-agent.pub \
|
| |
- + rsa-agent-cert.pub rsa.pub \
|
| |
- rsa1 rsa1-agent rsa1-agent.pub rsa1.pub rsa_ssh2_cr.prv \
|
| |
- - rsa_ssh2_crnl.prv scp-ssh-wrapper.exe \
|
| |
- + soft-pkcs11.so soft-pkcs11.o pkcs11*.crt pkcs11*.key \
|
| |
- + pkcs11.info rsa_ssh2_crnl.prv scp-ssh-wrapper.exe \
|
| |
- scp-ssh-wrapper.scp setuid-allowed sftp-server.log \
|
| |
- sftp-server.sh sftp.log ssh-log-wrapper.sh ssh.log \
|
| |
- ssh_config ssh_config.* ssh_proxy ssh_proxy_bak \
|
| |
- @@ -226,6 +228,7 @@ unit:
|
| |
- V="" ; \
|
| |
- test "x${USE_VALGRIND}" = "x" || \
|
| |
- V=${.CURDIR}/valgrind-unit.sh ; \
|
| |
- + $$V ${.OBJDIR}/unittests/pkcs11/test_pkcs11 ; \
|
| |
- $$V ${.OBJDIR}/unittests/sshbuf/test_sshbuf ; \
|
| |
- $$V ${.OBJDIR}/unittests/sshkey/test_sshkey \
|
| |
- -d ${.CURDIR}/unittests/sshkey/testdata ; \
|
| |
- diff -up openssh/regress/pkcs11.sh.pkcs11-uri openssh/regress/pkcs11.sh
|
| |
- --- openssh/regress/pkcs11.sh.pkcs11-uri 2018-10-12 13:52:55.451191409 +0200
|
| |
- +++ openssh/regress/pkcs11.sh 2018-10-12 13:52:55.451191409 +0200
|
| |
- @@ -0,0 +1,300 @@
|
| |
- +#
|
| |
- +# Copyright (c) 2017 Red Hat
|
| |
- +#
|
| |
- +# Authors: Jakub Jelen <jjelen@redhat.com>
|
| |
- +#
|
| |
- +# Permission to use, copy, modify, and distribute this software for any
|
| |
- +# purpose with or without fee is hereby granted, provided that the above
|
| |
- +# copyright notice and this permission notice appear in all copies.
|
| |
- +#
|
| |
- +# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
| |
- +# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
| |
- +# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
| |
- +# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
| |
- +# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
| |
- +# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
| |
- +# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
| |
- +
|
| |
- +tid="pkcs11 tests with soft token"
|
| |
- +
|
| |
- +TEST_SSH_PIN=""
|
| |
- +TEST_SSH_PKCS11=$OBJ/soft-pkcs11.so
|
| |
- +
|
| |
- +test -f "$TEST_SSH_PKCS11" || fatal "$TEST_SSH_PKCS11 does not exist"
|
| |
- +
|
| |
- +# requires ssh-agent built with correct path to ssh-pkcs11-helper
|
| |
- +# otherwise it fails to start the helper
|
| |
- +strings ${TEST_SSH_SSHAGENT} | grep "$TEST_SSH_SSHPKCS11HELPER"
|
| |
- +if [ $? -ne 0 ]; then
|
| |
- + fatal "Needs to reconfigure with --libexecdir=\`pwd\` or so"
|
| |
- +fi
|
| |
- +
|
| |
- +# setup environment for soft-pkcs11 token
|
| |
- +SOFTPKCS11RC=$OBJ/pkcs11.info
|
| |
- +rm -f $SOFTPKCS11RC
|
| |
- +export SOFTPKCS11RC
|
| |
- +# prevent ssh-agent from calling ssh-askpass
|
| |
- +SSH_ASKPASS=/usr/bin/true
|
| |
- +export SSH_ASKPASS
|
| |
- +unset DISPLAY
|
| |
- +
|
| |
- +# start command w/o tty, so ssh accepts pin from stdin (from agent-pkcs11.sh)
|
| |
- +notty() {
|
| |
- + perl -e 'use POSIX; POSIX::setsid();
|
| |
- + if (fork) { wait; exit($? >> 8); } else { exec(@ARGV) }' "$@"
|
| |
- +}
|
| |
- +
|
| |
- +create_key() {
|
| |
- + ID=$1
|
| |
- + LABEL=$2
|
| |
- + rm -f $OBJ/pkcs11-${ID}.key $OBJ/pkcs11-${ID}.crt
|
| |
- + openssl genrsa -out $OBJ/pkcs11-${ID}.key 2048 > /dev/null 2>&1
|
| |
- + chmod 600 $OBJ/pkcs11-${ID}.key
|
| |
- + openssl req -key $OBJ/pkcs11-${ID}.key -new -x509 \
|
| |
- + -out $OBJ/pkcs11-${ID}.crt -text -subj '/CN=pkcs11 test' >/dev/null
|
| |
- + printf "${ID}\t${LABEL}\t$OBJ/pkcs11-${ID}.crt\t$OBJ/pkcs11-${ID}.key\n" \
|
| |
- + >> $SOFTPKCS11RC
|
| |
- +}
|
| |
- +
|
| |
- +trace "Create a key pairs on soft token"
|
| |
- +ID1="02"
|
| |
- +ID2="04"
|
| |
- +create_key "$ID1" "SSH RSA Key"
|
| |
- +create_key "$ID2" "SSH RSA Key 2"
|
| |
- +
|
| |
- +trace "List the keys in the ssh-keygen with PKCS#11 URIs"
|
| |
- +${SSHKEYGEN} -D ${TEST_SSH_PKCS11} > $OBJ/token_keys
|
| |
- +if [ $? -ne 0 ]; then
|
| |
- + fail "keygen fails to enumerate keys on PKCS#11 token"
|
| |
- +fi
|
| |
- +grep "pkcs11:" $OBJ/token_keys > /dev/null
|
| |
- +if [ $? -ne 0 ]; then
|
| |
- + fail "The keys from ssh-keygen do not contain PKCS#11 URI as a comment"
|
| |
- +fi
|
| |
- +tail -n 1 $OBJ/token_keys > $OBJ/authorized_keys_$USER
|
| |
- +
|
| |
- +
|
| |
- +trace "Simple connect with ssh (without PKCS#11 URI)"
|
| |
- +echo ${TEST_SSH_PIN} | notty ${SSH} -I ${TEST_SSH_PKCS11} \
|
| |
- + -F $OBJ/ssh_proxy somehost exit 5
|
| |
- +r=$?
|
| |
- +if [ $r -ne 5 ]; then
|
| |
- + fail "ssh connect with pkcs11 failed (exit code $r)"
|
| |
- +fi
|
| |
- +
|
| |
- +
|
| |
- +trace "Connect with PKCS#11 URI"
|
| |
- +trace " (second key should succeed)"
|
| |
- +echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
|
| |
- + -i "pkcs11:id=${ID2}?module-path=${TEST_SSH_PKCS11}" somehost exit 5
|
| |
- +r=$?
|
| |
- +if [ $r -ne 5 ]; then
|
| |
- + fail "ssh connect with PKCS#11 URI failed (exit code $r)"
|
| |
- +fi
|
| |
- +
|
| |
- +trace " (first key should fail)"
|
| |
- +echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
|
| |
- + -i "pkcs11:id=${ID1}?module-path=${TEST_SSH_PKCS11}" somehost exit 5
|
| |
- +r=$?
|
| |
- +if [ $r -eq 5 ]; then
|
| |
- + fail "ssh connect with PKCS#11 URI succeeded (should fail)"
|
| |
- +fi
|
| |
- +
|
| |
- +trace "Connect with various filtering options in PKCS#11 URI"
|
| |
- +trace " (by object label, second key should succeed)"
|
| |
- +echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
|
| |
- + -i "pkcs11:object=SSH%20RSA%20Key%202?module-path=${TEST_SSH_PKCS11}" somehost exit 5
|
| |
- +r=$?
|
| |
- +if [ $r -ne 5 ]; then
|
| |
- + fail "ssh connect with PKCS#11 URI failed (exit code $r)"
|
| |
- +fi
|
| |
- +
|
| |
- +trace " (by object label, first key should fail)"
|
| |
- +echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
|
| |
- + -i "pkcs11:object=SSH%20RSA%20Key?module-path=${TEST_SSH_PKCS11}" somehost exit 5
|
| |
- +r=$?
|
| |
- +if [ $r -eq 5 ]; then
|
| |
- + fail "ssh connect with PKCS#11 URI succeeded (should fail)"
|
| |
- +fi
|
| |
- +
|
| |
- +trace " (by token label, second key should succeed)"
|
| |
- +echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
|
| |
- + -i "pkcs11:id=${ID2};token=SoftToken%20(token)?module-path=${TEST_SSH_PKCS11}" somehost exit 5
|
| |
- +r=$?
|
| |
- +if [ $r -ne 5 ]; then
|
| |
- + fail "ssh connect with PKCS#11 URI failed (exit code $r)"
|
| |
- +fi
|
| |
- +
|
| |
- +trace " (by wrong token label, should fail)"
|
| |
- +echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
|
| |
- + -i "pkcs11:token=SoftToken?module-path=${TEST_SSH_PKCS11}" somehost exit 5
|
| |
- +r=$?
|
| |
- +if [ $r -eq 5 ]; then
|
| |
- + fail "ssh connect with PKCS#11 URI succeeded (should fail)"
|
| |
- +fi
|
| |
- +
|
| |
- +
|
| |
- +
|
| |
- +
|
| |
- +trace "Test PKCS#11 URI specification in configuration files"
|
| |
- +echo "IdentityFile \"pkcs11:id=${ID2}?module-path=${TEST_SSH_PKCS11}\"" \
|
| |
- + >> $OBJ/ssh_proxy
|
| |
- +trace " (second key should succeed)"
|
| |
- +echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy somehost exit 5
|
| |
- +r=$?
|
| |
- +if [ $r -ne 5 ]; then
|
| |
- + fail "ssh connect with PKCS#11 URI in config failed (exit code $r)"
|
| |
- +fi
|
| |
- +
|
| |
- +trace " (first key should fail)"
|
| |
- +head -n 1 $OBJ/token_keys > $OBJ/authorized_keys_$USER
|
| |
- +echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy somehost exit 5
|
| |
- +r=$?
|
| |
- +if [ $r -eq 5 ]; then
|
| |
- + fail "ssh connect with PKCS#11 URI in config succeeded (should fail)"
|
| |
- +fi
|
| |
- +sed -i -e "/IdentityFile/d" $OBJ/ssh_proxy
|
| |
- +
|
| |
- +trace "Test PKCS#11 URI specification in configuration files with bogus spaces"
|
| |
- +echo "IdentityFile \" pkcs11:id=${ID1}?module-path=${TEST_SSH_PKCS11} \"" \
|
| |
- + >> $OBJ/ssh_proxy
|
| |
- +echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy somehost exit 5
|
| |
- +r=$?
|
| |
- +if [ $r -ne 5 ]; then
|
| |
- + fail "ssh connect with PKCS#11 URI with bogus spaces in config failed" \
|
| |
- + "(exit code $r)"
|
| |
- +fi
|
| |
- +sed -i -e "/IdentityFile/d" $OBJ/ssh_proxy
|
| |
- +
|
| |
- +
|
| |
- +trace "Combination of PKCS11Provider and PKCS11URI on commandline"
|
| |
- +trace " (first key should succeed)"
|
| |
- +echo ${TEST_SSH_PIN} | notty ${SSH} -F $OBJ/ssh_proxy \
|
| |
- + -i "pkcs11:id=${ID1}" -I ${TEST_SSH_PKCS11} somehost exit 5
|
| |
- +r=$?
|
| |
- +if [ $r -ne 5 ]; then
|
| |
- + fail "ssh connect with PKCS#11 URI and provider combination" \
|
| |
- + "failed (exit code $r)"
|
| |
- +fi
|
| |
- +
|
| |
- +trace "Regress: Missing provider in PKCS11URI option"
|
| |
- +${SSH} -F $OBJ/ssh_proxy \
|
| |
- + -o IdentityFile=\"pkcs11:token=segfault\" somehost exit 5
|
| |
- +r=$?
|
| |
- +if [ $r -eq 139 ]; then
|
| |
- + fail "ssh connect with missing provider_id from configuration option" \
|
| |
- + "crashed (exit code $r)"
|
| |
- +fi
|
| |
- +
|
| |
- +
|
| |
- +trace "SSH Agent can work with PKCS#11 URI"
|
| |
- +trace "start the agent"
|
| |
- +eval `${SSHAGENT} -s -P "${OBJ}/*"` > /dev/null
|
| |
- +
|
| |
- +r=$?
|
| |
- +if [ $r -ne 0 ]; then
|
| |
- + fail "could not start ssh-agent: exit code $r"
|
| |
- +else
|
| |
- + trace "add whole provider to agent"
|
| |
- + echo ${TEST_SSH_PIN} | notty ${SSHADD} \
|
| |
- + "pkcs11:?module-path=${TEST_SSH_PKCS11}" > /dev/null 2>&1
|
| |
- + r=$?
|
| |
- + if [ $r -ne 0 ]; then
|
| |
- + fail "ssh-add failed with whole provider: exit code $r"
|
| |
- + fi
|
| |
- +
|
| |
- + trace " pkcs11 list via agent (all keys)"
|
| |
- + ${SSHADD} -l > /dev/null 2>&1
|
| |
- + r=$?
|
| |
- + if [ $r -ne 0 ]; then
|
| |
- + fail "ssh-add -l failed with whole provider: exit code $r"
|
| |
- + fi
|
| |
- +
|
| |
- + trace " pkcs11 connect via agent (all keys)"
|
| |
- + ${SSH} -F $OBJ/ssh_proxy somehost exit 5
|
| |
- + r=$?
|
| |
- + if [ $r -ne 5 ]; then
|
| |
- + fail "ssh connect failed with whole provider (exit code $r)"
|
| |
- + fi
|
| |
- +
|
| |
- + trace " remove pkcs11 keys (all keys)"
|
| |
- + ${SSHADD} -d "pkcs11:?module-path=${TEST_SSH_PKCS11}" > /dev/null 2>&1
|
| |
- + r=$?
|
| |
- + if [ $r -ne 0 ]; then
|
| |
- + fail "ssh-add -d failed with whole provider: exit code $r"
|
| |
- + fi
|
| |
- +
|
| |
- + trace "add only first key to the agent"
|
| |
- + echo ${TEST_SSH_PIN} | notty ${SSHADD} \
|
| |
- + "pkcs11:id=${ID1}?module-path=${TEST_SSH_PKCS11}" > /dev/null 2>&1
|
| |
- + r=$?
|
| |
- + if [ $r -ne 0 ]; then
|
| |
- + fail "ssh-add failed with first key: exit code $r"
|
| |
- + fi
|
| |
- +
|
| |
- + trace " pkcs11 connect via agent (first key)"
|
| |
- + ${SSH} -F $OBJ/ssh_proxy somehost exit 5
|
| |
- + r=$?
|
| |
- + if [ $r -ne 5 ]; then
|
| |
- + fail "ssh connect failed with first key (exit code $r)"
|
| |
- + fi
|
| |
- +
|
| |
- + trace " remove first pkcs11 key"
|
| |
- + ${SSHADD} -d "pkcs11:id=${ID1}?module-path=${TEST_SSH_PKCS11}" \
|
| |
- + > /dev/null 2>&1
|
| |
- + r=$?
|
| |
- + if [ $r -ne 0 ]; then
|
| |
- + fail "ssh-add -d failed with first key: exit code $r"
|
| |
- + fi
|
| |
- +
|
| |
- + trace "add only second key to the agent"
|
| |
- + echo ${TEST_SSH_PIN} | notty ${SSHADD} \
|
| |
- + "pkcs11:id=${ID2}?module-path=${TEST_SSH_PKCS11}" > /dev/null 2>&1
|
| |
- + r=$?
|
| |
- + if [ $r -ne 0 ]; then
|
| |
- + fail "ssh-add failed with second key: exit code $r"
|
| |
- + fi
|
| |
- +
|
| |
- + trace " pkcs11 connect via agent (second key should fail)"
|
| |
- + ${SSH} -F $OBJ/ssh_proxy somehost exit 5
|
| |
- + r=$?
|
| |
- + if [ $r -eq 5 ]; then
|
| |
- + fail "ssh connect passed without key (should fail)"
|
| |
- + fi
|
| |
- +
|
| |
- + trace "add also the first key to the agent"
|
| |
- + echo ${TEST_SSH_PIN} | notty ${SSHADD} \
|
| |
- + "pkcs11:id=${ID1}?module-path=${TEST_SSH_PKCS11}" > /dev/null 2>&1
|
| |
- + r=$?
|
| |
- + if [ $r -ne 0 ]; then
|
| |
- + fail "ssh-add failed with first key: exit code $r"
|
| |
- + fi
|
| |
- +
|
| |
- + trace " remove second pkcs11 key"
|
| |
- + ${SSHADD} -d "pkcs11:id=${ID2}?module-path=${TEST_SSH_PKCS11}" \
|
| |
- + > /dev/null 2>&1
|
| |
- + r=$?
|
| |
- + if [ $r -ne 0 ]; then
|
| |
- + fail "ssh-add -d failed with second key: exit code $r"
|
| |
- + fi
|
| |
- +
|
| |
- + trace " remove already-removed pkcs11 key should fail"
|
| |
- + ${SSHADD} -d "pkcs11:id=${ID2}?module-path=${TEST_SSH_PKCS11}" \
|
| |
- + > /dev/null 2>&1
|
| |
- + r=$?
|
| |
- + if [ $r -eq 0 ]; then
|
| |
- + fail "ssh-add -d passed with non-existing key (should fail)"
|
| |
- + fi
|
| |
- +
|
| |
- + trace " pkcs11 connect via agent (the first key should be still usable)"
|
| |
- + ${SSH} -F $OBJ/ssh_proxy somehost exit 5
|
| |
- + r=$?
|
| |
- + if [ $r -ne 5 ]; then
|
| |
- + fail "ssh connect failed with first key (after removing second): exit code $r"
|
| |
- + fi
|
| |
- +
|
| |
- + trace "kill agent"
|
| |
- + ${SSHAGENT} -k > /dev/null
|
| |
- +fi
|
| |
- +
|
| |
- +rm -rf $OBJ/.tokens $OBJ/token_keys
|
| |
- diff -up openssh/regress/soft-pkcs11.c.pkcs11-uri openssh/regress/soft-pkcs11.c
|
| |
- --- openssh/regress/soft-pkcs11.c.pkcs11-uri 2018-10-12 13:52:55.452191417 +0200
|
| |
- +++ openssh/regress/soft-pkcs11.c 2018-10-12 13:52:55.452191417 +0200
|
| |
- @@ -0,0 +1,2058 @@
|
| |
- +/*
|
| |
- + * Copyright (c) 2004-2006, Stockholms universitet
|
| |
- + * (Stockholm University, Stockholm Sweden)
|
| |
- + * All rights reserved.
|
| |
- + *
|
| |
- + * Redistribution and use in source and binary forms, with or without
|
| |
- + * modification, are permitted provided that the following conditions
|
| |
- + * are met:
|
| |
- + *
|
| |
- + * 1. Redistributions of source code must retain the above copyright
|
| |
- + * notice, this list of conditions and the following disclaimer.
|
| |
- + *
|
| |
- + * 2. Redistributions in binary form must reproduce the above copyright
|
| |
- + * notice, this list of conditions and the following disclaimer in the
|
| |
- + * documentation and/or other materials provided with the distribution.
|
| |
- + *
|
| |
- + * 3. Neither the name of the university nor the names of its contributors
|
| |
- + * may be used to endorse or promote products derived from this software
|
| |
- + * without specific prior written permission.
|
| |
- + *
|
| |
- + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
| |
- + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
| |
- + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
| |
- + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
| |
- + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
| |
- + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
| |
- + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
| |
- + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
| |
- + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
| |
- + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
| |
- + * POSSIBILITY OF SUCH DAMAGE.
|
| |
- + */
|
| |
- +
|
| |
- +#include "locl.h"
|
| |
- +
|
| |
- +/* RCSID("$Id: main.c,v 1.24 2006/01/11 12:42:53 lha Exp $"); */
|
| |
- +
|
| |
- +#define OBJECT_ID_MASK 0xfff
|
| |
- +#define HANDLE_OBJECT_ID(h) ((h) & OBJECT_ID_MASK)
|
| |
- +#define OBJECT_ID(obj) HANDLE_OBJECT_ID((obj)->object_handle)
|
| |
- +
|
| |
- +#if OPENSSL_VERSION_NUMBER < 0x10100000L
|
| |
- + #define RSA_PKCS1_SSLeay RSA_PKCS1_OpenSSL
|
| |
- +#endif
|
| |
- +
|
| |
- +struct st_attr {
|
| |
- + CK_ATTRIBUTE attribute;
|
| |
- + int secret;
|
| |
- +};
|
| |
- +
|
| |
- +struct st_object {
|
| |
- + CK_OBJECT_HANDLE object_handle;
|
| |
- + struct st_attr *attrs;
|
| |
- + int num_attributes;
|
| |
- + enum {
|
| |
- + STO_T_CERTIFICATE,
|
| |
- + STO_T_PRIVATE_KEY,
|
| |
- + STO_T_PUBLIC_KEY
|
| |
- + } type;
|
| |
- + union {
|
| |
- + X509 *cert;
|
| |
- + EVP_PKEY *public_key;
|
| |
- + struct {
|
| |
- + const char *file;
|
| |
- + EVP_PKEY *key;
|
| |
- + X509 *cert;
|
| |
- + } private_key;
|
| |
- + } u;
|
| |
- +};
|
| |
- +
|
| |
- +static struct soft_token {
|
| |
- + CK_VOID_PTR application;
|
| |
- + CK_NOTIFY notify;
|
| |
- + struct {
|
| |
- + struct st_object **objs;
|
| |
- + int num_objs;
|
| |
- + } object;
|
| |
- + struct {
|
| |
- + int hardware_slot;
|
| |
- + int app_error_fatal;
|
| |
- + int login_done;
|
| |
- + } flags;
|
| |
- + int open_sessions;
|
| |
- + struct session_state {
|
| |
- + CK_SESSION_HANDLE session_handle;
|
| |
- +
|
| |
- + struct {
|
| |
- + CK_ATTRIBUTE *attributes;
|
| |
- + CK_ULONG num_attributes;
|
| |
- + int next_object;
|
| |
- + } find;
|
| |
- +
|
| |
- + int encrypt_object;
|
| |
- + CK_MECHANISM_PTR encrypt_mechanism;
|
| |
- + int decrypt_object;
|
| |
- + CK_MECHANISM_PTR decrypt_mechanism;
|
| |
- + int sign_object;
|
| |
- + CK_MECHANISM_PTR sign_mechanism;
|
| |
- + int verify_object;
|
| |
- + CK_MECHANISM_PTR verify_mechanism;
|
| |
- + int digest_object;
|
| |
- + } state[10];
|
| |
- +#define MAX_NUM_SESSION (sizeof(soft_token.state)/sizeof(soft_token.state[0]))
|
| |
- + FILE *logfile;
|
| |
- +} soft_token;
|
| |
- +
|
| |
- +static void
|
| |
- +application_error(const char *fmt, ...)
|
| |
- +{
|
| |
- + va_list ap;
|
| |
- + va_start(ap, fmt);
|
| |
- + vprintf(fmt, ap);
|
| |
- + va_end(ap);
|
| |
- + if (soft_token.flags.app_error_fatal)
|
| |
- + abort();
|
| |
- +}
|
| |
- +
|
| |
- +static void
|
| |
- +st_logf(const char *fmt, ...)
|
| |
- +{
|
| |
- + va_list ap;
|
| |
- + if (soft_token.logfile == NULL)
|
| |
- + return;
|
| |
- + va_start(ap, fmt);
|
| |
- + vfprintf(soft_token.logfile, fmt, ap);
|
| |
- + va_end(ap);
|
| |
- + fflush(soft_token.logfile);
|
| |
- +}
|
| |
- +
|
| |
- +static void
|
| |
- +snprintf_fill(char *str, size_t size, char fillchar, const char *fmt, ...)
|
| |
- +{
|
| |
- + int len;
|
| |
- + va_list ap;
|
| |
- + len = vsnprintf(str, size, fmt, ap);
|
| |
- + va_end(ap);
|
| |
- + if (len < 0 || len > (int) size)
|
| |
- + return;
|
| |
- + while(len < (int) size)
|
| |
- + str[len++] = fillchar;
|
| |
- +}
|
| |
- +
|
| |
- +#ifndef TEST_APP
|
| |
- +#define printf error_use_st_logf
|
| |
- +#endif
|
| |
- +
|
| |
- +#define VERIFY_SESSION_HANDLE(s, state) \
|
| |
- +{ \
|
| |
- + CK_RV ret; \
|
| |
- + ret = verify_session_handle(s, state); \
|
| |
- + if (ret != CKR_OK) { \
|
| |
- + /* return CKR_OK */; \
|
| |
- + } \
|
| |
- +}
|
| |
- +
|
| |
- +static CK_RV
|
| |
- +verify_session_handle(CK_SESSION_HANDLE hSession,
|
| |
- + struct session_state **state)
|
| |
- +{
|
| |
- + size_t i;
|
| |
- +
|
| |
- + for (i = 0; i < MAX_NUM_SESSION; i++){
|
| |
- + if (soft_token.state[i].session_handle == hSession)
|
| |
- + break;
|
| |
- + }
|
| |
- + if (i == MAX_NUM_SESSION) {
|
| |
- + application_error("use of invalid handle: 0x%08lx\n",
|
| |
- + (unsigned long)hSession);
|
| |
- + return CKR_SESSION_HANDLE_INVALID;
|
| |
- + }
|
| |
- + if (state)
|
| |
- + *state = &soft_token.state[i];
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +static CK_RV
|
| |
- +object_handle_to_object(CK_OBJECT_HANDLE handle,
|
| |
- + struct st_object **object)
|
| |
- +{
|
| |
- + int i = HANDLE_OBJECT_ID(handle);
|
| |
- +
|
| |
- + *object = NULL;
|
| |
- + if (i >= soft_token.object.num_objs)
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- + if (soft_token.object.objs[i] == NULL)
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- + if (soft_token.object.objs[i]->object_handle != handle)
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- + *object = soft_token.object.objs[i];
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +static int
|
| |
- +attributes_match(const struct st_object *obj,
|
| |
- + const CK_ATTRIBUTE *attributes,
|
| |
- + CK_ULONG num_attributes)
|
| |
- +{
|
| |
- + CK_ULONG i;
|
| |
- + int j;
|
| |
- + st_logf("attributes_match: %ld\n", (unsigned long)OBJECT_ID(obj));
|
| |
- +
|
| |
- + for (i = 0; i < num_attributes; i++) {
|
| |
- + int match = 0;
|
| |
- + for (j = 0; j < obj->num_attributes; j++) {
|
| |
- + if (attributes[i].type == obj->attrs[j].attribute.type &&
|
| |
- + attributes[i].ulValueLen == obj->attrs[j].attribute.ulValueLen &&
|
| |
- + memcmp(attributes[i].pValue, obj->attrs[j].attribute.pValue,
|
| |
- + attributes[i].ulValueLen) == 0) {
|
| |
- + match = 1;
|
| |
- + break;
|
| |
- + }
|
| |
- + }
|
| |
- + if (match == 0) {
|
| |
- + st_logf("type %d attribute have no match\n", attributes[i].type);
|
| |
- + return 0;
|
| |
- + }
|
| |
- + }
|
| |
- + st_logf("attribute matches\n");
|
| |
- + return 1;
|
| |
- +}
|
| |
- +
|
| |
- +static void
|
| |
- +print_attributes(const CK_ATTRIBUTE *attributes,
|
| |
- + CK_ULONG num_attributes)
|
| |
- +{
|
| |
- + CK_ULONG i;
|
| |
- +
|
| |
- + st_logf("find objects: attrs: %lu\n", (unsigned long)num_attributes);
|
| |
- +
|
| |
- + for (i = 0; i < num_attributes; i++) {
|
| |
- + st_logf(" type: ");
|
| |
- + switch (attributes[i].type) {
|
| |
- + case CKA_TOKEN: {
|
| |
- + CK_BBOOL *ck_true;
|
| |
- + if (attributes[i].ulValueLen != sizeof(CK_BBOOL)) {
|
| |
- + application_error("token attribute wrong length\n");
|
| |
- + break;
|
| |
- + }
|
| |
- + ck_true = attributes[i].pValue;
|
| |
- + st_logf("token: %s", *ck_true ? "TRUE" : "FALSE");
|
| |
- + break;
|
| |
- + }
|
| |
- + case CKA_CLASS: {
|
| |
- + CK_OBJECT_CLASS *class;
|
| |
- + if (attributes[i].ulValueLen != sizeof(CK_ULONG)) {
|
| |
- + application_error("class attribute wrong length\n");
|
| |
- + break;
|
| |
- + }
|
| |
- + class = attributes[i].pValue;
|
| |
- + st_logf("class ");
|
| |
- + switch (*class) {
|
| |
- + case CKO_CERTIFICATE:
|
| |
- + st_logf("certificate");
|
| |
- + break;
|
| |
- + case CKO_PUBLIC_KEY:
|
| |
- + st_logf("public key");
|
| |
- + break;
|
| |
- + case CKO_PRIVATE_KEY:
|
| |
- + st_logf("private key");
|
| |
- + break;
|
| |
- + case CKO_SECRET_KEY:
|
| |
- + st_logf("secret key");
|
| |
- + break;
|
| |
- + case CKO_DOMAIN_PARAMETERS:
|
| |
- + st_logf("domain parameters");
|
| |
- + break;
|
| |
- + default:
|
| |
- + st_logf("[class %lx]", (long unsigned)*class);
|
| |
- + break;
|
| |
- + }
|
| |
- + break;
|
| |
- + }
|
| |
- + case CKA_PRIVATE:
|
| |
- + st_logf("private");
|
| |
- + break;
|
| |
- + case CKA_LABEL:
|
| |
- + st_logf("label");
|
| |
- + break;
|
| |
- + case CKA_APPLICATION:
|
| |
- + st_logf("application");
|
| |
- + break;
|
| |
- + case CKA_VALUE:
|
| |
- + st_logf("value");
|
| |
- + break;
|
| |
- + case CKA_ID:
|
| |
- + st_logf("id");
|
| |
- + break;
|
| |
- + default:
|
| |
- + st_logf("[unknown 0x%08lx]", (unsigned long)attributes[i].type);
|
| |
- + break;
|
| |
- + }
|
| |
- + st_logf("\n");
|
| |
- + }
|
| |
- +}
|
| |
- +
|
| |
- +static struct st_object *
|
| |
- +add_st_object(void)
|
| |
- +{
|
| |
- + struct st_object *o, **objs;
|
| |
- + int i;
|
| |
- +
|
| |
- + o = malloc(sizeof(*o));
|
| |
- + if (o == NULL)
|
| |
- + return NULL;
|
| |
- + memset(o, 0, sizeof(*o));
|
| |
- + o->attrs = NULL;
|
| |
- + o->num_attributes = 0;
|
| |
- +
|
| |
- + for (i = 0; i < soft_token.object.num_objs; i++) {
|
| |
- + if (soft_token.object.objs == NULL) {
|
| |
- + soft_token.object.objs[i] = o;
|
| |
- + break;
|
| |
- + }
|
| |
- + }
|
| |
- + if (i == soft_token.object.num_objs) {
|
| |
- + objs = realloc(soft_token.object.objs,
|
| |
- + (soft_token.object.num_objs + 1) * sizeof(soft_token.object.objs[0]));
|
| |
- + if (objs == NULL) {
|
| |
- + free(o);
|
| |
- + return NULL;
|
| |
- + }
|
| |
- + soft_token.object.objs = objs;
|
| |
- + soft_token.object.objs[soft_token.object.num_objs++] = o;
|
| |
- + }
|
| |
- + soft_token.object.objs[i]->object_handle =
|
| |
- + (random() & (~OBJECT_ID_MASK)) | i;
|
| |
- +
|
| |
- + return o;
|
| |
- +}
|
| |
- +
|
| |
- +static CK_RV
|
| |
- +add_object_attribute(struct st_object *o,
|
| |
- + int secret,
|
| |
- + CK_ATTRIBUTE_TYPE type,
|
| |
- + CK_VOID_PTR pValue,
|
| |
- + CK_ULONG ulValueLen)
|
| |
- +{
|
| |
- + struct st_attr *a;
|
| |
- + int i;
|
| |
- +
|
| |
- + i = o->num_attributes;
|
| |
- + a = realloc(o->attrs, (i + 1) * sizeof(o->attrs[0]));
|
| |
- + if (a == NULL)
|
| |
- + return CKR_DEVICE_MEMORY;
|
| |
- + o->attrs = a;
|
| |
- + o->attrs[i].secret = secret;
|
| |
- + o->attrs[i].attribute.type = type;
|
| |
- + o->attrs[i].attribute.pValue = malloc(ulValueLen);
|
| |
- + if (o->attrs[i].attribute.pValue == NULL && ulValueLen != 0)
|
| |
- + return CKR_DEVICE_MEMORY;
|
| |
- + memcpy(o->attrs[i].attribute.pValue, pValue, ulValueLen);
|
| |
- + o->attrs[i].attribute.ulValueLen = ulValueLen;
|
| |
- + o->num_attributes++;
|
| |
- +
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +static CK_RV
|
| |
- +add_pubkey_info(struct st_object *o, CK_KEY_TYPE key_type, EVP_PKEY *key)
|
| |
- +{
|
| |
- + switch (key_type) {
|
| |
- + case CKK_RSA: {
|
| |
- + CK_BYTE *modulus = NULL;
|
| |
- + size_t modulus_len = 0;
|
| |
- + CK_ULONG modulus_bits = 0;
|
| |
- + CK_BYTE *exponent = NULL;
|
| |
- + size_t exponent_len = 0;
|
| |
- + RSA* rsa = NULL;
|
| |
- + const BIGNUM *n = NULL, *e = NULL;
|
| |
- +
|
| |
- + rsa = EVP_PKEY_get0_RSA(key);
|
| |
- + RSA_get0_key(rsa, &n, &e, NULL);
|
| |
- +
|
| |
- + modulus_bits = BN_num_bits(n);
|
| |
- +
|
| |
- + modulus_len = BN_num_bytes(n);
|
| |
- + modulus = malloc(modulus_len);
|
| |
- + BN_bn2bin(n, modulus);
|
| |
- +
|
| |
- + exponent_len = BN_num_bytes(e);
|
| |
- + exponent = malloc(exponent_len);
|
| |
- + BN_bn2bin(e, exponent);
|
| |
- +
|
| |
- + add_object_attribute(o, 0, CKA_MODULUS, modulus, modulus_len);
|
| |
- + add_object_attribute(o, 0, CKA_MODULUS_BITS,
|
| |
- + &modulus_bits, sizeof(modulus_bits));
|
| |
- + add_object_attribute(o, 0, CKA_PUBLIC_EXPONENT,
|
| |
- + exponent, exponent_len);
|
| |
- +
|
| |
- + RSA_set_method(rsa, RSA_PKCS1_OpenSSL());
|
| |
- +
|
| |
- + free(modulus);
|
| |
- + free(exponent);
|
| |
- + }
|
| |
- + default:
|
| |
- + /* XXX */
|
| |
- + break;
|
| |
- + }
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +
|
| |
- +static int
|
| |
- +pem_callback(char *buf, int num, int w, void *key)
|
| |
- +{
|
| |
- + return -1;
|
| |
- +}
|
| |
- +
|
| |
- +
|
| |
- +static CK_RV
|
| |
- +add_certificate(char *label,
|
| |
- + const char *cert_file,
|
| |
- + const char *private_key_file,
|
| |
- + char *id,
|
| |
- + int anchor)
|
| |
- +{
|
| |
- + struct st_object *o = NULL;
|
| |
- + CK_BBOOL bool_true = CK_TRUE;
|
| |
- + CK_BBOOL bool_false = CK_FALSE;
|
| |
- + CK_OBJECT_CLASS c;
|
| |
- + CK_CERTIFICATE_TYPE cert_type = CKC_X_509;
|
| |
- + CK_KEY_TYPE key_type;
|
| |
- + CK_MECHANISM_TYPE mech_type;
|
| |
- + void *cert_data = NULL;
|
| |
- + size_t cert_length;
|
| |
- + void *subject_data = NULL;
|
| |
- + size_t subject_length;
|
| |
- + void *issuer_data = NULL;
|
| |
- + size_t issuer_length;
|
| |
- + void *serial_data = NULL;
|
| |
- + size_t serial_length;
|
| |
- + CK_RV ret = CKR_GENERAL_ERROR;
|
| |
- + X509 *cert;
|
| |
- + EVP_PKEY *public_key;
|
| |
- +
|
| |
- + size_t id_len = strlen(id);
|
| |
- +
|
| |
- + {
|
| |
- + FILE *f;
|
| |
- +
|
| |
- + f = fopen(cert_file, "r");
|
| |
- + if (f == NULL) {
|
| |
- + st_logf("failed to open file %s\n", cert_file);
|
| |
- + return CKR_GENERAL_ERROR;
|
| |
- + }
|
| |
- +
|
| |
- + cert = PEM_read_X509(f, NULL, NULL, NULL);
|
| |
- + fclose(f);
|
| |
- + if (cert == NULL) {
|
| |
- + st_logf("failed reading PEM cert\n");
|
| |
- + return CKR_GENERAL_ERROR;
|
| |
- + }
|
| |
- +
|
| |
- + OPENSSL_ASN1_MALLOC_ENCODE(X509, cert_data, cert_length, cert, ret);
|
| |
- + if (ret)
|
| |
- + goto out;
|
| |
- +
|
| |
- + OPENSSL_ASN1_MALLOC_ENCODE(X509_NAME, issuer_data, issuer_length,
|
| |
- + X509_get_issuer_name(cert), ret);
|
| |
- + if (ret)
|
| |
- + goto out;
|
| |
- +
|
| |
- + OPENSSL_ASN1_MALLOC_ENCODE(X509_NAME, subject_data, subject_length,
|
| |
- + X509_get_subject_name(cert), ret);
|
| |
- + if (ret)
|
| |
- + goto out;
|
| |
- +
|
| |
- + OPENSSL_ASN1_MALLOC_ENCODE(ASN1_INTEGER, serial_data, serial_length,
|
| |
- + X509_get_serialNumber(cert), ret);
|
| |
- + if (ret)
|
| |
- + goto out;
|
| |
- +
|
| |
- + }
|
| |
- +
|
| |
- + st_logf("done parsing, adding to internal structure\n");
|
| |
- +
|
| |
- + o = add_st_object();
|
| |
- + if (o == NULL) {
|
| |
- + ret = CKR_DEVICE_MEMORY;
|
| |
- + goto out;
|
| |
- + }
|
| |
- + o->type = STO_T_CERTIFICATE;
|
| |
- + o->u.cert = cert;
|
| |
- + public_key = X509_get_pubkey(o->u.cert);
|
| |
- +
|
| |
- + switch (EVP_PKEY_base_id(public_key)) {
|
| |
- + case EVP_PKEY_RSA:
|
| |
- + key_type = CKK_RSA;
|
| |
- + break;
|
| |
- + case EVP_PKEY_DSA:
|
| |
- + key_type = CKK_DSA;
|
| |
- + break;
|
| |
- + default:
|
| |
- + /* XXX */
|
| |
- + break;
|
| |
- + }
|
| |
- +
|
| |
- + c = CKO_CERTIFICATE;
|
| |
- + add_object_attribute(o, 0, CKA_CLASS, &c, sizeof(c));
|
| |
- + add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
|
| |
- + add_object_attribute(o, 0, CKA_PRIVATE, &bool_false, sizeof(bool_false));
|
| |
- + add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
|
| |
- + add_object_attribute(o, 0, CKA_LABEL, label, strlen(label));
|
| |
- +
|
| |
- + add_object_attribute(o, 0, CKA_CERTIFICATE_TYPE, &cert_type, sizeof(cert_type));
|
| |
- + add_object_attribute(o, 0, CKA_ID, id, id_len);
|
| |
- +
|
| |
- + add_object_attribute(o, 0, CKA_SUBJECT, subject_data, subject_length);
|
| |
- + add_object_attribute(o, 0, CKA_ISSUER, issuer_data, issuer_length);
|
| |
- + add_object_attribute(o, 0, CKA_SERIAL_NUMBER, serial_data, serial_length);
|
| |
- + add_object_attribute(o, 0, CKA_VALUE, cert_data, cert_length);
|
| |
- + if (anchor)
|
| |
- + add_object_attribute(o, 0, CKA_TRUSTED, &bool_true, sizeof(bool_true));
|
| |
- + else
|
| |
- + add_object_attribute(o, 0, CKA_TRUSTED, &bool_false, sizeof(bool_false));
|
| |
- +
|
| |
- + st_logf("add cert ok: %lx\n", (unsigned long)OBJECT_ID(o));
|
| |
- +
|
| |
- + o = add_st_object();
|
| |
- + if (o == NULL) {
|
| |
- + ret = CKR_DEVICE_MEMORY;
|
| |
- + goto out;
|
| |
- + }
|
| |
- + o->type = STO_T_PUBLIC_KEY;
|
| |
- + o->u.public_key = public_key;
|
| |
- +
|
| |
- + c = CKO_PUBLIC_KEY;
|
| |
- + add_object_attribute(o, 0, CKA_CLASS, &c, sizeof(c));
|
| |
- + add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
|
| |
- + add_object_attribute(o, 0, CKA_PRIVATE, &bool_false, sizeof(bool_false));
|
| |
- + add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
|
| |
- + add_object_attribute(o, 0, CKA_LABEL, label, strlen(label));
|
| |
- +
|
| |
- + add_object_attribute(o, 0, CKA_KEY_TYPE, &key_type, sizeof(key_type));
|
| |
- + add_object_attribute(o, 0, CKA_ID, id, id_len);
|
| |
- + add_object_attribute(o, 0, CKA_START_DATE, "", 1); /* XXX */
|
| |
- + add_object_attribute(o, 0, CKA_END_DATE, "", 1); /* XXX */
|
| |
- + add_object_attribute(o, 0, CKA_DERIVE, &bool_false, sizeof(bool_false));
|
| |
- + add_object_attribute(o, 0, CKA_LOCAL, &bool_false, sizeof(bool_false));
|
| |
- + mech_type = CKM_RSA_X_509;
|
| |
- + add_object_attribute(o, 0, CKA_KEY_GEN_MECHANISM, &mech_type, sizeof(mech_type));
|
| |
- +
|
| |
- + add_object_attribute(o, 0, CKA_SUBJECT, subject_data, subject_length);
|
| |
- + add_object_attribute(o, 0, CKA_ENCRYPT, &bool_true, sizeof(bool_true));
|
| |
- + add_object_attribute(o, 0, CKA_VERIFY, &bool_true, sizeof(bool_true));
|
| |
- + add_object_attribute(o, 0, CKA_VERIFY_RECOVER, &bool_false, sizeof(bool_false));
|
| |
- + add_object_attribute(o, 0, CKA_WRAP, &bool_true, sizeof(bool_true));
|
| |
- + add_object_attribute(o, 0, CKA_TRUSTED, &bool_true, sizeof(bool_true));
|
| |
- +
|
| |
- + add_pubkey_info(o, key_type, public_key);
|
| |
- +
|
| |
- + st_logf("add key ok: %lx\n", (unsigned long)OBJECT_ID(o));
|
| |
- +
|
| |
- + if (private_key_file) {
|
| |
- + CK_FLAGS flags;
|
| |
- + FILE *f;
|
| |
- +
|
| |
- + o = add_st_object();
|
| |
- + if (o == NULL) {
|
| |
- + ret = CKR_DEVICE_MEMORY;
|
| |
- + goto out;
|
| |
- + }
|
| |
- + o->type = STO_T_PRIVATE_KEY;
|
| |
- + o->u.private_key.file = strdup(private_key_file);
|
| |
- + o->u.private_key.key = NULL;
|
| |
- +
|
| |
- + o->u.private_key.cert = cert;
|
| |
- +
|
| |
- + c = CKO_PRIVATE_KEY;
|
| |
- + add_object_attribute(o, 0, CKA_CLASS, &c, sizeof(c));
|
| |
- + add_object_attribute(o, 0, CKA_TOKEN, &bool_true, sizeof(bool_true));
|
| |
- + add_object_attribute(o, 0, CKA_PRIVATE, &bool_true, sizeof(bool_false));
|
| |
- + add_object_attribute(o, 0, CKA_MODIFIABLE, &bool_false, sizeof(bool_false));
|
| |
- + add_object_attribute(o, 0, CKA_LABEL, label, strlen(label));
|
| |
- +
|
| |
- + add_object_attribute(o, 0, CKA_KEY_TYPE, &key_type, sizeof(key_type));
|
| |
- + add_object_attribute(o, 0, CKA_ID, id, id_len);
|
| |
- + add_object_attribute(o, 0, CKA_START_DATE, "", 1); /* XXX */
|
| |
- + add_object_attribute(o, 0, CKA_END_DATE, "", 1); /* XXX */
|
| |
- + add_object_attribute(o, 0, CKA_DERIVE, &bool_false, sizeof(bool_false));
|
| |
- + add_object_attribute(o, 0, CKA_LOCAL, &bool_false, sizeof(bool_false));
|
| |
- + mech_type = CKM_RSA_X_509;
|
| |
- + add_object_attribute(o, 0, CKA_KEY_GEN_MECHANISM, &mech_type, sizeof(mech_type));
|
| |
- +
|
| |
- + add_object_attribute(o, 0, CKA_SUBJECT, subject_data, subject_length);
|
| |
- + add_object_attribute(o, 0, CKA_SENSITIVE, &bool_true, sizeof(bool_true));
|
| |
- + add_object_attribute(o, 0, CKA_SECONDARY_AUTH, &bool_false, sizeof(bool_true));
|
| |
- + flags = 0;
|
| |
- + add_object_attribute(o, 0, CKA_AUTH_PIN_FLAGS, &flags, sizeof(flags));
|
| |
- +
|
| |
- + add_object_attribute(o, 0, CKA_DECRYPT, &bool_true, sizeof(bool_true));
|
| |
- + add_object_attribute(o, 0, CKA_SIGN, &bool_true, sizeof(bool_true));
|
| |
- + add_object_attribute(o, 0, CKA_SIGN_RECOVER, &bool_false, sizeof(bool_false));
|
| |
- + add_object_attribute(o, 0, CKA_UNWRAP, &bool_true, sizeof(bool_true));
|
| |
- + add_object_attribute(o, 0, CKA_EXTRACTABLE, &bool_true, sizeof(bool_true));
|
| |
- + add_object_attribute(o, 0, CKA_NEVER_EXTRACTABLE, &bool_false, sizeof(bool_false));
|
| |
- +
|
| |
- + add_pubkey_info(o, key_type, public_key);
|
| |
- +
|
| |
- + f = fopen(private_key_file, "r");
|
| |
- + if (f == NULL) {
|
| |
- + st_logf("failed to open private key\n");
|
| |
- + return CKR_GENERAL_ERROR;
|
| |
- + }
|
| |
- +
|
| |
- + o->u.private_key.key = PEM_read_PrivateKey(f, NULL, pem_callback, NULL);
|
| |
- + fclose(f);
|
| |
- + if (o->u.private_key.key == NULL) {
|
| |
- + st_logf("failed to read private key a startup\n");
|
| |
- + /* don't bother with this failure for now,
|
| |
- + fix it at C_Login time */;
|
| |
- + } else {
|
| |
- + /* XXX verify keytype */
|
| |
- +
|
| |
- + if (key_type == CKK_RSA) {
|
| |
- + RSA *rsa = EVP_PKEY_get0_RSA(o->u.private_key.key);
|
| |
- + RSA_set_method(rsa, RSA_PKCS1_OpenSSL());
|
| |
- + }
|
| |
- +
|
| |
- + if (X509_check_private_key(cert, o->u.private_key.key) != 1) {
|
| |
- + EVP_PKEY_free(o->u.private_key.key);
|
| |
- + o->u.private_key.key = NULL;
|
| |
- + st_logf("private key doesn't verify\n");
|
| |
- + } else {
|
| |
- + st_logf("private key usable\n");
|
| |
- + soft_token.flags.login_done = 1;
|
| |
- + }
|
| |
- + }
|
| |
- + }
|
| |
- +
|
| |
- + ret = CKR_OK;
|
| |
- + out:
|
| |
- + if (ret != CKR_OK) {
|
| |
- + st_logf("something went wrong when adding cert!\n");
|
| |
- +
|
| |
- + /* XXX wack o */;
|
| |
- + }
|
| |
- + free(cert_data);
|
| |
- + free(serial_data);
|
| |
- + free(issuer_data);
|
| |
- + free(subject_data);
|
| |
- +
|
| |
- + return ret;
|
| |
- +}
|
| |
- +
|
| |
- +static void
|
| |
- +find_object_final(struct session_state *state)
|
| |
- +{
|
| |
- + if (state->find.attributes) {
|
| |
- + CK_ULONG i;
|
| |
- +
|
| |
- + for (i = 0; i < state->find.num_attributes; i++) {
|
| |
- + if (state->find.attributes[i].pValue)
|
| |
- + free(state->find.attributes[i].pValue);
|
| |
- + }
|
| |
- + free(state->find.attributes);
|
| |
- + state->find.attributes = NULL;
|
| |
- + state->find.num_attributes = 0;
|
| |
- + state->find.next_object = -1;
|
| |
- + }
|
| |
- +}
|
| |
- +
|
| |
- +static void
|
| |
- +reset_crypto_state(struct session_state *state)
|
| |
- +{
|
| |
- + state->encrypt_object = -1;
|
| |
- + if (state->encrypt_mechanism)
|
| |
- + free(state->encrypt_mechanism);
|
| |
- + state->encrypt_mechanism = NULL_PTR;
|
| |
- + state->decrypt_object = -1;
|
| |
- + if (state->decrypt_mechanism)
|
| |
- + free(state->decrypt_mechanism);
|
| |
- + state->decrypt_mechanism = NULL_PTR;
|
| |
- + state->sign_object = -1;
|
| |
- + if (state->sign_mechanism)
|
| |
- + free(state->sign_mechanism);
|
| |
- + state->sign_mechanism = NULL_PTR;
|
| |
- + state->verify_object = -1;
|
| |
- + if (state->verify_mechanism)
|
| |
- + free(state->verify_mechanism);
|
| |
- + state->verify_mechanism = NULL_PTR;
|
| |
- + state->digest_object = -1;
|
| |
- +}
|
| |
- +
|
| |
- +static void
|
| |
- +close_session(struct session_state *state)
|
| |
- +{
|
| |
- + if (state->find.attributes) {
|
| |
- + application_error("application didn't do C_FindObjectsFinal\n");
|
| |
- + find_object_final(state);
|
| |
- + }
|
| |
- +
|
| |
- + state->session_handle = CK_INVALID_HANDLE;
|
| |
- + soft_token.application = NULL_PTR;
|
| |
- + soft_token.notify = NULL_PTR;
|
| |
- + reset_crypto_state(state);
|
| |
- +}
|
| |
- +
|
| |
- +static const char *
|
| |
- +has_session(void)
|
| |
- +{
|
| |
- + return soft_token.open_sessions > 0 ? "yes" : "no";
|
| |
- +}
|
| |
- +
|
| |
- +static void
|
| |
- +read_conf_file(const char *fn)
|
| |
- +{
|
| |
- + char buf[1024], *cert, *key, *id, *label, *s, *p;
|
| |
- + int anchor;
|
| |
- + FILE *f;
|
| |
- +
|
| |
- + f = fopen(fn, "r");
|
| |
- + if (f == NULL) {
|
| |
- + st_logf("can't open configuration file %s\n", fn);
|
| |
- + return;
|
| |
- + }
|
| |
- +
|
| |
- + while(fgets(buf, sizeof(buf), f) != NULL) {
|
| |
- + buf[strcspn(buf, "\n")] = '\0';
|
| |
- +
|
| |
- + anchor = 0;
|
| |
- +
|
| |
- + st_logf("line: %s\n", buf);
|
| |
- +
|
| |
- + p = buf;
|
| |
- + while (isspace(*p))
|
| |
- + p++;
|
| |
- + if (*p == '#')
|
| |
- + continue;
|
| |
- + while (isspace(*p))
|
| |
- + p++;
|
| |
- +
|
| |
- + s = NULL;
|
| |
- + id = strtok_r(p, "\t", &s);
|
| |
- + if (id == NULL)
|
| |
- + continue;
|
| |
- + label = strtok_r(NULL, "\t", &s);
|
| |
- + if (label == NULL)
|
| |
- + continue;
|
| |
- + cert = strtok_r(NULL, "\t", &s);
|
| |
- + if (cert == NULL)
|
| |
- + continue;
|
| |
- + key = strtok_r(NULL, "\t", &s);
|
| |
- +
|
| |
- + /* XXX */
|
| |
- + if (strcmp(id, "anchor") == 0) {
|
| |
- + id = "\x00\x00";
|
| |
- + anchor = 1;
|
| |
- + }
|
| |
- +
|
| |
- + st_logf("adding: %s\n", label);
|
| |
- +
|
| |
- + add_certificate(label, cert, key, id, anchor);
|
| |
- + }
|
| |
- +}
|
| |
- +
|
| |
- +static CK_RV
|
| |
- +func_not_supported(void)
|
| |
- +{
|
| |
- + st_logf("function not supported\n");
|
| |
- + return CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_Initialize(CK_VOID_PTR a)
|
| |
- +{
|
| |
- + CK_C_INITIALIZE_ARGS_PTR args = a;
|
| |
- + st_logf("Initialize\n");
|
| |
- + size_t i;
|
| |
- +
|
| |
- + OpenSSL_add_all_algorithms();
|
| |
- + ERR_load_crypto_strings();
|
| |
- +
|
| |
- + srandom(getpid() ^ time(NULL));
|
| |
- +
|
| |
- + for (i = 0; i < MAX_NUM_SESSION; i++) {
|
| |
- + soft_token.state[i].session_handle = CK_INVALID_HANDLE;
|
| |
- + soft_token.state[i].find.attributes = NULL;
|
| |
- + soft_token.state[i].find.num_attributes = 0;
|
| |
- + soft_token.state[i].find.next_object = -1;
|
| |
- + reset_crypto_state(&soft_token.state[i]);
|
| |
- + }
|
| |
- +
|
| |
- + soft_token.flags.hardware_slot = 1;
|
| |
- + soft_token.flags.app_error_fatal = 0;
|
| |
- + soft_token.flags.login_done = 0;
|
| |
- +
|
| |
- + soft_token.object.objs = NULL;
|
| |
- + soft_token.object.num_objs = 0;
|
| |
- +
|
| |
- + soft_token.logfile = NULL;
|
| |
- +#if 1
|
| |
- +// soft_token.logfile = stdout;
|
| |
- +#endif
|
| |
- +#if 0
|
| |
- + soft_token.logfile = fopen("/tmp/log-pkcs11.txt", "a");
|
| |
- +#endif
|
| |
- +
|
| |
- + if (a != NULL_PTR) {
|
| |
- + st_logf("\tCreateMutex:\t%p\n", args->CreateMutex);
|
| |
- + st_logf("\tDestroyMutext\t%p\n", args->DestroyMutex);
|
| |
- + st_logf("\tLockMutext\t%p\n", args->LockMutex);
|
| |
- + st_logf("\tUnlockMutext\t%p\n", args->UnlockMutex);
|
| |
- + st_logf("\tFlags\t%04x\n", (unsigned int)args->flags);
|
| |
- + }
|
| |
- +
|
| |
- + {
|
| |
- + char *fn = NULL, *home = NULL;
|
| |
- +
|
| |
- + if (getuid() == geteuid()) {
|
| |
- + fn = getenv("SOFTPKCS11RC");
|
| |
- + if (fn)
|
| |
- + fn = strdup(fn);
|
| |
- + home = getenv("HOME");
|
| |
- + }
|
| |
- + if (fn == NULL && home == NULL) {
|
| |
- + struct passwd *pw = getpwuid(getuid());
|
| |
- + if(pw != NULL)
|
| |
- + home = pw->pw_dir;
|
| |
- + }
|
| |
- + if (fn == NULL) {
|
| |
- + if (home)
|
| |
- + asprintf(&fn, "%s/.soft-token.rc", home);
|
| |
- + else
|
| |
- + fn = strdup("/etc/soft-token.rc");
|
| |
- + }
|
| |
- +
|
| |
- + read_conf_file(fn);
|
| |
- + free(fn);
|
| |
- + }
|
| |
- +
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_Finalize(CK_VOID_PTR args)
|
| |
- +{
|
| |
- + size_t i;
|
| |
- +
|
| |
- + st_logf("Finalize\n");
|
| |
- +
|
| |
- + for (i = 0; i < MAX_NUM_SESSION; i++) {
|
| |
- + if (soft_token.state[i].session_handle != CK_INVALID_HANDLE) {
|
| |
- + application_error("application finalized without "
|
| |
- + "closing session\n");
|
| |
- + close_session(&soft_token.state[i]);
|
| |
- + }
|
| |
- + }
|
| |
- +
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_GetInfo(CK_INFO_PTR args)
|
| |
- +{
|
| |
- + st_logf("GetInfo\n");
|
| |
- +
|
| |
- + memset(args, 17, sizeof(*args));
|
| |
- + args->cryptokiVersion.major = 2;
|
| |
- + args->cryptokiVersion.minor = 10;
|
| |
- + snprintf_fill((char *)args->manufacturerID,
|
| |
- + sizeof(args->manufacturerID),
|
| |
- + ' ',
|
| |
- + "SoftToken");
|
| |
- + snprintf_fill((char *)args->libraryDescription,
|
| |
- + sizeof(args->libraryDescription), ' ',
|
| |
- + "SoftToken");
|
| |
- + args->libraryVersion.major = 1;
|
| |
- + args->libraryVersion.minor = 8;
|
| |
- +
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +extern CK_FUNCTION_LIST funcs;
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_GetFunctionList(CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
|
| |
- +{
|
| |
- + *ppFunctionList = &funcs;
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_GetSlotList(CK_BBOOL tokenPresent,
|
| |
- + CK_SLOT_ID_PTR pSlotList,
|
| |
- + CK_ULONG_PTR pulCount)
|
| |
- +{
|
| |
- + st_logf("GetSlotList: %s\n",
|
| |
- + tokenPresent ? "tokenPresent" : "token not Present");
|
| |
- + if (pSlotList)
|
| |
- + pSlotList[0] = 1;
|
| |
- + *pulCount = 1;
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_GetSlotInfo(CK_SLOT_ID slotID,
|
| |
- + CK_SLOT_INFO_PTR pInfo)
|
| |
- +{
|
| |
- + st_logf("GetSlotInfo: slot: %d : %s\n", (int)slotID, has_session());
|
| |
- +
|
| |
- + memset(pInfo, 18, sizeof(*pInfo));
|
| |
- +
|
| |
- + if (slotID != 1)
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- +
|
| |
- + snprintf_fill((char *)pInfo->slotDescription,
|
| |
- + sizeof(pInfo->slotDescription),
|
| |
- + ' ',
|
| |
- + "SoftToken (slot)");
|
| |
- + snprintf_fill((char *)pInfo->manufacturerID,
|
| |
- + sizeof(pInfo->manufacturerID),
|
| |
- + ' ',
|
| |
- + "SoftToken (slot)");
|
| |
- + pInfo->flags = CKF_TOKEN_PRESENT;
|
| |
- + if (soft_token.flags.hardware_slot)
|
| |
- + pInfo->flags |= CKF_HW_SLOT;
|
| |
- + pInfo->hardwareVersion.major = 1;
|
| |
- + pInfo->hardwareVersion.minor = 0;
|
| |
- + pInfo->firmwareVersion.major = 1;
|
| |
- + pInfo->firmwareVersion.minor = 0;
|
| |
- +
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_GetTokenInfo(CK_SLOT_ID slotID,
|
| |
- + CK_TOKEN_INFO_PTR pInfo)
|
| |
- +{
|
| |
- + st_logf("GetTokenInfo: %s\n", has_session());
|
| |
- +
|
| |
- + memset(pInfo, 19, sizeof(*pInfo));
|
| |
- +
|
| |
- + snprintf_fill((char *)pInfo->label,
|
| |
- + sizeof(pInfo->label),
|
| |
- + ' ',
|
| |
- + "SoftToken (token)");
|
| |
- + snprintf_fill((char *)pInfo->manufacturerID,
|
| |
- + sizeof(pInfo->manufacturerID),
|
| |
- + ' ',
|
| |
- + "SoftToken (token)");
|
| |
- + snprintf_fill((char *)pInfo->model,
|
| |
- + sizeof(pInfo->model),
|
| |
- + ' ',
|
| |
- + "SoftToken (token)");
|
| |
- + snprintf_fill((char *)pInfo->serialNumber,
|
| |
- + sizeof(pInfo->serialNumber),
|
| |
- + ' ',
|
| |
- + "4711");
|
| |
- + pInfo->flags =
|
| |
- + CKF_TOKEN_INITIALIZED |
|
| |
- + CKF_USER_PIN_INITIALIZED;
|
| |
- +
|
| |
- + if (soft_token.flags.login_done == 0)
|
| |
- + pInfo->flags |= CKF_LOGIN_REQUIRED;
|
| |
- +
|
| |
- + /* CFK_RNG |
|
| |
- + CKF_RESTORE_KEY_NOT_NEEDED |
|
| |
- + */
|
| |
- + pInfo->ulMaxSessionCount = MAX_NUM_SESSION;
|
| |
- + pInfo->ulSessionCount = soft_token.open_sessions;
|
| |
- + pInfo->ulMaxRwSessionCount = MAX_NUM_SESSION;
|
| |
- + pInfo->ulRwSessionCount = soft_token.open_sessions;
|
| |
- + pInfo->ulMaxPinLen = 1024;
|
| |
- + pInfo->ulMinPinLen = 0;
|
| |
- + pInfo->ulTotalPublicMemory = 4711;
|
| |
- + pInfo->ulFreePublicMemory = 4712;
|
| |
- + pInfo->ulTotalPrivateMemory = 4713;
|
| |
- + pInfo->ulFreePrivateMemory = 4714;
|
| |
- + pInfo->hardwareVersion.major = 2;
|
| |
- + pInfo->hardwareVersion.minor = 0;
|
| |
- + pInfo->firmwareVersion.major = 2;
|
| |
- + pInfo->firmwareVersion.minor = 0;
|
| |
- +
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_GetMechanismList(CK_SLOT_ID slotID,
|
| |
- + CK_MECHANISM_TYPE_PTR pMechanismList,
|
| |
- + CK_ULONG_PTR pulCount)
|
| |
- +{
|
| |
- + st_logf("GetMechanismList\n");
|
| |
- +
|
| |
- + *pulCount = 2;
|
| |
- + if (pMechanismList == NULL_PTR)
|
| |
- + return CKR_OK;
|
| |
- + pMechanismList[0] = CKM_RSA_X_509;
|
| |
- + pMechanismList[1] = CKM_RSA_PKCS;
|
| |
- +
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_GetMechanismInfo(CK_SLOT_ID slotID,
|
| |
- + CK_MECHANISM_TYPE type,
|
| |
- + CK_MECHANISM_INFO_PTR pInfo)
|
| |
- +{
|
| |
- + st_logf("GetMechanismInfo: slot %d type: %d\n",
|
| |
- + (int)slotID, (int)type);
|
| |
- + return CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_InitToken(CK_SLOT_ID slotID,
|
| |
- + CK_UTF8CHAR_PTR pPin,
|
| |
- + CK_ULONG ulPinLen,
|
| |
- + CK_UTF8CHAR_PTR pLabel)
|
| |
- +{
|
| |
- + st_logf("InitToken: slot %d\n", (int)slotID);
|
| |
- + return CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_OpenSession(CK_SLOT_ID slotID,
|
| |
- + CK_FLAGS flags,
|
| |
- + CK_VOID_PTR pApplication,
|
| |
- + CK_NOTIFY Notify,
|
| |
- + CK_SESSION_HANDLE_PTR phSession)
|
| |
- +{
|
| |
- + size_t i;
|
| |
- +
|
| |
- + st_logf("OpenSession: slot: %d\n", (int)slotID);
|
| |
- +
|
| |
- + if (soft_token.open_sessions == MAX_NUM_SESSION)
|
| |
- + return CKR_SESSION_COUNT;
|
| |
- +
|
| |
- + soft_token.application = pApplication;
|
| |
- + soft_token.notify = Notify;
|
| |
- +
|
| |
- + for (i = 0; i < MAX_NUM_SESSION; i++)
|
| |
- + if (soft_token.state[i].session_handle == CK_INVALID_HANDLE)
|
| |
- + break;
|
| |
- + if (i == MAX_NUM_SESSION)
|
| |
- + abort();
|
| |
- +
|
| |
- + soft_token.open_sessions++;
|
| |
- +
|
| |
- + soft_token.state[i].session_handle =
|
| |
- + (CK_SESSION_HANDLE)(random() & 0xfffff);
|
| |
- + *phSession = soft_token.state[i].session_handle;
|
| |
- +
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_CloseSession(CK_SESSION_HANDLE hSession)
|
| |
- +{
|
| |
- + struct session_state *state;
|
| |
- + st_logf("CloseSession\n");
|
| |
- +
|
| |
- + if (verify_session_handle(hSession, &state) != CKR_OK)
|
| |
- + application_error("closed session not open");
|
| |
- + else
|
| |
- + close_session(state);
|
| |
- +
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_CloseAllSessions(CK_SLOT_ID slotID)
|
| |
- +{
|
| |
- + size_t i;
|
| |
- +
|
| |
- + st_logf("CloseAllSessions\n");
|
| |
- +
|
| |
- + for (i = 0; i < MAX_NUM_SESSION; i++)
|
| |
- + if (soft_token.state[i].session_handle != CK_INVALID_HANDLE)
|
| |
- + close_session(&soft_token.state[i]);
|
| |
- +
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_GetSessionInfo(CK_SESSION_HANDLE hSession,
|
| |
- + CK_SESSION_INFO_PTR pInfo)
|
| |
- +{
|
| |
- + st_logf("GetSessionInfo\n");
|
| |
- +
|
| |
- + VERIFY_SESSION_HANDLE(hSession, NULL);
|
| |
- +
|
| |
- + memset(pInfo, 20, sizeof(*pInfo));
|
| |
- +
|
| |
- + pInfo->slotID = 1;
|
| |
- + if (soft_token.flags.login_done)
|
| |
- + pInfo->state = CKS_RO_USER_FUNCTIONS;
|
| |
- + else
|
| |
- + pInfo->state = CKS_RO_PUBLIC_SESSION;
|
| |
- + pInfo->flags = CKF_SERIAL_SESSION;
|
| |
- + pInfo->ulDeviceError = 0;
|
| |
- +
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_Login(CK_SESSION_HANDLE hSession,
|
| |
- + CK_USER_TYPE userType,
|
| |
- + CK_UTF8CHAR_PTR pPin,
|
| |
- + CK_ULONG ulPinLen)
|
| |
- +{
|
| |
- + char *pin = NULL;
|
| |
- + int i;
|
| |
- +
|
| |
- + st_logf("Login\n");
|
| |
- +
|
| |
- + VERIFY_SESSION_HANDLE(hSession, NULL);
|
| |
- +
|
| |
- + if (pPin != NULL_PTR) {
|
| |
- + asprintf(&pin, "%.*s", (int)ulPinLen, pPin);
|
| |
- + st_logf("type: %d password: %s\n", (int)userType, pin);
|
| |
- + }
|
| |
- +
|
| |
- + for (i = 0; i < soft_token.object.num_objs; i++) {
|
| |
- + struct st_object *o = soft_token.object.objs[i];
|
| |
- + FILE *f;
|
| |
- +
|
| |
- + if (o->type != STO_T_PRIVATE_KEY)
|
| |
- + continue;
|
| |
- +
|
| |
- + if (o->u.private_key.key)
|
| |
- + continue;
|
| |
- +
|
| |
- + f = fopen(o->u.private_key.file, "r");
|
| |
- + if (f == NULL) {
|
| |
- + st_logf("can't open private file: %s\n", o->u.private_key.file);
|
| |
- + continue;
|
| |
- + }
|
| |
- +
|
| |
- + o->u.private_key.key = PEM_read_PrivateKey(f, NULL, NULL, pin);
|
| |
- + fclose(f);
|
| |
- + if (o->u.private_key.key == NULL) {
|
| |
- + st_logf("failed to read key: %s error: %s\n",
|
| |
- + o->u.private_key.file,
|
| |
- + ERR_error_string(ERR_get_error(), NULL));
|
| |
- + /* just ignore failure */;
|
| |
- + continue;
|
| |
- + }
|
| |
- +
|
| |
- + /* XXX check keytype */
|
| |
- + RSA *rsa = EVP_PKEY_get0_RSA(o->u.private_key.key);
|
| |
- + RSA_set_method(rsa, RSA_PKCS1_OpenSSL());
|
| |
- +
|
| |
- + if (X509_check_private_key(o->u.private_key.cert, o->u.private_key.key) != 1) {
|
| |
- + EVP_PKEY_free(o->u.private_key.key);
|
| |
- + o->u.private_key.key = NULL;
|
| |
- + st_logf("private key %s doesn't verify\n", o->u.private_key.file);
|
| |
- + continue;
|
| |
- + }
|
| |
- +
|
| |
- + soft_token.flags.login_done = 1;
|
| |
- + }
|
| |
- + free(pin);
|
| |
- +
|
| |
- + return soft_token.flags.login_done ? CKR_OK : CKR_PIN_INCORRECT;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_Logout(CK_SESSION_HANDLE hSession)
|
| |
- +{
|
| |
- + st_logf("Logout\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, NULL);
|
| |
- + return CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_GetObjectSize(CK_SESSION_HANDLE hSession,
|
| |
- + CK_OBJECT_HANDLE hObject,
|
| |
- + CK_ULONG_PTR pulSize)
|
| |
- +{
|
| |
- + st_logf("GetObjectSize\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, NULL);
|
| |
- + return CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_GetAttributeValue(CK_SESSION_HANDLE hSession,
|
| |
- + CK_OBJECT_HANDLE hObject,
|
| |
- + CK_ATTRIBUTE_PTR pTemplate,
|
| |
- + CK_ULONG ulCount)
|
| |
- +{
|
| |
- + struct session_state *state;
|
| |
- + struct st_object *obj;
|
| |
- + CK_ULONG i;
|
| |
- + CK_RV ret;
|
| |
- + int j;
|
| |
- +
|
| |
- + st_logf("GetAttributeValue: %lx\n",
|
| |
- + (unsigned long)HANDLE_OBJECT_ID(hObject));
|
| |
- + VERIFY_SESSION_HANDLE(hSession, &state);
|
| |
- +
|
| |
- + if ((ret = object_handle_to_object(hObject, &obj)) != CKR_OK) {
|
| |
- + st_logf("object not found: %lx\n",
|
| |
- + (unsigned long)HANDLE_OBJECT_ID(hObject));
|
| |
- + return ret;
|
| |
- + }
|
| |
- +
|
| |
- + ret = CKR_OK;
|
| |
- + for (i = 0; i < ulCount; i++) {
|
| |
- + st_logf(" getting 0x%08lx\n", (unsigned long)pTemplate[i].type);
|
| |
- + for (j = 0; j < obj->num_attributes; j++) {
|
| |
- + if (obj->attrs[j].secret) {
|
| |
- + pTemplate[i].ulValueLen = (CK_ULONG)-1;
|
| |
- + break;
|
| |
- + }
|
| |
- + if (pTemplate[i].type == obj->attrs[j].attribute.type) {
|
| |
- + if (pTemplate[i].pValue != NULL_PTR && obj->attrs[j].secret == 0) {
|
| |
- + if (pTemplate[i].ulValueLen >= obj->attrs[j].attribute.ulValueLen)
|
| |
- + memcpy(pTemplate[i].pValue, obj->attrs[j].attribute.pValue,
|
| |
- + obj->attrs[j].attribute.ulValueLen);
|
| |
- + }
|
| |
- + pTemplate[i].ulValueLen = obj->attrs[j].attribute.ulValueLen;
|
| |
- + break;
|
| |
- + }
|
| |
- + }
|
| |
- + if (j == obj->num_attributes) {
|
| |
- + st_logf("key type: 0x%08lx not found\n", (unsigned long)pTemplate[i].type);
|
| |
- + pTemplate[i].ulValueLen = (CK_ULONG)-1;
|
| |
- + ret = CKR_ATTRIBUTE_TYPE_INVALID;
|
| |
- + }
|
| |
- +
|
| |
- + }
|
| |
- + return ret;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_FindObjectsInit(CK_SESSION_HANDLE hSession,
|
| |
- + CK_ATTRIBUTE_PTR pTemplate,
|
| |
- + CK_ULONG ulCount)
|
| |
- +{
|
| |
- + struct session_state *state;
|
| |
- +
|
| |
- + st_logf("FindObjectsInit\n");
|
| |
- +
|
| |
- + VERIFY_SESSION_HANDLE(hSession, &state);
|
| |
- +
|
| |
- + if (state->find.next_object != -1) {
|
| |
- + application_error("application didn't do C_FindObjectsFinal\n");
|
| |
- + find_object_final(state);
|
| |
- + }
|
| |
- + if (ulCount) {
|
| |
- + CK_ULONG i;
|
| |
- +
|
| |
- + print_attributes(pTemplate, ulCount);
|
| |
- +
|
| |
- + state->find.attributes =
|
| |
- + calloc(1, ulCount * sizeof(state->find.attributes[0]));
|
| |
- + if (state->find.attributes == NULL)
|
| |
- + return CKR_DEVICE_MEMORY;
|
| |
- + for (i = 0; i < ulCount; i++) {
|
| |
- + state->find.attributes[i].pValue =
|
| |
- + malloc(pTemplate[i].ulValueLen);
|
| |
- + if (state->find.attributes[i].pValue == NULL) {
|
| |
- + find_object_final(state);
|
| |
- + return CKR_DEVICE_MEMORY;
|
| |
- + }
|
| |
- + memcpy(state->find.attributes[i].pValue,
|
| |
- + pTemplate[i].pValue, pTemplate[i].ulValueLen);
|
| |
- + state->find.attributes[i].type = pTemplate[i].type;
|
| |
- + state->find.attributes[i].ulValueLen = pTemplate[i].ulValueLen;
|
| |
- + }
|
| |
- + state->find.num_attributes = ulCount;
|
| |
- + state->find.next_object = 0;
|
| |
- + } else {
|
| |
- + st_logf("find all objects\n");
|
| |
- + state->find.attributes = NULL;
|
| |
- + state->find.num_attributes = 0;
|
| |
- + state->find.next_object = 0;
|
| |
- + }
|
| |
- +
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_FindObjects(CK_SESSION_HANDLE hSession,
|
| |
- + CK_OBJECT_HANDLE_PTR phObject,
|
| |
- + CK_ULONG ulMaxObjectCount,
|
| |
- + CK_ULONG_PTR pulObjectCount)
|
| |
- +{
|
| |
- + struct session_state *state;
|
| |
- + int i;
|
| |
- +
|
| |
- + st_logf("FindObjects\n");
|
| |
- +
|
| |
- + VERIFY_SESSION_HANDLE(hSession, &state);
|
| |
- +
|
| |
- + if (state->find.next_object == -1) {
|
| |
- + application_error("application didn't do C_FindObjectsInit\n");
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- + }
|
| |
- + if (ulMaxObjectCount == 0) {
|
| |
- + application_error("application asked for 0 objects\n");
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- + }
|
| |
- + *pulObjectCount = 0;
|
| |
- + for (i = state->find.next_object; i < soft_token.object.num_objs; i++) {
|
| |
- + st_logf("FindObjects: %d\n", i);
|
| |
- + state->find.next_object = i + 1;
|
| |
- + if (attributes_match(soft_token.object.objs[i],
|
| |
- + state->find.attributes,
|
| |
- + state->find.num_attributes)) {
|
| |
- + *phObject++ = soft_token.object.objs[i]->object_handle;
|
| |
- + ulMaxObjectCount--;
|
| |
- + (*pulObjectCount)++;
|
| |
- + if (ulMaxObjectCount == 0)
|
| |
- + break;
|
| |
- + }
|
| |
- + }
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_FindObjectsFinal(CK_SESSION_HANDLE hSession)
|
| |
- +{
|
| |
- + struct session_state *state;
|
| |
- +
|
| |
- + st_logf("FindObjectsFinal\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, &state);
|
| |
- + find_object_final(state);
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +static CK_RV
|
| |
- +commonInit(CK_ATTRIBUTE *attr_match, int attr_match_len,
|
| |
- + const CK_MECHANISM_TYPE *mechs, int mechs_len,
|
| |
- + const CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey,
|
| |
- + struct st_object **o)
|
| |
- +{
|
| |
- + CK_RV ret;
|
| |
- + int i;
|
| |
- +
|
| |
- + *o = NULL;
|
| |
- + if ((ret = object_handle_to_object(hKey, o)) != CKR_OK)
|
| |
- + return ret;
|
| |
- +
|
| |
- + ret = attributes_match(*o, attr_match, attr_match_len);
|
| |
- + if (!ret) {
|
| |
- + application_error("called commonInit on key that doesn't "
|
| |
- + "support required attr");
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- + }
|
| |
- +
|
| |
- + for (i = 0; i < mechs_len; i++)
|
| |
- + if (mechs[i] == pMechanism->mechanism)
|
| |
- + break;
|
| |
- + if (i == mechs_len) {
|
| |
- + application_error("called mech (%08lx) not supported\n",
|
| |
- + pMechanism->mechanism);
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- + }
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +
|
| |
- +static CK_RV
|
| |
- +dup_mechanism(CK_MECHANISM_PTR *dup, const CK_MECHANISM_PTR pMechanism)
|
| |
- +{
|
| |
- + CK_MECHANISM_PTR p;
|
| |
- +
|
| |
- + p = malloc(sizeof(*p));
|
| |
- + if (p == NULL)
|
| |
- + return CKR_DEVICE_MEMORY;
|
| |
- +
|
| |
- + if (*dup)
|
| |
- + free(*dup);
|
| |
- + *dup = p;
|
| |
- + memcpy(p, pMechanism, sizeof(*p));
|
| |
- +
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_EncryptInit(CK_SESSION_HANDLE hSession,
|
| |
- + CK_MECHANISM_PTR pMechanism,
|
| |
- + CK_OBJECT_HANDLE hKey)
|
| |
- +{
|
| |
- + struct session_state *state;
|
| |
- + CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS, CKM_RSA_X_509 };
|
| |
- + CK_BBOOL bool_true = CK_TRUE;
|
| |
- + CK_ATTRIBUTE attr[] = {
|
| |
- + { CKA_ENCRYPT, &bool_true, sizeof(bool_true) }
|
| |
- + };
|
| |
- + struct st_object *o;
|
| |
- + CK_RV ret;
|
| |
- +
|
| |
- + st_logf("EncryptInit\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, &state);
|
| |
- +
|
| |
- + ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]),
|
| |
- + mechs, sizeof(mechs)/sizeof(mechs[0]),
|
| |
- + pMechanism, hKey, &o);
|
| |
- + if (ret)
|
| |
- + return ret;
|
| |
- +
|
| |
- + ret = dup_mechanism(&state->encrypt_mechanism, pMechanism);
|
| |
- + if (ret == CKR_OK)
|
| |
- + state->encrypt_object = OBJECT_ID(o);
|
| |
- +
|
| |
- + return ret;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_Encrypt(CK_SESSION_HANDLE hSession,
|
| |
- + CK_BYTE_PTR pData,
|
| |
- + CK_ULONG ulDataLen,
|
| |
- + CK_BYTE_PTR pEncryptedData,
|
| |
- + CK_ULONG_PTR pulEncryptedDataLen)
|
| |
- +{
|
| |
- + struct session_state *state;
|
| |
- + struct st_object *o;
|
| |
- + void *buffer = NULL;
|
| |
- + CK_RV ret;
|
| |
- + RSA *rsa;
|
| |
- + int padding, len, buffer_len, padding_len;
|
| |
- +
|
| |
- + st_logf("Encrypt\n");
|
| |
- +
|
| |
- + VERIFY_SESSION_HANDLE(hSession, &state);
|
| |
- +
|
| |
- + if (state->encrypt_object == -1)
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- +
|
| |
- + o = soft_token.object.objs[state->encrypt_object];
|
| |
- +
|
| |
- + if (o->u.public_key == NULL) {
|
| |
- + st_logf("public key NULL\n");
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- + }
|
| |
- +
|
| |
- + rsa = EVP_PKEY_get0_RSA(o->u.public_key);
|
| |
- + if (rsa == NULL)
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- +
|
| |
- + RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */
|
| |
- +
|
| |
- + buffer_len = RSA_size(rsa);
|
| |
- +
|
| |
- + buffer = malloc(buffer_len);
|
| |
- + if (buffer == NULL) {
|
| |
- + ret = CKR_DEVICE_MEMORY;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + ret = CKR_OK;
|
| |
- + switch(state->encrypt_mechanism->mechanism) {
|
| |
- + case CKM_RSA_PKCS:
|
| |
- + padding = RSA_PKCS1_PADDING;
|
| |
- + padding_len = RSA_PKCS1_PADDING_SIZE;
|
| |
- + break;
|
| |
- + case CKM_RSA_X_509:
|
| |
- + padding = RSA_NO_PADDING;
|
| |
- + padding_len = 0;
|
| |
- + break;
|
| |
- + default:
|
| |
- + ret = CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + if (buffer_len + padding_len < (long) ulDataLen) {
|
| |
- + ret = CKR_ARGUMENTS_BAD;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + if (pulEncryptedDataLen == NULL) {
|
| |
- + st_logf("pulEncryptedDataLen NULL\n");
|
| |
- + ret = CKR_ARGUMENTS_BAD;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + if (pData == NULL_PTR) {
|
| |
- + st_logf("data NULL\n");
|
| |
- + ret = CKR_ARGUMENTS_BAD;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + len = RSA_public_encrypt(ulDataLen, pData, buffer, rsa, padding);
|
| |
- + if (len <= 0) {
|
| |
- + ret = CKR_DEVICE_ERROR;
|
| |
- + goto out;
|
| |
- + }
|
| |
- + if (len > buffer_len)
|
| |
- + abort();
|
| |
- +
|
| |
- + if (pEncryptedData != NULL_PTR)
|
| |
- + memcpy(pEncryptedData, buffer, len);
|
| |
- + *pulEncryptedDataLen = len;
|
| |
- +
|
| |
- + out:
|
| |
- + if (buffer) {
|
| |
- + memset(buffer, 0, buffer_len);
|
| |
- + free(buffer);
|
| |
- + }
|
| |
- + return ret;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_EncryptUpdate(CK_SESSION_HANDLE hSession,
|
| |
- + CK_BYTE_PTR pPart,
|
| |
- + CK_ULONG ulPartLen,
|
| |
- + CK_BYTE_PTR pEncryptedPart,
|
| |
- + CK_ULONG_PTR pulEncryptedPartLen)
|
| |
- +{
|
| |
- + st_logf("EncryptUpdate\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, NULL);
|
| |
- + return CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- +}
|
| |
- +
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_EncryptFinal(CK_SESSION_HANDLE hSession,
|
| |
- + CK_BYTE_PTR pLastEncryptedPart,
|
| |
- + CK_ULONG_PTR pulLastEncryptedPartLen)
|
| |
- +{
|
| |
- + st_logf("EncryptFinal\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, NULL);
|
| |
- + return CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- +}
|
| |
- +
|
| |
- +
|
| |
- +/* C_DecryptInit initializes a decryption operation. */
|
| |
- +CK_RV
|
| |
- +C_DecryptInit(CK_SESSION_HANDLE hSession,
|
| |
- + CK_MECHANISM_PTR pMechanism,
|
| |
- + CK_OBJECT_HANDLE hKey)
|
| |
- +{
|
| |
- + struct session_state *state;
|
| |
- + CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS, CKM_RSA_X_509 };
|
| |
- + CK_BBOOL bool_true = CK_TRUE;
|
| |
- + CK_ATTRIBUTE attr[] = {
|
| |
- + { CKA_DECRYPT, &bool_true, sizeof(bool_true) }
|
| |
- + };
|
| |
- + struct st_object *o;
|
| |
- + CK_RV ret;
|
| |
- +
|
| |
- + st_logf("DecryptInit\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, &state);
|
| |
- +
|
| |
- + ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]),
|
| |
- + mechs, sizeof(mechs)/sizeof(mechs[0]),
|
| |
- + pMechanism, hKey, &o);
|
| |
- + if (ret)
|
| |
- + return ret;
|
| |
- +
|
| |
- + ret = dup_mechanism(&state->decrypt_mechanism, pMechanism);
|
| |
- + if (ret == CKR_OK)
|
| |
- + state->decrypt_object = OBJECT_ID(o);
|
| |
- +
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_Decrypt(CK_SESSION_HANDLE hSession,
|
| |
- + CK_BYTE_PTR pEncryptedData,
|
| |
- + CK_ULONG ulEncryptedDataLen,
|
| |
- + CK_BYTE_PTR pData,
|
| |
- + CK_ULONG_PTR pulDataLen)
|
| |
- +{
|
| |
- + struct session_state *state;
|
| |
- + struct st_object *o;
|
| |
- + void *buffer = NULL;
|
| |
- + CK_RV ret;
|
| |
- + RSA *rsa;
|
| |
- + int padding, len, buffer_len, padding_len;
|
| |
- +
|
| |
- + st_logf("Decrypt\n");
|
| |
- +
|
| |
- + VERIFY_SESSION_HANDLE(hSession, &state);
|
| |
- +
|
| |
- + if (state->decrypt_object == -1)
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- +
|
| |
- + o = soft_token.object.objs[state->decrypt_object];
|
| |
- +
|
| |
- + if (o->u.private_key.key == NULL) {
|
| |
- + st_logf("private key NULL\n");
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- + }
|
| |
- +
|
| |
- + rsa = EVP_PKEY_get0_RSA(o->u.private_key.key);
|
| |
- + if (rsa == NULL)
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- +
|
| |
- + RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */
|
| |
- +
|
| |
- + buffer_len = RSA_size(rsa);
|
| |
- +
|
| |
- + buffer = malloc(buffer_len);
|
| |
- + if (buffer == NULL) {
|
| |
- + ret = CKR_DEVICE_MEMORY;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + ret = CKR_OK;
|
| |
- + switch(state->decrypt_mechanism->mechanism) {
|
| |
- + case CKM_RSA_PKCS:
|
| |
- + padding = RSA_PKCS1_PADDING;
|
| |
- + padding_len = RSA_PKCS1_PADDING_SIZE;
|
| |
- + break;
|
| |
- + case CKM_RSA_X_509:
|
| |
- + padding = RSA_NO_PADDING;
|
| |
- + padding_len = 0;
|
| |
- + break;
|
| |
- + default:
|
| |
- + ret = CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + if (buffer_len + padding_len < (long) ulEncryptedDataLen) {
|
| |
- + ret = CKR_ARGUMENTS_BAD;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + if (pulDataLen == NULL) {
|
| |
- + st_logf("pulDataLen NULL\n");
|
| |
- + ret = CKR_ARGUMENTS_BAD;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + if (pEncryptedData == NULL_PTR) {
|
| |
- + st_logf("data NULL\n");
|
| |
- + ret = CKR_ARGUMENTS_BAD;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + len = RSA_private_decrypt(ulEncryptedDataLen, pEncryptedData, buffer,
|
| |
- + rsa, padding);
|
| |
- + if (len <= 0) {
|
| |
- + ret = CKR_DEVICE_ERROR;
|
| |
- + goto out;
|
| |
- + }
|
| |
- + if (len > buffer_len)
|
| |
- + abort();
|
| |
- +
|
| |
- + if (pData != NULL_PTR)
|
| |
- + memcpy(pData, buffer, len);
|
| |
- + *pulDataLen = len;
|
| |
- +
|
| |
- + out:
|
| |
- + if (buffer) {
|
| |
- + memset(buffer, 0, buffer_len);
|
| |
- + free(buffer);
|
| |
- + }
|
| |
- + return ret;
|
| |
- +}
|
| |
- +
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_DecryptUpdate(CK_SESSION_HANDLE hSession,
|
| |
- + CK_BYTE_PTR pEncryptedPart,
|
| |
- + CK_ULONG ulEncryptedPartLen,
|
| |
- + CK_BYTE_PTR pPart,
|
| |
- + CK_ULONG_PTR pulPartLen)
|
| |
- +
|
| |
- +{
|
| |
- + st_logf("DecryptUpdate\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, NULL);
|
| |
- + return CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- +}
|
| |
- +
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_DecryptFinal(CK_SESSION_HANDLE hSession,
|
| |
- + CK_BYTE_PTR pLastPart,
|
| |
- + CK_ULONG_PTR pulLastPartLen)
|
| |
- +{
|
| |
- + st_logf("DecryptFinal\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, NULL);
|
| |
- + return CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_DigestInit(CK_SESSION_HANDLE hSession,
|
| |
- + CK_MECHANISM_PTR pMechanism)
|
| |
- +{
|
| |
- + st_logf("DigestInit\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, NULL);
|
| |
- + return CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_SignInit(CK_SESSION_HANDLE hSession,
|
| |
- + CK_MECHANISM_PTR pMechanism,
|
| |
- + CK_OBJECT_HANDLE hKey)
|
| |
- +{
|
| |
- + struct session_state *state;
|
| |
- + CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS, CKM_RSA_X_509 };
|
| |
- + CK_BBOOL bool_true = CK_TRUE;
|
| |
- + CK_ATTRIBUTE attr[] = {
|
| |
- + { CKA_SIGN, &bool_true, sizeof(bool_true) }
|
| |
- + };
|
| |
- + struct st_object *o;
|
| |
- + CK_RV ret;
|
| |
- +
|
| |
- + st_logf("SignInit\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, &state);
|
| |
- +
|
| |
- + ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]),
|
| |
- + mechs, sizeof(mechs)/sizeof(mechs[0]),
|
| |
- + pMechanism, hKey, &o);
|
| |
- + if (ret)
|
| |
- + return ret;
|
| |
- +
|
| |
- + ret = dup_mechanism(&state->sign_mechanism, pMechanism);
|
| |
- + if (ret == CKR_OK)
|
| |
- + state->sign_object = OBJECT_ID(o);
|
| |
- +
|
| |
- + return CKR_OK;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_Sign(CK_SESSION_HANDLE hSession,
|
| |
- + CK_BYTE_PTR pData,
|
| |
- + CK_ULONG ulDataLen,
|
| |
- + CK_BYTE_PTR pSignature,
|
| |
- + CK_ULONG_PTR pulSignatureLen)
|
| |
- +{
|
| |
- + struct session_state *state;
|
| |
- + struct st_object *o;
|
| |
- + void *buffer = NULL;
|
| |
- + CK_RV ret;
|
| |
- + RSA *rsa;
|
| |
- + int padding, len, buffer_len;
|
| |
- + size_t padding_len;
|
| |
- +
|
| |
- + st_logf("Sign\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, &state);
|
| |
- +
|
| |
- + if (state->sign_object == -1)
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- +
|
| |
- + o = soft_token.object.objs[state->sign_object];
|
| |
- +
|
| |
- + if (o->u.private_key.key == NULL) {
|
| |
- + st_logf("private key NULL\n");
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- + }
|
| |
- +
|
| |
- + rsa = EVP_PKEY_get0_RSA(o->u.private_key.key);
|
| |
- + if (rsa == NULL)
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- +
|
| |
- + RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */
|
| |
- +
|
| |
- + buffer_len = RSA_size(rsa);
|
| |
- +
|
| |
- + buffer = malloc(buffer_len);
|
| |
- + if (buffer == NULL) {
|
| |
- + ret = CKR_DEVICE_MEMORY;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + switch(state->sign_mechanism->mechanism) {
|
| |
- + case CKM_RSA_PKCS:
|
| |
- + padding = RSA_PKCS1_PADDING;
|
| |
- + padding_len = RSA_PKCS1_PADDING_SIZE;
|
| |
- + break;
|
| |
- + case CKM_RSA_X_509:
|
| |
- + padding = RSA_NO_PADDING;
|
| |
- + padding_len = 0;
|
| |
- + break;
|
| |
- + default:
|
| |
- + ret = CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + if ((size_t) buffer_len < ulDataLen + padding_len) {
|
| |
- + ret = CKR_ARGUMENTS_BAD;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + if (pulSignatureLen == NULL) {
|
| |
- + st_logf("signature len NULL\n");
|
| |
- + ret = CKR_ARGUMENTS_BAD;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + if (pData == NULL_PTR) {
|
| |
- + st_logf("data NULL\n");
|
| |
- + ret = CKR_ARGUMENTS_BAD;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + len = RSA_private_encrypt(ulDataLen, pData, buffer, rsa, padding);
|
| |
- + st_logf("private encrypt done\n");
|
| |
- + if (len <= 0) {
|
| |
- + ret = CKR_DEVICE_ERROR;
|
| |
- + goto out;
|
| |
- + }
|
| |
- + if (len > buffer_len)
|
| |
- + abort();
|
| |
- +
|
| |
- + if (pSignature != NULL_PTR)
|
| |
- + memcpy(pSignature, buffer, len);
|
| |
- + *pulSignatureLen = len;
|
| |
- +
|
| |
- + ret = CKR_OK;
|
| |
- +
|
| |
- + out:
|
| |
- + if (buffer) {
|
| |
- + memset(buffer, 0, buffer_len);
|
| |
- + free(buffer);
|
| |
- + }
|
| |
- + return ret;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_SignUpdate(CK_SESSION_HANDLE hSession,
|
| |
- + CK_BYTE_PTR pPart,
|
| |
- + CK_ULONG ulPartLen)
|
| |
- +{
|
| |
- + st_logf("SignUpdate\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, NULL);
|
| |
- + return CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- +}
|
| |
- +
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_SignFinal(CK_SESSION_HANDLE hSession,
|
| |
- + CK_BYTE_PTR pSignature,
|
| |
- + CK_ULONG_PTR pulSignatureLen)
|
| |
- +{
|
| |
- + st_logf("SignUpdate\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, NULL);
|
| |
- + return CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_VerifyInit(CK_SESSION_HANDLE hSession,
|
| |
- + CK_MECHANISM_PTR pMechanism,
|
| |
- + CK_OBJECT_HANDLE hKey)
|
| |
- +{
|
| |
- + struct session_state *state;
|
| |
- + CK_MECHANISM_TYPE mechs[] = { CKM_RSA_PKCS, CKM_RSA_X_509 };
|
| |
- + CK_BBOOL bool_true = CK_TRUE;
|
| |
- + CK_ATTRIBUTE attr[] = {
|
| |
- + { CKA_VERIFY, &bool_true, sizeof(bool_true) }
|
| |
- + };
|
| |
- + struct st_object *o;
|
| |
- + CK_RV ret;
|
| |
- +
|
| |
- + st_logf("VerifyInit\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, &state);
|
| |
- +
|
| |
- + ret = commonInit(attr, sizeof(attr)/sizeof(attr[0]),
|
| |
- + mechs, sizeof(mechs)/sizeof(mechs[0]),
|
| |
- + pMechanism, hKey, &o);
|
| |
- + if (ret)
|
| |
- + return ret;
|
| |
- +
|
| |
- + ret = dup_mechanism(&state->verify_mechanism, pMechanism);
|
| |
- + if (ret == CKR_OK)
|
| |
- + state->verify_object = OBJECT_ID(o);
|
| |
- +
|
| |
- + return ret;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_Verify(CK_SESSION_HANDLE hSession,
|
| |
- + CK_BYTE_PTR pData,
|
| |
- + CK_ULONG ulDataLen,
|
| |
- + CK_BYTE_PTR pSignature,
|
| |
- + CK_ULONG ulSignatureLen)
|
| |
- +{
|
| |
- + struct session_state *state;
|
| |
- + struct st_object *o;
|
| |
- + void *buffer = NULL;
|
| |
- + CK_RV ret;
|
| |
- + RSA *rsa;
|
| |
- + int padding, len, buffer_len;
|
| |
- +
|
| |
- + st_logf("Verify\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, &state);
|
| |
- +
|
| |
- + if (state->verify_object == -1)
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- +
|
| |
- + o = soft_token.object.objs[state->verify_object];
|
| |
- +
|
| |
- + if (o->u.public_key == NULL) {
|
| |
- + st_logf("public key NULL\n");
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- + }
|
| |
- +
|
| |
- + rsa = EVP_PKEY_get0_RSA(o->u.public_key);
|
| |
- + if (rsa == NULL)
|
| |
- + return CKR_ARGUMENTS_BAD;
|
| |
- +
|
| |
- + RSA_blinding_off(rsa); /* XXX RAND is broken while running in mozilla ? */
|
| |
- +
|
| |
- + buffer_len = RSA_size(rsa);
|
| |
- +
|
| |
- + buffer = malloc(buffer_len);
|
| |
- + if (buffer == NULL) {
|
| |
- + ret = CKR_DEVICE_MEMORY;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + ret = CKR_OK;
|
| |
- + switch(state->verify_mechanism->mechanism) {
|
| |
- + case CKM_RSA_PKCS:
|
| |
- + padding = RSA_PKCS1_PADDING;
|
| |
- + break;
|
| |
- + case CKM_RSA_X_509:
|
| |
- + padding = RSA_NO_PADDING;
|
| |
- + break;
|
| |
- + default:
|
| |
- + ret = CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + if (buffer_len < (long) ulDataLen) {
|
| |
- + ret = CKR_ARGUMENTS_BAD;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + if (pSignature == NULL) {
|
| |
- + st_logf("signature NULL\n");
|
| |
- + ret = CKR_ARGUMENTS_BAD;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + if (pData == NULL_PTR) {
|
| |
- + st_logf("data NULL\n");
|
| |
- + ret = CKR_ARGUMENTS_BAD;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + len = RSA_public_decrypt(ulDataLen, pData, buffer, rsa, padding);
|
| |
- + st_logf("private encrypt done\n");
|
| |
- + if (len <= 0) {
|
| |
- + ret = CKR_DEVICE_ERROR;
|
| |
- + goto out;
|
| |
- + }
|
| |
- + if (len > buffer_len)
|
| |
- + abort();
|
| |
- +
|
| |
- + if ((size_t) len != ulSignatureLen) {
|
| |
- + ret = CKR_GENERAL_ERROR;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + if (memcmp(pSignature, buffer, len) != 0) {
|
| |
- + ret = CKR_GENERAL_ERROR;
|
| |
- + goto out;
|
| |
- + }
|
| |
- +
|
| |
- + out:
|
| |
- + if (buffer) {
|
| |
- + memset(buffer, 0, buffer_len);
|
| |
- + free(buffer);
|
| |
- + }
|
| |
- + return ret;
|
| |
- +}
|
| |
- +
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_VerifyUpdate(CK_SESSION_HANDLE hSession,
|
| |
- + CK_BYTE_PTR pPart,
|
| |
- + CK_ULONG ulPartLen)
|
| |
- +{
|
| |
- + st_logf("VerifyUpdate\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, NULL);
|
| |
- + return CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_VerifyFinal(CK_SESSION_HANDLE hSession,
|
| |
- + CK_BYTE_PTR pSignature,
|
| |
- + CK_ULONG ulSignatureLen)
|
| |
- +{
|
| |
- + st_logf("VerifyFinal\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, NULL);
|
| |
- + return CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- +}
|
| |
- +
|
| |
- +CK_RV
|
| |
- +C_GenerateRandom(CK_SESSION_HANDLE hSession,
|
| |
- + CK_BYTE_PTR RandomData,
|
| |
- + CK_ULONG ulRandomLen)
|
| |
- +{
|
| |
- + st_logf("GenerateRandom\n");
|
| |
- + VERIFY_SESSION_HANDLE(hSession, NULL);
|
| |
- + return CKR_FUNCTION_NOT_SUPPORTED;
|
| |
- +}
|
| |
- +
|
| |
- +
|
| |
- +CK_FUNCTION_LIST funcs = {
|
| |
- + { 2, 11 },
|
| |
- + C_Initialize,
|
| |
- + C_Finalize,
|
| |
- + C_GetInfo,
|
| |
- + C_GetFunctionList,
|
| |
- + C_GetSlotList,
|
| |
- + C_GetSlotInfo,
|
| |
- + C_GetTokenInfo,
|
| |
- + C_GetMechanismList,
|
| |
- + C_GetMechanismInfo,
|
| |
- + C_InitToken,
|
| |
- + (void *)func_not_supported, /* C_InitPIN */
|
| |
- + (void *)func_not_supported, /* C_SetPIN */
|
| |
- + C_OpenSession,
|
| |
- + C_CloseSession,
|
| |
- + C_CloseAllSessions,
|
| |
- + C_GetSessionInfo,
|
| |
- + (void *)func_not_supported, /* C_GetOperationState */
|
| |
- + (void *)func_not_supported, /* C_SetOperationState */
|
| |
- + C_Login,
|
| |
- + C_Logout,
|
| |
- + (void *)func_not_supported, /* C_CreateObject */
|
| |
- + (void *)func_not_supported, /* C_CopyObject */
|
| |
- + (void *)func_not_supported, /* C_DestroyObject */
|
| |
- + (void *)func_not_supported, /* C_GetObjectSize */
|
| |
- + C_GetAttributeValue,
|
| |
- + (void *)func_not_supported, /* C_SetAttributeValue */
|
| |
- + C_FindObjectsInit,
|
| |
- + C_FindObjects,
|
| |
- + C_FindObjectsFinal,
|
| |
- + C_EncryptInit,
|
| |
- + C_Encrypt,
|
| |
- + C_EncryptUpdate,
|
| |
- + C_EncryptFinal,
|
| |
- + C_DecryptInit,
|
| |
- + C_Decrypt,
|
| |
- + C_DecryptUpdate,
|
| |
- + C_DecryptFinal,
|
| |
- + C_DigestInit,
|
| |
- + (void *)func_not_supported, /* C_Digest */
|
| |
- + (void *)func_not_supported, /* C_DigestUpdate */
|
| |
- + (void *)func_not_supported, /* C_DigestKey */
|
| |
- + (void *)func_not_supported, /* C_DigestFinal */
|
| |
- + C_SignInit,
|
| |
- + C_Sign,
|
| |
- + C_SignUpdate,
|
| |
- + C_SignFinal,
|
| |
- + (void *)func_not_supported, /* C_SignRecoverInit */
|
| |
- + (void *)func_not_supported, /* C_SignRecover */
|
| |
- + C_VerifyInit,
|
| |
- + C_Verify,
|
| |
- + C_VerifyUpdate,
|
| |
- + C_VerifyFinal,
|
| |
- + (void *)func_not_supported, /* C_VerifyRecoverInit */
|
| |
- + (void *)func_not_supported, /* C_VerifyRecover */
|
| |
- + (void *)func_not_supported, /* C_DigestEncryptUpdate */
|
| |
- + (void *)func_not_supported, /* C_DecryptDigestUpdate */
|
| |
- + (void *)func_not_supported, /* C_SignEncryptUpdate */
|
| |
- + (void *)func_not_supported, /* C_DecryptVerifyUpdate */
|
| |
- + (void *)func_not_supported, /* C_GenerateKey */
|
| |
- + (void *)func_not_supported, /* C_GenerateKeyPair */
|
| |
- + (void *)func_not_supported, /* C_WrapKey */
|
| |
- + (void *)func_not_supported, /* C_UnwrapKey */
|
| |
- + (void *)func_not_supported, /* C_DeriveKey */
|
| |
- + (void *)func_not_supported, /* C_SeedRandom */
|
| |
- + C_GenerateRandom,
|
| |
- + (void *)func_not_supported, /* C_GetFunctionStatus */
|
| |
- + (void *)func_not_supported, /* C_CancelFunction */
|
| |
- + (void *)func_not_supported /* C_WaitForSlotEvent */
|
| |
- +};
|
| |
- diff -up openssh/regress/unittests/Makefile.pkcs11-uri openssh/regress/unittests/Makefile
|
| |
- --- openssh/regress/unittests/Makefile.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200
|
| |
- +++ openssh/regress/unittests/Makefile 2018-10-12 13:52:55.453191425 +0200
|
| |
- @@ -2,6 +2,6 @@
|
| |
-
|
| |
- REGRESS_FAIL_EARLY?= yes
|
| |
- SUBDIR= test_helper sshbuf sshkey bitmap kex hostkeys utf8 match conversion
|
| |
- -SUBDIR+=authopt
|
| |
- +SUBDIR+=pkcs11 authopt
|
| |
-
|
| |
- .include <bsd.subdir.mk>
|
| |
- diff -up openssh/regress/unittests/pkcs11/Makefile.pkcs11-uri openssh/regress/unittests/pkcs11/Makefile
|
| |
- --- openssh/regress/unittests/pkcs11/Makefile.pkcs11-uri 2018-10-12 13:52:55.453191425 +0200
|
| |
- +++ openssh/regress/unittests/pkcs11/Makefile 2018-10-12 13:52:55.453191425 +0200
|
| |
- @@ -0,0 +1,9 @@
|
| |
- +
|
| |
- +PROG=test_pkcs11
|
| |
- +SRCS=tests.c
|
| |
- +REGRESS_TARGETS=run-regress-${PROG}
|
| |
- +
|
| |
- +run-regress-${PROG}: ${PROG}
|
| |
- + env ${TEST_ENV} ./${PROG}
|
| |
- +
|
| |
- +.include <bsd.regress.mk>
|
| |
- diff -up openssh/regress/unittests/pkcs11/tests.c.pkcs11-uri openssh/regress/unittests/pkcs11/tests.c
|
| |
- --- openssh/regress/unittests/pkcs11/tests.c.pkcs11-uri 2018-10-12 13:52:55.453191425 +0200
|
| |
- +++ openssh/regress/unittests/pkcs11/tests.c 2018-10-12 13:52:55.453191425 +0200
|
| |
- @@ -0,0 +1,330 @@
|
| |
- +/*
|
| |
- + * Copyright (c) 2017 Red Hat
|
| |
- + *
|
| |
- + * Authors: Jakub Jelen <jjelen@redhat.com>
|
| |
- + *
|
| |
- + * Permission to use, copy, modify, and distribute this software for any
|
| |
- + * purpose with or without fee is hereby granted, provided that the above
|
| |
- + * copyright notice and this permission notice appear in all copies.
|
| |
- + *
|
| |
- + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
| |
- + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
| |
- + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
| |
- + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
| |
- + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
| |
- + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
| |
- + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
| |
- + */
|
| |
- +
|
| |
- +#include "includes.h"
|
| |
- +
|
| |
- +#include <locale.h>
|
| |
- +#include <string.h>
|
| |
- +
|
| |
- +#include "../test_helper/test_helper.h"
|
| |
- +
|
| |
- +#include "sshbuf.h"
|
| |
- +#include "ssh-pkcs11-uri.h"
|
| |
- +
|
| |
- +#define EMPTY_URI compose_uri(NULL, 0, NULL, NULL, NULL, NULL, NULL)
|
| |
- +
|
| |
- +/* prototypes are not public -- specify them here internally for tests */
|
| |
- +struct sshbuf *percent_encode(const char *, size_t, char *);
|
| |
- +int percent_decode(char *, char **);
|
| |
- +
|
| |
- +void
|
| |
- +compare_uri(struct pkcs11_uri *a, struct pkcs11_uri *b)
|
| |
- +{
|
| |
- + ASSERT_PTR_NE(a, NULL);
|
| |
- + ASSERT_PTR_NE(b, NULL);
|
| |
- + ASSERT_SIZE_T_EQ(a->id_len, b->id_len);
|
| |
- + ASSERT_MEM_EQ(a->id, b->id, a->id_len);
|
| |
- + if (b->object != NULL)
|
| |
- + ASSERT_STRING_EQ(a->object, b->object);
|
| |
- + else /* both should be null */
|
| |
- + ASSERT_PTR_EQ(a->object, b->object);
|
| |
- + if (b->module_path != NULL)
|
| |
- + ASSERT_STRING_EQ(a->module_path, b->module_path);
|
| |
- + else /* both should be null */
|
| |
- + ASSERT_PTR_EQ(a->module_path, b->module_path);
|
| |
- + if (b->token != NULL)
|
| |
- + ASSERT_STRING_EQ(a->token, b->token);
|
| |
- + else /* both should be null */
|
| |
- + ASSERT_PTR_EQ(a->token, b->token);
|
| |
- + if (b->manuf != NULL)
|
| |
- + ASSERT_STRING_EQ(a->manuf, b->manuf);
|
| |
- + else /* both should be null */
|
| |
- + ASSERT_PTR_EQ(a->manuf, b->manuf);
|
| |
- + if (b->lib_manuf != NULL)
|
| |
- + ASSERT_STRING_EQ(a->lib_manuf, b->lib_manuf);
|
| |
- + else /* both should be null */
|
| |
- + ASSERT_PTR_EQ(a->lib_manuf, b->lib_manuf);
|
| |
- +}
|
| |
- +
|
| |
- +void
|
| |
- +check_parse_rv(char *uri, struct pkcs11_uri *expect, int expect_rv)
|
| |
- +{
|
| |
- + char *buf = NULL, *str;
|
| |
- + struct pkcs11_uri *pkcs11uri = NULL;
|
| |
- + int rv;
|
| |
- +
|
| |
- + if (expect_rv == 0)
|
| |
- + str = "Valid";
|
| |
- + else
|
| |
- + str = "Invalid";
|
| |
- + asprintf(&buf, "%s PKCS#11 URI parsing: %s", str, uri);
|
| |
- + TEST_START(buf);
|
| |
- + free(buf);
|
| |
- + pkcs11uri = pkcs11_uri_init();
|
| |
- + rv = pkcs11_uri_parse(uri, pkcs11uri);
|
| |
- + ASSERT_INT_EQ(rv, expect_rv);
|
| |
- + if (rv == 0) /* in case of failure result is undefined */
|
| |
- + compare_uri(pkcs11uri, expect);
|
| |
- + pkcs11_uri_cleanup(pkcs11uri);
|
| |
- + free(expect);
|
| |
- + TEST_DONE();
|
| |
- +}
|
| |
- +
|
| |
- +void
|
| |
- +check_parse(char *uri, struct pkcs11_uri *expect)
|
| |
- +{
|
| |
- + check_parse_rv(uri, expect, 0);
|
| |
- +}
|
| |
- +
|
| |
- +struct pkcs11_uri *
|
| |
- +compose_uri(unsigned char *id, size_t id_len, char *token, char *lib_manuf,
|
| |
- + char *manuf, char *module_path, char *object)
|
| |
- +{
|
| |
- + struct pkcs11_uri *uri = pkcs11_uri_init();
|
| |
- + if (id_len > 0) {
|
| |
- + uri->id_len = id_len;
|
| |
- + uri->id = id;
|
| |
- + }
|
| |
- + uri->module_path = module_path;
|
| |
- + uri->token = token;
|
| |
- + uri->lib_manuf = lib_manuf;
|
| |
- + uri->manuf = manuf;
|
| |
- + uri->object = object;
|
| |
- + return uri;
|
| |
- +}
|
| |
- +
|
| |
- +static void
|
| |
- +test_parse_valid(void)
|
| |
- +{
|
| |
- + /* path arguments */
|
| |
- + check_parse("pkcs11:id=%01",
|
| |
- + compose_uri("\x01", 1, NULL, NULL, NULL, NULL, NULL));
|
| |
- + check_parse("pkcs11:id=%00%01",
|
| |
- + compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL, NULL));
|
| |
- + check_parse("pkcs11:token=SSH%20Keys",
|
| |
- + compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL));
|
| |
- + check_parse("pkcs11:library-manufacturer=OpenSC",
|
| |
- + compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL, NULL));
|
| |
- + check_parse("pkcs11:manufacturer=piv_II",
|
| |
- + compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, NULL));
|
| |
- + check_parse("pkcs11:object=SIGN%20Key",
|
| |
- + compose_uri(NULL, 0, NULL, NULL, NULL, NULL, "SIGN Key"));
|
| |
- + /* query arguments */
|
| |
- + check_parse("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so",
|
| |
- + compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL));
|
| |
- +
|
| |
- + /* combinations */
|
| |
- + /* ID SHOULD be percent encoded */
|
| |
- + check_parse("pkcs11:token=SSH%20Key;id=0",
|
| |
- + compose_uri("0", 1, "SSH Key", NULL, NULL, NULL, NULL));
|
| |
- + check_parse(
|
| |
- + "pkcs11:manufacturer=CAC?module-path=/usr/lib64/p11-kit-proxy.so",
|
| |
- + compose_uri(NULL, 0, NULL, NULL, "CAC",
|
| |
- + "/usr/lib64/p11-kit-proxy.so", NULL));
|
| |
- + check_parse(
|
| |
- + "pkcs11:object=RSA%20Key?module-path=/usr/lib64/pkcs11/opencryptoki.so",
|
| |
- + compose_uri(NULL, 0, NULL, NULL, NULL,
|
| |
- + "/usr/lib64/pkcs11/opencryptoki.so", "RSA Key"));
|
| |
- +
|
| |
- + /* empty path component matches everything */
|
| |
- + check_parse("pkcs11:", EMPTY_URI);
|
| |
- +
|
| |
- + /* empty string is a valid to match against (and different from NULL) */
|
| |
- + check_parse("pkcs11:token=",
|
| |
- + compose_uri(NULL, 0, "", NULL, NULL, NULL, NULL));
|
| |
- + /* Percent character needs to be percent-encoded */
|
| |
- + check_parse("pkcs11:token=%25",
|
| |
- + compose_uri(NULL, 0, "%", NULL, NULL, NULL, NULL));
|
| |
- +}
|
| |
- +
|
| |
- +static void
|
| |
- +test_parse_invalid(void)
|
| |
- +{
|
| |
- + /* Invalid percent encoding */
|
| |
- + check_parse_rv("pkcs11:id=%0", EMPTY_URI, -1);
|
| |
- + /* Invalid percent encoding */
|
| |
- + check_parse_rv("pkcs11:id=%ZZ", EMPTY_URI, -1);
|
| |
- + /* Space MUST be percent encoded -- XXX not enforced yet */
|
| |
- + check_parse("pkcs11:token=SSH Keys",
|
| |
- + compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL));
|
| |
- + /* MUST NOT contain duplicate attributes of the same name */
|
| |
- + check_parse_rv("pkcs11:id=%01;id=%02", EMPTY_URI, -1);
|
| |
- + /* Unrecognized attribute in path are ignored with log message */
|
| |
- + check_parse("pkcs11:key_name=SSH", EMPTY_URI);
|
| |
- + /* Unrecognized attribute in query SHOULD be ignored */
|
| |
- + check_parse("pkcs11:?key_name=SSH", EMPTY_URI);
|
| |
- +}
|
| |
- +
|
| |
- +void
|
| |
- +check_gen(char *expect, struct pkcs11_uri *uri)
|
| |
- +{
|
| |
- + char *buf = NULL, *uri_str;
|
| |
- +
|
| |
- + asprintf(&buf, "Valid PKCS#11 URI generation: %s", expect);
|
| |
- + TEST_START(buf);
|
| |
- + free(buf);
|
| |
- + uri_str = pkcs11_uri_get(uri);
|
| |
- + ASSERT_PTR_NE(uri_str, NULL);
|
| |
- + ASSERT_STRING_EQ(uri_str, expect);
|
| |
- + free(uri_str);
|
| |
- + TEST_DONE();
|
| |
- +}
|
| |
- +
|
| |
- +static void
|
| |
- +test_generate_valid(void)
|
| |
- +{
|
| |
- + /* path arguments */
|
| |
- + check_gen("pkcs11:id=%01",
|
| |
- + compose_uri("\x01", 1, NULL, NULL, NULL, NULL, NULL));
|
| |
- + check_gen("pkcs11:id=%00%01",
|
| |
- + compose_uri("\x00\x01", 2, NULL, NULL, NULL, NULL, NULL));
|
| |
- + check_gen("pkcs11:token=SSH%20Keys", /* space must be percent encoded */
|
| |
- + compose_uri(NULL, 0, "SSH Keys", NULL, NULL, NULL, NULL));
|
| |
- + /* library-manufacturer is not implmented now */
|
| |
- + /*check_gen("pkcs11:library-manufacturer=OpenSC",
|
| |
- + compose_uri(NULL, 0, NULL, "OpenSC", NULL, NULL, NULL));*/
|
| |
- + check_gen("pkcs11:manufacturer=piv_II",
|
| |
- + compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, NULL));
|
| |
- + check_gen("pkcs11:object=RSA%20Key",
|
| |
- + compose_uri(NULL, 0, NULL, NULL, NULL, NULL, "RSA Key"));
|
| |
- + /* query arguments */
|
| |
- + check_gen("pkcs11:?module-path=/usr/lib64/p11-kit-proxy.so",
|
| |
- + compose_uri(NULL, 0, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL));
|
| |
- +
|
| |
- + /* combinations */
|
| |
- + check_gen("pkcs11:id=%02;token=SSH%20Keys",
|
| |
- + compose_uri("\x02", 1, "SSH Keys", NULL, NULL, NULL, NULL));
|
| |
- + check_gen("pkcs11:id=%EE%02?module-path=/usr/lib64/p11-kit-proxy.so",
|
| |
- + compose_uri("\xEE\x02", 2, NULL, NULL, NULL, "/usr/lib64/p11-kit-proxy.so", NULL));
|
| |
- + check_gen("pkcs11:object=Encryption%20Key;manufacturer=piv_II",
|
| |
- + compose_uri(NULL, 0, NULL, NULL, "piv_II", NULL, "Encryption Key"));
|
| |
- +
|
| |
- + /* empty path component matches everything */
|
| |
- + check_gen("pkcs11:", EMPTY_URI);
|
| |
- +
|
| |
- +}
|
| |
- +
|
| |
- +void
|
| |
- +check_encode(char *source, size_t len, char *whitelist, char *expect)
|
| |
- +{
|
| |
- + char *buf = NULL;
|
| |
- + struct sshbuf *b;
|
| |
- +
|
| |
- + asprintf(&buf, "percent_encode: expected %s", expect);
|
| |
- + TEST_START(buf);
|
| |
- + free(buf);
|
| |
- +
|
| |
- + b = percent_encode(source, len, whitelist);
|
| |
- + ASSERT_STRING_EQ(sshbuf_ptr(b), expect);
|
| |
- + sshbuf_free(b);
|
| |
- + TEST_DONE();
|
| |
- +}
|
| |
- +
|
| |
- +static void
|
| |
- +test_percent_encode_multibyte(void)
|
| |
- +{
|
| |
- + /* SHOULD be encoded as octets according to the UTF-8 character encoding */
|
| |
- +
|
| |
- + /* multi-byte characters are "for free" */
|
| |
- + check_encode("$", 1, "", "%24");
|
| |
- + check_encode("¢", 2, "", "%C2%A2");
|
| |
- + check_encode("€", 3, "", "%E2%82%AC");
|
| |
- + check_encode("𐍈", 4, "", "%F0%90%8D%88");
|
| |
- +
|
| |
- + /* CK_UTF8CHAR is unsigned char (1 byte) */
|
| |
- + /* labels SHOULD be normalized to NFC [UAX15] */
|
| |
- +
|
| |
- +}
|
| |
- +
|
| |
- +static void
|
| |
- +test_percent_encode(void)
|
| |
- +{
|
| |
- + /* Without whitelist encodes everything (for CKA_ID) */
|
| |
- + check_encode("A*", 2, "", "%41%2A");
|
| |
- + check_encode("\x00", 1, "", "%00");
|
| |
- + check_encode("\x7F", 1, "", "%7F");
|
| |
- + check_encode("\x80", 1, "", "%80");
|
| |
- + check_encode("\xff", 1, "", "%FF");
|
| |
- +
|
| |
- + /* Default whitelist encodes anything but safe letters */
|
| |
- + check_encode("test" "\x00" "0alpha", 11, PKCS11_URI_WHITELIST,
|
| |
- + "test%000alpha");
|
| |
- + check_encode(" ", 1, PKCS11_URI_WHITELIST,
|
| |
- + "%20"); /* Space MUST be percent encoded */
|
| |
- + check_encode("/", 1, PKCS11_URI_WHITELIST,
|
| |
- + "%2F"); /* '/' delimiter MUST be percent encoded (in the path) */
|
| |
- + check_encode("?", 1, PKCS11_URI_WHITELIST,
|
| |
- + "%3F"); /* delimiter '?' MUST be percent encoded (in the path) */
|
| |
- + check_encode("#", 1, PKCS11_URI_WHITELIST,
|
| |
- + "%23"); /* '#' MUST be always percent encoded */
|
| |
- + check_encode("key=value;separator?query&#anch", 35, PKCS11_URI_WHITELIST,
|
| |
- + "key%3Dvalue%3Bseparator%3Fquery%26amp%3B%23anch");
|
| |
- +
|
| |
- + /* Components in query can have '/' unencoded (useful for paths) */
|
| |
- + check_encode("/path/to.file", 13, PKCS11_URI_WHITELIST "/",
|
| |
- + "/path/to.file");
|
| |
- +}
|
| |
- +
|
| |
- +void
|
| |
- +check_decode(char *source, char *expect, int expect_len)
|
| |
- +{
|
| |
- + char *buf = NULL, *out = NULL;
|
| |
- + int rv;
|
| |
- +
|
| |
- + asprintf(&buf, "percent_decode: %s", source);
|
| |
- + TEST_START(buf);
|
| |
- + free(buf);
|
| |
- +
|
| |
- + rv = percent_decode(source, &out);
|
| |
- + ASSERT_INT_EQ(rv, expect_len);
|
| |
- + if (rv >= 0)
|
| |
- + ASSERT_MEM_EQ(out, expect, expect_len);
|
| |
- + free(out);
|
| |
- + TEST_DONE();
|
| |
- +}
|
| |
- +
|
| |
- +static void
|
| |
- +test_percent_decode(void)
|
| |
- +{
|
| |
- + /* simple valid cases */
|
| |
- + check_decode("%00", "\x00", 1);
|
| |
- + check_decode("%FF", "\xFF", 1);
|
| |
- +
|
| |
- + /* normal strings shold be kept intact */
|
| |
- + check_decode("strings are left", "strings are left", 16);
|
| |
- + check_decode("10%25 of trees", "10% of trees", 12);
|
| |
- +
|
| |
- + /* make sure no more than 2 bytes are parsed */
|
| |
- + check_decode("%222", "\x22" "2", 2);
|
| |
- +
|
| |
- + /* invalid expects failure */
|
| |
- + check_decode("%0", "", -1);
|
| |
- + check_decode("%Z", "", -1);
|
| |
- + check_decode("%FG", "", -1);
|
| |
- +}
|
| |
- +
|
| |
- +void
|
| |
- +tests(void)
|
| |
- +{
|
| |
- + test_percent_encode();
|
| |
- + test_percent_encode_multibyte();
|
| |
- + test_percent_decode();
|
| |
- + test_parse_valid();
|
| |
- + test_parse_invalid();
|
| |
- + test_generate_valid();
|
| |
- +}
|
| |
- diff -up openssh/ssh-add.c.pkcs11-uri openssh/ssh-add.c
|
| |
- --- openssh/ssh-add.c.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200
|
| |
- +++ openssh/ssh-add.c 2018-10-12 13:52:55.454191434 +0200
|
| |
- @@ -64,6 +64,7 @@
|
| |
- #include "misc.h"
|
| |
- #include "ssherr.h"
|
| |
- #include "digest.h"
|
| |
- +#include "ssh-pkcs11-uri.h"
|
| |
-
|
| |
- /* argv0 */
|
| |
- extern char *__progname;
|
| |
- @@ -188,6 +189,24 @@ delete_all(int agent_fd, int qflag)
|
| |
- return ret;
|
| |
- }
|
| |
-
|
| |
- +#ifdef ENABLE_PKCS11
|
| |
- +static int update_card(int, int, const char *, int);
|
| |
- +
|
| |
- +int
|
| |
- +update_pkcs11_uri(int agent_fd, int adding, const char *pkcs11_uri, int qflag)
|
| |
- +{
|
| |
- + struct pkcs11_uri *uri;
|
| |
- +
|
| |
- + /* dry-run parse to make sure the URI is valid and to report errors */
|
| |
- + uri = pkcs11_uri_init();
|
| |
- + if (pkcs11_uri_parse((char *) pkcs11_uri, uri) != 0)
|
| |
- + fatal("Failed to parse PKCS#11 URI");
|
| |
- + pkcs11_uri_cleanup(uri);
|
| |
- +
|
| |
- + return update_card(agent_fd, adding, pkcs11_uri, qflag);
|
| |
- +}
|
| |
- +#endif
|
| |
- +
|
| |
- static int
|
| |
- add_file(int agent_fd, const char *filename, int key_only, int qflag)
|
| |
- {
|
| |
- @@ -495,6 +514,13 @@ lock_agent(int agent_fd, int lock)
|
| |
- static int
|
| |
- do_file(int agent_fd, int deleting, int key_only, char *file, int qflag)
|
| |
- {
|
| |
- +#ifdef ENABLE_PKCS11
|
| |
- + if (strlen(file) >= strlen(PKCS11_URI_SCHEME) &&
|
| |
- + strncmp(file, PKCS11_URI_SCHEME,
|
| |
- + strlen(PKCS11_URI_SCHEME)) == 0) {
|
| |
- + return update_pkcs11_uri(agent_fd, !deleting, file, qflag);
|
| |
- + }
|
| |
- +#endif
|
| |
- if (deleting) {
|
| |
- if (delete_file(agent_fd, file, key_only, qflag) == -1)
|
| |
- return -1;
|
| |
- diff -up openssh/ssh-agent.c.pkcs11-uri openssh/ssh-agent.c
|
| |
- --- openssh/ssh-agent.c.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200
|
| |
- +++ openssh/ssh-agent.c 2018-10-12 13:52:55.454191434 +0200
|
| |
- @@ -546,10 +546,72 @@ no_identities(SocketEntry *e)
|
| |
- }
|
| |
-
|
| |
- #ifdef ENABLE_PKCS11
|
| |
- +static char *
|
| |
- +sanitize_pkcs11_provider(const char *provider)
|
| |
- +{
|
| |
- + struct pkcs11_uri *uri = NULL;
|
| |
- + char *sane_uri, *module_path = NULL; /* default path */
|
| |
- + char canonical_provider[PATH_MAX];
|
| |
- +
|
| |
- + if (provider == NULL)
|
| |
- + return NULL;
|
| |
- +
|
| |
- + if (strlen(provider) >= strlen(PKCS11_URI_SCHEME) &&
|
| |
- + strncmp(provider, PKCS11_URI_SCHEME,
|
| |
- + strlen(PKCS11_URI_SCHEME)) == 0) {
|
| |
- + /* PKCS#11 URI */
|
| |
- + uri = pkcs11_uri_init();
|
| |
- + if (uri == NULL) {
|
| |
- + error("Failed to init PCKS#11 URI");
|
| |
- + return NULL;
|
| |
- + }
|
| |
- +
|
| |
- + if (pkcs11_uri_parse(provider, uri) != 0) {
|
| |
- + error("Failed to parse PKCS#11 URI");
|
| |
- + return NULL;
|
| |
- + }
|
| |
- + /* validate also provider from URI */
|
| |
- + if (uri->module_path)
|
| |
- + module_path = strdup(uri->module_path);
|
| |
- + } else
|
| |
- + module_path = strdup(provider); /* simple path */
|
| |
- +
|
| |
- + if (module_path != NULL) { /* do not validate default NULL path in URI */
|
| |
- + if (realpath(module_path, canonical_provider) == NULL) {
|
| |
- + verbose("failed PKCS#11 provider \"%.100s\": realpath: %s",
|
| |
- + module_path, strerror(errno));
|
| |
- + free(module_path);
|
| |
- + pkcs11_uri_cleanup(uri);
|
| |
- + return NULL;
|
| |
- + }
|
| |
- + free(module_path);
|
| |
- + if (match_pattern_list(canonical_provider, pkcs11_whitelist, 0) != 1) {
|
| |
- + verbose("refusing PKCS#11 provider \"%.100s\": "
|
| |
- + "not whitelisted", canonical_provider);
|
| |
- + pkcs11_uri_cleanup(uri);
|
| |
- + return NULL;
|
| |
- + }
|
| |
- +
|
| |
- + /* copy verified and sanitized provider path back to the uri */
|
| |
- + if (uri) {
|
| |
- + free(uri->module_path);
|
| |
- + uri->module_path = xstrdup(canonical_provider);
|
| |
- + }
|
| |
- + }
|
| |
- +
|
| |
- + if (uri) {
|
| |
- + sane_uri = pkcs11_uri_get(uri);
|
| |
- + pkcs11_uri_cleanup(uri);
|
| |
- + return sane_uri;
|
| |
- + } else {
|
| |
- + return xstrdup(canonical_provider); /* simple path */
|
| |
- + }
|
| |
- +}
|
| |
- +
|
| |
- static void
|
| |
- process_add_smartcard_key(SocketEntry *e)
|
| |
- {
|
| |
- - char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];
|
| |
- + char *provider = NULL, *pin = NULL, *sane_uri = NULL;
|
| |
- int r, i, count = 0, success = 0, confirm = 0;
|
| |
- u_int seconds;
|
| |
- time_t death = 0;
|
| |
- @@ -585,28 +647,23 @@ process_add_smartcard_key(SocketEntry *e
|
| |
- goto send;
|
| |
- }
|
| |
- }
|
| |
- - if (realpath(provider, canonical_provider) == NULL) {
|
| |
- - verbose("failed PKCS#11 add of \"%.100s\": realpath: %s",
|
| |
- - provider, strerror(errno));
|
| |
- - goto send;
|
| |
- - }
|
| |
- - if (match_pattern_list(canonical_provider, pkcs11_whitelist, 0) != 1) {
|
| |
- - verbose("refusing PKCS#11 add of \"%.100s\": "
|
| |
- - "provider not whitelisted", canonical_provider);
|
| |
- +
|
| |
- + sane_uri = sanitize_pkcs11_provider(provider);
|
| |
- + if (sane_uri == NULL)
|
| |
- goto send;
|
| |
- - }
|
| |
- - debug("%s: add %.100s", __func__, canonical_provider);
|
| |
- +
|
| |
- if (lifetime && !death)
|
| |
- death = monotime() + lifetime;
|
| |
-
|
| |
- - count = pkcs11_add_provider(canonical_provider, pin, &keys);
|
| |
- + debug("%s: add %.100s", __func__, sane_uri);
|
| |
- + count = pkcs11_add_provider(sane_uri, pin, &keys);
|
| |
- for (i = 0; i < count; i++) {
|
| |
- k = keys[i];
|
| |
- if (lookup_identity(k) == NULL) {
|
| |
- id = xcalloc(1, sizeof(Identity));
|
| |
- id->key = k;
|
| |
- - id->provider = xstrdup(canonical_provider);
|
| |
- - id->comment = xstrdup(canonical_provider); /* XXX */
|
| |
- + id->provider = xstrdup(sane_uri);
|
| |
- + id->comment = xstrdup(sane_uri);
|
| |
- id->death = death;
|
| |
- id->confirm = confirm;
|
| |
- TAILQ_INSERT_TAIL(&idtab->idlist, id, next);
|
| |
- @@ -620,6 +677,7 @@ process_add_smartcard_key(SocketEntry *e
|
| |
- send:
|
| |
- free(pin);
|
| |
- free(provider);
|
| |
- + free(sane_uri);
|
| |
- free(keys);
|
| |
- send_status(e, success);
|
| |
- }
|
| |
- @@ -627,7 +685,7 @@ send:
|
| |
- static void
|
| |
- process_remove_smartcard_key(SocketEntry *e)
|
| |
- {
|
| |
- - char *provider = NULL, *pin = NULL, canonical_provider[PATH_MAX];
|
| |
- + char *provider = NULL, *pin = NULL, *sane_uri = NULL;
|
| |
- int r, success = 0;
|
| |
- Identity *id, *nxt;
|
| |
-
|
| |
- @@ -638,30 +696,29 @@ process_remove_smartcard_key(SocketEntry
|
| |
- }
|
| |
- free(pin);
|
| |
-
|
| |
- - if (realpath(provider, canonical_provider) == NULL) {
|
| |
- - verbose("failed PKCS#11 add of \"%.100s\": realpath: %s",
|
| |
- - provider, strerror(errno));
|
| |
- + sane_uri = sanitize_pkcs11_provider(provider);
|
| |
- + if (sane_uri == NULL)
|
| |
- goto send;
|
| |
- - }
|
| |
-
|
| |
- - debug("%s: remove %.100s", __func__, canonical_provider);
|
| |
- + debug("%s: remove %.100s", __func__, sane_uri);
|
| |
- for (id = TAILQ_FIRST(&idtab->idlist); id; id = nxt) {
|
| |
- nxt = TAILQ_NEXT(id, next);
|
| |
- /* Skip file--based keys */
|
| |
- if (id->provider == NULL)
|
| |
- continue;
|
| |
- - if (!strcmp(canonical_provider, id->provider)) {
|
| |
- + if (!strcmp(sane_uri, id->provider)) {
|
| |
- TAILQ_REMOVE(&idtab->idlist, id, next);
|
| |
- free_identity(id);
|
| |
- idtab->nentries--;
|
| |
- }
|
| |
- }
|
| |
- - if (pkcs11_del_provider(canonical_provider) == 0)
|
| |
- + if (pkcs11_del_provider(sane_uri) == 0)
|
| |
- success = 1;
|
| |
- else
|
| |
- error("%s: pkcs11_del_provider failed", __func__);
|
| |
- send:
|
| |
- free(provider);
|
| |
- + free(sane_uri);
|
| |
- send_status(e, success);
|
| |
- }
|
| |
- #endif /* ENABLE_PKCS11 */
|
| |
- diff -up openssh/ssh_config.5.pkcs11-uri openssh/ssh_config.5
|
| |
- --- openssh/ssh_config.5.pkcs11-uri 2018-10-12 13:52:55.437191293 +0200
|
| |
- +++ openssh/ssh_config.5 2018-10-12 13:52:55.459191475 +0200
|
| |
- @@ -991,6 +991,19 @@ may also be used in conjunction with
|
| |
- .Cm CertificateFile
|
| |
- in order to provide any certificate also needed for authentication with
|
| |
- the identity.
|
| |
- +.Pp
|
| |
- +The authentication identity can be also specified in a form of PKCS#11 URI
|
| |
- +starting with a string
|
| |
- +.Cm pkcs11: .
|
| |
- +There is supported a subset of the PKCS#11 URI as defined
|
| |
- +in RFC 7512 (implemented path arguments
|
| |
- +.Cm id ,
|
| |
- +.Cm manufacturer ,
|
| |
- +.Cm object ,
|
| |
- +.Cm token
|
| |
- +and query argument
|
| |
- +.Cm module-path
|
| |
- +). The URI can not be in quotes.
|
| |
- .It Cm IgnoreUnknown
|
| |
- Specifies a pattern-list of unknown options to be ignored if they are
|
| |
- encountered in configuration parsing.
|
| |
- diff -up openssh/ssh.c.pkcs11-uri openssh/ssh.c
|
| |
- --- openssh/ssh.c.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200
|
| |
- +++ openssh/ssh.c 2018-10-12 13:52:55.458191467 +0200
|
| |
- @@ -769,6 +769,14 @@ main(int ac, char **av)
|
| |
- options.gss_deleg_creds = 1;
|
| |
- break;
|
| |
- case 'i':
|
| |
- +#ifdef ENABLE_PKCS11
|
| |
- + if (strlen(optarg) >= strlen(PKCS11_URI_SCHEME) &&
|
| |
- + strncmp(optarg, PKCS11_URI_SCHEME,
|
| |
- + strlen(PKCS11_URI_SCHEME)) == 0) {
|
| |
- + add_identity_file(&options, NULL, optarg, 1);
|
| |
- + break;
|
| |
- + }
|
| |
- +#endif
|
| |
- p = tilde_expand_filename(optarg, getuid());
|
| |
- if (stat(p, &st) < 0)
|
| |
- fprintf(stderr, "Warning: Identity file %s "
|
| |
- @@ -1975,6 +1983,45 @@ ssh_session2(struct ssh *ssh, struct pas
|
| |
- options.escape_char : SSH_ESCAPECHAR_NONE, id);
|
| |
- }
|
| |
-
|
| |
- +#ifdef ENABLE_PKCS11
|
| |
- +static void
|
| |
- +load_pkcs11_identity(char *pkcs11_uri, char *identity_files[],
|
| |
- + struct sshkey *identity_keys[], int *n_ids)
|
| |
- +{
|
| |
- + int nkeys, i;
|
| |
- + struct sshkey **keys;
|
| |
- + struct pkcs11_uri *uri;
|
| |
- +
|
| |
- + debug("identity file '%s' from pkcs#11", pkcs11_uri);
|
| |
- + uri = pkcs11_uri_init();
|
| |
- + if (uri == NULL)
|
| |
- + fatal("Failed to init PCKS#11 URI");
|
| |
- +
|
| |
- + if (pkcs11_uri_parse(pkcs11_uri, uri) != 0)
|
| |
- + fatal("Failed to parse PKCS#11 URI %s", pkcs11_uri);
|
| |
- +
|
| |
- + /* we need to merge URI and provider together */
|
| |
- + if (options.pkcs11_provider != NULL && uri->module_path == NULL)
|
| |
- + uri->module_path = strdup(options.pkcs11_provider);
|
| |
- +
|
| |
- + if (options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
|
| |
- + (nkeys = pkcs11_add_provider_by_uri(uri, NULL, &keys)) > 0) {
|
| |
- + for (i = 0; i < nkeys; i++) {
|
| |
- + if (*n_ids >= SSH_MAX_IDENTITY_FILES) {
|
| |
- + sshkey_free(keys[i]);
|
| |
- + continue;
|
| |
- + }
|
| |
- + identity_keys[*n_ids] = keys[i];
|
| |
- + identity_files[*n_ids] = pkcs11_uri_get(uri);
|
| |
- + (*n_ids)++;
|
| |
- + }
|
| |
- + free(keys);
|
| |
- + }
|
| |
- +
|
| |
- + pkcs11_uri_cleanup(uri);
|
| |
- +}
|
| |
- +#endif /* ENABLE_PKCS11 */
|
| |
- +
|
| |
- /* Loads all IdentityFile and CertificateFile keys */
|
| |
- static void
|
| |
- load_public_identity_files(struct passwd *pw)
|
| |
- @@ -1989,10 +2036,6 @@ load_public_identity_files(struct passwd
|
| |
- char *certificate_files[SSH_MAX_CERTIFICATE_FILES];
|
| |
- struct sshkey *certificates[SSH_MAX_CERTIFICATE_FILES];
|
| |
- int certificate_file_userprovided[SSH_MAX_CERTIFICATE_FILES];
|
| |
- -#ifdef ENABLE_PKCS11
|
| |
- - struct sshkey **keys;
|
| |
- - int nkeys;
|
| |
- -#endif /* PKCS11 */
|
| |
-
|
| |
- n_ids = n_certs = 0;
|
| |
- memset(identity_files, 0, sizeof(identity_files));
|
| |
- @@ -2005,32 +2048,46 @@ load_public_identity_files(struct passwd
|
| |
- sizeof(certificate_file_userprovided));
|
| |
-
|
| |
- #ifdef ENABLE_PKCS11
|
| |
- - if (options.pkcs11_provider != NULL &&
|
| |
- - options.num_identity_files < SSH_MAX_IDENTITY_FILES &&
|
| |
- - (pkcs11_init(!options.batch_mode) == 0) &&
|
| |
- - (nkeys = pkcs11_add_provider(options.pkcs11_provider, NULL,
|
| |
- - &keys)) > 0) {
|
| |
- - for (i = 0; i < nkeys; i++) {
|
| |
- - if (n_ids >= SSH_MAX_IDENTITY_FILES) {
|
| |
- - sshkey_free(keys[i]);
|
| |
- - continue;
|
| |
- - }
|
| |
- - identity_keys[n_ids] = keys[i];
|
| |
- - identity_files[n_ids] =
|
| |
- - xstrdup(options.pkcs11_provider); /* XXX */
|
| |
- - n_ids++;
|
| |
- - }
|
| |
- - free(keys);
|
| |
- + /* handle fallback from PKCS11Provider option */
|
| |
- + pkcs11_init(!options.batch_mode);
|
| |
- +
|
| |
- + if (options.pkcs11_provider != NULL) {
|
| |
- + struct pkcs11_uri *uri;
|
| |
- +
|
| |
- + uri = pkcs11_uri_init();
|
| |
- + if (uri == NULL)
|
| |
- + fatal("Failed to init PCKS#11 URI");
|
| |
- +
|
| |
- + /* Construct simple PKCS#11 URI to simplify access */
|
| |
- + uri->module_path = strdup(options.pkcs11_provider);
|
| |
- +
|
| |
- + /* Add it as any other IdentityFile */
|
| |
- + cp = pkcs11_uri_get(uri);
|
| |
- + add_identity_file(&options, NULL, cp, 1);
|
| |
- + free(cp);
|
| |
- +
|
| |
- + pkcs11_uri_cleanup(uri);
|
| |
- }
|
| |
- #endif /* ENABLE_PKCS11 */
|
| |
- for (i = 0; i < options.num_identity_files; i++) {
|
| |
- + char *name = options.identity_files[i];
|
| |
- if (n_ids >= SSH_MAX_IDENTITY_FILES ||
|
| |
- - strcasecmp(options.identity_files[i], "none") == 0) {
|
| |
- + strcasecmp(name, "none") == 0) {
|
| |
- free(options.identity_files[i]);
|
| |
- options.identity_files[i] = NULL;
|
| |
- continue;
|
| |
- }
|
| |
- - cp = tilde_expand_filename(options.identity_files[i], getuid());
|
| |
- +#ifdef ENABLE_PKCS11
|
| |
- + if (strlen(name) >= strlen(PKCS11_URI_SCHEME) &&
|
| |
- + strncmp(name, PKCS11_URI_SCHEME,
|
| |
- + strlen(PKCS11_URI_SCHEME)) == 0) {
|
| |
- + load_pkcs11_identity(name, identity_files,
|
| |
- + identity_keys, &n_ids);
|
| |
- + free(options.identity_files[i]);
|
| |
- + continue;
|
| |
- + }
|
| |
- +#endif /* ENABLE_PKCS11 */
|
| |
- + cp = tilde_expand_filename(name, getuid());
|
| |
- filename = percent_expand(cp, "d", pw->pw_dir,
|
| |
- "u", pw->pw_name, "l", thishost, "h", host,
|
| |
- "r", options.user, (char *)NULL);
|
| |
- diff -up openssh/ssh-keygen.c.pkcs11-uri openssh/ssh-keygen.c
|
| |
- --- openssh/ssh-keygen.c.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200
|
| |
- +++ openssh/ssh-keygen.c 2018-10-12 13:52:55.455191442 +0200
|
| |
- @@ -825,6 +825,7 @@ do_download(struct passwd *pw)
|
| |
- free(fp);
|
| |
- } else {
|
| |
- (void) sshkey_write(keys[i], stdout); /* XXX check */
|
| |
- + (void) pkcs11_uri_write(keys[i], stdout);
|
| |
- fprintf(stdout, "\n");
|
| |
- }
|
| |
- sshkey_free(keys[i]);
|
| |
- diff -up openssh/ssh-pkcs11-client.c.pkcs11-uri openssh/ssh-pkcs11-client.c
|
| |
- --- openssh/ssh-pkcs11-client.c.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200
|
| |
- +++ openssh/ssh-pkcs11-client.c 2018-10-12 13:52:55.455191442 +0200
|
| |
- @@ -126,6 +126,7 @@ pkcs11_rsa_private_encrypt(int flen, con
|
| |
- return (-1);
|
| |
- key.type = KEY_RSA;
|
| |
- key.rsa = rsa;
|
| |
- + key.ecdsa_nid = 0;
|
| |
- if ((r = sshkey_to_blob(&key, &blob, &blen)) != 0) {
|
| |
- error("%s: sshkey_to_blob: %s", __func__, ssh_err(r));
|
| |
- return -1;
|
| |
- @@ -210,6 +211,8 @@ pkcs11_add_provider(char *name, char *pi
|
| |
- u_int nkeys, i;
|
| |
- struct sshbuf *msg;
|
| |
-
|
| |
- + debug("%s: called, name = %s", __func__, name);
|
| |
- +
|
| |
- if (fd < 0 && pkcs11_start_helper() < 0)
|
| |
- return (-1);
|
| |
-
|
| |
- @@ -226,6 +229,7 @@ pkcs11_add_provider(char *name, char *pi
|
| |
- if ((r = sshbuf_get_u32(msg, &nkeys)) != 0)
|
| |
- fatal("%s: buffer error: %s", __func__, ssh_err(r));
|
| |
- *keysp = xcalloc(nkeys, sizeof(struct sshkey *));
|
| |
- + debug("%s: nkeys = %u", __func__, nkeys);
|
| |
- for (i = 0; i < nkeys; i++) {
|
| |
- /* XXX clean up properly instead of fatal() */
|
| |
- if ((r = sshbuf_get_string(msg, &blob, &blen)) != 0 ||
|
| |
- diff -up openssh/ssh-pkcs11.c.pkcs11-uri openssh/ssh-pkcs11.c
|
| |
- --- openssh/ssh-pkcs11.c.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200
|
| |
- +++ openssh/ssh-pkcs11.c 2018-10-12 13:54:35.755023297 +0200
|
| |
- @@ -49,8 +49,8 @@ struct pkcs11_slotinfo {
|
| |
- int logged_in;
|
| |
- };
|
| |
-
|
| |
- -struct pkcs11_provider {
|
| |
- - char *name;
|
| |
- +struct pkcs11_module {
|
| |
- + char *module_path;
|
| |
- void *handle;
|
| |
- CK_FUNCTION_LIST *function_list;
|
| |
- CK_INFO info;
|
| |
- @@ -59,6 +59,13 @@ struct pkcs11_provider {
|
| |
- struct pkcs11_slotinfo *slotinfo;
|
| |
- int valid;
|
| |
- int refcount;
|
| |
- +};
|
| |
- +
|
| |
- +struct pkcs11_provider {
|
| |
- + char *name;
|
| |
- + struct pkcs11_module *module; /* can be shared between various providers */
|
| |
- + int refcount;
|
| |
- + int valid;
|
| |
- TAILQ_ENTRY(pkcs11_provider) next;
|
| |
- };
|
| |
-
|
| |
- @@ -71,10 +78,46 @@ struct pkcs11_key {
|
| |
- RSA_METHOD *rsa_method;
|
| |
- char *keyid;
|
| |
- int keyid_len;
|
| |
- + char *label;
|
| |
- };
|
| |
-
|
| |
- int pkcs11_interactive = 0;
|
| |
-
|
| |
- +/*
|
| |
- + * This can't be in the ssh-pkcs11-uri, becase we can not depend on
|
| |
- + * PKCS#11 structures in ssh-agent (using client-helper communication)
|
| |
- + */
|
| |
- +int
|
| |
- +pkcs11_uri_write(const struct sshkey *key, FILE *f)
|
| |
- +{
|
| |
- + char *p = NULL;
|
| |
- + struct pkcs11_uri uri;
|
| |
- + struct pkcs11_key *k11;
|
| |
- +
|
| |
- + /* sanity - is it a RSA key with associated app_data? */
|
| |
- + if (key->type != KEY_RSA ||
|
| |
- + (k11 = RSA_get_app_data(key->rsa)) == NULL)
|
| |
- + return -1;
|
| |
- +
|
| |
- + /* omit type -- we are looking for private-public or private-certificate pairs */
|
| |
- + uri.id = k11->keyid;
|
| |
- + uri.id_len = k11->keyid_len;
|
| |
- + uri.token = k11->provider->module->slotinfo[k11->slotidx].token.label;
|
| |
- + uri.object = k11->label;
|
| |
- + uri.module_path = k11->provider->module->module_path;
|
| |
- + uri.lib_manuf = k11->provider->module->info.manufacturerID;
|
| |
- + uri.manuf = k11->provider->module->slotinfo[k11->slotidx].token.manufacturerID;
|
| |
- +
|
| |
- + p = pkcs11_uri_get(&uri);
|
| |
- + /* do not cleanup -- we do not allocate here, only reference */
|
| |
- + if (p == NULL)
|
| |
- + return -1;
|
| |
- +
|
| |
- + fprintf(f, " %s", p);
|
| |
- + free(p);
|
| |
- + return 0;
|
| |
- +}
|
| |
- +
|
| |
- int
|
| |
- pkcs11_init(int interactive)
|
| |
- {
|
| |
- @@ -90,26 +133,63 @@ pkcs11_init(int interactive)
|
| |
- * this is called when a provider gets unregistered.
|
| |
- */
|
| |
- static void
|
| |
- -pkcs11_provider_finalize(struct pkcs11_provider *p)
|
| |
- +pkcs11_module_finalize(struct pkcs11_module *m)
|
| |
- {
|
| |
- CK_RV rv;
|
| |
- CK_ULONG i;
|
| |
-
|
| |
- - debug("pkcs11_provider_finalize: %p refcount %d valid %d",
|
| |
- - p, p->refcount, p->valid);
|
| |
- - if (!p->valid)
|
| |
- + debug("%s: %p refcount %d valid %d", __func__,
|
| |
- + m, m->refcount, m->valid);
|
| |
- + if (!m->valid)
|
| |
- return;
|
| |
- - for (i = 0; i < p->nslots; i++) {
|
| |
- - if (p->slotinfo[i].session &&
|
| |
- - (rv = p->function_list->C_CloseSession(
|
| |
- - p->slotinfo[i].session)) != CKR_OK)
|
| |
- + for (i = 0; i < m->nslots; i++) {
|
| |
- + if (m->slotinfo[i].session &&
|
| |
- + (rv = m->function_list->C_CloseSession(
|
| |
- + m->slotinfo[i].session)) != CKR_OK)
|
| |
- error("C_CloseSession failed: %lu", rv);
|
| |
- }
|
| |
- - if ((rv = p->function_list->C_Finalize(NULL)) != CKR_OK)
|
| |
- + if ((rv = m->function_list->C_Finalize(NULL)) != CKR_OK)
|
| |
- error("C_Finalize failed: %lu", rv);
|
| |
- + m->valid = 0;
|
| |
- + m->function_list = NULL;
|
| |
- + dlclose(m->handle);
|
| |
- +}
|
| |
- +
|
| |
- +/*
|
| |
- + * remove a reference to the pkcs11 module.
|
| |
- + * called when a provider is unregistered.
|
| |
- + */
|
| |
- +static void
|
| |
- +pkcs11_module_unref(struct pkcs11_module *m)
|
| |
- +{
|
| |
- + debug("%s: %p refcount %d", __func__, m, m->refcount);
|
| |
- + if (--m->refcount <= 0) {
|
| |
- + pkcs11_module_finalize(m);
|
| |
- + if (m->valid)
|
| |
- + error("%s: %p still valid", __func__, m);
|
| |
- + free(m->slotlist);
|
| |
- + free(m->slotinfo);
|
| |
- + free(m->module_path);
|
| |
- + free(m);
|
| |
- + }
|
| |
- +}
|
| |
- +
|
| |
- +/*
|
| |
- + * finalize a provider shared libarary, it's no longer usable.
|
| |
- + * however, there might still be keys referencing this provider,
|
| |
- + * so the actuall freeing of memory is handled by pkcs11_provider_unref().
|
| |
- + * this is called when a provider gets unregistered.
|
| |
- + */
|
| |
- +static void
|
| |
- +pkcs11_provider_finalize(struct pkcs11_provider *p)
|
| |
- +{
|
| |
- + debug("%s: %p refcount %d valid %d", __func__,
|
| |
- + p, p->refcount, p->valid);
|
| |
- + if (!p->valid)
|
| |
- + return;
|
| |
- + pkcs11_module_unref(p->module);
|
| |
- + p->module = NULL;
|
| |
- p->valid = 0;
|
| |
- - p->function_list = NULL;
|
| |
- - dlclose(p->handle);
|
| |
- }
|
| |
-
|
| |
- /*
|
| |
- @@ -119,12 +199,11 @@ pkcs11_provider_finalize(struct pkcs11_p
|
| |
- static void
|
| |
- pkcs11_provider_unref(struct pkcs11_provider *p)
|
| |
- {
|
| |
- - debug("pkcs11_provider_unref: %p refcount %d", p, p->refcount);
|
| |
- + debug("%s: %p refcount %d", __func__, p, p->refcount);
|
| |
- if (--p->refcount <= 0) {
|
| |
- - if (p->valid)
|
| |
- - error("pkcs11_provider_unref: %p still valid", p);
|
| |
- - free(p->slotlist);
|
| |
- - free(p->slotinfo);
|
| |
- + if (p->module)
|
| |
- + pkcs11_module_unref(p->module);
|
| |
- + free(p->name);
|
| |
- free(p);
|
| |
- }
|
| |
- }
|
| |
- @@ -142,6 +221,20 @@ pkcs11_terminate(void)
|
| |
- }
|
| |
- }
|
| |
-
|
| |
- +/* lookup provider by module path */
|
| |
- +static struct pkcs11_module *
|
| |
- +pkcs11_provider_lookup_module(char *module_path)
|
| |
- +{
|
| |
- + struct pkcs11_provider *p;
|
| |
- +
|
| |
- + TAILQ_FOREACH(p, &pkcs11_providers, next) {
|
| |
- + debug("check %p %s (%s)", p, p->name, p->module->module_path);
|
| |
- + if (!strcmp(module_path, p->module->module_path))
|
| |
- + return (p->module);
|
| |
- + }
|
| |
- + return (NULL);
|
| |
- +}
|
| |
- +
|
| |
- /* lookup provider by name */
|
| |
- static struct pkcs11_provider *
|
| |
- pkcs11_provider_lookup(char *provider_id)
|
| |
- @@ -156,19 +249,52 @@ pkcs11_provider_lookup(char *provider_id
|
| |
- return (NULL);
|
| |
- }
|
| |
-
|
| |
- +int pkcs11_del_provider_by_uri(struct pkcs11_uri *);
|
| |
- +
|
| |
- /* unregister provider by name */
|
| |
- int
|
| |
- pkcs11_del_provider(char *provider_id)
|
| |
- {
|
| |
- + int rv;
|
| |
- + struct pkcs11_uri *uri;
|
| |
- +
|
| |
- + debug("%s: called, provider_id = %s", __func__, provider_id);
|
| |
- +
|
| |
- + uri = pkcs11_uri_init();
|
| |
- + if (uri == NULL)
|
| |
- + fatal("Failed to init PCKS#11 URI");
|
| |
- +
|
| |
- + if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) &&
|
| |
- + strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) {
|
| |
- + if (pkcs11_uri_parse(provider_id, uri) != 0)
|
| |
- + fatal("Failed to parse PKCS#11 URI");
|
| |
- + } else {
|
| |
- + uri->module_path = strdup(provider_id);
|
| |
- + }
|
| |
- +
|
| |
- + rv = pkcs11_del_provider_by_uri(uri);
|
| |
- + pkcs11_uri_cleanup(uri);
|
| |
- + return rv;
|
| |
- +}
|
| |
- +
|
| |
- +/* unregister provider by PKCS#11 URI */
|
| |
- +int
|
| |
- +pkcs11_del_provider_by_uri(struct pkcs11_uri *uri)
|
| |
- +{
|
| |
- struct pkcs11_provider *p;
|
| |
- + int rv = -1;
|
| |
- + char *provider_uri = pkcs11_uri_get(uri);
|
| |
-
|
| |
- - if ((p = pkcs11_provider_lookup(provider_id)) != NULL) {
|
| |
- + debug3("%s(%s): called", __func__, provider_uri);
|
| |
- +
|
| |
- + if ((p = pkcs11_provider_lookup(provider_uri)) != NULL) {
|
| |
- TAILQ_REMOVE(&pkcs11_providers, p, next);
|
| |
- pkcs11_provider_finalize(p);
|
| |
- pkcs11_provider_unref(p);
|
| |
- - return (0);
|
| |
- + rv = 0;
|
| |
- }
|
| |
- - return (-1);
|
| |
- + free(provider_uri);
|
| |
- + return rv;
|
| |
- }
|
| |
-
|
| |
- /* openssl callback for freeing an RSA key */
|
| |
- @@ -185,6 +311,7 @@ pkcs11_rsa_finish(RSA *rsa)
|
| |
- pkcs11_provider_unref(k11->provider);
|
| |
- RSA_meth_free(k11->rsa_method);
|
| |
- free(k11->keyid);
|
| |
- + free(k11->label);
|
| |
- free(k11);
|
| |
- }
|
| |
- return (rv);
|
| |
- @@ -201,8 +328,8 @@ pkcs11_find(struct pkcs11_provider *p, C
|
| |
- CK_RV rv;
|
| |
- int ret = -1;
|
| |
-
|
| |
- - f = p->function_list;
|
| |
- - session = p->slotinfo[slotidx].session;
|
| |
- + f = p->module->function_list;
|
| |
- + session = p->module->slotinfo[slotidx].session;
|
| |
- if ((rv = f->C_FindObjectsInit(session, attr, nattr)) != CKR_OK) {
|
| |
- error("C_FindObjectsInit failed (nattr %lu): %lu", nattr, rv);
|
| |
- return (-1);
|
| |
- @@ -249,12 +376,13 @@ pkcs11_rsa_private_encrypt(int flen, con
|
| |
- error("RSA_get_app_data failed for rsa %p", rsa);
|
| |
- return (-1);
|
| |
- }
|
| |
- - if (!k11->provider || !k11->provider->valid) {
|
| |
- + if (!k11->provider || !k11->provider->valid || !k11->provider->module
|
| |
- + || !k11->provider->module->valid) {
|
| |
- error("no pkcs11 (valid) provider for rsa %p", rsa);
|
| |
- return (-1);
|
| |
- }
|
| |
- - f = k11->provider->function_list;
|
| |
- - si = &k11->provider->slotinfo[k11->slotidx];
|
| |
- + f = k11->provider->module->function_list;
|
| |
- + si = &k11->provider->module->slotinfo[k11->slotidx];
|
| |
- if ((si->token.flags & CKF_LOGIN_REQUIRED) && !si->logged_in) {
|
| |
- if (!pkcs11_interactive) {
|
| |
- error("need pin entry%s", (si->token.flags &
|
| |
- @@ -313,7 +441,7 @@ pkcs11_rsa_private_decrypt(int flen, con
|
| |
- /* redirect private key operations for rsa key to pkcs11 token */
|
| |
- static int
|
| |
- pkcs11_rsa_wrap(struct pkcs11_provider *provider, CK_ULONG slotidx,
|
| |
- - CK_ATTRIBUTE *keyid_attrib, RSA *rsa)
|
| |
- + CK_ATTRIBUTE *keyid_attrib, CK_ATTRIBUTE *label_attrib, RSA *rsa)
|
| |
- {
|
| |
- struct pkcs11_key *k11;
|
| |
- const RSA_METHOD *def = RSA_get_default_method();
|
| |
- @@ -328,6 +456,11 @@ pkcs11_rsa_wrap(struct pkcs11_provider *
|
| |
- k11->keyid = xmalloc(k11->keyid_len);
|
| |
- memcpy(k11->keyid, keyid_attrib->pValue, k11->keyid_len);
|
| |
- }
|
| |
- + if (label_attrib->ulValueLen > 0 ) {
|
| |
- + k11->label = xmalloc(label_attrib->ulValueLen+1);
|
| |
- + memcpy(k11->label, label_attrib->pValue, label_attrib->ulValueLen);
|
| |
- + k11->label[label_attrib->ulValueLen] = 0;
|
| |
- + }
|
| |
- k11->rsa_method = RSA_meth_dup(def);
|
| |
- if (k11->rsa_method == NULL)
|
| |
- fatal("%s: RSA_meth_dup failed", __func__);
|
| |
- @@ -371,16 +504,16 @@ pkcs11_open_session(struct pkcs11_provid
|
| |
- CK_SESSION_HANDLE session;
|
| |
- int login_required;
|
| |
-
|
| |
- - f = p->function_list;
|
| |
- - login_required = p->slotinfo[slotidx].token.flags & CKF_LOGIN_REQUIRED;
|
| |
- + f = p->module->function_list;
|
| |
- + login_required = p->module->slotinfo[slotidx].token.flags & CKF_LOGIN_REQUIRED;
|
| |
- if (pin && login_required && !strlen(pin)) {
|
| |
- error("pin required");
|
| |
- return (-1);
|
| |
- }
|
| |
- - if ((rv = f->C_OpenSession(p->slotlist[slotidx], CKF_RW_SESSION|
|
| |
- + if ((rv = f->C_OpenSession(p->module->slotlist[slotidx], CKF_RW_SESSION|
|
| |
- CKF_SERIAL_SESSION, NULL, NULL, &session))
|
| |
- != CKR_OK) {
|
| |
- - error("C_OpenSession failed: %lu", rv);
|
| |
- + error("C_OpenSession failed for slot %lu: %lu", slotidx, rv);
|
| |
- return (-1);
|
| |
- }
|
| |
- if (login_required && pin) {
|
| |
- @@ -392,9 +525,9 @@ pkcs11_open_session(struct pkcs11_provid
|
| |
- error("C_CloseSession failed: %lu", rv);
|
| |
- return (-1);
|
| |
- }
|
| |
- - p->slotinfo[slotidx].logged_in = 1;
|
| |
- + p->module->slotinfo[slotidx].logged_in = 1;
|
| |
- }
|
| |
- - p->slotinfo[slotidx].session = session;
|
| |
- + p->module->slotinfo[slotidx].session = session;
|
| |
- return (0);
|
| |
- }
|
| |
-
|
| |
- @@ -404,39 +537,72 @@ pkcs11_open_session(struct pkcs11_provid
|
| |
- * keysp points to an (possibly empty) array with *nkeys keys.
|
| |
- */
|
| |
- static int pkcs11_fetch_keys_filter(struct pkcs11_provider *, CK_ULONG,
|
| |
- - CK_ATTRIBUTE [], CK_ATTRIBUTE [3], struct sshkey ***, int *)
|
| |
- + CK_ATTRIBUTE [], size_t, CK_ATTRIBUTE [3], struct sshkey ***, int *)
|
| |
- __attribute__((__bounded__(__minbytes__,4, 3 * sizeof(CK_ATTRIBUTE))));
|
| |
-
|
| |
- static int
|
| |
- pkcs11_fetch_keys(struct pkcs11_provider *p, CK_ULONG slotidx,
|
| |
- - struct sshkey ***keysp, int *nkeys)
|
| |
- + struct sshkey ***keysp, int *nkeys, struct pkcs11_uri *uri)
|
| |
- {
|
| |
- + size_t filter_size = 1;
|
| |
- CK_OBJECT_CLASS pubkey_class = CKO_PUBLIC_KEY;
|
| |
- CK_OBJECT_CLASS cert_class = CKO_CERTIFICATE;
|
| |
- CK_ATTRIBUTE pubkey_filter[] = {
|
| |
- - { CKA_CLASS, NULL, sizeof(pubkey_class) }
|
| |
- + { CKA_CLASS, NULL, sizeof(pubkey_class) },
|
| |
- + { CKA_ID, NULL, 0 },
|
| |
- + { CKA_LABEL, NULL, 0 }
|
| |
- };
|
| |
- CK_ATTRIBUTE cert_filter[] = {
|
| |
- - { CKA_CLASS, NULL, sizeof(cert_class) }
|
| |
- + { CKA_CLASS, NULL, sizeof(cert_class) },
|
| |
- + { CKA_ID, NULL, 0 },
|
| |
- + { CKA_LABEL, NULL, 0 }
|
| |
- };
|
| |
- CK_ATTRIBUTE pubkey_attribs[] = {
|
| |
- { CKA_ID, NULL, 0 },
|
| |
- + { CKA_LABEL, NULL, 0 },
|
| |
- { CKA_MODULUS, NULL, 0 },
|
| |
- { CKA_PUBLIC_EXPONENT, NULL, 0 }
|
| |
- };
|
| |
- CK_ATTRIBUTE cert_attribs[] = {
|
| |
- { CKA_ID, NULL, 0 },
|
| |
- + { CKA_LABEL, NULL, 0 },
|
| |
- { CKA_SUBJECT, NULL, 0 },
|
| |
- { CKA_VALUE, NULL, 0 }
|
| |
- };
|
| |
- pubkey_filter[0].pValue = &pubkey_class;
|
| |
- cert_filter[0].pValue = &cert_class;
|
| |
-
|
| |
- - if (pkcs11_fetch_keys_filter(p, slotidx, pubkey_filter, pubkey_attribs,
|
| |
- - keysp, nkeys) < 0 ||
|
| |
- - pkcs11_fetch_keys_filter(p, slotidx, cert_filter, cert_attribs,
|
| |
- - keysp, nkeys) < 0)
|
| |
- + if (uri->id != NULL) {
|
| |
- + pubkey_filter[filter_size].pValue = uri->id;
|
| |
- + pubkey_filter[filter_size].ulValueLen = uri->id_len;
|
| |
- + cert_filter[filter_size].pValue = uri->id;
|
| |
- + cert_filter[filter_size].ulValueLen = uri->id_len;
|
| |
- + filter_size++;
|
| |
- + }
|
| |
- + if (uri->object != NULL) {
|
| |
- + pubkey_filter[filter_size].pValue = uri->object;
|
| |
- + pubkey_filter[filter_size].ulValueLen = strlen(uri->object);
|
| |
- + pubkey_filter[filter_size].type = CKA_LABEL;
|
| |
- + cert_filter[filter_size].pValue = uri->object;
|
| |
- + cert_filter[filter_size].ulValueLen = strlen(uri->object);
|
| |
- + cert_filter[filter_size].type = CKA_LABEL;
|
| |
- + filter_size++;
|
| |
- + }
|
| |
- +
|
| |
- + if (pkcs11_fetch_keys_filter(p, slotidx, pubkey_filter, filter_size,
|
| |
- + pubkey_attribs, keysp, nkeys) < 0 ||
|
| |
- + pkcs11_fetch_keys_filter(p, slotidx, cert_filter, filter_size,
|
| |
- + cert_attribs, keysp, nkeys) < 0)
|
| |
- return (-1);
|
| |
- + if (*nkeys == 0) {
|
| |
- + /* Try once more without the label filter */
|
| |
- + filter_size--;
|
| |
- + if (pkcs11_fetch_keys_filter(p, slotidx, pubkey_filter, filter_size,
|
| |
- + pubkey_attribs, keysp, nkeys) < 0 ||
|
| |
- + pkcs11_fetch_keys_filter(p, slotidx, cert_filter, filter_size,
|
| |
- + cert_attribs, keysp, nkeys) < 0)
|
| |
- + return (-1);
|
| |
- + }
|
| |
- return (0);
|
| |
- }
|
| |
-
|
| |
- @@ -462,14 +619,15 @@ have_rsa_key(const RSA *rsa)
|
| |
-
|
| |
- static int
|
| |
- pkcs11_fetch_keys_filter(struct pkcs11_provider *p, CK_ULONG slotidx,
|
| |
- - CK_ATTRIBUTE filter[], CK_ATTRIBUTE attribs[3],
|
| |
- + CK_ATTRIBUTE filter[], size_t filter_size, CK_ATTRIBUTE attribs[4],
|
| |
- struct sshkey ***keysp, int *nkeys)
|
| |
- {
|
| |
- struct sshkey *key;
|
| |
- RSA *rsa;
|
| |
- X509 *x509;
|
| |
- - EVP_PKEY *evp;
|
| |
- + EVP_PKEY *evp = NULL;
|
| |
- int i;
|
| |
- + int nattribs = 4;
|
| |
- const u_char *cp;
|
| |
- CK_RV rv;
|
| |
- CK_OBJECT_HANDLE obj;
|
| |
- @@ -477,16 +635,15 @@ pkcs11_fetch_keys_filter(struct pkcs11_p
|
| |
- CK_SESSION_HANDLE session;
|
| |
- CK_FUNCTION_LIST *f;
|
| |
-
|
| |
- - f = p->function_list;
|
| |
- - session = p->slotinfo[slotidx].session;
|
| |
- + f = p->module->function_list;
|
| |
- + session = p->module->slotinfo[slotidx].session;
|
| |
- /* setup a filter the looks for public keys */
|
| |
- - if ((rv = f->C_FindObjectsInit(session, filter, 1)) != CKR_OK) {
|
| |
- + if ((rv = f->C_FindObjectsInit(session, filter, filter_size)) != CKR_OK) {
|
| |
- error("C_FindObjectsInit failed: %lu", rv);
|
| |
- return (-1);
|
| |
- }
|
| |
- while (1) {
|
| |
- - /* XXX 3 attributes in attribs[] */
|
| |
- - for (i = 0; i < 3; i++) {
|
| |
- + for (i = 0; i < nattribs; i++) {
|
| |
- attribs[i].pValue = NULL;
|
| |
- attribs[i].ulValueLen = 0;
|
| |
- }
|
| |
- @@ -494,22 +651,22 @@ pkcs11_fetch_keys_filter(struct pkcs11_p
|
| |
- || nfound == 0)
|
| |
- break;
|
| |
- /* found a key, so figure out size of the attributes */
|
| |
- - if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3))
|
| |
- + if ((rv = f->C_GetAttributeValue(session, obj, attribs, nattribs))
|
| |
- != CKR_OK) {
|
| |
- error("C_GetAttributeValue failed: %lu", rv);
|
| |
- continue;
|
| |
- }
|
| |
- /*
|
| |
- - * Allow CKA_ID (always first attribute) to be empty, but
|
| |
- - * ensure that none of the others are zero length.
|
| |
- + * Allow CKA_ID (always first attribute) and CKA_LABEL (second)
|
| |
- + * to be empty, but ensure that none of the others are zero length.
|
| |
- * XXX assumes CKA_ID is always first.
|
| |
- */
|
| |
- - if (attribs[1].ulValueLen == 0 ||
|
| |
- - attribs[2].ulValueLen == 0) {
|
| |
- + if (attribs[2].ulValueLen == 0 ||
|
| |
- + attribs[3].ulValueLen == 0) {
|
| |
- continue;
|
| |
- }
|
| |
- /* allocate buffers for attributes */
|
| |
- - for (i = 0; i < 3; i++) {
|
| |
- + for (i = 0; i < nattribs; i++) {
|
| |
- if (attribs[i].ulValueLen > 0) {
|
| |
- attribs[i].pValue = xmalloc(
|
| |
- attribs[i].ulValueLen);
|
| |
- @@ -517,23 +674,23 @@ pkcs11_fetch_keys_filter(struct pkcs11_p
|
| |
- }
|
| |
-
|
| |
- /*
|
| |
- - * retrieve ID, modulus and public exponent of RSA key,
|
| |
- - * or ID, subject and value for certificates.
|
| |
- + * retrieve ID, label, modulus and public exponent of RSA key,
|
| |
- + * or ID, label, subject and value for certificates.
|
| |
- */
|
| |
- rsa = NULL;
|
| |
- - if ((rv = f->C_GetAttributeValue(session, obj, attribs, 3))
|
| |
- + if ((rv = f->C_GetAttributeValue(session, obj, attribs, nattribs))
|
| |
- != CKR_OK) {
|
| |
- error("C_GetAttributeValue failed: %lu", rv);
|
| |
- - } else if (attribs[1].type == CKA_MODULUS ) {
|
| |
- + } else if (attribs[2].type == CKA_MODULUS ) {
|
| |
- if ((rsa = RSA_new()) == NULL) {
|
| |
- error("RSA_new failed");
|
| |
- } else {
|
| |
- BIGNUM *rsa_n, *rsa_e;
|
| |
-
|
| |
- - rsa_n = BN_bin2bn(attribs[1].pValue,
|
| |
- - attribs[1].ulValueLen, NULL);
|
| |
- - rsa_e = BN_bin2bn(attribs[2].pValue,
|
| |
- + rsa_n = BN_bin2bn(attribs[2].pValue,
|
| |
- attribs[2].ulValueLen, NULL);
|
| |
- + rsa_e = BN_bin2bn(attribs[3].pValue,
|
| |
- + attribs[3].ulValueLen, NULL);
|
| |
- if (rsa_n != NULL && rsa_e != NULL) {
|
| |
- if (!RSA_set0_key(rsa,
|
| |
- rsa_n, rsa_e, NULL))
|
| |
- @@ -544,10 +701,10 @@ pkcs11_fetch_keys_filter(struct pkcs11_p
|
| |
- BN_free(rsa_e);
|
| |
- }
|
| |
- } else {
|
| |
- - cp = attribs[2].pValue;
|
| |
- + cp = attribs[3].pValue;
|
| |
- if ((x509 = X509_new()) == NULL) {
|
| |
- error("X509_new failed");
|
| |
- - } else if (d2i_X509(&x509, &cp, attribs[2].ulValueLen)
|
| |
- + } else if (d2i_X509(&x509, &cp, attribs[3].ulValueLen)
|
| |
- == NULL) {
|
| |
- error("d2i_X509 failed");
|
| |
- } else if ((evp = X509_get_pubkey(x509)) == NULL ||
|
| |
- @@ -559,9 +716,10 @@ pkcs11_fetch_keys_filter(struct pkcs11_p
|
| |
- error("RSAPublicKey_dup");
|
| |
- }
|
| |
- X509_free(x509);
|
| |
- + EVP_PKEY_free(evp);
|
| |
- }
|
| |
- if (rsa && have_rsa_key(rsa) &&
|
| |
- - pkcs11_rsa_wrap(p, slotidx, &attribs[0], rsa) == 0) {
|
| |
- + pkcs11_rsa_wrap(p, slotidx, &attribs[0], &attribs[1], rsa) == 0) {
|
| |
- if ((key = sshkey_new(KEY_UNSPEC)) == NULL)
|
| |
- fatal("sshkey_new failed");
|
| |
- key->rsa = rsa;
|
| |
- @@ -580,7 +738,7 @@ pkcs11_fetch_keys_filter(struct pkcs11_p
|
| |
- } else if (rsa) {
|
| |
- RSA_free(rsa);
|
| |
- }
|
| |
- - for (i = 0; i < 3; i++)
|
| |
- + for (i = 0; i < nattribs; i++)
|
| |
- free(attribs[i].pValue);
|
| |
- }
|
| |
- if ((rv = f->C_FindObjectsFinal(session)) != CKR_OK)
|
| |
- @@ -592,126 +750,240 @@ pkcs11_fetch_keys_filter(struct pkcs11_p
|
| |
- int
|
| |
- pkcs11_add_provider(char *provider_id, char *pin, struct sshkey ***keyp)
|
| |
- {
|
| |
- - int nkeys, need_finalize = 0;
|
| |
- - struct pkcs11_provider *p = NULL;
|
| |
- + int rv;
|
| |
- + struct pkcs11_uri *uri;
|
| |
- +
|
| |
- + debug("%s: called, provider_id = %s", __func__, provider_id);
|
| |
- +
|
| |
- + uri = pkcs11_uri_init();
|
| |
- + if (uri == NULL)
|
| |
- + fatal("Failed to init PCKS#11 URI");
|
| |
- +
|
| |
- + if (strlen(provider_id) >= strlen(PKCS11_URI_SCHEME) &&
|
| |
- + strncmp(provider_id, PKCS11_URI_SCHEME, strlen(PKCS11_URI_SCHEME)) == 0) {
|
| |
- + if (pkcs11_uri_parse(provider_id, uri) != 0)
|
| |
- + fatal("Failed to parse PKCS#11 URI");
|
| |
- + } else {
|
| |
- + uri->module_path = strdup(provider_id);
|
| |
- + }
|
| |
- +
|
| |
- + rv = pkcs11_add_provider_by_uri(uri, pin, keyp);
|
| |
- + pkcs11_uri_cleanup(uri);
|
| |
- + return rv;
|
| |
- +}
|
| |
- +
|
| |
- +struct pkcs11_provider *
|
| |
- +pkcs11_provider_initialize(struct pkcs11_uri *uri)
|
| |
- +{
|
| |
- + int need_finalize = 0;
|
| |
- void *handle = NULL;
|
| |
- CK_RV (*getfunctionlist)(CK_FUNCTION_LIST **);
|
| |
- CK_RV rv;
|
| |
- CK_FUNCTION_LIST *f = NULL;
|
| |
- CK_TOKEN_INFO *token;
|
| |
- CK_ULONG i;
|
| |
- + char *provider_module = NULL;
|
| |
- + struct pkcs11_provider *p;
|
| |
- + struct pkcs11_module *m;
|
| |
-
|
| |
- - *keyp = NULL;
|
| |
- - if (pkcs11_provider_lookup(provider_id) != NULL) {
|
| |
- - debug("%s: provider already registered: %s",
|
| |
- - __func__, provider_id);
|
| |
- + /* if no provider specified, fallback to p11-kit */
|
| |
- + if (uri->module_path == NULL) {
|
| |
- +#ifdef PKCS11_DEFAULT_PROVIDER
|
| |
- + provider_module = strdup(PKCS11_DEFAULT_PROVIDER);
|
| |
- +#else
|
| |
- + error("%s: No module path provided", __func__);
|
| |
- goto fail;
|
| |
- +#endif
|
| |
- + } else
|
| |
- + provider_module = strdup(uri->module_path);
|
| |
- +
|
| |
- + p = xcalloc(1, sizeof(*p));
|
| |
- + p->name = pkcs11_uri_get(uri);
|
| |
- +
|
| |
- + if ((m = pkcs11_provider_lookup_module(provider_module)) != NULL
|
| |
- + && m->valid) {
|
| |
- + debug("%s: provider module already initialized: %s",
|
| |
- + __func__, provider_module);
|
| |
- + free(provider_module);
|
| |
- + /* Skip the initialization of PKCS#11 module */
|
| |
- + m->refcount++;
|
| |
- + p->module = m;
|
| |
- + p->valid = 1;
|
| |
- + TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
|
| |
- + p->refcount++; /* add to provider list */
|
| |
- + return p;
|
| |
- + } else {
|
| |
- + m = xcalloc(1, sizeof(*m));
|
| |
- + p->module = m;
|
| |
- + m->refcount++;
|
| |
- }
|
| |
- +
|
| |
- /* open shared pkcs11-libarary */
|
| |
- - if ((handle = dlopen(provider_id, RTLD_NOW)) == NULL) {
|
| |
- - error("dlopen %s failed: %s", provider_id, dlerror());
|
| |
- + if ((handle = dlopen(provider_module, RTLD_NOW)) == NULL) {
|
| |
- + error("dlopen %s failed: %s", provider_module, dlerror());
|
| |
- goto fail;
|
| |
- }
|
| |
- if ((getfunctionlist = dlsym(handle, "C_GetFunctionList")) == NULL) {
|
| |
- error("dlsym(C_GetFunctionList) failed: %s", dlerror());
|
| |
- goto fail;
|
| |
- }
|
| |
- - p = xcalloc(1, sizeof(*p));
|
| |
- - p->name = xstrdup(provider_id);
|
| |
- - p->handle = handle;
|
| |
- + m->handle = handle;
|
| |
- /* setup the pkcs11 callbacks */
|
| |
- if ((rv = (*getfunctionlist)(&f)) != CKR_OK) {
|
| |
- error("C_GetFunctionList for provider %s failed: %lu",
|
| |
- - provider_id, rv);
|
| |
- + provider_module, rv);
|
| |
- goto fail;
|
| |
- }
|
| |
- - p->function_list = f;
|
| |
- + m->function_list = f;
|
| |
- if ((rv = f->C_Initialize(NULL)) != CKR_OK) {
|
| |
- error("C_Initialize for provider %s failed: %lu",
|
| |
- - provider_id, rv);
|
| |
- + provider_module, rv);
|
| |
- goto fail;
|
| |
- }
|
| |
- need_finalize = 1;
|
| |
- - if ((rv = f->C_GetInfo(&p->info)) != CKR_OK) {
|
| |
- + if ((rv = f->C_GetInfo(&m->info)) != CKR_OK) {
|
| |
- error("C_GetInfo for provider %s failed: %lu",
|
| |
- - provider_id, rv);
|
| |
- + provider_module, rv);
|
| |
- + goto fail;
|
| |
- + }
|
| |
- + rmspace(m->info.manufacturerID, sizeof(m->info.manufacturerID));
|
| |
- + if (uri->lib_manuf != NULL &&
|
| |
- + strcmp(uri->lib_manuf, m->info.manufacturerID)) {
|
| |
- + debug("%s: Skipping provider %s not matching library_manufacturer",
|
| |
- + __func__, m->info.manufacturerID);
|
| |
- goto fail;
|
| |
- }
|
| |
- - rmspace(p->info.manufacturerID, sizeof(p->info.manufacturerID));
|
| |
- - rmspace(p->info.libraryDescription, sizeof(p->info.libraryDescription));
|
| |
- + rmspace(m->info.libraryDescription, sizeof(m->info.libraryDescription));
|
| |
- debug("provider %s: manufacturerID <%s> cryptokiVersion %d.%d"
|
| |
- " libraryDescription <%s> libraryVersion %d.%d",
|
| |
- - provider_id,
|
| |
- - p->info.manufacturerID,
|
| |
- - p->info.cryptokiVersion.major,
|
| |
- - p->info.cryptokiVersion.minor,
|
| |
- - p->info.libraryDescription,
|
| |
- - p->info.libraryVersion.major,
|
| |
- - p->info.libraryVersion.minor);
|
| |
- - if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &p->nslots)) != CKR_OK) {
|
| |
- + provider_module,
|
| |
- + m->info.manufacturerID,
|
| |
- + m->info.cryptokiVersion.major,
|
| |
- + m->info.cryptokiVersion.minor,
|
| |
- + m->info.libraryDescription,
|
| |
- + m->info.libraryVersion.major,
|
| |
- + m->info.libraryVersion.minor);
|
| |
- +
|
| |
- + if ((rv = f->C_GetSlotList(CK_TRUE, NULL, &m->nslots)) != CKR_OK) {
|
| |
- error("C_GetSlotList failed: %lu", rv);
|
| |
- goto fail;
|
| |
- }
|
| |
- - if (p->nslots == 0) {
|
| |
- + if (m->nslots == 0) {
|
| |
- debug("%s: provider %s returned no slots", __func__,
|
| |
- - provider_id);
|
| |
- + provider_module);
|
| |
- goto fail;
|
| |
- }
|
| |
- - p->slotlist = xcalloc(p->nslots, sizeof(CK_SLOT_ID));
|
| |
- - if ((rv = f->C_GetSlotList(CK_TRUE, p->slotlist, &p->nslots))
|
| |
- + m->slotlist = xcalloc(m->nslots, sizeof(CK_SLOT_ID));
|
| |
- + if ((rv = f->C_GetSlotList(CK_TRUE, m->slotlist, &m->nslots))
|
| |
- != CKR_OK) {
|
| |
- error("C_GetSlotList for provider %s failed: %lu",
|
| |
- - provider_id, rv);
|
| |
- + provider_module, rv);
|
| |
- goto fail;
|
| |
- }
|
| |
- - p->slotinfo = xcalloc(p->nslots, sizeof(struct pkcs11_slotinfo));
|
| |
- + m->slotinfo = xcalloc(m->nslots, sizeof(struct pkcs11_slotinfo));
|
| |
- + m->valid = 1;
|
| |
- p->valid = 1;
|
| |
- - nkeys = 0;
|
| |
- - for (i = 0; i < p->nslots; i++) {
|
| |
- - token = &p->slotinfo[i].token;
|
| |
- - if ((rv = f->C_GetTokenInfo(p->slotlist[i], token))
|
| |
- +
|
| |
- + for (i = 0; i < m->nslots; i++) {
|
| |
- + token = &m->slotinfo[i].token;
|
| |
- + if ((rv = f->C_GetTokenInfo(m->slotlist[i], token))
|
| |
- != CKR_OK) {
|
| |
- error("C_GetTokenInfo for provider %s slot %lu "
|
| |
- - "failed: %lu", provider_id, (unsigned long)i, rv);
|
| |
- + "failed: %lu", provider_module, (unsigned long)i, rv);
|
| |
- continue;
|
| |
- }
|
| |
- if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
|
| |
- - debug2("%s: ignoring uninitialised token in "
|
| |
- - "provider %s slot %lu", __func__,
|
| |
- - provider_id, (unsigned long)i);
|
| |
- continue;
|
| |
- }
|
| |
- rmspace(token->label, sizeof(token->label));
|
| |
- rmspace(token->manufacturerID, sizeof(token->manufacturerID));
|
| |
- rmspace(token->model, sizeof(token->model));
|
| |
- rmspace(token->serialNumber, sizeof(token->serialNumber));
|
| |
- + }
|
| |
- + m->module_path = provider_module;
|
| |
- + provider_module = NULL;
|
| |
- +
|
| |
- + /* insert unconditionally -- remove if there will be no keys later */
|
| |
- + TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
|
| |
- + p->refcount++; /* add to provider list */
|
| |
- + return p;
|
| |
- +
|
| |
- +fail:
|
| |
- + if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
|
| |
- + error("C_Finalize for provider %s failed: %lu",
|
| |
- + provider_module, rv);
|
| |
- + free(provider_module);
|
| |
- + free(p);
|
| |
- + if (handle)
|
| |
- + dlclose(handle);
|
| |
- + return NULL;
|
| |
- +}
|
| |
- +
|
| |
- +int
|
| |
- +pkcs11_add_provider_by_uri(struct pkcs11_uri *uri, char *pin, struct sshkey ***keyp)
|
| |
- +{
|
| |
- + int nkeys;
|
| |
- + struct pkcs11_provider *p = NULL;
|
| |
- + CK_TOKEN_INFO *token;
|
| |
- + CK_ULONG i;
|
| |
- + char *provider_uri = pkcs11_uri_get(uri);
|
| |
- +
|
| |
- + debug("%s: called, provider_uri = %s", __func__, provider_uri);
|
| |
- +
|
| |
- + *keyp = NULL;
|
| |
- + if ((p = pkcs11_provider_initialize(uri)) == NULL) {
|
| |
- + debug("%s: failed to initialize provider: %s",
|
| |
- + __func__, provider_uri);
|
| |
- + goto fail;
|
| |
- + }
|
| |
- +
|
| |
- + nkeys = 0;
|
| |
- + for (i = 0; i < p->module->nslots; i++) {
|
| |
- + token = &p->module->slotinfo[i].token;
|
| |
- + if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) {
|
| |
- + debug2("%s: ignoring uninitialised token in "
|
| |
- + "provider %s slot %lu", __func__,
|
| |
- + provider_uri, (unsigned long)i);
|
| |
- + continue;
|
| |
- + }
|
| |
- + if (uri->token != NULL &&
|
| |
- + strcmp(token->label, uri->token) != 0) {
|
| |
- + debug2("%s: ignoring token not matching label (%s) "
|
| |
- + "specified by PKCS#11 URI in slot %lu", __func__,
|
| |
- + token->label, (unsigned long)i);
|
| |
- + continue;
|
| |
- + }
|
| |
- + if (uri->manuf != NULL &&
|
| |
- + strcmp(token->manufacturerID, uri->manuf) != 0) {
|
| |
- + debug2("%s: ignoring token not matching requrested "
|
| |
- + "manufacturerID (%s) specified by PKCS#11 URI in "
|
| |
- + "slot %lu", __func__,
|
| |
- + token->manufacturerID, (unsigned long)i);
|
| |
- + continue;
|
| |
- + }
|
| |
- debug("provider %s slot %lu: label <%s> manufacturerID <%s> "
|
| |
- "model <%s> serial <%s> flags 0x%lx",
|
| |
- - provider_id, (unsigned long)i,
|
| |
- + provider_uri, (unsigned long)i,
|
| |
- token->label, token->manufacturerID, token->model,
|
| |
- token->serialNumber, token->flags);
|
| |
- - /* open session, login with pin and retrieve public keys */
|
| |
- - if (pkcs11_open_session(p, i, pin) == 0)
|
| |
- - pkcs11_fetch_keys(p, i, keyp, &nkeys);
|
| |
- + /* open session if not yet opened, login with pin
|
| |
- + * and retrieve public keys */
|
| |
- + if ((p->module->slotinfo[i].session != 0) ||
|
| |
- + pkcs11_open_session(p, i, pin) == 0)
|
| |
- + pkcs11_fetch_keys(p, i, keyp, &nkeys, uri);
|
| |
- }
|
| |
- if (nkeys > 0) {
|
| |
- - TAILQ_INSERT_TAIL(&pkcs11_providers, p, next);
|
| |
- - p->refcount++; /* add to provider list */
|
| |
- + free(provider_uri);
|
| |
- return (nkeys);
|
| |
- }
|
| |
- - debug("%s: provider %s returned no keys", __func__, provider_id);
|
| |
- + debug("%s: provider %s returned no keys", __func__, provider_uri);
|
| |
- /* don't add the provider, since it does not have any keys */
|
| |
- fail:
|
| |
- - if (need_finalize && (rv = f->C_Finalize(NULL)) != CKR_OK)
|
| |
- - error("C_Finalize for provider %s failed: %lu",
|
| |
- - provider_id, rv);
|
| |
- if (p) {
|
| |
- - free(p->slotlist);
|
| |
- - free(p->slotinfo);
|
| |
- - free(p);
|
| |
- + TAILQ_REMOVE(&pkcs11_providers, p, next);
|
| |
- + pkcs11_provider_unref(p);
|
| |
- }
|
| |
- - if (handle)
|
| |
- - dlclose(handle);
|
| |
- + free(provider_uri);
|
| |
- return (-1);
|
| |
- }
|
| |
-
|
| |
- diff -up openssh/ssh-pkcs11.h.pkcs11-uri openssh/ssh-pkcs11.h
|
| |
- --- openssh/ssh-pkcs11.h.pkcs11-uri 2018-10-11 02:56:36.000000000 +0200
|
| |
- +++ openssh/ssh-pkcs11.h 2018-10-12 13:52:55.457191459 +0200
|
| |
- @@ -14,10 +14,15 @@
|
| |
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
| |
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
| |
- */
|
| |
- +
|
| |
- +#include "ssh-pkcs11-uri.h"
|
| |
- +
|
| |
- int pkcs11_init(int);
|
| |
- void pkcs11_terminate(void);
|
| |
- int pkcs11_add_provider(char *, char *, struct sshkey ***);
|
| |
- +int pkcs11_add_provider_by_uri(struct pkcs11_uri *, char *, struct sshkey ***);
|
| |
- int pkcs11_del_provider(char *);
|
| |
- +int pkcs11_uri_write(const struct sshkey *, FILE *);
|
| |
-
|
| |
- #if !defined(WITH_OPENSSL) && defined(ENABLE_PKCS11)
|
| |
- #undef ENABLE_PKCS11
|
| |
- diff -up openssh/ssh-pkcs11-uri.c.pkcs11-uri openssh/ssh-pkcs11-uri.c
|
| |
- --- openssh/ssh-pkcs11-uri.c.pkcs11-uri 2018-10-12 13:52:55.456191450 +0200
|
| |
- +++ openssh/ssh-pkcs11-uri.c 2018-10-12 13:52:55.455191442 +0200
|
| |
- @@ -0,0 +1,395 @@
|
| |
- +/*
|
| |
- + * Copyright (c) 2017 Red Hat
|
| |
- + *
|
| |
- + * Authors: Jakub Jelen <jjelen@redhat.com>
|
| |
- + *
|
| |
- + * Permission to use, copy, modify, and distribute this software for any
|
| |
- + * purpose with or without fee is hereby granted, provided that the above
|
| |
- + * copyright notice and this permission notice appear in all copies.
|
| |
- + *
|
| |
- + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
| |
- + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
| |
- + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
| |
- + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
| |
- + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
| |
- + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
| |
- + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
| |
- + */
|
| |
- +
|
| |
- +#include "includes.h"
|
| |
- +
|
| |
- +#ifdef ENABLE_PKCS11
|
| |
- +
|
| |
- +#include <stdio.h>
|
| |
- +#include <string.h>
|
| |
- +
|
| |
- +#include "sshkey.h"
|
| |
- +#include "sshbuf.h"
|
| |
- +#include "log.h"
|
| |
- +
|
| |
- +#define CRYPTOKI_COMPAT
|
| |
- +#include "pkcs11.h"
|
| |
- +
|
| |
- +#include "ssh-pkcs11-uri.h"
|
| |
- +
|
| |
- +#define PKCS11_URI_PATH_SEPARATOR ";"
|
| |
- +#define PKCS11_URI_QUERY_SEPARATOR "&"
|
| |
- +#define PKCS11_URI_VALUE_SEPARATOR "="
|
| |
- +#define PKCS11_URI_ID "id"
|
| |
- +#define PKCS11_URI_TOKEN "token"
|
| |
- +#define PKCS11_URI_OBJECT "object"
|
| |
- +#define PKCS11_URI_LIB_MANUF "library-manufacturer"
|
| |
- +#define PKCS11_URI_MANUF "manufacturer"
|
| |
- +#define PKCS11_URI_MODULE_PATH "module-path"
|
| |
- +
|
| |
- +/* Keyword tokens. */
|
| |
- +typedef enum {
|
| |
- + pId, pToken, pObject, pLibraryManufacturer, pManufacturer, pModulePath,
|
| |
- + pBadOption
|
| |
- +} pkcs11uriOpCodes;
|
| |
- +
|
| |
- +/* Textual representation of the tokens. */
|
| |
- +static struct {
|
| |
- + const char *name;
|
| |
- + pkcs11uriOpCodes opcode;
|
| |
- +} keywords[] = {
|
| |
- + { PKCS11_URI_ID, pId },
|
| |
- + { PKCS11_URI_TOKEN, pToken },
|
| |
- + { PKCS11_URI_OBJECT, pObject },
|
| |
- + { PKCS11_URI_LIB_MANUF, pLibraryManufacturer },
|
| |
- + { PKCS11_URI_MANUF, pManufacturer },
|
| |
- + { PKCS11_URI_MODULE_PATH, pModulePath },
|
| |
- + { NULL, pBadOption }
|
| |
- +};
|
| |
- +
|
| |
- +static pkcs11uriOpCodes
|
| |
- +parse_token(const char *cp)
|
| |
- +{
|
| |
- + u_int i;
|
| |
- +
|
| |
- + for (i = 0; keywords[i].name; i++)
|
| |
- + if (strncasecmp(cp, keywords[i].name,
|
| |
- + strlen(keywords[i].name)) == 0)
|
| |
- + return keywords[i].opcode;
|
| |
- +
|
| |
- + return pBadOption;
|
| |
- +}
|
| |
- +
|
| |
- +int
|
| |
- +percent_decode(char *data, char **outp)
|
| |
- +{
|
| |
- + char tmp[3];
|
| |
- + char *out, *tmp_end;
|
| |
- + char *p = data;
|
| |
- + long value;
|
| |
- + size_t outlen = 0;
|
| |
- +
|
| |
- + out = malloc(strlen(data)+1); /* upper bound */
|
| |
- + if (out == NULL)
|
| |
- + return -1;
|
| |
- + while (*p != '\0') {
|
| |
- + switch (*p) {
|
| |
- + case '%':
|
| |
- + p++;
|
| |
- + if (*p == '\0')
|
| |
- + goto fail;
|
| |
- + tmp[0] = *p++;
|
| |
- + if (*p == '\0')
|
| |
- + goto fail;
|
| |
- + tmp[1] = *p++;
|
| |
- + tmp[2] = '\0';
|
| |
- + tmp_end = NULL;
|
| |
- + value = strtol(tmp, &tmp_end, 16);
|
| |
- + if (tmp_end != tmp+2)
|
| |
- + goto fail;
|
| |
- + else
|
| |
- + out[outlen++] = (char) value;
|
| |
- + break;
|
| |
- + default:
|
| |
- + out[outlen++] = *p++;
|
| |
- + break;
|
| |
- + }
|
| |
- + }
|
| |
- +
|
| |
- + /* zero terminate */
|
| |
- + out[outlen] = '\0';
|
| |
- + *outp = out;
|
| |
- + return outlen;
|
| |
- +fail:
|
| |
- + free(out);
|
| |
- + return -1;
|
| |
- +}
|
| |
- +
|
| |
- +struct sshbuf *
|
| |
- +percent_encode(const char *data, size_t length, const char *whitelist)
|
| |
- +{
|
| |
- + struct sshbuf *b = NULL;
|
| |
- + char tmp[4], *cp;
|
| |
- + size_t i;
|
| |
- +
|
| |
- + if ((b = sshbuf_new()) == NULL)
|
| |
- + return NULL;
|
| |
- + for (i = 0; i < length; i++) {
|
| |
- + cp = strchr(whitelist, data[i]);
|
| |
- + /* if c is specified as '\0' pointer to terminator is returned !! */
|
| |
- + if (cp != NULL && *cp != '\0') {
|
| |
- + if (sshbuf_put(b, &data[i], 1) != 0)
|
| |
- + goto err;
|
| |
- + } else
|
| |
- + if (snprintf(tmp, 4, "%%%02X", (unsigned char) data[i]) < 3
|
| |
- + || sshbuf_put(b, tmp, 3) != 0)
|
| |
- + goto err;
|
| |
- + }
|
| |
- + if (sshbuf_put(b, "\0", 1) == 0)
|
| |
- + return b;
|
| |
- +err:
|
| |
- + sshbuf_free(b);
|
| |
- + return NULL;
|
| |
- +}
|
| |
- +
|
| |
- +char *
|
| |
- +pkcs11_uri_append(char *part, const char *separator, const char *key,
|
| |
- + struct sshbuf *value)
|
| |
- +{
|
| |
- + char *new_part;
|
| |
- + size_t size = 0;
|
| |
- +
|
| |
- + if (value == NULL)
|
| |
- + return NULL;
|
| |
- +
|
| |
- + size = asprintf(&new_part,
|
| |
- + "%s%s%s" PKCS11_URI_VALUE_SEPARATOR "%s",
|
| |
- + (part != NULL ? part : ""),
|
| |
- + (part != NULL ? separator : ""),
|
| |
- + key, sshbuf_ptr(value));
|
| |
- + sshbuf_free(value);
|
| |
- + free(part);
|
| |
- +
|
| |
- + if (size <= 0)
|
| |
- + return NULL;
|
| |
- + return new_part;
|
| |
- +}
|
| |
- +
|
| |
- +char *
|
| |
- +pkcs11_uri_get(struct pkcs11_uri *uri)
|
| |
- +{
|
| |
- + size_t size = 0;
|
| |
- + char *p = NULL, *path = NULL, *query = NULL;
|
| |
- +
|
| |
- + /* compose a percent-encoded ID */
|
| |
- + if (uri->id_len > 0) {
|
| |
- + struct sshbuf *key_id = percent_encode(uri->id, uri->id_len, "");
|
| |
- + path = pkcs11_uri_append(path, PKCS11_URI_PATH_SEPARATOR,
|
| |
- + PKCS11_URI_ID, key_id);
|
| |
- + if (path == NULL)
|
| |
- + goto err;
|
| |
- + }
|
| |
- +
|
| |
- + /* Write object label */
|
| |
- + if (uri->object) {
|
| |
- + struct sshbuf *label = percent_encode(uri->object, strlen(uri->object),
|
| |
- + PKCS11_URI_WHITELIST);
|
| |
- + path = pkcs11_uri_append(path, PKCS11_URI_PATH_SEPARATOR,
|
| |
- + PKCS11_URI_OBJECT, label);
|
| |
- + if (path == NULL)
|
| |
- + goto err;
|
| |
- + }
|
| |
- +
|
| |
- + /* Write token label */
|
| |
- + if (uri->token) {
|
| |
- + struct sshbuf *label = percent_encode(uri->token, strlen(uri->token),
|
| |
- + PKCS11_URI_WHITELIST);
|
| |
- + path = pkcs11_uri_append(path, PKCS11_URI_PATH_SEPARATOR,
|
| |
- + PKCS11_URI_TOKEN, label);
|
| |
- + if (path == NULL)
|
| |
- + goto err;
|
| |
- + }
|
| |
- +
|
| |
- + /* Write manufacturer */
|
| |
- + if (uri->manuf) {
|
| |
- + struct sshbuf *manuf = percent_encode(uri->manuf,
|
| |
- + strlen(uri->manuf), PKCS11_URI_WHITELIST);
|
| |
- + path = pkcs11_uri_append(path, PKCS11_URI_PATH_SEPARATOR,
|
| |
- + PKCS11_URI_MANUF, manuf);
|
| |
- + if (path == NULL)
|
| |
- + goto err;
|
| |
- + }
|
| |
- +
|
| |
- + /* Write module_path */
|
| |
- + if (uri->module_path) {
|
| |
- + struct sshbuf *module = percent_encode(uri->module_path,
|
| |
- + strlen(uri->module_path), PKCS11_URI_WHITELIST "/");
|
| |
- + query = pkcs11_uri_append(query, PKCS11_URI_QUERY_SEPARATOR,
|
| |
- + PKCS11_URI_MODULE_PATH, module);
|
| |
- + if (query == NULL)
|
| |
- + goto err;
|
| |
- + }
|
| |
- +
|
| |
- + size = asprintf(&p, PKCS11_URI_SCHEME "%s%s%s",
|
| |
- + path != NULL ? path : "",
|
| |
- + query != NULL ? "?" : "",
|
| |
- + query != NULL ? query : "");
|
| |
- +err:
|
| |
- + free(query);
|
| |
- + free(path);
|
| |
- + if (size <= 0)
|
| |
- + return NULL;
|
| |
- + return p;
|
| |
- +}
|
| |
- +
|
| |
- +struct pkcs11_uri *
|
| |
- +pkcs11_uri_init()
|
| |
- +{
|
| |
- + struct pkcs11_uri *d = calloc(1, sizeof(struct pkcs11_uri));
|
| |
- + return d;
|
| |
- +}
|
| |
- +
|
| |
- +void
|
| |
- +pkcs11_uri_cleanup(struct pkcs11_uri *pkcs11)
|
| |
- +{
|
| |
- + free(pkcs11->id);
|
| |
- + free(pkcs11->module_path);
|
| |
- + free(pkcs11->token);
|
| |
- + free(pkcs11->object);
|
| |
- + free(pkcs11->lib_manuf);
|
| |
- + free(pkcs11->manuf);
|
| |
- + free(pkcs11);
|
| |
- +}
|
| |
- +
|
| |
- +int
|
| |
- +pkcs11_uri_parse(const char *uri, struct pkcs11_uri *pkcs11)
|
| |
- +{
|
| |
- + char *saveptr1, *saveptr2, *str1, *str2, *tok;
|
| |
- + int rv = 0, len;
|
| |
- + char *p = NULL;
|
| |
- +
|
| |
- + size_t scheme_len = strlen(PKCS11_URI_SCHEME);
|
| |
- + if (strlen(uri) < scheme_len || /* empty URI matches everything */
|
| |
- + strncmp(uri, PKCS11_URI_SCHEME, scheme_len) != 0) {
|
| |
- + error("%s: The '%s' does not look like PKCS#11 URI",
|
| |
- + __func__, uri);
|
| |
- + return -1;
|
| |
- + }
|
| |
- +
|
| |
- + if (pkcs11 == NULL) {
|
| |
- + error("%s: Bad arguments. The pkcs11 can't be null", __func__);
|
| |
- + return -1;
|
| |
- + }
|
| |
- +
|
| |
- + /* skip URI schema name */
|
| |
- + p = strdup(uri);
|
| |
- + str1 = p;
|
| |
- +
|
| |
- + /* everything before ? */
|
| |
- + tok = strtok_r(str1, "?", &saveptr1);
|
| |
- + if (tok == NULL) {
|
| |
- + free(p);
|
| |
- + error("%s: pk11-path expected, got EOF", __func__);
|
| |
- + return -1;
|
| |
- + }
|
| |
- +
|
| |
- + /* skip URI schema name:
|
| |
- + * the scheme ensures that there is at least something before "?"
|
| |
- + * allowing empty pk11-path. Resulting token at worst pointing to
|
| |
- + * \0 byte */
|
| |
- + tok = tok + scheme_len;
|
| |
- +
|
| |
- + /* parse pk11-path */
|
| |
- + for (str2 = tok; ; str2 = NULL) {
|
| |
- + char **charptr;
|
| |
- + pkcs11uriOpCodes opcode;
|
| |
- + tok = strtok_r(str2, PKCS11_URI_PATH_SEPARATOR, &saveptr2);
|
| |
- + if (tok == NULL)
|
| |
- + break;
|
| |
- + opcode = parse_token(tok);
|
| |
- +
|
| |
- + char *arg = tok + strlen(keywords[opcode].name) + 1; /* separator "=" */
|
| |
- + switch (opcode) {
|
| |
- + case pId:
|
| |
- + /* CKA_ID */
|
| |
- + if (pkcs11->id != NULL) {
|
| |
- + verbose("%s: The id already set in the PKCS#11 URI",
|
| |
- + __func__);
|
| |
- + rv = -1;
|
| |
- + }
|
| |
- + len = percent_decode(arg, &pkcs11->id);
|
| |
- + if (len <= 0) {
|
| |
- + verbose("%s: Failed to percent-decode CKA_ID: %s",
|
| |
- + __func__, arg);
|
| |
- + rv = -1;
|
| |
- + } else
|
| |
- + pkcs11->id_len = len;
|
| |
- + debug3("%s: Setting CKA_ID = %s from PKCS#11 URI",
|
| |
- + __func__, arg);
|
| |
- + break;
|
| |
- + case pToken:
|
| |
- + /* CK_TOKEN_INFO -> label */
|
| |
- + charptr = &pkcs11->token;
|
| |
- + parse_string:
|
| |
- + if (*charptr != NULL) {
|
| |
- + verbose("%s: The %s already set in the PKCS#11 URI",
|
| |
- + keywords[opcode].name, __func__);
|
| |
- + rv = -1;
|
| |
- + }
|
| |
- + percent_decode(arg, charptr);
|
| |
- + debug3("%s: Setting %s = %s from PKCS#11 URI",
|
| |
- + __func__, keywords[opcode].name, *charptr);
|
| |
- + break;
|
| |
- +
|
| |
- + case pObject:
|
| |
- + /* CK_TOKEN_INFO -> manufacturerID */
|
| |
- + charptr = &pkcs11->object;
|
| |
- + goto parse_string;
|
| |
- +
|
| |
- + case pManufacturer:
|
| |
- + /* CK_TOKEN_INFO -> manufacturerID */
|
| |
- + charptr = &pkcs11->manuf;
|
| |
- + goto parse_string;
|
| |
- +
|
| |
- + case pLibraryManufacturer:
|
| |
- + /* CK_INFO -> manufacturerID */
|
| |
- + charptr = &pkcs11->lib_manuf;
|
| |
- + goto parse_string;
|
| |
- +
|
| |
- + case pBadOption:
|
| |
- + default:
|
| |
- + /* Unrecognized attribute in the URI path SHOULD be error */
|
| |
- + verbose("%s: Unknown part of path in PKCS#11 URI: %s",
|
| |
- + __func__, tok);
|
| |
- + }
|
| |
- + }
|
| |
- +
|
| |
- + tok = strtok_r(NULL, "?", &saveptr1);
|
| |
- + if (tok == NULL) {
|
| |
- + free(p);
|
| |
- + return rv;
|
| |
- + }
|
| |
- + /* parse pk11-query (optional) */
|
| |
- + for (str2 = tok; ; str2 = NULL) {
|
| |
- + size_t key_len = strlen(PKCS11_URI_MODULE_PATH) + 1;
|
| |
- + tok = strtok_r(str2, PKCS11_URI_QUERY_SEPARATOR, &saveptr2);
|
| |
- + if (tok == NULL)
|
| |
- + break;
|
| |
- + if (strncasecmp(tok, PKCS11_URI_MODULE_PATH
|
| |
- + PKCS11_URI_VALUE_SEPARATOR, key_len) == 0) {
|
| |
- + /* module-path is PKCS11Provider */
|
| |
- + if (pkcs11->module_path != NULL) {
|
| |
- + verbose("%s: Multiple module-path attributes are"
|
| |
- + "not supported the PKCS#11 URI", __func__);
|
| |
- + rv = -1;
|
| |
- + }
|
| |
- + percent_decode(tok + key_len, &pkcs11->module_path);
|
| |
- + debug3("%s: Setting PKCS11Provider = %s from PKCS#11 URI",
|
| |
- + __func__, pkcs11->module_path);
|
| |
- + /* } else if ( pin-value ) { */
|
| |
- + } else {
|
| |
- + /* Unrecognized attribute in the URI query SHOULD be ignored */
|
| |
- + verbose("%s: Unknown part of query in PKCS#11 URI: %s",
|
| |
- + __func__, tok);
|
| |
- + }
|
| |
- + }
|
| |
- + free(p);
|
| |
- + return rv;
|
| |
- +}
|
| |
- +
|
| |
- +#endif /* ENABLE_PKCS11 */
|
| |
- diff -up openssh/ssh-pkcs11-uri.h.pkcs11-uri openssh/ssh-pkcs11-uri.h
|
| |
- --- openssh/ssh-pkcs11-uri.h.pkcs11-uri 2018-10-12 13:52:55.456191450 +0200
|
| |
- +++ openssh/ssh-pkcs11-uri.h 2018-10-12 13:52:55.456191450 +0200
|
| |
- @@ -0,0 +1,41 @@
|
| |
- +/*
|
| |
- + * Copyright (c) 2017 Red Hat
|
| |
- + *
|
| |
- + * Authors: Jakub Jelen <jjelen@redhat.com>
|
| |
- + *
|
| |
- + * Permission to use, copy, modify, and distribute this software for any
|
| |
- + * purpose with or without fee is hereby granted, provided that the above
|
| |
- + * copyright notice and this permission notice appear in all copies.
|
| |
- + *
|
| |
- + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
| |
- + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
| |
- + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
| |
- + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
| |
- + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
| |
- + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
| |
- + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
| |
- + */
|
| |
- +
|
| |
- +#define PKCS11_URI_SCHEME "pkcs11:"
|
| |
- +#define PKCS11_URI_WHITELIST "abcdefghijklmnopqrstuvwxyz" \
|
| |
- + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" \
|
| |
- + "0123456789_-.()"
|
| |
- +
|
| |
- +struct pkcs11_uri {
|
| |
- + /* path */
|
| |
- + char *id;
|
| |
- + size_t id_len;
|
| |
- + char *token;
|
| |
- + char *object;
|
| |
- + char *lib_manuf;
|
| |
- + char *manuf;
|
| |
- + /* query */
|
| |
- + char *module_path;
|
| |
- +};
|
| |
- +
|
| |
- +struct pkcs11_uri *pkcs11_uri_init();
|
| |
- +void pkcs11_uri_cleanup(struct pkcs11_uri *);
|
| |
- +int pkcs11_uri_parse(const char *, struct pkcs11_uri *);
|
| |
- +struct pkcs11_uri *pkcs11_uri_init();
|
| |
- +char * pkcs11_uri_get(struct pkcs11_uri *uri);
|
| |
- +
|
| |