[pkg-opensc-maint] Bug#1011065: libengine-pkcs11-openssl1.1: Drop transitional package

Bastian Germann bage at debian.org
Fri Dec 9 13:15:30 GMT 2022


I have uploaded a NMU to DELAYED/3. debdiff attached.
-------------- next part --------------
diff -Nru libp11-0.4.11/aclocal.m4 libp11-0.4.12/aclocal.m4
--- libp11-0.4.11/aclocal.m4	2020-10-11 15:46:56.000000000 +0200
+++ libp11-0.4.12/aclocal.m4	2022-07-15 21:56:26.000000000 +0200
@@ -1,6 +1,6 @@
-# generated automatically by aclocal 1.16.2 -*- Autoconf -*-
+# generated automatically by aclocal 1.16.4 -*- Autoconf -*-
 
-# Copyright (C) 1996-2020 Free Software Foundation, Inc.
+# Copyright (C) 1996-2021 Free Software Foundation, Inc.
 
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -296,7 +296,7 @@
 AS_VAR_IF([$1], [""], [$5], [$4])dnl
 ])dnl PKG_CHECK_VAR
 
-# Copyright (C) 2002-2020 Free Software Foundation, Inc.
+# Copyright (C) 2002-2021 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -311,7 +311,7 @@
 [am__api_version='1.16'
 dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
 dnl require some minimum version.  Point them to the right macro.
-m4_if([$1], [1.16.2], [],
+m4_if([$1], [1.16.4], [],
       [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
 ])
 
@@ -327,14 +327,14 @@
 # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
 # This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
 AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.16.2])dnl
+[AM_AUTOMAKE_VERSION([1.16.4])dnl
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
 _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
 
 # AM_AUX_DIR_EXPAND                                         -*- Autoconf -*-
 
-# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+# Copyright (C) 2001-2021 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -386,7 +386,7 @@
 
 # AM_CONDITIONAL                                            -*- Autoconf -*-
 
-# Copyright (C) 1997-2020 Free Software Foundation, Inc.
+# Copyright (C) 1997-2021 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -417,7 +417,7 @@
 Usually this means the macro was only invoked conditionally.]])
 fi])])
 
-# Copyright (C) 1999-2020 Free Software Foundation, Inc.
+# Copyright (C) 1999-2021 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -608,7 +608,7 @@
 
 # Generate code to set up dependency tracking.              -*- Autoconf -*-
 
-# Copyright (C) 1999-2020 Free Software Foundation, Inc.
+# Copyright (C) 1999-2021 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -676,7 +676,7 @@
 
 # Do all the work for Automake.                             -*- Autoconf -*-
 
-# Copyright (C) 1996-2020 Free Software Foundation, Inc.
+# Copyright (C) 1996-2021 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -740,7 +740,7 @@
 [_AM_SET_OPTIONS([$1])dnl
 dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
 m4_if(
-  m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+  m4_ifset([AC_PACKAGE_NAME], [ok]):m4_ifset([AC_PACKAGE_VERSION], [ok]),
   [ok:ok],,
   [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
  AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
@@ -792,6 +792,20 @@
 		  [m4_define([AC_PROG_OBJCXX],
 			     m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
 ])
+# Variables for tags utilities; see am/tags.am
+if test -z "$CTAGS"; then
+  CTAGS=ctags
+fi
+AC_SUBST([CTAGS])
+if test -z "$ETAGS"; then
+  ETAGS=etags
+fi
+AC_SUBST([ETAGS])
+if test -z "$CSCOPE"; then
+  CSCOPE=cscope
+fi
+AC_SUBST([CSCOPE])
+
 AC_REQUIRE([AM_SILENT_RULES])dnl
 dnl The testsuite driver may need to know about EXEEXT, so add the
 dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen.  This
@@ -873,7 +887,7 @@
 done
 echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
 
-# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+# Copyright (C) 2001-2021 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -894,7 +908,7 @@
 fi
 AC_SUBST([install_sh])])
 
-# Copyright (C) 2003-2020 Free Software Foundation, Inc.
+# Copyright (C) 2003-2021 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -915,7 +929,7 @@
 
 # Check to see how 'make' treats includes.	            -*- Autoconf -*-
 
-# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+# Copyright (C) 2001-2021 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -958,7 +972,7 @@
 
 # Fake the existence of programs that GNU maintainers use.  -*- Autoconf -*-
 
-# Copyright (C) 1997-2020 Free Software Foundation, Inc.
+# Copyright (C) 1997-2021 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -979,12 +993,7 @@
 [AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
 AC_REQUIRE_AUX_FILE([missing])dnl
 if test x"${MISSING+set}" != xset; then
-  case $am_aux_dir in
-  *\ * | *\	*)
-    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
-  *)
-    MISSING="\${SHELL} $am_aux_dir/missing" ;;
-  esac
+  MISSING="\${SHELL} '$am_aux_dir/missing'"
 fi
 # Use eval to expand $SHELL
 if eval "$MISSING --is-lightweight"; then
@@ -997,7 +1006,7 @@
 
 # Helper functions for option handling.                     -*- Autoconf -*-
 
-# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+# Copyright (C) 2001-2021 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1026,7 +1035,7 @@
 AC_DEFUN([_AM_IF_OPTION],
 [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
 
-# Copyright (C) 1999-2020 Free Software Foundation, Inc.
+# Copyright (C) 1999-2021 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1073,7 +1082,7 @@
 # For backward compatibility.
 AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
 
-# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+# Copyright (C) 2001-2021 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1092,7 +1101,7 @@
 
 # Check to make sure that the build environment is sane.    -*- Autoconf -*-
 
-# Copyright (C) 1996-2020 Free Software Foundation, Inc.
+# Copyright (C) 1996-2021 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1173,7 +1182,7 @@
 rm -f conftest.file
 ])
 
-# Copyright (C) 2009-2020 Free Software Foundation, Inc.
+# Copyright (C) 2009-2021 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1233,7 +1242,7 @@
 _AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
 ])
 
-# Copyright (C) 2001-2020 Free Software Foundation, Inc.
+# Copyright (C) 2001-2021 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1261,7 +1270,7 @@
 INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
 AC_SUBST([INSTALL_STRIP_PROGRAM])])
 
-# Copyright (C) 2006-2020 Free Software Foundation, Inc.
+# Copyright (C) 2006-2021 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1280,7 +1289,7 @@
 
 # Check how to create a tarball.                            -*- Autoconf -*-
 
-# Copyright (C) 2004-2020 Free Software Foundation, Inc.
+# Copyright (C) 2004-2021 Free Software Foundation, Inc.
 #
 # This file is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -1411,6 +1420,7 @@
 AC_SUBST([am__untar])
 ]) # _AM_PROG_TAR
 
+m4_include([m4/ax_pthread.m4])
 m4_include([m4/ld-version-script.m4])
 m4_include([m4/libtool.m4])
 m4_include([m4/ltoptions.m4])
diff -Nru libp11-0.4.11/compile libp11-0.4.12/compile
--- libp11-0.4.11/compile	2018-10-02 20:47:03.000000000 +0200
+++ libp11-0.4.12/compile	2022-03-15 18:14:17.000000000 +0100
@@ -3,7 +3,7 @@
 
 scriptversion=2018-03-07.03; # UTC
 
-# Copyright (C) 1999-2018 Free Software Foundation, Inc.
+# Copyright (C) 1999-2020 Free Software Foundation, Inc.
 # Written by Tom Tromey <tromey at cygnus.com>.
 #
 # This program is free software; you can redistribute it and/or modify
@@ -53,7 +53,7 @@
 	  MINGW*)
 	    file_conv=mingw
 	    ;;
-	  CYGWIN*)
+	  CYGWIN* | MSYS*)
 	    file_conv=cygwin
 	    ;;
 	  *)
@@ -67,7 +67,7 @@
 	mingw/*)
 	  file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
 	  ;;
-	cygwin/*)
+	cygwin/* | msys/*)
 	  file=`cygpath -m "$file" || echo "$file"`
 	  ;;
 	wine/*)
diff -Nru libp11-0.4.11/config.guess libp11-0.4.12/config.guess
--- libp11-0.4.11/config.guess	2018-10-02 20:47:03.000000000 +0200
+++ libp11-0.4.12/config.guess	2022-03-15 18:14:17.000000000 +0100
@@ -2,7 +2,7 @@
 # Attempt to guess a canonical system name.
 #   Copyright 1992-2018 Free Software Foundation, Inc.
 
-timestamp='2018-03-08'
+timestamp='2018-02-24'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -1046,7 +1046,11 @@
 	echo "$UNAME_MACHINE"-dec-linux-"$LIBC"
 	exit ;;
     x86_64:Linux:*:*)
-	echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
+	if objdump -f /bin/sh | grep -q elf32-x86-64; then
+	    echo "$UNAME_MACHINE"-pc-linux-"$LIBC"x32
+	else
+	    echo "$UNAME_MACHINE"-pc-linux-"$LIBC"
+	fi
 	exit ;;
     xtensa*:Linux:*:*)
 	echo "$UNAME_MACHINE"-unknown-linux-"$LIBC"
@@ -1469,7 +1473,7 @@
 exit 1
 
 # Local variables:
-# eval: (add-hook 'before-save-hook 'time-stamp)
+# eval: (add-hook 'write-file-functions 'time-stamp)
 # time-stamp-start: "timestamp='"
 # time-stamp-format: "%:y-%02m-%02d"
 # time-stamp-end: "'"
diff -Nru libp11-0.4.11/config.sub libp11-0.4.12/config.sub
--- libp11-0.4.11/config.sub	2018-10-02 20:47:03.000000000 +0200
+++ libp11-0.4.12/config.sub	2022-03-15 18:14:17.000000000 +0100
@@ -2,7 +2,7 @@
 # Configuration validation subroutine script.
 #   Copyright 1992-2018 Free Software Foundation, Inc.
 
-timestamp='2018-03-08'
+timestamp='2018-02-22'
 
 # This file is free software; you can redistribute it and/or modify it
 # under the terms of the GNU General Public License as published by
@@ -1376,7 +1376,7 @@
 	      | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
 	      | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
 	      | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
-	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* | -hcos* \
+	      | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
 	      | -chorusos* | -chorusrdb* | -cegcc* | -glidix* \
 	      | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
 	      | -midipix* | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
@@ -1794,7 +1794,7 @@
 exit
 
 # Local variables:
-# eval: (add-hook 'before-save-hook 'time-stamp)
+# eval: (add-hook 'write-file-functions 'time-stamp)
 # time-stamp-start: "timestamp='"
 # time-stamp-format: "%:y-%02m-%02d"
 # time-stamp-end: "'"
diff -Nru libp11-0.4.11/configure libp11-0.4.12/configure
--- libp11-0.4.11/configure	2020-10-11 15:46:57.000000000 +0200
+++ libp11-0.4.12/configure	2022-07-15 21:56:26.000000000 +0200
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for libp11 0.4.11.
+# Generated by GNU Autoconf 2.69 for libp11 0.4.12.
 #
 #
 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -587,8 +587,8 @@
 # Identity of this package.
 PACKAGE_NAME='libp11'
 PACKAGE_TARNAME='libp11'
-PACKAGE_VERSION='0.4.11'
-PACKAGE_STRING='libp11 0.4.11'
+PACKAGE_VERSION='0.4.12'
+PACKAGE_STRING='libp11 0.4.12'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -653,6 +653,11 @@
 pkgconfigdir
 OPENSSL_LIBS
 OPENSSL_CFLAGS
+PTHREAD_CFLAGS
+PTHREAD_LIBS
+PTHREAD_CXX
+PTHREAD_CC
+ax_pthread_config
 DOXYGEN
 RC
 LT_SYS_LIBRARY_PATH
@@ -700,18 +705,13 @@
 LDFLAGS
 CFLAGS
 CC
-host_os
-host_vendor
-host_cpu
-host
-build_os
-build_vendor
-build_cpu
-build
 AM_BACKSLASH
 AM_DEFAULT_VERBOSITY
 AM_DEFAULT_V
 AM_V
+CSCOPE
+ETAGS
+CTAGS
 am__untar
 am__tar
 AMTAR
@@ -735,6 +735,18 @@
 INSTALL_DATA
 INSTALL_SCRIPT
 INSTALL_PROGRAM
+target_os
+target_vendor
+target_cpu
+target
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
 target_alias
 host_alias
 build_alias
@@ -1363,7 +1375,7 @@
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures libp11 0.4.11 to adapt to many kinds of systems.
+\`configure' configures libp11 0.4.12 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1429,12 +1441,13 @@
 System types:
   --build=BUILD     configure for building on BUILD [guessed]
   --host=HOST       cross-compile to build programs to run on HOST [BUILD]
+  --target=TARGET   configure for building compilers for TARGET [HOST]
 _ACEOF
 fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of libp11 0.4.11:";;
+     short | recursive ) echo "Configuration of libp11 0.4.12:";;
    esac
   cat <<\_ACEOF
 
@@ -1565,7 +1578,7 @@
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-libp11 configure 0.4.11
+libp11 configure 0.4.12
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1930,7 +1943,7 @@
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by libp11 $as_me 0.4.11, which was
+It was created by libp11 $as_me 0.4.12, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2310,6 +2323,116 @@
 ac_config_headers="$ac_config_headers src/config.h"
 
 
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking target system type" >&5
+$as_echo_n "checking target system type... " >&6; }
+if ${ac_cv_target+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$target_alias" = x; then
+  ac_cv_target=$ac_cv_host
+else
+  ac_cv_target=`$SHELL "$ac_aux_dir/config.sub" $target_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $target_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_target" >&5
+$as_echo "$ac_cv_target" >&6; }
+case $ac_cv_target in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical target" "$LINENO" 5;;
+esac
+target=$ac_cv_target
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_target
+shift
+target_cpu=$1
+target_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+target_os=$*
+IFS=$ac_save_IFS
+case $target_os in *\ *) target_os=`echo "$target_os" | sed 's/ /-/g'`;; esac
+
+
+# The aliases save the names the user supplied, while $host etc.
+# will get canonicalized.
+test -n "$target_alias" &&
+  test "$program_prefix$program_suffix$program_transform_name" = \
+    NONENONEs,x,x, &&
+  program_prefix=${target_alias}-
 am__api_version='1.16'
 
 # Find a good install program.  We prefer a C program (faster),
@@ -2486,12 +2609,7 @@
 am_aux_dir=`cd "$ac_aux_dir" && pwd`
 
 if test x"${MISSING+set}" != xset; then
-  case $am_aux_dir in
-  *\ * | *\	*)
-    MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
-  *)
-    MISSING="\${SHELL} $am_aux_dir/missing" ;;
-  esac
+  MISSING="\${SHELL} '$am_aux_dir/missing'"
 fi
 # Use eval to expand $SHELL
 if eval "$MISSING --is-lightweight"; then
@@ -2796,7 +2914,7 @@
 
 # Define the identity of the package.
  PACKAGE='libp11'
- VERSION='0.4.11'
+ VERSION='0.4.12'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -2846,6 +2964,20 @@
 
 
 
+# Variables for tags utilities; see am/tags.am
+if test -z "$CTAGS"; then
+  CTAGS=ctags
+fi
+
+if test -z "$ETAGS"; then
+  ETAGS=etags
+fi
+
+if test -z "$CSCOPE"; then
+  CSCOPE=cscope
+fi
+
+
 
 # POSIX will say in a future version that running "rm -f" with no argument
 # is OK; and we want to be able to make that assumption in our Makefile
@@ -2892,7 +3024,7 @@
 
 LIBP11_VERSION_MAJOR="0"
 LIBP11_VERSION_MINOR="4"
-LIBP11_VERSION_FIX="11"
+LIBP11_VERSION_FIX="12"
 
 
 
@@ -2937,76 +3069,6 @@
 AM_BACKSLASH='\'
 
 
-# Make sure we can run config.sub.
-$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
-  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
-$as_echo_n "checking build system type... " >&6; }
-if ${ac_cv_build+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_build_alias=$build_alias
-test "x$ac_build_alias" = x &&
-  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
-test "x$ac_build_alias" = x &&
-  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
-ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
-  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
-$as_echo "$ac_cv_build" >&6; }
-case $ac_cv_build in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
-esac
-build=$ac_cv_build
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_build
-shift
-build_cpu=$1
-build_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-build_os=$*
-IFS=$ac_save_IFS
-case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
-$as_echo_n "checking host system type... " >&6; }
-if ${ac_cv_host+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test "x$host_alias" = x; then
-  ac_cv_host=$ac_cv_build
-else
-  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
-    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
-fi
-
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
-$as_echo "$ac_cv_host" >&6; }
-case $ac_cv_host in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
-esac
-host=$ac_cv_host
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_host
-shift
-host_cpu=$1
-host_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-host_os=$*
-IFS=$ac_save_IFS
-case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
-
 
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
@@ -4818,8 +4880,8 @@
 # the openssl version we link to. If the ABI is broken on a later
 # release, we should either stick to supporting a single openssl ABI
 # or bump the LT_OLDEST version sufficiently to avoid clashes.
-LIBP11_LT_REVISION="3"
-LIBP11_LT_CURRENT="7"
+LIBP11_LT_REVISION="0"
+LIBP11_LT_CURRENT="8"
 LIBP11_LT_AGE="$((${LIBP11_LT_CURRENT}-${LIBP11_LT_OLDEST}))"
 
 
@@ -4911,7 +4973,7 @@
 case "${host}" in
 	*-mingw*|*-winnt*)
 		WIN32="yes"
-		CPPFLAGS="${CPPFLAGS} -DWIN32_LEAN_AND_MEAN"
+		CPPFLAGS="${CPPFLAGS} -D_WIN32_WINNT=0x0600 -DWIN32_LEAN_AND_MEAN"
 		WIN_LIBPREFIX="lib"
 	;;
 	*-cygwin*)
@@ -5267,8 +5329,8 @@
 
 
 
-macro_version='2.4.6.42-b88ce'
-macro_revision='2.4.6.42'
+macro_version='2.4.6'
+macro_revision='2.4.6'
 
 
 
@@ -6353,7 +6415,7 @@
   lt_cv_deplibs_check_method=pass_all
   ;;
 
-netbsd*)
+netbsd* | netbsdelf*-gnu)
   if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
     lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
   else
@@ -6712,29 +6774,13 @@
 fi
 
 : ${AR=ar}
+: ${AR_FLAGS=cr}
 
 
 
 
 
 
-# Use ARFLAGS variable as AR's operation code to sync the variable naming with
-# Automake.  If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have
-# higher priority because thats what people were doing historically (setting
-# ARFLAGS for automake and AR_FLAGS for libtool).  FIXME: Make the AR_FLAGS
-# variable obsoleted/removed.
-
-test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr}
-lt_ar_flags=$AR_FLAGS
-
-
-
-
-
-
-# Make AR_FLAGS overridable by 'make ARFLAGS='.  Don't try to run-time override
-# by AR_FLAGS because that was never working and AR_FLAGS is about to die.
-
 
 
 
@@ -7183,7 +7229,7 @@
   if test "$lt_cv_nm_interface" = "MS dumpbin"; then
     # Fake it for dumpbin and say T for any non-static function,
     # D for any global variable and I for any imported variable.
-    # Also find C++ and __fastcall symbols from MSVC++ or ICC,
+    # Also find C++ and __fastcall symbols from MSVC++,
     # which start with @ or ?.
     lt_cv_sys_global_symbol_pipe="$AWK '"\
 "     {last_section=section; section=\$ 3};"\
@@ -7229,11 +7275,8 @@
   test $ac_status = 0; }; then
     # Now try to grab the symbols.
     nlist=conftest.nm
-    if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
-  (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } && test -s "$nlist"; then
+    $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&5
+    if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&5 && test -s "$nlist"; then
       # Try sorting and uniquifying the output.
       if sort "$nlist" | uniq > "$nlist"T; then
 	mv -f "$nlist"T "$nlist"
@@ -8452,8 +8495,8 @@
 _LT_EOF
       echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
       $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
-      echo "$AR $AR_FLAGS libconftest.a conftest.o" >&5
-      $AR $AR_FLAGS libconftest.a conftest.o 2>&5
+      echo "$AR cr libconftest.a conftest.o" >&5
+      $AR cr libconftest.a conftest.o 2>&5
       echo "$RANLIB libconftest.a" >&5
       $RANLIB libconftest.a 2>&5
       cat > conftest.c << _LT_EOF
@@ -8485,11 +8528,11 @@
       # to the OS version, if on x86, and 10.4, the deployment
       # target defaults to 10.4. Don't you love it?
       case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
-	10.0,*86*-darwin8*|10.0,*-darwin[91]*)
+	10.0,*86*-darwin8*|10.0,*-darwin[912]*)
 	  _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
 	10.[012][,.]*)
 	  _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
-	10.*)
+	10.*|11.*)
 	  _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
       esac
     ;;
@@ -9147,8 +9190,8 @@
 ofile=libtool
 can_build_shared=yes
 
-# All known linkers require a '.a' archive for static linking (except MSVC and
-# ICC, which need '.lib').
+# All known linkers require a '.a' archive for static linking (except MSVC,
+# which needs '.lib').
 libext=a
 
 with_gnu_ld=$lt_cv_prog_gnu_ld
@@ -9613,6 +9656,12 @@
 	lt_prog_compiler_pic='-KPIC'
 	lt_prog_compiler_static='-static'
         ;;
+      # flang / f18. f95 an alias for gfortran or flang on Debian
+      flang* | f18* | f95*)
+	lt_prog_compiler_wl='-Wl,'
+	lt_prog_compiler_pic='-fPIC'
+	lt_prog_compiler_static='-static'
+        ;;
       # icc used to be incompatible with GCC.
       # ICC 10 doesn't accept -KPIC any more.
       icc* | ifort*)
@@ -10075,20 +10124,23 @@
 
   case $host_os in
   cygwin* | mingw* | pw32* | cegcc*)
-    # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
     # When not using gcc, we currently assume that we are using
-    # Microsoft Visual C++ or Intel C++ Compiler.
+    # Microsoft Visual C++.
     if test yes != "$GCC"; then
       with_gnu_ld=no
     fi
     ;;
   interix*)
-    # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
     with_gnu_ld=yes
     ;;
   openbsd* | bitrig*)
     with_gnu_ld=no
     ;;
+  linux* | k*bsd*-gnu | gnu*)
+    link_all_deplibs=no
+    ;;
   esac
 
   ld_shlibs=yes
@@ -10247,7 +10299,6 @@
 	emximp -o $lib $output_objdir/$libname.def'
       old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
       enable_shared_with_static_runtimes=yes
-      file_list_spec='@'
       ;;
 
     interix[3-9]*)
@@ -10344,7 +10395,7 @@
       fi
       ;;
 
-    netbsd*)
+    netbsd* | netbsdelf*-gnu)
       if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
 	archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
 	wlarc=
@@ -10465,7 +10516,7 @@
 	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
 	  export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
 	else
-	  export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+	  export_symbols_cmds='`func_echo_all $NM | $SED -e '\''s/B\([^B]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && (substr(\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
 	fi
 	aix_use_runtimelinking=no
 
@@ -10732,12 +10783,12 @@
 
     cygwin* | mingw* | pw32* | cegcc*)
       # When not using gcc, we currently assume that we are using
-      # Microsoft Visual C++ or Intel C++ Compiler.
+      # Microsoft Visual C++.
       # hardcode_libdir_flag_spec is actually meaningless, as there is
       # no search path for DLLs.
       case $cc_basename in
-      cl* | icl*)
-	# Native MSVC or ICC
+      cl*)
+	# Native MSVC
 	hardcode_libdir_flag_spec=' '
 	allow_undefined_flag=unsupported
 	always_export_symbols=yes
@@ -10778,7 +10829,7 @@
           fi'
 	;;
       *)
-	# Assume MSVC and ICC wrapper
+	# Assume MSVC wrapper
 	hardcode_libdir_flag_spec=' '
 	allow_undefined_flag=unsupported
 	# Tell ltmain to make .lib files, not .a files.
@@ -11014,6 +11065,7 @@
 	if test yes = "$lt_cv_irix_exported_symbol"; then
           archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
 	fi
+	link_all_deplibs=no
       else
 	archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
 	archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
@@ -11035,7 +11087,7 @@
       esac
       ;;
 
-    netbsd*)
+    netbsd* | netbsdelf*-gnu)
       if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
 	archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
       else
@@ -11102,7 +11154,6 @@
 	emximp -o $lib $output_objdir/$libname.def'
       old_archive_From_new_cmds='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
       enable_shared_with_static_runtimes=yes
-      file_list_spec='@'
       ;;
 
     osf3*)
@@ -11810,8 +11861,8 @@
     dynamic_linker='Win32 ld.exe'
     ;;
 
-  *,cl* | *,icl*)
-    # Native MSVC or ICC
+  *,cl*)
+    # Native MSVC
     libname_spec='$name'
     soname_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext'
     library_names_spec='$libname.dll.lib'
@@ -11867,7 +11918,7 @@
     ;;
 
   *)
-    # Assume MSVC and ICC wrapper
+    # Assume MSVC wrapper
     library_names_spec='$libname`echo $release | $SED -e 's/[.]/-/g'`$versuffix$shared_ext $libname.lib'
     dynamic_linker='Win32 ld.exe'
     ;;
@@ -12151,6 +12202,18 @@
   dynamic_linker='GNU/Linux ld.so'
   ;;
 
+netbsdelf*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='NetBSD ld.elf_so'
+  ;;
+
 netbsd*)
   version_type=sunos
   need_lib_prefix=no
@@ -13046,41 +13109,30 @@
 old_striplib=
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
 $as_echo_n "checking whether stripping libraries is possible... " >&6; }
-if test -z "$STRIP"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-else
-  if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
-    old_striplib="$STRIP --strip-debug"
-    striplib="$STRIP --strip-unneeded"
-    { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-  else
-    case $host_os in
-    darwin*)
-      # FIXME - insert some real tests, host_os isn't really good enough
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP"; then
       striplib="$STRIP -x"
       old_striplib="$STRIP -S"
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-      ;;
-    freebsd*)
-      if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then
-        old_striplib="$STRIP --strip-debug"
-        striplib="$STRIP --strip-unneeded"
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-      else
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-      fi
-      ;;
-    *)
+    else
       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-      ;;
-    esac
-  fi
+    fi
+    ;;
+  *)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+    ;;
+  esac
 fi
 
 
@@ -13617,17 +13669,733 @@
 
 fi
 
-	for ac_func in __register_atfork
-do :
-  ac_fn_c_check_func "$LINENO" "__register_atfork" "ac_cv_func___register_atfork"
-if test "x$ac_cv_func___register_atfork" = xyes; then :
-  cat >>confdefs.h <<_ACEOF
-#define HAVE___REGISTER_ATFORK 1
+
+
+
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ax_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on Tru64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
+        ax_pthread_save_CC="$CC"
+        ax_pthread_save_CFLAGS="$CFLAGS"
+        ax_pthread_save_LIBS="$LIBS"
+        if test "x$PTHREAD_CC" != "x"; then :
+  CC="$PTHREAD_CC"
+fi
+        if test "x$PTHREAD_CXX" != "x"; then :
+  CXX="$PTHREAD_CXX"
+fi
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS" >&5
+$as_echo_n "checking for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS... " >&6; }
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char pthread_join ();
+int
+main ()
+{
+return pthread_join ();
+  ;
+  return 0;
+}
 _ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ax_pthread_ok=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5
+$as_echo "$ax_pthread_ok" >&6; }
+        if test "x$ax_pthread_ok" = "xno"; then
+                PTHREAD_LIBS=""
+                PTHREAD_CFLAGS=""
+        fi
+        CC="$ax_pthread_save_CC"
+        CFLAGS="$ax_pthread_save_CFLAGS"
+        LIBS="$ax_pthread_save_LIBS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try. Items with a "," contain both
+# C compiler flags (before ",") and linker flags (after ","). Other items
+# starting with a "-" are C compiler flags, and remaining items are
+# library names, except for "none" which indicates that we try without
+# any flags at all, and "pthread-config" which is a program returning
+# the flags for the Pth emulation library.
+
+ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important.  Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+#       other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
+#           (Note: HP C rejects this with "bad form for `-t' option")
+# -pthreads: Solaris/gcc (Note: HP C also rejects)
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+#      doesn't hurt to check since this sometimes defines pthreads and
+#      -D_REENTRANT too), HP C (must be checked before -lpthread, which
+#      is present but should not be used directly; and before -mthreads,
+#      because the compiler interprets this as "-mt" + "-hreads")
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case $target_os in
+
+        freebsd*)
+
+        # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+        # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+
+        ax_pthread_flags="-kthread lthread $ax_pthread_flags"
+        ;;
+
+        hpux*)
+
+        # From the cc(1) man page: "[-mt] Sets various -D flags to enable
+        # multi-threading and also sets -lpthread."
+
+        ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
+        ;;
+
+        openedition*)
+
+        # IBM z/OS requires a feature-test macro to be defined in order to
+        # enable POSIX threads at all, so give the user a hint if this is
+        # not set. (We don't define these ourselves, as they can affect
+        # other portions of the system API in unpredictable ways.)
+
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+#            if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
+             AX_PTHREAD_ZOS_MISSING
+#            endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "AX_PTHREAD_ZOS_MISSING" >/dev/null 2>&1; then :
+  { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&5
+$as_echo "$as_me: WARNING: IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support." >&2;}
+fi
+rm -f conftest*
+
+        ;;
+
+        solaris*)
+
+        # On Solaris (at least, for some versions), libc contains stubbed
+        # (non-functional) versions of the pthreads routines, so link-based
+        # tests will erroneously succeed. (N.B.: The stubs are missing
+        # pthread_cleanup_push, or rather a function called by this macro,
+        # so we could check for that, but who knows whether they'll stub
+        # that too in a future libc.)  So we'll check first for the
+        # standard Solaris way of linking pthreads (-mt -lpthread).
+
+        ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags"
+        ;;
+esac
+
+# Are we compiling with Clang?
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC is Clang" >&5
+$as_echo_n "checking whether $CC is Clang... " >&6; }
+if ${ax_cv_PTHREAD_CLANG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ax_cv_PTHREAD_CLANG=no
+     # Note that Autoconf sets GCC=yes for Clang as well as GCC
+     if test "x$GCC" = "xyes"; then
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
+#            if defined(__clang__) && defined(__llvm__)
+             AX_PTHREAD_CC_IS_CLANG
+#            endif
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "AX_PTHREAD_CC_IS_CLANG" >/dev/null 2>&1; then :
+  ax_cv_PTHREAD_CLANG=yes
+fi
+rm -f conftest*
+
+     fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG" >&5
+$as_echo "$ax_cv_PTHREAD_CLANG" >&6; }
+ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
+
+
+# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
+
+# Note that for GCC and Clang -pthread generally implies -lpthread,
+# except when -nostdlib is passed.
+# This is problematic using libtool to build C++ shared libraries with pthread:
+# [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460
+# [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333
+# [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555
+# To solve this, first try -pthread together with -lpthread for GCC
+
+if test "x$GCC" = "xyes"; then :
+  ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"
+fi
+
+# Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first
+
+if test "x$ax_pthread_clang" = "xyes"; then :
+  ax_pthread_flags="-pthread,-lpthread -pthread"
+fi
+
+
+# The presence of a feature test macro requesting re-entrant function
+# definitions is, on some systems, a strong hint that pthreads support is
+# correctly enabled
+
+case $target_os in
+        darwin* | hpux* | linux* | osf* | solaris*)
+        ax_pthread_check_macro="_REENTRANT"
+        ;;
+
+        aix*)
+        ax_pthread_check_macro="_THREAD_SAFE"
+        ;;
+
+        *)
+        ax_pthread_check_macro="--"
+        ;;
+esac
+if test "x$ax_pthread_check_macro" = "x--"; then :
+  ax_pthread_check_cond=0
+else
+  ax_pthread_check_cond="!defined($ax_pthread_check_macro)"
+fi
+
+
+if test "x$ax_pthread_ok" = "xno"; then
+for ax_pthread_try_flag in $ax_pthread_flags; do
+
+        case $ax_pthread_try_flag in
+                none)
+                { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work without any flags" >&5
+$as_echo_n "checking whether pthreads work without any flags... " >&6; }
+                ;;
+
+                *,*)
+                PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"`
+                PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"`
+                { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with \"$PTHREAD_CFLAGS\" and \"$PTHREAD_LIBS\"" >&5
+$as_echo_n "checking whether pthreads work with \"$PTHREAD_CFLAGS\" and \"$PTHREAD_LIBS\"... " >&6; }
+                ;;
+
+                -*)
+                { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether pthreads work with $ax_pthread_try_flag" >&5
+$as_echo_n "checking whether pthreads work with $ax_pthread_try_flag... " >&6; }
+                PTHREAD_CFLAGS="$ax_pthread_try_flag"
+                ;;
+
+                pthread-config)
+                # Extract the first word of "pthread-config", so it can be a program name with args.
+set dummy pthread-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ax_pthread_config+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ax_pthread_config"; then
+  ac_cv_prog_ax_pthread_config="$ax_pthread_config" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ax_pthread_config="yes"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_prog_ax_pthread_config" && ac_cv_prog_ax_pthread_config="no"
+fi
+fi
+ax_pthread_config=$ac_cv_prog_ax_pthread_config
+if test -n "$ax_pthread_config"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_config" >&5
+$as_echo "$ax_pthread_config" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+                if test "x$ax_pthread_config" = "xno"; then :
+  continue
+fi
+                PTHREAD_CFLAGS="`pthread-config --cflags`"
+                PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+                ;;
+
+                *)
+                { $as_echo "$as_me:${as_lineno-$LINENO}: checking for the pthreads library -l$ax_pthread_try_flag" >&5
+$as_echo_n "checking for the pthreads library -l$ax_pthread_try_flag... " >&6; }
+                PTHREAD_LIBS="-l$ax_pthread_try_flag"
+                ;;
+        esac
+
+        ax_pthread_save_CFLAGS="$CFLAGS"
+        ax_pthread_save_LIBS="$LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+
+        # Check for various functions.  We must include pthread.h,
+        # since some functions may be macros.  (On the Sequent, we
+        # need a special flag -Kthread to make this header compile.)
+        # We check for pthread_join because it is in -lpthread on IRIX
+        # while pthread_create is in libc.  We check for pthread_attr_init
+        # due to DEC craziness with -lpthreads.  We check for
+        # pthread_cleanup_push because it is one of the few pthread
+        # functions on Solaris that doesn't have a non-functional libc stub.
+        # We try pthread_create on general principles.
+
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <pthread.h>
+#                       if $ax_pthread_check_cond
+#                        error "$ax_pthread_check_macro must be defined"
+#                       endif
+                        static void *some_global = NULL;
+                        static void routine(void *a)
+                          {
+                             /* To avoid any unused-parameter or
+                                unused-but-set-parameter warning.  */
+                             some_global = a;
+                          }
+                        static void *start_routine(void *a) { return a; }
+int
+main ()
+{
+pthread_t th; pthread_attr_t attr;
+                        pthread_create(&th, 0, start_routine, 0);
+                        pthread_join(th, 0);
+                        pthread_attr_init(&attr);
+                        pthread_cleanup_push(routine, 0);
+                        pthread_cleanup_pop(0) /* ; */
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ax_pthread_ok=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+
+        CFLAGS="$ax_pthread_save_CFLAGS"
+        LIBS="$ax_pthread_save_LIBS"
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_pthread_ok" >&5
+$as_echo "$ax_pthread_ok" >&6; }
+        if test "x$ax_pthread_ok" = "xyes"; then :
+  break
+fi
+
+        PTHREAD_LIBS=""
+        PTHREAD_CFLAGS=""
+done
+fi
+
+
+# Clang needs special handling, because older versions handle the -pthread
+# option in a rather... idiosyncratic way
+
+if test "x$ax_pthread_clang" = "xyes"; then
+
+        # Clang takes -pthread; it has never supported any other flag
+
+        # (Note 1: This will need to be revisited if a system that Clang
+        # supports has POSIX threads in a separate library.  This tends not
+        # to be the way of modern systems, but it's conceivable.)
+
+        # (Note 2: On some systems, notably Darwin, -pthread is not needed
+        # to get POSIX threads support; the API is always present and
+        # active.  We could reasonably leave PTHREAD_CFLAGS empty.  But
+        # -pthread does define _REENTRANT, and while the Darwin headers
+        # ignore this macro, third-party headers might not.)
+
+        # However, older versions of Clang make a point of warning the user
+        # that, in an invocation where only linking and no compilation is
+        # taking place, the -pthread option has no effect ("argument unused
+        # during compilation").  They expect -pthread to be passed in only
+        # when source code is being compiled.
+        #
+        # Problem is, this is at odds with the way Automake and most other
+        # C build frameworks function, which is that the same flags used in
+        # compilation (CFLAGS) are also used in linking.  Many systems
+        # supported by AX_PTHREAD require exactly this for POSIX threads
+        # support, and in fact it is often not straightforward to specify a
+        # flag that is used only in the compilation phase and not in
+        # linking.  Such a scenario is extremely rare in practice.
+        #
+        # Even though use of the -pthread flag in linking would only print
+        # a warning, this can be a nuisance for well-run software projects
+        # that build with -Werror.  So if the active version of Clang has
+        # this misfeature, we search for an option to squash it.
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread" >&5
+$as_echo_n "checking whether Clang needs flag to prevent \"argument unused\" warning when linking with -pthread... " >&6; }
+if ${ax_cv_PTHREAD_CLANG_NO_WARN_FLAG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
+             # Create an alternate version of $ac_link that compiles and
+             # links in two steps (.c -> .o, .o -> exe) instead of one
+             # (.c -> exe), because the warning occurs only in the second
+             # step
+             ax_pthread_save_ac_link="$ac_link"
+             ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
+             ax_pthread_link_step=`$as_echo "$ac_link" | sed "$ax_pthread_sed"`
+             ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
+             ax_pthread_save_CFLAGS="$CFLAGS"
+             for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
+                if test "x$ax_pthread_try" = "xunknown"; then :
+  break
+fi
+                CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
+                ac_link="$ax_pthread_save_ac_link"
+                cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int main(void){return 0;}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_link="$ax_pthread_2step_ac_link"
+                     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+int main(void){return 0;}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  break
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+             done
+             ac_link="$ax_pthread_save_ac_link"
+             CFLAGS="$ax_pthread_save_CFLAGS"
+             if test "x$ax_pthread_try" = "x"; then :
+  ax_pthread_try=no
+fi
+             ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&5
+$as_echo "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" >&6; }
+
+        case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
+                no | unknown) ;;
+                *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
+        esac
+
+fi # $ax_pthread_clang = yes
+
+
+
+# Various other checks:
+if test "x$ax_pthread_ok" = "xyes"; then
+        ax_pthread_save_CFLAGS="$CFLAGS"
+        ax_pthread_save_LIBS="$LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+
+        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for joinable pthread attribute" >&5
+$as_echo_n "checking for joinable pthread attribute... " >&6; }
+if ${ax_cv_PTHREAD_JOINABLE_ATTR+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ax_cv_PTHREAD_JOINABLE_ATTR=unknown
+             for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+                 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <pthread.h>
+int
+main ()
+{
+int attr = $ax_pthread_attr; return attr /* ; */
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+             done
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_JOINABLE_ATTR" >&5
+$as_echo "$ax_cv_PTHREAD_JOINABLE_ATTR" >&6; }
+        if test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
+               test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
+               test "x$ax_pthread_joinable_attr_defined" != "xyes"; then :
+
+cat >>confdefs.h <<_ACEOF
+#define PTHREAD_CREATE_JOINABLE $ax_cv_PTHREAD_JOINABLE_ATTR
+_ACEOF
+
+               ax_pthread_joinable_attr_defined=yes
+
+fi
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether more special flags are required for pthreads" >&5
+$as_echo_n "checking whether more special flags are required for pthreads... " >&6; }
+if ${ax_cv_PTHREAD_SPECIAL_FLAGS+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ax_cv_PTHREAD_SPECIAL_FLAGS=no
+             case $target_os in
+             solaris*)
+             ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
+             ;;
+             esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_SPECIAL_FLAGS" >&5
+$as_echo "$ax_cv_PTHREAD_SPECIAL_FLAGS" >&6; }
+        if test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
+               test "x$ax_pthread_special_flags_added" != "xyes"; then :
+  PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
+               ax_pthread_special_flags_added=yes
+fi
+
+        { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PTHREAD_PRIO_INHERIT" >&5
+$as_echo_n "checking for PTHREAD_PRIO_INHERIT... " >&6; }
+if ${ax_cv_PTHREAD_PRIO_INHERIT+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <pthread.h>
+int
+main ()
+{
+int i = PTHREAD_PRIO_INHERIT;
+                                               return i;
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ax_cv_PTHREAD_PRIO_INHERIT=yes
+else
+  ax_cv_PTHREAD_PRIO_INHERIT=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_PTHREAD_PRIO_INHERIT" >&5
+$as_echo "$ax_cv_PTHREAD_PRIO_INHERIT" >&6; }
+        if test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
+               test "x$ax_pthread_prio_inherit_defined" != "xyes"; then :
+
+$as_echo "#define HAVE_PTHREAD_PRIO_INHERIT 1" >>confdefs.h
+
+               ax_pthread_prio_inherit_defined=yes
+
+fi
+
+        CFLAGS="$ax_pthread_save_CFLAGS"
+        LIBS="$ax_pthread_save_LIBS"
+
+        # More AIX lossage: compile with *_r variant
+        if test "x$GCC" != "xyes"; then
+            case $target_os in
+                aix*)
+                case "x/$CC" in #(
+  x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6) :
+    #handle absolute path differently from PATH based program lookup
+                     case "x$CC" in #(
+  x/*) :
+
+			   if as_fn_executable_p ${CC}_r; then :
+  PTHREAD_CC="${CC}_r"
+fi
+			   if test "x${CXX}" != "x"; then :
+  if as_fn_executable_p ${CXX}_r; then :
+  PTHREAD_CXX="${CXX}_r"
+fi
+fi
+			  ;; #(
+  *) :
+
+			   for ac_prog in ${CC}_r
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_PTHREAD_CC+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$PTHREAD_CC"; then
+  ac_cv_prog_PTHREAD_CC="$PTHREAD_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_PTHREAD_CC="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+PTHREAD_CC=$ac_cv_prog_PTHREAD_CC
+if test -n "$PTHREAD_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CC" >&5
+$as_echo "$PTHREAD_CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$PTHREAD_CC" && break
+done
+test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
+
+			   if test "x${CXX}" != "x"; then :
+  for ac_prog in ${CXX}_r
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_PTHREAD_CXX+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$PTHREAD_CXX"; then
+  ac_cv_prog_PTHREAD_CXX="$PTHREAD_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_PTHREAD_CXX="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
 fi
+fi
+PTHREAD_CXX=$ac_cv_prog_PTHREAD_CXX
+if test -n "$PTHREAD_CXX"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PTHREAD_CXX" >&5
+$as_echo "$PTHREAD_CXX" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$PTHREAD_CXX" && break
 done
+test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX"
+
+fi
 
+                      ;;
+esac
+                     ;; #(
+  *) :
+     ;;
+esac
+                ;;
+            esac
+        fi
+fi
+
+test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
+test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX"
+
+
+
+
+
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test "x$ax_pthread_ok" = "xyes"; then
+
+$as_echo "#define HAVE_PTHREAD 1" >>confdefs.h
+
+        :
+else
+        ax_pthread_ok=no
+
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+	LIBS="$PTHREAD_LIBS $LIBS"
+	CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+	CC="$PTHREAD_CC"
 fi
 
 
@@ -14326,7 +15094,7 @@
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by libp11 $as_me 0.4.11, which was
+This file was extended by libp11 $as_me 0.4.12, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -14392,7 +15160,7 @@
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-libp11 config.status 0.4.11
+libp11 config.status 0.4.12
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
@@ -14564,7 +15332,6 @@
 want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`'
 sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
 AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
-lt_ar_flags='`$ECHO "$lt_ar_flags" | $SED "$delay_single_quote_subst"`'
 AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
 archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`'
 STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
@@ -14736,6 +15503,7 @@
 want_nocaseglob \
 sharedlib_from_linklib_cmd \
 AR \
+AR_FLAGS \
 archiver_list_spec \
 STRIP \
 RANLIB \
@@ -15598,7 +16366,6 @@
     cat <<_LT_EOF >> "$cfgfile"
 #! $SHELL
 # Generated automatically by $as_me ($PACKAGE) $VERSION
-# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
 # NOTE: Changes made to this file will be lost: look at ltmain.sh.
 
 # Provide generalized library-building support services.
@@ -15745,11 +16512,8 @@
 # The archiver.
 AR=$lt_AR
 
-# Flags to create an archive (by configure).
-lt_ar_flags=$lt_ar_flags
-
 # Flags to create an archive.
-AR_FLAGS=\${ARFLAGS-"\$lt_ar_flags"}
+AR_FLAGS=$lt_AR_FLAGS
 
 # How to feed a file listing to the archiver.
 archiver_list_spec=$lt_archiver_list_spec
diff -Nru libp11-0.4.11/configure.ac libp11-0.4.12/configure.ac
--- libp11-0.4.11/configure.ac	2020-10-11 15:46:53.000000000 +0200
+++ libp11-0.4.12/configure.ac	2022-07-15 21:56:04.000000000 +0200
@@ -5,13 +5,14 @@
 # When bumping versions see also the LT version numbers below.
 define([PACKAGE_VERSION_MAJOR], [0])
 define([PACKAGE_VERSION_MINOR], [4])
-define([PACKAGE_VERSION_FIX], [11])
+define([PACKAGE_VERSION_FIX], [12])
 define([PACKAGE_SUFFIX], [])
 
 AC_INIT([libp11],[PACKAGE_VERSION_MAJOR.PACKAGE_VERSION_MINOR.PACKAGE_VERSION_FIX[]PACKAGE_SUFFIX])
 AC_CONFIG_AUX_DIR([.])
 AC_CONFIG_HEADERS([src/config.h])
 AC_CONFIG_MACRO_DIR([m4])
+AC_CANONICAL_TARGET
 AM_INIT_AUTOMAKE([subdir-objects])
 
 LIBP11_VERSION_MAJOR="PACKAGE_VERSION_MAJOR"
@@ -56,8 +57,8 @@
 # the openssl version we link to. If the ABI is broken on a later
 # release, we should either stick to supporting a single openssl ABI
 # or bump the LT_OLDEST version sufficiently to avoid clashes.
-LIBP11_LT_REVISION="3"
-LIBP11_LT_CURRENT="7"
+LIBP11_LT_REVISION="0"
+LIBP11_LT_CURRENT="8"
 LIBP11_LT_AGE="$((${LIBP11_LT_CURRENT}-${LIBP11_LT_OLDEST}))"
 
 gl_LD_VERSION_SCRIPT
@@ -75,7 +76,7 @@
 case "${host}" in
 	*-mingw*|*-winnt*)
 		WIN32="yes"
-		CPPFLAGS="${CPPFLAGS} -DWIN32_LEAN_AND_MEAN"
+		CPPFLAGS="${CPPFLAGS} -D_WIN32_WINNT=0x0600 -DWIN32_LEAN_AND_MEAN"
 		WIN_LIBPREFIX="lib"
 	;;
 	*-cygwin*)
@@ -193,7 +194,10 @@
 		,
 		[AC_MSG_ERROR([dlopen required])]
 	)
-	AC_CHECK_FUNCS([__register_atfork],,)
+	AX_PTHREAD
+	LIBS="$PTHREAD_LIBS $LIBS"
+	CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+	CC="$PTHREAD_CC"
 fi
 
 PKG_CHECK_MODULES(
diff -Nru libp11-0.4.11/debian/changelog libp11-0.4.12/debian/changelog
--- libp11-0.4.11/debian/changelog	2020-10-18 04:48:01.000000000 +0200
+++ libp11-0.4.12/debian/changelog	2022-12-09 13:58:32.000000000 +0100
@@ -1,3 +1,11 @@
+libp11 (0.4.12-0.1) unstable; urgency=medium
+
+  * Non-maintainer upload
+  * New upstream release (Closes: #1017385, #1017386)
+  * Drop transitional package (Closes: #1011065)
+
+ -- Bastian Germann <bage at debian.org>  Fri, 09 Dec 2022 12:58:32 +0000
+
 libp11 (0.4.11-1) unstable; urgency=medium
 
   * New upstream release
diff -Nru libp11-0.4.11/debian/control libp11-0.4.12/debian/control
--- libp11-0.4.11/debian/control	2020-10-18 04:48:01.000000000 +0200
+++ libp11-0.4.12/debian/control	2022-12-09 13:58:32.000000000 +0100
@@ -44,10 +44,6 @@
 Architecture: any
 Multi-Arch: same
 Depends: p11-kit, ${misc:Depends}, ${shlibs:Depends}
-Conflicts: libopensc-openssl
-Breaks: libengine-pkcs11-openssl1.1 (<< 0.4.9-2)
-Replaces: libopensc-openssl, libengine-pkcs11-openssl1.1 (<< 0.4.9-2)
-Provides: libopensc-openssl, libengine-pkcs11-openssl1.1
 Description: OpenSSL engine for PKCS#11 modules
  With this engine for OpenSSL you can use OpenSSL library
  and command line tools with any PKCS#11 implementation as
@@ -59,11 +55,3 @@
  .
  Engine_pkcs11 is a spin off from OpenSC and replaced
  libopensc-openssl.
-
-Package: libengine-pkcs11-openssl1.1
-Section: oldlibs
-Architecture: any
-Multi-Arch: same
-Depends: libengine-pkcs11-openssl (= ${binary:Version}), ${misc:Depends}
-Description: dummy package for upgrades from libengine-pkcs11-openssl1.1
- Can be safely removed.
diff -Nru libp11-0.4.11/debian/libp11-3.symbols libp11-0.4.12/debian/libp11-3.symbols
--- libp11-0.4.11/debian/libp11-3.symbols	2020-10-18 04:48:01.000000000 +0200
+++ libp11-0.4.12/debian/libp11-3.symbols	2022-12-09 13:58:32.000000000 +0100
@@ -48,4 +48,5 @@
  PKCS11_store_certificate at LIBP11_3 0.4.4
  PKCS11_store_private_key at LIBP11_3 0.4.4
  PKCS11_store_public_key at LIBP11_3 0.4.4
+ PKCS11_update_slots at LIBP11_3 0.4.12
  PKCS11_verify at LIBP11_3 0.4.4
diff -Nru libp11-0.4.11/debian/watch libp11-0.4.12/debian/watch
--- libp11-0.4.11/debian/watch	2020-10-18 04:48:01.000000000 +0200
+++ libp11-0.4.12/debian/watch	2022-12-09 13:55:18.000000000 +0100
@@ -1,4 +1,4 @@
 version=4
 
-opts=pgpsigurlmangle=s/$/.asc/ \
-  https://github.com/OpenSC/libp11/releases .*/download/(?:.*/)libp11-([\d\.]*)\.tar\.gz
+opts=searchmode=plain,pgpsigurlmangle=s/$/.asc/ \
+  https://api.github.com/repos/OpenSC/libp11/releases https://github.com/OpenSC/libp11/releases/download/libp11-[\d\.]+/libp11-([\d\.]+)\.tar\.gz
diff -Nru libp11-0.4.11/depcomp libp11-0.4.12/depcomp
--- libp11-0.4.11/depcomp	2018-10-02 20:47:03.000000000 +0200
+++ libp11-0.4.12/depcomp	2022-03-15 18:14:17.000000000 +0100
@@ -3,7 +3,7 @@
 
 scriptversion=2018-03-07.03; # UTC
 
-# Copyright (C) 1999-2018 Free Software Foundation, Inc.
+# Copyright (C) 1999-2020 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
diff -Nru libp11-0.4.11/doc/Makefile.in libp11-0.4.12/doc/Makefile.in
--- libp11-0.4.11/doc/Makefile.in	2020-10-11 15:46:57.000000000 +0200
+++ libp11-0.4.12/doc/Makefile.in	2022-07-15 21:56:26.000000000 +0200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.2 from Makefile.am.
+# Makefile.in generated by automake 1.16.4 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -88,9 +88,11 @@
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
+target_triplet = @target@
 subdir = doc
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/ld-version-script.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_pthread.m4 \
+	$(top_srcdir)/m4/ld-version-script.m4 \
 	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
 	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
 	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
@@ -167,6 +169,8 @@
 CFLAGS = @CFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
@@ -178,6 +182,7 @@
 ECHO_N = @ECHO_N@
 ECHO_T = @ECHO_T@
 EGREP = @EGREP@
+ETAGS = @ETAGS@
 EXEEXT = @EXEEXT@
 FGREP = @FGREP@
 GREP = @GREP@
@@ -224,6 +229,10 @@
 PKG_CONFIG = @PKG_CONFIG@
 PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
 PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_CXX = @PTHREAD_CXX@
+PTHREAD_LIBS = @PTHREAD_LIBS@
 RANLIB = @RANLIB@
 RC = @RC@
 SED = @SED@
@@ -246,6 +255,7 @@
 am__tar = @am__tar@
 am__untar = @am__untar@
 apidocdir = @apidocdir@
+ax_pthread_config = @ax_pthread_config@
 bindir = @bindir@
 build = @build@
 build_alias = @build_alias@
@@ -285,7 +295,11 @@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
 sysconfdir = @sysconfdir@
+target = @target@
 target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
@@ -381,7 +395,6 @@
 
 cscope cscopelist:
 
-
 distdir: $(BUILT_SOURCES)
 	$(MAKE) $(AM_MAKEFLAGS) distdir-am
 
diff -Nru libp11-0.4.11/examples/auth.c libp11-0.4.12/examples/auth.c
--- libp11-0.4.11/examples/auth.c	2020-02-27 06:50:01.000000000 +0100
+++ libp11-0.4.12/examples/auth.c	2022-07-05 22:22:51.000000000 +0200
@@ -267,10 +267,10 @@
 
 	/* now verify the result */
 	rc = RSA_verify(NID_sha1, random, RANDOM_SIZE,
-#if OPENSSL_VERSION_NUMBER >= 0x10100003L && !defined(LIBRESSL_VERSION_NUMBER)
-			signature, siglen, EVP_PKEY_get0_RSA(pubkey));
+#if OPENSSL_VERSION_NUMBER >= 0x10100003L || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3050000fL )
+			signature, siglen, (RSA *)EVP_PKEY_get0_RSA(pubkey));
 #else
-			signature, siglen, pubkey->pkey.rsa);
+			signature, siglen, (RSA *)pubkey->pkey.rsa);
 #endif
 	if (rc != 1) {
 		fprintf(stderr, "fatal: RSA_verify failed\n");
@@ -302,7 +302,7 @@
 	if (rc)
 		printf("authentication failed.\n");
 	else
-		printf("authentication successfull.\n");
+		printf("authentication successful.\n");
 	return rc;
 }
 
diff -Nru libp11-0.4.11/examples/decrypt.c libp11-0.4.12/examples/decrypt.c
--- libp11-0.4.11/examples/decrypt.c	2020-02-27 06:50:01.000000000 +0100
+++ libp11-0.4.12/examples/decrypt.c	2022-07-05 22:22:51.000000000 +0200
@@ -168,7 +168,7 @@
 	}
 
 	/* allocate destination buffer */
-#if OPENSSL_VERSION_NUMBER >= 0x10100003L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100003L || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3050000fL )
 	encrypted = OPENSSL_malloc(RSA_size(EVP_PKEY_get0_RSA(pubkey)));
 #else
 	encrypted = OPENSSL_malloc(RSA_size(pubkey->pkey.rsa));
@@ -181,8 +181,8 @@
 
 	/* use public key for encryption */
 	len = RSA_public_encrypt(RANDOM_SIZE, random, encrypted,
-#if OPENSSL_VERSION_NUMBER >= 0x10100003L && !defined(LIBRESSL_VERSION_NUMBER)
-			EVP_PKEY_get0_RSA(pubkey),
+#if OPENSSL_VERSION_NUMBER >= 0x10100003L || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3050000fL )
+			(RSA *)EVP_PKEY_get0_RSA(pubkey),
 #else
 			pubkey->pkey.rsa,
 #endif
@@ -248,7 +248,7 @@
 	}
 
 	/* allocate space for decrypted data */
-#if OPENSSL_VERSION_NUMBER >= 0x10100003L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100003L || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3050000fL )
 	decrypted = OPENSSL_malloc(RSA_size(EVP_PKEY_get0_RSA(pubkey)));
 #else
 	decrypted = OPENSSL_malloc(RSA_size(pubkey->pkey.rsa));
@@ -299,7 +299,7 @@
 	if (rc)
 		printf("decryption failed.\n");
 	else
-		printf("decryption successfull.\n");
+		printf("decryption successful.\n");
 	return rc;
 }
 
diff -Nru libp11-0.4.11/examples/Makefile.in libp11-0.4.12/examples/Makefile.in
--- libp11-0.4.11/examples/Makefile.in	2020-10-11 15:46:57.000000000 +0200
+++ libp11-0.4.12/examples/Makefile.in	2022-07-15 21:56:26.000000000 +0200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.2 from Makefile.am.
+# Makefile.in generated by automake 1.16.4 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -88,11 +88,13 @@
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
+target_triplet = @target@
 noinst_PROGRAMS = auth$(EXEEXT) decrypt$(EXEEXT) getrandom$(EXEEXT) \
 	listkeys$(EXEEXT)
 subdir = examples
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/ld-version-script.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_pthread.m4 \
+	$(top_srcdir)/m4/ld-version-script.m4 \
 	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
 	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
 	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
@@ -185,8 +187,6 @@
   unique=`for i in $$list; do \
     if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
   done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
 am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp README
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 ACLOCAL = @ACLOCAL@
@@ -203,6 +203,8 @@
 CFLAGS = @CFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
@@ -214,6 +216,7 @@
 ECHO_N = @ECHO_N@
 ECHO_T = @ECHO_T@
 EGREP = @EGREP@
+ETAGS = @ETAGS@
 EXEEXT = @EXEEXT@
 FGREP = @FGREP@
 GREP = @GREP@
@@ -260,6 +263,10 @@
 PKG_CONFIG = @PKG_CONFIG@
 PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
 PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_CXX = @PTHREAD_CXX@
+PTHREAD_LIBS = @PTHREAD_LIBS@
 RANLIB = @RANLIB@
 RC = @RC@
 SED = @SED@
@@ -282,6 +289,7 @@
 am__tar = @am__tar@
 am__untar = @am__untar@
 apidocdir = @apidocdir@
+ax_pthread_config = @ax_pthread_config@
 bindir = @bindir@
 build = @build@
 build_alias = @build_alias@
@@ -321,7 +329,11 @@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
 sysconfdir = @sysconfdir@
+target = @target@
 target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
@@ -488,7 +500,6 @@
 
 distclean-tags:
 	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
 distdir: $(BUILT_SOURCES)
 	$(MAKE) $(AM_MAKEFLAGS) distdir-am
 
diff -Nru libp11-0.4.11/INSTALL.md libp11-0.4.12/INSTALL.md
--- libp11-0.4.11/INSTALL.md	2020-02-27 06:50:01.000000000 +0100
+++ libp11-0.4.12/INSTALL.md	2022-07-05 22:22:51.000000000 +0200
@@ -100,12 +100,12 @@
 
 ### MinGW cross-compile on a Unix host
 
-We assume that OpenSSL is installed in /opt/openssl-mingw64.
-Update the paths to match your environment.
+Example configuration for a 64-bit OpenSSL installed in /opt/openssl-mingw64:
+  PKG_CONFIG_PATH=/opt/openssl-mingw64/lib64/pkgconfig ./configure --host=x86_64-w64-mingw32 --prefix=/opt/libp11-mingw64
 
-  export PKG_CONFIG_PATH=/opt/openssl-mingw64/lib/pkgconfig
-
-  ./configure --host=x86_64-w64-mingw32 --prefix=/opt/libp11-mingw64
+Example configuration for a 32-bit OpenSSL installed in /opt/openssl-mingw:
+  PKG_CONFIG_PATH=/opt/openssl-mingw/lib/pkgconfig ./configure --host=i686-w64-mingw32 --prefix=/opt/libp11-mingw
 
+Building and installing:
   make && sudo make install
 
diff -Nru libp11-0.4.11/install-sh libp11-0.4.12/install-sh
--- libp11-0.4.11/install-sh	2018-10-02 20:47:03.000000000 +0200
+++ libp11-0.4.12/install-sh	2022-03-15 18:14:17.000000000 +0100
@@ -1,7 +1,7 @@
 #!/bin/sh
 # install - install a program, script, or datafile
 
-scriptversion=2018-03-11.20; # UTC
+scriptversion=2020-11-14.01; # UTC
 
 # This originates from X11R5 (mit/util/scripts/install.sh), which was
 # later released in X11R6 (xc/config/util/install.sh) with the
@@ -69,6 +69,11 @@
 # Desired mode of installed file.
 mode=0755
 
+# Create dirs (including intermediate dirs) using mode 755.
+# This is like GNU 'install' as of coreutils 8.32 (2020).
+mkdir_umask=22
+
+backupsuffix=
 chgrpcmd=
 chmodcmd=$chmodprog
 chowncmd=
@@ -99,18 +104,28 @@
      --version  display version info and exit.
 
   -c            (ignored)
-  -C            install only if different (preserve the last data modification time)
+  -C            install only if different (preserve data modification time)
   -d            create directories instead of installing files.
   -g GROUP      $chgrpprog installed files to GROUP.
   -m MODE       $chmodprog installed files to MODE.
   -o USER       $chownprog installed files to USER.
+  -p            pass -p to $cpprog.
   -s            $stripprog installed files.
+  -S SUFFIX     attempt to back up existing files, with suffix SUFFIX.
   -t DIRECTORY  install into DIRECTORY.
   -T            report an error if DSTFILE is a directory.
 
 Environment variables override the default commands:
   CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
   RMPROG STRIPPROG
+
+By default, rm is invoked with -f; when overridden with RMPROG,
+it's up to you to specify -f if you want it.
+
+If -S is not specified, no backups are attempted.
+
+Email bug reports to bug-automake at gnu.org.
+Automake home page: https://www.gnu.org/software/automake/
 "
 
 while test $# -ne 0; do
@@ -137,8 +152,13 @@
     -o) chowncmd="$chownprog $2"
         shift;;
 
+    -p) cpprog="$cpprog -p";;
+
     -s) stripcmd=$stripprog;;
 
+    -S) backupsuffix="$2"
+        shift;;
+
     -t)
         is_target_a_directory=always
         dst_arg=$2
@@ -255,6 +275,10 @@
     dstdir=$dst
     test -d "$dstdir"
     dstdir_status=$?
+    # Don't chown directories that already exist.
+    if test $dstdir_status = 0; then
+      chowncmd=""
+    fi
   else
 
     # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
@@ -301,22 +325,6 @@
   if test $dstdir_status != 0; then
     case $posix_mkdir in
       '')
-        # Create intermediate dirs using mode 755 as modified by the umask.
-        # This is like FreeBSD 'install' as of 1997-10-28.
-        umask=`umask`
-        case $stripcmd.$umask in
-          # Optimize common cases.
-          *[2367][2367]) mkdir_umask=$umask;;
-          .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
-
-          *[0-7])
-            mkdir_umask=`expr $umask + 22 \
-              - $umask % 100 % 40 + $umask % 20 \
-              - $umask % 10 % 4 + $umask % 2
-            `;;
-          *) mkdir_umask=$umask,go-w;;
-        esac
-
         # With -d, create the new directory with the user-specified mode.
         # Otherwise, rely on $mkdir_umask.
         if test -n "$dir_arg"; then
@@ -326,52 +334,49 @@
         fi
 
         posix_mkdir=false
-        case $umask in
-          *[123567][0-7][0-7])
-            # POSIX mkdir -p sets u+wx bits regardless of umask, which
-            # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
-            ;;
-          *)
-            # Note that $RANDOM variable is not portable (e.g. dash);  Use it
-            # here however when possible just to lower collision chance.
-            tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
-
-            trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
-
-            # Because "mkdir -p" follows existing symlinks and we likely work
-            # directly in world-writeable /tmp, make sure that the '$tmpdir'
-            # directory is successfully created first before we actually test
-            # 'mkdir -p' feature.
-            if (umask $mkdir_umask &&
-                $mkdirprog $mkdir_mode "$tmpdir" &&
-                exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
-            then
-              if test -z "$dir_arg" || {
-                   # Check for POSIX incompatibilities with -m.
-                   # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
-                   # other-writable bit of parent directory when it shouldn't.
-                   # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
-                   test_tmpdir="$tmpdir/a"
-                   ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
-                   case $ls_ld_tmpdir in
-                     d????-?r-*) different_mode=700;;
-                     d????-?--*) different_mode=755;;
-                     *) false;;
-                   esac &&
-                   $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
-                     ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
-                     test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
-                   }
-                 }
-              then posix_mkdir=:
-              fi
-              rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
-            else
-              # Remove any dirs left behind by ancient mkdir implementations.
-              rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
-            fi
-            trap '' 0;;
-        esac;;
+	# The $RANDOM variable is not portable (e.g., dash).  Use it
+	# here however when possible just to lower collision chance.
+	tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+
+	trap '
+	  ret=$?
+	  rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null
+	  exit $ret
+	' 0
+
+	# Because "mkdir -p" follows existing symlinks and we likely work
+	# directly in world-writeable /tmp, make sure that the '$tmpdir'
+	# directory is successfully created first before we actually test
+	# 'mkdir -p'.
+	if (umask $mkdir_umask &&
+	    $mkdirprog $mkdir_mode "$tmpdir" &&
+	    exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
+	then
+	  if test -z "$dir_arg" || {
+	       # Check for POSIX incompatibilities with -m.
+	       # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+	       # other-writable bit of parent directory when it shouldn't.
+	       # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+	       test_tmpdir="$tmpdir/a"
+	       ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
+	       case $ls_ld_tmpdir in
+		 d????-?r-*) different_mode=700;;
+		 d????-?--*) different_mode=755;;
+		 *) false;;
+	       esac &&
+	       $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
+		 ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
+		 test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+	       }
+	     }
+	  then posix_mkdir=:
+	  fi
+	  rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
+	else
+	  # Remove any dirs left behind by ancient mkdir implementations.
+	  rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
+	fi
+	trap '' 0;;
     esac
 
     if
@@ -382,7 +387,7 @@
     then :
     else
 
-      # The umask is ridiculous, or mkdir does not conform to POSIX,
+      # mkdir does not conform to POSIX,
       # or it failed possibly due to a race condition.  Create the
       # directory the slow way, step by step, checking for races as we go.
 
@@ -411,7 +416,7 @@
           prefixes=
         else
           if $posix_mkdir; then
-            (umask=$mkdir_umask &&
+            (umask $mkdir_umask &&
              $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
             # Don't fail if two instances are running concurrently.
             test -d "$prefix" || exit 1
@@ -451,7 +456,18 @@
     trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
 
     # Copy the file name to the temp name.
-    (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+    (umask $cp_umask &&
+     { test -z "$stripcmd" || {
+	 # Create $dsttmp read-write so that cp doesn't create it read-only,
+	 # which would cause strip to fail.
+	 if test -z "$doit"; then
+	   : >"$dsttmp" # No need to fork-exec 'touch'.
+	 else
+	   $doit touch "$dsttmp"
+	 fi
+       }
+     } &&
+     $doit_exec $cpprog "$src" "$dsttmp") &&
 
     # and set any options; do chmod last to preserve setuid bits.
     #
@@ -477,6 +493,13 @@
     then
       rm -f "$dsttmp"
     else
+      # If $backupsuffix is set, and the file being installed
+      # already exists, attempt a backup.  Don't worry if it fails,
+      # e.g., if mv doesn't support -f.
+      if test -n "$backupsuffix" && test -f "$dst"; then
+        $doit $mvcmd -f "$dst" "$dst$backupsuffix" 2>/dev/null
+      fi
+
       # Rename the file to the real destination.
       $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
 
@@ -491,9 +514,9 @@
         # file should still install successfully.
         {
           test ! -f "$dst" ||
-          $doit $rmcmd -f "$dst" 2>/dev/null ||
+          $doit $rmcmd "$dst" 2>/dev/null ||
           { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
-            { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+            { $doit $rmcmd "$rmtmp" 2>/dev/null; :; }
           } ||
           { echo "$0: cannot unlink or rename $dst" >&2
             (exit 1); exit 1
diff -Nru libp11-0.4.11/ltmain.sh libp11-0.4.12/ltmain.sh
--- libp11-0.4.11/ltmain.sh	2018-10-02 20:46:56.000000000 +0200
+++ libp11-0.4.12/ltmain.sh	2022-03-15 18:14:13.000000000 +0100
@@ -1,12 +1,12 @@
 #! /bin/sh
 ## DO NOT EDIT - This file generated from ./build-aux/ltmain.in
-##               by inline-source v2018-07-24.06
+##               by inline-source v2014-01-03.01
 
-# libtool (GNU libtool) 2.4.6.42-b88ce
+# libtool (GNU libtool) 2.4.6
 # Provide generalized library-building support services.
 # Written by Gordon Matzigkeit <gord at gnu.ai.mit.edu>, 1996
 
-# Copyright (C) 1996-2018 Free Software Foundation, Inc.
+# Copyright (C) 1996-2015 Free Software Foundation, Inc.
 # This is free software; see the source for copying conditions.  There is NO
 # warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 
@@ -31,8 +31,8 @@
 
 PROGRAM=libtool
 PACKAGE=libtool
-VERSION=2.4.6.42-b88ce
-package_revision=2.4.6.42
+VERSION="2.4.6 Debian-2.4.6-15"
+package_revision=2.4.6
 
 
 ## ------ ##
@@ -64,25 +64,34 @@
 # libraries, which are installed to $pkgauxdir.
 
 # Set a version string for this script.
-scriptversion=2018-07-24.06; # UTC
+scriptversion=2015-01-20.17; # UTC
 
 # General shell script boiler plate, and helper functions.
 # Written by Gary V. Vaughan, 2004
 
-# This is free software.  There is NO warranty; not even for
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-#
-# Copyright (C) 2004-2018 Bootstrap Authors
-#
-# This file is dual licensed under the terms of the MIT license
-# <https://opensource.org/license/MIT>, and GPL version 3 or later
-# <http://www.gnu.org/licenses/gpl-2.0.html>.  You must apply one of
-# these licenses when using or redistributing this software or any of
-# the files within it.  See the URLs above, or the file `LICENSE`
-# included in the Bootstrap distribution for the full license texts.
+# Copyright (C) 2004-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# As a special exception to the GNU General Public License, if you distribute
+# this file as part of a program or library that is built using GNU Libtool,
+# you may include this file under the same distribution terms that you use
+# for the rest of that program.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNES FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
 
-# Please report bugs or propose patches to:
-# <https://github.com/gnulib-modules/bootstrap/issues>
+# Please report bugs or propose patches to gary at gnu.org.
 
 
 ## ------ ##
@@ -131,6 +140,9 @@
 	fi"
 done
 
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
 # Make sure IFS has a sensible default
 sp=' '
 nl='
@@ -147,26 +159,6 @@
 fi
 
 
-# func_unset VAR
-# --------------
-# Portably unset VAR.
-# In some shells, an 'unset VAR' statement leaves a non-zero return
-# status if VAR is already unset, which might be problematic if the
-# statement is used at the end of a function (thus poisoning its return
-# value) or when 'set -e' is active (causing even a spurious abort of
-# the script in this case).
-func_unset ()
-{
-    { eval $1=; (eval unset $1) >/dev/null 2>&1 && eval unset $1 || : ; }
-}
-
-
-# Make sure CDPATH doesn't cause `cd` commands to output the target dir.
-func_unset CDPATH
-
-# Make sure ${,E,F}GREP behave sanely.
-func_unset GREP_OPTIONS
-
 
 ## ------------------------- ##
 ## Locate command utilities. ##
@@ -267,7 +259,7 @@
     rm -f conftest.in conftest.tmp conftest.nl conftest.out
   }
 
-  func_path_progs "sed gsed" func_check_prog_sed "$PATH:/usr/xpg4/bin"
+  func_path_progs "sed gsed" func_check_prog_sed $PATH:/usr/xpg4/bin
   rm -f conftest.sed
   SED=$func_path_progs_result
 }
@@ -303,7 +295,7 @@
     rm -f conftest.in conftest.tmp conftest.nl conftest.out
   }
 
-  func_path_progs "grep ggrep" func_check_prog_grep "$PATH:/usr/xpg4/bin"
+  func_path_progs "grep ggrep" func_check_prog_grep $PATH:/usr/xpg4/bin
   GREP=$func_path_progs_result
 }
 
@@ -395,7 +387,7 @@
 # putting '$debug_cmd' at the start of all your functions, you can get
 # bash to show function call trace with:
 #
-#    debug_cmd='eval echo "${FUNCNAME[0]} $*" >&2' bash your-script-name
+#    debug_cmd='echo "${FUNCNAME[0]} $*" >&2' bash your-script-name
 debug_cmd=${debug_cmd-":"}
 exit_cmd=:
 
@@ -588,16 +580,16 @@
   {
     $debug_cmd
 
-    func_quote_arg pretty "$2"
-    eval "$1+=\\ \$func_quote_arg_result"
+    func_quote_for_eval "$2"
+    eval "$1+=\\ \$func_quote_for_eval_result"
   }'
 else
   func_append_quoted ()
   {
     $debug_cmd
 
-    func_quote_arg pretty "$2"
-    eval "$1=\$$1\\ \$func_quote_arg_result"
+    func_quote_for_eval "$2"
+    eval "$1=\$$1\\ \$func_quote_for_eval_result"
   }
 fi
 
@@ -1099,199 +1091,85 @@
 }
 
 
-# func_quote_portable EVAL ARG
-# ----------------------------
-# Internal function to portably implement func_quote_arg.  Note that we still
-# keep attention to performance here so we as much as possible try to avoid
-# calling sed binary (so far O(N) complexity as long as func_append is O(1)).
-func_quote_portable ()
+# func_quote_for_eval ARG...
+# --------------------------
+# Aesthetically quote ARGs to be evaled later.
+# This function returns two values:
+#   i) func_quote_for_eval_result
+#      double-quoted, suitable for a subsequent eval
+#  ii) func_quote_for_eval_unquoted_result
+#      has all characters that are still active within double
+#      quotes backslashified.
+func_quote_for_eval ()
 {
     $debug_cmd
 
-    func_quote_portable_result=$2
-
-    # one-time-loop (easy break)
-    while true
-    do
-      if $1; then
-        func_quote_portable_result=`$ECHO "$2" | $SED \
-          -e "$sed_double_quote_subst" -e "$sed_double_backslash"`
-        break
-      fi
-
-      # Quote for eval.
-      case $func_quote_portable_result in
+    func_quote_for_eval_unquoted_result=
+    func_quote_for_eval_result=
+    while test 0 -lt $#; do
+      case $1 in
         *[\\\`\"\$]*)
-          case $func_quote_portable_result in
-            *[\[\*\?]*)
-              func_quote_portable_result=`$ECHO "$func_quote_portable_result" \
-                  | $SED "$sed_quote_subst"`
-              break
-              ;;
-          esac
+	  _G_unquoted_arg=`printf '%s\n' "$1" |$SED "$sed_quote_subst"` ;;
+        *)
+          _G_unquoted_arg=$1 ;;
+      esac
+      if test -n "$func_quote_for_eval_unquoted_result"; then
+	func_append func_quote_for_eval_unquoted_result " $_G_unquoted_arg"
+      else
+        func_append func_quote_for_eval_unquoted_result "$_G_unquoted_arg"
+      fi
 
-          func_quote_portable_old_IFS=$IFS
-          for _G_char in '\' '`' '"' '$'
-          do
-            # STATE($1) PREV($2) SEPARATOR($3)
-            set start "" ""
-            func_quote_portable_result=dummy"$_G_char$func_quote_portable_result$_G_char"dummy
-            IFS=$_G_char
-            for _G_part in $func_quote_portable_result
-            do
-              case $1 in
-              quote)
-                func_append func_quote_portable_result "$3$2"
-                set quote "$_G_part" "\\$_G_char"
-                ;;
-              start)
-                set first "" ""
-                func_quote_portable_result=
-                ;;
-              first)
-                set quote "$_G_part" ""
-                ;;
-              esac
-            done
-          done
-          IFS=$func_quote_portable_old_IFS
+      case $_G_unquoted_arg in
+        # Double-quote args containing shell metacharacters to delay
+        # word splitting, command substitution and variable expansion
+        # for a subsequent eval.
+        # Many Bourne shells cannot handle close brackets correctly
+        # in scan sets, so we specify it separately.
+        *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+          _G_quoted_arg=\"$_G_unquoted_arg\"
           ;;
-        *) ;;
+        *)
+          _G_quoted_arg=$_G_unquoted_arg
+	  ;;
       esac
-      break
-    done
 
-    func_quote_portable_unquoted_result=$func_quote_portable_result
-    case $func_quote_portable_result in
-      # double-quote args containing shell metacharacters to delay
-      # word splitting, command substitution and variable expansion
-      # for a subsequent eval.
-      # many bourne shells cannot handle close brackets correctly
-      # in scan sets, so we specify it separately.
-      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
-        func_quote_portable_result=\"$func_quote_portable_result\"
-        ;;
-    esac
+      if test -n "$func_quote_for_eval_result"; then
+	func_append func_quote_for_eval_result " $_G_quoted_arg"
+      else
+        func_append func_quote_for_eval_result "$_G_quoted_arg"
+      fi
+      shift
+    done
 }
 
 
-# func_quotefast_eval ARG
-# -----------------------
-# Quote one ARG (internal).  This is equivalent to 'func_quote_arg eval ARG',
-# but optimized for speed.  Result is stored in $func_quotefast_eval.
-if test xyes = `(x=; printf -v x %q yes; echo x"$x") 2>/dev/null`; then
-  printf -v _GL_test_printf_tilde %q '~'
-  if test '\~' = "$_GL_test_printf_tilde"; then
-    func_quotefast_eval ()
-    {
-      printf -v func_quotefast_eval_result %q "$1"
-    }
-  else
-    # Broken older Bash implementations.  Make those faster too if possible.
-    func_quotefast_eval ()
-    {
-      case $1 in
-        '~'*)
-          func_quote_portable false "$1"
-          func_quotefast_eval_result=$func_quote_portable_result
-          ;;
-        *)
-          printf -v func_quotefast_eval_result %q "$1"
-          ;;
-      esac
-    }
-  fi
-else
-  func_quotefast_eval ()
-  {
-    func_quote_portable false "$1"
-    func_quotefast_eval_result=$func_quote_portable_result
-  }
-fi
-
+# func_quote_for_expand ARG
+# -------------------------
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+    $debug_cmd
 
-# func_quote_arg MODEs ARG
-# ------------------------
-# Quote one ARG to be evaled later.  MODEs argument may contain zero or more
-# specifiers listed below separated by ',' character.  This function returns two
-# values:
-#   i) func_quote_arg_result
-#      double-quoted (when needed), suitable for a subsequent eval
-#  ii) func_quote_arg_unquoted_result
-#      has all characters that are still active within double
-#      quotes backslashified.  Available only if 'unquoted' is specified.
-#
-# Available modes:
-# ----------------
-# 'eval' (default)
-#       - escape shell special characters
-# 'expand'
-#       - the same as 'eval';  but do not quote variable references
-# 'pretty'
-#       - request aesthetic output, i.e. '"a b"' instead of 'a\ b'.  This might
-#         be used later in func_quote to get output like: 'echo "a b"' instead
-#         of 'echo a\ b'.  This is slower than default on some shells.
-# 'unquoted'
-#       - produce also $func_quote_arg_unquoted_result which does not contain
-#         wrapping double-quotes.
-#
-# Examples for 'func_quote_arg pretty,unquoted string':
-#
-#   string      | *_result              | *_unquoted_result
-#   ------------+-----------------------+-------------------
-#   "           | \"                    | \"
-#   a b         | "a b"                 | a b
-#   "a b"       | "\"a b\""             | \"a b\"
-#   *           | "*"                   | *
-#   z="${x-$y}" | "z=\"\${x-\$y}\""     | z=\"\${x-\$y}\"
-#
-# Examples for 'func_quote_arg pretty,unquoted,expand string':
-#
-#   string        |   *_result          |  *_unquoted_result
-#   --------------+---------------------+--------------------
-#   z="${x-$y}"   | "z=\"${x-$y}\""     | z=\"${x-$y}\"
-func_quote_arg ()
-{
-    _G_quote_expand=false
-    case ,$1, in
-      *,expand,*)
-        _G_quote_expand=:
-        ;;
+    case $1 in
+      *[\\\`\"]*)
+	_G_arg=`$ECHO "$1" | $SED \
+	    -e "$sed_double_quote_subst" -e "$sed_double_backslash"` ;;
+      *)
+        _G_arg=$1 ;;
     esac
 
-    case ,$1, in
-      *,pretty,*|*,expand,*|*,unquoted,*)
-        func_quote_portable $_G_quote_expand "$2"
-        func_quote_arg_result=$func_quote_portable_result
-        func_quote_arg_unquoted_result=$func_quote_portable_unquoted_result
-        ;;
-      *)
-        # Faster quote-for-eval for some shells.
-        func_quotefast_eval "$2"
-        func_quote_arg_result=$func_quotefast_eval_result
+    case $_G_arg in
+      # Double-quote args containing shell metacharacters to delay
+      # word splitting and command substitution for a subsequent eval.
+      # Many Bourne shells cannot handle close brackets correctly
+      # in scan sets, so we specify it separately.
+      *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \	]*|*]*|"")
+        _G_arg=\"$_G_arg\"
         ;;
     esac
-}
 
-
-# func_quote MODEs ARGs...
-# ------------------------
-# Quote all ARGs to be evaled later and join them into single command.  See
-# func_quote_arg's description for more info.
-func_quote ()
-{
-    $debug_cmd
-    _G_func_quote_mode=$1 ; shift
-    func_quote_result=
-    while test 0 -lt $#; do
-      func_quote_arg "$_G_func_quote_mode" "$1"
-      if test -n "$func_quote_result"; then
-        func_append func_quote_result " $func_quote_arg_result"
-      else
-        func_append func_quote_result "$func_quote_arg_result"
-      fi
-      shift
-    done
+    func_quote_for_expand_result=$_G_arg
 }
 
 
@@ -1337,8 +1215,8 @@
     _G_cmd=$1
     _G_fail_exp=${2-':'}
 
-    func_quote_arg pretty,expand "$_G_cmd"
-    eval "func_notquiet $func_quote_arg_result"
+    func_quote_for_expand "$_G_cmd"
+    eval "func_notquiet $func_quote_for_expand_result"
 
     $opt_dry_run || {
       eval "$_G_cmd"
@@ -1363,8 +1241,8 @@
     _G_fail_exp=${2-':'}
 
     $opt_quiet || {
-      func_quote_arg expand,pretty "$_G_cmd"
-      eval "func_echo $func_quote_arg_result"
+      func_quote_for_expand "$_G_cmd"
+      eval "func_echo $func_quote_for_expand_result"
     }
 
     $opt_dry_run || {
@@ -1491,26 +1369,30 @@
 # End:
 #! /bin/sh
 
+# Set a version string for this script.
+scriptversion=2015-10-07.11; # UTC
+
 # A portable, pluggable option parser for Bourne shell.
 # Written by Gary V. Vaughan, 2010
 
-# This is free software.  There is NO warranty; not even for
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-#
-# Copyright (C) 2010-2018 Bootstrap Authors
-#
-# This file is dual licensed under the terms of the MIT license
-# <https://opensource.org/license/MIT>, and GPL version 3 or later
-# <http://www.gnu.org/licenses/gpl-2.0.html>.  You must apply one of
-# these licenses when using or redistributing this software or any of
-# the files within it.  See the URLs above, or the file `LICENSE`
-# included in the Bootstrap distribution for the full license texts.
+# Copyright (C) 2010-2015 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions.  There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
 
-# Please report bugs or propose patches to:
-# <https://github.com/gnulib-modules/bootstrap/issues>
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
 
-# Set a version string for this script.
-scriptversion=2018-07-24.06; # UTC
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Please report bugs or propose patches to gary at gnu.org.
 
 
 ## ------ ##
@@ -1533,7 +1415,7 @@
 #
 # In order for the '--version' option to work, you will need to have a
 # suitably formatted comment like the one at the top of this file
-# starting with '# Written by ' and ending with '# Copyright'.
+# starting with '# Written by ' and ending with '# warranty; '.
 #
 # For '-h' and '--help' to work, you will also need a one line
 # description of your script's purpose in a comment directly above the
@@ -1545,7 +1427,7 @@
 # to display verbose messages only when your user has specified
 # '--verbose'.
 #
-# After sourcing this file, you can plug in processing for additional
+# After sourcing this file, you can plug processing for additional
 # options by amending the variables from the 'Configuration' section
 # below, and following the instructions in the 'Option parsing'
 # section further down.
@@ -1594,8 +1476,8 @@
 ## ------------------------- ##
 
 # This section contains functions for adding, removing, and running hooks
-# in the main code.  A hook is just a list of function names that can be
-# run in order later on.
+# to the main code.  A hook is just a named list of of function, that can
+# be run in order later on.
 
 # func_hookable FUNC_NAME
 # -----------------------
@@ -1628,8 +1510,7 @@
 
 # func_remove_hook FUNC_NAME HOOK_FUNC
 # ------------------------------------
-# Remove HOOK_FUNC from the list of hook functions to be called by
-# FUNC_NAME.
+# Remove HOOK_FUNC from the list of functions called by FUNC_NAME.
 func_remove_hook ()
 {
     $debug_cmd
@@ -1638,28 +1519,10 @@
 }
 
 
-# func_propagate_result FUNC_NAME_A FUNC_NAME_B
-# ---------------------------------------------
-# If the *_result variable of FUNC_NAME_A _is set_, assign its value to
-# *_result variable of FUNC_NAME_B.
-func_propagate_result ()
-{
-    $debug_cmd
-
-    func_propagate_result_result=:
-    if eval "test \"\${${1}_result+set}\" = set"
-    then
-      eval "${2}_result=\$${1}_result"
-    else
-      func_propagate_result_result=false
-    fi
-}
-
-
 # func_run_hooks FUNC_NAME [ARG]...
 # ---------------------------------
 # Run all hook functions registered to FUNC_NAME.
-# It's assumed that the list of hook functions contains nothing more
+# It is assumed that the list of hook functions contains nothing more
 # than a whitespace-delimited list of legal shell function names, and
 # no effort is wasted trying to catch shell meta-characters or preserve
 # whitespace.
@@ -1667,21 +1530,26 @@
 {
     $debug_cmd
 
+    _G_rc_run_hooks=false
+
     case " $hookable_fns " in
       *" $1 "*) ;;
-      *) func_fatal_error "'$1' does not support hook functions." ;;
+      *) func_fatal_error "'$1' does not support hook funcions.n" ;;
     esac
 
     eval _G_hook_fns=\$$1_hooks; shift
 
     for _G_hook in $_G_hook_fns; do
-      func_unset "${_G_hook}_result"
-      eval $_G_hook '${1+"$@"}'
-      func_propagate_result $_G_hook func_run_hooks
-      if $func_propagate_result_result; then
-        eval set dummy "$func_run_hooks_result"; shift
+      if eval $_G_hook '"$@"'; then
+        # store returned options list back into positional
+        # parameters for next 'cmd' execution.
+        eval _G_hook_result=\$${_G_hook}_result
+        eval set dummy "$_G_hook_result"; shift
+        _G_rc_run_hooks=:
       fi
     done
+
+    $_G_rc_run_hooks && func_run_hooks_result=$_G_hook_result
 }
 
 
@@ -1691,16 +1559,14 @@
 ## --------------- ##
 
 # In order to add your own option parsing hooks, you must accept the
-# full positional parameter list from your hook function.  You may remove
-# or edit any options that you action, and then pass back the remaining
-# unprocessed options in '<hooked_function_name>_result', escaped
-# suitably for 'eval'.
-#
-# The '<hooked_function_name>_result' variable is automatically unset
-# before your hook gets called; for best performance, only set the
-# *_result variable when necessary (i.e. don't call the 'func_quote'
-# function unnecessarily because it can be an expensive operation on some
-# machines).
+# full positional parameter list in your hook function, you may remove/edit
+# any options that you action, and then pass back the remaining unprocessed
+# options in '<hooked_function_name>_result', escaped suitably for
+# 'eval'.  In this case you also must return $EXIT_SUCCESS to let the
+# hook's caller know that it should pay attention to
+# '<hooked_function_name>_result'.  Returning $EXIT_FAILURE signalizes that
+# arguments are left untouched by the hook and therefore caller will ignore the
+# result variable.
 #
 # Like this:
 #
@@ -1712,8 +1578,11 @@
 #        usage_message=$usage_message'
 #      -s, --silent       don'\''t print informational messages
 #    '
-#        # No change in '$@' (ignored completely by this hook).  Leave
-#        # my_options_prep_result variable intact.
+#        # No change in '$@' (ignored completely by this hook).  There is
+#        # no need to do the equivalent (but slower) action:
+#        # func_quote_for_eval ${1+"$@"}
+#        # my_options_prep_result=$func_quote_for_eval_result
+#        false
 #    }
 #    func_add_hook func_options_prep my_options_prep
 #
@@ -1724,7 +1593,7 @@
 #
 #        args_changed=false
 #
-#        # Note that, for efficiency, we parse as many options as we can
+#        # Note that for efficiency, we parse as many options as we can
 #        # recognise in a loop before passing the remainder back to the
 #        # caller on the first unrecognised argument we encounter.
 #        while test $# -gt 0; do
@@ -1741,17 +1610,18 @@
 #                         args_changed=:
 #                         ;;
 #            *)           # Make sure the first unrecognised option "$_G_opt"
-#                         # is added back to "$@" in case we need it later,
-#                         # if $args_changed was set to 'true'.
+#                         # is added back to "$@", we could need that later
+#                         # if $args_changed is true.
 #                         set dummy "$_G_opt" ${1+"$@"}; shift; break ;;
 #          esac
 #        done
 #
-#        # Only call 'func_quote' here if we processed at least one argument.
 #        if $args_changed; then
-#          func_quote eval ${1+"$@"}
-#          my_silent_option_result=$func_quote_result
+#          func_quote_for_eval ${1+"$@"}
+#          my_silent_option_result=$func_quote_for_eval_result
 #        fi
+#
+#        $args_changed
 #    }
 #    func_add_hook func_parse_options my_silent_option
 #
@@ -1762,6 +1632,8 @@
 #
 #        $opt_silent && $opt_verbose && func_fatal_help "\
 #    '--silent' and '--verbose' options are mutually exclusive."
+#
+#        false
 #    }
 #    func_add_hook func_validate_options my_option_validation
 #
@@ -1777,8 +1649,13 @@
 {
     $debug_cmd
 
-    func_run_hooks func_options ${1+"$@"}
-    func_propagate_result func_run_hooks func_options_finish
+    _G_func_options_finish_exit=false
+    if func_run_hooks func_options ${1+"$@"}; then
+      func_options_finish_result=$func_run_hooks_result
+      _G_func_options_finish_exit=:
+    fi
+
+    $_G_func_options_finish_exit
 }
 
 
@@ -1791,27 +1668,28 @@
 {
     $debug_cmd
 
-    _G_options_quoted=false
+    _G_rc_options=false
 
     for my_func in options_prep parse_options validate_options options_finish
     do
-      func_unset func_${my_func}_result
-      func_unset func_run_hooks_result
-      eval func_$my_func '${1+"$@"}'
-      func_propagate_result func_$my_func func_options
-      if $func_propagate_result_result; then
-        eval set dummy "$func_options_result"; shift
-        _G_options_quoted=:
+      if eval func_$my_func '${1+"$@"}'; then
+        eval _G_res_var='$'"func_${my_func}_result"
+        eval set dummy "$_G_res_var" ; shift
+        _G_rc_options=:
       fi
     done
 
-    $_G_options_quoted || {
-      # As we (func_options) are top-level options-parser function and
-      # nobody quoted "$@" for us yet, we need to do it explicitly for
-      # caller.
-      func_quote eval ${1+"$@"}
-      func_options_result=$func_quote_result
-    }
+    # Save modified positional parameters for caller.  As a top-level
+    # options-parser function we always need to set the 'func_options_result'
+    # variable (regardless the $_G_rc_options value).
+    if $_G_rc_options; then
+      func_options_result=$_G_res_var
+    else
+      func_quote_for_eval ${1+"$@"}
+      func_options_result=$func_quote_for_eval_result
+    fi
+
+    $_G_rc_options
 }
 
 
@@ -1821,7 +1699,8 @@
 # Note that when calling hook functions, we pass through the list of
 # positional parameters.  If a hook function modifies that list, and
 # needs to propagate that back to rest of this script, then the complete
-# modified list must be put in 'func_run_hooks_result' before returning.
+# modified list must be put in 'func_run_hooks_result' before
+# returning $EXIT_SUCCESS (otherwise $EXIT_FAILURE is returned).
 func_hookable func_options_prep
 func_options_prep ()
 {
@@ -1831,8 +1710,14 @@
     opt_verbose=false
     opt_warning_types=
 
-    func_run_hooks func_options_prep ${1+"$@"}
-    func_propagate_result func_run_hooks func_options_prep
+    _G_rc_options_prep=false
+    if func_run_hooks func_options_prep ${1+"$@"}; then
+      _G_rc_options_prep=:
+      # save modified positional parameters for caller
+      func_options_prep_result=$func_run_hooks_result
+    fi
+
+    $_G_rc_options_prep
 }
 
 
@@ -1844,32 +1729,27 @@
 {
     $debug_cmd
 
-    _G_parse_options_requote=false
+    func_parse_options_result=
+
+    _G_rc_parse_options=false
     # this just eases exit handling
     while test $# -gt 0; do
       # Defer to hook functions for initial option parsing, so they
       # get priority in the event of reusing an option name.
-      func_run_hooks func_parse_options ${1+"$@"}
-      func_propagate_result func_run_hooks func_parse_options
-      if $func_propagate_result_result; then
-        eval set dummy "$func_parse_options_result"; shift
-        # Even though we may have changed "$@", we passed the "$@" array
-        # down into the hook and it quoted it for us (because we are in
-        # this if-branch).  No need to quote it again.
-        _G_parse_options_requote=false
+      if func_run_hooks func_parse_options ${1+"$@"}; then
+        eval set dummy "$func_run_hooks_result"; shift
+        _G_rc_parse_options=:
       fi
 
       # Break out of the loop if we already parsed every option.
       test $# -gt 0 || break
 
-      # We expect that one of the options parsed in this function matches
-      # and thus we remove _G_opt from "$@" and need to re-quote.
       _G_match_parse_options=:
       _G_opt=$1
       shift
       case $_G_opt in
         --debug|-x)   debug_cmd='set -x'
-                      func_echo "enabling shell trace mode" >&2
+                      func_echo "enabling shell trace mode"
                       $debug_cmd
                       ;;
 
@@ -1880,7 +1760,7 @@
 
         --warnings|--warning|-W)
                       if test $# = 0 && func_missing_arg $_G_opt; then
-                        _G_parse_options_requote=:
+                        _G_rc_parse_options=:
                         break
                       fi
                       case " $warning_categories $1" in
@@ -1935,7 +1815,7 @@
                       shift
                       ;;
 
-        --)           _G_parse_options_requote=: ; break ;;
+        --)           _G_rc_parse_options=: ; break ;;
         -*)           func_fatal_help "unrecognised option: '$_G_opt'" ;;
         *)            set dummy "$_G_opt" ${1+"$@"}; shift
                       _G_match_parse_options=false
@@ -1943,16 +1823,17 @@
                       ;;
       esac
 
-      if $_G_match_parse_options; then
-        _G_parse_options_requote=:
-      fi
+      $_G_match_parse_options && _G_rc_parse_options=:
     done
 
-    if $_G_parse_options_requote; then
+
+    if $_G_rc_parse_options; then
       # save modified positional parameters for caller
-      func_quote eval ${1+"$@"}
-      func_parse_options_result=$func_quote_result
+      func_quote_for_eval ${1+"$@"}
+      func_parse_options_result=$func_quote_for_eval_result
     fi
+
+    $_G_rc_parse_options
 }
 
 
@@ -1965,14 +1846,21 @@
 {
     $debug_cmd
 
+    _G_rc_validate_options=false
+
     # Display all warnings if -W was not given.
     test -n "$opt_warning_types" || opt_warning_types=" $warning_categories"
 
-    func_run_hooks func_validate_options ${1+"$@"}
-    func_propagate_result func_run_hooks func_validate_options
+    if func_run_hooks func_validate_options ${1+"$@"}; then
+      # save modified positional parameters for caller
+      func_validate_options_result=$func_run_hooks_result
+      _G_rc_validate_options=:
+    fi
 
     # Bail if the options were screwed!
     $exit_cmd $EXIT_FAILURE
+
+    $_G_rc_validate_options
 }
 
 
@@ -2028,8 +1916,8 @@
 
 # func_split_equals STRING
 # ------------------------
-# Set func_split_equals_lhs and func_split_equals_rhs shell variables
-# after splitting STRING at the '=' sign.
+# Set func_split_equals_lhs and func_split_equals_rhs shell variables after
+# splitting STRING at the '=' sign.
 test -z "$_G_HAVE_XSI_OPS" \
     && (eval 'x=a/b/c;
       test 5aa/bb/cc = "${#x}${x%%/*}${x%/*}${x#*/}${x##*/}"') 2>/dev/null \
@@ -2044,9 +1932,8 @@
 
       func_split_equals_lhs=${1%%=*}
       func_split_equals_rhs=${1#*=}
-      if test "x$func_split_equals_lhs" = "x$1"; then
-        func_split_equals_rhs=
-      fi
+      test "x$func_split_equals_lhs" = "x$1" \
+        && func_split_equals_rhs=
   }'
 else
   # ...otherwise fall back to using expr, which is often a shell builtin.
@@ -2124,44 +2011,31 @@
 # func_version
 # ------------
 # Echo version message to standard output and exit.
-# The version message is extracted from the calling file's header
-# comments, with leading '# ' stripped:
-#   1. First display the progname and version
-#   2. Followed by the header comment line matching  /^# Written by /
-#   3. Then a blank line followed by the first following line matching
-#      /^# Copyright /
-#   4. Immediately followed by any lines between the previous matches,
-#      except lines preceding the intervening completely blank line.
-# For example, see the header comments of this file.
 func_version ()
 {
     $debug_cmd
 
     printf '%s\n' "$progname $scriptversion"
     $SED -n '
-        /^# Written by /!b
-        s|^# ||; p; n
-
-        :fwd2blnk
-        /./ {
-          n
-          b fwd2blnk
+        /(C)/!b go
+        :more
+        /\./!{
+          N
+          s|\n# | |
+          b more
         }
-        p; n
-
-        :holdwrnt
-        s|^# ||
-        s|^# *$||
-        /^Copyright /!{
-          /./H
-          n
-          b holdwrnt
+        :go
+        /^# Written by /,/# warranty; / {
+          s|^# ||
+          s|^# *$||
+          s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2|
+          p
         }
-
-        s|\((C)\)[ 0-9,-]*[ ,-]\([1-9][0-9]* \)|\1 \2|
-        G
-        s|\(\n\)\n*|\1|g
-        p; q' < "$progpath"
+        /^# Written by / {
+          s|^# ||
+          p
+        }
+        /^warranty; /q' < "$progpath"
 
     exit $?
 }
@@ -2171,12 +2045,12 @@
 # mode: shell-script
 # sh-indentation: 2
 # eval: (add-hook 'before-save-hook 'time-stamp)
-# time-stamp-pattern: "30/scriptversion=%:y-%02m-%02d.%02H; # UTC"
+# time-stamp-pattern: "10/scriptversion=%:y-%02m-%02d.%02H; # UTC"
 # time-stamp-time-zone: "UTC"
 # End:
 
 # Set a version string.
-scriptversion='(GNU libtool) 2.4.6.42-b88ce'
+scriptversion='(GNU libtool) 2.4.6'
 
 
 # func_echo ARG...
@@ -2267,7 +2141,7 @@
        compiler:       $LTCC
        compiler flags: $LTCFLAGS
        linker:         $LD (gnu? $with_gnu_ld)
-       version:        $progname (GNU libtool) 2.4.6.42-b88ce
+       version:        $progname $scriptversion Debian-2.4.6-15
        automake:       `($AUTOMAKE --version) 2>/dev/null |$SED 1q`
        autoconf:       `($AUTOCONF --version) 2>/dev/null |$SED 1q`
 
@@ -2323,7 +2197,7 @@
 # a configuration failure hint, and exit.
 func_fatal_configuration ()
 {
-    func_fatal_error ${1+"$@"} \
+    func__fatal_error ${1+"$@"} \
       "See the $PACKAGE documentation for more information." \
       "Fatal configuration error."
 }
@@ -2501,9 +2375,11 @@
 
     if $_G_rc_lt_options_prep; then
       # Pass back the list of options.
-      func_quote eval ${1+"$@"}
-      libtool_options_prep_result=$func_quote_result
+      func_quote_for_eval ${1+"$@"}
+      libtool_options_prep_result=$func_quote_for_eval_result
     fi
+
+    $_G_rc_lt_options_prep
 }
 func_add_hook func_options_prep libtool_options_prep
 
@@ -2606,9 +2482,11 @@
 
     if $_G_rc_lt_parse_options; then
       # save modified positional parameters for caller
-      func_quote eval ${1+"$@"}
-      libtool_parse_options_result=$func_quote_result
+      func_quote_for_eval ${1+"$@"}
+      libtool_parse_options_result=$func_quote_for_eval_result
     fi
+
+    $_G_rc_lt_parse_options
 }
 func_add_hook func_parse_options libtool_parse_options
 
@@ -2665,8 +2543,8 @@
     }
 
     # Pass back the unparsed argument list
-    func_quote eval ${1+"$@"}
-    libtool_validate_options_result=$func_quote_result
+    func_quote_for_eval ${1+"$@"}
+    libtool_validate_options_result=$func_quote_for_eval_result
 }
 func_add_hook func_validate_options libtool_validate_options
 
@@ -3632,8 +3510,8 @@
       esac
     done
 
-    func_quote_arg pretty "$libobj"
-    test "X$libobj" != "X$func_quote_arg_result" \
+    func_quote_for_eval "$libobj"
+    test "X$libobj" != "X$func_quote_for_eval_result" \
       && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"'	 &()|`$[]' \
       && func_warning "libobj name '$libobj' may not contain shell special characters."
     func_dirname_and_basename "$obj" "/" ""
@@ -3706,8 +3584,8 @@
 
     func_to_tool_file "$srcfile" func_convert_file_msys_to_w32
     srcfile=$func_to_tool_file_result
-    func_quote_arg pretty "$srcfile"
-    qsrcfile=$func_quote_arg_result
+    func_quote_for_eval "$srcfile"
+    qsrcfile=$func_quote_for_eval_result
 
     # Only build a PIC object if we are building libtool libraries.
     if test yes = "$build_libtool_libs"; then
@@ -4310,8 +4188,8 @@
        case $nonopt in *shtool*) :;; *) false;; esac
     then
       # Aesthetically quote it.
-      func_quote_arg pretty "$nonopt"
-      install_prog="$func_quote_arg_result "
+      func_quote_for_eval "$nonopt"
+      install_prog="$func_quote_for_eval_result "
       arg=$1
       shift
     else
@@ -4321,8 +4199,8 @@
 
     # The real first argument should be the name of the installation program.
     # Aesthetically quote it.
-    func_quote_arg pretty "$arg"
-    func_append install_prog "$func_quote_arg_result"
+    func_quote_for_eval "$arg"
+    func_append install_prog "$func_quote_for_eval_result"
     install_shared_prog=$install_prog
     case " $install_prog " in
       *[\\\ /]cp\ *) install_cp=: ;;
@@ -4379,12 +4257,12 @@
       esac
 
       # Aesthetically quote the argument.
-      func_quote_arg pretty "$arg"
-      func_append install_prog " $func_quote_arg_result"
+      func_quote_for_eval "$arg"
+      func_append install_prog " $func_quote_for_eval_result"
       if test -n "$arg2"; then
-	func_quote_arg pretty "$arg2"
+	func_quote_for_eval "$arg2"
       fi
-      func_append install_shared_prog " $func_quote_arg_result"
+      func_append install_shared_prog " $func_quote_for_eval_result"
     done
 
     test -z "$install_prog" && \
@@ -4395,8 +4273,8 @@
 
     if test -n "$install_override_mode" && $no_mode; then
       if $install_cp; then :; else
-	func_quote_arg pretty "$install_override_mode"
-	func_append install_shared_prog " -m $func_quote_arg_result"
+	func_quote_for_eval "$install_override_mode"
+	func_append install_shared_prog " -m $func_quote_for_eval_result"
       fi
     fi
 
@@ -4692,8 +4570,8 @@
 	        relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
 
 	        $opt_quiet || {
-	          func_quote_arg expand,pretty "$relink_command"
-		  eval "func_echo $func_quote_arg_result"
+	          func_quote_for_expand "$relink_command"
+		  eval "func_echo $func_quote_for_expand_result"
 	        }
 	        if eval "$relink_command"; then :
 	          else
@@ -5472,8 +5350,7 @@
   if test \"\$libtool_execute_magic\" != \"$magic\"; then
     file=\"\$0\""
 
-    func_quote_arg pretty "$ECHO"
-    qECHO=$func_quote_arg_result
+    qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
     $ECHO "\
 
 # A function that is used when there is no print builtin or printf.
@@ -5483,7 +5360,7 @@
 \$1
 _LTECHO_EOF'
 }
-    ECHO=$qECHO
+    ECHO=\"$qECHO\"
   fi
 
 # Very basic option parsing. These options are (a) specific to
@@ -6826,9 +6703,9 @@
     while test "$#" -gt 0; do
       arg=$1
       shift
-      func_quote_arg pretty,unquoted "$arg"
-      qarg=$func_quote_arg_unquoted_result
-      func_append libtool_args " $func_quote_arg_result"
+      func_quote_for_eval "$arg"
+      qarg=$func_quote_for_eval_unquoted_result
+      func_append libtool_args " $func_quote_for_eval_result"
 
       # If the previous option needs an argument, assign it.
       if test -n "$prev"; then
@@ -7426,9 +7303,9 @@
 	save_ifs=$IFS; IFS=,
 	for flag in $args; do
 	  IFS=$save_ifs
-          func_quote_arg pretty "$flag"
-	  func_append arg " $func_quote_arg_result"
-	  func_append compiler_flags " $func_quote_arg_result"
+          func_quote_for_eval "$flag"
+	  func_append arg " $func_quote_for_eval_result"
+	  func_append compiler_flags " $func_quote_for_eval_result"
 	done
 	IFS=$save_ifs
 	func_stripname ' ' '' "$arg"
@@ -7442,10 +7319,10 @@
 	save_ifs=$IFS; IFS=,
 	for flag in $args; do
 	  IFS=$save_ifs
-          func_quote_arg pretty "$flag"
-	  func_append arg " $wl$func_quote_arg_result"
-	  func_append compiler_flags " $wl$func_quote_arg_result"
-	  func_append linker_flags " $func_quote_arg_result"
+          func_quote_for_eval "$flag"
+	  func_append arg " $wl$func_quote_for_eval_result"
+	  func_append compiler_flags " $wl$func_quote_for_eval_result"
+	  func_append linker_flags " $func_quote_for_eval_result"
 	done
 	IFS=$save_ifs
 	func_stripname ' ' '' "$arg"
@@ -7469,8 +7346,8 @@
 
       # -msg_* for osf cc
       -msg_*)
-	func_quote_arg pretty "$arg"
-	arg=$func_quote_arg_result
+	func_quote_for_eval "$arg"
+	arg=$func_quote_for_eval_result
 	;;
 
       # Flags to be passed through unchanged, with rationale:
@@ -7491,12 +7368,14 @@
       # -stdlib=*            select c++ std lib with clang
       # -fsanitize=*         Clang/GCC memory and address sanitizer
       # -fuse-ld=*           Linker select flags for GCC
+      # -static-*            direct GCC to link specific libraries statically
+      # -fcilkplus           Cilk Plus language extension features for C/C++
       -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
       -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
       -O*|-g*|-flto*|-fwhopr*|-fuse-linker-plugin|-fstack-protector*|-stdlib=*| \
-      -specs=*|-fsanitize=*|-fuse-ld=*)
-        func_quote_arg pretty "$arg"
-	arg=$func_quote_arg_result
+      -specs=*|-fsanitize=*|-fuse-ld=*|-static-*|-fcilkplus)
+        func_quote_for_eval "$arg"
+	arg=$func_quote_for_eval_result
         func_append compile_command " $arg"
         func_append finalize_command " $arg"
         func_append compiler_flags " $arg"
@@ -7517,15 +7396,15 @@
 	  continue
         else
 	  # Otherwise treat like 'Some other compiler flag' below
-	  func_quote_arg pretty "$arg"
-	  arg=$func_quote_arg_result
+	  func_quote_for_eval "$arg"
+	  arg=$func_quote_for_eval_result
         fi
 	;;
 
       # Some other compiler flag.
       -* | +*)
-        func_quote_arg pretty "$arg"
-	arg=$func_quote_arg_result
+        func_quote_for_eval "$arg"
+	arg=$func_quote_for_eval_result
 	;;
 
       *.$objext)
@@ -7645,8 +7524,8 @@
       *)
 	# Unknown arguments in both finalize_command and compile_command need
 	# to be aesthetically quoted because they are evaled later.
-	func_quote_arg pretty "$arg"
-	arg=$func_quote_arg_result
+	func_quote_for_eval "$arg"
+	arg=$func_quote_for_eval_result
 	;;
       esac # arg
 
@@ -7787,7 +7666,10 @@
 	case $pass in
 	dlopen) libs=$dlfiles ;;
 	dlpreopen) libs=$dlprefiles ;;
-	link) libs="$deplibs %DEPLIBS% $dependency_libs" ;;
+	link)
+	  libs="$deplibs %DEPLIBS%"
+	  test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
+	  ;;
 	esac
       fi
       if test lib,dlpreopen = "$linkmode,$pass"; then
@@ -8106,19 +7988,19 @@
 	    # It is a libtool convenience library, so add in its objects.
 	    func_append convenience " $ladir/$objdir/$old_library"
 	    func_append old_convenience " $ladir/$objdir/$old_library"
+	    tmp_libs=
+	    for deplib in $dependency_libs; do
+	      deplibs="$deplib $deplibs"
+	      if $opt_preserve_dup_deps; then
+		case "$tmp_libs " in
+		*" $deplib "*) func_append specialdeplibs " $deplib" ;;
+		esac
+	      fi
+	      func_append tmp_libs " $deplib"
+	    done
 	  elif test prog != "$linkmode" && test lib != "$linkmode"; then
 	    func_fatal_error "'$lib' is not a convenience library"
 	  fi
-	  tmp_libs=
-	  for deplib in $dependency_libs; do
-	    deplibs="$deplib $deplibs"
-	    if $opt_preserve_dup_deps; then
-	      case "$tmp_libs " in
-	      *" $deplib "*) func_append specialdeplibs " $deplib" ;;
-	      esac
-	    fi
-	    func_append tmp_libs " $deplib"
-	  done
 	  continue
 	fi # $pass = conv
 
@@ -9042,6 +8924,9 @@
 	    revision=$number_minor
 	    lt_irix_increment=no
 	    ;;
+	  *)
+	    func_fatal_configuration "$modename: unknown library version type '$version_type'"
+	    ;;
 	  esac
 	  ;;
 	no)
@@ -10152,8 +10037,8 @@
 	    for cmd in $concat_cmds; do
 	      IFS=$save_ifs
 	      $opt_quiet || {
-		  func_quote_arg expand,pretty "$cmd"
-		  eval "func_echo $func_quote_arg_result"
+		  func_quote_for_expand "$cmd"
+		  eval "func_echo $func_quote_for_expand_result"
 	      }
 	      $opt_dry_run || eval "$cmd" || {
 		lt_exit=$?
@@ -10246,8 +10131,8 @@
 	  eval cmd=\"$cmd\"
 	  IFS=$save_ifs
 	  $opt_quiet || {
-	    func_quote_arg expand,pretty "$cmd"
-	    eval "func_echo $func_quote_arg_result"
+	    func_quote_for_expand "$cmd"
+	    eval "func_echo $func_quote_for_expand_result"
 	  }
 	  $opt_dry_run || eval "$cmd" || {
 	    lt_exit=$?
@@ -10721,13 +10606,12 @@
 	  elif eval var_value=\$$var; test -z "$var_value"; then
 	    relink_command="$var=; export $var; $relink_command"
 	  else
-	    func_quote_arg pretty "$var_value"
-	    relink_command="$var=$func_quote_arg_result; export $var; $relink_command"
+	    func_quote_for_eval "$var_value"
+	    relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
 	  fi
 	done
-	func_quote eval cd "`pwd`"
-	func_quote_arg pretty,unquoted "($func_quote_result; $relink_command)"
-	relink_command=$func_quote_arg_unquoted_result
+	relink_command="(cd `pwd`; $relink_command)"
+	relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
       fi
 
       # Only actually do things if not in dry run mode.
@@ -10967,15 +10851,13 @@
 	elif eval var_value=\$$var; test -z "$var_value"; then
 	  relink_command="$var=; export $var; $relink_command"
 	else
-	  func_quote_arg pretty,unquoted "$var_value"
-	  relink_command="$var=$func_quote_arg_unquoted_result; export $var; $relink_command"
+	  func_quote_for_eval "$var_value"
+	  relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
 	fi
       done
       # Quote the link command for shipping.
-      func_quote eval cd "`pwd`"
-      relink_command="($func_quote_result; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
-      func_quote_arg pretty,unquoted "$relink_command"
-      relink_command=$func_quote_arg_unquoted_result
+      relink_command="(cd `pwd`; $SHELL \"$progpath\" $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+      relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
       if test yes = "$hardcode_automatic"; then
 	relink_command=
       fi
diff -Nru libp11-0.4.11/m4/ax_pthread.m4 libp11-0.4.12/m4/ax_pthread.m4
--- libp11-0.4.11/m4/ax_pthread.m4	1970-01-01 01:00:00.000000000 +0100
+++ libp11-0.4.12/m4/ax_pthread.m4	2021-10-30 14:20:08.000000000 +0200
@@ -0,0 +1,522 @@
+# ===========================================================================
+#        https://www.gnu.org/software/autoconf-archive/ax_pthread.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+#   AX_PTHREAD([ACTION-IF-FOUND[, ACTION-IF-NOT-FOUND]])
+#
+# DESCRIPTION
+#
+#   This macro figures out how to build C programs using POSIX threads. It
+#   sets the PTHREAD_LIBS output variable to the threads library and linker
+#   flags, and the PTHREAD_CFLAGS output variable to any special C compiler
+#   flags that are needed. (The user can also force certain compiler
+#   flags/libs to be tested by setting these environment variables.)
+#
+#   Also sets PTHREAD_CC and PTHREAD_CXX to any special C compiler that is
+#   needed for multi-threaded programs (defaults to the value of CC
+#   respectively CXX otherwise). (This is necessary on e.g. AIX to use the
+#   special cc_r/CC_r compiler alias.)
+#
+#   NOTE: You are assumed to not only compile your program with these flags,
+#   but also to link with them as well. For example, you might link with
+#   $PTHREAD_CC $CFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
+#   $PTHREAD_CXX $CXXFLAGS $PTHREAD_CFLAGS $LDFLAGS ... $PTHREAD_LIBS $LIBS
+#
+#   If you are only building threaded programs, you may wish to use these
+#   variables in your default LIBS, CFLAGS, and CC:
+#
+#     LIBS="$PTHREAD_LIBS $LIBS"
+#     CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+#     CXXFLAGS="$CXXFLAGS $PTHREAD_CFLAGS"
+#     CC="$PTHREAD_CC"
+#     CXX="$PTHREAD_CXX"
+#
+#   In addition, if the PTHREAD_CREATE_JOINABLE thread-attribute constant
+#   has a nonstandard name, this macro defines PTHREAD_CREATE_JOINABLE to
+#   that name (e.g. PTHREAD_CREATE_UNDETACHED on AIX).
+#
+#   Also HAVE_PTHREAD_PRIO_INHERIT is defined if pthread is found and the
+#   PTHREAD_PRIO_INHERIT symbol is defined when compiling with
+#   PTHREAD_CFLAGS.
+#
+#   ACTION-IF-FOUND is a list of shell commands to run if a threads library
+#   is found, and ACTION-IF-NOT-FOUND is a list of commands to run it if it
+#   is not found. If ACTION-IF-FOUND is not specified, the default action
+#   will define HAVE_PTHREAD.
+#
+#   Please let the authors know if this macro fails on any platform, or if
+#   you have any other suggestions or comments. This macro was based on work
+#   by SGJ on autoconf scripts for FFTW (http://www.fftw.org/) (with help
+#   from M. Frigo), as well as ac_pthread and hb_pthread macros posted by
+#   Alejandro Forero Cuervo to the autoconf macro repository. We are also
+#   grateful for the helpful feedback of numerous users.
+#
+#   Updated for Autoconf 2.68 by Daniel Richard G.
+#
+# LICENSE
+#
+#   Copyright (c) 2008 Steven G. Johnson <stevenj at alum.mit.edu>
+#   Copyright (c) 2011 Daniel Richard G. <skunk at iSKUNK.ORG>
+#   Copyright (c) 2019 Marc Stevens <marc.stevens at cwi.nl>
+#
+#   This program is free software: you can redistribute it and/or modify it
+#   under the terms of the GNU General Public License as published by the
+#   Free Software Foundation, either version 3 of the License, or (at your
+#   option) any later version.
+#
+#   This program is distributed in the hope that it will be useful, but
+#   WITHOUT ANY WARRANTY; without even the implied warranty of
+#   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+#   Public License for more details.
+#
+#   You should have received a copy of the GNU General Public License along
+#   with this program. If not, see <https://www.gnu.org/licenses/>.
+#
+#   As a special exception, the respective Autoconf Macro's copyright owner
+#   gives unlimited permission to copy, distribute and modify the configure
+#   scripts that are the output of Autoconf when processing the Macro. You
+#   need not follow the terms of the GNU General Public License when using
+#   or distributing such scripts, even though portions of the text of the
+#   Macro appear in them. The GNU General Public License (GPL) does govern
+#   all other use of the material that constitutes the Autoconf Macro.
+#
+#   This special exception to the GPL applies to versions of the Autoconf
+#   Macro released by the Autoconf Archive. When you make and distribute a
+#   modified version of the Autoconf Macro, you may extend this special
+#   exception to the GPL to apply to your modified version as well.
+
+#serial 30
+
+AU_ALIAS([ACX_PTHREAD], [AX_PTHREAD])
+AC_DEFUN([AX_PTHREAD], [
+AC_REQUIRE([AC_CANONICAL_TARGET])
+AC_REQUIRE([AC_PROG_CC])
+AC_REQUIRE([AC_PROG_SED])
+AC_LANG_PUSH([C])
+ax_pthread_ok=no
+
+# We used to check for pthread.h first, but this fails if pthread.h
+# requires special compiler flags (e.g. on Tru64 or Sequent).
+# It gets checked for in the link test anyway.
+
+# First of all, check if the user has set any of the PTHREAD_LIBS,
+# etcetera environment variables, and if threads linking works using
+# them:
+if test "x$PTHREAD_CFLAGS$PTHREAD_LIBS" != "x"; then
+        ax_pthread_save_CC="$CC"
+        ax_pthread_save_CFLAGS="$CFLAGS"
+        ax_pthread_save_LIBS="$LIBS"
+        AS_IF([test "x$PTHREAD_CC" != "x"], [CC="$PTHREAD_CC"])
+        AS_IF([test "x$PTHREAD_CXX" != "x"], [CXX="$PTHREAD_CXX"])
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+        AC_MSG_CHECKING([for pthread_join using $CC $PTHREAD_CFLAGS $PTHREAD_LIBS])
+        AC_LINK_IFELSE([AC_LANG_CALL([], [pthread_join])], [ax_pthread_ok=yes])
+        AC_MSG_RESULT([$ax_pthread_ok])
+        if test "x$ax_pthread_ok" = "xno"; then
+                PTHREAD_LIBS=""
+                PTHREAD_CFLAGS=""
+        fi
+        CC="$ax_pthread_save_CC"
+        CFLAGS="$ax_pthread_save_CFLAGS"
+        LIBS="$ax_pthread_save_LIBS"
+fi
+
+# We must check for the threads library under a number of different
+# names; the ordering is very important because some systems
+# (e.g. DEC) have both -lpthread and -lpthreads, where one of the
+# libraries is broken (non-POSIX).
+
+# Create a list of thread flags to try. Items with a "," contain both
+# C compiler flags (before ",") and linker flags (after ","). Other items
+# starting with a "-" are C compiler flags, and remaining items are
+# library names, except for "none" which indicates that we try without
+# any flags at all, and "pthread-config" which is a program returning
+# the flags for the Pth emulation library.
+
+ax_pthread_flags="pthreads none -Kthread -pthread -pthreads -mthreads pthread --thread-safe -mt pthread-config"
+
+# The ordering *is* (sometimes) important.  Some notes on the
+# individual items follow:
+
+# pthreads: AIX (must check this before -lpthread)
+# none: in case threads are in libc; should be tried before -Kthread and
+#       other compiler flags to prevent continual compiler warnings
+# -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+# -pthread: Linux/gcc (kernel threads), BSD/gcc (userland threads), Tru64
+#           (Note: HP C rejects this with "bad form for `-t' option")
+# -pthreads: Solaris/gcc (Note: HP C also rejects)
+# -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+#      doesn't hurt to check since this sometimes defines pthreads and
+#      -D_REENTRANT too), HP C (must be checked before -lpthread, which
+#      is present but should not be used directly; and before -mthreads,
+#      because the compiler interprets this as "-mt" + "-hreads")
+# -mthreads: Mingw32/gcc, Lynx/gcc
+# pthread: Linux, etcetera
+# --thread-safe: KAI C++
+# pthread-config: use pthread-config program (for GNU Pth library)
+
+case $target_os in
+
+        freebsd*)
+
+        # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+        # lthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+
+        ax_pthread_flags="-kthread lthread $ax_pthread_flags"
+        ;;
+
+        hpux*)
+
+        # From the cc(1) man page: "[-mt] Sets various -D flags to enable
+        # multi-threading and also sets -lpthread."
+
+        ax_pthread_flags="-mt -pthread pthread $ax_pthread_flags"
+        ;;
+
+        openedition*)
+
+        # IBM z/OS requires a feature-test macro to be defined in order to
+        # enable POSIX threads at all, so give the user a hint if this is
+        # not set. (We don't define these ourselves, as they can affect
+        # other portions of the system API in unpredictable ways.)
+
+        AC_EGREP_CPP([AX_PTHREAD_ZOS_MISSING],
+            [
+#            if !defined(_OPEN_THREADS) && !defined(_UNIX03_THREADS)
+             AX_PTHREAD_ZOS_MISSING
+#            endif
+            ],
+            [AC_MSG_WARN([IBM z/OS requires -D_OPEN_THREADS or -D_UNIX03_THREADS to enable pthreads support.])])
+        ;;
+
+        solaris*)
+
+        # On Solaris (at least, for some versions), libc contains stubbed
+        # (non-functional) versions of the pthreads routines, so link-based
+        # tests will erroneously succeed. (N.B.: The stubs are missing
+        # pthread_cleanup_push, or rather a function called by this macro,
+        # so we could check for that, but who knows whether they'll stub
+        # that too in a future libc.)  So we'll check first for the
+        # standard Solaris way of linking pthreads (-mt -lpthread).
+
+        ax_pthread_flags="-mt,-lpthread pthread $ax_pthread_flags"
+        ;;
+esac
+
+# Are we compiling with Clang?
+
+AC_CACHE_CHECK([whether $CC is Clang],
+    [ax_cv_PTHREAD_CLANG],
+    [ax_cv_PTHREAD_CLANG=no
+     # Note that Autoconf sets GCC=yes for Clang as well as GCC
+     if test "x$GCC" = "xyes"; then
+        AC_EGREP_CPP([AX_PTHREAD_CC_IS_CLANG],
+            [/* Note: Clang 2.7 lacks __clang_[a-z]+__ */
+#            if defined(__clang__) && defined(__llvm__)
+             AX_PTHREAD_CC_IS_CLANG
+#            endif
+            ],
+            [ax_cv_PTHREAD_CLANG=yes])
+     fi
+    ])
+ax_pthread_clang="$ax_cv_PTHREAD_CLANG"
+
+
+# GCC generally uses -pthread, or -pthreads on some platforms (e.g. SPARC)
+
+# Note that for GCC and Clang -pthread generally implies -lpthread,
+# except when -nostdlib is passed.
+# This is problematic using libtool to build C++ shared libraries with pthread:
+# [1] https://gcc.gnu.org/bugzilla/show_bug.cgi?id=25460
+# [2] https://bugzilla.redhat.com/show_bug.cgi?id=661333
+# [3] https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=468555
+# To solve this, first try -pthread together with -lpthread for GCC
+
+AS_IF([test "x$GCC" = "xyes"],
+      [ax_pthread_flags="-pthread,-lpthread -pthread -pthreads $ax_pthread_flags"])
+
+# Clang takes -pthread (never supported any other flag), but we'll try with -lpthread first
+
+AS_IF([test "x$ax_pthread_clang" = "xyes"],
+      [ax_pthread_flags="-pthread,-lpthread -pthread"])
+
+
+# The presence of a feature test macro requesting re-entrant function
+# definitions is, on some systems, a strong hint that pthreads support is
+# correctly enabled
+
+case $target_os in
+        darwin* | hpux* | linux* | osf* | solaris*)
+        ax_pthread_check_macro="_REENTRANT"
+        ;;
+
+        aix*)
+        ax_pthread_check_macro="_THREAD_SAFE"
+        ;;
+
+        *)
+        ax_pthread_check_macro="--"
+        ;;
+esac
+AS_IF([test "x$ax_pthread_check_macro" = "x--"],
+      [ax_pthread_check_cond=0],
+      [ax_pthread_check_cond="!defined($ax_pthread_check_macro)"])
+
+
+if test "x$ax_pthread_ok" = "xno"; then
+for ax_pthread_try_flag in $ax_pthread_flags; do
+
+        case $ax_pthread_try_flag in
+                none)
+                AC_MSG_CHECKING([whether pthreads work without any flags])
+                ;;
+
+                *,*)
+                PTHREAD_CFLAGS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\1/"`
+                PTHREAD_LIBS=`echo $ax_pthread_try_flag | sed "s/^\(.*\),\(.*\)$/\2/"`
+                AC_MSG_CHECKING([whether pthreads work with "$PTHREAD_CFLAGS" and "$PTHREAD_LIBS"])
+                ;;
+
+                -*)
+                AC_MSG_CHECKING([whether pthreads work with $ax_pthread_try_flag])
+                PTHREAD_CFLAGS="$ax_pthread_try_flag"
+                ;;
+
+                pthread-config)
+                AC_CHECK_PROG([ax_pthread_config], [pthread-config], [yes], [no])
+                AS_IF([test "x$ax_pthread_config" = "xno"], [continue])
+                PTHREAD_CFLAGS="`pthread-config --cflags`"
+                PTHREAD_LIBS="`pthread-config --ldflags` `pthread-config --libs`"
+                ;;
+
+                *)
+                AC_MSG_CHECKING([for the pthreads library -l$ax_pthread_try_flag])
+                PTHREAD_LIBS="-l$ax_pthread_try_flag"
+                ;;
+        esac
+
+        ax_pthread_save_CFLAGS="$CFLAGS"
+        ax_pthread_save_LIBS="$LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+
+        # Check for various functions.  We must include pthread.h,
+        # since some functions may be macros.  (On the Sequent, we
+        # need a special flag -Kthread to make this header compile.)
+        # We check for pthread_join because it is in -lpthread on IRIX
+        # while pthread_create is in libc.  We check for pthread_attr_init
+        # due to DEC craziness with -lpthreads.  We check for
+        # pthread_cleanup_push because it is one of the few pthread
+        # functions on Solaris that doesn't have a non-functional libc stub.
+        # We try pthread_create on general principles.
+
+        AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>
+#                       if $ax_pthread_check_cond
+#                        error "$ax_pthread_check_macro must be defined"
+#                       endif
+                        static void *some_global = NULL;
+                        static void routine(void *a)
+                          {
+                             /* To avoid any unused-parameter or
+                                unused-but-set-parameter warning.  */
+                             some_global = a;
+                          }
+                        static void *start_routine(void *a) { return a; }],
+                       [pthread_t th; pthread_attr_t attr;
+                        pthread_create(&th, 0, start_routine, 0);
+                        pthread_join(th, 0);
+                        pthread_attr_init(&attr);
+                        pthread_cleanup_push(routine, 0);
+                        pthread_cleanup_pop(0) /* ; */])],
+            [ax_pthread_ok=yes],
+            [])
+
+        CFLAGS="$ax_pthread_save_CFLAGS"
+        LIBS="$ax_pthread_save_LIBS"
+
+        AC_MSG_RESULT([$ax_pthread_ok])
+        AS_IF([test "x$ax_pthread_ok" = "xyes"], [break])
+
+        PTHREAD_LIBS=""
+        PTHREAD_CFLAGS=""
+done
+fi
+
+
+# Clang needs special handling, because older versions handle the -pthread
+# option in a rather... idiosyncratic way
+
+if test "x$ax_pthread_clang" = "xyes"; then
+
+        # Clang takes -pthread; it has never supported any other flag
+
+        # (Note 1: This will need to be revisited if a system that Clang
+        # supports has POSIX threads in a separate library.  This tends not
+        # to be the way of modern systems, but it's conceivable.)
+
+        # (Note 2: On some systems, notably Darwin, -pthread is not needed
+        # to get POSIX threads support; the API is always present and
+        # active.  We could reasonably leave PTHREAD_CFLAGS empty.  But
+        # -pthread does define _REENTRANT, and while the Darwin headers
+        # ignore this macro, third-party headers might not.)
+
+        # However, older versions of Clang make a point of warning the user
+        # that, in an invocation where only linking and no compilation is
+        # taking place, the -pthread option has no effect ("argument unused
+        # during compilation").  They expect -pthread to be passed in only
+        # when source code is being compiled.
+        #
+        # Problem is, this is at odds with the way Automake and most other
+        # C build frameworks function, which is that the same flags used in
+        # compilation (CFLAGS) are also used in linking.  Many systems
+        # supported by AX_PTHREAD require exactly this for POSIX threads
+        # support, and in fact it is often not straightforward to specify a
+        # flag that is used only in the compilation phase and not in
+        # linking.  Such a scenario is extremely rare in practice.
+        #
+        # Even though use of the -pthread flag in linking would only print
+        # a warning, this can be a nuisance for well-run software projects
+        # that build with -Werror.  So if the active version of Clang has
+        # this misfeature, we search for an option to squash it.
+
+        AC_CACHE_CHECK([whether Clang needs flag to prevent "argument unused" warning when linking with -pthread],
+            [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG],
+            [ax_cv_PTHREAD_CLANG_NO_WARN_FLAG=unknown
+             # Create an alternate version of $ac_link that compiles and
+             # links in two steps (.c -> .o, .o -> exe) instead of one
+             # (.c -> exe), because the warning occurs only in the second
+             # step
+             ax_pthread_save_ac_link="$ac_link"
+             ax_pthread_sed='s/conftest\.\$ac_ext/conftest.$ac_objext/g'
+             ax_pthread_link_step=`AS_ECHO(["$ac_link"]) | sed "$ax_pthread_sed"`
+             ax_pthread_2step_ac_link="($ac_compile) && (echo ==== >&5) && ($ax_pthread_link_step)"
+             ax_pthread_save_CFLAGS="$CFLAGS"
+             for ax_pthread_try in '' -Qunused-arguments -Wno-unused-command-line-argument unknown; do
+                AS_IF([test "x$ax_pthread_try" = "xunknown"], [break])
+                CFLAGS="-Werror -Wunknown-warning-option $ax_pthread_try -pthread $ax_pthread_save_CFLAGS"
+                ac_link="$ax_pthread_save_ac_link"
+                AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
+                    [ac_link="$ax_pthread_2step_ac_link"
+                     AC_LINK_IFELSE([AC_LANG_SOURCE([[int main(void){return 0;}]])],
+                         [break])
+                    ])
+             done
+             ac_link="$ax_pthread_save_ac_link"
+             CFLAGS="$ax_pthread_save_CFLAGS"
+             AS_IF([test "x$ax_pthread_try" = "x"], [ax_pthread_try=no])
+             ax_cv_PTHREAD_CLANG_NO_WARN_FLAG="$ax_pthread_try"
+            ])
+
+        case "$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG" in
+                no | unknown) ;;
+                *) PTHREAD_CFLAGS="$ax_cv_PTHREAD_CLANG_NO_WARN_FLAG $PTHREAD_CFLAGS" ;;
+        esac
+
+fi # $ax_pthread_clang = yes
+
+
+
+# Various other checks:
+if test "x$ax_pthread_ok" = "xyes"; then
+        ax_pthread_save_CFLAGS="$CFLAGS"
+        ax_pthread_save_LIBS="$LIBS"
+        CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
+        LIBS="$PTHREAD_LIBS $LIBS"
+
+        # Detect AIX lossage: JOINABLE attribute is called UNDETACHED.
+        AC_CACHE_CHECK([for joinable pthread attribute],
+            [ax_cv_PTHREAD_JOINABLE_ATTR],
+            [ax_cv_PTHREAD_JOINABLE_ATTR=unknown
+             for ax_pthread_attr in PTHREAD_CREATE_JOINABLE PTHREAD_CREATE_UNDETACHED; do
+                 AC_LINK_IFELSE([AC_LANG_PROGRAM([#include <pthread.h>],
+                                                 [int attr = $ax_pthread_attr; return attr /* ; */])],
+                                [ax_cv_PTHREAD_JOINABLE_ATTR=$ax_pthread_attr; break],
+                                [])
+             done
+            ])
+        AS_IF([test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xunknown" && \
+               test "x$ax_cv_PTHREAD_JOINABLE_ATTR" != "xPTHREAD_CREATE_JOINABLE" && \
+               test "x$ax_pthread_joinable_attr_defined" != "xyes"],
+              [AC_DEFINE_UNQUOTED([PTHREAD_CREATE_JOINABLE],
+                                  [$ax_cv_PTHREAD_JOINABLE_ATTR],
+                                  [Define to necessary symbol if this constant
+                                   uses a non-standard name on your system.])
+               ax_pthread_joinable_attr_defined=yes
+              ])
+
+        AC_CACHE_CHECK([whether more special flags are required for pthreads],
+            [ax_cv_PTHREAD_SPECIAL_FLAGS],
+            [ax_cv_PTHREAD_SPECIAL_FLAGS=no
+             case $target_os in
+             solaris*)
+             ax_cv_PTHREAD_SPECIAL_FLAGS="-D_POSIX_PTHREAD_SEMANTICS"
+             ;;
+             esac
+            ])
+        AS_IF([test "x$ax_cv_PTHREAD_SPECIAL_FLAGS" != "xno" && \
+               test "x$ax_pthread_special_flags_added" != "xyes"],
+              [PTHREAD_CFLAGS="$ax_cv_PTHREAD_SPECIAL_FLAGS $PTHREAD_CFLAGS"
+               ax_pthread_special_flags_added=yes])
+
+        AC_CACHE_CHECK([for PTHREAD_PRIO_INHERIT],
+            [ax_cv_PTHREAD_PRIO_INHERIT],
+            [AC_LINK_IFELSE([AC_LANG_PROGRAM([[#include <pthread.h>]],
+                                             [[int i = PTHREAD_PRIO_INHERIT;
+                                               return i;]])],
+                            [ax_cv_PTHREAD_PRIO_INHERIT=yes],
+                            [ax_cv_PTHREAD_PRIO_INHERIT=no])
+            ])
+        AS_IF([test "x$ax_cv_PTHREAD_PRIO_INHERIT" = "xyes" && \
+               test "x$ax_pthread_prio_inherit_defined" != "xyes"],
+              [AC_DEFINE([HAVE_PTHREAD_PRIO_INHERIT], [1], [Have PTHREAD_PRIO_INHERIT.])
+               ax_pthread_prio_inherit_defined=yes
+              ])
+
+        CFLAGS="$ax_pthread_save_CFLAGS"
+        LIBS="$ax_pthread_save_LIBS"
+
+        # More AIX lossage: compile with *_r variant
+        if test "x$GCC" != "xyes"; then
+            case $target_os in
+                aix*)
+                AS_CASE(["x/$CC"],
+                    [x*/c89|x*/c89_128|x*/c99|x*/c99_128|x*/cc|x*/cc128|x*/xlc|x*/xlc_v6|x*/xlc128|x*/xlc128_v6],
+                    [#handle absolute path differently from PATH based program lookup
+                     AS_CASE(["x$CC"],
+                         [x/*],
+                         [
+			   AS_IF([AS_EXECUTABLE_P([${CC}_r])],[PTHREAD_CC="${CC}_r"])
+			   AS_IF([test "x${CXX}" != "x"], [AS_IF([AS_EXECUTABLE_P([${CXX}_r])],[PTHREAD_CXX="${CXX}_r"])])
+			 ],
+                         [
+			   AC_CHECK_PROGS([PTHREAD_CC],[${CC}_r],[$CC])
+			   AS_IF([test "x${CXX}" != "x"], [AC_CHECK_PROGS([PTHREAD_CXX],[${CXX}_r],[$CXX])])
+			 ]
+                     )
+                    ])
+                ;;
+            esac
+        fi
+fi
+
+test -n "$PTHREAD_CC" || PTHREAD_CC="$CC"
+test -n "$PTHREAD_CXX" || PTHREAD_CXX="$CXX"
+
+AC_SUBST([PTHREAD_LIBS])
+AC_SUBST([PTHREAD_CFLAGS])
+AC_SUBST([PTHREAD_CC])
+AC_SUBST([PTHREAD_CXX])
+
+# Finally, execute ACTION-IF-FOUND/ACTION-IF-NOT-FOUND:
+if test "x$ax_pthread_ok" = "xyes"; then
+        ifelse([$1],,[AC_DEFINE([HAVE_PTHREAD],[1],[Define if you have POSIX threads libraries and header files.])],[$1])
+        :
+else
+        ax_pthread_ok=no
+        $2
+fi
+AC_LANG_POP
+])dnl AX_PTHREAD
diff -Nru libp11-0.4.11/m4/libtool.m4 libp11-0.4.12/m4/libtool.m4
--- libp11-0.4.11/m4/libtool.m4	2018-10-02 20:46:57.000000000 +0200
+++ libp11-0.4.12/m4/libtool.m4	2022-03-15 18:14:13.000000000 +0100
@@ -1,6 +1,6 @@
 # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
 #
-#   Copyright (C) 1996-2001, 2003-2018 Free Software Foundation, Inc.
+#   Copyright (C) 1996-2001, 2003-2015 Free Software Foundation, Inc.
 #   Written by Gordon Matzigkeit, 1996
 #
 # This file is free software; the Free Software Foundation gives
@@ -219,8 +219,8 @@
 ofile=libtool
 can_build_shared=yes
 
-# All known linkers require a '.a' archive for static linking (except MSVC and
-# ICC, which need '.lib').
+# All known linkers require a '.a' archive for static linking (except MSVC,
+# which needs '.lib').
 libext=a
 
 with_gnu_ld=$lt_cv_prog_gnu_ld
@@ -728,7 +728,6 @@
     cat <<_LT_EOF >> "$cfgfile"
 #! $SHELL
 # Generated automatically by $as_me ($PACKAGE) $VERSION
-# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
 # NOTE: Changes made to this file will be lost: look at ltmain.sh.
 
 # Provide generalized library-building support services.
@@ -1042,8 +1041,8 @@
 _LT_EOF
       echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
       $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
-      echo "$AR $AR_FLAGS libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
-      $AR $AR_FLAGS libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+      echo "$AR cr libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+      $AR cr libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
       echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
       $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
       cat > conftest.c << _LT_EOF
@@ -1072,11 +1071,11 @@
       # to the OS version, if on x86, and 10.4, the deployment
       # target defaults to 10.4. Don't you love it?
       case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
-	10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+	10.0,*86*-darwin8*|10.0,*-darwin[[912]]*)
 	  _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
 	10.[[012]][[,.]]*)
 	  _lt_dar_allow_undefined='$wl-flat_namespace $wl-undefined ${wl}suppress' ;;
-	10.*)
+	10.*|11.*)
 	  _lt_dar_allow_undefined='$wl-undefined ${wl}dynamic_lookup' ;;
       esac
     ;;
@@ -1493,22 +1492,9 @@
 m4_defun([_LT_PROG_AR],
 [AC_CHECK_TOOLS(AR, [ar], false)
 : ${AR=ar}
+: ${AR_FLAGS=cr}
 _LT_DECL([], [AR], [1], [The archiver])
-
-# Use ARFLAGS variable as AR's operation code to sync the variable naming with
-# Automake.  If both AR_FLAGS and ARFLAGS are specified, AR_FLAGS should have
-# higher priority because thats what people were doing historically (setting
-# ARFLAGS for automake and AR_FLAGS for libtool).  FIXME: Make the AR_FLAGS
-# variable obsoleted/removed.
-
-test ${AR_FLAGS+y} || AR_FLAGS=${ARFLAGS-cr}
-lt_ar_flags=$AR_FLAGS
-_LT_DECL([], [lt_ar_flags], [0], [Flags to create an archive (by configure)])
-
-# Make AR_FLAGS overridable by 'make ARFLAGS='.  Don't try to run-time override
-# by AR_FLAGS because that was never working and AR_FLAGS is about to die.
-_LT_DECL([], [AR_FLAGS], [\@S|@{ARFLAGS-"\@S|@lt_ar_flags"}],
-         [Flags to create an archive])
+_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
 
 AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
   [lt_cv_ar_at_file=no
@@ -2220,35 +2206,26 @@
 striplib=
 old_striplib=
 AC_MSG_CHECKING([whether stripping libraries is possible])
-if test -z "$STRIP"; then
-  AC_MSG_RESULT([no])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+  test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+  test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+  AC_MSG_RESULT([yes])
 else
-  if $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
-    old_striplib="$STRIP --strip-debug"
-    striplib="$STRIP --strip-unneeded"
-    AC_MSG_RESULT([yes])
-  else
-    case $host_os in
-    darwin*)
-      # FIXME - insert some real tests, host_os isn't really good enough
+# FIXME - insert some real tests, host_os isn't really good enough
+  case $host_os in
+  darwin*)
+    if test -n "$STRIP"; then
       striplib="$STRIP -x"
       old_striplib="$STRIP -S"
       AC_MSG_RESULT([yes])
-      ;;
-    freebsd*)
-      if $STRIP -V 2>&1 | $GREP "elftoolchain" >/dev/null; then
-        old_striplib="$STRIP --strip-debug"
-        striplib="$STRIP --strip-unneeded"
-        AC_MSG_RESULT([yes])
-      else
-        AC_MSG_RESULT([no])
-      fi
-      ;;
-    *)
+    else
       AC_MSG_RESULT([no])
-      ;;
-    esac
-  fi
+    fi
+    ;;
+  *)
+    AC_MSG_RESULT([no])
+    ;;
+  esac
 fi
 _LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
 _LT_DECL([], [striplib], [1])
@@ -2587,8 +2564,8 @@
     dynamic_linker='Win32 ld.exe'
     ;;
 
-  *,cl* | *,icl*)
-    # Native MSVC or ICC
+  *,cl*)
+    # Native MSVC
     libname_spec='$name'
     soname_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext'
     library_names_spec='$libname.dll.lib'
@@ -2644,7 +2621,7 @@
     ;;
 
   *)
-    # Assume MSVC and ICC wrapper
+    # Assume MSVC wrapper
     library_names_spec='$libname`echo $release | $SED -e 's/[[.]]/-/g'`$versuffix$shared_ext $libname.lib'
     dynamic_linker='Win32 ld.exe'
     ;;
@@ -2909,6 +2886,18 @@
   dynamic_linker='GNU/Linux ld.so'
   ;;
 
+netbsdelf*-gnu)
+  version_type=linux
+  need_lib_prefix=no
+  need_version=no
+  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+  soname_spec='${libname}${release}${shared_ext}$major'
+  shlibpath_var=LD_LIBRARY_PATH
+  shlibpath_overrides_runpath=no
+  hardcode_into_libs=yes
+  dynamic_linker='NetBSD ld.elf_so'
+  ;;
+
 netbsd*)
   version_type=sunos
   need_lib_prefix=no
@@ -3568,7 +3557,7 @@
   lt_cv_deplibs_check_method=pass_all
   ;;
 
-netbsd*)
+netbsd* | netbsdelf*-gnu)
   if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
     lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
   else
@@ -4032,7 +4021,7 @@
   if test "$lt_cv_nm_interface" = "MS dumpbin"; then
     # Fake it for dumpbin and say T for any non-static function,
     # D for any global variable and I for any imported variable.
-    # Also find C++ and __fastcall symbols from MSVC++ or ICC,
+    # Also find C++ and __fastcall symbols from MSVC++,
     # which start with @ or ?.
     lt_cv_sys_global_symbol_pipe="$AWK ['"\
 "     {last_section=section; section=\$ 3};"\
@@ -4074,7 +4063,8 @@
   if AC_TRY_EVAL(ac_compile); then
     # Now try to grab the symbols.
     nlist=conftest.nm
-    if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
+    $ECHO "$as_me:$LINENO: $NM conftest.$ac_objext | $lt_cv_sys_global_symbol_pipe > $nlist" >&AS_MESSAGE_LOG_FD
+    if eval "$NM" conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist 2>&AS_MESSAGE_LOG_FD && test -s "$nlist"; then
       # Try sorting and uniquifying the output.
       if sort "$nlist" | uniq > "$nlist"T; then
 	mv -f "$nlist"T "$nlist"
@@ -4446,7 +4436,7 @@
 	    ;;
 	esac
 	;;
-      netbsd*)
+      netbsd* | netbsdelf*-gnu)
 	;;
       *qnx* | *nto*)
         # QNX uses GNU C++, but need to define -shared option too, otherwise
@@ -4714,6 +4704,12 @@
 	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
 	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
         ;;
+      # flang / f18. f95 an alias for gfortran or flang on Debian
+      flang* | f18* | f95*)
+	_LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+	_LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+	_LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+        ;;
       # icc used to be incompatible with GCC.
       # ICC 10 doesn't accept -KPIC any more.
       icc* | ifort*)
@@ -4941,7 +4937,7 @@
     if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
       _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
     else
-      _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+      _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
     fi
     ;;
   pw32*)
@@ -4949,7 +4945,7 @@
     ;;
   cygwin* | mingw* | cegcc*)
     case $cc_basename in
-    cl* | icl*)
+    cl*)
       _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
       ;;
     *)
@@ -4958,6 +4954,9 @@
       ;;
     esac
     ;;
+  linux* | k*bsd*-gnu | gnu*)
+    _LT_TAGVAR(link_all_deplibs, $1)=no
+    ;;
   *)
     _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
     ;;
@@ -5006,20 +5005,23 @@
 
   case $host_os in
   cygwin* | mingw* | pw32* | cegcc*)
-    # FIXME: the MSVC++ and ICC port hasn't been tested in a loooong time
+    # FIXME: the MSVC++ port hasn't been tested in a loooong time
     # When not using gcc, we currently assume that we are using
-    # Microsoft Visual C++ or Intel C++ Compiler.
+    # Microsoft Visual C++.
     if test yes != "$GCC"; then
       with_gnu_ld=no
     fi
     ;;
   interix*)
-    # we just hope/assume this is gcc and not c89 (= MSVC++ or ICC)
+    # we just hope/assume this is gcc and not c89 (= MSVC++)
     with_gnu_ld=yes
     ;;
   openbsd* | bitrig*)
     with_gnu_ld=no
     ;;
+  linux* | k*bsd*-gnu | gnu*)
+    _LT_TAGVAR(link_all_deplibs, $1)=no
+    ;;
   esac
 
   _LT_TAGVAR(ld_shlibs, $1)=yes
@@ -5178,7 +5180,6 @@
 	emximp -o $lib $output_objdir/$libname.def'
       _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
       _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-      _LT_TAGVAR(file_list_spec, $1)='@'
       ;;
 
     interix[[3-9]]*)
@@ -5275,7 +5276,7 @@
       fi
       ;;
 
-    netbsd*)
+    netbsd* | netbsdelf*-gnu)
       if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
 	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
 	wlarc=
@@ -5396,7 +5397,7 @@
 	if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
 	  _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { if (\$ 2 == "W") { print \$ 3 " weak" } else { print \$ 3 } } }'\'' | sort -u > $export_symbols'
 	else
-	  _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "L") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
+	  _LT_TAGVAR(export_symbols_cmds, $1)='`func_echo_all $NM | $SED -e '\''s/B\([[^B]]*\)$/P\1/'\''` -PCpgl $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) && ([substr](\$ 1,1,1) != ".")) { if ((\$ 2 == "W") || (\$ 2 == "V") || (\$ 2 == "Z")) { print \$ 1 " weak" } else { print \$ 1 } } }'\'' | sort -u > $export_symbols'
 	fi
 	aix_use_runtimelinking=no
 
@@ -5579,12 +5580,12 @@
 
     cygwin* | mingw* | pw32* | cegcc*)
       # When not using gcc, we currently assume that we are using
-      # Microsoft Visual C++ or Intel C++ Compiler.
+      # Microsoft Visual C++.
       # hardcode_libdir_flag_spec is actually meaningless, as there is
       # no search path for DLLs.
       case $cc_basename in
-      cl* | icl*)
-	# Native MSVC or ICC
+      cl*)
+	# Native MSVC
 	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
 	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
 	_LT_TAGVAR(always_export_symbols, $1)=yes
@@ -5625,7 +5626,7 @@
           fi'
 	;;
       *)
-	# Assume MSVC and ICC wrapper
+	# Assume MSVC wrapper
 	_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
 	_LT_TAGVAR(allow_undefined_flag, $1)=unsupported
 	# Tell ltmain to make .lib files, not .a files.
@@ -5796,6 +5797,7 @@
 	if test yes = "$lt_cv_irix_exported_symbol"; then
           _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags $wl-soname $wl$soname `test -n "$verstring" && func_echo_all "$wl-set_version $wl$verstring"` $wl-update_registry $wl$output_objdir/so_locations $wl-exports_file $wl$export_symbols -o $lib'
 	fi
+	_LT_TAGVAR(link_all_deplibs, $1)=no
       else
 	_LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -o $lib'
 	_LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry $output_objdir/so_locations -exports_file $export_symbols -o $lib'
@@ -5817,7 +5819,7 @@
       esac
       ;;
 
-    netbsd*)
+    netbsd* | netbsdelf*-gnu)
       if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
 	_LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'  # a.out
       else
@@ -5884,7 +5886,6 @@
 	emximp -o $lib $output_objdir/$libname.def'
       _LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
       _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-      _LT_TAGVAR(file_list_spec, $1)='@'
       ;;
 
     osf3*)
@@ -6444,7 +6445,7 @@
       # Commands to make compiler produce verbose output that lists
       # what "hidden" libraries, object files and flags are used when
       # linking a shared library.
-      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"'
 
     else
       GXX=no
@@ -6655,8 +6656,8 @@
 
       cygwin* | mingw* | pw32* | cegcc*)
 	case $GXX,$cc_basename in
-	,cl* | no,cl* | ,icl* | no,icl*)
-	  # Native MSVC or ICC
+	,cl* | no,cl*)
+	  # Native MSVC
 	  # hardcode_libdir_flag_spec is actually meaningless, as there is
 	  # no search path for DLLs.
 	  _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
@@ -6754,7 +6755,6 @@
 	  emximp -o $lib $output_objdir/$libname.def'
 	_LT_TAGVAR(old_archive_From_new_cmds, $1)='emximp -o $output_objdir/${libname}_dll.a $output_objdir/$libname.def'
 	_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
-	_LT_TAGVAR(file_list_spec, $1)='@'
 	;;
 
       dgux*)
@@ -6820,7 +6820,7 @@
             # explicitly linking system object files so we need to strip them
             # from the output so that they don't get included in the library
             # dependencies.
-            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+            output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
             ;;
           *)
             if test yes = "$GXX"; then
@@ -6885,7 +6885,7 @@
 	    # explicitly linking system object files so we need to strip them
 	    # from the output so that they don't get included in the library
 	    # dependencies.
-	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+	    output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP " \-L"`; list= ; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
 	    ;;
           *)
 	    if test yes = "$GXX"; then
@@ -7224,7 +7224,7 @@
 	      # Commands to make compiler produce verbose output that lists
 	      # what "hidden" libraries, object files and flags are used when
 	      # linking a shared library.
-	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	      output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"'
 
 	    else
 	      # FIXME: insert proper C++ library support
@@ -7308,7 +7308,7 @@
 	        # Commands to make compiler produce verbose output that lists
 	        # what "hidden" libraries, object files and flags are used when
 	        # linking a shared library.
-	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	        output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"'
 	      else
 	        # g++ 2.7 appears to require '-G' NOT '-shared' on this
 	        # platform.
@@ -7319,7 +7319,7 @@
 	        # Commands to make compiler produce verbose output that lists
 	        # what "hidden" libraries, object files and flags are used when
 	        # linking a shared library.
-	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+	        output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP " \-L"'
 	      fi
 
 	      _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='$wl-R $wl$libdir'
diff -Nru libp11-0.4.11/m4/lt~obsolete.m4 libp11-0.4.12/m4/lt~obsolete.m4
--- libp11-0.4.11/m4/lt~obsolete.m4	2018-10-02 20:46:57.000000000 +0200
+++ libp11-0.4.12/m4/lt~obsolete.m4	2022-03-15 18:14:13.000000000 +0100
@@ -1,6 +1,6 @@
 # lt~obsolete.m4 -- aclocal satisfying obsolete definitions.    -*-Autoconf-*-
 #
-#   Copyright (C) 2004-2005, 2007, 2009, 2011-2018 Free Software
+#   Copyright (C) 2004-2005, 2007, 2009, 2011-2015 Free Software
 #   Foundation, Inc.
 #   Written by Scott James Remnant, 2004.
 #
diff -Nru libp11-0.4.11/m4/ltoptions.m4 libp11-0.4.12/m4/ltoptions.m4
--- libp11-0.4.11/m4/ltoptions.m4	2018-10-02 20:46:57.000000000 +0200
+++ libp11-0.4.12/m4/ltoptions.m4	2022-03-15 18:14:13.000000000 +0100
@@ -1,6 +1,6 @@
 # Helper functions for option handling.                    -*- Autoconf -*-
 #
-#   Copyright (C) 2004-2005, 2007-2009, 2011-2018 Free Software
+#   Copyright (C) 2004-2005, 2007-2009, 2011-2015 Free Software
 #   Foundation, Inc.
 #   Written by Gary V. Vaughan, 2004
 #
diff -Nru libp11-0.4.11/m4/ltsugar.m4 libp11-0.4.12/m4/ltsugar.m4
--- libp11-0.4.11/m4/ltsugar.m4	2018-10-02 20:46:57.000000000 +0200
+++ libp11-0.4.12/m4/ltsugar.m4	2022-03-15 18:14:13.000000000 +0100
@@ -1,6 +1,6 @@
 # ltsugar.m4 -- libtool m4 base layer.                         -*-Autoconf-*-
 #
-# Copyright (C) 2004-2005, 2007-2008, 2011-2018 Free Software
+# Copyright (C) 2004-2005, 2007-2008, 2011-2015 Free Software
 # Foundation, Inc.
 # Written by Gary V. Vaughan, 2004
 #
diff -Nru libp11-0.4.11/m4/ltversion.m4 libp11-0.4.12/m4/ltversion.m4
--- libp11-0.4.11/m4/ltversion.m4	2018-10-02 20:46:57.000000000 +0200
+++ libp11-0.4.12/m4/ltversion.m4	2022-03-15 18:14:13.000000000 +0100
@@ -1,6 +1,6 @@
 # ltversion.m4 -- version numbers			-*- Autoconf -*-
 #
-#   Copyright (C) 2004, 2011-2018 Free Software Foundation, Inc.
+#   Copyright (C) 2004, 2011-2015 Free Software Foundation, Inc.
 #   Written by Scott James Remnant, 2004
 #
 # This file is free software; the Free Software Foundation gives
@@ -9,15 +9,15 @@
 
 # @configure_input@
 
-# serial 4221 ltversion.m4
+# serial 4179 ltversion.m4
 # This file is part of GNU Libtool
 
-m4_define([LT_PACKAGE_VERSION], [2.4.6.42-b88ce])
-m4_define([LT_PACKAGE_REVISION], [2.4.6.42])
+m4_define([LT_PACKAGE_VERSION], [2.4.6])
+m4_define([LT_PACKAGE_REVISION], [2.4.6])
 
 AC_DEFUN([LTVERSION_VERSION],
-[macro_version='2.4.6.42-b88ce'
-macro_revision='2.4.6.42'
+[macro_version='2.4.6'
+macro_revision='2.4.6'
 _LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
 _LT_DECL(, macro_revision, 0)
 ])
diff -Nru libp11-0.4.11/Makefile.in libp11-0.4.12/Makefile.in
--- libp11-0.4.11/Makefile.in	2020-10-11 15:46:57.000000000 +0200
+++ libp11-0.4.12/Makefile.in	2022-07-15 21:56:26.000000000 +0200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.2 from Makefile.am.
+# Makefile.in generated by automake 1.16.4 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -88,9 +88,11 @@
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
+target_triplet = @target@
 subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/ld-version-script.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_pthread.m4 \
+	$(top_srcdir)/m4/ld-version-script.m4 \
 	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
 	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
 	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
@@ -186,12 +188,10 @@
   unique=`for i in $$list; do \
     if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
   done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
-CSCOPE = cscope
 DIST_SUBDIRS = $(SUBDIRS)
-am__DIST_COMMON = $(srcdir)/Makefile.in COPYING NEWS compile \
-	config.guess config.sub depcomp install-sh ltmain.sh missing
+am__DIST_COMMON = $(srcdir)/Makefile.in COPYING INSTALL.md NEWS \
+	README.md compile config.guess config.sub depcomp install-sh \
+	ltmain.sh missing
 DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
 distdir = $(PACKAGE)-$(VERSION)
 top_distdir = $(distdir)
@@ -230,6 +230,8 @@
 DIST_ARCHIVES = $(distdir).tar.gz
 GZIP_ENV = --best
 DIST_TARGETS = dist-gzip
+# Exists only to be overridden by the user if desired.
+AM_DISTCHECK_DVI_TARGET = dvi
 distuninstallcheck_listfiles = find . -type f -print
 am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
   | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
@@ -248,6 +250,8 @@
 CFLAGS = @CFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
@@ -259,6 +263,7 @@
 ECHO_N = @ECHO_N@
 ECHO_T = @ECHO_T@
 EGREP = @EGREP@
+ETAGS = @ETAGS@
 EXEEXT = @EXEEXT@
 FGREP = @FGREP@
 GREP = @GREP@
@@ -305,6 +310,10 @@
 PKG_CONFIG = @PKG_CONFIG@
 PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
 PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_CXX = @PTHREAD_CXX@
+PTHREAD_LIBS = @PTHREAD_LIBS@
 RANLIB = @RANLIB@
 RC = @RC@
 SED = @SED@
@@ -327,6 +336,7 @@
 am__tar = @am__tar@
 am__untar = @am__untar@
 apidocdir = @apidocdir@
+ax_pthread_config = @ax_pthread_config@
 bindir = @bindir@
 build = @build@
 build_alias = @build_alias@
@@ -366,7 +376,11 @@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
 sysconfdir = @sysconfdir@
+target = @target@
 target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
@@ -561,7 +575,6 @@
 distclean-tags:
 	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
 	-rm -f cscope.out cscope.in.out cscope.po.out cscope.files
-
 distdir: $(BUILT_SOURCES)
 	$(MAKE) $(AM_MAKEFLAGS) distdir-am
 
@@ -711,7 +724,7 @@
 	    $(DISTCHECK_CONFIGURE_FLAGS) \
 	    --srcdir=../.. --prefix="$$dc_install_base" \
 	  && $(MAKE) $(AM_MAKEFLAGS) \
-	  && $(MAKE) $(AM_MAKEFLAGS) dvi \
+	  && $(MAKE) $(AM_MAKEFLAGS) $(AM_DISTCHECK_DVI_TARGET) \
 	  && $(MAKE) $(AM_MAKEFLAGS) check \
 	  && $(MAKE) $(AM_MAKEFLAGS) install \
 	  && $(MAKE) $(AM_MAKEFLAGS) installcheck \
diff -Nru libp11-0.4.11/make.rules.mak libp11-0.4.12/make.rules.mak
--- libp11-0.4.11/make.rules.mak	2020-02-27 06:50:01.000000000 +0100
+++ libp11-0.4.12/make.rules.mak	2021-10-30 14:20:08.000000000 +0200
@@ -43,6 +43,6 @@
 
 LIBS = "$(OPENSSL_LIB)" ws2_32.lib user32.lib advapi32.lib crypt32.lib gdi32.lib
 
-CFLAGS =  /nologo /GS /W3 /D_CRT_SECURE_NO_DEPRECATE /MT$(DEBUG_SUFFIX) $(OPENSSL_INC) /D_WIN32_WINNT=0x0502 /DWIN32_LEAN_AND_MEAN $(DEBUG_COMPILE)
+CFLAGS =  /nologo /GS /W3 /D_CRT_SECURE_NO_DEPRECATE /MT$(DEBUG_SUFFIX) $(OPENSSL_INC) /D_WIN32_WINNT=0x0600 /DWIN32_LEAN_AND_MEAN $(DEBUG_COMPILE)
 
 LINKFLAGS = /NOLOGO /INCREMENTAL:NO $(MACHINE) /MANIFEST:NO /NXCOMPAT /DYNAMICBASE $(DEBUG_LINK)
diff -Nru libp11-0.4.11/missing libp11-0.4.12/missing
--- libp11-0.4.11/missing	2018-10-02 20:47:03.000000000 +0200
+++ libp11-0.4.12/missing	2022-03-15 18:14:17.000000000 +0100
@@ -3,7 +3,7 @@
 
 scriptversion=2018-03-07.03; # UTC
 
-# Copyright (C) 1996-2018 Free Software Foundation, Inc.
+# Copyright (C) 1996-2020 Free Software Foundation, Inc.
 # Originally written by Fran,cois Pinard <pinard at iro.umontreal.ca>, 1996.
 
 # This program is free software; you can redistribute it and/or modify
diff -Nru libp11-0.4.11/NEWS libp11-0.4.12/NEWS
--- libp11-0.4.11/NEWS	2020-10-11 16:48:43.000000000 +0200
+++ libp11-0.4.12/NEWS	2022-07-15 23:36:16.000000000 +0200
@@ -1,5 +1,24 @@
 NEWS for Libp11 -- History of user visible changes
 
+New in 0.4.12; 2022-07-15; Michał Trojnara
+* Fixed using an explicitly provided PIN regardless of the secure login
+  flag (Alon Bar-Lev)
+* Fixed RSA_PKCS1_PADDING handling (Michał Trojnara)
+* Fixed a crash on LLP64, including 64-bit Windows (Małgorzata Olszówka)
+* Fixed searching objects when both ID and label are specified (minfrin)
+* Fixed the OAEP "source" parameter (S-P Chan)
+* Fixed object searching by label (Michał Trojnara)
+* Fixed thread safety in slot enumeration (Michał Trojnara)
+* Fixed storing certificates on tokens (Mateusz Kwiatkowski)
+* Fixed several memory leaks (Michał Trojnara, Jakub Jelen, Timo Teräs)
+* Fixed OpenSSL 3.0 compatibility (Jakub Jelen)
+* Fixed LibreSSL compatibility (orbea, patchMonkey156)
+* Major concurrency improvements and refactoring (Timo Teräs)
+* Added re-numeration of slots as an engine control command (Markus Koetter)
+* Added the PKCS11_update_slots() API function (Timo Teräs)
+* Added support for the SHA3 hash function (alegon01)
+* Added a self-test for engine RSA operations (Uri Blumenthal)
+
 New in 0.4.11; 2020-10-11; Michał Trojnara
 * Fixed "EVP_PKEY_derive:buffer too small" EC errors (Luka Logar)
 * Fixed various memory leaks (Mateusz Kwiatkowski)
@@ -176,7 +195,7 @@
 
 New in 0.2.6; 2009-07-22; Andreas Jellinghaus
 * Fix new version: add new symbol to export file
-* fix building on MSVC plattform
+* fix building on MSVC platform
 
 New in 0.2.5; 2009-06-15; Andreas Jellinghaus
 * Add function to export the slot id (Douglas E. Engert).
diff -Nru libp11-0.4.11/README.md libp11-0.4.12/README.md
--- libp11-0.4.11/README.md	2018-12-24 22:39:59.000000000 +0100
+++ libp11-0.4.12/README.md	2021-10-30 14:20:08.000000000 +0200
@@ -168,6 +168,7 @@
 * **SET_USER_INTERFACE**: Set the global user interface
 * **SET_CALLBACK_DATA**: Set the global user interface extra data
 * **FORCE_LOGIN**: Force login to the PKCS#11 module
+* **RE_ENUMERATE**: re-enumerate the slots/tokens, required when adding/removing tokens/slots
 
 An example code snippet setting specific module is shown below.
 
@@ -184,11 +185,14 @@
 
 ## Thread safety in libp11
 
-Thread-safety requires dynamic callbacks to be registered by the calling
-application with the following OpenSSL functions:
-* CRYPTO_set_dynlock_create_callback
-* CRYPTO_set_dynlock_destroy_callback
-* CRYPTO_set_dynlock_lock_callback
+libp11 internally uses OS locking, and configures the PKCS#11 module to do
+the same.
+
+Access to the the PKCS#11 tokens and objects is via a pool of PKCS#11 sessions.
+This allows concurrent usage of crypto operations in thread safe manner.
+
+However, many of the main PKCS11_* API functions are currently not fully thread
+safe. Work to fix this is pending.
 
 ## Submitting pull requests
 
diff -Nru libp11-0.4.11/src/config.h.in libp11-0.4.12/src/config.h.in
--- libp11-0.4.11/src/config.h.in	2020-10-11 15:47:02.000000000 +0200
+++ libp11-0.4.12/src/config.h.in	2022-07-15 21:56:31.000000000 +0200
@@ -30,6 +30,12 @@
 /* Define to 1 if you have the <memory.h> header file. */
 #undef HAVE_MEMORY_H
 
+/* Define if you have POSIX threads libraries and header files. */
+#undef HAVE_PTHREAD
+
+/* Have PTHREAD_PRIO_INHERIT. */
+#undef HAVE_PTHREAD_PRIO_INHERIT
+
 /* Define to 1 if you have the <stdint.h> header file. */
 #undef HAVE_STDINT_H
 
@@ -60,9 +66,6 @@
 /* Define to 1 if you have the <utmp.h> header file. */
 #undef HAVE_UTMP_H
 
-/* Define to 1 if you have the `__register_atfork' function. */
-#undef HAVE___REGISTER_ATFORK
-
 /* Define to the sub-directory where libtool stores uninstalled libraries. */
 #undef LT_OBJDIR
 
@@ -87,6 +90,10 @@
 /* Define to the version of this package. */
 #undef PACKAGE_VERSION
 
+/* Define to necessary symbol if this constant uses a non-standard name on
+   your system. */
+#undef PTHREAD_CREATE_JOINABLE
+
 /* Define to 1 if you have the ANSI C header files. */
 #undef STDC_HEADERS
 
diff -Nru libp11-0.4.11/src/eng_back.c libp11-0.4.12/src/eng_back.c
--- libp11-0.4.11/src/eng_back.c	2020-10-11 15:35:09.000000000 +0200
+++ libp11-0.4.12/src/eng_back.c	2022-07-05 22:22:51.000000000 +0200
@@ -27,6 +27,7 @@
  */
 
 #include "engine.h"
+#include "p11_pthread.h"
 #include <stdio.h>
 #include <string.h>
 
@@ -48,19 +49,14 @@
 	 */
 	char *pin;
 	size_t pin_length;
+	int forced_pin;
 	int verbose;
 	char *module;
 	char *init_args;
 	UI_METHOD *ui_method;
 	void *callback_data;
 	int force_login;
-
-	/* Engine initialization mutex */
-#if OPENSSL_VERSION_NUMBER >= 0x10100004L && !defined(LIBRESSL_VERSION_NUMBER)
-	CRYPTO_RWLOCK *rwlock;
-#else
-	int rwlock;
-#endif
+	pthread_mutex_t lock;
 
 	/* Current operations */
 	PKCS11_CTX *pkcs11_ctx;
@@ -68,6 +64,8 @@
 	unsigned int slot_count;
 };
 
+static int ctx_ctrl_set_pin(ENGINE_CTX *ctx, const char *pin);
+
 /******************************************************************************/
 /* Utility functions                                                          */
 /******************************************************************************/
@@ -92,6 +90,38 @@
 		ctx_log(ctx, level, "%02x", val[n]);
 }
 
+static void dump_expiry(ENGINE_CTX *ctx, int level,
+		const PKCS11_CERT *cert)
+{
+	BIO *bio;
+	const ASN1_TIME *exp;
+
+	char *data = NULL;
+	int len = 0;
+
+	if (level > ctx->verbose) {
+		return;
+	}
+
+	if (!cert || !cert->x509 || !(exp = X509_get0_notAfter(cert->x509))) {
+		ctx_log(ctx, level, "none");
+	}
+
+	if ((bio = BIO_new(BIO_s_mem())) == NULL) {
+		return;
+	}
+
+	ASN1_TIME_print(bio, exp);
+
+	len = BIO_get_mem_data(bio, &data);
+
+	ctx_log(ctx, level, "%.*s", len, data);
+
+	BIO_free(bio);
+
+	return;
+}
+
 /******************************************************************************/
 /* PIN handling                                                               */
 /******************************************************************************/
@@ -104,6 +134,7 @@
 		OPENSSL_free(ctx->pin);
 		ctx->pin = NULL;
 		ctx->pin_length = 0;
+		ctx->forced_pin = 0;
 	}
 }
 
@@ -182,7 +213,7 @@
 
 	/* If the token has a secure login (i.e., an external keypad),
 	 * then use a NULL PIN. Otherwise, obtain a new PIN if needed. */
-	if (tok->secureLogin) {
+	if (tok->secureLogin && !ctx->forced_pin) {
 		/* Free the PIN if it has already been
 		 * assigned (i.e, cached by ctx_get_pin) */
 		ctx_destroy_pin(ctx);
@@ -224,6 +255,7 @@
 	if (!ctx)
 		return NULL;
 	memset(ctx, 0, sizeof(ENGINE_CTX));
+	pthread_mutex_init(&ctx->lock, 0);
 
 	mod = getenv("PKCS11_MODULE_PATH");
 	if (mod) {
@@ -236,13 +268,6 @@
 #endif
 	}
 
-#if OPENSSL_VERSION_NUMBER >= 0x10100004L && !defined(LIBRESSL_VERSION_NUMBER)
-	ctx->rwlock = CRYPTO_THREAD_lock_new();
-#else
-	ctx->rwlock = CRYPTO_get_dynlock_create_callback() ?
-		CRYPTO_get_new_dynlockid() : 0;
-#endif
-
 	return ctx;
 }
 
@@ -253,69 +278,57 @@
 		ctx_destroy_pin(ctx);
 		OPENSSL_free(ctx->module);
 		OPENSSL_free(ctx->init_args);
-#if OPENSSL_VERSION_NUMBER >= 0x10100004L && !defined(LIBRESSL_VERSION_NUMBER)
-		CRYPTO_THREAD_lock_free(ctx->rwlock);
-#else
-		if (ctx->rwlock)
-			CRYPTO_destroy_dynlockid(ctx->rwlock);
-#endif
+		pthread_mutex_destroy(&ctx->lock);
 		OPENSSL_free(ctx);
 	}
 	return 1;
 }
 
+static int ctx_enumerate_slots_unlocked(ENGINE_CTX *ctx, PKCS11_CTX *pkcs11_ctx)
+{
+	/* PKCS11_update_slots() uses C_GetSlotList() via libp11 */
+	if (PKCS11_update_slots(pkcs11_ctx, &ctx->slot_list, &ctx->slot_count) < 0) {
+		ctx_log(ctx, 0, "Failed to enumerate slots\n");
+		return 0;
+	}
+	ctx_log(ctx, 1, "Found %u slot%s\n", ctx->slot_count,
+		ctx->slot_count <= 1 ? "" : "s");
+	return 1;
+}
+
+static int ctx_enumerate_slots(ENGINE_CTX *ctx, PKCS11_CTX *pkcs11_ctx)
+{
+	int rv;
+
+	pthread_mutex_lock(&ctx->lock);
+	rv = ctx_enumerate_slots_unlocked(ctx, pkcs11_ctx);
+	pthread_mutex_unlock(&ctx->lock);
+	return rv;
+}
+
 /* Initialize libp11 data: ctx->pkcs11_ctx and ctx->slot_list */
-static void ctx_init_libp11_unlocked(ENGINE_CTX *ctx)
+static int ctx_init_libp11_unlocked(ENGINE_CTX *ctx)
 {
 	PKCS11_CTX *pkcs11_ctx;
-	PKCS11_SLOT *slot_list = NULL;
-	unsigned int slot_count = 0;
 
-	ctx_log(ctx, 1, "PKCS#11: Initializing the engine\n");
+	if (ctx->pkcs11_ctx && ctx->slot_list)
+		return 0;
+
+	ctx_log(ctx, 1, "PKCS#11: Initializing the engine: %s\n", ctx->module);
 
 	pkcs11_ctx = PKCS11_CTX_new();
 	PKCS11_CTX_init_args(pkcs11_ctx, ctx->init_args);
 	PKCS11_set_ui_method(pkcs11_ctx, ctx->ui_method, ctx->callback_data);
-
-	/* PKCS11_CTX_load() uses C_GetSlotList() via p11-kit */
 	if (PKCS11_CTX_load(pkcs11_ctx, ctx->module) < 0) {
 		ctx_log(ctx, 0, "Unable to load module %s\n", ctx->module);
 		PKCS11_CTX_free(pkcs11_ctx);
-		return;
-	}
-
-	/* PKCS11_enumerate_slots() uses C_GetSlotList() via libp11 */
-	if (PKCS11_enumerate_slots(pkcs11_ctx, &slot_list, &slot_count) < 0) {
-		ctx_log(ctx, 0, "Failed to enumerate slots\n");
-		PKCS11_CTX_unload(pkcs11_ctx);
-		PKCS11_CTX_free(pkcs11_ctx);
-		return;
+		return -1;
 	}
-
-	ctx_log(ctx, 1, "Found %u slot%s\n", slot_count,
-		slot_count <= 1 ? "" : "s");
-
 	ctx->pkcs11_ctx = pkcs11_ctx;
-	ctx->slot_list = slot_list;
-	ctx->slot_count = slot_count;
-}
 
-static int ctx_init_libp11(ENGINE_CTX *ctx)
-{
-#if OPENSSL_VERSION_NUMBER >= 0x10100004L && !defined(LIBRESSL_VERSION_NUMBER)
-	CRYPTO_THREAD_write_lock(ctx->rwlock);
-#else
-	if (ctx->rwlock)
-		CRYPTO_w_lock(ctx->rwlock);
-#endif
-	if (!ctx->pkcs11_ctx|| !ctx->slot_list)
-		ctx_init_libp11_unlocked(ctx);
-#if OPENSSL_VERSION_NUMBER >= 0x10100004L && !defined(LIBRESSL_VERSION_NUMBER)
-	CRYPTO_THREAD_unlock(ctx->rwlock);
-#else
-	if (ctx->rwlock)
-		CRYPTO_w_unlock(ctx->rwlock);
-#endif
+	if (ctx_enumerate_slots_unlocked(ctx, pkcs11_ctx) != 1)
+		return -1;
+
 	return ctx->pkcs11_ctx && ctx->slot_list ? 0 : -1;
 }
 
@@ -327,21 +340,7 @@
 	 * Double-locking a non-recursive rwlock causes the application to
 	 * crash or hang, depending on the locking library implementation. */
 
-	/* Only attempt initialization when dynamic locks are unavailable.
-	 * This likely also indicates a single-threaded application,
-	 * so temporarily unlocking CRYPTO_LOCK_ENGINE should be safe. */
-#if OPENSSL_VERSION_NUMBER < 0x10100004L && !defined(LIBRESSL_VERSION_NUMBER)
-	if (CRYPTO_get_dynlock_create_callback() == NULL ||
-			CRYPTO_get_dynlock_lock_callback() == NULL ||
-			CRYPTO_get_dynlock_destroy_callback() == NULL) {
-		CRYPTO_w_unlock(CRYPTO_LOCK_ENGINE);
-		ctx_init_libp11_unlocked(ctx);
-		CRYPTO_w_lock(CRYPTO_LOCK_ENGINE);
-		return ctx->pkcs11_ctx && ctx->slot_list ? 1 : 0;
-	}
-#else
 	(void)ctx; /* squash the unused parameter warning */
-#endif
 	return 1;
 }
 
@@ -365,77 +364,74 @@
 }
 
 /******************************************************************************/
-/* Certificate handling                                                       */
+/* Utilities common to public, private key and certificate handling           */
 /******************************************************************************/
 
-/* prototype for OpenSSL ENGINE_load_cert */
-/* used by load_cert_ctrl via ENGINE_ctrl for now */
-
-static X509 *ctx_load_cert(ENGINE_CTX *ctx, const char *s_slot_cert_id,
-		const int login)
+static void *ctx_try_load_object(ENGINE_CTX *ctx,
+		const char *object_typestr,
+		void *(*match_func)(ENGINE_CTX *, PKCS11_TOKEN *,
+				const unsigned char *, size_t, const char *),
+		const char *object_uri, const int login,
+		UI_METHOD *ui_method, void *callback_data)
 {
 	PKCS11_SLOT *slot;
 	PKCS11_SLOT *found_slot = NULL, **matched_slots = NULL;
 	PKCS11_TOKEN *tok, *match_tok = NULL;
-	PKCS11_CERT *certs, *selected_cert = NULL;
-	X509 *x509 = NULL;
-	unsigned int cert_count, n, m;
-	unsigned char cert_id[MAX_VALUE_LEN / 2];
-	size_t cert_id_len = sizeof(cert_id);
-	char *cert_label = NULL;
+	unsigned int n, m;
+	unsigned char obj_id[MAX_VALUE_LEN / 2];
+	size_t obj_id_len = sizeof(obj_id);
+	char *obj_label = NULL;
 	char tmp_pin[MAX_PIN_LENGTH+1];
 	size_t tmp_pin_len = MAX_PIN_LENGTH;
 	int slot_nr = -1;
 	char flags[64];
 	size_t matched_count = 0;
+	void *object = NULL;
 
-	if (ctx_init_libp11(ctx)) /* Delayed libp11 initialization */
-		return NULL;
-
-	if (s_slot_cert_id && *s_slot_cert_id) {
-		if (!strncasecmp(s_slot_cert_id, "pkcs11:", 7)) {
-			n = parse_pkcs11_uri(ctx, s_slot_cert_id, &match_tok,
-				cert_id, &cert_id_len,
-				tmp_pin, &tmp_pin_len, &cert_label);
+	if (object_uri && *object_uri) {
+		if (!strncasecmp(object_uri, "pkcs11:", 7)) {
+			n = parse_pkcs11_uri(ctx, object_uri, &match_tok,
+				obj_id, &obj_id_len, tmp_pin, &tmp_pin_len, &obj_label);
 			if (!n) {
 				ctx_log(ctx, 0,
-					"The certificate ID is not a valid PKCS#11 URI\n"
-					"The PKCS#11 URI format is defined by RFC7512\n");
-				ENGerr(ENG_F_CTX_LOAD_CERT, ENG_R_INVALID_ID);
+					"The %s ID is not a valid PKCS#11 URI\n"
+					"The PKCS#11 URI format is defined by RFC7512\n",
+					object_typestr);
+				ENGerr(ENG_F_CTX_LOAD_OBJECT, ENG_R_INVALID_ID);
 				goto error;
 			}
 			if (tmp_pin_len > 0 && tmp_pin[0] != 0) {
-				ctx_destroy_pin(ctx);
-				ctx->pin = OPENSSL_malloc(MAX_PIN_LENGTH+1);
-				if (ctx->pin) {
-					memset(ctx->pin, 0, MAX_PIN_LENGTH+1);
-					memcpy(ctx->pin, tmp_pin, tmp_pin_len);
-					ctx->pin_length = tmp_pin_len;
+				tmp_pin[tmp_pin_len] = 0;
+				if (!ctx_ctrl_set_pin(ctx, tmp_pin)) {
+					goto error;
 				}
 			}
+			ctx_log(ctx, 1, "Looking in slots for %s %s login: ",
+				object_typestr, login ? "with" : "without");
 		} else {
-			n = parse_slot_id_string(ctx, s_slot_cert_id, &slot_nr,
-				cert_id, &cert_id_len, &cert_label);
+			n = parse_slot_id_string(ctx, object_uri, &slot_nr,
+				obj_id, &obj_id_len, &obj_label);
 			if (!n) {
 				ctx_log(ctx, 0,
-					"The certificate ID is not a valid PKCS#11 URI\n"
+					"The %s ID is not a valid PKCS#11 URI\n"
 					"The PKCS#11 URI format is defined by RFC7512\n"
 					"The legacy ENGINE_pkcs11 ID format is also "
-					"still accepted for now\n");
-				ENGerr(ENG_F_CTX_LOAD_CERT, ENG_R_INVALID_ID);
+					"still accepted for now\n",
+					object_typestr);
+				ENGerr(ENG_F_CTX_LOAD_OBJECT, ENG_R_INVALID_ID);
 				goto error;
 			}
+			ctx_log(ctx, 1, "Looking in slot %d for %s %s login: ",
+				slot_nr, object_typestr, login ? "with" : "without");
 		}
-		ctx_log(ctx, 1, "Looking in slot %d for certificate: ",
-			slot_nr);
-		if (cert_id_len != 0) {
+		if (obj_id_len != 0) {
 			ctx_log(ctx, 1, "id=");
-			dump_hex(ctx, 1, cert_id, cert_id_len);
+			dump_hex(ctx, 1, obj_id, obj_id_len);
 		}
-		if (cert_id_len != 0 && cert_label)
+		if (obj_id_len != 0 && obj_label)
 			ctx_log(ctx, 1, " ");
-		if (cert_label)
-			ctx_log(ctx, 1, "label=%s", cert_label);
+		if (obj_label)
+			ctx_log(ctx, 1, "label=%s", obj_label);
 		ctx_log(ctx, 1, "\n");
 	}
 
@@ -481,7 +477,7 @@
 					!strcmp(match_tok->model, slot->token->model))) {
 			found_slot = slot;
 		}
-		ctx_log(ctx, 1, "[%lu] %-25.25s  %-16s",
+		ctx_log(ctx, 1, "- [%lu] %-25.25s  %-36s",
 			PKCS11_get_slotid_from_slot(slot),
 			slot->description, flags);
 		if (slot->token) {
@@ -491,9 +487,6 @@
 		}
 		ctx_log(ctx, 1, "\n");
 
-		if (found_slot && found_slot->token && !found_slot->token->initialized)
-			ctx_log(ctx, 0, "Found uninitialized token\n");
-
 		/* Ignore slots without tokens or with uninitialized token */
 		if (found_slot && found_slot->token && found_slot->token->initialized) {
 			matched_slots[matched_count] = found_slot;
@@ -504,13 +497,20 @@
 
 	if (matched_count == 0) {
 		if (match_tok) {
-			ctx_log(ctx, 0, "Specified object not found\n");
+			if (found_slot) {
+				ctx_log(ctx, 0, "The %s was not found on token %s\n",
+					object_typestr, found_slot->token->label[0] ?
+					found_slot->token->label : "no label");
+			} else {
+				ctx_log(ctx, 0, "No matching initialized token was found for %s\n",
+					object_typestr);
+			}
 			goto error;
 		}
 
 		/* If the legacy slot ID format was used */
 		if (slot_nr != -1) {
-			ctx_log(ctx, 0, "Invalid slot number: %d\n", slot_nr);
+			ctx_log(ctx, 0, "The %s was not found on slot %d\n", object_typestr, slot_nr);
 			goto error;
 		} else {
 			found_slot = PKCS11_find_token(ctx->pkcs11_ctx,
@@ -531,7 +531,7 @@
 		slot = matched_slots[n];
 		tok = slot->token;
 		if (!tok) {
-			ctx_log(ctx, 0, "Empty token found\n");
+			ctx_log(ctx, 0, "Empty slot found\n");
 			break;
 		}
 
@@ -546,7 +546,7 @@
 				 * the PIN against all matching slots */
 				if (matched_count == 1) {
 					if (!ctx_login(ctx, slot, tok,
-							ctx->ui_method, ctx->callback_data)) {
+							ui_method, callback_data)) {
 						ctx_log(ctx, 0, "Login to token failed, returning NULL...\n");
 						goto error;
 					}
@@ -555,7 +555,7 @@
 						" login\n", matched_count);
 					for (m = 0; m < matched_count; m++){
 						slot = matched_slots[m];
-						ctx_log(ctx, 0, "[%u] %s: %s\n", m + 1,
+						ctx_log(ctx, 0, "- [%u] %s: %s\n", m + 1,
 								slot->description? slot->description:
 								"(no description)",
 								(slot->token && slot->token->label)?
@@ -566,48 +566,11 @@
 			}
 		}
 
-		if (PKCS11_enumerate_certs(tok, &certs, &cert_count)) {
-			ctx_log(ctx, 0, "Unable to enumerate certificates\n");
-			continue;
-		}
-
-		ctx_log(ctx, 1, "Found %u cert%s:\n", cert_count,
-				(cert_count <= 1) ? "" : "s");
-		if ((s_slot_cert_id && *s_slot_cert_id) &&
-				(cert_id_len != 0 || cert_label)) {
-			for (m = 0; m < cert_count; m++) {
-				PKCS11_CERT *k = certs + m;
-
-				if (cert_label && k->label && strcmp(k->label, cert_label) == 0)
-					selected_cert = k;
-				if (cert_id_len != 0 && k->id_len == cert_id_len &&
-						memcmp(k->id, cert_id, cert_id_len) == 0)
-					selected_cert = k;
-			}
-		} else {
-			for (m = 0; m < cert_count; m++) {
-				PKCS11_CERT *k = certs + m;
-				if (k->id && *(k->id)) {
-					selected_cert = k; /* Use the first certificate with nonempty id */
-					break;
-				}
-			}
-			if (!selected_cert)
-				selected_cert = certs; /* Use the first certificate */
-		}
-
-		if (selected_cert) {
+		object = match_func(ctx, tok, obj_id, obj_id_len, obj_label);
+		if (object)
 			break;
-		}
 	}
 
-	if (selected_cert) {
-		x509 = X509_dup(selected_cert->x509);
-	} else {
-		if (login) /* Only print the error on the second attempt */
-			ctx_log(ctx, 0, "Certificate not found.\n");
-		x509 = NULL;
-	}
 error:
 	/* Free the searched token data */
 	if (match_tok) {
@@ -618,363 +581,313 @@
 		OPENSSL_free(match_tok);
 	}
 
-	if (cert_label)
-		OPENSSL_free(cert_label);
+	if (obj_label)
+		OPENSSL_free(obj_label);
 	if (matched_slots)
 		free(matched_slots);
-	return x509;
+	return object;
 }
 
-static int ctx_ctrl_load_cert(ENGINE_CTX *ctx, void *p)
+static void *ctx_load_object(ENGINE_CTX *ctx,
+		const char *object_typestr,
+		void *(*match_func)(ENGINE_CTX *, PKCS11_TOKEN *,
+				const unsigned char *, size_t, const char *),
+		const char *object_uri, UI_METHOD *ui_method, void *callback_data)
 {
-	struct {
-		const char *s_slot_cert_id;
-		X509 *cert;
-	} *parms = p;
+	void *obj = NULL;
 
-	if (!parms) {
-		ENGerr(ENG_F_CTX_CTRL_LOAD_CERT, ERR_R_PASSED_NULL_PARAMETER);
-		return 0;
-	}
-	if (parms->cert) {
-		ENGerr(ENG_F_CTX_CTRL_LOAD_CERT, ENG_R_INVALID_PARAMETER);
-		return 0;
+	pthread_mutex_lock(&ctx->lock);
+
+	/* Delayed libp11 initialization */
+	if (ctx_init_libp11_unlocked(ctx)) {
+		ENGerr(ENG_F_CTX_LOAD_OBJECT, ENG_R_INVALID_PARAMETER);
+		pthread_mutex_unlock(&ctx->lock);
+		return NULL;
 	}
-	ERR_clear_error();
-	if (!ctx->force_login)
-		parms->cert = ctx_load_cert(ctx, parms->s_slot_cert_id, 0);
-	if (!parms->cert) { /* Try again with login */
+
+	if (!ctx->force_login) {
 		ERR_clear_error();
-		parms->cert = ctx_load_cert(ctx, parms->s_slot_cert_id, 1);
+		obj = ctx_try_load_object(ctx, object_typestr, match_func,
+			object_uri, 0, ui_method, callback_data);
 	}
-	if (!parms->cert) {
-		if (!ERR_peek_last_error())
-			ENGerr(ENG_F_CTX_CTRL_LOAD_CERT, ENG_R_OBJECT_NOT_FOUND);
-		return 0;
+
+	if (!obj) {
+		/* Try again with login */
+		ERR_clear_error();
+		obj = ctx_try_load_object(ctx, object_typestr, match_func,
+			object_uri, 1, ui_method, callback_data);
+		if (!obj) {
+			ctx_log(ctx, 0, "The %s was not found at: %s\n",
+				object_typestr, object_uri);
+		}
 	}
-	return 1;
+
+	pthread_mutex_unlock(&ctx->lock);
+	return obj;
 }
 
 /******************************************************************************/
-/* Private and public key handling                                            */
+/* Certificate handling                                                       */
 /******************************************************************************/
 
-static EVP_PKEY *ctx_load_key(ENGINE_CTX *ctx, const char *s_slot_key_id,
-		UI_METHOD *ui_method, void *callback_data,
-		const int isPrivate, const int login)
+static PKCS11_CERT *cert_cmp(PKCS11_CERT *a, PKCS11_CERT *b, time_t *ptime)
 {
-	PKCS11_SLOT *slot;
-	PKCS11_SLOT *found_slot = NULL, **matched_slots = NULL;
-	PKCS11_TOKEN *tok, *match_tok = NULL;
-	PKCS11_KEY *keys, *selected_key = NULL;
-	EVP_PKEY *pk = NULL;
-	unsigned int key_count, n, m;
-	unsigned char key_id[MAX_VALUE_LEN / 2];
-	size_t key_id_len = sizeof(key_id);
-	char *key_label = NULL;
-	int slot_nr = -1;
-	char tmp_pin[MAX_PIN_LENGTH+1];
-	size_t tmp_pin_len = MAX_PIN_LENGTH;
-	char flags[64];
-	size_t matched_count = 0;
+	const ASN1_TIME *a_time, *b_time;
+	int pday, psec;
 
-	if (ctx_init_libp11(ctx)) /* Delayed libp11 initialization */
-		goto error;
+	/* the best certificate exists */
+	if (!a || !a->x509) {
+		return b;
+	}
+	if (!b || !b->x509) {
+		return a;
+	}
 
-	ctx_log(ctx, 1, "Loading %s key \"%s\"\n",
-		(char *)(isPrivate ? "private" : "public"),
-		s_slot_key_id);
-	if (s_slot_key_id && *s_slot_key_id) {
-		if (!strncasecmp(s_slot_key_id, "pkcs11:", 7)) {
-			n = parse_pkcs11_uri(ctx, s_slot_key_id, &match_tok,
-				key_id, &key_id_len,
-				tmp_pin, &tmp_pin_len, &key_label);
-			if (!n) {
-				ctx_log(ctx, 0,
-					"The key ID is not a valid PKCS#11 URI\n"
-					"The PKCS#11 URI format is defined by RFC7512\n");
-				ENGerr(ENG_F_CTX_LOAD_KEY, ENG_R_INVALID_ID);
-				goto error;
-			}
-			if (tmp_pin_len > 0 && tmp_pin[0] != 0) {
-				/* If the searched key is public, try without login once even
-				 * when the PIN is provided */
-				if (!login && isPrivate)
-					goto error; /* Process on second attempt */
-				ctx_destroy_pin(ctx);
-				ctx->pin = OPENSSL_malloc(MAX_PIN_LENGTH+1);
-				if (ctx->pin) {
-					memset(ctx->pin, 0, MAX_PIN_LENGTH+1);
-					memcpy(ctx->pin, tmp_pin, tmp_pin_len);
-					ctx->pin_length = tmp_pin_len;
-				}
-			}
-		} else {
-			n = parse_slot_id_string(ctx, s_slot_key_id, &slot_nr,
-				key_id, &key_id_len, &key_label);
-			if (!n) {
-				ctx_log(ctx, 0,
-					"The key ID is not a valid PKCS#11 URI\n"
-					"The PKCS#11 URI format is defined by RFC7512\n"
-					"The legacy ENGINE_pkcs11 ID format is also "
-					"still accepted for now\n");
-				ENGerr(ENG_F_CTX_LOAD_KEY, ENG_R_INVALID_ID);
-				goto error;
-			}
-		}
-		ctx_log(ctx, 1, "Looking in slot %d for key: ",
-			slot_nr);
-		if (key_id_len != 0) {
-			ctx_log(ctx, 1, "id=");
-			dump_hex(ctx, 1, key_id, key_id_len);
+	a_time = X509_get0_notAfter(a->x509);
+	b_time = X509_get0_notAfter(b->x509);
+
+	/* the best certificate expires last */
+	if (ASN1_TIME_diff(&pday, &psec, a_time, b_time)) {
+		if (pday < 0 || psec < 0) {
+			return a;
+		} else if (pday > 0 || psec > 0) {
+			return b;
 		}
-		if (key_id_len != 0 && key_label)
-			ctx_log(ctx, 1, " ");
-		if (key_label)
-			ctx_log(ctx, 1, "label=%s", key_label);
-		ctx_log(ctx, 1, "\n");
 	}
 
-	matched_slots = (PKCS11_SLOT **)calloc(ctx->slot_count,
-		sizeof(PKCS11_SLOT *));
-	if (!matched_slots) {
-		ctx_log(ctx, 0, "Could not allocate memory for matched slots\n");
-		goto error;
+	/* deterministic tie break */
+	if (X509_cmp(a->x509, b->x509) < 1) {
+		return b;
+	} else {
+		return a;
 	}
+}
 
-	for (n = 0; n < ctx->slot_count; n++) {
-		slot = ctx->slot_list + n;
-		flags[0] = '\0';
-		if (slot->token) {
-			if (!slot->token->initialized)
-				strcat(flags, "uninitialized, ");
-			else if (!slot->token->userPinSet)
-				strcat(flags, "no pin, ");
-			if (slot->token->loginRequired)
-				strcat(flags, "login, ");
-			if (slot->token->readOnly)
-				strcat(flags, "ro, ");
-		} else {
-			strcpy(flags, "no token");
-		}
-		if ((m = strlen(flags)) != 0) {
-			flags[m - 2] = '\0';
-		}
+static void *match_cert(ENGINE_CTX *ctx, PKCS11_TOKEN *tok,
+		const unsigned char *obj_id, size_t obj_id_len, const char *obj_label)
+{
+	PKCS11_CERT *certs, *selected_cert = NULL;
+	unsigned int m, cert_count;
+	const char *which;
 
-		if (slot_nr != -1 &&
-			slot_nr == (int)PKCS11_get_slotid_from_slot(slot)) {
-			found_slot = slot;
-		}
+	if (PKCS11_enumerate_certs(tok, &certs, &cert_count)) {
+		ctx_log(ctx, 0, "Unable to enumerate certificates\n");
+		return NULL;
+	}
+	if (cert_count == 0)
+		return NULL;
 
-		if (match_tok && slot->token &&
-				(!match_tok->label ||
-					!strcmp(match_tok->label, slot->token->label)) &&
-				(!match_tok->manufacturer ||
-					!strcmp(match_tok->manufacturer, slot->token->manufacturer)) &&
-				(!match_tok->serialnr ||
-					!strcmp(match_tok->serialnr, slot->token->serialnr)) &&
-				(!match_tok->model ||
-					!strcmp(match_tok->model, slot->token->model))) {
-			found_slot = slot;
+	ctx_log(ctx, 1, "Found %u certificate%s:\n", cert_count, cert_count == 1 ? "" : "s");
+	if (obj_id_len != 0 || obj_label) {
+		which = "longest expiry matching";
+		for (m = 0; m < cert_count; m++) {
+			PKCS11_CERT *k = certs + m;
+
+			ctx_log(ctx, 1, "  %2u    id=", m + 1);
+			dump_hex(ctx, 1, k->id, k->id_len);
+			ctx_log(ctx, 1, " label=%s expiry=", k->label ? k->label : "(null)");
+			dump_expiry(ctx, 1, k);
+			ctx_log(ctx, 1, "\n");
+
+			if (obj_label && obj_id_len != 0) {
+				if (k->label && strcmp(k->label, obj_label) == 0 &&
+						k->id_len == obj_id_len &&
+						memcmp(k->id, obj_id, obj_id_len) == 0) {
+					selected_cert = cert_cmp(selected_cert, k, NULL);
+				}
+			} else if (obj_label && !obj_id_len) {
+				if (k->label && strcmp(k->label, obj_label) == 0) {
+					selected_cert = cert_cmp(selected_cert, k, NULL);
+				}
+			} else if (obj_id_len && !obj_label) {
+				if (k->id_len == obj_id_len &&
+						memcmp(k->id, obj_id, obj_id_len) == 0) {
+					selected_cert = cert_cmp(selected_cert, k, NULL);
+				}
+			}
 		}
-		ctx_log(ctx, 1, "[%lu] %-25.25s  %-16s",
-			PKCS11_get_slotid_from_slot(slot),
-			slot->description, flags);
-		if (slot->token) {
-			ctx_log(ctx, 1, "  (%s)",
-				slot->token->label[0] ?
-				slot->token->label : "no label");
+	} else {
+		which = "first (with id present)";
+		for (m = 0; m < cert_count; m++) {
+			PKCS11_CERT *k = certs + m;
+
+			ctx_log(ctx, 1, "  %2u    id=", m + 1);
+			dump_hex(ctx, 1, k->id, k->id_len);
+			ctx_log(ctx, 1, " label=%s expiry=", k->label ? k->label : "(null)");
+			dump_expiry(ctx, 1, k);
+			ctx_log(ctx, 1, "\n");
+
+			if (!selected_cert && k->id && *k->id) {
+				selected_cert = k; /* Use the first certificate with nonempty id */
+			}
+		}
+		if (!selected_cert) {
+			which = "first";
+			selected_cert = certs; /* Use the first certificate */
 		}
+	}
+
+	if (selected_cert) {
+		ctx_log(ctx, 1, "Returning %s certificate: id=", which);
+		dump_hex(ctx, 1, selected_cert->id, selected_cert->id_len);
+		ctx_log(ctx, 1, " label=%s expiry=", selected_cert->label ? selected_cert->label : "(null)");
+		dump_expiry(ctx, 1, selected_cert);
 		ctx_log(ctx, 1, "\n");
+	} else {
+		ctx_log(ctx, 1, "No matching certificate returned.\n");
+	}
 
-		if (found_slot && found_slot->token && !found_slot->token->initialized)
-			ctx_log(ctx, 0, "Found uninitialized token\n");
+	return selected_cert;
+}
 
-		/* Ignore slots without tokens or with uninitialized token */
-		if (found_slot && found_slot->token && found_slot->token->initialized) {
-			matched_slots[matched_count] = found_slot;
-			matched_count++;
-		}
-		found_slot = NULL;
-	}
+static int ctx_ctrl_load_cert(ENGINE_CTX *ctx, void *p)
+{
+	struct {
+		const char *s_slot_cert_id;
+		X509 *cert;
+	} *parms = p;
+	PKCS11_CERT *cert;
 
-	if (matched_count == 0) {
-		if (match_tok) {
-			ctx_log(ctx, 0, "Specified object not found\n");
-			goto error;
-		}
+	if (!parms) {
+		ENGerr(ENG_F_CTX_CTRL_LOAD_CERT, ERR_R_PASSED_NULL_PARAMETER);
+		return 0;
+	}
+	if (parms->cert) {
+		ENGerr(ENG_F_CTX_CTRL_LOAD_CERT, ENG_R_INVALID_PARAMETER);
+		return 0;
+	}
 
-		/* If the legacy slot ID format was used */
-		if (slot_nr != -1) {
-			ctx_log(ctx, 0, "Invalid slot number: %d\n", slot_nr);
-			goto error;
-		} else {
-			found_slot = PKCS11_find_token(ctx->pkcs11_ctx,
-								ctx->slot_list, ctx->slot_count);
-			/* Ignore if the the token is not initialized */
-			if (found_slot && found_slot->token &&
-					found_slot->token->initialized) {
-				matched_slots[matched_count] = found_slot;
-				matched_count++;
-			} else {
-				ctx_log(ctx, 0, "No tokens found\n");
-				goto error;
-			}
-		}
+	cert = ctx_load_object(ctx, "certificate", match_cert, parms->s_slot_cert_id,
+		ctx->ui_method, ctx->callback_data);
+	if (!cert) {
+		if (!ERR_peek_last_error())
+			ENGerr(ENG_F_CTX_CTRL_LOAD_CERT, ENG_R_OBJECT_NOT_FOUND);
+		return 0;
 	}
+	parms->cert = X509_dup(cert->x509);
+	return 1;
+}
 
-	for (n = 0; n < matched_count; n++) {
-		slot = matched_slots[n];
-		tok = slot->token;
-		if (!tok) {
-			ctx_log(ctx, 0, "Found empty token\n");
-			break;
-		}
+/******************************************************************************/
+/* Private and public key handling                                            */
+/******************************************************************************/
 
-		ctx_log(ctx, 1, "Found slot:  %s\n", slot->description);
-		ctx_log(ctx, 1, "Found token: %s\n", slot->token->label);
+static void *match_key(ENGINE_CTX *ctx, const char *key_type,
+		PKCS11_KEY *keys, unsigned int key_count,
+		const unsigned char *obj_id, size_t obj_id_len, const char *obj_label)
+{
+	PKCS11_KEY *selected_key = NULL;
+	unsigned int m;
+	const char *which;
 
-		/* Both private and public keys can have the CKA_PRIVATE attribute
-		 * set and thus require login (even to retrieve attributes!) */
-		if (login) {
-			/* Try to login only if login is required */
-			if (tok->loginRequired) {
-				/* Try to login only if a single slot matched to avoiding trying
-				 * the PIN against all matching slots */
-				if (matched_count == 1) {
-					if (!ctx_login(ctx, slot, tok, ui_method, callback_data)) {
-						ctx_log(ctx, 0, "Login to token failed, returning NULL...\n");
-						goto error;
-					}
-				} else {
-					ctx_log(ctx, 0, "Multiple matching slots (%lu); will not try to"
-						" login\n", matched_count);
-					for (m = 0; m < matched_count; m++){
-						slot = matched_slots[m];
-						ctx_log(ctx, 1, "[%u] %s: %s\n", m + 1,
-								slot->description? slot->description:
-								"(no description)",
-								(slot->token && slot->token->label)?
-								slot->token->label: "no label");
-					}
-					goto error;
-				}
-			}
-		}
+	if (key_count == 0)
+		return NULL;
 
-		if (isPrivate) {
-			/* Make sure there is at least one private key on the token */
-			if (PKCS11_enumerate_keys(tok, &keys, &key_count)) {
-				ctx_log(ctx, 0, "Unable to enumerate private keys\n");
-				continue;
-			}
-		} else {
-			/* Make sure there is at least one public key on the token */
-			if (PKCS11_enumerate_public_keys(tok, &keys, &key_count)) {
-				ctx_log(ctx, 0, "Unable to enumerate public keys\n");
-				continue;
-			}
-		}
-		if (key_count == 0) {
-			if (login) /* Only print the error on the second attempt */
-				ctx_log(ctx, 0, "No %s keys found.\n",
-						(char *)(isPrivate ? "private" : "public"));
-			continue;
-		}
-		ctx_log(ctx, 1, "Found %u %s key%s:\n", key_count,
-				(char *)(isPrivate ? "private" : "public"),
-				(key_count == 1) ? "" : "s");
-
-		if (s_slot_key_id && *s_slot_key_id && (key_id_len != 0 || key_label)) {
-			for (m = 0; m < key_count; m++) {
-				PKCS11_KEY *k = keys + m;
-
-				ctx_log(ctx, 1, "  %2u %c%c id=", m + 1,
-						k->isPrivate ? 'P' : ' ',
-						k->needLogin ? 'L' : ' ');
-				dump_hex(ctx, 1, k->id, k->id_len);
-				ctx_log(ctx, 1, " label=%s\n", k->label ? k->label : "(null)");
-				if (key_label && k->label && strcmp(k->label, key_label) == 0)
+	ctx_log(ctx, 1, "Found %u %s key%s:\n", key_count, key_type,
+		key_count == 1 ? "" : "s");
+
+	if (obj_id_len != 0 || obj_label) {
+		which = "last matching";
+		for (m = 0; m < key_count; m++) {
+			PKCS11_KEY *k = keys + m;
+
+			ctx_log(ctx, 1, "  %2u %c%c id=", m + 1,
+					k->isPrivate ? 'P' : ' ',
+					k->needLogin ? 'L' : ' ');
+			dump_hex(ctx, 1, k->id, k->id_len);
+			ctx_log(ctx, 1, " label=%s\n", k->label ? k->label : "(null)");
+
+			if (obj_label && obj_id_len != 0) {
+				if (k->label && strcmp(k->label, obj_label) == 0 &&
+						k->id_len == obj_id_len &&
+						memcmp(k->id, obj_id, obj_id_len) == 0) {
 					selected_key = k;
-				if (key_id_len != 0 && k->id_len == key_id_len
-						&& memcmp(k->id, key_id, key_id_len) == 0)
+				}
+			} else if (obj_label && !obj_id_len) {
+				if (k->label && strcmp(k->label, obj_label) == 0) {
+					selected_key = k;
+				}
+			} else if (obj_id_len && !obj_label) {
+				if (k->id_len == obj_id_len &&
+						memcmp(k->id, obj_id, obj_id_len) == 0) {
 					selected_key = k;
+				}
 			}
-		} else {
-			selected_key = keys; /* Use the first key */
-		}
-
-		if (selected_key) {
-			break;
 		}
+	} else {
+		which = "first";
+		selected_key = keys; /* Use the first key */
 	}
 
 	if (selected_key) {
-		pk = isPrivate ?
-			PKCS11_get_private_key(selected_key) :
-			PKCS11_get_public_key(selected_key);
+		ctx_log(ctx, 1, "Returning %s %s key: id=", which, key_type);
+		dump_hex(ctx, 1, selected_key->id, selected_key->id_len);
+		ctx_log(ctx, 1, " label=%s\n", selected_key->label ? selected_key->label : "(null)");
 	} else {
-		if (login) /* Only print the error on the second attempt */
-			ctx_log(ctx, 0, "Key not found.\n");
-		pk = NULL;
+		ctx_log(ctx, 1, "No matching %s key returned.\n", key_type);
 	}
 
-error:
-	/* Free the searched token data */
-	if (match_tok) {
-		OPENSSL_free(match_tok->model);
-		OPENSSL_free(match_tok->manufacturer);
-		OPENSSL_free(match_tok->serialnr);
-		OPENSSL_free(match_tok->label);
-		OPENSSL_free(match_tok);
+	return selected_key;
+}
+
+static void *match_public_key(ENGINE_CTX *ctx, PKCS11_TOKEN *tok,
+		const unsigned char *obj_id, size_t obj_id_len, const char *obj_label)
+{
+	PKCS11_KEY *keys;
+	unsigned int key_count;
+
+	/* Make sure there is at least one public key on the token */
+	if (PKCS11_enumerate_public_keys(tok, &keys, &key_count)) {
+		ctx_log(ctx, 0, "Unable to enumerate public keys\n");
+		return 0;
 	}
-	if (key_label)
-		OPENSSL_free(key_label);
-	if (matched_slots)
-		free(matched_slots);
-	return pk;
+	return match_key(ctx, "public", keys, key_count, obj_id, obj_id_len, obj_label);
+}
+
+static void *match_private_key(ENGINE_CTX *ctx, PKCS11_TOKEN *tok,
+		const unsigned char *obj_id, size_t obj_id_len, const char *obj_label)
+{
+	PKCS11_KEY *keys;
+	unsigned int key_count;
+
+	/* Make sure there is at least one private key on the token */
+	if (PKCS11_enumerate_keys(tok, &keys, &key_count)) {
+		ctx_log(ctx, 0, "Unable to enumerate private keys\n");
+		return 0;
+	}
+	return match_key(ctx, "private", keys, key_count, obj_id, obj_id_len, obj_label);
 }
 
 EVP_PKEY *ctx_load_pubkey(ENGINE_CTX *ctx, const char *s_key_id,
 		UI_METHOD *ui_method, void *callback_data)
 {
-	EVP_PKEY *pk = NULL;
+	PKCS11_KEY *key;
 
-	ERR_clear_error();
-	if (!ctx->force_login)
-		pk = ctx_load_key(ctx, s_key_id, ui_method, callback_data, 0, 0);
-	if (!pk) { /* Try again with login */
-		ERR_clear_error();
-		pk = ctx_load_key(ctx, s_key_id, ui_method, callback_data, 0, 1);
-	}
-	if (!pk) {
+	key = ctx_load_object(ctx, "public key", match_public_key, s_key_id,
+		ui_method, callback_data);
+	if (!key) {
 		ctx_log(ctx, 0, "PKCS11_load_public_key returned NULL\n");
 		if (!ERR_peek_last_error())
 			ENGerr(ENG_F_CTX_LOAD_PUBKEY, ENG_R_OBJECT_NOT_FOUND);
 		return NULL;
 	}
-	return pk;
+	return PKCS11_get_public_key(key);
 }
 
 EVP_PKEY *ctx_load_privkey(ENGINE_CTX *ctx, const char *s_key_id,
 		UI_METHOD *ui_method, void *callback_data)
 {
-	EVP_PKEY *pk = NULL;
+	PKCS11_KEY *key;
 
-	ERR_clear_error();
-	if (!ctx->force_login)
-		pk = ctx_load_key(ctx, s_key_id, ui_method, callback_data, 1, 0);
-	if (!pk) { /* Try again with login */
-		ERR_clear_error();
-		pk = ctx_load_key(ctx, s_key_id, ui_method, callback_data, 1, 1);
-	}
-	if (!pk) {
+	key = ctx_load_object(ctx, "private key", match_private_key, s_key_id,
+		ui_method, callback_data);
+	if (!key) {
 		ctx_log(ctx, 0, "PKCS11_get_private_key returned NULL\n");
 		if (!ERR_peek_last_error())
 			ENGerr(ENG_F_CTX_LOAD_PRIVKEY, ENG_R_OBJECT_NOT_FOUND);
 		return NULL;
 	}
-	return pk;
+	return PKCS11_get_private_key(key);
 }
 
 /******************************************************************************/
@@ -1020,6 +933,7 @@
 		return 0;
 	}
 	ctx->pin_length = strlen(ctx->pin);
+	ctx->forced_pin = 1;
 	return 1;
 }
 
@@ -1092,6 +1006,8 @@
 		return ctx_ctrl_set_callback_data(ctx, p);
 	case CMD_FORCE_LOGIN:
 		return ctx_ctrl_force_login(ctx);
+	case CMD_RE_ENUMERATE:
+		return ctx_enumerate_slots(ctx, ctx->pkcs11_ctx);
 	default:
 		ENGerr(ENG_F_CTX_ENGINE_CTRL, ENG_R_UNKNOWN_COMMAND);
 		break;
diff -Nru libp11-0.4.11/src/eng_err.h libp11-0.4.12/src/eng_err.h
--- libp11-0.4.11/src/eng_err.h	2018-02-20 08:52:07.000000000 +0100
+++ libp11-0.4.12/src/eng_err.h	2021-10-30 14:20:08.000000000 +0200
@@ -31,6 +31,7 @@
 # define ENG_F_CTX_CTRL_LOAD_CERT                         102
 # define ENG_F_CTX_CTRL_SET_PIN                           106
 # define ENG_F_CTX_ENGINE_CTRL                            105
+# define ENG_F_CTX_LOAD_OBJECT                            107
 # define ENG_F_CTX_LOAD_CERT                              100
 # define ENG_F_CTX_LOAD_KEY                               101
 # define ENG_F_CTX_LOAD_PRIVKEY                           103
diff -Nru libp11-0.4.11/src/eng_front.c libp11-0.4.12/src/eng_front.c
--- libp11-0.4.11/src/eng_front.c	2020-10-11 15:34:40.000000000 +0200
+++ libp11-0.4.12/src/eng_front.c	2021-10-30 14:20:08.000000000 +0200
@@ -75,6 +75,10 @@
 		"FORCE_LOGIN",
 		"Force login to the PKCS#11 module",
 		ENGINE_CMD_FLAG_NO_INPUT},
+	{CMD_RE_ENUMERATE,
+		"RE_ENUMERATE",
+		"re enumerate slots",
+		ENGINE_CMD_FLAG_NO_INPUT},
 	{0, NULL, NULL, 0}
 };
 
diff -Nru libp11-0.4.11/src/engine.h libp11-0.4.12/src/engine.h
--- libp11-0.4.11/src/engine.h	2018-08-03 07:57:27.000000000 +0200
+++ libp11-0.4.12/src/engine.h	2021-10-30 14:20:08.000000000 +0200
@@ -51,6 +51,7 @@
 #define CMD_SET_USER_INTERFACE	(ENGINE_CMD_BASE + 7)
 #define CMD_SET_CALLBACK_DATA	(ENGINE_CMD_BASE + 8)
 #define CMD_FORCE_LOGIN	(ENGINE_CMD_BASE+9)
+#define CMD_RE_ENUMERATE	(ENGINE_CMD_BASE+10)
 
 typedef struct st_engine_ctx ENGINE_CTX; /* opaque */
 
diff -Nru libp11-0.4.11/src/libp11.exports libp11-0.4.12/src/libp11.exports
--- libp11-0.4.11/src/libp11.exports	2018-08-05 13:11:37.000000000 +0200
+++ libp11-0.4.12/src/libp11.exports	2022-05-04 18:45:56.000000000 +0200
@@ -5,6 +5,7 @@
 PKCS11_CTX_free
 PKCS11_open_session
 PKCS11_enumerate_slots
+PKCS11_update_slots
 PKCS11_release_all_slots
 PKCS11_find_token
 PKCS11_find_next_token
diff -Nru libp11-0.4.11/src/libp11.h libp11-0.4.12/src/libp11.h
--- libp11-0.4.11/src/libp11.h	2018-08-09 07:17:07.000000000 +0200
+++ libp11-0.4.12/src/libp11.h	2022-05-04 18:45:56.000000000 +0200
@@ -60,7 +60,6 @@
 	size_t id_len;
 	unsigned char isPrivate;	/**< private key present? */
 	unsigned char needLogin;	/**< login to read private key? */
-	EVP_PKEY *evp_key;		/**< initially NULL, need to call PKCS11_load_key */
 	void *_private;
 } PKCS11_KEY;
 
@@ -93,7 +92,7 @@
 	unsigned char soPinFinalTry;
 	unsigned char soPinLocked;
 	unsigned char soPinToBeChanged;
-	void *_private;
+	struct PKCS11_slot_st *slot;
 } PKCS11_TOKEN;
 
 /** PKCS11 slot: card reader */
@@ -138,15 +137,6 @@
 extern int PKCS11_CTX_load(PKCS11_CTX * ctx, const char * ident);
 
 /**
- * Reinitialize a PKCS#11 module (after a fork)
- *
- * @param ctx context allocated by PKCS11_CTX_new()
- * @retval 0 success
- * @retval -1 error
- */
-extern int PKCS11_CTX_reload(PKCS11_CTX * ctx);
-
-/**
  * Unload a PKCS#11 module
  *
  * @param ctx context allocated by PKCS11_CTX_new()
@@ -182,6 +172,23 @@
 			PKCS11_SLOT **slotsp, unsigned int *nslotsp);
 
 /**
+ * Get or update a list of all slots
+ *
+ * The difference to PKCS11_enumerate_slots() is that this will
+ * expect as input previous slot list (or zero initialized count
+ * and null pointer) for the list. This function always reuses the
+ * slots found from the previous list to avoid unexpected slot
+ * and key object destructon.
+ * @param ctx context allocated by PKCS11_CTX_new()
+ * @param slotsp pointer on a list of slots
+ * @param nslotsp pointer to size of the allocated list
+ * @retval 0 success
+ * @retval -1 error
+ */
+extern int PKCS11_update_slots(PKCS11_CTX * ctx,
+			PKCS11_SLOT **slotsp, unsigned int *nslotsp);
+
+/**
  * Get the slot_id from a slot as it is stored in private
  *
  * @param slotp pointer on a slot
@@ -520,13 +527,14 @@
 # define CKR_F_PKCS11_PRIVATE_DECRYPT                     121
 # define CKR_F_PKCS11_PRIVATE_ENCRYPT                     122
 # define CKR_F_PKCS11_RELOAD_KEY                          123
-# define CKR_F_PKCS11_REOPEN_SESSION                      124
 # define CKR_F_PKCS11_SEED_RANDOM                         125
 # define CKR_F_PKCS11_STORE_CERTIFICATE                   126
 # define CKR_F_PKCS11_STORE_KEY                           127
 # define CKR_F_PKCS11_REMOVE_KEY                          128
 # define CKR_F_PKCS11_REMOVE_CERTIFICATE                  129
 # define CKR_F_PKCS11_GENERATE_KEY                        130
+# define CKR_F_PKCS11_RELOAD_CERTIFICATE                  131
+# define CKR_F_PKCS11_GET_SESSION                         132
 
 /* Backward compatibility of error function codes */
 #define PKCS11_F_PKCS11_CHANGE_PIN CKR_F_PKCS11_CHANGE_PIN
@@ -553,7 +561,6 @@
 #define PKCS11_F_PKCS11_PRIVATE_DECRYPT CKR_F_PKCS11_PRIVATE_DECRYPT
 #define PKCS11_F_PKCS11_PRIVATE_ENCRYPT CKR_F_PKCS11_PRIVATE_ENCRYPT
 #define PKCS11_F_PKCS11_RELOAD_KEY CKR_F_PKCS11_RELOAD_KEY
-#define PKCS11_F_PKCS11_REOPEN_SESSION CKR_F_PKCS11_REOPEN_SESSION
 #define PKCS11_F_PKCS11_SEED_RANDOM CKR_F_PKCS11_SEED_RANDOM
 #define PKCS11_F_PKCS11_STORE_CERTIFICATE CKR_F_PKCS11_STORE_CERTIFICATE
 #define PKCS11_F_PKCS11_STORE_KEY CKR_F_PKCS11_STORE_KEY
diff -Nru libp11-0.4.11/src/libp11-int.h libp11-0.4.12/src/libp11-int.h
--- libp11-0.4.11/src/libp11-int.h	2018-11-24 09:53:48.000000000 +0100
+++ libp11-0.4.12/src/libp11-int.h	2022-07-05 22:22:51.000000000 +0200
@@ -29,93 +29,81 @@
 #define CRYPTOKI_EXPORTS
 #include "pkcs11.h"
 
-#if OPENSSL_VERSION_NUMBER < 0x10100004L || defined(LIBRESSL_VERSION_NUMBER)
-typedef int PKCS11_RWLOCK;
-#else
-typedef CRYPTO_RWLOCK *PKCS11_RWLOCK;
-#endif
+#include "p11_pthread.h"
+
+/* forward and type declarations */
+typedef struct pkcs11_ctx_private PKCS11_CTX_private;
+typedef struct pkcs11_slot_private PKCS11_SLOT_private;
+typedef struct pkcs11_object_private PKCS11_OBJECT_private;
+typedef struct pkcs11_object_ops PKCS11_OBJECT_ops;
 
 /* get private implementations of PKCS11 structures */
 
 /*
  * PKCS11_CTX: context for a PKCS11 implementation
  */
-typedef struct pkcs11_ctx_private {
+struct pkcs11_ctx_private {
 	CK_FUNCTION_LIST_PTR method;
 	void *handle;
 	char *init_args;
 	UI_METHOD *ui_method; /* UI_METHOD for CKU_CONTEXT_SPECIFIC PINs */
 	void *ui_user_data;
 	unsigned int forkid;
-	PKCS11_RWLOCK rwlock;
-	int sign_initialized;
-	int decrypt_initialized;
-} PKCS11_CTX_private;
-#define PRIVCTX(ctx)		((PKCS11_CTX_private *) ((ctx)->_private))
-
-typedef struct pkcs11_slot_private {
-	PKCS11_CTX *parent;
-	unsigned char haveSession, loggedIn;
-	CK_SLOT_ID id;
-	CK_SESSION_HANDLE session;
-	unsigned int forkid;
-	int prev_rw; /* the rw status the session was open */
-
-	/* options used in last PKCS11_login */
-	char *prev_pin;
-	int prev_so;
-} PKCS11_SLOT_private;
-#define PRIVSLOT(slot)		((PKCS11_SLOT_private *) ((slot)->_private))
-#define SLOT2CTX(slot)		(PRIVSLOT(slot)->parent)
+	pthread_mutex_t fork_lock;
+};
+#define PRIVCTX(_ctx)		((PKCS11_CTX_private *) ((_ctx)->_private))
 
 typedef struct pkcs11_keys {
 	int num;
 	PKCS11_KEY *keys;
 } PKCS11_keys;
 
-typedef struct pkcs11_token_private {
-	PKCS11_SLOT *parent;
+struct pkcs11_slot_private {
+	int refcnt;
+	PKCS11_CTX_private *ctx;
+	pthread_mutex_t lock;
+	pthread_cond_t cond;
+	int8_t rw_mode, logged_in;
+	CK_SLOT_ID id;
+	CK_SESSION_HANDLE *session_pool;
+	unsigned int session_head, session_tail, session_poolsize;
+	unsigned int num_sessions, max_sessions;
+	unsigned int forkid;
+
+	/* options used in last PKCS11_login */
+	char *prev_pin;
+
+	/* members concerning the token */
+	CK_BBOOL secure_login;
 	PKCS11_keys prv, pub;
 	int ncerts;
 	PKCS11_CERT *certs;
-} PKCS11_TOKEN_private;
-#define PRIVTOKEN(token)	((PKCS11_TOKEN_private *) ((token)->_private))
-#define TOKEN2SLOT(token)	(PRIVTOKEN(token)->parent)
-#define TOKEN2CTX(token)	SLOT2CTX(TOKEN2SLOT(token))
-
-typedef struct pkcs11_key_ops {
-	int type; /* EVP_PKEY_xxx */
-	EVP_PKEY *(*get_evp_key) (PKCS11_KEY *);
-	void (*update_ex_data) (PKCS11_KEY *);
-} PKCS11_KEY_ops;
+};
+#define PRIVSLOT(_slot)		((PKCS11_SLOT_private *) ((_slot)->_private))
 
-typedef struct pkcs11_key_private {
-	PKCS11_TOKEN *parent;
+struct pkcs11_object_private {
+	PKCS11_SLOT_private *slot;
+	CK_OBJECT_CLASS object_class;
 	CK_OBJECT_HANDLE object;
 	CK_BBOOL always_authenticate;
 	unsigned char id[255];
 	size_t id_len;
-	PKCS11_KEY_ops *ops;
+	char *label;
+	PKCS11_OBJECT_ops *ops;
+	EVP_PKEY *evp_key;
+	X509 *x509;
 	unsigned int forkid;
-} PKCS11_KEY_private;
-#define PRIVKEY(key)		((PKCS11_KEY_private *) (key)->_private)
-#define KEY2SLOT(key)		TOKEN2SLOT(KEY2TOKEN(key))
-#define KEY2TOKEN(key)		(PRIVKEY(key)->parent)
-#define KEY2CTX(key)		TOKEN2CTX(KEY2TOKEN(key))
+};
+#define PRIVKEY(_key)		((PKCS11_OBJECT_private *) (_key)->_private)
+#define PRIVCERT(_cert)		((PKCS11_OBJECT_private *) (_cert)->_private)
+
+struct pkcs11_object_ops {
+	int pkey_type; /* EVP_PKEY_xxx */
+	EVP_PKEY *(*get_evp_key) (PKCS11_OBJECT_private *);
+};
 
-typedef struct pkcs11_cert_private {
-	PKCS11_TOKEN *parent;
-	CK_OBJECT_HANDLE object;
-	unsigned char id[255];
-	size_t id_len;
-} PKCS11_CERT_private;
-#define PRIVCERT(cert)		((PKCS11_CERT_private *) (cert)->_private)
-#define CERT2SLOT(cert)		TOKEN2SLOT(CERT2TOKEN(cert))
-#define CERT2TOKEN(cert)	(PRIVCERT(cert)->parent)
-#define CERT2CTX(cert)		TOKEN2CTX(CERT2TOKEN(cert))
-
-extern PKCS11_KEY_ops pkcs11_rsa_ops;
-extern PKCS11_KEY_ops *pkcs11_ec_ops;
+extern PKCS11_OBJECT_ops pkcs11_rsa_ops;
+extern PKCS11_OBJECT_ops pkcs11_ec_ops;
 
 /*
  * Internal functions
@@ -129,7 +117,7 @@
 		ERR_clear_error(); \
 	} while (0)
 #define CRYPTOKI_call(ctx, func_and_args) \
-	PRIVCTX(ctx)->method->func_and_args
+	ctx->method->func_and_args
 extern int ERR_load_CKR_strings(void);
 
 /* Memory allocation */
@@ -137,239 +125,229 @@
 	pkcs11_strdup((char *) s, sizeof(s))
 extern char *pkcs11_strdup(char *, size_t);
 
-/* Emulate the OpenSSL 1.1 locking API for older OpenSSL versions */
-#if OPENSSL_VERSION_NUMBER < 0x10100004L || defined(LIBRESSL_VERSION_NUMBER)
-int CRYPTO_THREAD_lock_new();
-void CRYPTO_THREAD_lock_free(int);
-#define CRYPTO_THREAD_write_lock(type) \
-	if(type) CRYPTO_lock(CRYPTO_LOCK|CRYPTO_WRITE,type,__FILE__,__LINE__)
-#define CRYPTO_THREAD_unlock(type) \
-	if(type) CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_WRITE,type,__FILE__,__LINE__)
-#define CRYPTO_THREAD_read_lock(type) \
-	if(type) CRYPTO_lock(CRYPTO_LOCK|CRYPTO_READ,type,__FILE__,__LINE__)
-#define CRYPTO_THREAD_read_unlock(type) \
-	if(type) CRYPTO_lock(CRYPTO_UNLOCK|CRYPTO_READ,type,__FILE__,__LINE__)
-#endif
-
 /* Emulate the OpenSSL 1.1 getters */
-#if OPENSSL_VERSION_NUMBER < 0x10100003L || defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER < 0x10100003L || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3000000L )
 #define EVP_PKEY_get0_RSA(key) ((key)->pkey.rsa)
 #define EVP_PKEY_get0_EC_KEY(key) ((key)->pkey.ec)
 #endif
 
-/* Reinitializing the module afer fork (if detected) */
+/* Reinitializing the module after fork (if detected) */
 extern unsigned int get_forkid();
-extern int check_fork(PKCS11_CTX *ctx);
-extern int check_slot_fork(PKCS11_SLOT *slot);
-extern int check_token_fork(PKCS11_TOKEN *token);
-extern int check_key_fork(PKCS11_KEY *key);
-extern int check_cert_fork(PKCS11_CERT *cert);
+extern int check_fork(PKCS11_CTX_private *ctx);
+extern int check_slot_fork(PKCS11_SLOT_private *slot);
+extern int check_object_fork(PKCS11_OBJECT_private *key);
 
 /* Other internal functions */
 extern void *C_LoadModule(const char *name, CK_FUNCTION_LIST_PTR_PTR);
 extern CK_RV C_UnloadModule(void *module);
-extern void pkcs11_destroy_keys(PKCS11_TOKEN *, unsigned int);
-extern void pkcs11_destroy_certs(PKCS11_TOKEN *);
-extern int pkcs11_reload_key(PKCS11_KEY *);
-extern int pkcs11_reopen_session(PKCS11_SLOT * slot);
-extern int pkcs11_relogin(PKCS11_SLOT * slot);
+extern void pkcs11_destroy_keys(PKCS11_SLOT_private *, unsigned int);
+extern void pkcs11_destroy_certs(PKCS11_SLOT_private *);
+extern int pkcs11_reload_object(PKCS11_OBJECT_private *);
+extern int pkcs11_reload_slot(PKCS11_SLOT_private *);
 
 /* Managing object attributes */
-extern int pkcs11_getattr_var(PKCS11_TOKEN *, CK_OBJECT_HANDLE,
-	unsigned int, CK_BYTE *, size_t *);
-extern int pkcs11_getattr_val(PKCS11_TOKEN *, CK_OBJECT_HANDLE,
-	unsigned int, void *, size_t);
-extern int pkcs11_getattr_alloc(PKCS11_TOKEN *, CK_OBJECT_HANDLE,
-	unsigned int, CK_BYTE **, size_t *);
+extern int pkcs11_getattr_var(PKCS11_CTX_private *, CK_SESSION_HANDLE, CK_OBJECT_HANDLE,
+	CK_ATTRIBUTE_TYPE, CK_BYTE *, size_t *);
+extern int pkcs11_getattr_val(PKCS11_CTX_private *, CK_SESSION_HANDLE, CK_OBJECT_HANDLE,
+	CK_ATTRIBUTE_TYPE, void *, size_t);
+extern int pkcs11_getattr_alloc(PKCS11_CTX_private *, CK_SESSION_HANDLE, CK_OBJECT_HANDLE,
+	CK_ATTRIBUTE_TYPE, CK_BYTE **, size_t *);
 /*
  * Caution: the BIGNUM ** shall reference either a NULL pointer or a
  * pointer to a valid BIGNUM.
  */
-extern int pkcs11_getattr_bn(PKCS11_TOKEN *, CK_OBJECT_HANDLE,
-	unsigned int, BIGNUM **);
-
-#define key_getattr_var(key, t, p, s) \
-	pkcs11_getattr_var(KEY2TOKEN((key)), PRIVKEY((key))->object, (t), (p), (s))
+extern int pkcs11_getattr_bn(PKCS11_CTX_private *, CK_SESSION_HANDLE, CK_OBJECT_HANDLE,
+	CK_ATTRIBUTE_TYPE, BIGNUM **);
 
-#define key_getattr_val(key, t, p, s) \
-	pkcs11_getattr_val(KEY2TOKEN((key)), PRIVKEY((key))->object, (t), (p), (s))
-
-#define key_getattr_alloc(key, t, p, s) \
-	pkcs11_getattr_alloc(KEY2TOKEN((key)), PRIVKEY((key))->object, (t), (p), (s))
-
-/*
- * Caution: bn shall reference either a NULL pointer or a pointer to
- * a valid BIGNUM.
- */
-#define key_getattr_bn(key, t, bn) \
-	pkcs11_getattr_bn(KEY2TOKEN((key)), PRIVKEY((key))->object, (t), (bn))
+typedef struct pkcs11_template_st {
+	unsigned long allocated;
+	unsigned int nattr;
+	CK_ATTRIBUTE attrs[32];
+} PKCS11_TEMPLATE;
 
 typedef int (*pkcs11_i2d_fn) (void *, unsigned char **);
-extern void pkcs11_addattr(CK_ATTRIBUTE_PTR, int, const void *, size_t);
-extern void pkcs11_addattr_int(CK_ATTRIBUTE_PTR, int, unsigned long);
-extern void pkcs11_addattr_bool(CK_ATTRIBUTE_PTR, int, int);
-extern void pkcs11_addattr_s(CK_ATTRIBUTE_PTR, int, const char *);
-extern void pkcs11_addattr_bn(CK_ATTRIBUTE_PTR, int, const BIGNUM *);
-extern void pkcs11_addattr_obj(CK_ATTRIBUTE_PTR, int, pkcs11_i2d_fn, void *);
-extern void pkcs11_zap_attrs(CK_ATTRIBUTE_PTR, unsigned int);
+extern unsigned int pkcs11_addattr(PKCS11_TEMPLATE *, int, void *, size_t);
+#define pkcs11_addattr_var(_tmpl, _type, _var) pkcs11_addattr(_tmpl, _type, &(_var), sizeof(_var))
+extern void pkcs11_addattr_bool(PKCS11_TEMPLATE *, int, int);
+extern void pkcs11_addattr_s(PKCS11_TEMPLATE *, int, const char *);
+extern void pkcs11_addattr_bn(PKCS11_TEMPLATE *, int, const BIGNUM *);
+extern void pkcs11_addattr_obj(PKCS11_TEMPLATE *, int, pkcs11_i2d_fn, void *);
+extern void pkcs11_zap_attrs(PKCS11_TEMPLATE *);
 
 /* Internal implementation of current features */
 
+/* Atomic reference counting */
+extern int pkcs11_atomic_add(int *, int, pthread_mutex_t *);
+
 /* Allocate the context */
 extern PKCS11_CTX *pkcs11_CTX_new(void);
 
 /* Specify any private PKCS#11 module initialization args, if necessary */
-extern void pkcs11_CTX_init_args(PKCS11_CTX * ctx, const char * init_args);
+extern void pkcs11_CTX_init_args(PKCS11_CTX *ctx, const char *init_args);
 
 /* Load a PKCS#11 module */
-extern int pkcs11_CTX_load(PKCS11_CTX * ctx, const char * ident);
+extern int pkcs11_CTX_load(PKCS11_CTX *ctx, const char *ident);
 
 /* Reinitialize a PKCS#11 module (after a fork) */
-extern int pkcs11_CTX_reload(PKCS11_CTX * ctx);
+extern int pkcs11_CTX_reload(PKCS11_CTX_private *ctx);
 
 /* Unload a PKCS#11 module */
-extern void pkcs11_CTX_unload(PKCS11_CTX * ctx);
+extern void pkcs11_CTX_unload(PKCS11_CTX *ctx);
 
 /* Free a libp11 context */
-extern void pkcs11_CTX_free(PKCS11_CTX * ctx);
+extern void pkcs11_CTX_free(PKCS11_CTX *ctx);
 
 /* Open a session in RO or RW mode */
-extern int pkcs11_open_session(PKCS11_SLOT * slot, int rw, int relogin);
+extern int pkcs11_open_session(PKCS11_SLOT_private *, int rw);
+
+/* Acquire a session from the slot specific session pool */
+extern int pkcs11_get_session(PKCS11_SLOT_private *, int rw, CK_SESSION_HANDLE *sessionp);
+
+/* Return a session the the slot specific session pool */
+extern void pkcs11_put_session(PKCS11_SLOT_private *, CK_SESSION_HANDLE session);
 
 /* Get a list of all slots */
-extern int pkcs11_enumerate_slots(PKCS11_CTX * ctx,
+extern int pkcs11_enumerate_slots(PKCS11_CTX_private * ctx,
 			PKCS11_SLOT **slotsp, unsigned int *nslotsp);
 
 /* Get the slot_id from a slot as it is stored in private */
-extern unsigned long pkcs11_get_slotid_from_slot(PKCS11_SLOT *slot);
+extern unsigned long pkcs11_get_slotid_from_slot(PKCS11_SLOT_private *);
+
+/* Increment slot reference count */
+extern PKCS11_SLOT_private *pkcs11_slot_ref(PKCS11_SLOT_private *slot);
+
+/* Decrement slot reference count, free if it becomes zero */
+extern void pkcs11_slot_unref(PKCS11_SLOT_private *slot);
 
 /* Free the list of slots allocated by PKCS11_enumerate_slots() */
-extern void pkcs11_release_all_slots(PKCS11_CTX * ctx,
-			PKCS11_SLOT *slots, unsigned int nslots);
+extern void pkcs11_release_all_slots(PKCS11_SLOT *slots, unsigned int nslots);
 
-/* Find the first slot with a token */
-extern PKCS11_SLOT *pkcs11_find_token(PKCS11_CTX * ctx,
-			PKCS11_SLOT *slots, unsigned int nslots);
-
-/* Find the next slot with a token */
-extern PKCS11_SLOT *pkcs11_find_next_token(PKCS11_CTX * ctx,
-			PKCS11_SLOT *slots, unsigned int nslots,
-			PKCS11_SLOT *current);
+/* Refresh the slot's token status */
+extern int pkcs11_refresh_token(PKCS11_SLOT *slot);
 
 /* Check if user is already authenticated to a card */
-extern int pkcs11_is_logged_in(PKCS11_SLOT * slot, int so, int * res);
+extern int pkcs11_is_logged_in(PKCS11_SLOT_private *, int so, int *res);
 
 /* Authenticate to the card */
-extern int pkcs11_login(PKCS11_SLOT * slot, int so, const char *pin, int relogin);
+extern int pkcs11_login(PKCS11_SLOT_private *, int so, const char *pin);
 
 /* De-authenticate from the card */
-extern int pkcs11_logout(PKCS11_SLOT * slot);
+extern int pkcs11_logout(PKCS11_SLOT_private *);
 
 /* Authenticate a private the key operation if needed */
-int pkcs11_authenticate(PKCS11_KEY *key);
+int pkcs11_authenticate(PKCS11_OBJECT_private *key, CK_SESSION_HANDLE session);
 
 /* Get a list of keys associated with this token */
-extern int pkcs11_enumerate_keys(PKCS11_TOKEN *token, unsigned int type,
+extern int pkcs11_enumerate_keys(PKCS11_SLOT_private *, unsigned int type,
 	PKCS11_KEY **keys, unsigned int *nkeys);
 
-/* Remove a key from the token */
-extern int pkcs11_remove_key(PKCS11_KEY *key);
+/* Create an object from a handle */
+extern PKCS11_OBJECT_private *pkcs11_object_from_handle(PKCS11_SLOT_private *slot,
+	CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object);
+
+/* Get an object based on template */
+extern PKCS11_OBJECT_private *pkcs11_object_from_template(PKCS11_SLOT_private *slot,
+	CK_SESSION_HANDLE session, PKCS11_TEMPLATE *tmpl);
+
+/* Get the corresponding object (same ID, given different object type) */
+extern PKCS11_OBJECT_private *pkcs11_object_from_object(PKCS11_OBJECT_private *obj,
+	CK_SESSION_HANDLE session, CK_OBJECT_CLASS object_class);
+
+/* Free an object */
+extern void pkcs11_object_free(PKCS11_OBJECT_private *obj);
 
 /* Get the key type (as EVP_PKEY_XXX) */
-extern int pkcs11_get_key_type(PKCS11_KEY *key);
+extern int pkcs11_get_key_type(PKCS11_OBJECT_private *key);
 
-/* Returns a EVP_PKEY object with the private or public key */
-extern EVP_PKEY *pkcs11_get_key(PKCS11_KEY *key, int isPrivate);
+/* Returns a EVP_PKEY object with the given key type */
+extern EVP_PKEY *pkcs11_get_key(PKCS11_OBJECT_private *key, CK_OBJECT_CLASS obj_class);
 
 /* Find the corresponding certificate (if any) */
-extern PKCS11_CERT *pkcs11_find_certificate(PKCS11_KEY *key);
+extern PKCS11_CERT *pkcs11_find_certificate(PKCS11_OBJECT_private *key);
 
 /* Find the corresponding key (if any) */
-extern PKCS11_KEY *pkcs11_find_key(PKCS11_CERT *cert);
-
-/* Find the corresponding key (if any)  pub <-> priv base on ID */
-extern PKCS11_KEY *pkcs11_find_key_from_key(PKCS11_KEY *key);
+extern PKCS11_KEY *pkcs11_find_key(PKCS11_OBJECT_private *cert);
 
 /* Get a list of all certificates associated with this token */
-extern int pkcs11_enumerate_certs(PKCS11_TOKEN *token,
+extern int pkcs11_enumerate_certs(PKCS11_SLOT_private *,
 	PKCS11_CERT **certs, unsigned int *ncerts);
 
-/* Remove a certificate from the token */
-extern int pkcs11_remove_certificate(PKCS11_CERT *key);
+/* Remove an object from the token */
+extern int pkcs11_remove_object(PKCS11_OBJECT_private *object);
 
 /* Set UI method to allow retrieving CKU_CONTEXT_SPECIFIC PINs interactively */
-extern int pkcs11_set_ui_method(PKCS11_CTX *ctx,
+extern int pkcs11_set_ui_method(PKCS11_CTX_private *ctx,
 	UI_METHOD *ui_method, void *ui_user_data);
 
 /* Initialize a token */
-extern int pkcs11_init_token(PKCS11_TOKEN * token, const char *pin,
+extern int pkcs11_init_token(PKCS11_SLOT_private *, const char *pin,
 	const char *label);
 
 /* Initialize the user PIN on a token */
-extern int pkcs11_init_pin(PKCS11_TOKEN * token, const char *pin);
+extern int pkcs11_init_pin(PKCS11_SLOT_private *, const char *pin);
 
 /* Change the user PIN on a token */
-extern int pkcs11_change_pin(PKCS11_SLOT * slot,
+extern int pkcs11_change_pin(PKCS11_SLOT_private *,
 	const char *old_pin, const char *new_pin);
 
 /* Store private key on a token */
-extern int pkcs11_store_private_key(PKCS11_TOKEN * token,
-	EVP_PKEY * pk, char *label, unsigned char *id, size_t id_len);
+extern int pkcs11_store_private_key(PKCS11_SLOT_private *,
+	EVP_PKEY *pk, char *label, unsigned char *id, size_t id_len);
 
 /* Store public key on a token */
-extern int pkcs11_store_public_key(PKCS11_TOKEN * token,
-	EVP_PKEY * pk, char *label, unsigned char *id, size_t id_len);
+extern int pkcs11_store_public_key(PKCS11_SLOT_private *,
+	EVP_PKEY *pk, char *label, unsigned char *id, size_t id_len);
 
 /* Store certificate on a token */
-extern int pkcs11_store_certificate(PKCS11_TOKEN * token, X509 * x509,
+extern int pkcs11_store_certificate(PKCS11_SLOT_private *, X509 * x509,
 		char *label, unsigned char *id, size_t id_len,
 		PKCS11_CERT **ret_cert);
 
 /* Access the random number generator */
-extern int pkcs11_seed_random(PKCS11_SLOT *, const unsigned char *s, unsigned int s_len);
-extern int pkcs11_generate_random(PKCS11_SLOT *, unsigned char *r, unsigned int r_len);
+extern int pkcs11_seed_random(PKCS11_SLOT_private *, const unsigned char *s, unsigned int s_len);
+extern int pkcs11_generate_random(PKCS11_SLOT_private *, unsigned char *r, unsigned int r_len);
 
 /* Internal implementation of deprecated features */
 
 /* Generate and store a private key on the token */
-extern int pkcs11_generate_key(PKCS11_TOKEN * token,
+extern int pkcs11_generate_key(PKCS11_SLOT_private *tpriv,
 	int algorithm, unsigned int bits,
 	char *label, unsigned char* id, size_t id_len);
 
 /* Get the RSA key modulus size (in bytes) */
-extern int pkcs11_get_key_size(PKCS11_KEY *);
+extern int pkcs11_get_key_size(PKCS11_OBJECT_private *);
 
 /* Get the RSA key modules as BIGNUM */
-extern int pkcs11_get_key_modulus(PKCS11_KEY *, BIGNUM **);
+extern int pkcs11_get_key_modulus(PKCS11_OBJECT_private *, BIGNUM **);
 
 /* Get the RSA key public exponent as BIGNUM */
-extern int pkcs11_get_key_exponent(PKCS11_KEY *, BIGNUM **);
+extern int pkcs11_get_key_exponent(PKCS11_OBJECT_private *, BIGNUM **);
 
 /* Sign with the RSA private key */
 extern int pkcs11_sign(int type,
 	const unsigned char *m, unsigned int m_len,
-	unsigned char *sigret, unsigned int *siglen, PKCS11_KEY * key);
+	unsigned char *sigret, unsigned int *siglen, PKCS11_OBJECT_private *key);
 
 /* This function has never been implemented */
 extern int pkcs11_verify(int type,
 	const unsigned char *m, unsigned int m_len,
-	unsigned char *signature, unsigned int siglen, PKCS11_KEY * key);
+	unsigned char *signature, unsigned int siglen, PKCS11_OBJECT_private *key);
 
 /* Encrypts data using the private key */
 extern int pkcs11_private_encrypt(
 	int flen, const unsigned char *from,
-	unsigned char *to, PKCS11_KEY * rsa, int padding);
+	unsigned char *to, PKCS11_OBJECT_private *rsa, int padding);
 
 /* Decrypts data using the private key */
 extern int pkcs11_private_decrypt(
 	int flen, const unsigned char *from,
-	unsigned char *to, PKCS11_KEY * key, int padding);
+	unsigned char *to, PKCS11_OBJECT_private *key, int padding);
 
 /* Retrieve PKCS11_KEY from an RSA key */
-extern PKCS11_KEY *pkcs11_get_ex_data_rsa(const RSA *rsa);
+extern PKCS11_OBJECT_private *pkcs11_get_ex_data_rsa(const RSA *rsa);
 
 /* Retrieve PKCS11_KEY from an EC_KEY */
-extern PKCS11_KEY *pkcs11_get_ex_data_ec(const EC_KEY *ec);
+extern PKCS11_OBJECT_private *pkcs11_get_ex_data_ec(const EC_KEY *ec);
 
 #endif
 
diff -Nru libp11-0.4.11/src/libp11.rc libp11-0.4.12/src/libp11.rc
--- libp11-0.4.11/src/libp11.rc	2020-10-11 17:18:12.000000000 +0200
+++ libp11-0.4.12/src/libp11.rc	2022-07-15 21:56:30.000000000 +0200
@@ -1,8 +1,8 @@
 #include <winresrc.h>
 
 VS_VERSION_INFO VERSIONINFO
-	FILEVERSION 7,4,3,0
-	PRODUCTVERSION 0,4,11,0
+	FILEVERSION 8,5,0,0
+	PRODUCTVERSION 0,4,12,0
 	FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
 	FILEFLAGS 0x21L
@@ -20,14 +20,14 @@
 			VALUE "Comments", "Provided under the terms of the GNU General Public License (LGPLv2.1+).\0"
 			VALUE "CompanyName", "OpenSC Project\0"
 			VALUE "FileDescription", "PKCS#11 access library\0"
-			VALUE "FileVersion", "7.4.3.0\0"
+			VALUE "FileVersion", "8.5.0.0\0"
 			VALUE "InternalName", "libp11\0"
 			VALUE "LegalCopyright", "OpenSC Project\0"
 			VALUE "LegalTrademarks", "\0"
 			VALUE "OriginalFilename", "libp11-3.dll\0"
 			VALUE "PrivateBuild", "\0"
 			VALUE "ProductName", "libp11\0"
-			VALUE "ProductVersion", "0.4.11.0\0"
+			VALUE "ProductVersion", "0.4.12.0\0"
 			VALUE "SpecialBuild", "\0"
 		END
 	END
diff -Nru libp11-0.4.11/src/Makefile.am libp11-0.4.12/src/Makefile.am
--- libp11-0.4.11/src/Makefile.am	2018-08-29 23:42:21.000000000 +0200
+++ libp11-0.4.12/src/Makefile.am	2022-03-15 18:13:43.000000000 +0100
@@ -4,7 +4,7 @@
 CLEANFILES = libp11.pc
 EXTRA_DIST = Makefile.mak libp11.rc.in pkcs11.rc.in
 
-noinst_HEADERS= libp11-int.h pkcs11.h
+noinst_HEADERS= libp11-int.h pkcs11.h p11_pthread.h
 include_HEADERS= libp11.h p11_err.h
 lib_LTLIBRARIES = libp11.la
 enginesexec_LTLIBRARIES = pkcs11.la
diff -Nru libp11-0.4.11/src/Makefile.in libp11-0.4.12/src/Makefile.in
--- libp11-0.4.11/src/Makefile.in	2020-10-11 15:46:57.000000000 +0200
+++ libp11-0.4.12/src/Makefile.in	2022-07-15 21:56:27.000000000 +0200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.2 from Makefile.am.
+# Makefile.in generated by automake 1.16.4 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -90,6 +90,7 @@
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
+target_triplet = @target@
 @WIN32_TRUE at am__append_1 = libp11.rc
 @HAVE_LD_VERSION_SCRIPT_TRUE at am__append_2 = -Wl,--version-script=libp11.map
 @HAVE_LD_VERSION_SCRIPT_TRUE@@WIN32_TRUE at am__append_3 = -export-symbols "$(srcdir)/libp11.exports"
@@ -97,7 +98,8 @@
 @WIN32_TRUE at am__append_5 = pkcs11.rc
 subdir = src
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/ld-version-script.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_pthread.m4 \
+	$(top_srcdir)/m4/ld-version-script.m4 \
 	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
 	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
 	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
@@ -253,8 +255,6 @@
   unique=`for i in $$list; do \
     if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
   done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
 am__DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/config.h.in \
 	$(srcdir)/libp11.pc.in $(srcdir)/libp11.rc.in \
 	$(srcdir)/pkcs11.rc.in $(top_srcdir)/depcomp
@@ -273,6 +273,8 @@
 CFLAGS = @CFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
@@ -284,6 +286,7 @@
 ECHO_N = @ECHO_N@
 ECHO_T = @ECHO_T@
 EGREP = @EGREP@
+ETAGS = @ETAGS@
 EXEEXT = @EXEEXT@
 FGREP = @FGREP@
 GREP = @GREP@
@@ -330,6 +333,10 @@
 PKG_CONFIG = @PKG_CONFIG@
 PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
 PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_CXX = @PTHREAD_CXX@
+PTHREAD_LIBS = @PTHREAD_LIBS@
 RANLIB = @RANLIB@
 RC = @RC@
 SED = @SED@
@@ -352,6 +359,7 @@
 am__tar = @am__tar@
 am__untar = @am__untar@
 apidocdir = @apidocdir@
+ax_pthread_config = @ax_pthread_config@
 bindir = @bindir@
 build = @build@
 build_alias = @build_alias@
@@ -391,7 +399,11 @@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
 sysconfdir = @sysconfdir@
+target = @target@
 target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
@@ -399,7 +411,7 @@
 DISTCLEANFILES = libp11.map
 CLEANFILES = libp11.pc
 EXTRA_DIST = Makefile.mak libp11.rc.in pkcs11.rc.in
-noinst_HEADERS = libp11-int.h pkcs11.h
+noinst_HEADERS = libp11-int.h pkcs11.h p11_pthread.h
 include_HEADERS = libp11.h p11_err.h
 lib_LTLIBRARIES = libp11.la
 enginesexec_LTLIBRARIES = pkcs11.la
@@ -865,7 +877,6 @@
 
 distclean-tags:
 	-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
-
 distdir: $(BUILT_SOURCES)
 	$(MAKE) $(AM_MAKEFLAGS) distdir-am
 
diff -Nru libp11-0.4.11/src/p11_atfork.c libp11-0.4.12/src/p11_atfork.c
--- libp11-0.4.11/src/p11_atfork.c	2020-02-27 06:50:01.000000000 +0100
+++ libp11-0.4.12/src/p11_atfork.c	2022-05-04 18:45:56.000000000 +0200
@@ -23,81 +23,67 @@
 #include "libp11-int.h"
 
 #ifndef _WIN32
-#include <unistd.h>
-
-#ifndef __STDC_VERSION__
-/* older than C90 */
-#define inline
-#endif /* __STDC_VERSION__ */
-
-#ifdef HAVE___REGISTER_ATFORK
-
-#ifdef __sun
-#pragma fini(lib_deinit)
-#pragma init(lib_init)
-#define _CONSTRUCTOR
-#define _DESTRUCTOR
-#else /* __sun */
-#define _CONSTRUCTOR __attribute__((constructor))
-#define _DESTRUCTOR __attribute__((destructor))
-#endif /* __sun */
 
 static unsigned int P11_forkid = 0;
 
-inline static unsigned int _P11_get_forkid(void)
-{
-	return P11_forkid;
-}
+#ifdef HAVE_PTHREAD
 
-inline static int _P11_detect_fork(unsigned int forkid)
-{
-	if (forkid == P11_forkid)
-		return 0;
-	return 1;
-}
+#include <pthread.h>
 
-static void fork_handler(void)
+static void _P11_atfork_child(void)
 {
 	P11_forkid++;
 }
 
-extern int __register_atfork(void (*)(void), void(*)(void), void (*)(void), void *);
-extern void *__dso_handle;
-
-_CONSTRUCTOR
+__attribute__((constructor))
 int _P11_register_fork_handler(void)
 {
-	if (__register_atfork(0, 0, fork_handler, __dso_handle) != 0)
+	if (pthread_atfork(0, 0, _P11_atfork_child) != 0)
 		return -1;
 	return 0;
 }
 
-#else /* HAVE___REGISTER_ATFORK */
-
-inline static unsigned int _P11_get_forkid(void)
+static unsigned int  _P11_update_forkid(void)
 {
-	return getpid();
+	return P11_forkid;
 }
 
-inline static int _P11_detect_fork(unsigned int forkid)
+#else /* HAVE_PTHREAD */
+
+#include <unistd.h>
+
+static unsigned int _P11_update_forkid(void)
 {
-	if (getpid() == forkid)
-		return 0;
-	return 1;
+	P11_forkid = (unsigned int)getpid();
+	return P11_forkid;
 }
 
-#endif /* HAVE___REGISTER_ATFORK */
+#endif /* HAVE_PTHREAD */
+
+#define CHECK_FORKID(ctx, forkid, function_call) \
+	do { \
+		int rv = 0; \
+		_P11_update_forkid(); \
+		if (forkid != P11_forkid) { \
+			pthread_mutex_lock(&ctx->fork_lock); \
+			function_call; \
+			pthread_mutex_unlock(&ctx->fork_lock); \
+		} \
+		return rv; \
+	} while (0)
 
 #else /* !_WIN32 */
 
-#define _P11_get_forkid() 0
-#define _P11_detect_fork(x) 0
+#define P11_forkid 0
+#define _P11_update_forkid() 0
+#define CHECK_FORKID(ctx, forkid, function_call) return 0
 
 #endif /* !_WIN32 */
 
 unsigned int get_forkid()
 {
-	return _P11_get_forkid();
+	_P11_update_forkid();
+	return P11_forkid;
 }
 
 /*
@@ -105,14 +91,12 @@
  * It wipes out the internal state of the PKCS#11 library
  * Any libp11 references to this state are no longer valid
  */
-static int check_fork_int(PKCS11_CTX *ctx)
+static int check_fork_int(PKCS11_CTX_private *ctx)
 {
-	PKCS11_CTX_private *cpriv = PRIVCTX(ctx);
-
-	if (_P11_detect_fork(cpriv->forkid)) {
+	if (ctx->forkid != P11_forkid) {
 		if (pkcs11_CTX_reload(ctx) < 0)
 			return -1;
-		cpriv->forkid = _P11_get_forkid();
+		ctx->forkid = P11_forkid;
 	}
 	return 0;
 }
@@ -121,48 +105,35 @@
  * PKCS#11 reinitialization after fork
  * Also relogins and reopens the session if needed
  */
-static int check_slot_fork_int(PKCS11_SLOT *slot)
+static int check_slot_fork_int(PKCS11_SLOT_private *slot)
 {
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
-	PKCS11_CTX *ctx = SLOT2CTX(slot);
-	PKCS11_CTX_private *cpriv = PRIVCTX(ctx);
-
-	if (check_fork_int(SLOT2CTX(slot)) < 0)
-		return -1;
-	if (spriv->forkid != cpriv->forkid) {
-		if (spriv->loggedIn) {
-			int saved = spriv->haveSession;
-			spriv->haveSession = 0;
-			spriv->loggedIn = 0;
-			if (pkcs11_relogin(slot) < 0)
-				return -1;
-			spriv->haveSession = saved;
-		}
-		if (spriv->haveSession) {
-			spriv->haveSession = 0;
-			if (pkcs11_reopen_session(slot) < 0)
-				return -1;
-		}
-		spriv->forkid = cpriv->forkid;
+	PKCS11_CTX_private *ctx = slot->ctx;
+
+	if (check_fork_int(ctx) < 0)
+		return -1;
+	if (slot->forkid != ctx->forkid) {
+		if (pkcs11_reload_slot(slot) < 0)
+			return -1;
+		slot->forkid = ctx->forkid;
 	}
 	return 0;
 }
 
 /*
  * PKCS#11 reinitialization after fork
- * Also reloads the key
+ * Also reloads the object
  */
-static int check_key_fork_int(PKCS11_KEY *key)
+static int check_object_fork_int(PKCS11_OBJECT_private *obj)
 {
-	PKCS11_SLOT *slot = KEY2SLOT(key);
-	PKCS11_KEY_private *kpriv = PRIVKEY(key);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
+	PKCS11_SLOT_private *slot = obj->slot;
 
 	if (check_slot_fork_int(slot) < 0)
 		return -1;
-	if (spriv->forkid != kpriv->forkid) {
-		pkcs11_reload_key(key);
-		kpriv->forkid = spriv->forkid;
+
+	if (slot->forkid != obj->forkid) {
+		if (pkcs11_reload_object(obj) < 0)
+			return -1;
+		obj->forkid = slot->forkid;
 	}
 	return 0;
 }
@@ -170,72 +141,31 @@
 /*
  * Locking interface to check_fork_int()
  */
-int check_fork(PKCS11_CTX *ctx)
+int check_fork(PKCS11_CTX_private *ctx)
 {
-	PKCS11_CTX_private *cpriv;
-	int rv;
-
 	if (!ctx)
 		return -1;
-	cpriv = PRIVCTX(ctx);
-	CRYPTO_THREAD_write_lock(cpriv->rwlock);
-	rv = check_fork_int(ctx);
-	CRYPTO_THREAD_unlock(cpriv->rwlock);
-	return rv;
+	CHECK_FORKID(ctx, ctx->forkid, check_fork_int(ctx));
 }
 
 /*
  * Locking interface to check_slot_fork_int()
  */
-int check_slot_fork(PKCS11_SLOT *slot)
+int check_slot_fork(PKCS11_SLOT_private *slot)
 {
-	PKCS11_CTX_private *cpriv;
-	int rv;
-
 	if (!slot)
 		return -1;
-	cpriv = PRIVCTX(SLOT2CTX(slot));
-	CRYPTO_THREAD_write_lock(cpriv->rwlock);
-	rv = check_slot_fork_int(slot);
-	CRYPTO_THREAD_unlock(cpriv->rwlock);
-	return rv;
-}
-
-/*
- * Reinitialize token (just its slot)
- */
-int check_token_fork(PKCS11_TOKEN *token)
-{
-	if (!token)
-		return -1;
-	return check_slot_fork(TOKEN2SLOT(token));
-}
-
-/*
- * Locking interface to check_key_fork_int()
- */
-int check_key_fork(PKCS11_KEY *key)
-{
-	PKCS11_CTX_private *cpriv;
-	int rv;
-
-	if (!key)
-		return -1;
-	cpriv = PRIVCTX(KEY2CTX(key));
-	CRYPTO_THREAD_write_lock(cpriv->rwlock);
-	rv = check_key_fork_int(key);
-	CRYPTO_THREAD_unlock(cpriv->rwlock);
-	return rv;
+	CHECK_FORKID(slot->ctx, slot->forkid, check_slot_fork_int(slot));
 }
 
 /*
- * Reinitialize cert (just its token)
+ * Locking interface to check_object_fork_int()
  */
-int check_cert_fork(PKCS11_CERT *cert)
+int check_object_fork(PKCS11_OBJECT_private *obj)
 {
-	if (!cert)
+	if (!obj)
 		return -1;
-	return check_token_fork(CERT2TOKEN(cert));
+	CHECK_FORKID(obj->slot->ctx, obj->forkid, check_object_fork_int(obj));
 }
 
 /* vim: set noexpandtab: */
diff -Nru libp11-0.4.11/src/p11_attr.c libp11-0.4.12/src/p11_attr.c
--- libp11-0.4.11/src/p11_attr.c	2020-02-27 06:50:01.000000000 +0100
+++ libp11-0.4.12/src/p11_attr.c	2022-05-04 18:45:56.000000000 +0200
@@ -33,9 +33,9 @@
 /*
  * Query pkcs11 attributes
  */
-static int pkcs11_getattr_int(PKCS11_CTX *ctx, CK_SESSION_HANDLE session,
-		CK_OBJECT_HANDLE o, CK_ATTRIBUTE_TYPE type, CK_BYTE *value,
-		size_t *size)
+int pkcs11_getattr_var(PKCS11_CTX_private *ctx, CK_SESSION_HANDLE session,
+		CK_OBJECT_HANDLE object, CK_ATTRIBUTE_TYPE type,
+		CK_BYTE *value, size_t *size)
 {
 	CK_ATTRIBUTE templ;
 	int rv;
@@ -43,35 +43,27 @@
 	templ.type = type;
 	templ.pValue = value;
 	templ.ulValueLen = *size;
-
-	rv = CRYPTOKI_call(ctx, C_GetAttributeValue(session, o, &templ, 1));
+	rv = CRYPTOKI_call(ctx, C_GetAttributeValue(session, object, &templ, 1));
 	CRYPTOKI_checkerr(CKR_F_PKCS11_GETATTR_INT, rv);
-
 	*size = templ.ulValueLen;
 	return 0;
 }
 
-int pkcs11_getattr_var(PKCS11_TOKEN *token, CK_OBJECT_HANDLE object,
-		unsigned int type, CK_BYTE *value, size_t *size)
-{
-	return pkcs11_getattr_int(TOKEN2CTX(token),
-		PRIVSLOT(TOKEN2SLOT(token))->session,
-		object, type, value, size);
-}
-
-int pkcs11_getattr_val(PKCS11_TOKEN *token, CK_OBJECT_HANDLE object,
-		unsigned int type, void *value, size_t size)
+int pkcs11_getattr_val(PKCS11_CTX_private *ctx, CK_SESSION_HANDLE session,
+		CK_OBJECT_HANDLE object, CK_ATTRIBUTE_TYPE type,
+		void *value, size_t size)
 {
-	return pkcs11_getattr_var(token, object, type, value, &size);
+	return pkcs11_getattr_var(ctx, session, object, type, value, &size);
 }
 
-int pkcs11_getattr_alloc(PKCS11_TOKEN *token, CK_OBJECT_HANDLE object,
-		unsigned int type, CK_BYTE **value, size_t *size)
+int pkcs11_getattr_alloc(PKCS11_CTX_private *ctx, CK_SESSION_HANDLE session,
+		CK_OBJECT_HANDLE object, CK_ATTRIBUTE_TYPE type,
+		CK_BYTE **value, size_t *size)
 {
 	CK_BYTE *data;
 	size_t len = 0;
 
-	if (pkcs11_getattr_var(token, object, type, NULL, &len))
+	if (pkcs11_getattr_var(ctx, session, object, type, NULL, &len))
 		return -1;
 	data = OPENSSL_malloc(len+1);
 	if (!data) {
@@ -79,7 +71,7 @@
 		return -1;
 	}
 	memset(data, 0, len+1); /* also null-terminate the allocated data */
-	if (pkcs11_getattr_var(token, object, type, data, &len)) {
+	if (pkcs11_getattr_var(ctx, session, object, type, data, &len)) {
 		OPENSSL_free(data);
 		return -1;
 	}
@@ -90,14 +82,14 @@
 	return 0;
 }
 
-int pkcs11_getattr_bn(PKCS11_TOKEN *token, CK_OBJECT_HANDLE object,
-		unsigned int type, BIGNUM **bn)
+int pkcs11_getattr_bn(PKCS11_CTX_private *ctx, CK_SESSION_HANDLE session,
+		CK_OBJECT_HANDLE object, CK_ATTRIBUTE_TYPE type, BIGNUM **bn)
 {
 	CK_BYTE *binary;
 	size_t size;
 
 	size = 0;
-	if (pkcs11_getattr_alloc(token, object, type, &binary, &size))
+	if (pkcs11_getattr_alloc(ctx, session, object, type, &binary, &size))
 		return -1;
 	/*
 	 * @ALON: invalid object,
@@ -116,63 +108,68 @@
 /*
  * Add attributes to template
  */
-void pkcs11_addattr(CK_ATTRIBUTE_PTR ap, int type, const void *data, size_t size)
+unsigned int pkcs11_addattr(PKCS11_TEMPLATE *tmpl, int type, void *data, size_t size)
 {
+	unsigned int n = tmpl->nattr;
+	CK_ATTRIBUTE_PTR ap;
+
+	assert(tmpl->nattr < sizeof(tmpl->attrs)/sizeof(tmpl->attrs[0]));
+	ap = &tmpl->attrs[tmpl->nattr++];
 	ap->type = type;
-	ap->pValue = OPENSSL_malloc(size);
-	if (!ap->pValue)
-		return;
-	memcpy(ap->pValue, data, size);
+	ap->pValue = data;
 	ap->ulValueLen = size;
+	return n;
 }
 
-/* In PKCS11, virtually every integer is a CK_ULONG */
-void pkcs11_addattr_int(CK_ATTRIBUTE_PTR ap, int type, unsigned long value)
+void pkcs11_addattr_bool(PKCS11_TEMPLATE *tmpl, int type, int value)
 {
-	CK_ULONG ulValue = value;
-
-	pkcs11_addattr(ap, type, &ulValue, sizeof(ulValue));
+	static CK_BBOOL true = CK_TRUE;
+	static CK_BBOOL false = CK_FALSE;
+	pkcs11_addattr(tmpl, type, value ? &true : &false, sizeof(CK_BBOOL));
 }
 
-void pkcs11_addattr_bool(CK_ATTRIBUTE_PTR ap, int type, int value)
+void pkcs11_addattr_s(PKCS11_TEMPLATE *tmpl, int type, const char *s)
 {
-	pkcs11_addattr(ap, type, &value, sizeof(CK_BBOOL));
+	pkcs11_addattr(tmpl, type, (void*) s, s ? strlen(s) : 0);
 }
 
-void pkcs11_addattr_s(CK_ATTRIBUTE_PTR ap, int type, const char *s)
+void pkcs11_addattr_bn(PKCS11_TEMPLATE *tmpl, int type, const BIGNUM *bn)
 {
-	pkcs11_addattr(ap, type, s, s ? strlen(s) : 0); /* RFC2279 string an unpadded string of CK_UTF8CHARs with no null-termination */
-}
+	int n = BN_num_bytes(bn);
+	uint8_t *buf = OPENSSL_malloc(n);
+	unsigned int i;
 
-void pkcs11_addattr_bn(CK_ATTRIBUTE_PTR ap, int type, const BIGNUM *bn)
-{
-	unsigned char temp[1024];
-	unsigned int n;
-
-	assert((size_t)BN_num_bytes(bn) <= sizeof(temp));
-	n = BN_bn2bin(bn, temp);
-	pkcs11_addattr(ap, type, temp, n);
+	if (buf && BN_bn2bin(bn, buf) == n) {
+		i = pkcs11_addattr(tmpl, type, buf, n);
+		tmpl->allocated |= 1<<i;
+	}
 }
 
-void pkcs11_addattr_obj(CK_ATTRIBUTE_PTR ap, int type, pkcs11_i2d_fn enc, void *obj)
+void pkcs11_addattr_obj(PKCS11_TEMPLATE *tmpl, int type, pkcs11_i2d_fn enc, void *obj)
 {
-	unsigned char *p;
-
-	ap->type = type;
-	ap->ulValueLen = enc(obj, NULL);
-	ap->pValue = OPENSSL_malloc(ap->ulValueLen);
-	if (!ap->pValue)
-		return;
-	p = ap->pValue;
-	enc(obj, &p);
+	unsigned char *buf, *p;
+	unsigned int i;
+	size_t n;
+
+	n = enc(obj, NULL);
+	buf = p = OPENSSL_malloc(n);
+	if (n && p) {
+		enc(obj, &p);
+		i = pkcs11_addattr(tmpl, type, buf, n);
+		tmpl->allocated |= 1<<i;
+	}
 }
 
-void pkcs11_zap_attrs(CK_ATTRIBUTE_PTR ap, unsigned int n)
+void pkcs11_zap_attrs(PKCS11_TEMPLATE *tmpl)
 {
-	while (n--) {
-		if (ap[n].pValue)
-			OPENSSL_free(ap[n].pValue);
+	if (!tmpl->allocated)
+		return;
+	for (unsigned i = 0; i < 32; i++) {
+		if (tmpl->allocated & (1<<i))
+			OPENSSL_free(tmpl->attrs[i].pValue);
 	}
+	tmpl->allocated = 0;
+	tmpl->nattr = 0;
 }
 
 /* vim: set noexpandtab: */
diff -Nru libp11-0.4.11/src/p11_cert.c libp11-0.4.12/src/p11_cert.c
--- libp11-0.4.11/src/p11_cert.c	2020-05-18 08:47:22.000000000 +0200
+++ libp11-0.4.12/src/p11_cert.c	2022-07-05 22:22:51.000000000 +0200
@@ -26,107 +26,51 @@
 #include "libp11-int.h"
 #include <string.h>
 
-static int pkcs11_find_certs(PKCS11_TOKEN *);
-static int pkcs11_next_cert(PKCS11_CTX *, PKCS11_TOKEN *, CK_SESSION_HANDLE);
-static int pkcs11_init_cert(PKCS11_CTX *ctx, PKCS11_TOKEN *token,
-	CK_SESSION_HANDLE session, CK_OBJECT_HANDLE o, PKCS11_CERT **);
+static int pkcs11_find_certs(PKCS11_SLOT_private *, CK_SESSION_HANDLE);
+static int pkcs11_next_cert(PKCS11_CTX_private *, PKCS11_SLOT_private *, CK_SESSION_HANDLE);
+static int pkcs11_init_cert(PKCS11_SLOT_private *token, CK_SESSION_HANDLE session,
+	CK_OBJECT_HANDLE o, PKCS11_CERT **);
 
 /*
  * Enumerate all certs on the card
  */
-int pkcs11_enumerate_certs(PKCS11_TOKEN *token,
-		PKCS11_CERT **certp, unsigned int *countp)
+int pkcs11_enumerate_certs(PKCS11_SLOT_private *slot, PKCS11_CERT **certp, unsigned int *countp)
 {
-	PKCS11_SLOT *slot = TOKEN2SLOT(token);
-	PKCS11_CTX *ctx = SLOT2CTX(slot);
-	PKCS11_TOKEN_private *tpriv = PRIVTOKEN(token);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
-	PKCS11_CTX_private *cpriv = PRIVCTX(ctx);
+	CK_SESSION_HANDLE session;
 	int rv;
 
-	/* Make sure we have a session */
-	if (!spriv->haveSession && PKCS11_open_session(slot, 0))
+	if (pkcs11_get_session(slot, 0, &session))
 		return -1;
 
-	CRYPTO_THREAD_write_lock(cpriv->rwlock);
-	rv = pkcs11_find_certs(token);
-	CRYPTO_THREAD_unlock(cpriv->rwlock);
+	rv = pkcs11_find_certs(slot, session);
+	pkcs11_put_session(slot, session);
 	if (rv < 0) {
-		pkcs11_destroy_certs(token);
+		pkcs11_destroy_certs(slot);
 		return -1;
 	}
 
 	if (certp)
-		*certp = tpriv->certs;
+		*certp = slot->certs;
 	if (countp)
-		*countp = tpriv->ncerts;
-	return 0;
-}
-
-/**
- * Remove a certificate from the associated token
- */
-int pkcs11_remove_certificate(PKCS11_CERT *cert){
-	PKCS11_SLOT *slot = CERT2SLOT(cert);
-	PKCS11_CTX *ctx = CERT2CTX(cert);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
-	CK_OBJECT_HANDLE obj;
-	CK_ULONG count;
-	CK_ATTRIBUTE search_parameters[32];
-	unsigned int n = 0;
-	int rv;
-
-	/* First, make sure we have a session */
-	if (!spriv->haveSession && PKCS11_open_session(slot, 1)){
-		return -1;
-	}
-	
-	pkcs11_addattr_int(search_parameters + n++, CKA_CLASS, CKO_CERTIFICATE);
-	if (cert->id && cert->id_len){
-		pkcs11_addattr(search_parameters + n++, CKA_ID, cert->id, cert->id_len);
-	}
-	if (cert->label){
-	 	pkcs11_addattr_s(search_parameters + n++, CKA_LABEL, cert->label);
-	}
-
-	rv = CRYPTOKI_call(ctx,
-		C_FindObjectsInit(spriv->session, search_parameters, n));
-	CRYPTOKI_checkerr(CKR_F_PKCS11_REMOVE_CERTIFICATE, rv);
-	
-	rv = CRYPTOKI_call(ctx, C_FindObjects(spriv->session, &obj, 1, &count));
-	CRYPTOKI_checkerr(CKR_F_PKCS11_REMOVE_CERTIFICATE, rv);
-
-	CRYPTOKI_call(ctx, C_FindObjectsFinal(spriv->session));
-	if (count!=1){
-		pkcs11_zap_attrs(search_parameters, n);
-		return -1;
-	}
-	rv = CRYPTOKI_call(ctx, C_DestroyObject(spriv->session, obj));
-	if (rv != CKR_OK){
-		pkcs11_zap_attrs(search_parameters, n);
-		return -1;
-	}
-	pkcs11_zap_attrs(search_parameters, n);
+		*countp = slot->ncerts;
 	return 0;
 }
 
 /*
  * Find certificate matching a key
  */
-PKCS11_CERT *pkcs11_find_certificate(PKCS11_KEY *key)
+PKCS11_CERT *pkcs11_find_certificate(PKCS11_OBJECT_private *key)
 {
-	PKCS11_KEY_private *kpriv;
-	PKCS11_CERT_private *cpriv;
+	PKCS11_OBJECT_private *cpriv;
 	PKCS11_CERT *cert;
 	unsigned int n, count;
 
-	kpriv = PRIVKEY(key);
-	if (PKCS11_enumerate_certs(KEY2TOKEN(key), &cert, &count))
+	if (pkcs11_enumerate_certs(key->slot, &cert, &count))
 		return NULL;
 	for (n = 0; n < count; n++, cert++) {
 		cpriv = PRIVCERT(cert);
-		if (cpriv->id_len == kpriv->id_len
-				&& !memcmp(cpriv->id, kpriv->id, kpriv->id_len))
+		if (cpriv->id_len == key->id_len
+				&& !memcmp(cpriv->id, key->id, key->id_len))
 			return cert;
 	}
 	return NULL;
@@ -135,11 +79,9 @@
 /*
  * Find all certs of a given type (public or private)
  */
-static int pkcs11_find_certs(PKCS11_TOKEN *token)
+static int pkcs11_find_certs(PKCS11_SLOT_private *slot, CK_SESSION_HANDLE session)
 {
-	PKCS11_SLOT *slot = TOKEN2SLOT(token);
-	PKCS11_CTX *ctx = SLOT2CTX(slot);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
+	PKCS11_CTX_private *ctx = slot->ctx;
 	CK_OBJECT_CLASS cert_search_class;
 	CK_ATTRIBUTE cert_search_attrs[] = {
 		{CKA_CLASS, &cert_search_class, sizeof(cert_search_class)},
@@ -148,19 +90,19 @@
 
 	/* Tell the PKCS11 lib to enumerate all matching objects */
 	cert_search_class = CKO_CERTIFICATE;
-	rv = CRYPTOKI_call(ctx, C_FindObjectsInit(spriv->session, cert_search_attrs, 1));
+	rv = CRYPTOKI_call(ctx, C_FindObjectsInit(session, cert_search_attrs, 1));
 	CRYPTOKI_checkerr(CKR_F_PKCS11_FIND_CERTS, rv);
 
 	do {
-		res = pkcs11_next_cert(ctx, token, spriv->session);
+		res = pkcs11_next_cert(ctx, slot, session);
 	} while (res == 0);
 
-	CRYPTOKI_call(ctx, C_FindObjectsFinal(spriv->session));
+	CRYPTOKI_call(ctx, C_FindObjectsFinal(session));
 
 	return (res < 0) ? -1 : 0;
 }
 
-static int pkcs11_next_cert(PKCS11_CTX *ctx, PKCS11_TOKEN *token,
+static int pkcs11_next_cert(PKCS11_CTX_private *ctx, PKCS11_SLOT_private *slot,
 		CK_SESSION_HANDLE session)
 {
 	CK_OBJECT_HANDLE obj;
@@ -174,73 +116,50 @@
 	if (count == 0)
 		return 1;
 
-	if (pkcs11_init_cert(ctx, token, session, obj, NULL))
+	if (pkcs11_init_cert(slot, session, obj, NULL))
 		return -1;
 
 	return 0;
 }
 
-static int pkcs11_init_cert(PKCS11_CTX *ctx, PKCS11_TOKEN *token,
-		CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj, PKCS11_CERT ** ret)
+static int pkcs11_init_cert(PKCS11_SLOT_private *slot, CK_SESSION_HANDLE session,
+	CK_OBJECT_HANDLE object, PKCS11_CERT ** ret)
 {
-	PKCS11_TOKEN_private *tpriv;
-	PKCS11_CERT_private *cpriv;
+	PKCS11_OBJECT_private *cpriv;
 	PKCS11_CERT *cert, *tmp;
-	unsigned char *data;
-	CK_CERTIFICATE_TYPE cert_type;
-	size_t size;
 	int i;
 
-	(void)ctx;
-	(void)session;
-
-	/* Ignore unknown certificate types */
-	size = sizeof(CK_CERTIFICATE_TYPE);
-	if (pkcs11_getattr_var(token, obj, CKA_CERTIFICATE_TYPE, (CK_BYTE *)&cert_type, &size))
-		return -1;
-	if (cert_type != CKC_X_509)
-		return 0;
-
 	/* Prevent re-adding existing PKCS#11 object handles */
 	/* TODO: Rewrite the O(n) algorithm as O(log n),
 	 * or it may be too slow with a large number of certificates */
-	for (i=0; i < PRIVTOKEN(token)->ncerts; ++i)
-		if (PRIVCERT(PRIVTOKEN(token)->certs + i)->object == obj)
+	for (i = 0; i < slot->ncerts; ++i) {
+		if (PRIVCERT(&slot->certs[i])->object == object) {
+			if (ret)
+				*ret = &slot->certs[i];
 			return 0;
+		}
+	}
 
-	/* Allocate memory */
-	cpriv = OPENSSL_malloc(sizeof(PKCS11_CERT_private));
+	cpriv = pkcs11_object_from_handle(slot, session, object);
 	if (!cpriv)
 		return -1;
-	memset(cpriv, 0, sizeof(PKCS11_CERT_private));
-	tpriv = PRIVTOKEN(token);
-	tmp = OPENSSL_realloc(tpriv->certs,
-		(tpriv->ncerts + 1) * sizeof(PKCS11_CERT));
-	if (!tmp)
+
+	/* Allocate memory */
+	tmp = OPENSSL_realloc(slot->certs, (slot->ncerts + 1) * sizeof(PKCS11_CERT));
+	if (!tmp) {
+		pkcs11_object_free(cpriv);
 		return -1;
-	tpriv->certs = tmp;
-	cert = tpriv->certs + tpriv->ncerts++;
+	}
+	slot->certs = tmp;
+	cert = slot->certs + slot->ncerts++;
 	memset(cert, 0, sizeof(PKCS11_CERT));
 
 	/* Fill public properties */
-	pkcs11_getattr_alloc(token, obj, CKA_LABEL, (CK_BYTE **)&cert->label, NULL);
-	size = 0;
-	if (!pkcs11_getattr_alloc(token, obj, CKA_VALUE, &data, &size)) {
-		const unsigned char *p = data;
-
-		cert->x509 = d2i_X509(NULL, &p, (long)size);
-		OPENSSL_free(data);
-	}
-	cert->id_len = 0;
-	pkcs11_getattr_alloc(token, obj, CKA_ID, &cert->id, &cert->id_len);
-
-	/* Fill private properties */
+	cert->id = cpriv->id;
+	cert->id_len = cpriv->id_len;
+	cert->label = cpriv->label;
+	cert->x509 = cpriv->x509;
 	cert->_private = cpriv;
-	cpriv->object = obj;
-	cpriv->parent = token;
-	cpriv->id_len = sizeof cpriv->id;
-	if (pkcs11_getattr_var(token, obj, CKA_ID, cpriv->id, &cpriv->id_len))
-		cpriv->id_len = 0;
 
 	if (ret)
 		*ret = cert;
@@ -250,68 +169,63 @@
 /*
  * Destroy all certs
  */
-void pkcs11_destroy_certs(PKCS11_TOKEN *token)
+void pkcs11_destroy_certs(PKCS11_SLOT_private *slot)
 {
-	PKCS11_TOKEN_private *tpriv = PRIVTOKEN(token);
-
-	while (tpriv->ncerts > 0) {
-		PKCS11_CERT *cert = &tpriv->certs[--(tpriv->ncerts)];
-
-		if (cert->x509)
-			X509_free(cert->x509);
-		OPENSSL_free(cert->label);
-		if (cert->id)
-			OPENSSL_free(cert->id);
+	while (slot->ncerts > 0) {
+		PKCS11_CERT *cert = &slot->certs[--slot->ncerts];
 		if (cert->_private)
-			OPENSSL_free(cert->_private);
+			pkcs11_object_free(PRIVCERT(cert));
 	}
-	if (tpriv->certs)
-		OPENSSL_free(tpriv->certs);
-	tpriv->certs = NULL;
-	tpriv->ncerts = 0;
+	if (slot->certs)
+		OPENSSL_free(slot->certs);
+	slot->certs = NULL;
+	slot->ncerts = 0;
 }
 
 /*
  * Store certificate
  */
-int pkcs11_store_certificate(PKCS11_TOKEN *token, X509 *x509, char *label,
-		unsigned char *id, size_t id_len, PKCS11_CERT ** ret_cert)
+int pkcs11_store_certificate(PKCS11_SLOT_private *slot, X509 *x509, char *label,
+		unsigned char *id, size_t id_len, PKCS11_CERT **ret_cert)
 {
-	PKCS11_SLOT *slot = TOKEN2SLOT(token);
-	PKCS11_CTX *ctx = SLOT2CTX(slot);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
+	PKCS11_CTX_private *ctx = slot->ctx;
+	CK_SESSION_HANDLE session;
 	CK_OBJECT_HANDLE object;
-	CK_ATTRIBUTE attrs[32];
-	unsigned int n = 0;
-	int rv;
+	int rv, r = -1;
 	int signature_nid;
+	int evp_md_nid = NID_sha1;
 	const EVP_MD* evp_md;
-	CK_MECHANISM_TYPE ckm_md;
 	unsigned char md[EVP_MAX_MD_SIZE];
 	unsigned int md_len;
+	PKCS11_TEMPLATE tmpl = {0};
+	CK_OBJECT_CLASS class_certificate = CKO_CERTIFICATE;
+	CK_CERTIFICATE_TYPE certificate_x509 = CKC_X_509;
+	CK_MECHANISM_TYPE ckm_md;
 
 	/* First, make sure we have a session */
-	if (!PRIVSLOT(slot)->haveSession && PKCS11_open_session(slot, 1))
+	if (pkcs11_get_session(slot, 1, &session))
 		return -1;
 
 	/* Now build the template */
-	pkcs11_addattr_int(attrs + n++, CKA_CLASS, CKO_CERTIFICATE);
-	pkcs11_addattr_bool(attrs + n++, CKA_TOKEN, TRUE);
-	pkcs11_addattr_int(attrs + n++, CKA_CERTIFICATE_TYPE, CKC_X_509);
-	pkcs11_addattr_obj(attrs + n++, CKA_SUBJECT,
+	pkcs11_addattr_var(&tmpl, CKA_CLASS, class_certificate);
+	pkcs11_addattr_bool(&tmpl, CKA_TOKEN, TRUE);
+	pkcs11_addattr_var(&tmpl, CKA_CERTIFICATE_TYPE, certificate_x509);
+	pkcs11_addattr_obj(&tmpl, CKA_SUBJECT,
 		(pkcs11_i2d_fn)i2d_X509_NAME, X509_get_subject_name(x509));
-	pkcs11_addattr_obj(attrs + n++, CKA_ISSUER,
+	pkcs11_addattr_obj(&tmpl, CKA_ISSUER,
 		(pkcs11_i2d_fn)i2d_X509_NAME, X509_get_issuer_name(x509));
 
 	/* Get digest algorithm from x509 certificate */
-#if OPENSSL_VERSION_NUMBER >= 0x10002000L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3050000fL )
 	signature_nid = X509_get_signature_nid(x509);
 #else
 	signature_nid = OBJ_obj2nid(x509->sig_alg->algorithm);
 #endif
-	evp_md = EVP_get_digestbynid(signature_nid);
-	switch (EVP_MD_type(evp_md)) {
+	OBJ_find_sigid_algs(signature_nid, &evp_md_nid, NULL);
+	switch (evp_md_nid) {
 	default:
+		evp_md_nid = NID_sha1;
+		/* fall through */
 	case NID_sha1:
 		ckm_md = CKM_SHA_1;
 		break;
@@ -327,29 +241,49 @@
 	case NID_sha384:
 		ckm_md = CKM_SHA384;
 		break;
+#if !defined(LIBRESSL_VERSION_NUMBER)
+	case NID_sha3_224:
+		ckm_md = CKM_SHA3_224;
+		break;
+	case NID_sha3_256:
+		ckm_md = CKM_SHA3_256;
+		break;
+	case NID_sha3_384:
+		ckm_md = CKM_SHA3_384;
+		break;
+	case NID_sha3_512:
+		ckm_md = CKM_SHA3_512;
+		break;
+#endif
 	}
 
+	evp_md = EVP_get_digestbynid(evp_md_nid);
+
 	/* Set hash algorithm; default is SHA-1 */
-	pkcs11_addattr_int(attrs + n++, CKA_NAME_HASH_ALGORITHM, ckm_md);
-	if(X509_pubkey_digest(x509,evp_md,md,&md_len))
-		pkcs11_addattr(attrs + n++, CKA_HASH_OF_SUBJECT_PUBLIC_KEY,md,md_len);
+	pkcs11_addattr_var(&tmpl, CKA_NAME_HASH_ALGORITHM, ckm_md);
+	if (X509_pubkey_digest(x509,evp_md,md,&md_len))
+		pkcs11_addattr(&tmpl, CKA_HASH_OF_SUBJECT_PUBLIC_KEY, md, md_len);
 
-	pkcs11_addattr_obj(attrs + n++, CKA_VALUE, (pkcs11_i2d_fn)i2d_X509, x509);
+	pkcs11_addattr_obj(&tmpl, CKA_VALUE, (pkcs11_i2d_fn)i2d_X509, x509);
 	if (label)
-		pkcs11_addattr_s(attrs + n++, CKA_LABEL, label);
+		pkcs11_addattr_s(&tmpl, CKA_LABEL, label);
 	if (id && id_len)
-		pkcs11_addattr(attrs + n++, CKA_ID, id, id_len);
+		pkcs11_addattr(&tmpl, CKA_ID, id, id_len);
 
 	/* Now call the pkcs11 module to create the object */
-	rv = CRYPTOKI_call(ctx, C_CreateObject(spriv->session, attrs, n, &object));
+	rv = CRYPTOKI_call(ctx, C_CreateObject(session, tmpl.attrs, tmpl.nattr, &object));
 
 	/* Zap all memory allocated when building the template */
-	pkcs11_zap_attrs(attrs, n);
-
-	CRYPTOKI_checkerr(CKR_F_PKCS11_STORE_CERTIFICATE, rv);
+	pkcs11_zap_attrs(&tmpl);
 
 	/* Gobble the key object */
-	return pkcs11_init_cert(ctx, token, spriv->session, object, ret_cert);
+	if (rv == CKR_OK) {
+		r = pkcs11_init_cert(slot, session, object, ret_cert);
+	}
+	pkcs11_put_session(slot, session);
+
+	CRYPTOKI_checkerr(CKR_F_PKCS11_STORE_CERTIFICATE, rv);
+	return r;
 }
 
 /* vim: set noexpandtab: */
diff -Nru libp11-0.4.11/src/p11_ckr.c libp11-0.4.12/src/p11_ckr.c
--- libp11-0.4.11/src/p11_ckr.c	2020-02-27 06:50:01.000000000 +0100
+++ libp11-0.4.12/src/p11_ckr.c	2021-10-30 14:20:08.000000000 +0200
@@ -52,10 +52,11 @@
 	{ERR_FUNC(CKR_F_PKCS11_PRIVATE_DECRYPT), "pkcs11_private_decrypt"},
 	{ERR_FUNC(CKR_F_PKCS11_PRIVATE_ENCRYPT), "pkcs11_private_encrypt"},
 	{ERR_FUNC(CKR_F_PKCS11_RELOAD_KEY), "pkcs11_reload_key"},
-	{ERR_FUNC(CKR_F_PKCS11_REOPEN_SESSION), "pkcs11_reopen_session"},
 	{ERR_FUNC(CKR_F_PKCS11_SEED_RANDOM), "pkcs11_seed_random"},
 	{ERR_FUNC(CKR_F_PKCS11_STORE_CERTIFICATE), "pkcs11_store_certificate"},
 	{ERR_FUNC(CKR_F_PKCS11_STORE_KEY), "pkcs11_store_key"},
+	{ERR_FUNC(CKR_F_PKCS11_RELOAD_CERTIFICATE), "pkcs11_reload_certificate"},
+	{ERR_FUNC(CKR_F_PKCS11_GET_SESSION), "pkcs11_get_session"},
 	{0, NULL}
 };
 
@@ -68,7 +69,7 @@
 	{CKR_ARGUMENTS_BAD, "Invalid arguments"},
 	{CKR_NO_EVENT, "No event"},
 	{CKR_NEED_TO_CREATE_THREADS, "Need to create threads"},
-	{CKR_CANT_LOCK, "Cannott lock"},
+	{CKR_CANT_LOCK, "Cannot lock"},
 	{CKR_ATTRIBUTE_READ_ONLY, "Attribute read only"},
 	{CKR_ATTRIBUTE_SENSITIVE, "Attribute sensitive"},
 	{CKR_ATTRIBUTE_TYPE_INVALID, "Attribute type invalid"},
diff -Nru libp11-0.4.11/src/p11_ec.c libp11-0.4.12/src/p11_ec.c
--- libp11-0.4.11/src/p11_ec.c	2020-02-27 06:50:01.000000000 +0100
+++ libp11-0.4.12/src/p11_ec.c	2022-07-05 22:22:51.000000000 +0200
@@ -49,6 +49,7 @@
 	void *(*)(const void *, size_t, void *, size_t *));
 #endif
 static compute_key_fn ossl_ecdh_compute_key;
+static void (*ossl_ec_finish)(EC_KEY *);
 
 static int ec_ex_index = 0;
 
@@ -187,14 +188,15 @@
 
 /* Retrieve EC parameters from key into ec
  * return nonzero on error */
-static int pkcs11_get_params(EC_KEY *ec, PKCS11_KEY *key)
+static int pkcs11_get_params(EC_KEY *ec, PKCS11_OBJECT_private *key, CK_SESSION_HANDLE session)
 {
 	CK_BYTE *params;
 	size_t params_len = 0;
 	const unsigned char *a;
 	int rv;
 
-	if (key_getattr_alloc(key, CKA_EC_PARAMS, &params, &params_len))
+	if (pkcs11_getattr_alloc(key->slot->ctx, session, key->object,
+			CKA_EC_PARAMS, &params, &params_len))
 		return -1;
 
 	a = params;
@@ -203,9 +205,41 @@
 	return rv;
 }
 
+/* Retrieve EC point from x509 certificate into ec
+ * return nonzero on error */
+static int pkcs11_get_point_x509(EC_KEY *ec, X509 *x509)
+{
+	EVP_PKEY *pubkey = NULL;
+	EC_KEY *pubkey_ec;
+	const EC_POINT *point;
+	int rv = -1;
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+	pubkey = X509_get0_pubkey(x509);
+#else
+	pubkey = X509_get_pubkey(x509);
+#endif
+	if (!pubkey)
+		goto error;
+	pubkey_ec = (EC_KEY *)EVP_PKEY_get0_EC_KEY(pubkey);
+	if (!pubkey_ec)
+		goto error;
+	point = EC_KEY_get0_public_key(pubkey_ec);
+	if (!point)
+		goto error;
+	if (EC_KEY_set_public_key(ec, point) == 0)
+		goto error;
+	rv = 0;
+error:
+#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
+	EVP_PKEY_free(pubkey);
+#endif
+	return rv;
+}
+
 /* Retrieve EC point from key into ec
  * return nonzero on error */
-static int pkcs11_get_point_key(EC_KEY *ec, PKCS11_KEY *key)
+static int pkcs11_get_point(EC_KEY *ec, PKCS11_OBJECT_private *key, CK_SESSION_HANDLE session)
 {
 	CK_BYTE *point;
 	size_t point_len = 0;
@@ -213,7 +247,11 @@
 	ASN1_OCTET_STRING *os;
 	int rv = -1;
 
-	if (!key || key_getattr_alloc(key, CKA_EC_POINT, &point, &point_len))
+	if (key->x509 && pkcs11_get_point_x509(ec, key->x509) == 0)
+		return 0;
+
+	if (!key || pkcs11_getattr_alloc(key->slot->ctx, session, key->object,
+			CKA_EC_POINT, &point, &point_len))
 		return -1;
 
 	/* PKCS#11-compliant modules should return ASN1_OCTET_STRING */
@@ -232,42 +270,23 @@
 	return rv;
 }
 
-/* Retrieve EC point from cert into ec
- * return nonzero on error */
-static int pkcs11_get_point_cert(EC_KEY *ec, PKCS11_CERT *cert)
+static int pkcs11_get_point_associated(EC_KEY *ec, PKCS11_OBJECT_private *key,
+	CK_OBJECT_CLASS object_class, CK_SESSION_HANDLE session)
 {
-	EVP_PKEY *pubkey = NULL;
-	EC_KEY *pubkey_ec;
-	const EC_POINT *point;
-	int rv = -1;
+	int r;
+	PKCS11_OBJECT_private *obj = pkcs11_object_from_object(key, session, object_class);
 
-	if (!cert)
-		goto error;
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
-	pubkey = X509_get0_pubkey(cert->x509);
-#else
-	pubkey = X509_get_pubkey(cert->x509);
-#endif
-	if (!pubkey)
-		goto error;
-	pubkey_ec = EVP_PKEY_get0_EC_KEY(pubkey);
-	if (!pubkey_ec)
-		goto error;
-	point = EC_KEY_get0_public_key(pubkey_ec);
-	if (!point)
-		goto error;
-	if (EC_KEY_set_public_key(ec, point) == 0)
-		goto error;
-	rv = 0;
-error:
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
-	EVP_PKEY_free(pubkey);
-#endif
-	return rv;
+	if (!obj)
+		return -1;
+	r = pkcs11_get_point(ec, obj, session);
+	pkcs11_object_free(obj);
+	return r;
 }
 
-static EC_KEY *pkcs11_get_ec(PKCS11_KEY *key)
+static EC_KEY *pkcs11_get_ec(PKCS11_OBJECT_private *key)
 {
+	PKCS11_SLOT_private *slot = key->slot;
+	CK_SESSION_HANDLE session;
 	EC_KEY *ec;
 	int no_params, no_point;
 
@@ -280,21 +299,26 @@
 	 * Continue even if it fails, as the sign operation does not need
 	 * it if the PKCS#11 module or the hardware can figure this out
 	 */
-	no_params = pkcs11_get_params(ec, key);
-	no_point = pkcs11_get_point_key(ec, key);
-	if (no_point && key->isPrivate) /* Retry with the public key */
-		no_point = pkcs11_get_point_key(ec, pkcs11_find_key_from_key(key));
-	if (no_point && key->isPrivate) /* Retry with the certificate */
-		no_point = pkcs11_get_point_cert(ec, pkcs11_find_certificate(key));
+	if (pkcs11_get_session(slot, 0, &session)) {
+		EC_KEY_free(ec);
+		return NULL;
+	}
+	no_params = pkcs11_get_params(ec, key, session);
+	no_point = pkcs11_get_point(ec, key, session);
+	if (no_point && key->object_class == CKO_PRIVATE_KEY) /* Retry with the public key */
+		no_point = pkcs11_get_point_associated(ec, key, CKO_PUBLIC_KEY, session);
+	if (no_point && key->object_class == CKO_PRIVATE_KEY) /* Retry with the certificate */
+		no_point = pkcs11_get_point_associated(ec, key, CKO_CERTIFICATE, session);
+	pkcs11_put_session(slot, session);
 
-	if (key->isPrivate && EC_KEY_get0_private_key(ec) == NULL) {
+	if (key->object_class == CKO_PRIVATE_KEY && EC_KEY_get0_private_key(ec) == NULL) {
 		BIGNUM *bn = BN_new();
 		EC_KEY_set_private_key(ec, bn);
 		BN_free(bn);
 	}
 
 	/* A public keys requires both the params and the point to be present */
-	if (!key->isPrivate && (no_params || no_point)) {
+	if (key->object_class == CKO_PUBLIC_KEY && (no_params || no_point)) {
 		EC_KEY_free(ec);
 		return NULL;
 	}
@@ -302,7 +326,7 @@
 	return ec;
 }
 
-PKCS11_KEY *pkcs11_get_ex_data_ec(const EC_KEY *ec)
+PKCS11_OBJECT_private *pkcs11_get_ex_data_ec(const EC_KEY *ec)
 {
 #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
 	return EC_KEY_get_ex_data(ec, ec_ex_index);
@@ -311,7 +335,7 @@
 #endif
 }
 
-static void pkcs11_set_ex_data_ec(EC_KEY *ec, PKCS11_KEY *key)
+static void pkcs11_set_ex_data_ec(EC_KEY *ec, PKCS11_OBJECT_private *key)
 {
 #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
 	EC_KEY_set_ex_data(ec, ec_ex_index, key);
@@ -320,20 +344,6 @@
 #endif
 }
 
-static void pkcs11_update_ex_data_ec(PKCS11_KEY *key)
-{
-	EVP_PKEY *evp = key->evp_key;
-	EC_KEY *ec;
-	if (!evp)
-		return;
-	if (EVP_PKEY_base_id(evp) != EVP_PKEY_EC)
-		return;
-
-	ec = EVP_PKEY_get1_EC_KEY(evp);
-	pkcs11_set_ex_data_ec(ec, key);
-	EC_KEY_free(ec);
-}
-
 /*
  * Get EC key material and stash pointer in ex_data
  * Note we get called twice, once for private key, and once for public
@@ -343,7 +353,7 @@
  * is not in the private key, and the params may or may not be.
  *
  */
-static EVP_PKEY *pkcs11_get_evp_key_ec(PKCS11_KEY *key)
+static EVP_PKEY *pkcs11_get_evp_key_ec(PKCS11_OBJECT_private *key)
 {
 	EVP_PKEY *pk;
 	EC_KEY *ec;
@@ -356,9 +366,8 @@
 		EC_KEY_free(ec);
 		return NULL;
 	}
-	EVP_PKEY_set1_EC_KEY(pk, ec); /* Also increments the ec ref count */
 
-	if (key->isPrivate) {
+	if (key->object_class == CKO_PRIVATE_KEY) {
 #if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
 		EC_KEY_set_method(ec, PKCS11_get_ec_key_method());
 #else
@@ -370,6 +379,7 @@
 	 * unless the key has the "sensitive" attribute set */
 
 	pkcs11_set_ex_data_ec(ec, key);
+	EVP_PKEY_set1_EC_KEY(pk, ec); /* Also increments the ec ref count */
 	EC_KEY_free(ec); /* Drops our reference to it */
 	return pk;
 }
@@ -379,13 +389,12 @@
 /* Signature size is the issue, will assume the caller has a big buffer! */
 /* No padding or other stuff needed.  We can call PKCS11 from here */
 static int pkcs11_ecdsa_sign(const unsigned char *msg, unsigned int msg_len,
-		unsigned char *sigret, unsigned int *siglen, PKCS11_KEY *key)
+		unsigned char *sigret, unsigned int *siglen, PKCS11_OBJECT_private *key)
 {
 	int rv;
-	PKCS11_SLOT *slot = KEY2SLOT(key);
-	PKCS11_CTX *ctx = KEY2CTX(key);
-	PKCS11_KEY_private *kpriv = PRIVKEY(key);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
+	PKCS11_SLOT_private *slot = key->slot;
+	PKCS11_CTX_private *ctx = slot->ctx;
+	CK_SESSION_HANDLE session;
 	CK_MECHANISM mechanism;
 	CK_ULONG ck_sigsize;
 
@@ -394,15 +403,17 @@
 	memset(&mechanism, 0, sizeof(mechanism));
 	mechanism.mechanism = CKM_ECDSA;
 
-	CRYPTO_THREAD_write_lock(PRIVCTX(ctx)->rwlock);
+	if (pkcs11_get_session(slot, 0, &session))
+		return -1;
+
 	rv = CRYPTOKI_call(ctx,
-		C_SignInit(spriv->session, &mechanism, kpriv->object));
-	if (!rv && kpriv->always_authenticate == CK_TRUE)
-		rv = pkcs11_authenticate(key);
+		C_SignInit(session, &mechanism, key->object));
+	if (!rv && key->always_authenticate == CK_TRUE)
+		rv = pkcs11_authenticate(key, session);
 	if (!rv)
 		rv = CRYPTOKI_call(ctx,
-			C_Sign(spriv->session, (CK_BYTE *)msg, msg_len, sigret, &ck_sigsize));
-	CRYPTO_THREAD_unlock(PRIVCTX(ctx)->rwlock);
+			C_Sign(session, (CK_BYTE *)msg, msg_len, sigret, &ck_sigsize));
+	pkcs11_put_session(slot, session);
 
 	if (rv) {
 		CKRerr(CKR_F_PKCS11_ECDSA_SIGN, rv);
@@ -413,6 +424,19 @@
 	return ck_sigsize;
 }
 
+static void pkcs11_ec_finish(EC_KEY *ec)
+{
+	PKCS11_OBJECT_private *key;
+
+	key = pkcs11_get_ex_data_ec(ec);
+	if (key) {
+		pkcs11_set_ex_data_ec(ec, NULL);
+		pkcs11_object_free(key);
+	}
+	if (ossl_ec_finish)
+		ossl_ec_finish(ec);
+}
+
 /**
  * ECDSA signing method (replaces ossl_ecdsa_sign_sig)
  *
@@ -428,7 +452,7 @@
 {
 	unsigned char sigret[512]; /* HACK for now */
 	ECDSA_SIG *sig;
-	PKCS11_KEY *key;
+	PKCS11_OBJECT_private *key;
 	unsigned int siglen;
 	BIGNUM *r, *s, *order;
 
@@ -436,9 +460,9 @@
 	(void)rp; /* Precomputed values are not used for PKCS#11 */
 
 	key = pkcs11_get_ex_data_ec(ec);
-	if (check_key_fork(key) < 0) {
+	if (check_object_fork(key) < 0) {
 		sign_sig_fn orig_sign_sig;
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3050000fL )
 		const EC_KEY_METHOD *meth = EC_KEY_OpenSSL();
 		EC_KEY_METHOD_get_sign((EC_KEY_METHOD *)meth,
 			NULL, NULL, &orig_sign_sig);
@@ -470,7 +494,7 @@
 	sig = ECDSA_SIG_new();
 	if (!sig)
 		return NULL;
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3050000fL )
 	ECDSA_SIG_set0(sig, r, s);
 #else
 	BN_free(sig->r);
@@ -538,13 +562,11 @@
 		const unsigned long ecdh_mechanism,
 		const void *ec_params,
 		void *outnewkey,
-		PKCS11_KEY *key)
+		PKCS11_OBJECT_private *key)
 {
-	PKCS11_SLOT *slot = KEY2SLOT(key);
-	PKCS11_CTX *ctx = KEY2CTX(key);
-	PKCS11_TOKEN *token = KEY2TOKEN(key);
-	PKCS11_KEY_private *kpriv = PRIVKEY(key);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
+	PKCS11_SLOT_private *slot = key->slot;
+	PKCS11_CTX_private *ctx = slot->ctx;
+	CK_SESSION_HANDLE session;
 	CK_MECHANISM mechanism;
 	int rv;
 
@@ -585,28 +607,37 @@
 			return -1;
 	}
 
-	rv = CRYPTOKI_call(ctx, C_DeriveKey(spriv->session, &mechanism, kpriv->object,
+	if (pkcs11_get_session(slot, 0, &session))
+		return -1;
+
+	rv = CRYPTOKI_call(ctx, C_DeriveKey(session, &mechanism, key->object,
 		newkey_template, sizeof(newkey_template)/sizeof(*newkey_template), &newkey));
-	CRYPTOKI_checkerr(CKR_F_PKCS11_ECDH_DERIVE, rv);
+	if (rv != CKR_OK)
+		goto error;
 
 	/* Return the value of the secret key and/or the object handle of the secret key */
 	if (out && outlen) { /* pkcs11_ec_ckey only asks for the value */
-		if (pkcs11_getattr_alloc(token, newkey, CKA_VALUE, out, outlen)) {
-			CKRerr(CKR_F_PKCS11_ECDH_DERIVE, CKR_ATTRIBUTE_VALUE_INVALID);
-			CRYPTOKI_call(ctx, C_DestroyObject(spriv->session, newkey));
-			return -1;
+		if (pkcs11_getattr_alloc(ctx, session, newkey, CKA_VALUE, out, outlen)) {
+			CRYPTOKI_call(ctx, C_DestroyObject(session, newkey));
+			goto error;
 		}
 	}
 	if (tmpnewkey) /* For future use (not used by pkcs11_ec_ckey) */
 		*tmpnewkey = newkey;
 	else /* Destroy the temporary key */
-		CRYPTOKI_call(ctx, C_DestroyObject(spriv->session, newkey));
+		CRYPTOKI_call(ctx, C_DestroyObject(session, newkey));
+
+	pkcs11_put_session(slot, session);
 
 	return 0;
+error:
+	pkcs11_put_session(slot, session);
+	CKRerr(CKR_F_PKCS11_ECDH_DERIVE, rv);
+	return -1;
 }
 
 static int pkcs11_ecdh_compute_key(unsigned char **buf, size_t *buflen,
-		const EC_POINT *peer_point, const EC_KEY *ecdh, PKCS11_KEY *key)
+		const EC_POINT *peer_point, const EC_KEY *ecdh, PKCS11_OBJECT_private *key)
 {
 	const EC_GROUP *group = EC_KEY_get0_group(ecdh);
 	const int key_len = (EC_GROUP_get_degree(group) + 7) / 8;
@@ -636,12 +667,12 @@
 static int pkcs11_ec_ckey(unsigned char **out, size_t *outlen,
 		const EC_POINT *peer_point, const EC_KEY *ecdh)
 {
-	PKCS11_KEY *key;
+	PKCS11_OBJECT_private *key;
 	unsigned char *buf = NULL;
 	size_t buflen;
 
 	key = pkcs11_get_ex_data_ec(ecdh);
-	if (check_key_fork(key) < 0)
+	if (check_object_fork(key) < 0)
 		return ossl_ecdh_compute_key(out, outlen, peer_point, ecdh);
 	if (pkcs11_ecdh_compute_key(&buf, &buflen, peer_point, ecdh, key) < 0)
 		return 0;
@@ -667,12 +698,12 @@
 		const EC_POINT *peer_point, const EC_KEY *ecdh,
 		void *(*KDF)(const void *, size_t, void *, size_t *))
 {
-	PKCS11_KEY *key;
+	PKCS11_OBJECT_private *key;
 	unsigned char *buf = NULL;
 	size_t buflen;
 
 	key = pkcs11_get_ex_data_ec(ecdh);
-	if (check_key_fork(key) < 0)
+	if (check_object_fork(key) < 0)
 		return ossl_ecdh_compute_key(out, outlen, peer_point, ecdh, KDF);
 	if (pkcs11_ecdh_compute_key(&buf, &buflen, peer_point, ecdh, key) < 0)
 		return -1;
@@ -708,12 +739,21 @@
 EC_KEY_METHOD *PKCS11_get_ec_key_method(void)
 {
 	static EC_KEY_METHOD *ops = NULL;
+	int (*orig_init)(EC_KEY *);
+	int (*orig_copy)(EC_KEY *, const EC_KEY *);
+	int (*orig_set_group)(EC_KEY *, const EC_GROUP *);
+	int (*orig_set_private)(EC_KEY *, const BIGNUM *);
+	int (*orig_set_public)(EC_KEY *, const EC_POINT *);
 	int (*orig_sign)(int, const unsigned char *, int, unsigned char *,
 		unsigned int *, const BIGNUM *, const BIGNUM *, EC_KEY *) = NULL;
 
 	alloc_ec_ex_index();
 	if (!ops) {
 		ops = EC_KEY_METHOD_new((EC_KEY_METHOD *)EC_KEY_OpenSSL());
+		EC_KEY_METHOD_get_init(ops, &orig_init, &ossl_ec_finish, &orig_copy,
+			&orig_set_group, &orig_set_private, &orig_set_public);
+		EC_KEY_METHOD_set_init(ops, orig_init, pkcs11_ec_finish, orig_copy,
+			orig_set_group, orig_set_private, orig_set_public);
 		EC_KEY_METHOD_get_sign(ops, &orig_sign, NULL, NULL);
 		EC_KEY_METHOD_set_sign(ops, orig_sign, NULL, pkcs11_ecdsa_sign_sig);
 		EC_KEY_METHOD_get_compute_key(ops, &ossl_ecdh_compute_key);
@@ -768,17 +808,13 @@
 
 #endif /* OPENSSL_VERSION_NUMBER */
 
-PKCS11_KEY_ops pkcs11_ec_ops_s = {
+PKCS11_OBJECT_ops pkcs11_ec_ops = {
 	EVP_PKEY_EC,
 	pkcs11_get_evp_key_ec,
-	pkcs11_update_ex_data_ec,
 };
-PKCS11_KEY_ops *pkcs11_ec_ops = {&pkcs11_ec_ops_s};
 
 #else /* OPENSSL_NO_EC */
 
-PKCS11_KEY_ops *pkcs11_ec_ops = {NULL};
-
 /* if not built with EC or OpenSSL does not support ECDSA
  * add these routines so engine_pkcs11 can be built now and not
  * require further changes */
diff -Nru libp11-0.4.11/src/p11_front.c libp11-0.4.12/src/p11_front.c
--- libp11-0.4.11/src/p11_front.c	2018-12-12 21:07:46.000000000 +0100
+++ libp11-0.4.12/src/p11_front.c	2022-05-04 18:45:56.000000000 +0200
@@ -34,95 +34,149 @@
 
 void PKCS11_CTX_init_args(PKCS11_CTX *ctx, const char *init_args)
 {
-	if (check_fork(ctx) < 0)
+	if (check_fork(PRIVCTX(ctx)) < 0)
 		return;
 	pkcs11_CTX_init_args(ctx, init_args);
 }
 
 int PKCS11_CTX_load(PKCS11_CTX *ctx, const char *ident)
 {
-	if (check_fork(ctx) < 0)
+	if (check_fork(PRIVCTX(ctx)) < 0)
 		return -1;
 	return pkcs11_CTX_load(ctx, ident);
 }
 
 void PKCS11_CTX_unload(PKCS11_CTX *ctx)
 {
-	if (check_fork(ctx) < 0)
+	if (check_fork(PRIVCTX(ctx)) < 0)
 		return;
 	pkcs11_CTX_unload(ctx);
 }
 
 void PKCS11_CTX_free(PKCS11_CTX *ctx)
 {
-	if (check_fork(ctx) < 0)
+	if (check_fork(PRIVCTX(ctx)) < 0)
 		return;
 	pkcs11_CTX_free(ctx);
 }
 
-int PKCS11_open_session(PKCS11_SLOT *slot, int rw)
+int PKCS11_open_session(PKCS11_SLOT *pslot, int rw)
 {
+	PKCS11_SLOT_private *slot = PRIVSLOT(pslot);
 	if (check_slot_fork(slot) < 0)
 		return -1;
-	return pkcs11_open_session(slot, rw, 0);
+	return pkcs11_open_session(slot, rw);
 }
 
-int PKCS11_enumerate_slots(PKCS11_CTX *ctx,
+int PKCS11_enumerate_slots(PKCS11_CTX *pctx,
 		PKCS11_SLOT **slotsp, unsigned int *nslotsp)
 {
+	PKCS11_CTX_private *ctx = PRIVCTX(pctx);
 	if (check_fork(ctx) < 0)
 		return -1;
+	if (!nslotsp)
+		return -1;
+	if (slotsp)
+		*slotsp = 0;
+	if (nslotsp)
+		*nslotsp = 0;
 	return pkcs11_enumerate_slots(ctx, slotsp, nslotsp);
 }
 
-unsigned long PKCS11_get_slotid_from_slot(PKCS11_SLOT *slot)
+int PKCS11_update_slots(PKCS11_CTX *pctx,
+		PKCS11_SLOT **slotsp, unsigned int *nslotsp)
 {
+	PKCS11_CTX_private *ctx = PRIVCTX(pctx);
+	if (check_fork(ctx) < 0)
+		return -1;
+	if (!nslotsp)
+		return -1;
+	return pkcs11_enumerate_slots(ctx, slotsp, nslotsp);
+}
+
+unsigned long PKCS11_get_slotid_from_slot(PKCS11_SLOT *pslot)
+{
+	PKCS11_SLOT_private *slot = PRIVSLOT(pslot);
 	if (check_slot_fork(slot) < 0)
 		return 0L;
 	return pkcs11_get_slotid_from_slot(slot);
 }
 
-void PKCS11_release_all_slots(PKCS11_CTX *ctx,
+void PKCS11_release_all_slots(PKCS11_CTX *pctx,
 		PKCS11_SLOT *slots, unsigned int nslots)
 {
+	PKCS11_CTX_private *ctx = PRIVCTX(pctx);
 	if (check_fork(ctx) < 0)
 		return;
-	pkcs11_release_all_slots(ctx, slots, nslots);
+	pkcs11_release_all_slots(slots, nslots);
 }
 
 PKCS11_SLOT *PKCS11_find_token(PKCS11_CTX *ctx,
 		PKCS11_SLOT *slots, unsigned int nslots)
 {
-	if (check_fork(ctx) < 0)
+	PKCS11_SLOT *slot, *best;
+	PKCS11_TOKEN *tok;
+	unsigned int n;
+
+	if (check_fork(PRIVCTX(ctx)) < 0)
 		return NULL;
-	return pkcs11_find_token(ctx, slots, nslots);
+	if (!slots)
+		return NULL;
+
+	best = NULL;
+	for (n = 0, slot = slots; n < nslots; n++, slot++) {
+		if ((tok = slot->token) != NULL) {
+			if (!best ||
+					(tok->initialized > best->token->initialized &&
+					tok->userPinSet > best->token->userPinSet &&
+					tok->loginRequired > best->token->loginRequired))
+				best = slot;
+		}
+	}
+	return best;
 }
 
 PKCS11_SLOT *PKCS11_find_next_token(PKCS11_CTX *ctx,
 		PKCS11_SLOT *slots, unsigned int nslots,
 		PKCS11_SLOT *current)
 {
-	if (check_fork(ctx) < 0)
+	int offset;
+
+	if (check_fork(PRIVCTX(ctx)) < 0)
+		return NULL;
+	if (!slots)
 		return NULL;
-	return pkcs11_find_next_token(ctx, slots, nslots, current);
+
+	if (current) {
+		offset = current + 1 - slots;
+		if (offset < 1 || (unsigned int)offset >= nslots)
+			return NULL;
+	} else {
+		offset = 0;
+	}
+
+	return PKCS11_find_token(ctx, slots + offset, nslots - offset);
 }
 
-int PKCS11_is_logged_in(PKCS11_SLOT *slot, int so, int *res)
+int PKCS11_is_logged_in(PKCS11_SLOT *pslot, int so, int *res)
 {
+	PKCS11_SLOT_private *slot = PRIVSLOT(pslot);
 	if (check_slot_fork(slot) < 0)
 		return -1;
 	return pkcs11_is_logged_in(slot, so, res);
 }
 
-int PKCS11_login(PKCS11_SLOT *slot, int so, const char *pin)
+int PKCS11_login(PKCS11_SLOT *pslot, int so, const char *pin)
 {
+	PKCS11_SLOT_private *slot = PRIVSLOT(pslot);
 	if (check_slot_fork(slot) < 0)
 		return -1;
-	return pkcs11_login(slot, so, pin, 0);
+	return pkcs11_login(slot, so, pin);
 }
 
-int PKCS11_logout(PKCS11_SLOT *slot)
+int PKCS11_logout(PKCS11_SLOT *pslot)
 {
+	PKCS11_SLOT_private *slot = PRIVSLOT(pslot);
 	if (check_slot_fork(slot) < 0)
 		return -1;
 	return pkcs11_logout(slot);
@@ -131,57 +185,65 @@
 int PKCS11_enumerate_keys(PKCS11_TOKEN *token,
 		PKCS11_KEY **keys, unsigned int *nkeys)
 {
-	if (check_token_fork(token) < 0)
+	PKCS11_SLOT_private *slot = PRIVSLOT(token->slot);
+	if (check_slot_fork(slot) < 0)
 		return -1;
-	return pkcs11_enumerate_keys(token, CKO_PRIVATE_KEY, keys, nkeys);
+	return pkcs11_enumerate_keys(slot, CKO_PRIVATE_KEY, keys, nkeys);
 }
 
-int PKCS11_remove_key(PKCS11_KEY *key)
+int PKCS11_remove_key(PKCS11_KEY *pkey)
 {
-	if (check_key_fork(key) < 0)
+	PKCS11_OBJECT_private *key = PRIVKEY(pkey);
+	if (check_object_fork(key) < 0)
 		return -1;
-	return pkcs11_remove_key(key);
+	return pkcs11_remove_object(key);
 }
 
 int PKCS11_enumerate_public_keys(PKCS11_TOKEN *token,
 		PKCS11_KEY **keys, unsigned int *nkeys)
 {
-	if (check_token_fork(token) < 0)
+	PKCS11_SLOT_private *slot = PRIVSLOT(token->slot);
+	if (check_slot_fork(slot) < 0)
 		return -1;
-	return pkcs11_enumerate_keys(token, CKO_PUBLIC_KEY, keys, nkeys);
+	return pkcs11_enumerate_keys(slot, CKO_PUBLIC_KEY, keys, nkeys);
 }
 
-int PKCS11_get_key_type(PKCS11_KEY *key)
+int PKCS11_get_key_type(PKCS11_KEY *pkey)
 {
-	if (check_key_fork(key) < 0)
+	PKCS11_OBJECT_private *key = PRIVKEY(pkey);
+	if (check_object_fork(key) < 0)
 		return -1;
 	return pkcs11_get_key_type(key);
 }
 
-EVP_PKEY *PKCS11_get_private_key(PKCS11_KEY *key)
+EVP_PKEY *PKCS11_get_private_key(PKCS11_KEY *pkey)
 {
-	if (check_key_fork(key) < 0)
+	PKCS11_OBJECT_private *key = PRIVKEY(pkey);
+	if (check_object_fork(key) < 0)
 		return NULL;
-	return pkcs11_get_key(key, 1);
+	return pkcs11_get_key(key, CKO_PRIVATE_KEY);
 }
 
-EVP_PKEY *PKCS11_get_public_key(PKCS11_KEY *key)
+EVP_PKEY *PKCS11_get_public_key(PKCS11_KEY *pkey)
 {
-	if (check_key_fork(key) < 0)
+	PKCS11_OBJECT_private *key = PRIVKEY(pkey);
+	if (check_object_fork(key) < 0)
 		return NULL;
-	return pkcs11_get_key(key, 0);
+	return pkcs11_get_key(key, CKO_PUBLIC_KEY);
 }
 
-PKCS11_CERT *PKCS11_find_certificate(PKCS11_KEY *key)
+PKCS11_CERT *PKCS11_find_certificate(PKCS11_KEY *pkey)
 {
-	if (check_key_fork(key) < 0)
+	PKCS11_OBJECT_private *key = PRIVKEY(pkey);
+	if (check_object_fork(key) < 0)
 		return NULL;
 	return pkcs11_find_certificate(key);
 }
 
-PKCS11_KEY *PKCS11_find_key(PKCS11_CERT *cert)
+PKCS11_KEY *PKCS11_find_key(PKCS11_CERT *pcert)
 {
-	if (check_cert_fork(cert) < 0)
+	PKCS11_OBJECT_private *cert = PRIVCERT(pcert);
+	if (check_object_fork(cert) < 0)
 		return NULL;
 	return pkcs11_find_key(cert);
 }
@@ -189,75 +251,100 @@
 int PKCS11_enumerate_certs(PKCS11_TOKEN *token,
 		PKCS11_CERT **certs, unsigned int *ncerts)
 {
-	if (check_token_fork(token) < 0)
+	PKCS11_SLOT_private *slot = PRIVSLOT(token->slot);
+	if (check_slot_fork(slot) < 0)
 		return -1;
-	return pkcs11_enumerate_certs(token, certs, ncerts);
+	return pkcs11_enumerate_certs(slot, certs, ncerts);
 }
 
-int PKCS11_remove_certificate(PKCS11_CERT *cert)
+int PKCS11_remove_certificate(PKCS11_CERT *pcert)
 {
-	if (check_cert_fork(cert) < 0)
+	PKCS11_OBJECT_private *cert = PRIVCERT(pcert);
+	if (check_object_fork(cert) < 0)
 		return -1;
-	return pkcs11_remove_certificate(cert);
+	return pkcs11_remove_object(cert);
 }
 
 int PKCS11_init_token(PKCS11_TOKEN *token, const char *pin,
 		const char *label)
 {
-	if (check_token_fork(token) < 0)
+	PKCS11_SLOT_private *slot = PRIVSLOT(token->slot);
+	if (check_slot_fork(slot) < 0)
 		return -1;
-	return pkcs11_init_token(token, pin, label);
+	return pkcs11_init_token(slot, pin, label);
 }
 
 int PKCS11_init_pin(PKCS11_TOKEN *token, const char *pin)
 {
-	if (check_token_fork(token) < 0)
+	PKCS11_SLOT_private *slot = PRIVSLOT(token->slot);
+	int r;
+
+	if (check_slot_fork(slot) < 0)
 		return -1;
-	return pkcs11_init_pin(token, pin);
+	r = pkcs11_init_pin(slot, pin);
+	if (r == 0)
+		r = pkcs11_refresh_token(token->slot);
+	return r;
 }
 
-int PKCS11_change_pin(PKCS11_SLOT *slot,
+int PKCS11_change_pin(PKCS11_SLOT *pslot,
 		const char *old_pin, const char *new_pin)
 {
+	PKCS11_SLOT_private *slot = PRIVSLOT(pslot);
+	int r;
+
 	if (check_slot_fork(slot) < 0)
 		return -1;
-	return pkcs11_change_pin(slot, old_pin, new_pin);
+	r = pkcs11_change_pin(slot, old_pin, new_pin);
+	if (r == 0)
+		r = pkcs11_refresh_token(pslot);
+	return r;
 }
 
 int PKCS11_store_private_key(PKCS11_TOKEN *token,
 		EVP_PKEY *pk, char *label, unsigned char *id, size_t id_len)
 {
-	if (check_token_fork(token) < 0)
+	PKCS11_SLOT_private *slot = PRIVSLOT(token->slot);
+	if (check_slot_fork(slot) < 0)
 		return -1;
-	return pkcs11_store_private_key(token, pk, label, id, id_len);
+	return pkcs11_store_private_key(slot, pk, label, id, id_len);
 }
 
 int PKCS11_store_public_key(PKCS11_TOKEN *token,
     	EVP_PKEY *pk, char *label, unsigned char *id, size_t id_len)
 {
-	if (check_token_fork(token) < 0)
+	PKCS11_SLOT_private *slot = PRIVSLOT(token->slot);
+	if (check_slot_fork(slot) < 0)
 		return -1;
-	return pkcs11_store_public_key(token, pk, label, id, id_len);
+	return pkcs11_store_public_key(slot, pk, label, id, id_len);
 }
 
 int PKCS11_store_certificate(PKCS11_TOKEN *token, X509 *x509,
 		char *label, unsigned char *id, size_t id_len,
 		PKCS11_CERT **ret_cert)
 {
-	if (check_token_fork(token) < 0)
+	PKCS11_SLOT_private *slot = PRIVSLOT(token->slot);
+	if (check_slot_fork(slot) < 0)
 		return -1;
-	return pkcs11_store_certificate(token, x509, label, id, id_len, ret_cert);
+	return pkcs11_store_certificate(slot, x509, label, id, id_len, ret_cert);
 }
 
-int PKCS11_seed_random(PKCS11_SLOT *slot, const unsigned char *s, unsigned int s_len)
+int PKCS11_seed_random(PKCS11_SLOT *pslot, const unsigned char *s, unsigned int s_len)
 {
+	PKCS11_SLOT_private *slot = PRIVSLOT(pslot);
+	int r;
+
 	if (check_slot_fork(slot) < 0)
 		return -1;
-	return pkcs11_seed_random(slot, s, s_len);
+	r = pkcs11_seed_random(slot, s, s_len);
+	if (r == 0)
+		r = pkcs11_refresh_token(pslot);
+	return r;
 }
 
-int PKCS11_generate_random(PKCS11_SLOT *slot, unsigned char *r, unsigned int r_len)
+int PKCS11_generate_random(PKCS11_SLOT *pslot, unsigned char *r, unsigned int r_len)
 {
+	PKCS11_SLOT_private *slot = PRIVSLOT(pslot);
 	if (check_slot_fork(slot) < 0)
 		return -1;
 	return pkcs11_generate_random(slot, r, r_len);
@@ -272,8 +359,9 @@
 	ERR_load_CKR_strings();
 }
 
-int PKCS11_set_ui_method(PKCS11_CTX *ctx, UI_METHOD *ui_method, void *ui_user_data)
+int PKCS11_set_ui_method(PKCS11_CTX *pctx, UI_METHOD *ui_method, void *ui_user_data)
 {
+	PKCS11_CTX_private *ctx = PRIVCTX(pctx);
 	if (check_fork(ctx) < 0)
 		return -1;
 	return pkcs11_set_ui_method(ctx, ui_method, ui_user_data);
@@ -285,52 +373,59 @@
 		int algorithm, unsigned int bits,
 		char *label, unsigned char *id, size_t id_len)
 {
-	if (check_token_fork(token) < 0)
+	PKCS11_SLOT_private *slot = PRIVSLOT(token->slot);
+	if (check_slot_fork(slot) < 0)
 		return -1;
-	return pkcs11_generate_key(token, algorithm, bits, label, id, id_len);
+	return pkcs11_generate_key(slot, algorithm, bits, label, id, id_len);
 }
 
-int PKCS11_get_key_size(PKCS11_KEY *key)
+int PKCS11_get_key_size(PKCS11_KEY *pkey)
 {
-	if (check_key_fork(key) < 0)
+	PKCS11_OBJECT_private *key = PRIVKEY(pkey);
+	if (check_object_fork(key) < 0)
 		return -1;
 	return pkcs11_get_key_size(key);
 }
 
-int PKCS11_get_key_modulus(PKCS11_KEY *key, BIGNUM **bn)
+int PKCS11_get_key_modulus(PKCS11_KEY *pkey, BIGNUM **bn)
 {
-	if (check_key_fork(key) < 0)
+	PKCS11_OBJECT_private *key = PRIVKEY(pkey);
+	if (check_object_fork(key) < 0)
 		return -1;
 	return pkcs11_get_key_modulus(key, bn);
 }
 
-int PKCS11_get_key_exponent(PKCS11_KEY *key, BIGNUM **bn)
+int PKCS11_get_key_exponent(PKCS11_KEY *pkey, BIGNUM **bn)
 {
-	if (check_key_fork(key) < 0)
+	PKCS11_OBJECT_private *key = PRIVKEY(pkey);
+	if (check_object_fork(key) < 0)
 		return -1;
 	return pkcs11_get_key_exponent(key, bn);
 }
 
 int PKCS11_sign(int type, const unsigned char *m, unsigned int m_len,
-		unsigned char *sigret, unsigned int *siglen, PKCS11_KEY *key)
+		unsigned char *sigret, unsigned int *siglen, PKCS11_KEY *pkey)
 {
-	if (check_key_fork(key) < 0)
+	PKCS11_OBJECT_private *key = PRIVKEY(pkey);
+	if (check_object_fork(key) < 0)
 		return -1;
 	return pkcs11_sign(type, m, m_len, sigret, siglen, key);
 }
 
 int PKCS11_private_encrypt(int flen, const unsigned char *from, unsigned char *to,
-		PKCS11_KEY *key, int padding)
+		PKCS11_KEY *pkey, int padding)
 {
-	if (check_key_fork(key) < 0)
+	PKCS11_OBJECT_private *key = PRIVKEY(pkey);
+	if (check_object_fork(key) < 0)
 		return -1;
 	return pkcs11_private_encrypt(flen, from, to, key, padding);
 }
 
 int PKCS11_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
-		PKCS11_KEY *key, int padding)
+		PKCS11_KEY *pkey, int padding)
 {
-	if (check_key_fork(key) < 0)
+	PKCS11_OBJECT_private *key = PRIVKEY(pkey);
+	if (check_object_fork(key) < 0)
 		return -1;
 	return pkcs11_private_decrypt(flen, from, to, key, padding);
 }
diff -Nru libp11-0.4.11/src/p11_key.c libp11-0.4.12/src/p11_key.c
--- libp11-0.4.11/src/p11_key.c	2020-10-04 22:13:22.000000000 +0200
+++ libp11-0.4.12/src/p11_key.c	2022-07-05 22:22:51.000000000 +0200
@@ -22,172 +22,288 @@
 #include <openssl/ui.h>
 #include <openssl/bn.h>
 
-#ifdef _WIN32
+#if defined(_WIN32) && !defined(strncasecmp)
 #define strncasecmp strnicmp
 #endif
 
 /* The maximum length of PIN */
 #define MAX_PIN_LENGTH   32
 
-static int pkcs11_find_keys(PKCS11_TOKEN *, unsigned int);
-static int pkcs11_next_key(PKCS11_CTX *ctx, PKCS11_TOKEN *token,
+static int pkcs11_find_keys(PKCS11_SLOT_private *, CK_SESSION_HANDLE, unsigned int);
+static int pkcs11_next_key(PKCS11_CTX_private *ctx, PKCS11_SLOT_private *,
 	CK_SESSION_HANDLE session, CK_OBJECT_CLASS type);
-static int pkcs11_init_key(PKCS11_CTX *ctx, PKCS11_TOKEN *token,
-	CK_SESSION_HANDLE session, CK_OBJECT_HANDLE o,
-	CK_OBJECT_CLASS type, PKCS11_KEY **);
-static int pkcs11_store_key(PKCS11_TOKEN *, EVP_PKEY *, unsigned int,
+static int pkcs11_init_key(PKCS11_SLOT_private *, CK_SESSION_HANDLE session,
+	CK_OBJECT_HANDLE o, CK_OBJECT_CLASS type, PKCS11_KEY **);
+static int pkcs11_store_key(PKCS11_SLOT_private *, EVP_PKEY *, CK_OBJECT_CLASS,
 	char *, unsigned char *, size_t, PKCS11_KEY **);
 
-/* Set UI method to allow retrieving CKU_CONTEXT_SPECIFIC PINs interactively */
-int pkcs11_set_ui_method(PKCS11_CTX *ctx,
-		UI_METHOD *ui_method, void *ui_user_data)
+/* Helper to acquire object handle from given template */
+static CK_OBJECT_HANDLE pkcs11_handle_from_template(PKCS11_SLOT_private *slot,
+	CK_SESSION_HANDLE session, PKCS11_TEMPLATE *tmpl)
 {
-	PKCS11_CTX_private *cpriv = PRIVCTX(ctx);
-	if (!cpriv)
-		return -1;
-	cpriv->ui_method = ui_method;
-	cpriv->ui_user_data = ui_user_data;
-	return 0;
+	PKCS11_CTX_private *ctx = slot->ctx;
+	CK_OBJECT_HANDLE object;
+	CK_ULONG count;
+	CK_RV rv;
+
+	rv = CRYPTOKI_call(ctx,
+		C_FindObjectsInit(session, tmpl->attrs, tmpl->nattr));
+	if (rv == CKR_OK) {
+		rv = CRYPTOKI_call(ctx,
+			C_FindObjects(session, &object, 1, &count));
+		CRYPTOKI_call(ctx, C_FindObjectsFinal(session));
+	}
+	pkcs11_zap_attrs(tmpl);
+
+	if (rv == CKR_OK && count == 1)
+		return object;
+
+	return CK_INVALID_HANDLE;
 }
 
-/*
- * Find private key matching a certificate
- */
-PKCS11_KEY *pkcs11_find_key(PKCS11_CERT *cert)
+/* Get object from a handle */
+PKCS11_OBJECT_private *pkcs11_object_from_handle(PKCS11_SLOT_private *slot,
+		CK_SESSION_HANDLE session, CK_OBJECT_HANDLE object)
 {
-	PKCS11_CERT_private *cpriv = PRIVCERT(cert);
-	PKCS11_KEY *keys;
-	unsigned int n, count;
+	PKCS11_CTX_private *ctx = slot->ctx;
+	PKCS11_OBJECT_private *obj;
+	PKCS11_OBJECT_ops *ops = NULL;
+	CK_OBJECT_CLASS object_class = -1;
+	CK_KEY_TYPE key_type = -1;
+	CK_CERTIFICATE_TYPE cert_type = -1;
+	size_t size;
+	unsigned char *data;
 
-	if (pkcs11_enumerate_keys(CERT2TOKEN(cert), CKO_PRIVATE_KEY, &keys, &count))
+	if (pkcs11_getattr_val(ctx, session, object, CKA_CLASS,
+			(CK_BYTE *) &object_class, sizeof(object_class)))
+		return NULL;
+
+	switch (object_class) {
+	case CKO_PUBLIC_KEY:
+	case CKO_PRIVATE_KEY:
+		if (pkcs11_getattr_val(ctx, session, object, CKA_KEY_TYPE,
+				(CK_BYTE *)&key_type, sizeof(key_type)))
+			return NULL;
+		switch (key_type) {
+		case CKK_RSA:
+			ops = &pkcs11_rsa_ops;
+			break;
+#ifndef OPENSSL_NO_EC
+		case CKK_EC:
+			ops = &pkcs11_ec_ops;
+			break;
+#endif
+		default:
+			/* Ignore any keys we don't understand */
+			return 0;
+		}
+		break;
+	case CKO_CERTIFICATE:
+		if (pkcs11_getattr_val(ctx, session, object, CKA_CERTIFICATE_TYPE,
+				(CK_BYTE *)&cert_type, sizeof(cert_type)))
+			return NULL;
+		/* Ignore unknown certificate types */
+		if (cert_type != CKC_X_509)
+			return 0;
+		break;
+	default:
 		return NULL;
-	for (n = 0; n < count; n++) {
-		PKCS11_KEY_private *kpriv = PRIVKEY(&keys[n]);
-		if (kpriv && cpriv->id_len == kpriv->id_len
-				&& !memcmp(cpriv->id, kpriv->id, cpriv->id_len))
-			return &keys[n];
 	}
-	return NULL;
+
+	obj = OPENSSL_malloc(sizeof(*obj));
+	if (!obj)
+		return NULL;
+
+	memset(obj, 0, sizeof(*obj));
+	obj->object_class = object_class;
+	obj->object = object;
+	obj->slot = pkcs11_slot_ref(slot);
+	obj->id_len = sizeof(obj->id);
+	if (pkcs11_getattr_var(ctx, session, object, CKA_ID, obj->id, &obj->id_len))
+		obj->id_len = 0;
+	pkcs11_getattr_alloc(ctx, session, object, CKA_LABEL, (CK_BYTE **)&obj->label, NULL);
+	obj->ops = ops;
+	obj->forkid = get_forkid();
+	switch (object_class) {
+	case CKO_PRIVATE_KEY:
+		if (pkcs11_getattr_val(ctx, session, object, CKA_ALWAYS_AUTHENTICATE,
+				&obj->always_authenticate, sizeof(CK_BBOOL))) {
+#ifdef DEBUG
+			fprintf(stderr, "Missing CKA_ALWAYS_AUTHENTICATE attribute\n");
+#endif
+		}
+		break;
+	case CKO_CERTIFICATE:
+		if (!pkcs11_getattr_alloc(ctx, session, object, CKA_VALUE,
+				&data, &size)) {
+			const unsigned char *p = data;
+			obj->x509 = d2i_X509(NULL, &p, (long)size);
+			OPENSSL_free(data);
+		}
+		break;
+	}
+	return obj;
+}
+
+/* Get object based on template */
+PKCS11_OBJECT_private *pkcs11_object_from_template(PKCS11_SLOT_private *slot,
+	CK_SESSION_HANDLE session, PKCS11_TEMPLATE *tmpl)
+{
+	PKCS11_OBJECT_private *obj;
+	int release = 0;
+
+	if (session == CK_INVALID_HANDLE) {
+		if (pkcs11_get_session(slot, 0, &session))
+			return NULL;
+		release = 1;
+	}
+
+	obj = pkcs11_object_from_handle(slot, session,
+		pkcs11_handle_from_template(slot, session, tmpl));
+
+	if (release)
+		pkcs11_put_session(slot, session);
+
+	return obj;
+}
+
+PKCS11_OBJECT_private *pkcs11_object_from_object(PKCS11_OBJECT_private *obj,
+	CK_SESSION_HANDLE session, CK_OBJECT_CLASS object_class)
+{
+	PKCS11_TEMPLATE tmpl = {0};
+	pkcs11_addattr_var(&tmpl, CKA_CLASS, object_class);
+	pkcs11_addattr(&tmpl, CKA_ID, obj->id, obj->id_len);
+	return pkcs11_object_from_template(obj->slot, session, &tmpl);
+}
+
+void pkcs11_object_free(PKCS11_OBJECT_private *obj)
+{
+	if (obj->evp_key) {
+		/* When the EVP object is reference count goes to zero,
+		 * it will call this function again. */
+		EVP_PKEY *pkey = obj->evp_key;
+		obj->evp_key = NULL;
+		EVP_PKEY_free(pkey);
+		return;
+	}
+	pkcs11_slot_unref(obj->slot);
+	X509_free(obj->x509);
+	OPENSSL_free(obj->label);
+	OPENSSL_free(obj);
+}
+
+/* Set UI method to allow retrieving CKU_CONTEXT_SPECIFIC PINs interactively */
+int pkcs11_set_ui_method(PKCS11_CTX_private *ctx,
+		UI_METHOD *ui_method, void *ui_user_data)
+{
+	if (!ctx)
+		return -1;
+	ctx->ui_method = ui_method;
+	ctx->ui_user_data = ui_user_data;
+	return 0;
 }
 
 /*
- * Find key matching a key of the other type (public vs private)
+ * Find private key matching a certificate
  */
-PKCS11_KEY *pkcs11_find_key_from_key(PKCS11_KEY *keyin)
+PKCS11_KEY *pkcs11_find_key(PKCS11_OBJECT_private *cert)
 {
-	PKCS11_KEY_private *kinpriv = PRIVKEY(keyin);
 	PKCS11_KEY *keys;
-	unsigned int n, count, type =
-		keyin->isPrivate ? CKO_PUBLIC_KEY : CKO_PRIVATE_KEY;
+	unsigned int n, count;
 
-	if (pkcs11_enumerate_keys(KEY2TOKEN(keyin), type, &keys, &count))
+	if (pkcs11_enumerate_keys(cert->slot, CKO_PRIVATE_KEY, &keys, &count))
 		return NULL;
 	for (n = 0; n < count; n++) {
-		PKCS11_KEY_private *kpriv = PRIVKEY(&keys[n]);
-		if (kpriv && kinpriv->id_len == kpriv->id_len
-				&& !memcmp(kinpriv->id, kpriv->id, kinpriv->id_len))
+		PKCS11_OBJECT_private *kpriv = PRIVKEY(&keys[n]);
+		if (kpriv && cert->id_len == kpriv->id_len
+				&& !memcmp(cert->id, kpriv->id, cert->id_len))
 			return &keys[n];
 	}
 	return NULL;
 }
 
 /*
- * Reopens the object associated with the key
+ * Reopens the object by refresing the object handle
  */
-int pkcs11_reload_key(PKCS11_KEY *key)
+int pkcs11_reload_object(PKCS11_OBJECT_private *obj)
 {
-	PKCS11_KEY_private *kpriv = PRIVKEY(key);
-	PKCS11_SLOT *slot = KEY2SLOT(key);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
-	PKCS11_CTX *ctx = SLOT2CTX(slot);
-	CK_OBJECT_CLASS key_search_class =
-		key->isPrivate ? CKO_PRIVATE_KEY : CKO_PUBLIC_KEY;
-	CK_ATTRIBUTE key_search_attrs[2] = {
-		{CKA_CLASS, &key_search_class, sizeof(key_search_class)},
-		{CKA_ID, kpriv->id, kpriv->id_len},
-	};
-	CK_ULONG count;
-	int rv;
+	PKCS11_SLOT_private *slot = obj->slot;
+	CK_SESSION_HANDLE session;
+	PKCS11_TEMPLATE tmpl = {0};
 
-	/* this is already covered with a per-ctx lock */
+	if (pkcs11_get_session(slot, 0, &session))
+		return -1;
 
-	rv = CRYPTOKI_call(ctx,
-		C_FindObjectsInit(spriv->session, key_search_attrs, 2));
-	CRYPTOKI_checkerr(CKR_F_PKCS11_RELOAD_KEY, rv);
+	pkcs11_addattr_var(&tmpl, CKA_CLASS, obj->object_class);
+	if (obj->id_len)
+		pkcs11_addattr(&tmpl, CKA_ID, obj->id, obj->id_len);
+	if (obj->label)
+		pkcs11_addattr_s(&tmpl, CKA_LABEL, obj->label);
 
-	rv = CRYPTOKI_call(ctx,
-		C_FindObjects(spriv->session, &kpriv->object, 1, &count));
-	CRYPTOKI_checkerr(CKR_F_PKCS11_RELOAD_KEY, rv);
+	obj->object = pkcs11_handle_from_template(slot, session, &tmpl);
+	pkcs11_put_session(slot, session);
 
-	CRYPTOKI_call(ctx, C_FindObjectsFinal(spriv->session));
+	if (obj->object == CK_INVALID_HANDLE)
+		CRYPTOKI_checkerr(CKR_F_PKCS11_RELOAD_KEY, CKR_OBJECT_HANDLE_INVALID);
 
 	return 0;
 }
 
 /**
- * Generate a keyPair directly on token
+ * Generate a key pair directly on token
  */
-int pkcs11_generate_key(PKCS11_TOKEN *token, int algorithm, unsigned int bits,
+int pkcs11_generate_key(PKCS11_SLOT_private *slot, int algorithm, unsigned int bits,
 		char *label, unsigned char* id, size_t id_len) {
 
-	PKCS11_SLOT *slot = TOKEN2SLOT(token);
-	PKCS11_CTX *ctx = TOKEN2CTX(token);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
-
-	CK_ATTRIBUTE pubkey_attrs[32];
-	CK_ATTRIBUTE privkey_attrs[32];
-	unsigned int n_pub = 0, n_priv = 0;
+	PKCS11_CTX_private *ctx = slot->ctx;
+	CK_SESSION_HANDLE session;
+	PKCS11_TEMPLATE pubtmpl = {0}, privtmpl = {0};
 	CK_MECHANISM mechanism = {
 		CKM_RSA_PKCS_KEY_PAIR_GEN, NULL_PTR, 0
 	};
+	CK_ULONG num_bits = bits;
 	CK_BYTE public_exponent[] = { 1, 0, 1 };
 	CK_OBJECT_HANDLE pub_key_obj, priv_key_obj;
 	int rv;
 
 	(void)algorithm; /* squash the unused parameter warning */
 
-	/* make sure we have a session */
-	if (!spriv->haveSession && PKCS11_open_session(slot, 1))
+	if (pkcs11_get_session(slot, 1, &session))
 		return -1;
 
 	/* pubkey attributes */
-	pkcs11_addattr(pubkey_attrs + n_pub++, CKA_ID, id, id_len);
+	pkcs11_addattr(&pubtmpl, CKA_ID, id, id_len);
 	if (label)
-		pkcs11_addattr_s(pubkey_attrs + n_pub++, CKA_LABEL, label);
-	pkcs11_addattr_bool(pubkey_attrs + n_pub++, CKA_TOKEN, TRUE);
-
-	pkcs11_addattr_bool(pubkey_attrs + n_pub++, CKA_ENCRYPT, TRUE);
-	pkcs11_addattr_bool(pubkey_attrs + n_pub++, CKA_VERIFY, TRUE);
-	pkcs11_addattr_bool(pubkey_attrs + n_pub++, CKA_WRAP, TRUE);
-	pkcs11_addattr_int(pubkey_attrs + n_pub++, CKA_MODULUS_BITS, bits);
-	pkcs11_addattr(pubkey_attrs + n_pub++, CKA_PUBLIC_EXPONENT, public_exponent, 3);
+		pkcs11_addattr_s(&pubtmpl, CKA_LABEL, label);
+	pkcs11_addattr_bool(&pubtmpl, CKA_TOKEN, TRUE);
+	pkcs11_addattr_bool(&pubtmpl, CKA_ENCRYPT, TRUE);
+	pkcs11_addattr_bool(&pubtmpl, CKA_VERIFY, TRUE);
+	pkcs11_addattr_bool(&pubtmpl, CKA_WRAP, TRUE);
+	pkcs11_addattr_var(&pubtmpl, CKA_MODULUS_BITS, num_bits);
+	pkcs11_addattr(&pubtmpl, CKA_PUBLIC_EXPONENT, public_exponent, 3);
 
 	/* privkey attributes */
-	pkcs11_addattr(privkey_attrs + n_priv++, CKA_ID, id, id_len);
+	pkcs11_addattr(&privtmpl, CKA_ID, id, id_len);
 	if (label)
-		pkcs11_addattr_s(privkey_attrs + n_priv++, CKA_LABEL, label);
-	pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_TOKEN, TRUE);
-	pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_PRIVATE, TRUE);
-	pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_SENSITIVE, TRUE);
-	pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_DECRYPT, TRUE);
-	pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_SIGN, TRUE);
-	pkcs11_addattr_bool(privkey_attrs + n_priv++, CKA_UNWRAP, TRUE);
+		pkcs11_addattr_s(&privtmpl, CKA_LABEL, label);
+	pkcs11_addattr_bool(&privtmpl, CKA_TOKEN, TRUE);
+	pkcs11_addattr_bool(&privtmpl, CKA_PRIVATE, TRUE);
+	pkcs11_addattr_bool(&privtmpl, CKA_SENSITIVE, TRUE);
+	pkcs11_addattr_bool(&privtmpl, CKA_DECRYPT, TRUE);
+	pkcs11_addattr_bool(&privtmpl, CKA_SIGN, TRUE);
+	pkcs11_addattr_bool(&privtmpl, CKA_UNWRAP, TRUE);
 
 	/* call the pkcs11 module to create the key pair */
 	rv = CRYPTOKI_call(ctx, C_GenerateKeyPair(
-		spriv->session,
-		&mechanism,
-		pubkey_attrs,
-		n_pub,
-		privkey_attrs,
-		n_priv,
-		&pub_key_obj,
-		&priv_key_obj
-	));
+		session, &mechanism,
+		pubtmpl.attrs, pubtmpl.nattr,
+		privtmpl.attrs, privtmpl.nattr,
+		&pub_key_obj, &priv_key_obj));
+	pkcs11_put_session(slot, session);
 
 	/* zap all memory allocated when building the template */
-	pkcs11_zap_attrs(privkey_attrs, n_priv);
-	pkcs11_zap_attrs(pubkey_attrs, n_pub);
+	pkcs11_zap_attrs(&privtmpl);
+	pkcs11_zap_attrs(&pubtmpl);
 
 	CRYPTOKI_checkerr(CKR_F_PKCS11_GENERATE_KEY, rv);
 
@@ -197,18 +313,18 @@
 /*
  * Store a private key on the token
  */
-int pkcs11_store_private_key(PKCS11_TOKEN *token, EVP_PKEY *pk,
+int pkcs11_store_private_key(PKCS11_SLOT_private *slot, EVP_PKEY *pk,
 		char *label, unsigned char *id, size_t id_len)
 {
-	if (pkcs11_store_key(token, pk, CKO_PRIVATE_KEY, label, id, id_len, NULL))
+	if (pkcs11_store_key(slot, pk, CKO_PRIVATE_KEY, label, id, id_len, NULL))
 		return -1;
 	return 0;
 }
 
-int pkcs11_store_public_key(PKCS11_TOKEN *token, EVP_PKEY *pk,
+int pkcs11_store_public_key(PKCS11_SLOT_private *slot, EVP_PKEY *pk,
 		char *label, unsigned char *id, size_t id_len)
 {
-	if (pkcs11_store_key(token, pk, CKO_PUBLIC_KEY, label, id, id_len, NULL))
+	if (pkcs11_store_key(slot, pk, CKO_PUBLIC_KEY, label, id, id_len, NULL))
 		return -1;
 	return 0;
 }
@@ -216,45 +332,39 @@
 /*
  * Store private key
  */
-static int pkcs11_store_key(PKCS11_TOKEN *token, EVP_PKEY *pk,
-		unsigned int type, char *label, unsigned char *id, size_t id_len,
+static int pkcs11_store_key(PKCS11_SLOT_private *slot, EVP_PKEY *pk,
+		CK_OBJECT_CLASS type, char *label, unsigned char *id, size_t id_len,
 		PKCS11_KEY ** ret_key)
 {
-	PKCS11_SLOT *slot = TOKEN2SLOT(token);
-	PKCS11_CTX *ctx = TOKEN2CTX(token);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
+	PKCS11_CTX_private *ctx = slot->ctx;
+	PKCS11_TEMPLATE tmpl = {0};
+	CK_SESSION_HANDLE session;
 	CK_OBJECT_HANDLE object;
-	CK_ATTRIBUTE attrs[32];
-	unsigned int n = 0;
-	int rv;
+	CK_KEY_TYPE key_type_rsa = CKK_RSA;
+	int rv, r = -1;
 	const BIGNUM *rsa_n, *rsa_e, *rsa_d, *rsa_p, *rsa_q, *rsa_dmp1, *rsa_dmq1, *rsa_iqmp;
 
-	/* First, make sure we have a session */
-	if (!spriv->haveSession && PKCS11_open_session(slot, 1))
-		return -1;
-
 	/* Now build the key attrs */
-	pkcs11_addattr_int(attrs + n++, CKA_CLASS, type);
+	pkcs11_addattr_var(&tmpl, CKA_CLASS, type);
 	if (label)
-		pkcs11_addattr_s(attrs + n++, CKA_LABEL, label);
+		pkcs11_addattr_s(&tmpl, CKA_LABEL, label);
 	if (id && id_len)
-		pkcs11_addattr(attrs + n++, CKA_ID, id, id_len);
-	pkcs11_addattr_bool(attrs + n++, CKA_TOKEN, TRUE);
+		pkcs11_addattr(&tmpl, CKA_ID, id, id_len);
+	pkcs11_addattr_bool(&tmpl, CKA_TOKEN, TRUE);
 	if (type == CKO_PRIVATE_KEY) {
-		pkcs11_addattr_bool(attrs + n++, CKA_PRIVATE, TRUE);
-		pkcs11_addattr_bool(attrs + n++, CKA_SENSITIVE, TRUE);
-		pkcs11_addattr_bool(attrs + n++, CKA_DECRYPT, TRUE);
-		pkcs11_addattr_bool(attrs + n++, CKA_SIGN, TRUE);
-		pkcs11_addattr_bool(attrs + n++, CKA_UNWRAP, TRUE);
+		pkcs11_addattr_bool(&tmpl, CKA_PRIVATE, TRUE);
+		pkcs11_addattr_bool(&tmpl, CKA_SENSITIVE, TRUE);
+		pkcs11_addattr_bool(&tmpl, CKA_DECRYPT, TRUE);
+		pkcs11_addattr_bool(&tmpl, CKA_SIGN, TRUE);
+		pkcs11_addattr_bool(&tmpl, CKA_UNWRAP, TRUE);
 	} else { /* CKO_PUBLIC_KEY */
-		pkcs11_addattr_bool(attrs + n++, CKA_ENCRYPT, TRUE);
-		pkcs11_addattr_bool(attrs + n++, CKA_VERIFY, TRUE);
-		pkcs11_addattr_bool(attrs + n++, CKA_WRAP, TRUE);
+		pkcs11_addattr_bool(&tmpl, CKA_ENCRYPT, TRUE);
+		pkcs11_addattr_bool(&tmpl, CKA_VERIFY, TRUE);
+		pkcs11_addattr_bool(&tmpl, CKA_WRAP, TRUE);
 	}
-#if OPENSSL_VERSION_NUMBER >= 0x10100003L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100003L || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3050000fL )
 	if (EVP_PKEY_base_id(pk) == EVP_PKEY_RSA) {
 		RSA *rsa = EVP_PKEY_get1_RSA(pk);
-		pkcs11_addattr_int(attrs + n++, CKA_KEY_TYPE, CKK_RSA);
 		RSA_get0_key(rsa, &rsa_n, &rsa_e, &rsa_d);
 		RSA_get0_factors(rsa, &rsa_p, &rsa_q);
 		RSA_get0_crt_params(rsa, &rsa_dmp1, &rsa_dmq1, &rsa_iqmp);
@@ -262,7 +372,6 @@
 #else
 	if (pk->type == EVP_PKEY_RSA) {
 		RSA *rsa = pk->pkey.rsa;
-		pkcs11_addattr_int(attrs + n++, CKA_KEY_TYPE, CKK_RSA);
 		rsa_n=rsa->n;
 		rsa_e=rsa->e;
 		rsa_d=rsa->d;
@@ -272,107 +381,114 @@
 		rsa_dmq1=rsa->dmq1;
 		rsa_iqmp=rsa->iqmp;
 #endif
-		pkcs11_addattr_bn(attrs + n++, CKA_MODULUS, rsa_n);
-		pkcs11_addattr_bn(attrs + n++, CKA_PUBLIC_EXPONENT, rsa_e);
+		pkcs11_addattr_var(&tmpl, CKA_KEY_TYPE, key_type_rsa);
+		pkcs11_addattr_bn(&tmpl, CKA_MODULUS, rsa_n);
+		pkcs11_addattr_bn(&tmpl, CKA_PUBLIC_EXPONENT, rsa_e);
 		if (type == CKO_PRIVATE_KEY) {
-			pkcs11_addattr_bn(attrs + n++, CKA_PRIVATE_EXPONENT, rsa_d);
-			pkcs11_addattr_bn(attrs + n++, CKA_PRIME_1, rsa_p);
-			pkcs11_addattr_bn(attrs + n++, CKA_PRIME_2, rsa_q);
+			pkcs11_addattr_bn(&tmpl, CKA_PRIVATE_EXPONENT, rsa_d);
+			pkcs11_addattr_bn(&tmpl, CKA_PRIME_1, rsa_p);
+			pkcs11_addattr_bn(&tmpl, CKA_PRIME_2, rsa_q);
 			if (rsa_dmp1)
-				pkcs11_addattr_bn(attrs + n++, CKA_EXPONENT_1, rsa_dmp1);
+				pkcs11_addattr_bn(&tmpl, CKA_EXPONENT_1, rsa_dmp1);
 			if (rsa_dmq1)
-				pkcs11_addattr_bn(attrs + n++, CKA_EXPONENT_2, rsa_dmq1);
+				pkcs11_addattr_bn(&tmpl, CKA_EXPONENT_2, rsa_dmq1);
 			if (rsa_iqmp)
-				pkcs11_addattr_bn(attrs + n++, CKA_COEFFICIENT, rsa_iqmp);
+				pkcs11_addattr_bn(&tmpl, CKA_COEFFICIENT, rsa_iqmp);
 		}
 	} else {
-		pkcs11_zap_attrs(attrs, n);
+		pkcs11_zap_attrs(&tmpl);
 		P11err(P11_F_PKCS11_STORE_KEY, P11_R_NOT_SUPPORTED);
 		return -1;
 	}
 
+	if (pkcs11_get_session(slot, 1, &session)) {
+		pkcs11_zap_attrs(&tmpl);
+		return -1;
+	}
+
 	/* Now call the pkcs11 module to create the object */
-	rv = CRYPTOKI_call(ctx, C_CreateObject(spriv->session, attrs, n, &object));
+	rv = CRYPTOKI_call(ctx, C_CreateObject(session, tmpl.attrs, tmpl.nattr, &object));
 
 	/* Zap all memory allocated when building the template */
-	pkcs11_zap_attrs(attrs, n);
+	pkcs11_zap_attrs(&tmpl);
+
+	if (rv == CKR_OK) {
+		/* Gobble the key object */
+		r = pkcs11_init_key(slot, session, object, type, ret_key);
+	}
+	pkcs11_put_session(slot, session);
 
 	CRYPTOKI_checkerr(CKR_F_PKCS11_STORE_KEY, rv);
+	return r;
 
-	/* Gobble the key object */
-	return pkcs11_init_key(ctx, token, spriv->session, object, type, ret_key);
 }
 
 /*
  * Get the key type
  */
-int pkcs11_get_key_type(PKCS11_KEY *key)
+int pkcs11_get_key_type(PKCS11_OBJECT_private *key)
 {
-	PKCS11_KEY_private *kpriv = PRIVKEY(key);
-
-	return kpriv->ops->type;
+	if (key->ops)
+		return key->ops->pkey_type;
+	return EVP_PKEY_NONE;
 }
 
 /*
  * Create an EVP_PKEY OpenSSL object for a given key
- * Returns private or public key depending on isPrivate
+ * Returns the key type specified in object_class.
  */
-EVP_PKEY *pkcs11_get_key(PKCS11_KEY *key, int isPrivate)
+EVP_PKEY *pkcs11_get_key(PKCS11_OBJECT_private *key0, CK_OBJECT_CLASS object_class)
 {
-	if (key->isPrivate != isPrivate)
-		key = pkcs11_find_key_from_key(key);
-	if (!key)
-		return NULL;
+	PKCS11_OBJECT_private *key = key0;
+	EVP_PKEY *ret = NULL;
+
+	if (key->object_class != object_class)
+		key = pkcs11_object_from_object(key, CK_INVALID_HANDLE, object_class);
+	if (!key || !key->ops)
+		goto err;
 	if (!key->evp_key) {
-		PKCS11_KEY_private *kpriv = PRIVKEY(key);
-		key->evp_key = kpriv->ops->get_evp_key(key);
+		key->evp_key = key->ops->get_evp_key(key);
 		if (!key->evp_key)
-			return NULL;
-		kpriv->always_authenticate = CK_FALSE;
-		if (isPrivate && key_getattr_val(key, CKA_ALWAYS_AUTHENTICATE,
-				&kpriv->always_authenticate, sizeof(CK_BBOOL))) {
-#ifdef DEBUG
-			fprintf(stderr, "Missing CKA_ALWAYS_AUTHENTICATE attribute\n");
-#endif
-		}
+			goto err;
 	}
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3050000fL )
 	EVP_PKEY_up_ref(key->evp_key);
 #else
 	CRYPTO_add(&key->evp_key->references, 1, CRYPTO_LOCK_EVP_PKEY);
 #endif
-	return key->evp_key;
+	ret = key->evp_key;
+err:
+	if (key != key0)
+		pkcs11_object_free(key);
+	return ret;
 }
 
 /*
  * Authenticate a private the key operation if needed
  * This function *only* handles CKU_CONTEXT_SPECIFIC logins.
  */
-int pkcs11_authenticate(PKCS11_KEY *key)
+int pkcs11_authenticate(PKCS11_OBJECT_private *key, CK_SESSION_HANDLE session)
 {
-	PKCS11_TOKEN *token = KEY2TOKEN(key);
-	PKCS11_SLOT *slot = TOKEN2SLOT(token);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
-	PKCS11_CTX *ctx = SLOT2CTX(slot);
-	PKCS11_CTX_private *cpriv = PRIVCTX(ctx);
+	PKCS11_SLOT_private *slot = key->slot;
+	PKCS11_CTX_private *ctx = slot->ctx;
 	char pin[MAX_PIN_LENGTH+1];
 	char* prompt;
 	UI *ui;
 	int rv;
 
 	/* Handle CKF_PROTECTED_AUTHENTICATION_PATH */
-	if (token->secureLogin) {
+	if (slot->secure_login) {
 		rv = CRYPTOKI_call(ctx,
-			C_Login(spriv->session, CKU_CONTEXT_SPECIFIC, NULL, 0));
+			C_Login(session, CKU_CONTEXT_SPECIFIC, NULL, 0));
 		return rv == CKR_USER_ALREADY_LOGGED_IN ? 0 : rv;
 	}
 
 	/* Call UI to ask for a PIN */
-	ui = UI_new_method(cpriv->ui_method);
+	ui = UI_new_method(ctx->ui_method);
 	if (!ui)
 		return P11_R_UI_FAILED;
-	if (cpriv->ui_user_data)
-		UI_add_user_data(ui, cpriv->ui_user_data);
+	if (ctx->ui_user_data)
+		UI_add_user_data(ui, ctx->ui_user_data);
 	memset(pin, 0, MAX_PIN_LENGTH+1);
 	prompt = UI_construct_prompt(ui, "PKCS#11 key PIN", key->label);
 	if (!prompt) {
@@ -394,7 +510,7 @@
 
 	/* Login with the PIN */
 	rv = CRYPTOKI_call(ctx,
-		C_Login(spriv->session, CKU_CONTEXT_SPECIFIC,
+		C_Login(session, CKU_CONTEXT_SPECIFIC,
 			(CK_UTF8CHAR *)pin, strlen(pin)));
 	OPENSSL_cleanse(pin, MAX_PIN_LENGTH+1);
 	return rv == CKR_USER_ALREADY_LOGGED_IN ? 0 : rv;
@@ -404,40 +520,23 @@
  * Return keys of a given type (public or private)
  * Use the cached values if available
  */
-int pkcs11_enumerate_keys(PKCS11_TOKEN *token, unsigned int type,
-		PKCS11_KEY ** keyp, unsigned int *countp)
+int pkcs11_enumerate_keys(PKCS11_SLOT_private *slot, unsigned int type,
+		PKCS11_KEY **keyp, unsigned int *countp)
 {
-	PKCS11_SLOT *slot = TOKEN2SLOT(token);
-	PKCS11_CTX *ctx = TOKEN2CTX(token);
-	PKCS11_TOKEN_private *tpriv = PRIVTOKEN(token);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
-	PKCS11_CTX_private *cpriv = PRIVCTX(ctx);
-	PKCS11_keys *keys = (type == CKO_PRIVATE_KEY) ? &tpriv->prv : &tpriv->pub;
-	PKCS11_KEY *first_key_prev = keys->keys;
+	PKCS11_keys *keys = (type == CKO_PRIVATE_KEY) ? &slot->prv : &slot->pub;
+	CK_SESSION_HANDLE session;
 	int rv;
-	int i;
 
-	/* Make sure we have a session */
-	if (!spriv->haveSession && PKCS11_open_session(slot, 0))
+	if (pkcs11_get_session(slot, 0, &session))
 		return -1;
 
-	CRYPTO_THREAD_write_lock(cpriv->rwlock);
-	rv = pkcs11_find_keys(token, type);
-	CRYPTO_THREAD_unlock(cpriv->rwlock);
+	rv = pkcs11_find_keys(slot, session, type);
+	pkcs11_put_session(slot, session);
 	if (rv < 0) {
-		pkcs11_destroy_keys(token, type);
+		pkcs11_destroy_keys(slot, type);
 		return -1;
 	}
 
-	/* Always update key references if the keys pointer changed */
-	if (first_key_prev && first_key_prev != keys->keys) {
-		for (i = 0; i < keys->num; ++i) {
-			PKCS11_KEY *key = keys->keys + i;
-			PKCS11_KEY_private *kpriv = PRIVKEY(key);
-			kpriv->ops->update_ex_data(key);
-		}
-	}
-
 	if (keyp)
 		*keyp = keys->keys;
 	if (countp)
@@ -446,59 +545,31 @@
 }
 
 /**
- * Remove a key from the associated token
+ * Remove an object from the associated token
  */
-int pkcs11_remove_key(PKCS11_KEY *key) {
-	PKCS11_SLOT *slot = KEY2SLOT(key);
-	PKCS11_CTX *ctx = KEY2CTX(key);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
-	CK_OBJECT_HANDLE obj;
-	CK_ULONG count;
-	CK_ATTRIBUTE search_parameters[32];
-	unsigned int n = 0;
+int pkcs11_remove_object(PKCS11_OBJECT_private *obj)
+{
+	PKCS11_SLOT_private *slot = obj->slot;
+	PKCS11_CTX_private *ctx = slot->ctx;
+	CK_SESSION_HANDLE session;
 	int rv;
 
-	/* First, make sure we have a session */
-	if (!spriv->haveSession && PKCS11_open_session(slot, 1))
+	if (pkcs11_get_session(slot, 1, &session))
 		return -1;
-	if (key->isPrivate)
-		pkcs11_addattr_int(search_parameters + n++, CKA_CLASS, CKO_PRIVATE_KEY);
-	else
-		pkcs11_addattr_int(search_parameters + n++, CKA_CLASS, CKO_PUBLIC_KEY);
-	if (key->id && key->id_len)
-		pkcs11_addattr(search_parameters + n++, CKA_ID, key->id, key->id_len);
-	if (key->label)
-	 	pkcs11_addattr_s(search_parameters + n++, CKA_LABEL, key->label);
-
-	rv = CRYPTOKI_call(ctx,
-		C_FindObjectsInit(spriv->session, search_parameters, n));
-	CRYPTOKI_checkerr(CKR_F_PKCS11_REMOVE_KEY, rv);
 
-	rv = CRYPTOKI_call(ctx, C_FindObjects(spriv->session, &obj, 1, &count));
+	rv = CRYPTOKI_call(ctx, C_DestroyObject(session, obj->object));
+	pkcs11_put_session(slot, session);
 	CRYPTOKI_checkerr(CKR_F_PKCS11_REMOVE_KEY, rv);
 
-	CRYPTOKI_call(ctx, C_FindObjectsFinal(spriv->session));
-	if (count!=1) {
-		pkcs11_zap_attrs(search_parameters, n);
-		return -1;
-	}
-	rv = CRYPTOKI_call(ctx, C_DestroyObject(spriv->session, obj));
-	if (rv != CKR_OK) {
-		pkcs11_zap_attrs(search_parameters, n);
-		return -1;
-	}
-	pkcs11_zap_attrs(search_parameters, n);
 	return 0;
 }
 
 /*
  * Find all keys of a given type (public or private)
  */
-static int pkcs11_find_keys(PKCS11_TOKEN *token, unsigned int type)
+static int pkcs11_find_keys(PKCS11_SLOT_private *slot, CK_SESSION_HANDLE session, unsigned int type)
 {
-	PKCS11_SLOT *slot = TOKEN2SLOT(token);
-	PKCS11_CTX *ctx = TOKEN2CTX(token);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
+	PKCS11_CTX_private *ctx = slot->ctx;
 	CK_OBJECT_CLASS key_search_class;
 	CK_ATTRIBUTE key_search_attrs[1] = {
 		{CKA_CLASS, &key_search_class, sizeof(key_search_class)},
@@ -508,19 +579,19 @@
 	/* Tell the PKCS11 lib to enumerate all matching objects */
 	key_search_class = type;
 	rv = CRYPTOKI_call(ctx,
-		C_FindObjectsInit(spriv->session, key_search_attrs, 1));
+		C_FindObjectsInit(session, key_search_attrs, 1));
 	CRYPTOKI_checkerr(CKR_F_PKCS11_FIND_KEYS, rv);
 
 	do {
-		res = pkcs11_next_key(ctx, token, spriv->session, type);
+		res = pkcs11_next_key(ctx, slot, session, type);
 	} while (res == 0);
 
-	CRYPTOKI_call(ctx, C_FindObjectsFinal(spriv->session));
+	CRYPTOKI_call(ctx, C_FindObjectsFinal(session));
 
 	return (res < 0) ? -1 : 0;
 }
 
-static int pkcs11_next_key(PKCS11_CTX *ctx, PKCS11_TOKEN *token,
+static int pkcs11_next_key(PKCS11_CTX_private *ctx, PKCS11_SLOT_private *slot,
 		CK_SESSION_HANDLE session, CK_OBJECT_CLASS type)
 {
 	CK_OBJECT_HANDLE obj;
@@ -534,80 +605,51 @@
 	if (count == 0)
 		return 1;
 
-	if (pkcs11_init_key(ctx, token, session, obj, type, NULL))
+	if (pkcs11_init_key(slot, session, obj, type, NULL))
 		return -1;
 
 	return 0;
 }
 
-static int pkcs11_init_key(PKCS11_CTX *ctx, PKCS11_TOKEN *token,
-		CK_SESSION_HANDLE session, CK_OBJECT_HANDLE obj,
-		CK_OBJECT_CLASS type, PKCS11_KEY ** ret)
-{
-	PKCS11_TOKEN_private *tpriv = PRIVTOKEN(token);
-	PKCS11_keys *keys = (type == CKO_PRIVATE_KEY) ? &tpriv->prv : &tpriv->pub;
-	PKCS11_KEY_private *kpriv;
+static int pkcs11_init_key(PKCS11_SLOT_private *slot, CK_SESSION_HANDLE session,
+	CK_OBJECT_HANDLE object, CK_OBJECT_CLASS type, PKCS11_KEY **ret)
+{
+	PKCS11_keys *keys = (type == CKO_PRIVATE_KEY) ? &slot->prv : &slot->pub;
+	PKCS11_OBJECT_private *kpriv;
 	PKCS11_KEY *key, *tmp;
-	CK_KEY_TYPE key_type;
-	PKCS11_KEY_ops *ops;
-	size_t size;
 	int i;
 
-	(void)ctx;
-	(void)session;
-
-	/* Ignore unknown key types */
-	size = sizeof(CK_KEY_TYPE);
-	if (pkcs11_getattr_var(token, obj, CKA_KEY_TYPE, (CK_BYTE *)&key_type, &size))
-		return -1;
-	switch (key_type) {
-	case CKK_RSA:
-		ops = &pkcs11_rsa_ops;
-		break;
-	case CKK_EC:
-		ops = pkcs11_ec_ops;
-		if (!ops)
-			return 0; /* not supported */
-		break;
-	default:
-		/* Ignore any keys we don't understand */
-		return 0;
-	}
-
 	/* Prevent re-adding existing PKCS#11 object handles */
 	/* TODO: Rewrite the O(n) algorithm as O(log n),
 	 * or it may be too slow with a large number of keys */
-	for (i=0; i < keys->num; ++i)
-		if (PRIVKEY(keys->keys + i)->object == obj)
+	for (i = 0; i < keys->num; ++i) {
+		if (PRIVKEY(&keys->keys[i])->object == object) {
+			if (ret)
+				*ret = &keys->keys[i];
 			return 0;
+		}
+	}
 
-	/* Allocate memory */
-	kpriv = OPENSSL_malloc(sizeof(PKCS11_KEY_private));
+	kpriv = pkcs11_object_from_handle(slot, session, object);
 	if (!kpriv)
 		return -1;
-	memset(kpriv, 0, sizeof(PKCS11_KEY_private));
+
+	/* Allocate memory */
 	tmp = OPENSSL_realloc(keys->keys, (keys->num + 1) * sizeof(PKCS11_KEY));
-	if (!tmp)
+	if (!tmp) {
+		pkcs11_object_free(kpriv);
 		return -1;
+	}
 	keys->keys = tmp;
 	key = keys->keys + keys->num++;
 	memset(key, 0, sizeof(PKCS11_KEY));
 
 	/* Fill public properties */
-	pkcs11_getattr_alloc(token, obj, CKA_LABEL, (CK_BYTE **)&key->label, NULL);
-	key->id_len = 0;
-	pkcs11_getattr_alloc(token, obj, CKA_ID, &key->id, &key->id_len);
-	key->isPrivate = (type == CKO_PRIVATE_KEY);
-
-	/* Fill private properties */
 	key->_private = kpriv;
-	kpriv->object = obj;
-	kpriv->parent = token;
-	kpriv->id_len = sizeof kpriv->id;
-	if (pkcs11_getattr_var(token, obj, CKA_ID, kpriv->id, &kpriv->id_len))
-		kpriv->id_len = 0;
-	kpriv->ops = ops;
-	kpriv->forkid = get_forkid();
+	key->id = kpriv->id;
+	key->id_len = kpriv->id_len;
+	key->label = kpriv->label;
+	key->isPrivate = (type == CKO_PRIVATE_KEY);
 
 	if (ret)
 		*ret = key;
@@ -617,22 +659,14 @@
 /*
  * Destroy all keys of a given type (public or private)
  */
-void pkcs11_destroy_keys(PKCS11_TOKEN *token, unsigned int type)
+void pkcs11_destroy_keys(PKCS11_SLOT_private *slot, unsigned int type)
 {
-	PKCS11_TOKEN_private *tpriv = PRIVTOKEN(token);
-	PKCS11_keys *keys = (type == CKO_PRIVATE_KEY) ? &tpriv->prv : &tpriv->pub;
+	PKCS11_keys *keys = (type == CKO_PRIVATE_KEY) ? &slot->prv : &slot->pub;
 
 	while (keys->num > 0) {
-		PKCS11_KEY *key = &keys->keys[--(keys->num)];
-
-		if (key->evp_key)
-			EVP_PKEY_free(key->evp_key);
-		if (key->label)
-			OPENSSL_free(key->label);
-		if (key->id)
-			OPENSSL_free(key->id);
+		PKCS11_KEY *key = &keys->keys[--keys->num];
 		if (key->_private)
-			OPENSSL_free(key->_private);
+			pkcs11_object_free(PRIVKEY(key));
 	}
 	if (keys->keys)
 		OPENSSL_free(keys->keys);
diff -Nru libp11-0.4.11/src/p11_load.c libp11-0.4.12/src/p11_load.c
--- libp11-0.4.11/src/p11_load.c	2020-10-04 22:13:22.000000000 +0200
+++ libp11-0.4.12/src/p11_load.c	2022-05-04 18:45:56.000000000 +0200
@@ -40,9 +40,7 @@
 	memset(ctx, 0, sizeof(PKCS11_CTX));
 	ctx->_private = cpriv;
 	cpriv->forkid = get_forkid();
-	cpriv->rwlock = CRYPTO_THREAD_lock_new();
-	cpriv->sign_initialized = 0;
-	cpriv->decrypt_initialized = 0;
+	pthread_mutex_init(&cpriv->fork_lock, 0);
 
 	return ctx;
 fail:
@@ -113,23 +111,22 @@
 /*
  * Reinitialize (e.g., after a fork).
  */
-int pkcs11_CTX_reload(PKCS11_CTX *ctx)
+int pkcs11_CTX_reload(PKCS11_CTX_private *ctx)
 {
-	PKCS11_CTX_private *cpriv = PRIVCTX(ctx);
 	CK_C_INITIALIZE_ARGS _args;
 	CK_C_INITIALIZE_ARGS *args = NULL;
 	int rv;
 
-	if (!cpriv->method) /* Module not loaded */
+	if (!ctx->method) /* Module not loaded */
 		return 0;
 
 	/* Tell the PKCS11 to initialize itself */
-	if (cpriv->init_args) {
+	if (ctx->init_args) {
 		memset(&_args, 0, sizeof(_args));
 		args = &_args;
-		args->pReserved = cpriv->init_args;
+		args->pReserved = ctx->init_args;
 	}
-	rv = cpriv->method->C_Initialize(args);
+	rv = ctx->method->C_Initialize(args);
 	if (rv && rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) {
 		CKRerr(P11_F_PKCS11_CTX_RELOAD, rv);
 		return -1;
@@ -172,7 +169,7 @@
 	if (cpriv->handle) {
 		OPENSSL_free(cpriv->handle);
 	}
-	CRYPTO_THREAD_lock_free(cpriv->rwlock);
+	pthread_mutex_destroy(&cpriv->fork_lock);
 	OPENSSL_free(ctx->manufacturer);
 	OPENSSL_free(ctx->description);
 	OPENSSL_free(ctx->_private);
diff -Nru libp11-0.4.11/src/p11_misc.c libp11-0.4.12/src/p11_misc.c
--- libp11-0.4.11/src/p11_misc.c	2020-02-27 06:50:01.000000000 +0100
+++ libp11-0.4.12/src/p11_misc.c	2022-07-05 22:22:51.000000000 +0200
@@ -39,32 +39,25 @@
 	return res;
 }
 
-/*
- * CRYPTO dynlock wrappers: 0 is an invalid dynamic lock ID
- */
-
-#if OPENSSL_VERSION_NUMBER < 0x10100004L || defined(LIBRESSL_VERSION_NUMBER)
-
-int CRYPTO_THREAD_lock_new()
-{
-	int i;
-
-	if (CRYPTO_get_dynlock_create_callback() == NULL ||
-			CRYPTO_get_dynlock_lock_callback() == NULL ||
-			CRYPTO_get_dynlock_destroy_callback() == NULL)
-		return 0; /* Dynamic callbacks not set */
-	i = CRYPTO_get_new_dynlockid();
-	if (i == 0)
-		ERR_clear_error(); /* Dynamic locks are optional -> ignore */
-	return i;
-}
-
-void CRYPTO_THREAD_lock_free(int i)
+int pkcs11_atomic_add(int *value, int amount, pthread_mutex_t *lock)
 {
-	if (i)
-		CRYPTO_destroy_dynlockid(i);
-}
+#if defined( _WIN32)
+	(void) lock;
+	/* both int and long are 32-bit on all WIN32 platforms */
+	return InterlockedExchangeAdd((LONG *)value, amount) + amount;
+#elif defined(__GNUC__) && defined(__ATOMIC_ACQ_REL)
+	(void) lock;
+	return __atomic_add_fetch(value, amount, __ATOMIC_ACQ_REL);
+#else
+	int ret;
+
+	pthread_mutex_lock(lock);
+	*value += amount;
+	ret = *value;
+	pthread_mutex_unlock(lock);
 
+	return ret;
 #endif
+}
 
 /* vim: set noexpandtab: */
diff -Nru libp11-0.4.11/src/p11_pkey.c libp11-0.4.12/src/p11_pkey.c
--- libp11-0.4.11/src/p11_pkey.c	2020-10-11 15:41:03.000000000 +0200
+++ libp11-0.4.12/src/p11_pkey.c	2022-07-15 21:48:10.000000000 +0200
@@ -197,6 +197,16 @@
 		return CKM_SHA512;
 	case NID_sha384:
 		return CKM_SHA384;
+#if !defined(LIBRESSL_VERSION_NUMBER)
+	case NID_sha3_224:
+		return CKM_SHA3_224;
+	case NID_sha3_256:
+		return CKM_SHA3_256;
+	case NID_sha3_384:
+		return CKM_SHA3_384;
+	case NID_sha3_512:
+		return CKM_SHA3_512;
+#endif
 	default:
 		return 0;
 	}
@@ -215,6 +225,16 @@
 		return CKG_MGF1_SHA512;
 	case NID_sha384:
 		return CKG_MGF1_SHA384;
+#if !defined(LIBRESSL_VERSION_NUMBER)
+	case NID_sha3_224:
+		return CKG_MGF1_SHA3_224;
+	case NID_sha3_256:
+		return CKG_MGF1_SHA3_256;
+	case NID_sha3_384:
+		return CKG_MGF1_SHA3_384;
+	case NID_sha3_512:
+		return CKG_MGF1_SHA3_512;
+#endif
 	default:
 		return 0;
 	}
@@ -285,8 +305,8 @@
 	if (!oaep->hashAlg || !oaep->mgf)
 		return -1;
 	/* we do not support the OAEP "label" parameter yet... */
-	oaep->source = 0UL; /* empty parameter (label) */
-	oaep->pSourceData = NULL;
+	oaep->source = CKZ_DATA_SPECIFIED;
+	oaep->pSourceData = NULL; /* empty parameter (label) */
 	oaep->ulSourceDataLen = 0;
 	return 0;
 }
@@ -297,36 +317,39 @@
 {
 	EVP_PKEY *pkey;
 	RSA *rsa;
-	PKCS11_KEY *key;
-	int rv = 0;
+	int rv = 0, padding;
 	CK_ULONG size = *siglen;
-	PKCS11_SLOT *slot;
-	PKCS11_CTX *ctx;
-	PKCS11_KEY_private *kpriv;
-	PKCS11_SLOT_private *spriv;
-	PKCS11_CTX_private *cpriv;
+	PKCS11_OBJECT_private *key;
+	PKCS11_SLOT_private *slot;
+	PKCS11_CTX_private *ctx;
 	const EVP_MD *sig_md;
+	CK_SESSION_HANDLE session;
+	CK_MECHANISM mechanism;
+	CK_RSA_PKCS_PSS_PARAMS pss_params;
 
 #ifdef DEBUG
 	fprintf(stderr, "%s:%d pkcs11_try_pkey_rsa_sign() "
 		"sig=%p *siglen=%lu tbs=%p tbslen=%lu\n",
 		__FILE__, __LINE__, sig, *siglen, tbs, tbslen);
 #endif
+	/* RSA method has EVP_PKEY_FLAG_AUTOARGLEN set. OpenSSL core will handle
+	 * the size inquiry internally. */
+	 if (!sig)
+		return -1;
+
 	pkey = EVP_PKEY_CTX_get0_pkey(evp_pkey_ctx);
 	if (!pkey)
 		return -1;
-	rsa = EVP_PKEY_get0_RSA(pkey);
+	rsa = (RSA *)EVP_PKEY_get0_RSA(pkey);
 	if (!rsa)
 		return -1;
+
 	key = pkcs11_get_ex_data_rsa(rsa);
-	if (check_key_fork(key) < 0)
+	if (check_object_fork(key) < 0)
 		return -1;
-	slot = KEY2SLOT(key);
-	ctx = KEY2CTX(key);
-	kpriv = PRIVKEY(key);
-	spriv = PRIVSLOT(slot);
-	cpriv = PRIVCTX(ctx);
 
+	slot = key->slot;
+	ctx = slot->ctx;
 	if (!evp_pkey_ctx)
 		return -1;
 	if (EVP_PKEY_CTX_get_signature_md(evp_pkey_ctx, &sig_md) <= 0)
@@ -334,45 +357,39 @@
 	if (tbslen != (size_t)EVP_MD_size(sig_md))
 		return -1;
 
-	if (!cpriv->sign_initialized) {
-		int padding;
-		CK_MECHANISM mechanism;
-		CK_RSA_PKCS_PSS_PARAMS pss_params;
-
-		memset(&mechanism, 0, sizeof mechanism);
-		EVP_PKEY_CTX_get_rsa_padding(evp_pkey_ctx, &padding);
-		switch (padding) {
-		case RSA_PKCS1_PSS_PADDING:
-#ifdef DEBUG
-			fprintf(stderr, "%s:%d padding=RSA_PKCS1_PSS_PADDING\n",
-				__FILE__, __LINE__);
-#endif
-			if (pkcs11_params_pss(&pss_params, evp_pkey_ctx) < 0)
-				return -1;
-			mechanism.mechanism = CKM_RSA_PKCS_PSS;
-			mechanism.pParameter = &pss_params;
-			mechanism.ulParameterLen = sizeof pss_params;
-			break;
-		default:
+	memset(&mechanism, 0, sizeof mechanism);
+	EVP_PKEY_CTX_get_rsa_padding(evp_pkey_ctx, &padding);
+	switch (padding) {
+	case RSA_PKCS1_PSS_PADDING:
 #ifdef DEBUG
-			fprintf(stderr, "%s:%d unsupported padding: %d\n",
-				__FILE__, __LINE__, padding);
+		fprintf(stderr, "%s:%d padding=RSA_PKCS1_PSS_PADDING\n",
+			__FILE__, __LINE__);
 #endif
+		if (pkcs11_params_pss(&pss_params, evp_pkey_ctx) < 0)
 			return -1;
-		} /* end switch(padding) */
+		mechanism.mechanism = CKM_RSA_PKCS_PSS;
+		mechanism.pParameter = &pss_params;
+		mechanism.ulParameterLen = sizeof pss_params;
+		break;
+	default:
+#ifdef DEBUG
+		fprintf(stderr, "%s:%d unsupported padding: %d\n",
+			__FILE__, __LINE__, padding);
+#endif
+		return -1;
+	} /* end switch(padding) */
 
-		CRYPTO_THREAD_write_lock(cpriv->rwlock);
-		rv = CRYPTOKI_call(ctx,
-			C_SignInit(spriv->session, &mechanism, kpriv->object));
-		if (!rv && kpriv->always_authenticate == CK_TRUE)
-			rv = pkcs11_authenticate(key);
-	}
+	if (pkcs11_get_session(slot, 0, &session))
+		return -1;
+
+	rv = CRYPTOKI_call(ctx,
+		C_SignInit(session, &mechanism, key->object));
+	if (!rv && key->always_authenticate == CK_TRUE)
+		rv = pkcs11_authenticate(key, session);
 	if (!rv)
 		rv = CRYPTOKI_call(ctx,
-			C_Sign(spriv->session, (CK_BYTE_PTR)tbs, tbslen, sig, &size));
-	cpriv->sign_initialized = !rv && sig == NULL;
-	if (!cpriv->sign_initialized)
-		CRYPTO_THREAD_unlock(cpriv->rwlock);
+			C_Sign(session, (CK_BYTE_PTR)tbs, tbslen, sig, &size));
+	pkcs11_put_session(slot, session);
 #ifdef DEBUG
 	fprintf(stderr, "%s:%d C_SignInit or C_Sign rv=%d\n",
 		__FILE__, __LINE__, rv);
@@ -402,85 +419,84 @@
 {
 	EVP_PKEY *pkey;
 	RSA *rsa;
-	PKCS11_KEY *key;
-	int rv = 0;
+	int rv = 0, padding;
 	CK_ULONG size = *outlen;
-	PKCS11_SLOT *slot;
-	PKCS11_CTX *ctx;
-	PKCS11_KEY_private *kpriv;
-	PKCS11_SLOT_private *spriv;
-	PKCS11_CTX_private *cpriv;
+	PKCS11_OBJECT_private *key;
+	PKCS11_SLOT_private *slot;
+	PKCS11_CTX_private *ctx;
+	CK_SESSION_HANDLE session;
+	CK_MECHANISM mechanism;
+	CK_RSA_PKCS_OAEP_PARAMS oaep_params;
 
 #ifdef DEBUG
 	fprintf(stderr, "%s:%d pkcs11_try_pkey_rsa_decrypt() "
 		"out=%p *outlen=%lu in=%p inlen=%lu\n",
 		__FILE__, __LINE__, out, *outlen, in, inlen);
 #endif
+	/* RSA method has EVP_PKEY_FLAG_AUTOARGLEN set. OpenSSL core will handle
+	 * the size inquiry internally. */
+	 if (!out)
+		return -1;
+
 	pkey = EVP_PKEY_CTX_get0_pkey(evp_pkey_ctx);
 	if (!pkey)
 		return -1;
-	rsa = EVP_PKEY_get0_RSA(pkey);
+	rsa = (RSA *)EVP_PKEY_get0_RSA(pkey);
 	if (!rsa)
 		return -1;
+
 	key = pkcs11_get_ex_data_rsa(rsa);
-	if (check_key_fork(key) < 0)
+	if (check_object_fork(key) < 0)
 		return -1;
-	slot = KEY2SLOT(key);
-	ctx = KEY2CTX(key);
-	kpriv = PRIVKEY(key);
-	spriv = PRIVSLOT(slot);
-	cpriv = PRIVCTX(ctx);
+
+	slot = key->slot;
+	ctx = slot->ctx;
 
 	if (!evp_pkey_ctx)
 		return -1;
 
-	if (!cpriv->decrypt_initialized) {
-		int padding;
-		CK_MECHANISM mechanism;
-		CK_RSA_PKCS_OAEP_PARAMS oaep_params;
-
-		memset(&mechanism, 0, sizeof mechanism);
-		EVP_PKEY_CTX_get_rsa_padding(evp_pkey_ctx, &padding);
-		switch (padding) {
-		case RSA_PKCS1_OAEP_PADDING:
-#ifdef DEBUG
-			fprintf(stderr, "%s:%d padding=RSA_PKCS1_OAEP_PADDING\n",
-				__FILE__, __LINE__);
-#endif
-			if (pkcs11_params_oaep(&oaep_params, evp_pkey_ctx) < 0)
-				return -1;
-			mechanism.mechanism = CKM_RSA_PKCS_OAEP;
-			mechanism.pParameter = &oaep_params;
-			mechanism.ulParameterLen = sizeof oaep_params;
-			break;
-		case CKM_RSA_PKCS:
-#ifdef DEBUG
-			fprintf(stderr, "%s:%d padding=CKM_RSA_PKCS\n",
-				__FILE__, __LINE__);
-#endif
-			mechanism.pParameter = NULL;
-			mechanism.ulParameterLen = 0;
-			break;
-		default:
+	memset(&mechanism, 0, sizeof mechanism);
+	EVP_PKEY_CTX_get_rsa_padding(evp_pkey_ctx, &padding);
+	switch (padding) {
+	case RSA_PKCS1_OAEP_PADDING:
 #ifdef DEBUG
-			fprintf(stderr, "%s:%d unsupported padding: %d\n",
-				__FILE__, __LINE__, padding);
+		fprintf(stderr, "%s:%d padding=RSA_PKCS1_OAEP_PADDING\n",
+			__FILE__, __LINE__);
 #endif
+		if (pkcs11_params_oaep(&oaep_params, evp_pkey_ctx) < 0)
 			return -1;
-		} /* end switch(padding) */
+		mechanism.mechanism = CKM_RSA_PKCS_OAEP;
+		mechanism.pParameter = &oaep_params;
+		mechanism.ulParameterLen = sizeof oaep_params;
+		break;
+	case RSA_PKCS1_PADDING:
+#ifdef DEBUG
+		fprintf(stderr, "%s:%d padding=RSA_PKCS1_PADDING\n",
+			__FILE__, __LINE__);
+#endif
+		mechanism.mechanism = CKM_RSA_PKCS;
+		mechanism.pParameter = NULL;
+		mechanism.ulParameterLen = 0;
+		break;
+	default:
+#ifdef DEBUG
+		fprintf(stderr, "%s:%d unsupported padding: %d\n",
+			__FILE__, __LINE__, padding);
+#endif
+		return -1;
+	} /* end switch(padding) */
 
-		CRYPTO_THREAD_write_lock(cpriv->rwlock);
-		rv = CRYPTOKI_call(ctx,
-			C_DecryptInit(spriv->session, &mechanism, kpriv->object));
-		if (!rv && kpriv->always_authenticate == CK_TRUE)
-			rv = pkcs11_authenticate(key);
-	}
+	if (pkcs11_get_session(slot, 0, &session))
+		return -1;
+
+	rv = CRYPTOKI_call(ctx,
+		C_DecryptInit(session, &mechanism, key->object));
+	if (!rv && key->always_authenticate == CK_TRUE)
+		rv = pkcs11_authenticate(key, session);
 	if (!rv)
 		rv = CRYPTOKI_call(ctx,
-			C_Decrypt(spriv->session, (CK_BYTE_PTR)in, inlen, out, &size));
-	cpriv->decrypt_initialized = !rv && out == NULL;
-	if (!cpriv->decrypt_initialized)
-		CRYPTO_THREAD_unlock(cpriv->rwlock);
+			C_Decrypt(session, (CK_BYTE_PTR)in, inlen, out, &size));
+	pkcs11_put_session(slot, session);
 #ifdef DEBUG
 	fprintf(stderr, "%s:%d C_DecryptInit or C_Decrypt rv=%d\n",
 		__FILE__, __LINE__, rv);
@@ -541,16 +557,15 @@
 {
 	EVP_PKEY *pkey;
 	EC_KEY *eckey;
-	PKCS11_KEY *key;
 	int rv = CKR_GENERAL_ERROR;
 	CK_ULONG size = *siglen;
-	PKCS11_SLOT *slot;
-	PKCS11_CTX *ctx;
-	PKCS11_KEY_private *kpriv;
-	PKCS11_SLOT_private *spriv;
-	PKCS11_CTX_private *cpriv;
+	PKCS11_OBJECT_private *key;
+	PKCS11_SLOT_private *slot;
+	PKCS11_CTX_private *ctx;
+	CK_SESSION_HANDLE session;
 	const EVP_MD *sig_md;
 	ECDSA_SIG *ossl_sig;
+	CK_MECHANISM mechanism;
 
 #ifdef DEBUG
 	fprintf(stderr, "%s:%d pkcs11_try_pkey_ec_sign() "
@@ -570,18 +585,21 @@
 	if (!eckey)
 		goto error;
 
+	if (!sig) {
+		*siglen = (size_t)ECDSA_size(eckey);
+		rv = CKR_OK;
+		goto error;
+	}
+
 	if (*siglen < (size_t)ECDSA_size(eckey))
 		goto error;
 
 	key = pkcs11_get_ex_data_ec(eckey);
-	if (check_key_fork(key) < 0)
+	if (check_object_fork(key) < 0)
 		goto error;
 
-	slot = KEY2SLOT(key);
-	ctx = KEY2CTX(key);
-	kpriv = PRIVKEY(key);
-	spriv = PRIVSLOT(slot);
-	cpriv = PRIVCTX(ctx);
+	slot = key->slot;
+	ctx = slot->ctx;
 
 	if (!evp_pkey_ctx)
 		goto error;
@@ -593,25 +611,20 @@
 		goto error;
 
 	rv = 0;
-	if (!cpriv->sign_initialized) {
-		CK_MECHANISM mechanism;
-		memset(&mechanism, 0, sizeof mechanism);
+	memset(&mechanism, 0, sizeof mechanism);
+	mechanism.mechanism = CKM_ECDSA;
 
-		mechanism.mechanism = CKM_ECDSA;
-
-		CRYPTO_THREAD_write_lock(cpriv->rwlock);
-		rv = CRYPTOKI_call(ctx,
-			C_SignInit(spriv->session, &mechanism, kpriv->object));
-		if (!rv && kpriv->always_authenticate == CK_TRUE)
-			rv = pkcs11_authenticate(key);
-	}
+	if (pkcs11_get_session(slot, 0, &session))
+		return -1;
+	rv = CRYPTOKI_call(ctx,
+		C_SignInit(session, &mechanism, key->object));
+	if (!rv && key->always_authenticate == CK_TRUE)
+		rv = pkcs11_authenticate(key, session);
 	if (!rv)
 		rv = CRYPTOKI_call(ctx,
-			C_Sign(spriv->session, (CK_BYTE_PTR)tbs, tbslen, sig, &size));
+			C_Sign(session, (CK_BYTE_PTR)tbs, tbslen, sig, &size));
+	pkcs11_put_session(slot, session);
 
-	cpriv->sign_initialized = !rv && sig == NULL;
-	if (!cpriv->sign_initialized)
-		CRYPTO_THREAD_unlock(cpriv->rwlock);
 #ifdef DEBUG
 	fprintf(stderr, "%s:%d C_SignInit or C_Sign rv=%d\n",
 		__FILE__, __LINE__, rv);
@@ -621,7 +634,7 @@
 		BIGNUM *r = BN_bin2bn(sig, size/2, NULL);
 		BIGNUM *s = BN_bin2bn(sig + size/2, size/2, NULL);
 
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3050000fL )
 		ECDSA_SIG_set0(ossl_sig, r, s);
 #else
 		BN_free(ossl_sig->r);
diff -Nru libp11-0.4.11/src/p11_pthread.h libp11-0.4.12/src/p11_pthread.h
--- libp11-0.4.11/src/p11_pthread.h	1970-01-01 01:00:00.000000000 +0100
+++ libp11-0.4.12/src/p11_pthread.h	2021-10-30 14:20:08.000000000 +0200
@@ -0,0 +1,94 @@
+/* libp11, a simple layer on to of PKCS#11 API
+ * Copyright (C) 2017 Douglas E. Engert <deengert at gmail.com>
+ * Copyright (C) 2017-2018 Michał Trojnara <Michal.Trojnara at stunnel.org>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
+ */
+
+#if defined(HAVE_PTHREAD)
+
+#include <pthread.h>
+
+#elif defined( _WIN32)
+
+/* Simple wrappers for used pthread API using Windows Vista+ APIs. */
+#if _WIN32_WINNT < 0x0600
+#error Windows Vista (or Server 2008) or later required.
+#endif
+
+#include <windows.h>
+
+typedef CRITICAL_SECTION pthread_mutex_t;
+typedef void pthread_mutexattr_t;
+
+static int pthread_mutex_init(pthread_mutex_t *mutex, pthread_mutexattr_t *attr)
+{
+	(void)attr;
+	InitializeCriticalSection(mutex);
+	return 0;
+}
+
+static int pthread_mutex_destroy(pthread_mutex_t *mutex)
+{
+	DeleteCriticalSection(mutex);
+	return 0;
+}
+
+static int pthread_mutex_lock(pthread_mutex_t *mutex)
+{
+	EnterCriticalSection(mutex);
+	return 0;
+}
+
+static int pthread_mutex_unlock(pthread_mutex_t *mutex)
+{
+	LeaveCriticalSection(mutex);
+	return 0;
+}
+
+typedef CONDITION_VARIABLE pthread_cond_t;
+typedef void pthread_condattr_t;
+
+static int pthread_cond_init(pthread_cond_t *cond, pthread_condattr_t *attr)
+{
+	(void)attr;
+	InitializeConditionVariable(cond);
+	return 0;
+}
+
+static int pthread_cond_destroy(pthread_cond_t *cond)
+{
+	(void)cond;
+	return 0;
+}
+
+static int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex)
+{
+	if (!SleepConditionVariableCS(cond, mutex, INFINITE))
+		return 1;
+	return 0;
+}
+
+static int pthread_cond_signal(pthread_cond_t *cond)
+{
+	WakeConditionVariable(cond);
+	return 0;
+}
+
+#else
+
+#error Locking not supported on this platform.
+
+#endif
diff -Nru libp11-0.4.11/src/p11_rsa.c libp11-0.4.12/src/p11_rsa.c
--- libp11-0.4.11/src/p11_rsa.c	2020-10-11 15:41:00.000000000 +0200
+++ libp11-0.4.12/src/p11_rsa.c	2022-07-05 22:22:51.000000000 +0200
@@ -29,13 +29,16 @@
 
 static int rsa_ex_index = 0;
 
-static RSA *pkcs11_rsa(PKCS11_KEY *key)
+static RSA *pkcs11_rsa(PKCS11_OBJECT_private *key)
 {
-	EVP_PKEY *evp_key = pkcs11_get_key(key, key->isPrivate);
+	EVP_PKEY *evp_key = pkcs11_get_key(key, key->object_class);
 	RSA *rsa;
 	if (!evp_key)
 		return NULL;
-	rsa = EVP_PKEY_get0_RSA(evp_key);
+	rsa = (RSA *)EVP_PKEY_get0_RSA(evp_key);
+	/* Danger: this assumes evp_key returned above has at least reference
+	 * count of 2. Which is true in current code as long as key->object_class
+	 * is used for the object_class. */
 	EVP_PKEY_free(evp_key);
 	return rsa;
 }
@@ -43,7 +46,7 @@
 /* PKCS#1 v1.5 RSA signature */
 /* TODO: remove this function in libp11 0.5.0 */
 int pkcs11_sign(int type, const unsigned char *m, unsigned int m_len,
-		unsigned char *sigret, unsigned int *siglen, PKCS11_KEY *key)
+		unsigned char *sigret, unsigned int *siglen, PKCS11_OBJECT_private *key)
 {
 	RSA *rsa = pkcs11_rsa(key);
 	if (!rsa)
@@ -76,14 +79,13 @@
 /* OpenSSL assumes that the output buffer is always big enough */
 int pkcs11_private_encrypt(int flen,
 		const unsigned char *from, unsigned char *to,
-		PKCS11_KEY *key, int padding)
+		PKCS11_OBJECT_private *key, int padding)
 {
-	PKCS11_SLOT *slot = KEY2SLOT(key);
-	PKCS11_CTX *ctx = KEY2CTX(key);
-	PKCS11_KEY_private *kpriv = PRIVKEY(key);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
+	PKCS11_SLOT_private *slot = key->slot;
+	PKCS11_CTX_private *ctx = slot->ctx;
 	CK_MECHANISM mechanism;
 	CK_ULONG size;
+	CK_SESSION_HANDLE session;
 	int rv;
 
 	size = pkcs11_get_key_size(key);
@@ -91,26 +93,28 @@
 	if (pkcs11_mechanism(&mechanism, padding) < 0)
 		return -1;
 
-	CRYPTO_THREAD_write_lock(PRIVCTX(ctx)->rwlock);
+	if (pkcs11_get_session(slot, 0, &session))
+		return -1;
+
 	/* Try signing first, as applications are more likely to use it */
 	rv = CRYPTOKI_call(ctx,
-		C_SignInit(spriv->session, &mechanism, kpriv->object));
-	if (!rv && kpriv->always_authenticate == CK_TRUE)
-		rv = pkcs11_authenticate(key);
+		C_SignInit(session, &mechanism, key->object));
+	if (!rv && key->always_authenticate == CK_TRUE)
+		rv = pkcs11_authenticate(key, session);
 	if (!rv)
 		rv = CRYPTOKI_call(ctx,
-			C_Sign(spriv->session, (CK_BYTE *)from, flen, to, &size));
+			C_Sign(session, (CK_BYTE *)from, flen, to, &size));
 	if (rv == CKR_KEY_FUNCTION_NOT_PERMITTED) {
 		/* OpenSSL may use it for encryption rather than signing */
 		rv = CRYPTOKI_call(ctx,
-			C_EncryptInit(spriv->session, &mechanism, kpriv->object));
-		if (!rv && kpriv->always_authenticate == CK_TRUE)
-			rv = pkcs11_authenticate(key);
+			C_EncryptInit(session, &mechanism, key->object));
+		if (!rv && key->always_authenticate == CK_TRUE)
+			rv = pkcs11_authenticate(key, session);
 		if (!rv)
 			rv = CRYPTOKI_call(ctx,
-				C_Encrypt(spriv->session, (CK_BYTE *)from, flen, to, &size));
+				C_Encrypt(session, (CK_BYTE *)from, flen, to, &size));
 	}
-	CRYPTO_THREAD_unlock(PRIVCTX(ctx)->rwlock);
+	pkcs11_put_session(slot, session);
 
 	if (rv) {
 		CKRerr(CKR_F_PKCS11_PRIVATE_ENCRYPT, rv);
@@ -122,12 +126,11 @@
 
 /* RSA private key decryption */
 int pkcs11_private_decrypt(int flen, const unsigned char *from, unsigned char *to,
-		PKCS11_KEY *key, int padding)
+		PKCS11_OBJECT_private *key, int padding)
 {
-	PKCS11_SLOT *slot = KEY2SLOT(key);
-	PKCS11_CTX *ctx = KEY2CTX(key);
-	PKCS11_KEY_private *kpriv = PRIVKEY(key);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
+	PKCS11_SLOT_private *slot = key->slot;
+	PKCS11_CTX_private *ctx = slot->ctx;
+	CK_SESSION_HANDLE session;
 	CK_MECHANISM mechanism;
 	CK_ULONG size = flen;
 	CK_RV rv;
@@ -135,16 +138,18 @@
 	if (pkcs11_mechanism(&mechanism, padding) < 0)
 		return -1;
 
-	CRYPTO_THREAD_write_lock(PRIVCTX(ctx)->rwlock);
+	if (pkcs11_get_session(slot, 0, &session))
+		return -1;
+
 	rv = CRYPTOKI_call(ctx,
-		C_DecryptInit(spriv->session, &mechanism, kpriv->object));
-	if (!rv && kpriv->always_authenticate == CK_TRUE)
-		rv = pkcs11_authenticate(key);
+		C_DecryptInit(session, &mechanism, key->object));
+	if (!rv && key->always_authenticate == CK_TRUE)
+		rv = pkcs11_authenticate(key, session);
 	if (!rv)
 		rv = CRYPTOKI_call(ctx,
-			C_Decrypt(spriv->session, (CK_BYTE *)from, size,
+			C_Decrypt(session, (CK_BYTE *)from, size,
 				(CK_BYTE_PTR)to, &size));
-	CRYPTO_THREAD_unlock(PRIVCTX(ctx)->rwlock);
+	pkcs11_put_session(slot, session);
 
 	if (rv) {
 		CKRerr(CKR_F_PKCS11_PRIVATE_DECRYPT, rv);
@@ -156,7 +161,7 @@
 
 /* TODO: remove this function in libp11 0.5.0 */
 int pkcs11_verify(int type, const unsigned char *m, unsigned int m_len,
-		unsigned char *signature, unsigned int siglen, PKCS11_KEY *key)
+		unsigned char *signature, unsigned int siglen, PKCS11_OBJECT_private *key)
 {
 	(void)type;
 	(void)m;
@@ -173,19 +178,27 @@
 /*
  * Get RSA key material
  */
-static RSA *pkcs11_get_rsa(PKCS11_KEY *key)
+static RSA *pkcs11_get_rsa(PKCS11_OBJECT_private *key)
 {
+	CK_OBJECT_CLASS class_public_key = CKO_PUBLIC_KEY;
+	PKCS11_SLOT_private *slot = key->slot;
+	PKCS11_CTX_private *ctx = slot->ctx;
+	PKCS11_OBJECT_private *pubkey;
+	PKCS11_TEMPLATE tmpl = {0};
+	CK_OBJECT_HANDLE object = key->object;
+	CK_SESSION_HANDLE session;
 	RSA *rsa;
-	PKCS11_KEY *keys;
-	unsigned int i, count;
 	BIGNUM *rsa_n = NULL, *rsa_e = NULL;
 
-	/* Retrieve the modulus */
-	if (key_getattr_bn(key, CKA_MODULUS, &rsa_n))
+	if (pkcs11_get_session(slot, 0, &session))
 		return NULL;
 
+	/* Retrieve the modulus */
+	if (pkcs11_getattr_bn(ctx, session, object, CKA_MODULUS, &rsa_n))
+		goto failure;
+
 	/* Retrieve the public exponent */
-	if (!key_getattr_bn(key, CKA_PUBLIC_EXPONENT, &rsa_e)) {
+	if (!pkcs11_getattr_bn(ctx, session, object, CKA_PUBLIC_EXPONENT, &rsa_e)) {
 		if (!BN_is_zero(rsa_e)) /* A valid public exponent */
 			goto success;
 		BN_clear_free(rsa_e);
@@ -194,18 +207,15 @@
 
 	/* The public exponent was not found in the private key:
 	 * retrieve it from the corresponding public key */
-	if (!PKCS11_enumerate_public_keys(KEY2TOKEN(key), &keys, &count)) {
-		for (i = 0; i < count; i++) {
-			BIGNUM *pubmod = NULL;
-			if (!key_getattr_bn(&keys[i], CKA_MODULUS, &pubmod)) {
-				int found = BN_cmp(rsa_n, pubmod) == 0;
-				BN_clear_free(pubmod);
-				if (found && !key_getattr_bn(&keys[i],
-						CKA_PUBLIC_EXPONENT, &rsa_e))
-					goto success;
-			}
-		}
+	pkcs11_addattr_var(&tmpl, CKA_CLASS, class_public_key);
+	pkcs11_addattr_bn(&tmpl, CKA_MODULUS, rsa_n);
+	pubkey = pkcs11_object_from_template(slot, session, &tmpl);
+	if (pubkey && !pkcs11_getattr_bn(ctx, session, pubkey->object,
+			CKA_PUBLIC_EXPONENT, &rsa_e)) {
+		pkcs11_object_free(pubkey);
+		goto success;
 	}
+	pkcs11_object_free(pubkey);
 
 	/* Last resort: use the most common default */
 	rsa_e = BN_new();
@@ -213,6 +223,7 @@
 		goto success;
 
 failure:
+	pkcs11_put_session(slot, session);
 	if (rsa_n)
 		BN_clear_free(rsa_n);
 	if (rsa_e)
@@ -220,10 +231,11 @@
 	return NULL;
 
 success:
+	pkcs11_put_session(slot, session);
 	rsa = RSA_new();
 	if (!rsa)
 		goto failure;
-#if OPENSSL_VERSION_NUMBER >= 0x10100005L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100005L || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3050000fL )
 	RSA_set0_key(rsa, rsa_n, rsa_e, NULL);
 #else
 	rsa->n = rsa_n;
@@ -232,33 +244,20 @@
 	return rsa;
 }
 
-PKCS11_KEY *pkcs11_get_ex_data_rsa(const RSA *rsa)
+PKCS11_OBJECT_private *pkcs11_get_ex_data_rsa(const RSA *rsa)
 {
 	return RSA_get_ex_data(rsa, rsa_ex_index);
 }
 
-static void pkcs11_set_ex_data_rsa(RSA *rsa, PKCS11_KEY *key)
+static void pkcs11_set_ex_data_rsa(RSA *rsa, PKCS11_OBJECT_private *key)
 {
 	RSA_set_ex_data(rsa, rsa_ex_index, key);
 }
 
-static void pkcs11_update_ex_data_rsa(PKCS11_KEY *key)
-{
-	EVP_PKEY *evp = key->evp_key;
-	RSA *rsa;
-	if (!evp)
-		return;
-	if (EVP_PKEY_base_id(evp) != EVP_PKEY_RSA)
-		return;
-
-	rsa = EVP_PKEY_get1_RSA(evp);
-	pkcs11_set_ex_data_rsa(rsa, key);
-	RSA_free(rsa);
-}
 /*
  * Build an EVP_PKEY object
  */
-static EVP_PKEY *pkcs11_get_evp_key_rsa(PKCS11_KEY *key)
+static EVP_PKEY *pkcs11_get_evp_key_rsa(PKCS11_OBJECT_private *key)
 {
 	EVP_PKEY *pk;
 	RSA *rsa;
@@ -271,11 +270,9 @@
 		RSA_free(rsa);
 		return NULL;
 	}
-	EVP_PKEY_set1_RSA(pk, rsa); /* Also increments the rsa ref count */
-
-	if (key->isPrivate) {
+	if (key->object_class == CKO_PRIVATE_KEY) {
 		RSA_set_method(rsa, PKCS11_get_rsa_method());
-#if OPENSSL_VERSION_NUMBER >= 0x10100005L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100005L || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3050000fL )
 		RSA_set_flags(rsa, RSA_FLAG_EXT_PKEY);
 #else
 		rsa->flags |= RSA_FLAG_EXT_PKEY;
@@ -289,19 +286,21 @@
 	rsa->flags |= RSA_FLAG_SIGN_VER;
 #endif
 	pkcs11_set_ex_data_rsa(rsa, key);
+
+	EVP_PKEY_set1_RSA(pk, rsa); /* Also increments the rsa ref count */
 	RSA_free(rsa); /* Drops our reference to it */
 	return pk;
 }
 
 /* TODO: remove this function in libp11 0.5.0 */
-int pkcs11_get_key_modulus(PKCS11_KEY *key, BIGNUM **bn)
+int pkcs11_get_key_modulus(PKCS11_OBJECT_private *key, BIGNUM **bn)
 {
 	RSA *rsa = pkcs11_rsa(key);
 	const BIGNUM *rsa_n;
 
 	if (!rsa)
 		return 0;
-#if OPENSSL_VERSION_NUMBER >= 0x10100005L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100005L || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3050000fL )
 	RSA_get0_key(rsa, &rsa_n, NULL, NULL);
 #else
 	rsa_n=rsa->n;
@@ -311,14 +310,14 @@
 }
 
 /* TODO: remove this function in libp11 0.5.0 */
-int pkcs11_get_key_exponent(PKCS11_KEY *key, BIGNUM **bn)
+int pkcs11_get_key_exponent(PKCS11_OBJECT_private *key, BIGNUM **bn)
 {
 	RSA *rsa = pkcs11_rsa(key);
 	const BIGNUM *rsa_e;
 
 	if (!rsa)
 		return 0;
-#if OPENSSL_VERSION_NUMBER >= 0x10100005L && !defined(LIBRESSL_VERSION_NUMBER)
+#if OPENSSL_VERSION_NUMBER >= 0x10100005L || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x3050000fL )
 	RSA_get0_key(rsa, NULL, &rsa_e, NULL);
 #else
 	rsa_e=rsa->e;
@@ -328,7 +327,7 @@
 }
 
 /* TODO: make this function static in libp11 0.5.0 */
-int pkcs11_get_key_size(PKCS11_KEY *key)
+int pkcs11_get_key_size(PKCS11_OBJECT_private *key)
 {
 	RSA *rsa = pkcs11_rsa(key);
 	if (!rsa)
@@ -336,7 +335,7 @@
 	return RSA_size(rsa);
 }
 
-#if OPENSSL_VERSION_NUMBER < 0x10100005L || defined(LIBRESSL_VERSION_NUMBER)
+#if ( ( defined (OPENSSL_VERSION_NUMBER) && OPENSSL_VERSION_NUMBER < 0x10100005L ) || ( defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x3020199L ) )
 
 int (*RSA_meth_get_priv_enc(const RSA_METHOD *meth))
 		(int flen, const unsigned char *from,
@@ -362,32 +361,36 @@
 static int pkcs11_rsa_priv_dec_method(int flen, const unsigned char *from,
 		unsigned char *to, RSA *rsa, int padding)
 {
-	PKCS11_KEY *key = pkcs11_get_ex_data_rsa(rsa);
+	PKCS11_OBJECT_private *key = pkcs11_get_ex_data_rsa(rsa);
 	int (*priv_dec) (int flen, const unsigned char *from,
 		unsigned char *to, RSA *rsa, int padding);
-	if (check_key_fork(key) < 0) {
+	if (check_object_fork(key) < 0) {
 		priv_dec = RSA_meth_get_priv_dec(RSA_get_default_method());
 		return priv_dec(flen, from, to, rsa, padding);
 	}
-	return PKCS11_private_decrypt(flen, from, to, key, padding);
+	return pkcs11_private_decrypt(flen, from, to, key, padding);
 }
 
 static int pkcs11_rsa_priv_enc_method(int flen, const unsigned char *from,
 		unsigned char *to, RSA *rsa, int padding)
 {
-	PKCS11_KEY *key = pkcs11_get_ex_data_rsa(rsa);
+	PKCS11_OBJECT_private *key = pkcs11_get_ex_data_rsa(rsa);
 	int (*priv_enc) (int flen, const unsigned char *from,
 		unsigned char *to, RSA *rsa, int padding);
-	if (check_key_fork(key) < 0) {
+	if (check_object_fork(key) < 0) {
 		priv_enc = RSA_meth_get_priv_enc(RSA_get_default_method());
 		return priv_enc(flen, from, to, rsa, padding);
 	}
-	return PKCS11_private_encrypt(flen, from, to, key, padding);
+	return pkcs11_private_encrypt(flen, from, to, key, padding);
 }
 
 static int pkcs11_rsa_free_method(RSA *rsa)
 {
-	RSA_set_ex_data(rsa, rsa_ex_index, NULL);
+	PKCS11_OBJECT_private *key = pkcs11_get_ex_data_rsa(rsa);
+	if (key) {
+		pkcs11_set_ex_data_rsa(rsa, NULL);
+		pkcs11_object_free(key);
+	}
 	int (*orig_rsa_free_method)(RSA *rsa) =
 		RSA_meth_get_finish(RSA_get_default_method());
 	if (orig_rsa_free_method) {
@@ -508,10 +511,9 @@
 	free_rsa_ex_index();
 }
 
-PKCS11_KEY_ops pkcs11_rsa_ops = {
+PKCS11_OBJECT_ops pkcs11_rsa_ops = {
 	EVP_PKEY_RSA,
 	pkcs11_get_evp_key_rsa,
-	pkcs11_update_ex_data_rsa
 };
 
 /* vim: set noexpandtab: */
diff -Nru libp11-0.4.11/src/p11_slot.c libp11-0.4.12/src/p11_slot.c
--- libp11-0.4.11/src/p11_slot.c	2020-02-27 06:50:01.000000000 +0100
+++ libp11-0.4.12/src/p11_slot.c	2022-05-04 18:45:56.000000000 +0200
@@ -21,53 +21,52 @@
 #include <string.h>
 #include <openssl/buffer.h>
 
-static int pkcs11_init_slot(PKCS11_CTX *, PKCS11_SLOT *, CK_SLOT_ID);
-static void pkcs11_release_slot(PKCS11_CTX *, PKCS11_SLOT *);
-static int pkcs11_check_token(PKCS11_CTX *, PKCS11_SLOT *);
+static PKCS11_SLOT_private *pkcs11_slot_new(PKCS11_CTX_private *, CK_SLOT_ID);
+static int pkcs11_init_slot(PKCS11_CTX_private *, PKCS11_SLOT *, PKCS11_SLOT_private *);
+static void pkcs11_release_slot(PKCS11_SLOT *);
 static void pkcs11_destroy_token(PKCS11_TOKEN *);
 
 /*
  * Get slotid from private
  */
-unsigned long pkcs11_get_slotid_from_slot(PKCS11_SLOT *slot)
+unsigned long pkcs11_get_slotid_from_slot(PKCS11_SLOT_private *slot)
 {
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
-
-	return spriv->id;
+	return slot->id;
 }
 
 /*
  * Enumerate slots
  */
-int pkcs11_enumerate_slots(PKCS11_CTX *ctx, PKCS11_SLOT **slotp,
+int pkcs11_enumerate_slots(PKCS11_CTX_private *ctx, PKCS11_SLOT **slotp,
 		unsigned int *countp)
 {
-	PKCS11_CTX_private *cpriv = PRIVCTX(ctx);
 	CK_SLOT_ID *slotid;
-	CK_ULONG nslots, n;
+	CK_ULONG nslots, n, i;
 	PKCS11_SLOT *slots;
-	size_t alloc_size;
 	int rv;
 
-	rv = cpriv->method->C_GetSlotList(FALSE, NULL_PTR, &nslots);
+	rv = ctx->method->C_GetSlotList(FALSE, NULL_PTR, &nslots);
 	CRYPTOKI_checkerr(CKR_F_PKCS11_ENUMERATE_SLOTS, rv);
-
-	alloc_size = nslots * sizeof(CK_SLOT_ID);
-	if (alloc_size / sizeof(CK_SLOT_ID) != nslots) /* integer overflow */
+	if (nslots > 0x10000)
 		return -1;
-	slotid = OPENSSL_malloc(alloc_size);
+
+	if (!slotp) {
+		/* Fast path for size inquiry */
+		*countp = nslots;
+		return 0;
+	}
+
+	slotid = OPENSSL_malloc(nslots * sizeof(*slotid));
 	if (!slotid)
 		return -1;
 
-	rv = cpriv->method->C_GetSlotList(FALSE, slotid, &nslots);
-	CRYPTOKI_checkerr(CKR_F_PKCS11_ENUMERATE_SLOTS, rv);
-
-	alloc_size = nslots * sizeof(PKCS11_SLOT);
-	if (alloc_size / sizeof(PKCS11_SLOT) != nslots) { /* integer overflow */
+	rv = ctx->method->C_GetSlotList(FALSE, slotid, &nslots);
+	if (rv != CKR_OK) {
 		OPENSSL_free(slotid);
-		return -1;
+		CRYPTOKI_checkerr(CKR_F_PKCS11_ENUMERATE_SLOTS, rv);
 	}
-	slots = OPENSSL_malloc(alloc_size);
+
+	slots = OPENSSL_malloc(nslots * sizeof(*slots));
 	if (!slots) {
 		OPENSSL_free(slotid);
 		return -1;
@@ -75,238 +74,209 @@
 
 	memset(slots, 0, nslots * sizeof(PKCS11_SLOT));
 	for (n = 0; n < nslots; n++) {
-		if (pkcs11_init_slot(ctx, &slots[n], slotid[n])) {
-			while (n--)
-				pkcs11_release_slot(ctx, slots + n);
+		PKCS11_SLOT_private *slot = NULL;
+		for (i = 0; i < *countp; i++) {
+			if (PRIVSLOT(slotp[i])->id != slotid[n])
+				continue;
+			slot = pkcs11_slot_ref(PRIVSLOT(slotp[i]));
+			break;
+		}
+		if (!slot)
+			slot = pkcs11_slot_new(ctx, slotid[n]);
+
+		if (pkcs11_init_slot(ctx, &slots[n], slot)) {
+			pkcs11_slot_unref(slot);
+			pkcs11_release_all_slots(slots, n);
 			OPENSSL_free(slotid);
-			OPENSSL_free(slots);
 			return -1;
 		}
 	}
 
-	if (slotp)
-		*slotp = slots;
-	else
-		OPENSSL_free(slots);
-	if (countp)
-		*countp = nslots;
 	OPENSSL_free(slotid);
+	pkcs11_release_all_slots(*slotp, *countp);
+	*slotp = slots;
+	*countp = nslots;
 	return 0;
 }
 
 /*
- * Find a slot with a token that looks "valuable"
+ * Open a session with this slot
  */
-PKCS11_SLOT *pkcs11_find_token(PKCS11_CTX *ctx, PKCS11_SLOT *slots,
-		unsigned int nslots)
+int pkcs11_open_session(PKCS11_SLOT_private *slot, int rw)
 {
-	PKCS11_SLOT *slot, *best;
-	PKCS11_TOKEN *tok;
-	unsigned int n;
+	PKCS11_CTX_private *ctx = slot->ctx;
 
-	(void)ctx;
+	pthread_mutex_lock(&slot->lock);
+	/* If different mode requested, flush pool */
+	if (rw != slot->rw_mode) {
+		CRYPTOKI_call(ctx, C_CloseAllSessions(slot->id));
+		slot->rw_mode = rw;
+	}
+	slot->num_sessions = 0;
+	slot->session_head = slot->session_tail = 0;
+	pthread_mutex_unlock(&slot->lock);
 
-	if (!slots)
-		return NULL;
-
-	best = NULL;
-	for (n = 0, slot = slots; n < nslots; n++, slot++) {
-		if ((tok = slot->token) != NULL) {
-			if (!best ||
-					(tok->initialized > best->token->initialized &&
-					tok->userPinSet > best->token->userPinSet &&
-					tok->loginRequired > best->token->loginRequired))
-				best = slot;
-		}
-	}
-	return best;
+	return 0;
 }
 
-/*
- * Find the next slot with a token that looks "valuable"
- */
-PKCS11_SLOT *pkcs11_find_next_token(PKCS11_CTX *ctx, PKCS11_SLOT *slots,
-		unsigned int nslots, PKCS11_SLOT *current)
+int pkcs11_get_session(PKCS11_SLOT_private * slot, int rw, CK_SESSION_HANDLE *sessionp)
 {
-	int offset;
-
-	if (!slots)
-		return NULL;
+	PKCS11_CTX_private *ctx = slot->ctx;
+	int rv = CKR_OK;
 
-	if (current) {
-		offset = current + 1 - slots;
-		if (offset < 1 || (unsigned int)offset >= nslots)
-			return NULL;
-	} else {
-		offset = 0;
-	}
-
-	return pkcs11_find_token(ctx, slots + offset, nslots - offset);
-}
+	if (rw < 0)
+		return -1;
 
-/*
- * Open a session with this slot
- */
-int pkcs11_open_session(PKCS11_SLOT *slot, int rw, int relogin)
-{
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
-	PKCS11_CTX *ctx = SLOT2CTX(slot);
-	int rv;
+	pthread_mutex_lock(&slot->lock);
+	if (slot->rw_mode < 0)
+		slot->rw_mode = rw;
+	rw = slot->rw_mode;
+	do {
+		/* Get session from the pool */
+		if (slot->session_head != slot->session_tail) {
+			*sessionp = slot->session_pool[slot->session_head];
+			slot->session_head = (slot->session_head + 1) % slot->session_poolsize;
+			break;
+		}
 
-	if (relogin == 0) {
-		if (spriv->haveSession) {
-			CRYPTOKI_call(ctx, C_CloseSession(spriv->session));
-			spriv->haveSession = 0;
+		/* Check if new can be instantiated */
+		if (slot->num_sessions < slot->max_sessions) {
+			rv = CRYPTOKI_call(ctx,
+				C_OpenSession(slot->id,
+					CKF_SERIAL_SESSION | (rw ? CKF_RW_SESSION : 0),
+					NULL, NULL, sessionp));
+			if (rv == CKR_OK) {
+				slot->num_sessions++;
+				break;
+			}
+
+			/* Remember the maximum session count */
+			if (rv == CKR_SESSION_COUNT)
+				slot->max_sessions = slot->num_sessions;
 		}
-	}
-	rv = CRYPTOKI_call(ctx,
-		C_OpenSession(spriv->id,
-			CKF_SERIAL_SESSION | (rw ? CKF_RW_SESSION : 0),
-			NULL, NULL, &spriv->session));
-	CRYPTOKI_checkerr(CKR_F_PKCS11_OPEN_SESSION, rv);
-	spriv->haveSession = 1;
-	spriv->prev_rw = rw;
+
+		/* Wait for a session to become available */
+		pthread_cond_wait(&slot->cond, &slot->lock);
+	} while (1);
+	pthread_mutex_unlock(&slot->lock);
 
 	return 0;
 }
 
-int pkcs11_reopen_session(PKCS11_SLOT *slot)
+void pkcs11_put_session(PKCS11_SLOT_private *slot, CK_SESSION_HANDLE session)
 {
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
-	PKCS11_CTX *ctx = SLOT2CTX(slot);
-	int rv;
+	pthread_mutex_lock(&slot->lock);
 
-	rv = CRYPTOKI_call(ctx,
-		C_OpenSession(spriv->id,
-			CKF_SERIAL_SESSION | (spriv->prev_rw ? CKF_RW_SESSION : 0),
-			NULL, NULL, &spriv->session));
-	CRYPTOKI_checkerr(CKR_F_PKCS11_REOPEN_SESSION, rv);
-	spriv->haveSession = 1;
+	slot->session_pool[slot->session_tail] = session;
+	slot->session_tail = (slot->session_tail + 1) % slot->session_poolsize;
+	pthread_cond_signal(&slot->cond);
 
-	return 0;
+	pthread_mutex_unlock(&slot->lock);
 }
 
 /*
  * Determines if user is authenticated with token
  */
-int pkcs11_is_logged_in(PKCS11_SLOT *slot, int so, int *res)
+int pkcs11_is_logged_in(PKCS11_SLOT_private *slot, int so, int *res)
 {
-	PKCS11_CTX *ctx = SLOT2CTX(slot);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
-	CK_SESSION_INFO session_info;
-	int rv;
-
-	if (spriv->loggedIn) {
-		*res = 1;
-		return 0;
-	}
-	if (!spriv->haveSession) {
-		/* SO gets a r/w session by default,
-		 * user gets a r/o session by default. */
-		if (PKCS11_open_session(slot, so))
-			return -1;
-	}
-
-	rv = CRYPTOKI_call(ctx, C_GetSessionInfo(spriv->session, &session_info));
-	CRYPTOKI_checkerr(CKR_F_PKCS11_IS_LOGGED_IN, rv);
-	if (so) {
-		*res = session_info.state == CKS_RW_SO_FUNCTIONS;
-	} else {
-		*res = session_info.state == CKS_RO_USER_FUNCTIONS ||
-			session_info.state == CKS_RW_USER_FUNCTIONS;
-	}
+	*res = slot->logged_in == so;
 	return 0;
 }
 
 /*
- * Authenticate with the card. relogin should be set if we automatically
- * relogin after a fork.
+ * Authenticate with the card.
  */
-int pkcs11_login(PKCS11_SLOT *slot, int so, const char *pin, int relogin)
+int pkcs11_login(PKCS11_SLOT_private *slot, int so, const char *pin)
 {
-	PKCS11_CTX *ctx = SLOT2CTX(slot);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
+	PKCS11_CTX_private *ctx = slot->ctx;
+	CK_SESSION_HANDLE session;
 	int rv;
 
-	if (!relogin && spriv->loggedIn)
+	if (slot->logged_in >= 0)
 		return 0; /* Nothing to do */
 
-	if (!spriv->haveSession) {
-		/* SO gets a r/w session by default,
-		 * user gets a r/o session by default. */
-		if (pkcs11_open_session(slot, so, relogin))
-			return -1;
-	}
+	/* SO needs a r/w session, user can be checked with a r/o session. */
+	if (pkcs11_get_session(slot, so, &session))
+		return -1;
 
 	rv = CRYPTOKI_call(ctx,
-		C_Login(spriv->session, so ? CKU_SO : CKU_USER,
+		C_Login(session, so ? CKU_SO : CKU_USER,
 			(CK_UTF8CHAR *) pin, pin ? (unsigned long) strlen(pin) : 0));
-	if (rv && rv != CKR_USER_ALREADY_LOGGED_IN) /* logged in -> OK */
-		CRYPTOKI_checkerr(CKR_F_PKCS11_LOGIN, rv);
-	spriv->loggedIn = 1;
+	pkcs11_put_session(slot, session);
 
-	if (spriv->prev_pin != pin) {
-		if (spriv->prev_pin) {
-			OPENSSL_cleanse(spriv->prev_pin, strlen(spriv->prev_pin));
-			OPENSSL_free(spriv->prev_pin);
+	if (rv && rv != CKR_USER_ALREADY_LOGGED_IN) { /* logged in -> OK */
+		CRYPTOKI_checkerr(CKR_F_PKCS11_LOGIN, rv);
+	}
+	if (slot->prev_pin != pin) {
+		if (slot->prev_pin) {
+			OPENSSL_cleanse(slot->prev_pin, strlen(slot->prev_pin));
+			OPENSSL_free(slot->prev_pin);
 		}
-		spriv->prev_pin = OPENSSL_strdup(pin);
+		slot->prev_pin = OPENSSL_strdup(pin);
 	}
-	spriv->prev_so = so;
+	slot->logged_in = so;
 	return 0;
 }
 
 /*
- * Authenticate with the card
+ * Reopens the slot by creating a session and logging in if needed.
  */
-int pkcs11_relogin(PKCS11_SLOT *slot)
+int pkcs11_reload_slot(PKCS11_SLOT_private *slot)
 {
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
+	int logged_in = slot->logged_in;
+
+	slot->num_sessions = 0;
+	slot->session_head = slot->session_tail = 0;
+	if (logged_in >= 0) {
+		slot->logged_in = -1;
+		if (pkcs11_login(slot, logged_in, slot->prev_pin))
+			return -1;
+	}
 
-	return pkcs11_login(slot, spriv->prev_so, spriv->prev_pin, 1);
+	return 0;
+}
+
+static void pkcs11_wipe_cache(PKCS11_SLOT_private *slot)
+{
+	pkcs11_destroy_keys(slot, CKO_PRIVATE_KEY);
+	pkcs11_destroy_keys(slot, CKO_PUBLIC_KEY);
+	pkcs11_destroy_certs(slot);
 }
 
 /*
  * Log out
  */
-int pkcs11_logout(PKCS11_SLOT *slot)
+int pkcs11_logout(PKCS11_SLOT_private *slot)
 {
-	PKCS11_CTX *ctx = SLOT2CTX(slot);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
-	int rv;
+	PKCS11_CTX_private *ctx = slot->ctx;
+	CK_SESSION_HANDLE session;
+	int rv = CKR_OK;
 
 	/* Calling PKCS11_logout invalidates all cached
 	 * keys we have */
-	if (slot->token) {
-		pkcs11_destroy_keys(slot->token, CKO_PRIVATE_KEY);
-		pkcs11_destroy_keys(slot->token, CKO_PUBLIC_KEY);
-		pkcs11_destroy_certs(slot->token);
-	}
-	if (!spriv->haveSession) {
-		P11err(P11_F_PKCS11_LOGOUT, P11_R_NO_SESSION);
-		return -1;
-	}
+	pkcs11_wipe_cache(slot);
 
-	rv = CRYPTOKI_call(ctx, C_Logout(spriv->session));
+	if (pkcs11_get_session(slot, slot->logged_in, &session) == 0) {
+		rv = CRYPTOKI_call(ctx, C_Logout(session));
+		pkcs11_put_session(slot, session);
+	}
 	CRYPTOKI_checkerr(CKR_F_PKCS11_LOGOUT, rv);
-	spriv->loggedIn = 0;
+	slot->logged_in = -1;
 	return 0;
 }
 
 /*
  * Initialize the token
  */
-int pkcs11_init_token(PKCS11_TOKEN *token, const char *pin, const char *label)
+int pkcs11_init_token(PKCS11_SLOT_private *slot, const char *pin, const char *label)
 {
-	PKCS11_SLOT *slot = TOKEN2SLOT(token);
-	PKCS11_CTX *ctx = SLOT2CTX(slot);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
+	PKCS11_CTX_private *ctx = slot->ctx;
 	int rv;
 
 	if (!label)
 		label = "PKCS#11 Token";
 	rv = CRYPTOKI_call(ctx,
-		C_InitToken(spriv->id,
+		C_InitToken(slot->id,
 			(CK_UTF8CHAR *) pin, (unsigned long) strlen(pin),
 			(CK_UTF8CHAR *) label));
 	CRYPTOKI_checkerr(CKR_F_PKCS11_INIT_TOKEN, rv);
@@ -327,36 +297,36 @@
 /*
  * Set the User PIN
  */
-int pkcs11_init_pin(PKCS11_TOKEN *token, const char *pin)
+int pkcs11_init_pin(PKCS11_SLOT_private *slot, const char *pin)
 {
-	PKCS11_SLOT *slot = TOKEN2SLOT(token);
-	PKCS11_CTX *ctx = SLOT2CTX(slot);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
+	PKCS11_CTX_private *ctx = slot->ctx;
+	CK_OBJECT_HANDLE session;
 	int len, rv;
 
-	if (!spriv->haveSession) {
+	if (pkcs11_get_session(slot, 1, &session)) {
 		P11err(P11_F_PKCS11_INIT_PIN, P11_R_NO_SESSION);
 		return -1;
 	}
 
 	len = pin ? (int) strlen(pin) : 0;
-	rv = CRYPTOKI_call(ctx, C_InitPIN(spriv->session, (CK_UTF8CHAR *) pin, len));
+	rv = CRYPTOKI_call(ctx, C_InitPIN(session, (CK_UTF8CHAR *) pin, len));
+	pkcs11_put_session(slot, session);
 	CRYPTOKI_checkerr(CKR_F_PKCS11_INIT_PIN, rv);
 
-	return pkcs11_check_token(ctx, TOKEN2SLOT(token));
+	return 0;
 }
 
 /*
  * Change the User PIN
  */
-int pkcs11_change_pin(PKCS11_SLOT *slot, const char *old_pin,
+int pkcs11_change_pin(PKCS11_SLOT_private *slot, const char *old_pin,
 		const char *new_pin)
 {
-	PKCS11_CTX *ctx = SLOT2CTX(slot);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
+	PKCS11_CTX_private *ctx = slot->ctx;
+	CK_SESSION_HANDLE session;
 	int old_len, new_len, rv;
 
-	if (!spriv->haveSession) {
+	if (pkcs11_get_session(slot, 1, &session)) {
 		P11err(P11_F_PKCS11_CHANGE_PIN, P11_R_NO_SESSION);
 		return -1;
 	}
@@ -364,139 +334,163 @@
 	old_len = old_pin ? (int) strlen(old_pin) : 0;
 	new_len = new_pin ? (int) strlen(new_pin) : 0;
 	rv = CRYPTOKI_call(ctx,
-		C_SetPIN(spriv->session, (CK_UTF8CHAR *) old_pin, old_len,
+		C_SetPIN(session, (CK_UTF8CHAR *) old_pin, old_len,
 			(CK_UTF8CHAR *) new_pin, new_len));
+	pkcs11_put_session(slot, session);
 	CRYPTOKI_checkerr(CKR_F_PKCS11_CHANGE_PIN, rv);
 
-	return pkcs11_check_token(ctx, slot);
+	return 0;
 }
 
 /*
  * Seed the random number generator
  */
-int pkcs11_seed_random(PKCS11_SLOT *slot, const unsigned char *s,
+int pkcs11_seed_random(PKCS11_SLOT_private *slot, const unsigned char *s,
 		unsigned int s_len)
 {
-	PKCS11_CTX *ctx = SLOT2CTX(slot);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
+	PKCS11_CTX_private *ctx = slot->ctx;
+	CK_SESSION_HANDLE session;
 	int rv;
 
-	if (!spriv->haveSession && PKCS11_open_session(slot, 0)) {
+	if (pkcs11_get_session(slot, 0, &session)) {
 		P11err(P11_F_PKCS11_SEED_RANDOM, P11_R_NO_SESSION);
 		return -1;
 	}
 
 	rv = CRYPTOKI_call(ctx,
-		C_SeedRandom(spriv->session, (CK_BYTE_PTR) s, s_len));
+		C_SeedRandom(session, (CK_BYTE_PTR) s, s_len));
+	pkcs11_put_session(slot, session);
 	CRYPTOKI_checkerr(CKR_F_PKCS11_SEED_RANDOM, rv);
 
-	return pkcs11_check_token(ctx, slot);
+	return 0;
 }
 
 /*
  * Generate random numbers
  */
-int pkcs11_generate_random(PKCS11_SLOT *slot, unsigned char *r,
+int pkcs11_generate_random(PKCS11_SLOT_private *slot, unsigned char *r,
 		unsigned int r_len)
 {
-	PKCS11_CTX *ctx = SLOT2CTX(slot);
-	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
+	PKCS11_CTX_private *ctx = slot->ctx;
+	CK_SESSION_HANDLE session;
 	int rv;
 
-	if (!spriv->haveSession && PKCS11_open_session(slot, 0)) {
+	if (pkcs11_get_session(slot, 0, &session)) {
 		P11err(P11_F_PKCS11_GENERATE_RANDOM, P11_R_NO_SESSION);
 		return -1;
 	}
 
 	rv = CRYPTOKI_call(ctx,
-		C_GenerateRandom(spriv->session, (CK_BYTE_PTR) r, r_len));
+		C_GenerateRandom(session, (CK_BYTE_PTR) r, r_len));
+	pkcs11_put_session(slot, session);
+
 	CRYPTOKI_checkerr(CKR_F_PKCS11_GENERATE_RANDOM, rv);
 
-	return pkcs11_check_token(ctx, slot);
+	return 0;
 }
 
 /*
  * Helper functions
  */
-static int pkcs11_init_slot(PKCS11_CTX *ctx, PKCS11_SLOT *slot, CK_SLOT_ID id)
+static PKCS11_SLOT_private *pkcs11_slot_new(PKCS11_CTX_private *ctx, CK_SLOT_ID id)
+{
+	PKCS11_SLOT_private *slot;
+
+	slot = OPENSSL_malloc(sizeof(*slot));
+	if (!slot)
+		return NULL;
+	memset(slot, 0, sizeof(*slot));
+	slot->refcnt = 1;
+	slot->ctx = ctx;
+	slot->id = id;
+	slot->forkid = ctx->forkid;
+	slot->logged_in = -1;
+	slot->rw_mode = -1;
+	slot->max_sessions = 16;
+	slot->session_poolsize = slot->max_sessions + 1;
+	slot->session_pool = OPENSSL_malloc(slot->session_poolsize * sizeof(CK_SESSION_HANDLE));
+	pthread_mutex_init(&slot->lock, 0);
+	pthread_cond_init(&slot->cond, 0);
+	return slot;
+}
+
+PKCS11_SLOT_private *pkcs11_slot_ref(PKCS11_SLOT_private *slot)
+{
+	pkcs11_atomic_add(&slot->refcnt, 1, &slot->lock);
+	return slot;
+}
+
+void pkcs11_slot_unref(PKCS11_SLOT_private *slot)
+{
+	if (pkcs11_atomic_add(&slot->refcnt, -1, &slot->lock) != 0)
+		return;
+
+	pkcs11_wipe_cache(slot);
+	if (slot->prev_pin) {
+		OPENSSL_cleanse(slot->prev_pin, strlen(slot->prev_pin));
+		OPENSSL_free(slot->prev_pin);
+	}
+	CRYPTOKI_call(slot->ctx, C_CloseAllSessions(slot->id));
+	OPENSSL_free(slot->session_pool);
+	pthread_mutex_destroy(&slot->lock);
+	pthread_cond_destroy(&slot->cond);
+}
+
+static int pkcs11_init_slot(PKCS11_CTX_private *ctx, PKCS11_SLOT *slot, PKCS11_SLOT_private *spriv)
 {
-	PKCS11_SLOT_private *spriv;
 	CK_SLOT_INFO info;
 	int rv;
 
-	rv = CRYPTOKI_call(ctx, C_GetSlotInfo(id, &info));
+	rv = CRYPTOKI_call(ctx, C_GetSlotInfo(spriv->id, &info));
 	CRYPTOKI_checkerr(CKR_F_PKCS11_INIT_SLOT, rv);
 
-	spriv = OPENSSL_malloc(sizeof(PKCS11_SLOT_private));
-	if (!spriv)
-		return -1;
-	memset(spriv, 0, sizeof(PKCS11_SLOT_private));
-
-	spriv->parent = ctx;
-	spriv->id = id;
-	spriv->forkid = PRIVCTX(ctx)->forkid;
-	spriv->prev_rw = 0;
-	spriv->prev_pin = NULL;
-	spriv->prev_so = 0;
-
+	slot->_private = spriv;
 	slot->description = PKCS11_DUP(info.slotDescription);
 	slot->manufacturer = PKCS11_DUP(info.manufacturerID);
 	slot->removable = (info.flags & CKF_REMOVABLE_DEVICE) ? 1 : 0;
-	slot->_private = spriv;
-
-	if ((info.flags & CKF_TOKEN_PRESENT) && pkcs11_check_token(ctx, slot))
-		return -1;
 
+	if (info.flags & CKF_TOKEN_PRESENT) {
+		if (pkcs11_refresh_token(slot))
+			return -1;
+	}
 	return 0;
 }
 
-void pkcs11_release_all_slots(PKCS11_CTX *ctx,  PKCS11_SLOT *slots,
-		unsigned int nslots)
+void pkcs11_release_all_slots(PKCS11_SLOT *slots, unsigned int nslots)
 {
 	unsigned int i;
 
 	for (i=0; i < nslots; i++)
-		pkcs11_release_slot(ctx, &slots[i]);
+		pkcs11_release_slot(&slots[i]);
 	OPENSSL_free(slots);
 }
 
-static void pkcs11_release_slot(PKCS11_CTX *ctx, PKCS11_SLOT *slot)
+static void pkcs11_release_slot(PKCS11_SLOT *slot)
 {
 	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
 
-	if (spriv) {
-		if (spriv->prev_pin) {
-			OPENSSL_cleanse(spriv->prev_pin, strlen(spriv->prev_pin));
-			OPENSSL_free(spriv->prev_pin);
-		}
-		CRYPTOKI_call(ctx, C_CloseAllSessions(spriv->id));
-	}
-	OPENSSL_free(slot->_private);
-	OPENSSL_free(slot->description);
-	OPENSSL_free(slot->manufacturer);
 	if (slot->token) {
 		pkcs11_destroy_token(slot->token);
 		OPENSSL_free(slot->token);
 	}
+	if (spriv)
+		pkcs11_slot_unref(spriv);
+	OPENSSL_free(slot->description);
+	OPENSSL_free(slot->manufacturer);
+	OPENSSL_free(slot->_private);
 
 	memset(slot, 0, sizeof(*slot));
 }
 
-static int pkcs11_check_token(PKCS11_CTX *ctx, PKCS11_SLOT *slot)
+int pkcs11_refresh_token(PKCS11_SLOT *slot)
 {
 	PKCS11_SLOT_private *spriv = PRIVSLOT(slot);
-	PKCS11_TOKEN_private *tpriv;
+	PKCS11_CTX_private *ctx = spriv->ctx;
 	CK_TOKEN_INFO info;
 	int rv;
 
-	if (slot->token) {
+	if (slot->token)
 		pkcs11_destroy_token(slot->token);
-	} else {
-		slot->token = OPENSSL_malloc(sizeof(PKCS11_TOKEN));
-		if (!slot->token)
-			return -1;
-		memset(slot->token, 0, sizeof(PKCS11_TOKEN));
-	}
 
 	rv = CRYPTOKI_call(ctx, C_GetTokenInfo(spriv->id, &info));
 	if (rv == CKR_TOKEN_NOT_PRESENT || rv == CKR_TOKEN_NOT_RECOGNIZED) {
@@ -507,16 +501,12 @@
 	CRYPTOKI_checkerr(CKR_F_PKCS11_CHECK_TOKEN, rv);
 
 	/* We have a token */
-	tpriv = OPENSSL_malloc(sizeof(PKCS11_TOKEN_private));
-	if (!tpriv)
-		return -1;
-	memset(tpriv, 0, sizeof(PKCS11_TOKEN_private));
-	tpriv->parent = slot;
-	tpriv->prv.keys = NULL;
-	tpriv->prv.num = 0;
-	tpriv->pub.keys = NULL;
-	tpriv->pub.num = 0;
-	tpriv->ncerts = 0;
+	if (!slot->token) {
+		slot->token = OPENSSL_malloc(sizeof(PKCS11_TOKEN));
+		if (!slot->token)
+			return -1;
+		memset(slot->token, 0, sizeof(PKCS11_TOKEN));
+	}
 
 	slot->token->label = PKCS11_DUP(info.label);
 	slot->token->manufacturer = PKCS11_DUP(info.manufacturerID);
@@ -536,22 +526,20 @@
 	slot->token->soPinFinalTry = (info.flags & CKF_SO_PIN_FINAL_TRY) ? 1 : 0;
 	slot->token->soPinLocked = (info.flags & CKF_SO_PIN_LOCKED) ? 1 : 0;
 	slot->token->soPinToBeChanged = (info.flags & CKF_SO_PIN_TO_BE_CHANGED) ? 1 : 0;
-	slot->token->_private = tpriv;
+	slot->token->slot = slot;
+
+	spriv->secure_login = (info.flags & CKF_PROTECTED_AUTHENTICATION_PATH) ? 1 : 0;
 
 	return 0;
 }
 
 static void pkcs11_destroy_token(PKCS11_TOKEN *token)
 {
-	pkcs11_destroy_keys(token, CKO_PRIVATE_KEY);
-	pkcs11_destroy_keys(token, CKO_PUBLIC_KEY);
-	pkcs11_destroy_certs(token);
-
+	pkcs11_wipe_cache(PRIVSLOT(token->slot));
 	OPENSSL_free(token->label);
 	OPENSSL_free(token->manufacturer);
 	OPENSSL_free(token->model);
 	OPENSSL_free(token->serialnr);
-	OPENSSL_free(token->_private);
 	memset(token, 0, sizeof(*token));
 }
 
diff -Nru libp11-0.4.11/src/pkcs11.h libp11-0.4.12/src/pkcs11.h
--- libp11-0.4.11/src/pkcs11.h	2020-05-18 08:47:22.000000000 +0200
+++ libp11-0.4.12/src/pkcs11.h	2022-03-15 18:13:43.000000000 +0100
@@ -592,6 +592,22 @@
 #define CKM_SHA512			(0x270UL)
 #define CKM_SHA512_HMAC			(0x271UL)
 #define CKM_SHA512_HMAC_GENERAL		(0x272UL)
+#define CKM_SHA3_256				(0x2B0UL)
+#define CKM_SHA3_256_HMAC			(0x2B1UL)
+#define CKM_SHA3_256_HMAC_GENERAL	(0x2B2UL)
+#define CKM_SHA3_256_KEY_GEN		(0x2B3UL)
+#define CKM_SHA3_224				(0x2B5UL)
+#define CKM_SHA3_224_HMAC			(0x2B6UL)
+#define CKM_SHA3_224_HMAC_GENERAL	(0x2B7UL)
+#define CKM_SHA3_224_KEY_GEN		(0x2B8UL)
+#define CKM_SHA3_384				(0x2C0UL)
+#define CKM_SHA3_384_HMAC			(0x2C1UL)
+#define CKM_SHA3_384_HMAC_GENERAL	(0x2C2UL)
+#define CKM_SHA3_384_KEY_GEN		(0x2C3UL)
+#define CKM_SHA3_512				(0x2D0UL)
+#define CKM_SHA3_512_HMAC			(0x2D1UL)
+#define CKM_SHA3_512_HMAC_GENERAL	(0x2D2UL)
+#define CKM_SHA3_512_KEY_GEN		(0x2D3UL)
 #define CKM_CAST_KEY_GEN		(0x300UL)
 #define CKM_CAST_ECB			(0x301UL)
 #define CKM_CAST_CBC			(0x302UL)
@@ -845,6 +861,10 @@
 #define CKG_MGF1_SHA256		(0x00000002UL)
 #define CKG_MGF1_SHA384		(0x00000003UL)
 #define CKG_MGF1_SHA512		(0x00000004UL)
+#define CKG_MGF1_SHA3_224	(0x00000006UL)
+#define CKG_MGF1_SHA3_256	(0x00000007UL)
+#define CKG_MGF1_SHA3_384	(0x00000008UL)
+#define CKG_MGF1_SHA3_512	(0x00000009UL)
 
 #define CKZ_DATA_SPECIFIED	(0x00000001UL)
 
diff -Nru libp11-0.4.11/src/pkcs11.rc libp11-0.4.12/src/pkcs11.rc
--- libp11-0.4.11/src/pkcs11.rc	2020-10-11 17:18:13.000000000 +0200
+++ libp11-0.4.12/src/pkcs11.rc	2022-07-15 21:56:30.000000000 +0200
@@ -1,8 +1,8 @@
 #include <winresrc.h>
 
 VS_VERSION_INFO VERSIONINFO
-	FILEVERSION 0,4,11,0
-	PRODUCTVERSION 0,4,11,0
+	FILEVERSION 0,4,12,0
+	PRODUCTVERSION 0,4,12,0
 	FILEFLAGSMASK 0x3fL
 #ifdef _DEBUG
 	FILEFLAGS 0x21L
@@ -20,14 +20,14 @@
 			VALUE "Comments", "Provided under the terms of the GNU General Public License (LGPLv2.1+).\0"
 			VALUE "CompanyName", "OpenSC Project\0"
 			VALUE "FileDescription", "OpenSSL PKCS#11 engine\0"
-			VALUE "FileVersion", "0.4.11.0\0"
+			VALUE "FileVersion", "0.4.12.0\0"
 			VALUE "InternalName", "libp11\0"
 			VALUE "LegalCopyright", "OpenSC Project\0"
 			VALUE "LegalTrademarks", "\0"
 			VALUE "OriginalFilename", "pkcs11.dll\0"
 			VALUE "PrivateBuild", "\0"
 			VALUE "ProductName", "libp11\0"
-			VALUE "ProductVersion", "0.4.11.0\0"
+			VALUE "ProductVersion", "0.4.12.0\0"
 			VALUE "SpecialBuild", "\0"
 		END
 	END
diff -Nru libp11-0.4.11/test-driver libp11-0.4.12/test-driver
--- libp11-0.4.11/test-driver	2018-10-02 20:47:03.000000000 +0200
+++ libp11-0.4.12/test-driver	2022-03-15 18:14:17.000000000 +0100
@@ -3,7 +3,7 @@
 
 scriptversion=2018-03-07.03; # UTC
 
-# Copyright (C) 2011-2018 Free Software Foundation, Inc.
+# Copyright (C) 2011-2020 Free Software Foundation, Inc.
 #
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -42,11 +42,13 @@
 {
   cat <<END
 Usage:
-  test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
-              [--expect-failure={yes|no}] [--color-tests={yes|no}]
-              [--enable-hard-errors={yes|no}] [--]
+  test-driver --test-name NAME --log-file PATH --trs-file PATH
+              [--expect-failure {yes|no}] [--color-tests {yes|no}]
+              [--enable-hard-errors {yes|no}] [--]
               TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
+
 The '--test-name', '--log-file' and '--trs-file' options are mandatory.
+See the GNU Automake documentation for information.
 END
 }
 
diff -Nru libp11-0.4.11/tests/ec-cert-store.softhsm libp11-0.4.12/tests/ec-cert-store.softhsm
--- libp11-0.4.11/tests/ec-cert-store.softhsm	1970-01-01 01:00:00.000000000 +0100
+++ libp11-0.4.12/tests/ec-cert-store.softhsm	2021-02-08 12:17:15.000000000 +0100
@@ -0,0 +1,47 @@
+#!/bin/sh
+
+# Copyright (C) 2015 Nikos Mavrogiannopoulos
+# Copyright (C) 2019 Anderson Toshiyuki Sasaki
+# Copyright (C) 2019 Red Hat, Inc.
+# Copyright (C) 2020 Mateusz Kwiatkowski
+# Copyright (C) 2020 AVSystem
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+outdir="output.$$"
+
+# Load common test functions
+. ${srcdir}/ec-no-pubkey.sh
+
+sed -e "s|@MODULE_PATH@|${MODULE}|g" -e "s|@ENGINE_PATH@|../src/.libs/pkcs11.so|g" <"${srcdir}/engines.cnf.in" >"${outdir}/engines.cnf"
+
+export OPENSSL_ENGINES="../src/.libs/"
+CERTIFICATE="${outdir}/ec-cert.pem"
+CERTIFICATE_URL="pkcs11:token=libp11-test;object=stored-cert;pin-value=1234"
+
+./store-cert ${CERTIFICATE} ${CERTIFICATE_URL} ${MODULE} "${outdir}/engines.cnf"
+if test $? != 0;then
+	echo "The certificate storing couldn't be performed"
+	exit 1;
+fi
+
+pkcs11-tool -p 1234 --module ${MODULE} -l -O | grep -q stored-cert
+if test $? != 0;then
+	echo "The certificate was not properly stored"
+	exit 1;
+fi
+
+rm -rf "$outdir"
+
+exit 0
diff -Nru libp11-0.4.11/tests/ec-check-privkey.softhsm libp11-0.4.12/tests/ec-check-privkey.softhsm
--- libp11-0.4.11/tests/ec-check-privkey.softhsm	2020-02-27 06:50:01.000000000 +0100
+++ libp11-0.4.12/tests/ec-check-privkey.softhsm	2021-10-30 14:20:08.000000000 +0200
@@ -31,13 +31,13 @@
 
 ./check-privkey ${CERTIFICATE} ${PRIVATE_KEY} ${MODULE} "${outdir}/engines.cnf"
 if test $? != 0;then
-	echo "The private key loading couln't get the public key from the certificate"
+	echo "The private key loading couldn't get the public key from the certificate"
 	exit 1;
 fi
 
 ./check-privkey ${CERTIFICATE_URL} ${PRIVATE_KEY} ${MODULE} "${outdir}/engines.cnf"
 if test $? != 0;then
-	echo "The private key loading couln't get the public key from the certificate URL"
+	echo "The private key loading couldn't get the public key from the certificate URL"
 	exit 1;
 fi
 
diff -Nru libp11-0.4.11/tests/evp-sign.c libp11-0.4.12/tests/evp-sign.c
--- libp11-0.4.11/tests/evp-sign.c	2020-02-27 06:50:01.000000000 +0100
+++ libp11-0.4.12/tests/evp-sign.c	2021-10-30 14:20:08.000000000 +0200
@@ -88,7 +88,7 @@
 		case UIT_VERIFY:
 		{
 			/* If there is a default PIN, just
-			 * return without outputing any prompt */
+			 * return without outputting any prompt */
 			const char *password =
 				((const char *)UI_get0_user_data(ui));
 			if (password && password[0] != '\0')
diff -Nru libp11-0.4.11/tests/fork-change-slot.c libp11-0.4.12/tests/fork-change-slot.c
--- libp11-0.4.11/tests/fork-change-slot.c	2020-02-27 06:50:01.000000000 +0100
+++ libp11-0.4.12/tests/fork-change-slot.c	2021-10-30 14:20:08.000000000 +0200
@@ -65,10 +65,6 @@
 #define RANDOM_SIZE 20
 #define MAX_SIGSIZE 1024
 
-#if OPENSSL_VERSION_NUMBER < 0x10100003L
-#define EVP_PKEY_get0_RSA(key) ((key)->pkey.rsa)
-#endif
-
 static int do_wait(pid_t pids[], int num)
 {
     int i;
diff -Nru libp11-0.4.11/tests/fork-test.c libp11-0.4.12/tests/fork-test.c
--- libp11-0.4.11/tests/fork-test.c	2020-02-27 06:50:01.000000000 +0100
+++ libp11-0.4.12/tests/fork-test.c	2021-10-30 14:20:08.000000000 +0200
@@ -52,10 +52,6 @@
 #define RANDOM_SIZE 20
 #define MAX_SIGSIZE 1024
 
-#if OPENSSL_VERSION_NUMBER < 0x10100003L
-#define EVP_PKEY_get0_RSA(key) ((key)->pkey.rsa)
-#endif
-
 static void do_fork();
 static void error_queue(const char *name);
 
diff -Nru libp11-0.4.11/tests/list-tokens.c libp11-0.4.12/tests/list-tokens.c
--- libp11-0.4.11/tests/list-tokens.c	2020-02-27 06:50:01.000000000 +0100
+++ libp11-0.4.12/tests/list-tokens.c	2021-02-08 12:17:15.000000000 +0100
@@ -39,7 +39,6 @@
 {
 	PKCS11_CTX *ctx;
 	PKCS11_SLOT *slots, *slot;
-	PKCS11_CERT *certs;
 
 	int rc = 0, token_found = 0;
 
diff -Nru libp11-0.4.11/tests/Makefile.am libp11-0.4.12/tests/Makefile.am
--- libp11-0.4.11/tests/Makefile.am	2020-02-27 06:50:01.000000000 +0100
+++ libp11-0.4.12/tests/Makefile.am	2022-03-15 18:13:43.000000000 +0100
@@ -1,4 +1,4 @@
-EXTRA_DIST = engines.cnf.in rsa-common.sh ec-common.sh ec-no-pubkey.sh
+EXTRA_DIST = engines.cnf.in rsa-common.sh rsa-no-pubkey.sh ec-common.sh ec-no-pubkey.sh
 
 AM_CFLAGS = $(OPENSSL_CFLAGS)
 AM_CPPFLAGS = \
@@ -16,7 +16,8 @@
 	list-tokens \
 	rsa-pss-sign \
 	rsa-oaep \
-	check-privkey
+	check-privkey \
+	store-cert
 dist_check_SCRIPTS = \
 	rsa-testpkcs11.softhsm \
 	rsa-testfork.softhsm \
@@ -28,9 +29,11 @@
 	rsa-pss-sign.softhsm \
 	rsa-oaep.softhsm \
 	case-insensitive.softhsm \
+	rsa-check-privkey.softhsm \
 	ec-check-privkey.softhsm \
 	pkcs11-uri-without-token.softhsm \
-	search-all-matching-tokens.softhsm
+	search-all-matching-tokens.softhsm \
+	ec-cert-store.softhsm
 dist_check_DATA = \
 	rsa-cert.der rsa-prvkey.der rsa-pubkey.der \
 	ec-cert.der ec-prvkey.der ec-pubkey.der
diff -Nru libp11-0.4.11/tests/Makefile.in libp11-0.4.12/tests/Makefile.in
--- libp11-0.4.11/tests/Makefile.in	2020-10-11 15:46:57.000000000 +0200
+++ libp11-0.4.12/tests/Makefile.in	2022-07-15 21:56:27.000000000 +0200
@@ -1,7 +1,7 @@
-# Makefile.in generated by automake 1.16.2 from Makefile.am.
+# Makefile.in generated by automake 1.16.4 from Makefile.am.
 # @configure_input@
 
-# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+# Copyright (C) 1994-2021 Free Software Foundation, Inc.
 
 # This Makefile.in is free software; the Free Software Foundation
 # gives unlimited permission to copy and/or distribute it,
@@ -87,13 +87,15 @@
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
+target_triplet = @target@
 check_PROGRAMS = openssl_version$(EXEEXT) fork-test$(EXEEXT) \
 	evp-sign$(EXEEXT) fork-change-slot$(EXEEXT) \
 	list-tokens$(EXEEXT) rsa-pss-sign$(EXEEXT) rsa-oaep$(EXEEXT) \
-	check-privkey$(EXEEXT)
+	check-privkey$(EXEEXT) store-cert$(EXEEXT)
 subdir = tests
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
-am__aclocal_m4_deps = $(top_srcdir)/m4/ld-version-script.m4 \
+am__aclocal_m4_deps = $(top_srcdir)/m4/ax_pthread.m4 \
+	$(top_srcdir)/m4/ld-version-script.m4 \
 	$(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \
 	$(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \
 	$(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/configure.ac
@@ -142,6 +144,10 @@
 rsa_pss_sign_OBJECTS = rsa-pss-sign.$(OBJEXT)
 rsa_pss_sign_LDADD = $(LDADD)
 rsa_pss_sign_DEPENDENCIES = ../src/libp11.la $(am__DEPENDENCIES_1)
+store_cert_SOURCES = store-cert.c
+store_cert_OBJECTS = store-cert.$(OBJEXT)
+store_cert_LDADD = $(LDADD)
+store_cert_DEPENDENCIES = ../src/libp11.la $(am__DEPENDENCIES_1)
 AM_V_P = $(am__v_P_ at AM_V@)
 am__v_P_ = $(am__v_P_ at AM_DEFAULT_V@)
 am__v_P_0 = false
@@ -161,7 +167,7 @@
 	./$(DEPDIR)/evp-sign.Po ./$(DEPDIR)/fork-change-slot.Po \
 	./$(DEPDIR)/fork-test.Po ./$(DEPDIR)/list-tokens.Po \
 	./$(DEPDIR)/openssl_version.Po ./$(DEPDIR)/rsa-oaep.Po \
-	./$(DEPDIR)/rsa-pss-sign.Po
+	./$(DEPDIR)/rsa-pss-sign.Po ./$(DEPDIR)/store-cert.Po
 am__mv = mv -f
 COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
 	$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
@@ -182,10 +188,11 @@
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
 SOURCES = check-privkey.c evp-sign.c fork-change-slot.c fork-test.c \
-	list-tokens.c openssl_version.c rsa-oaep.c rsa-pss-sign.c
+	list-tokens.c openssl_version.c rsa-oaep.c rsa-pss-sign.c \
+	store-cert.c
 DIST_SOURCES = check-privkey.c evp-sign.c fork-change-slot.c \
 	fork-test.c list-tokens.c openssl_version.c rsa-oaep.c \
-	rsa-pss-sign.c
+	rsa-pss-sign.c store-cert.c
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
     n|no|NO) false;; \
@@ -208,8 +215,6 @@
   unique=`for i in $$list; do \
     if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
   done | $(am__uniquify_input)`
-ETAGS = etags
-CTAGS = ctags
 am__tty_colors_dummy = \
   mgn= red= grn= lgn= blu= brg= std=; \
   am__color_tests=no
@@ -392,6 +397,7 @@
   bases='$(TEST_LOGS)'; \
   bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
   bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
 RECHECK_LOGS = $(TEST_LOGS)
 AM_RECURSIVE_TARGETS = check recheck
 TEST_SUITE_LOG = test-suite.log
@@ -431,6 +437,8 @@
 CFLAGS = @CFLAGS@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
+CSCOPE = @CSCOPE@
+CTAGS = @CTAGS@
 CYGPATH_W = @CYGPATH_W@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
@@ -442,6 +450,7 @@
 ECHO_N = @ECHO_N@
 ECHO_T = @ECHO_T@
 EGREP = @EGREP@
+ETAGS = @ETAGS@
 EXEEXT = @EXEEXT@
 FGREP = @FGREP@
 GREP = @GREP@
@@ -488,6 +497,10 @@
 PKG_CONFIG = @PKG_CONFIG@
 PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
 PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PTHREAD_CC = @PTHREAD_CC@
+PTHREAD_CFLAGS = @PTHREAD_CFLAGS@
+PTHREAD_CXX = @PTHREAD_CXX@
+PTHREAD_LIBS = @PTHREAD_LIBS@
 RANLIB = @RANLIB@
 RC = @RC@
 SED = @SED@
@@ -510,6 +523,7 @@
 am__tar = @am__tar@
 am__untar = @am__untar@
 apidocdir = @apidocdir@
+ax_pthread_config = @ax_pthread_config@
 bindir = @bindir@
 build = @build@
 build_alias = @build_alias@
@@ -549,11 +563,15 @@
 sharedstatedir = @sharedstatedir@
 srcdir = @srcdir@
 sysconfdir = @sysconfdir@
+target = @target@
 target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
 top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
-EXTRA_DIST = engines.cnf.in rsa-common.sh ec-common.sh ec-no-pubkey.sh
+EXTRA_DIST = engines.cnf.in rsa-common.sh rsa-no-pubkey.sh ec-common.sh ec-no-pubkey.sh
 AM_CFLAGS = $(OPENSSL_CFLAGS)
 AM_CPPFLAGS = \
 	-I$(top_srcdir) \
@@ -573,9 +591,11 @@
 	rsa-pss-sign.softhsm \
 	rsa-oaep.softhsm \
 	case-insensitive.softhsm \
+	rsa-check-privkey.softhsm \
 	ec-check-privkey.softhsm \
 	pkcs11-uri-without-token.softhsm \
-	search-all-matching-tokens.softhsm
+	search-all-matching-tokens.softhsm \
+	ec-cert-store.softhsm
 
 dist_check_DATA = \
 	rsa-cert.der rsa-prvkey.der rsa-pubkey.der \
@@ -663,6 +683,10 @@
 	@rm -f rsa-pss-sign$(EXEEXT)
 	$(AM_V_CCLD)$(LINK) $(rsa_pss_sign_OBJECTS) $(rsa_pss_sign_LDADD) $(LIBS)
 
+store-cert$(EXEEXT): $(store_cert_OBJECTS) $(store_cert_DEPENDENCIES) $(EXTRA_store_cert_DEPENDENCIES) 
+	@rm -f store-cert$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(store_cert_OBJECTS) $(store_cert_LDADD) $(LIBS)
+
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
 
@@ -677,6 +701,7 @@
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/openssl_version.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/rsa-oaep.Po at am__quote@ # am--include-marker
 @AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/rsa-pss-sign.Po at am__quote@ # am--include-marker
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/store-cert.Po at am__quote@ # am--include-marker
 
 $(am__depfiles_remade):
 	@$(MKDIR_P) $(@D)
@@ -873,7 +898,7 @@
 	  test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG);		\
 	fi;								\
 	echo "$${col}$$br$${std}"; 					\
-	echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}";	\
+	echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}";	\
 	echo "$${col}$$br$${std}"; 					\
 	create_testsuite_report --maybe-color;				\
 	echo "$$col$$br$$std";						\
@@ -977,6 +1002,13 @@
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+rsa-check-privkey.softhsm.log: rsa-check-privkey.softhsm
+	@p='rsa-check-privkey.softhsm'; \
+	b='rsa-check-privkey.softhsm'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 ec-check-privkey.softhsm.log: ec-check-privkey.softhsm
 	@p='ec-check-privkey.softhsm'; \
 	b='ec-check-privkey.softhsm'; \
@@ -998,6 +1030,13 @@
 	--log-file $$b.log --trs-file $$b.trs \
 	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
 	"$$tst" $(AM_TESTS_FD_REDIRECT)
+ec-cert-store.softhsm.log: ec-cert-store.softhsm
+	@p='ec-cert-store.softhsm'; \
+	b='ec-cert-store.softhsm'; \
+	$(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+	--log-file $$b.log --trs-file $$b.trs \
+	$(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+	"$$tst" $(AM_TESTS_FD_REDIRECT)
 .test.log:
 	@p='$<'; \
 	$(am__set_b); \
@@ -1012,7 +1051,6 @@
 @am__EXEEXT_TRUE@	--log-file $$b.log --trs-file $$b.trs \
 @am__EXEEXT_TRUE@	$(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
 @am__EXEEXT_TRUE@	"$$tst" $(AM_TESTS_FD_REDIRECT)
-
 distdir: $(BUILT_SOURCES)
 	$(MAKE) $(AM_MAKEFLAGS) distdir-am
 
@@ -1100,6 +1138,7 @@
 	-rm -f ./$(DEPDIR)/openssl_version.Po
 	-rm -f ./$(DEPDIR)/rsa-oaep.Po
 	-rm -f ./$(DEPDIR)/rsa-pss-sign.Po
+	-rm -f ./$(DEPDIR)/store-cert.Po
 	-rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
 	distclean-tags
@@ -1153,6 +1192,7 @@
 	-rm -f ./$(DEPDIR)/openssl_version.Po
 	-rm -f ./$(DEPDIR)/rsa-oaep.Po
 	-rm -f ./$(DEPDIR)/rsa-pss-sign.Po
+	-rm -f ./$(DEPDIR)/store-cert.Po
 	-rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
diff -Nru libp11-0.4.11/tests/rsa-check-privkey.softhsm libp11-0.4.12/tests/rsa-check-privkey.softhsm
--- libp11-0.4.11/tests/rsa-check-privkey.softhsm	1970-01-01 01:00:00.000000000 +0100
+++ libp11-0.4.12/tests/rsa-check-privkey.softhsm	2021-10-30 14:20:08.000000000 +0200
@@ -0,0 +1,47 @@
+#!/bin/bash
+
+# Copyright (C) 2015 Nikos Mavrogiannopoulos
+# Copyright (C) 2019 Anderson Toshiyuki Sasaki
+# Copyright (C) 2019 Red Hat, Inc.
+# Copyright (C) 2021 Uri Blumenthal, MIT
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+outdir="output.$$"
+
+# Load common test functions
+. ${srcdir}/rsa-no-pubkey.sh
+
+sed -e "s|@MODULE_PATH@|${MODULE}|g" -e "s|@ENGINE_PATH@|../src/.libs/pkcs11.so|g" <"${srcdir}/engines.cnf.in" >"${outdir}/engines.cnf"
+
+export OPENSSL_ENGINES="../src/.libs/"
+PRIVATE_KEY="pkcs11:token=libp11-test;id=%01%02%03%04;object=server-key;type=private;pin-value=1234"
+CERTIFICATE="${outdir}/rsa-cert.pem"
+CERTIFICATE_URL="pkcs11:token=libp11-test;id=%01%02%03%04;object=server-key;type=cert;pin-value=1234"
+
+./check-privkey ${CERTIFICATE} ${PRIVATE_KEY} ${MODULE} "${outdir}/engines.cnf"
+if test $? != 0;then
+	echo "The private key loading couldn't get the public key from the certificate"
+	exit 1;
+fi
+
+./check-privkey ${CERTIFICATE_URL} ${PRIVATE_KEY} ${MODULE} "${outdir}/engines.cnf"
+if test $? != 0;then
+	echo "The private key loading couldn't get the public key from the certificate URL"
+	exit 1;
+fi
+
+rm -rf "$outdir"
+
+exit 0
diff -Nru libp11-0.4.11/tests/rsa-no-pubkey.sh libp11-0.4.12/tests/rsa-no-pubkey.sh
--- libp11-0.4.11/tests/rsa-no-pubkey.sh	1970-01-01 01:00:00.000000000 +0100
+++ libp11-0.4.12/tests/rsa-no-pubkey.sh	2021-10-30 14:20:08.000000000 +0200
@@ -0,0 +1,123 @@
+#!/bin/sh
+
+# Copyright (C) 2013 Nikos Mavrogiannopoulos
+# Copyright (C) 2019 Anderson Toshiyuki Sasaki
+# Copyright (C) 2019 Red Hat, Inc.
+# Copyright (C) 2021 Uri Blumenthal, MIT
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <https://www.gnu.org/licenses/>.
+
+OPENSSL_VERSION=$(./openssl_version | cut -d ' ' -f 2)
+case "${OPENSSL_VERSION}" in
+0.*)
+    echo "EC tests skipped with OpenSSL ${OPENSSL_VERSION}"
+	exit 77
+	;;
+*)
+	;;
+esac
+
+echo "Current directory: $(pwd)"
+echo "Source directory: ${srcdir}"
+echo "Output directory: ${outdir}"
+
+mkdir -p $outdir
+
+for i in /usr/lib64/pkcs11 /usr/lib64/softhsm /usr/lib/x86_64-linux-gnu/softhsm /usr/local/lib/softhsm /opt/local/lib/softhsm /usr/lib/softhsm /usr/lib ;do
+	if test -f "$i/libsofthsm2.so"; then
+		MODULE="$i/libsofthsm2.so"
+		break
+	else
+		if test -f "$i/libsofthsm.so";then
+			MODULE="$i/libsofthsm.so"
+			break
+		fi
+	fi
+done
+
+if (! test -x /usr/bin/pkcs11-tool && ! test -x /usr/local/bin/pkcs11-tool);then
+	exit 77
+fi
+
+init_card () {
+	PIN="$1"
+	PUK="$2"
+
+	if test -x "/usr/bin/softhsm"; then
+		export SOFTHSM_CONF="$outdir/softhsm-testpkcs11.config"
+		SOFTHSM_TOOL="/usr/bin/softhsm"
+	fi
+
+	if test -x "/usr/local/bin/softhsm2-util"; then
+		export SOFTHSM2_CONF="$outdir/softhsm-testpkcs11.config"
+		SOFTHSM_TOOL="/usr/local/bin/softhsm2-util"
+	fi
+
+	if test -x "/opt/local/bin/softhsm2-util"; then
+		export SOFTHSM2_CONF="$outdir/softhsm-testpkcs11.config"
+		SOFTHSM_TOOL="/opt/local/bin/softhsm2-util"
+	fi
+
+	if test -x "/usr/bin/softhsm2-util"; then
+		export SOFTHSM2_CONF="$outdir/softhsm-testpkcs11.config"
+		SOFTHSM_TOOL="/usr/bin/softhsm2-util"
+	fi
+
+	if test -z "${SOFTHSM_TOOL}"; then
+		echo "Could not find softhsm(2) tool"
+		exit 77
+	fi
+
+	if test -n "${SOFTHSM2_CONF}"; then
+		rm -rf $outdir/softhsm-testpkcs11.db
+		mkdir -p $outdir/softhsm-testpkcs11.db
+		echo "objectstore.backend = file" > "${SOFTHSM2_CONF}"
+		echo "directories.tokendir = $outdir/softhsm-testpkcs11.db" >> "${SOFTHSM2_CONF}"
+	else
+		rm -rf $outdir/softhsm-testpkcs11.db
+		echo "0:$outdir/softhsm-testpkcs11.db" > "${SOFTHSM_CONF}"
+	fi
+
+
+	echo -n "* Initializing smart card... "
+	${SOFTHSM_TOOL} --init-token --slot 0 --label "libp11-test" --so-pin "${PUK}" --pin "${PIN}" >/dev/null
+	if test $? = 0; then
+		echo ok
+	else
+		echo failed
+		exit 1
+	fi
+}
+
+PIN=1234
+PUK=1234
+init_card $PIN $PUK
+
+# generate key in token
+pkcs11-tool -p $PIN --module $MODULE -d 01020304 -a server-key -l -w ${srcdir}/rsa-prvkey.der -y privkey >/dev/null
+if test $? != 0;then
+	exit 1;
+fi
+
+pkcs11-tool -p $PIN --module $MODULE -d 01020304 -a server-key -l -w ${srcdir}/rsa-cert.der -y cert >/dev/null
+if test $? != 0;then
+	exit 1;
+fi
+
+openssl x509 -in ${srcdir}/rsa-cert.der -inform DER -out ${outdir}/rsa-cert.pem -outform PEM
+
+echo "***************"
+echo "Listing objects"
+echo "***************"
+pkcs11-tool -p $PIN --module $MODULE -l -O
diff -Nru libp11-0.4.11/tests/rsa-oaep.c libp11-0.4.12/tests/rsa-oaep.c
--- libp11-0.4.11/tests/rsa-oaep.c	2018-08-03 07:57:27.000000000 +0200
+++ libp11-0.4.12/tests/rsa-oaep.c	2021-10-30 14:20:08.000000000 +0200
@@ -230,7 +230,7 @@
 	/* Compare output */
 
 	if (!memcmp(dec, data, data_len)) {
-		printf("Sucessfuly decrypted\n");
+		printf("Successfully decrypted\n");
 	}
 	else {
 		printf("Decrypted data does not match original data\n");
diff -Nru libp11-0.4.11/tests/store-cert.c libp11-0.4.12/tests/store-cert.c
--- libp11-0.4.11/tests/store-cert.c	1970-01-01 01:00:00.000000000 +0100
+++ libp11-0.4.12/tests/store-cert.c	2021-02-08 12:17:15.000000000 +0100
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2019 Anderson Toshiyuki Sasaki
+ * Copyright (C) 2019 Red Hat, Inc.
+ * Copyright (C) 2020 Mateusz Kwiatkowski
+ * Copyright (C) 2020 AVSystem
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program.  If not, see <https://www.gnu.org/licenses/>.
+ */
+
+#include <libp11.h>
+#include <openssl/conf.h>
+#include <openssl/engine.h>
+#include <openssl/pem.h>
+#include <string.h>
+
+static void
+usage(char* argv[])
+{
+	fprintf(stderr,
+		"%s [source certificate file] [target certificate URL]\n",
+		argv[0]);
+}
+
+static void
+display_openssl_errors(int l)
+{
+	const char* file;
+	char buf[120];
+	int e, line;
+
+	if (ERR_peek_error() == 0)
+		return;
+	fprintf(stderr, "At main.c:%d:\n", l);
+
+	while ((e = ERR_get_error_line(&file, &line))) {
+		ERR_error_string(e, buf);
+		fprintf(stderr, "- SSL %s: %s:%d\n", buf, file, line);
+	}
+}
+
+static int
+extract_url_fields(char* address,
+		   char** out_token,
+		   char** out_label,
+		   char** out_pin)
+{
+	static const char DELIMITERS[] = ":;?&=";
+	char *str, *token;
+	if (strncmp(address, "pkcs11:", strlen("pkcs11:")) != 0) {
+		printf("URL does not look valid: %s\n", address);
+		return -1;
+	}
+	str = address + strlen("pkcs11:");
+	while ((token = strtok(str, DELIMITERS))) {
+		char** out = NULL;
+		str = NULL;
+		if (strcmp(token, "token") == 0) {
+			out = out_token;
+		} else if (strcmp(token, "object") == 0) {
+			out = out_label;
+		} else if (strcmp(token, "pin-value") == 0) {
+			out = out_pin;
+		} else {
+			printf("Unrecognized token: %s\n", token);
+			return -1;
+		}
+		if (out) {
+			if (*out) {
+				return -1;
+				printf("Repeated token: %s\n", token);
+			} else if ((token = strtok(str, DELIMITERS))) {
+				*out = token;
+			}
+		}
+	}
+	if (!*out_token || !*out_label || !*out_pin) {
+		printf("URL incomplete\n");
+		return -1;
+	}
+	return 0;
+}
+
+static PKCS11_CTX* global_pkcs11_ctx;
+static PKCS11_SLOT* global_pkcs11_slots;
+static unsigned int global_pkcs11_slot_num;
+
+static int
+store_certificate(char* address, X509* cert)
+{
+	char *token = NULL, *label = NULL, *pin = NULL;
+	if (extract_url_fields(address, &token, &label, &pin)) {
+		return -1;
+	}
+
+	PKCS11_SLOT* slot = PKCS11_find_token(
+	  global_pkcs11_ctx, global_pkcs11_slots, global_pkcs11_slot_num);
+	while (slot) {
+		if (strcmp(token, slot->token->label) == 0) {
+			break;
+		}
+		slot = PKCS11_find_next_token(global_pkcs11_ctx,
+					      global_pkcs11_slots,
+					      global_pkcs11_slot_num,
+					      slot);
+	}
+
+	if (!slot) {
+		printf("Could not find token: %s\n", token);
+		return -1;
+	}
+
+	if (PKCS11_open_session(slot, 1)) {
+		printf("Could not open session\n");
+		return -1;
+	}
+
+	if (PKCS11_login(slot, 0, pin)) {
+		printf("Could not login to slot\n");
+		return -1;
+	}
+
+	if (PKCS11_store_certificate(slot->token,
+				     cert,
+				     label,
+				     (unsigned char*)label,
+				     strlen(label),
+				     NULL)) {
+		printf("Could not store certificate\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+int
+main(int argc, char* argv[])
+{
+	ENGINE* engine = NULL;
+	X509* cert = NULL;
+	FILE* cert_fp = NULL;
+
+	char *certfile, *target, *module, *efile;
+
+	int ret = 0;
+
+	struct
+	{
+		const char* cert_id;
+		X509* cert;
+	} params = { 0 };
+
+	if (argc < 2) {
+		printf("Too few arguments\n");
+		usage(argv);
+		return 1;
+	}
+
+	certfile = argv[1];
+	target = argv[2];
+	module = argv[3];
+	efile = argv[4];
+
+	ret = CONF_modules_load_file(efile, "engines", 0);
+	if (ret <= 0) {
+		fprintf(stderr, "cannot load %s\n", efile);
+		display_openssl_errors(__LINE__);
+		exit(1);
+	}
+
+	ENGINE_add_conf_module();
+#if OPENSSL_VERSION_NUMBER >= 0x10100000
+	OPENSSL_init_crypto(OPENSSL_INIT_ADD_ALL_CIPHERS |
+			      OPENSSL_INIT_ADD_ALL_DIGESTS |
+			      OPENSSL_INIT_LOAD_CONFIG,
+			    NULL);
+#else
+	OpenSSL_add_all_algorithms();
+	OpenSSL_add_all_digests();
+	ERR_load_crypto_strings();
+#endif
+	ERR_clear_error();
+
+	ENGINE_load_builtin_engines();
+
+	engine = ENGINE_by_id("pkcs11");
+	if (engine == NULL) {
+		printf("Could not get engine\n");
+		display_openssl_errors(__LINE__);
+		ret = 1;
+		goto end;
+	}
+
+	if (!ENGINE_ctrl_cmd_string(engine, "VERBOSE", NULL, 0)) {
+		display_openssl_errors(__LINE__);
+		exit(1);
+	}
+
+	if (!ENGINE_ctrl_cmd_string(engine, "MODULE_PATH", module, 0)) {
+		display_openssl_errors(__LINE__);
+		exit(1);
+	}
+
+	if (!ENGINE_init(engine)) {
+		printf("Could not initialize engine\n");
+		display_openssl_errors(__LINE__);
+		ret = 1;
+		goto end;
+	}
+
+	if (!strncmp(certfile, "pkcs11:", 7)) {
+		params.cert_id = certfile;
+		if (!ENGINE_ctrl_cmd(
+		      engine, "LOAD_CERT_CTRL", 0, &params, NULL, 1)) {
+			fprintf(
+			  stderr, "Could not get certificate %s\n", certfile);
+			ret = 1;
+			goto end;
+		}
+		cert = params.cert;
+	} else {
+		cert_fp = fopen(certfile, "rb");
+		if (!cert_fp) {
+			fprintf(stderr, "Could not open file %s\n", certfile);
+			ret = 1;
+			goto end;
+		}
+
+		cert = PEM_read_X509(cert_fp, NULL, NULL, NULL);
+		if (!cert) {
+			fprintf(stderr,
+				"Could not read certificate file"
+				"(must be PEM format)\n");
+		}
+
+		if (cert_fp) {
+			fclose(cert_fp);
+		}
+	}
+
+	if (!(global_pkcs11_ctx = PKCS11_CTX_new())) {
+		printf("Could not initialize libp11 context\n");
+		ret = 1;
+	} else if (PKCS11_CTX_load(global_pkcs11_ctx, module)) {
+		printf("Could not load PKCS11 module\n");
+		ret = 1;
+	} else if (PKCS11_enumerate_slots(global_pkcs11_ctx,
+					  &global_pkcs11_slots,
+					  &global_pkcs11_slot_num)) {
+		printf("Could not enumerate slots\n");
+		ret = 1;
+	} else if (!(ret = store_certificate(target, cert) ? 1 : 0)) {
+		printf("Certificate stored\n");
+		ret = 0;
+	}
+
+	ENGINE_finish(engine);
+
+	CONF_modules_unload(1);
+end:
+	X509_free(cert);
+
+	return ret;
+}


More information about the pkg-opensc-maint mailing list