[pkg-opensc-maint] Bug#1025802: opensc: Import new upstream version

Bastian Germann bage at debian.org
Tue Jan 10 18:37:44 GMT 2023


On Thu, 5 Jan 2023 18:37:13 +0100 Bastian Germann <bage at debian.org> wrote:
> The only change that is required to build 0.23.0 is dropping gcc12.patch which is included upstream.
> If you do not have the time to make this happen, I can do it for you via a NMU.

I have just uploaded a NMU to DELAYED/10 with the attached debdiff.
-------------- next part --------------
diff -Nru opensc-0.22.0/.appveyor.yml opensc-0.23.0/.appveyor.yml
--- opensc-0.22.0/.appveyor.yml	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/.appveyor.yml	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,129 @@
+version: 0.23.0.{build}
+
+platform:
+  - x86
+  - x64
+
+configuration:
+  - Release
+  - Light
+
+environment:
+  GH_TOKEN:
+    secure: aLu3tFc7lRJbotnmnHLx/QruIHc5rLaGm1RttoEdy4QILlPXzVkCZ6loYMz0sfrY
+  PATH: C:\cygwin\bin;%PATH%
+  OPENPACE_VER: 1.1.2
+  ZLIB_VER_DOT: 1.2.12
+  matrix:
+  # not compatible with OpenSSL 1.1.1:
+  # - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
+  #   VCVARSALL: "%VS120COMNTOOLS%/../../VC/vcvarsall.bat"
+  - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
+    VCVARSALL: "%VS140COMNTOOLS%/../../VC/vcvarsall.bat"
+    DO_PUSH_ARTIFACT: yes
+  - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
+    VCVARSALL: "%ProgramFiles(x86)%/Microsoft Visual Studio/2017/Community/VC/Auxiliary/Build/vcvarsall.bat"
+  # not compatible with WiX 3.11.2:
+  # - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
+  #   VCVARSALL: "%ProgramFiles(x86)%/Microsoft Visual Studio/2019/Community/VC/Auxiliary/Build/vcvarsall.bat"
+
+install:
+  - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
+        https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
+        Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
+        throw "There are newer queued builds for this pull request, failing early." }
+  - date /T & time /T
+  - ps: $env:PACKAGE_NAME=(git describe --tags --abbrev=0)
+  - ps: >-
+      If ($env:Platform -Match "x86") {
+        $env:OPENSSL_PF="Win32"
+        $env:ARTIFACT="OpenSC-${env:PACKAGE_NAME}_win32"
+      } Else {
+        $env:OPENSSL_PF="Win64"
+        $env:ARTIFACT="OpenSC-${env:PACKAGE_NAME}_win64"
+      }
+  - ps: >-
+      If ($env:Configuration -Like "*Light*") {
+        $env:ARTIFACT+="-Light"
+      } Else {
+        $env:NMAKE_EXTRA+=" OPENSSL_DEF=/DENABLE_OPENSSL OPENSSL_DIR=C:\OpenSSL-v111-${env:OPENSSL_PF}"
+        $env:NMAKE_EXTRA+=" OPENSSL_EXTRA_CFLAGS=/DOPENSSL_SECURE_MALLOC_SIZE=65536"
+        If (!(Test-Path C:\zlib )) {
+          appveyor DownloadFile "https://github.com/madler/zlib/archive/v${env:ZLIB_VER_DOT}.zip" -FileName zlib.zip
+          7z x zlib.zip -oC:\
+          Rename-Item -path "c:\zlib-${env:ZLIB_VER_DOT}" -newName "zlib"
+        }
+        If (!(Test-Path C:\openpace )) {
+          appveyor DownloadFile "https://github.com/frankmorgner/openpace/archive/${env:OPENPACE_VER}.zip" -FileName openpace.zip
+          7z x openpace.zip -oC:\
+          Rename-Item -path "c:\openpace-${env:OPENPACE_VER}" -newName "openpace"
+        }
+      }
+      If (!(Test-Path cpdksetup.exe )) {
+          appveyor DownloadFile "https://download.microsoft.com/download/1/7/6/176909B0-50F2-4DF3-B29B-830A17EA7E38/CPDK_RELEASE_UPDATE/cpdksetup.exe"
+      }
+  - echo "Using %APPVEYOR_BUILD_WORKER_IMAGE% with %VCVARSALL%"
+  - call "%VCVARSALL%" %Platform%
+  - cpdksetup.exe /quiet
+  - uname -a
+  - set
+
+build_script:
+  - ps: >-
+      if (!($env:Configuration -Like "*Light*")) {
+        If (!(Test-Path -Path "C:\zlib-${env:OPENSSL_PF}" )) {
+          # build zlib.lib as a static library
+          xcopy C:\zlib C:\zlib-${env:OPENSSL_PF} /e /i /y /s
+          cd C:\zlib-${env:OPENSSL_PF}
+          (Get-Content win32/Makefile.msc).replace('-MD', '-MT') | Set-Content win32/Makefile.msc
+          nmake /nologo -f win32/Makefile.msc zlib.lib
+        }
+        $env:NMAKE_EXTRA+=" ZLIBSTATIC_DEF=/DENABLE_ZLIB_STATIC ZLIB_INCL_DIR=/IC:\zlib-${env:OPENSSL_PF} ZLIB_LIB=C:\zlib-${env:OPENSSL_PF}\zlib.lib"
+        If (!(Test-Path -Path "C:\openpace-${env:OPENSSL_PF}" )) {
+          # build libeac.lib as a static library
+          xcopy C:\openpace C:\openpace-${env:OPENSSL_PF} /e /i /y /s
+          cd C:\openpace-${env:OPENSSL_PF}\src
+          # OpenSSL 1.1.0
+          #cl /nologo /IC:\OpenSSL-v110-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /DHAVE_ASN1_STRING_GET0_DATA=1 /DHAVE_DECL_OPENSSL_ZALLOC=1 /DHAVE_DH_GET0_KEY=1 /DHAVE_DH_GET0_PQG=1 /DHAVE_DH_SET0_KEY=1 /DHAVE_DH_SET0_PQG=1 /DHAVE_ECDSA_SIG_GET0=1 /DHAVE_ECDSA_SIG_SET0=1 /DHAVE_EC_KEY_METHOD=1 /DHAVE_RSA_GET0_KEY=1 /DHAVE_RSA_SET0_KEY=1 /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c ssl_compat.c
+          # OpenSSL 1.1.1
+          cl /nologo /IC:\OpenSSL-v111-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /DHAVE_ASN1_STRING_GET0_DATA=1 /DHAVE_DECL_OPENSSL_ZALLOC=1 /DHAVE_DH_GET0_KEY=1 /DHAVE_DH_GET0_PQG=1 /DHAVE_DH_SET0_KEY=1 /DHAVE_DH_SET0_PQG=1 /DHAVE_ECDSA_SIG_GET0=1 /DHAVE_ECDSA_SIG_SET0=1 /DHAVE_EC_KEY_METHOD=1 /DHAVE_RSA_GET0_KEY=1 /DHAVE_RSA_SET0_KEY=1 /DHAVE_EC_POINT_GET_AFFINE_COORDINATES=1 /DHAVE_EC_POINT_SET_AFFINE_COORDINATES=1 /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c ssl_compat.c
+          # OpenSSL 1.0.2
+          #cl /nologo /IC:\OpenSSL-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c ssl_compat.c
+          lib /nologo /out:libeac.lib ca_lib.obj cv_cert.obj cvc_lookup.obj x509_lookup.obj eac_asn1.obj eac.obj eac_ca.obj eac_dh.obj eac_ecdh.obj eac_kdf.obj eac_lib.obj eac_print.obj eac_util.obj misc.obj pace.obj pace_lib.obj pace_mappings.obj ri.obj ri_lib.obj ta.obj ta_lib.obj objects.obj ssl_compat.obj
+          cd C:\projects\OpenSC
+        }
+        $env:NMAKE_EXTRA+=" OPENPACE_DEF=/DENABLE_OPENPACE OPENPACE_DIR=C:\openpace-${env:OPENSSL_PF}"
+      }
+  - bash -c "exec 0</dev/null && if [ \"$APPVEYOR_REPO_BRANCH\" == \"master\" -a -z \"$APPVEYOR_PULL_REQUEST_NUMBER\" ]; then ./bootstrap; fi"
+  - bash -c "exec 0</dev/null && if [ \"$APPVEYOR_REPO_BRANCH\" == \"master\" -a -n \"$APPVEYOR_PULL_REQUEST_NUMBER\" ]; then ./bootstrap.ci -s \"-pr$APPVEYOR_PULL_REQUEST_NUMBER\"; fi"
+  - bash -c "exec 0</dev/null && if [ \"$APPVEYOR_REPO_BRANCH\" != \"master\" -a -z \"$APPVEYOR_PULL_REQUEST_NUMBER\" ]; then ./bootstrap.ci -s \"-$APPVEYOR_REPO_BRANCH\"; fi"
+  - bash -c "exec 0</dev/null && if [ \"$APPVEYOR_REPO_BRANCH\" != \"master\" -a -n \"$APPVEYOR_PULL_REQUEST_NUMBER\" ]; then ./bootstrap.ci -s \"-$APPVEYOR_REPO_BRANCH-prAPPVEYOR_PULL_REQUEST_NUMBER\"; fi"
+  # disable features to speed up the script
+  - bash -c "exec 0</dev/null && ./configure --with-cygwin-native --disable-openssl --disable-readline --disable-zlib || cat config.log"
+  - bash -c "exec 0</dev/null && rm src/getopt.h"
+  - nmake /f Makefile.mak %NMAKE_EXTRA%
+  - cd win32 && nmake /nologo /f Makefile.mak %NMAKE_EXTRA% OpenSC.msi && cd ..
+  - move win32\OpenSC.msi %ARTIFACT%.msi
+  # put all pdb files for dump analysis, but this consumes approx 100 MB per build
+  - md %ARTIFACT%-Debug
+  - ps: >-
+      Get-ChildItem -recurse C:\projects\OpenSC -exclude vc*.pdb *.pdb | % {
+        7z a -tzip ${env:ARTIFACT}-Debug.zip $_.FullName
+      }
+  - appveyor PushArtifact %ARTIFACT%.msi
+  - appveyor PushArtifact %ARTIFACT%-Debug.zip
+
+deploy_script:
+  # keep in sync with .travis.yml
+  - bash -c "git config --global user.email 'no-reply at appveyor.com'"
+  - bash -c "git config --global user.name 'AppVeyor'"
+  - bash -c "if [ \"$DO_PUSH_ARTIFACT\" = yes -a -z \"$APPVEYOR_PULL_REQUEST_NUMBER\" -a \"$APPVEYOR_REPO_NAME\" = \"OpenSC/OpenSC\" ]; then .github/push_artifacts.sh \"AppVeyor build ${APPVEYOR_BUILD_NUMBER}.${APPVEYOR_JOB_NUMBER}\"; fi"
+
+cache:
+  - C:\zlib -> .appveyor.yml
+  - C:\zlib-Win32 -> .appveyor.yml
+  - C:\zlib-Win64 -> .appveyor.yml
+  - C:\openpace -> .appveyor.yml
+  - C:\openpace-Win32 -> .appveyor.yml
+  - C:\openpace-Win64 -> .appveyor.yml
+  - cpdksetup.exe -> .appveyor.yml
diff -Nru opensc-0.22.0/appveyor.yml opensc-0.23.0/appveyor.yml
--- opensc-0.22.0/appveyor.yml	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/appveyor.yml	1970-01-01 01:00:00.000000000 +0100
@@ -1,129 +0,0 @@
-version: 0.22.0.{build}
-
-platform:
-  - x86
-  - x64
-
-configuration:
-  - Release
-  - Light
-
-environment:
-  GH_TOKEN:
-    secure: aLu3tFc7lRJbotnmnHLx/QruIHc5rLaGm1RttoEdy4QILlPXzVkCZ6loYMz0sfrY
-  PATH: C:\cygwin\bin;%PATH%
-  OPENPACE_VER: 1.1.1
-  ZLIB_VER_DOT: 1.2.11
-  matrix:
-  # not compatible with OpenSSL 1.1.1:
-  # - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2013
-  #   VCVARSALL: "%VS120COMNTOOLS%/../../VC/vcvarsall.bat"
-  - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2015
-    VCVARSALL: "%VS140COMNTOOLS%/../../VC/vcvarsall.bat"
-    DO_PUSH_ARTIFACT: yes
-  - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
-    VCVARSALL: "%ProgramFiles(x86)%/Microsoft Visual Studio/2017/Community/VC/Auxiliary/Build/vcvarsall.bat"
-  # not compatible with WiX 3.11.2:
-  # - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
-  #   VCVARSALL: "%ProgramFiles(x86)%/Microsoft Visual Studio/2019/Community/VC/Auxiliary/Build/vcvarsall.bat"
-
-install:
-  - ps: if ($env:APPVEYOR_PULL_REQUEST_NUMBER -and $env:APPVEYOR_BUILD_NUMBER -ne ((Invoke-RestMethod `
-        https://ci.appveyor.com/api/projects/$env:APPVEYOR_ACCOUNT_NAME/$env:APPVEYOR_PROJECT_SLUG/history?recordsNumber=50).builds | `
-        Where-Object pullRequestId -eq $env:APPVEYOR_PULL_REQUEST_NUMBER)[0].buildNumber) { `
-        throw "There are newer queued builds for this pull request, failing early." }
-  - date /T & time /T
-  - ps: $env:PACKAGE_NAME=(git describe --tags --abbrev=0)
-  - ps: >-
-      If ($env:Platform -Match "x86") {
-        $env:OPENSSL_PF="Win32"
-        $env:ARTIFACT="OpenSC-${env:PACKAGE_NAME}_win32"
-      } Else {
-        $env:OPENSSL_PF="Win64"
-        $env:ARTIFACT="OpenSC-${env:PACKAGE_NAME}_win64"
-      }
-  - ps: >-
-      If ($env:Configuration -Like "*Light*") {
-        $env:ARTIFACT+="-Light"
-      } Else {
-        $env:NMAKE_EXTRA+=" OPENSSL_DEF=/DENABLE_OPENSSL OPENSSL_DIR=C:\OpenSSL-v111-${env:OPENSSL_PF}"
-        $env:NMAKE_EXTRA+=" OPENSSL_EXTRA_CFLAGS=/DOPENSSL_SECURE_MALLOC_SIZE=65536"
-        If (!(Test-Path C:\zlib )) {
-          appveyor DownloadFile "https://github.com/madler/zlib/archive/v${env:ZLIB_VER_DOT}.zip" -FileName zlib.zip
-          7z x zlib.zip -oC:\
-          Rename-Item -path "c:\zlib-${env:ZLIB_VER_DOT}" -newName "zlib"
-        }
-        If (!(Test-Path C:\openpace )) {
-          appveyor DownloadFile "https://github.com/frankmorgner/openpace/archive/${env:OPENPACE_VER}.zip" -FileName openpace.zip
-          7z x openpace.zip -oC:\
-          Rename-Item -path "c:\openpace-${env:OPENPACE_VER}" -newName "openpace"
-        }
-      }
-      If (!(Test-Path cpdksetup.exe )) {
-          appveyor DownloadFile "https://download.microsoft.com/download/1/7/6/176909B0-50F2-4DF3-B29B-830A17EA7E38/CPDK_RELEASE_UPDATE/cpdksetup.exe"
-      }
-  - echo "Using %APPVEYOR_BUILD_WORKER_IMAGE% with %VCVARSALL%"
-  - call "%VCVARSALL%" %Platform%
-  - cpdksetup.exe /quiet
-  - uname -a
-  - set
-
-build_script:
-  - ps: >-
-      if (!($env:Configuration -Like "*Light*")) {
-        If (!(Test-Path -Path "C:\zlib-${env:OPENSSL_PF}" )) {
-          # build zlib.lib as a static library
-          xcopy C:\zlib C:\zlib-${env:OPENSSL_PF} /e /i /y /s
-          cd C:\zlib-${env:OPENSSL_PF}
-          (Get-Content win32/Makefile.msc).replace('-MD', '-MT') | Set-Content win32/Makefile.msc
-          nmake /nologo -f win32/Makefile.msc zlib.lib
-        }
-        $env:NMAKE_EXTRA+=" ZLIBSTATIC_DEF=/DENABLE_ZLIB_STATIC ZLIB_INCL_DIR=/IC:\zlib-${env:OPENSSL_PF} ZLIB_LIB=C:\zlib-${env:OPENSSL_PF}\zlib.lib"
-        If (!(Test-Path -Path "C:\openpace-${env:OPENSSL_PF}" )) {
-          # build libeac.lib as a static library
-          xcopy C:\openpace C:\openpace-${env:OPENSSL_PF} /e /i /y /s
-          cd C:\openpace-${env:OPENSSL_PF}\src
-          # OpenSSL 1.1.0
-          #cl /nologo /IC:\OpenSSL-v110-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /DHAVE_ASN1_STRING_GET0_DATA=1 /DHAVE_DECL_OPENSSL_ZALLOC=1 /DHAVE_DH_GET0_KEY=1 /DHAVE_DH_GET0_PQG=1 /DHAVE_DH_SET0_KEY=1 /DHAVE_DH_SET0_PQG=1 /DHAVE_ECDSA_SIG_GET0=1 /DHAVE_ECDSA_SIG_SET0=1 /DHAVE_EC_KEY_METHOD=1 /DHAVE_RSA_GET0_KEY=1 /DHAVE_RSA_SET0_KEY=1 /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c ssl_compat.c
-          # OpenSSL 1.1.1
-          cl /nologo /IC:\OpenSSL-v111-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /DHAVE_ASN1_STRING_GET0_DATA=1 /DHAVE_DECL_OPENSSL_ZALLOC=1 /DHAVE_DH_GET0_KEY=1 /DHAVE_DH_GET0_PQG=1 /DHAVE_DH_SET0_KEY=1 /DHAVE_DH_SET0_PQG=1 /DHAVE_ECDSA_SIG_GET0=1 /DHAVE_ECDSA_SIG_SET0=1 /DHAVE_EC_KEY_METHOD=1 /DHAVE_RSA_GET0_KEY=1 /DHAVE_RSA_SET0_KEY=1 /DHAVE_EC_POINT_GET_AFFINE_COORDINATES=1 /DHAVE_EC_POINT_SET_AFFINE_COORDINATES=1 /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c ssl_compat.c
-          # OpenSSL 1.0.2
-          #cl /nologo /IC:\OpenSSL-${env:OPENSSL_PF}\include /I. /DX509DIR=\`"/\`" /DCVCDIR=\`"/\`" /W3 /D_CRT_SECURE_NO_DEPRECATE /DWIN32_LEAN_AND_MEAN /GS /MT /c ca_lib.c cv_cert.c cvc_lookup.c x509_lookup.c eac_asn1.c eac.c eac_ca.c eac_dh.c eac_ecdh.c eac_kdf.c eac_lib.c eac_print.c eac_util.c misc.c pace.c pace_lib.c pace_mappings.c ri.c ri_lib.c ta.c ta_lib.c objects.c ssl_compat.c
-          lib /nologo /out:libeac.lib ca_lib.obj cv_cert.obj cvc_lookup.obj x509_lookup.obj eac_asn1.obj eac.obj eac_ca.obj eac_dh.obj eac_ecdh.obj eac_kdf.obj eac_lib.obj eac_print.obj eac_util.obj misc.obj pace.obj pace_lib.obj pace_mappings.obj ri.obj ri_lib.obj ta.obj ta_lib.obj objects.obj ssl_compat.obj
-          cd C:\projects\OpenSC
-        }
-        $env:NMAKE_EXTRA+=" OPENPACE_DEF=/DENABLE_OPENPACE OPENPACE_DIR=C:\openpace-${env:OPENSSL_PF}"
-      }
-  - bash -c "exec 0</dev/null && if [ \"$APPVEYOR_REPO_BRANCH\" == \"master\" -a -z \"$APPVEYOR_PULL_REQUEST_NUMBER\" ]; then ./bootstrap; fi"
-  - bash -c "exec 0</dev/null && if [ \"$APPVEYOR_REPO_BRANCH\" == \"master\" -a -n \"$APPVEYOR_PULL_REQUEST_NUMBER\" ]; then ./bootstrap.ci -s \"-pr$APPVEYOR_PULL_REQUEST_NUMBER\"; fi"
-  - bash -c "exec 0</dev/null && if [ \"$APPVEYOR_REPO_BRANCH\" != \"master\" -a -z \"$APPVEYOR_PULL_REQUEST_NUMBER\" ]; then ./bootstrap.ci -s \"-$APPVEYOR_REPO_BRANCH\"; fi"
-  - bash -c "exec 0</dev/null && if [ \"$APPVEYOR_REPO_BRANCH\" != \"master\" -a -n \"$APPVEYOR_PULL_REQUEST_NUMBER\" ]; then ./bootstrap.ci -s \"-$APPVEYOR_REPO_BRANCH-prAPPVEYOR_PULL_REQUEST_NUMBER\"; fi"
-  # disable features to speed up the script
-  - bash -c "exec 0</dev/null && ./configure --with-cygwin-native --disable-openssl --disable-readline --disable-zlib || cat config.log"
-  - bash -c "exec 0</dev/null && rm src/getopt.h"
-  - nmake /f Makefile.mak %NMAKE_EXTRA%
-  - cd win32 && nmake /nologo /f Makefile.mak %NMAKE_EXTRA% OpenSC.msi && cd ..
-  - move win32\OpenSC.msi %ARTIFACT%.msi
-  # put all pdb files for dump analysis, but this consumes approx 100 MB per build
-  - md %ARTIFACT%-Debug
-  - ps: >-
-      Get-ChildItem -recurse C:\projects\OpenSC -exclude vc*.pdb *.pdb | % {
-        7z a -tzip ${env:ARTIFACT}-Debug.zip $_.FullName
-      }
-  - appveyor PushArtifact %ARTIFACT%.msi
-  - appveyor PushArtifact %ARTIFACT%-Debug.zip
-
-deploy_script:
-  # keep in sync with .travis.yml
-  - bash -c "git config --global user.email 'no-reply at appveyor.com'"
-  - bash -c "git config --global user.name 'AppVeyor'"
-  - bash -c "if [ \"$DO_PUSH_ARTIFACT\" = yes -a -z \"$APPVEYOR_PULL_REQUEST_NUMBER\" -a \"$APPVEYOR_REPO_NAME\" = \"OpenSC/OpenSC\" ]; then .github/push_artifacts.sh \"AppVeyor build ${APPVEYOR_BUILD_NUMBER}.${APPVEYOR_JOB_NUMBER}\"; fi"
-
-cache:
-  - C:\zlib -> appveyor.yml
-  - C:\zlib-Win32 -> appveyor.yml
-  - C:\zlib-Win64 -> appveyor.yml
-  - C:\openpace -> appveyor.yml
-  - C:\openpace-Win32 -> appveyor.yml
-  - C:\openpace-Win64 -> appveyor.yml
-  - cpdksetup.exe -> appveyor.yml
diff -Nru opensc-0.22.0/bootstrap.ci opensc-0.23.0/bootstrap.ci
--- opensc-0.22.0/bootstrap.ci	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/bootstrap.ci	2022-11-29 09:34:43.000000000 +0100
@@ -41,12 +41,12 @@
   make distclean
 fi
 
-rm -rf *~ *.cache config.guess config.log config.status config.sub depcomp ltmain.sh version.m4.ci
+rm -rf *~ *.cache config.guess config.log config.status config.sub depcomp ltmain.sh m4/version.m4.ci
 
 if [ -n "$SUFFIX" ]
 then
     echo Set package suffix "$SUFFIX"
-    sed 's/^define(\[PACKAGE_SUFFIX\],\s*\[\([-~]*[0-9a-zA-Z]*\)\])$/define(\[PACKAGE_SUFFIX\], \['$SUFFIX'\])/g' < version.m4 > version.m4.ci
+    sed 's/^define(\[PACKAGE_SUFFIX\],\s*\[\([-~]*[0-9a-zA-Z]*\)\])$/define(\[PACKAGE_SUFFIX\], \['$SUFFIX'\])/g' < m4/version.m4 > m4/version.m4.ci
 fi
 
 ./bootstrap
diff -Nru opensc-0.22.0/configure.ac opensc-0.23.0/configure.ac
--- opensc-0.22.0/configure.ac	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/configure.ac	2022-11-29 09:34:43.000000000 +0100
@@ -7,7 +7,7 @@
 define([PRODUCT_BUGREPORT], [https://github.com/OpenSC/OpenSC/issues])
 define([PRODUCT_URL], [https://github.com/OpenSC/OpenSC])
 define([PACKAGE_VERSION_MAJOR], [0])
-define([PACKAGE_VERSION_MINOR], [22])
+define([PACKAGE_VERSION_MINOR], [23])
 define([PACKAGE_VERSION_FIX], [0])
 define([PACKAGE_SUFFIX], [])
 
@@ -19,9 +19,9 @@
 define([VS_FF_PRODUCT_UPDATES], [https://github.com/OpenSC/OpenSC/releases])
 define([VS_FF_PRODUCT_URL], [https://github.com/OpenSC/OpenSC])
 
-m4_sinclude(version.m4.ci)
+m4_sinclude(m4/version.m4.ci)
 
-m4_define([openssl_minimum_version], [1.0.1])
+m4_define([openssl_minimum_version], [1.1.1])
 
 AC_INIT([PRODUCT_NAME],[PACKAGE_VERSION_MAJOR.PACKAGE_VERSION_MINOR.PACKAGE_VERSION_FIX[]PACKAGE_SUFFIX],[PRODUCT_BUGREPORT],[PRODUCT_TARNAME],[PRODUCT_URL])
 AC_CONFIG_AUX_DIR([.])
@@ -45,7 +45,7 @@
 #   (Code changed:                      REVISION++)
 #   (Oldest interface changed/removed:  OLDEST++)
 #   (Interfaces added:                  CURRENT++, REVISION=0)
-OPENSC_LT_CURRENT="8"
+OPENSC_LT_CURRENT="9"
 OPENSC_LT_OLDEST="8"
 OPENSC_LT_REVISION="0"
 OPENSC_LT_AGE="0"
@@ -131,6 +131,19 @@
 	;;
 esac
 
+dnl with Firefox's osclientcerts.so we skip registering our PKCS#11 module on Windows and macOS by default
+case "${host}" in
+	*-*-darwin*)
+		PKCS11_REGISTER_SKIP_FIREFOX="on"
+	;;
+	*-mingw*|*-winnt*|*-cygwin*)
+		PKCS11_REGISTER_SKIP_FIREFOX="on"
+	;;
+	*)
+		PKCS11_REGISTER_SKIP_FIREFOX="off"
+	;;
+esac
+
 AX_CODE_COVERAGE()
 
 AX_CHECK_COMPILE_FLAG([-Wunknown-warning-option], [have_unknown_warning_option="yes"], [have_unknown_warning_option="no"])
@@ -138,7 +151,7 @@
 
 AC_ARG_ENABLE(
 	[fuzzing],
-	[AS_HELP_STRING([--enable-fuzzing],[enable compile of fuzzing tests @<:@disabled@:>@, note that CFLAGS and FUZZING_LIBS should be set accordingly, e.g. to something like CFLAGS="-fsanitize=address,fuzzer" FUZZING_LIBS="-fsanitize=fuzzer"])],
+	[AS_HELP_STRING([--enable-fuzzing],[enable compile of fuzzing tests @<:@disabled@:>@, note that CC, CFLAGS and FUZZING_LIBS should be set accordingly, e.g. to something like CC="clang" CFLAGS="-fsanitize=fuzzer-no-link" FUZZING_LIBS="-fsanitize=fuzzer"])],
 	,
 	[enable_fuzzing="no"]
 )
@@ -453,9 +466,20 @@
 
 if test "${WIN32}" = "no"; then
 	dnl dl support
-	AC_SEARCH_LIBS([dlopen], [dl dld], [], [
-		AC_MSG_ERROR([unable to find the dlopen() function])
-	])
+	AC_ARG_VAR([LDL_LIBS], [linker flags for ldl])
+	if test -z "${LDL_LIBS}"; then
+		AC_CHECK_LIB(
+			[dl],
+			[dlopen],
+			[LDL_LIBS="-ldl"],
+			AC_CHECK_LIB(
+				[dld],
+				[dlopen],
+				[LDL_LIBS="-ldld"],
+				AC_MSG_ERROR([unable to find the dlopen() function])
+			)
+		)
+	fi
 
 	dnl Special check for pthread support.
 	AX_PTHREAD(
@@ -506,7 +530,7 @@
 fi
 
 case "${host}" in
-	*-*-darwin*)
+	*-*-darwin*|*-mingw*|*-winnt*|*-cygwin*)
 			have_notify="yes"
 		;;
 	*)
@@ -530,6 +554,10 @@
 							   have_notify="no"
 							   have_gio2="no"  ])
 			LIBS="$saved_LIBS"
+			if test "${have_gio2}" = "yes"; then
+				# we do not need lglib-2.0
+				GIO2_LIBS="-lgio-2.0 -lgobject-2.0"
+			fi
 		;;
 esac
 
@@ -703,6 +731,9 @@
 	fi
 fi
 
+if test "${enable_fuzzing}" = "yes"; then
+	AC_DEFINE([FUZZING_ENABLED], [1], [Define if fuzzing is enabled])
+fi
 
 
 PKG_CHECK_EXISTS([libeac], [PKG_CHECK_MODULES([OPENPACE], [libeac >= 0.9])],
@@ -721,6 +752,7 @@
 AC_TRY_LINK_FUNC(EAC_CTX_init_pace, [ AC_MSG_RESULT([yes]) ],
                  [ AC_MSG_WARN([Cannot link against libeac])
                  have_openpace="no" ])
+AC_CHECK_FUNCS([EAC_OBJ_nid2obj])
 
 CPPFLAGS="$saved_CPPFLAGS"
 LIBS="$saved_LIBS"
@@ -1067,6 +1099,7 @@
 AM_CONDITIONAL([ENABLE_READLINE], [test "${enable_readline}" = "yes"])
 AM_CONDITIONAL([ENABLE_OPENSSL], [test "${enable_openssl}" = "yes"])
 AM_CONDITIONAL([ENABLE_OPENPACE], [test "${enable_openpace}" = "yes"])
+AM_CONDITIONAL([ENABLE_NOTIFY], [test "${enable_notify}" = "yes"])
 AM_CONDITIONAL([ENABLE_CRYPTOTOKENKIT], [test "${enable_cryptotokenkit}" = "yes"])
 AM_CONDITIONAL([ENABLE_OPENCT], [test "${enable_openct}" = "yes"])
 AM_CONDITIONAL([ENABLE_DOC], [test "${enable_doc}" = "yes"])
@@ -1083,6 +1116,8 @@
 AM_CONDITIONAL([ENABLE_FUZZING], [test "${enable_fuzzing}" = "yes"])
 AM_CONDITIONAL([ENABLE_SHARED], [test "${enable_shared}" = "yes"])
 AS_IF([test "${enable_shared}" = "yes"], [AC_DEFINE([ENABLE_SHARED], [1], [Enable shared libraries])])
+AM_CONDITIONAL([ENABLE_STATIC], [test "${enable_static}" = "yes"])
+AS_IF([test "${enable_static}" = "yes"], [AC_DEFINE([ENABLE_static], [1], [Enable static libraries])])
 
 if test "${enable_pedantic}" = "yes"; then
 	enable_strict="yes";
@@ -1131,6 +1166,7 @@
 	MacOSX/Makefile
 	MacOSX/build-package
 	MacOSX/Distribution.xml
+	MacOSX/Distribution_universal.xml
 	MacOSX/resources/Welcome.html
 ])
 
@@ -1189,6 +1225,7 @@
 Linker flags:            ${LDFLAGS}
 Libraries:               ${LIBS}
 
+LDL_LIBS:                ${LDL_LIBS}
 READLINE_CFLAGS:         ${READLINE_CFLAGS}
 READLINE_LIBS:           ${READLINE_LIBS}
 ZLIB_CFLAGS:             ${ZLIB_CFLAGS}
diff -Nru opensc-0.22.0/containers/opensc-build/Containerfile opensc-0.23.0/containers/opensc-build/Containerfile
--- opensc-0.22.0/containers/opensc-build/Containerfile	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/containers/opensc-build/Containerfile	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,12 @@
+FROM ubuntu:latest
+RUN apt update
+# Install sudo to mimic Github Actions runnner
+# Install tzdata to avoid messing up with interactive prompts later
+RUN export DEBIAN_FRONTEND=noninteractive; \
+    export DEBCONF_NONINTERACTIVE_SEEN=true; \
+    echo 'tzdata tzdata/Areas select Etc' | debconf-set-selections; \
+    echo 'tzdata tzdata/Zones/Etc select UTC' | debconf-set-selections; \
+    apt-get install -y --no-install-recommends tzdata sudo
+WORKDIR /src
+RUN /src/.github/setup-linux.sh
+CMD /src/.github/build.sh dist
diff -Nru opensc-0.22.0/containers/opensc-build-ix86/Containerfile opensc-0.23.0/containers/opensc-build-ix86/Containerfile
--- opensc-0.22.0/containers/opensc-build-ix86/Containerfile	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/containers/opensc-build-ix86/Containerfile	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,12 @@
+FROM ubuntu:latest
+RUN apt update
+# Install sudo to mimic Github Actions runnner
+# Install tzdata to avoid messing up with interactive prompts later
+RUN export DEBIAN_FRONTEND=noninteractive; \
+    export DEBCONF_NONINTERACTIVE_SEEN=true; \
+    echo 'tzdata tzdata/Areas select Etc' | debconf-set-selections; \
+    echo 'tzdata tzdata/Zones/Etc select UTC' | debconf-set-selections; \
+    apt-get install -y --no-install-recommends tzdata sudo
+WORKDIR /src
+RUN /src/.github/setup-linux.sh ix86
+CMD /src/.github/build.sh ix86
diff -Nru opensc-0.22.0/containers/opensc-mingw/Containerfile opensc-0.23.0/containers/opensc-mingw/Containerfile
--- opensc-0.22.0/containers/opensc-mingw/Containerfile	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/containers/opensc-mingw/Containerfile	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,12 @@
+FROM ubuntu:latest
+RUN apt update
+# Install sudo to mimic Github Actions runnner
+# Install tzdata to avoid messing up with interactive prompts later
+RUN export DEBIAN_FRONTEND=noninteractive; \
+    export DEBCONF_NONINTERACTIVE_SEEN=true; \
+    echo 'tzdata tzdata/Areas select Etc' | debconf-set-selections; \
+    echo 'tzdata tzdata/Zones/Etc select UTC' | debconf-set-selections; \
+    apt-get install -y --no-install-recommends tzdata sudo
+WORKDIR /src
+RUN /src/.github/setup-linux.sh mingw
+CMD /src/.github/build.sh mingw
diff -Nru opensc-0.22.0/containers/opensc-test-cac/Containerfile opensc-0.23.0/containers/opensc-test-cac/Containerfile
--- opensc-0.22.0/containers/opensc-test-cac/Containerfile	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/containers/opensc-test-cac/Containerfile	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,13 @@
+FROM ubuntu:latest
+RUN apt update
+# Install sudo to mimic Github Actions runnner
+# Install tzdata to avoid messing up with interactive prompts later
+RUN export DEBIAN_FRONTEND=noninteractive; \
+    export DEBCONF_NONINTERACTIVE_SEEN=true; \
+    echo 'tzdata tzdata/Areas select Etc' | debconf-set-selections; \
+    echo 'tzdata tzdata/Zones/Etc select UTC' | debconf-set-selections; \
+    apt-get install -y --no-install-recommends tzdata sudo
+WORKDIR /src
+RUN /src/.github/setup-linux.sh cac
+RUN /src/.github/build.sh
+CMD /src/.github/test-cac.sh
diff -Nru opensc-0.22.0/containers/opensc-test-oseid/Containerfile opensc-0.23.0/containers/opensc-test-oseid/Containerfile
--- opensc-0.22.0/containers/opensc-test-oseid/Containerfile	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/containers/opensc-test-oseid/Containerfile	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,13 @@
+FROM ubuntu:latest
+RUN apt update
+# Install sudo to mimic Github Actions runnner
+# Install tzdata to avoid messing up with interactive prompts later
+RUN export DEBIAN_FRONTEND=noninteractive; \
+    export DEBCONF_NONINTERACTIVE_SEEN=true; \
+    echo 'tzdata tzdata/Areas select Etc' | debconf-set-selections; \
+    echo 'tzdata tzdata/Zones/Etc select UTC' | debconf-set-selections; \
+    apt-get install -y --no-install-recommends tzdata sudo
+WORKDIR /src
+RUN /src/.github/setup-linux.sh oseid
+RUN /src/.github/build.sh
+CMD /src/.github/test-oseid.sh
diff -Nru opensc-0.22.0/containers/opensc-test-piv/Containerfile opensc-0.23.0/containers/opensc-test-piv/Containerfile
--- opensc-0.22.0/containers/opensc-test-piv/Containerfile	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/containers/opensc-test-piv/Containerfile	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,13 @@
+FROM ubuntu:18.04
+RUN apt update
+# Install sudo to mimic Github Actions runnner
+# Install tzdata to avoid messing up with interactive prompts later
+RUN export DEBIAN_FRONTEND=noninteractive; \
+    export DEBCONF_NONINTERACTIVE_SEEN=true; \
+    echo 'tzdata tzdata/Areas select Etc' | debconf-set-selections; \
+    echo 'tzdata tzdata/Zones/Etc select UTC' | debconf-set-selections; \
+    apt-get install -y --no-install-recommends tzdata sudo
+WORKDIR /src
+RUN /src/.github/setup-linux.sh piv
+RUN /src/.github/build.sh
+CMD /src/.github/test-piv.sh
diff -Nru opensc-0.22.0/containers/README.md opensc-0.23.0/containers/README.md
--- opensc-0.22.0/containers/README.md	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/containers/README.md	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,63 @@
+# Testing locally using containers
+
+You can run the tests executed in github actions in containers locally. This can
+be handy to test some modification of the code or the CI pipeline.
+
+First, we need to prepare the container image. This already runs setup and
+mounts current working directory to the container:
+
+```
+$ podman build -v $PWD:/src:z -t opensc-build containers/opensc-build
+```
+
+Now, you can jump into the container with preinstalled dependencies to build
+OpenSC:
+
+```
+$ podman run -v $PWD:/src:z -ti opensc-build
+```
+If you want to run the build manually, investigate some issues, you can start
+with shell
+```
+$ podman run -v $PWD:/src:z -ti opensc-build /bin/bash
+# .github/build.sh
+```
+To debug some issues with gdb, the container needs some more capabilities.
+With the following configuration, I am able to run gdb to debug possible
+issues:
+```
+$ podman run --cap-add=SYS_PTRACE --security-opt seccomp=unconfined -v $PWD:/src:z -ti opensc-build /bin/bash
+# .github/build.sh
+# apt install -y libtool-bin gdb
+# libtool --mode=execute gdb --args ./src/tools/pkcs11-tool --test-threads IN -L --module=/usr/lib/softhsm/libsofthsm2.so
+```
+
+Similarly for tests, you can build a container for example for CAC testing:
+```
+$ podman build -v $PWD:/src:z -t opensc-cac containers/opensc-test-cac
+```
+and then run the tests:
+```
+$ podman run -v $PWD:/src:z -ti opensc-cac
+```
+
+The javacard tests are very similar. This can be used to build a container for
+PIV testing:
+```
+$ podman build -v $PWD:/src:z -t opensc-piv containers/opensc-test-piv
+```
+and then run the tests:
+```
+$ podman run -v $PWD:/src:z -ti opensc-piv
+```
+
+## Footnotes and explanations
+
+If you are using Docker, you will need to replace "podman" with "docker" and
+maybe change the generic Containerfile name to Dockerfile, but otherwise it
+should work the same way.
+
+The `:z` option to the volume argument is needed on SELinux-enabled systems to
+allow podman accessing your files. On the first invocation, podman will relabel
+the directory to be accessible from the container. On any follow-up invocations
+it will make sure the new files have expected labels.
diff -Nru opensc-0.22.0/CONTRIBUTING.md opensc-0.23.0/CONTRIBUTING.md
--- opensc-0.22.0/CONTRIBUTING.md	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/CONTRIBUTING.md	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,30 @@
+# Testing locally
+
+To learn how to run the tests from Github actions locally in containers, see
+[`containers`](containers/README.md).
+
+# Spelling
+
+One of the GitHub actions checks spelling using
+[codespell](https://github.com/codespell-project/codespell).
+If you need to ignore some words, such as variable names or
+words in languages other than English, add them to file
+`codespell_ignore_words.txt`.
+
+Note that [codespell](https://github.com/codespell-project/codespell#usage)
+expects words to be lower case:
+> **Important note:** The list passed to -I is case-sensitive
+> based on how it is listed in the codespell dictionaries.
+
+After installing
+[codespell](https://github.com/codespell-project/codespell#installation),
+you can run it from the command line as:
+```sh
+codespell -I .github/codespell_ignore_words.txt
+```
+
+# Release process
+
+The release process is described in [OpenSC wiki](https://github.com/OpenSC/OpenSC/wiki/OpenSC-Release-Howto)
+
+TODO tarball signing: https://github.com/OpenSC/OpenSC/issues/1129
diff -Nru opensc-0.22.0/debian/changelog opensc-0.23.0/debian/changelog
--- opensc-0.22.0/debian/changelog	2022-10-15 18:26:16.000000000 +0200
+++ opensc-0.23.0/debian/changelog	2023-01-10 18:00:21.000000000 +0100
@@ -1,3 +1,10 @@
+opensc (0.23.0-0.1) unstable; urgency=medium
+
+  * Non-maintainer upload
+  * New upstream release (Closes: #1025802)
+
+ -- Bastian Germann <bage at debian.org>  Tue, 10 Jan 2023 18:00:21 +0100
+
 opensc (0.22.0-2.1) unstable; urgency=medium
 
   * Non-maintainer upload.
diff -Nru opensc-0.22.0/debian/copyright opensc-0.23.0/debian/copyright
--- opensc-0.22.0/debian/copyright	2022-01-31 07:02:55.000000000 +0100
+++ opensc-0.23.0/debian/copyright	2023-01-10 18:00:21.000000000 +0100
@@ -14,7 +14,6 @@
  src/libopensc/iasecc-sm.c
  src/libopensc/iasecc.h
  src/libopensc/sm.h
- src/libsm/sm-common.c
  src/smm/sm-card-authentic.c
  src/smm/sm-card-iasecc.c
  src/smm/sm-cwa14890.c
@@ -26,7 +25,6 @@
 
 Files: src/libopensc/card-gpk.c
  src/libopensc/card-openpgp.c
- src/libopensc/cardctl.h
  src/libopensc/ctbcs.c
  src/libopensc/pkcs15-algo.c
  src/libopensc/pkcs15-openpgp.c
@@ -46,6 +44,11 @@
 Copyright: 2001-2003, Olaf Kirch <okir at lst.de>
 License: LGPL-2.1+
 
+Files: src/libopensc/cardctl.h
+Copyright: 2003  Olaf Kirch <okir at lse.de>
+ 2018-2019 GSMK - Gesellschaft für Sichere Mobile Kommunikation mbH
+License: LGPL-2.1+
+
 Files: src/libopensc/card-dnie.c
  src/libopensc/cwa-dnie.c
  src/libopensc/cwa14890.c
@@ -64,6 +67,32 @@
 Copyright: 2001-2002, Timo Teräs <timo.teras at iki.fi>
 License: LGPL-2.1+
 
+Files: src/libopensc/pkcs15-emulator-filter.*
+ src/tests/fuzzing/fuzz_card.c
+ src/tests/fuzzing/fuzzer.c
+ src/tests/fuzzing/fuzzer_tool.*
+ src/tests/fuzzing/fuzz_piv_tool.c
+ src/tests/fuzzing/fuzz_pkcs11.c
+ src/tests/fuzzing/fuzz_pkcs15_crypt.c
+ src/tests/fuzzing/fuzz_pkcs15_encode.c
+ src/tests/fuzzing/fuzz_pkcs15_tool.c
+ src/tests/fuzzing/fuzz_pkcs15init.c
+ src/tests/fuzzing/fuzz_scconf_parse_string.c
+ src/tests/p11test/p11test_case_secret.*
+ src/tests/p11test/p11test_case_wrap.*
+ src/tests/unittests/decode_ecdsa_signature.c
+ src/tests/unittests/pkcs15-emulator-filter.c
+Copyright: 2021-2022 Red Hat, Inc.
+License: LGPL-2.1+
+
+Files: src/tests/unittests/hextobin.c
+Copyright: 2022 Peter Popovec <popovec.peter at gmail.com>
+License: LGPL-2.1+
+
+Files: src/tests/unittests/openpgp-tool.c
+Copyright: 2021  Vincent Pelletier <plr.vincent at gmail.com>
+License: LGPL-2.1+
+
 Files: src/scconf/*
 Copyright: 2002, 2003, Antti Tapaninen <aet at cc.hut.fi>
 License: LGPL-2.1+
@@ -84,8 +113,6 @@
  src/libopensc/muscle.h
  src/libopensc/compression.c
  src/libopensc/compression.h
- src/libopensc/p15card-helper.c
- src/libopensc/p15card-helper.h
  src/pkcs15init/pkcs15-muscle.c
 Copyright: 2006, Identity Alliance, Thomas Harning <support at identityalliance.com>
 License: LGPL-2.1+
@@ -210,10 +237,6 @@
 Copyright: 2005, Nils Larsch <nils at larsch.net>
 License: LGPL-2.1+
 
-Files: src/libsm/sm-common.h
-Copyright: 2013, Viktor Tarasov <viktor.tarasov at gmail.com>
-License: LGPL-2.1+
-
 Files: src/libopensc/card-epass2003.c
  src/pkcs15init/pkcs15-epass2003.c
 Copyright: 2008, 2011 Weitao Sun <weitao at ftsafe.com>
@@ -279,6 +302,10 @@
 Copyright: 2012, Frank Morgner <morgner at informatik.hu-berlin.de>
 License: LGPL-2.1+
 
+Files: src/tests/fuzzing/fuzzer_reader.*
+Copyright: 2019 Frank Morgner <frankmorgner at gmail.com>
+License: LGPL-2.1+
+
 Files: src/libopensc/pkcs15-dnie.c
 Copyright: 2011, Andre Zepezauer <andre.zepezauer at student.uni-halle.de>
   2011, Juan Antonio Martinez <jonsito at terra.es>
@@ -331,6 +358,7 @@
 
 Files: src/libopensc/card-sc-hsm.c
 Copyright: 2012, Andreas Schwier, CardContact, Minden, Germany, and others
+ 2018-2019 GSMK - Gesellschaft für Sichere Mobile Kommunikation mbH
 License: LGPL-2.1+
 
 Files: src/libopensc/pkcs15-esteid.c
@@ -350,15 +378,6 @@
   2005, Zetes
 License: LGPL-2.1+
 
-Files: src/libopensc/card-jcop.c
-Copyright: 2003, Chaskiel Grundman <cg2v at andrew.cmu.edu>
-License: LGPL-2.1+
-
-Files: src/pkcs15init/pkcs15-jcop.c
-Copyright: 2002, Olaf Kirch <okir at lst.de>
-  2003, Chaskiel Grundman <cg2v at andrew.cmu.edu>
-License: LGPL-2.1+
-
 Files: src/libopensc/pkcs15-data.c
 Copyright: 2002, Danny De Cock <daniel.decock at postbox.be>
 License: LGPL-2.1+
@@ -435,6 +454,7 @@
 Files: src/tools/sc-hsm-tool.c
 Copyright: 2001, Juha Yrjölä <juha.yrjola at iki.fi>
   2012, www.CardContact.de, Andreas Schwier, Minden, Germany
+  2018-2019 GSMK - Gesellschaft für Sichere Mobile Kommunikation mbH
 License: LGPL-2.1+
 
 Files: src/libopensc/card-starcos.c
@@ -473,7 +493,7 @@
 Copyright: 2005, 2011, Peter Koch <pk at opensc-project.org>
 License: LGPL-2.1+
 
-Files: src/tools/openpgp-tool.c
+Files: src/tools/openpgp-tool*
 Copyright: 2012, Peter Marschall <peter at adpm.de>
 License: LGPL-2.1+
 
@@ -485,6 +505,11 @@
 Copyright: 2010, Viktor Tarasov <vtarasov at gmail.com>
 License: LGPL-2.1+
 
+Files: src/libopensc/card-nqApplet.*
+ src/libopensc/pkcs15-starcos-esign.c
+Copyright: 2021 jozsefd <jozsef.dojcsak at gmail.com>
+License: LGPL-2.1+
+
 Files: src/pkcs15init/pkcs15-setcos.c
 Copyright: 2003, 2005 Zetes
 License: LGPL-2.1+
diff -Nru opensc-0.22.0/debian/patches/gcc12.patch opensc-0.23.0/debian/patches/gcc12.patch
--- opensc-0.22.0/debian/patches/gcc12.patch	2022-10-15 18:26:16.000000000 +0200
+++ opensc-0.23.0/debian/patches/gcc12.patch	1970-01-01 01:00:00.000000000 +0100
@@ -1,31 +0,0 @@
-From 0f7082ea46562b15221f428860b993e0519c6cbd Mon Sep 17 00:00:00 2001
-From: Veronika Hanulikova <vhanulik at redhat.com>
-Date: Wed, 16 Feb 2022 11:59:27 +0100
-Bug-Debian: https://bugs.debian.org/1013011
-Subject: [PATCH] Fix usage of pointer after realloc
-
----
- src/sm/sm-iso.c | 5 +++--
- 1 file changed, 3 insertions(+), 2 deletions(-)
-
-diff --git a/src/sm/sm-iso.c b/src/sm/sm-iso.c
-index 5baded77c6..2c3f6bcabd 100644
---- a/src/sm/sm-iso.c
-+++ b/src/sm/sm-iso.c
-@@ -181,13 +181,14 @@ static int format_le(size_t le, struct sc_asn1_entry *le_entry,
- 
- static int prefix_buf(u8 prefix, u8 *buf, size_t buflen, u8 **cat)
- {
--	u8 *p;
-+	u8 *p = NULL;
-+	int ptr_same = *cat == buf;
- 
- 	p = realloc(*cat, buflen + 1);
- 	if (!p)
- 		return SC_ERROR_OUT_OF_MEMORY;
- 
--	if (*cat == buf) {
-+	if (ptr_same) {
- 		memmove(p + 1, p, buflen);
- 	} else {
- 		/* Flawfinder: ignore */
diff -Nru opensc-0.22.0/debian/patches/series opensc-0.23.0/debian/patches/series
--- opensc-0.22.0/debian/patches/series	2022-10-15 18:26:16.000000000 +0200
+++ opensc-0.23.0/debian/patches/series	2023-01-10 17:57:32.000000000 +0100
@@ -1,2 +1 @@
 0001-Use-sysconfdir-opensc-for-opensc.conf.patch
-gcc12.patch
diff -Nru opensc-0.22.0/doc/files/files.html opensc-0.23.0/doc/files/files.html
--- opensc-0.22.0/doc/files/files.html	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/doc/files/files.html	2022-11-29 09:34:43.000000000 +0100
@@ -177,7 +177,7 @@
 				</p></dd><dt><a name="card_drivers"></a><span class="term">
 					<code class="option">card_drivers =  <em class="replaceable"><code>name</code></em>... ;</code>
 				</span></dt><dd><p>
-						Whitelist of card drivers to load at start-up.
+						Allowlist of card drivers to load at start-up.
 						The special value <code class="literal">internal</code> (the
 						default) will load all statically linked drivers.
 					</p><p>
@@ -749,8 +749,16 @@
 					</span></dt><dd><p>
 							Whether to cache the card's files (e.g.
 							certificates) on disk in
-							<code class="option">file_cache_dir</code> (Default:
-							<code class="literal">false</code>).
+							<code class="option">file_cache_dir</code>.
+							Possible parameters:
+							</p><div class="itemizedlist"><ul class="itemizedlist" style="list-style-type: disc; "><li class="listitem"><p>
+									<code class="literal">yes</code>: Cache all files (public and private).
+								</p></li><li class="listitem"><p>
+									<code class="literal">public</code>: Cache only public files.
+								</p></li><li class="listitem"><p>
+									<code class="literal">no</code>: File caching disabled.
+								</p></li></ul></div><p>
+							(Default:<code class="literal">no</code>).
 						</p><p>
 							If caching is done by a system process, the
 							cached files may be placed inaccessible from
@@ -837,12 +845,11 @@
 						<code class="option">builtin_emulators = <em class="replaceable"><code>emulators</code></em>;</code>
 					</span></dt><dd><p>
 							List of the builtin pkcs15 emulators to test
-							(Default: <code class="literal">westcos, openpgp, 
-								starcert, tcos, esteid, itacns, 
-								PIV-II, cac, gemsafeGPK, gemsafeV1, actalis,
-								atrust-acos, tccardos, entersafe, pteid,
-								oberthur, sc-hsm, dnie, gids, iasecc, jpki,
-								coolkey, din66291</code>)
+							(Default: <code class="literal">internal</code>)
+						</p><p>
+							Special value <code class="literal">internal</code> will try all not disabled builtin pkcs15 emulators.
+						</p><p>
+							Special value of <code class="literal">old</code> will try all disabled pkcs15 emulators.
 					</p></dd><dt><span class="term">
 						<code class="option">pkcs11_enable_InitToken = <em class="replaceable"><code>bool</code></em>;</code>
 					</span></dt><dd><p>
diff -Nru opensc-0.22.0/doc/files/opensc.conf.5.xml.in opensc-0.23.0/doc/files/opensc.conf.5.xml.in
--- opensc-0.22.0/doc/files/opensc.conf.5.xml.in	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/doc/files/opensc.conf.5.xml.in	2022-11-29 09:34:43.000000000 +0100
@@ -209,7 +209,7 @@
 							rep="repeat"><replaceable>name</replaceable></arg>;</option>
 				</term>
 				<listitem><para>
-						Whitelist of card drivers to load at start-up.
+						Allowlist of card drivers to load at start-up.
 						The special value <literal>internal</literal> (the
 						default) will load all statically linked drivers.
 					</para>
@@ -1128,8 +1128,20 @@
 					<listitem><para>
 							Whether to cache the card's files (e.g.
 							certificates) on disk in
-							<option>file_cache_dir</option> (Default:
-							<literal>false</literal>).
+							<option>file_cache_dir</option>.
+							Possible parameters:
+							<itemizedlist>
+								<listitem><para>
+									<literal>yes</literal>: Cache all files (public and private).
+								</para></listitem>
+									<literal>public</literal>: Cache only public files.
+								<listitem><para>
+								</para></listitem>
+									<literal>no</literal>: File caching disabled.
+								<listitem><para>
+								</para></listitem>
+							</itemizedlist>
+							(Default: <literal>no</literal>).
 						</para>
 						<para>
 							If caching is done by a system process, the
@@ -1269,12 +1281,13 @@
 					</term>
 					<listitem><para>
 							List of the builtin pkcs15 emulators to test
-							(Default: <literal>westcos, openpgp, 
-								starcert, tcos, esteid, itacns, 
-								PIV-II, cac, gemsafeGPK, gemsafeV1, actalis,
-								atrust-acos, tccardos, entersafe, pteid,
-								oberthur, sc-hsm, dnie, gids, iasecc, jpki,
-								coolkey, din66291</literal>)
+							(Default: <literal>internal</literal>)
+						</para>
+						<para>
+							Special value of <literal>internal</literal> will try all not disabled builtin pkcs15 emulators.
+						</para>
+						<para>
+							Special value of <literal>old</literal> will try all disabled pkcs15 emulators.
 					</para></listitem>
 				</varlistentry>
 				<varlistentry>
diff -Nru opensc-0.22.0/doc/tools/npa-tool.1.xml opensc-0.23.0/doc/tools/npa-tool.1.xml
--- opensc-0.22.0/doc/tools/npa-tool.1.xml	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/doc/tools/npa-tool.1.xml	2022-11-29 09:34:43.000000000 +0100
@@ -28,6 +28,11 @@
 			stored on the German eID card (neuer Personalausweis, <abbrev>nPA</abbrev>),
 			and to perform some write and verification operations.
 		</para>
+		<para>
+			Extended Access Control version 2 is performed according to ICAO Doc
+			9303 or BSI TR-03110 so that other identity cards and machine
+			readable travel documents (MRTDs) may be read as well.
+		</para>
 	</refsect1>
 
 	<refsect1>
diff -Nru opensc-0.22.0/doc/tools/opensc-explorer.1.xml opensc-0.23.0/doc/tools/opensc-explorer.1.xml
--- opensc-0.22.0/doc/tools/opensc-explorer.1.xml	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/doc/tools/opensc-explorer.1.xml	2022-11-29 09:34:43.000000000 +0100
@@ -485,7 +485,7 @@
 							List files in the current DF.
 							If no <replaceable>pattern</replaceable> is given,
 							then all files are listed.
-							If one ore more <replaceable>pattern</replaceable>s are given,
+							If one or more <replaceable>pattern</replaceable>s are given,
 							only files matching at least one
 							<replaceable>pattern</replaceable> are listed.
 						</para>
diff -Nru opensc-0.22.0/doc/tools/opensc-tool.1.xml opensc-0.23.0/doc/tools/opensc-tool.1.xml
--- opensc-0.22.0/doc/tools/opensc-tool.1.xml	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/doc/tools/opensc-tool.1.xml	2022-11-29 09:34:43.000000000 +0100
@@ -141,8 +141,19 @@
 						<option>--send-apdu</option> <replaceable>apdu</replaceable>,
 						<option>-s</option> <replaceable>apdu</replaceable>
 					</term>
-					<listitem><para>Sends an arbitrary APDU to the card in the format
-					<code>AA:BB:CC:DD:EE:FF...</code>.</para></listitem>
+					<listitem>
+						<para>
+							Sends an arbitrary APDU to the card in the format
+							<code>AA:BB:CC:DD:EE:FF...</code>. Use this option
+							multiple times to send more than one APDU.
+						</para>
+						<para>
+                            The built-in card drivers may send additional APDUs
+                            for detection and initialization. To avoid this
+							behavior, you may additionally specify
+							<option>--card-driver</option> <literal>default</literal>.
+						</para>
+					</listitem>
 				</varlistentry>
 				<varlistentry>
 					<term>
diff -Nru opensc-0.22.0/doc/tools/pkcs11-tool.1.xml opensc-0.23.0/doc/tools/pkcs11-tool.1.xml
--- opensc-0.22.0/doc/tools/pkcs11-tool.1.xml	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/doc/tools/pkcs11-tool.1.xml	2022-11-29 09:34:43.000000000 +0100
@@ -78,17 +78,17 @@
 					<listitem>
 						<para>
 							Specify hash algorithm used with RSA-PKCS-PSS signature or RSA-OAEP decryption.
-							Allowed values are "SHA-1", "SHA256", "SHA384", "SHA512", and some tokens may 
+							Allowed values are "SHA-1", "SHA256", "SHA384", "SHA512", and some tokens may
 							also allow "SHA224". Default is "SHA-1".
 						</para>
-						<para> 
+						<para>
 							Note that the input to RSA-PKCS-PSS has to be of the size equal to
 							the specified hash algorithm. E.g., for SHA256 the signature input must
 							be exactly 32 bytes long (for mechanisms SHA256-RSA-PKCS-PSS there is no
 							such restriction). For RSA-OAEP, the plaintext input size mLen must be
 							at most keyLen - 2 - 2*hashLen. For example, for RSA 3072-bit key and
 							SHA384, the longest plaintext to encrypt with RSA-OAEP is (with all
-							sizes in bytes): 384 - 2 - 2*48 = 286, aka 286 bytes. 
+							sizes in bytes): 384 - 2 - 2*48 = 286, aka 286 bytes.
 						</para>
 					</listitem>
 				</varlistentry>
@@ -162,7 +162,13 @@
 					<term>
 						<option>--usage-decrypt</option>
 					</term>
-					<listitem><para>Specify 'decrypt' key usage flag (RSA only, set DECRYPT privkey, ENCRYPT in pubkey).</para></listitem>
+					<listitem>
+						<para>Specify 'decrypt' key usage flag.</para>
+						<para>
+							For RSA keys, sets DECRYPT in privkey and ENCRYPT in pubkey. For secret
+							keys, sets both DECRYPT and ENCRYPT.
+						</para>
+					</listitem>
 				</varlistentry>
 
 				<varlistentry>
@@ -230,6 +236,13 @@
 
 				<varlistentry>
 					<term>
+						<option>--session-rw</option>,
+					</term>
+					<listitem><para>Forces to open the PKCS#11 session with CKF_RW_SESSION.</para></listitem>
+				</varlistentry>
+
+				<varlistentry>
+					<term>
 						<option>--login</option>,
 						<option>-l</option>
 					</term>
@@ -344,6 +357,13 @@
 
 				<varlistentry>
 					<term>
+						<option>--undestroyable</option>
+					</term>
+					<listitem><para>Set the CKA_DESTROYABLE attribute to false (object cannot be destroyed)</para></listitem>
+				</varlistentry>
+
+				<varlistentry>
+					<term>
 						<option>--set-id</option> <replaceable>id</replaceable>,
 						<option>-e</option> <replaceable>id</replaceable>
 					</term>
@@ -375,6 +395,24 @@
 
 				<varlistentry>
 					<term>
+						<option>--encrypt</option>,
+					</term>
+					<listitem><para>Encrypt some data.</para></listitem>
+				</varlistentry>
+				<varlistentry>
+					<term>
+						<option>--unwrap</option>,
+					</term>
+					<listitem><para>Unwrap key.</para></listitem>
+				</varlistentry>
+				<varlistentry>
+					<term>
+						<option>--wrap</option>,
+					</term>
+					<listitem><para>Wrap key.</para></listitem>
+				</varlistentry>
+				<varlistentry>
+					<term>
 						<option>--derive</option>,
 					</term>
 					<listitem><para>Derive a secret key using another key and some data.</para></listitem>
@@ -394,7 +432,9 @@
 					<listitem><para>Specify how many bytes of salt should
 					be used in RSA-PSS signatures. Accepts two special values:
 					"-1" means salt length equals to digest length,
-					"-2" means use maximum permissible length.
+					"-2" or "-3" means use maximum permissible length.
+					For verify operation "-2" means that the salt length is automatically recovered from signature.
+					The value "-2" for the verify operation is supported for opensc pkcs#11 module only.
 					Default is digest length (-1).</para></listitem>
 				</varlistentry>
 
@@ -533,7 +573,7 @@
 					</term>
 					<listitem><para>Specify the type of object to operate on.
 					Valid value are <literal>cert</literal>, <literal>privkey</literal>,
-					<literal>pubkey</literal>, <literal>secrkey</literal> 
+					<literal>pubkey</literal>, <literal>secrkey</literal>
 					and <literal>data</literal>.</para></listitem>
 				</varlistentry>
 
@@ -646,6 +686,15 @@
 					</para></listitem>
 				</varlistentry>
 
+				<varlistentry>
+					<term>
+						<option>--iv</option> <replaceable>data</replaceable>
+					</term>
+					<listitem><para>Initialization vector for symmetric ciphers.
+					The <replaceable>data</replaceable> is hexadecimal number, i.e. "000013aa7bffa0".
+					</para></listitem>
+				</varlistentry>
+
 			</variablelist>
 		</para>
 	</refsect1>
@@ -668,6 +717,25 @@
 			using the private key with ID <replaceable>ID</replaceable> and
 			using the RSA-PKCS mechanism:
 				<programlisting>pkcs11-tool --sign --id ID --mechanism RSA-PKCS --input-file data --output-file data.sig</programlisting>
+
+			To encrypt file using the AES key with ID 85 and using mechanism AES-CBC with padding:
+				<programlisting>
+pkcs11-tool --encrypt --id 85 -m AES-CBC-PAD \
+ --iv "00000000000000000000000000000000" \
+ -i file.txt -o encrypted_file.data
+				</programlisting>
+
+			Use the key with ID 22 and mechanism RSA-PKCS to unwrap key from file
+			<replaceable>aes_wrapped.key</replaceable>. After a successful unwrap operation,
+			a new AES key is created on token. ID of this key is set to 90 and label of this
+			key is set to <replaceable>unwrapped-key</replaceable>
+			Note: for the MyEID card, the AES key size must be present in key
+			specification i.e. AES:16
+				<programlisting>
+pkcs11-tool --unwrap --mechanism RSA-PKCS --id 22 \
+  -i aes_wrapped.key --key-type AES: \
+  --application-id 90 --applicatin-label unwrapped-key
+				</programlisting>
 		</para>
 	</refsect1>
 
diff -Nru opensc-0.22.0/doc/tools/pkcs15-init.1.xml opensc-0.23.0/doc/tools/pkcs15-init.1.xml
--- opensc-0.22.0/doc/tools/pkcs15-init.1.xml	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/doc/tools/pkcs15-init.1.xml	2022-11-29 09:34:43.000000000 +0100
@@ -133,7 +133,7 @@
 				You can do this using:
 			</para>
 			<para>
-				<command>pkcs15-init --generate-key " keyspec " --auth-id " nn</command>
+				<command>pkcs15-init --generate-key "keyspec" --auth-id "nn"</command>
 			</para>
 			<para>
 				where <replaceable>keyspec</replaceable> describes the algorithm and the parameters
@@ -173,7 +173,7 @@
 				Note that usage of <option>--id</option> option in the <command>pkcs15-init</command>
 				commands to generate or to import a new key is deprecated.
 				Better practice is to let the middleware to derive the identifier from the key material.
-				(SHA1(modulus) for RSA, SHA1(pub) for DSA, ...).
+				(SHA1(modulus) for RSA, ...).
 				This allows easily set up relation between 'related' objects
 				(private/public keys and certificates).
 			</para>
@@ -677,6 +677,17 @@
 						</para>
 					</listitem>
 				</varlistentry>
+
+				<varlistentry>
+					<term>
+						<option>--label</option> <replaceable>LABEL</replaceable>
+					</term>
+					<listitem>
+						<para>
+							Specify label for a PIN, key, certificate or data object when creating a new objects. When deleting objects, this can be used to delete object by label.
+						</para>
+					</listitem>
+				</varlistentry>
 
 				<varlistentry>
 					<term>
diff -Nru opensc-0.22.0/doc/tools/pkcs15-tool.1.xml opensc-0.23.0/doc/tools/pkcs15-tool.1.xml
--- opensc-0.22.0/doc/tools/pkcs15-tool.1.xml	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/doc/tools/pkcs15-tool.1.xml	2022-11-29 09:34:43.000000000 +0100
@@ -38,7 +38,7 @@
 			<variablelist>
                                 <varlistentry>
                                         <term>
-                                                <option>--version</option>,
+                                                <option>--version</option>
                                         </term>
                                         <listitem><para>Print the OpenSC package release version.</para></listitem>
                                 </varlistentry>
@@ -152,7 +152,7 @@
 
 				<varlistentry>
 					<term>
-						<option>--short</option>
+						<option>--short</option>,
 						<option>-s</option>
 					</term>
 					<listitem><para>Output lists in compact format.</para></listitem>
@@ -177,16 +177,6 @@
 
 				<varlistentry>
 					<term>
-						<option>--clear-cache</option>
-					</term>
-					<listitem><para>Removes the user's cache directory. On
-					Windows, this option additionally removes the system's
-					caching directory (requires administrator
-					privileges).</para></listitem>
-				</varlistentry>
-
-				<varlistentry>
-					<term>
 						<option>--output</option> <replaceable>filename</replaceable>,
 						<option>-o</option> <replaceable>filename</replaceable>
 					</term>
@@ -216,7 +206,7 @@
 
 				<varlistentry>
 					<term>
-						<option>--read-data-object</option> <replaceable>cert</replaceable>,
+						<option>--read-data-object</option> <replaceable>data</replaceable>,
 						<option>-R</option> <replaceable>data</replaceable>
 					</term>
 					<listitem><para>Reads data object with OID, applicationName or label.
@@ -262,7 +252,7 @@
 				<varlistentry>
 					<term>
 						<option>--test-update</option>,
-						<option>-T</option>,
+						<option>-T</option>
 					</term>
 					<listitem><para>Test if the card needs a security update</para></listitem>
 				</varlistentry>
@@ -270,7 +260,7 @@
 				<varlistentry>
 					<term>
 						<option>--update</option>,
-						<option>-U</option>,
+						<option>-U</option>
 					</term>
 					<listitem><para>Update the card with a security update</para></listitem>
 				</varlistentry>
@@ -311,7 +301,7 @@
 				<varlistentry>
 					<term>
 						<option>--pin</option> <replaceable>pin</replaceable>,
-						<option>--new-pin</option> <replaceable>newpin</replaceable>
+						<option>--new-pin</option> <replaceable>newpin</replaceable>,
 						<option>--puk</option> <replaceable>puk</replaceable>
 					</term>
 					<listitem>
diff -Nru opensc-0.22.0/doc/tools/sc-hsm-tool.1.xml opensc-0.23.0/doc/tools/sc-hsm-tool.1.xml
--- opensc-0.22.0/doc/tools/sc-hsm-tool.1.xml	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/doc/tools/sc-hsm-tool.1.xml	2022-11-29 09:34:43.000000000 +0100
@@ -46,6 +46,7 @@
 						<para>Use <option>--pin-retry</option> to define the maximum number of wrong user PIN presentations.</para>
 						<para>Use with <option>--dkek-shares</option> to enable key wrap / unwrap.</para>
 						<para>Use with <option>--label</option> to define a token label</para>
+						<para>Use with <option>--public-key-auth</option> and <option>--required-pub-keys</option> to require public key authentication for login</para>
 					</listitem>
 				</varlistentry>
 
@@ -230,6 +231,74 @@
 						</para>
 					</listitem>
 				</varlistentry>
+
+				<varlistentry>
+					<term>
+						<option>--public-key-auth</option> <replaceable>total-number-of-public-keys</replaceable>,
+						<option>-K</option> <replaceable>total-number-of-public-keys</replaceable>
+					</term>
+					<listitem>
+						<para>Define the total number of public keys to use for public key authentication when using <option>--initialize</option>.
+							  <option>--public-key-auth</option> is optional, but if it's present, it must be used with <option>--required-pub-keys</option>.
+						</para>
+						<para>When the SmartCard-HSM is initialized with these options, it will require M-of-N public key authentication to be used, where
+							<option>--required-pub-keys</option> sets the M and <option>--public-key-auth</option> sets the N. After the initialization,
+							the user should use <option>--register-public-key</option> to register the N public keys before the SmartCard-HSM can be used.
+						</para>
+					</listitem>
+				</varlistentry>
+
+				<varlistentry>
+					<term>
+						<option>--required-pub-keys</option> <replaceable>required-number-of-public-keys</replaceable>,
+						<option>-n</option> <replaceable>required-number-of-public-keys</replaceable>
+					</term>
+					<listitem>
+						<para>Define the required number of public keys to use for public key authentication when using <option>--initialize</option>.
+							  This is the M in M-of-N public key authentication. See <option>--public-key-auth</option> for more information.
+						</para>
+					</listitem>
+				</varlistentry>
+
+				<varlistentry>
+					<term>
+						<option>--register-public-key</option> <replaceable>input-public-key-file</replaceable>,
+						<option>-g</option> <replaceable>input-public-key-file</replaceable>
+					</term>
+					<listitem>
+						<para>Register a public key to be used for M-of-N public key authentication. The file can be exported from
+							  a different SmartCard-HSM with <option>--export-for-pub-key-auth</option>. This can only be used when the
+							  SmartCard-HSM has been initialized with <option>--public-key-auth</option> and <option>--required-pub-keys</option>
+							  and fewer than N public keys have been registered. Use <option>--public-key-auth-status</option> to check the
+							  how many public keys have been registered.
+						</para>
+					</listitem>
+				</varlistentry>
+
+				<varlistentry>
+					<term>
+						<option>--export-for-pub-key-auth</option> <replaceable>output-public-key-file</replaceable>,
+						<option>-e</option> <replaceable>output-public-key-file</replaceable>
+					</term>
+					<listitem>
+						<para>Export a public key to be used for M-of-N public key authentication. This should be used with
+							  <option>--key-reference</option> to choose the key to export. The file should be registered on
+							  another SmartCard-HSM using <option>--register-public-key</option>.
+						</para>
+					</listitem>
+				</varlistentry>
+
+				<varlistentry>
+					<term>
+						<option>--public-key-auth-status</option>
+						<option>-S</option>
+					</term>
+					<listitem>
+						<para>Print the public key authentication status. This is only valid if the SmartCard-HSM was initialized
+							  to use M-of-N public key authentication.
+						</para>
+					</listitem>
+				</varlistentry>
 				
 				<varlistentry>
 					<term>
@@ -268,6 +337,13 @@
 		<para><command>sc-hsm-tool --wrap-key wrap-key.bin --key-reference 1 --pin 648219</command></para>
 		<para>Unwrap key into same or in different SmartCard-HSM with the same DKEK:</para>
 		<para><command>sc-hsm-tool --unwrap-key wrap-key.bin --key-reference 10 --pin 648219 --force</command></para>
+		<para>Initialize SmartCard-HSM to use M-of-N public key authentication with M=2 and N=5</para>
+		<para><command>sc-hsm-tool --initialize --required-pub-keys 2 --public-key-auth 5</command></para>
+		<para>Export a public key for M-of-N public key authentication to a file</para>
+		<para><command>sc-hsm-tool --key-reference 1 --export-for-pub-key-auth ./public_key1.asn1</command></para>
+		<para>Register a public key for M-of-N public key authentication from a file</para>
+		<para><command>sc-hsm-tool --register-public-key ./public_key1.asn1</command></para>
+
 	</refsect1>
 	
 	<refsect1>
diff -Nru opensc-0.22.0/doc/tools/tools.html opensc-0.23.0/doc/tools/tools.html
--- opensc-0.22.0/doc/tools/tools.html	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/doc/tools/tools.html	2022-11-29 09:34:43.000000000 +0100
@@ -5,7 +5,7 @@
 }
 
 .title {
-  font-size: 1.5em; 
+  font-size: 1.5em;
   text-align: center;
 }
 
@@ -50,7 +50,7 @@
 		</span></dt><dt><span class="refentrytitle"><a href="#netkey-tool">netkey-tool</a></span><span class="refpurpose"> — administrative utility for Netkey E4 cards</span></dt><dt><span class="refentrytitle"><a href="#npa-tool">npa-tool</a></span><span class="refpurpose"> — displays information on the German eID card (neuer Personalausweis, <abbr class="abbrev">nPA</abbr>).
 		</span></dt><dt><span class="refentrytitle"><a href="#openpgp-tool">openpgp-tool</a></span><span class="refpurpose"> — utility for accessing visible data OpenPGP smart cards
 		and compatible tokens</span></dt><dt><span class="refentrytitle"><a href="#opensc-asn1">opensc-asn1</a></span><span class="refpurpose"> — parse ASN.1 data
-		</span></dt><dt><span class="refentrytitle"><a href="#opensc-explorer">opensc-explorer</a></span><span class="refpurpose"> — 
+		</span></dt><dt><span class="refentrytitle"><a href="#opensc-explorer">opensc-explorer</a></span><span class="refpurpose"> —
 			generic interactive utility for accessing smart card
 			and similar security token functions
 		</span></dt><dt><span class="refentrytitle"><a href="#opensc-notify">opensc-notify</a></span><span class="refpurpose"> —  monitor smart card events and send notifications
@@ -164,7 +164,7 @@
 		</p></div><div class="refsect1"><a name="id-1.3.6"></a><h2>See also</h2><p>
 			<span class="citerefentry"><span class="refentrytitle">pkcs15-tool</span>(1)</span>
 		</p></div><div class="refsect1"><a name="id-1.3.7"></a><h2>Authors</h2><p><span class="command"><strong>cryptoflex-tool</strong></span> was written by
-		Juha Yrjölä <code class="email"><<a class="email" href="mailto:juha.yrjola at iki.fi">juha.yrjola at iki.fi</a>></code>.</p></div></div><div class="refentry"><div class="refentry.separator"><hr></div><a name="dnie-tool"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>dnie-tool — displays information about DNIe based security tokens</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">dnie-tool</code>  [<em class="replaceable"><code>OPTIONS</code></em>]</p></div></div><div class="refsect1"><a name="id-1.4.4"></a><h2>Description</h2><p>
+		Juha Yrjölä <code class="email"><<a class="email" href="mailto:juha.yrjola at iki.fi">juha.yrjola at iki.fi</a>></code>.</p></div></div><div class="refentry"><div class="refentry.separator"><hr></div><a name="dnie-tool"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>dnie-tool — displays information about DNIe based security tokens</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">dnie-tool</code>  [<em class="replaceable"><code>OPTIONS</code></em>]</p></div></div><div class="refsect1"><a name="id-1.4.4"></a><h2>Description</h2><p>
 			The <span class="command"><strong>dnie-tool</strong></span> utility is used to display additional information about DNIe, the Spanish National eID card.
 		</p></div><div class="refsect1"><a name="id-1.4.5"></a><h2>Options</h2><p>
 			</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">
@@ -211,12 +211,12 @@
 							<em class="replaceable"><code>arg</code></em> is an ATR, the
 							reader with a matching card will be chosen.
 						</p></dd><dt><span class="term">
-						<code class="option">--wait</code>, 
+						<code class="option">--wait</code>,
 						<code class="option">-w</code>
 					</span></dt><dd><p>Causes <span class="command"><strong>dnie-tool</strong></span> to wait for the token to be inserted into reader.</p></dd><dt><span class="term">
 						<code class="option">--verbose</code>,
 						<code class="option">-v</code>
-					</span></dt><dd><p>Causes <span class="command"><strong>dnie-tool</strong></span> to be more verbose. 
+					</span></dt><dd><p>Causes <span class="command"><strong>dnie-tool</strong></span> to be more verbose.
 					Specify this flag several times
 to enable debug output in the opensc library.</p></dd></dl></div><p>
 		</p></div><div class="refsect1"><a name="id-1.4.6"></a><h2>Authors</h2><p><span class="command"><strong>dnie-tool</strong></span> was written by
@@ -244,11 +244,11 @@
 						Specify this flag several times to be more verbose.
 					</p></dd></dl></div><p>
 		</p><div class="refsect2"><a name="id-1.5.5.3"></a><h3>Health Care Application (<abbr class="abbrev">HCA</abbr>)</h3><div class="variablelist"><dl class="variablelist"><dt><span class="term"><code class="option">--pd</code></span></dt><dd><p>
-						Show 'Persönliche Versicherungsdaten' (XML).
+						Show 'Persönliche Versicherungsdaten' (XML).
 					</p></dd><dt><span class="term"><code class="option">--vd</code></span></dt><dd><p>
 						Show 'Allgemeine Versicherungsdaten' (XML).
 					</p></dd><dt><span class="term"><code class="option">--gvd</code></span></dt><dd><p>
-						Show 'Geschützte Versicherungsdaten' (XML).
+						Show 'Geschützte Versicherungsdaten' (XML).
 					</p></dd><dt><span class="term"><code class="option">--vsd-status</code></span></dt><dd><p>
 						Show 'Versichertenstammdaten-Status'.
 					</p></dd></dl></div></div></div><div class="refsect1"><a name="id-1.5.6"></a><h2>Authors</h2><p><span class="command"><strong>egk-tool</strong></span> was written by
@@ -557,7 +557,7 @@
 					</span></dt><dd><p>
 						Specify the terminal's private key.
 					</p></dd><dt><span class="term"><code class="option">--cvc-dir</code> <em class="replaceable"><code>DIRECTORY</code></em></span></dt><dd><p>
-						Specify where to look for the certificate of the 
+						Specify where to look for the certificate of the
 						Country Verifying Certification Authority
 						(<abbr class="abbrev">CVCA</abbr>).
 						If not given, it defaults to
@@ -743,7 +743,7 @@
 						<code class="option">--version</code>,
 						<code class="option">-V</code></span></dt><dd><p>Print version and exit.</p></dd></dl></div><p>
 		</p></div><div class="refsect1"><a name="id-1.12.6"></a><h2>Authors</h2><p><span class="command"><strong>opensc-asn1</strong></span> was written by
-		Frank Morgner <code class="email"><<a class="email" href="mailto:frankmorgner at gmail.com">frankmorgner at gmail.com</a>></code>.</p></div></div><div class="refentry"><div class="refentry.separator"><hr></div><a name="opensc-explorer"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>opensc-explorer — 
+		Frank Morgner <code class="email"><<a class="email" href="mailto:frankmorgner at gmail.com">frankmorgner at gmail.com</a>></code>.</p></div></div><div class="refentry"><div class="refentry.separator"><hr></div><a name="opensc-explorer"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>opensc-explorer —
 			generic interactive utility for accessing smart card
 			and similar security token functions
 		</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">opensc-explorer</code>  [<em class="replaceable"><code>OPTIONS</code></em>] [<em class="replaceable"><code>SCRIPT</code></em>]</p></div></div><div class="refsect1"><a name="id-1.13.4"></a><h2>Description</h2><p>
@@ -812,14 +812,14 @@
 			The following commands are supported:
 			</p><div class="variablelist"><dl class="variablelist"><dt><span class="term">
 						<span class="command"><strong>#</strong></span>
-						  <em class="replaceable"><code></code></em>... 
+						  <em class="replaceable"><code></code></em>...
 					</span></dt><dd><p>
 							Treat line as a comment.
 							Ignore anything until the end of the line introduced by
 							<code class="literal">#</code>.
 						</p></dd><dt><span class="term">
 						<span class="command"><strong>apdu</strong></span>
-						  <em class="replaceable"><code>data</code></em>... 
+						  <em class="replaceable"><code>data</code></em>...
 					</span></dt><dd><p>
 							Send a custom APDU command to the card.
 							<em class="replaceable"><code>data</code></em> is a series of
@@ -872,7 +872,7 @@
 							<em class="replaceable"><code>DF-name</code></em>.
 						</p></dd><dt><span class="term">
 						<span class="command"><strong>change</strong></span>
-						  <code class="literal">CHV</code><em class="replaceable"><code>pin-ref</code></em> 
+						  <code class="literal">CHV</code><em class="replaceable"><code>pin-ref</code></em>
 						 [
 							[<em class="replaceable"><code>old-pin</code></em>]
 							<em class="replaceable"><code>new-pin</code></em>
@@ -951,7 +951,7 @@
 							in double quotes (<code class="literal">"..."</code>).
 						</p></dd><dt><span class="term">
 						<span class="command"><strong>echo</strong></span>
-						  <em class="replaceable"><code>string</code></em>... 
+						  <em class="replaceable"><code>string</code></em>...
 					</span></dt><dd><p>
 							Print the <em class="replaceable"><code>string</code></em>s given.
 						</p></dd><dt><span class="term">
@@ -1013,7 +1013,7 @@
 							List files in the current DF.
 							If no <em class="replaceable"><code>pattern</code></em> is given,
 							then all files are listed.
-							If one ore more <em class="replaceable"><code>pattern</code></em>s are given,
+							If one or more <em class="replaceable"><code>pattern</code></em>s are given,
 							only files matching at least one
 							<em class="replaceable"><code>pattern</code></em> are listed.
 						</p></dd><dt><span class="term">
@@ -1207,7 +1207,7 @@
 		</p></div><div class="refsect1"><a name="id-1.13.7"></a><h2>See also</h2><p>
 			<span class="citerefentry"><span class="refentrytitle">opensc-tool</span>(1)</span>
 		</p></div><div class="refsect1"><a name="id-1.13.8"></a><h2>Authors</h2><p><span class="command"><strong>opensc-explorer</strong></span> was written by
-		Juha Yrjölä <code class="email"><<a class="email" href="mailto:juha.yrjola at iki.fi">juha.yrjola at iki.fi</a>></code>.</p></div></div><div class="refentry"><div class="refentry.separator"><hr></div><a name="opensc-notify"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>opensc-notify —  monitor smart card events and send notifications
+		Juha Yrjölä <code class="email"><<a class="email" href="mailto:juha.yrjola at iki.fi">juha.yrjola at iki.fi</a>></code>.</p></div></div><div class="refentry"><div class="refentry.separator"><hr></div><a name="opensc-notify"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>opensc-notify —  monitor smart card events and send notifications
 		</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">opensc-notify</code>  [<em class="replaceable"><code>OPTIONS</code></em>]</p></div></div><div class="refsect1"><a name="id-1.14.4"></a><h2>Description</h2><p>
 			The <span class="command"><strong>opensc-notify</strong></span> utility is used to
 			monitor smart card events and send the appropriate notification.
@@ -1324,7 +1324,7 @@
 		</p></div><div class="refsect1"><a name="id-1.15.6"></a><h2>See also</h2><p>
 			<span class="citerefentry"><span class="refentrytitle">opensc-explorer</span>(1)</span>
 		</p></div><div class="refsect1"><a name="id-1.15.7"></a><h2>Authors</h2><p><span class="command"><strong>opensc-tool</strong></span> was written by
-		Juha Yrjölä <code class="email"><<a class="email" href="mailto:juha.yrjola at iki.fi">juha.yrjola at iki.fi</a>></code>.</p></div></div><div class="refentry"><div class="refentry.separator"><hr></div><a name="piv-tool"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>piv-tool — smart card utility for HSPD-12 PIV cards</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">piv-tool</code>  [<em class="replaceable"><code>OPTIONS</code></em>]</p></div></div><div class="refsect1"><a name="id-1.16.4"></a><p>
+		Juha Yrjölä <code class="email"><<a class="email" href="mailto:juha.yrjola at iki.fi">juha.yrjola at iki.fi</a>></code>.</p></div></div><div class="refentry"><div class="refentry.separator"><hr></div><a name="piv-tool"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>piv-tool — smart card utility for HSPD-12 PIV cards</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">piv-tool</code>  [<em class="replaceable"><code>OPTIONS</code></em>]</p></div></div><div class="refsect1"><a name="id-1.16.4"></a><p>
 			The <span class="command"><strong>piv-tool</strong></span> utility can be used from the command line to perform
 			miscellaneous smart card operations on a HSPD-12 PIV smart card as defined in NIST 800-73-3.
 			It is intended for use with test cards only. It can be used to load objects, and generate
@@ -1442,16 +1442,16 @@
 						<code class="option">--hash-algorithm</code> <em class="replaceable"><code>mechanism</code></em>
 					</span></dt><dd><p>
 							Specify hash algorithm used with RSA-PKCS-PSS signature or RSA-OAEP decryption.
-							Allowed values are "SHA-1", "SHA256", "SHA384", "SHA512", and some tokens may 
+							Allowed values are "SHA-1", "SHA256", "SHA384", "SHA512", and some tokens may
 							also allow "SHA224". Default is "SHA-1".
-						</p><p> 
+						</p><p>
 							Note that the input to RSA-PKCS-PSS has to be of the size equal to
 							the specified hash algorithm. E.g., for SHA256 the signature input must
 							be exactly 32 bytes long (for mechanisms SHA256-RSA-PKCS-PSS there is no
 							such restriction). For RSA-OAEP, the plaintext input size mLen must be
 							at most keyLen - 2 - 2*hashLen. For example, for RSA 3072-bit key and
 							SHA384, the longest plaintext to encrypt with RSA-OAEP is (with all
-							sizes in bytes): 384 - 2 - 2*48 = 286, aka 286 bytes. 
+							sizes in bytes): 384 - 2 - 2*48 = 286, aka 286 bytes.
 						</p></dd><dt><span class="term">
 						<code class="option">--id</code> <em class="replaceable"><code>id</code></em>,
 						<code class="option">-d</code> <em class="replaceable"><code>id</code></em>
@@ -1557,6 +1557,8 @@
 					</span></dt><dd><p>Set the CKA_SENSITIVE attribute (object cannot be revealed in plaintext).</p></dd><dt><span class="term">
 						<code class="option">--extractable</code>
 					</span></dt><dd><p>Set the CKA_EXTRACTABLE attribute (object can be extracted)</p></dd><dt><span class="term">
+						<code class="option">--undestroyable</code>
+					</span></dt><dd><p>Set the CKA_DESTROYABLE attribute to false (object cannot be destroyed)</p></dd><dt><span class="term">
 						<code class="option">--set-id</code> <em class="replaceable"><code>id</code></em>,
 						<code class="option">-e</code> <em class="replaceable"><code>id</code></em>
 					</span></dt><dd><p>Set the CKA_ID of the object.</p></dd><dt><span class="term">
@@ -1633,7 +1635,7 @@
 						<code class="option">-y</code> <em class="replaceable"><code>type</code></em>
 					</span></dt><dd><p>Specify the type of object to operate on.
 					Valid value are <code class="literal">cert</code>, <code class="literal">privkey</code>,
-					<code class="literal">pubkey</code>, <code class="literal">secrkey</code> 
+					<code class="literal">pubkey</code>, <code class="literal">secrkey</code>
 					and <code class="literal">data</code>.</p></dd><dt><span class="term">
 						<code class="option">--verbose</code>, <code class="option">-v</code>
 					</span></dt><dd><p>Cause <span class="command"><strong>pkcs11-tool</strong></span> to be
@@ -1802,7 +1804,7 @@
 			<span class="citerefentry"><span class="refentrytitle">pkcs15-init</span>(1)</span>,
 			<span class="citerefentry"><span class="refentrytitle">pkcs15-tool</span>(1)</span>
 		</p></div><div class="refsect1"><a name="id-1.18.7"></a><h2>Authors</h2><p><span class="command"><strong>pkcs15-crypt</strong></span> was written by
-		Juha Yrjölä <code class="email"><<a class="email" href="mailto:juha.yrjola at iki.fi">juha.yrjola at iki.fi</a>></code>.</p></div></div><div class="refentry"><div class="refentry.separator"><hr></div><a name="pkcs15-init"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>pkcs15-init — smart card personalization utility</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">pkcs15-init</code>  [<em class="replaceable"><code>OPTIONS</code></em>]</p></div></div><div class="refsect1"><a name="id-1.19.5"></a><h2>Description</h2><p>
+		Juha Yrjölä <code class="email"><<a class="email" href="mailto:juha.yrjola at iki.fi">juha.yrjola at iki.fi</a>></code>.</p></div></div><div class="refentry"><div class="refentry.separator"><hr></div><a name="pkcs15-init"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>pkcs15-init — smart card personalization utility</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">pkcs15-init</code>  [<em class="replaceable"><code>OPTIONS</code></em>]</p></div></div><div class="refsect1"><a name="id-1.19.5"></a><h2>Description</h2><p>
 			The <span class="command"><strong>pkcs15-init</strong></span> utility can be used to create a PKCS #15
 			structure on a smart card, and add key or certificate objects. Details of the
 			structure that will be created are controlled via profiles.
@@ -1898,7 +1900,7 @@
 				Note that usage of <code class="option">--id</code> option in the <span class="command"><strong>pkcs15-init</strong></span>
 				commands to generate or to import a new key is deprecated.
 				Better practice is to let the middleware to derive the identifier from the key material.
-				(SHA1(modulus) for RSA, SHA1(pub) for DSA, ...).
+				(SHA1(modulus) for RSA, ...).
 				This allows easily set up relation between 'related' objects
 				(private/public keys and certificates).
 			</p><p>
@@ -2445,7 +2447,7 @@
 			<span class="citerefentry"><span class="refentrytitle">pkcs15-init</span>(1)</span>,
 			<span class="citerefentry"><span class="refentrytitle">pkcs15-crypt</span>(1)</span>
 		</p></div><div class="refsect1"><a name="id-1.20.7"></a><h2>Authors</h2><p><span class="command"><strong>pkcs15-tool</strong></span> was written by
-		Juha Yrjölä <code class="email"><<a class="email" href="mailto:juha.yrjola at iki.fi">juha.yrjola at iki.fi</a>></code>.</p></div></div><div class="refentry"><div class="refentry.separator"><hr></div><a name="sc-hsm-tool"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>sc-hsm-tool — smart card utility for SmartCard-HSM</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">sc-hsm-tool</code>  [<em class="replaceable"><code>OPTIONS</code></em>]</p></div></div><div class="refsect1"><a name="id-1.21.4"></a><p>
+		Juha Yrjölä <code class="email"><<a class="email" href="mailto:juha.yrjola at iki.fi">juha.yrjola at iki.fi</a>></code>.</p></div></div><div class="refentry"><div class="refentry.separator"><hr></div><a name="sc-hsm-tool"></a><div class="titlepage"></div><div class="refnamediv"><h2>Name</h2><p>sc-hsm-tool — smart card utility for SmartCard-HSM</p></div><div class="refsynopsisdiv"><h2>Synopsis</h2><div class="cmdsynopsis"><p><code class="command">sc-hsm-tool</code>  [<em class="replaceable"><code>OPTIONS</code></em>]</p></div></div><div class="refsect1"><a name="id-1.21.4"></a><p>
 			The <span class="command"><strong>sc-hsm-tool</strong></span> utility can be used from the command line to perform
 			extended maintenance tasks not available via PKCS#11 or other tools in the OpenSC package.
 			It can be used to query the status of a SmartCard-HSM, initialize a device, generate and import
@@ -2460,20 +2462,20 @@
 						<code class="option">-C</code> <em class="replaceable"><code>filename</code></em>
 					</span></dt><dd><p>Create a DKEK share encrypted under a password and save it to the file
 						      given as parameter.</p><p>Use <code class="option">--password</code> to provide a password for encryption rather than prompting for one.</p><p>Use <code class="option">--pwd-shares-threshold</code> and <code class="option">--pwd-shares-total</code> to randomly generate a password and split is using a (t, n) threshold scheme.</p></dd><dt><span class="term">
-						<code class="option">--import-dkek-share</code> <em class="replaceable"><code>filename</code></em>, 
+						<code class="option">--import-dkek-share</code> <em class="replaceable"><code>filename</code></em>,
 						<code class="option">-I</code> <em class="replaceable"><code>filename</code></em>
 					</span></dt><dd><p>Prompt for user password, read and decrypt DKEK share and import into SmartCard-HSM.</p><p>Use <code class="option">--password</code> to provide a password for decryption rather than prompting for one.</p><p>Use <code class="option">--pwd-shares-total</code> to specify the number of shares that should be entered to reconstruct the password.</p></dd><dt><span class="term">
-						<code class="option">--wrap-key</code> <em class="replaceable"><code>filename</code></em>, 
+						<code class="option">--wrap-key</code> <em class="replaceable"><code>filename</code></em>,
 						<code class="option">-W</code> <em class="replaceable"><code>filename</code></em>
 					</span></dt><dd><p>Wrap the key referenced in <code class="option">--key-reference</code> and save with it together with the key description
 						and certificate to the given file.</p><p>Use <code class="option">--pin</code> to provide the user PIN on the command line.</p></dd><dt><span class="term">
-						<code class="option">--unwrap-key</code> <em class="replaceable"><code>filename</code></em>, 
+						<code class="option">--unwrap-key</code> <em class="replaceable"><code>filename</code></em>,
 						<code class="option">-U</code> <em class="replaceable"><code>filename</code></em>
 					</span></dt><dd><p>Read wrapped key, description and certificate from file and import into SmartCard-HSM
 						     under the key reference given in <code class="option">--key-reference</code>.</p><p>Determine the key reference using the output of <span class="command"><strong>pkcs15-tool -D</strong></span>.</p><p>Use <code class="option">--pin</code> to provide a user PIN on the command line.</p><p>Use <code class="option">--force</code> to remove any key, key description or certificate in the way.</p></dd><dt><span class="term">
-						<code class="option">--dkek-shares</code> <em class="replaceable"><code>number-of-shares</code></em>, 
+						<code class="option">--dkek-shares</code> <em class="replaceable"><code>number-of-shares</code></em>,
 						<code class="option">-s</code> <em class="replaceable"><code>number-of-shares</code></em>
-					</span></dt><dd><p>Define the number of DKEK shares to use for recreating the DKEK.</p><p>This is an optional parameter. Using <code class="option">--initialize</code> without 
+					</span></dt><dd><p>Define the number of DKEK shares to use for recreating the DKEK.</p><p>This is an optional parameter. Using <code class="option">--initialize</code> without
 						      <code class="option">--dkek-shares</code> will disable the DKEK completely.</p><p>Using <code class="option">--dkek-shares</code> with 0 shares requests the SmartCard-HSM to
 						      generate a random DKEK. Keys wrapped with this DKEK can only be unwrapped in the
 						      same SmartCard-HSM.</p><p>After using <code class="option">--initialize</code> with one or more DKEK shares, the
diff -Nru opensc-0.22.0/.editorconfig opensc-0.23.0/.editorconfig
--- opensc-0.22.0/.editorconfig	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/.editorconfig	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,20 @@
+root = true
+
+[*]
+charset = utf-8
+max_line_length = 110
+end_of_line = lf
+trim_trailing_whitespace = true
+insert_final_newline = true
+
+[*.{c,h}]
+indent_style = tab
+tab_width = 4
+
+[{Makefile.am,configure.ac}]
+indent_style = tab
+tab_width = 4
+
+[*.{yml,yaml}]
+indent_style = space
+indent_size = 2
diff -Nru opensc-0.22.0/etc/opensc.conf opensc-0.23.0/etc/opensc.conf
--- opensc-0.22.0/etc/opensc.conf	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/etc/opensc.conf	2022-11-29 09:34:43.000000000 +0100
@@ -2,6 +2,6 @@
 	# debug = 3;
 	# debug_file = opensc-debug.txt;
 	framework pkcs15 {
-		# use_file_caching = true;
+		# use_file_caching = public;
 	}
 }
diff -Nru opensc-0.22.0/etc/opensc.conf.example.in opensc-0.23.0/etc/opensc.conf.example.in
--- opensc-0.22.0/etc/opensc.conf.example.in	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/etc/opensc.conf.example.in	2022-11-29 09:34:43.000000000 +0100
@@ -133,7 +133,7 @@
 		# max_recv_size = 65536;
 	}
 
-	# Whitelist of card drivers to load at start-up
+	# Allowlist of card drivers to load at start-up
 	#
 	# The supported internal card driver names can be retrieved
 	# from the output of:
@@ -883,8 +883,8 @@
 		# inaccessible from the user account. Use a global caching directory if
 		# you wish to share the cached information.
 		#
-		# Default: false
-		# use_file_caching = true;
+		# Default: no
+		# use_file_caching = public;
 		#
 		# set a path for caching
 		# so you do not use the env variables and for pam_pkcs11
@@ -929,8 +929,10 @@
 		# enable_builtin_emulation = no;
 		#
 		# List of the builtin pkcs15 emulators to test
-		# Default: esteid, openpgp, tcos, starcert, itacns, actalis, atrust-acos, gemsafeGPK, gemsafeV1, tccardos, PIV-II;
-		# builtin_emulators = openpgp;
+		# Special value of 'internal' will try all not disabled builtin pkcs15 emulators.
+		# Special value of 'old' will try all disabled pkcs15 emulators. 
+		# Default: internal;
+		# builtin_emulators = old, internal;
 
 		# additional settings per driver
 		#
diff -Nru opensc-0.22.0/.github/actions/packit/action.yml opensc-0.23.0/.github/actions/packit/action.yml
--- opensc-0.22.0/.github/actions/packit/action.yml	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/.github/actions/packit/action.yml	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,5 @@
+name: Packit RPM build
+description: Action that provides Packit RPM build
+runs:
+  using: "docker"
+  image: "Dockerfile"
diff -Nru opensc-0.22.0/.github/actions/packit/Dockerfile opensc-0.23.0/.github/actions/packit/Dockerfile
--- opensc-0.22.0/.github/actions/packit/Dockerfile	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/.github/actions/packit/Dockerfile	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,5 @@
+FROM quay.io/packit/packit
+
+RUN git config --system --add safe.directory /github/workspace
+
+ENTRYPOINT ["./.github/test-packit.sh"]
diff -Nru opensc-0.22.0/.github/build.sh opensc-0.23.0/.github/build.sh
--- opensc-0.22.0/.github/build.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/.github/build.sh	2022-11-29 09:34:43.000000000 +0100
@@ -1,4 +1,6 @@
-#!/bin/bash -e
+#!/bin/bash
+
+set -ex -o xtrace
 
 export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig;
 
@@ -32,13 +34,25 @@
 	unset CC
 	unset CXX
 	./configure --host=$HOST --with-completiondir=/tmp --disable-openssl --disable-readline --disable-zlib --disable-notify --prefix=$PWD/win32/opensc || cat config.log;
-	make -j 2
+	make -j 2 V=1
 	# no point in running tests on mingw
 else
+	if [ "$1" == "ix86" ]; then
+		export CFLAGS="-m32"
+		export LDFLAGS="-m32"
+	fi
 	# normal procedure
-	./configure  --disable-dependency-tracking
-	make -j 2
-	make check
+
+	if [ "$1" == "no-shared" ]; then
+		./configure --disable-shared
+	else
+		./configure --disable-dependency-tracking
+	fi
+	make -j 2 V=1
+	# 32b build has some issues to find openssl correctly
+	if [ "$1" != "ix86" ]; then
+		make check
+	fi
 fi
 
 # this is broken in old ubuntu
diff -Nru opensc-0.22.0/.github/cleanup-macos.sh opensc-0.23.0/.github/cleanup-macos.sh
--- opensc-0.22.0/.github/cleanup-macos.sh	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/.github/cleanup-macos.sh	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,7 @@
+#!/bin/bash
+
+set -ex -o xtrace
+
+if [ -n "$PASS_SECRETS_TAR_ENC" ]; then
+    .github/remove_signing_key.sh
+fi
diff -Nru opensc-0.22.0/.github/.codeql.yml opensc-0.23.0/.github/.codeql.yml
--- opensc-0.22.0/.github/.codeql.yml	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/.github/.codeql.yml	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,14 @@
+name: "CodeQL configuration file"
+
+paths:
+  - src/
+paths-ignore:
+  - 'src/tools/*-cmdline.*'
+  - src/tests/
+  - tests/
+
+query-filters:
+  - exclude:
+      # This reports all the uses of the DES, but this is needed for
+      # interoperability with cards not supporting AES
+      id: cpp/weak-cryptographic-algorithm
diff -Nru opensc-0.22.0/.github/codespell_ignore_words.txt opensc-0.23.0/.github/codespell_ignore_words.txt
--- opensc-0.22.0/.github/codespell_ignore_words.txt	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/.github/codespell_ignore_words.txt	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,22 @@
+ans
+ba
+comandos
+componentes
+datas
+direccion
+ede
+fase
+feld
+gost
+hist
+ist
+keypair
+nmake
+oder
+parm
+parms
+requiere
+responde
+sie
+signatur
+standarts
diff -Nru opensc-0.22.0/.github/push_artifacts.sh opensc-0.23.0/.github/push_artifacts.sh
--- opensc-0.22.0/.github/push_artifacts.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/.github/push_artifacts.sh	2022-11-29 09:34:43.000000000 +0100
@@ -2,6 +2,10 @@
 
 set -ex -o xtrace
 
+if [ -z "$GH_TOKEN" ]; then
+    exit 0
+fi
+
 BUILDPATH=${PWD}
 BRANCH="`git log --max-count=1 --date=short --abbrev=8 --pretty=format:"%cd_%h"`"
 
diff -Nru opensc-0.22.0/.github/restart-pcscd.sh opensc-0.23.0/.github/restart-pcscd.sh
--- opensc-0.22.0/.github/restart-pcscd.sh	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/.github/restart-pcscd.sh	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,39 @@
+#!/bin/bash -e
+
+# This file is made to be sourced into other test scripts and not executed
+# manually because it sets trap to restore pcscd to working state
+
+# register cleanup handler
+function pcscd_cleanup {
+	echo "Process terminated: resetting pcscd"
+	sudo pkill pcscd
+	if which systemctl && systemctl is-system-running; then
+		sudo systemctl start pcscd.socket
+	fi
+}
+trap pcscd_cleanup EXIT
+
+
+# stop the pcscd service and run it from console to see possible errors
+if which systemctl && systemctl is-system-running; then
+	sudo systemctl stop pcscd.service pcscd.socket
+else
+	sudo pkill pcscd || echo "no pcscd process was running"
+fi
+sudo /usr/sbin/pcscd -f 2>&1 | sed -e 's/^/pcscd: /;' &
+
+
+# Try to wait up to 30 seconds for pcscd to come up and create PID file
+for ((i=1;i<=30;i++)); do
+	echo "Waiting for pcscd to start: $i s"
+	if [ -f "/var/run/pcscd/pcscd.pid" ]; then
+		break
+	fi
+	sleep 1
+done
+
+
+# if it did not come up, warn, but continue
+if [ ! -f "/var/run/pcscd/pcscd.pid" ]; then
+	echo "WARNING: The pcscd pid file does not exist ... trying anyway"
+fi
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/.github/secrets.tar.enc und /tmp/MJ1fzeiQgB/opensc-0.23.0/.github/secrets.tar.enc sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/.github/secrets.tar.gpg und /tmp/MJ1fzeiQgB/opensc-0.23.0/.github/secrets.tar.gpg sind verschieden.
diff -Nru opensc-0.22.0/.github/setup-java.sh opensc-0.23.0/.github/setup-java.sh
--- opensc-0.22.0/.github/setup-java.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/.github/setup-java.sh	2022-11-29 09:34:43.000000000 +0100
@@ -1,4 +1,6 @@
-#!/bin/bash -e
+#!/bin/bash
+
+set -ex -o xtrace
 
 # Select the right java
 sudo update-java-alternatives -s java-1.8.0-openjdk-amd64
@@ -11,14 +13,21 @@
 ./.github/setup-vsmartcard.sh
 
 # Javacard SDKs
-git clone https://github.com/martinpaljak/oracle_javacard_sdks.git
+if [ ! -d "oracle_javacard_sdks" ]; then
+	git clone https://github.com/martinpaljak/oracle_javacard_sdks.git
+fi
 export JC_HOME=$PWD/oracle_javacard_sdks/jc222_kit
 export JC_CLASSIC_HOME=$PWD/oracle_javacard_sdks/jc305u3_kit
 
 # jCardSim
-git clone https://github.com/arekinath/jcardsim.git
+if [ ! -d "jcardsim" ]; then
+	# https://github.com/licel/jcardsim/pull/174
+	git clone https://github.com/Jakuje/jcardsim.git
+fi
 pushd jcardsim
 env | grep -i openjdk
 export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/
-mvn initialize && mvn clean install
+if [ ! -f target/jcardsim-3.0.5-SNAPSHOT.jar ]; then
+	mvn initialize && mvn clean install
+fi
 popd
diff -Nru opensc-0.22.0/.github/setup-libressl.sh opensc-0.23.0/.github/setup-libressl.sh
--- opensc-0.22.0/.github/setup-libressl.sh	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/.github/setup-libressl.sh	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,22 @@
+#!/bin/bash
+
+set -ex -o xtrace
+
+V=libressl-3.4.2
+
+sudo apt-get remove -y libssl-dev
+
+if [ ! -d "$V" ]; then
+	# letsencrypt CA does not seem to be included in CI runner
+	wget --no-check-certificate https://ftp.openbsd.org/pub/OpenBSD/LibreSSL/$V.tar.gz
+	tar xzf $V.tar.gz
+fi
+pushd $V
+./configure --prefix=/usr/local
+make -j $(nproc)
+sudo make install
+popd
+
+# update dynamic linker to find the libraries in non-standard path
+echo "/usr/local/lib64" | sudo tee /etc/ld.so.conf.d/openssl.conf
+sudo ldconfig
diff -Nru opensc-0.22.0/.github/setup-linux.sh opensc-0.23.0/.github/setup-linux.sh
--- opensc-0.22.0/.github/setup-linux.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/.github/setup-linux.sh	2022-11-29 09:34:43.000000000 +0100
@@ -1,19 +1,32 @@
-#!/bin/bash -e
+#!/bin/bash
 
-DEPS="docbook-xsl libpcsclite-dev xsltproc gengetopt libcmocka-dev help2man pcscd check softhsm2 pcsc-tools libtool make autoconf autoconf-archive automake libssl-dev zlib1g-dev pkg-config libreadline-dev openssl git"
+set -ex -o xtrace
+
+# Generic dependencies
+DEPS="docbook-xsl xsltproc gengetopt help2man pcscd check pcsc-tools libtool make autoconf autoconf-archive automake pkg-config git xxd openssl"
+
+# 64bit or 32bit dependencies
+if [ "$1" == "ix86" ]; then
+	sudo dpkg --add-architecture i386
+	DEPS="$DEPS gcc-multilib libpcsclite-dev:i386 libcmocka-dev:i386 libssl-dev:i386 zlib1g-dev:i386 libreadline-dev:i386 softhsm2:i386"
+else
+	DEPS="$DEPS libpcsclite-dev libcmocka-dev libssl-dev zlib1g-dev libreadline-dev softhsm2"
+fi
 
 if [ "$1" == "clang-tidy" ]; then
 	DEPS="$DEPS clang-tidy"
 elif [ "$1" == "cac" ]; then
 	DEPS="$DEPS libglib2.0-dev libnss3-dev gnutls-bin libusb-dev libudev-dev flex libnss3-tools"
 elif [ "$1" == "oseid" ]; then
-	DEPS="$DEPS socat gawk xxd"
+	DEPS="$DEPS socat gawk"
 elif [ "$1" == "piv" -o "$1" == "isoapplet" -o "$1" == "gidsapplet" -o "$1" == "openpgp" ]; then
 	if [ "$1" == "piv" ]; then
 		DEPS="$DEPS cmake"
 	fi
-	DEPS="$DEPS ant openjdk-8-jdk"
+	DEPS="$DEPS ant openjdk-8-jdk maven"
 elif [ "$1" == "mingw" -o "$1" == "mingw32" ]; then
+	# Note, that this list is somehow magic and adding libwine, libwine:i386 or wine64
+	# will make the following sections break without any useful logs. See GH#2458
 	DEPS="$DEPS wine wine32 xvfb wget"
 	sudo dpkg --add-architecture i386
 	if [ "$1" == "mingw" ]; then
@@ -23,11 +36,26 @@
 	fi
 fi
 
+# The Github's Ubuntu images since 20211122.1 are broken
+# https://github.com/actions/virtual-environments/issues/4589
+if [ "$1" == "mingw" -o "$1" == "mingw32" -o "$1" == "ix86" ]; then
+	sudo rm -f /etc/apt/sources.list.d/microsoft-prod.list
+	sudo apt-get update -qq
+	sudo apt-get install -yqq --allow-downgrades libgd3/focal libpcre2-8-0/focal libpcre2-16-0/focal libpcre2-32-0/focal libpcre2-posix2/focal
+	sudo apt-get purge -yqq libmono* moby* mono* php* libgdiplus libpcre2-posix3 libzip4
+fi
+
 # make sure we do not get prompts
 export DEBIAN_FRONTEND=noninteractive
+export DEBCONF_NONINTERACTIVE_SEEN=true
 sudo apt-get update
 sudo apt-get install -y build-essential $DEPS
 
+# install libressl if needed
+if [ "$1" == "libressl" -o "$2" == "libressl" ]; then
+	./.github/setup-libressl.sh &> /tmp/libressl.log || cat /tmp/libressl.log
+fi
+
 if [ "$1" == "mingw" -o "$1" == "mingw32" ]; then
 	if [ ! -f "$(winepath 'C:/Program Files/Inno Setup 5/ISCC.exe')" ]; then
 		/sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16
diff -Nru opensc-0.22.0/.github/setup-macos.sh opensc-0.23.0/.github/setup-macos.sh
--- opensc-0.22.0/.github/setup-macos.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/.github/setup-macos.sh	2022-11-29 09:34:43.000000000 +0100
@@ -1,31 +1,16 @@
 #!/bin/bash
 
-brew install automake
+set -ex -o xtrace
 
-# gengetopt
-curl https://ftp.gnu.org/gnu/gengetopt/gengetopt-2.23.tar.xz -L --output gengetopt-2.23.tar.xz
-tar xfj gengetopt-2.23.tar.xz
-pushd gengetopt-2.23
-./configure && make
-sudo make install
-popd
-
-# help2man
-curl https://ftp.gnu.org/gnu/help2man/help2man-1.47.16.tar.xz -L --output help2man-1.47.16.tar.xz
-tar xjf help2man-1.47.16.tar.xz
-pushd help2man-1.47.16
-./configure && make
-sudo make install
-popd
+brew install automake gengetopt help2man
 
 # openSCToken
 export PATH="/usr/local/opt/ccache/libexec:$PATH"
 git clone https://github.com/frankmorgner/OpenSCToken.git
 sudo rm -rf /Library/Developer/CommandLineTools;
 
-# TODO make the encrypted key working in github
-if [ "$GITHUB_EVENT_NAME" == "pull_request" -a -n "$encrypted_3b9f0b9d36d1_key" ]; then
-    openssl aes-256-cbc -K $encrypted_3b9f0b9d36d1_key -iv $encrypted_3b9f0b9d36d1_iv -in .github/secrets.tar.enc -out .github/secrets.tar -d;
+if [ -n "$PASS_SECRETS_TAR_ENC" ]; then
+    gpg --quiet --batch --yes --decrypt --passphrase="$PASS_SECRETS_TAR_ENC" --output .github/secrets.tar .github/secrets.tar.gpg
     .github/add_signing_key.sh;
 else
     unset CODE_SIGN_IDENTITY INSTALLER_SIGN_IDENTITY;
diff -Nru opensc-0.22.0/.github/setup-vsmartcard.sh opensc-0.23.0/.github/setup-vsmartcard.sh
--- opensc-0.22.0/.github/setup-vsmartcard.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/.github/setup-vsmartcard.sh	2022-11-29 09:34:43.000000000 +0100
@@ -1,5 +1,7 @@
 #!/bin/bash
 
+set -ex -o xtrace
+
 if [ ! -d "vsmartcard" ]; then
 	git clone https://github.com/frankmorgner/vsmartcard.git
 fi
diff -Nru opensc-0.22.0/.github/test-cac.sh opensc-0.23.0/.github/test-cac.sh
--- opensc-0.22.0/.github/test-cac.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/.github/test-cac.sh	2022-11-29 09:34:43.000000000 +0100
@@ -1,4 +1,6 @@
-#!/bin/bash -e
+#!/bin/bash
+
+set -ex -o xtrace
 
 # install the opensc
 sudo make install
@@ -15,28 +17,26 @@
 ./autogen.sh --prefix=/usr && make -j2 && sudo make install
 popd
 
+# prepare pcscd
+. .github/restart-pcscd.sh
+
 # virt_cacard
 if [ ! -d "virt_cacard" ]; then
 	git clone https://github.com/Jakuje/virt_cacard.git
 fi
 pushd virt_cacard
 ./autogen.sh && ./configure && make
+./setup-softhsm2.sh
+export SOFTHSM2_CONF=$PWD/softhsm2.conf
+# register cleanup function on exit
+trap "pkill -9 virt_cacard" EXIT
+./virt_cacard 2>&1 | sed -e 's/^/virt_cacard: /;' &
 popd
 
-sudo /etc/init.d/pcscd restart
-
+# run the tests
 pushd src/tests/p11test/
-./p11test -s 0 -p 12345678 -i -o virt_cacard.json &
 sleep 5
-popd
-
-# virt_cacard startup
-pushd virt_cacard
-./setup-softhsm2.sh
-export SOFTHSM2_CONF=$PWD/softhsm2.conf
-./virt_cacard &
-wait $(ps aux | grep '[p]11test'| awk '{print $2}')
-kill -9 $(ps aux | grep '[v]irt_cacard'| awk '{print $2}')
+./p11test -s 0 -p 12345678 -o virt_cacard.json
 popd
 
 # cleanup -- this would break later uses of pcscd
diff -Nru opensc-0.22.0/.github/test-gidsapplet.sh opensc-0.23.0/.github/test-gidsapplet.sh
--- opensc-0.22.0/.github/test-gidsapplet.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/.github/test-gidsapplet.sh	2022-11-29 09:34:43.000000000 +0100
@@ -1,4 +1,6 @@
-#!/bin/bash -e
+#!/bin/bash
+
+set -ex -o xtrace
 
 # install the opensc
 sudo make install
@@ -16,10 +18,9 @@
 echo "com.licel.jcardsim.vsmartcard.host=localhost" >> gids_jcardsim.cfg;
 echo "com.licel.jcardsim.vsmartcard.port=35963" >> gids_jcardsim.cfg;
 
-# log errors from pcscd to console
-sudo systemctl stop pcscd.service pcscd.socket
-sudo /usr/sbin/pcscd -f &
-PCSCD_PID=$!
+
+# prepare pcscd
+. .github/restart-pcscd.sh
 
 
 # start the applet and run couple of commands against that
@@ -30,7 +31,3 @@
 opensc-tool -n;
 gids-tool --initialize --pin 123456 --admin-key 000000000000000000000000000000000000000000000000 --serial 00000000000000000000000000000000;
 kill -9 $PID
-
-
-# cleanup
-sudo kill -9 $PCSCD_PID
diff -Nru opensc-0.22.0/.github/test-isoapplet.sh opensc-0.23.0/.github/test-isoapplet.sh
--- opensc-0.22.0/.github/test-isoapplet.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/.github/test-isoapplet.sh	2022-11-29 09:34:43.000000000 +0100
@@ -1,4 +1,6 @@
-#!/bin/bash -e
+#!/bin/bash
+
+set -ex -o xtrace
 
 # install the opensc
 sudo make install
@@ -8,34 +10,79 @@
 ./.github/setup-java.sh
 
 # The ISO applet
-git clone https://github.com/philipWendland/IsoApplet.git;
-javac -classpath jcardsim/target/jcardsim-3.0.5-SNAPSHOT.jar IsoApplet/src/net/pwendland/javacard/pki/isoapplet/*.java;
-echo "com.licel.jcardsim.card.applet.0.AID=F276A288BCFBA69D34F31001" > isoapplet_jcardsim.cfg;
-echo "com.licel.jcardsim.card.applet.0.Class=net.pwendland.javacard.pki.isoapplet.IsoApplet" >> isoapplet_jcardsim.cfg;
-echo "com.licel.jcardsim.card.ATR=3B80800101" >> isoapplet_jcardsim.cfg;
-echo "com.licel.jcardsim.vsmartcard.host=localhost" >> isoapplet_jcardsim.cfg;
-echo "com.licel.jcardsim.vsmartcard.port=35963" >> isoapplet_jcardsim.cfg;
-
-# log errors from pcscd to console
-sudo systemctl stop pcscd.service pcscd.socket
-sudo /usr/sbin/pcscd -f &
-PCSCD_PID=$!
+if [ ! -d IsoApplet ]; then
+	git clone https://github.com/philipWendland/IsoApplet.git
+	# enable IsoApplet key import patch
+	sed "s/DEF_PRIVATE_KEY_IMPORT_ALLOWED = false/DEF_PRIVATE_KEY_IMPORT_ALLOWED = true/g" -i IsoApplet/src/net/pwendland/javacard/pki/isoapplet/IsoApplet.java
+fi
+javac -classpath jcardsim/target/jcardsim-3.0.5-SNAPSHOT.jar IsoApplet/src/net/pwendland/javacard/pki/isoapplet/*.java
+echo "com.licel.jcardsim.card.applet.0.AID=F276A288BCFBA69D34F31001" > isoapplet_jcardsim.cfg
+echo "com.licel.jcardsim.card.applet.0.Class=net.pwendland.javacard.pki.isoapplet.IsoApplet" >> isoapplet_jcardsim.cfg
+echo "com.licel.jcardsim.card.ATR=3B80800101" >> isoapplet_jcardsim.cfg
+echo "com.licel.jcardsim.vsmartcard.host=localhost" >> isoapplet_jcardsim.cfg
+echo "com.licel.jcardsim.vsmartcard.port=35963" >> isoapplet_jcardsim.cfg
+
+
+# prepare pcscd
+. .github/restart-pcscd.sh
+
 
 # start the applet and run couple of commands against that
 java -noverify -cp IsoApplet/src/:jcardsim/target/jcardsim-3.0.5-SNAPSHOT.jar com.licel.jcardsim.remote.VSmartCard isoapplet_jcardsim.cfg >/dev/null &
-PID=$!;
-sleep 5;
-opensc-tool --card-driver default --send-apdu 80b800001a0cf276a288bcfba69d34f310010cf276a288bcfba69d34f3100100;
-opensc-tool -n;
-pkcs15-init --create-pkcs15 --so-pin 123456 --so-puk 0123456789abcdef;
-pkcs15-tool --change-pin --pin 123456 --new-pin 654321;
-pkcs15-tool --unblock-pin --puk 0123456789abcdef --new-pin 123456;
-pkcs15-init --generate-key rsa/2048     --id 1 --key-usage decrypt,sign --auth-id FF --pin 123456;
-pkcs15-init --generate-key rsa/2048     --id 2 --key-usage decrypt      --auth-id FF --pin 123456;
-pkcs15-init --generate-key ec/secp256r1 --id 3 --key-usage sign         --auth-id FF --pin 123456;
-pkcs15-tool -D;
-pkcs11-tool -l -t -p 123456;
-kill -9 $PID;
+PID=$!
+sleep 5
 
+# Does OpenSC see the uninitialized card?
+pkcs11-tool -L | tee opensc.log
+# report as "token not recognized"
+grep "(token not recognized)" opensc.log
+
+# Does OpenSC see the uninitialized card with options for InitToken?
+cat >opensc.conf <<EOF
+app default {
+    enable_default_driver = true;
+    card_atr 3B:80:80:01:01 {
+        pkcs11_enable_InitToken = yes;
+    }
+    card_drivers = default;
+}
+EOF
+OPENSC_CONF=opensc.conf pkcs11-tool -L | tee opensc.log
+# report as "token not recognized"
+grep "uninitialized" opensc.log
+
+opensc-tool --card-driver default --send-apdu 80b800001a0cf276a288bcfba69d34f310010cf276a288bcfba69d34f3100100
+opensc-tool -n
+pkcs15-init --create-pkcs15 --so-pin 123456 --so-puk 0123456789abcdef
+pkcs15-tool --change-pin --pin 123456 --new-pin 654321
+pkcs15-tool --unblock-pin --puk 0123456789abcdef --new-pin 123456
+pkcs15-init --generate-key rsa/2048     --id 1 --key-usage decrypt,sign --auth-id FF --pin 123456
+pkcs15-init --generate-key rsa/2048     --id 2 --key-usage decrypt      --auth-id FF --pin 123456
+pkcs15-init --generate-key ec/secp256r1 --id 3 --key-usage sign         --auth-id FF --pin 123456
+pkcs15-tool -D
+pkcs11-tool -l -t -p 123456
+
+# run the tests
+pushd src/tests/p11test/
+sleep 5
+./p11test -s 0 -p 123456 -o isoapplet.json || true # ec_sign_size_test is failing here
+popd
+
+# random data to be signed
+dd if=/dev/random of=/tmp/data.bin bs=300 count=1
+# sign & verify using secp256r1 key
+pkcs11-tool -l -p 123456 -s -m ECDSA-SHA1 -d 3 -i /tmp/data.bin -o /tmp/data.sig
+pkcs11-tool --verify -m ECDSA-SHA1 -d 3 -i /tmp/data.bin --signature-file /tmp/data.sig
+# import, sign & verify using another secp256r1 key
+openssl ecparam -name secp256r1 -genkey -noout -out /tmp/ECprivKey.pem
+openssl ec -in /tmp/ECprivKey.pem -pubout -out /tmp/ECpubKey.pem
+pkcs11-tool -l -p 123456 -w /tmp/ECprivKey.pem -y privkey -d 4
+pkcs11-tool -l -p 123456 -w /tmp/ECpubKey.pem -y pubkey -d 4
+pkcs11-tool -l -p 123456 -s -m ECDSA-SHA1 -d 4 -i /tmp/data.bin -o /tmp/data.sig
+pkcs11-tool --verify -m ECDSA-SHA1 -d 4 -i /tmp/data.bin --signature-file /tmp/data.sig
 # cleanup
-sudo kill -9 $PCSCD_PID
+rm /tmp/ECprivKey.pem /tmp/ECpubKey.pem /tmp/data.bin /tmp/data.sig
+
+kill -9 $PID
+
+diff -u3 src/tests/p11test/isoapplet{_ref,}.json
diff -Nru opensc-0.22.0/.github/test-openpgp.sh opensc-0.23.0/.github/test-openpgp.sh
--- opensc-0.22.0/.github/test-openpgp.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/.github/test-openpgp.sh	2022-11-29 09:34:43.000000000 +0100
@@ -1,4 +1,6 @@
-#!/bin/bash -e
+#!/bin/bash
+
+set -ex -o xtrace
 
 # install the opensc
 sudo make install
@@ -9,19 +11,18 @@
 
 # The OpenPGP applet
 git clone --recursive https://github.com/Yubico/ykneo-openpgp.git;
-cd ykneo-openpgp;
+pushd ykneo-openpgp;
 ant -DJAVACARD_HOME=${JC_HOME};
-cd $TRAVIS_BUILD_DIR;
+popd
 echo "com.licel.jcardsim.card.applet.0.AID=D2760001240102000000000000010000" > openpgp_jcardsim.cfg;
 echo "com.licel.jcardsim.card.applet.0.Class=openpgpcard.OpenPGPApplet" >> openpgp_jcardsim.cfg;
 echo "com.licel.jcardsim.card.ATR=3B80800101" >> openpgp_jcardsim.cfg;
 echo "com.licel.jcardsim.vsmartcard.host=localhost" >> openpgp_jcardsim.cfg;
 echo "com.licel.jcardsim.vsmartcard.port=35963" >> openpgp_jcardsim.cfg;
 
-# log errors from pcscd to console
-sudo systemctl stop pcscd.service pcscd.socket
-sudo /usr/sbin/pcscd -f &
-PCSCD_PID=$!
+
+# prepare pcscd
+. .github/restart-pcscd.sh
 
 
 # start the applet and run couple of commands against that
@@ -34,7 +35,3 @@
 pkcs15-init --verify --auth-id 3 --pin 12345678 --delete-objects privkey,pubkey --id 2 --generate-key rsa/2048;
 pkcs11-tool -l -t -p 123456;
 kill -9 $PID
-
-
-# cleanup
-sudo kill -9 $PCSCD_PID
diff -Nru opensc-0.22.0/.github/test-oseid.sh opensc-0.23.0/.github/test-oseid.sh
--- opensc-0.22.0/.github/test-oseid.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/.github/test-oseid.sh	2022-11-29 09:34:43.000000000 +0100
@@ -1,4 +1,6 @@
-#!/bin/bash -e
+#!/bin/bash
+
+set -ex -o xtrace
 
 # install the opensc
 sudo make install
@@ -40,6 +42,9 @@
 ./OsEID-tool EC-SIGN-TEST
 ./OsEID-tool EC-SIGN-PKCS11-TEST
 ./OsEID-tool EC-ECDH-TEST
+./OsEID-tool UNWRAP-WRAP-TEST
+./OsEID-tool DES-AES-UPLOAD-KEYS
+./OsEID-tool SYM-CRYPT-TEST
 popd
 
 # this does not work as we have random key IDs in here
diff -Nru opensc-0.22.0/.github/test-packit.sh opensc-0.23.0/.github/test-packit.sh
--- opensc-0.22.0/.github/test-packit.sh	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/.github/test-packit.sh	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+# Install build requirements
+REQUIREMENTS=$(sed -n -e '/^BuildRequires*/p' packaging/opensc.spec | sed 's/[^ ]* //')
+sudo dnf install -y ${REQUIREMENTS}
+
+# Run packit
+packit --debug build locally
diff -Nru opensc-0.22.0/.github/test-piv.sh opensc-0.23.0/.github/test-piv.sh
--- opensc-0.22.0/.github/test-piv.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/.github/test-piv.sh	2022-11-29 09:34:43.000000000 +0100
@@ -1,32 +1,39 @@
-#!/bin/bash -e
+#!/bin/bash
+
+set -ex -o xtrace
 
 # install the opensc
 sudo make install
 export LD_LIBRARY_PATH=/usr/local/lib
 
-# setup java stuff
+# setup java stuff and virutal smartcard
 . .github/setup-java.sh
 
 # The PIV Applet
-git clone --recursive https://github.com/arekinath/PivApplet.git
+if [ ! -d "PivApplet" ]; then
+	git clone --recursive https://github.com/arekinath/PivApplet.git
+fi
 pushd PivApplet
 JC_HOME=${JC_CLASSIC_HOME} ant dist
 popd
 
 # yubico-piv-tool is needed for PIV Applet management 
-git clone https://github.com/Yubico/yubico-piv-tool.git
+if [ ! -d "yubico-piv-tool" ]; then
+	git clone https://github.com/Yubico/yubico-piv-tool.git
+fi
 pushd yubico-piv-tool
-mkdir build
+if [ ! -d "build" ]; then
+	mkdir build
+fi
 pushd build
 cmake .. && make && sudo make install
+export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib/x86_64-linux-gnu
 popd
 popd
 
 
-# log errors from pcscd to console
-sudo systemctl stop pcscd.service pcscd.socket
-sudo /usr/sbin/pcscd -f &
-PCSCD_PID=$!
+# prepare pcscd
+. .github/restart-pcscd.sh
 
 
 # start the applet and run couple of commands against that
@@ -35,11 +42,15 @@
 sleep 5
 opensc-tool --card-driver default --send-apdu 80b80000120ba000000308000010000100050000020F0F7f
 opensc-tool -n
-yubico-piv-tool -v 9999 -r 'Virtual PCD 00 00' -P 123456 -s 9e -a generate -A RSA2048
-yubico-piv-tool -v 9999 -r 'Virtual PCD 00 00' -P 123456 -s 9a -a generate -A ECCP256
-pkcs11-tool -l -t -p 123456
-kill -9 $PID
 
+yubico-piv-tool -v 9999 -r 'Virtual PCD 00 00' -P 123456 -s 9e -a generate -A RSA2048 | tee 9e.pub
+yubico-piv-tool -v 9999 -r 'Virtual PCD 00 00' -P 123456 -s 9e -S'/CN=barCard/OU=test/O=example.com/' -averify -aselfsign < 9e.pub | tee 9e.cert
+yubico-piv-tool -v 9999 -r 'Virtual PCD 00 00' -P 123456 -s 9e -aimport-certificate <9e.cert
+
+yubico-piv-tool -v 9999 -r 'Virtual PCD 00 00' -P 123456 -s 9a -a generate -A ECCP256 | tee 9a.pub
+yubico-piv-tool -v 9999 -r 'Virtual PCD 00 00' -P 123456 -s 9a -S'/CN=bar/OU=test/O=example.com/' -averify -aselfsign < 9a.pub | tee 9e.cert
+yubico-piv-tool -v 9999 -r 'Virtual PCD 00 00' -P 123456 -s 9a -aimport-certificate < 9e.cert
 
-# cleanup
-sudo kill -9 $PCSCD_PID
+pkcs11-tool -l -O -p 123456
+pkcs11-tool -l -t -p 123456
+kill -9 $PID
diff -Nru opensc-0.22.0/.github/workflows/cifuzz.yml opensc-0.23.0/.github/workflows/cifuzz.yml
--- opensc-0.22.0/.github/workflows/cifuzz.yml	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/.github/workflows/cifuzz.yml	2022-11-29 09:34:43.000000000 +0100
@@ -4,6 +4,7 @@
     paths:
       - '**.c'
       - '**.h'
+      - .github/workflows/cifuzz.yml
 jobs:
  Fuzzing:
    runs-on: ubuntu-latest
diff -Nru opensc-0.22.0/.github/workflows/codeql.yml opensc-0.23.0/.github/workflows/codeql.yml
--- opensc-0.22.0/.github/workflows/codeql.yml	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/.github/workflows/codeql.yml	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,44 @@
+name: "CodeQL"
+
+on:
+  push:
+    branches: [ "master" ]
+  pull_request:
+    # The branches below must be a subset of the branches above
+    branches: [ "master" ]
+  schedule:
+    - cron: '30 16 * * 0'
+    
+permissions: {}
+jobs:
+  analyze:
+    name: Analyze
+    runs-on: ubuntu-latest
+    permissions:
+      actions: read
+      contents: read
+      security-events: write
+
+    strategy:
+      fail-fast: false
+      matrix:
+        language: [ 'cpp' ]
+
+    steps:
+    - name: Checkout repository
+      uses: actions/checkout at v3
+
+    # Initializes the CodeQL tools for scanning.
+    - name: Initialize CodeQL
+      uses: github/codeql-action/init at v2
+      with:
+        languages: ${{ matrix.language }}
+        config-file: ./.github/.codeql.yml
+        
+    - run: .github/setup-linux.sh
+    - run: .github/build.sh
+
+    - name: Perform CodeQL Analysis
+      uses: github/codeql-action/analyze at v2
+      with:
+        category: "/language:${{matrix.language}}"
diff -Nru opensc-0.22.0/.github/workflows/codespell.yml opensc-0.23.0/.github/workflows/codespell.yml
--- opensc-0.22.0/.github/workflows/codespell.yml	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/.github/workflows/codespell.yml	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,21 @@
+---
+name: Codespell
+
+on:
+  pull_request:
+  push:
+
+permissions:
+  contents: read  #  to fetch code (actions/checkout)
+
+jobs:
+  codespell:
+    name: Check for spelling errors
+    runs-on: ubuntu-latest
+
+    steps:
+      - uses: actions/checkout at v2
+      - uses: codespell-project/actions-codespell at master
+        with:
+          skip: compat_*
+          ignore_words_file: .github/codespell_ignore_words.txt
diff -Nru opensc-0.22.0/.github/workflows/coverity.yml opensc-0.23.0/.github/workflows/coverity.yml
--- opensc-0.22.0/.github/workflows/coverity.yml	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/.github/workflows/coverity.yml	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,25 @@
+name: Coverity CI
+
+# We only want to test master or explicitly via coverity branch
+on:
+  push:
+    branches: [master, coverity]
+
+
+permissions:
+  contents: read  #  to fetch code (actions/checkout)
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    steps:
+    - uses: actions/checkout at v2
+    - run: .github/setup-linux.sh
+    - run: ./bootstrap
+    - run: ./configure  --disable-dependency-tracking
+    - uses: vapier/coverity-scan-action at v0
+      with:
+        project: OpenSC%2FOpenSC
+        token: ${{ secrets.COVERITY_SCAN_TOKEN }}
+        email: 'viktor.tarasov at gmail.com'
+        command: 'make'
diff -Nru opensc-0.22.0/.github/workflows/linux.yml opensc-0.23.0/.github/workflows/linux.yml
--- opensc-0.22.0/.github/workflows/linux.yml	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/.github/workflows/linux.yml	2022-11-29 09:34:43.000000000 +0100
@@ -5,38 +5,55 @@
     paths:
       - '**.c'
       - '**.h'
+      - .github/workflows/linux.yml
+      - .github/setup-linux.sh
+      - .github/build.sh
+      - .github/push-artifacts.sh
+      - '**.am'
   push:
 
+permissions:
+  contents: read  #  to fetch code (actions/checkout)
+
 jobs:
   build:
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-20.04
     steps:
       - uses: actions/checkout at v2
       - run: .github/setup-linux.sh
       - run: .github/build.sh dist
+      - name: Upload test logs
+        uses: actions/upload-artifact at v2
+        if: failure()
+        with:
+          name: ubuntu-test-logs
+          path:
+            tests/*.log
       - uses: actions/cache at v2
         id: cache-build
         with:
           path: ./*
           key: ${{ runner.os }}-${{ github.sha }}
-      - name: Upload artifacts
+      - name: Upload build artifacts
         uses: actions/upload-artifact at v2
         with:
           name: opensc-build
           path:
             opensc*.tar.gz
 
-  build-ubuntu-18:
-    runs-on: ubuntu-18.04
+  build-no-shared:
+    runs-on: ubuntu-latest
     steps:
       - uses: actions/checkout at v2
       - run: .github/setup-linux.sh
-      - run: .github/build.sh
-      - uses: actions/cache at v2
-        id: cache-build
-        with:
-          path: ./*
-          key: ${{ runner.os }}-18-${{ github.sha }}
+      - run: .github/build.sh no-shared
+
+  build-ix86:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout at v2
+      - run: .github/setup-linux.sh ix86
+      - run: .github/build.sh ix86
 
   build-mingw:
     runs-on: ubuntu-latest
@@ -65,60 +82,59 @@
             win32/Output/OpenSC*.exe
 
   test-piv:
-    runs-on: ubuntu-18.04
-    needs: [build-ubuntu-18]
+    runs-on: ubuntu-20.04
+    needs: [build]
     steps:
       - uses: actions/checkout at v2
       - uses: actions/cache at v2
         id: cache-build
         with:
           path: ./*
-          key: ${{ runner.os }}-18-${{ github.sha }}
+          key: ${{ runner.os }}-${{ github.sha }}
       - run: .github/setup-linux.sh piv
       - run: .github/test-piv.sh
 
   test-isoapplet:
-    runs-on: ubuntu-18.04
-    needs: [build-ubuntu-18]
+    runs-on: ubuntu-20.04
+    needs: [build]
     steps:
       - uses: actions/checkout at v2
       - uses: actions/cache at v2
         id: cache-build
         with:
           path: ./*
-          key: ${{ runner.os }}-18-${{ github.sha }}
+          key: ${{ runner.os }}-${{ github.sha }}
       - run: .github/setup-linux.sh isoapplet
       - run: .github/test-isoapplet.sh
 
   test-gidsapplet:
-    runs-on: ubuntu-18.04
-    needs: [build-ubuntu-18]
+    runs-on: ubuntu-20.04
+    needs: [build]
     steps:
       - uses: actions/checkout at v2
       - uses: actions/cache at v2
         id: cache-build
         with:
           path: ./*
-          key: ${{ runner.os }}-18-${{ github.sha }}
+          key: ${{ runner.os }}-${{ github.sha }}
       - run: .github/setup-linux.sh gidsapplet
       - run: .github/test-gidsapplet.sh
 
   test-openpgp:
-    runs-on: ubuntu-18.04
-    needs: [build-ubuntu-18]
+    runs-on: ubuntu-20.04
+    needs: [build]
     steps:
       - uses: actions/checkout at v2
       - uses: actions/cache at v2
         id: cache-build
         with:
           path: ./*
-          key: ${{ runner.os }}-18-${{ github.sha }}
+          key: ${{ runner.os }}-${{ github.sha }}
       - run: .github/setup-linux.sh openpgp
-      # the openpgp sometimes fails
-      - run: .github/test-openpgp.sh || true
+      - run: .github/test-openpgp.sh
 
   build-clang-tidy:
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-20.04
     needs: [build]
     steps:
       - uses: actions/checkout at v2
@@ -131,7 +147,7 @@
       - run: .github/build.sh
 
   test-cac:
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-20.04
     needs: [build]
     steps:
       - uses: actions/checkout at v2
@@ -144,7 +160,7 @@
       - run: .github/test-cac.sh
 
   test-oseid:
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-20.04
     needs: [build]
     steps:
       - uses: actions/checkout at v2
@@ -156,6 +172,113 @@
       - run: .github/setup-linux.sh oseid
       - run: .github/test-oseid.sh
 
+  ############################################
+  ## Ubuntu 22.04 with OpenSSL 3.0 pipeline ##
+  ############################################
+  build-ubuntu-22:
+    runs-on: ubuntu-22.04
+    steps:
+      - uses: actions/checkout at v3
+      - run: .github/setup-linux.sh
+      - run: .github/build.sh dist
+      - uses: actions/upload-artifact at v3
+        if: failure()
+        with:
+          name: ubuntu-22-test-logs
+          path:
+            tests/*.log
+      - uses: actions/cache at v2
+        id: cache-build
+        if: ${{ success() }}
+        with:
+          path: ./*
+          key: ${{ runner.os }}-22-${{ github.sha }}
+      - name: Upload artifacts
+        uses: actions/upload-artifact at v2
+        if: ${{ success() }}
+        with:
+          name: opensc-build
+          path:
+            opensc*.tar.gz
+
+  test-cac-ubuntu-22:
+    runs-on: ubuntu-22.04
+    needs: [build-ubuntu-22]
+    steps:
+      - uses: actions/checkout at v3
+      - uses: actions/cache at v3
+        id: cache-build
+        with:
+          path: ./*
+          key: ${{ runner.os }}-22-${{ github.sha }}
+      - run: .github/setup-linux.sh cac
+      - run: .github/test-cac.sh
+
+  test-oseid-ubuntu-22:
+    runs-on: ubuntu-22.04
+    needs: [build-ubuntu-22]
+    steps:
+      - uses: actions/checkout at v3
+      - uses: actions/cache at v3
+        id: cache-build
+        with:
+          path: ./*
+          key: ${{ runner.os }}-22-${{ github.sha }}
+      - run: .github/setup-linux.sh oseid
+      - run: .github/test-oseid.sh
+
+  #######################
+  ## LibreSSL pipeline ##
+  #######################
+  build-libressl:
+    runs-on: ubuntu-latest
+    steps:
+      - uses: actions/checkout at v3
+      - run: .github/setup-linux.sh libressl
+      - run: .github/build.sh dist libressl
+      - uses: actions/upload-artifact at v3
+        if: failure()
+        with:
+          name: libressl-logs
+          path: |
+            tests/test-suite.log
+            config.log
+      - uses: actions/cache at v2
+        id: cache-build
+        if: ${{ success() }}
+        with:
+          path: ./*
+          key: ${{ runner.os }}-libressl-${{ github.sha }}
+
+  test-cac-libressl:
+    runs-on: ubuntu-latest
+    needs: [build-libressl]
+    steps:
+      - uses: actions/checkout at v3
+      - uses: actions/cache at v3
+        id: cache-build
+        with:
+          path: ./*
+          key: ${{ runner.os }}-libressl-${{ github.sha }}
+      - run: .github/setup-linux.sh cac libressl
+      - run: .github/test-cac.sh
+
+  test-oseid-libressl:
+    runs-on: ubuntu-latest
+    needs: [build-libressl]
+    steps:
+      - uses: actions/checkout at v3
+      - uses: actions/cache at v3
+        id: cache-build
+        with:
+          path: ./*
+          key: ${{ runner.os }}-libressl-${{ github.sha }}
+      - run: .github/setup-linux.sh oseid libressl
+      - run: .github/test-oseid.sh
+
+  ####################
+  ## Push artifacts ##
+  ####################
   push-artifacts:
     runs-on: ubuntu-latest
     needs: [build, build-mingw]
@@ -173,4 +296,4 @@
       - run: git config --global user.email "builds at github.com"
       - run: git config --global user.name "Github Actions";
       - run: .github/push_artifacts.sh "Github Actions ${GITHUB_REF}"
-        if: ${{ github.event_name != 'pull_request' && github.repository == 'OpenSC/OpenSC' }}
+        if: ${{ github.repository == 'OpenSC/OpenSC' }}
diff -Nru opensc-0.22.0/.github/workflows/macos.yml opensc-0.23.0/.github/workflows/macos.yml
--- opensc-0.22.0/.github/workflows/macos.yml	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/.github/workflows/macos.yml	2022-11-29 09:34:43.000000000 +0100
@@ -5,21 +5,43 @@
     paths:
       - '**.c'
       - '**.h'
+      - '**.m'
+      - .github/workflows/macos.yml
+      - .github/setup-macos.sh
+      - .github/cleanup-macos.sh
+      - .github/build.sh
+      - .github/push-artifacts.sh
+      - '**.am'
+      - MacOSX/**
   push:
 
+permissions:
+  contents: read  #  to fetch code (actions/checkout)
+
 jobs:
   build:
     runs-on: macos-latest
     steps:
       - uses: actions/checkout at v2
       - run: .github/setup-macos.sh
+        env:
+          KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
+          PASS_SECRETS_TAR_ENC: ${{ secrets.PASS_SECRETS_TAR_ENC }}
       - run: .github/build.sh
+        env:
+          CODE_SIGN_IDENTITY: ${{ secrets.CODE_SIGN_IDENTITY }}
+          DEVELOPMENT_TEAM: ${{ secrets.DEVELOPMENT_TEAM }}
+          INSTALLER_SIGN_IDENTITY: ${{ secrets.INSTALLER_SIGN_IDENTITY }}
       - name: Cache build artifacts
         uses: actions/upload-artifact at v2
         with:
           name: opensc-build-macos
           path:
             OpenSC*.dmg
+      - run: .github/cleanup-macos.sh
+        env:
+          KEY_PASSWORD: ${{ secrets.KEY_PASSWORD }}
+          PASS_SECRETS_TAR_ENC: ${{ secrets.PASS_SECRETS_TAR_ENC }}
 
   push-artifacts:
     runs-on: macos-latest
@@ -33,7 +55,4 @@
       - run: git config --global user.email "builds at github.com"
       - run: git config --global user.name "Github Actions";
       - run: .github/push_artifacts.sh "Github Actions ${GITHUB_REF}"
-        if: ${{ github.event_name != 'pull_request' && github.repository == 'OpenSC/OpenSC' }}
-# TODO this fails probably because the key is not loaded in keychain before with
-# security: SecKeychainDelete: The specified keychain could not be found.
-#      - run: .github/remove_signing_key.sh; rm -f .github/secrets.tar
+        if: ${{ github.repository == 'OpenSC/OpenSC' }}
diff -Nru opensc-0.22.0/.github/workflows/packit.yaml opensc-0.23.0/.github/workflows/packit.yaml
--- opensc-0.22.0/.github/workflows/packit.yaml	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/.github/workflows/packit.yaml	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,39 @@
+name: Packit
+on:
+  pull_request:
+    paths:
+      - '**.c'
+      - '**.h'
+      - '**.am'
+      - .github/workflows/packit.yaml
+  push:
+
+jobs:
+  packit_srpm:
+    runs-on: ubuntu-latest
+    name: Packit SRPM
+    steps:
+        - uses: actions/checkout at v3
+          with:
+              fetch-depth: 0
+        - uses: packit/actions/srpm at main
+        - name: Upload build artifacts
+          uses: actions/upload-artifact at v2
+          with:
+              name: opensc-srpm
+              path:
+                  opensc*.src.rpm
+  packit_rpm:
+    runs-on: ubuntu-latest
+    name: Packit RPM
+    steps:
+        - uses: actions/checkout at v3
+          with:
+              fetch-depth: 0
+        - uses: ./.github/actions/packit
+        - name: Upload build artifacts
+          uses: actions/upload-artifact at v2
+          with:
+              name: opensc-rpm
+              path:
+                  x86_64/opensc*.rpm
diff -Nru opensc-0.22.0/.gitignore opensc-0.23.0/.gitignore
--- opensc-0.22.0/.gitignore	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/.gitignore	2022-11-29 09:34:43.000000000 +0100
@@ -97,7 +97,7 @@
 win32/OpenSC.wixpdb
 
 MacOSX/build-package
-MacOSX/Distribution.xml
+MacOSX/Distribution*.xml
 
 *.dmg
 *.pkg
@@ -121,7 +121,11 @@
 src/tests/unittests/*.log
 src/tests/unittests/*.trs
 src/tests/unittests/asn1
+src/tests/unittests/cachedir
 src/tests/unittests/compression
+src/tests/unittests/openpgp-tool
+src/tests/unittests/pkcs15filter
 src/tests/unittests/simpletlv
+src/tests/unittests/sm
 
 version.m4.ci
diff -Nru opensc-0.22.0/.gitlab-ci.yml opensc-0.23.0/.gitlab-ci.yml
--- opensc-0.22.0/.gitlab-ci.yml	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/.gitlab-ci.yml	1970-01-01 01:00:00.000000000 +0100
@@ -1,126 +0,0 @@
-before_script:
-  # Avoid picking up PIV endpoint in CAC cards
-  - sed -e "/PIV-II/d" -i src/libopensc/ctx.c
-  # enable debug messages in the testsuite
-  - sed -e "s/^p11test_CFLAGS/#p11test_CFLAGS/g" -i src/tests/p11test/Makefile.am
-  - ./bootstrap
-  - ./configure
-  - make -j4
-  - make check
-  - make install
-  - ldconfig /usr/local/lib
-  - git clone https://github.com/PL4typus/virt_cacard.git
-  - cd virt_cacard && export CACARD_DIR=$PWD && ./autogen.sh && ./configure && make
-variables:
-  SOFTHSM2_CONF: softhsm2.conf
-  CNTNR_REGISTRY: pl4typus/opensc-images
-  FEDORA29_BUILD: fedora-29
-  FEDORA30_BUILD: fedora-30
-  UBUNTU_BUILD: ubuntu-18.04
-  DEBIAN_BUILD: debian-testing
-
-.job_base: &base_job
-  artifacts:
-    expire_in: '1 week'
-    when: on_failure
-    paths:
-      - src/tests/p11test/*.log
-
-.job_template: &functional_test
-  <<: *base_job
-  artifacts:
-    expire_in: '1 week'
-    when: on_failure
-    paths:
-      - src/tests/p11test/*.log
-      - src/tests/p11test/*.json
-      - tests/test-suite.log
-  cache:
-    paths:
-      - src/tests/p11test/*.json
-
-.virt_cacard: &virt_cacard
-  only:
-    - virt_cacard
-  script:
-    - ./setup-softhsm2.sh 
-    - cd ../src/tests/p11test/
-    - pcscd -x  
-    - ./p11test -s 0 -p 12345678 -o cac.json -i | tee cac.log &
-    - sleep 5
-    - cd $CACARD_DIR 
-    - ./virt_cacard & 
-    - cd ../src/tests/p11test/
-    - wait $(ps aux | grep '[p]11test'| awk '{print $2}')
-    - kill -9 $(ps aux | grep '[v]irt_cacard'| awk '{print $2}')
-    - if [[ -f cac_old.json ]]; then diff -u3 cac_old.json cac.json; fi
-    - cp cac.json cac_old.json
-    # cache the results for the next run
-  tags:
-    - shared
-
-.virt_cacard_valgrind: &virt_cacard_valgrind
-  only:
-    - virt_cacard
-  script:
-    - ./setup-softhsm2.sh 
-    - cd ../src/tests/p11test/
-    # remove the dlcose() calls to have reasonable traces
-    - sed '/if(pkcs11_so)/I {N;d;}' -i p11test_loader.c
-    - make
-    - pcscd -x  
-    - valgrind --leak-check=full --trace-children=yes --suppressions=p11test.supp ./p11test -s 0 -p 12345678 -i 2>&1| tee cac.log &
-    - sleep 5
-    - cd $CACARD_DIR
-    - ./virt_cacard &
-    - wait $(ps aux | grep '[v]algrind'| awk '{print $2}')
-    - kill -9 $(ps aux | grep '[v]irt_cacard'| awk '{print $2}')
-    - cd ../src/tests/p11test/
-    - grep "definitely lost:.*0 bytes in 0 blocks" cac.log
-  tags:
-    - shared
-
-################################
-##      Virtual CACard        ##
-################################
-
-Fedora29 Build and Test virt_cacard:
-  <<: *functional_test
-  image: $CI_REGISTRY/$CNTNR_REGISTRY/$FEDORA29_BUILD:latest
-  <<: *virt_cacard
-
-Fedora30 Build and Test virt_cacard:
-  <<: *functional_test
-  image: $CI_REGISTRY/$CNTNR_REGISTRY/$FEDORA30_BUILD:latest
-  <<: *virt_cacard
-
-Ubuntu18.04 Build and Test virt_cacard:
-  <<: *functional_test
-  image: $CI_REGISTRY/$CNTNR_REGISTRY/$UBUNTU_BUILD:latest
-  <<: *virt_cacard
-
-Debian-testing Build and Test virt_cacard:
-  <<: *functional_test
-  image: $CI_REGISTRY/$CNTNR_REGISTRY/$DEBIAN_BUILD:latest
-  <<: *virt_cacard
-
-Fedora29 Build and Test virt_cacard with valgrind:
-  <<: *base_job
-  image: $CI_REGISTRY/$CNTNR_REGISTRY/$FEDORA29_BUILD:latest
-  <<: *virt_cacard_valgrind
-
-Fedora30 Build and Test virt_cacard with valgrind:
-  <<: *base_job
-  image: $CI_REGISTRY/$CNTNR_REGISTRY/$FEDORA30_BUILD:latest
-  <<: *virt_cacard_valgrind
-
-Ubuntu18.04 Build and Test virt_cacard with valgrind:
-  <<: *base_job
-  image: $CI_REGISTRY/$CNTNR_REGISTRY/$UBUNTU_BUILD:latest
-  <<: *virt_cacard_valgrind
-
-Debian-testing Build and Test virt_cacard with valgrind:
-  <<: *base_job
-  image: $CI_REGISTRY/$CNTNR_REGISTRY/$DEBIAN_BUILD:latest
-  <<: *virt_cacard_valgrind
-
diff -Nru opensc-0.22.0/m4/version.m4 opensc-0.23.0/m4/version.m4
--- opensc-0.22.0/m4/version.m4	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/m4/version.m4	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,5 @@
+dnl version.m4 - source for version.m4.ci generated by bootstrap.ci
+dnl * bootstrap.ci generates version.m4.ci based on this file
+dnl * if version.m4.ci exists, it is included in configure.ac
+define([PACKAGE_SUFFIX], [])
+
diff -Nru opensc-0.22.0/MacOSX/build-package.in opensc-0.23.0/MacOSX/build-package.in
--- opensc-0.22.0/MacOSX/build-package.in	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/MacOSX/build-package.in	2022-11-29 09:34:43.000000000 +0100
@@ -58,12 +58,15 @@
 if test -n "${BUILD_ARM}"; then
 	export CFLAGS="$CFLAGS -arch x86_64 -arch arm64"
 	export LDFLAGS="$LDFLAGS -arch x86_64 -arch arm64"
+	DISTRIBUTION_XML=MacOSX/Distribution_universal.xml
+else
+	DISTRIBUTION_XML=MacOSX/Distribution.xml
 fi
 export OBJCFLAGS=$CFLAGS
 
 if ! test -e $BUILDPATH/openpace_bin/$PREFIX/lib/pkgconfig; then
 	if ! test -e openpace; then
-		git clone --depth=1 https://github.com/frankmorgner/openpace.git -b 1.1.1
+		git clone --depth=1 https://github.com/frankmorgner/openpace.git -b 1.1.2
 	fi
 	cd openpace
 	autoreconf -vis
@@ -108,7 +111,7 @@
 
 
 if ! test -e NotificationProxy; then
-	git clone http://github.com/frankmorgner/NotificationProxy.git
+	git clone https://github.com/frankmorgner/NotificationProxy.git
 fi
 if test -n "${CODE_SIGN_IDENTITY}" -a -n "${DEVELOPMENT_TEAM}"; then
 	xcodebuild -target NotificationProxy -configuration Release -project NotificationProxy/NotificationProxy.xcodeproj install DSTROOT=$BUILDPATH/target/Library/OpenSC/ \
@@ -127,7 +130,7 @@
 if (( $(xcodebuild -version | sed -En 's/Xcode[[:space:]]+([0-9]+)(\.[0-9]*)*/\1/p') < 10 )); then
 	# Check out OpenSC.tokend, if not already fetched.
 	if ! test -e OpenSC.tokend; then
-		git clone http://github.com/OpenSC/OpenSC.tokend.git
+		git clone https://github.com/OpenSC/OpenSC.tokend.git
 	fi
 
 	# Create the symlink to OpenSC sources
@@ -220,7 +223,7 @@
 pkgbuild --root ${BUILDPATH}/target_startup --component-plist MacOSX/target_startup.plist --identifier org.opensc-project.startup --version @PACKAGE_VERSION@ --install-location / OpenSC-startup.pkg
 
 # Build product
-productbuild --distribution MacOSX/Distribution.xml --package-path . --resources MacOSX/resources "${imagedir}/OpenSC @PACKAGE_VERSION at .pkg"
+productbuild --distribution $DISTRIBUTION_XML --package-path . --resources MacOSX/resources "${imagedir}/OpenSC @PACKAGE_VERSION at .pkg"
 
 # Sign installer
 if test -n "${INSTALLER_SIGN_IDENTITY}"; then
diff -Nru opensc-0.22.0/MacOSX/Distribution_universal.xml.in opensc-0.23.0/MacOSX/Distribution_universal.xml.in
--- opensc-0.22.0/MacOSX/Distribution_universal.xml.in	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/MacOSX/Distribution_universal.xml.in	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<!--
+https://developer.apple.com/library/mac/documentation/DeveloperTools/Reference/DistributionDefinitionRef/
+https://developer.apple.com/library/mac/documentation/DeveloperTools/Reference/InstallerJavaScriptRef/
+-->
+<installer-gui-script minSpecVersion="2">
+    <allowed-os-versions>
+      <os-version min="10.10"/>
+    </allowed-os-versions>
+    <background file="background.jpg" mime-type="image/jpeg" scaling="tofit"/>
+    <welcome file="Welcome.html" mime-type="text/html"/>
+    <title>@PACKAGE_STRING@</title>
+    <options customize="allow" hostArchitectures="arm64,x86_64" require-scripts="false" rootVolumeOnly="true"/>
+    <script>
+      <![CDATA[
+    function osx_before_catalina() {
+      return system.compareVersions(system.version.ProductVersion, '10.15') < 0;
+    }
+    function osx_after_catalina() {
+      return system.compareVersions(system.version.ProductVersion, '10.15') >= 0;
+    }
+    function osx_after_yosemite() {
+      return system.compareVersions(system.version.ProductVersion, '10.12') >= 0;
+    }
+      ]]>
+    </script>
+    <choices-outline>
+        <line choice="default" />
+        <line choice="startup" />
+        <line choice="tokend" />
+        <line choice="token" />
+    </choices-outline>
+    <choice id="default" title="PKCS#11 module and smart card tools" enabled="false">
+        <pkg-ref id="org.opensc-project.mac">OpenSC.pkg</pkg-ref>
+    </choice>
+    <choice id="tokend" title="TokenD-based smart card driver" start_selected="osx_before_catalina()">
+        <pkg-ref id="org.opensc-project.tokend">OpenSC-tokend.pkg</pkg-ref>
+    </choice>
+    <choice id="token" title="CryptoTokenKit-based smart card driver" visible="osx_after_yosemite()" start_selected="osx_after_catalina()">
+        <pkg-ref id="org.opensc-project.mac.opensctoken">OpenSCToken.pkg</pkg-ref>
+    </choice>
+    <choice id="startup" title="Automatic startup items">
+        <pkg-ref id="org.opensc-project.startup">OpenSC-startup.pkg</pkg-ref>
+    </choice>
+</installer-gui-script>
diff -Nru opensc-0.22.0/MacOSX/Distribution.xml.in opensc-0.23.0/MacOSX/Distribution.xml.in
--- opensc-0.22.0/MacOSX/Distribution.xml.in	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/MacOSX/Distribution.xml.in	2022-11-29 09:34:43.000000000 +0100
@@ -1,6 +1,7 @@
 <?xml version="1.0" encoding="utf-8" standalone="no"?>
 <!--
 https://developer.apple.com/library/mac/documentation/DeveloperTools/Reference/DistributionDefinitionRef/
+https://developer.apple.com/library/mac/documentation/DeveloperTools/Reference/InstallerJavaScriptRef/
 -->
 <installer-gui-script minSpecVersion="2">
     <allowed-os-versions>
@@ -12,36 +13,15 @@
     <options customize="allow" require-scripts="false" rootVolumeOnly="true"/>
     <script>
       <![CDATA[
-	function osx_before_catalina() {
-	 if((system.compareVersions(system.version.ProductVersion, '10.15')) == -1)
-	 {
-	  return true;
-	 }
-	 else
-	 {
-	  return false;
-	 }
-	}
-	function osx_after_catalina() {
-	 if((system.compareVersions(system.version.ProductVersion, '10.15')) >= 0)
-	 {
-	  return true;
-	 }
-	 else
-	 {
-	  return false;
-	 }
-	}
-	function osx_after_yosemite() {
-	 if((system.compareVersions(system.version.ProductVersion, '10.12')) >= 0)
-	 {
-	  return true;
-	 }
-	 else
-	 {
-	  return false;
-	 }
-	}
+    function osx_before_catalina() {
+      return system.compareVersions(system.version.ProductVersion, '10.15') < 0;
+    }
+    function osx_after_catalina() {
+      return system.compareVersions(system.version.ProductVersion, '10.15') >= 0;
+    }
+    function osx_after_yosemite() {
+      return system.compareVersions(system.version.ProductVersion, '10.12') >= 0;
+    }
       ]]>
     </script>
     <choices-outline>
diff -Nru opensc-0.22.0/MacOSX/Makefile.am opensc-0.23.0/MacOSX/Makefile.am
--- opensc-0.22.0/MacOSX/Makefile.am	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/MacOSX/Makefile.am	2022-11-29 09:34:43.000000000 +0100
@@ -1,5 +1,10 @@
 MAINTAINERCLEANFILES = $(srcdir)/Makefile.in
-EXTRA_DIST = build build-package.in Distribution.xml.in libtool-bundle opensc-uninstall \
+EXTRA_DIST = build \
+	build-package.in \
+	Distribution.xml.in \
+	Distribution_universal.xml.in \
+	libtool-bundle \
+	opensc-uninstall \
 	resources \
 	resources/background.jpg \
 	resources/Welcome.html.in \
diff -Nru opensc-0.22.0/MacOSX/opensc-uninstall opensc-0.23.0/MacOSX/opensc-uninstall
--- opensc-0.22.0/MacOSX/opensc-uninstall	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/MacOSX/opensc-uninstall	2022-11-29 09:34:43.000000000 +0100
@@ -32,13 +32,17 @@
 rm -rf "/Applications/Utilities/OpenSC Notify.app"
 rm -rf /Library/OpenSC
 rm -rf /Library/Security/tokend/OpenSC.tokend
-rm -f  /Library/LaunchAgents/pkcs11-register.plist
-rm -f  /Library/LaunchAgents/opensc-notify.plist
+rm -f  /Library/LaunchAgents/org.opensc-project.mac.pkcs11-register.plist
+rm -f  /Library/LaunchAgents/org.opensc-project.mac.opensc-notify.plist
 rm -rf /System/Library/Security/tokend/OpenSC.tokend
 
-# Unload launchagents
-launchctl remove pkcs11-register
-launchctl remove opensc-notify
+# Remove LaunchAgents
+for label in \
+  org.opensc-project.mac.pkcs11-register \
+  org.opensc-project.mac.opensc-notify
+do
+  launchctl asuser "$(id -u "${SUDO_USER:-$USER}")" launchctl remove "$label"
+done
 
 # delete receipts on 10.6+
 pkgutil --forget org.opensc-project.mac             > /dev/null 2>/dev/null
diff -Nru opensc-0.22.0/NEWS opensc-0.23.0/NEWS
--- opensc-0.22.0/NEWS	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/NEWS	2022-11-29 09:34:43.000000000 +0100
@@ -1,5 +1,74 @@
 NEWS for OpenSC -- History of user visible changes
 
+# New in 0.23.0; 2022-11-29
+## General improvements
+* Support signing of data with a length of more than 512 bytes (#2314)
+* By default, disable support for old card drivers (#2391) and remove support for old drivers MioCOS and JCOP (#2374)
+* Bump minimal required OpenSSL version to 1.1.1 and add support for OpenSSL 3.0 (#2438, #2506)
+* Compatibility with LibreSSL (#2495, #2595)
+* Remove support for DSA (#2503)
+* Extend p11test to support symmetric keys (#2430)
+* Notice detached reader on macOS (#2418)
+* Support for OAEP padding (#2475, #2484)
+* Fix for PSS salt length (#2478)
+* Improve fuzzing by adding new tests (#2417, #2500, #2520, #2550, #2637)
+* Fixed various issues reported by OSS-Fuzz and Coverity regarding card drivers, PKCS#11 and PKCS#15 init
+* Fix issues with OpenPACE (#2472)
+* Containers support for local testing
+* Add support for encryption and decryption using symmetric keys (#2473, #2607)
+* Stop building support for Gost algorithms with OpenSSL 3.0 as they require deprecated API (#2586)
+* Fix detection of disconnected readers in PCSC (#2600)
+* Add configuration option for on-disk caching of private data (#2588)
+* Skip building empty binaries when dependencies are missing and remove needless linking (#2617)
+* Define arm64 as a supported architecture in the Installer package (#2610)
+## PKCS#11
+* Implement `C_CreateObject` for EC keys and fix signature verification for `CKM_ECDSA_SHAx` cards (#2420)
+## pkcs11-tool
+* Add more elliptic curves (#2301)
+* Add support for symmetric encrypt and decrypt, wrap and unwrap operations, and initialization vector (#2268)
+* Fix consistent handling of secret key attributes (#2497)
+* Add support for signing and verifying with HMAC (#2385)
+* Add support for SHA3 (#2467)
+* Make object selectable via label (#2570)
+* Do not require an R/W session for some operations and add `--session-rw` option (#2579)
+* Print more information: CKA_UNIQUE_ID attribute, SHA3 HMACs and serial number for certificates (#2644, #2643, #2641)
+* Add new option --undestroyable to create keys with CKA_DESTROYABLE=FALSE (#2645)
+## sc-hsm-tool
+* Add options for public key authentication (#2301)
+## Minidriver
+* Fix reinit of the card (#2525)
+* Add an entry for Italian CNS (e) (#2548)
+* Fix detection of ECC mechanisms (#2523)
+* Fix ATRs before adding them to the windows registry (#2628)
+## NQ-Applet
+* Add support for the JCOP4 Cards with NQ-Applet (#2425)
+## ItaCNS
+* Add support for ItaCMS v1.1 (key length 2048) (#2371)
+## Belpic
+* Add support for applet v1.8 (#2455)
+## Starcos
+* Add ATR for V3.4 (#2464)
+* Add PKCS#15 emulator for 3.x cards with eSign app (#2544)
+## ePass2003
+* Fix PKCS#15 initialization (#2403)
+* Add support for FIPS (#2543)
+* Fix matching with newer versions and tokens initialized with OpenSC (#2575)
+## MyEID
+* Support logout operation (#2557)
+* Support for symmetric encryption and decryption (#2473, #2607)
+## GIDS
+* Fix decipher for TPM (#1881)
+## OpenPGP
+* Get the list of supported algorithms from algorithm information on the card (#2287)
+* Support for 3 certificates with OpenPGP 3+ (#2103)
+## nPA
+* Fix card detection (#2463)
+## Rutoken
+* Fix formatting rtecp cards (#2599)
+## PIV
+* Add new PIVKey ATRs for current cards (#2602)
+
+
 # New in 0.22.0; 2021-08-10
 ## General improvements
  * Use standard paths for file cache on Linux (#2148) and OSX (#2214)
@@ -7,7 +76,7 @@
  * Add threading test to `pkcs11-tool` (#2067)
  * Add support to generate generic secret keys (#2140)
  * `opensc-explorer`: Print information about LCS (Life cycle status byte) (#2195)
- * Add support for Apple's arm64 (M1) binaries, removed TokenD. A seperate installer with TokenD (and without arm64 binaries) will be available (#2179).
+ * Add support for Apple's arm64 (M1) binaries, removed TokenD. A separate installer with TokenD (and without arm64 binaries) will be available (#2179).
  * Support for gcc11 and its new strict aliasing rules (#2241, #2260)
  * Initial support for building with OpenSSL 3.0 (#2343)
  * pkcs15-tool: Write data objects in binary mode (#2324)
@@ -262,7 +331,7 @@
     * added support for reading ECDSA ssh keys
 * `p11test`
     *  Filter certificates other than `CKC_X_509`
-* `opengpg-tool`
+* `openpgp-tool`
     * allow calling -d multiple times
     * clarify usage text
 ## sc-hsm
diff -Nru opensc-0.22.0/packaging/opensc.module opensc-0.23.0/packaging/opensc.module
--- opensc-0.22.0/packaging/opensc.module	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/packaging/opensc.module	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,9 @@
+# This file describes how to load the opensc module
+# See: https://p11-glue.github.io/p11-glue/p11-kit/manual/pkcs11-conf.html
+# or man pkcs11.conf
+
+# This is a relative path, which means it will be loaded from
+# the p11-kit default path which is usually $(libdir)/pkcs11.
+# Doing it this way allows for packagers to package opensc for
+# 32-bit and 64-bit and make them parallel installable
+module: opensc-pkcs11.so
diff -Nru opensc-0.22.0/packaging/opensc.spec opensc-0.23.0/packaging/opensc.spec
--- opensc-0.22.0/packaging/opensc.spec	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/packaging/opensc.spec	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,190 @@
+Name:           opensc
+Version:        0.1.0
+Release:        1%{?dist}
+Summary:        Smart card library and applications
+
+License:        LGPLv2+
+URL:            https://github.com/OpenSC/OpenSC/wiki
+Source0:        opensc-0.1.0.tar.gz
+Source1:        opensc.module
+
+BuildRequires:  make
+BuildRequires:  pcsc-lite-devel
+BuildRequires:  readline-devel
+BuildRequires:  openssl-devel
+BuildRequires:  /usr/bin/xsltproc
+BuildRequires:  docbook-style-xsl
+BuildRequires:  autoconf automake libtool gcc
+BuildRequires:  bash-completion
+BuildRequires:  zlib-devel
+# For tests
+BuildRequires:  libcmocka-devel
+BuildRequires:  softhsm
+BuildRequires:  openssl
+Requires:       pcsc-lite-libs%{?_isa}
+Requires:       pcsc-lite
+Obsoletes:      mozilla-opensc-signer < 0.12.0
+Obsoletes:      opensc-devel < 0.12.0
+Obsoletes:      coolkey <= 1.1.0-36
+# The simclist is bundled in upstream
+Provides:       bundled(simclist) = 1.5
+
+%description
+OpenSC provides a set of libraries and utilities to work with smart cards. Its
+main focus is on cards that support cryptographic operations, and facilitate
+their use in security applications such as authentication, mail encryption and
+digital signatures. OpenSC implements the PKCS#11 API so applications
+supporting this API (such as Mozilla Firefox and Thunderbird) can use it. On
+the card OpenSC implements the PKCS#15 standard and aims to be compatible with
+every software/card that does so, too.
+
+
+%prep
+%setup -q
+
+# The test-pkcs11-tool-allowed-mechanisms already works in Fedora
+sed -i -e '/XFAIL_TESTS/,$ {
+  s/XFAIL_TESTS.*/XFAIL_TESTS=test-pkcs11-tool-test-threads.sh test-pkcs11-tool-test.sh test-pkcs11-tool-unwrap-wrap-test.sh/
+  q
+}' tests/Makefile.am
+
+
+cp -p src/pkcs15init/README ./README.pkcs15init
+cp -p src/scconf/README.scconf .
+# No {_libdir} here to avoid multilib conflicts; it's just an example
+sed -i -e 's|/usr/local/towitoko/lib/|/usr/lib/ctapi/|' etc/opensc.conf.example.in
+
+
+%build
+autoreconf -fvi
+%ifarch %{ix86}
+sed -i -e 's/opensc.conf/opensc-%{_arch}.conf/g' src/libopensc/Makefile.in
+%endif
+sed -i -e 's|"/lib /usr/lib\b|"/%{_lib} %{_libdir}|' configure # lib64 rpaths
+%set_build_flags
+CFLAGS="$CFLAGS -Wstrict-aliasing=2 -Wno-deprecated-declarations"
+%configure --disable-static\
+  --disable-autostart-items \
+  --disable-notify \
+  --disable-assert \
+  --enable-pcsc \
+  --enable-cmocka \
+  --enable-sm \
+  --with-pcsc-provider=libpcsclite.so.1
+%make_build
+
+
+%check
+make check
+
+
+%install
+%make_install
+install -Dpm 644 %{SOURCE1} $RPM_BUILD_ROOT%{_datadir}/p11-kit/modules/opensc.module
+
+%ifarch %{ix86}
+# To avoid multilib issues, move these files on 32b intel architectures
+rm -f $RPM_BUILD_ROOT%{_sysconfdir}/opensc.conf
+install -Dpm 644 etc/opensc.conf $RPM_BUILD_ROOT%{_sysconfdir}/opensc-%{_arch}.conf
+rm -f $RPM_BUILD_ROOT%{_mandir}/man5/opensc.conf.5
+install -Dpm 644 doc/files/opensc.conf.5 $RPM_BUILD_ROOT%{_mandir}/man5/opensc-%{_arch}.conf.5
+# use NEWS file timestamp as reference for configuration file
+touch -r NEWS $RPM_BUILD_ROOT%{_sysconfdir}/opensc-%{_arch}.conf
+touch -r NEWS $RPM_BUILD_ROOT%{_mandir}/man5/opensc-%{_arch}.conf.5
+%else
+# For backward compatibility, symlink the old location to the new files
+ln -s %{_sysconfdir}/opensc.conf $RPM_BUILD_ROOT%{_sysconfdir}/opensc-%{_arch}.conf
+%endif
+
+find $RPM_BUILD_ROOT%{_libdir} -type f -name "*.la" | xargs rm
+
+rm -rf $RPM_BUILD_ROOT%{_datadir}/doc/opensc
+
+# Upstream considers libopensc API internal and no longer ships
+# public headers and pkgconfig files.
+# Remove the symlink as nothing is supposed to link against libopensc.
+rm -f $RPM_BUILD_ROOT%{_libdir}/libopensc.so
+# remove the .pc file so we do not confuse users #1673139
+rm -f $RPM_BUILD_ROOT%{_libdir}/pkgconfig/*.pc
+rm -f $RPM_BUILD_ROOT%{_libdir}/libsmm-local.so
+
+# the npa-tool builds to nothing since we do not have OpenPACE library
+rm -rf %{buildroot}%{_bindir}/npa-tool
+rm -rf %{buildroot}%{_mandir}/man1/npa-tool.1*
+
+# the pkcs11-register is not applicable to Fedora/RHEL where we use p11-kit
+rm -rf %{buildroot}%{_bindir}/pkcs11-register
+rm -rf %{buildroot}%{_mandir}/man1/pkcs11-register.1*
+
+# Remove the notification files
+rm %{buildroot}%{_datadir}/applications/org.opensc.notify.desktop
+rm %{buildroot}%{_mandir}/man1/opensc-notify.1*
+
+
+%files
+%doc COPYING NEWS README*
+
+%{_datadir}/bash-completion/*
+
+%ifarch %{ix86}
+%{_mandir}/man5/opensc-%{_arch}.conf.5*
+%else
+%config(noreplace) %{_sysconfdir}/opensc.conf
+%{_mandir}/man5/opensc.conf.5*
+%endif
+
+%config(noreplace) %{_sysconfdir}/opensc-%{_arch}.conf
+# Co-owned with p11-kit so it is not hard dependency
+%dir %{_datadir}/p11-kit
+%dir %{_datadir}/p11-kit/modules
+%{_datadir}/p11-kit/modules/opensc.module
+%{_bindir}/cardos-tool
+%{_bindir}/cryptoflex-tool
+%{_bindir}/eidenv
+%{_bindir}/iasecc-tool
+%{_bindir}/gids-tool
+%{_bindir}/netkey-tool
+%{_bindir}/openpgp-tool
+%{_bindir}/opensc-explorer
+%{_bindir}/opensc-tool
+%{_bindir}/opensc-asn1
+%{_bindir}/piv-tool
+%{_bindir}/pkcs11-tool
+%{_bindir}/pkcs15-crypt
+%{_bindir}/pkcs15-init
+%{_bindir}/pkcs15-tool
+%{_bindir}/sc-hsm-tool
+%{_bindir}/dnie-tool
+%{_bindir}/westcos-tool
+%{_bindir}/egk-tool
+%{_bindir}/goid-tool
+%{_libdir}/lib*.so.*
+%{_libdir}/opensc-pkcs11.so
+%{_libdir}/pkcs11-spy.so
+%{_libdir}/onepin-opensc-pkcs11.so
+%dir %{_libdir}/pkcs11
+%{_libdir}/pkcs11/opensc-pkcs11.so
+%{_libdir}/pkcs11/onepin-opensc-pkcs11.so
+%{_libdir}/pkcs11/pkcs11-spy.so
+%{_datadir}/opensc/
+%{_mandir}/man1/cardos-tool.1*
+%{_mandir}/man1/cryptoflex-tool.1*
+%{_mandir}/man1/eidenv.1*
+%{_mandir}/man1/gids-tool.1*
+%{_mandir}/man1/goid-tool.1*
+%{_mandir}/man1/iasecc-tool.1*
+%{_mandir}/man1/netkey-tool.1*
+%{_mandir}/man1/openpgp-tool.1*
+%{_mandir}/man1/opensc-explorer.*
+%{_mandir}/man1/opensc-tool.1*
+%{_mandir}/man1/opensc-asn1.1*
+%{_mandir}/man1/piv-tool.1*
+%{_mandir}/man1/pkcs11-tool.1*
+%{_mandir}/man1/pkcs15-crypt.1*
+%{_mandir}/man1/pkcs15-init.1*
+%{_mandir}/man1/pkcs15-tool.1*
+%{_mandir}/man1/sc-hsm-tool.1*
+%{_mandir}/man1/westcos-tool.1*
+%{_mandir}/man1/dnie-tool.1*
+%{_mandir}/man1/egk-tool.1*
+%{_mandir}/man5/pkcs15-profile.5*
diff -Nru opensc-0.22.0/.packit.yaml opensc-0.23.0/.packit.yaml
--- opensc-0.22.0/.packit.yaml	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/.packit.yaml	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,23 @@
+upstream_project_url: https://github.com/OpenSC/OpenSC
+
+specfile_path: packaging/opensc.spec
+files_to_sync:
+  - packaging/opensc.spec
+  - .packit.yaml
+upstream_package_name: opensc
+downstream_package_name: opensc
+merge_pr_in_ci: false
+
+notifications:
+  pull_request:
+    successful_build: true
+
+jobs:
+- job: copr_build
+  trigger: pull_request
+  metadata:
+    targets:
+    - fedora-development-x86_64
+    - fedora-development-aarch64
+    - fedora-development-ppc64le
+    - fedora-development-s390x
diff -Nru opensc-0.22.0/README opensc-0.23.0/README
--- opensc-0.22.0/README	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/README	2022-11-29 09:34:43.000000000 +0100
@@ -4,11 +4,32 @@
 
 Please take a look at the documentation before trying to use OpenSC.
 
+Do NOT use any links from wiki to download the OpenSC because wiki can be modified by anybody, see
+[#2554](https://github.com/OpenSC/OpenSC/issues/2554). For downloading OpenSC, use the links here in README.
+
+# Downloads
+
+[OpenSC 0.22.0](https://github.com/OpenSC/OpenSC/releases/tag/0.22.0) is the latest stable version released on 10.08.2021. It is available as
+
+ * Windows installer
+   * [OpenSC-0.22.0_win64.msi](https://github.com/OpenSC/OpenSC/releases/download/0.22.0/OpenSC-0.22.0_win64.msi) for 64 bit programs
+   * [OpenSC-0.22.0_win32.msi](https://github.com/OpenSC/OpenSC/releases/download/0.22.0/OpenSC-0.22.0_win32.msi) for 32 bit programs
+ * [OpenSC-0.22.0.dmg](https://github.com/OpenSC/OpenSC/releases/download/0.22.0/OpenSC-0.22.0.dmg): macOS installer
+ * [opensc-0.22.0.tar.gz](https://github.com/OpenSC/OpenSC/releases/download/0.22.0/opensc-0.22.0.tar.gz): Source code distribution
+
+## Nightly build
+
+The latest source code is available through [GitHub](https://github.com/OpenSC/OpenSC/archive/master.zip).
+Nightly builds are available by their git hash in branches of [OpenSC/Nightly](https://github.com/OpenSC/Nightly).
+
+
+# Build and testing status
+
 [![Linux build](https://github.com/OpenSC/OpenSC/actions/workflows/linux.yml/badge.svg)](https://github.com/OpenSC/OpenSC/actions/workflows/linux.yml)
 [![OSX build](https://github.com/OpenSC/OpenSC/actions/workflows/macos.yml/badge.svg)](https://github.com/OpenSC/OpenSC/actions/workflows/macos.yml)
 [![AppVeyor CI Build Status](https://ci.appveyor.com/api/projects/status/github/OpenSC/OpenSC?branch=master&svg=true)](https://ci.appveyor.com/project/LudovicRousseau/OpenSC/branch/master)
 [![Coverity Scan Status](https://scan.coverity.com/projects/4026/badge.svg)](https://scan.coverity.com/projects/4026)
-[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/OpenSC/OpenSC.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/OpenSC/OpenSC/context:cpp)
+[![CodeQL](https://github.com/OpenSC/OpenSC/actions/workflows/codeql.yml/badge.svg?event=push)](https://github.com/OpenSC/OpenSC/actions/workflows/codeql.yml)
 [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/opensc.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:opensc)
 [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3908/badge)](https://bestpractices.coreinfrastructure.org/projects/3908)
 
diff -Nru opensc-0.22.0/README.md opensc-0.23.0/README.md
--- opensc-0.22.0/README.md	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/README.md	2022-11-29 09:34:43.000000000 +0100
@@ -4,11 +4,32 @@
 
 Please take a look at the documentation before trying to use OpenSC.
 
+Do NOT use any links from wiki to download the OpenSC because wiki can be modified by anybody, see
+[#2554](https://github.com/OpenSC/OpenSC/issues/2554). For downloading OpenSC, use the links here in README.
+
+# Downloads
+
+[OpenSC 0.22.0](https://github.com/OpenSC/OpenSC/releases/tag/0.22.0) is the latest stable version released on 10.08.2021. It is available as
+
+ * Windows installer
+   * [OpenSC-0.22.0_win64.msi](https://github.com/OpenSC/OpenSC/releases/download/0.22.0/OpenSC-0.22.0_win64.msi) for 64 bit programs
+   * [OpenSC-0.22.0_win32.msi](https://github.com/OpenSC/OpenSC/releases/download/0.22.0/OpenSC-0.22.0_win32.msi) for 32 bit programs
+ * [OpenSC-0.22.0.dmg](https://github.com/OpenSC/OpenSC/releases/download/0.22.0/OpenSC-0.22.0.dmg): macOS installer
+ * [opensc-0.22.0.tar.gz](https://github.com/OpenSC/OpenSC/releases/download/0.22.0/opensc-0.22.0.tar.gz): Source code distribution
+
+## Nightly build
+
+The latest source code is available through [GitHub](https://github.com/OpenSC/OpenSC/archive/master.zip).
+Nightly builds are available by their git hash in branches of [OpenSC/Nightly](https://github.com/OpenSC/Nightly).
+
+
+# Build and testing status
+
 [![Linux build](https://github.com/OpenSC/OpenSC/actions/workflows/linux.yml/badge.svg)](https://github.com/OpenSC/OpenSC/actions/workflows/linux.yml)
 [![OSX build](https://github.com/OpenSC/OpenSC/actions/workflows/macos.yml/badge.svg)](https://github.com/OpenSC/OpenSC/actions/workflows/macos.yml)
 [![AppVeyor CI Build Status](https://ci.appveyor.com/api/projects/status/github/OpenSC/OpenSC?branch=master&svg=true)](https://ci.appveyor.com/project/LudovicRousseau/OpenSC/branch/master)
 [![Coverity Scan Status](https://scan.coverity.com/projects/4026/badge.svg)](https://scan.coverity.com/projects/4026)
-[![Language grade: C/C++](https://img.shields.io/lgtm/grade/cpp/g/OpenSC/OpenSC.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/OpenSC/OpenSC/context:cpp)
+[![CodeQL](https://github.com/OpenSC/OpenSC/actions/workflows/codeql.yml/badge.svg?event=push)](https://github.com/OpenSC/OpenSC/actions/workflows/codeql.yml)
 [![Fuzzing Status](https://oss-fuzz-build-logs.storage.googleapis.com/badges/opensc.svg)](https://bugs.chromium.org/p/oss-fuzz/issues/list?sort=-opened&can=1&q=proj:opensc)
 [![CII Best Practices](https://bestpractices.coreinfrastructure.org/projects/3908/badge)](https://bestpractices.coreinfrastructure.org/projects/3908)
 
diff -Nru opensc-0.22.0/src/common/libscdl.c opensc-0.23.0/src/common/libscdl.c
--- opensc-0.22.0/src/common/libscdl.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/common/libscdl.c	2022-11-29 09:34:43.000000000 +0100
@@ -26,9 +26,12 @@
 
 #ifdef _WIN32
 #include <windows.h>
+#include <shlwapi.h>
+
 void *sc_dlopen(const char *filename)
 {
-	return (void *)LoadLibraryA(filename);
+	DWORD flags = PathIsRelativeA(filename) ? 0 : LOAD_WITH_ALTERED_SEARCH_PATH;
+	return (void *)LoadLibraryExA(filename, NULL, flags);
 }
 
 void *sc_dlsym(void *handle, const char *symbol)
diff -Nru opensc-0.22.0/src/common/Makefile.am opensc-0.23.0/src/common/Makefile.am
--- opensc-0.22.0/src/common/Makefile.am	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/common/Makefile.am	2022-11-29 09:34:43.000000000 +0100
@@ -28,6 +28,7 @@
 libpkcs11_la_SOURCES = libpkcs11.c
 
 libscdl_la_SOURCES = libscdl.c
+libscdl_la_LIBADD = $(LDL_LIBS)
 
 TIDY_FLAGS = $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
 TIDY_FILES = \
diff -Nru opensc-0.22.0/src/libopensc/apdu.c opensc-0.23.0/src/libopensc/apdu.c
--- opensc-0.22.0/src/libopensc/apdu.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/apdu.c	2022-11-29 09:34:43.000000000 +0100
@@ -455,6 +455,10 @@
 		unsigned char resp[256];
 		size_t resp_len = le;
 
+		/* we have all the data the caller requested even if the card has more data */
+		if (buflen == 0)
+			break;
+
 		/* call GET RESPONSE to get more date from the card;
 		 * note: GET RESPONSE returns the left amount of data (== SW2) */
 		memset(resp, 0, sizeof(resp));
@@ -478,10 +482,6 @@
 		buf    += le;
 		buflen -= le;
 
-		/* we have all the data the caller requested even if the card has more data */
-		if (buflen == 0)
-			break;
-
 		minlen -= le;
 		if (rv != 0)
 			le = minlen = (size_t)rv;
@@ -521,18 +521,20 @@
 	 * 1. the card returned 0x6Cxx: in this case APDU will be re-transmitted with Le set to SW2
 	 * (possible only if response buffer size is larger than new Le = SW2)
 	 */
-	if (apdu->sw1 == 0x6C && (apdu->flags & SC_APDU_FLAGS_NO_RETRY_WL) == 0)
+	if (apdu->sw1 == 0x6C && (apdu->flags & SC_APDU_FLAGS_NO_RETRY_WL) == 0) {
 		r = sc_set_le_and_transmit(card, apdu, olen);
-	LOG_TEST_RET(ctx, r, "cannot re-transmit APDU ");
+		LOG_TEST_RET(ctx, r, "cannot re-transmit APDU ");
+	}
 
 	/* 2. the card returned 0x61xx: more data can be read from the card
 	 *    using the GET RESPONSE command (mostly used in the T0 protocol).
 	 *    Unless the SC_APDU_FLAGS_NO_GET_RESP is set we try to read as
 	 *    much data as possible using GET RESPONSE.
 	 */
-	if (apdu->sw1 == 0x61 && (apdu->flags & SC_APDU_FLAGS_NO_GET_RESP) == 0)
+	if (apdu->sw1 == 0x61 && (apdu->flags & SC_APDU_FLAGS_NO_GET_RESP) == 0) {
 		r = sc_get_response(card, apdu, olen);
-	LOG_TEST_RET(ctx, r, "cannot get all data with 'GET RESPONSE'");
+		LOG_TEST_RET(ctx, r, "cannot get all data with 'GET RESPONSE'");
+	}
 
 	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
 }
diff -Nru opensc-0.22.0/src/libopensc/asn1.c opensc-0.23.0/src/libopensc/asn1.c
--- opensc-0.22.0/src/libopensc/asn1.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/asn1.c	2022-11-29 09:34:43.000000000 +0100
@@ -1679,6 +1679,38 @@
 	return 0;
 }
 
+static void sc_free_entry(struct sc_asn1_entry *asn1) {
+	int idx = 0;
+	struct sc_asn1_entry *entry = asn1;
+
+	if (!asn1)
+		return;
+
+	for (idx = 0; asn1[idx].name != NULL; idx++) {
+		entry = &asn1[idx];
+		switch (entry->type) {
+		case SC_ASN1_CHOICE:
+		case SC_ASN1_STRUCT:
+			sc_free_entry((struct sc_asn1_entry *) entry->parm);
+			break;
+		case SC_ASN1_OCTET_STRING:
+		case SC_ASN1_BIT_STRING_NI:
+		case SC_ASN1_BIT_STRING:
+		case SC_ASN1_GENERALIZEDTIME:
+		case SC_ASN1_PRINTABLESTRING:
+		case SC_ASN1_UTF8STRING:
+			if ((entry->flags & SC_ASN1_ALLOC) && (entry->flags & SC_ASN1_PRESENT)) {
+				u8 **buf = (u8 **)entry->parm;
+				free(*buf);
+				*buf = NULL;
+			}
+			break;
+		default:
+			break;
+		}
+	}
+}
+
 static int asn1_decode(sc_context_t *ctx, struct sc_asn1_entry *asn1,
 		       const u8 *in, size_t len, const u8 **newp, size_t *len_left,
 		       int choice, int depth)
@@ -1689,7 +1721,7 @@
 	size_t left = len, objlen;
 
 	sc_debug(ctx, SC_LOG_DEBUG_ASN1,
-		 "%*.*scalled, left=%"SC_FORMAT_LEN_SIZE_T"u, depth %d%s\n",
+		 "%*.*s""called, left=%"SC_FORMAT_LEN_SIZE_T"u, depth %d%s\n",
 		 depth, depth, "", left, depth, choice ? ", choice" : "");
 
 	if (!p)
@@ -1745,6 +1777,7 @@
 				}
 				sc_debug(ctx, SC_LOG_DEBUG_ASN1, "next tag: %s\n", line);
 			}
+			sc_free_entry(asn1);
 			SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_ASN1, SC_ERROR_ASN1_OBJECT_NOT_FOUND);
 		}
 		r = asn1_decode_entry(ctx, entry, obj, objlen, depth);
@@ -2061,7 +2094,7 @@
 int
 sc_der_copy(sc_pkcs15_der_t *dst, const sc_pkcs15_der_t *src)
 {
-	if (!dst)
+	if (!dst || !src)
 		return SC_ERROR_INVALID_ARGUMENTS;
 	memset(dst, 0, sizeof(*dst));
 	if (src->len) {
@@ -2192,3 +2225,53 @@
 
 	LOG_FUNC_RETURN(ctx, rv);
 }
+
+int sc_asn1_decode_ecdsa_signature(sc_context_t *ctx, const u8 *data, size_t datalen, size_t fieldsize, u8 **out, size_t outlen) {
+	int i, r;
+	const unsigned char *pseq, *pint, *pend;
+	unsigned int cla, tag;
+	size_t seqlen, intlen;
+
+	if (!ctx || !data || !out || !(*out)) {
+		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
+	}
+	if (outlen < 2 * fieldsize) {
+		LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Output too small for EC signature");
+	}
+
+	memset(*out, 0, outlen);
+
+	pseq = data;
+	r = sc_asn1_read_tag(&pseq, datalen, &cla, &tag, &seqlen);
+	if (pseq == NULL || r < 0 || seqlen == 0 || (cla | tag) != 0x30)
+		LOG_TEST_RET(ctx, SC_ERROR_INVALID_DATA, "Can not find 0x30 tag");
+
+	pint = pseq;
+	pend = pseq + seqlen;
+	for (i = 0; i < 2; i++) {
+		r = sc_asn1_read_tag(&pint, (pend - pint), &cla, &tag, &intlen);
+		if (pint == NULL || r < 0 || intlen == 0 || (cla | tag) != 0x02) {
+			r = SC_ERROR_INVALID_DATA;
+			LOG_TEST_GOTO_ERR(ctx, SC_ERROR_INVALID_DATA, "Can not find 0x02");
+		}
+
+		if (intlen == fieldsize + 1) { /* drop leading 00 if present */
+			if (*pint != 0x00) {
+				r = SC_ERROR_INVALID_DATA;
+				LOG_TEST_GOTO_ERR(ctx, SC_ERROR_INVALID_DATA, "Signature too long");
+			}
+			pint++;
+			intlen--;
+		}
+		if (intlen > fieldsize) {
+			r = SC_ERROR_INVALID_DATA;
+			LOG_TEST_GOTO_ERR(ctx, SC_ERROR_INVALID_DATA, "Signature too long");
+		}
+		memcpy(*out + fieldsize * i + fieldsize - intlen , pint, intlen);
+		pint += intlen; /* next integer */
+	}
+	r = 2 * fieldsize;
+err:
+	LOG_FUNC_RETURN(ctx, r);
+}
+
diff -Nru opensc-0.22.0/src/libopensc/asn1.h opensc-0.23.0/src/libopensc/asn1.h
--- opensc-0.22.0/src/libopensc/asn1.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/asn1.h	2022-11-29 09:34:43.000000000 +0100
@@ -127,6 +127,10 @@
 		const unsigned char *in, size_t inlen,
                 unsigned char *buf, size_t buflen);
 
+/* ECDSA signature decoding*/
+int sc_asn1_decode_ecdsa_signature(sc_context_t *ctx, const u8 *data, size_t datalen,
+		size_t fieldsize, u8 **out, size_t outlen);
+
 /* long form tags use these */
 /* Same as  SC_ASN1_TAG_* shifted left by 24 bits  */
 #define SC_ASN1_CLASS_MASK		0xC0000000
diff -Nru opensc-0.22.0/src/libopensc/base64.c opensc-0.23.0/src/libopensc/base64.c
--- opensc-0.22.0/src/libopensc/base64.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/base64.c	2022-11-29 09:34:43.000000000 +0100
@@ -150,8 +150,8 @@
 
 int sc_base64_decode(const char *in, u8 *out, size_t outlen)
 {
-	int len = 0, r, skip;
-	unsigned int i;
+	int len = 0, r = 0, skip = 0;
+	unsigned int i = 0;
 
 	while ((r = from_base64(in, &i, &skip)) > 0) {
 		int finished = 0, s = 16;
diff -Nru opensc-0.22.0/src/libopensc/card-atrust-acos.c opensc-0.23.0/src/libopensc/card-atrust-acos.c
--- opensc-0.22.0/src/libopensc/card-atrust-acos.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-atrust-acos.c	2022-11-29 09:34:43.000000000 +0100
@@ -721,7 +721,7 @@
 				flags = SC_ALGORITHM_RSA_HASH_NONE;
 			tmp_len = sizeof(sbuf);
 			r = sc_pkcs1_encode(card->ctx, flags, data, datalen,
-					sbuf, &tmp_len, sizeof(sbuf)*8);
+					sbuf, &tmp_len, sizeof(sbuf)*8, NULL);
 			if (r < 0)
 				return r;
 		} else {
diff -Nru opensc-0.22.0/src/libopensc/card-authentic.c opensc-0.23.0/src/libopensc/card-authentic.c
--- opensc-0.22.0/src/libopensc/card-authentic.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-authentic.c	2022-11-29 09:34:43.000000000 +0100
@@ -152,9 +152,9 @@
 
 
 static int
-authentic_parse_size(unsigned char *in, size_t *out)
+authentic_parse_size(unsigned char *in, size_t in_len, size_t *out)
 {
-	if (!in || !out)
+	if (!in || !out || in_len < 1)
 		return SC_ERROR_INVALID_ARGUMENTS;
 
 	if (*in < 0x80)   {
@@ -162,10 +162,14 @@
 		return 1;
 	}
 	else if (*in == 0x81)   {
+		if (in_len < 2)
+			return SC_ERROR_INVALID_DATA;
 		*out = *(in + 1);
 		return 2;
 	}
 	else if (*in == 0x82)   {
+		if (in_len < 3)
+			return SC_ERROR_INVALID_DATA;
 		*out = *(in + 1) * 0x100 + *(in + 2);
 		return 3;
 	}
@@ -194,10 +198,16 @@
 			tag_len = 1;
 		}
 
-		size_len = authentic_parse_size(in + offs + tag_len, &size);
+		if (offs + tag_len >= in_len)
+			LOG_TEST_RET(ctx, SC_ERROR_INTERNAL, "parse error: invalid data");
+
+		size_len = authentic_parse_size(in + offs + tag_len, in_len - (offs + tag_len), &size);
 		LOG_TEST_RET(ctx, size_len, "parse error: invalid size data");
 
 		if (tag == in_tag)   {
+			if (offs + tag_len + size_len >= in_len)
+				LOG_TEST_RET(ctx, SC_ERROR_INTERNAL, "parse error: invalid data");
+
 			*out = in + offs + tag_len + size_len;
 			*out_len = size;
 
diff -Nru opensc-0.22.0/src/libopensc/card-belpic.c opensc-0.23.0/src/libopensc/card-belpic.c
--- opensc-0.22.0/src/libopensc/card-belpic.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-belpic.c	2022-11-29 09:34:43.000000000 +0100
@@ -111,7 +111,7 @@
 /* Data in the return value for the GET CARD DATA command:
  * All fields are one byte, except when noted otherwise.
  *
- * See §6.9 in
+ * See §6.9 in
  * https://github.com/Fedict/eid-mw/blob/master/doc/sdk/documentation/Public_Belpic_Applet_v1%207_Ref_Manual%20-%20A01.pdf
  * for the full documentation on the GET CARD DATA command.
  */
@@ -146,6 +146,8 @@
 static size_t next_idx = (size_t)-1;
 
 static const struct sc_atr_table belpic_atrs[] = {
+	/* Applet V1.8 */
+	{ "3B:7F:96:00:00:80:31:80:65:B0:85:04:01:20:12:0F:FF:82:90:00", NULL, NULL, SC_CARD_TYPE_BELPIC_EID, 0, NULL },
 	/* Applet V1.1 */
 	{ "3B:98:13:40:0A:A5:03:01:01:01:AD:13:11", NULL, NULL, SC_CARD_TYPE_BELPIC_EID, 0, NULL },
 	/* Applet V1.0 with new EMV-compatible ATR */
@@ -193,7 +195,7 @@
 		return r;
 	}
 	if(apdu.resplen < carddataloc_len) {
-		sc_log(card->ctx, 
+		sc_log(card->ctx,
 			 "GetCardData: card returned %"SC_FORMAT_LEN_SIZE_T"u bytes rather than expected %d\n",
 			 apdu.resplen, carddataloc_len);
 		return SC_ERROR_WRONG_LENGTH;
diff -Nru opensc-0.22.0/src/libopensc/card.c opensc-0.23.0/src/libopensc/card.c
--- opensc-0.22.0/src/libopensc/card.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card.c	2022-11-29 09:34:43.000000000 +0100
@@ -413,8 +413,6 @@
 	ctx = card->ctx;
 	LOG_FUNC_CALLED(ctx);
 
-	if (card->lock_count != 0)
-		return SC_ERROR_NOT_ALLOWED;
 	if (card->ops->finish) {
 		int r = card->ops->finish(card);
 		if (r)
@@ -507,8 +505,17 @@
 	}
 
 	/* give card driver a chance to do something when reader lock first obtained */
-	if (r == 0 && reader_lock_obtained == 1  && card->ops->card_reader_lock_obtained)
+	if (r == 0 && reader_lock_obtained == 1  && card->ops->card_reader_lock_obtained) {
 		r = card->ops->card_reader_lock_obtained(card, was_reset);
+		/* return value of card->reader->ops->lock is overwritten here
+		   by card->ops->card_reader_lock_obtained */
+		if (r != 0) {
+			/* unlock reader and get the card to its original state in case of failure*/
+			if (card->reader->ops->unlock != NULL)
+				r = card->reader->ops->unlock(card->reader);
+			card->lock_count--;
+		}
+	}
 
 	LOG_FUNC_RETURN(card->ctx, r);
 }
@@ -1154,16 +1161,13 @@
 
 		if (info->algorithm != algorithm)
 			continue;
-		if (param)   {
-			if (info->algorithm == SC_ALGORITHM_EC ||
-				info->algorithm == SC_ALGORITHM_EDDSA ||
-				info->algorithm == SC_ALGORITHM_XEDDSA)
-				if (sc_compare_oid((struct sc_object_id *)param, &info->u._ec.params.id))
-					return info;
-		}
-		if (info->key_length != key_length)
-			continue;
-		return info;
+		if (param && (info->algorithm == SC_ALGORITHM_EC ||
+			info->algorithm == SC_ALGORITHM_EDDSA ||
+			info->algorithm == SC_ALGORITHM_XEDDSA)) {
+			if (sc_compare_oid((struct sc_object_id *)param, &info->u._ec.params.id))
+				return info;
+		} else if (info->key_length == key_length)
+			return info;
 	}
 	return NULL;
 }
@@ -1455,8 +1459,10 @@
 	dst->id = src->id;
 	if (src->der.value && src->der.len)   {
 		dst->der.value = malloc(src->der.len);
-		if (!dst->der.value)
+		if (!dst->der.value) {
+			free(dst->named_curve);
 			return SC_ERROR_OUT_OF_MEMORY;
+		}
 		memcpy(dst->der.value, src->der.value, src->der.len);
 		dst->der.len = src->der.len;
 	}
diff -Nru opensc-0.22.0/src/libopensc/card-cardos.c opensc-0.23.0/src/libopensc/card-cardos.c
--- opensc-0.22.0/src/libopensc/card-cardos.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-cardos.c	2022-11-29 09:34:43.000000000 +0100
@@ -496,7 +496,7 @@
 {
 	sc_apdu_t apdu;
 	u8        rbuf[256], offset = 0;
-	const u8  *p = rbuf, *q;
+	const u8  *p, *q, *tag;
 	int       r;
 	size_t    fids = 0, len;
 
@@ -521,19 +521,22 @@
 		sc_log(card->ctx,  "directory listing > 256 bytes, cutting");
 	}
 
+	p = rbuf;
 	len = apdu.resplen;
 	while (len != 0) {
 		size_t   tlen = 0, ilen = 0;
 		/* is there a file information block (0x6f) ? */
-		p = sc_asn1_find_tag(card->ctx, p, len, 0x6f, &tlen);
-		if (p == NULL) {
+		tag = sc_asn1_find_tag(card->ctx, p, len, 0x6f, &tlen);
+		if (tag == NULL) {
 			sc_log(card->ctx,  "directory tag missing");
 			return SC_ERROR_INTERNAL;
 		}
+		len = len - tlen - (tag - p);
+		p = tag + tlen;
 		if (tlen == 0)
 			/* empty directory */
 			break;
-		q = sc_asn1_find_tag(card->ctx, p, tlen, 0x86, &ilen);
+		q = sc_asn1_find_tag(card->ctx, tag, tlen, 0x86, &ilen);
 		if (q == NULL || ilen != 2) {
 			sc_log(card->ctx,  "error parsing file id TLV object");
 			return SC_ERROR_INTERNAL;
@@ -547,13 +550,11 @@
 			/* not enough space left in buffer => break */
 			break;
 		/* extract next offset */
-		q = sc_asn1_find_tag(card->ctx, p, tlen, 0x8a, &ilen);
+		q = sc_asn1_find_tag(card->ctx, tag, tlen, 0x8a, &ilen);
 		if (q != NULL && ilen == 1) {
 			offset = (u8)ilen;
 			goto get_next_part;
 		}
-		len -= tlen + 2;
-		p   += tlen;
 	}
 
 	r = fids;
diff -Nru opensc-0.22.0/src/libopensc/cardctl.h opensc-0.23.0/src/libopensc/cardctl.h
--- opensc-0.22.0/src/libopensc/cardctl.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/cardctl.h	2022-11-29 09:34:43.000000000 +0100
@@ -2,6 +2,7 @@
  * cardctl.h: card_ctl command numbers
  *
  * Copyright (C) 2003  Olaf Kirch <okir at lse.de>
+ * Copyright (C) 2018-2019 GSMK - Gesellschaft für Sichere Mobile Kommunikation mbH
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -63,12 +64,6 @@
 	SC_CARDCTL_CRYPTOFLEX_GENERATE_KEY,
 
 	/*
-	 * MioCOS specific calls
-	 */
-	SC_CARDCTL_MIOCOS_BASE = _CTL_PREFIX('M', 'I', 'O'),
-	SC_CARDCTL_MIOCOS_CREATE_AC,
-
-	/*
 	 * TCOS specific calls
 	 */
 	SC_CARDCTL_TCOS_BASE = _CTL_PREFIX('T','C','S'),
@@ -95,12 +90,6 @@
 	SC_CARDCTL_STARCOS_GENERATE_KEY,
 
 	/*
-	 * JCOP specific calls
-	 */
-	SC_CARDCTL_JCOP_BASE = _CTL_PREFIX('J', 'C', 'P'),
-	SC_CARDCTL_JCOP_GENERATE_KEY,
-
-	/*
 	 * Oberthur specific calls
 	 */
 	SC_CARDCTL_OBERTHUR_BASE = _CTL_PREFIX('O', 'B', 'R'),
@@ -263,6 +252,7 @@
 	SC_CARDCTL_OPENPGP_BASE = _CTL_PREFIX('P', 'G', 'P'),
 	SC_CARDCTL_OPENPGP_GENERATE_KEY,
 	SC_CARDCTL_OPENPGP_STORE_KEY,
+	SC_CARDCTL_OPENPGP_SELECT_DATA,
 
 	/*
 	 * SmartCard-HSM
@@ -273,6 +263,8 @@
 	SC_CARDCTL_SC_HSM_IMPORT_DKEK_SHARE,
 	SC_CARDCTL_SC_HSM_WRAP_KEY,
 	SC_CARDCTL_SC_HSM_UNWRAP_KEY,
+	SC_CARDCTL_SC_HSM_REGISTER_PUBLIC_KEY,
+	SC_CARDCTL_SC_HSM_PUBLIC_KEY_AUTH_STATUS,
 
 	/*
 	 * DNIe specific calls
@@ -394,26 +386,6 @@
 	unsigned int		pubkey_len;
 };
 
-enum {
-	SC_CARDCTL_MIOCOS_AC_PIN,
-	SC_CARDCTL_MIOCOS_AC_CHAL,
-	SC_CARDCTL_MIOCOS_AC_LOGICAL,
-	SC_CARDCTL_MIOCOS_AC_SMARTPIN
-};
-
-/*
- * MioCOS AC info
- */
-struct sc_cardctl_miocos_ac_info {
-	int type;
-	int ref;
-	int max_tries;
-	int enable_ac;		/* only applicable to PINs */
-	u8 key_value[8];
-	int max_unblock_tries;	/* same here */
-	u8 unblock_value[8];	/* and here */
-};
-
 /*
  * Siemens CardOS PIN info
  */
@@ -501,14 +473,6 @@
 	u8	*modulus;
 } sc_starcos_gen_key_data;
 
-struct sc_cardctl_jcop_genkey  {
-     unsigned long exponent;
-     sc_path_t pub_file_ref;
-     sc_path_t pri_file_ref;
-     unsigned char *	pubkey;
-     unsigned int	pubkey_len;
-};
-
 /*
  * Oberthur ex_data stuff
  */
@@ -518,8 +482,6 @@
 	SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC = 0xA1,
 	SC_CARDCTL_OBERTHUR_KEY_RSA_SFM,
 	SC_CARDCTL_OBERTHUR_KEY_RSA_CRT,
-	SC_CARDCTL_OBERTHUR_KEY_DSA_PUBLIC,
-	SC_CARDCTL_OBERTHUR_KEY_DSA_PRIVATE,
 	SC_CARDCTL_OBERTHUR_KEY_EC_CRT,
 	SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC
 };
@@ -1057,6 +1019,8 @@
 	struct sc_aid bio2;			/* AID of biometric server for template 2 */
 	u8 options[2];				/* Initialization options */
 	signed char dkek_shares;	/* Number of DKEK shares, 0 for card generated, -1 for none */
+	signed char num_of_pub_keys;         /* Total number of public keys used for public authentication (if > 0) */
+	u8 required_pub_keys;       /* Number of public keys required for authentication (if public auth. is used) */
 	char *label;				/* Token label to be set in EF.TokenInfo (2F03) */
 } sc_cardctl_sc_hsm_init_param_t;
 
@@ -1074,6 +1038,19 @@
 	size_t wrapped_key_length;	/* Length of key blob */
 } sc_cardctl_sc_hsm_wrapped_key_t;
 
+typedef struct sc_cardctl_sc_hsm_pka_status {
+    u8 num_total;
+    u8 num_missing;
+    u8 num_required;
+    u8 num_authenticated;
+} sc_cardctl_sc_hsm_pka_status_t;
+
+typedef struct sc_cardctl_sc_hsm_pka_register {
+    u8 *buf;
+    size_t buflen;
+    sc_cardctl_sc_hsm_pka_status_t new_status;
+} sc_cardctl_sc_hsm_pka_register_t;
+
 /*
  * isoApplet
  */
diff -Nru opensc-0.22.0/src/libopensc/card-dnie.c opensc-0.23.0/src/libopensc/card-dnie.c
--- opensc-0.22.0/src/libopensc/card-dnie.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-dnie.c	2022-11-29 09:34:43.000000000 +0100
@@ -1444,7 +1444,6 @@
 		case SC_ALGORITHM_RSA:
 			result = SC_SUCCESS;
 			break;
-		case SC_ALGORITHM_DSA:
 		case SC_ALGORITHM_EC:
 		case SC_ALGORITHM_GOSTR3410:
 		default:
diff -Nru opensc-0.22.0/src/libopensc/card-edo.c opensc-0.23.0/src/libopensc/card-edo.c
--- opensc-0.22.0/src/libopensc/card-edo.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-edo.c	2022-11-29 09:34:43.000000000 +0100
@@ -59,16 +59,6 @@
 };
 
 
-static void edo_eac_init() {
-	extern void EAC_init(void);
-	static int initialized = 0;
-	if (!initialized) {
-		EAC_init();
-		initialized = 1;
-	}
-}
-
-
 static int edo_match_card(sc_card_t* card) {
 	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
 	if (_sc_match_atr(card, edo_atrs, &card->type) >= 0) {
@@ -291,8 +281,6 @@
 static int edo_init(sc_card_t* card) {
 	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
 
-	edo_eac_init();
-
 	memset(&card->sm_ctx, 0, sizeof card->sm_ctx);
 
 	card->max_send_size = SC_MAX_APDU_RESP_SIZE;
diff -Nru opensc-0.22.0/src/libopensc/card-epass2003.c opensc-0.23.0/src/libopensc/card-epass2003.c
--- opensc-0.22.0/src/libopensc/card-epass2003.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-epass2003.c	2022-11-29 09:34:43.000000000 +0100
@@ -41,15 +41,28 @@
 
 #include <openssl/evp.h>
 #include <openssl/sha.h>
+#include <openssl/cmac.h>
 
 #include "internal.h"
 #include "asn1.h"
 #include "cardctl.h"
 
+/*
+ * See https://github.com/OpenSC/OpenSC/issues/2572
+ * 2012 ATR: note version 01:00:11
+ *        3b:9f:95:81:31:fe:9f:00:66:46:53:05:01:00:11:71:df:00:00:03:90:00:80
+ * 2022 ATRs: note version 23:00:25
+ *   OpenSC-initialized ATR:
+ *        3b 9f:95:81:31:fe:9f:00:66:46:53:05:23:00:25:71:df:00:00:03:90:00:96
+ *   Feitian-initalized ATR:
+ *        3b:9f:95:81:31:fe:9f:00:66:46:53:05:23:00:25:71:df:00:00:00:00:00:05
+ */
+
 static const struct sc_atr_table epass2003_atrs[] = {
 	/* This is a FIPS certified card using SCP01 security messaging. */
-	{"3B:9F:95:81:31:FE:9F:00:66:46:53:05:10:00:11:71:df:00:00:00:6a:82:5e",
-	 "FF:FF:FF:FF:FF:00:FF:FF:FF:FF:FF:FF:00:00:00:ff:00:ff:ff:00:00:00:00",
+	/* will match all the above */
+	{"3B:9F:95:81:31:FE:9F:00:66:46:53:05:00:00:00:71:df:00:00:00:00:00:00",
+	 "FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00:00:FF:FF:FF:FF:00:00:00:00",
 	 "FTCOS/ePass2003", SC_CARD_TYPE_ENTERSAFE_FTCOS_EPASS2003, 0, NULL },
 	{NULL, NULL, NULL, 0, 0, NULL}
 };
@@ -98,6 +111,7 @@
 	unsigned char sk_enc[16];	/* encrypt session key */
 	unsigned char sk_mac[16];	/* mac session key */
 	unsigned char icv_mac[16];	/* instruction counter vector(for sm) */
+	unsigned char bFipsCertification;	/* fips mode Alg */
 	unsigned char currAlg;		/* current Alg */
 	unsigned int  ecAlgFlags; 	/* Ec Alg mechanism type*/
 } epass2003_exdata;
@@ -169,6 +183,58 @@
 	{ 0x9000,SC_SUCCESS,                       NULL }
 };
 
+typedef struct sec_attr_to_acl_entries {
+	unsigned int file_type;		/* file->type */
+	unsigned int file_ef_structure;	/* file->ef_structure */
+	int indx;			/* index in  epass2003 iversion of sec_attr */
+	/* use the follow for sc_file_add_entry */
+	int op;				/* SC_AC_OP_* */
+} sec_attr_to_acl_entries_t;
+
+/* Known combinations of file type and methods. More can be added as needed */
+static const sec_attr_to_acl_entries_t sec_attr_to_acl_entry[] = {
+	{SC_FILE_TYPE_DF, 0, 0,				SC_AC_OP_LIST_FILES},
+	{SC_FILE_TYPE_DF, 0, 1,				SC_AC_OP_CREATE},
+	{SC_FILE_TYPE_DF, 0, 3,				SC_AC_OP_DELETE},
+
+	{SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_TRANSPARENT, 0,  SC_AC_OP_READ},
+	{SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_TRANSPARENT, 1,  SC_AC_OP_UPDATE},
+	{SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_TRANSPARENT, 3,  SC_AC_OP_DELETE},
+
+	{SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_TRANSPARENT, 0,  SC_AC_OP_READ},
+	{SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_TRANSPARENT, 1,  SC_AC_OP_UPDATE},
+	{SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_TRANSPARENT, 3,  SC_AC_OP_DELETE},
+
+	{SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_LINEAR_FIXED, 0,  SC_AC_OP_READ},
+	{SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_LINEAR_FIXED, 1,  SC_AC_OP_UPDATE},
+	{SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_LINEAR_FIXED, 2,  SC_AC_OP_WRITE},
+	{SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_LINEAR_FIXED, 3,  SC_AC_OP_DELETE},
+
+	{SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_LINEAR_VARIABLE, 0,  SC_AC_OP_READ},
+	{SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_LINEAR_VARIABLE, 1,  SC_AC_OP_UPDATE},
+	{SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_LINEAR_VARIABLE, 2,  SC_AC_OP_WRITE},
+	{SC_FILE_TYPE_WORKING_EF, SC_FILE_EF_LINEAR_VARIABLE, 3,  SC_AC_OP_DELETE},
+
+	{SC_FILE_TYPE_BSO, 0, 0,				SC_AC_OP_UPDATE},
+	{SC_FILE_TYPE_BSO, 0, 3,				SC_AC_OP_DELETE},
+
+	{SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_RSA_CRT, 1,	SC_AC_OP_UPDATE},
+	{SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_EC_CRT,  1,	SC_AC_OP_UPDATE},
+	{SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_RSA_CRT, 2,	SC_AC_OP_CRYPTO},
+	{SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_EC_CRT,  2,	SC_AC_OP_CRYPTO},
+	{SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_RSA_CRT, 3,	SC_AC_OP_DELETE},
+	{SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_EC_CRT,  3,	SC_AC_OP_DELETE},
+
+	{SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC, 0, SC_AC_OP_READ},
+	{SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC,  0, SC_AC_OP_READ},
+	{SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC, 1, SC_AC_OP_UPDATE},
+	{SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC,  1, SC_AC_OP_UPDATE},
+	{SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC, 2, SC_AC_OP_CRYPTO},
+	{SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC,  2, SC_AC_OP_CRYPTO},
+	{SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC, 3, SC_AC_OP_DELETE},
+	{SC_FILE_TYPE_INTERNAL_EF, SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC,  3, SC_AC_OP_DELETE},
+};
+
 static int epass2003_transmit_apdu(struct sc_card *card, struct sc_apdu *apdu);
 static int epass2003_select_file(struct sc_card *card, const sc_path_t * in_path, sc_file_t ** file_out);
 int epass2003_refresh(struct sc_card *card);
@@ -270,6 +336,124 @@
 	return r;
 }
 
+static int
+aes128_encrypt_cmac_ft(const unsigned char *key, int keysize,
+        const unsigned char *input, size_t length, unsigned char *output,unsigned char *iv) 
+{
+	unsigned char data1[32] = {0}; 
+	unsigned char data2[32] = {0}; 
+	unsigned char k1Bin[32] = {0}; 
+	unsigned char k2Bin[32] = {0}; 
+
+	unsigned char check = 0; 
+	BIGNUM *enc1,*lenc1; 
+	BIGNUM *enc2,*lenc2; 
+
+    // k1
+	int offset = 0; 
+	int r = SC_ERROR_INTERNAL;
+	unsigned char out[32] = {0}; 
+	unsigned char iv0[EVP_MAX_IV_LENGTH] = {0}; 
+	r = openssl_enc(EVP_aes_128_ecb(), key, iv0, data1, 16, out);
+	if( r != SC_SUCCESS)
+		return r;
+	
+	check = out[0];
+	enc1 = BN_new();
+	lenc1 = BN_new();
+	BN_bin2bn(out,16,enc1);
+	BN_lshift1(lenc1,enc1);
+	BN_bn2bin(lenc1,k1Bin);
+	if(check > 0x80){
+		offset = 1; 
+		k1Bin[15+offset] ^= 0x87; 
+	}
+	BN_free(enc1);
+	BN_free(lenc1);
+
+    // k2
+	enc2 = BN_new();
+	lenc2 = BN_new();
+	check = k1Bin[offset];
+	BN_bin2bn(&k1Bin[offset],16,enc2);
+
+	offset = 0;
+	BN_lshift1(lenc2,enc2);
+	BN_bn2bin(lenc2,k2Bin);
+	if(check > 0x80){
+		offset = 1;
+		k2Bin[15+offset] ^= 0x87;
+	}
+	BN_free(enc2);
+	BN_free(lenc2);
+    //padding 
+	if(length < 16){
+		memcpy(&data2[0],input,length);
+		data2[length] = 0x80;
+	}
+
+    //k2 xor padded data
+	for (int i=0;i<16;i++){
+		data2[i]=data2[i]^k2Bin[offset + i];
+	}
+	return openssl_enc(EVP_aes_128_cbc(), key, iv, data2, 16, output);
+}
+
+static int
+aes128_encrypt_cmac(const unsigned char *key, int keysize,
+        const unsigned char *input, size_t length, unsigned char *output)
+{
+	size_t mactlen = 0;
+	int r = SC_ERROR_INTERNAL;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	CMAC_CTX *ctx = CMAC_CTX_new();
+	if(ctx == NULL) {
+		return SC_ERROR_INTERNAL;
+	}
+	
+	if(!CMAC_Init(ctx, key,keysize/8, EVP_aes_128_cbc(), NULL)) {
+		goto err;
+	}
+	if(!CMAC_Update(ctx, input, length)) {
+		goto err;
+	}
+	if(!CMAC_Final(ctx, output, &mactlen)) {
+		goto err;
+	}
+	r = SC_SUCCESS;
+err:
+	CMAC_CTX_free(ctx);
+#else
+	EVP_MAC *mac = EVP_MAC_fetch(NULL, "cmac", NULL);
+	if(mac == NULL){    
+		return r;
+	}
+
+	OSSL_PARAM params[2] = {0}; 
+	params[0] = OSSL_PARAM_construct_utf8_string("cipher","aes-128-cbc", 0);
+	params[1] = OSSL_PARAM_construct_end();
+
+	EVP_MAC_CTX *ctx = EVP_MAC_CTX_new(mac);
+	if(ctx == NULL){
+		EVP_MAC_CTX_free(ctx);
+		return r;
+	}    
+	if(!EVP_MAC_init(ctx, (const unsigned char *)key, keysize/8,params)){
+		goto err;
+	}
+	if(!EVP_MAC_update(ctx, input,length)){
+		goto err; 
+	}
+	if(!EVP_MAC_final(ctx, output, &mactlen, 16)) {    
+		goto err; 
+	}    
+	r = SC_SUCCESS;
+err:
+	EVP_MAC_CTX_free(ctx);
+	EVP_MAC_free(mac);
+#endif
+	return r;
+}
 
 static int
 aes128_encrypt_ecb(const unsigned char *key, int keysize,
@@ -381,8 +565,8 @@
 	}
 		
 	EVP_MD_CTX_init(ctx);
-	EVP_DigestInit_ex(ctx, digest, NULL);
-	if (!EVP_DigestUpdate(ctx, input, length)) {
+	if (!EVP_DigestInit_ex(ctx, digest, NULL)
+			|| !EVP_DigestUpdate(ctx, input, length)) {
 		r = SC_ERROR_INTERNAL;
 		goto err;
 	}
@@ -421,6 +605,7 @@
 	struct sc_apdu apdu;
 	unsigned char data[256] = { 0 };
 	unsigned char tmp_sm;
+	unsigned char isFips;
 	unsigned long blocksize = 0;
 	unsigned char cryptogram[256] = { 0 };	/* host cryptogram */
 	unsigned char iv[16] = { 0 };
@@ -430,6 +615,7 @@
 		return SC_ERROR_INVALID_ARGUMENTS;
 	
 	exdata = (epass2003_exdata *)card->drv_data;
+	isFips = exdata->bFipsCertification;
 
 	LOG_FUNC_CALLED(card->ctx);
 
@@ -437,7 +623,11 @@
 	apdu.cla = 0x80;
 	apdu.lc = apdu.datalen = sizeof(g_random);
 	apdu.data = g_random;	/* host random */
-	apdu.le = apdu.resplen = 28;
+	if(isFips)
+		apdu.le = apdu.resplen = 29;
+	else
+		apdu.le = apdu.resplen = 28;
+
 	apdu.resp = result;	/* card random is result[12~19] */
 
 	tmp_sm = exdata->sm;
@@ -450,37 +640,78 @@
 	LOG_TEST_RET(card->ctx, r, "gen_init_key failed");
 
 	/* Step 1 - Generate Derivation data */
-	memcpy(data, &result[16], 4);
-	memcpy(&data[4], g_random, 4);
-	memcpy(&data[8], &result[12], 4);
-	memcpy(&data[12], &g_random[4], 4);
+	if(isFips){
+		memset(data,0x00,15);
+		data[11] = 0x04;
+		data[14] = 0x80;
+		data[15] = 0x01;
+		memcpy(&data[16], g_random, 8);
+		memcpy(&data[24], &result[12+1], 8);
+	}
+	else{
+		memcpy(data, &result[16], 4);
+		memcpy(&data[4], g_random, 4);
+		memcpy(&data[8], &result[12], 4);
+		memcpy(&data[12], &g_random[4], 4);
+	}
 
 	/* Step 2,3 - Create S-ENC/S-MAC Session Key */
 	if (KEY_TYPE_AES == key_type) {
-		aes128_encrypt_ecb(key_enc, 16, data, 16, exdata->sk_enc);
-		aes128_encrypt_ecb(key_mac, 16, data, 16, exdata->sk_mac);
+		if(isFips){
+        	    	r = aes128_encrypt_cmac(key_enc, 128, data, 32, exdata->sk_enc);
+            		LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cmac enc failed");
+            		memset(&data[11], 0x06, 1);
+            		r = aes128_encrypt_cmac(key_mac, 128, data, 32, exdata->sk_mac);
+            		LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cmac mac  failed");
+        	}else{
+			r = aes128_encrypt_ecb(key_enc, 16, data, 16, exdata->sk_enc);
+			LOG_TEST_RET(card->ctx, r, "aes128_encrypt_ecb enc  failed");
+			r = aes128_encrypt_ecb(key_mac, 16, data, 16, exdata->sk_mac);
+			LOG_TEST_RET(card->ctx, r, "aes128_encrypt_ecb mac  failed");
+		}
 	}
 	else {
-		des3_encrypt_ecb(key_enc, 16, data, 16, exdata->sk_enc);
-		des3_encrypt_ecb(key_mac, 16, data, 16, exdata->sk_mac);
+		r = des3_encrypt_ecb(key_enc, 16, data, 16, exdata->sk_enc);
+		LOG_TEST_RET(card->ctx, r, "des3_encrypt_ecb failed");
+		r = des3_encrypt_ecb(key_mac, 16, data, 16, exdata->sk_mac);
+		LOG_TEST_RET(card->ctx, r, "des3_encrypt_ecb failed");
+	}
+
+	if(isFips){
+		data[11] = 0x00;
+		data[14] = 0x40;
+	}
+	else{
+		memcpy(data, g_random, 8);
+		memcpy(&data[8], &result[12], 8);
+		data[16] = 0x80;
+		blocksize = (key_type == KEY_TYPE_AES ? 16 : 8);
+		memset(&data[17], 0x00, blocksize - 1);
 	}
 
-	memcpy(data, g_random, 8);
-	memcpy(&data[8], &result[12], 8);
-	data[16] = 0x80;
-	blocksize = (key_type == KEY_TYPE_AES ? 16 : 8);
-	memset(&data[17], 0x00, blocksize - 1);
-
 	/* calculate host cryptogram */
 	if (KEY_TYPE_AES == key_type)
-		aes128_encrypt_cbc(exdata->sk_enc, 16, iv, data, 16 + blocksize, cryptogram);
+	{
+		if(isFips){
+			r = aes128_encrypt_cmac(exdata->sk_enc, 128, data, 32, cryptogram);
+		}
+		else{
+			r = aes128_encrypt_cbc(exdata->sk_enc, 16, iv, data, 16 + blocksize, cryptogram);
+		}
+	}
 	else
-		des3_encrypt_cbc(exdata->sk_enc, 16, iv, data, 16 + blocksize, cryptogram);
+		r = des3_encrypt_cbc(exdata->sk_enc, 16, iv, data, 16 + blocksize, cryptogram);
 
-	/* verify card cryptogram */
-	if (0 != memcmp(&cryptogram[16], &result[20], 8))
-		LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED);
+	LOG_TEST_RET(card->ctx, r, "calculate host cryptogram failed");
 
+	/* verify card cryptogram */
+	if(isFips){
+		if (0 != memcmp(&cryptogram[0], &result[20+1], 8))
+			LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED);
+	}else{
+		if (0 != memcmp(&cryptogram[16], &result[20], 8))
+			LOG_FUNC_RETURN(card->ctx, SC_ERROR_CARD_CMD_FAILED);
+	}
 	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
 }
 
@@ -497,49 +728,84 @@
 	unsigned char mac[256] = { 0 };
 	unsigned long i;
 	unsigned char tmp_sm;
+	unsigned char isFips;
 	epass2003_exdata *exdata = NULL;
 
 	if (!card->drv_data) 
 		return SC_ERROR_INVALID_ARGUMENTS;
 	exdata = (epass2003_exdata *)card->drv_data;
+	isFips = exdata->bFipsCertification;
 
 	LOG_FUNC_CALLED(card->ctx);
-
-	memcpy(data, ran_key, 8);
-	memcpy(&data[8], g_random, 8);
-	data[16] = 0x80;
-	memset(&data[17], 0x00, blocksize - 1);
-	memset(iv, 0, 16);
+	
+	if(isFips)
+	{
+		memset(data,0x00,15);
+		data[11] = 0x01;
+		data[14] = 0x40;
+		data[15] = 0x01;
+		memcpy(&data[16], g_random, 8);
+		memcpy(&data[24], ran_key, 8);
+	}
+	else{
+		memcpy(data, ran_key, 8);
+		memcpy(&data[8], g_random, 8);
+		data[16] = 0x80;
+		memset(&data[17], 0x00, blocksize - 1);
+		memset(iv, 0, 16);
+	}
 
 	/* calculate host cryptogram */
 	if (KEY_TYPE_AES == key_type) {
-		aes128_encrypt_cbc(exdata->sk_enc, 16, iv, data, 16 + blocksize,
-				   cryptogram);
+		if(isFips){
+			r = aes128_encrypt_cmac(exdata->sk_enc, 128, data, 32, cryptogram);
+		}
+		else{
+			r = aes128_encrypt_cbc(exdata->sk_enc, 16, iv, data, 16 + blocksize,cryptogram);
+		}
 	} else {
-		des3_encrypt_cbc(exdata->sk_enc, 16, iv, data, 16 + blocksize,
-				 cryptogram);
+		r = des3_encrypt_cbc(exdata->sk_enc, 16, iv, data, 16 + blocksize,cryptogram);
 	}
 
+	LOG_TEST_RET(card->ctx, r, "calculate host cryptogram  failed");
+
 	memset(data, 0, sizeof(data));
 	memcpy(data, "\x84\x82\x03\x00\x10", 5);
-	memcpy(&data[5], &cryptogram[16], 8);
-	memcpy(&data[13], "\x80\x00\x00", 3);
+	if(isFips){
+        	memcpy(&data[5], &cryptogram[0], 8);
+	}
+	else{
+		memcpy(&data[5], &cryptogram[16], 8);
+		memcpy(&data[13], "\x80\x00\x00", 3);
+	}
 
 	/* calculate mac icv */
 	memset(iv, 0x00, 16);
 	if (KEY_TYPE_AES == key_type) {
-		aes128_encrypt_cbc(exdata->sk_mac, 16, iv, data, 16, mac);
+		if(isFips){
+			r = aes128_encrypt_cmac(exdata->sk_mac, 128, data, 13, mac);
+		}
+		else{
+			r = aes128_encrypt_cbc(exdata->sk_mac, 16, iv, data, 16, mac);
+		}
 		i = 0;
 	} else {
-		des3_encrypt_cbc(exdata->sk_mac, 16, iv, data, 16, mac);
+		r = des3_encrypt_cbc(exdata->sk_mac, 16, iv, data, 16, mac);
 		i = 8;
 	}
+
+	LOG_TEST_RET(card->ctx, r, "calculate mac icv failed");
 	/* save mac icv */
 	memset(exdata->icv_mac, 0x00, 16);
 	memcpy(exdata->icv_mac, &mac[i], 8);
 
 	/* verify host cryptogram */
-	memcpy(data, &cryptogram[16], 8);
+	if(isFips){
+		memcpy(data, &cryptogram[0], 8);
+	}
+	else{
+		memcpy(data, &cryptogram[16], 8);
+	}
 	memcpy(&data[8], &mac[i], 8);
 	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x82, 0x03, 0x00);
 	apdu.cla = 0x84;
@@ -576,7 +842,12 @@
 
 	r = gen_init_key(card, key_enc, key_mac, result, exdata->smtype);
 	LOG_TEST_RET(ctx, r, "gen_init_key failed");
-	memcpy(ran_key, &result[12], 8);
+	if(exdata->bFipsCertification){
+		memcpy(ran_key, &result[12+1], 8);
+	}
+	else{
+		memcpy(ran_key, &result[12], 8);
+	}
 
 	r = verify_init_key(card, ran_key, exdata->smtype);
 	LOG_TEST_RET(ctx, r, "verify_init_key failed");
@@ -618,6 +889,7 @@
 	size_t tlv_more;	/* increased tlv length */
 	unsigned char iv[16] = { 0 };
 	epass2003_exdata *exdata = NULL;
+	int r = 0;
 
 	if (!card->drv_data) 
 		return SC_ERROR_INVALID_ARGUMENTS;
@@ -650,10 +922,13 @@
 	memcpy(data_tlv, &apdu_buf[block_size], tlv_more);
 
 	/* encrypt Data */
-	if (KEY_TYPE_AES == key_type)
-		aes128_encrypt_cbc(exdata->sk_enc, 16, iv, pad, pad_len, apdu_buf + block_size + tlv_more);
-	else
-		des3_encrypt_cbc(exdata->sk_enc, 16, iv, pad, pad_len, apdu_buf + block_size + tlv_more);
+	if (KEY_TYPE_AES == key_type) {
+		r = aes128_encrypt_cbc(exdata->sk_enc, 16, iv, pad, pad_len, apdu_buf + block_size + tlv_more);
+		LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cbc failed");
+	} else {
+		r = des3_encrypt_cbc(exdata->sk_enc, 16, iv, pad, pad_len, apdu_buf + block_size + tlv_more);
+		LOG_TEST_RET(card->ctx, r, "des3_encrypt_cbc failed");
+	}
 
 	memcpy(data_tlv + tlv_more, apdu_buf + block_size + tlv_more, pad_len);
 	*data_tlv_len = tlv_more + pad_len;
@@ -696,6 +971,7 @@
 	unsigned char mac[4096] = { 0 };
 	size_t mac_len;
 	unsigned char icv[16] = { 0 };
+	int r ;
 	int i = (KEY_TYPE_AES == key_type ? 15 : 7);
 	epass2003_exdata *exdata = NULL;
 
@@ -736,22 +1012,121 @@
 	memset(icv, 0, sizeof(icv));
 	memcpy(icv, exdata->icv_mac, 16);
 	if (KEY_TYPE_AES == key_type) {
-		aes128_encrypt_cbc(exdata->sk_mac, 16, icv, apdu_buf, mac_len, mac);
-		memcpy(mac_tlv + 2, &mac[mac_len - 16], 8);
+		if(exdata->bFipsCertification)
+        	{
+            		for (int i=0;i<16;i++)
+            		{
+                		apdu_buf[i]=apdu_buf[i]^icv[i];
+            		}
+            		r = aes128_encrypt_cmac(exdata->sk_mac, 128, apdu_buf, data_tlv_len+le_tlv_len+block_size, mac);
+            		LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cmac failed");
+            		memcpy(mac_tlv+2, &mac[0/*ulmacLen-16*/], 8);
+            		for (int j=0;j<4;j++)
+            		{
+                		apdu_buf[j]=apdu_buf[j]^icv[j];
+            		}
+        	}
+		else{
+			r = aes128_encrypt_cbc(exdata->sk_mac, 16, icv, apdu_buf, mac_len, mac);
+			LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cbc failed");
+			memcpy(mac_tlv + 2, &mac[mac_len - 16], 8);
+		}
 	}
 	else {
 		unsigned char iv[EVP_MAX_IV_LENGTH] = { 0 };
 		unsigned char tmp[8] = { 0 };
-		des_encrypt_cbc(exdata->sk_mac, 8, icv, apdu_buf, mac_len, mac);
-		des_decrypt_cbc(&exdata->sk_mac[8], 8, iv, &mac[mac_len - 8], 8, tmp);
+		r = des_encrypt_cbc(exdata->sk_mac, 8, icv, apdu_buf, mac_len, mac);
+		LOG_TEST_RET(card->ctx, r, "des_encrypt_cbc 1 failed");
+		r = des_decrypt_cbc(&exdata->sk_mac[8], 8, iv, &mac[mac_len - 8], 8, tmp);
+		LOG_TEST_RET(card->ctx, r, "des_decrypt_cbc failed");
 		memset(iv, 0x00, sizeof iv);
-		des_encrypt_cbc(exdata->sk_mac, 8, iv, tmp, 8, mac_tlv + 2);
+		r = des_encrypt_cbc(exdata->sk_mac, 8, iv, tmp, 8, mac_tlv + 2);
+		LOG_TEST_RET(card->ctx, r, "des_encrypt_cbc 2 failed");
 	}
 
 	*mac_tlv_len = 2 + 8;
 	return 0;
 }
 
+/* MAC(TLV case 1) */
+static int
+construct_mac_tlv_case1(struct sc_card *card, unsigned char *apdu_buf, size_t data_tlv_len, size_t le_tlv_len,
+        unsigned char *mac_tlv, size_t * mac_tlv_len, const unsigned char key_type)
+{
+    int r;
+    size_t block_size = 4;
+    unsigned char mac[4096] = { 0 };
+    size_t mac_len;
+    int i = (KEY_TYPE_AES == key_type ? 15 : 7);
+    unsigned char icv[16] = { 0 };
+
+    epass2003_exdata *exdata = NULL;
+
+    if (!card->drv_data)
+        return SC_ERROR_INVALID_ARGUMENTS;
+
+    exdata = (epass2003_exdata *)card->drv_data;
+
+    if (0 == data_tlv_len && 0 == le_tlv_len) {
+        mac_len = block_size;
+    }
+    else {
+        /* padding */
+        *(apdu_buf + block_size + data_tlv_len + le_tlv_len) = 0x80;
+        if ((data_tlv_len + le_tlv_len + 1) % block_size)
+        {
+            mac_len = (((data_tlv_len + le_tlv_len + 1) / block_size) +1) * block_size + block_size;
+        }
+        else
+        {
+            mac_len = data_tlv_len + le_tlv_len + 1 + block_size;
+        }
+
+    }
+	/* increase icv */
+    for (; i >= 0; i--) {
+        if (exdata->icv_mac[i] == 0xff) {
+            exdata->icv_mac[i] = 0;
+        }
+        else {
+            exdata->icv_mac[i]++;
+            break;
+        }
+    }
+
+    /* calculate MAC */
+	memset(icv, 0, sizeof(icv));
+    memcpy(icv, exdata->icv_mac, 16);
+    if (KEY_TYPE_AES == key_type) {
+        if(exdata->bFipsCertification)
+        {
+            r = aes128_encrypt_cmac_ft(exdata->sk_mac, 128, apdu_buf,data_tlv_len+le_tlv_len+block_size, mac, &icv[0]);
+            LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cmac_ft failed");
+            memcpy(mac_tlv+2, &mac[0/*ulmacLen-16*/], 8);
+        }
+        else
+        {
+            r = aes128_encrypt_cbc(exdata->sk_mac, 16, icv, apdu_buf, mac_len, mac);
+            LOG_TEST_RET(card->ctx, r, "aes128_encrypt_cbc failed");
+            memcpy(mac_tlv + 2, &mac[mac_len - 16], 8);
+        }
+    }
+    else
+    {
+        unsigned char iv[EVP_MAX_IV_LENGTH] = { 0 };
+        unsigned char tmp[8] = { 0 };
+        r = des_encrypt_cbc(exdata->sk_mac, 8, icv, apdu_buf, mac_len, mac);
+        LOG_TEST_RET(card->ctx, r, "des_encrypt_cbc  failed");
+        r = des_decrypt_cbc(&exdata->sk_mac[8], 8, iv, &mac[mac_len - 8], 8, tmp);
+        LOG_TEST_RET(card->ctx, r, "des_decrypt_cbc failed");
+        memset(iv, 0x00, sizeof iv);
+        r = des_encrypt_cbc(exdata->sk_mac, 8, iv, tmp, 8, mac_tlv + 2);
+        LOG_TEST_RET(card->ctx, r, "des_encrypt_cbc failed");
+    }
+
+    *mac_tlv_len = 2 + 8;
+    return 0;
+}
 
 /* According to GlobalPlatform Card Specification's SCP01
  * encode APDU from
@@ -790,7 +1165,12 @@
 	apdu_buf[3] = (unsigned char)plain->p2;
 	/* plain_le = plain->le; */
 	/* padding */
-	apdu_buf[4] = 0x80;
+	if(exdata->bFipsCertification && plain->lc == 0 && apdu_buf[1] == 0x82 && apdu_buf[2] == 0x01){
+		apdu_buf[4] = 0x00;
+	}
+	else{
+		apdu_buf[4] = 0x80;
+	}
 	memset(&apdu_buf[5], 0x00, block_size - 5);
 
 	/* Data -> Data' */
@@ -802,9 +1182,15 @@
 		if (0 != construct_le_tlv(plain, apdu_buf, data_tlv_len, le_tlv,
 				     &le_tlv_len, exdata->smtype))
 			return -1;
-
-	if (0 != construct_mac_tlv(card, apdu_buf, data_tlv_len, le_tlv_len, mac_tlv, &mac_tlv_len, exdata->smtype))
-		return -1;
+	
+	if(exdata->bFipsCertification && plain->lc == 0 && apdu_buf[1] == 0x82 && apdu_buf[2] == 0x01){
+		if(0 != construct_mac_tlv_case1(card, apdu_buf, data_tlv_len, le_tlv_len, mac_tlv, &mac_tlv_len, exdata->smtype))
+			return -1;
+	}
+	else{
+		if (0 != construct_mac_tlv(card, apdu_buf, data_tlv_len, le_tlv_len, mac_tlv, &mac_tlv_len, exdata->smtype))
+			return -1;
+	}
 
 	memset(apdu_buf + 4, 0, *apdu_buf_len - 4);
 	sm->lc = sm->datalen = data_tlv_len + le_tlv_len + mac_tlv_len;
@@ -1178,6 +1564,14 @@
 		return SC_ERROR_INVALID_CARD;
 	}
 
+	if(memcmp(&data[32],"\x87\x01\x01" , 3)==0 && memcmp(&data[0],"\x80\x01\x01", 3)==0){
+		exdata->bFipsCertification = 0x01;
+	}
+	else{
+		exdata->bFipsCertification = 0x00;
+	}
+
+
 	if (0x01 == data[2])
 		exdata->smtype = KEY_TYPE_AES;
 	else
@@ -1235,8 +1629,13 @@
 static int
 epass2003_hook_path(struct sc_path *path, int inc)
 {
-	u8 fid_h = path->value[path->len - 2];
-	u8 fid_l = path->value[path->len - 1];
+	u8 fid_h = 0;
+	u8 fid_l = 0;
+
+	if (!path || path->len < 2)
+		return -1;
+	fid_h = path->value[path->len - 2];
+	fid_l = path->value[path->len - 1];
 
 	switch (fid_h) {
 	case 0x29:
@@ -1258,17 +1657,24 @@
 }
 
 
-static void
+static int
 epass2003_hook_file(struct sc_file *file, int inc)
 {
 	int fidl = file->id & 0xff;
 	int fidh = file->id & 0xff00;
-	if (epass2003_hook_path(&file->path, inc)) {
+	int rv = 0;
+
+	rv = epass2003_hook_path(&file->path, inc);
+
+	if (rv > 0) {
 		if (inc)
 			file->id = fidh + fidl * FID_STEP;
 		else
 			file->id = fidh + fidl / FID_STEP;
 	}
+	if (rv < 0)
+		return rv;
+	return SC_SUCCESS;
 }
 
 
@@ -1281,7 +1687,9 @@
 	int r, pathlen;
 	sc_file_t *file = NULL;
 
-	epass2003_hook_path(in_path, 1);
+	r = epass2003_hook_path(in_path, 1);
+	LOG_TEST_RET(card->ctx, r, "Can not hook path");
+
 	memcpy(path, in_path->value, in_path->len);
 	pathlen = in_path->len;
 
@@ -1806,6 +2214,51 @@
 	LOG_FUNC_RETURN(card->ctx, SC_ERROR_INCORRECT_PARAMETERS);
 }
 
+/* Use epass2003 sec_attr to add acl entries */
+int
+sec_attr_to_entry(struct sc_card *card, sc_file_t *file, int indx)
+{
+	int i;
+	int found = 0;
+
+	unsigned int method;
+	unsigned long  keyref;
+
+	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
+
+	switch  (file->sec_attr[indx]) {
+		case (EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_EVERYONE):
+			method = SC_AC_NONE;
+			keyref = SC_AC_KEY_REF_NONE;
+			break;
+		case (EPASS2003_AC_MAC_NOLESS | EPASS2003_AC_USER):
+			method = SC_AC_CHV;
+			keyref = 1;
+			break;
+		default:
+			sc_log(card->ctx,"Unknown value 0x%2.2x in file->sec_attr[%d]", file->sec_attr[indx], indx);
+			method = SC_AC_NEVER;
+			keyref = SC_AC_KEY_REF_NONE;
+
+			break;
+	}
+	
+	for (i = 0; i < (int)(sizeof(sec_attr_to_acl_entry) / sizeof(sec_attr_to_acl_entries_t)); i++) {
+		const sec_attr_to_acl_entries_t *e = &sec_attr_to_acl_entry[i];
+
+		if (indx == e->indx && file->type == e->file_type
+				&& file->ef_structure == e->file_ef_structure) {
+				/* may add multiple entries */
+			sc_file_add_acl_entry(file, e->op, method, keyref);
+			found++;
+		}
+	}
+	if (found != 1) {
+		sc_log(card->ctx,"found %d entries ", found);
+	}
+
+	return 0;
+}
 
 static int
 epass2003_process_fci(struct sc_card *card, sc_file_t * file, const u8 * buf, size_t buflen)
@@ -1914,8 +2367,13 @@
 		sc_file_set_prop_attr(file, tag, taglen);
 
 	tag = sc_asn1_find_tag(ctx, p, len, 0x86, &taglen);
-	if (tag != NULL && taglen)
+	if (tag != NULL && taglen) {
+		unsigned int i;
 		sc_file_set_sec_attr(file, tag, taglen);
+		for (i = 0; i< taglen; i++)
+			if (tag[i] != 0xff) /* skip unused entries */
+				sec_attr_to_entry(card, file, i);
+	}
 
 	tag = sc_asn1_find_tag(ctx, p, len, 0x8A, &taglen);
 	if (tag != NULL && taglen == 1) {
@@ -2033,6 +2491,7 @@
 	if (file->sec_attr_len) {
 		memcpy(buf, file->sec_attr, file->sec_attr_len);
 		sc_asn1_put_tag(0x86, buf, file->sec_attr_len, p, *outlen - (p - out), &p);
+
 	}
 	else {
 		sc_log(card->ctx, "SC_FILE_ACL");
@@ -2163,18 +2622,16 @@
 	LOG_FUNC_CALLED(card->ctx);
 
 	r = sc_select_file(card, path, NULL);
-	epass2003_hook_path((struct sc_path *)path, 1);
-	if (r == SC_SUCCESS) {
-		sbuf[0] = path->value[path->len - 2];
-		sbuf[1] = path->value[path->len - 1];
-		sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00);
-		apdu.lc = 2;
-		apdu.datalen = 2;
-		apdu.data = sbuf;
-	}
-	else   {
-		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
-	}
+	LOG_TEST_RET(card->ctx, r, "Can not select file");
+	r = epass2003_hook_path((struct sc_path *)path, 1);
+	LOG_TEST_RET(card->ctx, r, "Can not hook path");
+
+	sbuf[0] = path->value[path->len - 2];
+	sbuf[1] = path->value[path->len - 1];
+	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE4, 0x00, 0x00);
+	apdu.lc = 2;
+	apdu.datalen = 2;
+	apdu.data = sbuf;
 
 	r = sc_transmit_apdu_t(card, &apdu);
 	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
diff -Nru opensc-0.22.0/src/libopensc/card-gpk.c opensc-0.23.0/src/libopensc/card-gpk.c
--- opensc-0.22.0/src/libopensc/card-gpk.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-gpk.c	2022-11-29 09:34:43.000000000 +0100
@@ -186,11 +186,6 @@
 			priv->offset_shift = 0;
 			priv->offset_mask = 0;
 		}
-		if (info[12] & 0x10) {
-			/* DSA supported - add algo information.
-			 * It's highly unlikely we'll ever see this.
-			 */
-		}
 		if (info[12] & 0x08) {
 			priv->locked = 1;
 		}
@@ -908,14 +903,14 @@
 	if (!EVP_EncryptUpdate(ctx, kats, &outl, r_rn+4, 8))
 		r = SC_ERROR_INTERNAL;
 
-	if (!EVP_CIPHER_CTX_cleanup(ctx))
+	if (!EVP_CIPHER_CTX_reset(ctx))
 		r = SC_ERROR_INTERNAL;
 	if (r == SC_SUCCESS) {
-		EVP_CIPHER_CTX_init(ctx);
+		EVP_CIPHER_CTX_reset(ctx);
 		EVP_EncryptInit_ex(ctx, EVP_des_ede(), NULL, out, NULL);
 		if (!EVP_EncryptUpdate(ctx, kats+8, &outl, r_rn+4, 8))
 			r = SC_ERROR_INTERNAL;
-	if (!EVP_CIPHER_CTX_cleanup(ctx))
+	if (!EVP_CIPHER_CTX_reset(ctx))
 		r = SC_ERROR_INTERNAL;
 	}
 	memset(out, 0, sizeof(out));
@@ -925,7 +920,7 @@
 	 * here? INVALID_ARGS doesn't seem quite right
 	 */
 	if (r == SC_SUCCESS) {
-		EVP_CIPHER_CTX_init(ctx);
+		EVP_CIPHER_CTX_reset(ctx);
 		EVP_EncryptInit_ex(ctx, EVP_des_ede(), NULL, kats, NULL);
 		if (!EVP_EncryptUpdate(ctx, out, &outl, challenge, 8))
 			r = SC_ERROR_INTERNAL;
diff -Nru opensc-0.22.0/src/libopensc/card-iasecc.c opensc-0.23.0/src/libopensc/card-iasecc.c
--- opensc-0.22.0/src/libopensc/card-iasecc.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-iasecc.c	2022-11-29 09:34:43.000000000 +0100
@@ -38,6 +38,17 @@
 #include <openssl/pkcs12.h>
 #include <openssl/x509v3.h>
 
+/*
+ * OpenSSL-3.0.0 does not allow access to the SHA data
+ * so this driver can not produces signatures
+ * OpenSSL 1.1.1 uses EVP_MD_CTX_md_data
+ * LibreSSL
+ */
+
+#if defined(LIBRESSL_VERSION_NUMBER)
+# define  EVP_MD_CTX_md_data(x)  (x->md_data)
+#endif
+
 #include "internal.h"
 #include "asn1.h"
 #include "cardctl.h"
@@ -819,7 +830,7 @@
 
 		sc_log(ctx, "READ method/reference %X/%X", entry->method, entry->key_ref);
 		if ((entry->method == SC_AC_SCB) && (entry->key_ref & IASECC_SCB_METHOD_SM))   {
-			unsigned char se_num = (entry->method == SC_AC_SCB) ? (entry->key_ref & IASECC_SCB_METHOD_MASK_REF) : 0;
+			unsigned char se_num = entry->key_ref & IASECC_SCB_METHOD_MASK_REF;
 
 			rv = iasecc_sm_read_binary(card, se_num, offs, buff, count);
 			LOG_FUNC_RETURN(ctx, rv);
@@ -854,7 +865,7 @@
 
 		sc_log(ctx, "UPDATE method/reference %X/%X", entry->method, entry->key_ref);
 		if (entry->method == SC_AC_SCB && (entry->key_ref & IASECC_SCB_METHOD_SM))   {
-			unsigned char se_num = entry->method == SC_AC_SCB ? entry->key_ref & IASECC_SCB_METHOD_MASK_REF : 0;
+			unsigned char se_num = entry->key_ref & IASECC_SCB_METHOD_MASK_REF;
 
 			rv = iasecc_sm_update_binary(card, se_num, offs, buff, count);
 			LOG_FUNC_RETURN(ctx, rv);
@@ -1558,7 +1569,7 @@
 
 	sc_log(ctx, "DELETE method/reference %X/%X", entry->method, entry->key_ref);
 	if (entry->method == SC_AC_SCB && (entry->key_ref & IASECC_SCB_METHOD_SM))   {
-		unsigned char se_num = (entry->method == SC_AC_SCB) ? (entry->key_ref & IASECC_SCB_METHOD_MASK_REF) : 0;
+		unsigned char se_num = entry->key_ref & IASECC_SCB_METHOD_MASK_REF;
 		rv = iasecc_sm_delete_file(card, se_num, file->id);
 	}
 	else   {
@@ -3164,10 +3175,14 @@
 iasecc_qsign_data_sha1(struct sc_context *ctx, const unsigned char *in, size_t in_len,
 				struct iasecc_qsign_data *out)
 {
-	SHA_CTX sha;
-	SHA_LONG pre_hash_Nl, *hh[5] = {
-		&sha.h0, &sha.h1, &sha.h2, &sha.h3, &sha.h4
-	};
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+
+	int r = SC_ERROR_INTERNAL;
+	EVP_MD_CTX *mdctx = NULL;
+	const EVP_MD *md = NULL;
+	SHA_CTX *md_data = NULL;
+	unsigned int md_out_len;
+	SHA_LONG pre_hash_Nl, *hh[5] = {NULL, NULL, NULL, NULL, NULL};
 	int jj, ii;
 	int hh_size = sizeof(SHA_LONG), hh_num = SHA_DIGEST_LENGTH / sizeof(SHA_LONG);
 
@@ -3181,8 +3196,30 @@
 	       in_len);
 	memset(out, 0, sizeof(struct iasecc_qsign_data));
 
-	SHA1_Init(&sha);
-	SHA1_Update(&sha, in, in_len);
+	md = EVP_get_digestbyname("SHA1");
+	mdctx = EVP_MD_CTX_new();
+        if (EVP_DigestInit_ex(mdctx, md, NULL) != 1) {
+		sc_log(ctx, "EVP_DigestInit_ex failed");
+		goto err;
+	}
+	
+	md_data = EVP_MD_CTX_md_data(mdctx);
+	if (md_data == NULL) {
+		sc_log(ctx, "Failed to find md_data");
+		r = SC_ERROR_NOT_SUPPORTED;
+		goto err;
+	}
+
+	if (EVP_DigestUpdate(mdctx, in, in_len) != 1) {
+		sc_log(ctx, "EVP_DigestUpdate failed");
+		goto err;
+	}
+
+	hh[0] = &md_data->h0;
+	hh[1] = &md_data->h1;
+	hh[2] = &md_data->h2;
+	hh[3] = &md_data->h3;
+	hh[4] = &md_data->h4;
 
 	for (jj=0; jj<hh_num; jj++)
 		for(ii=0; ii<hh_size; ii++)
@@ -3190,28 +3227,45 @@
 	out->pre_hash_size = SHA_DIGEST_LENGTH;
 	sc_log(ctx, "Pre SHA1:%s", sc_dump_hex(out->pre_hash, out->pre_hash_size));
 
-	pre_hash_Nl = sha.Nl - (sha.Nl % (sizeof(sha.data) * 8));
+	pre_hash_Nl = md_data->Nl - (md_data->Nl % (sizeof(md_data->data) *8));
 	for (ii=0; ii<hh_size; ii++)   {
-		out->counter[ii] = (sha.Nh >> 8*(hh_size-1-ii)) &0xFF;
+		out->counter[ii] = (md_data->Nh >> 8*(hh_size-1-ii)) &0xFF;
 		out->counter[hh_size+ii] = (pre_hash_Nl >> 8*(hh_size-1-ii)) &0xFF;
 	}
 	for (ii=0, out->counter_long=0; ii<(int)sizeof(out->counter); ii++)
 		out->counter_long = out->counter_long*0x100 + out->counter[ii];
 	sc_log(ctx, "Pre counter(%li):%s", out->counter_long, sc_dump_hex(out->counter, sizeof(out->counter)));
 
-	if (sha.num)   {
-		memcpy(out->last_block, in + in_len - sha.num, sha.num);
-		out->last_block_size = sha.num;
+	if (md_data->num)   {
+		memcpy(out->last_block, in + in_len - md_data->num, md_data->num);
+		out->last_block_size = md_data->num;
 		sc_log(ctx, "Last block(%"SC_FORMAT_LEN_SIZE_T"u):%s",
 		       out->last_block_size,
 		       sc_dump_hex(out->last_block, out->last_block_size));
 	}
 
-	SHA1_Final(out->hash, &sha);
+	if (EVP_DigestFinal_ex(mdctx, out->hash, &md_out_len) != 1) {
+		sc_log(ctx, "EVP_DigestFinal_ex failed");
+		goto err;
+	}
+
 	out->hash_size = SHA_DIGEST_LENGTH;
 	sc_log(ctx, "Expected digest %s\n", sc_dump_hex(out->hash, out->hash_size));
 
-	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
+	r = SC_SUCCESS;
+	goto end;
+
+err:
+	if (ctx->debug > 0 && ctx->debug_file != 0)
+		ERR_print_errors_fp(ctx->debug_file);
+end:
+	EVP_MD_CTX_free(mdctx);
+
+	LOG_FUNC_RETURN(ctx, r);
+
+#else /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+	LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
 }
 
 
@@ -3219,7 +3273,14 @@
 iasecc_qsign_data_sha256(struct sc_context *ctx, const unsigned char *in, size_t in_len,
 				struct iasecc_qsign_data *out)
 {
-	SHA256_CTX sha256;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+
+	int r = SC_ERROR_INTERNAL;
+	EVP_MD_CTX *mdctx = NULL;
+	const EVP_MD *md = NULL;
+	SHA256_CTX *md_data;
+	unsigned int md_out_len;
+
 	SHA_LONG pre_hash_Nl;
 	int jj, ii;
 	int hh_size = sizeof(SHA_LONG), hh_num = SHA256_DIGEST_LENGTH / sizeof(SHA_LONG);
@@ -3233,37 +3294,70 @@
 	       in_len);
 	memset(out, 0, sizeof(struct iasecc_qsign_data));
 
-	SHA256_Init(&sha256);
-	SHA256_Update(&sha256, in, in_len);
+	md = EVP_get_digestbyname("SHA256");
+	mdctx = EVP_MD_CTX_new();
+	if (EVP_DigestInit_ex(mdctx, md, NULL) != 1) {
+		sc_log(ctx, "EVP_DigestInit_ex failed");
+		goto err;
+	}
+
+	md_data = EVP_MD_CTX_md_data(mdctx);
+	if (md_data == NULL) {
+		sc_log(ctx, "Failed to find md_data");
+		r = SC_ERROR_NOT_SUPPORTED;
+		goto err;
+	}
+
+	if (EVP_DigestUpdate(mdctx, in, in_len) != 1) {
+		sc_log(ctx, "EVP_DigestUpdate failed");
+		goto err;
+	}
 
 	for (jj=0; jj<hh_num; jj++)
 		for(ii=0; ii<hh_size; ii++)
-			out->pre_hash[jj*hh_size + ii] = ((sha256.h[jj] >> 8*(hh_size-1-ii)) & 0xFF);
+			out->pre_hash[jj*hh_size + ii] = ((md_data->h[jj] >> 8*(hh_size-1-ii)) & 0xFF);
 	out->pre_hash_size = SHA256_DIGEST_LENGTH;
 	sc_log(ctx, "Pre hash:%s", sc_dump_hex(out->pre_hash, out->pre_hash_size));
 
-	pre_hash_Nl = sha256.Nl - (sha256.Nl % (sizeof(sha256.data) * 8));
+	pre_hash_Nl = md_data->Nl - (md_data->Nl % (sizeof(md_data->data) * 8));
 	for (ii=0; ii<hh_size; ii++)   {
-		out->counter[ii] = (sha256.Nh >> 8*(hh_size-1-ii)) &0xFF;
+		out->counter[ii] = (md_data->Nh >> 8*(hh_size-1-ii)) &0xFF;
 		out->counter[hh_size+ii] = (pre_hash_Nl >> 8*(hh_size-1-ii)) &0xFF;
 	}
 	for (ii=0, out->counter_long=0; ii<(int)sizeof(out->counter); ii++)
 		out->counter_long = out->counter_long*0x100 + out->counter[ii];
 	sc_log(ctx, "Pre counter(%li):%s", out->counter_long, sc_dump_hex(out->counter, sizeof(out->counter)));
 
-	if (sha256.num)   {
-		memcpy(out->last_block, in + in_len - sha256.num, sha256.num);
-		out->last_block_size = sha256.num;
+	if (md_data->num)   {
+		memcpy(out->last_block, in + in_len - md_data->num, md_data->num);
+		out->last_block_size = md_data->num;
 		sc_log(ctx, "Last block(%"SC_FORMAT_LEN_SIZE_T"u):%s",
 		       out->last_block_size,
 		       sc_dump_hex(out->last_block, out->last_block_size));
 	}
 
-	SHA256_Final(out->hash, &sha256);
+	if (EVP_DigestFinal_ex(mdctx, out->hash, &md_out_len) != 1) {
+		sc_log(ctx, "EVP_DigestFinal_ex failed");
+		goto err;
+	}
+
 	out->hash_size = SHA256_DIGEST_LENGTH;
 	sc_log(ctx, "Expected digest %s\n", sc_dump_hex(out->hash, out->hash_size));
 
-	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
+	r = SC_SUCCESS;
+	goto end;
+
+err:
+	if (ctx->debug > 0 && ctx->debug_file != 0)
+		ERR_print_errors_fp(ctx->debug_file);
+end:
+	EVP_MD_CTX_free(mdctx);
+
+	LOG_FUNC_RETURN(ctx, r);
+
+#else /* OPENSSL_VERSION_NUMBER < 0x30000000L */
+	LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
 }
 
 
diff -Nru opensc-0.22.0/src/libopensc/card-idprime.c opensc-0.23.0/src/libopensc/card-idprime.c
--- opensc-0.22.0/src/libopensc/card-idprime.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-idprime.c	2022-11-29 09:34:43.000000000 +0100
@@ -168,18 +168,22 @@
 		goto done;
 	}
 
-	r = iso_ops->read_binary(card, 0, buf, length, 0);
-	if (r < 1) {
-		r = SC_ERROR_WRONG_LENGTH;
-		goto done;
-	}
+	r = 0;
+	do {
+		if (length == r) {
+			r = SC_ERROR_NOT_ENOUGH_MEMORY;
+			goto done;
+		}
+		const int got = iso_ops->read_binary(card, r, buf + r, length - r, 0);
+		if (got < 1) {
+			r = SC_ERROR_WRONG_LENGTH;
+			goto done;
+		}
+		/* First byte shows the number of entries, each of them 21 bytes long */
+		num_entries = buf[0];
+		r += got;
+	} while(r < num_entries * 21 + 1);
 
-	/* First byte shows the number of entries, each of them 21 bytes long */
-	num_entries = buf[0];
-	if (r < num_entries*21 + 1) {
-		r = SC_ERROR_INVALID_DATA;
-		goto done;
-	}
 	new_object.fd = 0;
 	for (i = 0; i < num_entries; i++) {
 		u8 *start = &buf[i*21+1];
@@ -211,6 +215,7 @@
 					new_object.key_reference = 0xF7 + key_id;
 					break;
 				case SC_CARD_TYPE_IDPRIME_V4:
+				default:
 					new_object.key_reference = 0x56 + key_id;
 					break;
 				}
@@ -334,6 +339,8 @@
 
 	card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO;
 
+	card->caps |= SC_CARD_CAP_RNG;
+
 	LOG_FUNC_RETURN(card->ctx, 0);
 }
 
@@ -813,6 +820,38 @@
 		LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2));
 }
 
+static int
+idprime_get_challenge(struct sc_card *card, u8 *rnd, size_t len)
+{
+	u8 rbuf[16];
+	size_t out_len;
+	struct sc_apdu apdu;
+	int r;
+
+	LOG_FUNC_CALLED(card->ctx);
+
+	if (len <= 8) {
+		/* official closed driver always calls this regardless the length */
+		sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x84, 0x00, 0x01);
+		apdu.le = apdu.resplen = 8;
+	} else {
+		/* this was discovered accidentally - all 16 bytes seem random */
+		sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x84, 0x00, 0x00);
+		apdu.le = apdu.resplen = 16;
+	}
+	apdu.resp = rbuf;
+
+	r = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+
+	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	LOG_TEST_RET(card->ctx, r, "GET CHALLENGE failed");
+
+	out_len = len < apdu.resplen ? len : apdu.resplen;
+	memcpy(rnd, rbuf, out_len);
+
+	LOG_FUNC_RETURN(card->ctx, (int) out_len);
+}
 
 static struct sc_card_driver * sc_get_driver(void)
 {
@@ -832,6 +871,8 @@
 	idprime_ops.compute_signature = idprime_compute_signature;
 	idprime_ops.decipher = idprime_decipher;
 
+	idprime_ops.get_challenge = idprime_get_challenge;
+
 	return &idprime_drv;
 }
 
diff -Nru opensc-0.22.0/src/libopensc/card-isoApplet.c opensc-0.23.0/src/libopensc/card-isoApplet.c
--- opensc-0.22.0/src/libopensc/card-isoApplet.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-isoApplet.c	2022-11-29 09:34:43.000000000 +0100
@@ -234,7 +234,6 @@
 		 * should be kept in sync with the explicit parameters in the pkcs15-init
 		 * driver. */
 		flags = 0;
-		flags |= SC_ALGORITHM_ECDSA_RAW;
 		flags |= SC_ALGORITHM_ECDSA_HASH_SHA1;
 		flags |= SC_ALGORITHM_ONBOARD_KEY_GEN;
 		ext_flags = SC_ALGORITHM_EXT_EC_UNCOMPRESES;
@@ -1116,14 +1115,14 @@
 			break;
 
 		case SC_ALGORITHM_EC:
-			if( env->algorithm_flags & SC_ALGORITHM_ECDSA_RAW )
+			if( env->algorithm_flags & SC_ALGORITHM_ECDSA_HASH_SHA1 )
 			{
 				drvdata->sec_env_alg_ref = ISOAPPLET_ALG_REF_ECDSA;
 				drvdata->sec_env_ec_field_length = env->algorithm_ref;
 			}
 			else
 			{
-				LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "IsoApplet only supports raw ECDSA.");
+				LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "IsoApplet only supports ECDSA with on-card SHA1.");
 			}
 			break;
 
diff -Nru opensc-0.22.0/src/libopensc/card-itacns.c opensc-0.23.0/src/libopensc/card-itacns.c
--- opensc-0.22.0/src/libopensc/card-itacns.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-itacns.c	2022-11-29 09:34:43.000000000 +0100
@@ -104,8 +104,8 @@
 	if(card->driver) {
 		DRVDATA(card)->cns_version = atr[i];
 	}
-	/* Warn if the version is not 1.0. */
-	if(atr[i] != 0x10) {
+	/* Warn if version is not 1.X. */
+	if(atr[i] != 0x10 && atr[i] != 0x11) {
 		char version[8];
 		snprintf(version, sizeof(version), "%d.%d", (atr[i] >> 4) & 0x0f, atr[i] & 0x0f);
 		sc_log(card->ctx, "CNS card version %s; no official specifications "
@@ -219,8 +219,13 @@
 		| SC_ALGORITHM_RSA_RAW
 		| SC_ALGORITHM_RSA_HASHES
 		;
+
 	_sc_card_add_rsa_alg(card, 1024, flags, 0);
 
+	if (DRVDATA(card)->cns_version == 0x11) {
+		card->caps |= SC_CARD_CAP_APDU_EXT;
+		_sc_card_add_rsa_alg(card, 2048, flags, 0);
+	}
 	return SC_SUCCESS;
 }
 
diff -Nru opensc-0.22.0/src/libopensc/card-jcop.c opensc-0.23.0/src/libopensc/card-jcop.c
--- opensc-0.22.0/src/libopensc/card-jcop.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-jcop.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,934 +0,0 @@
-/*
- * card-jcop.c
- *
- * Copyright (C) 2003 Chaskiel Grundman <cg2v at andrew.cmu.edu>
- *
- * 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 HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <string.h>
-#include <stdlib.h>
-
-#include "internal.h"
-#include "cardctl.h"
-
-static const struct sc_atr_table jcop_atrs[] = {
-	{ "3B:E6:00:FF:81:31:FE:45:4A:43:4F:50:33:31:06", NULL, NULL, SC_CARD_TYPE_JCOP_GENERIC, 0, NULL },
-	{ NULL, NULL, NULL, 0, 0, NULL }
-};
-
-static struct sc_card_operations jcop_ops;
-static struct sc_card_driver jcop_drv = {
-	"JCOP cards with BlueZ PKCS#15 applet",
-	"jcop",
-	&jcop_ops,
-	NULL, 0, NULL
-};
-
-#define SELECT_MF 0
-#define SELECT_EFDIR 1
-#define SELECT_APPDF 2
-#define SELECT_EF 3
-#define SELECT_UNKNOWN 4
-#define SELECTING_TARGET 0xf
-#define SELECTING_ABS 0x80
-#define SELECTING_VIA_APPDF 0x100
-
-struct jcop_private_data 
-{
-     sc_file_t *virtmf;
-     sc_file_t *virtdir;
-     sc_path_t aid;
-     int selected;
-     int invalid_senv;
-     int nfiles;
-     u8 *filelist;
-};
-#define DRVDATA(card)   ((struct jcop_private_data *) ((card)->drv_data))
-
-static int jcop_finish(sc_card_t *card)
-{
-     struct jcop_private_data *drvdata=DRVDATA(card);
-     if (drvdata) {
-	  sc_file_free(drvdata->virtmf);
-	  sc_file_free(drvdata->virtdir);
-	  free(drvdata);
-	  card->drv_data=NULL;
-     }
-     
-     return 0;
-}
-
-static int jcop_match_card(sc_card_t *card)
-{
-	int i;
-
-	i = _sc_match_atr(card, jcop_atrs, &card->type);
-	if (i < 0)
-		return 0;
-	return 1;
-}
-
-static unsigned char ef_dir_contents[128] = {
-     0x61, 0x21, 
-     0x4f, 0xc, 0xA0, 0x0, 0x0, 0x0, 0x63, 'P', 'K', 'C', 'S', '-', '1', '5',
-     0x50, 0xb, 'O', 'p', 'e', 'n', 'S', 'C', ' ', 'C', 'a', 'r', 'd',
-     0x51, 0x04, 0x3f, 0x00, 0x50, 0x15
-};
-
-
-static int jcop_init(sc_card_t *card)
-{
-     struct jcop_private_data *drvdata;
-     sc_file_t *f;
-     int flags;
-     
-     drvdata=malloc(sizeof(struct jcop_private_data));
-     if (!drvdata)
-	  return SC_ERROR_OUT_OF_MEMORY;
-     memset(drvdata, 0, sizeof(struct jcop_private_data));
-     
-     sc_format_path("A000:0000:6350:4B43:532D:3135", &drvdata->aid);
-     drvdata->aid.type = SC_PATH_TYPE_DF_NAME;
-     drvdata->selected=SELECT_MF;
-     drvdata->invalid_senv=1;
-     drvdata->nfiles=-1;
-     drvdata->filelist=NULL;
-     f=sc_file_new();
-     if (!f){
-	  free(drvdata);
-	  return SC_ERROR_OUT_OF_MEMORY;
-     }
-     
-     sc_format_path("3f00", &f->path);
-     f->type=SC_FILE_TYPE_DF;
-     f->shareable=0;
-     f->ef_structure=SC_FILE_EF_UNKNOWN;
-     f->size=0;
-     f->id=0x3f00;
-     f->status=SC_FILE_STATUS_ACTIVATED;
-     sc_file_add_acl_entry(f, SC_AC_OP_SELECT, SC_AC_NONE, 0);
-     sc_file_add_acl_entry(f, SC_AC_OP_LIST_FILES, SC_AC_NONE, 0);
-     sc_file_add_acl_entry(f, SC_AC_OP_LOCK, SC_AC_NEVER, 0);
-     sc_file_add_acl_entry(f, SC_AC_OP_DELETE, SC_AC_NEVER, 0);
-     sc_file_add_acl_entry(f, SC_AC_OP_CREATE, SC_AC_NEVER, 0);
-
-     drvdata->virtmf=f;
-
-     f=sc_file_new();
-     if (!f){
-	  sc_file_free(drvdata->virtmf);
-	  free(drvdata);
-	  return SC_ERROR_OUT_OF_MEMORY;
-     }
-     
-     sc_format_path("3f002f00", &f->path);
-     f->type=SC_FILE_TYPE_WORKING_EF;
-     f->shareable=0;
-     f->ef_structure=SC_FILE_EF_TRANSPARENT;
-     f->size=128;
-     f->id=0x2f00;
-     f->status=SC_FILE_STATUS_ACTIVATED;
-     sc_file_add_acl_entry(f, SC_AC_OP_READ, SC_AC_NONE, 0);
-     sc_file_add_acl_entry(f, SC_AC_OP_LOCK, SC_AC_NEVER, 0);
-     sc_file_add_acl_entry(f, SC_AC_OP_ERASE, SC_AC_NEVER, 0);
-     sc_file_add_acl_entry(f, SC_AC_OP_UPDATE, SC_AC_NEVER, 0);
-     sc_file_add_acl_entry(f, SC_AC_OP_WRITE, SC_AC_NEVER, 0);
-     sc_file_add_acl_entry(f, SC_AC_OP_CRYPTO, SC_AC_NEVER, 0);
-     
-     drvdata->virtdir=f;
-     
-     
-     card->drv_data = drvdata;
-     card->cla = 0x00;
-
-     /* card supports host-side padding, but not raw rsa */
-     flags = SC_ALGORITHM_RSA_PAD_PKCS1;
-     flags |= SC_ALGORITHM_RSA_HASH_NONE;
-     flags |= SC_ALGORITHM_RSA_HASH_SHA1;
-     flags |= SC_ALGORITHM_RSA_HASH_MD5;
-     /* only supports keygen with 3 and F-4  exponents */
-     flags |= SC_ALGORITHM_ONBOARD_KEY_GEN;
-     _sc_card_add_rsa_alg(card, 512, flags, 0);
-     _sc_card_add_rsa_alg(card, 768, flags, 0);
-     _sc_card_add_rsa_alg(card, 1024, flags, 0);
-     _sc_card_add_rsa_alg(card, 2048, flags, 0);
-     /* State that we have an RNG */
-     card->caps |= SC_CARD_CAP_RNG;
-
-     return 0;
-}
-
-static int jcop_get_default_key(sc_card_t *card,
-                                struct sc_cardctl_default_key *data)
-{
-	const char *key;
-
-	if (data->method != SC_AC_PRO || data->key_ref > 2)
-		return SC_ERROR_NO_DEFAULT_KEY;
-
-	key = "40:41:42:43:44:45:46:47:48:49:4A:4B:4C:4D:4E:4F";
-	return sc_hex_to_bin(key, data->key_data, &data->len);
-}
-
-/* since the card is actually a javacard, we're expected to use ISO
-   7816-4 direct application selection instead of reading the DIR
-   ourselves and selecting the AppDF by path. Since opensc doesn' do
-   that, I fake an MF containing the AppDF and a fixed DIR pointing at
-   the fake AppDF. This has the added advantage of allowing
-   opensc-explorer to be used with this driver */
-static int jcop_select_file(sc_card_t *card, const sc_path_t *path,
-			    sc_file_t **file)
-{
-     struct jcop_private_data *drvdata=DRVDATA(card);
-     int r,selecting;
-     struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
-     const struct sc_card_operations *iso_ops = iso_drv->ops;
-     sc_path_t       shortpath;
-     sc_file_t  *tfile, **fileptr;
-     
-     if (!drvdata)
-	  return SC_ERROR_FILE_NOT_FOUND;
-
-     /* Something about the card does not like Case 4 APDU's to be sent as
-	Case 3. you must send a length and accept a response. */
-	
-     if (file) {
-	  fileptr=file;
-     } else {
-	  fileptr=&tfile;
-     }
-
-     /* Selecting the MF. return a copy of the constructed MF */
-     if (path->len == 2 && memcmp(path->value, "\x3F\x00", 2) == 0) {
-	  drvdata->selected=SELECT_MF;
-	  if (file) {
-		sc_file_dup(file, drvdata->virtmf);
-		if (*file == NULL)
-			return SC_ERROR_OUT_OF_MEMORY;
-	  }
-	  return 0;
-     }
-     /* Selecting the EF(DIR). return a copy of the constructed EF(DIR) */
-     if ((path->len == 4 && 
-	  memcmp(path->value, "\x3F\x00\x2F\x00", 4) == 0) ||
-	 (drvdata->selected == SELECT_MF && path->len == 2 &&
-	  memcmp(path->value, "\x2F\x00", 2) == 0)) {
-	  drvdata->selected=SELECT_EFDIR;
-	  if (file) {
-		sc_file_dup(file, drvdata->virtdir);
-		if (*file == NULL)
-			return SC_ERROR_OUT_OF_MEMORY;
-	  }
-	  return 0;
-     }	  
-     /* selecting the PKCS15 AppDF or a file in it. Select the applet, then 
-	pass through any remaining path components to the applet's select 
-	command
-     */
-     selecting=SELECT_UNKNOWN;
-     
-     if (path->len >= 4 && 
-	 memcmp(path->value, "\x3F\x00\x50\x15", 4) == 0) {
-	  if (path->len == 4)
-	       selecting = SELECTING_ABS | SELECT_APPDF;
-	  else
-	       selecting = SELECTING_ABS | SELECT_EF;
-     }
-     
-     if	 (drvdata->selected==SELECT_MF && 
-	  memcmp(path->value, "\x50\x15", 2) == 0) {
-	  if (path->len == 2)
-	       selecting = SELECTING_VIA_APPDF | SELECT_APPDF;
-	  else
-	       selecting = SELECTING_VIA_APPDF | SELECT_EF;
-     }
-    
-     if (selecting & (SELECTING_ABS|SELECTING_VIA_APPDF))
-     {
-	  if (file == NULL && 
-	      (selecting & SELECTING_TARGET) == SELECT_APPDF  && 
-	      drvdata->selected == SELECT_APPDF) {
-	       return 0;
-	  }
-	  if ((r = iso_ops->select_file(card, &drvdata->aid, fileptr)) < 0)
-	       return r;
-	  if (fileptr && (selecting & SELECTING_TARGET) == SELECT_APPDF) {
-	       (*fileptr)->type = SC_FILE_TYPE_DF;
-	       drvdata->selected=SELECT_APPDF;
-	       goto select_ok;
-	  }
-	  sc_file_free(*fileptr);
-	  *fileptr=NULL;
-	  memset(&shortpath, 0, sizeof(sc_path_t));	  
-	  if (selecting & SELECTING_ABS) {
-	       memcpy(&shortpath.value, &path->value[4], path->len-4);
-	       shortpath.len=path->len-4;
-	  } else {
-	       memcpy(&shortpath.value, &path->value[2], path->len-2);
-	       shortpath.len=path->len-2;
-	  }
-	  shortpath.type = shortpath.len == 2 ? SC_PATH_TYPE_FILE_ID :
-	       path->type;
-	  shortpath.index=path->index;
-	  shortpath.count=path->count;
-	  path=&shortpath;
-     } else {
-	  /* There seems to be better debugging output if I call sc_check_sw
-	   * with appropriate input than if I just return the appropriate 
-	   * SC_ERROR_*, so that's what I do for all errors returned by code 
-	   * related to the MF/DIR emulation 
-	   */
-	  if (drvdata->selected == SELECT_MF || 
-              drvdata->selected == SELECT_EFDIR)
-	       return sc_check_sw(card, 0x6A, 0x82);
-     }
-	
-     r = iso_ops->select_file(card, path, fileptr);
-     if (r)
-	  return r;
-     drvdata->selected=SELECT_EF;
- select_ok:
-     if (!file) {
-	  sc_file_free(*fileptr);
-     }
-     return 0;
-}
-
-static int jcop_read_binary(sc_card_t *card, unsigned int idx,
-			    u8 * buf, size_t count, unsigned long flags) {
-     struct jcop_private_data *drvdata=DRVDATA(card);
-     struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
-     const struct sc_card_operations *iso_ops = iso_drv->ops;
-     int r;
-     
-     if (drvdata->selected == SELECT_MF) {
-          return sc_check_sw(card, 0x69, 0x86);
-     }
-     if (drvdata->selected == SELECT_EFDIR) {
-	  if (idx > 127) {
-	       return sc_check_sw(card, 0x6A, 0x86);
-	  }
-	  if (idx + count > 128) {
-	       count=128-idx;
-	  }
-	  r = iso_ops->select_file(card, &drvdata->aid, NULL);
-	  if (r < 0) { /* no pkcs15 app, so return empty DIR. */
-	       memset(buf, 0, count);
-	  } else {
-	       memcpy(buf, (u8 *)(ef_dir_contents + idx), count);
-	  }
-	  return count;
-     }
-     return iso_ops->read_binary(card, idx, buf, count, flags);
-}
-
-static int jcop_list_files(sc_card_t *card, u8 *buf, size_t buflen) {
-     struct jcop_private_data *drvdata=DRVDATA(card);
-     struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
-     const struct sc_card_operations *iso_ops = iso_drv->ops;
-     int r;
-
-     if (drvdata->selected == SELECT_MF) {
-	  if (buflen < 2)
-	       return 0;
-	  memcpy(buf, "\x2f\x00", 2);
-	  if (buflen < 4)
-	       return 2;
-	  /* AppDF only exists if applet is selectable */
-	  r = iso_ops->select_file(card, &drvdata->aid, NULL);
-	  if (r < 0) { 
-	       return 2;
-	  } else {
-	       memcpy(buf+2, "\x50\x15", 2);
-	       return 4;
-	  }
-     }
-     
-     if (drvdata->nfiles == -1)
-	  return SC_ERROR_NOT_ALLOWED;
-     if (drvdata->nfiles == 0)
-	  return 0;
-     if (buflen > 2 * (size_t)drvdata->nfiles)
-	  buflen=2*drvdata->nfiles;
-     memcpy(buf, drvdata->filelist, buflen);
-     return buflen;
-}
-
-static int sa_to_acl(sc_file_t *file, unsigned int operation, 
-		     int nibble) {
-     switch (nibble & 0x7) {
-     case 0:
-	  sc_file_add_acl_entry(file, operation, SC_AC_NONE, SC_AC_KEY_REF_NONE);
-	  break;
-     case 1:
-	  sc_file_add_acl_entry(file, operation, SC_AC_NEVER, SC_AC_KEY_REF_NONE);
-	  break;
-     case 2:
-	  sc_file_add_acl_entry(file, operation, SC_AC_CHV, 1);
-	  break;
-     case 3:
-	  sc_file_add_acl_entry(file, operation, SC_AC_CHV, 2);
-	  break;
-     case 4:
-	  sc_file_add_acl_entry(file, operation, SC_AC_CHV, 3);
-	  break;
-     case 5:
-	  sc_file_add_acl_entry(file, operation, SC_AC_AUT, SC_AC_KEY_REF_NONE);
-	  break;
-     case 6:
-	  sc_file_add_acl_entry(file, operation, SC_AC_PRO, SC_AC_KEY_REF_NONE);
-	  break;
-     default:
-	  sc_file_add_acl_entry(file, operation, SC_AC_UNKNOWN, SC_AC_KEY_REF_NONE);
-     }
-     return 0;
-}
-
-
-static int jcop_process_fci(sc_card_t *card, sc_file_t *file,
-			    const u8 *buf, size_t buflen) {
-     struct jcop_private_data *drvdata=DRVDATA(card);
-     struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
-     const struct sc_card_operations *iso_ops = iso_drv->ops;
-     u8 *sa;
-     int r;
-
-     /* the FCI for EF's includes a bogus length for the overall structure!  */
-     if (buflen == 19)
-       buflen=24;
-     r=iso_ops->process_fci(card, file, buf, buflen);
-     
-     if (r < 0)
-	  return r;
-     if (file->type != SC_FILE_TYPE_DF) {
-	  if (drvdata->nfiles) {
-	       drvdata->nfiles=-1;
-	       free(drvdata->filelist);
-	       drvdata->filelist=NULL;
-	  }
-	  if(file->sec_attr_len >=3) {
-	       /* The security attribute bytes are divided into nibbles and are
-		  as follows:
-		  READ | MODIFY || SIGN | ENCIPHER || DECIPHER | DELETE 
-	       */
-	       sa=file->sec_attr;
-	       sa_to_acl(file, SC_AC_OP_READ, sa[0] >> 4);
-	       sa_to_acl(file, SC_AC_OP_UPDATE, sa[0] & 0xf);
-	       /* Files may be locked by anyone who can MODIFY. */
-	       /* opensc seems to think LOCK ACs are only on DFs */
-	       /* sa_to_acl(file, SC_AC_OP_LOCK, sa[0] & 0xf); */
-	       /* there are separate SIGN, ENCIPHER, and DECIPHER ACs.
-		  I use SIGN for SC_AC_OP_CRYPTO unless it is NEVER, in 
-		  which case I use DECIPHER */
-	       if ((sa[1] & 0xf0) == 0x10)
-		    sa_to_acl(file, SC_AC_OP_CRYPTO, sa[1] >> 4);
-	       else
-		    sa_to_acl(file, SC_AC_OP_CRYPTO, sa[2] >> 4);
-	       sa_to_acl(file, SC_AC_OP_ERASE, sa[2] & 0xf);
-	  }
-     } else {
-	  /* No AC information is reported for the AppDF */
-	  sc_file_add_acl_entry(file, SC_AC_OP_SELECT, SC_AC_NONE, 0);
-	  sc_file_add_acl_entry(file, SC_AC_OP_CREATE, SC_AC_CHV, 3);
-	  sc_file_add_acl_entry(file, SC_AC_OP_DELETE, SC_AC_NONE, 0);
-	  sc_file_add_acl_entry(file, SC_AC_OP_LIST_FILES, SC_AC_NONE, 0);
-	  if (drvdata->nfiles) {
-	       drvdata->nfiles=0;
-	       free(drvdata->filelist);
-	       drvdata->filelist=NULL;
-	  }    
-	  /* the format of the poprietary attributes is:
-	     4 bytes     unique id
-	     1 byte      # files in DF
-	     2 bytes     1st File ID
-	     2 bytes     2nd File ID
-	     ...
-	  */
-	  if (file->prop_attr_len > 4) {
-	       int nfiles;
-	       u8 *filelist;
-	       nfiles=file->prop_attr[4];
-	       if (nfiles) {
-		    filelist=malloc(2*nfiles);
-		    if (!filelist)
-			 return SC_ERROR_OUT_OF_MEMORY;
-		    memcpy(filelist, &file->prop_attr[5], 2*nfiles);
-		    drvdata->nfiles=nfiles;
-		    drvdata->filelist=filelist;
-	       }
-	  }
-     }
-     
-     return r;
-}
-static int acl_to_ac_nibble(const sc_acl_entry_t *e)
-{
-        if (e == NULL)
-                return -1;
-        if (e->next != NULL)    /* FIXME */
-                return -1;
-        switch (e->method) {
-        case SC_AC_NONE:
-                return 0x00;
-        case SC_AC_NEVER:
-                return 0x01;
-        case SC_AC_CHV:
-                switch (e->key_ref) {
-                case 1:
-                        return 0x02;
-                case 2:
-                        return 0x03;
-                case 3:
-                        return 0x04;
-                }
-                return -1;
-        case SC_AC_AUT:
-                return 0x05;
-        case SC_AC_PRO:
-                return 0x06;
-        }
-        return -1;
-}
-
-
-static int jcop_create_file(sc_card_t *card, sc_file_t *file) {
-     struct jcop_private_data *drvdata=DRVDATA(card);
-     unsigned char sec_attr_data[3];
-     int ops[6];
-     int i, r;
-     struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
-     const struct sc_card_operations *iso_ops = iso_drv->ops;
-     
-     if (drvdata->selected == SELECT_MF || drvdata->selected == SELECT_EFDIR )
-	  return sc_check_sw(card, 0x69, 0x82);
-     
-     /* Can't create DFs */
-     if (file->type != SC_FILE_TYPE_WORKING_EF)
-	  return sc_check_sw(card, 0x6A, 0x80);
-     
-     ops[0] = SC_AC_OP_READ;      /* read */
-     ops[1] = SC_AC_OP_UPDATE;    /* modify */
-     ops[2] = SC_AC_OP_CRYPTO;    /* sign */
-     ops[3] = -1;                 /* encipher */
-     ops[4] = SC_AC_OP_CRYPTO;    /* decipher */
-     ops[5] = SC_AC_OP_ERASE;     /* delete */
-     memset(sec_attr_data, 0, 3);
-     for (i = 0; i < 6; i++) {
-	  const sc_acl_entry_t *entry;
-	  if (ops[i] == -1) {
-	       sec_attr_data[i/2] |= 1 << ((i % 2) ? 0 : 4);
-	       continue;
-	  }
-	  
-	  entry = sc_file_get_acl_entry(file, ops[i]);
-	  r = acl_to_ac_nibble(entry);
-	  if (r >= 0) {
-		sec_attr_data[i/2] |= r << ((i % 2) ? 0 : 4);
-	  }
-     }
-
-     sc_file_set_sec_attr(file, sec_attr_data, 3);
-     
-     r=iso_ops->create_file(card, file);
-     if (r > 0)
-          drvdata->selected=SELECT_EF;
-     return r;
-}
-
-
-/* We need to trap these functions so that proper errors can be returned
-   when one of the virtual files is selected */
-static int jcop_write_binary(sc_card_t *card,
-			unsigned int idx, const u8 *buf,
-			size_t count, unsigned long flags) {
-     struct jcop_private_data *drvdata=DRVDATA(card);
-     struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
-     const struct sc_card_operations *iso_ops = iso_drv->ops;
-
-     if (drvdata->selected == SELECT_MF)
-	       return sc_check_sw(card, 0x6A, 0x86);
-     if (drvdata->selected == SELECT_EFDIR)
-	       return sc_check_sw(card, 0x69, 0x82);
-
-     return iso_ops->write_binary(card, idx, buf, count, flags);
-}
-
-
-static int jcop_update_binary(sc_card_t *card,
-			 unsigned int idx, const u8 *buf,
-			 size_t count, unsigned long flags) {
-     
-     struct jcop_private_data *drvdata=DRVDATA(card);
-     struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
-     const struct sc_card_operations *iso_ops = iso_drv->ops;
-     if (drvdata->selected == SELECT_MF)
-	       return sc_check_sw(card, 0x69, 0x86);
-     if (drvdata->selected == SELECT_EFDIR)
-	       return sc_check_sw(card, 0x69, 0x82);
-
-     return iso_ops->update_binary(card, idx, buf, count, flags);
-}
-
-static int jcop_delete_file(sc_card_t *card, const sc_path_t *path) {
-     struct jcop_private_data *drvdata=DRVDATA(card);
-     struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
-     const struct sc_card_operations *iso_ops = iso_drv->ops;
-
-     if (drvdata->selected == SELECT_MF || drvdata->selected == SELECT_EFDIR )
-          return sc_check_sw(card, 0x69, 0x82);
-
-     return iso_ops->delete_file(card, path);
-}
-
-
-/* BlueZ doesn't support stored security environments. you have
-   to construct one with SET every time */
-static int jcop_set_security_env(sc_card_t *card,
-                                    const sc_security_env_t *env,
-                                    int se_num)
-{
-        sc_apdu_t apdu;
-        u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
-        u8 *p;
-        int r;
-	struct jcop_private_data *drvdata=DRVDATA(card);
-
-        assert(card != NULL && env != NULL);
-	if (se_num) 
-	     LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
-	if (drvdata->selected == SELECT_MF || 
-	    drvdata->selected == SELECT_EFDIR) {
-	     drvdata->invalid_senv=1;
-	     return 0;
-	}
-	
-        if (env->flags & SC_SEC_ENV_ALG_PRESENT) {
-                sc_security_env_t tmp;
-
-                tmp = *env;
-                tmp.flags &= ~SC_SEC_ENV_ALG_PRESENT;
-                tmp.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
-                if (tmp.algorithm != SC_ALGORITHM_RSA) {
-                        sc_log(card->ctx,  "Only RSA algorithm supported.\n");
-                        return SC_ERROR_NOT_SUPPORTED;
-                }
-                if (!(env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1)){
-                        sc_log(card->ctx,  "Card requires RSA padding\n");
-                        return SC_ERROR_NOT_SUPPORTED;
-                }
-                tmp.algorithm_ref = 0x02;
-                /* potential FIXME: return an error, if an unsupported
-                 * pad or hash was requested, although this shouldn't happen.
-                 */
-                if (tmp.algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
-                        tmp.algorithm_ref |= 0x10;
-                if (tmp.algorithm_flags & SC_ALGORITHM_RSA_HASH_MD5)
-                        tmp.algorithm_ref |= 0x20;
-
-		memcpy((sc_security_env_t *) env, &tmp, sizeof(struct sc_security_env));
-	}
-	
-        sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xC1, 0);
-        switch (env->operation) {
-        case SC_SEC_OPERATION_DECIPHER:
-	     apdu.p2 = 0xB8;
-	     break;
-        case SC_SEC_OPERATION_SIGN:
-	     apdu.p2 = 0xB6;
-	     break;
-        default:
-	     return SC_ERROR_INVALID_ARGUMENTS;
-        }
-        apdu.le = 0;
-        if (!(env->flags & SC_SEC_ENV_ALG_REF_PRESENT))
-	     return SC_ERROR_INVALID_ARGUMENTS;
-        if (!(env->flags & SC_SEC_ENV_FILE_REF_PRESENT))
-	     return SC_ERROR_INVALID_ARGUMENTS;
-        if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT) {
-	     if (env->key_ref_len > 1 || env->key_ref[0] != 0)
-		  return SC_ERROR_INVALID_ARGUMENTS;
-	}
-
-        p = sbuf;
-	*p++ = 0x80;    /* algorithm reference */
-	*p++ = 0x01;
-	*p++ = env->algorithm_ref & 0xFF;
-
-	*p++ = 0x81;
-	*p++ = env->file_ref.len;
-	memcpy(p, env->file_ref.value, env->file_ref.len);
-	p += env->file_ref.len;
-
-        r = p - sbuf;
-        apdu.lc = r;
-        apdu.datalen = r;
-        apdu.data = sbuf;
-        apdu.resplen = 0;
-	r = sc_transmit_apdu(card, &apdu);
-	if (r) {
-	     sc_log(card->ctx, 
-		"%s: APDU transmit failed", sc_strerror(r));
-	     return r;
-	}
-	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
-	if (r) {
-	     sc_log(card->ctx,  
-		"%s: Card returned error", sc_strerror(r));
-	     return r;
-	}
-	drvdata->invalid_senv=0;
-	return 0;
-}
-static int jcop_compute_signature(sc_card_t *card,
-				  const u8 * data, size_t datalen,
-				  u8 * out, size_t outlen) {
-
-
-       int r;
-        sc_apdu_t apdu;
-        u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
-        u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
-	struct jcop_private_data *drvdata=DRVDATA(card);
-
-        assert(card != NULL && data != NULL && out != NULL);
-        if (datalen > 256)
-                SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
-
-	if (drvdata->invalid_senv)
-	     return sc_check_sw(card, 0x69, 0x88);
-
-        /* INS: 0x2A  PERFORM SECURITY OPERATION
-         * P1:  0x9E  Resp: Digital Signature
-         * P2:  0x9A  Cmd: Input for Digital Signature */
-        sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x9E,
-                       0x9A);
-        apdu.resp = rbuf;
-        apdu.resplen = sizeof(rbuf); /* FIXME */
-        apdu.le = 256;
-	if (datalen == 256) {
-	     apdu.p2 = data[0];
-	     memcpy(sbuf, data+1, datalen-1);
-	     apdu.lc = datalen - 1;
-	     apdu.datalen = datalen - 1;
-	} else {
-	     memcpy(sbuf, data, datalen);
-	     apdu.lc = datalen;
-	     apdu.datalen = datalen;
-	}
-
-        apdu.data = sbuf;
-        r = sc_transmit_apdu(card, &apdu);
-        LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
-        if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
-                int len = apdu.resplen > outlen ? outlen : apdu.resplen;
-
-                memcpy(out, apdu.resp, len);
-                SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, len);
-        }
-        SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
-}
- 
-
-
-static int jcop_decipher(sc_card_t *card,
-			 const u8 * crgram, size_t crgram_len,
-			 u8 * out, size_t outlen) {
-
-        int r;
-        sc_apdu_t apdu;
-        u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
-        u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
-	struct jcop_private_data *drvdata=DRVDATA(card);
-
-        assert(card != NULL && crgram != NULL && out != NULL);
-        LOG_FUNC_CALLED(card->ctx);
-        if (crgram_len > 256)
-                SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
-	if (drvdata->invalid_senv)
-	     return sc_check_sw(card, 0x69, 0x88);
-
-        /* INS: 0x2A  PERFORM SECURITY OPERATION
-         * P1:  0x80  Resp: Plain value
-         * P2:  0x86  Cmd: Padding indicator byte followed by cryptogram */
-        sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x86);
-        apdu.resp = rbuf;
-        apdu.resplen = sizeof(rbuf); /* FIXME */
-        apdu.le = crgram_len;
-        
-	if (crgram_len == 256) {
-	     apdu.p2 = crgram[0];
-	     memcpy(sbuf, crgram+1, crgram_len-1);
-	     apdu.lc = crgram_len - 1;
-	     apdu.datalen = crgram_len -1;
-	} else {
-	     sbuf[0] = 0; /* padding indicator byte, 0x00 = No further indication */
-	     memcpy(sbuf + 1, crgram, crgram_len);
-	     apdu.lc = crgram_len + 1;
-	     apdu.datalen = crgram_len + 1;
-	}
-	
-        apdu.data = sbuf;
-        r = sc_transmit_apdu(card, &apdu);
-        LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
-        if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
-                int len = apdu.resplen > outlen ? outlen : apdu.resplen;
-
-                memcpy(out, apdu.resp, len);
-                SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, len);
-        }
-        SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
-}
- 
-static int jcop_generate_key(sc_card_t *card, struct sc_cardctl_jcop_genkey *a) {
-     int r;
-     sc_apdu_t apdu;
-     u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
-     u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
-     u8 *p;
-     int is_f4;
-     struct jcop_private_data *drvdata=DRVDATA(card);
-
-     if (drvdata->selected == SELECT_MF || drvdata->selected == SELECT_EFDIR )
-	  return sc_check_sw(card, 0x6A, 0x82);
-
-     is_f4=0;
-     
-     if (a->exponent == 0x10001) {
-	  is_f4=1;
-     } else if (a->exponent != 3) {
-	  sc_log(card->ctx,  
-		"%s: Invalid exponent", sc_strerror(SC_ERROR_NOT_SUPPORTED));
-	  return SC_ERROR_NOT_SUPPORTED;
-     }
-     
-     sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xC1, 0xB6);
-
-     p = sbuf;
-     *p++ = 0x80;    /* algorithm reference */
-     *p++ = 0x01;
-     *p++ = is_f4 ? 0x6E : 0x6D;
-     
-     *p++ = 0x81;
-     *p++ = a->pub_file_ref.len;
-     memcpy(p, a->pub_file_ref.value, a->pub_file_ref.len);
-     p += a->pub_file_ref.len;
-     
-     *p++ = 0x81;
-     *p++ = a->pri_file_ref.len;
-     memcpy(p, a->pri_file_ref.value, a->pri_file_ref.len);
-     p += a->pri_file_ref.len;
-     
-     r = p - sbuf;
-
-     apdu.lc = r;
-     apdu.datalen = r;
-     apdu.data = sbuf;
-     apdu.resplen = 0;
-     r = sc_transmit_apdu(card, &apdu);
-     if (r) {
-	  sc_log(card->ctx,  
-		"%s: APDU transmit failed", sc_strerror(r));
-	  return r;
-     }
-     r = sc_check_sw(card, apdu.sw1, apdu.sw2);
-     if (r) {
-	  sc_log(card->ctx,  
-	  	"%s: Card returned error", sc_strerror(r));
-	  return r;
-     }
-
-     sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0x46, 0, 0);
-
-     apdu.le = 256;
-     apdu.resp=rbuf;
-     apdu.resplen = sizeof(rbuf);
-     
-     r = sc_transmit_apdu(card, &apdu);
-     if (r) {
-	  sc_log(card->ctx,  
-		"%s: APDU transmit failed", sc_strerror(r));
-	  return r;
-     }
-     r = sc_check_sw(card, apdu.sw1, apdu.sw2);
-     if (r) {
-	  sc_log(card->ctx,  
-		"%s: Card returned error", sc_strerror(r));
-	  return r;
-     }
-
-     if (rbuf[0] != 0x4) {
-	  return SC_ERROR_INVALID_DATA;
-     }
-     if (a->pubkey_len < rbuf[1])
-	  return SC_ERROR_BUFFER_TOO_SMALL;
-     a->pubkey_len=rbuf[1] * 4;
-     memcpy(a->pubkey, &rbuf[2], a->pubkey_len);
-     
-     return 0;
-}
-
-static int jcop_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
-{
-        switch (cmd) {
-        case SC_CARDCTL_GET_DEFAULT_KEY:
-                return jcop_get_default_key(card,
-                                (struct sc_cardctl_default_key *) ptr);
-        case SC_CARDCTL_JCOP_GENERATE_KEY:
-                return jcop_generate_key(card,
-                                (struct sc_cardctl_jcop_genkey *) ptr);
-        }
-
-        return SC_ERROR_NOT_SUPPORTED;
-}
-
-static struct sc_card_driver * sc_get_driver(void)
-{
-     struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
-
-     jcop_ops = *iso_drv->ops;
-     jcop_ops.match_card = jcop_match_card;
-     jcop_ops.init = jcop_init;
-     jcop_ops.finish = jcop_finish;
-     /* no record oriented file services */
-     jcop_ops.read_record = NULL;
-     jcop_ops.write_record = NULL;
-     jcop_ops.append_record = NULL;
-     jcop_ops.update_record = NULL;
-     jcop_ops.read_binary = jcop_read_binary;
-     jcop_ops.write_binary = jcop_write_binary;
-     jcop_ops.update_binary = jcop_update_binary;
-     jcop_ops.select_file = jcop_select_file;
-     jcop_ops.create_file = jcop_create_file;
-     jcop_ops.delete_file = jcop_delete_file;
-     jcop_ops.list_files = jcop_list_files;
-     jcop_ops.set_security_env = jcop_set_security_env;
-     jcop_ops.compute_signature = jcop_compute_signature;
-     jcop_ops.decipher = jcop_decipher;
-     jcop_ops.process_fci = jcop_process_fci;
-     jcop_ops.card_ctl = jcop_card_ctl;
-     
-     return &jcop_drv;
-}
-
-struct sc_card_driver * sc_get_jcop_driver(void)
-{
-     return sc_get_driver();
-}
-
diff -Nru opensc-0.22.0/src/libopensc/card-miocos.c opensc-0.23.0/src/libopensc/card-miocos.c
--- opensc-0.22.0/src/libopensc/card-miocos.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-miocos.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,504 +0,0 @@
-/*
- * card-miocos.c: Support for PKI cards by Miotec
- *
- * Copyright (C) 2002  Juha Yrjölä <juha.yrjola at iki.fi>
- *
- * 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 HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <stdlib.h>
-#include <string.h>
-
-#include "internal.h"
-#include "asn1.h"
-#include "cardctl.h"
-
-static const struct sc_atr_table miocos_atrs[] = {
-	/* Test card with 32 kB memory */
-	{ "3B:9D:94:40:23:00:68:10:11:4D:69:6F:43:4F:53:00:90:00", NULL, NULL, SC_CARD_TYPE_MIOCOS_GENERIC, 0, NULL },
-	/* Test card with 64 kB memory */
-	{ "3B:9D:94:40:23:00:68:20:01:4D:69:6F:43:4F:53:00:90:00", NULL, NULL, SC_CARD_TYPE_MIOCOS_GENERIC, 0, NULL },
-	{ NULL, NULL, NULL, 0, 0, NULL }
-};
-
-static struct sc_card_operations miocos_ops;
-static struct sc_card_driver miocos_drv = {
-	"MioCOS 1.1",
-	"miocos",
-	&miocos_ops,
-	NULL, 0, NULL
-};
-
-static int miocos_match_card(sc_card_t *card)
-{
-	int i;
-
-	i = _sc_match_atr(card, miocos_atrs, &card->type);
-	if (i < 0)
-		return 0;
-	return 1;
-}
-
-static int miocos_init(sc_card_t *card)
-{
-	card->name = "MioCOS";
-	card->cla = 0x00;
-
-	if (1) {
-		unsigned long flags;
-		
-		flags = SC_ALGORITHM_RSA_RAW | SC_ALGORITHM_RSA_PAD_PKCS1;
-		flags |= SC_ALGORITHM_RSA_HASH_NONE | SC_ALGORITHM_RSA_HASH_SHA1;
-
-		_sc_card_add_rsa_alg(card, 1024, flags, 0);
-	}
-
-	/* read_binary and friends shouldn't do more than 244 bytes
-	 * per operation */
-	card->max_send_size = 244;
-	card->max_recv_size = 244;
-
-	return 0;
-}
-
-static const struct sc_card_operations *iso_ops = NULL;
-
-static int acl_to_byte(const sc_acl_entry_t *e)
-{
-	switch (e->method) {
-	case SC_AC_NONE:
-		return 0x00;
-	case SC_AC_CHV:
-	case SC_AC_TERM:
-	case SC_AC_AUT:
-		if (e->key_ref == SC_AC_KEY_REF_NONE)
-			return -1;
-		if (e->key_ref < 1 || e->key_ref > 14)
-			return -1;
-		return e->key_ref;
-	case SC_AC_NEVER:
-		return 0x0F;
-	}
-	return 0x00;
-}
-
-static int encode_file_structure(sc_card_t *card, const sc_file_t *file,
-				 u8 *buf, size_t *buflen)
-{
-	u8 *p = buf;
-	const int df_ops[8] = {
-		SC_AC_OP_DELETE, SC_AC_OP_CREATE,
-		/* RFU */ -1, /* CREATE AC */ SC_AC_OP_CREATE,
-		/* UPDATE AC */ SC_AC_OP_CREATE, -1, -1, -1
-	};
-	const int ef_ops[8] = {
-		/* DELETE */ SC_AC_OP_UPDATE, -1, SC_AC_OP_READ,
-		SC_AC_OP_UPDATE, -1, -1, SC_AC_OP_INVALIDATE,
-		SC_AC_OP_REHABILITATE
-	};
-	const int key_ops[8] = {
-		/* DELETE */ SC_AC_OP_UPDATE, -1, -1,
-		SC_AC_OP_UPDATE, SC_AC_OP_CRYPTO, -1, SC_AC_OP_INVALIDATE,
-		SC_AC_OP_REHABILITATE
-	};
-        const int *ops;
-        int i;
-
-	*p++ = file->id >> 8;
-	*p++ = file->id & 0xFF;
-	switch (file->type) {
-	case SC_FILE_TYPE_DF:
-		*p++ = 0x20;
-		ops = df_ops;
-		break;
-	case SC_FILE_TYPE_WORKING_EF:
-		switch (file->ef_structure) {
-		case SC_FILE_EF_TRANSPARENT:
-			*p++ = 0x40;
-			break;
-		case SC_FILE_EF_LINEAR_FIXED:
-			*p++ = 0x41;
-                        break;
-		case SC_FILE_EF_CYCLIC:
-			*p++ = 0x43;
-			break;
-		default:
-			sc_log(card->ctx,  "Invalid EF structure\n");
-			return SC_ERROR_INVALID_ARGUMENTS;
-		}
-		ops = ef_ops;
-		break;
-	case SC_FILE_TYPE_INTERNAL_EF:
-		*p++ = 0x44;
-		ops = key_ops;
-		break;
-	default:
-		sc_log(card->ctx,  "Unknown file type\n");
-                return SC_ERROR_INVALID_ARGUMENTS;
-	}
-	if (file->type == SC_FILE_TYPE_DF) {
-		*p++ = 0;
-		*p++ = 0;
-	} else {
-		*p++ = file->size >> 8;
-		*p++ = file->size & 0xFF;
-	}
-	if (file->sec_attr_len == 4) {
-		memcpy(p, file->sec_attr, 4);
-		p += 4;
-	} else for (i = 0; i < 8; i++) {
-		u8 nibble;
-
-		if (ops[i] == -1)
-			nibble = 0x00;
-		else {
-			int byte = acl_to_byte(sc_file_get_acl_entry(file, ops[i]));
-			if (byte < 0) {
-				sc_log(card->ctx,  "Invalid ACL\n");
-				return SC_ERROR_INVALID_ARGUMENTS;
-			}
-			nibble = byte;
-		}
-		if ((i & 1) == 0)
-			*p = nibble << 4;
-		else {
-			*p |= nibble & 0x0F;
-			p++;
-		}
-	}
-	if (file->type == SC_FILE_TYPE_WORKING_EF &&
-	    file->ef_structure != SC_FILE_EF_TRANSPARENT)
-                *p++ = file->record_length;
-	else
-		*p++ = 0;
-	if (file->status == SC_FILE_STATUS_INVALIDATED)
-		*p++ = 0;
-	else
-		*p++ = 0x01;
-	if (file->type == SC_FILE_TYPE_DF && file->namelen) {
-                assert(file->namelen <= 16);
-		memcpy(p, file->name, file->namelen);
-		p += file->namelen;
-	}
-	*buflen = p - buf;
-
-        return 0;
-}
-
-static int miocos_create_file(sc_card_t *card, sc_file_t *file)
-{
-	sc_apdu_t apdu;
-	u8 sbuf[32];
-        size_t buflen;
-	int r;
-
-	r = encode_file_structure(card, file, sbuf, &buflen);
-	if (r)
-		return r;
-	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xE0, 0x00, 0x00);
-	apdu.data = sbuf;
-	apdu.datalen = buflen;
-	apdu.lc = buflen;
-
-	r = sc_transmit_apdu(card, &apdu);
-        LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
-        if (apdu.sw1 == 0x6A && apdu.sw2 == 0x89)
-        	return SC_ERROR_FILE_ALREADY_EXISTS;
-        r = sc_check_sw(card, apdu.sw1, apdu.sw2);
-        LOG_TEST_RET(card->ctx, r, "Card returned error");
-
-	return 0;
-}
-
-static int miocos_set_security_env(sc_card_t *card,
-				  const sc_security_env_t *env,
-				  int se_num)
-{
-	if (env->flags & SC_SEC_ENV_ALG_PRESENT) {
-		sc_security_env_t tmp;
-
-		tmp = *env;
-		tmp.flags &= ~SC_SEC_ENV_ALG_PRESENT;
-		tmp.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
-		if (tmp.algorithm != SC_ALGORITHM_RSA) {
-			sc_log(card->ctx,  "Only RSA algorithm supported.\n");
-			return SC_ERROR_NOT_SUPPORTED;
-		}
-		tmp.algorithm_ref = 0x00;
-		/* potential FIXME: return an error, if an unsupported
-		 * pad or hash was requested, although this shouldn't happen.
-		 */
-		if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1)
-			tmp.algorithm_ref = 0x02;
-		if (tmp.algorithm_flags & SC_ALGORITHM_RSA_HASH_SHA1)
-			tmp.algorithm_ref |= 0x10;
-		return iso_ops->set_security_env(card, &tmp, se_num);
-	}
-	return iso_ops->set_security_env(card, env, se_num);
-}
-
-static void add_acl_entry(sc_file_t *file, int op, u8 byte)
-{
-	unsigned int method, key_ref = SC_AC_KEY_REF_NONE;
-
-	switch (byte) {
-	case 0:
-		method = SC_AC_NONE;
-		break;
-	case 15:
-		method = SC_AC_NEVER;
-		break;
-	default:
-		method = SC_AC_CHV;
-		key_ref = byte;
-		break;
-	}
-	sc_file_add_acl_entry(file, op, method, key_ref);
-}
-
-static void parse_sec_attr(sc_file_t *file, const u8 *buf, size_t len)
-{
-	int i;
-	const int df_ops[8] = {
-		SC_AC_OP_DELETE, SC_AC_OP_CREATE,
-		-1, /* CREATE AC */ -1, /* UPDATE AC */ -1, -1, -1, -1
-	};
-	const int ef_ops[8] = {
-		SC_AC_OP_DELETE, -1, SC_AC_OP_READ,
-		SC_AC_OP_UPDATE, -1, -1, SC_AC_OP_INVALIDATE,
-		SC_AC_OP_REHABILITATE
-	};
-	const int key_ops[8] = {
-		SC_AC_OP_DELETE, -1, -1,
-		SC_AC_OP_UPDATE, SC_AC_OP_CRYPTO, -1, SC_AC_OP_INVALIDATE,
-		SC_AC_OP_REHABILITATE
-	};
-        const int *ops;
-
-	if (len < 4)
-                return;
-	switch (file->type) {
-	case SC_FILE_TYPE_WORKING_EF:
-		ops = ef_ops;
-		break;
-	case SC_FILE_TYPE_INTERNAL_EF:
-		ops = key_ops;
-		break;
-	case SC_FILE_TYPE_DF:
-		ops = df_ops;
-		break;
-	default:
-                return;
-	}
-	for (i = 0; i < 8; i++) {
-		if (ops[i] == -1)
-			continue;
-		if ((i & 1) == 0)
-			add_acl_entry(file, ops[i], (u8)(buf[i / 2] >> 4));
-		else
-			add_acl_entry(file, ops[i], (u8)(buf[i / 2] & 0x0F));
-	}
-}
-
-static int miocos_get_acl(sc_card_t *card, sc_file_t *file)
-{
-	sc_apdu_t apdu;
-	u8 rbuf[256];
-	const u8 *seq = rbuf;
-	size_t left;
-	int r;
-	unsigned int i;
-	
-	sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, 0x01);
-	apdu.resp = rbuf;
-	apdu.resplen = sizeof(rbuf);
-	apdu.le = sizeof(rbuf);
-	r = sc_transmit_apdu(card, &apdu);
-	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
-	if (apdu.resplen == 0)
-		return sc_check_sw(card, apdu.sw1, apdu.sw2);
-	left = apdu.resplen;
-	seq = sc_asn1_skip_tag(card->ctx, &seq, &left,
-			       SC_ASN1_SEQUENCE | SC_ASN1_CONS, &left);
-	if (seq == NULL)
-		LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN_DATA_RECEIVED);
-	LOG_TEST_RET(card->ctx, r, "Unable to process reply");
-	for (i = 1; i < 15; i++) {
-		int j;
-		const u8 *tag;
-		size_t taglen;
-		
-		tag = sc_asn1_skip_tag(card->ctx, &seq, &left,
-				       SC_ASN1_CTX | i, &taglen);
-		if (tag == NULL || taglen == 0)
-			continue;
-		for (j = 0; j < SC_MAX_AC_OPS; j++) {
-			sc_acl_entry_t *e;
-			
-			e = (sc_acl_entry_t *) sc_file_get_acl_entry(file, j);
-			if (e == NULL)
-				continue;
-			if (e->method != SC_AC_CHV)
-				continue;
-			if (e->key_ref != i)
-				continue;
-			switch (tag[0]) {
-			case 0x01:
-				e->method = SC_AC_CHV;
-				break;
-			case 0x02:
-				e->method = SC_AC_AUT;
-				break;
-			default:
-				e->method = SC_AC_UNKNOWN;
-				break;
-			}
-		}
-	}
-	return 0;
-}
-
-static int miocos_select_file(sc_card_t *card,
-			       const sc_path_t *in_path,
-			       sc_file_t **file)
-{
-	int r;
-
-	r = iso_ops->select_file(card, in_path, file);
-	if (r)
-		return r;
-	if (file != NULL && *file != NULL) {
-		parse_sec_attr(*file, (*file)->sec_attr, (*file)->sec_attr_len);
-		miocos_get_acl(card, *file);
-	}
-
-	return 0;
-}
-
-static int miocos_list_files(sc_card_t *card, u8 *buf, size_t buflen)
-{
-	sc_apdu_t apdu;
-	int r;
-
-	sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xCA, 0x01, 0);
-	apdu.resp = buf;
-	apdu.resplen = buflen;
-	apdu.le = buflen > 256 ? 256 : buflen;
-	r = sc_transmit_apdu(card, &apdu);
-	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
-	if (apdu.resplen == 0)
-		return sc_check_sw(card, apdu.sw1, apdu.sw2);
-	return apdu.resplen;
-}
-
-static int miocos_delete_file(sc_card_t *card, const sc_path_t *path)
-{
-	int r;
-	sc_apdu_t apdu;
-
-	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
-	if (path->type != SC_PATH_TYPE_FILE_ID && path->len != 2) {
-		sc_log(card->ctx,  "File type has to be SC_PATH_TYPE_FILE_ID\n");
-		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
-	}
-	r = sc_select_file(card, path, NULL);
-	LOG_TEST_RET(card->ctx, r, "Unable to select file to be deleted");
-	
-	sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0xE4, 0x00, 0x00);
-	apdu.cla = 0xA0;
-
-	r = sc_transmit_apdu(card, &apdu);
-	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
-	return sc_check_sw(card, apdu.sw1, apdu.sw2);
-}
-
-static int miocos_create_ac(sc_card_t *card,
-			    struct sc_cardctl_miocos_ac_info *ac)
-{
-	sc_apdu_t apdu;
-	u8 sbuf[20];
-	int miocos_type, r;
-	size_t sendsize;
-	
-	if (ac->max_tries > 15)
-		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
-	switch (ac->type) {
-	case SC_CARDCTL_MIOCOS_AC_PIN:
-		if (ac->max_unblock_tries > 15)
-			LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
-		miocos_type = 0x01;
-		sbuf[0] = (ac->max_tries << 4) | ac->max_tries;
-		sbuf[1] = 0xFF; /* FIXME... */
-		memcpy(sbuf + 2, ac->key_value, 8);
-		sbuf[10] = (ac->max_unblock_tries << 4) | ac->max_unblock_tries;
-		sbuf[11] = 0xFF;
-		memcpy(sbuf + 12, ac->unblock_value, 8);
-		sendsize = 20;
-		break;
-	default:
-		sc_log(card->ctx,  "AC type %d not supported\n", ac->type);
-		return SC_ERROR_NOT_SUPPORTED;
-	}
-	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x1E, miocos_type,
-		       ac->ref);
-	apdu.lc = sendsize;
-	apdu.datalen = sendsize;
-	apdu.data = sbuf;
-	r = sc_transmit_apdu(card, &apdu);
-	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
-	return sc_check_sw(card, apdu.sw1, apdu.sw2);
-}
-
-static int miocos_card_ctl(sc_card_t *card, unsigned long cmd,
-			   void *arg)
-{
-	switch (cmd) {
-	case SC_CARDCTL_MIOCOS_CREATE_AC:
-		return miocos_create_ac(card, (struct sc_cardctl_miocos_ac_info *) arg);
-	}
-	sc_log(card->ctx,  "card_ctl command 0x%lX not supported\n", cmd);
-	return SC_ERROR_NOT_SUPPORTED;
-}
-
-
-static struct sc_card_driver * sc_get_driver(void)
-{
-	struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
-
-	miocos_ops = *iso_drv->ops;
-	miocos_ops.match_card = miocos_match_card;
-	miocos_ops.init = miocos_init;
-	if (iso_ops == NULL)
-                iso_ops = iso_drv->ops;
-	miocos_ops.create_file = miocos_create_file;
-	miocos_ops.set_security_env = miocos_set_security_env;
-	miocos_ops.select_file = miocos_select_file;
-	miocos_ops.list_files = miocos_list_files;
-	miocos_ops.delete_file = miocos_delete_file;
-	miocos_ops.card_ctl = miocos_card_ctl;
-	
-        return &miocos_drv;
-}
-
-#if 1
-struct sc_card_driver * sc_get_miocos_driver(void)
-{
-	return sc_get_driver();
-}
-#endif
diff -Nru opensc-0.22.0/src/libopensc/card-muscle.c opensc-0.23.0/src/libopensc/card-muscle.c
--- opensc-0.22.0/src/libopensc/card-muscle.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-muscle.c	2022-11-29 09:34:43.000000000 +0100
@@ -122,7 +122,9 @@
 		case SC_AC_UNKNOWN:
 			break;
 		case SC_AC_CHV:
-			acl_entry |= (1 << key); /* Assuming key 0 == SO */
+			/* Ignore shift with more bits that acl_entry has */
+			if ((size_t) key < sizeof(acl_entry) * 8)
+				acl_entry |= (1u << key); /* Assuming key 0 == SO */
 			break;
 		case SC_AC_AUT:
 		case SC_AC_TERM:
@@ -270,6 +272,7 @@
 	msc_id id = file_data->objectId;
 	u8* oid = id.id;
 	int r;
+	file_data->deleteFile = 1;
 
 	if(!file_data->ef) {
 		int x;
@@ -285,13 +288,14 @@
 			childFile = &fs->cache.array[x];
 			objectId = childFile->objectId;
 
-			if(0 == memcmp(oid + 2, objectId.id, 2)) {
+			if(0 == memcmp(oid + 2, objectId.id, 2) && !childFile->deleteFile) {
 				sc_log(card->ctx, 
 					"DELETING: %02X%02X%02X%02X\n",
 					objectId.id[0],objectId.id[1],
 					objectId.id[2],objectId.id[3]);
 				r = muscle_delete_mscfs_file(card, childFile);
 				if(r < 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,r);
+
 			}
 		}
 		oid[0] = oid[2];
@@ -299,9 +303,6 @@
 		oid[2] = oid[3] = 0;
 		/* ??? objectId = objectId >> 16; */
 	}
-	if((0 == memcmp(oid, "\x3F\x00\x00\x00", 4))
-		|| (0 == memcmp(oid, "\x3F\x00\x3F\x00", 4))) {
-	}
 	r = msc_delete_object(card, id, 1);
 	/* Check if its the root... this file generally is virtual
 	 * So don't return an error if it fails */
@@ -325,6 +326,10 @@
 
 	r = mscfs_loadFileInfo(fs, path_in->value, path_in->len, &file_data, NULL);
 	if(r < 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,r);
+	for(int x = 0; x < fs->cache.size; x++) {
+		mscfs_file_t *file = &fs->cache.array[x];
+		file->deleteFile = 0;
+	}
 	r = muscle_delete_mscfs_file(card, file_data);
 	mscfs_clear_cache(fs);
 	if(r < 0) SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,r);
@@ -555,7 +560,9 @@
 		case SC_AC_CHV: {
 			sc_apdu_t apdu;
 			int r;
-			msc_verify_pin_apdu(card, &apdu, buffer, bufferLength, cmd->pin_reference, cmd->pin1.data, cmd->pin1.len);
+			r = msc_verify_pin_apdu(card, &apdu, buffer, bufferLength, cmd->pin_reference, cmd->pin1.data, cmd->pin1.len);
+			if (r < 0)
+				return r;
 			cmd->apdu = &apdu;
 			cmd->pin1.offset = 5;
 			r = iso_ops->pin_cmd(card, cmd, tries_left);
@@ -575,7 +582,10 @@
 		switch(cmd->pin_type) {
 		case SC_AC_CHV: {
 			sc_apdu_t apdu;
-			msc_change_pin_apdu(card, &apdu, buffer, bufferLength, cmd->pin_reference, cmd->pin1.data, cmd->pin1.len, cmd->pin2.data, cmd->pin2.len);
+			int r;
+			r = msc_change_pin_apdu(card, &apdu, buffer, bufferLength, cmd->pin_reference, cmd->pin1.data, cmd->pin1.len, cmd->pin2.data, cmd->pin2.len);
+			if (r < 0)
+				return r;
 			cmd->apdu = &apdu;
 			return iso_ops->pin_cmd(card, cmd, tries_left);
 		}
@@ -591,7 +601,10 @@
 	switch(cmd->pin_type) {
 		case SC_AC_CHV: {
 			sc_apdu_t apdu;
-			msc_unblock_pin_apdu(card, &apdu, buffer, bufferLength, cmd->pin_reference, cmd->pin1.data, cmd->pin1.len);
+			int r;
+			r = msc_unblock_pin_apdu(card, &apdu, buffer, bufferLength, cmd->pin_reference, cmd->pin1.data, cmd->pin1.len);
+			if (r < 0)
+				return r;
 			cmd->apdu = &apdu;
 			return iso_ops->pin_cmd(card, cmd, tries_left);
 		}
diff -Nru opensc-0.22.0/src/libopensc/card-myeid.c opensc-0.23.0/src/libopensc/card-myeid.c
--- opensc-0.22.0/src/libopensc/card-myeid.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-myeid.c	2022-11-29 09:34:43.000000000 +0100
@@ -84,6 +84,13 @@
 	 after this pair of calls and must not be used elsewhere. */
 	const struct sc_security_env* sec_env;
 	int disable_hw_pkcs1_padding;
+	/* buffers for AES(DES) block cipher */
+	uint8_t sym_crypt_buffer[16];
+	uint8_t sym_plain_buffer[16];
+	uint8_t sym_crypt_buffer_len;
+	uint8_t sym_plain_buffer_len;
+	/* PSO for AES/DES need algo+flags from sec env */
+	unsigned int algorithm, algorithm_flags;
 } myeid_private_data_t;
 
 typedef struct myeid_card_caps {
@@ -333,6 +340,8 @@
 
 static int acl_to_byte(const struct sc_acl_entry *e)
 {
+	if (NULL == e)
+		return 0x00;
 	switch (e->method) {
 	case SC_AC_NONE:
 		return 0x00;
@@ -425,6 +434,21 @@
 	LOG_FUNC_RETURN(card->ctx, r);
 }
 
+static int myeid_logout(struct sc_card *card)
+{
+	sc_apdu_t apdu;
+	int r;
+
+	LOG_FUNC_CALLED(card->ctx);
+
+	sc_format_apdu(card, &apdu, SC_APDU_CASE_1, 0x2E, 0x00, 0x00 /*pin ref: 0x01-0x0E, 0=ALL*/);
+	apdu.cla = 0;
+
+	r = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+
+	LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2));
+}
 
 static int myeid_list_files(struct sc_card *card, u8 *buf, size_t buflen)
 {
@@ -696,6 +720,8 @@
 	LOG_FUNC_RETURN(card->ctx, iso_ops->pin_cmd(card, data, tries_left));
 }
 
+#define IS_SYMETRIC_CRYPT(x) ((x) == SC_SEC_OPERATION_ENCRYPT_SYM || (x) == SC_SEC_OPERATION_DECRYPT_SYM)
+
 static int myeid_set_security_env_rsa(sc_card_t *card, const sc_security_env_t *env,
 		int se_num)
 {
@@ -739,6 +765,14 @@
 		apdu.p1 = 0x81;
 		apdu.p2 = 0xB8;
 		break;
+	case SC_SEC_OPERATION_ENCRYPT_SYM:
+		apdu.p1 = 0x81;
+		apdu.p2 = 0xB8;
+		break;
+	case SC_SEC_OPERATION_DECRYPT_SYM:
+		apdu.p1 = 0x41;
+		apdu.p2 = 0xB8;
+		break;
 	default:
 		return SC_ERROR_INVALID_ARGUMENTS;
 	}
@@ -757,9 +791,16 @@
 		memcpy(p, env->file_ref.value, 2);
 		p += 2;
 	}
+	/* symmetric operations: we need to set the key reference */
+	if (IS_SYMETRIC_CRYPT(env->operation)) {
+		*p++ = 0x83;
+		*p++ = 1;
+		*p++ = 0;
+	}
 	if (env->flags & SC_SEC_ENV_KEY_REF_PRESENT && env->operation != SC_SEC_OPERATION_UNWRAP &&
-		env->operation != SC_SEC_OPERATION_WRAP)
-	{
+			env->operation != SC_SEC_OPERATION_WRAP &&
+			env->operation != SC_SEC_OPERATION_ENCRYPT_SYM &&
+			env->operation != SC_SEC_OPERATION_DECRYPT_SYM) {
 		*p++ = 0x84;
 		*p++ = 1;
 		*p++ = 0;
@@ -778,11 +819,13 @@
 			break;
 	    }
 
-	if (env->operation ==  SC_SEC_OPERATION_UNWRAP || env->operation == SC_SEC_OPERATION_WRAP)
-	{
-	    /* add IV if present */
+	r = 0;
+	if (env->operation == SC_SEC_OPERATION_UNWRAP || env->operation == SC_SEC_OPERATION_WRAP ||
+			IS_SYMETRIC_CRYPT(env->operation)) {
+		/* add IV if present */
 		for (i = 0; i < SC_SEC_ENV_MAX_PARAMS; i++)
 			if (env->params[i].param_type == SC_SEC_ENV_PARAM_IV) {
+				r = 1;
 				*p++ = 0x87;
 				*p++ = (unsigned char) env->params[i].value_len;
 				if (p + env->params[i].value_len >= sbuf + SC_MAX_APDU_BUFFER_SIZE) {
@@ -794,6 +837,15 @@
 				break;
 			}
 	}
+	/* for AES_ECB we need to reset the IV but we respect if the IV is already present */
+	if (IS_SYMETRIC_CRYPT(env->operation) && env->algorithm == SC_ALGORITHM_AES &&
+			env->algorithm_flags == SC_ALGORITHM_AES_ECB && r == 0) {
+		*p++ = 0x87;
+		*p++ = 16;
+		memset(p, 0, 16);
+		p += 16;
+	}
+
 	r = p - sbuf;
 	apdu.lc = r;
 	apdu.datalen = r;
@@ -919,6 +971,10 @@
 	/* store security environment to differentiate between ECDH and RSA in decipher - Hannu*/
 	priv->sec_env = env;
 
+	/* for symmetric operation save algo and algo flags */
+	priv->algorithm_flags = env->algorithm_flags;
+	priv->algorithm = env->algorithm;
+
 	if (env->flags & SC_SEC_ENV_ALG_PRESENT)
 	{
 		sc_security_env_t tmp;
@@ -965,6 +1021,13 @@
 
 			if ((tmp.algorithm_flags & SC_ALGORITHM_AES_CBC_PAD) == SC_ALGORITHM_AES_CBC_PAD)
 				tmp.algorithm_ref |= 0x80;		/* set PKCS#7 padding */
+			/* Tag 0x80 algorithm_ref - value 0x80 or 0x8A is working only for UNWRAP/WRAP
+			 * AES is supported from version 4.0 but without pkcs#7 padding.
+			 * For SC_SEC_OPERATION_ENCRYPT_SYM and SC_SEC_OPERATION_DECRYPT_SYM we running
+			 * PKCS#7 in software, here we fix the algorithm_ref variable.
+			 */
+			if (IS_SYMETRIC_CRYPT(env->operation))
+				tmp.algorithm_ref &= ~0x80; /* do not handle padding in card */
 
 			/* from this point, there's no difference to RSA SE */
 			return myeid_set_security_env_rsa(card, &tmp, se_num);
@@ -1799,6 +1862,245 @@
 	return SC_SUCCESS;
 }
 
+static int
+myeid_enc_dec_sym(struct sc_card *card, const u8 *data, size_t datalen,
+		u8 *out, size_t *outlen, int decipher)
+{
+
+	struct sc_context *ctx;
+
+	struct sc_apdu apdu;
+	u8 rbuf[SC_MAX_APDU_BUFFER_SIZE];
+	u8 sbuf[SC_MAX_APDU_BUFFER_SIZE];
+	u8 *sdata;
+	int r, padding = 0, cbc = 0;
+
+	size_t block_size;
+	size_t len, rest_len;
+	size_t return_len = 0;
+
+	size_t max_apdu_datalen;
+	size_t apdu_datalen;
+
+	assert(card != NULL);
+
+	ctx = card->ctx;
+	LOG_FUNC_CALLED(ctx);
+
+	myeid_private_data_t *priv;
+	priv = (myeid_private_data_t *)card->drv_data;
+
+	/* How many cipher blocks will fit in the APDU. We do not use the APDU chaining
+	 * mechanism from OpenSC, because we need the size of the APDU data block
+	 * to match a multiple of the cipher block size */
+
+	max_apdu_datalen = sc_get_max_send_size(card);
+	if (max_apdu_datalen > sc_get_max_recv_size(card))
+		max_apdu_datalen = sc_get_max_recv_size(card);
+
+	if (max_apdu_datalen > SC_MAX_APDU_BUFFER_SIZE)
+		max_apdu_datalen = SC_MAX_APDU_BUFFER_SIZE;
+
+	sc_log(ctx, "algorithm %d algorithm_flags %x", priv->algorithm, priv->algorithm_flags);
+
+	/* for C_Encrypt/C_EncryptUpdate/C_EncryptFinalize/C_Decrypt/C_DecryptUpdate/C_DecryptFinalize
+	 * the 'outlen' is always not NULL (src/pkcs11/framework-pkcs15.c).
+	 * For C_EncryptInit and C_DecrytpInit the 'outlen' is set to NULL
+	 */
+	if (outlen == NULL) {
+		/* C_EncryptInit/C_DecryptInit - clear buffers */
+		sc_log(ctx, "%s (symmetric key) initialized", decipher ? "C_DecryptInit" : "C_EncryptInit");
+		priv->sym_crypt_buffer_len = 0;
+		priv->sym_plain_buffer_len = 0;
+		return SC_SUCCESS;
+	}
+
+	switch (priv->algorithm) {
+	case SC_ALGORITHM_AES:
+		block_size = 16;
+		if (priv->algorithm_flags & SC_ALGORITHM_AES_ECB) {
+			padding = 0;
+			cbc = 0;
+		} else if (priv->algorithm_flags & SC_ALGORITHM_AES_CBC) {
+			padding = 0;
+			cbc = 1;
+		} else if (priv->algorithm_flags & SC_ALGORITHM_AES_CBC_PAD) {
+			padding = 1;
+			cbc = 1;
+		}
+		break;
+	default:
+		LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
+	}
+
+	/* MyEID: ECB APDU must match exact cipher block size in CBC
+	 * mode up to 240 bytes can be handled in one APDU
+	 * round max_apdu_datalen to multiple of block_size (CBC mode) */
+
+	if (cbc)
+		max_apdu_datalen -= max_apdu_datalen % block_size;
+	else
+		max_apdu_datalen = block_size;
+
+	/* Maybe we have more input data (from previous PSO operation). */
+	rest_len = priv->sym_crypt_buffer_len;
+
+	/* no input data from application (this is C_EncryptFinalize/C_DecryptFinalize */
+	if (data == NULL) {
+		if (datalen != 0)
+			LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_LENGTH);
+		if (decipher) {
+			/* C_DecryptFinalize */
+			/* decrypted buffer size must match the block size */
+			if (priv->sym_plain_buffer_len != block_size)
+				LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_LENGTH);
+			/* do we have any encrypted data left? */
+			if (rest_len)
+				LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_LENGTH);
+
+			return_len = block_size;
+			if (padding) {
+				/* check padding */
+				uint8_t i, pad_byte = *(priv->sym_plain_buffer + block_size - 1);
+
+				sc_log(ctx, "Found padding byte %02x", pad_byte);
+				if (pad_byte == 0 || pad_byte > block_size)
+					LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_PADDING);
+				sdata = priv->sym_plain_buffer + block_size - pad_byte;
+				for (i = 0; i < pad_byte; i++)
+					if (sdata[i] != pad_byte)
+						LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_PADDING);
+				return_len = block_size - pad_byte;
+			}
+			*outlen = return_len;
+			if (return_len > *outlen)
+				LOG_FUNC_RETURN(ctx, SC_ERROR_BUFFER_TOO_SMALL);
+			memcpy(out, priv->sym_plain_buffer, return_len);
+			sc_log(ctx, "C_DecryptFinal %zu bytes", *outlen);
+			return SC_SUCCESS;
+		} else {
+			/* C_EncryptFinalize */
+			if (padding) {
+				uint8_t pad_byte = block_size - rest_len;
+				sc_log(ctx, "Generating padding, padding byte: %d", pad_byte);
+				sdata = priv->sym_crypt_buffer + rest_len;
+				memset(sdata, pad_byte, pad_byte);
+				rest_len = block_size;
+
+			} else if (rest_len) {
+				LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_LENGTH);
+			}
+			/* fall through - encipher last block */
+		}
+	}
+	/* check output buffer size */
+	len = datalen + rest_len;
+
+	sc_log(ctx, "datalen=%zu rest_len=%zu len=%zu outlen=%zu", datalen, rest_len, len, *outlen);
+	/* there is block_size bytes space that can be saved to next run */
+	len -= (len % block_size);
+
+	/* application can request buffer size or actual buffer size is too small */
+	*outlen = len;
+	if (out == NULL)
+		LOG_FUNC_RETURN(ctx, SC_SUCCESS);
+	/* application buffer is too small */
+	if (*outlen < len)
+		LOG_FUNC_RETURN(ctx, SC_ERROR_BUFFER_TOO_SMALL);
+
+	/* main loop */
+	while (len >= block_size) {
+		if (!decipher)
+			sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x84, 0x80);
+		else
+			sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A, 0x80, 0x84);
+		apdu.cla = 0;
+
+		if (len > max_apdu_datalen)
+			apdu_datalen = max_apdu_datalen;
+		else
+			apdu_datalen = len;
+
+		if (cbc)
+			apdu.cla = 0x10;
+
+		len -= apdu_datalen;
+		sdata = sbuf;
+
+		apdu.le = apdu_datalen;
+		apdu.lc = apdu_datalen;
+		apdu.datalen = apdu_datalen;
+		apdu.data = sbuf;
+		apdu.resplen = sizeof(rbuf);
+		apdu.resp = rbuf;
+
+		/* do we have any data from the previous step ? */
+		if (rest_len) {
+			memcpy(sbuf, priv->sym_crypt_buffer, rest_len);
+			sdata += rest_len;
+			apdu_datalen -= rest_len;
+			priv->sym_crypt_buffer_len = 0;
+			rest_len = 0;
+		}
+		memcpy(sdata, data, apdu_datalen);
+		data += apdu_datalen;
+		datalen -= apdu_datalen;
+
+		r = sc_transmit_apdu(card, &apdu);
+		LOG_TEST_RET(ctx, r, "APDU transmit failed");
+		r = sc_check_sw(card, apdu.sw1, apdu.sw2);
+		LOG_TEST_RET(ctx, r, "decrypt_sym/encrypt_sym failed");
+		if (apdu.resplen != apdu.datalen)
+			LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_LENGTH);
+		memcpy(out, apdu.resp, apdu.resplen);
+		out += apdu.resplen;
+		return_len += apdu.resplen;
+	}
+	/* last block is stored in buffer and is returned to application
+	 * in next call to C_DecryptUpdate or C_DecryptFinal. This allow us
+	 * to compute how many bytes is to be returned after padding removal.
+	 * Whole handling of this is here, because "data" and "out" buffer
+	 * can be in the same place.
+	 */
+	if (decipher) {
+		uint8_t tmp_buf[16];
+		if (return_len >= block_size) {
+			/* save last block to temp buffer */
+			memcpy(tmp_buf, out - block_size, block_size);
+			if (priv->sym_plain_buffer_len) {
+				/* insert previous last block to output buffer */
+				sc_log(ctx, "inserting block from previous decrypt");
+				memmove(out - return_len + block_size, out - return_len, return_len - block_size);
+				memcpy(out - return_len, priv->sym_plain_buffer, block_size);
+			} else
+				return_len -= block_size;
+			/* save last (decrypted) block */
+			memcpy(priv->sym_plain_buffer, tmp_buf, block_size);
+			priv->sym_plain_buffer_len = block_size;
+
+		} else
+			priv->sym_plain_buffer_len = 0;
+	}
+	/* save rest of data for next run */
+	priv->sym_crypt_buffer_len = datalen;
+	sc_log(ctx, "rest data len = %zu", datalen);
+	memcpy(priv->sym_crypt_buffer, data, datalen);
+	sc_log(ctx, "return data len = %zu", return_len);
+	*outlen = return_len;
+	return SC_SUCCESS;
+}
+
+static int
+myeid_encrypt_sym(struct sc_card *card, const u8 *data, size_t datalen, u8 *out, size_t *outlen)
+{
+	return myeid_enc_dec_sym(card, data, datalen, out, outlen, 0);
+}
+
+static int
+myeid_decrypt_sym(struct sc_card *card, const u8 *data, size_t datalen, u8 *out, size_t *outlen)
+{
+	return myeid_enc_dec_sym(card, data, datalen, out, outlen, 1);
+}
 
 static struct sc_card_driver * sc_get_driver(void)
 {
@@ -1818,6 +2120,7 @@
 	myeid_ops.update_record		= NULL;
 	myeid_ops.select_file		= myeid_select_file;
 	myeid_ops.get_response		= iso_ops->get_response;
+	myeid_ops.logout		= myeid_logout;
 	myeid_ops.create_file		= myeid_create_file;
 	myeid_ops.delete_file		= myeid_delete_file;
 	myeid_ops.list_files		= myeid_list_files;
@@ -1829,6 +2132,8 @@
 	myeid_ops.pin_cmd		= myeid_pin_cmd;
 	myeid_ops.wrap			= myeid_wrap_key;
 	myeid_ops.unwrap		= myeid_unwrap_key;
+	myeid_ops.encrypt_sym		= myeid_encrypt_sym;
+	myeid_ops.decrypt_sym		= myeid_decrypt_sym;
 	return &myeid_drv;
 }
 
diff -Nru opensc-0.22.0/src/libopensc/card-npa.c opensc-0.23.0/src/libopensc/card-npa.c
--- opensc-0.22.0/src/libopensc/card-npa.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-npa.c	2022-11-29 09:34:43.000000000 +0100
@@ -136,51 +136,33 @@
 	return r;
 }
 
+unsigned char dir_content_ref[] = {
+	0x61, 0x32, 0x4F, 0x0F, 0xE8, 0x28, 0xBD, 0x08, 0x0F, 0xA0, 0x00, 0x00,
+	0x01, 0x67, 0x45, 0x53, 0x49, 0x47, 0x4E, 0x50, 0x0F, 0x43, 0x49, 0x41,
+	0x20, 0x7A, 0x75, 0x20, 0x44, 0x46, 0x2E, 0x65, 0x53, 0x69, 0x67, 0x6E,
+	0x51, 0x00, 0x73, 0x0C, 0x4F, 0x0A, 0xA0, 0x00, 0x00, 0x01, 0x67, 0x45,
+	0x53, 0x49, 0x47, 0x4E, 0x61, 0x09, 0x4F, 0x07, 0xA0, 0x00, 0x00, 0x02,
+	0x47, 0x10, 0x01, 0x61, 0x0B, 0x4F, 0x09, 0xE8, 0x07, 0x04, 0x00, 0x7F,
+	0x00, 0x07, 0x03, 0x02, 0x61, 0x0C, 0x4F, 0x0A, 0xA0, 0x00, 0x00, 0x01,
+	0x67, 0x45, 0x53, 0x49, 0x47, 0x4E,
+};
+
 static int npa_match_card(sc_card_t * card)
 {
-	int r = 0;
+	unsigned char dir_content[sizeof dir_content_ref];
+	unsigned char id[] = {0x2F, 0x00};
+	sc_apdu_t select_ef_dir;
+
+	sc_format_apdu_ex(&select_ef_dir, 0x00, 0xA4, 0x02, 0x0C, id, sizeof id, NULL, 0);
+
+	if (SC_SUCCESS == sc_select_file(card, sc_get_mf_path(), NULL)
+			&& SC_SUCCESS == sc_transmit_apdu(card, &select_ef_dir)
+			&& select_ef_dir.sw1 == 0x90 && select_ef_dir.sw2 == 0x00
+			&& sizeof dir_content == sc_read_binary(card, 0, dir_content, sizeof dir_content, 0)
+			&& 0 == memcmp(dir_content_ref, dir_content, sizeof dir_content))
+		return 1;
 
-	if (SC_SUCCESS == sc_enum_apps(card)) {
-		unsigned char esign_aid_0[] = {
-			0xE8, 0x28, 0xBD, 0x08, 0x0F, 0xA0, 0x00, 0x00, 0x01, 0x67, 0x45, 0x53, 0x49, 0x47, 0x4E,
-		}, esign_aid_1[] = {
-			0xa0, 0x00, 0x00, 0x02, 0x47, 0x10, 0x01,
-		}, esign_aid_2[] = {
-			0xe8, 0x07, 0x04, 0x00, 0x7f, 0x00, 0x07, 0x03, 0x02,
-		}, esign_aid_3[] = {
-			0xA0, 0x00, 0x00, 0x01, 0x67, 0x45, 0x53, 0x49, 0x47, 0x4E,
-		};
-		int i, found_0 = 0, found_1 = 0, found_2 = 0, found_3 = 0;
-		for (i = 0; i < card->app_count; i++)   {
-			struct sc_app_info *app_info = card->app[i];
-			if (sizeof esign_aid_0 == app_info->aid.len
-					&& 0 == memcmp(esign_aid_0, app_info->aid.value,
-						sizeof esign_aid_0))
-				found_0 = 1;
-			if (sizeof esign_aid_1 == app_info->aid.len
-					&& 0 == memcmp(esign_aid_1, app_info->aid.value,
-						sizeof esign_aid_1))
-				found_1 = 1;
-			if (sizeof esign_aid_2 == app_info->aid.len
-					&& 0 == memcmp(esign_aid_2, app_info->aid.value,
-						sizeof esign_aid_2))
-				found_2 = 1;
-			if (sizeof esign_aid_3 == app_info->aid.len
-					&& 0 == memcmp(esign_aid_3, app_info->aid.value,
-						sizeof esign_aid_3))
-				found_3 = 1;
-		}
-		if (found_0 && found_1 && found_2 && found_3) {
-			card->type = SC_CARD_TYPE_NPA;
-			r = 1;
-		}
-	}
-
-	if (r == 0) {
-		sc_free_apps(card);
-	}
-
-	return r;
+	return 0;
 }
 
 static void npa_get_cached_pace_params(sc_card_t *card,
@@ -369,6 +351,42 @@
 	return SC_SUCCESS;
 }
 
+static void npa_init_apps(sc_card_t * card)
+{
+	/* this initializes the internal structures with the data from
+	 * `dir_content_ref` */
+	const u8 *aids[] = {
+		(const u8 *) "\xa0\x00\x00\x02\x47\x10\x01",
+		(const u8 *) "\xe8\x07\x04\x00\x7f\x00\x07\x03\x02",
+		(const u8 *) "\xa0\x00\x00\x01\x67\x45\x53\x49\x47\x4e",
+	};
+	const size_t lens[] = {7, 9, 10};
+	size_t i;
+
+	sc_free_apps(card);
+	card->app_count = 0;
+
+	for (i = 0; i < 3; i++) {
+		const u8 *aid = aids[i];
+		size_t aid_len = lens[i];
+		struct sc_app_info *app = calloc(1, sizeof *app);
+		if (NULL == app)
+			continue;
+
+		app->aid.len = aid_len;
+		memcpy(app->aid.value, aid, aid_len);
+
+		app->path.len = aid_len;
+		memcpy(app->path.value, aid, aid_len);
+		app->path.type = SC_PATH_TYPE_DF_NAME;
+
+		app->rec_nr = -1;
+
+		card->app[card->app_count] = app;
+		card->app_count++;
+	}
+}
+
 static int npa_init(sc_card_t * card)
 {
 	int flags = SC_ALGORITHM_ECDSA_RAW;
@@ -415,6 +433,8 @@
 	if (r != SC_SUCCESS)
 		goto err;
 
+	npa_init_apps(card);
+
 	/* unlock the eSign application for reading the certificates
 	 * by the PKCS#15 layer (i.e. sc_pkcs15_bind_internal) */
 	if (SC_SUCCESS != npa_unlock_esign(card)) {
diff -Nru opensc-0.22.0/src/libopensc/card-nqApplet.c opensc-0.23.0/src/libopensc/card-nqApplet.c
--- opensc-0.22.0/src/libopensc/card-nqApplet.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/libopensc/card-nqApplet.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,511 @@
+/*
+ * Support for the JCOP4 Cards with NQ-Applet
+ *
+ * Copyright (C) 2021 jozsefd <jozsef.dojcsak at gmail.com>
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "opensc.h"
+#include "asn1.h"
+#include "cardctl.h"
+#include "internal.h"
+#include "log.h"
+
+#define APPLET_VERSION_LEN  2
+#define APPLET_MEMTYPE_LEN  1
+#define APPLET_SERIALNR_LEN 8
+
+/* card constants */
+static const struct sc_atr_table nqapplet_atrs[] = {
+	{"3b:d5:18:ff:81:91:fe:1f:c3:80:73:c8:21:10:0a", NULL, NULL, SC_CARD_TYPE_NQ_APPLET, 0, NULL},
+	{NULL, NULL, NULL, 0, 0, NULL}};
+
+static const u8 nqapplet_aid[] = {0xd2, 0x76, 0x00, 0x01, 0x80, 0xBA, 0x01, 0x44, 0x02, 0x01, 0x00};
+
+static struct sc_card_operations nqapplet_operations;
+static struct sc_card_operations *iso_operations = NULL;
+
+#define KEY_REFERENCE_NO_KEY   0x00
+#define KEY_REFERENCE_AUTH_KEY 0x01
+#define KEY_REFERENCE_ENCR_KEY 0x02
+
+struct nqapplet_driver_data {
+	u8 version_minor;
+	u8 version_major;
+	u8 key_reference;
+};
+typedef struct nqapplet_driver_data *nqapplet_driver_data_ptr;
+
+static struct sc_card_driver nqapplet_driver = {
+	"NQ-Applet",          // name
+	"nqapplet",           // short name
+	&nqapplet_operations, // operations
+	NULL,                 // atr table
+	0,                    // nr of atr
+	NULL                  // dll?
+};
+
+static const struct sc_card_error nqapplet_errors[] = {
+	{0x6700, SC_ERROR_WRONG_LENGTH, "Invalid LC or LE"},
+	{0x6982, SC_ERROR_SECURITY_STATUS_NOT_SATISFIED, "Security status not satisfied"}, // TODO MK/DK??
+	{0x6985, SC_ERROR_NOT_ALLOWED, "Invalid PIN or key"},
+	{0x6986, SC_ERROR_NOT_ALLOWED, "Conditions of use not satisfied"},
+	{0x6A80, SC_ERROR_INVALID_ARGUMENTS, "Invalid parameters"},
+	{0x6A82, SC_ERROR_OBJECT_NOT_FOUND, "Data object not found"},
+	{0x6A84, SC_ERROR_NOT_ENOUGH_MEMORY, "Not enough memory"},
+	{0x6A86, SC_ERROR_INCORRECT_PARAMETERS, "Invalid P1 or P2"},
+	{0x6A88, SC_ERROR_INVALID_ARGUMENTS, "Wrong key ID"},
+	{0x6D00, SC_ERROR_FILE_NOT_FOUND, "Applet not found"}};
+
+/* convenience functions */
+
+static int init_driver_data(sc_card_t *card, u8 version_major, u8 version_minor)
+{
+	nqapplet_driver_data_ptr data = calloc(1, sizeof(struct nqapplet_driver_data));
+	if (data == NULL) {
+		LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
+	}
+
+	data->version_major = version_major;
+	data->version_minor = version_minor;
+	data->key_reference = KEY_REFERENCE_NO_KEY;
+	card->drv_data = (void *)data;
+	return SC_SUCCESS;
+}
+
+/**
+ * SELECT NQ-Applet, on success it returns the applet version and card serial nr.
+ *
+ * @param[in]     	card
+ * @param[out,opt]  version_major	Version major of the applet
+ * @param[out,opt]  version_minor	Version minor of the applet
+ * @param[out,opt]  serial_nr		Buffer to receive serial number octets
+ * @param[in]  		cb_serial_nr	Size of buffer in octets
+ * @param[out,opt]	serial_nr_len	The actual number of octet copied into serial_nr buffer
+ *
+ * @return SC_SUCCESS: The applet is present and selected.
+ *
+ */
+static int select_nqapplet(sc_card_t *card, u8 *version_major, u8 *version_minor, u8 *serial_nr,
+                           size_t cb_serial_nr, size_t *serial_nr_len)
+{
+	int rv;
+	sc_context_t *ctx = card->ctx;
+	sc_apdu_t apdu;
+	u8 buffer[APPLET_VERSION_LEN + APPLET_MEMTYPE_LEN + APPLET_SERIALNR_LEN + 2];
+	size_t cb_buffer = sizeof(buffer);
+	size_t cb_aid = sizeof(nqapplet_aid);
+
+	LOG_FUNC_CALLED(card->ctx);
+
+	sc_format_apdu_ex(&apdu, 0x00, 0xA4, 0x04, 0x00, nqapplet_aid, cb_aid, buffer, cb_buffer);
+
+	rv = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_RET(ctx, rv, "APDU transmit failure.");
+
+	rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	LOG_TEST_RET(card->ctx, rv, "Card returned error");
+
+	if (apdu.resplen < APPLET_VERSION_LEN + APPLET_MEMTYPE_LEN + APPLET_SERIALNR_LEN) {
+		SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_NORMAL, SC_ERROR_WRONG_LENGTH);
+	}
+
+	if (version_major != NULL) {
+		*version_major = buffer[0];
+	}
+	if (version_minor != NULL) {
+		*version_minor = buffer[1];
+	}
+	if (serial_nr != NULL && cb_serial_nr > 0 && serial_nr_len != NULL) {
+		size_t cb = MIN(APPLET_SERIALNR_LEN, cb_serial_nr);
+		memcpy(serial_nr, buffer + 3, cb);
+		*serial_nr_len = cb;
+	}
+
+	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+}
+
+/* driver operations API */
+static int nqapplet_match_card(struct sc_card *card)
+{
+	int rv = _sc_match_atr(card, nqapplet_atrs, &card->type);
+	return (rv >= 0);
+}
+
+static int nqapplet_init(struct sc_card *card)
+{
+	u8 version_major;
+	u8 version_minor;
+	u8 serial_nr[APPLET_SERIALNR_LEN];
+	size_t cb_serial_nr = sizeof(serial_nr);
+	unsigned long rsa_flags = 0;
+
+	LOG_FUNC_CALLED(card->ctx);
+	int rv =
+		select_nqapplet(card, &version_major, &version_minor, serial_nr, cb_serial_nr, &cb_serial_nr);
+	if (rv != SC_SUCCESS) {
+		LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_CARD, "Cannot select NQ-Applet.");
+	}
+
+	rv = init_driver_data(card, version_major, version_minor);
+	LOG_TEST_RET(card->ctx, rv, "Failed to initialize driver data.");
+
+	card->max_send_size = 255;
+	card->max_recv_size = 256;
+	card->caps |= SC_CARD_CAP_RNG | SC_CARD_CAP_ISO7816_PIN_INFO;
+	rsa_flags |= SC_ALGORITHM_RSA_RAW;
+	_sc_card_add_rsa_alg(card, 3072, rsa_flags, 0);
+
+	card->serialnr.len = MIN(sizeof(card->serialnr.value), cb_serial_nr);
+	memcpy(card->serialnr.value, serial_nr, card->serialnr.len);
+
+	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+}
+
+static int nqapplet_finish(struct sc_card *card)
+{
+	nqapplet_driver_data_ptr data = (nqapplet_driver_data_ptr)card->drv_data;
+
+	LOG_FUNC_CALLED(card->ctx);
+	if (data != NULL) {
+		free(data);
+		card->drv_data = NULL;
+	}
+	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+}
+
+static int nqapplet_get_response(struct sc_card *card, size_t *cb_resp, u8 *resp)
+{
+	struct sc_apdu apdu;
+	int rv;
+	size_t resplen;
+
+	LOG_FUNC_CALLED(card->ctx);
+	resplen = MIN(sc_get_max_recv_size(card), *cb_resp);
+
+	sc_format_apdu_ex(&apdu, 0x80, 0xC0, 0x00, 0x00, NULL, 0, resp, resplen);
+	apdu.flags |= SC_APDU_FLAGS_NO_GET_RESP;
+
+	rv = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
+	if (apdu.resplen == 0) {
+		LOG_FUNC_RETURN(card->ctx, sc_check_sw(card, apdu.sw1, apdu.sw2));
+	}
+
+	*cb_resp = apdu.resplen;
+
+	if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
+		rv = SC_SUCCESS;
+	} else if (apdu.sw1 == 0x61) {
+		rv = apdu.sw2 == 0 ? 256 : apdu.sw2;
+	} else if (apdu.sw1 == 0x62 && apdu.sw2 == 0x82) {
+		rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	}
+
+	LOG_FUNC_RETURN(card->ctx, rv);
+}
+
+static int nqapplet_get_challenge(struct sc_card *card, u8 *buf, size_t count)
+{
+	int r;
+	struct sc_apdu apdu;
+
+	LOG_FUNC_CALLED(card->ctx);
+	sc_format_apdu(card, &apdu, SC_APDU_CASE_2, 0x84, 0x00, 0x00);
+	apdu.le = count;
+	apdu.resp = buf;
+	apdu.resplen = count;
+
+	r = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+
+	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	LOG_TEST_RET(card->ctx, r, "GET CHALLENGE failed");
+
+	if (count < apdu.resplen) {
+		return (int)count;
+	}
+
+	return (int)apdu.resplen;
+}
+
+static int nqapplet_logout(struct sc_card *card)
+{
+	LOG_FUNC_CALLED(card->ctx);
+	/* selecting NQ-Applet again will reset the applet status and unauthorize PINs */
+	int rv = select_nqapplet(card, NULL, NULL, NULL, 0, NULL);
+	if (rv != SC_SUCCESS) {
+		LOG_TEST_RET(card->ctx, rv, "Failed to logout");
+	}
+
+	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+}
+
+int nqapplet_set_security_env(struct sc_card *card, const struct sc_security_env *env, int se_num)
+{
+	/* Note: the NQ-Applet does not have APDU for SET SECURITY ENV,
+	this function checks the intended parameters and sets card_data.key_reference */
+	nqapplet_driver_data_ptr data;
+	u8 key_reference = KEY_REFERENCE_NO_KEY;
+
+	LOG_FUNC_CALLED(card->ctx);
+
+	data = (nqapplet_driver_data_ptr)card->drv_data;
+	data->key_reference = KEY_REFERENCE_NO_KEY;
+
+	if (se_num != 0) {
+		LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED,
+		             "Storing of security environment is not supported");
+	}
+	if (env->key_ref_len == 1) {
+		key_reference = env->key_ref[0];
+	}
+
+	switch (env->operation) {
+	case SC_SEC_OPERATION_DECIPHER:
+		if (key_reference != KEY_REFERENCE_AUTH_KEY && key_reference != KEY_REFERENCE_ENCR_KEY) {
+			LOG_TEST_RET(card->ctx, SC_ERROR_INCOMPATIBLE_KEY,
+			             "Decipher operation is only supported with AUTH and ENCR keys.");
+		}
+		data->key_reference = key_reference;
+		break;
+	case SC_SEC_OPERATION_SIGN:
+		if (key_reference != KEY_REFERENCE_AUTH_KEY) {
+			LOG_TEST_RET(card->ctx, SC_ERROR_INCOMPATIBLE_KEY,
+			             "Sign operation is only supported with AUTH key.");
+		}
+		data->key_reference = key_reference;
+		break;
+	default:
+		LOG_TEST_RET(card->ctx, SC_ERROR_NOT_SUPPORTED, "Unsupported sec. operation.");
+	}
+
+	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+}
+
+static int nqapplet_decipher(struct sc_card *card, const u8 *data, size_t cb_data, u8 *out, size_t outlen)
+{
+	int rv;
+	struct sc_apdu apdu;
+	u8 p1 = 0x80;
+	u8 p2 = 0x86;
+	nqapplet_driver_data_ptr drv_data;
+
+	LOG_FUNC_CALLED(card->ctx);
+
+	drv_data = (nqapplet_driver_data_ptr)card->drv_data;
+
+	if (drv_data->key_reference == KEY_REFERENCE_AUTH_KEY) {
+		p1 = 0x9E;
+		p2 = 0x9A;
+	} else if (drv_data->key_reference != KEY_REFERENCE_ENCR_KEY) {
+		LOG_TEST_RET(card->ctx, SC_ERROR_INCOMPATIBLE_KEY,
+		             "Decipher operation is only supported with AUTH and ENCR keys.");
+	}
+
+	/* the applet supports only 3072 RAW RSA, input buffer size must be 384 octets,
+	output buffer size must be at least 384 octets */
+	sc_format_apdu_ex(&apdu, 0x80, 0x2A, p1, p2, data, cb_data, out, outlen);
+	apdu.le = 256;
+	apdu.flags |= SC_APDU_FLAGS_CHAINING;
+	rv = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
+
+	if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
+		rv = apdu.resplen;
+	} else if (apdu.sw1 == 0x61) {
+		rv = apdu.sw2 == 0 ? 256 : apdu.sw2;
+	} else {
+		rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	}
+
+	LOG_FUNC_RETURN(card->ctx, rv);
+}
+
+static int nqapplet_compute_signature(struct sc_card *card, const u8 *data, size_t cb_data, u8 *out,
+                                      size_t outlen)
+{
+	int rv;
+	struct sc_apdu apdu;
+	nqapplet_driver_data_ptr drv_data;
+
+	LOG_FUNC_CALLED(card->ctx);
+	drv_data = (nqapplet_driver_data_ptr)card->drv_data;
+
+	if (drv_data->key_reference != KEY_REFERENCE_AUTH_KEY) {
+		LOG_TEST_RET(card->ctx, SC_ERROR_INCOMPATIBLE_KEY,
+		             "Sign operation is only supported with AUTH key.");
+	}
+
+	/* the applet supports only 3072 RAW RSA, input buffer size must be 384 octets,
+	output buffer size must be at least 384 octets */
+	sc_format_apdu_ex(&apdu, 0x80, 0x2A, 0x9E, 0x9A, data, cb_data, out, outlen);
+	apdu.le = 256;
+	apdu.flags |= SC_APDU_FLAGS_CHAINING;
+	rv = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
+
+	if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
+		rv = apdu.resplen;
+	} else if (apdu.sw1 == 0x61) {
+		rv = apdu.sw2 == 0 ? 256 : apdu.sw2;
+	} else {
+		rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	}
+
+	LOG_FUNC_RETURN(card->ctx, rv);
+}
+
+static int nqapplet_check_sw(struct sc_card *card, unsigned int sw1, unsigned int sw2)
+{
+	const int nqapplet_error_count = sizeof(nqapplet_errors) / sizeof(struct sc_card_error);
+	int i;
+
+	LOG_FUNC_CALLED(card->ctx);
+	sc_log(card->ctx, "Checking sw1 = 0x%02x, sw2 = 0x%02x\n", sw1, sw2);
+
+	for (i = 0; i < nqapplet_error_count; i++) {
+		if (nqapplet_errors[i].SWs == ((sw1 << 8) | sw2)) {
+			LOG_TEST_RET(card->ctx, nqapplet_errors[i].errorno, nqapplet_errors[i].errorstr);
+		}
+	}
+
+	return iso_operations->check_sw(card, sw1, sw2);
+}
+
+static int nqapplet_get_data(struct sc_card *card, unsigned int id, u8 *resp, size_t cb_resp)
+{
+	struct sc_apdu apdu;
+	int rv;
+
+	LOG_FUNC_CALLED(card->ctx);
+
+	sc_format_apdu_ex(&apdu, 0x80, 0xB0, 0x00, (u8)id, NULL, 0, resp, cb_resp);
+	apdu.le = 256;
+
+	rv = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_RET(card->ctx, rv, "APDU transmit failed");
+
+	if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
+		rv = apdu.resplen;
+	} else if (apdu.sw1 == 0x61) {
+		rv = apdu.sw2 == 0 ? 256 : apdu.sw2;
+	} else if (apdu.sw1 == 0x62 && apdu.sw2 == 0x82) {
+		rv = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	}
+
+	LOG_FUNC_RETURN(card->ctx, rv);
+}
+
+static int nqapplet_select_file(struct sc_card *card, const struct sc_path *in_path,
+                                struct sc_file **file_out)
+{
+	LOG_FUNC_CALLED(card->ctx);
+
+	/* the applet does not support SELECT EF/DF except for SELECT APPLET.
+	In order to enable opensc-explorer add support for virtually selecting MF only */
+	if (in_path->type == SC_PATH_TYPE_PATH && in_path->len == 2 &&
+	    memcmp(in_path->value, "\x3F\x00", 2) == 0) {
+		if (file_out != NULL) {
+			struct sc_file *file = sc_file_new();
+			if (file == NULL) {
+				LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
+			}
+			file->path = *in_path;
+			*file_out = file;
+			LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+		}
+	}
+	// TODO allow selecting Applet AID
+
+	LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
+}
+
+static int nqapplet_card_ctl(sc_card_t *card, unsigned long cmd, void *ptr)
+{
+	switch (cmd) {
+	case SC_CARDCTL_GET_SERIALNR:
+		if (card->serialnr.len) {
+			sc_serial_number_t *serial = (sc_serial_number_t *)ptr;
+			memcpy(serial->value, card->serialnr.value, card->serialnr.len);
+			serial->len = card->serialnr.len;
+			return SC_SUCCESS;
+		}
+		break;
+	}
+	return SC_ERROR_NOT_SUPPORTED;
+}
+
+struct sc_card_driver *sc_get_nqApplet_driver(void)
+{
+	sc_card_driver_t *iso_driver = sc_get_iso7816_driver();
+
+	if (iso_operations == NULL) {
+		iso_operations = iso_driver->ops;
+	}
+
+	nqapplet_operations = *iso_driver->ops;
+
+	/* supported operations */
+	nqapplet_operations.match_card = nqapplet_match_card;
+	nqapplet_operations.init = nqapplet_init;
+	nqapplet_operations.finish = nqapplet_finish;
+	nqapplet_operations.get_response = nqapplet_get_response;
+	nqapplet_operations.get_challenge = nqapplet_get_challenge;
+	nqapplet_operations.logout = nqapplet_logout;
+	nqapplet_operations.set_security_env = nqapplet_set_security_env;
+	nqapplet_operations.decipher = nqapplet_decipher;
+	nqapplet_operations.compute_signature = nqapplet_compute_signature;
+	nqapplet_operations.check_sw = nqapplet_check_sw;
+	nqapplet_operations.get_data = nqapplet_get_data;
+	nqapplet_operations.select_file = nqapplet_select_file;
+	nqapplet_operations.card_ctl = nqapplet_card_ctl;
+
+	/* unsupported operations */
+	nqapplet_operations.read_binary = NULL;
+	nqapplet_operations.write_binary = NULL;
+	nqapplet_operations.update_binary = NULL;
+	nqapplet_operations.erase_binary = NULL;
+	nqapplet_operations.read_record = NULL;
+	nqapplet_operations.write_record = NULL;
+	nqapplet_operations.append_record = NULL;
+	nqapplet_operations.update_record = NULL;
+
+	nqapplet_operations.verify = NULL;
+	nqapplet_operations.restore_security_env = NULL;
+	nqapplet_operations.change_reference_data = NULL;
+	nqapplet_operations.reset_retry_counter = NULL;
+	nqapplet_operations.create_file = NULL;
+	nqapplet_operations.delete_file = NULL;
+	nqapplet_operations.list_files = NULL;
+	nqapplet_operations.process_fci = NULL;
+	nqapplet_operations.construct_fci = NULL;
+	nqapplet_operations.put_data = NULL;
+	nqapplet_operations.delete_record = NULL;
+	nqapplet_operations.read_public_key = NULL;
+
+	/* let iso driver handle these operations
+	nqapplet_operations.pin_cmd;
+	nqapplet_operations.card_reader_lock_obtained;
+	nqapplet_operations.wrap;
+	nqapplet_operations.unwrap;
+	*/
+
+	return &nqapplet_driver;
+}
diff -Nru opensc-0.22.0/src/libopensc/card-openpgp.c opensc-0.23.0/src/libopensc/card-openpgp.c
--- opensc-0.22.0/src/libopensc/card-openpgp.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-openpgp.c	2022-11-29 09:34:43.000000000 +0100
@@ -129,7 +129,7 @@
 
 static int		pgp_get_card_features(sc_card_t *card);
 static int		pgp_finish(sc_card_t *card);
-static void		pgp_iterate_blobs(pgp_blob_t *, int, void (*func)());
+static void		pgp_iterate_blobs(pgp_blob_t *, void (*func)());
 
 static int		pgp_get_blob(sc_card_t *card, pgp_blob_t *blob,
 				 unsigned int id, pgp_blob_t **ret);
@@ -137,6 +137,7 @@
 static void		pgp_free_blob(pgp_blob_t *);
 static int		pgp_get_pubkey(sc_card_t *, unsigned int, u8 *, size_t);
 static int		pgp_get_pubkey_pem(sc_card_t *, unsigned int, u8 *, size_t);
+static int		pgp_enumerate_blob(sc_card_t *card, pgp_blob_t *blob);
 
 
 static pgp_do_info_t	pgp1x_objects[] = {	/* OpenPGP card spec 1.1 */
@@ -196,7 +197,7 @@
 	{ 0x00de, SIMPLE,      READ_ALWAYS | WRITE_PIN3,  NULL,               sc_put_data },
 	{ 0x00de, SIMPLE,      READ_ALWAYS | WRITE_NEVER, NULL,               NULL        },
 	/* DO FA is CONSTRUCTED in spec; we treat it as SIMPLE for the time being */
-	{ 0x00fa, SIMPLE,      READ_ALWAYS | WRITE_NEVER, NULL,               NULL        },
+	{ 0x00fa, CONSTRUCTED, READ_ALWAYS | WRITE_NEVER, sc_get_data,        NULL        },
 	/* DO FB is CONSTRUCTED in spec; we treat it as SIMPLE for the time being */
 	{ 0x00fb, SIMPLE,      READ_ALWAYS | WRITE_PIN3,  NULL,               sc_put_data },
 	/* DO FC is CONSTRUCTED in spec; we treat it as SIMPLE for the time being */
@@ -257,7 +258,7 @@
 	{ 0x5f50, SIMPLE,      READ_ALWAYS | WRITE_PIN3,  sc_get_data,        sc_put_data },
 	{ 0x5f52, SIMPLE,      READ_ALWAYS | WRITE_NEVER, sc_get_data,        NULL        },
 	/* DO 7F21 is CONSTRUCTED in spec; we treat it as SIMPLE: no need to parse TLV */
-	{ DO_CERT, SIMPLE,      READ_ALWAYS | WRITE_PIN3,  sc_get_data,        sc_put_data },
+	{ DO_CERT, SIMPLE,      READ_ALWAYS | WRITE_PIN3,  sc_get_data,       sc_put_data },
 	{ 0x7f48, CONSTRUCTED, READ_NEVER  | WRITE_NEVER, NULL,               NULL        },
 	{ 0x7f49, CONSTRUCTED, READ_ALWAYS | WRITE_NEVER, NULL,               NULL        },
 	{ DO_AUTH,     CONSTRUCTED, READ_ALWAYS | WRITE_NEVER, pgp_get_pubkey,     NULL   },
@@ -497,7 +498,9 @@
 	}
 
 	/* get card_features from ATR & DOs */
-	pgp_get_card_features(card);
+	if (pgp_get_card_features(card)) {
+		LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+	}
 
 	/* if algorithm attributes can be changed,
 	 * add supported algorithms based on specification for pkcs15-init */
@@ -662,6 +665,83 @@
 	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
 }
 
+int _pgp_handle_curve25519(sc_card_t *card,
+	sc_cardctl_openpgp_keygen_info_t key_info, size_t do_num)
+{
+	if (!sc_compare_oid(&key_info.u.ec.oid, &curve25519_oid))
+		return 0;
+
+	/* CKM_XEDDSA supports both Sign and Derive, but
+	* OpenPGP card supports only derivation using these
+	* keys as far as I know */
+	_sc_card_add_xeddsa_alg(card, key_info.u.ec.key_length,
+	    SC_ALGORITHM_ECDH_CDH_RAW, 0, &key_info.u.ec.oid);
+	sc_log(card->ctx, "DO %zX: Added XEDDSA algorithm (%d), mod_len = %d",
+	    do_num, SC_ALGORITHM_XEDDSA, key_info.u.ec.key_length);
+	return 1;
+}
+
+int _pgp_add_algo(sc_card_t *card, sc_cardctl_openpgp_keygen_info_t key_info, size_t do_num)
+{
+	unsigned long flags = 0, ext_flags = 0;
+
+	/* [RFC 4880], [draft-ietf-openpgp-crypto-refresh] */
+	switch (key_info.algorithm) {
+	case SC_OPENPGP_KEYALGO_RSA:
+		/* OpenPGP card spec 1.1 & 2.x, section 7.2.9 & 7.2.10 /
+		 * v3.x section 7.2.11 & 7.2.12 */
+		flags = SC_ALGORITHM_RSA_PAD_PKCS1 |
+			SC_ALGORITHM_RSA_HASH_NONE |
+			SC_ALGORITHM_ONBOARD_KEY_GEN;	/* key gen on card */
+
+		_sc_card_add_rsa_alg(card, key_info.u.rsa.modulus_len, flags, 0);
+		sc_log(card->ctx, "DO %zX: Added RSA algorithm, mod_len = %"
+			SC_FORMAT_LEN_SIZE_T"u",
+			do_num, key_info.u.rsa.modulus_len);
+		break;
+	case SC_OPENPGP_KEYALGO_ECDH:
+		/* The montgomery curve (curve25519) needs to go through
+		 * different paths, otherwise we handle it as a normal EC key */
+		if (_pgp_handle_curve25519(card, key_info, do_num))
+			break;
+		/* fall through */
+	case SC_OPENPGP_KEYALGO_ECDSA:
+		/* v3.0+: ECC [RFC 4880 & 6637] */
+
+		/* Allow curve to be used by both ECDH and ECDSA.
+		 * pgp_init set these flags the same way */
+		flags = SC_ALGORITHM_ECDH_CDH_RAW;
+		flags |= SC_ALGORITHM_ECDSA_RAW;
+		flags |= SC_ALGORITHM_ECDSA_HASH_NONE;
+		flags |= SC_ALGORITHM_ONBOARD_KEY_GEN;
+		ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE;
+
+		_sc_card_add_ec_alg(card, key_info.u.ec.key_length, flags, ext_flags,
+			&key_info.u.ec.oid);
+		sc_log(card->ctx, "DO %zX: Added EC algorithm (%d), mod_len = %d" ,
+			do_num, key_info.algorithm, key_info.u.ec.key_length);
+		break;
+	case SC_OPENPGP_KEYALGO_EDDSA:
+		/* EdDSA from draft-ietf-openpgp-rfc4880bis-08 */
+		/* Handle Yubikey bug, that in DO FA curve25519 has EDDSA algo */
+		if (_pgp_handle_curve25519(card, key_info, do_num))
+			break;
+		_sc_card_add_eddsa_alg(card, key_info.u.ec.key_length,
+			SC_ALGORITHM_EDDSA_RAW, 0, &key_info.u.ec.oid);
+
+		sc_log(card->ctx, "DO %zX: Added EDDSA algorithm (%d), mod_len = %d" ,
+			do_num, key_info.algorithm, key_info.u.ec.key_length);
+		break;
+	default:
+		sc_log(card->ctx, "DO %zX: Unknown algorithm ID (%d)" ,
+			do_num, key_info.algorithm);
+		/* return "false" if we do not understand algo */
+		return 0;
+	}
+	/* return true */
+	return 1;
+}
+
 
 /**
  * Internal: get features of the card: capabilities, ...
@@ -673,7 +753,8 @@
 	u8 *hist_bytes = card->reader->atr_info.hist_bytes;
 	size_t hist_bytes_len = card->reader->atr_info.hist_bytes_len;
 	size_t i;
-	pgp_blob_t *blob, *blob6e, *blob73;
+	pgp_blob_t *blob, *blob6e, *blob73, *blobfa;
+	int handled_algos = 0;
 
 	LOG_FUNC_CALLED(card->ctx);
 
@@ -725,6 +806,24 @@
 		card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO;
 	}
 
+	if (priv->bcd_version >= OPENPGP_CARD_3_4) {
+		/* Parse supported algorithms from Algorithm Information DO
+		 * see OpenPGP card spec 3.4 section 4.4.3.11 */
+		if (pgp_get_blob(card, priv->mf, 0x00fa, &blobfa) >= 0) {
+			pgp_blob_t *child;
+			pgp_enumerate_blob(card, blobfa);
+			/* There will be multiple children with the same ID, but
+			 * different algos, so we need to iterate over all of them */
+			for (child = blobfa->files; child; child = child->next) {
+				if ((child->id < 0x00c1) || (child->id > 0x00c3))
+					continue;
+				sc_cardctl_openpgp_keygen_info_t key_info;
+				if (pgp_parse_algo_attr_blob(card, child, &key_info) >= 0)
+					handled_algos += _pgp_add_algo(card, key_info, 0x00fa);
+			}
+		}
+	}
+
 	/* v1.1 & v2.x: special DOs are limited to 254 bytes */
 	priv->max_specialDO_size = 254;
 
@@ -797,6 +896,22 @@
 			card->max_pin_len = blob->data[1];
 		}
 
+		if (priv->bcd_version >= OPENPGP_CARD_3_0) {
+			/* v3.0+: get length info from "extended length information" DO */
+			if ((pgp_get_blob(card, blob6e, 0x7f66, &blob) >= 0) &&
+				(blob->data != NULL) && (blob->len >= 8)) {
+				/* kludge: treat as SIMPLE DO and use appropriate offsets */
+				card->max_send_size = bebytes2ushort(blob->data + 2);
+				card->max_recv_size = bebytes2ushort(blob->data + 6);
+			}
+		}
+
+		/* if we found at least one usable algo, let's skip other ways to find them */
+		if (handled_algos) {
+			sc_log(card->ctx, "Algo list populated from Algorithm Information DO");
+			LOG_FUNC_RETURN(card->ctx, handled_algos);
+		}
+
 		/* get _current_ algorithms & key lengths from "algorithm attributes" DOs
 		 *
 		 * All available algorithms should be already provided by pgp_init. However, if another
@@ -806,87 +921,18 @@
 		for (i = 0x00c1; i <= 0x00c3; i++) {
 			sc_cardctl_openpgp_keygen_info_t key_info;
 
-			sc_log(card->ctx, "Parsing algorithm attribues DO %zX" , i);
+			sc_log(card->ctx, "Parsing algorithm attributes DO %zX" , i);
 
 			/* OpenPGP card spec 1.1 & 2.x section 4.3.3.6 / v3.x section 4.4.3.7 */
 			if ((pgp_get_blob(card, blob73, i, &blob) >= 0) &&
 			    (pgp_parse_algo_attr_blob(card, blob, &key_info) >= 0)) {
-				unsigned long flags = 0, ext_flags = 0;
-
-				/* RSA [RFC 4880] */
-				switch (key_info.algorithm) {
-				case SC_OPENPGP_KEYALGO_RSA:
-					/* OpenPGP card spec 1.1 & 2.x, section 7.2.9 & 7.2.10 /
-					 * v3.x section 7.2.11 & 7.2.12 */
-					flags = SC_ALGORITHM_RSA_PAD_PKCS1 |
-						SC_ALGORITHM_RSA_HASH_NONE |
-						SC_ALGORITHM_ONBOARD_KEY_GEN;	/* key gen on card */
-
-					_sc_card_add_rsa_alg(card, key_info.u.rsa.modulus_len, flags, 0);
-					sc_log(card->ctx, "DO %zX: Added RSA algorithm, mod_len = %"
-						SC_FORMAT_LEN_SIZE_T"u",
-						i, key_info.u.rsa.modulus_len);
-					break;
-				case SC_OPENPGP_KEYALGO_ECDH:
-					/* The montgomery curve (curve25519) needs to go through
-					 * different paths, otherwise we handle it as a normal EC key */
-					if (sc_compare_oid(&key_info.u.ec.oid, &curve25519_oid)) {
-						/* CKM_XEDDSA supports both Sign and Derive, but
-						 * OpenPGP card supports only derivation using these
-						 * keys as far as I know */
-						_sc_card_add_xeddsa_alg(card, key_info.u.ec.key_length,
-							SC_ALGORITHM_ECDH_CDH_RAW, 0, &key_info.u.ec.oid);
-
-						sc_log(card->ctx, "DO %zX: Added XEDDSA algorithm (%d), mod_len = %d" ,
-							i, key_info.algorithm, key_info.u.ec.key_length);
-						break;
-					}
-					/* fall through */
-				case SC_OPENPGP_KEYALGO_ECDSA:
-					/* v3.0+: ECC [RFC 4880 & 6637] */
-					/* EdDSA from draft-ietf-openpgp-rfc4880bis-08 */
-					flags = 0, ext_flags = 0;
-
-					if (key_info.algorithm == SC_OPENPGP_KEYALGO_ECDH)
-						flags = SC_ALGORITHM_ECDH_CDH_RAW;
-					if (key_info.algorithm == SC_OPENPGP_KEYALGO_ECDSA)
-						flags = SC_ALGORITHM_ECDSA_RAW;
-					flags |= SC_ALGORITHM_ECDSA_HASH_NONE;
-					flags |= SC_ALGORITHM_ONBOARD_KEY_GEN;
-					ext_flags =  SC_ALGORITHM_EXT_EC_NAMEDCURVE;
-
-					_sc_card_add_ec_alg(card, key_info.u.ec.key_length, flags, ext_flags,
-						&key_info.u.ec.oid);
-					sc_log(card->ctx, "DO %zX: Added EC algorithm (%d), mod_len = %d" ,
-						i, key_info.algorithm, key_info.u.ec.key_length);
-					break;
-				case SC_OPENPGP_KEYALGO_EDDSA:
-					_sc_card_add_eddsa_alg(card, key_info.u.ec.key_length,
-						SC_ALGORITHM_EDDSA_RAW, 0, &key_info.u.ec.oid);
-
-					sc_log(card->ctx, "DO %zX: Added EDDSA algorithm (%d), mod_len = %d" ,
-						i, key_info.algorithm, key_info.u.ec.key_length);
-					break;
-				default:
-					sc_log(card->ctx, "DO %zX: Unknown algorithm ID (%d)" ,
-						i, key_info.algorithm);
-					break;
-				}
+				_pgp_add_algo(card, key_info, i);
 			}
 		}
 
-		if (priv->bcd_version >= OPENPGP_CARD_3_0) {
-			/* v3.0+: get length info from "extended length information" DO */
-			if ((pgp_get_blob(card, blob6e, 0x7f66, &blob) >= 0) &&
-				(blob->data != NULL) && (blob->len >= 8)) {
-				/* kludge: treat as SIMPLE DO and use appropriate offsets */
-				card->max_send_size = bebytes2ushort(blob->data + 2);
-				card->max_recv_size = bebytes2ushort(blob->data + 6);
-			}
-		}
 	}
 
-	return SC_SUCCESS;
+	LOG_FUNC_RETURN(card->ctx, handled_algos);
 }
 
 
@@ -901,7 +947,7 @@
 
 		if (priv != NULL) {
 			/* delete fake file hierarchy */
-			pgp_iterate_blobs(priv->mf, 99, pgp_free_blob);
+			pgp_iterate_blobs(priv->mf, pgp_free_blob);
 
 			/* delete private data */
 			free(priv);
@@ -1104,18 +1150,16 @@
  * Internal: iterate through the blob tree, calling a function for each blob.
  */
 static void
-pgp_iterate_blobs(pgp_blob_t *blob, int level, void (*func)())
+pgp_iterate_blobs(pgp_blob_t *blob, void (*func)())
 {
 	if (blob) {
-		if (level > 0) {
-			pgp_blob_t *child = blob->files;
+		pgp_blob_t *child = blob->files;
 
-			while (child != NULL) {
-				pgp_blob_t *next = child->next;
+		while (child != NULL) {
+			pgp_blob_t *next = child->next;
 
-				pgp_iterate_blobs(child, level-1, func);
-				child = next;
-			}
+			pgp_iterate_blobs(child, func);
+			child = next;
 		}
 		func(blob);
 	}
@@ -1180,6 +1224,7 @@
 {
 	const u8	*in;
 	int		r;
+	sc_file_t	*file = NULL;
 
 	if (blob->files != NULL)
 		return SC_SUCCESS;
@@ -1200,20 +1245,31 @@
 
 		r = sc_asn1_read_tag(&data, blob->len - (in - blob->data),
 					&cla, &tag, &len);
-		if (r < 0 || data == NULL) {
-			sc_log(card->ctx,
-				 "Unexpected end of contents\n");
+		if (r == SC_ERROR_INVALID_ASN1_OBJECT) {
+			sc_log(card->ctx, "Invalid ASN.1 object");
 			return SC_ERROR_OBJECT_NOT_VALID;
 		}
-
-		if (data + len > blob->data + blob->len)
+		/* Check for unknown error, or empty data */
+		if (((r < 0) && (r != SC_ERROR_ASN1_END_OF_CONTENTS)) ||
+		    (data == NULL)) {
+			sc_log(card->ctx, "Unexpected end of contents");
 			return SC_ERROR_OBJECT_NOT_VALID;
+		}
 
 		/* undo ASN1's split of tag & class */
 		for (tmptag = tag; tmptag > 0x0FF; tmptag >>= 8) {
 			cla <<= 8;
 		}
 		tag |= cla;
+		/* Check for length mismatch */
+		if ((r == SC_ERROR_ASN1_END_OF_CONTENTS) ||
+		    (data + len > blob->data + blob->len)) {
+			// Check if it is not known Yubikey 5 issue
+			if ((tag != blob->id) || (tag != 0xfa)) {
+				sc_log(card->ctx, "Unexpected end of contents");
+				return SC_ERROR_OBJECT_NOT_VALID;
+			}
+		}
 
 		/* Awful hack for composite DOs that have
 		 * a TLV with the DO's id encompassing the
@@ -1225,9 +1281,15 @@
 
 		/* create fake file system hierarchy by
 		 * using constructed DOs as DF */
-		if ((new = pgp_new_blob(card, blob, tag, sc_file_new())) == NULL)
+		file = sc_file_new();
+		if ((new = pgp_new_blob(card, blob, tag, file)) == NULL) {
+			sc_file_free(file);
+			return SC_ERROR_OUT_OF_MEMORY;
+		}
+		if (pgp_set_blob(new, data, len) != SC_SUCCESS) {
+			sc_file_free(file);
 			return SC_ERROR_OUT_OF_MEMORY;
-		pgp_set_blob(new, data, len);
+		}
 		in = data + len;
 	}
 
@@ -1698,7 +1760,7 @@
 		p15pubkey.u.eddsa.pubkey.len = 0;
 	}
 	sc_pkcs15_erase_pubkey(&p15pubkey);
-	
+
 	LOG_TEST_RET(card->ctx, r, "public key encoding failed");
 
 	if (len > buf_len)
@@ -1711,6 +1773,43 @@
 
 
 /**
+ * Internal: SELECT DATA - selects a DO within a DO tag with several instances
+ * (supported since OpenPGP Card v3 for DO 7F21 only, see section 7.2.5 of the specification;
+ *  this enables us to store multiple Card holder certificates in DO 7F21)
+ *
+ * p1: number of an instance (DO 7F21: 0x00 for AUT, 0x01 for DEC and 0x02 for SIG)
+ */
+static int
+pgp_select_data(sc_card_t *card, u8 p1){
+	sc_apdu_t	apdu;
+	u8	apdu_data[6];
+	int	r;
+
+	LOG_FUNC_CALLED(card->ctx);
+
+	sc_log(card->ctx, "select data with: %u", p1);
+
+	// create apdu data (taken from spec: SELECT DATA 7.2.5.)
+	apdu_data[0] = 0x60;
+	apdu_data[1] = 0x04;
+	apdu_data[2] = 0x5c;
+	apdu_data[3] = 0x02;
+	apdu_data[4] = 0x7f;
+	apdu_data[5] = 0x21;
+
+	// apdu, cla, ins, p1, p2, data, datalen, resp, resplen
+	sc_format_apdu_ex(&apdu, 0x00, 0xA5, p1, 0x04, apdu_data, sizeof(apdu_data), NULL, 0);
+
+	// transmit apdu
+	r = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	LOG_TEST_RET(card->ctx, r, "Card returned error");
+	LOG_FUNC_RETURN(card->ctx, r);
+}
+
+
+/**
  * ABI: ISO 7816-4 GET DATA - get contents of a DO.
  */
 static int
@@ -1749,7 +1848,6 @@
 	LOG_FUNC_RETURN(card->ctx, (int)apdu.resplen);
 }
 
-
 /**
  * Internal: write certificate for Gnuk.
  */
@@ -2275,7 +2373,7 @@
 		}
 		pklen = r;
 
-		/* Calculate lenght of Public Key DO (0x7F49) */
+		/* Calculate length of Public Key DO (0x7F49) */
 		r = sc_asn1_put_tag(0x7f49, NULL, pklen, NULL, 0, NULL);
 		if (r <= 0) {
 			free(temp);
@@ -2315,6 +2413,7 @@
 		*/
 		/* fall through */
 	default:
+		free(temp);
 		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
 	}
 
@@ -3456,13 +3555,15 @@
 		memmove((sc_serial_number_t *) ptr, &card->serialnr, sizeof(card->serialnr));
 		LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
 		break;
-
+	case SC_CARDCTL_OPENPGP_SELECT_DATA:
+		r = pgp_select_data(card, *((u8 *) ptr));
+		LOG_FUNC_RETURN(card->ctx, r);
+		break;
 #ifdef ENABLE_OPENSSL
 	case SC_CARDCTL_OPENPGP_GENERATE_KEY:
 		r = pgp_gen_key(card, (sc_cardctl_openpgp_keygen_info_t *) ptr);
 		LOG_FUNC_RETURN(card->ctx, r);
 		break;
-
 	case SC_CARDCTL_OPENPGP_STORE_KEY:
 		r = pgp_store_key(card, (sc_cardctl_openpgp_keystore_info_t *) ptr);
 		LOG_FUNC_RETURN(card->ctx, r);
diff -Nru opensc-0.22.0/src/libopensc/card-piv.c opensc-0.23.0/src/libopensc/card-piv.c
--- opensc-0.22.0/src/libopensc/card-piv.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-piv.c	2022-11-29 09:34:43.000000000 +0100
@@ -239,19 +239,49 @@
 	{ "3B:D8:18:00:80:B1:FE:45:1F:07:80:31:C1:64:08:06:92:0F:D5", NULL, NULL, SC_CARD_TYPE_PIV_II_OBERTHUR, 0, NULL },
 	{ "3b:86:80:01:80:31:c1:52:41:1a:7e", NULL, NULL, SC_CARD_TYPE_PIV_II_OBERTHUR, 0, NULL }, /* contactless */
 
-
-	/* PIVKEY from Taligo */
-	/* PIVKEY T600 token and T800  on Feitian eJAVA */
-	{ "3B:FC:18:00:00:81:31:80:45:90:67:46:4A:00:64:2D:70:C1:72:FE:E0:FE", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
-
-	/* PIVKEY C910 */
+	/* Following PIVKEY entries are from Windows registry provided by gw at taglio.com 2022-09-05 */
+	/* PIVKEY PIVKey Feitian (02) */
+	{ "3b:9f:95:81:31:fe:9f:00:66:46:53:05:10:00:11:71:df:00:00:00:00:00:02", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/* PIVKey Feitian (7C)  aka C910 contactless */
+	{ "3b:8c:80:01:90:67:46:4a:00:64:16:06:f2:72:7e:00:7c", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/*PIVKey Feitian (E0)  aka C910 */
 	{ "3b:fc:18:00:00:81:31:80:45:90:67:46:4a:00:64:16:06:f2:72:7e:00:e0", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
-	{ "3b:8c:80:01:90:67:46:4a:00:64:16:06:f2:72:7e:00:7c", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL }, /* contactless */
-
-
-	/* PIVKEY C980 */
-	{ "3B:f9:96:00:00:81:31:fe:45:53:50:49:56:4b:45:59:37:30:28", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
-	{ "3b:89:80:01:53:50:49:56:4b:45:59:37:30:44", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL }, /* contactless */
+	/* PIVKey Feitian (FE)  aka PIVKEY T600 token and T800  on Feitian eJAVA */
+	{ "3b:fc:18:00:00:81:31:80:45:90:67:46:4a:00:64:2d:70:c1:72:fe:e0:fe", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/* PIVKey JCOP241 (AD) */
+	{ "3b:f9:13:00:00:81:31:fe:45:53:50:49:56:4b:45:59:37:30:ad", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/* PIVKey JCOP242R2 (16) */
+	{ "3b:88:80:01:50:49:56:4b:45:59:37:30:16", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/* PIVKey JCOP242R2 (5E) */
+	{ "3b:88:80:01:4a:43:4f:50:76:32:34:31:5e", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/* PIVKey JCOP242R2 (B7) */
+	{ "3b:f8:13:00:00:81:31:fe:45:4a:43:4f:50:76:32:34:31:b7", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/* PIVKey JCOP3 (67) */
+	{ "3b:88:80:01:46:49:44:45:53:4d:4f:31:67", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/* PIVKey JCOP3 (8E) */
+	{ "3b:f8:13:00:00:81:31:fe:45:46:49:44:45:53:4d:4f:31:8e", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/* PIVKey JCOP31 (57) */
+	{ "3b:f9:18:00:ff:81:31:fe:45:4a:43:4f:50:33:31:56:32:32:57", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/* PIVKey NXP JCOP (03) */
+	{ "3b:8a:80:01:01:50:49:56:4b:45:59:37:30:16:03", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/* PIVKey NXP JCOP (FF)  aka CP70 */
+	{ "3b:f8:13:00:00:81:31:fe:45:50:49:56:4b:45:59:37:30:ff", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/* PIVKey SLE78 (3B) */
+	{ "3b:8d:80:01:53:4c:4a:35:32:47:44:4c:31:32:38:43:52:3b", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/* PIVKey SLE78 (6D) */
+	{ "3b:88:80:01:00:00:00:11:77:81:83:00:6d", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/* PIVKey SLE78 (28) aka C980 */
+	{ "3b:f9:96:00:00:81:31:fe:45:53:50:49:56:4b:45:59:37:30:28", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/* PIVKey SLE78 (44) aka C980 contactless */
+	{ "3b:89:80:01:53:50:49:56:4b:45:59:37:30:44", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/* PIVKey SLE78 (57B) */
+	{ "3b:fd:96:00:00:81:31:fe:45:53:4c:4a:35:32:47:44:4c:31:32:38:43:52:57", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/* PIVKey uTrust (01) ISO 14443 Type B without historical bytes */
+	{ "3b:80:80:01:01", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/* PIVKey uTrust (73) */
+	{ "3b:96:11:81:21:75:75:54:72:75:73:74:73", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
+	/* PIVKey uTrust FIDO2 (73) */
+	{ "3b:96:11:81:21:75:75:54:72:75:73:74:73", NULL, NULL, SC_CARD_TYPE_PIV_II_PIVKEY, 0, NULL },
 
 	/* ID-One PIV 2.4.1 on Cosmo V8.1 */
 	{ "3b:d6:96:00:81:b1:fe:45:1f:87:80:31:c1:52:41:1a:2a", NULL, NULL, SC_CARD_TYPE_PIV_II_OBERTHUR, 0, NULL },
@@ -260,6 +290,15 @@
 	{ NULL, NULL, NULL, 0, 0, NULL }
 };
 
+static struct piv_supported_ec_curves {
+	struct sc_object_id oid;
+	size_t size;
+} ec_curves[] = {
+	{{{1, 2, 840, 10045, 3, 1, 7, -1}},     256}, /* secp256r1, nistp256, prime256v1, ansiX9p256r1 */
+	{{{1, 3, 132, 0, 34, -1}},              384}, /* secp384r1, nistp384, prime384v1, ansiX9p384r1 */
+	{{{-1}}, 0} /* This entry must not be touched. */
+};
+
 /* all have same AID */
 static struct piv_aid piv_aids[] = {
 	{SC_CARD_TYPE_PIV_II_GENERIC, /* TODO not really card type but what PIV AID is supported */
@@ -994,7 +1033,7 @@
 			r = SC_ERROR_FILE_NOT_FOUND;
 			priv->obj_cache[enumtag].flags |= PIV_OBJ_CACHE_VALID;
 			priv->obj_cache[enumtag].obj_len = 0;
-		} else if ( r < 0) {
+		} else {
 			goto err;
 		}
 	}
@@ -1778,7 +1817,7 @@
 		goto err;
 	}
 
-	EVP_CIPHER_CTX_cleanup(ctx);
+	EVP_CIPHER_CTX_reset(ctx);
 
 	if (!EVP_DecryptInit(ctx, cipher, key, NULL)) {
 		r = SC_ERROR_INTERNAL;
@@ -1927,7 +1966,7 @@
 		goto err;
 	}
 
-	/* Store this to sanity check that plaintext length and cyphertext lengths match */
+	/* Store this to sanity check that plaintext length and ciphertext lengths match */
 	/* TODO is this required */
 	tmplen = challenge_len;
 
@@ -2397,14 +2436,8 @@
 {
 	piv_private_data_t * priv = PIV_DATA(card);
 	int r;
-	int i;
 	size_t nLen;
 	u8 rbuf[128]; /* For EC conversions  384 will fit */
-	const unsigned char *pseq, *pint, *ptemp, *pend;
-	unsigned int cla, tag;
-	size_t seqlen;
-	size_t intlen;
-	size_t templen;
 
 	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
 
@@ -2424,40 +2457,12 @@
 			r = SC_ERROR_INVALID_DATA;
 			goto err;
 		}
-		memset(out, 0, outlen);
 
 		r = piv_validate_general_authentication(card, data, datalen, rbuf, sizeof rbuf);
 		if (r < 0)
 			goto err;
-
-		pseq = rbuf;
-		r = sc_asn1_read_tag(&pseq, r, &cla, &tag, &seqlen);
-		if (pseq == NULL || r < 0 || seqlen == 0 || (cla|tag) != 0x30)
-			LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA, "Can't find 0x30");
-
-		pint = pseq;
-		pend = pseq + seqlen;
-		for (i = 0; i < 2; i++) {
-			r = sc_asn1_read_tag(&pint, (pend - pint), &cla, &tag, &intlen);
-			if (pint == NULL || r < 0 || intlen == 0 || (cla|tag) != 0x02)
-				LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA, "Can't find 0x02");
-			if (intlen > nLen + 1)
-				LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA,"Signature too long");
-
-			ptemp = pint;
-			templen = intlen;
-			if (intlen > nLen) { /* drop leading 00 if present */
-				if (*ptemp != 0x00) {
-					LOG_TEST_GOTO_ERR(card->ctx, SC_ERROR_INVALID_DATA,"Signature too long");
-				}
-				ptemp++;
-				templen--;
-			}
-			memcpy(out + nLen*i + nLen - templen, ptemp, templen);
-			pint += intlen; /* next integer */
-			
-		}
-		r = 2 * nLen;
+		
+		r = sc_asn1_decode_ecdsa_signature(card->ctx, rbuf, r, nLen, &out, outlen);
 	} else { /* RSA is all set */
 		r = piv_validate_general_authentication(card, data, datalen, out, outlen);
 	}
@@ -3006,6 +3011,11 @@
 
 	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
 	if (priv) {
+		if (priv->context_specific) {
+			sc_log(card->ctx, "Clearing CONTEXT_SPECIFIC lock");
+			priv->context_specific = 0;
+			sc_unlock(card);
+		}
 		if (priv->w_buf)
 			free(priv->w_buf);
 		if (priv->offCardCertURL)
@@ -3452,12 +3462,14 @@
 	_sc_card_add_rsa_alg(card, 3072, flags, 0); /* optional */
 
 	if (!(priv->card_issues & CI_NO_EC)) {
+		int i;
 		flags = SC_ALGORITHM_ECDSA_RAW | SC_ALGORITHM_ECDH_CDH_RAW | SC_ALGORITHM_ECDSA_HASH_NONE;
 		ext_flags = SC_ALGORITHM_EXT_EC_NAMEDCURVE | SC_ALGORITHM_EXT_EC_UNCOMPRESES;
 
-		_sc_card_add_ec_alg(card, 256, flags, ext_flags, NULL);
-		if (!(priv->card_issues & CI_NO_EC384))
-			_sc_card_add_ec_alg(card, 384, flags, ext_flags, NULL);
+		for (i = 0; ec_curves[i].oid.value[0] >= 0; i++) {
+			if (!(priv->card_issues & CI_NO_EC384 && ec_curves[i].size == 384))
+				_sc_card_add_ec_alg(card, ec_curves[i].size, flags, ext_flags, &ec_curves[i].oid);
+		}
 	}
 
 	if (!(priv->card_issues & CI_NO_RANDOM))
@@ -3748,7 +3760,7 @@
 
 /*
  * Called when a sc_lock gets a reader lock and PCSC SCardBeginTransaction
- * If SCardBeginTransaction may pass back tha a card reset was seen since
+ * If SCardBeginTransaction may pass back that a card reset was seen since
  * the last transaction  completed.
  * There may have been one or more resets, by other card drivers in different
  * processes, and they may have taken action already
diff -Nru opensc-0.22.0/src/libopensc/card-sc-hsm.c opensc-0.23.0/src/libopensc/card-sc-hsm.c
--- opensc-0.22.0/src/libopensc/card-sc-hsm.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-sc-hsm.c	2022-11-29 09:34:43.000000000 +0100
@@ -4,6 +4,7 @@
  * Driver for the SmartCard-HSM, a light-weight hardware security module
  *
  * Copyright (C) 2012 Andreas Schwier, CardContact, Minden, Germany, and others
+ * Copyright (C) 2018-2019 GSMK - Gesellschaft für Sichere Mobile Kommunikation mbH
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -923,7 +924,10 @@
 	}
 	LOG_TEST_RET(card->ctx, r, "ENUMERATE OBJECTS APDU transmit failed");
 
-	memcpy(buf, recvbuf, buflen);
+	if (buflen < apdu.resplen)
+		memcpy(buf, recvbuf, buflen);
+	else
+		memcpy(buf, recvbuf, apdu.resplen);
 
 	LOG_FUNC_RETURN(card->ctx, apdu.resplen);
 }
@@ -1030,10 +1034,8 @@
 					const u8 * data, size_t datalen,
 					u8 * out, size_t outlen) {
 
-	int i, r;
+	int r;
 	size_t fieldsizebytes;
-	const u8 *body, *tag;
-	size_t bodylen, taglen;
 
 	// Determine field size from length of signature
 	if (datalen <= 58) {			// 192 bit curve = 24 * 2 + 10 byte maximum DER signature
@@ -1046,7 +1048,7 @@
 		fieldsizebytes = 40;
 	} else if (datalen <= 106) {		// 384 bit curve = 48 * 2 + 10 byte maximum DER signature
 		fieldsizebytes = 48;
-	} else if (datalen <= 138) {		// 512 bit curve = 64 * 2 + 10 byte maximum DER signature
+	} else if (datalen <= 137) {		// 512 bit curve = 64 * 2 + 9 byte maximum DER signature
 		fieldsizebytes = 64;
 	} else {
 		fieldsizebytes = 66;
@@ -1056,41 +1058,7 @@
 	       "Field size %"SC_FORMAT_LEN_SIZE_T"u, signature buffer size %"SC_FORMAT_LEN_SIZE_T"u",
 	       fieldsizebytes, outlen);
 
-	if (outlen < (fieldsizebytes * 2)) {
-		LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "output too small for EC signature");
-	}
-	memset(out, 0, outlen);
-
-	// Copied from card-piv.c. Thanks
-	body = sc_asn1_find_tag(card->ctx, data, datalen, 0x30, &bodylen);
-
-	for (i = 0; i<2; i++) {
-		if (body) {
-			tag = sc_asn1_find_tag(card->ctx, body,  bodylen, 0x02, &taglen);
-			if (tag) {
-				bodylen -= taglen - (tag - body);
-				body = tag + taglen;
-
-				if (taglen > fieldsizebytes) { /* drop leading 00 if present */
-					if (*tag != 0x00) {
-						r = SC_ERROR_INVALID_DATA;
-						goto err;
-					}
-					tag++;
-					taglen--;
-				}
-				memcpy(out + fieldsizebytes*i + fieldsizebytes - taglen , tag, taglen);
-			} else {
-				r = SC_ERROR_INVALID_DATA;
-				goto err;
-			}
-		} else  {
-			r = SC_ERROR_INVALID_DATA;
-			goto err;
-		}
-	}
-	r = 2 * fieldsizebytes;
-err:
+	r = sc_asn1_decode_ecdsa_signature(card->ctx, data, datalen, fieldsizebytes, &out, outlen);
 	LOG_FUNC_RETURN(card->ctx, r);
 }
 
@@ -1235,7 +1203,7 @@
 	int r;
 	size_t tilen;
 	sc_apdu_t apdu;
-	u8 ibuff[64+0xFF], *p;
+	u8 ibuff[68+0xFF], *p;
 
 	LOG_FUNC_CALLED(card->ctx);
 
@@ -1268,6 +1236,13 @@
 		*p++ = (u8)params->dkek_shares;
 	}
 
+	if (params->num_of_pub_keys > 0) {
+		*p++ = 0x93;	// Use public key authentication
+		*p++ = 0x02;
+		*p++ = params->num_of_pub_keys; // Total number of public keys used for public authentication
+		*p++ = params->required_pub_keys; // Number of public keys required for authentication
+	}
+
 	if (params->bio1.len) {
 		*p++ = 0x95;
 		*p++ = params->bio1.len;
@@ -1424,10 +1399,174 @@
 	r = sc_transmit_apdu(card, &apdu);
 	LOG_TEST_RET(ctx, r, "APDU transmit failed");
 
-	r =  sc_check_sw(card, apdu.sw1, apdu.sw2);
+	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	LOG_TEST_RET(ctx, r, "Check SW error");
+
+	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+}
+
+static int verify_certificate(sc_card_t *card, sc_cvc_t *cvc,
+		const u8 *cvc_buf, size_t cvc_buf_len)
+{
+	u8 tag = SC_ASN1_TAG_CONTEXT | SC_ASN1_TAG_BIT_STRING; /* 0x83 */
+	size_t pukref_len;
+	u8 pukref[BUFSIZ];
+	sc_apdu_t apdu;
+	u8 *ptr;
+	int r;
 
+	LOG_FUNC_CALLED(card->ctx);
+
+	/* check if public key is already known */
+	if ((r = sc_asn1_put_tag(tag, (u8 *)cvc->chr, cvc->chrLen,
+					pukref, sizeof(pukref), &ptr)) < 0) {
+		sc_log(card->ctx, "Error formatting ASN.1 sequence: %s\n", sc_strerror(r));
+		LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN);
+	}
+	pukref_len = ptr - pukref;
+
+	/* MANAGE SECURITY ENVIRONMENT to query public key by chr */
+	sc_format_apdu_ex(&apdu, 0x00, 0x22, 0x81, 0xB6, pukref, pukref_len, NULL, 0);
+
+	r = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+
+	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	if (!r) {
+		/* already known */
+		LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+	}
+	if (apdu.sw1 != 0x6A && apdu.sw2 != 0x88) {
+		LOG_TEST_RET(card->ctx, SC_ERROR_UNKNOWN, "Check SW error");
+	}
+
+	if ((r = sc_asn1_put_tag(tag, (u8 *)cvc->car, cvc->carLen,
+					pukref, sizeof(pukref), &ptr)) < 0) {
+		sc_log(card->ctx, "Error formatting ASN.1 sequence: %s\n", sc_strerror(r));
+		LOG_FUNC_RETURN(card->ctx, SC_ERROR_UNKNOWN);
+	}
+	pukref_len = ptr - pukref;
+
+	/* MANAGE SECURITY ENVIRONMENT to set the CAR public key */
+	sc_format_apdu_ex(&apdu, 0x00, 0x22, 0x81, 0xB6, pukref, pukref_len, NULL, 0);
+
+	r = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	LOG_TEST_RET(card->ctx, r, "Check SW error");
+
+	/* PERFORM SECURITY OPERATION -> VERIFY CERTIFICATE */
+	sc_format_apdu_ex(&apdu, 0x00, 0x2A, 0x00, 0xBE, cvc_buf, cvc_buf_len, NULL, 0);
+
+	r = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	LOG_TEST_RET(card->ctx, r, "Check SW error");
+
+	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+}
+
+
+
+static int sc_hsm_register_public_key(sc_card_t *card,
+		sc_cardctl_sc_hsm_pka_register_t *pka_register)
+{
+	u8 tag = SC_ASN1_TAG_CONTEXT | SC_ASN1_TAG_BIT_STRING; /* 0x83 */
+	u8 recvbuf[4];
+	sc_context_t *ctx = card->ctx;
+	sc_apdu_t apdu;
+	u8 *ptr;
+	int r;
+	sc_pkcs15_card_t p15card;
+	const u8 *pka_buf;
+	size_t pka_buf_len;
+	sc_cvc_pka_t pka;
+	/* outer CAR in ASN.1 needs a byte for tag and a byte for length */
+	u8 asn1_outer_car[sizeof(pka.public_key_req.cvc.outer_car) + 2];
+
+	LOG_FUNC_CALLED(ctx);
+
+	memset(&pka, 0, sizeof(pka));
+	memset(&p15card, 0, sizeof(p15card));
+	p15card.card = card;
+
+	pka_buf = pka_register->buf;
+	pka_buf_len = pka_register->buflen;
+	r = sc_pkcs15emu_sc_hsm_decode_pka(&p15card, &pka_buf, &pka_buf_len, &pka);
+	LOG_TEST_GOTO_ERR(ctx, r, "sc_pkcs15emu_sc_hsm_decode_pka failed");
+
+	/* the DICA CVC must be verified first */
+	r = verify_certificate(card, &pka.dica.cvc, pka.dica.ptr, pka.dica.len);
+	LOG_TEST_GOTO_ERR(ctx, r, "Verify device issuer CA CVC failed");
+
+	/* the device CVC must be verified before registering the public key */
+	r = verify_certificate(card, &pka.device.cvc, pka.device.ptr, pka.device.len);
+	LOG_TEST_GOTO_ERR(ctx, r, "Verify device CVC failed");
+
+	r = sc_asn1_put_tag(tag,
+			(u8 *)pka.public_key_req.cvc.outer_car,
+			pka.public_key_req.cvc.outerCARLen,
+			asn1_outer_car, sizeof(asn1_outer_car), &ptr);
+	LOG_TEST_GOTO_ERR(ctx, r, "ASN.1 encode outer CAR failed");
+
+	/* MANAGE SECURITY ENVIRONMENT with the outer CAR of the public key */
+	sc_format_apdu_ex(&apdu, 0x00, 0x22, 0x81, 0xB6,
+			asn1_outer_car, ptr - asn1_outer_car, NULL, 0);
+
+	r = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_GOTO_ERR(ctx, r, "APDU transmit failed");
+	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	LOG_TEST_GOTO_ERR(ctx, r, "Check SW error");
+
+	sc_format_apdu_ex(&apdu, 0x80, 0x54, 0x00, 0x00,
+			pka.public_key_req.ptr, pka.public_key_req.len,
+			recvbuf, sizeof(recvbuf));
+
+	r = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_GOTO_ERR(ctx, r, "APDU transmit failed");
+	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
+	LOG_TEST_GOTO_ERR(ctx, r, "Check SW error");
+
+	pka_register->new_status.num_total = recvbuf[0];
+	pka_register->new_status.num_missing = recvbuf[1];
+	pka_register->new_status.num_required = recvbuf[2];
+	pka_register->new_status.num_authenticated = recvbuf[3];
+
+	r = 0;
+	/* fall-through */
+
+err:
+	sc_pkcs15emu_sc_hsm_free_cvc_pka(&pka);
+	return r;
+}
+
+
+
+static int sc_hsm_public_key_auth_status(sc_card_t *card,
+	sc_cardctl_sc_hsm_pka_status_t *status)
+{
+	u8 recvbuf[4];
+	sc_context_t *ctx = card->ctx;
+	sc_apdu_t apdu;
+	int r;
+
+	LOG_FUNC_CALLED(card->ctx);
+
+	/* get status */
+	sc_format_apdu_ex(&apdu, 0x00, 0x54, 0x00, 0x00, NULL, 0, recvbuf, sizeof recvbuf);
+	apdu.cla = 0x80;
+
+	r = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_RET(ctx, r, "APDU transmit failed");
+
+	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
 	LOG_TEST_RET(ctx, r, "Check SW error");
 
+	status->num_total = recvbuf[0];
+	status->num_missing = recvbuf[1];
+	status->num_required = recvbuf[2];
+	status->num_authenticated = recvbuf[3];
+
 	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
 }
 
@@ -1597,6 +1736,10 @@
 		return sc_hsm_wrap_key(card, (sc_cardctl_sc_hsm_wrapped_key_t *)ptr);
 	case SC_CARDCTL_SC_HSM_UNWRAP_KEY:
 		return sc_hsm_unwrap_key(card, (sc_cardctl_sc_hsm_wrapped_key_t *)ptr);
+	case SC_CARDCTL_SC_HSM_REGISTER_PUBLIC_KEY:
+		return sc_hsm_register_public_key(card, ptr);
+	case SC_CARDCTL_SC_HSM_PUBLIC_KEY_AUTH_STATUS:
+		return sc_hsm_public_key_auth_status(card, ptr);
 	}
 	return SC_ERROR_NOT_SUPPORTED;
 }
diff -Nru opensc-0.22.0/src/libopensc/card-sc-hsm.h opensc-0.23.0/src/libopensc/card-sc-hsm.h
--- opensc-0.22.0/src/libopensc/card-sc-hsm.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-sc-hsm.h	2022-11-29 09:34:43.000000000 +0100
@@ -74,6 +74,7 @@
 struct sc_cvc {
 	int cpi;							// Certificate profile indicator (0)
 	char car[17];						// Certification authority reference
+	size_t carLen;						// strlen of car
 
 	struct sc_object_id pukoid;			// Public key algorithm object identifier
 	u8 *primeOrModulus;					// Prime for ECC or modulus for RSA
@@ -94,11 +95,14 @@
 	int modulusSize;					// Size of RSA modulus in bits
 
 	char chr[21];						// Certificate holder reference
+	size_t chrLen;						// strlen of chr
 
 	u8 *signature;						// Certificate signature or request self-signed signature
 	size_t signatureLen;
 
 	char outer_car[17];					// Instance signing the request
+	size_t outerCARLen;					// strlen of outer_car
+
 	u8 *outerSignature;					// Request authenticating signature
 	size_t outerSignatureLen;
 };
@@ -116,15 +120,29 @@
 	const struct sc_lv_data coFactor;
 };
 
-
+typedef struct sc_cvc_pka_component {
+	sc_cvc_t cvc;
+	const u8 *ptr; /* don't free, this points to the middle of a buffer */
+	size_t len;
+} sc_cvc_pka_component_t;
+
+typedef struct sc_cvc_pka {
+	sc_cvc_pka_component_t public_key_req;	/* CVC request with public key */
+	sc_cvc_pka_component_t device;			/* device CVC*/
+	sc_cvc_pka_component_t dica;			/* device issuer CA CVC */
+} sc_cvc_pka_t;
 
 int sc_pkcs15emu_sc_hsm_decode_cvc(sc_pkcs15_card_t * p15card,
 											const u8 ** buf, size_t *buflen,
 											sc_cvc_t *cvc);
+int sc_pkcs15emu_sc_hsm_decode_pka(sc_pkcs15_card_t * p15card,
+	const u8 **buf, size_t *buflen,
+	sc_cvc_pka_t *pka);
 int sc_pkcs15emu_sc_hsm_encode_cvc(sc_pkcs15_card_t * p15card,
 		sc_cvc_t *cvc,
 		u8 ** buf, size_t *buflen);
 void sc_pkcs15emu_sc_hsm_free_cvc(sc_cvc_t *cvc);
+void sc_pkcs15emu_sc_hsm_free_cvc_pka(sc_cvc_pka_t *pka);
 int sc_pkcs15emu_sc_hsm_get_curve(struct ec_curve **curve, u8 *oid, size_t oidlen);
 int sc_pkcs15emu_sc_hsm_get_public_key(struct sc_context *ctx, sc_cvc_t *cvc, struct sc_pkcs15_pubkey *pubkey);
 
diff -Nru opensc-0.22.0/src/libopensc/card-setcos.c opensc-0.23.0/src/libopensc/card-setcos.c
--- opensc-0.22.0/src/libopensc/card-setcos.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-setcos.c	2022-11-29 09:34:43.000000000 +0100
@@ -436,7 +436,7 @@
 	/* Set file creation status  */
 	sc_file_set_prop_attr(file, &bFileStatus, 1);
 
-	/* Build ACI from local structure = get AC for each operation group */
+	/* Build ACL from local structure = get AC for each operation group */
 	if (file->sec_attr_len == 0) {
 		const int* p_idx;
 		int	       i;
diff -Nru opensc-0.22.0/src/libopensc/cards.h opensc-0.23.0/src/libopensc/cards.h
--- opensc-0.22.0/src/libopensc/cards.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/cards.h	2022-11-29 09:34:43.000000000 +0100
@@ -68,10 +68,6 @@
 	SC_CARD_TYPE_GPK_GPK8000_16K,
 	SC_CARD_TYPE_GPK_GPK16000 = 3160,
 
-	/* miocos driver */
-	SC_CARD_TYPE_MIOCOS_BASE = 4000,
-	SC_CARD_TYPE_MIOCOS_GENERIC,
-
 	/* mcrd driver */
 	SC_CARD_TYPE_MCRD_BASE = 5000,
 	SC_CARD_TYPE_MCRD_GENERIC,
@@ -94,6 +90,8 @@
 	SC_CARD_TYPE_STARCOS_GENERIC,
 	SC_CARD_TYPE_STARCOS_V3_4,
 	SC_CARD_TYPE_STARCOS_V3_5,
+	SC_CARD_TYPE_STARCOS_V3_4_ESIGN,
+	SC_CARD_TYPE_STARCOS_V3_5_ESIGN,
 
 	/* tcos driver */
 	SC_CARD_TYPE_TCOS_BASE = 8000,
@@ -108,10 +106,6 @@
 	SC_CARD_TYPE_OPENPGP_V3,
 	SC_CARD_TYPE_OPENPGP_GNUK,
 
-	/* jcop driver */
-	SC_CARD_TYPE_JCOP_BASE = 10000,
-	SC_CARD_TYPE_JCOP_GENERIC,
-
 	/* oberthur driver */
 	SC_CARD_TYPE_OBERTHUR_BASE = 11000,
 	SC_CARD_TYPE_OBERTHUR_GENERIC,
@@ -273,7 +267,10 @@
 	SC_CARD_TYPE_IDPRIME_GENERIC,
 
 	/* eDO cards */
-	SC_CARD_TYPE_EDO = 38000
+	SC_CARD_TYPE_EDO = 38000,
+
+	/* JCOP4 cards with NQ-Applet */
+	SC_CARD_TYPE_NQ_APPLET = 39000
 };
 
 extern sc_card_driver_t *sc_get_default_driver(void);
@@ -282,13 +279,11 @@
 extern sc_card_driver_t *sc_get_cyberflex_driver(void);
 extern sc_card_driver_t *sc_get_gpk_driver(void);
 extern sc_card_driver_t *sc_get_gemsafeV1_driver(void);
-extern sc_card_driver_t *sc_get_miocos_driver(void);
 extern sc_card_driver_t *sc_get_mcrd_driver(void);
 extern sc_card_driver_t *sc_get_setcos_driver(void);
 extern sc_card_driver_t *sc_get_starcos_driver(void);
 extern sc_card_driver_t *sc_get_tcos_driver(void);
 extern sc_card_driver_t *sc_get_openpgp_driver(void);
-extern sc_card_driver_t *sc_get_jcop_driver(void);
 extern sc_card_driver_t *sc_get_oberthur_driver(void);
 extern sc_card_driver_t *sc_get_belpic_driver(void);
 extern sc_card_driver_t *sc_get_atrust_acos_driver(void);
@@ -319,6 +314,7 @@
 extern sc_card_driver_t *sc_get_esteid2018_driver(void);
 extern sc_card_driver_t *sc_get_idprime_driver(void);
 extern sc_card_driver_t *sc_get_edo_driver(void);
+extern sc_card_driver_t *sc_get_nqApplet_driver(void);
 
 #ifdef __cplusplus
 }
diff -Nru opensc-0.22.0/src/libopensc/card-starcos.c opensc-0.23.0/src/libopensc/card-starcos.c
--- opensc-0.22.0/src/libopensc/card-starcos.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-starcos.c	2022-11-29 09:34:43.000000000 +0100
@@ -1,7 +1,7 @@
 /*
  * card-starcos.c: Support for STARCOS SPK 2.3 cards
  *
- * Copyright (C) 2003  Jörn Zukowski <zukowski at trustcenter.de> and 
+ * Copyright (C) 2003  Jörn Zukowski <zukowski at trustcenter.de> and
  *                     Nils Larsch   <larsch at trustcenter.de>, TrustCenter AG
  *
  * This library is free software; you can redistribute it and/or
@@ -44,7 +44,8 @@
 	{ "3B:DF:96:FF:81:31:FE:45:80:5B:44:45:2E:42:4E:4F:54:4B:31:30:30:81:05:A0", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5, 0, NULL },
 	{ "3B:D9:96:FF:81:31:FE:45:80:31:B8:73:86:01:E0:81:05:22", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5, 0, NULL },
 	{ "3B:D0:97:FF:81:B1:FE:45:1F:07:2B", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_4, 0, NULL },
-	{ "3b:df:96:ff:81:31:fe:45:80:5b:44:45:2e:42:41:5f:53:43:33:35:32:81:05:b5", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5, 0, NULL },
+	{ "3B:D0:96:FF:81:B1:FE:45:1F:07:2A", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_4, 0, NULL },
+	{ "3b:df:96:ff:81:31:fe:45:80:5b:44:45:2e:42:41:5f:53:43:33:35:32:81:05:b5", NULL, NULL, SC_CARD_TYPE_STARCOS_V3_5_ESIGN, 0, NULL },
 	{ NULL, NULL, NULL, 0, 0, NULL }
 };
 
@@ -58,7 +59,7 @@
 	NULL, 0, NULL
 };
 
-static const struct sc_card_error starcos_errors[] = 
+static const struct sc_card_error starcos_errors[] =
 {
 	{ 0x6600, SC_ERROR_INCORRECT_PARAMETERS, "Error setting the security env"},
 	{ 0x66F0, SC_ERROR_INCORRECT_PARAMETERS, "No space left for padding"},
@@ -84,6 +85,12 @@
 	unsigned int    pin_encoding;
 } starcos_ex_data;
 
+/*
+   This constant allows signing or
+   decrypting with RSA keys up to 4096 bits.
+*/
+#define STARCOS3X_PROBE_APDU_LENGTH	512
+
 #define PIN_ENCODING_DETERMINE	0
 #define PIN_ENCODING_DEFAULT	SC_PIN_ENCODING_GLP
 
@@ -106,6 +113,11 @@
 		} \
 	} while (0);
 
+/* card type helpers */
+#define IS_V34(card) card->type == SC_CARD_TYPE_STARCOS_V3_4 || card->type == SC_CARD_TYPE_STARCOS_V3_4_ESIGN
+#define IS_V35(card) card->type == SC_CARD_TYPE_STARCOS_V3_5 || card->type == SC_CARD_TYPE_STARCOS_V3_5_ESIGN
+#define IS_V3x(card) IS_V34(card) || IS_V35(card)
+
 /* the starcos part */
 static int starcos_match_card(sc_card_t *card)
 {
@@ -137,7 +149,7 @@
 static const char * starcos_ef_keyd = "3F000013";
 
 /**
- * Parses supported securiy mechanisms record data.
+ * Parses supported security mechanisms record data.
  * It returns SC_SUCCESS and the ctrl_ref_template structure data on success
  */
 static int starcos_parse_supported_sec_mechanisms(struct sc_card *card, const unsigned char * buf, size_t buflen, starcos_ctrl_ref_template * ctrl_ref_template)
@@ -167,7 +179,7 @@
 			LOG_FUNC_RETURN(ctx, SC_SUCCESS);
 		}
 	}
-	
+
 	LOG_FUNC_RETURN(ctx, SC_ERROR_TEMPLATE_NOT_FOUND);
 }
 
@@ -248,7 +260,7 @@
 /**
  * Determine v3.x PIN encoding by parsing either
  * EF.PWDD (for v3.4) or EF.KEYD (for v3.5)
- * 
+ *
  * It returns an OpenSC PIN encoding, using the default value on failure
  */
 static unsigned int starcos_determine_pin_encoding(sc_card_t *card)
@@ -256,9 +268,9 @@
 	unsigned int pin_format = PIN_FORMAT_DEFAULT;
 	unsigned int encoding = PIN_ENCODING_DETERMINE;
 
-	if ( card->type == SC_CARD_TYPE_STARCOS_V3_4 ) {
+	if ( IS_V34(card) ) {
 		starcos_determine_pin_format34(card, &pin_format);
-	} else if ( card->type == SC_CARD_TYPE_STARCOS_V3_5 ) {
+	} else if ( IS_V35(card) ) {
 		starcos_determine_pin_format35(card, &pin_format);
 	}
 
@@ -280,7 +292,66 @@
 	return encoding;
 }
 
+/**
+ * Returns 1 if an extended APDU can be sent to the card
+ * with the given card reader. Otherwise returns 0.
+ */
+static int starcos_probe_reader_for_ext_apdu(sc_card_t * card) {
+	sc_apdu_t apdu;
+	int rv;
+	/* try to read STARCOS3X_PROBE_APDU_LENGTH bytes */
+	u8 data[STARCOS3X_PROBE_APDU_LENGTH];
+
+	/* Get Data: Get Chip Serial Number */
+	sc_format_apdu(card, &apdu, SC_APDU_CASE_2_EXT, 0xCA, 0x9F, 0x6C);
+	apdu.cla = 0xA0;
+	apdu.resp = data;
+	apdu.resplen = sizeof(data);
+	apdu.le = apdu.resplen;
+	rv = sc_transmit_apdu(card, &apdu);
+	LOG_TEST_RET(card->ctx, rv, "Failed to send Get Data ext. APDU");
+	return (apdu.sw1 == 0x90 && apdu.sw2 == 0x00);
+}
+
+static int starcos_select_mf(sc_card_t * card) {
+	sc_apdu_t apdu;
+	const u8 mf_buf[2] = {0x3f, 0x00};
+
+	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x00, 0x0C);
+	apdu.le = 0;
+	apdu.lc = 2;
+	apdu.data    = mf_buf;
+	apdu.datalen = 2;
+	apdu.resplen = 0;
+
+	return sc_transmit_apdu(card, &apdu);
+}
+
+static int starcos_select_aid(sc_card_t *card,
+			      const u8 aid[16], size_t len,
+			      sc_file_t **file_out);
+
+/* returns 1 if the card has the eSign app with AID A0:00:00:02:45:53:69:67:6E
+   otherwise returns 0
+ */
+static int starcos_has_esign_app(sc_card_t * card) {
+	static const char * starcos_esign_aid = "A0:00:00:02:45:53:69:67:6E";
+	int rv;
 
+	rv = starcos_select_mf(card);
+	if ( rv == SC_SUCCESS ) {
+		u8 aid[SC_MAX_PATH_SIZE];
+		size_t len = sizeof(aid);
+
+		rv = sc_hex_to_bin(starcos_esign_aid, aid, &len);
+		LOG_TEST_RET(card->ctx, rv, "Failed to convert eSing AID");
+		rv = starcos_select_aid(card, aid, len, NULL);
+		if ( rv == SC_SUCCESS ) {
+			starcos_select_mf(card);
+		}
+	}
+	return ( rv == SC_SUCCESS );
+}
 
 static int starcos_init(sc_card_t *card)
 {
@@ -296,7 +367,7 @@
 	card->drv_data = (void *)ex_data;
 	ex_data->pin_encoding = PIN_ENCODING_DETERMINE;
 
-	flags = SC_ALGORITHM_RSA_PAD_PKCS1 
+	flags = SC_ALGORITHM_RSA_PAD_PKCS1
 		| SC_ALGORITHM_ONBOARD_KEY_GEN
 		| SC_ALGORITHM_RSA_PAD_ISO9796
 		| SC_ALGORITHM_RSA_HASH_NONE
@@ -305,22 +376,16 @@
 		| SC_ALGORITHM_RSA_HASH_RIPEMD160
 		| SC_ALGORITHM_RSA_HASH_MD5_SHA1;
 
-	card->caps = SC_CARD_CAP_RNG; 
+	card->caps = SC_CARD_CAP_RNG;
 
-	if (card->type == SC_CARD_TYPE_STARCOS_V3_4
-			|| card->type == SC_CARD_TYPE_STARCOS_V3_5) {
-		if (card->type == SC_CARD_TYPE_STARCOS_V3_4)
-			card->name = "STARCOS 3.4";
-		else
-			card->name = "STARCOS 3.5";
-		card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO;
-		card->caps |= SC_CARD_CAP_APDU_EXT;
+	if ( IS_V3x(card) ) {
 
 		flags |= SC_CARD_FLAG_RNG
 			| SC_ALGORITHM_RSA_HASH_SHA224
 			| SC_ALGORITHM_RSA_HASH_SHA256
 			| SC_ALGORITHM_RSA_HASH_SHA384
-			| SC_ALGORITHM_RSA_HASH_SHA512;
+			| SC_ALGORITHM_RSA_HASH_SHA512
+			| SC_ALGORITHM_RSA_PAD_PSS;
 
 		_sc_card_add_rsa_alg(card, 512, flags, 0x10001);
 		_sc_card_add_rsa_alg(card, 768, flags, 0x10001);
@@ -328,6 +393,15 @@
 		_sc_card_add_rsa_alg(card,1728, flags, 0x10001);
 		_sc_card_add_rsa_alg(card,1976, flags, 0x10001);
 		_sc_card_add_rsa_alg(card,2048, flags, 0x10001);
+		if ( IS_V34(card) ) {
+			card->name = "STARCOS 3.4";
+			card->caps |= SC_CARD_CAP_ISO7816_PIN_INFO;
+		} else {
+			card->name = "STARCOS 3.5";
+			_sc_card_add_rsa_alg(card,3072, flags, 0x10001);
+		}
+		card->max_send_size = 255;
+		card->max_recv_size = 256;
 	} else {
 		_sc_card_add_rsa_alg(card, 512, flags, 0x10001);
 		_sc_card_add_rsa_alg(card, 768, flags, 0x10001);
@@ -339,14 +413,41 @@
 	}
 
 	if (sc_parse_ef_atr(card) == SC_SUCCESS) {
-		if (card->ef_atr->card_capabilities & ISO7816_CAP_EXTENDED_LENGTH) {
-			card->caps |= SC_CARD_CAP_APDU_EXT;
+		size_t max_recv_size = 0;
+		size_t max_send_size = 0;
+
+		/* Add max. length values from IAS/ECC specific issuer data */
+		if ( card->ef_atr->issuer_data_len >= 4 ) {
+			max_recv_size = bebytes2ushort(card->ef_atr->issuer_data);
+			max_send_size = bebytes2ushort(card->ef_atr->issuer_data + 2);
 		}
+		/* which could be overridden with ISO7816 EF.ATR options, if present */
 		if (card->ef_atr->max_response_apdu > 0) {
-			card->max_recv_size = card->ef_atr->max_response_apdu;
+			max_recv_size = card->ef_atr->max_response_apdu;
 		}
 		if (card->ef_atr->max_command_apdu > 0) {
-			card->max_send_size = card->ef_atr->max_command_apdu;
+			max_send_size = card->ef_atr->max_command_apdu;
+		}
+
+		if ( max_send_size > 256 && max_recv_size > 256 ) {
+			size_t max_recv_size_prev = card->max_recv_size;
+			size_t max_send_size_prev = card->max_send_size;
+			/* allow SC_CARD_CAP_APDU_EXT independent of ef_atr->caps, see IAS/ECC issuer data above */
+			card->caps |= SC_CARD_CAP_APDU_EXT;
+			/* the received data should not exceed max_recv_size including the sw1/sw2 */
+			card->max_recv_size = max_recv_size - 2;
+			/* the sent APDU should not exceed max_send_size including the 4 bytes of the APDU and 2 * 3 bytes Lc/Le */
+			card->max_send_size = max_send_size - 10;
+			/* probe reader for extended APDU support */
+			if ( starcos_probe_reader_for_ext_apdu(card) ) {
+				sc_log(card->ctx, "Successfully probed extended APDU, enabling extended APDU with max send/recv %d/%d",
+					(int)card->max_send_size, (int)card->max_recv_size);
+			} else {
+				card->caps &= ~(SC_CARD_CAP_APDU_EXT);
+				card->max_recv_size = max_recv_size_prev;
+				card->max_send_size = max_send_size_prev;
+				sc_log(card->ctx, "Ext APDU probing failed, the actual reader does not support ext APDU");
+			}
 		}
 	}
 
@@ -355,6 +456,11 @@
 		ex_data->pin_encoding = starcos_determine_pin_encoding(card);
 	}
 
+	if ( card->type == SC_CARD_TYPE_STARCOS_V3_4 && starcos_has_esign_app(card) ) {
+		card->type = SC_CARD_TYPE_STARCOS_V3_4_ESIGN;
+		sc_log(card->ctx, "Card has eSign app, card type changed to %d", card->type);
+	}
+
 	return 0;
 }
 
@@ -376,7 +482,7 @@
 
 	size_t taglen, len = buflen;
 	const u8 *tag = NULL, *p;
-  
+
 	sc_log(ctx,  "processing FCI bytes\n");
 
 	if (buflen < 2)
@@ -394,16 +500,16 @@
 	file->shareable = 0;
 	file->record_length = 0;
 	file->size = 0;
-  
+
 	tag = sc_asn1_find_tag(ctx, p, len, 0x80, &taglen);
 	if (tag != NULL && taglen >= 2) {
 		int bytes = (tag[0] << 8) + tag[1];
-		sc_log(ctx, 
+		sc_log(ctx,
 			"  bytes in file: %d\n", bytes);
 		file->size = bytes;
 	}
 
-  	tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen);
+	tag = sc_asn1_find_tag(ctx, p, len, 0x82, &taglen);
 	if (tag != NULL) {
 		const char *type = "unknown";
 		const char *structure = "unknown";
@@ -447,9 +553,9 @@
 			}
 		}
 
- 		sc_log(ctx, 
+		sc_log(ctx,
 			"  type: %s\n", type);
-		sc_log(ctx, 
+		sc_log(ctx,
 			"  EF structure: %s\n", structure);
 	}
 	file->magic = SC_FILE_MAGIC;
@@ -463,7 +569,7 @@
 	size_t taglen, len = buflen;
 	const u8 *tag = NULL, *p;
 
-	sc_log(ctx, 
+	sc_log(ctx,
 		 "processing %"SC_FORMAT_LEN_SIZE_T"u FCI bytes\n", buflen);
 
 	if (buflen < 2)
@@ -499,7 +605,7 @@
 	size_t taglen, len = buflen;
 	const u8 *tag = NULL, *p;
 
-	sc_log(ctx, 
+	sc_log(ctx,
 		 "processing %"SC_FORMAT_LEN_SIZE_T"u FCP bytes\n", buflen);
 
 	if (buflen < 2)
@@ -514,7 +620,7 @@
 	tag = sc_asn1_find_tag(ctx, p, len, 0x80, &taglen);
 	if (tag != NULL && taglen >= 2) {
 		int bytes = (tag[0] << 8) + tag[1];
-		sc_log(ctx, 
+		sc_log(ctx,
 			"  bytes in file: %d\n", bytes);
 		file->size = bytes;
 	}
@@ -522,7 +628,7 @@
 	tag = sc_asn1_find_tag(ctx, p, len, 0xc5, &taglen);
 	if (tag != NULL && taglen >= 2) {
 		int bytes = (tag[0] << 8) + tag[1];
-		sc_log(ctx, 
+		sc_log(ctx,
 			"  bytes in file 2: %d\n", bytes);
 		file->size = bytes;
 	}
@@ -576,9 +682,9 @@
 				break;
 			}
 		}
-		sc_log(ctx, 
+		sc_log(ctx,
 			"  type: %s\n", type);
-		sc_log(ctx, 
+		sc_log(ctx,
 			"  EF structure: %s\n", structure);
 		if (taglen >= 2) {
 			if (tag[1] != 0x41 || taglen != 5) {
@@ -587,7 +693,7 @@
 			/* formatted EF */
 			file->record_length = (tag[2] << 8) + tag[3];
 			file->record_count = tag[4];
-			sc_log(ctx, 
+			sc_log(ctx,
 				"  rec_len: %"SC_FORMAT_LEN_SIZE_T"u  rec_cnt: %"SC_FORMAT_LEN_SIZE_T"u\n\n",
 				file->record_length, file->record_count);
 		}
@@ -636,7 +742,7 @@
 }
 
 static int starcos_select_aid(sc_card_t *card,
-			      u8 aid[16], size_t len,
+			      const u8 aid[16], size_t len,
 			      sc_file_t **file_out)
 {
 	sc_apdu_t apdu;
@@ -654,8 +760,8 @@
 
 	/* check return value */
 	if (!(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) && apdu.sw1 != 0x61 )
-    		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
-  
+		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, sc_check_sw(card, apdu.sw1, apdu.sw2));
+
 	/* update cache */
 	card->cache.current_path.type = SC_PATH_TYPE_DF_NAME;
 	card->cache.current_path.len = len;
@@ -670,7 +776,7 @@
 		file->path.len = 0;
 		file->size = 0;
 		/* AID */
-		for (i = 0; i < len; i++)  
+		for (i = 0; i < len; i++)
 			file->name[i] = aid[i];
 		file->namelen = len;
 		file->id = 0x0000;
@@ -701,8 +807,7 @@
 	apdu.data = (u8*)data;
 	apdu.datalen = 2;
 
-	if (card->type == SC_CARD_TYPE_STARCOS_V3_4
-			|| card->type == SC_CARD_TYPE_STARCOS_V3_5) {
+	if ( IS_V3x(card) ) {
 		if (id_hi == 0x3f && id_lo == 0x0) {
 			apdu.p1 = 0x0;
 			apdu.p2 = 0x0;
@@ -730,8 +835,7 @@
 		apdu.le = 0;
 		r = sc_transmit_apdu(card, &apdu);
 		LOG_TEST_RET(card->ctx, r, "APDU re-transmit failed");
-	} else if ((card->type == SC_CARD_TYPE_STARCOS_V3_4
-				|| card->type == SC_CARD_TYPE_STARCOS_V3_5)
+	} else if ((IS_V3x(card))
 			&& apdu.p2 == 0x4 && apdu.sw1 == 0x6a && apdu.sw2 == 0x82) {
 		/* not a file, could be a path */
 		bIsDF = 1;
@@ -796,8 +900,7 @@
 			*file_out = file;
 		} else {
 			/* ok, assume we have a EF */
-			if (card->type == SC_CARD_TYPE_STARCOS_V3_4
-					|| card->type == SC_CARD_TYPE_STARCOS_V3_5) {
+			if ( IS_V3x(card) ) {
 				if (isFCP) {
 					r = process_fcp_v3_4(card->ctx, file, apdu.resp,
 							apdu.resplen);
@@ -826,9 +929,12 @@
 			       sc_file_t **file_out)
 {
 	u8 pathbuf[SC_MAX_PATH_SIZE], *path = pathbuf;
-	int    r;
+	int    r, pathtype;
 	size_t i, pathlen;
 	char pbuf[SC_MAX_PATH_STRING_SIZE];
+	/* option for path caching, it is deactivated by default,
+	   but it can be enabled by setting cache_valid to option: card->cache.valid */
+	int    cache_valid = 0;
 
 	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_VERBOSE);
 
@@ -836,27 +942,54 @@
 	if (r != SC_SUCCESS)
 		pbuf[0] = '\0';
 
-	sc_log(card->ctx, 
+	sc_log(card->ctx,
 		 "current path (%s, %s): %s (len: %"SC_FORMAT_LEN_SIZE_T"u)\n",
 		 card->cache.current_path.type == SC_PATH_TYPE_DF_NAME ?
 		 "aid" : "path",
-		 card->cache.valid ? "valid" : "invalid", pbuf,
+		 cache_valid ? "valid" : "invalid", pbuf,
 		 card->cache.current_path.len);
 
+	if ( in_path->len > sizeof(pathbuf) ) {
+		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_BUFFER_TOO_SMALL);
+	}
 	memcpy(path, in_path->value, in_path->len);
 	pathlen = in_path->len;
+	pathtype = in_path->type;
+
+	if (in_path->aid.len) {
+		if (!pathlen) {
+			if ( in_path->aid.len > sizeof(pathbuf) ) {
+				SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_BUFFER_TOO_SMALL);
+			}
+			memcpy(path, in_path->aid.value, in_path->aid.len);
+			pathlen = in_path->aid.len;
+			pathtype = SC_PATH_TYPE_DF_NAME;
+		} else {
+			if (!cache_valid
+				|| card->cache.current_path.type != SC_PATH_TYPE_DF_NAME
+				|| card->cache.current_path.len != pathlen
+				|| memcmp(card->cache.current_path.value, in_path->aid.value, in_path->aid.len) != 0 ) {
+				r = starcos_select_aid(card, in_path->aid.value, in_path->aid.len, file_out);
+				LOG_TEST_RET(card->ctx, r, "Could not select AID!");
+			}
+
+			if (pathtype == SC_PATH_TYPE_DF_NAME) {
+				pathtype = SC_PATH_TYPE_FILE_ID;
+			}
+		}
+	}
 
-	if (in_path->type == SC_PATH_TYPE_FILE_ID)
+	if (pathtype == SC_PATH_TYPE_FILE_ID)
 	{	/* SELECT EF/DF with ID */
 		/* Select with 2byte File-ID */
 		if (pathlen != 2)
 			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_INVALID_ARGUMENTS);
 		return starcos_select_fid(card, path[0], path[1], file_out, 1);
 	}
-	else if (in_path->type == SC_PATH_TYPE_DF_NAME)
-      	{	/* SELECT DF with AID */
+	else if (pathtype == SC_PATH_TYPE_DF_NAME)
+    {	/* SELECT DF with AID */
 		/* Select with 1-16byte Application-ID */
-		if (card->cache.valid 
+		if (cache_valid
 		    && card->cache.current_path.type == SC_PATH_TYPE_DF_NAME
 		    && card->cache.current_path.len == pathlen
 		    && memcmp(card->cache.current_path.value, pathbuf, pathlen) == 0 )
@@ -867,7 +1000,7 @@
 		else
 			return starcos_select_aid(card, pathbuf, pathlen, file_out);
 	}
-	else if (in_path->type == SC_PATH_TYPE_PATH)
+	else if (pathtype == SC_PATH_TYPE_PATH)
 	{
 		u8 n_pathbuf[SC_MAX_PATH_SIZE];
 		int bMatch = -1;
@@ -884,8 +1017,7 @@
 		if (pathlen == 6 && ( path[0] != 0x3f || path[1] != 0x00 ))
 			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
 
-		if (card->type != SC_CARD_TYPE_STARCOS_V3_4
-				&& card->type != SC_CARD_TYPE_STARCOS_V3_5) {
+		if ( IS_V3x(card) ) {
 			/* unify path (the first FID should be MF) */
 			if (path[0] != 0x3f || path[1] != 0x00)
 			{
@@ -896,21 +1028,20 @@
 				pathlen += 2;
 			}
 		}
-	
+
 		/* check current working directory */
-		if (card->cache.valid 
+		if (cache_valid
 		    && card->cache.current_path.type == SC_PATH_TYPE_PATH
 		    && card->cache.current_path.len >= 2
 		    && card->cache.current_path.len <= pathlen )
 		{
 			bMatch = 0;
 			for (i=0; i < card->cache.current_path.len; i+=2)
-				if (card->cache.current_path.value[i] == path[i] 
+				if (card->cache.current_path.value[i] == path[i]
 				    && card->cache.current_path.value[i+1] == path[i+1] )
 					bMatch += 2;
 
-			if ((card->type == SC_CARD_TYPE_STARCOS_V3_4
-						|| card->type == SC_CARD_TYPE_STARCOS_V3_5)
+			if ((IS_V3x(card))
 					&& bMatch > 0 && (size_t) bMatch < card->cache.current_path.len) {
 				/* we're in the wrong folder, start traversing from root */
 				bMatch = 0;
@@ -918,7 +1049,7 @@
 			}
 		}
 
-		if ( card->cache.valid && bMatch >= 0 )
+		if ( cache_valid && bMatch >= 0 )
 		{
 			if ( pathlen - bMatch == 2 )
 				/* we are in the right directory */
@@ -927,23 +1058,23 @@
 			{
 				/* two more steps to go */
 				sc_path_t new_path;
-	
+
 				/* first step: change directory */
 				r = starcos_select_fid(card, path[bMatch], path[bMatch+1], NULL, 0);
 				LOG_TEST_RET(card->ctx, r, "SELECT FILE (DF-ID) failed");
-	
-				memset(&new_path, 0, sizeof(sc_path_t));	
+
+				memset(&new_path, 0, sizeof(sc_path_t));
 				new_path.type = SC_PATH_TYPE_PATH;
 				new_path.len  = pathlen - bMatch-2;
 				memcpy(new_path.value, &(path[bMatch+2]), new_path.len);
 				/* final step: select file */
 				return starcos_select_file(card, &new_path, file_out);
-      			}
+			}
 			else /* if (bMatch - pathlen == 0) */
 			{
 				/* done: we are already in the
 				 * requested directory */
-				sc_log(card->ctx, 
+				sc_log(card->ctx,
 					"cache hit\n");
 				/* copy file info (if necessary) */
 				if (file_out) {
@@ -1023,7 +1154,7 @@
  *
  * This function tries to create a somewhat usable Starcos spk 2.3 acl
  * from the OpenSC internal acl (storing the result in the supplied
- * sc_starcos_create_data structure). 
+ * sc_starcos_create_data structure).
  */
 static int starcos_process_acl(sc_card_t *card, sc_file_t *file,
 	sc_starcos_create_data *data)
@@ -1157,7 +1288,7 @@
  * \param card pointer to the sc_card structure
  * \param data pointer to a sc_starcos_create_data object
  * \return SC_SUCCESS or error code
- * 
+ *
  * This function creates the MF based on the information stored
  * in the sc_starcos_create_data.mf structure. Note: CREATE END must be
  * called separately to activate the ACs.
@@ -1179,7 +1310,7 @@
 
 	r = sc_transmit_apdu(card, &apdu);
 	LOG_TEST_RET(ctx, r, "APDU transmit failed");
-	return sc_check_sw(card, apdu.sw1, apdu.sw2);	
+	return sc_check_sw(card, apdu.sw1, apdu.sw2);
 }
 
 /** starcos_create_df
@@ -1239,7 +1370,7 @@
  * the sc_starcos_create_data.ef data structure.
  */
 static int starcos_create_ef(sc_card_t *card, sc_starcos_create_data *data)
-{	
+{
 	int    r;
 	sc_apdu_t       apdu;
 	sc_context_t   *ctx = card->ctx;
@@ -1300,7 +1431,7 @@
  * information in the sc_file structure (using starcos_process_acl).
  */
 static int starcos_create_file(sc_card_t *card, sc_file_t *file)
-{	
+{
 	int    r;
 	sc_starcos_create_data data;
 
@@ -1352,7 +1483,7 @@
 	apdu.lc   = 2;
 	apdu.datalen = 2;
 	apdu.data = sbuf;
-	
+
 	r = sc_transmit_apdu(card, &apdu);
 	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
 	sc_invalidate_cache(card);
@@ -1411,16 +1542,15 @@
 	tlen = data->key_len;
 	while (tlen != 0) {
 		/* transmit the key in chunks of STARCOS_WKEY_CSIZE bytes */
-		u8 clen = tlen < STARCOS_WKEY_CSIZE ? tlen : STARCOS_WKEY_CSIZE;
+		u8 c_len = tlen < STARCOS_WKEY_CSIZE ? tlen : STARCOS_WKEY_CSIZE;
 		sbuf[0] = 0xc2;
-		sbuf[1] = 3 + clen;
+		sbuf[1] = 3 + c_len;
 		sbuf[2] = data->kid;
 		sbuf[3] = (offset >> 8) & 0xff;
 		sbuf[4] = offset & 0xff;
-		memcpy(sbuf+5, p, clen);
-		len     = 5 + clen;
-		sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xf4,
-			       data->mode, 0x00);
+		memcpy(sbuf+5, p, c_len);
+		len = 5 + c_len;
+		sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xf4, data->mode, 0x00);
 		apdu.cla    |= 0x80;
 		apdu.lc      = len;
 		apdu.datalen = len;
@@ -1430,9 +1560,9 @@
 		LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
 		if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
 			return sc_check_sw(card, apdu.sw1, apdu.sw2);
-		offset += clen;
-		p      += clen;
-		tlen   -= clen;
+		offset += c_len;
+		p      += c_len;
+		tlen   -= c_len;
 	}
 	return SC_SUCCESS;
 }
@@ -1457,7 +1587,7 @@
 	CHECK_NOT_SUPPORTED_V3_4(card);
 
 	/* generate key */
-	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x46,  0x00, 
+	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x46,  0x00,
 			data->key_id);
 	apdu.le      = 0;
 	sbuf[0] = (u8)(data->key_length >> 8);
@@ -1522,15 +1652,15 @@
 
 	p     = sbuf;
 
-	if (card->type == SC_CARD_TYPE_STARCOS_V3_4
-			|| card->type == SC_CARD_TYPE_STARCOS_V3_5) {
-		if (!(env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) ||
+	if ( IS_V3x(card) ) {
+		u8 algorithm_supported = (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) ||
+								(env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PSS);
+		if (!algorithm_supported ||
 			!(env->flags & SC_SEC_ENV_KEY_REF_PRESENT) || env->key_ref_len != 1) {
 			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
 		}
 
-		/* don't know what these mean but doesn't matter as card seems to take
-		 * algorithm / cipher from PKCS#1 padding prefix */
+		/* Tag '84' (length 1) denotes key name or key reference */
 		*p++ = 0x84;
 		*p++ = 0x01;
 		if (env->flags & SC_SEC_ENV_FILE_REF_PRESENT) {
@@ -1544,27 +1674,40 @@
 				sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xB6);
 
 				/* algorithm / cipher selector? */
+				/* algorithm: 13.23 PKCS#1 signature with RSA (standard) */
+				/* algorithm: 13.33.30 PKCS#1-PSS signature with SHA-256 */
 				*p++ = 0x89;
-				*p++ = 0x02;
-				*p++ = 0x13;
-				*p++ = 0x23;
+				if (env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PSS) {
+					*p++ = 0x03;
+					*p++ = 0x13;
+					*p++ = 0x33;
+					*p++ = 0x30;
+				} else {
+					// fall back, RSA PKCS1 Padding
+					*p++ = 0x02;
+					*p++ = 0x13;
+					*p++ = 0x23;
+				}
 				break;
 
 			case SC_SEC_OPERATION_DECIPHER:
 				sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0x41, 0xB8);
 
 				/* algorithm / cipher selector? */
+				/* algorithm: 11.3  Encipherment RSA (standard) */
+				/* algorithm: 11.31 Encipherment RSA (standard) with PKCS#1 padding */
+				/* algorithm: 11.32 Encipherment RSA OAEP padding */
 				*p++ = 0x89;
 				*p++ = 0x02;
 				*p++ = 0x11;
-				if (card->type == SC_CARD_TYPE_STARCOS_V3_4)
+				if ( IS_V34(card) )
 					*p++ = 0x30;
 				else
 					*p++ = 0x31;
 				break;
 
 			default:
-				sc_log(card->ctx, 
+				sc_log(card->ctx,
 						"not supported for STARCOS 3.4 cards");
 				return SC_ERROR_NOT_SUPPORTED;
 		}
@@ -1660,7 +1803,7 @@
 		apdu.datalen = p - sbuf;
 		apdu.lc      = p - sbuf;
 		apdu.le      = 0;
-		/* we don't know whether to use 
+		/* we don't know whether to use
 		 * COMPUTE SIGNATURE or INTERNAL AUTHENTICATE */
 		r = sc_transmit_apdu(card, &apdu);
 		LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
@@ -1676,7 +1819,7 @@
 	}
 try_authenticate:
 	/* try INTERNAL AUTHENTICATE */
-	if (operation == SC_SEC_OPERATION_AUTHENTICATE && 
+	if (operation == SC_SEC_OPERATION_AUTHENTICATE &&
 	    env->algorithm_flags & SC_ALGORITHM_RSA_PAD_PKCS1) {
 		*p++ = 0x80;
 		*p++ = 0x01;
@@ -1714,16 +1857,15 @@
 
 	if (ex_data->sec_ops == SC_SEC_OPERATION_SIGN) {
 		/* compute signature with the COMPUTE SIGNATURE command */
-		
-		if (card->type == SC_CARD_TYPE_STARCOS_V3_4
-				|| card->type == SC_CARD_TYPE_STARCOS_V3_5) {
+
+		if ( IS_V3x(card) ) {
 			size_t tmp_len;
 
-			sc_format_apdu(card, &apdu, SC_APDU_CASE_4_SHORT, 0x2A,
+			sc_format_apdu(card, &apdu, SC_APDU_CASE_4, 0x2A,
 					   0x9E, 0x9A);
-			apdu.resp = rbuf;
-			apdu.resplen = sizeof(rbuf);
-			apdu.le = 0;
+			apdu.resp = out;
+			apdu.resplen = outlen;
+			apdu.le = outlen;
 			if (ex_data->fix_digestInfo) {
 				// need to pad data
 				unsigned int flags = ex_data->fix_digestInfo & SC_ALGORITHM_RSA_HASHES;
@@ -1731,7 +1873,11 @@
 					flags = SC_ALGORITHM_RSA_HASH_NONE;
 				}
 				tmp_len = sizeof(sbuf);
-				r = sc_pkcs1_encode(card->ctx, flags, data, datalen, sbuf, &tmp_len, sizeof(sbuf)*8);
+				if (ex_data->fix_digestInfo & SC_ALGORITHM_RSA_PAD_PSS) {
+					r = sc_pkcs1_strip_digest_info_prefix(NULL, data, datalen, sbuf, &tmp_len);
+				} else {
+					r = sc_pkcs1_encode(card->ctx, flags, data, datalen, sbuf, &tmp_len, sizeof(sbuf)*8, NULL);
+				}
 				LOG_TEST_RET(card->ctx, r, "sc_pkcs1_encode failed");
 			} else {
 				memcpy(sbuf, data, datalen);
@@ -1741,9 +1887,7 @@
 			apdu.data = sbuf;
 			apdu.datalen = tmp_len;
 			apdu.lc = tmp_len;
-			apdu.resp = rbuf;
-			apdu.resplen = sizeof(rbuf);
-			apdu.le = 0;
+
 			r = sc_transmit_apdu(card, &apdu);
 			LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
 		} else {
@@ -1777,7 +1921,9 @@
 		}
 		if (apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
 			size_t len = apdu.resplen > outlen ? outlen : apdu.resplen;
-			memcpy(out, apdu.resp, len);
+			if ( out != apdu.resp ) {
+				memcpy(out, apdu.resp, len);
+			}
 			SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, len);
 		}
 	} else if (ex_data->sec_ops == SC_SEC_OPERATION_AUTHENTICATE) {
@@ -1793,7 +1939,7 @@
 				flags = SC_ALGORITHM_RSA_HASH_NONE;
 			tmp_len = sizeof(sbuf);
 			r = sc_pkcs1_encode(card->ctx, flags, data, datalen,
-					sbuf, &tmp_len, sizeof(sbuf)*8);
+					sbuf, &tmp_len, sizeof(sbuf)*8, NULL);
 			if (r < 0)
 				return r;
 		} else {
@@ -1856,8 +2002,7 @@
 		}
 	}
 
-	if (card->type == SC_CARD_TYPE_STARCOS_V3_4
-			|| card->type == SC_CARD_TYPE_STARCOS_V3_5) {
+	if ( IS_V3x(card) ) {
 		sc_apdu_t apdu;
 
 		u8 *sbuf = malloc(crgram_len + 1);
@@ -1904,9 +2049,9 @@
 	const int err_count = sizeof(starcos_errors)/sizeof(starcos_errors[0]);
 	int i;
 
-	sc_log(card->ctx, 
+	sc_log(card->ctx,
 		"sw1 = 0x%02x, sw2 = 0x%02x\n", sw1, sw2);
-  
+
 	if (sw1 == 0x90)
 		return SC_SUCCESS;
 	if (sw1 == 0x63 && (sw2 & ~0x0fU) == 0xc0 )
@@ -1915,7 +2060,7 @@
 		(sw2 & 0x0f));
 		return SC_ERROR_PIN_CODE_INCORRECT;
 	}
-  
+
 	/* check starcos error messages */
 	for (i = 0; i < err_count; i++)
 		if (starcos_errors[i].SWs == ((sw1 << 8) | sw2))
@@ -1923,7 +2068,7 @@
 			sc_log(card->ctx,  "%s\n", starcos_errors[i].errorstr);
 			return starcos_errors[i].errorno;
 		}
-  
+
 	/* iso error */
 	return iso_ops->check_sw(card, sw1, sw2);
 }
@@ -1943,34 +2088,29 @@
 		return SC_SUCCESS;
 	}
 
-	switch (card->type) {
-		case SC_CARD_TYPE_STARCOS_V3_4:
-		case SC_CARD_TYPE_STARCOS_V3_5:
-			card->serialnr.len = SC_MAX_SERIALNR;
-			r = sc_parse_ef_gdo(card, card->serialnr.value, &card->serialnr.len, NULL, 0);
-			if (r < 0) {
-				card->serialnr.len = 0;
-				return r;
-			}
-			break;
-
-		default:
-			/* get serial number via GET CARD DATA */
-			sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xf6, 0x00, 0x00);
-			apdu.cla |= 0x80;
-			apdu.resp = rbuf;
-			apdu.resplen = sizeof(rbuf);
-			apdu.le   = 256;
-			apdu.lc   = 0;
-			apdu.datalen = 0;
-			r = sc_transmit_apdu(card, &apdu);
-			LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
-			if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
-				return SC_ERROR_INTERNAL;
-			/* cache serial number */
-			memcpy(card->serialnr.value, apdu.resp, MIN(apdu.resplen, SC_MAX_SERIALNR));
-			card->serialnr.len = MIN(apdu.resplen, SC_MAX_SERIALNR);
-			break;
+	if ( IS_V3x(card) ) {
+		card->serialnr.len = SC_MAX_SERIALNR;
+		r = sc_parse_ef_gdo(card, card->serialnr.value, &card->serialnr.len, NULL, 0);
+		if (r < 0) {
+			card->serialnr.len = 0;
+			return r;
+		}
+	} else {
+		/* get serial number via GET CARD DATA */
+		sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xf6, 0x00, 0x00);
+		apdu.cla |= 0x80;
+		apdu.resp = rbuf;
+		apdu.resplen = sizeof(rbuf);
+		apdu.le   = 256;
+		apdu.lc   = 0;
+		apdu.datalen = 0;
+		r = sc_transmit_apdu(card, &apdu);
+		LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
+		if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
+			return SC_ERROR_INTERNAL;
+		/* cache serial number */
+		memcpy(card->serialnr.value, apdu.resp, MIN(apdu.resplen, SC_MAX_SERIALNR));
+		card->serialnr.len = MIN(apdu.resplen, SC_MAX_SERIALNR);
 	}
 
 	/* copy and return serial number */
@@ -2010,19 +2150,37 @@
 	}
 }
 
+/**
+ * starcos_logout_v3_x()
+ * StarCOS 3.x cards will not clear the security status by selecting MF.
+ * Returning NOT_SUPPORTED would cause card reset, effectively invalidating
+ * the security status.
+ */
+static int starcos_logout_v3_x(sc_card_t *card)
+{
+	int r = SC_ERROR_NOT_SUPPORTED;
+	SC_FUNC_CALLED(card->ctx, SC_LOG_DEBUG_NORMAL);
+
+	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
+}
+
 static int starcos_logout(sc_card_t *card)
 {
 	int r;
 	sc_apdu_t apdu;
 	const u8 mf_buf[2] = {0x3f, 0x00};
 
+	if ( IS_V3x(card) ) {
+		return starcos_logout_v3_x(card);
+	}
+
 	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0xA4, 0x00, 0x0C);
 	apdu.le = 0;
 	apdu.lc = 2;
 	apdu.data    = mf_buf;
 	apdu.datalen = 2;
 	apdu.resplen = 0;
-	
+
 	r = sc_transmit_apdu(card, &apdu);
 	LOG_TEST_RET(card->ctx, r, "APDU re-transmit failed");
 
@@ -2042,15 +2200,11 @@
 
 	LOG_FUNC_CALLED(card->ctx);
 	starcos_ex_data * ex_data = (starcos_ex_data*)card->drv_data;
-	switch (card->type) {
-		case SC_CARD_TYPE_STARCOS_V3_4:
-		case SC_CARD_TYPE_STARCOS_V3_5:
-			data->flags |= SC_PIN_CMD_NEED_PADDING;
-			data->pin1.encoding = ex_data->pin_encoding;
-			/* fall through */
-		default:
-			r = iso_ops->pin_cmd(card, data, tries_left);
+	if ( IS_V3x(card) ) {
+		data->flags |= SC_PIN_CMD_NEED_PADDING;
+		data->pin1.encoding = ex_data->pin_encoding;
 	}
+	r = iso_ops->pin_cmd(card, data, tries_left);
 	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
 }
 
@@ -2059,7 +2213,7 @@
 	struct sc_card_driver *iso_drv = sc_get_iso7816_driver();
 	if (iso_ops == NULL)
 		iso_ops = iso_drv->ops;
-  
+
 	starcos_ops = *iso_drv->ops;
 	starcos_ops.match_card = starcos_match_card;
 	starcos_ops.init   = starcos_init;
@@ -2075,7 +2229,7 @@
 	starcos_ops.card_ctl    = starcos_card_ctl;
 	starcos_ops.logout      = starcos_logout;
 	starcos_ops.pin_cmd     = starcos_pin_cmd;
-  
+
 	return &starcos_drv;
 }
 
diff -Nru opensc-0.22.0/src/libopensc/card-westcos.c opensc-0.23.0/src/libopensc/card-westcos.c
--- opensc-0.22.0/src/libopensc/card-westcos.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/card-westcos.c	2022-11-29 09:34:43.000000000 +0100
@@ -57,13 +57,8 @@
 #ifdef DEBUG_SSL
 static void print_openssl_error(void)
 {
-	static int charge = 0;
 	long r;
 
-	if (!charge) {
-		ERR_load_crypto_strings();
-		charge = 1;
-	}
 	while ((r = ERR_get_error()) != 0)
 		fprintf(stderr, "%s\n", ERR_error_string(r, NULL));
 }
@@ -663,7 +658,10 @@
 {
 	int r;
 #ifdef ENABLE_OPENSSL
-	DES_key_schedule ks1, ks2;
+	EVP_CIPHER_CTX *cctx = NULL;
+	int tmplen = 0;
+	if ((cctx = EVP_CIPHER_CTX_new()) == NULL)
+		return SC_ERROR_INTERNAL;
 #endif
 	u8 buf[8];
 	if ((*len) < sizeof(buf))
@@ -673,9 +671,19 @@
 	if (r)
 		return r;
 #ifdef ENABLE_OPENSSL
-	DES_set_key((const_DES_cblock *) & key[0], &ks1);
-	DES_set_key((const_DES_cblock *) & key[8], &ks2);
-	DES_ecb2_encrypt((const_DES_cblock *)buf, (DES_cblock*)result, &ks1, &ks2, DES_ENCRYPT);
+	if (EVP_EncryptInit_ex(cctx, EVP_des_ede_ecb(), NULL, key, NULL) != 1 ||
+		EVP_CIPHER_CTX_set_padding(cctx,0) != 1 ||
+		EVP_EncryptUpdate(cctx, result, &tmplen, buf, *len) != 1) {
+		EVP_CIPHER_CTX_free(cctx);
+		return SC_ERROR_INTERNAL;
+	}
+	*len = tmplen;
+	if (EVP_EncryptFinal_ex(cctx, result + tmplen, &tmplen)  != 1) {
+		EVP_CIPHER_CTX_free(cctx);
+		return SC_ERROR_INTERNAL;
+    }
+	*len += tmplen;
+	EVP_CIPHER_CTX_free(cctx);
 	return SC_SUCCESS;
 #else
 	return SC_ERROR_NOT_SUPPORTED;
@@ -1096,15 +1104,17 @@
 				 const u8 * data, size_t data_len, u8 * out,
 				 size_t outlen)
 {
-	int r;
+	int r = SC_SUCCESS;
 	sc_file_t *keyfile = NULL;
 #ifdef ENABLE_OPENSSL
 	int idx = 0;
 	u8 buf[180];
 	priv_data_t *priv_data = NULL;
 	int pad;
-	RSA *rsa = NULL;
+	EVP_PKEY_CTX *ctx = NULL;
 	BIO *mem = BIO_new(BIO_s_mem());
+	EVP_PKEY *pkey = NULL;
+	size_t tmplen = 0;
 #endif
 
 	if (card == NULL)
@@ -1175,29 +1185,32 @@
 		idx += r;
 	} while (1);
 	BIO_set_mem_eof_return(mem, -1);
-	if (!d2i_RSAPrivateKey_bio(mem, &rsa)) {
+	if (!(pkey = d2i_PrivateKey_bio(mem, NULL))) {
 		sc_log(card->ctx, 
 			"RSA key invalid, %lu\n", ERR_get_error());
 		r = SC_ERROR_UNKNOWN;
 		goto out;
 	}
 
-	/* pkcs11 reset openssl functions */
-	RSA_set_method(rsa, RSA_PKCS1_OpenSSL());
-
-	if ((size_t)RSA_size(rsa) > outlen) {
+	if ((size_t)EVP_PKEY_size(pkey) > outlen) {
 		sc_log(card->ctx,  "Buffer too small\n");
 		r = SC_ERROR_OUT_OF_MEMORY;
 		goto out;
 	}
-#if 1
+
+	if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL) {
+		sc_log(card->ctx,  "Can not establish context\n");
+		r = SC_ERROR_UNKNOWN;
+		goto out;
+	}
+
 	if (mode) {		/* decipher */
-		r = RSA_private_decrypt(data_len, data, out, rsa, pad);
-		if (r == -1) {
+		if (EVP_PKEY_decrypt_init(ctx) != 1 ||
+			EVP_PKEY_CTX_set_rsa_padding(ctx, pad) != 1 ||
+			EVP_PKEY_decrypt(ctx, out, &tmplen, data, data_len) != 1) {
 
 #ifdef DEBUG_SSL
 			print_openssl_error();
-
 #endif
 			sc_log(card->ctx, 
 				"Decipher error %lu\n", ERR_get_error());
@@ -1207,13 +1220,12 @@
 	}
 
 	else {			/* sign */
-
-		r = RSA_private_encrypt(data_len, data, out, rsa, pad);
-		if (r == -1) {
+		if (EVP_PKEY_encrypt_init(ctx) != 1 ||
+			EVP_PKEY_CTX_set_rsa_padding(ctx, pad) != 1 ||
+			EVP_PKEY_encrypt(ctx, out, &tmplen, data, data_len) != 1) {
 
 #ifdef DEBUG_SSL
 			print_openssl_error();
-
 #endif
 			sc_log(card->ctx, 
 				"Signature error %lu\n", ERR_get_error());
@@ -1222,21 +1234,11 @@
 		}
 	}
 
-#else
-	if (RSA_sign(nid, data, data_len, out, &outlen, rsa) != 1) {
-		sc_log(card->ctx, 
-			"RSA_sign error %d \n", ERR_get_error());
-		r = SC_ERROR_UNKNOWN;
-		goto out;
-	}
-	r = outlen;
-
-#endif
 out:
 	if (mem)
 		BIO_free(mem);
-	if (rsa)
-		RSA_free(rsa);
+	EVP_PKEY_free(pkey);
+	EVP_PKEY_CTX_free(ctx);
 out2:
 #endif /* ENABLE_OPENSSL */
 	sc_file_free(keyfile);
diff -Nru opensc-0.22.0/src/libopensc/ctx.c opensc-0.23.0/src/libopensc/ctx.c
--- opensc-0.22.0/src/libopensc/ctx.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/ctx.c	2022-11-29 09:34:43.000000000 +0100
@@ -40,7 +40,11 @@
 #include "common/libscdl.h"
 #include "common/compat_strlcpy.h"
 #include "internal.h"
+#ifdef ENABLE_OPENSSL
+#include <openssl/crypto.h>
 #include "sc-ossl-compat.h"
+#endif
+
 
 static int ignored_reader(sc_context_t *ctx, sc_reader_t *reader)
 {
@@ -95,13 +99,8 @@
 
 static const struct _sc_driver_entry internal_card_drivers[] = {
 	{ "cardos",	(void *(*)(void)) sc_get_cardos_driver },
-	{ "flex",	(void *(*)(void)) sc_get_cryptoflex_driver },
 	{ "cyberflex",	(void *(*)(void)) sc_get_cyberflex_driver },
-#ifdef ENABLE_OPENSSL
-	{ "gpk",	(void *(*)(void)) sc_get_gpk_driver },
-#endif
 	{ "gemsafeV1",	(void *(*)(void)) sc_get_gemsafeV1_driver },
-	{ "asepcos",	(void *(*)(void)) sc_get_asepcos_driver },
 	{ "starcos",	(void *(*)(void)) sc_get_starcos_driver },
 	{ "tcos",	(void *(*)(void)) sc_get_tcos_driver },
 #ifdef ENABLE_OPENSSL
@@ -110,8 +109,6 @@
 	{ "iasecc",	(void *(*)(void)) sc_get_iasecc_driver },
 #endif
 	{ "belpic",	(void *(*)(void)) sc_get_belpic_driver },
-	{ "incrypto34", (void *(*)(void)) sc_get_incrypto34_driver },
-	{ "akis",	(void *(*)(void)) sc_get_akis_driver },
 #ifdef ENABLE_OPENSSL
 	{ "entersafe",(void *(*)(void)) sc_get_entersafe_driver },
 #ifdef ENABLE_SM
@@ -125,8 +122,6 @@
 	{ "dnie",       (void *(*)(void)) sc_get_dnie_driver },
 #endif
 	{ "masktech",	(void *(*)(void)) sc_get_masktech_driver },
-	{ "atrust-acos",(void *(*)(void)) sc_get_atrust_acos_driver },
-	{ "westcos",	(void *(*)(void)) sc_get_westcos_driver },
 	{ "esteid2018",	(void *(*)(void)) sc_get_esteid2018_driver },
 	{ "idprime",	(void *(*)(void)) sc_get_idprime_driver },
 #if defined(ENABLE_SM) && defined(ENABLE_OPENPACE)
@@ -154,6 +149,7 @@
 	{ "jpki",	(void *(*)(void)) sc_get_jpki_driver },
 	{ "npa",	(void *(*)(void)) sc_get_npa_driver },
 	{ "cac1",	(void *(*)(void)) sc_get_cac1_driver },
+	{ "nqapplet",	(void *(*)(void)) sc_get_nqApplet_driver },
 	/* The default driver should be last, as it handles all the
 	 * unrecognized cards. */
 	{ "default",	(void *(*)(void)) sc_get_default_driver },
@@ -161,8 +157,15 @@
 };
 
 static const struct _sc_driver_entry old_card_drivers[] = {
-	{ "miocos",	(void *(*)(void)) sc_get_miocos_driver },
-	{ "jcop",	(void *(*)(void)) sc_get_jcop_driver },
+	{ "akis",       (void *(*)(void)) sc_get_akis_driver },
+	{ "asepcos",    (void *(*)(void)) sc_get_asepcos_driver },
+	{ "atrust-acos",(void *(*)(void)) sc_get_atrust_acos_driver },
+	{ "flex",       (void *(*)(void)) sc_get_cryptoflex_driver },
+#ifdef ENABLE_OPENSSL
+    { "gpk",        (void *(*)(void)) sc_get_gpk_driver },
+#endif
+	{ "incrypto34", (void *(*)(void)) sc_get_incrypto34_driver },
+	{ "westcos",    (void *(*)(void)) sc_get_westcos_driver },
 	{ NULL, NULL }
 };
 
@@ -845,7 +848,7 @@
 		return r;
 	}
 
-#if defined(ENABLE_OPENSSL) && defined(OPENSSL_SECURE_MALLOC_SIZE)
+#if defined(ENABLE_OPENSSL) && defined(OPENSSL_SECURE_MALLOC_SIZE) && !defined(LIBRESSL_VERSION_NUMBER)
 	if (!CRYPTO_secure_malloc_initialized()) {
 		CRYPTO_secure_malloc_init(OPENSSL_SECURE_MALLOC_SIZE, OPENSSL_SECURE_MALLOC_SIZE/8);
 	}
diff -Nru opensc-0.22.0/src/libopensc/cwa14890.c opensc-0.23.0/src/libopensc/cwa14890.c
--- opensc-0.22.0/src/libopensc/cwa14890.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/cwa14890.c	2022-11-29 09:34:43.000000000 +0100
@@ -43,6 +43,15 @@
 #include <openssl/rand.h>
 #include "cwa14890.h"
 #include "cwa-dnie.h"
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+# include <openssl/core_names.h>
+# include <openssl/param_build.h>
+# include <openssl/provider.h>
+#endif
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	static OSSL_PROVIDER *legacy_provider = NULL;
+#endif
 
 #define MAX_RESP_BUFFER_SIZE 2048
 
@@ -108,7 +117,7 @@
  * @param card smart card info structure
  * @return SC_SUCCESS if ok; else error code
  *
- * TODO: to further study: what about using bignum arithmetics?
+ * TODO: to further study: what about using bignum arithmetic?
  */
 static int cwa_increase_ssc(sc_card_t * card)
 {
@@ -512,15 +521,15 @@
  *
  * @param card pointer to st_card_t card data information
  * @param icc_pubkey public key of card
- * @param ifd_privkey private RSA key of ifd
+ * @param ifd_privkey private key of ifd
  * @param sn_icc card serial number
  * @param sig signature buffer
  * @param sig_len signature buffer length
  * @return SC_SUCCESS if ok; else errorcode
  */
 static int cwa_prepare_external_auth(sc_card_t * card,
-				     const RSA * icc_pubkey,
-				     const RSA * ifd_privkey,
+				     EVP_PKEY *icc_pubkey,
+				     EVP_PKEY *ifd_privkey,
 				     u8 * sig,
 				     size_t sig_len)
 {
@@ -545,18 +554,30 @@
 	 */
 	char *msg = NULL;		/* to store error messages */
 	int res = SC_SUCCESS;
-	u8 *buf1;		/* where to encrypt with icc pub key */
-	u8 *buf2;		/* where to encrypt with ifd pub key */
-	u8 *buf3;		/* where to compose message to be encrypted */
-	int len1, len2, len3;
-	u8 *sha_buf;		/* to compose message to be sha'd */
-	u8 *sha_data;		/* sha signature data */
+	u8 *buf1 = NULL;		/* where to encrypt with icc pub key */
+	u8 *buf2 = NULL;		/* where to encrypt with ifd pub key */
+	u8 *buf3 = NULL;		/* where to compose message to be encrypted */
+	size_t len1 = 128, len2 = 128, len3 = 128;
+	u8 *sha_buf = NULL;		/* to compose message to be sha'd */
+	u8 *sha_data = NULL;		/* sha signature data */
 	BIGNUM *bn = NULL;
 	BIGNUM *bnsub = NULL;
 	BIGNUM *bnres = NULL;
 	sc_context_t *ctx = NULL;
-	const BIGNUM *ifd_privkey_n, *ifd_privkey_e, *ifd_privkey_d;
 	struct sm_cwa_session * sm = &card->sm_ctx.info.session.cwa;
+	EVP_PKEY_CTX *pctx = NULL;
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	const BIGNUM *ifd_privkey_n = NULL;
+	const RSA *rsa_ifd_privkey = EVP_PKEY_get0_RSA(ifd_privkey);
+	if (!rsa_ifd_privkey) {
+		res = SC_ERROR_INTERNAL;
+		msg = "Can not extract RSA object ifd priv";
+		goto prepare_external_auth_end;
+	}
+#else
+	BIGNUM *ifd_privkey_n = NULL;
+#endif
 
 	/* safety check */
 	if (!card || !card->ctx)
@@ -593,13 +614,19 @@
 	memcpy(buf3 + 1 + 74 + 32, sha_data, SHA_DIGEST_LENGTH);
 	buf3[127] = 0xBC;	/* iso padding */
 
-	/* encrypt with ifd private key */
-	len2 = RSA_private_decrypt(128, buf3, buf2, (RSA *)ifd_privkey, RSA_NO_PADDING);
-	if (len2 < 0) {
-		msg = "Prepare external auth: ifd_privk encrypt failed";
+	/* decrypt with ifd private key */
+	pctx = EVP_PKEY_CTX_new(ifd_privkey, NULL);
+	if (!pctx ||
+		EVP_PKEY_decrypt_init(pctx) != 1 ||
+		EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_NO_PADDING) != 1 ||
+		EVP_PKEY_decrypt(pctx, buf2, &len2, buf3, 128) != 1) {
+		msg = "Prepare external auth: ifd_privk decrypt failed";
 		res = SC_ERROR_SM_ENCRYPT_FAILED;
+		EVP_PKEY_CTX_free(pctx);
 		goto prepare_external_auth_end;
 	}
+	EVP_PKEY_CTX_free(pctx);
+	pctx = NULL;
 
 	/* evaluate value of minsig and store into buf3 */
 	bn = BN_bin2bn(buf2, len2, NULL);
@@ -609,7 +636,16 @@
 		res = SC_ERROR_INTERNAL;
 		goto prepare_external_auth_end;
 	}
-	RSA_get0_key(ifd_privkey, &ifd_privkey_n, &ifd_privkey_e, &ifd_privkey_d);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	RSA_get0_key(rsa_ifd_privkey, &ifd_privkey_n, NULL, NULL);
+#else
+	if (EVP_PKEY_get_bn_param(ifd_privkey, OSSL_PKEY_PARAM_RSA_N, &ifd_privkey_n) != 1) {
+		msg = "Prepare external auth: BN get param failed";
+		res = SC_ERROR_INTERNAL;
+		goto prepare_external_auth_end;
+	}
+#endif
+
 	res = BN_sub(bnsub, ifd_privkey_n, bn);	/* eval N.IFD-SIG */
 	if (res == 0) {		/* 1:success 0 fail */
 		msg = "Prepare external auth: BN sigmin evaluation failed";
@@ -630,12 +666,18 @@
 	}
 
 	/* re-encrypt result with icc public key */
-	len1 = RSA_public_encrypt(len3, buf3, buf1, (RSA *)icc_pubkey, RSA_NO_PADDING);
-	if (len1 <= 0 || (size_t) len1 != sig_len) {
+	pctx = EVP_PKEY_CTX_new(icc_pubkey, NULL);
+	if (!pctx ||
+		EVP_PKEY_encrypt_init(pctx) != 1 ||
+		EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_NO_PADDING) != 1 ||
+		EVP_PKEY_encrypt(pctx, buf1, &len1, buf3, 128) != 1 ||
+		(size_t) len1 != sig_len) {
 		msg = "Prepare external auth: icc_pubk encrypt failed";
 		res = SC_ERROR_SM_ENCRYPT_FAILED;
+		EVP_PKEY_CTX_free(pctx);
 		goto prepare_external_auth_end;
 	}
+	EVP_PKEY_CTX_free(pctx);
 
 	/* process done: copy result into cwa_internal buffer and return success */
 	memcpy(sig, buf1, len1);
@@ -665,6 +707,11 @@
 	if (sha_data) {
 		free(sha_data);
 	}
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	if (ifd_privkey_n) {
+		BN_clear_free(ifd_privkey_n);
+	}
+#endif
 
 	if (res != SC_SUCCESS)
 		sc_log(ctx, "%s", msg);
@@ -842,8 +889,8 @@
  * @return SC_SUCCESS if ok; else error code
  */
 static int cwa_verify_internal_auth(sc_card_t * card,
-				    const RSA * icc_pubkey,
-				    const RSA * ifd_privkey,
+				    EVP_PKEY *icc_pubkey,
+				    EVP_PKEY *ifd_privkey,
 				    u8 * ifdbuf,
 				    size_t ifdlen,
 				    u8 * sig,
@@ -854,14 +901,24 @@
 	u8 *buf1 = NULL;	/* to decrypt with our private key */
 	u8 *buf2 = NULL;	/* to try SIGNUM==SIG */
 	u8 *buf3 = NULL;	/* to try SIGNUM==N.ICC-SIG */
-	int len1 = 0;
-	int len2 = 0;
-	int len3 = 0;
+	size_t len1 = 128, len2 = 128, len3 = 128;
 	BIGNUM *bn = NULL;
 	BIGNUM *sigbn = NULL;
 	sc_context_t *ctx = NULL;
-	const BIGNUM *icc_pubkey_n, *icc_pubkey_e, *icc_pubkey_d;
 	struct sm_cwa_session * sm = &card->sm_ctx.info.session.cwa;
+	EVP_PKEY_CTX *pctx = NULL;
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	const BIGNUM *icc_pubkey_n = NULL;
+	const RSA *rsa_icc_pubkey = EVP_PKEY_get0_RSA(icc_pubkey);
+	if (!rsa_icc_pubkey) {
+		res = SC_ERROR_INTERNAL;
+		msg = "Can not extract RSA object icc pub";
+		goto verify_internal_done;
+	}
+#else
+	BIGNUM *icc_pubkey_n = NULL;
+#endif
 
 	if (!card || !card->ctx)
 		return SC_ERROR_INVALID_ARGUMENTS;
@@ -901,19 +958,34 @@
 	 */
 
 	/* decrypt data with our ifd priv key */
-	len1 = RSA_private_decrypt(sig_len, sig, buf1, (RSA *)ifd_privkey, RSA_NO_PADDING);
-	if (len1 <= 0) {
+	pctx = EVP_PKEY_CTX_new(ifd_privkey, NULL);
+	if (!pctx ||
+		EVP_PKEY_decrypt_init(pctx) != 1 ||
+		EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_NO_PADDING) != 1 ||
+		EVP_PKEY_decrypt(pctx, buf1, &len1, sig, sig_len) != 1) {
 		msg = "Verify Signature: decrypt with ifd privk failed";
 		res = SC_ERROR_SM_ENCRYPT_FAILED;
+		EVP_PKEY_CTX_free(pctx);
 		goto verify_internal_done;
 	}
+	EVP_PKEY_CTX_free(pctx);
+	pctx = NULL;
 
 	/* OK: now we have SIGMIN in buf1 */
 	/* check if SIGMIN data matches SIG or N.ICC-SIG */
 	/* evaluate DS[SK.ICC.AUTH](SIG) trying to decrypt with icc pubk */
-	len3 = RSA_public_encrypt(len1, buf1, buf3, (RSA *) icc_pubkey, RSA_NO_PADDING);
-	if (len3 <= 0)
+	pctx = EVP_PKEY_CTX_new(icc_pubkey, NULL);
+	if (!pctx ||
+		EVP_PKEY_encrypt_init(pctx) != 1 ||
+		EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_NO_PADDING) != 1 ||
+		EVP_PKEY_encrypt(pctx, buf3, &len3, buf1, len1) != 1) {
+		EVP_PKEY_CTX_free(pctx);
 		goto verify_nicc_sig;	/* evaluate N.ICC-SIG and retry */
+	}
+
+	EVP_PKEY_CTX_free(pctx);
+	pctx = NULL;
+
 	res = cwa_compare_signature(buf3, len3, ifdbuf);
 	if (res == SC_SUCCESS)
 		goto verify_internal_ok;
@@ -930,7 +1002,15 @@
 		res = SC_ERROR_OUT_OF_MEMORY;
 		goto verify_internal_done;
 	}
-	RSA_get0_key(icc_pubkey, &icc_pubkey_n, &icc_pubkey_e, &icc_pubkey_d);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	RSA_get0_key(rsa_icc_pubkey, &icc_pubkey_n, NULL, NULL);
+#else
+	if (EVP_PKEY_get_bn_param(icc_pubkey, OSSL_PKEY_PARAM_RSA_N, &icc_pubkey_n) != 1) {
+		msg = "Verify Signature: BN get param failed";
+		res = SC_ERROR_INTERNAL;
+		goto verify_internal_ok;
+	}
+#endif
 	res = BN_sub(sigbn, icc_pubkey_n, bn);	/* eval N.ICC-SIG */
 	if (!res) {
 		msg = "Verify Signature: evaluation of N.ICC-SIG failed";
@@ -945,12 +1025,19 @@
 	}
 	/* ok: check again with new data */
 	/* evaluate DS[SK.ICC.AUTH](I.ICC-SIG) trying to decrypt with icc pubk */
-	len3 = RSA_public_encrypt(len2, buf2, buf3, (RSA *)icc_pubkey, RSA_NO_PADDING);
-	if (len3 <= 0) {
+	pctx = EVP_PKEY_CTX_new(icc_pubkey, NULL);
+	if (!pctx ||
+		EVP_PKEY_encrypt_init(pctx) != 1 ||
+		EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_NO_PADDING) != 1 ||
+		EVP_PKEY_encrypt(pctx, buf3, &len3, buf2, len2) != 1) {
 		msg = "Verify Signature: cannot get valid SIG data";
 		res = SC_ERROR_INVALID_DATA;
+		EVP_PKEY_CTX_free(pctx);
 		goto verify_internal_done;
 	}
+	EVP_PKEY_CTX_free(pctx);
+	pctx = NULL;
+
 	res = cwa_compare_signature(buf3, len3, ifdbuf);
 	if (res != SC_SUCCESS) {
 		msg = "Verify Signature: cannot get valid SIG data";
@@ -972,6 +1059,10 @@
 		BN_free(bn);
 	if (sigbn)
 		BN_free(sigbn);
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	if (icc_pubkey_n)
+		BN_clear_free(icc_pubkey_n);
+#endif
 	if (res != SC_SUCCESS)
 		sc_log(ctx, "%s", msg);
 	LOG_FUNC_RETURN(ctx, res);
@@ -1276,8 +1367,8 @@
 
 	/* verify received signature */
 	sc_log(ctx, "Verify Internal Auth command response");
-	res = cwa_verify_internal_auth(card, EVP_PKEY_get0_RSA(icc_pubkey),	/* evaluated icc public key */
-				       EVP_PKEY_get0_RSA(ifd_privkey),	/* evaluated from DGP's Manual Annex 3 Data */
+	res = cwa_verify_internal_auth(card, icc_pubkey,	/* evaluated icc public key */
+				       ifd_privkey,	/* evaluated from DGP's Manual Annex 3 Data */
 				       rndbuf,	/* RND.IFD || SN.IFD */
 				       16,	/* rndbuf length; should be 16 */
 				       sig, 128
@@ -1296,9 +1387,7 @@
 	}
 
 	/* compose signature data for external auth */
-	res = cwa_prepare_external_auth(card,
-					EVP_PKEY_get0_RSA(icc_pubkey),
-					EVP_PKEY_get0_RSA(ifd_privkey), sig, 128);
+	res = cwa_prepare_external_auth(card, icc_pubkey, ifd_privkey, sig, 128);
 	if (res != SC_SUCCESS) {
 		msg = "Prepare external auth failed";
 		goto csc_end;
@@ -1376,8 +1465,6 @@
 	u8 *ccbuf = NULL;		/* where to store data to eval cryptographic checksum CC */
 	size_t cclen = 0;
 	u8 macbuf[8];		/* to store and compute CC */
-	DES_key_schedule k1;
-	DES_key_schedule k2;
 	char *msg = NULL;
 
 	size_t i, j;		/* for xor loops */
@@ -1387,6 +1474,10 @@
 	u8 *msgbuf = NULL;	/* to encrypt apdu data */
 	u8 *cryptbuf = NULL;
 
+	EVP_CIPHER_CTX *cctx = NULL;
+	unsigned char *key = NULL;
+	int tmplen = 0;
+
 	/* mandatory check */
 	if (!card || !card->ctx || !provider)
 		return SC_ERROR_INVALID_ARGUMENTS;
@@ -1454,30 +1545,38 @@
 	*(ccbuf + cclen++) = to->p2;
 	cwa_iso7816_padding(ccbuf, &cclen);	/* pad header (4 bytes pad) */
 
+	if (!(cctx = EVP_CIPHER_CTX_new())) {
+		res = SC_ERROR_INTERNAL;
+		goto err;
+	}
+
 	/* if no data, skip data encryption step */
 	if (from->lc != 0) {
-		size_t dlen = from->lc;
-
-		/* prepare keys */
-		DES_cblock iv = { 0, 0, 0, 0, 0, 0, 0, 0 };
-		DES_set_key_unchecked((const_DES_cblock *) & (sm_session->session_enc[0]),
-				      &k1);
-		DES_set_key_unchecked((const_DES_cblock *) & (sm_session->session_enc[8]),
-				      &k2);
+		unsigned char iv[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+		int dlen = from->lc;
+		size_t len = dlen;
 
 		/* pad message */
 		memcpy(msgbuf, from->data, dlen);
-		cwa_iso7816_padding(msgbuf, &dlen);
+		cwa_iso7816_padding(msgbuf, &len);
+		dlen = len;
 
 		/* start kriptbuff with iso padding indicator */
 		*cryptbuf = 0x01;
-		/* apply TDES + CBC with kenc and iv=(0,..,0) */
-		DES_ede3_cbc_encrypt(msgbuf, cryptbuf + 1, dlen, &k1, &k2, &k1,
-				     &iv, DES_ENCRYPT);
+		key = sm_session->session_enc;
+
+		if (EVP_EncryptInit_ex(cctx, EVP_des_ede_cbc(), NULL, key, iv) != 1 ||
+			EVP_CIPHER_CTX_set_padding(cctx, 0) != 1 ||
+			EVP_EncryptUpdate(cctx, cryptbuf + 1, &dlen, msgbuf, dlen) != 1 ||
+			EVP_EncryptFinal_ex(cctx, cryptbuf + 1 + dlen, &tmplen) != 1) {
+			msg = "Error in encrypting APDU";
+			res = SC_ERROR_INTERNAL;
+			goto encode_end;
+		}
+		dlen += tmplen;
+
 		/* compose data TLV and add to result buffer */
-		res =
-		    cwa_compose_tlv(card, 0x87, dlen + 1, cryptbuf, &ccbuf,
-				    &cclen);
+		res = cwa_compose_tlv(card, 0x87, dlen + 1, cryptbuf, &ccbuf, &cclen);
 		if (res != SC_SUCCESS) {
 			msg = "Error in compose tag 8x87 TLV";
 			goto encode_end;
@@ -1513,22 +1612,55 @@
 		msg = "Error in computing SSC";
 		goto encode_end;
 	}
-	/* set up keys for mac computing */
-	DES_set_key_unchecked((const_DES_cblock *) & (sm_session->session_mac[0]),&k1);
-	DES_set_key_unchecked((const_DES_cblock *) & (sm_session->session_mac[8]),&k2);
 
 	memcpy(macbuf, sm_session->ssc, 8);	/* start with computed SSC */
+
+	tmplen = 0;
+	key = sm_session->session_mac;
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	if (!legacy_provider) {
+		if (!(legacy_provider = OSSL_PROVIDER_try_load(NULL, "legacy", 1))) {
+			msg = "Failed to load legacy provider";
+			res = SC_ERROR_INTERNAL;
+			goto encode_end;
+		}
+	}
+#endif
+
+	if (EVP_EncryptInit_ex(cctx, EVP_des_ecb(), NULL, key, NULL) != 1 ||
+		EVP_CIPHER_CTX_set_padding(cctx, 0) != 1) {
+		msg = "Error in DES ECB encryption";
+		res = SC_ERROR_INTERNAL;
+		goto encode_end;
+	 }
+
 	for (i = 0; i < cclen; i += 8) {	/* divide data in 8 byte blocks */
 		/* compute DES */
-		DES_ecb_encrypt((const_DES_cblock *) macbuf,
-				(DES_cblock *) macbuf, &k1, DES_ENCRYPT);
+		if (EVP_EncryptUpdate(cctx, macbuf, &tmplen, macbuf , 8) != 1) {
+			msg = "Error in DES ECB encryption";
+			res = SC_ERROR_INTERNAL;
+			goto encode_end;
+		}
 		/* XOR with next data and repeat */
 		for (j = 0; j < 8; j++)
 			macbuf[j] ^= ccbuf[i + j];
 	}
+	if (EVP_EncryptFinal_ex(cctx, macbuf + tmplen, &tmplen) != 1) {
+		msg = "Error in DES ECB encryption";
+		res = SC_ERROR_INTERNAL;
+		goto encode_end;
+	}
+
 	/* and apply 3DES to result */
-	DES_ecb2_encrypt((const_DES_cblock *) macbuf, (DES_cblock *) macbuf,
-			 &k1, &k2, DES_ENCRYPT);
+	if (EVP_EncryptInit_ex(cctx, EVP_des_ede_ecb(), NULL, key, NULL) != 1 ||
+		EVP_CIPHER_CTX_set_padding(cctx, 0) != 1 ||
+		EVP_EncryptUpdate(cctx, macbuf, &tmplen, macbuf, 8) != 1 ||
+		EVP_EncryptFinal_ex(cctx, macbuf + tmplen, &tmplen) != 1) {
+		msg = "Error in 3DEC ECB encryption";
+		res = SC_ERROR_INTERNAL;
+		goto encode_end;
+	}
 
 	/* compose and add computed MAC TLV to result buffer */
 	tlv_len = (card->atr.value[15] >= DNIE_30_VERSION)? 8 : 4;
@@ -1555,6 +1687,8 @@
 	if (from->resp != to->resp)
 		free(to->resp);
 encode_end_apdu_valid:
+	if (cctx)
+		EVP_CIPHER_CTX_free(cctx);
 	if (msg)
 		sc_log(ctx, "%s", msg);
 	free(msgbuf);
@@ -1592,13 +1726,18 @@
 	size_t cclen = 0;	/* ccbuf len */
 	u8 macbuf[8];		/* where to calculate mac */
 	size_t resplen = 0;	/* respbuf length */
-	DES_key_schedule k1;
-	DES_key_schedule k2;
 	int res = SC_SUCCESS;
 	char *msg = NULL;	/* to store error messages */
 	sc_context_t *ctx = NULL;
 	struct sm_cwa_session * sm_session = &card->sm_ctx.info.session.cwa;
 
+	EVP_CIPHER_CTX *cctx = NULL;
+	unsigned char *key = NULL;
+	int tmplen = 0;
+
+	if ((cctx = EVP_CIPHER_CTX_new()) == NULL)
+		return SC_ERROR_INTERNAL;
+
 	/* mandatory check */
 	if (!card || !card->ctx || !provider)
 		return SC_ERROR_INVALID_ARGUMENTS;
@@ -1718,22 +1857,53 @@
 		msg = "Error in computing SSC";
 		goto response_decode_end;
 	}
-	/* set up keys for mac computing */
-	DES_set_key_unchecked((const_DES_cblock *) & (sm_session->session_mac[0]), &k1);
-	DES_set_key_unchecked((const_DES_cblock *) & (sm_session->session_mac[8]), &k2);
+	/* set up key for mac computing */
+	key = sm_session->session_mac;
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	if (!legacy_provider) {
+		if (!(legacy_provider = OSSL_PROVIDER_try_load(NULL, "legacy", 1))) {
+			msg = "Failed to load legacy provider";
+			res = SC_ERROR_INTERNAL;
+			goto response_decode_end;
+		}
+	}
+#endif
+
+	if (EVP_EncryptInit_ex(cctx, EVP_des_ecb(), NULL, key, NULL) != 1 ||
+		EVP_CIPHER_CTX_set_padding(cctx, 0) != 1) {
+		msg = "Error in DES ECB encryption";
+		res = SC_ERROR_INTERNAL;
+		goto response_decode_end;
+	 }
 
 	memcpy(macbuf, sm_session->ssc, 8);	/* start with computed SSC */
 	for (i = 0; i < cclen; i += 8) {	/* divide data in 8 byte blocks */
 		/* compute DES */
-		DES_ecb_encrypt((const_DES_cblock *) macbuf,
-				(DES_cblock *) macbuf, &k1, DES_ENCRYPT);
+		if (EVP_EncryptUpdate(cctx, macbuf, &tmplen, macbuf, 8) != 1) {
+			msg = "Error in DES ECB encryption";
+			res = SC_ERROR_INTERNAL;
+			goto response_decode_end;
+		}
 		/* XOR with data and repeat */
 		for (j = 0; j < 8; j++)
 			macbuf[j] ^= ccbuf[i + j];
 	}
+	if (EVP_EncryptFinal_ex(cctx, macbuf + tmplen, &tmplen) != 1) {
+		msg = "Error in DES ECB encryption";
+		res = SC_ERROR_INTERNAL;
+		goto response_decode_end;
+	}
+
 	/* finally apply 3DES to result */
-	DES_ecb2_encrypt((const_DES_cblock *) macbuf, (DES_cblock *) macbuf,
-			 &k1, &k2, DES_ENCRYPT);
+	if (EVP_EncryptInit_ex(cctx, EVP_des_ede_ecb(), NULL, key, NULL) != 1 ||
+		EVP_CIPHER_CTX_set_padding(cctx, 0) != 1 ||
+		EVP_EncryptUpdate(cctx, macbuf, &tmplen, macbuf, 8) != 1 ||
+		EVP_EncryptFinal_ex(cctx, macbuf + tmplen, &tmplen) != 1) {
+		msg = "Error in 3DEC ECB encryption";
+		res = SC_ERROR_INTERNAL;
+		goto response_decode_end;
+	}
 
 	/* check evaluated mac with provided by apdu response */
 
@@ -1763,7 +1933,8 @@
 
 	/* if encoded data, decode and store into apdu response */
 	else if (e_tlv->buf) {	/* encoded data */
-		DES_cblock iv = { 0, 0, 0, 0, 0, 0, 0, 0 };
+		unsigned char iv[8] = { 0, 0, 0, 0, 0, 0, 0, 0 };
+		int dlen = apdu->resplen;
 		/* check data len */
 		if ((e_tlv->len < 9) || ((e_tlv->len - 1) % 8) != 0) {
 			msg = "Invalid length for Encoded data TLV";
@@ -1777,21 +1948,25 @@
 			goto response_decode_end;
 		}
 		/* prepare keys to decode */
-		DES_set_key_unchecked((const_DES_cblock *) & (sm_session->session_enc[0]),
-				      &k1);
-		DES_set_key_unchecked((const_DES_cblock *) & (sm_session->session_enc[8]),
-				      &k2);
+		key = sm_session->session_enc;
+
 		/* decrypt into response buffer
 		 * by using 3DES CBC by mean of kenc and iv={0,...0} */
-		DES_ede3_cbc_encrypt(&e_tlv->data[1], apdu->resp, e_tlv->len - 1,
-				     &k1, &k2, &k1, &iv, DES_DECRYPT);
-		apdu->resplen = e_tlv->len - 1;
+		if (EVP_DecryptInit_ex(cctx, EVP_des_ede_cbc(), NULL, key, iv) != 1 ||
+			EVP_CIPHER_CTX_set_padding(cctx, 0) != 1 ||
+			EVP_DecryptUpdate(cctx, apdu->resp, &dlen, &e_tlv->data[1], e_tlv->len - 1) != 1 ||
+			EVP_DecryptFinal_ex(cctx, apdu->resp + dlen, &tmplen) != 1) {
+			res = SC_ERROR_INTERNAL;
+			msg = "Can not decrypt 3DES CBC";
+			goto response_decode_end;
+		}
+		apdu->resplen = dlen + tmplen;
+
 		/* remove iso padding from response length */
 		for (; (apdu->resplen > 0) && *(apdu->resp + apdu->resplen - 1) == 0x00; apdu->resplen--) ;	/* empty loop */
 
 		if (*(apdu->resp + apdu->resplen - 1) != 0x80) {	/* check padding byte */
-			msg =
-			    "Decrypted TLV has no 0x80 iso padding indicator!";
+			msg = "Decrypted TLV has no 0x80 iso padding indicator!";
 			res = SC_ERROR_INVALID_DATA;
 			goto response_decode_end;
 		}
@@ -1806,6 +1981,7 @@
 	res = SC_SUCCESS;
 
  response_decode_end:
+ 	EVP_CIPHER_CTX_free(cctx);
 	if (buffer)
 		free(buffer);
 	if (ccbuf)
diff -Nru opensc-0.22.0/src/libopensc/cwa-dnie.c opensc-0.23.0/src/libopensc/cwa-dnie.c
--- opensc-0.22.0/src/libopensc/cwa-dnie.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/cwa-dnie.c	2022-11-29 09:34:43.000000000 +0100
@@ -44,6 +44,10 @@
 #include <openssl/x509.h>
 #include <openssl/evp.h>
 #include <openssl/rsa.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+# include <openssl/core_names.h>
+# include <openssl/param_build.h>
+#endif
 
 #define MAX_RESP_BUFFER_SIZE 2048
 
@@ -612,7 +616,7 @@
  * Just created in case this will be modified.
  *
  * @param card Pointer to card driver structure
- * @param data The data for the channel will be assined here
+ * @param data The data for the channel will be assigned here
  * @return SC_SUCCESS if ok; else error code
  */
 static int dnie_get_channel_data(sc_card_t * card, dnie_channel_data_t ** data) {
@@ -675,44 +679,91 @@
  */
 static int dnie_get_root_ca_pubkey(sc_card_t * card, EVP_PKEY ** root_ca_key)
 {
-	int res=SC_SUCCESS;
-	RSA *root_ca_rsa=NULL;
-	BIGNUM *root_ca_rsa_n, *root_ca_rsa_e;
+	int res = SC_SUCCESS;
+	BIGNUM *root_ca_rsa_n = NULL, *root_ca_rsa_e = NULL;
 	dnie_channel_data_t *data;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	RSA *root_ca_rsa = NULL;
+	root_ca_rsa = RSA_new();
+	*root_ca_key = EVP_PKEY_new();
+	if (!root_ca_rsa || !*root_ca_key) {
+		if (root_ca_rsa)
+			RSA_free(root_ca_rsa);
+		if (*root_ca_key)
+			EVP_PKEY_free(*root_ca_key);
+#else
+	EVP_PKEY_CTX *ctx = NULL;
+	OSSL_PARAM_BLD *bld = NULL;
+	OSSL_PARAM *params = NULL;
+	
+	ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
+	if (!ctx) {
+#endif
+		sc_log(card->ctx, "Cannot create data for root CA public key");
+		return SC_ERROR_OUT_OF_MEMORY;
+	}
+
 	LOG_FUNC_CALLED(card->ctx);
 
 	/* obtain the data channel info for the card */
 	res = dnie_get_channel_data(card, &data);
+	if (res < 0) {
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+		RSA_free(root_ca_rsa);
+		EVP_PKEY_free(*root_ca_key);
+#else
+		EVP_PKEY_CTX_free(ctx);
+#endif
+	}
 	LOG_TEST_RET(card->ctx, res, "Error getting the card channel data");
 
 	/* compose root_ca_public key with data provided by Dnie Manual */
-	*root_ca_key = EVP_PKEY_new();
-	root_ca_rsa = RSA_new();
-	if (!*root_ca_key || !root_ca_rsa) {
-		sc_log(card->ctx, "Cannot create data for root CA public key");
-		return SC_ERROR_OUT_OF_MEMORY;
-	}
-
 	root_ca_rsa_n = BN_bin2bn(data->icc_root_ca.modulus.value, data->icc_root_ca.modulus.len, NULL);
 	root_ca_rsa_e = BN_bin2bn(data->icc_root_ca.exponent.value, data->icc_root_ca.exponent.len, NULL);
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 	if (RSA_set0_key(root_ca_rsa, root_ca_rsa_n, root_ca_rsa_e, NULL) != 1) {
 		BN_free(root_ca_rsa_n);
 		BN_free(root_ca_rsa_e);
-		if (*root_ca_key)
-			EVP_PKEY_free(*root_ca_key);
-		if (root_ca_rsa)
-			RSA_free(root_ca_rsa);
+		EVP_PKEY_free(*root_ca_key);
+		RSA_free(root_ca_rsa);
 		sc_log(card->ctx, "Cannot set RSA values for CA public key");
 		return SC_ERROR_INTERNAL;
 	}
-
 	res = EVP_PKEY_assign_RSA(*root_ca_key, root_ca_rsa);
 	if (!res) {
-		if (*root_ca_key)
-			EVP_PKEY_free(*root_ca_key);	/*implies root_ca_rsa free() */
+		RSA_free(root_ca_rsa);
+#else
+	if (!(bld = OSSL_PARAM_BLD_new()) ||
+		OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, root_ca_rsa_n) != 1 ||
+		OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, root_ca_rsa_e) != 1 ||
+		!(params = OSSL_PARAM_BLD_to_param(bld))) {
+		OSSL_PARAM_BLD_free(bld);
+		OSSL_PARAM_free(params);
+		EVP_PKEY_CTX_free(ctx);
+		sc_log(card->ctx, "Cannot set RSA values for CA public key");
+		return SC_ERROR_INTERNAL;
+	}
+	OSSL_PARAM_BLD_free(bld);
+
+	if (EVP_PKEY_fromdata_init(ctx) != 1 ||
+		EVP_PKEY_fromdata(ctx, root_ca_key, EVP_PKEY_PUBLIC_KEY, params) != 1) {
+		EVP_PKEY_CTX_free(ctx);
+		OSSL_PARAM_free(params);
+#endif
+		BN_free(root_ca_rsa_n);
+		BN_free(root_ca_rsa_e);
+		EVP_PKEY_free(*root_ca_key);
 		sc_log(card->ctx, "Cannot compose root CA public key");
 		return SC_ERROR_INTERNAL;
 	}
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	EVP_PKEY_CTX_free(ctx);
+	OSSL_PARAM_free(params);
+	BN_free(root_ca_rsa_n);
+	BN_free(root_ca_rsa_e);
+#endif
 	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
 }
 
@@ -823,22 +874,41 @@
                             u8 * public_exponent, int public_exponent_len,
                             u8 * private_exponent, int private_exponent_len)
 {
-	RSA *ifd_rsa=NULL;
-	BIGNUM *ifd_rsa_n, *ifd_rsa_e, *ifd_rsa_d = NULL;
-	int res=SC_SUCCESS;
+	BIGNUM *ifd_rsa_n = NULL, *ifd_rsa_e = NULL, *ifd_rsa_d = NULL;
 
-	LOG_FUNC_CALLED(card->ctx);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	int res = SC_ERROR_INTERNAL;
+	RSA *ifd_rsa = NULL;
 
-	/* compose ifd_private key with data provided in Annex 3 of DNIe Manual */
-	*ifd_privkey = EVP_PKEY_new();
+	LOG_FUNC_CALLED(card->ctx);
 	ifd_rsa = RSA_new();
-	if (!*ifd_privkey || !ifd_rsa) {
+	*ifd_privkey = EVP_PKEY_new();
+
+	if (!ifd_rsa || !*ifd_privkey) {
+		if (ifd_rsa)
+			RSA_free(ifd_rsa);
+		if (*ifd_privkey)
+			EVP_PKEY_free(*ifd_privkey);
+#else
+	OSSL_PARAM_BLD *bld = NULL;
+	OSSL_PARAM *params = NULL;
+	EVP_PKEY_CTX *ctx = NULL;
+
+	LOG_FUNC_CALLED(card->ctx);
+	ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
+
+	if (!ctx) { 
+#endif
 		sc_log(card->ctx, "Cannot create data for IFD private key");
 		return SC_ERROR_OUT_OF_MEMORY;
 	}
+
+	/* compose ifd_private key with data provided in Annex 3 of DNIe Manual */
 	ifd_rsa_n = BN_bin2bn(modulus, modulus_len, NULL);
 	ifd_rsa_e = BN_bin2bn(public_exponent, public_exponent_len, NULL);
 	ifd_rsa_d = BN_bin2bn(private_exponent, private_exponent_len, NULL);
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 	if (RSA_set0_key(ifd_rsa, ifd_rsa_n, ifd_rsa_e, ifd_rsa_d) != 1) {
 		BN_free(ifd_rsa_n);
 		BN_free(ifd_rsa_e);
@@ -851,11 +921,43 @@
 
 	res = EVP_PKEY_assign_RSA(*ifd_privkey, ifd_rsa);
 	if (!res) {
+		RSA_free(ifd_rsa);
+#else
+	if (!(bld = OSSL_PARAM_BLD_new()) ||
+		OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_N, ifd_rsa_n) != 1 ||
+		OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_E, ifd_rsa_e) != 1 ||
+		OSSL_PARAM_BLD_push_BN(bld, OSSL_PKEY_PARAM_RSA_D, ifd_rsa_d) != 1 ||
+		!(params = OSSL_PARAM_BLD_to_param(bld))) {
+		OSSL_PARAM_BLD_free(bld);
+		OSSL_PARAM_free(params);
+		EVP_PKEY_CTX_free(ctx);
+		BN_free(ifd_rsa_n);
+		BN_free(ifd_rsa_e);
+		BN_free(ifd_rsa_d);
+		sc_log(card->ctx, "Cannot set RSA values for CA public key");
+		return SC_ERROR_INTERNAL;
+	}
+	OSSL_PARAM_BLD_free(bld);
+
+	if (EVP_PKEY_fromdata_init(ctx) != 1 ||
+		EVP_PKEY_fromdata(ctx, ifd_privkey, EVP_PKEY_KEYPAIR, params) != 1) {
+		EVP_PKEY_CTX_free(ctx);
+#endif
+		BN_free(ifd_rsa_n);
+		BN_free(ifd_rsa_e);
+		BN_free(ifd_rsa_d);
 		if (*ifd_privkey)
 			EVP_PKEY_free(*ifd_privkey);	/* implies ifd_rsa free() */
 		sc_log(card->ctx, "Cannot compose IFD private key");
 		return SC_ERROR_INTERNAL;
 	}
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	OSSL_PARAM_free(params);
+	EVP_PKEY_CTX_free(ctx);
+	BN_free(ifd_rsa_n);
+	BN_free(ifd_rsa_e);
+	BN_free(ifd_rsa_d);
+#endif
 	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
 }
 
diff -Nru opensc-0.22.0/src/libopensc/errors.c opensc-0.23.0/src/libopensc/errors.c
--- opensc-0.22.0/src/libopensc/errors.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/errors.c	2022-11-29 09:34:43.000000000 +0100
@@ -30,6 +30,7 @@
 
 const char *sc_strerror(int error)
 {
+	unsigned int error_index = 0;
 	const char *rdr_errors[] = {
 		"Generic reader error",
 		"No readers found",
@@ -49,7 +50,7 @@
 		"Reader reattached",
 		"Reader in use by another application"
 	};
-	const int rdr_base = -SC_ERROR_READER;
+	const unsigned int rdr_base = -SC_ERROR_READER;
 
 	const char *card_errors[] = {
 		"Card command failed",
@@ -74,7 +75,7 @@
 		"End of file/record reached before reading Le bytes",
 		"Reference data not usable"
 	};
-	const int card_base = -SC_ERROR_CARD_CMD_FAILED;
+	const unsigned int card_base = -SC_ERROR_CARD_CMD_FAILED;
 
 	const char *arg_errors[] = {
 		"Invalid arguments",
@@ -84,7 +85,7 @@
 		"Invalid PIN length",
 		"Invalid data",
 	};
-	const int arg_base = -SC_ERROR_INVALID_ARGUMENTS;
+	const unsigned int arg_base = -SC_ERROR_INVALID_ARGUMENTS;
 
 	const char *int_errors[] = {
 		"Internal error",
@@ -107,7 +108,7 @@
 		"Invalid Simple TLV object",
 		"Premature end of Simple TLV stream",
 	};
-	const int int_base = -SC_ERROR_INTERNAL;
+	const unsigned int int_base = -SC_ERROR_INTERNAL;
 
 	const char *p15i_errors[] = {
 		"Generic PKCS#15 initialization error",
@@ -122,7 +123,7 @@
 		"Invalid PIN reference",
 		"File too small",
 	};
-	const int p15i_base = -SC_ERROR_PKCS15INIT;
+	const unsigned int p15i_base = -SC_ERROR_PKCS15INIT;
 
 	const char *sm_errors[] = {
 		"Generic Secure Messaging error",
@@ -139,54 +140,53 @@
 		"SM session already active",
 		"Invalid checksum"
 	};
-	const int sm_base = -SC_ERROR_SM;
+	const unsigned int sm_base = -SC_ERROR_SM;
 
 	const char *misc_errors[] = {
 		"Unknown error",
 		"PKCS#15 compatible smart card not found",
 	};
-	const int misc_base = -SC_ERROR_UNKNOWN;
+	const unsigned int misc_base = -SC_ERROR_UNKNOWN;
 
 	const char *no_errors = "Success";
 	const char **errors = NULL;
-	int count = 0, err_base = 0;
+	unsigned int count = 0, err_base = 0;
 
 	if (!error)
 		return no_errors;
-	if (error < 0)
-		error = -error;
+	error_index = error < 0 ? -((long long int) error) : error;
 
-	if (error >= misc_base) {
+	if (error_index >= misc_base) {
 		errors = misc_errors;
 		count = DIM(misc_errors);
 		err_base = misc_base;
-	} else if (error >= sm_base) {
+	} else if (error_index >= sm_base) {
 		errors = sm_errors;
 		count = DIM(sm_errors);
 		err_base = sm_base;
-	} else if (error >= p15i_base) {
+	} else if (error_index >= p15i_base) {
 		errors = p15i_errors;
 		count = DIM(p15i_errors);
 		err_base = p15i_base;
-	} else if (error >= int_base) {
+	} else if (error_index >= int_base) {
 		errors = int_errors;
 		count = DIM(int_errors);
 		err_base = int_base;
-	} else if (error >= arg_base) {
+	} else if (error_index >= arg_base) {
 		errors = arg_errors;
 		count = DIM(arg_errors);
 		err_base = arg_base;
-	} else if (error >= card_base) {
+	} else if (error_index >= card_base) {
 		errors = card_errors;
 		count = DIM(card_errors);
 		err_base = card_base;
-	} else if (error >= rdr_base) {
+	} else if (error_index >= rdr_base) {
 		errors = rdr_errors;
 		count = DIM(rdr_errors);
 		err_base = rdr_base;
 	}
-	error -= err_base;
-	if (error >= count || count == 0)
+	error_index -= err_base;
+	if (error_index >= count)
 		return misc_errors[0];
-	return errors[error];
+	return errors[error_index];
 }
diff -Nru opensc-0.22.0/src/libopensc/internal.h opensc-0.23.0/src/libopensc/internal.h
--- opensc-0.22.0/src/libopensc/internal.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/internal.h	2022-11-29 09:34:43.000000000 +0100
@@ -170,6 +170,10 @@
 		u8 *out_dat, size_t *out_len);
 int sc_pkcs1_strip_digest_info_prefix(unsigned int *algorithm,
 		const u8 *in_dat, size_t in_len, u8 *out_dat, size_t *out_len);
+#ifdef ENABLE_OPENSSL
+int sc_pkcs1_strip_oaep_padding(sc_context_t *ctx, u8 *data, size_t len,
+		unsigned long flags, uint8_t *param, size_t paramlen);
+#endif
 
 /**
  * PKCS1 encodes the given data.
@@ -183,7 +187,7 @@
  * @return SC_SUCCESS on success and an error code otherwise
  */
 int sc_pkcs1_encode(sc_context_t *ctx, unsigned long flags,
-		const u8 *in, size_t inlen, u8 *out, size_t *outlen, size_t mod_bits);
+		const u8 *in, size_t inlen, u8 *out, size_t *outlen, size_t mod_bits, void *pMechanism);
 /**
  * Get the necessary padding and sec. env. flags.
  * @param  ctx     IN  sc_contex_t object
diff -Nru opensc-0.22.0/src/libopensc/iso7816.c opensc-0.23.0/src/libopensc/iso7816.c
--- opensc-0.22.0/src/libopensc/iso7816.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/iso7816.c	2022-11-29 09:34:43.000000000 +0100
@@ -933,8 +933,10 @@
 			goto err;
 		}
 	}
-	if (se_num <= 0)
-		return 0;
+	if (se_num <= 0) {
+		r = SC_SUCCESS;
+		goto err;
+	}
 	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x22, 0xF2, se_num);
 	r = sc_transmit_apdu(card, &apdu);
 	sc_unlock(card);
@@ -1165,8 +1167,8 @@
 
 	/* Many cards do support PIN status queries, but some cards don't and
 	 * mistakenly count the command as a failed PIN attempt, so for now we
-	 * whitelist cards with this flag.  In future this may be reduced to a
-	 * blacklist, subject to testing more cards. */
+	 * allow cards with this flag.  In future this may be reduced to a
+	 * blocklist, subject to testing more cards. */
 	if (data->cmd == SC_PIN_CMD_GET_INFO &&
 	    !(card->caps & SC_CARD_CAP_ISO7816_PIN_INFO)) {
 		sc_log(card->ctx, "Card does not support PIN status queries");
@@ -1324,7 +1326,9 @@
 	NULL,			/* read_public_key */
 	NULL,			/* card_reader_lock_obtained */
 	NULL,			/* wrap */
-	NULL			/* unwrap */
+	NULL,			/* unwrap */
+	NULL,			/* encrypt_sym */
+	NULL			/* decrypt_sym */
 };
 
 static struct sc_card_driver iso_driver = {
@@ -1378,7 +1382,7 @@
 	r = sc_check_sw(card, apdu.sw1, apdu.sw2);
 	if (r < 0 && r != SC_ERROR_FILE_END_REACHED)
 		goto err;
-	/* emulate the behaviour of sc_read_binary */
+	/* emulate the behaviour of iso7816_read_binary */
 	r = apdu.resplen;
 
 	while(1) {
@@ -1386,11 +1390,13 @@
 			*ef_len += r;
 			break;
 		}
-		if (r == 0 || r == SC_ERROR_FILE_END_REACHED)
-			break;
-		if (r < 0) {
-			sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not read EF.");
-			goto err;
+		if (r <= 0) {
+			if (*ef_len > 0)
+				break;
+			else {
+				sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not read EF.");
+				goto err;
+			}
 		}
 		*ef_len += r;
 
@@ -1401,7 +1407,7 @@
 		}
 		*ef = p;
 
-		r = sc_read_binary(card, *ef_len,
+		r = iso7816_read_binary(card, *ef_len,
 				*ef + *ef_len, read, 0);
 	}
 
diff -Nru opensc-0.22.0/src/libopensc/libopensc.exports opensc-0.23.0/src/libopensc/libopensc.exports
--- opensc-0.22.0/src/libopensc/libopensc.exports	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/libopensc.exports	2022-11-29 09:34:43.000000000 +0100
@@ -83,6 +83,7 @@
 sc_ctx_win32_get_config_value
 _sc_delete_reader
 sc_decipher
+sc_decrypt_sym
 sc_delete_file
 sc_delete_record
 sc_der_copy
@@ -94,6 +95,7 @@
 _sc_debug
 _sc_debug_hex
 sc_enum_apps
+sc_encrypt_sym
 sc_encode_oid
 sc_parse_ef_atr
 sc_establish_context
@@ -158,7 +160,6 @@
 sc_pkcs15_decode_dodf_entry
 sc_pkcs15_decode_prkdf_entry
 sc_pkcs15_decode_pubkey
-sc_pkcs15_decode_pubkey_dsa
 sc_pkcs15_decode_pubkey_rsa
 sc_pkcs15_decode_pubkey_ec
 sc_pkcs15_decode_pubkey_gostr3410
@@ -172,16 +173,18 @@
 sc_pkcs15_encode_odf
 sc_pkcs15_encode_prkdf_entry
 sc_pkcs15_encode_pubkey
-sc_pkcs15_encode_pubkey_dsa
 sc_pkcs15_encode_pubkey_rsa
 sc_pkcs15_encode_pubkey_ec
 sc_pkcs15_encode_pubkey_eddsa
 sc_pkcs15_encode_pubkey_gostr3410
 sc_pkcs15_encode_pubkey_as_spki
 sc_pkcs15_encode_pukdf_entry
+sc_pkcs15_encode_skdf_entry
 sc_pkcs15_encode_tokeninfo
 sc_pkcs15_encode_unusedspace
+sc_pkcs15_encrypt_sym
 sc_pkcs15_erase_pubkey
+sc_pkcs15_decrypt_sym
 sc_pkcs15_dup_pubkey
 sc_pkcs15_find_cert_by_id
 sc_pkcs15_find_data_object_by_app_oid
@@ -269,11 +272,13 @@
 sc_strerror
 sc_transmit_apdu
 sc_unlock
+sc_unwrap
 sc_update_binary
 sc_update_dir
 sc_update_record
 sc_verify
 sc_wait_for_event
+sc_wrap
 sc_write_binary
 sc_write_record
 sc_erase_binary
@@ -300,9 +305,7 @@
 sc_pkcs15init_get_gpk_ops
 sc_pkcs15init_get_gids_ops
 sc_pkcs15init_get_incrypto34_ops
-sc_pkcs15init_get_jcop_ops
 sc_pkcs15init_get_manufacturer
-sc_pkcs15init_get_miocos_ops
 sc_pkcs15init_get_muscle_ops
 sc_pkcs15init_get_oberthur_ops
 sc_pkcs15init_get_pin_info
diff -Nru opensc-0.22.0/src/libopensc/log.h opensc-0.23.0/src/libopensc/log.h
--- opensc-0.22.0/src/libopensc/log.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/log.h	2022-11-29 09:34:43.000000000 +0100
@@ -59,9 +59,15 @@
 #define __FUNCTION__ NULL
 #endif
 
+#ifdef __FILE_NAME__
+#define FILENAME __FILE_NAME__
+#else
+#define FILENAME __FILE__
+#endif
+
 #if defined(__GNUC__)
-#define sc_debug(ctx, level, format, args...)	sc_do_log(ctx, level, __FILE__, __LINE__, __FUNCTION__, format , ## args)
-#define sc_log(ctx, format, args...)   sc_do_log(ctx, SC_LOG_DEBUG_NORMAL, __FILE__, __LINE__, __FUNCTION__, format , ## args)
+#define sc_debug(ctx, level, format, args...)	sc_do_log(ctx, level, FILENAME, __LINE__, __FUNCTION__, format , ## args)
+#define sc_log(ctx, format, args...)   sc_do_log(ctx, SC_LOG_DEBUG_NORMAL, FILENAME, __LINE__, __FUNCTION__, format , ## args)
 #else
 #define sc_debug _sc_debug
 #define sc_log _sc_log
@@ -109,7 +115,7 @@
  * @param[in] len   Length of \a data
  */
 #define sc_debug_hex(ctx, level, label, data, len) \
-    _sc_debug_hex(ctx, level, __FILE__, __LINE__, __FUNCTION__, label, data, len)
+    _sc_debug_hex(ctx, level, FILENAME, __LINE__, __FUNCTION__, label, data, len)
 #define sc_log_hex(ctx, label, data, len) \
     sc_debug_hex(ctx, SC_LOG_DEBUG_NORMAL, label, data, len)
 /** 
@@ -131,17 +137,17 @@
 const char * sc_dump_hex(const u8 * in, size_t count);
 const char * sc_dump_oid(const struct sc_object_id *oid);
 #define SC_FUNC_CALLED(ctx, level) do { \
-	 sc_do_log(ctx, level, __FILE__, __LINE__, __FUNCTION__, "called\n"); \
+	 sc_do_log(ctx, level, FILENAME, __LINE__, __FUNCTION__, "called\n"); \
 } while (0)
 #define LOG_FUNC_CALLED(ctx) SC_FUNC_CALLED((ctx), SC_LOG_DEBUG_NORMAL)
 
 #define SC_FUNC_RETURN(ctx, level, r) do { \
 	int _ret = r; \
 	if (_ret <= 0) { \
-		sc_do_log_color(ctx, level, __FILE__, __LINE__, __FUNCTION__, _ret ? SC_COLOR_FG_RED : 0, \
+		sc_do_log_color(ctx, level, FILENAME, __LINE__, __FUNCTION__, _ret ? SC_COLOR_FG_RED : 0, \
 			"returning with: %d (%s)\n", _ret, sc_strerror(_ret)); \
 	} else { \
-		sc_do_log(ctx, level, __FILE__, __LINE__, __FUNCTION__, \
+		sc_do_log(ctx, level, FILENAME, __LINE__, __FUNCTION__, \
 			"returning with: %d\n", _ret); \
 	} \
 	return _ret; \
@@ -151,7 +157,7 @@
 #define SC_TEST_RET(ctx, level, r, text) do { \
 	int _ret = (r); \
 	if (_ret < 0) { \
-		sc_do_log_color(ctx, level, __FILE__, __LINE__, __FUNCTION__, SC_COLOR_FG_RED, \
+		sc_do_log_color(ctx, level, FILENAME, __LINE__, __FUNCTION__, SC_COLOR_FG_RED, \
 			"%s: %d (%s)\n", (text), _ret, sc_strerror(_ret)); \
 		return _ret; \
 	} \
@@ -161,7 +167,7 @@
 #define SC_TEST_GOTO_ERR(ctx, level, r, text) do { \
 	int _ret = (r); \
 	if (_ret < 0) { \
-		sc_do_log_color(ctx, level, __FILE__, __LINE__, __FUNCTION__, SC_COLOR_FG_RED, \
+		sc_do_log_color(ctx, level, FILENAME, __LINE__, __FUNCTION__, SC_COLOR_FG_RED, \
 			"%s: %d (%s)\n", (text), _ret, sc_strerror(_ret)); \
 		goto err; \
 	} \
diff -Nru opensc-0.22.0/src/libopensc/Makefile.am opensc-0.23.0/src/libopensc/Makefile.am
--- opensc-0.22.0/src/libopensc/Makefile.am	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/Makefile.am	2022-11-29 09:34:43.000000000 +0100
@@ -6,7 +6,7 @@
 
 lib_LTLIBRARIES = libopensc.la
 noinst_HEADERS = cards.h ctbcs.h internal.h muscle.h muscle-filesystem.h \
-	internal-winscard.h p15card-helper.h pkcs15-syn.h \
+	internal-winscard.h pkcs15-syn.h pkcs15-emulator-filter.h \
 	opensc.h pkcs15.h gp.h \
 	cardctl.h asn1.h log.h simpletlv.h \
 	errors.h types.h compression.h itacns.h iso7816.h \
@@ -31,15 +31,15 @@
 	\
 	pkcs15.c pkcs15-cert.c pkcs15-data.c pkcs15-pin.c \
 	pkcs15-prkey.c pkcs15-pubkey.c pkcs15-skey.c \
-	pkcs15-sec.c pkcs15-algo.c pkcs15-cache.c pkcs15-syn.c \
+	pkcs15-sec.c pkcs15-algo.c pkcs15-cache.c pkcs15-syn.c pkcs15-emulator-filter.c \
 	\
 	muscle.c muscle-filesystem.c \
 	\
 	ctbcs.c reader-ctapi.c reader-pcsc.c reader-openct.c reader-tr03119.c \
 	\
-	card-setcos.c card-miocos.c card-flex.c card-gpk.c \
+	card-setcos.c card-flex.c card-gpk.c \
 	card-cardos.c card-tcos.c card-default.c \
-	card-mcrd.c card-starcos.c card-openpgp.c card-jcop.c \
+	card-mcrd.c card-starcos.c card-openpgp.c \
 	card-oberthur.c card-belpic.c card-atrust-acos.c \
 	card-entersafe.c card-epass2003.c card-coolkey.c card-incrypto34.c \
 	card-piv.c card-cac-common.c card-cac.c card-cac1.c \
@@ -50,16 +50,16 @@
 	card-dnie.c cwa14890.c cwa-dnie.c \
 	card-isoApplet.c card-masktech.c card-gids.c card-jpki.c \
 	card-npa.c card-esteid2018.c card-idprime.c \
-	card-edo.c \
+	card-edo.c card-nqApplet.c \
 	\
 	pkcs15-openpgp.c pkcs15-starcert.c pkcs15-cardos.c \
 	pkcs15-tcos.c pkcs15-esteid.c pkcs15-gemsafeGPK.c \
 	pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c pkcs15-piv.c \
 	pkcs15-cac.c pkcs15-esinit.c pkcs15-westcos.c pkcs15-pteid.c \
 	pkcs15-oberthur.c pkcs15-itacns.c pkcs15-gemsafeV1.c pkcs15-sc-hsm.c \
-	pkcs15-coolkey.c pkcs15-din-66291.c pkcs15-idprime.c \
+	pkcs15-coolkey.c pkcs15-din-66291.c pkcs15-idprime.c pkcs15-nqApplet.c \
 	pkcs15-dnie.c pkcs15-gids.c pkcs15-iasecc.c pkcs15-jpki.c pkcs15-esteid2018.c \
-	compression.c p15card-helper.c sm.c \
+	pkcs15-starcos-esign.c compression.c sm.c \
 	aux-data.c
 
 if ENABLE_CRYPTOTOKENKIT
@@ -87,7 +87,7 @@
 	$(top_builddir)/src/sm/libsmeac.la \
 	$(top_builddir)/src/common/libcompat.la
 if WIN32
-libopensc_la_LIBADD += -lws2_32
+libopensc_la_LIBADD += -lws2_32 -lshlwapi
 endif
 libopensc_static_la_LIBADD = $(libopensc_la_LIBADD)
 libopensc_la_LDFLAGS = $(AM_LDFLAGS) \
@@ -114,15 +114,15 @@
 	\
 	pkcs15-cert.c pkcs15-data.c pkcs15-pin.c \
 	pkcs15-prkey.c pkcs15-pubkey.c pkcs15-skey.c \
-	pkcs15-sec.c pkcs15-algo.c pkcs15-cache.c pkcs15-syn.c \
+	pkcs15-sec.c pkcs15-algo.c pkcs15-cache.c pkcs15-syn.c pkcs15-emulator-filter.c \
 	\
 	muscle.c muscle-filesystem.c \
 	\
 	ctbcs.c reader-ctapi.c reader-pcsc.c reader-openct.c reader-tr03119.c \
 	\
-	card-setcos.c card-miocos.c card-flex.c card-gpk.c \
+	card-setcos.c card-flex.c card-gpk.c \
 	card-cardos.c card-tcos.c card-default.c \
-	card-mcrd.c card-starcos.c card-jcop.c \
+	card-mcrd.c card-starcos.c \
 	card-oberthur.c card-belpic.c card-atrust-acos.c \
 	card-entersafe.c card-epass2003.c card-coolkey.c card-incrypto34.c \
 	card-cac-common.c card-cac.c card-cac1.c \
@@ -133,16 +133,16 @@
 	cwa14890.c cwa-dnie.c \
 	card-isoApplet.c card-masktech.c card-jpki.c \
 	card-npa.c card-esteid2018.c card-idprime.c \
-	card-edo.c \
+	card-edo.c card-nqApplet.c \
 	\
 	pkcs15-openpgp.c pkcs15-cardos.c \
 	pkcs15-tcos.c pkcs15-esteid.c \
 	pkcs15-actalis.c pkcs15-atrust-acos.c pkcs15-tccardos.c \
 	pkcs15-cac.c pkcs15-esinit.c pkcs15-westcos.c pkcs15-pteid.c \
 	pkcs15-oberthur.c pkcs15-itacns.c pkcs15-sc-hsm.c \
-	pkcs15-coolkey.c pkcs15-din-66291.c pkcs15-idprime.c \
+	pkcs15-coolkey.c pkcs15-din-66291.c pkcs15-idprime.c pkcs15-nqApplet.c \
 	pkcs15-dnie.c pkcs15-gids.c pkcs15-iasecc.c pkcs15-jpki.c pkcs15-esteid2018.c \
-	compression.c p15card-helper.c sm.c \
+	pkcs15-starcos-esign.c compression.c sm.c \
 	aux-data.c \
 	#$(SOURCES)
 
diff -Nru opensc-0.22.0/src/libopensc/Makefile.mak opensc-0.23.0/src/libopensc/Makefile.mak
--- opensc-0.22.0/src/libopensc/Makefile.mak	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/Makefile.mak	2022-11-29 09:34:43.000000000 +0100
@@ -8,15 +8,15 @@
 	\
 	pkcs15.obj pkcs15-cert.obj pkcs15-data.obj pkcs15-pin.obj \
 	pkcs15-prkey.obj pkcs15-pubkey.obj pkcs15-skey.obj \
-	pkcs15-sec.obj pkcs15-algo.obj pkcs15-cache.obj pkcs15-syn.obj \
+	pkcs15-sec.obj pkcs15-algo.obj pkcs15-cache.obj pkcs15-syn.obj pkcs15-emulator-filter.obj \
 	\
 	muscle.obj muscle-filesystem.obj \
 	\
 	ctbcs.obj reader-ctapi.obj reader-pcsc.obj reader-openct.obj reader-tr03119.obj \
 	\
-	card-setcos.obj card-miocos.obj card-flex.obj card-gpk.obj \
+	card-setcos.obj card-flex.obj card-gpk.obj \
 	card-cardos.obj card-tcos.obj card-default.obj \
-	card-mcrd.obj card-starcos.obj card-openpgp.obj card-jcop.obj \
+	card-mcrd.obj card-starcos.obj card-openpgp.obj \
 	card-oberthur.obj card-belpic.obj card-atrust-acos.obj \
 	card-entersafe.obj card-epass2003.obj card-coolkey.obj \
 	card-incrypto34.obj card-cac.obj card-cac1.obj card-cac-common.obj \
@@ -28,7 +28,7 @@
 	card-sc-hsm.obj card-dnie.obj card-isoApplet.obj pkcs15-coolkey.obj \
 	card-masktech.obj card-gids.obj card-jpki.obj \
 	card-npa.obj card-esteid2018.obj card-idprime.obj \
-	card-edo.obj \
+	card-edo.obj card-nqApplet.obj \
 	\
 	pkcs15-openpgp.obj pkcs15-starcert.obj pkcs15-cardos.obj \
 	pkcs15-tcos.obj pkcs15-esteid.obj pkcs15-gemsafeGPK.obj \
@@ -36,8 +36,8 @@
 	pkcs15-cac.obj pkcs15-esinit.obj pkcs15-westcos.obj pkcs15-pteid.obj pkcs15-din-66291.obj \
 	pkcs15-oberthur.obj pkcs15-itacns.obj pkcs15-gemsafeV1.obj pkcs15-sc-hsm.obj \
 	pkcs15-dnie.obj pkcs15-gids.obj pkcs15-iasecc.obj pkcs15-jpki.obj \
-	pkcs15-esteid2018.obj pkcs15-idprime.obj \
-	compression.obj p15card-helper.obj sm.obj \
+	pkcs15-esteid2018.obj pkcs15-idprime.obj pkcs15-nqApplet.obj \
+	pkcs15-starcos-esign.obj compression.obj sm.obj \
 	aux-data.obj \
 	$(TOPDIR)\win32\versioninfo.res
 LIBS = $(TOPDIR)\src\scconf\scconf.lib \
@@ -57,7 +57,7 @@
 	echo LIBRARY $* > $*.def
 	echo EXPORTS >> $*.def
 	type lib$*.exports >> $*.def
-	link $(LINKFLAGS) /dll /def:$*.def /implib:$*.lib /out:opensc.dll $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) $(ZLIB_LIB) gdi32.lib Comctl32.lib Shell32.lib user32.lib advapi32.lib ws2_32.lib
+	link $(LINKFLAGS) /dll /def:$*.def /implib:$*.lib /out:opensc.dll $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) $(ZLIB_LIB) gdi32.lib Comctl32.lib Shell32.lib user32.lib advapi32.lib ws2_32.lib shlwapi.lib
 	if EXIST opensc.dll.manifest mt -manifest opensc.dll.manifest -outputresource:opensc.dll;2
 
 opensc_a.lib: $(OBJECTS)
diff -Nru opensc-0.22.0/src/libopensc/muscle.c opensc-0.23.0/src/libopensc/muscle.c
--- opensc-0.22.0/src/libopensc/muscle.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/muscle.c	2022-11-29 09:34:43.000000000 +0100
@@ -30,8 +30,6 @@
 #define MSC_RSA_PUBLIC		0x01
 #define MSC_RSA_PRIVATE 	0x02
 #define MSC_RSA_PRIVATE_CRT	0x03
-#define MSC_DSA_PUBLIC		0x04
-#define MSC_DSA_PRIVATE 	0x05
 
 static msc_id inputId = { { 0xFF, 0xFF, 0xFF, 0xFF } };
 static msc_id outputId = { { 0xFF, 0xFF, 0xFF, 0xFE } };
@@ -290,9 +288,13 @@
 
 	const int bufferLength = MSC_MAX_PIN_LENGTH;
 	u8 buffer[MSC_MAX_PIN_LENGTH];
-	assert(pinLength <= MSC_MAX_PIN_LENGTH);
 
-	msc_verify_pin_apdu(card, &apdu, buffer, bufferLength, pinNumber, pinValue, pinLength);
+	if (pinLength > MSC_MAX_PIN_LENGTH)
+		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
+
+	r = msc_verify_pin_apdu(card, &apdu, buffer, bufferLength, pinNumber, pinValue, pinLength);
+	LOG_TEST_RET(card->ctx, r, "APDU verification failed");
+
 	if(tries)
 		*tries = -1;
 	r = sc_transmit_apdu(card, &apdu);
@@ -313,11 +315,10 @@
 }
 
 /* USE ISO_VERIFY due to tries return */
-void msc_verify_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, u8* buffer, size_t bufferLength, int pinNumber, const u8 *pinValue, int pinLength)
+int msc_verify_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, u8* buffer, size_t bufferLength, int pinNumber, const u8 *pinValue, int pinLength)
 {
-	assert(buffer);
-	assert(bufferLength >= (size_t)pinLength);
-	assert(pinLength <= MSC_MAX_PIN_LENGTH);
+	if (!buffer || bufferLength < (size_t)pinLength || pinLength > MSC_MAX_PIN_LENGTH)
+		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
 
 	truncatePinNulls(pinValue, &pinLength);
 
@@ -326,6 +327,7 @@
 	apdu->lc = pinLength;
 	apdu->data = buffer;
 	apdu->datalen = pinLength;
+	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
 }
 
 int msc_unblock_pin(sc_card_t *card, int pinNumber, const u8 *pukValue, int pukLength, int *tries)
@@ -335,9 +337,12 @@
 	const int bufferLength = MSC_MAX_PIN_LENGTH;
 	u8 buffer[MSC_MAX_PIN_LENGTH];
 
-	assert(pukLength <= MSC_MAX_PIN_LENGTH);
+	if (pukLength > MSC_MAX_PIN_LENGTH)
+		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
+
+	r = msc_unblock_pin_apdu(card, &apdu, buffer, bufferLength, pinNumber, pukValue, pukLength);
+	LOG_TEST_RET(card->ctx, r, "APDU unblock failed");
 
-	msc_unblock_pin_apdu(card, &apdu, buffer, bufferLength, pinNumber, pukValue, pukLength);
 	if(tries)
 		*tries = -1;
 	r = sc_transmit_apdu(card, &apdu);
@@ -357,11 +362,10 @@
 	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,  SC_ERROR_PIN_CODE_INCORRECT);
 }
 
-void msc_unblock_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, u8* buffer, size_t bufferLength, int pinNumber, const u8 *pukValue, int pukLength)
+int msc_unblock_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, u8* buffer, size_t bufferLength, int pinNumber, const u8 *pukValue, int pukLength)
 {
-	assert(buffer);
-	assert(bufferLength >= (size_t)pukLength);
-	assert(pukLength <= MSC_MAX_PIN_LENGTH);
+	if (!buffer || bufferLength < (size_t)pukLength || pukLength > MSC_MAX_PIN_LENGTH)
+		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
 
 	truncatePinNulls(pukValue, &pukLength);
 
@@ -370,6 +374,7 @@
 	apdu->lc = pukLength;
 	apdu->data = buffer;
 	apdu->datalen = pukLength;
+	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
 }
 
 int msc_change_pin(sc_card_t *card, int pinNumber, const u8 *pinValue, int pinLength, const u8 *newPin, int newPinLength, int *tries)
@@ -379,7 +384,8 @@
 	const int bufferLength = (MSC_MAX_PIN_LENGTH + 1) * 2;
 	u8 buffer[(MSC_MAX_PIN_LENGTH + 1) * 2];
 
-	msc_change_pin_apdu(card, &apdu, buffer, bufferLength, pinNumber, pinValue, pinLength, newPin, newPinLength);
+	r = msc_change_pin_apdu(card, &apdu, buffer, bufferLength, pinNumber, pinValue, pinLength, newPin, newPinLength);
+	LOG_TEST_RET(card->ctx, r, "APDU change failed");
 	if(tries)
 		*tries = -1;
 	r = sc_transmit_apdu(card, &apdu);
@@ -400,13 +406,12 @@
 }
 
 /* USE ISO_VERIFY due to tries return */
-void msc_change_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, u8* buffer, size_t bufferLength, int pinNumber, const u8 *pinValue, int pinLength, const u8 *newPin, int newPinLength)
+int msc_change_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, u8* buffer, size_t bufferLength, int pinNumber, const u8 *pinValue, int pinLength, const u8 *newPin, int newPinLength)
 {
 	u8 *ptr;
-	assert(pinLength <= MSC_MAX_PIN_LENGTH);
-	assert(newPinLength <= MSC_MAX_PIN_LENGTH);
-	assert(buffer);
-	assert(bufferLength >= pinLength + newPinLength + 2UL);
+	if (pinLength > MSC_MAX_PIN_LENGTH || newPinLength > MSC_MAX_PIN_LENGTH
+		|| !buffer || bufferLength < pinLength + newPinLength + 2UL)
+		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
 
 	truncatePinNulls(pinValue, &pinLength);
 	truncatePinNulls(newPin, &newPinLength);
@@ -424,6 +429,7 @@
 	apdu->lc = pinLength + newPinLength + 2;
 	apdu->datalen = apdu->lc;
 	apdu->data = buffer;
+	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
 }
 
 int msc_get_challenge(sc_card_t *card, unsigned short dataLength, unsigned short seedLength, u8 *seedData, u8 *outputData)
@@ -437,8 +443,8 @@
 	cse = (location == 1) ? SC_APDU_CASE_4_SHORT : SC_APDU_CASE_3_SHORT;
 	len = seedLength + 4;
 	
-	assert(seedLength < MSC_MAX_SEND - 4);
-	assert(dataLength < MSC_MAX_READ - 9); /* Output buffer doesn't seem to operate as desired.... nobody can read/delete */
+	if (seedLength >= MSC_MAX_SEND - 4 || dataLength >= MSC_MAX_READ - 9)/* Output buffer doesn't seem to operate as desired.... nobody can read/delete */
+		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
 	
 	buffer = malloc(len);
 	if(!buffer) LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
@@ -512,7 +518,8 @@
 	unsigned short prRead = 0xFFFF, prWrite = 0x0002, prCompute = 0x0002,
 		puRead = 0x0000, puWrite = 0x0002, puCompute = 0x0000;
 
-	assert(privateKey <= 0x0F && publicKey <= 0x0F);
+	if (privateKey > 0x0F || publicKey > 0x0F)
+		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
 	
 	sc_format_apdu(card, &apdu, SC_APDU_CASE_3_SHORT, 0x30, privateKey, publicKey);
 
@@ -675,7 +682,8 @@
 		short receivedData = outputBuffer[0] << 8 | outputBuffer[1];
 		*outputDataLength = receivedData;
 
-		assert(receivedData <= MSC_MAX_APDU);
+		if (receivedData > MSC_MAX_APDU)
+			LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA);
 		memcpy(outputData, outputBuffer + 2, receivedData);
 		return 0;
 	}
@@ -725,7 +733,9 @@
 	if(apdu.sw1 == 0x90 && apdu.sw2 == 0x00) {
 		short receivedData = outputBuffer[0] << 8 | outputBuffer[1];
 		*outputDataLength = receivedData;
-		assert(receivedData <= MSC_MAX_APDU);
+
+		if (receivedData > MSC_MAX_APDU)
+			LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_DATA);
 		memcpy(outputData, outputBuffer + 2, receivedData);
 		return 0;
 	}
@@ -827,7 +837,9 @@
 	int r;
 
 	size_t received = 0;
-	assert(outputDataLength >= dataLength);
+
+	if (outputDataLength < dataLength)
+		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
 	
 	/* Don't send data during init... apparently current version does not support it */
 	toSend = 0;
@@ -888,7 +900,9 @@
 	sc_apdu_t apdu;
 	int r;
 
-	assert(data->keyType == 0x02 || data->keyType == 0x03);
+	if (data->keyType != 0x02 && data->keyType != 0x03)
+		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
+
 	if(data->keyType == 0x02) {
 		if( (data->pLength == 0 || !data->pValue)
 		|| (data->modLength == 0 || !data->modValue))
diff -Nru opensc-0.22.0/src/libopensc/muscle-filesystem.h opensc-0.23.0/src/libopensc/muscle-filesystem.h
--- opensc-0.22.0/src/libopensc/muscle-filesystem.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/muscle-filesystem.h	2022-11-29 09:34:43.000000000 +0100
@@ -34,6 +34,7 @@
 	size_t size;
 	unsigned short read, write, delete;
 	int ef;
+	int deleteFile;
 } mscfs_file_t;
 
 typedef struct mscfs_cache {
diff -Nru opensc-0.22.0/src/libopensc/muscle.h opensc-0.23.0/src/libopensc/muscle.h
--- opensc-0.22.0/src/libopensc/muscle.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/muscle.h	2022-11-29 09:34:43.000000000 +0100
@@ -47,11 +47,11 @@
 int msc_select_applet(sc_card_t *card, u8 *appletId, size_t appletIdLength);
 
 int msc_verify_pin(sc_card_t *card, int pinNumber, const u8 *pinValue, int pinLength, int *tries);
-void msc_verify_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, u8* buffer, size_t bufferLength, int pinNumber, const u8 *pinValue, int pinLength);
+int msc_verify_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, u8* buffer, size_t bufferLength, int pinNumber, const u8 *pinValue, int pinLength);
 int msc_unblock_pin(sc_card_t *card, int pinNumber, const u8 *pukValue, int pukLength, int *tries);
-void msc_unblock_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, u8* buffer, size_t bufferLength, int pinNumber, const u8 *pukValue, int pukLength);
+int msc_unblock_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, u8* buffer, size_t bufferLength, int pinNumber, const u8 *pukValue, int pukLength);
 int msc_change_pin(sc_card_t *card, int pinNumber, const u8 *pinValue, int pinLength, const u8 *newPin, int newPinLength, int *tries);
-void msc_change_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, u8* buffer, size_t bufferLength, int pinNumber, const u8 *pinValue, int pinLength, const u8 *newPin, int newPinLength);
+int msc_change_pin_apdu(sc_card_t *card, sc_apdu_t *apdu, u8* buffer, size_t bufferLength, int pinNumber, const u8 *pinValue, int pinLength, const u8 *newPin, int newPinLength);
 
 int msc_get_challenge(sc_card_t *card, unsigned short dataLength, unsigned short seedLength, u8 *seedData, u8 *outputData);
 
diff -Nru opensc-0.22.0/src/libopensc/opensc.h opensc-0.23.0/src/libopensc/opensc.h
--- opensc-0.22.0/src/libopensc/opensc.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/opensc.h	2022-11-29 09:34:43.000000000 +0100
@@ -59,7 +59,8 @@
 #define SC_SEC_OPERATION_DERIVE         0x0004
 #define SC_SEC_OPERATION_WRAP		0x0005
 #define SC_SEC_OPERATION_UNWRAP		0x0006
-
+#define SC_SEC_OPERATION_ENCRYPT_SYM	0x0007
+#define SC_SEC_OPERATION_DECRYPT_SYM	0x0008
 /* sc_security_env flags */
 #define SC_SEC_ENV_ALG_REF_PRESENT	0x0001
 #define SC_SEC_ENV_FILE_REF_PRESENT	0x0002
@@ -75,8 +76,7 @@
 
 /* PK algorithms */
 #define SC_ALGORITHM_RSA		0
-#define SC_ALGORITHM_DSA		1
-#define SC_ALGORITHM_EC			2
+#define SC_ALGORITHM_EC		2
 #define SC_ALGORITHM_GOSTR3410		3
 #define SC_ALGORITHM_EDDSA		4
 #define SC_ALGORITHM_XEDDSA		5
@@ -721,6 +721,16 @@
 	int (*select_file)(struct sc_card *card, const struct sc_path *path,
 			   struct sc_file **file_out);
 	int (*get_response)(struct sc_card *card, size_t *count, u8 *buf);
+	/**
+	 * Get random data from the card
+	 *
+	 * Implementation of this call back is optional and may be NULL.
+	 *
+	 * @param  card   struct sc_card object on which to issue the command
+	 * @param  buf    buffer to be filled with random data
+	 * @param  count  number of random bytes to initialize
+	 * @return number of random bytes successfully initialized (i.e. `count` or less bytes) or an error code
+	 */
 	int (*get_challenge)(struct sc_card *card, u8 * buf, size_t count);
 
 	/*
@@ -805,6 +815,11 @@
 	int (*wrap)(struct sc_card *card, u8 *out, size_t outlen);
 
 	int (*unwrap)(struct sc_card *card, const u8 *crgram, size_t crgram_len);
+
+	int (*encrypt_sym)(struct sc_card *card, const u8 *plaintext, size_t plaintext_len,
+			u8 *out, size_t *outlen);
+	int (*decrypt_sym)(struct sc_card *card, const u8 *EncryptedData, size_t EncryptedDataLen,
+			u8 *out, size_t *outlen);
 };
 
 typedef struct sc_card_driver {
@@ -1027,11 +1042,22 @@
  * @param  ctx   pointer to a sc_context_t
  * @param  pcsc_context_handle pointer to the  new context_handle to use
  * @param  pcsc_card_handle pointer to the new card_handle to use
- * @return SC_SUCCESS on success and an error code otherwise.
+ * @return SC_SUCCESS or 1 on success and an error code otherwise.
+ *		a return of 1 indicates to call reinit_card_for, as
+ *		the reader has changed.
  */
 int sc_ctx_use_reader(sc_context_t *ctx, void * pcsc_context_handle, void * pcsc_card_handle);
 
 /**
+ * detect if the given handles are referencing `reader`
+ *
+ * 0 -> handles also point to `reader`
+ * 1 -> handles don't point to `reader`, but to a different reader
+ */
+int
+pcsc_check_reader_handles(sc_context_t *ctx, sc_reader_t *reader, void * pcsc_context_handle, void * pcsc_card_handle);
+
+/**
  * Returns a pointer to the specified sc_reader_t object
  * @param  ctx  OpenSC context
  * @param  name name of the reader to look for
@@ -1320,7 +1346,7 @@
 /**
  * Gets challenge from the card (normally random data).
  * @param  card    struct sc_card object on which to issue the command
- * @param  rndout  buffer for the returned random challenge
+ * @param  rndout  buffer for the returned random challenge. Note that the buffer may be only partially initialized on error.
  * @param  len     length of the challenge
  * @return SC_SUCCESS on success and an error code otherwise
  */
@@ -1358,6 +1384,11 @@
 			   const u8 *newref, size_t newlen);
 int sc_build_pin(u8 *buf, size_t buflen, struct sc_pin_cmd_pin *pin, int pad);
 
+int sc_encrypt_sym(struct sc_card *card, const u8 *Data, size_t DataLen,
+		u8 *out, size_t *outlen);
+
+int sc_decrypt_sym(struct sc_card *card, const u8 *EncryptedData, size_t EncryptedDataLen,
+		u8 *out, size_t *outlen);
 
 /********************************************************************/
 /*               ISO 7816-9 related functions                       */
@@ -1539,6 +1570,10 @@
 void sc_mem_clear(void *ptr, size_t len);
 void *sc_mem_secure_alloc(size_t len);
 void sc_mem_secure_free(void *ptr, size_t len);
+#define sc_mem_secure_clear_free(ptr, len) do { \
+	sc_mem_clear(ptr, len); \
+	sc_mem_secure_free(ptr, len); \
+} while (0);
 int sc_mem_reverse(unsigned char *buf, size_t len);
 
 int sc_get_cache_dir(sc_context_t *ctx, char *buf, size_t bufsize);
diff -Nru opensc-0.22.0/src/libopensc/p15card-helper.c opensc-0.23.0/src/libopensc/p15card-helper.c
--- opensc-0.22.0/src/libopensc/p15card-helper.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/p15card-helper.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,358 +0,0 @@
-/*
- * p15card-helper.c: Utility library to assist in PKCS#15 emulation on Non-filesystem cards
- *
- * Copyright (C) 2006, Identity Alliance, Thomas Harning <thomas.harning at identityalliance.com>
- *
- * 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 HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#ifdef ENABLE_OPENSSL	/* empty file without openssl */
-#include <string.h>
-#include <stdlib.h>
-#include <openssl/bn.h>
-#include <openssl/bio.h>
-#include <openssl/rsa.h>
-#include <openssl/x509.h>
-
-#include "internal.h"
-#include "p15card-helper.h"
-#include "opensc.h"
-#include "types.h"
-#include "log.h"
-#include "pkcs15.h"
-
-int sc_pkcs15emu_initialize_objects(sc_pkcs15_card_t *p15card, p15data_items *items) {
-	sc_card_t* card = p15card->card;
-	const objdata* objects = items->objects;
-	int i, r;
-	if(!objects) return SC_SUCCESS;
-	for (i = 0; objects[i].label; i++) {
-		struct sc_pkcs15_data_info obj_info;
-		struct sc_pkcs15_object    obj_obj;
-
-		memset(&obj_info, 0, sizeof(obj_info));
-		memset(&obj_obj, 0, sizeof(obj_obj));
-		sc_pkcs15_format_id(objects[i].id, &obj_info.id);
-		sc_format_path(objects[i].path, &obj_info.path);
-		strncpy(obj_info.app_label, objects[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
-		r = sc_format_oid(&obj_info.app_oid, objects[i].aoid);
-		if (r != SC_SUCCESS)
-			return r;
-
-		strncpy(obj_obj.label, objects[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
-		obj_obj.flags = objects[i].obj_flags;
-		
-		r = sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_DATA_OBJECT, 
-			&obj_obj, &obj_info); 
-		if (r < 0)
-			LOG_FUNC_RETURN(card->ctx, r);
-	}
-	return SC_SUCCESS;
-}
-
-static const prdata* get_prkey_by_cert(p15data_items* items, const cdata* cert) {
-	const prdata* keys;
-	if(!items->private_keys)
-		return NULL;
-	for(keys = items->private_keys; keys->id; keys++) {
-		if(0 == strcmp(cert->id, keys->id))
-			return keys;
-	}
-	return NULL;
-}
-
-static int add_private_key(sc_pkcs15_card_t *p15card, const prdata* key, int usage, int modulus_length) {
-	struct sc_pkcs15_prkey_info prkey_info;
-	struct sc_pkcs15_object     prkey_obj;
-
-	memset(&prkey_info, 0, sizeof(prkey_info));
-	memset(&prkey_obj,  0, sizeof(prkey_obj));
-	
-	sc_pkcs15_format_id(key->id, &prkey_info.id);
-	
-	prkey_info.native        = 1;
-	prkey_info.key_reference = key->ref;
-
-	if(!modulus_length) modulus_length = key->modulus_len;
-	prkey_info.modulus_length= modulus_length;
-	
-	sc_format_path(key->path, &prkey_info.path);
-	
-	strncpy(prkey_obj.label, key->label, SC_PKCS15_MAX_LABEL_SIZE - 1);
-	
-	prkey_obj.flags = key->obj_flags;
-	
-	/* Setup key usage */
-	if(!usage) usage = key->usage;
-	prkey_info.usage = usage;
-	
-	if (key->auth_id)
-		sc_pkcs15_format_id(key->auth_id, &prkey_obj.auth_id);
-	
-	return sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
-}
-
-static int add_public_key(sc_pkcs15_card_t *p15card, const pubdata *key, int usage, int modulus_length) {
-	struct sc_pkcs15_pubkey_info pubkey_info;
-	struct sc_pkcs15_object     pubkey_obj;
-
-	memset(&pubkey_info, 0, sizeof(pubkey_info));
-	memset(&pubkey_obj,  0, sizeof(pubkey_obj));
-
-	sc_pkcs15_format_id(key->id, &pubkey_info.id);
-	if(!usage) usage = key->usage;
-	pubkey_info.usage         = usage;
-	pubkey_info.native        = 1;
-	pubkey_info.key_reference = key->ref;
-	if(!modulus_length) modulus_length = key->modulus_len;
-	pubkey_info.modulus_length= modulus_length;
-	/* we really don't know how many bits or module length,
-	 * we will assume 1024 for now 
-	 */
-	sc_format_path(key->path, &pubkey_info.path);
-
-	strncpy(pubkey_obj.label, key->label, SC_PKCS15_MAX_LABEL_SIZE - 1);
-
-	pubkey_obj.flags = key->obj_flags;
-
-	if (key->auth_id)
-		sc_pkcs15_format_id(key->auth_id, &pubkey_obj.auth_id);
-
-	return sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
-}
-
-/* int default_cert_handle(sc_pkcs15_card_t *p15card, p15data_items* items, cdata* cert, u8* data, size_t length) { */
-CERT_HANDLE_FUNCTION(default_cert_handle) {
-	/* Certificate data exists, parse it */
-	int r;
-	X509 *cert_data = NULL;
-	EVP_PKEY *pkey = NULL;
-	const RSA * rsa = NULL;
-	int certtype = 0;
-	int modulus_len = 0;
-	const prdata* key = get_prkey_by_cert(items, cert);
-	if(!key) {
-		sc_log(p15card->card->ctx,  "Error: No key for this certificate");
-		return SC_ERROR_INTERNAL;
-	}
-
-	if(!d2i_X509(&cert_data, (const u8**)&data, length)) {
-		sc_log(p15card->card->ctx,  "Error converting certificate");
-		return SC_ERROR_INTERNAL;
-	}
-
-	pkey = X509_get_pubkey(cert_data);
-	
-	if(pkey == NULL) {
-		sc_log(p15card->card->ctx,  "Error: no public key associated with the certificate");
-		r = SC_ERROR_INTERNAL;
-		goto err;
-	}
-
-	certtype = X509_certificate_type(cert_data, pkey);
-	if(! (EVP_PK_RSA & certtype)) {
-		sc_log(p15card->card->ctx,  "Error: certificate is not for an RSA key");
-		r = SC_ERROR_INTERNAL;
-		goto err;
-	}
-	rsa = EVP_PKEY_get0_RSA(pkey);
-	if( rsa == NULL) {
-		sc_log(p15card->card->ctx,  "Error: no modulus associated with the certificate");
-		r = SC_ERROR_INTERNAL;
-		goto err;
-	}
-	
-	modulus_len =  RSA_bits(rsa);
-
-	/* printf("Key Size: %d bits\n\n", modulus_len); */
-	/* cached_cert->modulusLength = modulus_len; */
-	
-	if(key->label) {
-		int usage = 0;
-		if (certtype & EVP_PKT_SIGN) {
-			usage |= SC_PKCS15_PRKEY_USAGE_SIGN;
-			usage |= SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
-		}
-		
-		if (certtype & EVP_PKT_ENC) {
-			usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT;
-			usage |= SC_PKCS15_PRKEY_USAGE_DECRYPT;
-		}
-		if (certtype & EVP_PKT_EXCH) {
-			usage |= SC_PKCS15_PRKEY_USAGE_WRAP;
-			usage |= SC_PKCS15_PRKEY_USAGE_UNWRAP;
-		}
-		r = add_private_key(p15card, key, usage, modulus_len);
-		if (r < 0)
-			goto err;
-	}
-	r = SC_SUCCESS;
-err:
-	if(pkey) {
-		EVP_PKEY_free(pkey);
-		pkey = NULL;
-	}
-	if(cert_data) {
-		X509_free(cert_data);
-		cert_data = NULL;
-	}
-	LOG_FUNC_RETURN(p15card->card->ctx, r);
-}
-
-int sc_pkcs15emu_initialize_certificates(sc_pkcs15_card_t *p15card, p15data_items* items) {
-	/* set certs */
-	sc_card_t* card = p15card->card;
-	const cdata* certs = items->certs;
-	int onFailResume = items->cert_continue;
-	int i, r;
-	if(!certs) return SC_SUCCESS;
-	for (i = 0; certs[i].label; i++) {
-		struct sc_pkcs15_cert_info cert_info;
-		struct sc_pkcs15_object    cert_obj;
-		
-		memset(&cert_info, 0, sizeof(cert_info));
-		memset(&cert_obj,  0, sizeof(cert_obj));
-		
-		sc_pkcs15_format_id(certs[i].id, &cert_info.id);
-		cert_info.authority = certs[i].authority;
-		sc_format_path(certs[i].path, &cert_info.path);
-
-		strncpy(cert_obj.label, certs[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
-		cert_obj.flags = certs[i].obj_flags;
-		
-		if(items->cert_load) {
-			u8* cert_buffer = NULL;
-			size_t cert_length = 0;
-			int should_free = 0;
-			if(SC_SUCCESS != sc_select_file(card, &cert_info.path, NULL)) {
-				if(onFailResume)
-					continue;
-				else
-					break;
-			}
-			if(SC_SUCCESS != (r = items->cert_load(card, &cert_buffer, &cert_length, &should_free))) {
-				if(onFailResume)
-					continue;
-				else
-					break;
-			}
-			/* Handle cert */
-			/* If no cert handler, add.. if cert handler succeeds.. add */
-			if(!items->cert_handle || SC_SUCCESS == (r = items->cert_handle(p15card, items, &certs[i], cert_buffer, cert_length))) {
-				r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
-			}
-			if(should_free)
-				free(cert_buffer);
-			if(SC_SUCCESS != r) {
-				if(onFailResume)
-					continue;
-				else
-					break;
-			}
-		} else { /* Automatically add */
-			if(SC_SUCCESS != sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info)) {
-				if(onFailResume)
-					continue;
-				else
-					break;
-			}
-		}
-	}
-	return SC_SUCCESS;
-}
-
-int sc_pkcs15emu_initialize_pins(sc_pkcs15_card_t *p15card, p15data_items* items) {
-	/* set pins */
-	int i,r;
-	const pindata* pins = items->pins;
-	if(!pins) return SC_SUCCESS;
-	for (i = 0; pins[i].label; i++) {
-		struct sc_pkcs15_auth_info pin_info;
-		struct sc_pkcs15_object   pin_obj;
-
-		memset(&pin_info, 0, sizeof(pin_info));
-		memset(&pin_obj,  0, sizeof(pin_obj));
-
-		pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
-		sc_pkcs15_format_id(pins[i].id, &pin_info.auth_id);
-
-		pin_info.attrs.pin.reference     = pins[i].ref;
-		pin_info.attrs.pin.flags         = pins[i].flags;
-		pin_info.attrs.pin.type          = pins[i].type;
-		pin_info.attrs.pin.min_length    = pins[i].minlen;
-		pin_info.attrs.pin.stored_length = pins[i].storedlen;
-		pin_info.attrs.pin.max_length    = pins[i].maxlen;
-		pin_info.attrs.pin.pad_char      = pins[i].pad_char;
-
-		sc_format_path(pins[i].path, &pin_info.path);
-		pin_info.tries_left    = -1;
-
-		strncpy(pin_obj.label, pins[i].label, SC_PKCS15_MAX_LABEL_SIZE - 1);
-		pin_obj.flags = pins[i].obj_flags;
-
-		if(0 > (r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info)))
-			LOG_FUNC_RETURN(p15card->card->ctx, r);
-	}
-	return SC_SUCCESS;
-}
-
-int sc_pkcs15emu_initialize_private_keys(sc_pkcs15_card_t *p15card, p15data_items* items) {
-	const prdata *prkeys = items->private_keys;
-	int i, r;
-	if(!prkeys) return SC_SUCCESS;
-	/* set private keys */
-	for (i = 0; prkeys[i].label; i++) {
-		r = add_private_key(p15card, &prkeys[i], 0, 0);
-		if (r < 0)
-			LOG_FUNC_RETURN(p15card->card->ctx, r);
-	}
-	return SC_SUCCESS;
-}
-
-int sc_pkcs15emu_initialize_public_keys(sc_pkcs15_card_t *p15card, p15data_items *items) {
-	const pubdata *keys = items->public_keys;
-	int i, r;
-	if(!keys) return SC_SUCCESS;
-	/* set public keys */
-	for (i = 0; keys[i].label; i++) {
-		r = add_public_key(p15card, &keys[i], 0, 0);
-		if (r < 0)
-			LOG_FUNC_RETURN(p15card->card->ctx, r);
-	}
-	return SC_SUCCESS;
-
-}
-
-int sc_pkcs15emu_initialize_all(sc_pkcs15_card_t *p15card, p15data_items* items) {
-	int r;
-	if(SC_SUCCESS != (r = sc_pkcs15emu_initialize_objects(p15card, items)))
-		return r;
-	if(SC_SUCCESS != (r = sc_pkcs15emu_initialize_certificates(p15card, items)))
-		return r;
-	if(SC_SUCCESS != (r = sc_pkcs15emu_initialize_pins(p15card, items)))
-		return r;
-
-	if(items->forced_private && (SC_SUCCESS != (r = sc_pkcs15emu_initialize_private_keys(p15card, items))))
-		return r;
-	if(items->forced_public && (SC_SUCCESS != (r = sc_pkcs15emu_initialize_public_keys(p15card, items))))
-		return r;
-	return SC_SUCCESS;
-}
-
-#endif	/* ENABLE_OPENSSL */
diff -Nru opensc-0.22.0/src/libopensc/p15card-helper.h opensc-0.23.0/src/libopensc/p15card-helper.h
--- opensc-0.22.0/src/libopensc/p15card-helper.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/p15card-helper.h	1970-01-01 01:00:00.000000000 +0100
@@ -1,137 +0,0 @@
-/*
- * p15card-helper.h: Utility library to assist in PKCS#15 emulation on Non-filesystem cards
- *
- * Copyright (C) 2006, Identity Alliance, Thomas Harning <thomas.harning at identityalliance.com>
- *
- * 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
- */
-
-#ifndef P15CARD_HELPER_H
-#define P15CARD_HELPER_H
-
-#include "libopensc/pkcs15.h"
-
-
-#define USAGE_NONREP	SC_PKCS15_PRKEY_USAGE_NONREPUDIATION | \
-			SC_PKCS15_PRKEY_USAGE_SIGN
-#define USAGE_DS	SC_PKCS15_PRKEY_USAGE_SIGN
-#define USAGE_CRYPTO	SC_PKCS15_PRKEY_USAGE_ENCRYPT | \
-			SC_PKCS15_PRKEY_USAGE_DECRYPT | \
-			SC_PKCS15_PRKEY_USAGE_WRAP    | \
-			SC_PKCS15_PRKEY_USAGE_UNWRAP
-#define USAGE_KE	SC_PKCS15_PRKEY_USAGE_ENCRYPT | \
-			SC_PKCS15_PRKEY_USAGE_DECRYPT | \
-			SC_PKCS15_PRKEY_USAGE_WRAP    | \
-			SC_PKCS15_PRKEY_USAGE_UNWRAP
-#define USAGE_AUT	SC_PKCS15_PRKEY_USAGE_ENCRYPT | \
-			SC_PKCS15_PRKEY_USAGE_DECRYPT | \
-			SC_PKCS15_PRKEY_USAGE_WRAP    | \
-			SC_PKCS15_PRKEY_USAGE_UNWRAP  | \
-			SC_PKCS15_PRKEY_USAGE_SIGN
-
-
-typedef struct objdata_st {
-	const char *id;
-	const char *label;
-	const char *aoid;
-	int     authority;
-	const char *path;
-	int         obj_flags;
-} objdata;
-
-typedef struct cdata_st {
-	const char *id;
-	const char *label;
-	int	    authority;
-	const char *path;
-	int         obj_flags;
-} cdata;
-
-typedef struct pdata_st {
-	const char *id;
-	const char *label;
-	const char *path;
-	int         ref;
-	int         type;
-	unsigned int maxlen;
-	unsigned int minlen;
-	unsigned int storedlen;
-	int         flags;	
-	int         tries_left;
-	const char  pad_char;
-	int         obj_flags;
-} pindata; 
-
-typedef struct pubdata_st {
-	const char *id;
-	const char *label;
-	unsigned int modulus_len;
-	int         usage;
-	const char *path;
-	int         ref;
-	const char *auth_id;
-	int         obj_flags;
-} pubdata;
-
-typedef struct prdata_st {
-	const char *id;
-	const char *label;
-	unsigned int modulus_len;
-	int         usage;
-	const char *path;
-	int         ref;
-	const char *auth_id;
-	int         obj_flags;
-} prdata;
-
-typedef struct keyinfo_st {
-	int fileid;
-	sc_pkcs15_id_t id;
-	unsigned int modulus_len;
-	u8 modulus[1024/8];
-} keyinfo;
-
-typedef struct p15data_items p15data_items;
-
-typedef int (*cert_load_function)(sc_card_t *card, u8** data, size_t* length, int* shouldFree);
-#define CERT_LOAD_FUNCTION(x) int x(sc_card_t *card, u8** data, size_t*length, int *shouldFree)
-typedef int (*cert_handle_function)(sc_pkcs15_card_t *p15card, p15data_items* items, const cdata* cert, u8* data, size_t length);
-#define CERT_HANDLE_FUNCTION(x) int x(sc_pkcs15_card_t *p15card, p15data_items* items, const cdata* cert, u8* data, size_t length)
-
-struct p15data_items {
-	const objdata* objects;
-	const cdata* certs;
-	const pindata* pins;
-	const pubdata* public_keys;
-	const prdata* private_keys;
-	
-	cert_load_function cert_load;
-	cert_handle_function cert_handle;
-	int cert_continue; /* Continue after cert failure */
-	int forced_private; /* Should add all private keys w/o cert-management */
-	int forced_public; /* Should add public keys (generally not needed..) */
-};
-
-CERT_HANDLE_FUNCTION(default_cert_handle);
-
-int sc_pkcs15emu_initialize_objects(sc_pkcs15_card_t *p15card, p15data_items* items);
-int sc_pkcs15emu_initialize_certificates(sc_pkcs15_card_t *p15card, p15data_items* items);
-int sc_pkcs15emu_initialize_pins(sc_pkcs15_card_t *p15card, p15data_items *items);
-int sc_pkcs15emu_initialize_private_keys(sc_pkcs15_card_t *p15card, p15data_items *items);
-int sc_pkcs15emu_initialize_public_keys(sc_pkcs15_card_t *p15card, p15data_items *items);
-int sc_pkcs15emu_initialize_all(sc_pkcs15_card_t *p15card, p15data_items *items);
-
-#endif
-
diff -Nru opensc-0.22.0/src/libopensc/padding.c opensc-0.23.0/src/libopensc/padding.c
--- opensc-0.22.0/src/libopensc/padding.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/padding.c	2022-11-29 09:34:43.000000000 +0100
@@ -33,7 +33,7 @@
 #include <stdlib.h>
 
 #include "internal.h"
-
+#include "pkcs11/pkcs11.h"
 /* TODO doxygen comments */
 
 /*
@@ -184,6 +184,136 @@
 	LOG_FUNC_RETURN(ctx, len - n);
 }
 
+#ifdef ENABLE_OPENSSL
+static int mgf1(u8 *mask, size_t len, u8 *seed, size_t seedLen, const EVP_MD *dgst)
+{
+	int i;
+	size_t outlen = 0;
+	u8 cnt[4];
+	EVP_MD_CTX *md_ctx = NULL;
+	int mdlen;
+	u8 md[EVP_MAX_MD_SIZE];
+	int rv = 1;
+
+	if (!(md_ctx = EVP_MD_CTX_new()))
+		goto out;
+
+	mdlen = EVP_MD_size(dgst);
+	if (mdlen < 0)
+		goto out;
+
+	for (i = 0; outlen < len; i++) {
+		cnt[0] = (u8) ((i >> 24) & 255);
+		cnt[1] = (u8) ((i >> 16) & 255);
+		cnt[2] = (u8) ((i >> 8) & 255);
+		cnt[3] = (u8) ((i >> 0) & 255);
+		if (!EVP_DigestInit_ex(md_ctx, dgst, NULL)
+		    || !EVP_DigestUpdate(md_ctx, seed, seedLen)
+		    || !EVP_DigestUpdate(md_ctx, cnt, 4))
+			goto out;
+		if (outlen + mdlen <= len) {
+			if (!EVP_DigestFinal_ex(md_ctx, mask + outlen, NULL))
+				goto out;
+			outlen += mdlen;
+		} else {
+			if (!EVP_DigestFinal_ex(md_ctx, md, NULL))
+				goto out;
+			memcpy(mask + outlen, md, len - outlen);
+			outlen = len;
+		}
+	}
+	rv = 0;
+ out:
+	OPENSSL_cleanse(md, sizeof(md));
+	if (md_ctx)
+		EVP_MD_CTX_free(md_ctx);
+	return rv;
+}
+
+/* forward declarations */
+static const EVP_MD *mgf1_flag2md(unsigned int mgf1);
+static const EVP_MD *hash_flag2md(unsigned int hash);
+
+/* check/remove OAEP - RFC 8017 padding */
+int sc_pkcs1_strip_oaep_padding(sc_context_t *ctx, u8 *data, size_t len, unsigned long flags, uint8_t *param, size_t paramlen)
+{
+	size_t i,j;
+	size_t mdlen, dblen;
+	u8 seed[EVP_MAX_MD_SIZE];
+	const EVP_MD *mgf1_md, *hash_md;
+	u8 db[512];		/* up to RSA 4096 */
+	u8 label[EVP_MAX_MD_SIZE];
+	EVP_MD_CTX *md_ctx;
+	unsigned int hash_len = 0;
+
+	LOG_FUNC_CALLED(ctx);
+	if (data == NULL)
+		LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL);
+
+	/* https://www.rfc-editor.org/rfc/pdfrfc/rfc8017.txt.pdf, page 26, 3.a. */
+	hash_md = hash_flag2md(flags);
+	if (!hash_md)
+		return SC_ERROR_NOT_SUPPORTED;
+
+	memset(label, 0, sizeof(label));
+	if ((md_ctx = EVP_MD_CTX_new())) {
+		if (!EVP_DigestInit_ex(md_ctx, hash_md, NULL)
+		    || !EVP_DigestUpdate(md_ctx, param, paramlen)
+		    || !EVP_DigestFinal_ex(md_ctx, label, &hash_len))
+			hash_len = 0;
+		EVP_MD_CTX_free(md_ctx);
+	}
+	if (!hash_len)
+		LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL);
+
+	mgf1_md = mgf1_flag2md(flags);
+	if (!mgf1_md)
+		return SC_ERROR_NOT_SUPPORTED;
+
+	mdlen = EVP_MD_size(mgf1_md);
+
+	if (len < 2 * mdlen + 2)
+		LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_PADDING);
+
+	if (*data != 0)
+		LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_PADDING);
+
+	dblen = len - 1 - mdlen;
+	if (dblen > sizeof(db))
+		LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL);
+
+	if (mgf1(seed, mdlen, data + mdlen + 1, dblen, mgf1_md))
+		LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL);
+	for (i = 0; i < mdlen; i++)
+		seed[i] ^= data[i + 1];
+
+	if (mgf1(db, dblen, seed, mdlen, mgf1_md))
+		LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL);
+	for (i = 0; i < dblen; i++) {
+		db[i] ^= data[i + mdlen + 1];
+		/* clear lHash' if same as lHash */
+		if (i < hash_len)
+			db[i] ^= label[i];
+	}
+	/* if the padding is correct, it is a concatenation:
+	 *   00...00 || 01 || plaintext
+	 * check padding but do not leak information about error:
+	 */
+	for (j = 0, i = 0; i < dblen;) {
+		j += db[i++] + 1;
+		if (i > mdlen) {
+			if (j == i + 1) {
+				/* OK correct padding found */
+				len = dblen - i;
+				memcpy(data, db + i, len);
+				LOG_FUNC_RETURN(ctx, len);
+			}
+		}
+	}
+	LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_PADDING);
+}
+#endif
+
 /* add/remove DigestInfo prefix */
 static int sc_pkcs1_add_digest_info_prefix(unsigned int algorithm,
 	const u8 *in, size_t in_len, u8 *out, size_t *out_len)
@@ -275,9 +405,11 @@
 	}
 }
 
+/* large enough up to RSA 4096 */
+#define PSS_MAX_SALT_SIZE 512
 /* add PKCS#1 v2.0 PSS padding */
 static int sc_pkcs1_add_pss_padding(unsigned int hash, unsigned int mgf1_hash,
-    const u8 *in, size_t in_len, u8 *out, size_t *out_len, size_t mod_bits)
+    const u8 *in, size_t in_len, u8 *out, size_t *out_len, size_t mod_bits, size_t sLen)
 {
 	/* hLen = sLen in our case */
 	int rv = SC_ERROR_INTERNAL, i, j, hlen, dblen, plen, round, mgf_rounds;
@@ -285,7 +417,7 @@
 	const EVP_MD* md, *mgf1_md;
 	EVP_MD_CTX* ctx = NULL;
 	u8 buf[8];
-	u8 salt[EVP_MAX_MD_SIZE], mask[EVP_MAX_MD_SIZE];
+	u8 salt[PSS_MAX_SALT_SIZE], mask[EVP_MAX_MD_SIZE];
 	size_t mod_length = (mod_bits + 7) / 8;
 
 	if (*out_len < mod_length)
@@ -296,15 +428,16 @@
 		return SC_ERROR_NOT_SUPPORTED;
 	hlen = EVP_MD_size(md);
 	dblen = mod_length - hlen - 1; /* emLen - hLen - 1 */
-	plen = mod_length - 2*hlen - 1;
+	plen = mod_length - sLen - hlen - 1;
 	if (in_len != (unsigned)hlen)
 		return SC_ERROR_INVALID_ARGUMENTS;
-	if (2 * (unsigned)hlen + 2 > mod_length)
+	if (sLen + (unsigned)hlen + 2 > mod_length)
 		/* RSA key too small for chosen hash (1296 bits or higher needed for
 		 * signing SHA-512 hashes) */
 		return SC_ERROR_NOT_SUPPORTED;
-
-	if (RAND_bytes(salt, hlen) != 1)
+	if (sLen > PSS_MAX_SALT_SIZE)
+		return SC_ERROR_INVALID_ARGUMENTS;
+	if (RAND_bytes(salt, sLen) != 1)
 		return SC_ERROR_INTERNAL;
 
 	/* Hash M' to create H */
@@ -314,7 +447,7 @@
 	if (EVP_DigestInit_ex(ctx, md, NULL) != 1 ||
 	    EVP_DigestUpdate(ctx, buf, 8) != 1 ||
 	    EVP_DigestUpdate(ctx, in, hlen) != 1 || /* mHash */
-	    EVP_DigestUpdate(ctx, salt, hlen) != 1) {
+	    EVP_DigestUpdate(ctx, salt, sLen) != 1) {
 		goto done;
 	}
 
@@ -322,7 +455,7 @@
 	/* DB = PS || 0x01 || salt */
 	memset(out, 0x00, plen - 1); /* emLen - sLen - hLen - 2 */
 	out[plen - 1] = 0x01;
-	memcpy(out + plen, salt, hlen);
+	memcpy(out + plen, salt, sLen);
 	if (EVP_DigestFinal_ex(ctx, out + dblen, NULL) != 1) { /* H */
 		goto done;
 	}
@@ -395,7 +528,7 @@
 
 /* general PKCS#1 encoding function */
 int sc_pkcs1_encode(sc_context_t *ctx, unsigned long flags,
-	const u8 *in, size_t in_len, u8 *out, size_t *out_len, size_t mod_bits)
+	const u8 *in, size_t in_len, u8 *out, size_t *out_len, size_t mod_bits, void *pMechanism)
 {
 	int    rv, i;
 	size_t tmp_len = *out_len;
@@ -403,6 +536,8 @@
 	unsigned int hash_algo, pad_algo;
 	size_t mod_len = (mod_bits + 7) / 8;
 #ifdef ENABLE_OPENSSL
+	size_t sLen;
+	const EVP_MD* md;
 	unsigned int mgf1_hash;
 #endif
 
@@ -450,8 +585,21 @@
 			 */
 			hash_algo = hash_len2algo(tmp_len);
 		}
+		/* sLen is by default same as hash length */
+		if (!(md = hash_flag2md(hash_algo)))
+			return SC_ERROR_NOT_SUPPORTED;
+		sLen = EVP_MD_size(md);
+		/* if application provide sLen, use it */
+		if (pMechanism != NULL) {
+			CK_MECHANISM *mech = (CK_MECHANISM *)pMechanism;
+			CK_RSA_PKCS_PSS_PARAMS *pss_params;
+			if (mech->pParameter && sizeof(CK_RSA_PKCS_PSS_PARAMS) == mech->ulParameterLen) {
+				pss_params = mech->pParameter;
+				sLen = pss_params->sLen;
+			}
+		}
 		rv = sc_pkcs1_add_pss_padding(hash_algo, mgf1_hash,
-		    tmp, tmp_len, out, out_len, mod_bits);
+		    tmp, tmp_len, out, out_len, mod_bits, sLen);
 #else
 		rv = SC_ERROR_NOT_SUPPORTED;
 #endif
@@ -497,11 +645,13 @@
 	} else if ((caps & SC_ALGORITHM_RSA_RAW) &&
 				(iflags & SC_ALGORITHM_RSA_PAD_PKCS1
 				|| iflags & SC_ALGORITHM_RSA_PAD_PSS
+#ifdef ENABLE_OPENSSL
+				|| iflags & SC_ALGORITHM_RSA_PAD_OAEP
+#endif
 				|| iflags & SC_ALGORITHM_RSA_PAD_NONE)) {
 		/* Use the card's raw RSA capability on the padded input */
 		*sflags = SC_ALGORITHM_RSA_PAD_NONE;
 		*pflags = iflags;
-		/* TODO emulate the OAEP decryption */
 
 	} else if ((caps & (SC_ALGORITHM_RSA_PAD_PKCS1 | SC_ALGORITHM_RSA_HASH_NONE)) &&
 			(iflags & SC_ALGORITHM_RSA_PAD_PKCS1)) {
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-actalis.c opensc-0.23.0/src/libopensc/pkcs15-actalis.c
--- opensc-0.22.0/src/libopensc/pkcs15-actalis.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-actalis.c	2022-11-29 09:34:43.000000000 +0100
@@ -141,6 +141,8 @@
 	int r;
 
 #ifdef ENABLE_ZLIB
+	int use_file_cache_backup = p15card->opts.use_file_cache;
+	
 	int i = 0, j = 0;
 	const char *certLabel[] = {
 		"User Non-repudiation Certificate",	/* "User Non-repudiation Certificate" */
@@ -165,8 +167,8 @@
 
 	const char *authPRKEY = "Authentication Key";
 	/* const char *nonrepPRKEY = "Non repudiation Key"; */
-	
-	p15card->opts.use_file_cache = 1;	
+
+	p15card->opts.use_file_cache = SC_PKCS15_OPTS_CACHE_ALL_FILES;	
 
 	/* Get Serial number */
 	sc_format_path("3F0030000001", &path);
@@ -223,6 +225,8 @@
 			if (!cert || !compCert) {
 				free(cert);
 				free(compCert);
+				sc_pkcs15_card_clear(p15card);
+				p15card->opts.use_file_cache = use_file_cache_backup;
 				return SC_ERROR_OUT_OF_MEMORY;
 			}
 
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-algo.c opensc-0.23.0/src/libopensc/pkcs15-algo.c
--- opensc-0.22.0/src/libopensc/pkcs15-algo.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-algo.c	2022-11-29 09:34:43.000000000 +0100
@@ -358,9 +358,6 @@
 #ifdef SC_ALGORITHM_MD5
 	{ SC_ALGORITHM_MD5, {{ 1, 2, 840, 113549, 2, 5, -1}}, NULL, NULL, NULL },
 #endif
-#ifdef SC_ALGORITHM_DSA
-	{ SC_ALGORITHM_DSA, {{ 1, 2, 840, 10040, 4, 3, -1}}, NULL, NULL, NULL },
-#endif
 #ifdef SC_ALGORITHM_RSA /* really rsaEncryption */
 	{ SC_ALGORITHM_RSA, {{ 1, 2, 840, 113549, 1, 1, 1, -1}}, NULL, NULL, NULL },
 #endif
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-atrust-acos.c opensc-0.23.0/src/libopensc/pkcs15-atrust-acos.c
--- opensc-0.22.0/src/libopensc/pkcs15-atrust-acos.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-atrust-acos.c	2022-11-29 09:34:43.000000000 +0100
@@ -27,6 +27,7 @@
 #include <string.h>
 #include <stdio.h>
 
+#include "internal.h"
 #include "common/compat_strlcpy.h"
 #include "libopensc/pkcs15.h"
 #include "libopensc/cardctl.h"
@@ -152,22 +153,20 @@
 	r = sc_bin_to_hex(buf, 8, buf2, sizeof(buf2), 0);
 	if (r != SC_SUCCESS)
 		return SC_ERROR_INTERNAL;
-	free(p15card->tokeninfo->serial_number);
-	p15card->tokeninfo->serial_number = strdup(buf2);
+
+	set_string(&p15card->tokeninfo->serial_number, buf2);
 	if (!p15card->tokeninfo->serial_number)
 		return SC_ERROR_INTERNAL;
 
 	/* manufacturer ID */
-	free(p15card->tokeninfo->manufacturer_id);
-	p15card->tokeninfo->manufacturer_id = strdup(MANU_ID);
+	set_string(&p15card->tokeninfo->manufacturer_id, MANU_ID);
 	if (!p15card->tokeninfo->manufacturer_id)
-		return SC_ERROR_INTERNAL;
+		goto err;
 
 	/* card label */
-	free(p15card->tokeninfo->label);
-	p15card->tokeninfo->label = strdup(CARD_LABEL);
+	set_string(&p15card->tokeninfo->label, CARD_LABEL);
 	if (!p15card->tokeninfo->label)
-		return SC_ERROR_INTERNAL;
+		goto err;
 
 	/* set certs */
 	for (i = 0; certs[i].label; i++) {
@@ -189,7 +188,7 @@
 
 		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
 		if (r < 0)
-			return SC_ERROR_INTERNAL;
+			goto err;
 	}
 	/* set pins */
 	for (i = 0; pins[i].label; i++) {
@@ -217,7 +216,7 @@
 
 		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
 		if (r < 0)
-			return SC_ERROR_INTERNAL;
+			goto err;
 	}
 	/* set private keys */
 	for (i = 0; prkeys[i].label; i++) {
@@ -241,19 +240,23 @@
 
 		r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
 		if (r < 0)
-			return SC_ERROR_INTERNAL;
+			goto err;
 	}
 		
 	/* select the application DF */
 	sc_format_path("DF71", &path);
 	r = sc_select_file(card, &path, &file);
 	if (r != SC_SUCCESS || !file)
-		return SC_ERROR_INTERNAL;
+		goto err;
 	/* set the application DF */
 	sc_file_free(p15card->file_app);
 	p15card->file_app = file;
 
 	return SC_SUCCESS;
+
+err:
+	sc_pkcs15_card_clear(p15card);
+	return SC_ERROR_INTERNAL;
 }
 
 int sc_pkcs15emu_atrust_acos_init_ex(sc_pkcs15_card_t *p15card,
diff -Nru opensc-0.22.0/src/libopensc/pkcs15.c opensc-0.23.0/src/libopensc/pkcs15.c
--- opensc-0.22.0/src/libopensc/pkcs15.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15.c	2022-11-29 09:34:43.000000000 +0100
@@ -306,6 +306,7 @@
 	size_t algo_ref_len = sizeof(ti->supported_algos[0].algo_ref);
 	struct sc_asn1_entry asn1_last_update[C_ASN1_LAST_UPDATE_SIZE];
 	struct sc_asn1_entry asn1_profile_indication[C_ASN1_PROFILE_INDICATION_SIZE];
+	u8 serial[128];
 
 	sc_copy_asn1_entry(c_asn1_toki_attrs, asn1_toki_attrs);
 	sc_copy_asn1_entry(c_asn1_tokeninfo, asn1_tokeninfo);
@@ -340,7 +341,6 @@
 
 	sc_format_asn1_entry(asn1_toki_attrs + 0, &ti->version, NULL, 1);
 	if (ti->serial_number != NULL) {
-		u8 serial[128];
 		serial_len = 0;
 		if (strlen(ti->serial_number)/2 > sizeof(serial))
 			return SC_ERROR_BUFFER_TOO_SMALL;
@@ -859,6 +859,8 @@
 		p15card->tokeninfo->seInfo     = NULL;
 		p15card->tokeninfo->num_seInfo = 0;
 	}
+
+	sc_pkcs15_free_app(p15card);
 }
 
 
@@ -910,6 +912,7 @@
 		return NULL;
 	}
 	memcpy(out->ddo.value, info->ddo.value, info->ddo.len);
+	out->ddo.len = info->ddo.len;
 
 	return out;
 }
@@ -1217,6 +1220,7 @@
 	struct sc_context *ctx;
 	scconf_block *conf_block = NULL;
 	int r, emu_first, enable_emu;
+	const char *use_file_cache;
 	const char *private_certificate;
 
 	if (card == NULL || p15card_out == NULL) {
@@ -1232,7 +1236,8 @@
 		LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
 
 	p15card->card = card;
-	p15card->opts.use_file_cache = 0;
+	p15card->opts.use_file_cache = SC_PKCS15_OPTS_CACHE_NO_FILES;
+	use_file_cache = "no";
 	p15card->opts.use_pin_cache = 1;
 	p15card->opts.pin_cache_counter = 10;
 	p15card->opts.pin_cache_ignore_user_consent = 0;
@@ -1246,13 +1251,22 @@
 
 	conf_block = sc_get_conf_block(ctx, "framework", "pkcs15", 1);
 	if (conf_block) {
-		p15card->opts.use_file_cache = scconf_get_bool(conf_block, "use_file_caching", p15card->opts.use_file_cache);
+		use_file_cache = scconf_get_str(conf_block, "use_file_caching", use_file_cache);
 		p15card->opts.use_pin_cache = scconf_get_bool(conf_block, "use_pin_caching", p15card->opts.use_pin_cache);
 		p15card->opts.pin_cache_counter = scconf_get_int(conf_block, "pin_cache_counter", p15card->opts.pin_cache_counter);
 		p15card->opts.pin_cache_ignore_user_consent = scconf_get_bool(conf_block, "pin_cache_ignore_user_consent",
 				p15card->opts.pin_cache_ignore_user_consent);
 		private_certificate = scconf_get_str(conf_block, "private_certificate", private_certificate);
 	}
+
+	if (0 == strcmp(use_file_cache, "yes")) {
+		p15card->opts.use_file_cache = SC_PKCS15_OPTS_CACHE_ALL_FILES;
+	} else if (0 == strcmp(use_file_cache, "public")) {
+		p15card->opts.use_file_cache = SC_PKCS15_OPTS_CACHE_PUBLIC_FILES;
+	} else if (0 == strcmp(use_file_cache, "no")) {
+		p15card->opts.use_file_cache = SC_PKCS15_OPTS_CACHE_NO_FILES;
+	}
+
 	if (0 == strcmp(private_certificate, "protect")) {
 		p15card->opts.private_certificate = SC_PKCS15_CARD_OPTS_PRIV_CERT_PROTECT;
 	} else if (0 == strcmp(private_certificate, "ignore")) {
@@ -2046,6 +2060,7 @@
 		buf = p;
 		memcpy(buf + bufsize, tmp, tmpsize);
 		free(tmp);
+		tmp = NULL;
 		bufsize += tmpsize;
 	}
 	*buf_out = buf;
@@ -2098,7 +2113,7 @@
 		sc_log(ctx, "unknown DF type: %d", df->type);
 		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
 	}
-	r = sc_pkcs15_read_file(p15card, &df->path, &buf, &bufsize);
+	r = sc_pkcs15_read_file(p15card, &df->path, &buf, &bufsize, 0);
 	LOG_TEST_RET(ctx, r, "pkcs15 read file failed");
 
 	p = buf;
@@ -2339,7 +2354,7 @@
 
 int
 sc_pkcs15_read_file(struct sc_pkcs15_card *p15card, const struct sc_path *in_path,
-		unsigned char **buf, size_t *buflen)
+		unsigned char **buf, size_t *buflen, int private_data)
 {
 	struct sc_context *ctx;
 	struct sc_file *file = NULL;
@@ -2356,7 +2371,8 @@
 	sc_log(ctx, "path=%s, index=%u, count=%d", sc_print_path(in_path), in_path->index, in_path->count);
 
 	r = -1; /* file state: not in cache */
-	if (p15card->opts.use_file_cache) {
+	if (p15card->opts.use_file_cache
+	    && ((p15card->opts.use_file_cache & SC_PKCS15_OPTS_CACHE_ALL_FILES) || !private_data)) {
 		r = sc_pkcs15_read_cached_file(p15card, in_path, &data, &len);
 
 		if (!r && in_path->aid.len > 0 && in_path->len >= 2)   {
@@ -2444,7 +2460,8 @@
 
 		sc_file_free(file);
 
-		if (len && p15card->opts.use_file_cache) {
+		if (len && p15card->opts.use_file_cache
+		    && ((p15card->opts.use_file_cache & SC_PKCS15_OPTS_CACHE_ALL_FILES) || !private_data)) {
 			sc_pkcs15_cache_file(p15card, in_path, data, len);
 		}
 	}
@@ -2557,8 +2574,7 @@
 			|| SC_PKCS15_TYPE_SKEY & obj->type
 			|| SC_PKCS15_TYPE_PRKEY & obj->type) {
 			/* clean everything that potentially contains a secret */
-			sc_mem_clear(obj->content.value, obj->content.len);
-			sc_mem_secure_free(obj->content.value, obj->content.len);
+			sc_mem_secure_clear_free(obj->content.value, obj->content.len);
 		} else {
 			free(obj->content.value);
 		}
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-cac.c opensc-0.23.0/src/libopensc/pkcs15-cac.c
--- opensc-0.22.0/src/libopensc/pkcs15-cac.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-cac.c	2022-11-29 09:34:43.000000000 +0100
@@ -170,36 +170,31 @@
 
 		/* get the ACA path in case it needs to be selected before PIN verify */
 		r = sc_card_ctl(card, SC_CARDCTL_CAC_GET_ACA_PATH, &pin_info.path);
-		if (r < 0) {
-			LOG_FUNC_RETURN(card->ctx, r);
-		}
+		LOG_TEST_GOTO_ERR(card->ctx, r, "Can not get ACA path.");
 
 		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
-		if (r < 0)
-			LOG_FUNC_RETURN(card->ctx, r);
+		LOG_TEST_GOTO_ERR(card->ctx, r, "Can not add pin object.");
 	}
 
 	/* set other objects */
 	r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_INIT_GET_GENERIC_OBJECTS, &count);
-	LOG_TEST_RET(card->ctx, r, "Can not initiate generic objects.");
+	LOG_TEST_GOTO_ERR(card->ctx, r, "Can not initiate generic objects.");
 
 	for (i = 0; i < count; i++) {
 		struct sc_pkcs15_data_info obj_info;
 		struct sc_pkcs15_object    obj_obj;
 
 		r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_GET_NEXT_GENERIC_OBJECT, &obj_info);
-		if (r < 0)
-			LOG_FUNC_RETURN(card->ctx, r);
+		LOG_TEST_GOTO_ERR(card->ctx, r, "Can not get next generic object.");
 		memset(&obj_obj, 0, sizeof(obj_obj));
 		memcpy(obj_obj.label, obj_info.app_label, sizeof(obj_obj.label));
 
 		r = sc_pkcs15emu_object_add(p15card, SC_PKCS15_TYPE_DATA_OBJECT,
 			&obj_obj, &obj_info);
-		if (r < 0)
-			LOG_FUNC_RETURN(card->ctx, r);
+		LOG_TEST_GOTO_ERR(card->ctx, r, "Can not finalize generic object.");
 	}
 	r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_FINAL_GET_GENERIC_OBJECTS, &count);
-	LOG_TEST_RET(card->ctx, r, "Can not finalize generic objects.");
+	LOG_TEST_GOTO_ERR(card->ctx, r, "Can not finalize generic objects.");
 
 	/*
 	 * certs, pubkeys and priv keys are related and we assume
@@ -209,7 +204,7 @@
 	 */
 	sc_log(card->ctx,  "CAC adding certs, pub and priv keys...");
 	r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_INIT_GET_CERT_OBJECTS, &count);
-	LOG_TEST_RET(card->ctx, r, "Can not initiate cert objects.");
+	LOG_TEST_GOTO_ERR(card->ctx, r, "Can not initiate cert objects.");
 
 	for (i = 0; i < count; i++) {
 		struct sc_pkcs15_data_info obj_info;
@@ -257,7 +252,7 @@
 		prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
 		sc_pkcs15_format_id(pins[0].id, &prkey_obj.auth_id);
 
-		r = sc_pkcs15_read_file(p15card, &cert_info.path, &cert_der.value, &cert_der.len);
+		r = sc_pkcs15_read_file(p15card, &cert_info.path, &cert_der.value, &cert_der.len, 0);
 
 		if (r) {
 			sc_log(card->ctx,  "No cert found,i=%d", i);
@@ -279,7 +274,7 @@
 		}
 
 		/* following will find the cached cert in cert_info */
-		r =  sc_pkcs15_read_certificate(p15card, &cert_info, &cert_out);
+		r =  sc_pkcs15_read_certificate(p15card, &cert_info, 0, &cert_out);
 		if (r < 0 || cert_out->key == NULL) {
 			sc_log(card->ctx,  "Failed to read/parse the certificate r=%d",r);
 			if (cert_out != NULL)
@@ -334,29 +329,42 @@
 		if (cert_out->key->algorithm != SC_ALGORITHM_RSA) {
 			sc_log(card->ctx, "unsupported key.algorithm %d", cert_out->key->algorithm);
 			sc_pkcs15_free_certificate(cert_out);
+			free(pubkey_info.direct.spki.value);
 			continue;
 		} else {
 			pubkey_info.modulus_length = cert_out->key->u.rsa.modulus.len * 8;
 			prkey_info.modulus_length = cert_out->key->u.rsa.modulus.len * 8;
 			r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
 			sc_log(card->ctx,  "adding rsa public key r=%d usage=%x",r, pubkey_info.usage);
-			if (r < 0)
+			if (r < 0) {
+				free(pubkey_info.direct.spki.value);
 				goto fail;
+			}
+			pubkey_info.direct.spki.value = NULL; /* moved to the pubkey object on p15card  */
+			pubkey_info.direct.spki.len = 0;
 			r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
+			if (r < 0)
+				goto fail;
 			sc_log(card->ctx,  "adding rsa private key r=%d usage=%x",r, prkey_info.usage);
 		}
 
 		cert_out->key = NULL;
 fail:
 		sc_pkcs15_free_certificate(cert_out);
-		if (r < 0)
-			LOG_FUNC_RETURN(card->ctx, r); /* should not fail */
+		if (r < 0) {
+			(card->ops->card_ctl)(card, SC_CARDCTL_CAC_FINAL_GET_CERT_OBJECTS, &count);
+			LOG_TEST_GOTO_ERR(card->ctx, r, "Failed to add object.");
+		}
 
 	}
 	r = (card->ops->card_ctl)(card, SC_CARDCTL_CAC_FINAL_GET_CERT_OBJECTS, &count);
-	LOG_TEST_RET(card->ctx, r, "Can not finalize cert objects.");
+	LOG_TEST_GOTO_ERR(card->ctx, r, "Can not finalize cert objects.");
 
 	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+
+err:
+	sc_pkcs15_card_clear(p15card);
+	LOG_FUNC_RETURN(card->ctx, r);
 }
 
 int sc_pkcs15emu_cac_init_ex(sc_pkcs15_card_t *p15card,
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-cert.c opensc-0.23.0/src/libopensc/pkcs15-cert.c
--- opensc-0.22.0/src/libopensc/pkcs15-cert.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-cert.c	2022-11-29 09:34:43.000000000 +0100
@@ -367,7 +367,7 @@
 
 int
 sc_pkcs15_read_certificate(struct sc_pkcs15_card *p15card, const struct sc_pkcs15_cert_info *info,
-		struct sc_pkcs15_cert **cert_out)
+		int private_obj, struct sc_pkcs15_cert **cert_out)
 {
 	struct sc_context *ctx = NULL;
 	struct sc_pkcs15_cert *cert = NULL;
@@ -384,7 +384,7 @@
 		sc_der_copy(&der, &info->value);
 	}
 	else if (info->path.len) {
-		r = sc_pkcs15_read_file(p15card, &info->path, &der.value, &der.len);
+		r = sc_pkcs15_read_file(p15card, &info->path, &der.value, &der.len, private_obj);
 		LOG_TEST_RET(ctx, r, "Unable to read certificate file.");
 	}
 	else   {
@@ -573,9 +573,6 @@
 		       SC_PKCS15_PRKEY_USAGE_DECRYPT | SC_PKCS15_PRKEY_USAGE_UNWRAP |
 		       SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_SIGNRECOVER |
 		       SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
-	case SC_ALGORITHM_DSA:
-		return SC_PKCS15_PRKEY_USAGE_VERIFY| SC_PKCS15_PRKEY_USAGE_SIGN |
-		       SC_PKCS15_PRKEY_USAGE_NONREPUDIATION;
 #ifdef SC_ALGORITHM_DH
 	case SC_ALGORITHM_DH:
 		return SC_PKCS15_PRKEY_USAGE_DERIVE ;
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-coolkey.c opensc-0.23.0/src/libopensc/pkcs15-coolkey.c
--- opensc-0.22.0/src/libopensc/pkcs15-coolkey.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-coolkey.c	2022-11-29 09:34:43.000000000 +0100
@@ -147,9 +147,9 @@
 static int
 coolkey_get_attribute_ulong(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, CK_ATTRIBUTE_TYPE type, CK_ULONG *value)
 {
-	const u8 *val;
-	size_t val_len;
-	u8 data_type;
+	const u8 *val = NULL;
+	size_t val_len = 0;
+	u8 data_type = 0;
 	int r;
 
 	r  = coolkey_get_attribute(card, obj, type, &val, &val_len, &data_type);
@@ -168,8 +168,8 @@
 coolkey_get_attribute_boolean(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, CK_ATTRIBUTE_TYPE attr_type)
 {
 	int r;
-	const u8 *val;
-	size_t val_len;
+	const u8 *val = NULL;
+	size_t val_len = 0;
 
 	r = coolkey_get_attribute(card, obj, attr_type, &val, &val_len, NULL);
 	if (r < 0) {
@@ -186,7 +186,7 @@
 coolkey_get_attribute_bytes(sc_card_t *card, sc_cardctl_coolkey_object_t *obj, CK_ATTRIBUTE_TYPE type, u8 *data, size_t *data_len, size_t max_data_len)
 {
 	const u8 *val;
-	size_t val_len;
+	size_t val_len = 0;
 	int r;
 
 	r = coolkey_get_attribute(card, obj, type, &val, &val_len, NULL);
@@ -423,7 +423,8 @@
 	sc_pkcs15_cert_info_t cert_info;
 	sc_pkcs15_cert_t *cert_out = NULL;
 	sc_pkcs15_pubkey_t *key = NULL;
-	int r;
+	int r, private_obj;
+	unsigned int flags;
 
 	memset(&cert_info, 0, sizeof(cert_info));
 
@@ -431,7 +432,10 @@
 	if (r < 0) {
 		goto fail;
 	}
-	r = sc_pkcs15_read_certificate(p15card, &cert_info, &cert_out);
+
+	coolkey_get_flags(p15card->card, obj, &flags);
+	private_obj = flags & SC_PKCS15_CO_FLAG_PRIVATE;
+	r = sc_pkcs15_read_certificate(p15card, &cert_info, private_obj, &cert_out);
 	if (r < 0) {
 		goto fail;
 	}
@@ -461,6 +465,7 @@
 
 static int sc_pkcs15emu_coolkey_init(sc_pkcs15_card_t *p15card)
 {
+	int use_pin_cache_backup = p15card->opts.use_pin_cache;
 	static const pindata pins[] = {
 		{ "1", NULL, "", 0x00,
 		  SC_PKCS15_PIN_TYPE_ASCII_NUMERIC,
@@ -493,7 +498,6 @@
 	 * anyway */
 	p15card->opts.use_pin_cache = 0;
 
-
 	/* get the token info from the card */
 	r = sc_card_ctl(card, SC_CARDCTL_COOLKEY_GET_TOKEN_INFO, p15card->tokeninfo);
 	if (r < 0) {
@@ -531,13 +535,12 @@
 		pin_obj.flags = pins[i].obj_flags;
 
 		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
-		if (r < 0)
-			LOG_FUNC_RETURN(card->ctx, r);
+		LOG_TEST_GOTO_ERR(card->ctx, r, "Can not add pin object.");
 	}
 
 	/* set other objects */
 	r = (card->ops->card_ctl)(card, SC_CARDCTL_COOLKEY_INIT_GET_OBJECTS, &count);
-	LOG_TEST_RET(card->ctx, r, "Can not initiate objects.");
+	LOG_TEST_GOTO_ERR(card->ctx, r, "Can not initiate objects.");
 
 	sc_log(card->ctx,  "Iterating over %d objects", count);
 	for (i = 0; i < count; i++) {
@@ -554,9 +557,7 @@
 		size_t len;
 
 		r = (card->ops->card_ctl)(card, SC_CARDCTL_COOLKEY_GET_NEXT_OBJECT, &coolkey_obj);
-		if (r < 0)
-			LOG_FUNC_RETURN(card->ctx, r);
-
+		LOG_TEST_GOTO_ERR(card->ctx, r, "Can not get next object from card.");
 		sc_log(card->ctx, "Loading object %d", i);
 		memset(&obj_obj, 0, sizeof(obj_obj));
 		/* coolkey applets have label only on the certificates,
@@ -643,6 +644,7 @@
 				obj_type = SC_PKCS15_TYPE_PUBKEY_EC;
 				pubkey_info.field_length = key->u.ec.params.field_length;
 			} else {
+				free(pubkey_info.direct.spki.value);
 				goto fail;
 			}
 			/* set the obj values */
@@ -680,7 +682,7 @@
 
 	}
 	r = (card->ops->card_ctl)(card, SC_CARDCTL_COOLKEY_FINAL_GET_OBJECTS, &count);
-	LOG_TEST_RET(card->ctx, r, "Can not finalize objects.");
+	LOG_TEST_GOTO_ERR(card->ctx, r, "Can not finalize objects.");
 
 	/* Iterate over all the created objects and fill missing labels */
 	for (obj = p15card->obj_list; obj != NULL; obj = obj->next) {
@@ -712,6 +714,12 @@
 	}
 
 	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+
+err:
+	sc_pkcs15_card_clear(p15card);
+	p15card->opts.use_pin_cache = use_pin_cache_backup;
+
+	LOG_FUNC_RETURN(card->ctx, r);
 }
 
 int
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-data.c opensc-0.23.0/src/libopensc/pkcs15-data.c
--- opensc-0.22.0/src/libopensc/pkcs15-data.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-data.c	2022-11-29 09:34:43.000000000 +0100
@@ -41,6 +41,7 @@
 int
 sc_pkcs15_read_data_object(struct sc_pkcs15_card *p15card,
 		const struct sc_pkcs15_data_info *info,
+		int private_obj,
 		struct sc_pkcs15_data **data_object_out)
 {
 	struct sc_context *ctx = p15card->card->ctx;
@@ -53,7 +54,7 @@
 		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
 
 	if (!info->data.value)   {
-		r = sc_pkcs15_read_file(p15card, &info->path, (unsigned char **) &info->data.value, (size_t *) &info->data.len);
+		r = sc_pkcs15_read_file(p15card, &info->path, (unsigned char **) &info->data.value, (size_t *) &info->data.len, private_obj);
 		LOG_TEST_RET(ctx, r, "Cannot get DATA object data");
 	}
 
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-din-66291.c opensc-0.23.0/src/libopensc/pkcs15-din-66291.c
--- opensc-0.22.0/src/libopensc/pkcs15-din-66291.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-din-66291.c	2022-11-29 09:34:43.000000000 +0100
@@ -23,6 +23,7 @@
 #include <config.h>
 #endif
 
+#include "internal.h"
 #include "common/compat_strlcpy.h"
 #include "log.h"
 #include "pkcs15.h"
@@ -106,8 +107,10 @@
                 pin_obj.auth_id.len = 1;
             }
 
-            if (0 > sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info))
+            if (0 > sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info)) {
+                sc_pkcs15_card_clear(p15card);
                 return SC_ERROR_INTERNAL;
+            }
         }
 
         for (i = 0; i < 2; i++) {
@@ -146,7 +149,7 @@
 
             if (i == 0) {
                 sc_pkcs15_cert_t *cert;
-                if (SC_SUCCESS == sc_pkcs15_read_certificate(p15card, &cert_info, &cert)) {
+                if (SC_SUCCESS == sc_pkcs15_read_certificate(p15card, &cert_info, 0, &cert)) {
                     static const struct sc_object_id cn_oid = {{ 2, 5, 4, 3, -1 }};
                     u8 *cn_name = NULL;
                     size_t cn_len = 0;
@@ -254,7 +257,7 @@
             && SC_SUCCESS == sc_card_ctl(p15card->card, SC_CARDCTL_GET_SERIALNR, &serial)) {
         char serial_hex[SC_MAX_SERIALNR*2+2];
         sc_bin_to_hex(serial.value, serial.len , serial_hex, sizeof serial_hex, 0);
-        p15card->tokeninfo->serial_number = strdup(serial_hex);
+        set_string(&p15card->tokeninfo->serial_number, serial_hex);
     }
 
     r = SC_SUCCESS;
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-dnie.c opensc-0.23.0/src/libopensc/pkcs15-dnie.c
--- opensc-0.22.0/src/libopensc/pkcs15-dnie.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-dnie.c	2022-11-29 09:34:43.000000000 +0100
@@ -143,6 +143,7 @@
 	size_t len = sizeof(buf);
 	int rv;
 	struct sc_pkcs15_cert_info *p15_info = NULL;
+	int use_pin_cache_backup = p15card->opts.use_pin_cache;
 
 	sc_context_t *ctx = p15card->card->ctx;
 	LOG_FUNC_CALLED(ctx);
@@ -171,38 +172,32 @@
 	/* Set root path of this application */
 	sc_file_free(p15card->file_app);
 	p15card->file_app = sc_file_new();
-	if (NULL == p15card->file_app)
-		LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_ENOUGH_MEMORY);
+	if (NULL == p15card->file_app) {
+		rv = SC_ERROR_NOT_ENOUGH_MEMORY;
+		LOG_TEST_GOTO_ERR(ctx, rv, "Can not create file.");
+	}
 	sc_format_path("3F00", &p15card->file_app->path);
 
 	/* Load TokenInfo */
 	rv = dump_ef(p15card->card, "3F0050155032", buf, &len);
-	if (rv != SC_SUCCESS) {
-		sc_log(ctx, "Reading of EF.TOKENINFO failed: %d", rv);
-		LOG_FUNC_RETURN(ctx, rv);
-	}
+	LOG_TEST_GOTO_ERR(ctx, rv, "Reading of EF.TOKENINFO failed.");
+
 	rv = sc_pkcs15_parse_tokeninfo(p15card->card->ctx, p15card->tokeninfo,
 				       buf, len);
-	if (rv != SC_SUCCESS) {
-		sc_log(ctx, "Decoding of EF.TOKENINFO failed: %d", rv);
-		LOG_FUNC_RETURN(ctx, rv);
-	}
+	LOG_TEST_GOTO_ERR(ctx, rv, "Decoding of EF.TOKENINFO failed.");
 
 	/* Only accept the original stuff */
-	if (strcmp(p15card->tokeninfo->manufacturer_id, "DGP-FNMT") != 0)
-		LOG_FUNC_RETURN(ctx, SC_ERROR_WRONG_CARD);
+	if (strcmp(p15card->tokeninfo->manufacturer_id, "DGP-FNMT") != 0) {
+		rv = SC_ERROR_WRONG_CARD;
+		LOG_TEST_GOTO_ERR(ctx, rv, "Wrong card.");
+	}
 
 	/* Load ODF */
 	rv = dump_ef(p15card->card, "3F0050155031", buf, &len);
-	if (rv != SC_SUCCESS) {
-		sc_log(ctx, "Reading of ODF failed: %d", rv);
-		LOG_FUNC_RETURN(ctx, rv);
-	}
+	LOG_TEST_GOTO_ERR(ctx, rv, "Reading of ODF failed.");
+
 	rv = parse_odf(buf, len, p15card);
-	if (rv != SC_SUCCESS) {
-		sc_log(ctx, "Decoding of ODF failed: %d", rv);
-		LOG_FUNC_RETURN(ctx, rv);
-	}
+	LOG_TEST_GOTO_ERR(ctx, rv, "Decoding of ODF failed.");
 
 	/* Decode EF.PrKDF, EF.PuKDF and EF.CDF */
 	for (df = p15card->df_list; df != NULL; df = df->next) {
@@ -270,6 +265,11 @@
 	}
 	
 	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
+
+err:
+	sc_pkcs15_card_clear(p15card);
+	p15card->opts.use_pin_cache = use_pin_cache_backup;
+	LOG_FUNC_RETURN(ctx, rv);
 }
 #endif
 
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-emulator-filter.c opensc-0.23.0/src/libopensc/pkcs15-emulator-filter.c
--- opensc-0.22.0/src/libopensc/pkcs15-emulator-filter.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/libopensc/pkcs15-emulator-filter.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,128 @@
+/*
+ * pkcs15-emulator-filter.c: PKCS #15 emulator filter
+ *
+ * Copyright (C) 2021 Red Hat, Inc.
+ *
+ * Author: Veronika Hanulikova <vhanulik at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "internal.h"
+#include "pkcs15-syn.h"
+#include "pkcs15-emulator-filter.h"
+
+static int add_emul(struct _sc_pkcs15_emulators* filtered_emulators,
+					struct sc_pkcs15_emulator_handler* emul_handler)
+{
+	struct sc_pkcs15_emulator_handler** lst;
+	int *cp, max, i;
+
+	if (!filtered_emulators || !emul_handler || !emul_handler->name || !emul_handler->handler)
+		return SC_ERROR_INVALID_ARGUMENTS;
+	
+	lst = filtered_emulators->list_of_handlers;
+	cp = &filtered_emulators->ccount;
+	max = SC_MAX_PKCS15_EMULATORS;
+
+	if (*cp > max)
+		return SC_ERROR_INVALID_ARGUMENTS;
+	if (*cp == max)
+		return SC_ERROR_TOO_MANY_OBJECTS;
+
+	for (i = 0; i < *cp; i++) {
+		if (!lst[i])
+			return SC_ERROR_OBJECT_NOT_VALID;
+		if (!strcmp(lst[i]->name, emul_handler->name))
+			return SC_SUCCESS;
+	}
+
+	lst[*cp] = emul_handler;
+	(*cp)++;
+	return SC_SUCCESS;
+}
+
+static int add_emul_list(struct _sc_pkcs15_emulators* filtered_emulators,
+						 struct sc_pkcs15_emulator_handler* emulators)
+{
+	struct sc_pkcs15_emulator_handler* lst;
+	int i, r;
+
+	if (!filtered_emulators || !emulators)
+		return SC_ERROR_INVALID_ARGUMENTS;
+
+	lst = emulators;
+	for(i = 0; lst[i].name; i++) {
+		if ((r = add_emul(filtered_emulators, &lst[i])))
+			return r;
+	}
+	return SC_SUCCESS;
+}
+
+int set_emulators(sc_context_t *ctx, struct _sc_pkcs15_emulators* filtered_emulators, const scconf_list *list,
+				  struct sc_pkcs15_emulator_handler* internal, struct sc_pkcs15_emulator_handler* old)
+{
+	const scconf_list *item;
+	int *cp, i, r, count;
+	
+	LOG_FUNC_CALLED(ctx);
+
+	if (!filtered_emulators || !list || !internal || !old)
+		return SC_ERROR_INVALID_ARGUMENTS;
+
+	cp = &filtered_emulators->ccount;
+	r = SC_SUCCESS;
+
+	for (item = list; item; item = item->next) {
+		if (!item->data)
+			continue;
+
+		if (!strcmp(item->data, "internal")) {
+			if ((r = add_emul_list(filtered_emulators, internal)))
+				goto out;
+		} else if (!strcmp(item->data, "old")) {
+			if ((r = add_emul_list(filtered_emulators, old)))
+				goto out;
+		} else {
+			count = *cp;
+			for (i = 0; internal[i].name; i++) {
+				if (!strcmp(internal[i].name, item->data)) {
+					if ((r = add_emul(filtered_emulators, &internal[i])))
+						goto out;
+					break;
+				}
+			}
+			for (i = 0; old[i].name && count == *cp; i++) {
+				if (!strcmp(old[i].name, item->data)) {
+					if ((r = add_emul(filtered_emulators, &old[i])))
+						goto out;
+					break;
+				}
+			}
+			if (count == *cp)
+				sc_log(ctx, "Warning: Trying to add non-existing emulator '%s'.", item->data);
+		}
+	}
+out:
+	if (r == SC_SUCCESS || r == SC_ERROR_TOO_MANY_OBJECTS) {
+		filtered_emulators->list_of_handlers[*cp] = NULL;
+		if (r == SC_ERROR_TOO_MANY_OBJECTS)
+			sc_log(ctx, "Warning: Number of filtered emulators exceeded %d.", SC_MAX_PKCS15_EMULATORS);
+	}
+	LOG_FUNC_RETURN(ctx, r);
+}
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-emulator-filter.h opensc-0.23.0/src/libopensc/pkcs15-emulator-filter.h
--- opensc-0.22.0/src/libopensc/pkcs15-emulator-filter.h	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/libopensc/pkcs15-emulator-filter.h	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,28 @@
+/*
+ * pkcs15-emulator-filter.h: PKCS #15 emulator filter
+ *
+ * Copyright (C) 2021 Red Hat, Inc.
+ *
+ * Author: Veronika Hanulikova <vhanulik at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+struct _sc_pkcs15_emulators {
+	struct sc_pkcs15_emulator_handler *list_of_handlers[SC_MAX_PKCS15_EMULATORS + 1];
+	int ccount;
+};
+
+int set_emulators(sc_context_t *ctx, struct _sc_pkcs15_emulators* filtered_emulators, const scconf_list *list,
+					struct sc_pkcs15_emulator_handler* builtin, struct sc_pkcs15_emulator_handler* old);
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-esinit.c opensc-0.23.0/src/libopensc/pkcs15-esinit.c
--- opensc-0.22.0/src/libopensc/pkcs15-esinit.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-esinit.c	2022-11-29 09:34:43.000000000 +0100
@@ -58,16 +58,18 @@
 	r = sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0);
 	if (r != SC_SUCCESS)
 		return SC_ERROR_INTERNAL;
-	free(p15card->tokeninfo->serial_number);
-	p15card->tokeninfo->serial_number = strdup(buf);
+
+	set_string(&p15card->tokeninfo->serial_number, buf);
 	if (!p15card->tokeninfo->serial_number)
 		return SC_ERROR_INTERNAL;
 
 	/* the manufacturer ID, in this case Giesecke & Devrient GmbH */
-	free(p15card->tokeninfo->manufacturer_id);
-	p15card->tokeninfo->manufacturer_id = strdup(MANU_ID);
-	if (!p15card->tokeninfo->manufacturer_id)
+	set_string(&p15card->tokeninfo->manufacturer_id, MANU_ID);
+	if (!p15card->tokeninfo->manufacturer_id) {
+		free(p15card->tokeninfo->serial_number);
+		p15card->tokeninfo->serial_number = NULL;
 		return SC_ERROR_INTERNAL;
+	}
 
 	return SC_SUCCESS;
 }
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-esteid2018.c opensc-0.23.0/src/libopensc/pkcs15-esteid2018.c
--- opensc-0.22.0/src/libopensc/pkcs15-esteid2018.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-esteid2018.c	2022-11-29 09:34:43.000000000 +0100
@@ -80,16 +80,15 @@
 		cert_info.id.value[0] = esteid_cert_ids[i];
 		cert_info.id.len = 1;
 		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
-		if (r < 0)
-			LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
+		LOG_TEST_GOTO_ERR(card->ctx, r, "Could not add cert oebjct");
 
 		// Read data from first cert
 		if (i != 0)
 			continue;
 
 		sc_pkcs15_cert_t *cert = NULL;
-		r = sc_pkcs15_read_certificate(p15card, &cert_info, &cert);
-		LOG_TEST_RET(card->ctx, r, "Could not read authentication certificate");
+		r = sc_pkcs15_read_certificate(p15card, &cert_info, 0, &cert);
+		LOG_TEST_GOTO_ERR(card->ctx, r, "Could not read authentication certificate");
 
 		if (cert->key->algorithm == SC_ALGORITHM_EC)
 			field_length = cert->key->u.ec.params.field_length;
@@ -154,20 +153,19 @@
 		}
 
 		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
-		if (r < 0)
-			LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
+		LOG_TEST_GOTO_ERR(card->ctx, r, "Could not add pin object");
 	}
 
 	// trigger PIN counter refresh via pin_cmd
 	struct sc_pkcs15_object *objs[3];
 	r = sc_pkcs15_get_objects(p15card, SC_PKCS15_TYPE_AUTH, objs, 3);
 	if (r != 3) {
-		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
+		sc_log(card->ctx, "Can not get auth objects");
+		goto err;
 	}
 	for (i = 0; i < r; i++) {
 		r = sc_pkcs15_get_pin_info(p15card, objs[i]);
-		if (r < 0)
-			LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
+		LOG_TEST_GOTO_ERR(card->ctx, r, "Could not get pin object");
 	}
 
 	/* add private keys */
@@ -201,11 +199,13 @@
 		prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
 
 		r = sc_pkcs15emu_add_ec_prkey(p15card, &prkey_obj, &prkey_info);
-		if (r < 0)
-			LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
+		LOG_TEST_GOTO_ERR(card->ctx, r, "Could not add private key object");
 	}
 
 	return SC_SUCCESS;
+err:
+	sc_pkcs15_card_clear(p15card);
+	LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
 }
 
 int sc_pkcs15emu_esteid2018_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *aid) {
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-esteid.c opensc-0.23.0/src/libopensc/pkcs15-esteid.c
--- opensc-0.22.0/src/libopensc/pkcs15-esteid.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-esteid.c	2022-11-29 09:34:43.000000000 +0100
@@ -51,11 +51,11 @@
 	/* Select application directory */
 	sc_format_path ("3f00eeee5044", &tmppath);
 	r = sc_select_file (card, &tmppath, NULL);
-	LOG_TEST_RET(card->ctx, r, "select esteid PD failed");
+	LOG_TEST_GOTO_ERR(card->ctx, r, "select esteid PD failed");
 
 	/* read the serial (document number) */
 	r = sc_read_record (card, SC_ESTEID_PD_DOCUMENT_NR, buff, sizeof(buff), SC_RECORD_BY_REC_NR);
-	LOG_TEST_RET(card->ctx, r, "read document number failed");
+	LOG_TEST_GOTO_ERR(card->ctx, r, "read document number failed");
 	buff[MIN((size_t) r, (sizeof buff)-1)] = '\0';
 	set_string(&p15card->tokeninfo->serial_number, (const char *)buff);
 
@@ -85,14 +85,14 @@
 		strlcpy(cert_obj.label, esteid_cert_names[i], sizeof(cert_obj.label));
 		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
 		if (r < 0)
-			return SC_ERROR_INTERNAL;
+			goto err;
 		if (i != 0)
 			continue;
 
 		sc_pkcs15_cert_t *cert = NULL;
-		r = sc_pkcs15_read_certificate(p15card, &cert_info, &cert);
+		r = sc_pkcs15_read_certificate(p15card, &cert_info, 0, &cert);
 		if (r < 0)
-			return SC_ERROR_INTERNAL;
+			goto err;
 		if (cert->key->algorithm == SC_ALGORITHM_EC)
 			field_length = cert->key->u.ec.params.field_length;
 		else
@@ -115,7 +115,7 @@
 	sc_format_path ("3f000016", &tmppath);
 	r = sc_select_file (card, &tmppath, NULL);
 	if (r < 0)
-		return SC_ERROR_INTERNAL;
+		goto err;
 
 	/* add pins */
 	for (i = 0; i < 3; i++) {
@@ -138,7 +138,7 @@
 		/* read the number of tries left for the PIN */
 		r = sc_read_record (card, (unsigned int) i + 1, buff, sizeof(buff), SC_RECORD_BY_REC_NR);
 		if (r < 6)
-			return SC_ERROR_INTERNAL;
+			goto err;
 
 		pin_info.auth_id.len = 1;
 		pin_info.auth_id.value[0] = esteid_pin_authid[i];
@@ -164,7 +164,7 @@
 
 		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
 		if (r < 0)
-			return SC_ERROR_INTERNAL;
+			goto err;
 	}
 
 	/* add private keys */
@@ -205,10 +205,13 @@
 		else
 			r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
 		if (r < 0)
-			return SC_ERROR_INTERNAL;
+			goto err;
 	}
 
 	return SC_SUCCESS;
+err:
+	sc_pkcs15_card_clear(p15card);
+	return SC_ERROR_INTERNAL;
 }
 
 int sc_pkcs15emu_esteid_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *aid)
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-gemsafeGPK.c opensc-0.23.0/src/libopensc/pkcs15-gemsafeGPK.c
--- opensc-0.22.0/src/libopensc/pkcs15-gemsafeGPK.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-gemsafeGPK.c	2022-11-29 09:34:43.000000000 +0100
@@ -223,11 +223,15 @@
 	set_string(&p15card->tokeninfo->manufacturer_id, MANU_ID);
 	/* get serial number */
 	r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
-	if (r != SC_SUCCESS)
+	if (r != SC_SUCCESS) {
+		sc_pkcs15_card_clear(p15card);
 		return SC_ERROR_INTERNAL;
+	}
 	r = sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0);
-	if (r != SC_SUCCESS)
+	if (r != SC_SUCCESS) {
+		sc_pkcs15_card_clear(p15card);
 		return SC_ERROR_INTERNAL;
+	}
 	set_string(&p15card->tokeninfo->serial_number, buf);
 
 	/* test if we have a gemsafe app df */
@@ -243,8 +247,10 @@
 		r = sc_select_file(card, &path, &file);
 	}
 
-	if (r < 0)
+	if (r < 0) {
+		sc_pkcs15_card_clear(p15card);
 		return SC_ERROR_WRONG_CARD;
+	}
 
 	/* we will use dfpath in all other references */
 	dfpath = file->id;
@@ -307,6 +313,7 @@
 	 path.value[3] = dfpath & 0xff; 
 	
 	if (sc_select_file(card, &path, &file) < 0) {
+		sc_pkcs15_card_clear(p15card);
 		return SC_ERROR_WRONG_CARD;
 	}
 
@@ -338,6 +345,7 @@
 		struct sc_pkcs15_cert_info cert_info;
 		struct sc_pkcs15_object    cert_obj;
 		sc_pkcs15_cert_t 		*cert_out;
+		int private_obj;
 
 		memset(&cert_info, 0, sizeof(cert_info));
 		memset(&cert_obj,  0, sizeof(cert_obj));
@@ -398,14 +406,16 @@
 		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
 		if (r < 0) {
 			free(gsdata);
+			sc_pkcs15_card_clear(p15card);
 			return SC_ERROR_INTERNAL;
 		}
 
 		/* now lets see if we have a matching key for this cert */
-		
-		r = sc_pkcs15_read_certificate(p15card, &cert_info, &cert_out);
+		private_obj = cert_obj.flags & SC_PKCS15_CO_FLAG_PRIVATE;
+		r = sc_pkcs15_read_certificate(p15card, &cert_info, private_obj, &cert_out);
 		if (r < 0) {
 			free(gsdata);
+			sc_pkcs15_card_clear(p15card);
 			return SC_ERROR_INTERNAL;
 		}
 
@@ -457,8 +467,10 @@
 		pin_obj.flags = pins[i].obj_flags;
 
 		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
-		if (r < 0)
+		if (r < 0) {
+			sc_pkcs15_card_clear(p15card);
 			return SC_ERROR_INTERNAL;
+		}
 	}
 
 	/* needs work, as we may want to add more then one key */
@@ -501,8 +513,10 @@
 			sc_pkcs15_format_id(prkeys[i].auth_id, &prkey_obj.auth_id);
 
 		r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
-		if (r < 0)
+		if (r < 0) {
+			sc_pkcs15_card_clear(p15card);
 			return SC_ERROR_INTERNAL;
+		}
 	}
 	return SC_SUCCESS;
 }
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-gemsafeV1.c opensc-0.23.0/src/libopensc/pkcs15-gemsafeV1.c
--- opensc-0.22.0/src/libopensc/pkcs15-gemsafeV1.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-gemsafeV1.c	2022-11-29 09:34:43.000000000 +0100
@@ -305,15 +305,16 @@
 
 	sc_log(p15card->card->ctx, "Setting pkcs15 parameters");
 
-	free(p15card->tokeninfo->label);
-	p15card->tokeninfo->label = strdup(APPLET_NAME);
+	set_string(&p15card->tokeninfo->label, APPLET_NAME);
 	if (!p15card->tokeninfo->label)
 		return SC_ERROR_INTERNAL;
 
-	free(p15card->tokeninfo->serial_number);
-	p15card->tokeninfo->serial_number = strdup(DRIVER_SERIAL_NUMBER);
-	if (!p15card->tokeninfo->serial_number)
+	set_string(&p15card->tokeninfo->serial_number, DRIVER_SERIAL_NUMBER);
+	if (!p15card->tokeninfo->serial_number) {
+		free(p15card->tokeninfo->label);
+		p15card->tokeninfo->label = NULL;
 		return SC_ERROR_INTERNAL;
+	}
 
 	/* the GemSAFE applet version number */
 	sc_format_apdu(card, &apdu, SC_APDU_CASE_2_SHORT, 0xca, 0xdf, 0x03);
@@ -325,23 +326,28 @@
 	apdu.lc = 0;
 	apdu.datalen = 0;
 	r = sc_transmit_apdu(card, &apdu);
+	if (r < 0)
+		sc_pkcs15_card_clear(p15card);
 	LOG_TEST_RET(card->ctx, r, "APDU transmit failed");
 
-	if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00)
-		return SC_ERROR_INTERNAL;
-	if (r != SC_SUCCESS)
+	if (apdu.sw1 != 0x90 || apdu.sw2 != 0x00 || r != SC_SUCCESS) {
+		sc_pkcs15_card_clear(p15card);
 		return SC_ERROR_INTERNAL;
+	}
 
 	/* the manufacturer ID, in this case GemPlus */
-	free(p15card->tokeninfo->manufacturer_id);
-	p15card->tokeninfo->manufacturer_id = strdup(MANU_ID);
-	if (!p15card->tokeninfo->manufacturer_id)
+	set_string(&p15card->tokeninfo->manufacturer_id, MANU_ID);
+	if (!p15card->tokeninfo->manufacturer_id) {
+		sc_pkcs15_card_clear(p15card);
 		return SC_ERROR_INTERNAL;
+	}
 
 	/* determine allocated key containers and length of certificates */
 	r = gemsafe_get_cert_len(card);
-	if (r != SC_SUCCESS)
+	if (r != SC_SUCCESS) {
+		sc_pkcs15_card_clear(p15card);
 		return SC_ERROR_INTERNAL;
+	}
 
 	/* set certs */
 	sc_log(p15card->card->ctx, "Setting certificates");
@@ -420,8 +426,10 @@
 	sc_log(p15card->card->ctx, "Selecting application DF");
 	sc_format_path(GEMSAFE_APP_PATH, &path);
 	r = sc_select_file(card, &path, &file);
-	if (r != SC_SUCCESS || !file)
+	if (r != SC_SUCCESS || !file) {
+		sc_pkcs15_card_clear(p15card);
 		return SC_ERROR_INTERNAL;
+	}
 	/* set the application DF */
 	sc_file_free(p15card->file_app);
 	p15card->file_app = file;
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-gids.c opensc-0.23.0/src/libopensc/pkcs15-gids.c
--- opensc-0.22.0/src/libopensc/pkcs15-gids.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-gids.c	2022-11-29 09:34:43.000000000 +0100
@@ -136,8 +136,11 @@
 
 	if (p15card->tokeninfo->label == NULL) {
 		p15card->tokeninfo->label = strdup("GIDS card");
-		if (p15card->tokeninfo->label == NULL)
+		if (p15card->tokeninfo->label == NULL) {
+			free(p15card->tokeninfo->serial_number);
+			p15card->tokeninfo->serial_number = NULL;
 			LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
+		}
 	}
 
 	if ((p15card->tokeninfo->manufacturer_id != NULL) && !strcmp("(unknown)", p15card->tokeninfo->manufacturer_id)) {
@@ -147,8 +150,10 @@
 
 	if (p15card->tokeninfo->manufacturer_id == NULL) {
 		p15card->tokeninfo->manufacturer_id = strdup("www.mysmartlogon.com");
-		if (p15card->tokeninfo->manufacturer_id == NULL)
+		if (p15card->tokeninfo->manufacturer_id == NULL) {
+			sc_pkcs15_card_clear(p15card);
 			LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
+		}
 	}
 	if (p15card->card->type == SC_CARD_TYPE_GIDS_V2) {
 		p15card->tokeninfo->version = 2;
@@ -198,7 +203,7 @@
 	}
 
 	r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
-	LOG_TEST_RET(card->ctx, r, "unable to sc_pkcs15emu_add_pin_obj");
+	LOG_TEST_GOTO_ERR(card->ctx, r, "unable to sc_pkcs15emu_add_pin_obj");
 
 	if (has_puk) {
 		pin_info.auth_id.value[0] = 0x81;
@@ -209,11 +214,11 @@
 		strlcpy(pin_obj.label, "PUK", sizeof(pin_obj.label));
 		pin_obj.auth_id.len = 0;
 		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
-		LOG_TEST_RET(card->ctx, r, "unable to sc_pkcs15emu_add_pin_obj with PUK");
+		LOG_TEST_GOTO_ERR(card->ctx, r, "unable to sc_pkcs15emu_add_pin_obj with PUK");
 	}
 
 	r = sc_card_ctl(card, SC_CARDCTL_GIDS_GET_ALL_CONTAINERS, &recordsnum);
-	LOG_TEST_RET(card->ctx, r, "sc_card_ctl SC_CARDCTL_GIDS_GET_ALL_CONTAINERS");
+	LOG_TEST_GOTO_ERR(card->ctx, r, "sc_card_ctl SC_CARDCTL_GIDS_GET_ALL_CONTAINERS");
 
 	for (i = 0; i < recordsnum; i++) {
 		sc_cardctl_gids_get_container_t container;
@@ -228,6 +233,9 @@
 		sc_pkcs15emu_gids_add_prkey(p15card, &container);
 	}
 	return SC_SUCCESS;
+err:
+	sc_pkcs15_card_clear(p15card);
+	LOG_FUNC_RETURN(card->ctx, r);
 }
 
 int sc_pkcs15emu_gids_init_ex(sc_pkcs15_card_t *p15card,
diff -Nru opensc-0.22.0/src/libopensc/pkcs15.h opensc-0.23.0/src/libopensc/pkcs15.h
--- opensc-0.22.0/src/libopensc/pkcs15.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15.h	2022-11-29 09:34:43.000000000 +0100
@@ -192,24 +192,6 @@
 	sc_pkcs15_bignum_t dmq1;
 };
 
-struct sc_pkcs15_pubkey_dsa {
-	sc_pkcs15_bignum_t pub;
-	sc_pkcs15_bignum_t p;
-	sc_pkcs15_bignum_t q;
-	sc_pkcs15_bignum_t g;
-};
-
-struct sc_pkcs15_prkey_dsa {
-	/* public components */
-	sc_pkcs15_bignum_t pub;
-	sc_pkcs15_bignum_t p;
-	sc_pkcs15_bignum_t q;
-	sc_pkcs15_bignum_t g;
-
-	/* private key */
-	sc_pkcs15_bignum_t priv;
-};
-
 struct sc_pkcs15_gost_parameters {
 	struct sc_object_id key;
 	struct sc_object_id hash;
@@ -253,7 +235,6 @@
 	/* Decoded key */
 	union {
 		struct sc_pkcs15_pubkey_rsa rsa;
-		struct sc_pkcs15_pubkey_dsa dsa;
 		struct sc_pkcs15_pubkey_ec ec;
 		struct sc_pkcs15_pubkey_eddsa eddsa;
 		struct sc_pkcs15_pubkey_gostr3410 gostr3410;
@@ -267,7 +248,6 @@
 
 	union {
 		struct sc_pkcs15_prkey_rsa rsa;
-		struct sc_pkcs15_prkey_dsa dsa;
 		struct sc_pkcs15_prkey_ec ec;
 		struct sc_pkcs15_prkey_eddsa eddsa;
 		struct sc_pkcs15_prkey_gostr3410 gostr3410;
@@ -448,7 +428,6 @@
 
 #define SC_PKCS15_TYPE_PRKEY			0x100
 #define SC_PKCS15_TYPE_PRKEY_RSA		0x101
-#define SC_PKCS15_TYPE_PRKEY_DSA		0x102
 #define SC_PKCS15_TYPE_PRKEY_GOSTR3410		0x103
 #define SC_PKCS15_TYPE_PRKEY_EC		0x104
 #define SC_PKCS15_TYPE_PRKEY_EDDSA		0x105
@@ -456,7 +435,6 @@
 
 #define SC_PKCS15_TYPE_PUBKEY			0x200
 #define SC_PKCS15_TYPE_PUBKEY_RSA		0x201
-#define SC_PKCS15_TYPE_PUBKEY_DSA		0x202
 #define SC_PKCS15_TYPE_PUBKEY_GOSTR3410		0x203
 #define SC_PKCS15_TYPE_PUBKEY_EC		0x204
 #define SC_PKCS15_TYPE_PUBKEY_EDDSA		0x205
@@ -629,6 +607,11 @@
 /* flags suitable for struct sc_pkcs15_card */
 #define SC_PKCS15_CARD_FLAG_EMULATED			0x02000000
 
+/* suitable for struct sc_pkcs15_card.opts.use_file_cache */
+#define SC_PKCS15_OPTS_CACHE_NO_FILES			0
+#define SC_PKCS15_OPTS_CACHE_PUBLIC_FILES		1
+#define SC_PKCS15_OPTS_CACHE_ALL_FILES			2
+
 /* suitable for struct sc_pkcs15_card.opts.private_certificate */
 #define SC_PKCS15_CARD_OPTS_PRIV_CERT_PROTECT		0
 #define SC_PKCS15_CARD_OPTS_PRIV_CERT_IGNORE		1
@@ -676,7 +659,7 @@
 int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card,
 		       const struct sc_pkcs15_object *prkey_obj,
 		       unsigned long flags,
-		       const u8 *in, size_t inlen, u8 *out, size_t outlen);
+		       const u8 *in, size_t inlen, u8 *out, size_t outlen, void *pMechanism);
 
 int sc_pkcs15_derive(struct sc_pkcs15_card *p15card,
 		       const struct sc_pkcs15_object *prkey_obj,
@@ -700,7 +683,19 @@
 int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
 				const struct sc_pkcs15_object *prkey_obj,
 				unsigned long alg_flags, const u8 *in,
-				size_t inlen, u8 *out, size_t outlen);
+				size_t inlen, u8 *out, size_t outlen, void *pMechanism);
+
+int sc_pkcs15_encrypt_sym(struct sc_pkcs15_card *p15card,
+		const struct sc_pkcs15_object *obj,
+		unsigned long flags,
+		const u8 *in, size_t inlen, u8 *out, size_t *outlen,
+		const u8 *param, size_t paramlen);
+
+int sc_pkcs15_decrypt_sym(struct sc_pkcs15_card *p15card,
+		const struct sc_pkcs15_object *obj,
+		unsigned long flags,
+		const u8 *in, size_t inlen, u8 *out, size_t *outlen,
+		const u8 *param, size_t paramlen);
 
 int sc_pkcs15_read_pubkey(struct sc_pkcs15_card *,
 		const struct sc_pkcs15_object *, struct sc_pkcs15_pubkey **);
@@ -708,10 +703,6 @@
 		struct sc_pkcs15_pubkey_rsa *, const u8 *, size_t);
 int sc_pkcs15_encode_pubkey_rsa(struct sc_context *,
 		struct sc_pkcs15_pubkey_rsa *, u8 **, size_t *);
-int sc_pkcs15_decode_pubkey_dsa(struct sc_context *,
-		struct sc_pkcs15_pubkey_dsa *, const u8 *, size_t);
-int sc_pkcs15_encode_pubkey_dsa(struct sc_context *,
-		struct sc_pkcs15_pubkey_dsa *, u8 **, size_t *);
 int sc_pkcs15_decode_pubkey_gostr3410(struct sc_context *,
 		struct sc_pkcs15_pubkey_gostr3410 *, const u8 *, size_t);
 int sc_pkcs15_encode_pubkey_gostr3410(struct sc_context *,
@@ -747,6 +738,7 @@
 
 int sc_pkcs15_read_data_object(struct sc_pkcs15_card *p15card,
 			       const struct sc_pkcs15_data_info *info,
+			       int private_obj,
 			       struct sc_pkcs15_data **data_object_out);
 int sc_pkcs15_find_data_object_by_id(struct sc_pkcs15_card *p15card,
 				     const struct sc_pkcs15_id *id,
@@ -762,6 +754,7 @@
 
 int sc_pkcs15_read_certificate(struct sc_pkcs15_card *card,
 			       const struct sc_pkcs15_cert_info *info,
+			       int private_obj,
 			       struct sc_pkcs15_cert **cert);
 void sc_pkcs15_free_certificate(struct sc_pkcs15_cert *cert);
 int sc_pkcs15_find_cert_by_id(struct sc_pkcs15_card *card,
@@ -933,7 +926,7 @@
 /* Generic file i/o */
 int sc_pkcs15_read_file(struct sc_pkcs15_card *p15card,
 			const struct sc_path *path,
-			u8 **buf, size_t *buflen);
+			u8 **buf, size_t *buflen, int private_data);
 
 /* Caching functions */
 int sc_pkcs15_read_cached_file(struct sc_pkcs15_card *p15card,
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-iasecc.c opensc-0.23.0/src/libopensc/pkcs15-iasecc.c
--- opensc-0.22.0/src/libopensc/pkcs15-iasecc.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-iasecc.c	2022-11-29 09:34:43.000000000 +0100
@@ -51,13 +51,15 @@
 	struct sc_pkcs15_id id;
 	int rv, offs;
 	unsigned flags;
+	int private_obj;
 
 	LOG_FUNC_CALLED(ctx);
 
 	if (!dobj)
 		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
 
-	rv = sc_pkcs15_read_data_object(p15card, (struct sc_pkcs15_data_info *)dobj->data, &ddata);
+	private_obj = dobj->flags & SC_PKCS15_CO_FLAG_PRIVATE;
+	rv = sc_pkcs15_read_data_object(p15card, (struct sc_pkcs15_data_info *)dobj->data, private_obj, &ddata);
 	LOG_TEST_RET(ctx, rv, "Failed to read container DATA object data");
 
 	offs = 0;
@@ -184,12 +186,13 @@
 	count = rv;
 	for(ii=0; ii<count; ii++)   {
 		struct sc_pkcs15_data_info *dinfo = (struct sc_pkcs15_data_info *)dobjs[ii]->data;
+		int private_obj = dobjs[ii]->flags & SC_PKCS15_CO_FLAG_PRIVATE;
 
 		if (strcmp(dinfo->app_label, IASECC_GEMALTO_MD_APPLICATION_NAME))
 			continue;
 
 		if (!strcmp(dobjs[ii]->label, IASECC_GEMALTO_MD_DEFAULT_CONT_LABEL))   {
-			rv = sc_pkcs15_read_data_object(p15card, (struct sc_pkcs15_data_info *)dobjs[ii]->data, &default_guid);
+			rv = sc_pkcs15_read_data_object(p15card, (struct sc_pkcs15_data_info *)dobjs[ii]->data, private_obj, &default_guid);
 			LOG_TEST_RET(ctx, rv, "Failed to read 'default container' DATA object data");
 			break;
 		}
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-idprime.c opensc-0.23.0/src/libopensc/pkcs15-idprime.c
--- opensc-0.22.0/src/libopensc/pkcs15-idprime.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-idprime.c	2022-11-29 09:34:43.000000000 +0100
@@ -110,8 +110,7 @@
 	pin_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
 
 	r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
-	if (r < 0)
-		LOG_FUNC_RETURN(card->ctx, r);
+	LOG_TEST_GOTO_ERR(card->ctx, r, "Can not add pin object");
 
 	/*
 	 * get token name if provided
@@ -133,7 +132,7 @@
 	 */
 	sc_log(card->ctx,  "IDPrime adding certs, pub and priv keys...");
 	r = (card->ops->card_ctl)(card, SC_CARDCTL_IDPRIME_INIT_GET_OBJECTS, &count);
-	LOG_TEST_RET(card->ctx, r, "Can not initiate cert objects.");
+	LOG_TEST_GOTO_ERR(card->ctx, r, "Can not initiate cert objects.");
 
 	for (i = 0; i < count; i++) {
 		struct sc_pkcs15_prkey_info prkey_info;
@@ -146,7 +145,7 @@
 		sc_pkcs15_cert_t *cert_out = NULL;
 
 		r = (card->ops->card_ctl)(card, SC_CARDCTL_IDPRIME_GET_NEXT_OBJECT, &prkey_info);
-		LOG_TEST_RET(card->ctx, r, "Can not get next object");
+		LOG_TEST_GOTO_ERR(card->ctx, r, "Can not get next object");
 
 		memset(&cert_info, 0, sizeof(cert_info));
 		memset(&pubkey_info, 0, sizeof(pubkey_info));
@@ -174,7 +173,7 @@
 		prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
 		sc_pkcs15_format_id(pin_id, &prkey_obj.auth_id);
 
-		r = sc_pkcs15_read_file(p15card, &cert_info.path, &cert_der.value, &cert_der.len);
+		r = sc_pkcs15_read_file(p15card, &cert_info.path, &cert_der.value, &cert_der.len, 0);
 
 		if (r) {
 			sc_log(card->ctx,  "No cert found,i=%d", i);
@@ -196,7 +195,7 @@
 		}
 
 		/* following will find the cached cert in cert_info */
-		r =  sc_pkcs15_read_certificate(p15card, &cert_info, &cert_out);
+		r =  sc_pkcs15_read_certificate(p15card, &cert_info, 0, &cert_out);
 		if (r < 0 || cert_out->key == NULL) {
 			sc_log(card->ctx,  "Failed to read/parse the certificate r=%d",r);
 			if (cert_out != NULL)
@@ -252,14 +251,19 @@
 		if (cert_out->key->algorithm != SC_ALGORITHM_RSA) {
 			sc_log(card->ctx, "unsupported key.algorithm %d", cert_out->key->algorithm);
 			sc_pkcs15_free_certificate(cert_out);
+			free(pubkey_info.direct.spki.value);
 			continue;
 		} else {
 			pubkey_info.modulus_length = cert_out->key->u.rsa.modulus.len * 8;
 			prkey_info.modulus_length = cert_out->key->u.rsa.modulus.len * 8;
 			sc_log(card->ctx,  "adding rsa public key r=%d usage=%x",r, pubkey_info.usage);
 			r = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
-			if (r < 0)
+			if (r < 0) {
+				free(pubkey_info.direct.spki.value);
 				goto fail;
+			}
+			pubkey_info.direct.spki.value = NULL; /* moved to the pubkey object on p15card  */
+			pubkey_info.direct.spki.len = 0;
 			sc_log(card->ctx,  "adding rsa private key r=%d usage=%x",r, prkey_info.usage);
 			r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
 			if (r < 0)
@@ -269,14 +273,20 @@
 		cert_out->key = NULL;
 fail:
 		sc_pkcs15_free_certificate(cert_out);
-		if (r < 0)
-			LOG_FUNC_RETURN(card->ctx, r); /* should not fail */
+		if (r < 0) {
+			(card->ops->card_ctl)(card, SC_CARDCTL_IDPRIME_FINAL_GET_OBJECTS, &count);
+			LOG_TEST_GOTO_ERR(card->ctx, r, "Failed to add object.");
+		}
 
 	}
 	r = (card->ops->card_ctl)(card, SC_CARDCTL_IDPRIME_FINAL_GET_OBJECTS, &count);
-	LOG_TEST_RET(card->ctx, r, "Can not finalize cert objects.");
+	LOG_TEST_GOTO_ERR(card->ctx, r, "Can not finalize cert objects.");
 
 	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+	
+err:
+	sc_pkcs15_card_clear(p15card);
+	LOG_FUNC_RETURN(card->ctx, r);
 }
 
 int sc_pkcs15emu_idprime_init_ex(sc_pkcs15_card_t *p15card,
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-itacns.c opensc-0.23.0/src/libopensc/pkcs15-itacns.c
--- opensc-0.22.0/src/libopensc/pkcs15-itacns.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-itacns.c	2022-11-29 09:34:43.000000000 +0100
@@ -189,7 +189,7 @@
 static int itacns_add_cert(sc_pkcs15_card_t *p15card,
 	int type, int authority, const sc_path_t *path,
 	const sc_pkcs15_id_t *id, const char *label, int obj_flags,
-	int *ext_info_ok, int *key_usage, int *x_key_usage)
+	int *ext_info_ok, int *key_usage, int *x_key_usage, int *modulus_len)
 {
 	int r;
 	/* const char *label = "Certificate"; */
@@ -198,6 +198,7 @@
 #ifdef ENABLE_OPENSSL
 	X509 *x509;
 	sc_pkcs15_cert_t *cert;
+	int private_obj;
 #endif
 
 	SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_NORMAL);
@@ -228,8 +229,8 @@
 
 	/* If we have OpenSSL, read keyUsage */
 #ifdef ENABLE_OPENSSL
-
-	r = sc_pkcs15_read_certificate(p15card, &info, &cert);
+	private_obj = obj_flags & SC_PKCS15_CO_FLAG_PRIVATE;
+	r = sc_pkcs15_read_certificate(p15card, &info, private_obj, &cert);
 	LOG_TEST_RET(p15card->card->ctx, r,
 		"Could not read X.509 certificate");
 
@@ -237,6 +238,11 @@
 		const u8 *throwaway = cert->data.value;
 		x509 = d2i_X509(NULL, &throwaway, cert->data.len);
 	}
+
+	if (cert->key && cert->key->algorithm == SC_ALGORITHM_RSA) {
+		*modulus_len = cert->key->u.rsa.modulus.len * 8;
+	}
+
 	sc_pkcs15_free_certificate(cert);
 	if (!x509) return SC_SUCCESS;
 	X509_check_purpose(x509, -1, 0);
@@ -260,7 +266,7 @@
 
 static int itacns_add_pubkey(sc_pkcs15_card_t *p15card,
 	 const sc_path_t *path, const sc_pkcs15_id_t *id, const char *label,
-	int usage, int ref, int obj_flags, int *modulus_len_out)
+	int usage, int ref, int obj_flags, int modulus_len)
 {
 	int r;
 	sc_pkcs15_pubkey_info_t info;
@@ -279,13 +285,8 @@
 	strlcpy(obj.label, label, sizeof(obj.label));
 	obj.flags		= obj_flags;
 
-	/*
-	 * This is hard-coded, unless unforeseen versions of the CNS
-	 * turn up sometime.
-	 */
-	info.modulus_length = 1024;
+	info.modulus_length = modulus_len;
 
-	*modulus_len_out = info.modulus_length;
 	r = sc_pkcs15emu_add_rsa_pubkey(p15card, &obj, &info);
 	LOG_TEST_RET(p15card->card->ctx, r,
 		"Could not add pub key");
@@ -493,6 +494,7 @@
 	sc_pkcs15_data_info_t dinfo;
 	struct sc_pkcs15_object *objs[32];
 	struct sc_pkcs15_data_info *cinfo;
+	int private_obj;
 
 	for(i=0; i < array_size; i++) {
 		sc_path_t path;
@@ -548,7 +550,8 @@
 		return SC_SUCCESS;
 	}
 
-	rv = sc_pkcs15_read_data_object(p15card, cinfo, &p15_personaldata);
+	private_obj = objs[i]->flags & SC_PKCS15_CO_FLAG_PRIVATE;
+	rv = sc_pkcs15_read_data_object(p15card, cinfo, private_obj, &p15_personaldata);
 	if (rv) {
 		sc_log(p15card->card->ctx,
 			"Could not read EF_DatiPersonali: "
@@ -580,7 +583,7 @@
 	const char *label, int sec_env, sc_pkcs15_id_t *cert_id,
 	const char *pubkey_path, const char *prkey_path,
 	unsigned int pubkey_usage_flags, unsigned int prkey_usage_flags,
-	u8 pin_ref)
+	u8 pin_ref, int modulus_len)
 {
 	int r;
 	sc_path_t path;
@@ -588,15 +591,13 @@
 	char pinlabel[16];
 	int fake_puk_authid, pin_flags;
 
-	/* This is hard-coded, for the time being. */
-	int modulus_length = 1024;
 
 	/* Public key; not really needed */
 	/* FIXME: set usage according to the certificate. */
 	if (pubkey_path) {
 		sc_format_path(pubkey_path, &path);
 		r = itacns_add_pubkey(p15card, &path, cert_id, label,
-			pubkey_usage_flags, sec_env, 0, &modulus_length);
+			pubkey_usage_flags, sec_env, 0, modulus_len);
 		LOG_TEST_RET(p15card->card->ctx, r,
 			"Could not add public key");
 	}
@@ -610,7 +611,7 @@
 		private_path = &path;
 	}
 	r = itacns_add_prkey(p15card, cert_id, label, SC_PKCS15_TYPE_PRKEY_RSA,
-		modulus_length,
+		modulus_len,
 		prkey_usage_flags,
 		private_path, sec_env, cert_id, SC_PKCS15_CO_FLAG_PRIVATE);
 	LOG_TEST_RET(p15card->card->ctx, r,
@@ -661,7 +662,7 @@
 	sc_path_t path;
 	sc_pkcs15_id_t cert_id;
 	int ext_info_ok;
-	int ku = 0, xku = 0;
+	int ku = 0, xku = 0, modulus_len = 0;
 	int pubkey_usage_flags = 0, prkey_usage_flags = 0;
 
 	cert_id.len = 1;
@@ -707,7 +708,7 @@
 	}
 
 	r = itacns_add_cert(p15card, SC_PKCS15_TYPE_CERT_X509, 0,
-		&path, &cert_id, label, 0, &ext_info_ok, &ku, &xku);
+		&path, &cert_id, label, 0, &ext_info_ok, &ku, &xku, &modulus_len);
 	if (r == SC_ERROR_INVALID_ASN1_OBJECT)
 		return 0;
 	LOG_TEST_RET(p15card->card->ctx, r,
@@ -752,7 +753,7 @@
 
 	r = itacns_add_keyset(p15card, label, sec_env, &cert_id,
 		pubkey_path, prkey_path, pubkey_usage_flags, prkey_usage_flags,
-		pin_ref);
+		pin_ref, modulus_len);
 	LOG_TEST_RET(p15card->card->ctx, r,
 		"Could not add keys for this certificate");
 
@@ -827,7 +828,7 @@
 
 	/* Data files */
 	r = itacns_add_data_files(p15card);
-	LOG_TEST_RET(p15card->card->ctx, r,
+	LOG_TEST_GOTO_ERR(p15card->card->ctx, r,
 		"Could not add data files");
 
 	/*** Certificate and keys. ***/
@@ -835,7 +836,7 @@
 	r = itacns_check_and_add_keyset(p15card, "CNS0", cns0_secenv,
 		0, "3F0011001101", "3F003F01", NULL,
 		0x10, &found_certs);
-	LOG_TEST_RET(p15card->card->ctx, r,
+	LOG_TEST_GOTO_ERR(p15card->card->ctx, r,
 		"Could not add CNS0");
 	certificate_count += found_certs;
 
@@ -843,7 +844,7 @@
 	r = itacns_check_and_add_keyset(p15card, "CNS01", 0x21,
 		5, "3F002FFF8228", NULL, "3F002FFF0000",
 		0x10, &found_certs);
-	LOG_TEST_RET(p15card->card->ctx, r,
+	LOG_TEST_GOTO_ERR(p15card->card->ctx, r,
 		"Could not add CNS01");
 	certificate_count += found_certs;
 
@@ -851,7 +852,7 @@
 	r = itacns_check_and_add_keyset(p15card, "CNS1", 0x10,
 		0, "3F0014009010", "3F00140081108010", "3F0014008110",
 		0x1a, &found_certs);
-	LOG_TEST_RET(p15card->card->ctx, r,
+	LOG_TEST_GOTO_ERR(p15card->card->ctx, r,
 		"Could not add CNS1");
 	certificate_count += found_certs;
 
@@ -863,10 +864,14 @@
 	/* Back to Master File */
 	sc_format_path("3F00", &path);
 	r = sc_select_file(p15card->card, &path, NULL);
-	LOG_TEST_RET(p15card->card->ctx, r,
+	LOG_TEST_GOTO_ERR(p15card->card->ctx, r,
 		"Could not select master file again");
 
-	return r;
+	LOG_FUNC_RETURN(p15card->card->ctx, r);
+
+err:
+	sc_pkcs15_card_clear(p15card);
+	LOG_FUNC_RETURN(p15card->card->ctx, r);
 }
 
 int sc_pkcs15emu_itacns_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *aid)
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-jpki.c opensc-0.23.0/src/libopensc/pkcs15-jpki.c
--- opensc-0.22.0/src/libopensc/pkcs15-jpki.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-jpki.c	2022-11-29 09:34:43.000000000 +0100
@@ -90,8 +90,10 @@
 		cert_info.authority = jpki_cert_authority[i];
 		cert_obj.flags = jpki_cert_flags[i];
 		rc = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
-		if (rc < 0)
+		if (rc < 0) {
+			sc_pkcs15_card_clear(p15card);
 			LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
+		}
 
 	}
 
@@ -146,8 +148,10 @@
 		pin_obj.flags = jpki_pin_flags[i];
 
 		rc = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
-		if (rc < 0)
+		if (rc < 0) {
+			sc_pkcs15_card_clear(p15card);
 			LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
+		}
 	}
 
 	/* add private keys */
@@ -182,8 +186,10 @@
 		prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
 
 		rc = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
-		if (rc < 0)
+		if (rc < 0) {
+			sc_pkcs15_card_clear(p15card);
 			LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
+		}
 	}
 
 	/* add public keys */
@@ -213,8 +219,10 @@
 		pubkey_info.path.type = SC_PATH_TYPE_FILE_ID;
 
 		rc = sc_pkcs15emu_add_rsa_pubkey(p15card, &pubkey_obj, &pubkey_info);
-		if (rc < 0)
+		if (rc < 0) {
+			sc_pkcs15_card_clear(p15card);
 			LOG_FUNC_RETURN(card->ctx, SC_ERROR_INTERNAL);
+		}
 	}
 	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
 }
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-nqApplet.c opensc-0.23.0/src/libopensc/pkcs15-nqApplet.c
--- opensc-0.22.0/src/libopensc/pkcs15-nqApplet.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/libopensc/pkcs15-nqApplet.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,229 @@
+/*
+ * PKCS15 emulation for JCOP4 Cards with NQ-Applet
+ *
+ * Copyright (C) 2021 jozsefd <jozsef.dojcsak at gmail.com>
+ *
+ * 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
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "internal.h"
+#include "opensc.h"
+#include "cards.h"
+#include "common/compat_strlcpy.h"
+#include "log.h"
+#include "pkcs15.h"
+
+static const char name_Card[] = "NQ-Applet";
+static const char name_Vendor[] = "NXP";
+
+static int get_nqapplet_certificate(sc_card_t *card, u8 data_id, struct sc_pkcs15_der *cert_info)
+{
+	int rv;
+	u8 buffer[3072];
+	size_t cb_buffer = sizeof(buffer);
+	LOG_FUNC_CALLED(card->ctx);
+
+	rv = sc_get_data(card, data_id, buffer, cb_buffer);
+	LOG_TEST_RET(card->ctx, rv, "GET DATA failed");
+	if (rv == 0) {
+		LOG_TEST_RET(card->ctx, SC_ERROR_FILE_NOT_FOUND, "No certificate data returned");
+	}
+
+	if (cert_info != NULL) {
+		free(cert_info->value);
+		cert_info->value = malloc(rv);
+		if (cert_info->value != NULL) {
+			cert_info->len = rv;
+			memcpy(cert_info->value, buffer, rv);
+		}
+	}
+	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+}
+
+static int add_nqapplet_pin(sc_pkcs15_card_t *p15card, const char *id, u8 reference)
+{
+	int rv;
+	struct sc_pkcs15_auth_info pin_info;
+	struct sc_pkcs15_object pin_obj;
+	sc_card_t *card = p15card->card;
+
+	LOG_FUNC_CALLED(card->ctx);
+
+	memset(&pin_info, 0, sizeof(pin_info));
+	memset(&pin_obj, 0, sizeof(pin_obj));
+
+	sc_pkcs15_format_id(id, &pin_info.auth_id);
+	pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
+	pin_info.attrs.pin.reference = reference;
+	pin_info.attrs.pin.flags = SC_PKCS15_PIN_FLAG_INITIALIZED | SC_PKCS15_PIN_FLAG_CASE_SENSITIVE |
+	                           SC_PKCS15_PIN_TYPE_FLAGS_PIN_GLOBAL | SC_PKCS15_PIN_AUTH_TYPE_PIN;
+	pin_info.attrs.pin.type = SC_PKCS15_PIN_TYPE_UTF8;
+	pin_info.attrs.pin.min_length = 6;
+	pin_info.attrs.pin.stored_length = 6;
+	pin_info.attrs.pin.max_length = 6;
+	pin_info.attrs.pin.pad_char = '\0';
+	pin_info.tries_left = -1; // TODO
+	pin_info.max_tries = 3;
+
+	strlcpy(pin_obj.label, "UserPIN", sizeof(pin_obj.label));
+	pin_obj.flags = SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE;
+
+	rv = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
+	LOG_TEST_RET(card->ctx, rv, "sc_pkcs15emu_add_pin_obj failed");
+
+	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+}
+
+static int add_nqapplet_certificate(sc_pkcs15_card_t *p15card, const char *id, const char *name, u8 data_id)
+{
+	int rv;
+	struct sc_pkcs15_cert_info cert_info;
+	struct sc_pkcs15_object cert_obj;
+	sc_card_t *card = p15card->card;
+
+	LOG_FUNC_CALLED(card->ctx);
+
+	memset(&cert_info, 0, sizeof(cert_info));
+	memset(&cert_obj, 0, sizeof(cert_obj));
+
+	sc_pkcs15_format_id(id, &cert_info.id);
+	rv = get_nqapplet_certificate(card, data_id, &cert_info.value);
+	LOG_TEST_RET(card->ctx, rv, "Failed to get certificate");
+
+	strlcpy(cert_obj.label, name, sizeof(cert_obj.label));
+
+	rv = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
+	LOG_TEST_RET(card->ctx, rv, "sc_pkcs15emu_add_x509_cert failed");
+
+	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+}
+
+static int add_nqapplet_private_key(sc_pkcs15_card_t *p15card, const char *id, int reference,
+                                    const char *name, const char *pin_id, unsigned int usage)
+{
+	int rv;
+	struct sc_pkcs15_prkey_info prkey_info;
+	struct sc_pkcs15_object prkey_obj;
+	sc_card_t *card = p15card->card;
+
+	LOG_FUNC_CALLED(card->ctx);
+
+	memset(&prkey_info, 0, sizeof(prkey_info));
+	memset(&prkey_obj, 0, sizeof(prkey_obj));
+
+	sc_pkcs15_format_id(id, &prkey_info.id);
+	prkey_info.usage = usage;
+	prkey_info.native = 1;
+	prkey_info.key_reference = reference;
+	prkey_info.modulus_length = 3072;
+
+	strlcpy(prkey_obj.label, name, sizeof(prkey_obj.label));
+	prkey_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
+	sc_pkcs15_format_id(pin_id, &prkey_obj.auth_id);
+
+	rv = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
+	LOG_TEST_RET(card->ctx, rv, "sc_pkcs15emu_add_rsa_prkey failed");
+
+	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+}
+
+static int add_nqapplet_objects(sc_pkcs15_card_t *p15card)
+{
+	int rv;
+	sc_card_t *card = p15card->card;
+
+	LOG_FUNC_CALLED(card->ctx);
+
+	// 1) User PIN
+	rv = add_nqapplet_pin(p15card, "1", 0x01);
+	LOG_TEST_RET(card->ctx, rv, "Failed to add PIN 1");
+
+	// 2.1) C.CH.Auth
+	rv = add_nqapplet_certificate(p15card, "1", "C.CH.Auth", 0x00);
+	LOG_TEST_RET(card->ctx, rv, "Failed to add Auth. certificate");
+
+	// 2.2) PrK.CH.Auth
+	rv = add_nqapplet_private_key(p15card, "1", 0x01, "PrK.CH.Auth", "1",
+	                              SC_PKCS15_PRKEY_USAGE_SIGN | SC_PKCS15_PRKEY_USAGE_DECRYPT);
+	LOG_TEST_RET(card->ctx, rv, "Failed to add Auth. private key");
+
+	// 3.1) C.CH.Encr
+	rv = add_nqapplet_certificate(p15card, "2", "C.CH.Encr", 0x01);
+	LOG_TEST_RET(card->ctx, rv, "Failed to add Encr. certificate");
+
+	// 3.2) PrK.CH.Encr
+	rv = add_nqapplet_private_key(p15card, "2", 0x02, "PrK.CH.Encr", "1", SC_PKCS15_PRKEY_USAGE_DECRYPT);
+	LOG_TEST_RET(card->ctx, rv, "Failed to add Encr. private key");
+
+	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
+}
+
+int sc_pkcs15emu_nqapplet_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *aid)
+{
+	int rv = SC_ERROR_WRONG_CARD;
+	sc_context_t *ctx;
+	sc_card_t *card;
+
+	if (!p15card || !p15card->card || !p15card->card->ctx) {
+		return SC_ERROR_INVALID_ARGUMENTS;
+	}
+
+	card = p15card->card;
+	ctx = card->ctx;
+
+	SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL);
+
+	if (card->type != SC_CARD_TYPE_NQ_APPLET) {
+		sc_log(p15card->card->ctx, "Unsupported card type: %d", card->type);
+		return SC_ERROR_WRONG_CARD;
+	}
+
+	rv = add_nqapplet_objects(p15card);
+	LOG_TEST_GOTO_ERR(ctx, rv, "Failed to add PKCS15");
+
+	if (aid != NULL) {
+		struct sc_file *file = sc_file_new();
+		if (file != NULL) {
+			/* PKCS11 depends on the file_app object, provide MF */
+			sc_format_path("3f00", &file->path);
+			sc_file_free(p15card->file_app);
+			p15card->file_app = file;
+		}
+	}
+
+	sc_pkcs15_free_tokeninfo(p15card->tokeninfo);
+
+	p15card->tokeninfo = sc_pkcs15_tokeninfo_new();
+	if (p15card->tokeninfo == NULL) {
+		rv = SC_ERROR_OUT_OF_MEMORY;
+		LOG_TEST_GOTO_ERR(ctx, rv, "unable to create tokeninfo struct");
+	} else {
+		char serial_hex[SC_MAX_SERIALNR * 2 + 2];
+
+		sc_bin_to_hex(card->serialnr.value, card->serialnr.len, serial_hex, sizeof(serial_hex), 0);
+		set_string(&p15card->tokeninfo->serial_number, serial_hex);
+		set_string(&p15card->tokeninfo->label, name_Card);
+		set_string(&p15card->tokeninfo->manufacturer_id, name_Vendor);
+		p15card->tokeninfo->flags = SC_PKCS15_TOKEN_READONLY;
+	}
+
+	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
+err:
+	sc_pkcs15_card_clear(p15card);
+	LOG_FUNC_RETURN(ctx, rv);
+}
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-oberthur.c opensc-0.23.0/src/libopensc/pkcs15-oberthur.c
--- opensc-0.22.0/src/libopensc/pkcs15-oberthur.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-oberthur.c	2022-11-29 09:34:43.000000000 +0100
@@ -1033,7 +1033,7 @@
 
 	sc_format_path(AWP_PIN_DF, &path);
 	rv = sc_select_file(card, &path, NULL);
-	LOG_TEST_RET(ctx, rv, "Oberthur init failed: cannot select PIN dir");
+	LOG_TEST_GOTO_ERR(ctx, rv, "Oberthur init failed: cannot select PIN dir");
 
 	tries_left = -1;
 	rv = sc_verify(card, SC_AC_CHV, sopin_reference, (unsigned char *)"", 0, &tries_left);
@@ -1042,7 +1042,7 @@
 		rv = sc_verify(card, SC_AC_CHV, sopin_reference, (unsigned char *)"", 0, &tries_left);
 	}
 	if (rv && rv != SC_ERROR_PIN_CODE_INCORRECT)
-		LOG_TEST_RET(ctx, rv, "Invalid state of SO-PIN");
+		LOG_TEST_GOTO_ERR(ctx, rv, "Invalid state of SO-PIN");
 
 	/* add PIN */
 	memset(&auth_info, 0, sizeof(auth_info));
@@ -1071,7 +1071,7 @@
 	sc_log(ctx, "Add PIN(%s,auth_id:%s,reference:%i)", obj.label,
 			sc_pkcs15_print_id(&auth_info.auth_id), auth_info.attrs.pin.reference);
 	rv = sc_pkcs15emu_add_pin_obj(p15card, &obj, &auth_info);
-	LOG_TEST_RET(ctx, rv, "Oberthur init failed: cannot add PIN object");
+	LOG_TEST_GOTO_ERR(ctx, rv, "Oberthur init failed: cannot add PIN object");
 
 	tries_left = -1;
 	rv = sc_verify(card, SC_AC_CHV, 0x81, (unsigned char *)"", 0, &tries_left);
@@ -1115,10 +1115,10 @@
 		sc_log(ctx, "Add PIN(%s,auth_id:%s,reference:%i)", obj.label,
 				sc_pkcs15_print_id(&auth_info.auth_id), auth_info.attrs.pin.reference);
 		rv = sc_pkcs15emu_add_pin_obj(p15card, &obj, &auth_info);
-		LOG_TEST_RET(ctx, rv, "Oberthur init failed: cannot add PIN object");
+		LOG_TEST_GOTO_ERR(ctx, rv, "Oberthur init failed: cannot add PIN object");
 	}
 	else if (rv != SC_ERROR_DATA_OBJECT_NOT_FOUND)    {
-		LOG_TEST_RET(ctx, rv, "Oberthur init failed: cannot verify PIN");
+		LOG_TEST_GOTO_ERR(ctx, rv, "Oberthur init failed: cannot verify PIN");
 	}
 
 	for (ii=0; oberthur_infos[ii].name; ii++)   {
@@ -1126,17 +1126,21 @@
 		free(oberthur_infos[ii].content);
 		rv = sc_oberthur_read_file(p15card, oberthur_infos[ii].path,
 				&oberthur_infos[ii].content, &oberthur_infos[ii].len, 1);
-		LOG_TEST_RET(ctx, rv, "Oberthur init failed: read oberthur file error");
+		LOG_TEST_GOTO_ERR(ctx, rv, "Oberthur init failed: read oberthur file error");
 
 		sc_log(ctx,
 		       "Oberthur init: parse %s file, content length %"SC_FORMAT_LEN_SIZE_T"u",
 		       oberthur_infos[ii].name, oberthur_infos[ii].len);
 		rv = oberthur_infos[ii].parser(p15card, oberthur_infos[ii].content, oberthur_infos[ii].len,
 				oberthur_infos[ii].postpone_allowed);
-		LOG_TEST_RET(ctx, rv, "Oberthur init failed: parse error");
+		LOG_TEST_GOTO_ERR(ctx, rv, "Oberthur init failed: parse error");
 	}
 
 	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
+
+err:
+	sc_pkcs15_card_clear(p15card);
+	LOG_FUNC_RETURN(ctx, rv);
 }
 
 
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-openpgp.c opensc-0.23.0/src/libopensc/pkcs15-openpgp.c
--- opensc-0.22.0/src/libopensc/pkcs15-openpgp.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-openpgp.c	2022-11-29 09:34:43.000000000 +0100
@@ -32,6 +32,7 @@
 #include "internal.h"
 #include "pkcs15.h"
 #include "log.h"
+#include "card-openpgp.h"
 
 static int sc_pkcs15emu_openpgp_add_data(sc_pkcs15_card_t *);
 
@@ -44,6 +45,7 @@
 				| SC_PKCS15_PIN_FLAG_SO_PIN)
 
 #define PGP_NUM_PRIVDO       4
+#define PGP_MAX_NUM_CERTS    3
 
 typedef struct _pgp_pin_cfg {
 	const char	*label;
@@ -93,12 +95,25 @@
 	int		pubkey_usage;
 } pgp_key_cfg_t;
 
+typedef struct cdata_st {
+	const char *label;
+	int	    authority;
+	const char *path;
+	const char *id;
+	int         obj_flags;
+} cdata;
+
 static const pgp_key_cfg_t key_cfg[3] = {
 	{ "Signature key",      "B601", 1, PGP_SIG_PRKEY_USAGE,  PGP_SIG_PUBKEY_USAGE  },
 	{ "Encryption key",     "B801", 2, PGP_ENC_PRKEY_USAGE,  PGP_ENC_PUBKEY_USAGE  },
 	{ "Authentication key", "A401", 2, PGP_AUTH_PRKEY_USAGE | PGP_ENC_PRKEY_USAGE, PGP_AUTH_PUBKEY_USAGE | PGP_ENC_PUBKEY_USAGE }
 };
 
+static const cdata certs[PGP_MAX_NUM_CERTS] = {
+	{"AUT certificate", 0, "3F007F21", "3", SC_PKCS15_CO_FLAG_MODIFIABLE},
+	{"DEC certificate", 0, "3F007F21", "2", SC_PKCS15_CO_FLAG_MODIFIABLE},
+	{"SIG certificate", 0, "3F007F21", "1", SC_PKCS15_CO_FLAG_MODIFIABLE}
+};
 
 typedef struct _pgp_manuf_map {
 	unsigned short		id;
@@ -212,7 +227,8 @@
 	if (r != 7) {
 		sc_log(ctx, 
 			"CHV status bytes have unexpected length (expected 7, got %d)\n", r);
-		return SC_ERROR_OBJECT_NOT_VALID;
+		r = SC_ERROR_OBJECT_NOT_VALID;
+		goto failed;
 	}
 
 	/* Add PIN codes */
@@ -246,8 +262,10 @@
 		}
 
 		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
-		if (r < 0)
-			return SC_ERROR_INTERNAL;
+		if (r < 0) {
+			r = SC_ERROR_INTERNAL;
+			goto failed;
+		}
 	}
 
 	/* Get private key finger prints from DO 006E/0073/00C5:
@@ -261,7 +279,8 @@
 	if (r < 60) {
 		sc_log(ctx,
 			"finger print bytes have unexpected length (expected 60, got %d)\n", r);
-		return SC_ERROR_OBJECT_NOT_VALID;
+		r = SC_ERROR_OBJECT_NOT_VALID;
+		goto failed;
 	}
 
 	sc_log(ctx, "Adding private keys");
@@ -388,8 +407,10 @@
 					cxdata[0], r);
 			}
 
-			if (r < 0)
-				return SC_ERROR_INTERNAL;
+			if (r < 0) {
+				r = SC_ERROR_INTERNAL;
+				goto failed;
+			}
 		}
 	}
 
@@ -510,8 +531,10 @@
 					cxdata[0], r);
 			}
 
-			if (r < 0)
-				return SC_ERROR_INTERNAL;
+			if (r < 0) {
+				r = SC_ERROR_INTERNAL;
+				goto failed;
+			}
 		}
 	}
 
@@ -521,26 +544,63 @@
 	if (r < 0)
 		goto failed;
 
-	/* If DO 7F21 holds data, we declare a cert object for pkcs15 */
-	if (file->size > 0) {
+	for(u8 i=0; i<PGP_MAX_NUM_CERTS; i++) {
 		struct sc_pkcs15_cert_info cert_info;
 		struct sc_pkcs15_object    cert_obj;
+		u8* buffer = malloc(MAX_OPENPGP_DO_SIZE);
+		int resp_len = 0;
+
+		if (buffer == NULL)
+			goto failed;
 
 		memset(&cert_info, 0, sizeof(cert_info));
 		memset(&cert_obj,  0, sizeof(cert_obj));
 
+		/* only try to SELECT DATA for OpenPGP >= v3 */
+		if (card->type >= SC_CARD_TYPE_OPENPGP_V3) {
+			r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_SELECT_DATA, &i);
+			if (r < 0) {
+				free(buffer);
+				LOG_TEST_RET(card->ctx, r, "Failed OpenPGP - select data");
+			}
+		}
+		sc_format_path(certs[i].path, &cert_info.path);
+
 		/* Certificate ID. We use the same ID as the authentication key */
-		cert_info.id.value[0] = 3;
-		cert_info.id.len = 1;
-		/* Authority, flag is zero */
-		/* The path following which PKCS15 will find the content of the object */
-		sc_format_path("3F007F21", &cert_info.path);
+		sc_pkcs15_format_id(certs[i].id, &cert_info.id);
+
+		resp_len = sc_get_data(card, 0x7F21, buffer, MAX_OPENPGP_DO_SIZE);
+
+		/* Response length => free buffer and continue with next id */
+		if (resp_len == 0) {
+			free(buffer);
+			continue;
+		}
+
+		/* Catch error during sc_get_data */
+		if (resp_len < 0) {
+			free(buffer);
+			goto failed;
+		}
+
+		/* Assemble certificate info struct, based on `certs` array */
+		cert_info.value.len = resp_len;
+		cert_info.value.value = buffer;
+		cert_info.authority = certs[i].authority;
+		cert_obj.flags = certs[i].obj_flags;
+
 		/* Object label */
-		strlcpy(cert_obj.label, "Cardholder certificate", sizeof(cert_obj.label));
+		strlcpy(cert_obj.label, certs[i].label, sizeof(cert_obj.label));
 
 		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
-		if (r < 0)
+		if (r < 0) {
+			free(buffer);
 			goto failed;
+		}
+
+		/* only iterate, for OpenPGP >= v3, thus break on < v3 */
+		if (card->type < SC_CARD_TYPE_OPENPGP_V3)
+			break;
 	}
 
 	/* Add PKCS#15 DATA objects from other OpenPGP card DOs. The return
@@ -553,9 +613,9 @@
 		sc_log(card->ctx,
 				"Failed to initialize OpenPGP emulation: %s\n",
 				sc_strerror(r));
+		sc_pkcs15_card_clear(p15card);
 	}
 	sc_file_free(file);
-
 	LOG_FUNC_RETURN(ctx, r);
 }
 
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-piv.c opensc-0.23.0/src/libopensc/pkcs15-piv.c
--- opensc-0.22.0/src/libopensc/pkcs15-piv.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-piv.c	2022-11-29 09:34:43.000000000 +0100
@@ -144,6 +144,8 @@
 	r = sc_card_ctl(p15card->card, SC_CARDCTL_GET_SERIALNR, &serialnr);
 	if (r)
 		return r;
+	if (serialnr.len > SC_MAX_SERIALNR)
+		return SC_ERROR_INTERNAL;
 
 	memset(guid_bin, 0, sizeof(guid_bin));
 	memset(out, 0, *out_size);
@@ -719,6 +721,7 @@
 		struct sc_pkcs15_object    cert_obj;
 		sc_pkcs15_der_t   cert_der;
 		sc_pkcs15_cert_t *cert_out = NULL;
+		int private_obj;
 		
 		ckis[i].cert_found = 0;
 		ckis[i].key_alg = -1;
@@ -748,7 +751,8 @@
 			continue;
 		}
 
-		r = sc_pkcs15_read_file(p15card, &cert_info.path, &cert_der.value, &cert_der.len);
+		private_obj = cert_obj.flags & SC_PKCS15_CO_FLAG_PRIVATE;
+		r = sc_pkcs15_read_file(p15card, &cert_info.path, &cert_der.value, &cert_der.len, private_obj);
 
 		if (r) {
 			sc_log(card->ctx,  "No cert found,i=%d", i);
@@ -761,12 +765,13 @@
 		if (cert_der.value) {
 			cert_info.value.value = cert_der.value;
 			cert_info.value.len = cert_der.len;
-			if (!p15card->opts.use_file_cache) {
+			if (!p15card->opts.use_file_cache
+			    || (private_obj && !(p15card->opts.use_file_cache & SC_PKCS15_OPTS_CACHE_ALL_FILES))) {
 				cert_info.path.len = 0; /* use in mem cert from now on */
 			}
 		}
 		/* following will find the cached cert in cert_info */
-		r =  sc_pkcs15_read_certificate(p15card, &cert_info, &cert_out);
+		r =  sc_pkcs15_read_certificate(p15card, &cert_info, private_obj, &cert_out);
 		if (r < 0 || cert_out == NULL || cert_out->key == NULL) {
 			sc_log(card->ctx,  "Failed to read/parse the certificate r=%d",r);
 			if (cert_out != NULL)
@@ -1217,6 +1222,7 @@
 	for (i = 0; i < PIV_NUM_CERTS_AND_KEYS; i++) {
 		sc_pkcs15_free_pubkey(ckis[i].pubkey_from_cert);
 	}
+	sc_pkcs15_card_clear(p15card);
 	LOG_FUNC_RETURN(card->ctx, r);
 }
 
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-prkey.c opensc-0.23.0/src/libopensc/pkcs15-prkey.c
--- opensc-0.22.0/src/libopensc/pkcs15-prkey.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-prkey.c	2022-11-29 09:34:43.000000000 +0100
@@ -35,7 +35,11 @@
 #include <openssl/err.h>
 #include <openssl/bn.h>
 #include <openssl/rsa.h>
-#include <openssl/dsa.h>
+#include <openssl/evp.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+# include <openssl/core_names.h>
+# include <openssl/param_build.h>
+#endif
 #ifndef OPENSSL_NO_EC
 #include <openssl/ec.h>
 #endif
@@ -119,31 +123,6 @@
 	{ NULL, 0, 0, 0, NULL, NULL }
 };
 
-#define C_ASN1_DSAKEY_I_P_ATTR_SIZE 2
-static const struct sc_asn1_entry c_asn1_dsakey_i_p_attr[C_ASN1_DSAKEY_I_P_ATTR_SIZE] = {
-	{ "path",	SC_ASN1_PATH, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
-	{ NULL, 0, 0, 0, NULL, NULL }
-};
-
-#define C_ASN1_DSAKEY_VALUE_ATTR_SIZE 3
-static const struct sc_asn1_entry c_asn1_dsakey_value_attr[C_ASN1_DSAKEY_VALUE_ATTR_SIZE] = {
-	{ "path",	SC_ASN1_PATH, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
-	{ "pathProtected",SC_ASN1_STRUCT, SC_ASN1_CTX | 1 | SC_ASN1_CONS, 0, NULL, NULL},
-	{ NULL, 0, 0, 0, NULL, NULL }
-};
-
-#define C_ASN1_DSAKEY_ATTR_SIZE 2
-static const struct sc_asn1_entry c_asn1_dsakey_attr[C_ASN1_DSAKEY_ATTR_SIZE] = {
-	{ "value",	SC_ASN1_CHOICE, 0, 0, NULL, NULL },
-	{ NULL, 0, 0, 0, NULL, NULL }
-};
-
-#define C_ASN1_PRK_DSA_ATTR_SIZE 2
-static const struct sc_asn1_entry c_asn1_prk_dsa_attr[C_ASN1_PRK_DSA_ATTR_SIZE] = {
-	{ "privateDSAKeyAttributes", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
-	{ NULL, 0, 0, 0, NULL, NULL }
-};
-
 /*
  * The element fieldSize is a proprietary extension to ISO 7816-15, providing to the middleware
  * the size of the underlying ECC field. This value is required for determine a proper size for
@@ -163,11 +142,10 @@
 	{ NULL, 0, 0, 0, NULL, NULL }
 };
 
-#define C_ASN1_PRKEY_SIZE 5
+#define C_ASN1_PRKEY_SIZE 4
 static const struct sc_asn1_entry c_asn1_prkey[C_ASN1_PRKEY_SIZE] = {
 	{ "privateRSAKey", SC_ASN1_PKCS15_OBJECT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
 	{ "privateECCKey", SC_ASN1_PKCS15_OBJECT,  0 | SC_ASN1_CTX | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
-	{ "privateDSAKey", SC_ASN1_PKCS15_OBJECT,  2 | SC_ASN1_CTX | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
 	{ "privateGOSTR3410Key", SC_ASN1_PKCS15_OBJECT, 4 | SC_ASN1_CTX | SC_ASN1_CONS, SC_ASN1_OPTIONAL, NULL, NULL },
 	{ NULL, 0, 0, 0, NULL, NULL }
 };
@@ -187,10 +165,6 @@
 	struct sc_asn1_entry asn1_com_prkey_attr[C_ASN1_COM_PRKEY_ATTR_SIZE];
 	struct sc_asn1_entry asn1_rsakey_attr[C_ASN1_RSAKEY_ATTR_SIZE];
 	struct sc_asn1_entry asn1_prk_rsa_attr[C_ASN1_PRK_RSA_ATTR_SIZE];
-	struct sc_asn1_entry asn1_dsakey_attr[C_ASN1_DSAKEY_ATTR_SIZE];
-	struct sc_asn1_entry asn1_prk_dsa_attr[C_ASN1_PRK_DSA_ATTR_SIZE];
-	struct sc_asn1_entry asn1_dsakey_i_p_attr[C_ASN1_DSAKEY_I_P_ATTR_SIZE];
-	struct sc_asn1_entry asn1_dsakey_value_attr[C_ASN1_DSAKEY_VALUE_ATTR_SIZE];
 	struct sc_asn1_entry asn1_gostr3410key_attr[C_ASN1_GOSTR3410KEY_ATTR_SIZE];
 	struct sc_asn1_entry asn1_prk_gostr3410_attr[C_ASN1_PRK_GOSTR3410_ATTR_SIZE];
 	struct sc_asn1_entry asn1_ecckey_attr[C_ASN1_ECCKEY_ATTR];
@@ -198,7 +172,6 @@
 	struct sc_asn1_entry asn1_prkey[C_ASN1_PRKEY_SIZE];
 	struct sc_asn1_entry asn1_supported_algorithms[C_ASN1_SUPPORTED_ALGORITHMS_SIZE];
 	struct sc_asn1_pkcs15_object rsa_prkey_obj = {obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_rsa_attr};
-	struct sc_asn1_pkcs15_object dsa_prkey_obj = {obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_dsa_attr};
 	struct sc_asn1_pkcs15_object gostr3410_prkey_obj = {obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_gostr3410_attr};
 	struct sc_asn1_pkcs15_object ecc_prkey_obj = { obj, asn1_com_key_attr, asn1_com_prkey_attr, asn1_prk_ecc_attr };
 
@@ -207,10 +180,6 @@
 
 	sc_copy_asn1_entry(c_asn1_prk_rsa_attr, asn1_prk_rsa_attr);
 	sc_copy_asn1_entry(c_asn1_rsakey_attr, asn1_rsakey_attr);
-	sc_copy_asn1_entry(c_asn1_prk_dsa_attr, asn1_prk_dsa_attr);
-	sc_copy_asn1_entry(c_asn1_dsakey_attr, asn1_dsakey_attr);
-	sc_copy_asn1_entry(c_asn1_dsakey_value_attr, asn1_dsakey_value_attr);
-	sc_copy_asn1_entry(c_asn1_dsakey_i_p_attr, asn1_dsakey_i_p_attr);
 	sc_copy_asn1_entry(c_asn1_prk_gostr3410_attr, asn1_prk_gostr3410_attr);
 	sc_copy_asn1_entry(c_asn1_gostr3410key_attr, asn1_gostr3410key_attr);
 	sc_copy_asn1_entry(c_asn1_prk_ecc_attr, asn1_prk_ecc_attr);
@@ -221,22 +190,15 @@
 
 	sc_format_asn1_entry(asn1_prkey + 0, &rsa_prkey_obj, NULL, 0);
 	sc_format_asn1_entry(asn1_prkey + 1, &ecc_prkey_obj, NULL, 0);
-	sc_format_asn1_entry(asn1_prkey + 2, &dsa_prkey_obj, NULL, 0);
-	sc_format_asn1_entry(asn1_prkey + 3, &gostr3410_prkey_obj, NULL, 0);
+	sc_format_asn1_entry(asn1_prkey + 2, &gostr3410_prkey_obj, NULL, 0);
 
 	sc_format_asn1_entry(asn1_prk_rsa_attr + 0, asn1_rsakey_attr, NULL, 0);
-	sc_format_asn1_entry(asn1_prk_dsa_attr + 0, asn1_dsakey_attr, NULL, 0);
 	sc_format_asn1_entry(asn1_prk_gostr3410_attr + 0, asn1_gostr3410key_attr, NULL, 0);
 	sc_format_asn1_entry(asn1_prk_ecc_attr + 0, asn1_ecckey_attr, NULL, 0);
 
 	sc_format_asn1_entry(asn1_rsakey_attr + 0, &info.path, NULL, 0);
 	sc_format_asn1_entry(asn1_rsakey_attr + 1, &info.modulus_length, NULL, 0);
 
-	sc_format_asn1_entry(asn1_dsakey_attr + 0, asn1_dsakey_value_attr, NULL, 0);
-	sc_format_asn1_entry(asn1_dsakey_value_attr + 0, &info.path, NULL, 0);
-	sc_format_asn1_entry(asn1_dsakey_value_attr + 1, asn1_dsakey_i_p_attr, NULL, 0);
-	sc_format_asn1_entry(asn1_dsakey_i_p_attr + 0, &info.path, NULL, 0);
-
 	sc_format_asn1_entry(asn1_gostr3410key_attr + 0, &info.path, NULL, 0);
 	sc_format_asn1_entry(asn1_gostr3410key_attr + 1, &gostr3410_params[0], NULL, 0);
 	sc_format_asn1_entry(asn1_gostr3410key_attr + 2, &gostr3410_params[1], NULL, 0);
@@ -274,12 +236,6 @@
 		obj->type = SC_PKCS15_TYPE_PRKEY_EC;
 	}
 	else if (asn1_prkey[2].flags & SC_ASN1_PRESENT) {
-		obj->type = SC_PKCS15_TYPE_PRKEY_DSA;
-		/* If the value was indirect-protected, mark the path */
-		if (asn1_dsakey_i_p_attr[0].flags & SC_ASN1_PRESENT)
-			info.path.type = SC_PATH_TYPE_PATH_PROT;
-	}
-	else if (asn1_prkey[3].flags & SC_ASN1_PRESENT) {
 		/* FIXME proper handling of gost parameters without the need of
 		 * allocating data here. this would also make sc_pkcs15_free_key_params
 		 * obsolete */
@@ -302,7 +258,7 @@
 	}
 	else {
 		r = SC_ERROR_INVALID_ASN1_OBJECT;
-		LOG_TEST_GOTO_ERR(ctx, r, "Neither RSA or DSA or GOSTR3410 or ECC key in PrKDF entry.");
+		LOG_TEST_GOTO_ERR(ctx, r, "Neither RSA or GOSTR3410 or ECC key in PrKDF entry.");
 	}
 
 	if (!p15card->app || !p15card->app->ddo.aid.len) {
@@ -382,10 +338,6 @@
 	struct sc_asn1_entry asn1_com_prkey_attr[C_ASN1_COM_PRKEY_ATTR_SIZE];
 	struct sc_asn1_entry asn1_rsakey_attr[C_ASN1_RSAKEY_ATTR_SIZE];
 	struct sc_asn1_entry asn1_prk_rsa_attr[C_ASN1_PRK_RSA_ATTR_SIZE];
-	struct sc_asn1_entry asn1_dsakey_attr[C_ASN1_DSAKEY_ATTR_SIZE];
-	struct sc_asn1_entry asn1_prk_dsa_attr[C_ASN1_PRK_DSA_ATTR_SIZE];
-	struct sc_asn1_entry asn1_dsakey_value_attr[C_ASN1_DSAKEY_VALUE_ATTR_SIZE];
-	struct sc_asn1_entry asn1_dsakey_i_p_attr[C_ASN1_DSAKEY_I_P_ATTR_SIZE];
 	struct sc_asn1_entry asn1_gostr3410key_attr[C_ASN1_GOSTR3410KEY_ATTR_SIZE];
 	struct sc_asn1_entry asn1_prk_gostr3410_attr[C_ASN1_PRK_GOSTR3410_ATTR_SIZE];
 	struct sc_asn1_entry asn1_ecckey_attr[C_ASN1_ECCKEY_ATTR];
@@ -396,10 +348,6 @@
 		(struct sc_pkcs15_object *) obj, asn1_com_key_attr,
 		asn1_com_prkey_attr, asn1_prk_rsa_attr
 	};
-	struct sc_asn1_pkcs15_object dsa_prkey_obj = {
-		(struct sc_pkcs15_object *) obj, asn1_com_key_attr,
-		asn1_com_prkey_attr, asn1_prk_dsa_attr
-	};
 	struct sc_asn1_pkcs15_object gostr3410_prkey_obj = {
 		(struct sc_pkcs15_object *) obj,
 		asn1_com_key_attr, asn1_com_prkey_attr,
@@ -420,10 +368,6 @@
 
 	sc_copy_asn1_entry(c_asn1_prk_rsa_attr, asn1_prk_rsa_attr);
 	sc_copy_asn1_entry(c_asn1_rsakey_attr, asn1_rsakey_attr);
-	sc_copy_asn1_entry(c_asn1_prk_dsa_attr, asn1_prk_dsa_attr);
-	sc_copy_asn1_entry(c_asn1_dsakey_attr, asn1_dsakey_attr);
-	sc_copy_asn1_entry(c_asn1_dsakey_value_attr, asn1_dsakey_value_attr);
-	sc_copy_asn1_entry(c_asn1_dsakey_i_p_attr, asn1_dsakey_i_p_attr);
 	sc_copy_asn1_entry(c_asn1_prk_gostr3410_attr, asn1_prk_gostr3410_attr);
 	sc_copy_asn1_entry(c_asn1_gostr3410key_attr, asn1_gostr3410key_attr);
 	sc_copy_asn1_entry(c_asn1_prk_ecc_attr, asn1_prk_ecc_attr);
@@ -445,21 +389,8 @@
 		sc_format_asn1_entry(asn1_ecckey_attr + 0, &prkey->path, NULL, 1);
 		sc_format_asn1_entry(asn1_ecckey_attr + 1, &prkey->field_length, NULL, 1);
 		break;
-	case SC_PKCS15_TYPE_PRKEY_DSA:
-		sc_format_asn1_entry(asn1_prkey + 2, &dsa_prkey_obj, NULL, 1);
-		sc_format_asn1_entry(asn1_prk_dsa_attr + 0, asn1_dsakey_value_attr, NULL, 1);
-		if (prkey->path.type != SC_PATH_TYPE_PATH_PROT) {
-			/* indirect: just add the path */
-			sc_format_asn1_entry(asn1_dsakey_value_attr + 0, &prkey->path, NULL, 1);
-		}
-		else {
-			/* indirect-protected */
-			sc_format_asn1_entry(asn1_dsakey_value_attr + 1, asn1_dsakey_i_p_attr, NULL, 1);
-			sc_format_asn1_entry(asn1_dsakey_i_p_attr + 0, &prkey->path, NULL, 1);
-		}
-		break;
 	case SC_PKCS15_TYPE_PRKEY_GOSTR3410:
-		sc_format_asn1_entry(asn1_prkey + 3, &gostr3410_prkey_obj, NULL, 1);
+		sc_format_asn1_entry(asn1_prkey + 2, &gostr3410_prkey_obj, NULL, 1);
 		sc_format_asn1_entry(asn1_prk_gostr3410_attr + 0, asn1_gostr3410key_attr, NULL, 1);
 		sc_format_asn1_entry(asn1_gostr3410key_attr + 0, &prkey->path, NULL, 1);
 		if (prkey->params.len == sizeof(*keyinfo_gostparams))   {
@@ -527,11 +458,6 @@
 
 	key_info = (struct sc_pkcs15_prkey_info *) key_object->data;
 
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-	ERR_load_ERR_strings();
-#endif
-	ERR_load_crypto_strings();
-
 	sc_log(ctx, "CertValue(%"SC_FORMAT_LEN_SIZE_T"u) %p",
 	       cert_object->content.len, cert_object->content.value);
 	mem = BIO_new_mem_buf(cert_object->content.value, cert_object->content.len);
@@ -570,7 +496,6 @@
 		OPENSSL_free(buff);
 
 	ERR_clear_error();
-	ERR_free_strings();
 
 	if (out_key_object)
 		*out_key_object = key_object;
@@ -599,13 +524,6 @@
 		free(key->u.rsa.dmp1.data);
 		free(key->u.rsa.dmq1.data);
 		break;
-	case SC_ALGORITHM_DSA:
-		free(key->u.dsa.pub.data);
-		free(key->u.dsa.p.data);
-		free(key->u.dsa.q.data);
-		free(key->u.dsa.g.data);
-		free(key->u.dsa.priv.data);
-		break;
 	case SC_ALGORITHM_GOSTR3410:
 		free(key->u.gostr3410.d.data);
 		break;
@@ -676,92 +594,160 @@
 	switch (pk_type) {
 	case EVP_PKEY_RSA: {
 		struct sc_pkcs15_prkey_rsa *dst = &pkcs15_key->u.rsa;
-		RSA *src = EVP_PKEY_get1_RSA(pk);
+		
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 		const BIGNUM *src_n, *src_e, *src_d, *src_p, *src_q, *src_iqmp, *src_dmp1, *src_dmq1;
+		RSA *src = NULL;
+		if (!(src = EVP_PKEY_get1_RSA(pk)))
+			return SC_ERROR_INCOMPATIBLE_KEY;
 
 		RSA_get0_key(src, &src_n, &src_e, &src_d);
 		RSA_get0_factors(src, &src_p, &src_q);
 		RSA_get0_crt_params(src, &src_dmp1, &src_dmq1, &src_iqmp);
-
+#else
+		BIGNUM *src_n = NULL, *src_e = NULL, *src_d = NULL, *src_p = NULL, *src_q= NULL, *src_iqmp = NULL, *src_dmp1 = NULL, *src_dmq1 = NULL;
+		if (EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_RSA_N, &src_n) != 1 ||
+			EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_RSA_E, &src_e) != 1 ||
+			EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_RSA_D, &src_d) != 1 ||
+			EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_RSA_FACTOR1, &src_p) != 1 ||
+			EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_RSA_FACTOR2, &src_q) != 1 ||
+			EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_RSA_EXPONENT1, &src_dmp1) != 1 ||
+			EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_RSA_EXPONENT2, &src_dmq1) != 1 ||
+			EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, &src_iqmp) != 1) {
+			BN_free(src_n); BN_free(src_e); BN_free(src_d);
+			BN_free(src_p); BN_free(src_q);
+			BN_free(src_dmp1); BN_free(src_dmq1);
+			return SC_ERROR_UNKNOWN;
+		}
+#endif
 		pkcs15_key->algorithm = SC_ALGORITHM_RSA;
-		if (!sc_pkcs15_convert_bignum(&dst->modulus, src_n)
-		 || !sc_pkcs15_convert_bignum(&dst->exponent, src_e)
-		 || !sc_pkcs15_convert_bignum(&dst->d, src_d)
-		 || !sc_pkcs15_convert_bignum(&dst->p, src_p)
-		 || !sc_pkcs15_convert_bignum(&dst->q, src_q))
+		if (!sc_pkcs15_convert_bignum(&dst->modulus, src_n) ||
+			!sc_pkcs15_convert_bignum(&dst->exponent, src_e) ||
+			!sc_pkcs15_convert_bignum(&dst->d, src_d) ||
+			!sc_pkcs15_convert_bignum(&dst->p, src_p) ||
+			!sc_pkcs15_convert_bignum(&dst->q, src_q)) {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+			BN_free(src_n); BN_free(src_e); BN_free(src_d);
+			BN_free(src_p); BN_free(src_q);
+			BN_free(src_iqmp); BN_free(src_dmp1); BN_free(src_dmq1);
+#else
+			RSA_free(src);
+#endif
 			return SC_ERROR_NOT_SUPPORTED;
+		 }
 		if (src_iqmp && src_dmp1 && src_dmq1) {
 			sc_pkcs15_convert_bignum(&dst->iqmp, src_iqmp);
 			sc_pkcs15_convert_bignum(&dst->dmp1, src_dmp1);
 			sc_pkcs15_convert_bignum(&dst->dmq1, src_dmq1);
 		}
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 		RSA_free(src);
+#else
+		BN_free(src_n); BN_free(src_e); BN_free(src_d);
+		BN_free(src_p); BN_free(src_q);
+		BN_free(src_iqmp); BN_free(src_dmp1); BN_free(src_dmq1);
+#endif
 		break;
 		}
-	case EVP_PKEY_DSA: {
-		struct sc_pkcs15_prkey_dsa *dst = &pkcs15_key->u.dsa;
-		DSA *src = EVP_PKEY_get1_DSA(pk);
-		const BIGNUM *src_pub_key, *src_p, *src_q, *src_g, *src_priv_key;
-
-		DSA_get0_key(src, &src_pub_key, &src_priv_key);
-		DSA_get0_pqg(src, &src_p, &src_q, &src_g);
-
-		pkcs15_key->algorithm = SC_ALGORITHM_DSA;
-		sc_pkcs15_convert_bignum(&dst->pub, src_pub_key);
-		sc_pkcs15_convert_bignum(&dst->p, src_p);
-		sc_pkcs15_convert_bignum(&dst->q, src_q);
-		sc_pkcs15_convert_bignum(&dst->g, src_g);
-		sc_pkcs15_convert_bignum(&dst->priv, src_priv_key);
-		DSA_free(src);
-		break;
-		}
+
 #if !defined(OPENSSL_NO_EC)
 	case NID_id_GostR3410_2001: {
 		struct sc_pkcs15_prkey_gostr3410 *dst = &pkcs15_key->u.gostr3410;
-		EC_KEY *src = EVP_PKEY_get0(pk);
-
-		assert(src);
 		pkcs15_key->algorithm = SC_ALGORITHM_GOSTR3410;
-		assert(EC_KEY_get0_private_key(src));
-		sc_pkcs15_convert_bignum(&dst->d, EC_KEY_get0_private_key(src));
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+		const BIGNUM *src_priv_key = NULL;
+		EC_KEY *src = NULL;
+		if (!(src = EVP_PKEY_get0(pk)))
+			return SC_ERROR_INCOMPATIBLE_KEY;
+		if (!(src_priv_key = EC_KEY_get0_private_key(src)))
+			return SC_ERROR_INTERNAL;
+#else
+		BIGNUM *src_priv_key = NULL;
+		if (EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_PRIV_KEY, &src_priv_key) != 1) {
+			return SC_ERROR_UNKNOWN;
+		}
+#endif
+		sc_pkcs15_convert_bignum(&dst->d, src_priv_key);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+		EC_KEY_free(src);
+#else
+		BN_free(src_priv_key);
+#endif
 		break;
 		}
+
 	case EVP_PKEY_EC: {
 		struct sc_pkcs15_prkey_ec *dst = &pkcs15_key->u.ec;
-		const EC_KEY *src = NULL;
-		const EC_GROUP *grp = NULL;
 		unsigned char buf[255];
 		size_t buflen = 255;
 		int nid;
-
-		src = EVP_PKEY_get0_EC_KEY(pk);
-		assert(src);
-		assert(EC_KEY_get0_private_key(src));
-		assert(EC_KEY_get0_public_key(src));
-
 		pkcs15_key->algorithm = SC_ALGORITHM_EC;
-
-		if (!sc_pkcs15_convert_bignum(&dst->privateD, EC_KEY_get0_private_key(src)))
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+		const EC_KEY *src = NULL;
+		const EC_GROUP *grp = NULL;
+		const BIGNUM *src_priv_key = NULL;
+		const EC_POINT *src_pub_key = NULL;
+		if (!(src = EVP_PKEY_get0_EC_KEY(pk)))
+			return SC_ERROR_INCOMPATIBLE_KEY;
+		if (!(src_priv_key = EC_KEY_get0_private_key(src)) ||
+			!(src_pub_key = EC_KEY_get0_public_key(src)) ||
+			!(grp = EC_KEY_get0_group(src)))
 			return SC_ERROR_INCOMPATIBLE_KEY;
+		nid = EC_GROUP_get_curve_name(grp);
+#else
+		EC_GROUP *grp = NULL;
+		BIGNUM *src_priv_key = NULL;
+		char grp_name[256];
 
-		grp = EC_KEY_get0_group(src);
-		if(grp == 0)
+		if (EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_PRIV_KEY, &src_priv_key) != 1) {
+			return SC_ERROR_UNKNOWN;
+		}
+
+		if (EVP_PKEY_get_group_name(pk, grp_name, sizeof(grp_name), NULL) != 1) {
+			BN_free(src_priv_key);
+			return SC_ERROR_UNKNOWN;
+		}
+		if ((nid = OBJ_sn2nid(grp_name)) == 0) {
+			BN_free(src_priv_key);
+			return SC_ERROR_UNKNOWN;
+		}
+		if ((grp = EC_GROUP_new_by_curve_name(nid)) == NULL) {
+			BN_free(src_priv_key);
+			return SC_ERROR_UNKNOWN;
+		}
+#endif
+
+		if (!sc_pkcs15_convert_bignum(&dst->privateD, src_priv_key)) {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+			BN_free(src_priv_key);
+			EC_GROUP_free(grp);
+#endif
 			return SC_ERROR_INCOMPATIBLE_KEY;
+		}
 
-		/* get curve name */
-		nid = EC_GROUP_get_curve_name(grp);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 		if(nid != 0) {
 			const char *sn = OBJ_nid2sn(nid);
 			if (sn)
 				dst->params.named_curve = strdup(sn);
 		}
+#else
+		dst->params.named_curve = strdup(grp_name);
+#endif
 
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 		/* Decode EC_POINT from a octet string */
-		buflen = EC_POINT_point2oct(grp, (const EC_POINT *) EC_KEY_get0_public_key(src),
+		buflen = EC_POINT_point2oct(grp, src_pub_key,
 				POINT_CONVERSION_UNCOMPRESSED, buf, buflen, NULL);
 		if (!buflen)
 			return SC_ERROR_INCOMPATIBLE_KEY;
-
+#else
+		/* Decode EC_POINT from a octet string */
+		if (EVP_PKEY_get_octet_string_param(pk, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, buf, buflen, &buflen) != 1) {
+			return SC_ERROR_INCOMPATIBLE_KEY;
+		}
+#endif
 		/* copy the public key */
 		dst->ecpointQ.value = malloc(buflen);
 		if (!dst->ecpointQ.value)
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-pteid.c opensc-0.23.0/src/libopensc/pkcs15-pteid.c
--- opensc-0.22.0/src/libopensc/pkcs15-pteid.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-pteid.c	2022-11-29 09:34:43.000000000 +0100
@@ -194,6 +194,7 @@
 	rv = parse_odf(buf, len, p15card);
 	if (rv != SC_SUCCESS) {
 		sc_log(ctx, "Decoding of ODF failed: %d", rv);
+		sc_pkcs15_card_clear(p15card);
 		LOG_FUNC_RETURN(ctx, rv);
 	}
 
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-pubkey.c opensc-0.23.0/src/libopensc/pkcs15-pubkey.c
--- opensc-0.22.0/src/libopensc/pkcs15-pubkey.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-pubkey.c	2022-11-29 09:34:43.000000000 +0100
@@ -37,9 +37,12 @@
 #ifdef ENABLE_OPENSSL
 #include <openssl/bn.h>
 #include <openssl/rsa.h>
-#include <openssl/dsa.h>
 #include <openssl/evp.h>
 #include <openssl/err.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+# include <openssl/core_names.h>
+# include <openssl/param_build.h>
+#endif
 #ifndef OPENSSL_NO_EC
 #include <openssl/ec.h>
 #endif
@@ -115,18 +118,6 @@
 		{ NULL, 0, 0, 0, NULL, NULL }
 };
 
-#define C_ASN1_DSAKEY_ATTR_SIZE 2
-static const struct sc_asn1_entry c_asn1_dsakey_attr[C_ASN1_DSAKEY_ATTR_SIZE] = {
-		{ "value", SC_ASN1_PATH, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
-		{ NULL, 0, 0, 0, NULL, NULL }
-};
-
-#define C_ASN1_DSA_TYPE_ATTR_SIZE 2
-static const struct sc_asn1_entry c_asn1_dsa_type_attr[C_ASN1_DSA_TYPE_ATTR_SIZE] = {
-		{ "publicDSAKeyAttributes", SC_ASN1_STRUCT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
-		{ NULL, 0, 0, 0, NULL, NULL }
-};
-
 #define C_ASN1_GOST3410KEY_ATTR_SIZE 5
 static const struct sc_asn1_entry c_asn1_gostr3410key_attr[C_ASN1_GOST3410KEY_ATTR_SIZE] = {
 		{ "value", SC_ASN1_PATH, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
@@ -142,10 +133,9 @@
 		{ NULL, 0, 0, 0, NULL, NULL }
 };
 
-#define C_ASN1_PUBKEY_CHOICE_SIZE 5
+#define C_ASN1_PUBKEY_CHOICE_SIZE 4
 static const struct sc_asn1_entry c_asn1_pubkey_choice[C_ASN1_PUBKEY_CHOICE_SIZE] = {
 		{ "publicRSAKey", SC_ASN1_PKCS15_OBJECT, SC_ASN1_TAG_SEQUENCE | SC_ASN1_CONS, 0, NULL, NULL },
-		{ "publicDSAKey", SC_ASN1_PKCS15_OBJECT, 2 | SC_ASN1_CTX | SC_ASN1_CONS, 0, NULL, NULL },
 		{ "publicGOSTR3410Key", SC_ASN1_PKCS15_OBJECT, 4 | SC_ASN1_CTX | SC_ASN1_CONS, 0, NULL, NULL },
 		{ "publicECKey", SC_ASN1_PKCS15_OBJECT, 0 | SC_ASN1_CTX | SC_ASN1_CONS, 0, NULL, NULL },
 		/*TODO: -DEE not clear EC is needed here  as look like it is for pukdf */
@@ -224,8 +214,6 @@
 	struct sc_asn1_entry asn1_eckey_value_choice[C_ASN1_ECKEY_VALUE_CHOICE_SIZE];
 	struct sc_asn1_entry asn1_eckey_attr[C_ASN1_ECKEY_ATTR_SIZE];
 	struct sc_asn1_entry asn1_ec_type_attr[C_ASN1_EC_TYPE_ATTR_SIZE];
-	struct sc_asn1_entry asn1_dsakey_attr[C_ASN1_DSAKEY_ATTR_SIZE];
-	struct sc_asn1_entry asn1_dsa_type_attr[C_ASN1_DSA_TYPE_ATTR_SIZE];
 	struct sc_asn1_entry asn1_gostr3410key_attr[C_ASN1_GOST3410KEY_ATTR_SIZE];
 	struct sc_asn1_entry asn1_gostr3410_type_attr[C_ASN1_GOST3410_TYPE_ATTR_SIZE];
 	struct sc_asn1_entry asn1_pubkey_choice[C_ASN1_PUBKEY_CHOICE_SIZE];
@@ -234,8 +222,6 @@
 			asn1_com_pubkey_attr, asn1_rsa_type_attr };
 	struct sc_asn1_pkcs15_object eckey_obj = { obj, asn1_com_key_attr,
 			asn1_com_pubkey_attr, asn1_ec_type_attr };
-	struct sc_asn1_pkcs15_object dsakey_obj = { obj, asn1_com_key_attr,
-			asn1_com_pubkey_attr, asn1_dsa_type_attr };
 	struct sc_asn1_pkcs15_object gostr3410key_obj =  { obj, asn1_com_key_attr,
 			asn1_com_pubkey_attr, asn1_gostr3410_type_attr };
 
@@ -255,8 +241,6 @@
 	sc_copy_asn1_entry(c_asn1_ec_type_attr, asn1_ec_type_attr);
 	sc_copy_asn1_entry(c_asn1_eckey_value_choice, asn1_eckey_value_choice);
 	sc_copy_asn1_entry(c_asn1_eckey_attr, asn1_eckey_attr);
-	sc_copy_asn1_entry(c_asn1_dsa_type_attr, asn1_dsa_type_attr);
-	sc_copy_asn1_entry(c_asn1_dsakey_attr, asn1_dsakey_attr);
 	sc_copy_asn1_entry(c_asn1_gostr3410_type_attr, asn1_gostr3410_type_attr);
 	sc_copy_asn1_entry(c_asn1_gostr3410key_attr, asn1_gostr3410key_attr);
 	sc_copy_asn1_entry(c_asn1_com_pubkey_attr, asn1_com_pubkey_attr);
@@ -265,9 +249,8 @@
 	sc_format_asn1_entry(asn1_com_pubkey_attr + 0, &info->subject.value, &info->subject.len, 0);
 
 	sc_format_asn1_entry(asn1_pubkey_choice + 0, &rsakey_obj, NULL, 0);
-	sc_format_asn1_entry(asn1_pubkey_choice + 1, &dsakey_obj, NULL, 0);
-	sc_format_asn1_entry(asn1_pubkey_choice + 2, &gostr3410key_obj, NULL, 0);
-	sc_format_asn1_entry(asn1_pubkey_choice + 3, &eckey_obj, NULL, 0);
+	sc_format_asn1_entry(asn1_pubkey_choice + 1, &gostr3410key_obj, NULL, 0);
+	sc_format_asn1_entry(asn1_pubkey_choice + 2, &eckey_obj, NULL, 0);
 
 	sc_format_asn1_entry(asn1_rsa_type_attr + 0, asn1_rsakey_attr, NULL, 0);
 
@@ -284,10 +267,6 @@
 
 	sc_format_asn1_entry(asn1_eckey_attr + 0, asn1_eckey_value_choice, NULL, 0);
 
-	sc_format_asn1_entry(asn1_dsa_type_attr + 0, asn1_dsakey_attr, NULL, 0);
-
-	sc_format_asn1_entry(asn1_dsakey_attr + 0, &info->path, NULL, 0);
-
 	sc_format_asn1_entry(asn1_gostr3410_type_attr + 0, asn1_gostr3410key_attr, NULL, 0);
 
 	sc_format_asn1_entry(asn1_gostr3410key_attr + 0, &info->path, NULL, 0);
@@ -314,7 +293,7 @@
 	LOG_TEST_GOTO_ERR(ctx, r, "ASN.1 decoding failed");
 	if (asn1_pubkey_choice[0].flags & SC_ASN1_PRESENT) {
 		obj->type = SC_PKCS15_TYPE_PUBKEY_RSA;
-	} else if (asn1_pubkey_choice[2].flags & SC_ASN1_PRESENT) {
+	} else if (asn1_pubkey_choice[1].flags & SC_ASN1_PRESENT) {
 		obj->type = SC_PKCS15_TYPE_PUBKEY_GOSTR3410;
 		assert(info->modulus_length == 0);
 		info->modulus_length = SC_PKCS15_GOSTR3410_KEYSIZE;
@@ -331,11 +310,11 @@
 		keyinfo_gostparams->gostr3411 = (unsigned int)gostr3410_params[1];
 		keyinfo_gostparams->gost28147 = (unsigned int)gostr3410_params[2];
 	}
-	else if (asn1_pubkey_choice[3].flags & SC_ASN1_PRESENT) {
+	else if (asn1_pubkey_choice[2].flags & SC_ASN1_PRESENT) {
 		obj->type = SC_PKCS15_TYPE_PUBKEY_EC;
 	}
 	else {
-		obj->type = SC_PKCS15_TYPE_PUBKEY_DSA;
+		goto err;
 	}
 
 	if (!p15card->app || !p15card->app->ddo.aid.len) {
@@ -390,8 +369,6 @@
 	struct sc_asn1_entry asn1_eckey_value_choice[C_ASN1_ECKEY_VALUE_CHOICE_SIZE];
 	struct sc_asn1_entry asn1_eckey_attr[C_ASN1_ECKEY_ATTR_SIZE];
 	struct sc_asn1_entry asn1_ec_type_attr[C_ASN1_EC_TYPE_ATTR_SIZE];
-	struct sc_asn1_entry asn1_dsakey_attr[C_ASN1_DSAKEY_ATTR_SIZE];
-	struct sc_asn1_entry asn1_dsa_type_attr[C_ASN1_DSA_TYPE_ATTR_SIZE];
 	struct sc_asn1_entry asn1_gostr3410key_attr[C_ASN1_GOST3410KEY_ATTR_SIZE];
 	struct sc_asn1_entry asn1_gostr3410_type_attr[C_ASN1_GOST3410_TYPE_ATTR_SIZE];
 	struct sc_asn1_entry asn1_pubkey_choice[C_ASN1_PUBKEY_CHOICE_SIZE];
@@ -404,9 +381,6 @@
 	struct sc_asn1_pkcs15_object eckey_obj = { (struct sc_pkcs15_object *) obj,
 			asn1_com_key_attr,
 			asn1_com_pubkey_attr, asn1_ec_type_attr };
-	struct sc_asn1_pkcs15_object dsakey_obj = { (struct sc_pkcs15_object *) obj,
-			asn1_com_key_attr,
-			asn1_com_pubkey_attr, asn1_dsa_type_attr };
 	struct sc_asn1_pkcs15_object gostr3410key_obj =  { (struct sc_pkcs15_object *) obj,
 			asn1_com_key_attr,
 			asn1_com_pubkey_attr, asn1_gostr3410_type_attr };
@@ -423,8 +397,6 @@
 	sc_copy_asn1_entry(c_asn1_ec_type_attr, asn1_ec_type_attr);
 	sc_copy_asn1_entry(c_asn1_eckey_value_choice, asn1_eckey_value_choice);
 	sc_copy_asn1_entry(c_asn1_eckey_attr, asn1_eckey_attr);
-	sc_copy_asn1_entry(c_asn1_dsa_type_attr, asn1_dsa_type_attr);
-	sc_copy_asn1_entry(c_asn1_dsakey_attr, asn1_dsakey_attr);
 	sc_copy_asn1_entry(c_asn1_gostr3410_type_attr, asn1_gostr3410_type_attr);
 	sc_copy_asn1_entry(c_asn1_gostr3410key_attr, asn1_gostr3410key_attr);
 	sc_copy_asn1_entry(c_asn1_com_pubkey_attr, asn1_com_pubkey_attr);
@@ -467,15 +439,8 @@
 		sc_format_asn1_entry(asn1_rsakey_attr + 0, asn1_rsakey_value_choice, NULL, 1);
 		sc_format_asn1_entry(asn1_rsakey_attr + 1, &pubkey->modulus_length, NULL, 1);
 		break;
-	case SC_PKCS15_TYPE_PUBKEY_DSA:
-		sc_format_asn1_entry(asn1_pubkey_choice + 1, &dsakey_obj, NULL, 1);
-
-		sc_format_asn1_entry(asn1_dsa_type_attr + 0, asn1_dsakey_attr, NULL, 1);
-
-		sc_format_asn1_entry(asn1_dsakey_attr + 0, &pubkey->path, NULL, 1);
-		break;
 	case SC_PKCS15_TYPE_PUBKEY_GOSTR3410:
-		sc_format_asn1_entry(asn1_pubkey_choice + 2, &gostr3410key_obj, NULL, 1);
+		sc_format_asn1_entry(asn1_pubkey_choice + 1, &gostr3410key_obj, NULL, 1);
 
 		sc_format_asn1_entry(asn1_gostr3410_type_attr + 0, asn1_gostr3410key_attr, NULL, 1);
 
@@ -491,7 +456,7 @@
 		}
 		break;
 	case SC_PKCS15_TYPE_PUBKEY_EC:
-		sc_format_asn1_entry(asn1_pubkey_choice + 3, &eckey_obj, NULL, 1);
+		sc_format_asn1_entry(asn1_pubkey_choice + 2, &eckey_obj, NULL, 1);
 
 		sc_format_asn1_entry(asn1_ec_type_attr + 0, asn1_eckey_attr, NULL, 1);
 
@@ -559,15 +524,6 @@
 		{ NULL, 0, 0, 0, NULL, NULL }
 };
 
-#define C_ASN1_DSA_PUB_COEFFICIENTS_SIZE 5
-static struct sc_asn1_entry c_asn1_dsa_pub_coefficients[C_ASN1_DSA_PUB_COEFFICIENTS_SIZE] = {
-		{ "publicKey",SC_ASN1_OCTET_STRING, SC_ASN1_TAG_INTEGER, SC_ASN1_ALLOC|SC_ASN1_UNSIGNED, NULL, NULL },
-		{ "paramP",   SC_ASN1_OCTET_STRING, SC_ASN1_TAG_INTEGER, SC_ASN1_ALLOC|SC_ASN1_UNSIGNED, NULL, NULL },
-		{ "paramQ",   SC_ASN1_OCTET_STRING, SC_ASN1_TAG_INTEGER, SC_ASN1_ALLOC|SC_ASN1_UNSIGNED, NULL, NULL },
-		{ "paramG",   SC_ASN1_OCTET_STRING, SC_ASN1_TAG_INTEGER, SC_ASN1_ALLOC|SC_ASN1_UNSIGNED, NULL, NULL },
-		{ NULL, 0, 0, 0, NULL, NULL },
-};
-
 #define C_ASN1_GOSTR3410_PUB_COEFFICIENTS_SIZE 2
 static struct sc_asn1_entry c_asn1_gostr3410_pub_coefficients[C_ASN1_GOSTR3410_PUB_COEFFICIENTS_SIZE] = {
 		{ "xy", SC_ASN1_OCTET_STRING, SC_ASN1_TAG_OCTET_STRING, SC_ASN1_ALLOC, NULL, NULL },
@@ -634,56 +590,6 @@
 
 
 int
-sc_pkcs15_decode_pubkey_dsa(sc_context_t *ctx, struct sc_pkcs15_pubkey_dsa *key,
-		const u8 *buf, size_t buflen)
-{
-	struct sc_asn1_entry asn1_public_key[C_ASN1_PUBLIC_KEY_SIZE];
-	struct sc_asn1_entry asn1_dsa_pub_coefficients[C_ASN1_DSA_PUB_COEFFICIENTS_SIZE];
-	int r;
-
-	LOG_FUNC_CALLED(ctx);
-	sc_copy_asn1_entry(c_asn1_public_key, asn1_public_key);
-	sc_copy_asn1_entry(c_asn1_dsa_pub_coefficients, asn1_dsa_pub_coefficients);
-
-	sc_format_asn1_entry(asn1_public_key + 0, asn1_dsa_pub_coefficients, NULL, 1);
-	sc_format_asn1_entry(asn1_dsa_pub_coefficients + 0, &key->pub.data, &key->pub.len, 0);
-	sc_format_asn1_entry(asn1_dsa_pub_coefficients + 1, &key->g.data, &key->g.len, 0);
-	sc_format_asn1_entry(asn1_dsa_pub_coefficients + 2, &key->p.data, &key->p.len, 0);
-	sc_format_asn1_entry(asn1_dsa_pub_coefficients + 3, &key->q.data, &key->q.len, 0);
-
-	r = sc_asn1_decode(ctx, asn1_public_key, buf, buflen, NULL, NULL);
-	LOG_TEST_RET(ctx, r, "ASN.1 decoding failed");
-
-	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
-}
-
-
-int
-sc_pkcs15_encode_pubkey_dsa(sc_context_t *ctx, struct sc_pkcs15_pubkey_dsa *key,
-		u8 **buf, size_t *buflen)
-{
-	struct sc_asn1_entry asn1_public_key[C_ASN1_PUBLIC_KEY_SIZE];
-	struct sc_asn1_entry asn1_dsa_pub_coefficients[C_ASN1_DSA_PUB_COEFFICIENTS_SIZE];
-	int r;
-
-	LOG_FUNC_CALLED(ctx);
-	sc_copy_asn1_entry(c_asn1_public_key, asn1_public_key);
-	sc_copy_asn1_entry(c_asn1_dsa_pub_coefficients, asn1_dsa_pub_coefficients);
-
-	sc_format_asn1_entry(asn1_public_key + 0, asn1_dsa_pub_coefficients, NULL, 1);
-	sc_format_asn1_entry(asn1_dsa_pub_coefficients + 0, key->pub.data, &key->pub.len, 1);
-	sc_format_asn1_entry(asn1_dsa_pub_coefficients + 1, key->g.data, &key->g.len, 1);
-	sc_format_asn1_entry(asn1_dsa_pub_coefficients + 2, key->p.data, &key->p.len, 1);
-	sc_format_asn1_entry(asn1_dsa_pub_coefficients + 3, key->q.data, &key->q.len, 1);
-
-	r = sc_asn1_encode(ctx, asn1_public_key, buf, buflen);
-	LOG_TEST_RET(ctx, r, "ASN.1 encoding failed");
-
-	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
-}
-
-
-int
 sc_pkcs15_decode_pubkey_gostr3410(sc_context_t *ctx, struct sc_pkcs15_pubkey_gostr3410 *key,
 		const u8 *buf, size_t buflen)
 {
@@ -732,7 +638,7 @@
 		const u8 *buf, size_t buflen)
 {
 	int r;
-	u8 * ecpoint_data;
+	u8 * ecpoint_data = NULL;
 	size_t ecpoint_len;
 	struct sc_asn1_entry asn1_ec_pointQ[C_ASN1_EC_POINTQ_SIZE];
 
@@ -740,11 +646,15 @@
 	sc_copy_asn1_entry(c_asn1_ec_pointQ, asn1_ec_pointQ);
 	sc_format_asn1_entry(asn1_ec_pointQ + 0, &ecpoint_data, &ecpoint_len, 1);
 	r = sc_asn1_decode(ctx, asn1_ec_pointQ, buf, buflen, NULL, NULL);
-	if (r < 0)
+	if (r < 0) {
+		free(ecpoint_data);
 		LOG_TEST_RET(ctx, r, "ASN.1 decoding failed");
+	}
 
-	if (*ecpoint_data != 0x04)
+	if (ecpoint_len == 0 || *ecpoint_data != 0x04) {
+		free(ecpoint_data);
 		LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Supported only uncompressed EC pointQ value");
+	}
 
 	key->ecpointQ.len = ecpoint_len;
 	key->ecpointQ.value = ecpoint_data;
@@ -821,8 +731,6 @@
 {
 	if (key->algorithm == SC_ALGORITHM_RSA)
 		return sc_pkcs15_encode_pubkey_rsa(ctx, &key->u.rsa, buf, len);
-	if (key->algorithm == SC_ALGORITHM_DSA)
-		return sc_pkcs15_encode_pubkey_dsa(ctx, &key->u.dsa, buf, len);
 	if (key->algorithm == SC_ALGORITHM_GOSTR3410)
 		return sc_pkcs15_encode_pubkey_gostr3410(ctx, &key->u.gostr3410, buf, len);
 	if (key->algorithm == SC_ALGORITHM_EC)
@@ -949,8 +857,6 @@
 {
 	if (key->algorithm == SC_ALGORITHM_RSA)
 		return sc_pkcs15_decode_pubkey_rsa(ctx, &key->u.rsa, buf, len);
-	if (key->algorithm == SC_ALGORITHM_DSA)
-		return sc_pkcs15_decode_pubkey_dsa(ctx, &key->u.dsa, buf, len);
 	if (key->algorithm == SC_ALGORITHM_GOSTR3410)
 		return sc_pkcs15_decode_pubkey_gostr3410(ctx, &key->u.gostr3410, buf, len);
 	if (key->algorithm == SC_ALGORITHM_EC)
@@ -977,6 +883,7 @@
 	unsigned char *data = NULL;
 	size_t	len;
 	int	algorithm, r;
+	int	private_obj;
 
 	if (p15card == NULL || p15card->card == NULL || p15card->card->ops == NULL
 			|| obj == NULL || out == NULL) {
@@ -991,9 +898,6 @@
 	case SC_PKCS15_TYPE_PUBKEY_RSA:
 		algorithm = SC_ALGORITHM_RSA;
 		break;
-	case SC_PKCS15_TYPE_PUBKEY_DSA:
-		algorithm = SC_ALGORITHM_DSA;
-		break;
 	case SC_PKCS15_TYPE_PUBKEY_GOSTR3410:
 		algorithm = SC_ALGORITHM_GOSTR3410;
 		break;
@@ -1048,7 +952,8 @@
 	}
 	else if (info->path.len)   {
 		sc_log(ctx, "Read from EF and decode");
-		r = sc_pkcs15_read_file(p15card, &info->path, &data, &len);
+		private_obj = obj->flags & SC_PKCS15_CO_FLAG_PRIVATE;
+		r = sc_pkcs15_read_file(p15card, &info->path, &data, &len, private_obj);
 		LOG_TEST_GOTO_ERR(ctx, r, "Failed to read public key file.");
 
 		if ((algorithm == SC_ALGORITHM_EC || algorithm == SC_ALGORITHM_EDDSA || algorithm == SC_ALGORITHM_XEDDSA)
@@ -1116,15 +1021,6 @@
 		if (!rv)
 			rv = sc_pkcs15_dup_bignum(&pubkey->u.rsa.exponent, &prvkey->u.rsa.exponent);
 		break;
-	case SC_ALGORITHM_DSA:
-		rv = sc_pkcs15_dup_bignum(&pubkey->u.dsa.pub, &prvkey->u.dsa.pub);
-		if (!rv)
-			rv = sc_pkcs15_dup_bignum(&pubkey->u.dsa.p, &prvkey->u.dsa.p);
-		if (!rv)
-			rv = sc_pkcs15_dup_bignum(&pubkey->u.dsa.q, &prvkey->u.dsa.q);
-		if (!rv)
-			rv = sc_pkcs15_dup_bignum(&pubkey->u.dsa.g, &prvkey->u.dsa.g);
-		break;
 	case SC_ALGORITHM_GOSTR3410:
 		break;
 	case SC_ALGORITHM_EC:
@@ -1206,15 +1102,6 @@
 		if (!rv)
 			rv = sc_pkcs15_dup_bignum(&pubkey->u.rsa.exponent, &key->u.rsa.exponent);
 		break;
-	case SC_ALGORITHM_DSA:
-		rv = sc_pkcs15_dup_bignum(&pubkey->u.dsa.pub, &key->u.dsa.pub);
-		if (!rv)
-			rv = sc_pkcs15_dup_bignum(&pubkey->u.dsa.p, &key->u.dsa.p);
-		if (!rv)
-			rv = sc_pkcs15_dup_bignum(&pubkey->u.dsa.q, &key->u.dsa.q);
-		if (!rv)
-			rv = sc_pkcs15_dup_bignum(&pubkey->u.dsa.g, &key->u.dsa.g);
-		break;
 	case SC_ALGORITHM_GOSTR3410:
 		break;
 	case SC_ALGORITHM_EC:
@@ -1289,16 +1176,6 @@
 		if (key->u.rsa.exponent.data)
 			free(key->u.rsa.exponent.data);
 		break;
-	case SC_ALGORITHM_DSA:
-		if (key->u.dsa.pub.data)
-			free(key->u.dsa.pub.data);
-		if (key->u.dsa.g.data)
-			free(key->u.dsa.g.data);
-		if (key->u.dsa.p.data)
-			free(key->u.dsa.p.data);
-		if (key->u.dsa.q.data)
-			free(key->u.dsa.q.data);
-		break;
 	case SC_ALGORITHM_GOSTR3410:
 		if (key->u.gostr3410.xy.data)
 			free(key->u.gostr3410.xy.data);
@@ -1717,50 +1594,93 @@
 	switch (pk_type) {
 	case EVP_PKEY_RSA: {
 		struct sc_pkcs15_pubkey_rsa *dst = &pkcs15_key->u.rsa;
-		RSA *src = EVP_PKEY_get1_RSA(pk);
+		/* Get parameters */
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 		const BIGNUM *src_n, *src_e;
-
+		RSA *src = NULL;
+		if (!(src = EVP_PKEY_get1_RSA(pk)))
+			return SC_ERROR_INCOMPATIBLE_KEY;
 		RSA_get0_key(src, &src_n, &src_e, NULL);
-
+		if (!src_n || !src_e) {
+			free(src);
+			return SC_ERROR_INTERNAL;
+		}
+#else
+		BIGNUM *src_n = NULL, *src_e = NULL;
+		if (EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_RSA_N, &src_n) != 1 ||
+			EVP_PKEY_get_bn_param(pk, OSSL_PKEY_PARAM_RSA_E, &src_e) != 1) {
+			BN_free(src_n);
+			return SC_ERROR_INTERNAL;
+		}
+#endif
+		/* Convert */
 		pkcs15_key->algorithm = SC_ALGORITHM_RSA;
-		if (!sc_pkcs15_convert_bignum(&dst->modulus, src_n) || !sc_pkcs15_convert_bignum(&dst->exponent, src_e))
+		if (!sc_pkcs15_convert_bignum(&dst->modulus, src_n) ||
+			!sc_pkcs15_convert_bignum(&dst->exponent, src_e)) {
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+			RSA_free(src);
+#else
+			BN_free(src_n); BN_free(src_e);
+#endif
 			return SC_ERROR_INVALID_DATA;
+		}
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 		RSA_free(src);
-		break;
-	}
-	case EVP_PKEY_DSA: {
-		struct sc_pkcs15_pubkey_dsa *dst = &pkcs15_key->u.dsa;
-		DSA *src = EVP_PKEY_get1_DSA(pk);
-		const BIGNUM *src_pub_key, *src_priv_key, *src_p, *src_q, *src_g;
-
-		DSA_get0_key(src, &src_pub_key, &src_priv_key);
-		DSA_get0_pqg(src, &src_p, &src_q, &src_g);
-
-		pkcs15_key->algorithm = SC_ALGORITHM_DSA;
-		sc_pkcs15_convert_bignum(&dst->pub, src_pub_key);
-		sc_pkcs15_convert_bignum(&dst->p, src_p);
-		sc_pkcs15_convert_bignum(&dst->q, src_q);
-		sc_pkcs15_convert_bignum(&dst->g, src_g);
-		DSA_free(src);
+#else
+		BN_free(src_n); BN_free(src_e);
+#endif
 		break;
 	}
 #if !defined(OPENSSL_NO_EC)
 	case NID_id_GostR3410_2001: {
 		struct sc_pkcs15_pubkey_gostr3410 *dst = &pkcs15_key->u.gostr3410;
-		EC_KEY *eckey = EVP_PKEY_get0(pk);
-		const EC_POINT *point;
 		BIGNUM *X, *Y;
 		int r = 0;
-
-		assert(eckey);
-		point = EC_KEY_get0_public_key(eckey);
-		if (!point)
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+		const EC_KEY *eckey = NULL;
+		const EC_POINT *point = NULL;
+		const EC_GROUP *group = NULL;
+		if (!(eckey = EVP_PKEY_get0(pk)))
+			return SC_ERROR_INCOMPATIBLE_KEY;
+		if (!(point = EC_KEY_get0_public_key(eckey)) ||
+			!(group = EC_KEY_get0_group(eckey)))
+			return SC_ERROR_INTERNAL;
+#else
+		EC_POINT *point = NULL;
+		EC_GROUP *group = NULL;
+		int nid = 0;
+		unsigned char *pub = NULL; size_t pub_len = 0;
+		char *group_name = NULL; size_t group_name_len = 0;
+		EVP_PKEY_get_octet_string_param(pk, OSSL_PKEY_PARAM_PUB_KEY, NULL, 0, &pub_len);
+		EVP_PKEY_get_group_name(pk, NULL, 0, &group_name_len);
+		if (!(pub = malloc(pub_len)) || !(group_name = malloc(group_name_len))) {
+			free(pub);
+			return SC_ERROR_OUT_OF_MEMORY;
+		}
+		if (EVP_PKEY_get_octet_string_param(pk, OSSL_PKEY_PARAM_PUB_KEY, pub, pub_len, NULL) != 1 ||
+			EVP_PKEY_get_group_name(pk, group_name, group_name_len, NULL) != 1) {
+			free(pub);
+			free(group_name);
+			return SC_ERROR_INTERNAL;
+		}
+		if ((nid = OBJ_sn2nid(group_name) == 0) ||
+			!(group = EC_GROUP_new_by_curve_name(nid)) ||
+			!(point = EC_POINT_new(group)) ||
+			EC_POINT_oct2point(group, point, pub, pub_len, NULL) != 1) {
+			free(pub);
+			free(group_name);
+			EC_POINT_free(point);
+			EC_GROUP_free(group);
 			return SC_ERROR_INTERNAL;
+		}
+		free(pub);
+		free(group_name);
+#endif
 		X = BN_new();
 		Y = BN_new();
-		if (X && Y && EC_KEY_get0_group(eckey))
-					r = EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(eckey),
-					point, X, Y, NULL);
+		if (X && Y && group)
+				r = EC_POINT_get_affine_coordinates(group, point, X, Y, NULL);
 		if (r == 1) {
 			dst->xy.len = BN_num_bytes(X) + BN_num_bytes(Y);
 			dst->xy.data = malloc(dst->xy.len);
@@ -1777,38 +1697,56 @@
 		}
 		BN_free(X);
 		BN_free(Y);
+
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+		EC_GROUP_free(group);
+		EC_POINT_free(point);
+#endif
 		if (r != 1)
 			return SC_ERROR_INTERNAL;
 		break;
 	}
 	case EVP_PKEY_EC: {
 		struct sc_pkcs15_pubkey_ec *dst = &pkcs15_key->u.ec;
+		pkcs15_key->algorithm = SC_ALGORITHM_EC;
+		unsigned char buf[255]; size_t buflen = 255;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 		const EC_KEY *src = NULL;
 		const EC_GROUP *grp = NULL;
-		unsigned char buf[255];
-		size_t buflen = 255;
-		int nid;
-
-		src = EVP_PKEY_get0_EC_KEY(pk);
-		assert(src);
-		assert(EC_KEY_get0_public_key(src));
+		const EC_POINT *point = NULL;
+		int nid = 0;
 
-		pkcs15_key->algorithm = SC_ALGORITHM_EC;
-		grp = EC_KEY_get0_group(src);
-		if(grp == 0)
+		if (!(src = EVP_PKEY_get0_EC_KEY(pk)))
 			return SC_ERROR_INCOMPATIBLE_KEY;
+		if (!(point = EC_KEY_get0_public_key(src)) ||
+			!(grp = EC_KEY_get0_group(src))) {
+			return SC_ERROR_INCOMPATIBLE_KEY;
+		 }
 
 		/* Decode EC_POINT from a octet string */
-		buflen = EC_POINT_point2oct(grp, (const EC_POINT *) EC_KEY_get0_public_key(src),
+		buflen = EC_POINT_point2oct(grp, point,
 				POINT_CONVERSION_UNCOMPRESSED, buf, buflen, NULL);
 
 		/* get curve name */
 		nid = EC_GROUP_get_curve_name(grp);
 		if(nid != 0) {
-			const char *name = OBJ_nid2sn(nid);
-			if (name)
-				dst->params.named_curve = strdup(name);
+			const char *group_name = OBJ_nid2sn(nid);
+			if (group_name)
+				dst->params.named_curve = strdup(group_name);
+		}
+#else
+		char group_name[256];
+		if (EVP_PKEY_get_octet_string_param(pk, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, buf, buflen, NULL) != 1)
+			return SC_ERROR_INTERNAL;
+		if (EVP_PKEY_get_group_name(pk, group_name, sizeof(group_name), NULL) != 1)
+			return SC_ERROR_INTERNAL;
+		dst->params.named_curve = strdup(group_name);
+		
+		/* Decode EC_POINT from a octet string */
+		if (EVP_PKEY_get_octet_string_param(pk, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, buf, buflen, &buflen) != 1) {
+			return SC_ERROR_INCOMPATIBLE_KEY;
 		}
+#endif
 
 		/* copy the public key */
 		if (buflen > 0) {
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-sc-hsm.c opensc-0.23.0/src/libopensc/pkcs15-sc-hsm.c
--- opensc-0.22.0/src/libopensc/pkcs15-sc-hsm.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-sc-hsm.c	2022-11-29 09:34:43.000000000 +0100
@@ -181,7 +181,7 @@
 #define C_ASN1_CVC_BODY_SIZE 5
 static const struct sc_asn1_entry c_asn1_cvc_body[C_ASN1_CVC_BODY_SIZE] = {
 	{ "certificateProfileIdentifier", SC_ASN1_INTEGER, SC_ASN1_APP | 0x1F29, 0, NULL, NULL },
-	{ "certificationAuthorityReference", SC_ASN1_PRINTABLESTRING, SC_ASN1_APP | 2, 0, NULL, NULL },
+	{ "certificationAuthorityReference", SC_ASN1_PRINTABLESTRING, SC_ASN1_APP | 2, SC_ASN1_OPTIONAL, NULL, NULL },
 	{ "publicKey", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_APP | 0x1F49, 0, NULL, NULL },
 	{ "certificateHolderReference", SC_ASN1_PRINTABLESTRING, SC_ASN1_APP | 0x1F20, 0, NULL, NULL },
 	{ NULL, 0, 0, 0, NULL, NULL }
@@ -214,6 +214,26 @@
 	{ NULL, 0, 0, 0, NULL, NULL }
 };
 
+struct sc_object_id sc_hsm_public_key_oid = {
+    {1, 3, 6, 1, 4, 1, 24991, 4, 3, 1, -1}
+};
+
+#define C_ASN1_SC_HSM_PKA_NEW_SIZE 5
+static const struct sc_asn1_entry c_asn1_sc_hsm_pka_new_format[C_ASN1_SC_HSM_PKA_NEW_SIZE] = {
+	{ "oid", SC_ASN1_OBJECT, SC_ASN1_TAG_UNIVERSAL | SC_ASN1_TAG_OBJECT, 0, NULL, NULL },
+	{ "dicaCVC", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_APP | 1, 0, NULL, NULL },
+	{ "deviceCVC", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_APP | 2, 0, NULL, NULL },
+	{ "publicKey", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_APP | 3, 0, NULL, NULL },
+	{ NULL, 0, 0, 0, NULL, NULL }
+};
+
+#define C_ASN1_SC_HSM_PKA_OLD_SIZE 4
+static const struct sc_asn1_entry c_asn1_sc_hsm_pka_old_format[C_ASN1_SC_HSM_PKA_OLD_SIZE] = {
+	{ "publicKey", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_APP | 7, 0, NULL, NULL },
+	{ "deviceCVCert", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_APP | 0x1F21, 0, NULL, NULL },
+	{ "dicaCVCert", SC_ASN1_STRUCT, SC_ASN1_CONS | SC_ASN1_APP | 0x1F21, 0, NULL, NULL },
+	{ NULL, 0, 0, 0, NULL, NULL }
+};
 
 
 static int read_file(sc_pkcs15_card_t * p15card, u8 fid[2],
@@ -261,37 +281,45 @@
 	return SC_SUCCESS;
 }
 
-
+static void fixup_cvc_printable_string_lengths(sc_cvc_t *cvc)
+{
+	/* SC_ASN1_PRINTABLESTRING adds 1 for the null-terminator */
+	if (cvc->chrLen > 0) {
+		cvc->chrLen--;
+	}
+	if (cvc->carLen > 0) {
+		cvc->carLen--;
+	}
+	if (cvc->outerCARLen > 0) {
+		cvc->outerCARLen--;
+	}
+}
 
 /*
- * Decode a card verifiable certificate as defined in TR-03110.
+ * Sets up asn1_cvcert to point to asn1_cvc_body, asn1_cvc_pubkey, and
+ * cvc. When sc_asn1_decode is called on asn1_cvcert, it will populate fields
+ * in cvc.
+ *
+ * @param asn1_cvcert: unpopulated array with len matching c_asn1_cvcert
+ * @param asn1_cvc_cert: unpopulated array with len matching c_asn1_cvc_body
+ * @param asn1_cvc_pubkey: unpopulated array matching c_asn1_cvc_pubkey
+ * @param cvc: non NULL cvc struct
  */
-int sc_pkcs15emu_sc_hsm_decode_cvc(sc_pkcs15_card_t * p15card,
-											const u8 ** buf, size_t *buflen,
-											sc_cvc_t *cvc)
+static int sc_pkcs15emu_sc_hsm_format_asn1_cvcert(
+		struct sc_asn1_entry *asn1_cvcert, size_t asn1_cvcert_len,
+		struct sc_asn1_entry *asn1_cvc_body, size_t asn1_cvc_body_len,
+		struct sc_asn1_entry *asn1_cvc_pubkey, size_t asn1_cvc_pubkey_len,
+		sc_cvc_t *cvc)
 {
-	sc_card_t *card = p15card->card;
-	struct sc_asn1_entry asn1_req[C_ASN1_REQ_SIZE];
-	struct sc_asn1_entry asn1_authreq[C_ASN1_AUTHREQ_SIZE];
-	struct sc_asn1_entry asn1_cvc[C_ASN1_CVC_SIZE];
-	struct sc_asn1_entry asn1_cvcert[C_ASN1_CVCERT_SIZE];
-	struct sc_asn1_entry asn1_cvc_body[C_ASN1_CVC_BODY_SIZE];
-	struct sc_asn1_entry asn1_cvc_pubkey[C_ASN1_CVC_PUBKEY_SIZE];
-	unsigned int cla,tag;
-	size_t taglen;
-	size_t lenchr = sizeof(cvc->chr);
-	size_t lencar = sizeof(cvc->car);
-	size_t lenoutercar = sizeof(cvc->outer_car);
-	const u8 *tbuf;
-	int r;
+	if ((asn1_cvc_pubkey_len < C_ASN1_CVC_PUBKEY_SIZE) ||
+		(asn1_cvc_body_len < C_ASN1_CVC_BODY_SIZE) ||
+		(asn1_cvcert_len < C_ASN1_CVCERT_SIZE)) {
+		return SC_ERROR_BUFFER_TOO_SMALL;
+	}
 
-	memset(cvc, 0, sizeof(*cvc));
-	sc_copy_asn1_entry(c_asn1_req, asn1_req);
-	sc_copy_asn1_entry(c_asn1_authreq, asn1_authreq);
-	sc_copy_asn1_entry(c_asn1_cvc, asn1_cvc);
-	sc_copy_asn1_entry(c_asn1_cvcert, asn1_cvcert);
-	sc_copy_asn1_entry(c_asn1_cvc_body, asn1_cvc_body);
 	sc_copy_asn1_entry(c_asn1_cvc_pubkey, asn1_cvc_pubkey);
+	sc_copy_asn1_entry(c_asn1_cvc_body, asn1_cvc_body);
+	sc_copy_asn1_entry(c_asn1_cvcert, asn1_cvcert);
 
 	sc_format_asn1_entry(asn1_cvc_pubkey    , &cvc->pukoid, NULL, 0);
 	sc_format_asn1_entry(asn1_cvc_pubkey + 1, &cvc->primeOrModulus, &cvc->primeOrModuluslen, 0);
@@ -304,20 +332,84 @@
 	sc_format_asn1_entry(asn1_cvc_pubkey + 8, &cvc->modulusSize, NULL, 0);
 
 	sc_format_asn1_entry(asn1_cvc_body    , &cvc->cpi, NULL, 0);
-	sc_format_asn1_entry(asn1_cvc_body + 1, &cvc->car, &lencar, 0);
-	sc_format_asn1_entry(asn1_cvc_body + 2, &asn1_cvc_pubkey, NULL, 0);
-	sc_format_asn1_entry(asn1_cvc_body + 3, &cvc->chr, &lenchr, 0);
+	cvc->carLen = sizeof(cvc->car);
+	sc_format_asn1_entry(asn1_cvc_body + 1, &cvc->car, &cvc->carLen, 0);
+	sc_format_asn1_entry(asn1_cvc_body + 2, asn1_cvc_pubkey, NULL, 0);
+	cvc->chrLen = sizeof(cvc->chr);
+	sc_format_asn1_entry(asn1_cvc_body + 3, &cvc->chr, &cvc->chrLen, 0);
 
-	sc_format_asn1_entry(asn1_cvcert    , &asn1_cvc_body, NULL, 0);
+	sc_format_asn1_entry(asn1_cvcert    , asn1_cvc_body, NULL, 0);
 	sc_format_asn1_entry(asn1_cvcert + 1, &cvc->signature, &cvc->signatureLen, 0);
+	return SC_SUCCESS;
+}
 
-	sc_format_asn1_entry(asn1_cvc , &asn1_cvcert, NULL, 0);
+/*
+ * Sets up asn1_req to point to asn1_authreq, which points to asn1_cvcert and
+ * cvc
+ * When sc_asn1_decode is called on asn1_authreq, it will populate fields
+ * in cvc and asn1_cvcert
+ *
+ * @param asn1_authreq: unpopulated array with len matching c_asn1_req
+ * @param asn1_authreq: unpopulated array with len matching c_asn1_authreq
+ * @param asn1_cvcert: already-initialized array matching c_asn1_cvcert
+ *
+ */
+static int sc_pkcs15emu_sc_hsm_format_asn1_req(
+		struct sc_asn1_entry *asn1_authreq, size_t asn1_authreq_len,
+		struct sc_asn1_entry *asn1_cvcert,
+		sc_cvc_t *cvc)
+{
+	if (asn1_authreq_len < C_ASN1_AUTHREQ_SIZE) {
+		return SC_ERROR_BUFFER_TOO_SMALL;
+	}
+
+	sc_copy_asn1_entry(c_asn1_authreq, asn1_authreq);
 
-	sc_format_asn1_entry(asn1_authreq    , &asn1_cvcert, NULL, 0);
-	sc_format_asn1_entry(asn1_authreq + 1, &cvc->outer_car, &lenoutercar, 0);
+	sc_format_asn1_entry(asn1_authreq    , asn1_cvcert, NULL, 0);
+	cvc->outerCARLen = sizeof(cvc->outer_car);
+	sc_format_asn1_entry(asn1_authreq + 1, &cvc->outer_car, &cvc->outerCARLen, 0);
 	sc_format_asn1_entry(asn1_authreq + 2, &cvc->outerSignature, &cvc->outerSignatureLen, 0);
+	return SC_SUCCESS;
+}
+
+/*
+ * Decode a card verifiable certificate as defined in TR-03110.
+ */
+int sc_pkcs15emu_sc_hsm_decode_cvc(sc_pkcs15_card_t * p15card,
+	const u8 ** buf, size_t *buflen,
+	sc_cvc_t *cvc)
+{
+	sc_card_t *card = p15card->card;
+	struct sc_asn1_entry asn1_req[C_ASN1_REQ_SIZE];
+	struct sc_asn1_entry asn1_authreq[C_ASN1_AUTHREQ_SIZE];
+	struct sc_asn1_entry asn1_cvc[C_ASN1_CVC_SIZE];
+	struct sc_asn1_entry asn1_cvcert[C_ASN1_CVCERT_SIZE];
+	struct sc_asn1_entry asn1_cvc_body[C_ASN1_CVC_BODY_SIZE];
+	struct sc_asn1_entry asn1_cvc_pubkey[C_ASN1_CVC_PUBKEY_SIZE];
+	unsigned int cla,tag;
+	size_t taglen;
+	const u8 *tbuf;
+	int r;
+
+	memset(cvc, 0, sizeof(*cvc));
+	sc_copy_asn1_entry(c_asn1_req, asn1_req);
+	sc_copy_asn1_entry(c_asn1_cvc, asn1_cvc);
 
-	sc_format_asn1_entry(asn1_req , &asn1_authreq, NULL, 0);
+	r = sc_pkcs15emu_sc_hsm_format_asn1_cvcert(
+			asn1_cvcert, C_ASN1_CVCERT_SIZE,
+			asn1_cvc_body, C_ASN1_CVC_BODY_SIZE,
+			asn1_cvc_pubkey, C_ASN1_CVC_PUBKEY_SIZE,
+			cvc);
+	LOG_TEST_RET(card->ctx, r, "sc_asn1_entry array too small");
+
+	sc_format_asn1_entry(asn1_cvc, asn1_cvcert, NULL, 0);
+
+	r = sc_pkcs15emu_sc_hsm_format_asn1_req(
+			asn1_authreq, C_ASN1_AUTHREQ_SIZE,
+			asn1_cvcert, cvc);
+	LOG_TEST_RET(card->ctx, r, "sc_asn1_entry array too small");
+
+	sc_format_asn1_entry(asn1_req, asn1_authreq, NULL, 0);
 
 /*	sc_asn1_print_tags(*buf, *buflen); */
 
@@ -334,11 +426,338 @@
 
 	LOG_TEST_RET(card->ctx, r, "Could not decode card verifiable certificate");
 
+	fixup_cvc_printable_string_lengths(cvc);
+
 	LOG_FUNC_RETURN(card->ctx, SC_SUCCESS);
 }
 
+struct sc_asn1_cvc_format {
+	struct sc_asn1_entry asn1_cvc[C_ASN1_CVC_SIZE];
+	struct sc_asn1_entry asn1_cvcert[C_ASN1_CVCERT_SIZE];
+	struct sc_asn1_entry asn1_cvc_body[C_ASN1_CVC_BODY_SIZE];
+	struct sc_asn1_entry asn1_cvc_pubkey[C_ASN1_CVC_PUBKEY_SIZE];
+};
+
+struct sc_asn1_sc_hsm_pka_callback_arg {
+	sc_context_t *ctx;
+	struct sc_asn1_entry *next_entry;
+	sc_cvc_pka_component_t *component;
+};
 
 
+struct sc_asn1_sc_hsm_pka_data {
+	struct sc_asn1_entry asn1_public_key_req[C_ASN1_REQ_SIZE];
+	struct sc_asn1_entry asn1_public_key_authreq[C_ASN1_AUTHREQ_SIZE];
+	struct sc_asn1_cvc_format asn1_public_key_cvc;
+	struct sc_asn1_cvc_format asn1_device_cvc;
+	struct sc_asn1_cvc_format asn1_dica_cvc;
+	struct sc_asn1_sc_hsm_pka_callback_arg public_key_req_arg;
+	struct sc_asn1_sc_hsm_pka_callback_arg device_arg;
+	struct sc_asn1_sc_hsm_pka_callback_arg dica_arg;
+};
+
+struct sc_asn1_sc_hsm_pka_new_format {
+	struct sc_asn1_entry seq[C_ASN1_SC_HSM_PKA_NEW_SIZE];
+	struct sc_asn1_sc_hsm_pka_data data;
+	struct sc_object_id oid;
+};
+
+struct sc_asn1_sc_hsm_pka_old_format {
+	struct sc_asn1_entry seq[C_ASN1_SC_HSM_PKA_OLD_SIZE];
+	struct sc_asn1_sc_hsm_pka_data data;
+};
+
+/*
+ * Saves the current pointer then continues to decode
+ */
+static int sc_asn1_sc_hsm_pka_set_ptr_callback(
+		sc_context_t *nctx, void *arg, const u8 *obj,
+		size_t objlen, int depth)
+{
+	struct sc_asn1_sc_hsm_pka_callback_arg *carg = arg;
+
+	carg->component->ptr = obj;
+	carg->component->len = objlen;
+
+	return sc_asn1_decode(carg->ctx, carg->next_entry, obj, objlen, NULL, NULL);
+}
+
+static int sc_asn1_sc_hsm_pka_data_init(sc_context_t *ctx,
+	struct sc_asn1_sc_hsm_pka_data *data,
+	sc_cvc_pka_t *pka)
+{
+	int r;
+
+	data->public_key_req_arg.ctx = ctx;
+	data->device_arg.ctx = ctx;
+	data->dica_arg.ctx = ctx;
+
+	/* public key info is in an authenticatedrequest (0x67) */
+	r = sc_pkcs15emu_sc_hsm_format_asn1_cvcert(
+			data->asn1_public_key_cvc.asn1_cvcert, C_ASN1_CVCERT_SIZE,
+			data->asn1_public_key_cvc.asn1_cvc_body, C_ASN1_CVC_BODY_SIZE,
+			data->asn1_public_key_cvc.asn1_cvc_pubkey, C_ASN1_CVC_PUBKEY_SIZE,
+			&pka->public_key_req.cvc);
+	LOG_TEST_RET(ctx, r, "sc_asn1_entry too small");
+
+	r = sc_pkcs15emu_sc_hsm_format_asn1_req(
+			data->asn1_public_key_authreq, C_ASN1_AUTHREQ_SIZE,
+			data->asn1_public_key_cvc.asn1_cvcert,
+			&pka->public_key_req.cvc);
+	LOG_TEST_RET(ctx, r, "sc_asn1_entry too small");
+
+	/*
+	 * insert a callback between req and authreq
+	 * the HSM expects the contents of the 0x67 authenticatedrequest tag (not
+	 * including the 0x67 tag itself)
+	 */
+	sc_copy_asn1_entry(c_asn1_req, data->asn1_public_key_req);
+	data->asn1_public_key_req[0].type = SC_ASN1_CALLBACK;
+	data->public_key_req_arg.component = &pka->public_key_req;
+	data->public_key_req_arg.next_entry = data->asn1_public_key_authreq;
+	sc_format_asn1_entry(data->asn1_public_key_req,
+			sc_asn1_sc_hsm_pka_set_ptr_callback,
+			&data->public_key_req_arg, 0);
+
+	/* device CVC is a certificate (0x7F21) */
+	r = sc_pkcs15emu_sc_hsm_format_asn1_cvcert(
+			data->asn1_device_cvc.asn1_cvcert, C_ASN1_CVCERT_SIZE,
+			data->asn1_device_cvc.asn1_cvc_body, C_ASN1_CVC_BODY_SIZE,
+			data->asn1_device_cvc.asn1_cvc_pubkey, C_ASN1_CVC_PUBKEY_SIZE,
+			&pka->device.cvc);
+	LOG_TEST_RET(ctx, r, "sc_asn1_entry too small");
+
+	/*
+	 * insert a callback between asn1_cvc and asn1_cvcert
+	 * the HSM expects the contents of the 0x7F21 CVC tag (not including the
+	 * 0x7F21 tag itself)
+	 */
+	sc_copy_asn1_entry(c_asn1_cvc, data->asn1_device_cvc.asn1_cvc);
+	data->asn1_device_cvc.asn1_cvc[0].type = SC_ASN1_CALLBACK;
+	data->device_arg.component = &pka->device;
+	data->device_arg.next_entry = data->asn1_device_cvc.asn1_cvcert;
+	sc_format_asn1_entry(data->asn1_device_cvc.asn1_cvc,
+			sc_asn1_sc_hsm_pka_set_ptr_callback,
+			&data->device_arg, 0);
+
+	/* device issuer CA CVC is a certificate (0x7F21) */
+	r = sc_pkcs15emu_sc_hsm_format_asn1_cvcert(
+			data->asn1_dica_cvc.asn1_cvcert, C_ASN1_CVCERT_SIZE,
+			data->asn1_dica_cvc.asn1_cvc_body, C_ASN1_CVC_BODY_SIZE,
+			data->asn1_dica_cvc.asn1_cvc_pubkey, C_ASN1_CVC_PUBKEY_SIZE,
+			&pka->dica.cvc);
+	LOG_TEST_RET(ctx, r, "sc_asn1_entry too small");
+
+	/*
+	 * insert a callback between asn1_cvc and asn1_cvcert
+	 * the HSM expects the contents of the 0x7F21 CVC tag (not including the
+	 * 0x7F21 tag itself)
+	 */
+	sc_copy_asn1_entry(c_asn1_cvc, data->asn1_dica_cvc.asn1_cvc);
+	data->asn1_dica_cvc.asn1_cvc[0].type = SC_ASN1_CALLBACK;
+	data->dica_arg.component = &pka->dica;
+	data->dica_arg.next_entry = data->asn1_dica_cvc.asn1_cvcert;
+	sc_format_asn1_entry(data->asn1_dica_cvc.asn1_cvc,
+			sc_asn1_sc_hsm_pka_set_ptr_callback,
+			&data->dica_arg, 0);
+	return SC_SUCCESS;
+}
+
+/*
+ * For SmartCard HSMs, this is the older format for registering a public key
+ * for public key authentication.
+ *
+ * @param buf: *buf should point to the first tag in the sequence
+ *
+ * SEQUENCE (0x30)
+ *	 authenticatedrequest for public key details (0x67)
+ *	 device CVC (0x7F21)
+ *	 device issuer CA CVC (0x7F21)
+ */
+static int decode_pka_old_format(sc_pkcs15_card_t *p15card,
+	const u8 **buf, size_t *buflen,
+	sc_cvc_pka_t *pka)
+{
+	int r;
+	sc_card_t *card;
+	struct sc_asn1_sc_hsm_pka_old_format *format = NULL;
+
+	card = p15card->card;
+
+	format = calloc(1, sizeof(*format));
+	if (format == NULL) {
+		r = SC_ERROR_OUT_OF_MEMORY;
+		goto err;
+	}
+
+	r = sc_asn1_sc_hsm_pka_data_init(card->ctx, &format->data, pka);
+	LOG_TEST_GOTO_ERR(card->ctx, r, "sc_asn1_entry array too small");
+
+	sc_copy_asn1_entry(c_asn1_sc_hsm_pka_old_format, format->seq);
+	format->seq[0] = format->data.asn1_public_key_req[0];
+	format->seq[1] = format->data.asn1_device_cvc.asn1_cvc[0];
+	format->seq[2] = format->data.asn1_dica_cvc.asn1_cvc[0];
+
+	r = sc_asn1_decode(p15card->card->ctx, format->seq, *buf, *buflen,
+			buf, buflen);
+	LOG_TEST_GOTO_ERR(card->ctx, r,
+		"Could not decode ASN.1 for public key file's old format");
+
+	r = SC_SUCCESS;
+	/* fall-through */
+
+err:
+	free(format);
+	format = NULL;
+	return r;
+}
+
+/*
+ * For SmartCard HSMs, this is the newer format for registering a public key
+ * for public key authentication.
+ *
+ * @param buf: *buf should point to the first tag after the sequence tag
+ *
+ * 1.3.6.1.4.1.24991 is the CardContact organization
+ * The 4.3.1 part is from inspecting their exported public key, but it doesn't
+ * seem to be publicly registered.
+ *
+ * SEQUENCE (0x30)
+ *   OID (0x6) 1.3.6.1.4.1.24991.4.3.1
+ *   Application 1 (0x61)
+ *      device CVC (0x7F21)
+ *   Application 2 (0x62)
+ *      device issuer CA CVC (0x7F21)
+ *   Application 3 (0x63)
+ *      authenticatedrequest for public key details (0x67)
+ */
+static int decode_pka_new_format(sc_pkcs15_card_t *p15card,
+	const u8 **buf, size_t *buflen,
+	sc_cvc_pka_t *pka)
+{
+	int r;
+	sc_card_t *card;
+	struct sc_asn1_sc_hsm_pka_new_format *format = NULL;
+
+	card = p15card->card;
+
+	format = calloc(1, sizeof(*format));
+	if (format == NULL) {
+		r = SC_ERROR_OUT_OF_MEMORY;
+		goto err;
+	}
+
+	r = sc_asn1_sc_hsm_pka_data_init(card->ctx, &format->data, pka);
+	LOG_TEST_GOTO_ERR(card->ctx, r, "sc_asn1_entry array too small");
+
+	sc_copy_asn1_entry(c_asn1_sc_hsm_pka_new_format, format->seq);
+	sc_format_asn1_entry(&format->seq[0], &format->oid, NULL, 0);
+	sc_format_asn1_entry(&format->seq[1],
+			format->data.asn1_dica_cvc.asn1_cvc, NULL, 0);
+	sc_format_asn1_entry(&format->seq[2],
+			format->data.asn1_device_cvc.asn1_cvc, NULL, 0);
+	sc_format_asn1_entry(&format->seq[3],
+			format->data.asn1_public_key_req, NULL, 0);
+
+	r = sc_asn1_decode(p15card->card->ctx, format->seq, *buf, *buflen,
+			buf, buflen);
+	LOG_TEST_GOTO_ERR(card->ctx, r,
+		"Could not decode ASN.1 for public key file's new format");
+
+	if (sc_compare_oid(&format->oid, &sc_hsm_public_key_oid) == 0) {
+		/* sc_dump_oid uses static memory */
+		sc_log(p15card->card->ctx, "OID %s did not match expected value",
+			   sc_dump_oid(&format->oid));
+		r = -1;
+		goto err;
+	}
+
+	r = SC_SUCCESS;
+	/* fall-through */
+
+err:
+	free(format);
+	format = NULL;
+	return r;
+}
+
+/*
+ * @param pka: will be overwritten, should be uninitialized or memset to 0
+ */
+int sc_pkcs15emu_sc_hsm_decode_pka(sc_pkcs15_card_t *p15card,
+	const u8 **buf, size_t *buflen,
+	sc_cvc_pka_t *pka)
+{
+	int r;
+	const u8 *curr;
+	const u8 *peek;
+	unsigned int cla, tag;
+	size_t taglen;
+	size_t currlen;
+	sc_card_t *card;
+
+	memset(pka, 0, sizeof(*pka));
+
+	card = p15card->card;
+	curr = *buf;
+	currlen = *buflen;
+
+	/* first tag should be sequence */
+	r = sc_asn1_read_tag(&curr, currlen, &cla, &tag, &taglen);
+	LOG_TEST_GOTO_ERR(card->ctx, r,
+			"Could not decode first sequence tag for public key file");
+	currlen = *buflen - (curr - *buf);
+
+	if ((cla != (SC_ASN1_TAG_UNIVERSAL|SC_ASN1_TAG_CONSTRUCTED)) ||
+			(tag != SC_ASN1_TAG_SEQUENCE)) {
+		sc_log(card->ctx,
+			   "Expected sequence tag, but got tag %u class 0x%x", tag, cla);
+		r = SC_ERROR_INVALID_ASN1_OBJECT;
+		goto err;
+	}
+
+	/* next tag is either OID (new format) or 0x67 (old format) */
+	peek = curr;
+	r = sc_asn1_read_tag(&peek, currlen, &cla, &tag, &taglen);
+	LOG_TEST_GOTO_ERR(card->ctx, r,
+			"Could not decode first sequence element tag for public key file");
+
+	if (tag == SC_ASN1_TAG_OBJECT) {
+		/* OID means it's the new format */
+		r = decode_pka_new_format(p15card, &curr, &currlen, pka);
+		LOG_TEST_GOTO_ERR(card->ctx, r,
+			"Could not decode public key file new format");
+	} else if ((cla == (SC_ASN1_TAG_APPLICATION|SC_ASN1_TAG_CONSTRUCTED)) &&
+				(tag == 7)) {
+		/*
+		 * if it's authenticatedrequest (Application 7 / 0x67), then attempt
+		 * to parse the old format
+		 */
+		r = decode_pka_old_format(p15card, &curr, &currlen, pka);
+		LOG_TEST_GOTO_ERR(card->ctx, r,
+			"Could not decode authenticatedrequest for public key file");
+	} else {
+		sc_log(card->ctx,
+				"Unexpected tag %u class 0x%x for first element of sequence",
+				tag, cla);
+		r = SC_ERROR_INVALID_ASN1_OBJECT;
+		goto err;
+	}
+
+	fixup_cvc_printable_string_lengths(&pka->public_key_req.cvc);
+	fixup_cvc_printable_string_lengths(&pka->device.cvc);
+	fixup_cvc_printable_string_lengths(&pka->dica.cvc);
+
+	*buf = curr;
+	*buflen = *buflen - (curr - *buf);
+
+	return SC_SUCCESS;
+
+err:
+	sc_pkcs15emu_sc_hsm_free_cvc_pka(pka);
+	return r;
+}
+
 /*
  * Encode a card verifiable certificate as defined in TR-03110.
  */
@@ -351,8 +770,6 @@
 	struct sc_asn1_entry asn1_cvcert[C_ASN1_CVCERT_SIZE];
 	struct sc_asn1_entry asn1_cvc_body[C_ASN1_CVC_BODY_SIZE];
 	struct sc_asn1_entry asn1_cvc_pubkey[C_ASN1_CVC_PUBKEY_SIZE];
-	size_t lenchr;
-	size_t lencar;
 	int r;
 
 	sc_copy_asn1_entry(c_asn1_cvc, asn1_cvc);
@@ -382,11 +799,9 @@
 	}
 
 	sc_format_asn1_entry(asn1_cvc_body    , &cvc->cpi, NULL, 1);
-	lencar = strnlen(cvc->car, sizeof cvc->car);
-	sc_format_asn1_entry(asn1_cvc_body + 1, &cvc->car, &lencar, 1);
+	sc_format_asn1_entry(asn1_cvc_body + 1, &cvc->car, &cvc->carLen, 1);
 	sc_format_asn1_entry(asn1_cvc_body + 2, &asn1_cvc_pubkey, NULL, 1);
-	lenchr = strnlen(cvc->chr, sizeof cvc->chr);
-	sc_format_asn1_entry(asn1_cvc_body + 3, &cvc->chr, &lenchr, 1);
+	sc_format_asn1_entry(asn1_cvc_body + 3, &cvc->chr, &cvc->chrLen, 1);
 
 	sc_format_asn1_entry(asn1_cvcert    , &asn1_cvc_body, NULL, 1);
 	if (cvc->signature && (cvc->signatureLen > 0)) {
@@ -542,6 +957,10 @@
 
 void sc_pkcs15emu_sc_hsm_free_cvc(sc_cvc_t *cvc)
 {
+	if (cvc->outerSignature) {
+		free(cvc->outerSignature);
+		cvc->outerSignature = NULL;
+	}
 	if (cvc->signature) {
 		free(cvc->signature);
 		cvc->signature = NULL;
@@ -576,7 +995,13 @@
 	}
 }
 
-
+void sc_pkcs15emu_sc_hsm_free_cvc_pka(sc_cvc_pka_t *pka)
+{
+	sc_pkcs15emu_sc_hsm_free_cvc(&pka->public_key_req.cvc);
+	sc_pkcs15emu_sc_hsm_free_cvc(&pka->device.cvc);
+	sc_pkcs15emu_sc_hsm_free_cvc(&pka->dica.cvc);
+	memset(pka, 0, sizeof(*pka));
+}
 
 static int sc_pkcs15emu_sc_hsm_add_pubkey(sc_pkcs15_card_t *p15card, u8 *efbin, size_t len, sc_pkcs15_prkey_info_t *key_info, char *label)
 {
@@ -622,6 +1047,8 @@
 		pubkey_info.usage = SC_PKCS15_PRKEY_USAGE_VERIFY;
 		r = sc_pkcs15emu_add_ec_pubkey(p15card, &pubkey_obj, &pubkey_info);
 	}
+	if (r < 0)
+		free(pubkey_info.direct.spki.value);
 	LOG_TEST_RET(ctx, r, "Could not add public key");
 
 	sc_pkcs15emu_sc_hsm_free_cvc(&cvc);
@@ -930,13 +1357,17 @@
 		} else {
 			p15card->tokeninfo->manufacturer_id = strdup("www.CardContact.de");
 		}
-		if (p15card->tokeninfo->manufacturer_id == NULL)
+		if (p15card->tokeninfo->manufacturer_id == NULL) {
+			sc_pkcs15_card_clear(p15card);
 			LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
+		}
 	}
 
 	appinfo->label = strdup(p15card->tokeninfo->label);
-	if (appinfo->label == NULL)
+	if (appinfo->label == NULL) {
+		sc_pkcs15_card_clear(p15card);
 		LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
+	}
 
 	len = strnlen(devcert.chr, sizeof devcert.chr);		/* Strip last 5 digit sequence number from CHR */
 	assert(len >= 8);
@@ -944,8 +1375,10 @@
 
 	free(p15card->tokeninfo->serial_number);
 	p15card->tokeninfo->serial_number = calloc(len + 1, 1);
-	if (p15card->tokeninfo->serial_number == NULL)
+	if (p15card->tokeninfo->serial_number == NULL) {
+		sc_pkcs15_card_clear(p15card);
 		LOG_FUNC_RETURN(card->ctx, SC_ERROR_OUT_OF_MEMORY);
+	}
 
 	memcpy(p15card->tokeninfo->serial_number, devcert.chr, len);
 	*(p15card->tokeninfo->serial_number + len) = 0;
@@ -977,8 +1410,10 @@
 	pin_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE|SC_PKCS15_CO_FLAG_MODIFIABLE;
 
 	r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
-	if (r < 0)
+	if (r < 0) {
+		sc_pkcs15_card_clear(p15card);
 		LOG_FUNC_RETURN(card->ctx, r);
+	}
 
 	memset(&pin_info, 0, sizeof(pin_info));
 	memset(&pin_obj, 0, sizeof(pin_obj));
@@ -1001,8 +1436,10 @@
 	pin_obj.flags = SC_PKCS15_CO_FLAG_PRIVATE;
 
 	r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
-	if (r < 0)
+	if (r < 0) {
+		sc_pkcs15_card_clear(p15card);
 		LOG_FUNC_RETURN(card->ctx, r);
+	}
 
 
 	if (card->type == SC_CARD_TYPE_SC_HSM_SOC
@@ -1031,6 +1468,8 @@
 
 
 	filelistlength = sc_list_files(card, filelist, sizeof(filelist));
+	if (filelistlength < 0)
+		sc_pkcs15_card_clear(p15card);
 	LOG_TEST_RET(card->ctx, filelistlength, "Could not enumerate file and key identifier");
 
 	for (i = 0; i < filelistlength; i += 2) {
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-sec.c opensc-0.23.0/src/libopensc/pkcs15-sec.c
--- opensc-0.22.0/src/libopensc/pkcs15-sec.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-sec.c	2022-11-29 09:34:43.000000000 +0100
@@ -249,7 +249,7 @@
 			senv_out->algorithm_ref = prkey->field_length;
 			break;
 		case SC_PKCS15_TYPE_SKEY_GENERIC:
-			if (obj->type == SC_PKCS15_TYPE_SKEY_GENERIC && skey->key_type != CKK_AES)
+			if (skey->key_type != CKK_AES)
 				LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Key type not supported");
 			*alg_info_out = sc_card_find_alg(p15card->card, SC_ALGORITHM_AES,
 			skey->value_len, NULL);
@@ -280,7 +280,7 @@
 int sc_pkcs15_decipher(struct sc_pkcs15_card *p15card,
 		const struct sc_pkcs15_object *obj,
 		unsigned long flags,
-		const u8 * in, size_t inlen, u8 *out, size_t outlen)
+		const u8 * in, size_t inlen, u8 *out, size_t outlen, void *pMechanism)
 {
 	sc_context_t *ctx = p15card->card->ctx;
 	int r;
@@ -312,7 +312,26 @@
 		r = sc_pkcs1_strip_02_padding(ctx, out, s, out, &s);
 		LOG_TEST_RET(ctx, r, "Invalid PKCS#1 padding");
 	}
-
+#ifdef ENABLE_OPENSSL
+	if (pad_flags & SC_ALGORITHM_RSA_PAD_OAEP)
+	{
+		size_t s = r;
+		uint8_t *param = NULL;
+		size_t paramlen = 0;
+		if (pMechanism != NULL) {
+			CK_MECHANISM *mech = (CK_MECHANISM *)pMechanism;
+			if (mech->pParameter && sizeof(CK_RSA_PKCS_OAEP_PARAMS) == mech->ulParameterLen) {
+				CK_RSA_PKCS_OAEP_PARAMS * oaep_params = mech->pParameter;
+				if (oaep_params->source == CKZ_DATA_SPECIFIED) {
+					param = oaep_params->pSourceData;
+					paramlen = (size_t)oaep_params->ulSourceDataLen;
+				}
+			}
+		}
+		r = sc_pkcs1_strip_oaep_padding(ctx, out, s, flags, param, paramlen);
+		LOG_TEST_RET(ctx, r, "Invalid OAEP padding");
+	}
+#endif
 	LOG_FUNC_RETURN(ctx, r);
 }
 
@@ -574,15 +593,15 @@
 int sc_pkcs15_compute_signature(struct sc_pkcs15_card *p15card,
 				const struct sc_pkcs15_object *obj,
 				unsigned long flags, const u8 *in, size_t inlen,
-				u8 *out, size_t outlen)
+				u8 *out, size_t outlen, void *pMechanism)
 {
 	sc_context_t *ctx = p15card->card->ctx;
 	int r;
 	sc_security_env_t senv;
 	sc_algorithm_info_t *alg_info;
 	const struct sc_pkcs15_prkey_info *prkey = (const struct sc_pkcs15_prkey_info *) obj->data;
-	u8 buf[1024], *tmp;
-	size_t modlen;
+	u8 *buf = NULL, *tmp;
+	size_t modlen = 0, buflen = 0;
 	unsigned long pad_flags = 0, sec_flags = 0;
 
 	LOG_FUNC_CALLED(ctx);
@@ -612,9 +631,13 @@
 	}
 
 	/* Probably never happens, but better make sure */
-	if (inlen > sizeof(buf) || outlen < modlen)
+	if (outlen < modlen)
 		LOG_FUNC_RETURN(ctx, SC_ERROR_BUFFER_TOO_SMALL);
 
+	buflen = inlen + modlen;
+	buf = sc_mem_secure_alloc(buflen);
+	if (buf == NULL)
+		LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
 	memcpy(buf, in, inlen);
 
 	/* revert data to sign when signing with the GOST key.
@@ -622,7 +645,7 @@
 	 * TODO: tested with RuTokenECP, has to be validated for RuToken. */
 	if (obj->type == SC_PKCS15_TYPE_PRKEY_GOSTR3410) {
 		r = sc_mem_reverse(buf, inlen);
-		LOG_TEST_RET(ctx, r, "Reverse memory error");
+		LOG_TEST_GOTO_ERR(ctx, r, "Reverse memory error");
 	}
 
 	tmp = buf;
@@ -639,26 +662,26 @@
 		if ((alg_info->flags & SC_ALGORITHM_NEED_USAGE) &&
 			((prkey->usage & USAGE_ANY_SIGN) &&
 			(prkey->usage & USAGE_ANY_DECIPHER)) ) {
-			size_t tmplen = sizeof(buf);
+			size_t tmplen = buflen;
 			if (flags & SC_ALGORITHM_RSA_RAW) {
-				r = sc_pkcs15_decipher(p15card, obj, flags, in, inlen, out, outlen);
-				LOG_FUNC_RETURN(ctx, r);
+				r = sc_pkcs15_decipher(p15card, obj, flags, in, inlen, out, outlen, NULL);
+				goto err;
 			}
 			if (modlen > tmplen)
-				LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "Buffer too small, needs recompile!");
+				LOG_TEST_GOTO_ERR(ctx, SC_ERROR_NOT_ALLOWED, "Buffer too small, needs recompile!");
 
 			/* XXX Assuming RSA key here */
-			r = sc_pkcs1_encode(ctx, flags, in, inlen, buf, &tmplen, prkey->modulus_length);
+			r = sc_pkcs1_encode(ctx, flags, in, inlen, buf, &tmplen, prkey->modulus_length, pMechanism);
 
 			/* no padding needed - already done */
 			flags &= ~SC_ALGORITHM_RSA_PADS;
 			/* instead use raw rsa */
 			flags |= SC_ALGORITHM_RSA_RAW;
 
-			LOG_TEST_RET(ctx, r, "Unable to add padding");
+			LOG_TEST_GOTO_ERR(ctx, r, "Unable to add padding");
 
-			r = sc_pkcs15_decipher(p15card, obj, flags, buf, modlen, out, outlen);
-			LOG_FUNC_RETURN(ctx, r);
+			r = sc_pkcs15_decipher(p15card, obj, flags, buf, modlen, out, outlen, NULL);
+			goto err;
 		}
 
 
@@ -673,12 +696,12 @@
 		    !(alg_info->flags & SC_ALGORITHM_RSA_HASH_NONE) &&
 		    (alg_info->flags & SC_ALGORITHM_RSA_PAD_PKCS1)) {
 			unsigned int algo;
-			size_t tmplen = sizeof(buf);
+			size_t tmplen = buflen;
 
 			r = sc_pkcs1_strip_digest_info_prefix(&algo, tmp, inlen, tmp, &tmplen);
 			if (r != SC_SUCCESS || algo == SC_ALGORITHM_RSA_HASH_NONE) {
-				sc_mem_clear(buf, sizeof(buf));
-				LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_DATA);
+				r = SC_ERROR_INVALID_DATA;
+				goto err;
 			}
 			flags &= ~SC_ALGORITHM_RSA_HASH_NONE;
 			flags |= algo;
@@ -687,7 +710,7 @@
 	}
 
 
-	/* ECDSA sofware hash has already been done, or is not needed, or card will do hash */
+	/* ECDSA software hash has already been done, or is not needed, or card will do hash */
 	/* if card can not do the hash, will use SC_ALGORITHM_ECDSA_RAW */
 	if (obj->type == SC_PKCS15_TYPE_PRKEY_EC) {
 		if ((alg_info->flags & SC_ALGORITHM_ECDSA_RAW)
@@ -700,8 +723,7 @@
 
 	r = sc_get_encoding_flags(ctx, flags, alg_info->flags, &pad_flags, &sec_flags);
 	if (r != SC_SUCCESS) {
-		sc_mem_clear(buf, sizeof(buf));
-		LOG_FUNC_RETURN(ctx, r);
+		goto err;
 	}
 	/* senv now has flags card or driver will do */
 	senv.algorithm_flags = sec_flags;
@@ -711,20 +733,22 @@
 
 	/* add the padding bytes (if necessary) */
 	if (pad_flags != 0) {
-		size_t tmplen = sizeof(buf);
+		size_t tmplen = buflen;
 
 		/* XXX Assuming RSA key here */
 		r = sc_pkcs1_encode(ctx, pad_flags, tmp, inlen, tmp, &tmplen,
-		    prkey->modulus_length);
-		LOG_TEST_RET(ctx, r, "Unable to add padding");
+		    prkey->modulus_length, pMechanism);
+		LOG_TEST_GOTO_ERR(ctx, r, "Unable to add padding");
 		inlen = tmplen;
 	}
 	else if ( senv.algorithm == SC_ALGORITHM_RSA &&
 	          (flags & SC_ALGORITHM_RSA_PADS) == SC_ALGORITHM_RSA_PAD_NONE) {
 		/* Add zero-padding if input is shorter than the modulus */
 		if (inlen < modlen) {
-			if (modlen > sizeof(buf))
-				return SC_ERROR_BUFFER_TOO_SMALL;
+			if (modlen > buflen) {
+				r = SC_ERROR_BUFFER_TOO_SMALL;
+				goto err;
+			}
 			memmove(tmp+modlen-inlen, tmp, inlen);
 			memset(tmp, 0, modlen-inlen);
 		}
@@ -744,7 +768,7 @@
 
 	r = use_key(p15card, obj, &senv, sc_compute_signature, tmp, inlen,
 			out, outlen);
-	LOG_TEST_RET(ctx, r, "use_key() failed");
+	LOG_TEST_GOTO_ERR(ctx, r, "use_key() failed");
 
 	/* Some cards may return RSA signature as integer without leading zero bytes */
 	/* Already know outlen >= modlen and r >= 0 */
@@ -754,7 +778,182 @@
 		r = modlen;
 	}
 
-	sc_mem_clear(buf, sizeof(buf));
+err:
+	sc_mem_secure_clear_free(buf, buflen);
+
+	LOG_FUNC_RETURN(ctx, r);
+}
+
+int
+sc_pkcs15_encrypt_sym(struct sc_pkcs15_card *p15card,
+		const struct sc_pkcs15_object *obj,
+		unsigned long flags,
+		const u8 *in, size_t inlen, u8 *out, size_t *outlen,
+		const u8 *param, size_t paramlen)
+{
+
+	sc_context_t *ctx = p15card->card->ctx;
+
+	int i, r;
+	sc_algorithm_info_t *alg_info = NULL;
+	sc_security_env_t senv;
+	sc_sec_env_param_t senv_param;
+	const struct sc_pkcs15_skey_info *skey;
+	unsigned long pad_flags = 0, sec_flags = 0;
+	int revalidated_cached_pin = 0;
+	sc_path_t path;
+
+	sc_log(ctx, "called with flags 0x%lX", flags);
+
+	skey = (const struct sc_pkcs15_skey_info *)obj->data;
+	if (!(skey->usage & SC_PKCS15_PRKEY_USAGE_ENCRYPT))
+		LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This key cannot be used for encryption");
+
+	r = format_senv(p15card, obj, &senv, &alg_info);
+	LOG_TEST_RET(ctx, r, "Could not initialize security environment");
+	senv.operation = SC_SEC_OPERATION_ENCRYPT_SYM;
+
+	r = sc_get_encoding_flags(ctx, flags, alg_info->flags, &pad_flags, &sec_flags);
+	LOG_TEST_RET(ctx, r, "cannot encode security operation flags");
+	senv.algorithm_flags = sec_flags;
+
+	for (i = 0; i < SC_MAX_SUPPORTED_ALGORITHMS && senv.supported_algos[i].reference; i++) {
+		if ((senv.supported_algos[i].mechanism == CKM_AES_ECB && sec_flags == SC_ALGORITHM_AES_ECB) ||
+				(senv.supported_algos[i].mechanism == CKM_AES_CBC && sec_flags == SC_ALGORITHM_AES_CBC) ||
+				(senv.supported_algos[i].mechanism == CKM_AES_CBC_PAD && sec_flags == SC_ALGORITHM_AES_CBC_PAD)) {
+			senv.algorithm_ref = senv.supported_algos[i].algo_ref;
+			senv.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
+			break;
+		}
+	}
+
+	if ((sec_flags & (SC_ALGORITHM_AES_CBC | SC_ALGORITHM_AES_CBC_PAD)) > 0) {
+		senv_param = (sc_sec_env_param_t){
+				SC_SEC_ENV_PARAM_IV, (void *)param, paramlen};
+		LOG_TEST_RET(ctx, sec_env_add_param(&senv, &senv_param), "failed to add IV to security environment");
+	}
+
+	LOG_TEST_RET(p15card->card->ctx, get_file_path(obj, &path), "Failed to get key file path.");
+
+	LOG_TEST_RET(p15card->card->ctx, r, "sc_lock() failed");
+
+	do {
+		r = SC_SUCCESS;
+		if (outlen == NULL) {
+			/* C_EncryptInit */
+			/* select key file and set sec env */
+			if (path.len != 0 || path.aid.len != 0) {
+				r = select_key_file(p15card, obj, &senv);
+				if (r < 0)
+					sc_log(p15card->card->ctx, "Unable to select key file");
+			}
+			if (r == SC_SUCCESS) {
+				r = sc_set_security_env(p15card->card, &senv, 0);
+				if (r < 0)
+					sc_log(p15card->card->ctx, "Unable to set security env");
+			}
+		}
+
+		if (r == SC_SUCCESS)
+			r = sc_encrypt_sym(p15card->card, in, inlen, out, outlen);
+
+		if (revalidated_cached_pin)
+			/* only re-validate once */
+			break;
+		if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) {
+			r = sc_pkcs15_pincache_revalidate(p15card, obj);
+			if (r < 0)
+				break;
+			revalidated_cached_pin = 1;
+		}
+	} while (revalidated_cached_pin);
+
+	LOG_FUNC_RETURN(ctx, r);
+}
+
+int
+sc_pkcs15_decrypt_sym(struct sc_pkcs15_card *p15card,
+		const struct sc_pkcs15_object *obj,
+		unsigned long flags,
+		const u8 *in, size_t inlen, u8 *out, size_t *outlen,
+		const u8 *param, size_t paramlen)
+{
+
+	sc_context_t *ctx = p15card->card->ctx;
+
+	int i, r;
+	sc_algorithm_info_t *alg_info = NULL;
+	sc_security_env_t senv;
+	sc_sec_env_param_t senv_param;
+	const struct sc_pkcs15_skey_info *skey;
+	unsigned long pad_flags = 0, sec_flags = 0;
+	int revalidated_cached_pin = 0;
+	sc_path_t path;
+
+	sc_log(ctx, "called with flags 0x%lX", flags);
+
+	skey = (const struct sc_pkcs15_skey_info *)obj->data;
+	if (!(skey->usage & SC_PKCS15_PRKEY_USAGE_DECRYPT))
+		LOG_TEST_RET(ctx, SC_ERROR_NOT_ALLOWED, "This key cannot be used for encryption");
+
+	r = format_senv(p15card, obj, &senv, &alg_info);
+	LOG_TEST_RET(ctx, r, "Could not initialize security environment");
+	senv.operation = SC_SEC_OPERATION_DECRYPT_SYM;
+
+	r = sc_get_encoding_flags(ctx, flags, alg_info->flags, &pad_flags, &sec_flags);
+	LOG_TEST_RET(ctx, r, "cannot encode security operation flags");
+	senv.algorithm_flags = sec_flags;
+
+	for (i = 0; i < SC_MAX_SUPPORTED_ALGORITHMS && senv.supported_algos[i].reference; i++) {
+		if ((senv.supported_algos[i].mechanism == CKM_AES_ECB && sec_flags == SC_ALGORITHM_AES_ECB) ||
+				(senv.supported_algos[i].mechanism == CKM_AES_CBC && sec_flags == SC_ALGORITHM_AES_CBC) ||
+				(senv.supported_algos[i].mechanism == CKM_AES_CBC_PAD && sec_flags == SC_ALGORITHM_AES_CBC_PAD)) {
+			senv.algorithm_ref = senv.supported_algos[i].algo_ref;
+			senv.flags |= SC_SEC_ENV_ALG_REF_PRESENT;
+			break;
+		}
+	}
+
+	if ((sec_flags & (SC_ALGORITHM_AES_CBC | SC_ALGORITHM_AES_CBC_PAD)) > 0) {
+		senv_param = (sc_sec_env_param_t){
+				SC_SEC_ENV_PARAM_IV, (void *)param, paramlen};
+		LOG_TEST_RET(ctx, sec_env_add_param(&senv, &senv_param), "failed to add IV to security environment");
+	}
+
+	LOG_TEST_RET(p15card->card->ctx, get_file_path(obj, &path), "Failed to get key file path.");
+
+	LOG_TEST_RET(p15card->card->ctx, r, "sc_lock() failed");
+
+	do {
+		r = SC_SUCCESS;
+		if (outlen == NULL) {
+			/* C_DecryptInit */
+			/* select key file and set sec env */
+			if (path.len != 0 || path.aid.len != 0) {
+				r = select_key_file(p15card, obj, &senv);
+				if (r < 0)
+					sc_log(p15card->card->ctx, "Unable to select key file");
+			}
+			if (r == SC_SUCCESS) {
+				r = sc_set_security_env(p15card->card, &senv, 0);
+				if (r < 0)
+					sc_log(p15card->card->ctx, "Unable to set security env");
+			}
+		}
+
+		if (r == SC_SUCCESS)
+			r = sc_decrypt_sym(p15card->card, in, inlen, out, outlen);
+
+		if (revalidated_cached_pin)
+			/* only re-validate once */
+			break;
+		if (r == SC_ERROR_SECURITY_STATUS_NOT_SATISFIED) {
+			r = sc_pkcs15_pincache_revalidate(p15card, obj);
+			if (r < 0)
+				break;
+			revalidated_cached_pin = 1;
+		}
+	} while (revalidated_cached_pin);
 
 	LOG_FUNC_RETURN(ctx, r);
 }
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-starcert.c opensc-0.23.0/src/libopensc/pkcs15-starcert.c
--- opensc-0.22.0/src/libopensc/pkcs15-starcert.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-starcert.c	2022-11-29 09:34:43.000000000 +0100
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <stdio.h>
 
+#include "internal.h"
 #include "common/compat_strlcpy.h"
 #include "pkcs15.h"
 #include "cardctl.h"
@@ -167,15 +168,14 @@
 	r = sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0);
 	if (r != SC_SUCCESS)
 		return SC_ERROR_INTERNAL;
-	free(p15card->tokeninfo->serial_number);
-	p15card->tokeninfo->serial_number = strdup(buf);
+
+	set_string(&p15card->tokeninfo->serial_number, buf);
 	if (!p15card->tokeninfo->serial_number)
 		return SC_ERROR_INTERNAL;
 	/* the manufacturer ID, in this case Giesecke & Devrient GmbH */
-	free(p15card->tokeninfo->manufacturer_id);
-	p15card->tokeninfo->manufacturer_id = strdup(MANU_ID);
+	set_string(&p15card->tokeninfo->manufacturer_id, MANU_ID);
 	if (!p15card->tokeninfo->manufacturer_id)
-		return SC_ERROR_INTERNAL;
+		goto err;
 
 	/* set certs */
 	for (i = 0; certs[i].label; i++) {
@@ -197,7 +197,7 @@
 
 		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
 		if (r < 0)
-			return SC_ERROR_INTERNAL;
+			goto err;
 	}
 	/* set pins */
 	for (i = 0; pins[i].label; i++) {
@@ -226,7 +226,7 @@
 
 		r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
 		if (r < 0)
-			return SC_ERROR_INTERNAL;
+			goto err;
 	}
 	/* set private keys */
 	for (i = 0; prkeys[i].label; i++) {
@@ -250,19 +250,23 @@
 
 		r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
 		if (r < 0)
-			return SC_ERROR_INTERNAL;
+			goto err;
 	}
 		
 	/* select the application DF */
 	sc_format_path("3F00DF01", &path);
 	r = sc_select_file(card, &path, &file);
 	if (r != SC_SUCCESS || !file)
-		return SC_ERROR_INTERNAL;
+		goto err;
 	/* set the application DF */
 	sc_file_free(p15card->file_app);
 	p15card->file_app = file;
 
 	return SC_SUCCESS;
+
+err:
+	sc_pkcs15_card_clear(p15card);
+	return SC_ERROR_INTERNAL;
 }
 
 int sc_pkcs15emu_starcert_init_ex(sc_pkcs15_card_t *p15card,
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-starcos-esign.c opensc-0.23.0/src/libopensc/pkcs15-starcos-esign.c
--- opensc-0.22.0/src/libopensc/pkcs15-starcos-esign.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/libopensc/pkcs15-starcos-esign.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,363 @@
+/**
+ * PKCS15 emulation layer for Giesecke & Devrient StarCOS 3.x cards 
+ * with eSign application
+ *
+ * Copyright (C) 2022, jozsefd
+ *
+ * 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
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "common/compat_strlcpy.h"
+#include "internal.h"
+#include "log.h"
+#include "pkcs15.h"
+#include "cards.h"
+
+#include <stdlib.h>
+#include <string.h>
+
+/* compile time option: define ENABLE_ESIGN_ISSUER_CONTAINERS to enable containers holding the issuer certificates */
+
+static const char name_Card[] = "ESIGN";
+static const char name_Vendor[] = "Giesecke & Devrient";
+static const char name_ESign[] = "ESIGN";
+static const unsigned char aid_ESIGN[] = {0xA0, 0x00, 0x00, 0x02, 0x45, 0x53, 0x69, 0x67, 0x6E};
+
+typedef struct cdata_st {
+	const char *label;
+	int authority;
+	const char *path;
+	const char *id;
+	int obj_flags;
+} cdata, *pcdata;
+
+typedef struct pdata_st {
+	const char *id;
+	const char *label;
+	const char *path;
+	int ref;
+	int type;
+	unsigned int maxlen;
+	unsigned int minlen;
+	unsigned int storedlen;
+	int flags;
+	int tries_left;
+	int max_tries;
+	const char pad_char;
+	int obj_flags;
+} pindata, *ppindata;
+
+typedef struct prdata_st {
+	const char *id;
+	const char *label;
+	unsigned int modulus_len;
+	int usage;
+	const char *path;
+	int ref;
+	const char *auth_id;
+	int obj_flags;
+} prdata, *pprdata;
+
+typedef struct container_st {
+	const char *id;
+	const pcdata certdata;
+	const ppindata pindata;
+	const pprdata prdata;
+} container;
+
+#define USAGE_NONREP SC_PKCS15_PRKEY_USAGE_NONREPUDIATION
+#define USAGE_KE     SC_PKCS15_PRKEY_USAGE_ENCRYPT | \
+				 SC_PKCS15_PRKEY_USAGE_DECRYPT | \
+				 SC_PKCS15_PRKEY_USAGE_WRAP | \
+				 SC_PKCS15_PRKEY_USAGE_UNWRAP
+#define USAGE_AUT SC_PKCS15_PRKEY_USAGE_ENCRYPT | \
+				  SC_PKCS15_PRKEY_USAGE_DECRYPT | \
+				  SC_PKCS15_PRKEY_USAGE_WRAP | \
+				  SC_PKCS15_PRKEY_USAGE_UNWRAP | \
+				  SC_PKCS15_PRKEY_USAGE_SIGN
+#define USER_PIN  SC_PKCS15_PIN_FLAG_INITIALIZED | \
+				SC_PKCS15_PIN_FLAG_CASE_SENSITIVE | \
+				SC_PKCS15_PIN_TYPE_FLAGS_PIN_GLOBAL | \
+				SC_PKCS15_PIN_AUTH_TYPE_PIN
+
+static int
+get_cert_size(sc_card_t *card, sc_path_t *path, size_t *psize)
+{
+	int r;
+	sc_file_t *file = NULL;
+
+	r = sc_select_file(card, path, &file);
+	LOG_TEST_RET(card->ctx, r, "Failed to select EF certificate");
+
+	*psize = file->size;
+	sc_file_free(file);
+
+	return SC_SUCCESS;
+}
+
+static int
+add_app(sc_pkcs15_card_t *p15card, const container *containers, int container_count)
+{
+	int i, containers_added = 0, r = SC_SUCCESS;
+	ppindata installed_pins[4];
+	size_t installed_pin_count = 0;
+	sc_card_t *card = p15card->card;
+
+	LOG_FUNC_CALLED(card->ctx);
+
+	for (i = 0; i < container_count; i++) {
+		struct sc_pkcs15_cert_info cert_info;
+		struct sc_pkcs15_object cert_obj;
+		size_t cert_size;
+
+		memset(&cert_info, 0, sizeof(cert_info));
+		memset(&cert_obj, 0, sizeof(cert_obj));
+
+		sc_pkcs15_format_id(containers[i].id, &cert_info.id);
+		cert_info.authority = containers[i].certdata->authority;
+		sc_format_path(containers[i].certdata->path, &cert_info.path);
+
+		r = get_cert_size(card, &cert_info.path, &cert_size);
+		if ( r != SC_SUCCESS ) {
+			sc_log(card->ctx, "Failed to determine size of certificate %s, ignoring container", containers[i].certdata->label);
+			continue;
+		}
+
+		strlcpy(cert_obj.label, containers[i].certdata->label, sizeof(cert_obj.label));
+		cert_obj.flags = containers[i].certdata->obj_flags;
+
+		r = sc_pkcs15emu_add_x509_cert(p15card, &cert_obj, &cert_info);
+		LOG_TEST_RET(card->ctx, r, "Failed to add certificate");
+
+		if (containers[i].pindata != 0) {
+			size_t j;
+			int is_pin_installed = 0;
+
+			/* A pin object could be used by more than 1 container, ensure it is added only once */
+			for (j = 0; j < installed_pin_count; j++) {
+				if (installed_pins[j] == containers[i].pindata) {
+					is_pin_installed = 1;
+					break;
+				}
+			}
+
+			if (!is_pin_installed) {
+				struct sc_pkcs15_auth_info pin_info;
+				struct sc_pkcs15_object pin_obj;
+
+				if (installed_pin_count < (int)(sizeof(installed_pins) / sizeof(ppindata))) {
+					installed_pins[installed_pin_count++] = containers[i].pindata;
+				} else {
+					sc_log(card->ctx, "Warning: cannot add more than 4 pins");
+					continue;
+				}
+
+				memset(&pin_info, 0, sizeof(pin_info));
+				memset(&pin_obj, 0, sizeof(pin_obj));
+
+				sc_pkcs15_format_id(containers[i].pindata->id, &pin_info.auth_id);
+				pin_info.auth_type = SC_PKCS15_PIN_AUTH_TYPE_PIN;
+				pin_info.attrs.pin.reference = containers[i].pindata->ref;
+				pin_info.attrs.pin.flags = containers[i].pindata->flags;
+				pin_info.attrs.pin.type = containers[i].pindata->type;
+				pin_info.attrs.pin.min_length = containers[i].pindata->minlen;
+				pin_info.attrs.pin.stored_length = containers[i].pindata->storedlen;
+				pin_info.attrs.pin.max_length = containers[i].pindata->maxlen;
+				pin_info.attrs.pin.pad_char = containers[i].pindata->pad_char;
+				if (containers[i].pindata->path != NULL)
+					sc_format_path(containers[i].pindata->path, &pin_info.path);
+				pin_info.tries_left = -1;
+				pin_info.max_tries = containers[i].pindata->max_tries;
+
+				strlcpy(pin_obj.label, containers[i].pindata->label, sizeof(pin_obj.label));
+				pin_obj.flags = containers[i].pindata->obj_flags;
+
+				r = sc_pkcs15emu_add_pin_obj(p15card, &pin_obj, &pin_info);
+				LOG_TEST_RET(card->ctx, r, "Failed to add PIN object");
+			}
+		}
+
+		if (containers[i].prdata != 0) {
+			struct sc_pkcs15_prkey_info prkey_info;
+			struct sc_pkcs15_object prkey_obj;
+			int modulus_len = containers[i].prdata->modulus_len;
+			memset(&prkey_info, 0, sizeof(prkey_info));
+			memset(&prkey_obj, 0, sizeof(prkey_obj));
+
+			sc_pkcs15_format_id(containers[i].id, &prkey_info.id);
+			prkey_info.usage = containers[i].prdata->usage;
+			prkey_info.native = 1;
+			prkey_info.key_reference = containers[i].prdata->ref;
+			prkey_info.modulus_length = modulus_len;
+			sc_format_path(containers[i].prdata->path, &prkey_info.path);
+
+			strlcpy(prkey_obj.label, containers[i].prdata->label, sizeof(prkey_obj.label));
+			prkey_obj.flags = containers[i].prdata->obj_flags;
+			if (containers[i].prdata->auth_id) {
+				sc_pkcs15_format_id(containers[i].prdata->auth_id, &prkey_obj.auth_id);
+			}
+
+			r = sc_pkcs15emu_add_rsa_prkey(p15card, &prkey_obj, &prkey_info);
+			LOG_TEST_RET(card->ctx, r, "Failed to add RSA prkey");
+		}
+
+		containers_added++;
+	}
+
+	if (containers_added == 0) {
+		r = SC_ERROR_INVALID_CARD;
+	} else {
+		r = SC_SUCCESS;
+	}
+
+	LOG_FUNC_RETURN(card->ctx, r);
+}
+
+/*
+ * adds the PKCS15 objects of the ESIGN application. The app may contain
+ * 1) Authentication container
+ *  - 2048-bit RSA key
+ *  - CH certificate
+ * 2) Encryption container
+ *  - 2048-bit RSA key
+ *  - CH certificate
+ * 3) Authentication Issuer container
+ *  - issuer certificate
+ * 3) Encryption Issuer container
+ *  - issuer certificate
+ * Depending on the card profile, some containers may be missing.
+ * Both RSA keys are protected with the UserPIN. The app may have a PUK, not
+ * supported by this emulator.
+ * 
+ * The issuer certificates are not included by default, define ENABLE_ESIGN_ISSUER_CONTAINERS
+ * to enable them.
+ */
+static int
+starcos_add_esign_app(sc_pkcs15_card_t *p15card)
+{
+	static cdata auth_cert = {"C.CH.AUT", 0, "3F00060843F1", "1", 0};
+	static cdata encr_cert = {"C.CH.ENC", 0, "3F0006084301", "2", 0};
+#ifdef ENABLE_ESIGN_ISSUER_CONTAINERS
+	const cdata auth_root_cert = { "C.RootCA_Auth", 1, "3F00060843F0", "3", 0 };
+	const cdata encr_root_cert = { "C.RootCA_Enc", 1, "3F0006084300", "4", 0 };
+#endif
+
+	static prdata auth_key = {"1", "PrK.CH.AUT", 2048, USAGE_AUT, "3F000608", 0x81, "1", SC_PKCS15_CO_FLAG_PRIVATE};
+	static prdata encr_key = {"2", "PrK.CH.ENC", 2048, USAGE_KE, "3F000608", 0x83, "1", SC_PKCS15_CO_FLAG_PRIVATE};
+
+	static pindata auth_pin = {"1", "UserPIN", "3F00", 0x01, SC_PKCS15_PIN_TYPE_UTF8, 16, 6, 0,
+			USER_PIN, -1, 3, 0x00, SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE};
+
+	static pindata auth_pin_v35 = {"1", "UserPIN", "3F00", 0x06, SC_PKCS15_PIN_TYPE_UTF8, 16, 6, 0,
+			USER_PIN, -1, 3, 0x00, SC_PKCS15_CO_FLAG_MODIFIABLE | SC_PKCS15_CO_FLAG_PRIVATE};
+
+	ppindata auth = (p15card->card->type == SC_CARD_TYPE_STARCOS_V3_5_ESIGN) ? &auth_pin_v35 : &auth_pin;
+
+	const container containers[] = {
+			{"1", &auth_cert, auth, &auth_key},
+			{"2", &encr_cert, auth, &encr_key},
+#ifdef ENABLE_ESIGN_ISSUER_CONTAINERS
+			{ "3", &auth_root_cert, 0, 0 },
+			{ "4", &encr_root_cert, 0, 0 },
+#endif
+	};
+
+	return add_app(p15card, containers, sizeof(containers) / sizeof(container));
+}
+
+static int
+starcos_esign_init(sc_pkcs15_card_t *p15card, struct sc_aid *aid)
+{
+	sc_card_t *card = p15card->card;
+	sc_context_t *ctx = card->ctx;
+	const char *label = name_Card;
+	int r;
+	int apps_added = 0;
+
+	SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_NORMAL);
+
+	if (card->type != SC_CARD_TYPE_STARCOS_V3_4_ESIGN && card->type != SC_CARD_TYPE_STARCOS_V3_5_ESIGN) {
+		return SC_ERROR_WRONG_CARD;
+	}
+
+	if (aid == NULL) {
+		// no aid: in this case all emulated apps are added, currently only the esign_app
+		r = starcos_add_esign_app(p15card);
+		if (r == SC_SUCCESS)
+			apps_added++;
+	} else {
+		// aid specified: only the matching app is added
+		if (aid->len == sizeof(aid_ESIGN) && memcmp(aid->value, aid_ESIGN, sizeof(aid_ESIGN)) == 0) {
+			r = starcos_add_esign_app(p15card);
+			if (r == SC_SUCCESS) {
+				label = name_ESign;
+				apps_added++;
+			}
+		}
+
+		if (apps_added > 0) {
+			// pkcs11 requires the file_app
+			struct sc_path path;
+			struct sc_file *file = NULL;
+			sc_path_set(&path, SC_PATH_TYPE_DF_NAME, aid->value, aid->len, 0, 0);
+			r = sc_select_file(card, &path, &file);
+			if (r != SC_SUCCESS || !file)
+				return SC_ERROR_INTERNAL;
+			sc_file_free(p15card->file_app);
+			p15card->file_app = file;
+		}
+	}
+
+	if (apps_added == 0) {
+		LOG_TEST_RET(ctx, SC_ERROR_WRONG_CARD, "No supported app found on this card");
+	}
+
+	sc_pkcs15_free_tokeninfo(p15card->tokeninfo);
+
+	p15card->tokeninfo = sc_pkcs15_tokeninfo_new();
+	if (!p15card->tokeninfo) {
+		LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "unable to create tokeninfo struct");
+	} else {
+		sc_serial_number_t serial;
+		char serial_hex[SC_MAX_SERIALNR * 2 + 2];
+		r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
+		LOG_TEST_RET(ctx, r, "Failed to query card serial number");
+
+		r = sc_bin_to_hex(serial.value, serial.len, serial_hex, sizeof serial_hex, 0);
+		LOG_TEST_RET(ctx, r, "Failed to convert S/N to hex");
+		p15card->tokeninfo->serial_number = strdup(serial_hex);
+		p15card->tokeninfo->label = strdup(label);
+		p15card->tokeninfo->manufacturer_id = strdup(name_Vendor);
+		p15card->tokeninfo->flags = SC_PKCS15_TOKEN_READONLY;
+	}
+
+	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
+}
+
+int
+sc_pkcs15emu_starcos_esign_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *aid)
+{
+	int r = SC_ERROR_WRONG_CARD;
+
+	if (!p15card || !p15card->card || !p15card->card->ctx)
+		return SC_ERROR_INVALID_ARGUMENTS;
+
+	r = starcos_esign_init(p15card, aid);
+	LOG_FUNC_RETURN(p15card->card->ctx, r);
+}
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-syn.c opensc-0.23.0/src/libopensc/pkcs15-syn.c
--- opensc-0.22.0/src/libopensc/pkcs15-syn.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-syn.c	2022-11-29 09:34:43.000000000 +0100
@@ -33,9 +33,9 @@
 #include "asn1.h"
 #include "pkcs15.h"
 #include "pkcs15-syn.h"
+#include "pkcs15-emulator-filter.h"
 
 struct sc_pkcs15_emulator_handler builtin_emulators[] = {
-	{ "westcos",	sc_pkcs15emu_westcos_init_ex	},
 	{ "openpgp",	sc_pkcs15emu_openpgp_init_ex	},
 	{ "starcert",	sc_pkcs15emu_starcert_init_ex	},
 	{ "tcos",	sc_pkcs15emu_tcos_init_ex	},
@@ -44,11 +44,7 @@
 	{ "PIV-II",     sc_pkcs15emu_piv_init_ex	},
 	{ "cac",        sc_pkcs15emu_cac_init_ex	},
 	{ "idprime",    sc_pkcs15emu_idprime_init_ex	},
-	{ "gemsafeGPK",	sc_pkcs15emu_gemsafeGPK_init_ex	},
 	{ "gemsafeV1",	sc_pkcs15emu_gemsafeV1_init_ex	},
-	{ "actalis",	sc_pkcs15emu_actalis_init_ex	},
-	{ "atrust-acos",sc_pkcs15emu_atrust_acos_init_ex},
-	{ "tccardos",	sc_pkcs15emu_tccardos_init_ex	},
 	{ "entersafe",  sc_pkcs15emu_entersafe_init_ex	},
 	{ "pteid",	sc_pkcs15emu_pteid_init_ex	},
 	{ "oberthur",   sc_pkcs15emu_oberthur_init_ex	},
@@ -61,10 +57,20 @@
 	{ "din66291",   sc_pkcs15emu_din_66291_init_ex	},
 	{ "esteid2018", sc_pkcs15emu_esteid2018_init_ex	},
 	{ "cardos",     sc_pkcs15emu_cardos_init_ex	},
-
+	{ "nqapplet",   sc_pkcs15emu_nqapplet_init_ex },
+	{ "esign",      sc_pkcs15emu_starcos_esign_init_ex },
 	{ NULL, NULL }
 };
 
+struct sc_pkcs15_emulator_handler old_emulators[] = {
+	{ "westcos",	sc_pkcs15emu_westcos_init_ex	},
+	{ "gemsafeGPK",	sc_pkcs15emu_gemsafeGPK_init_ex	},
+	{ "atrust-acos",sc_pkcs15emu_atrust_acos_init_ex},
+	{ "actalis",	sc_pkcs15emu_actalis_init_ex	},
+	{ "tccardos",	sc_pkcs15emu_tccardos_init_ex	},
+	{ NULL, NULL }
+};	
+
 static int parse_emu_block(sc_pkcs15_card_t *, struct sc_aid *, scconf_block *);
 static sc_pkcs15_df_t * sc_pkcs15emu_get_df(sc_pkcs15_card_t *p15card,
 	unsigned int type);
@@ -100,6 +106,9 @@
 		case SC_CARD_TYPE_ESTEID_2018:
 		case SC_CARD_TYPE_CARDOS_V5_0:
 		case SC_CARD_TYPE_CARDOS_V5_3:
+		case SC_CARD_TYPE_NQ_APPLET:
+		case SC_CARD_TYPE_STARCOS_V3_4_ESIGN:
+		case SC_CARD_TYPE_STARCOS_V3_5_ESIGN:
 
 			return 1;
 		default:
@@ -132,25 +141,34 @@
 	} else {
 		/* we have a conf file => let's use it */
 		int builtin_enabled;
-		const scconf_list *list, *item;
+		const scconf_list *list;
 
 		builtin_enabled = scconf_get_bool(conf_block, "enable_builtin_emulation", 1);
 		list = scconf_find_list(conf_block, "builtin_emulators"); /* FIXME: rename to enabled_emulators */
 
 		if (builtin_enabled && list) {
-			/* get the list of enabled emulation drivers */
-			for (item = list; item; item = item->next) {
-				/* go through the list of builtin drivers */
-				const char *name = item->data;
-
-				sc_log(ctx, "trying %s", name);
-				for (i = 0; builtin_emulators[i].name; i++)
-					if (!strcmp(builtin_emulators[i].name, name)) {
-						r = builtin_emulators[i].handler(p15card, aid);
-						if (r == SC_SUCCESS)
-							/* we got a hit */
-							goto out;
-					}
+			/* filter enabled emulation drivers from conf file */
+			struct _sc_pkcs15_emulators filtered_emulators;
+			struct sc_pkcs15_emulator_handler** lst;
+			int ret;
+
+			filtered_emulators.ccount = 0;
+			ret = set_emulators(ctx, &filtered_emulators, list, builtin_emulators, old_emulators);
+			if (ret == SC_SUCCESS || ret == SC_ERROR_TOO_MANY_OBJECTS) {
+				lst = filtered_emulators.list_of_handlers;
+
+				if (ret == SC_ERROR_TOO_MANY_OBJECTS)
+					sc_log(ctx, "trying first %d emulators from conf file", SC_MAX_PKCS15_EMULATORS);
+
+				for (i = 0; lst[i]; i++) {
+					sc_log(ctx, "trying %s", lst[i]->name);
+					r = lst[i]->handler(p15card, aid);
+					if (r == SC_SUCCESS)
+						/* we got a hit */
+						goto out;
+				}
+			} else {
+				sc_log(ctx, "failed to filter enabled card emulators: %s", sc_strerror(ret));
 			}
 		}
 		else if (builtin_enabled) {
@@ -222,6 +240,14 @@
 				break;
 			}
 		}
+		if (init_func_ex == NULL) {
+			for (i = 0; old_emulators[i].name; i++) {
+				if (!strcmp(old_emulators[i].name, module_name)) {
+					init_func_ex = old_emulators[i].handler;
+					break;
+				}
+			}
+		}
 	} else {
 		const char *(*get_version)(void);
 		const char *name = NULL;
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-syn.h opensc-0.23.0/src/libopensc/pkcs15-syn.h
--- opensc-0.22.0/src/libopensc/pkcs15-syn.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-syn.h	2022-11-29 09:34:43.000000000 +0100
@@ -55,6 +55,8 @@
 int sc_pkcs15emu_din_66291_init_ex(sc_pkcs15_card_t *p15card,	struct sc_aid *);
 int sc_pkcs15emu_idprime_init_ex(sc_pkcs15_card_t *p15card,	struct sc_aid *);
 int sc_pkcs15emu_cardos_init_ex(sc_pkcs15_card_t *p15card,	struct sc_aid *);
+int sc_pkcs15emu_nqapplet_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *);
+int sc_pkcs15emu_starcos_esign_init_ex(sc_pkcs15_card_t *p15card, struct sc_aid *);
 
 struct sc_pkcs15_emulator_handler {
 	const char *name;
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-tccardos.c opensc-0.23.0/src/libopensc/pkcs15-tccardos.c
--- opensc-0.22.0/src/libopensc/pkcs15-tccardos.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-tccardos.c	2022-11-29 09:34:43.000000000 +0100
@@ -325,26 +325,38 @@
 		return SC_ERROR_OUT_OF_MEMORY;
 	/* set the manufacturer ID */
 	set_string(&p15card->tokeninfo->manufacturer_id, MANU_ID);
-	if (p15card->tokeninfo->manufacturer_id == NULL)
-		return SC_ERROR_OUT_OF_MEMORY;
+	if (p15card->tokeninfo->manufacturer_id == NULL) {
+		r = SC_ERROR_OUT_OF_MEMORY;
+		goto err;
+	}
 	/* set the serial number */
 	r = sc_parse_ef_gdo(card, iccsn.value, &iccsn.len, NULL, 0);
-	if (r != SC_SUCCESS || iccsn.len < 5+8)
-		return SC_ERROR_INTERNAL;
+	if (r != SC_SUCCESS || iccsn.len < 5+8) {
+		r = SC_ERROR_INTERNAL;
+		goto err;
+	}
 	sc_bin_to_hex(iccsn.value + 5, 8, hex_buf, sizeof(hex_buf), 0);
 	set_string(&p15card->tokeninfo->serial_number, hex_buf);
-	if (p15card->tokeninfo->serial_number == NULL)
-		return SC_ERROR_OUT_OF_MEMORY;
+	if (p15card->tokeninfo->serial_number == NULL) {
+		r = SC_ERROR_OUT_OF_MEMORY;
+		goto err;
+	}
 	/* select the application DF */
 	sc_format_path(TC_CARDOS_APP_DF, &path);
 	r = sc_select_file(card, &path, &file);
-	if (r != SC_SUCCESS || file == NULL)
-		return SC_ERROR_INTERNAL;
+	if (r != SC_SUCCESS || file == NULL) {
+		r = SC_ERROR_INTERNAL;
+		goto err;
+	}
 	/* set the application DF */
 	sc_file_free(p15card->file_app);
 	p15card->file_app = file;
 
 	return SC_SUCCESS;
+
+err:
+	sc_pkcs15_card_clear(p15card);
+	return r;
 }
 
 int sc_pkcs15emu_tccardos_init_ex(sc_pkcs15_card_t *p15card,
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-tcos.c opensc-0.23.0/src/libopensc/pkcs15-tcos.c
--- opensc-0.22.0/src/libopensc/pkcs15-tcos.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-tcos.c	2022-11-29 09:34:43.000000000 +0100
@@ -543,5 +543,6 @@
 	if(!detect_signtrust(p15card)) return SC_SUCCESS;
 	if(!detect_datev(p15card)) return SC_SUCCESS;
 
+	sc_pkcs15_card_clear(p15card);
 	return SC_ERROR_INTERNAL;
 }
diff -Nru opensc-0.22.0/src/libopensc/pkcs15-westcos.c opensc-0.23.0/src/libopensc/pkcs15-westcos.c
--- opensc-0.22.0/src/libopensc/pkcs15-westcos.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/pkcs15-westcos.c	2022-11-29 09:34:43.000000000 +0100
@@ -43,10 +43,9 @@
 	r = sc_select_file(card, &path, NULL);
 	if (r)
 		goto out;
-	free(p15card->tokeninfo->label);
-	p15card->tokeninfo->label = strdup("westcos");
-	free(p15card->tokeninfo->manufacturer_id);
-	p15card->tokeninfo->manufacturer_id = strdup("CEV");
+
+	set_string(&p15card->tokeninfo->label, "westcos");
+	set_string(&p15card->tokeninfo->manufacturer_id, "CEV");
 
 	/* get serial number */
 	r = sc_card_ctl(card, SC_CARDCTL_GET_SERIALNR, &serial);
@@ -55,8 +54,8 @@
 	r = sc_bin_to_hex(serial.value, serial.len, buf, sizeof(buf), 0);
 	if (r)
 		goto out;
-	free(p15card->tokeninfo->serial_number);
-	p15card->tokeninfo->serial_number = strdup(buf);
+
+	set_string(&p15card->tokeninfo->serial_number, buf);
 	sc_format_path("AAAA", &path);
 	r = sc_select_file(card, &path, NULL);
 	if (r) 
@@ -132,7 +131,7 @@
 		cert_info.id.value[0] = 0x45;
 		cert_info.authority = 0;
 		cert_info.path = path;
-		r = sc_pkcs15_read_certificate(p15card, &cert_info, &cert);
+		r = sc_pkcs15_read_certificate(p15card, &cert_info, 0, &cert);
 		cert_obj.data = (void *) cert;
 		if (!r) {
 			strlcpy(cert_obj.label, "User certificate",
@@ -223,6 +222,7 @@
 	}
 	r = 0;
 out:
+	sc_pkcs15_card_clear(p15card);
 	return r;
 }
 
diff -Nru opensc-0.22.0/src/libopensc/reader-pcsc.c opensc-0.23.0/src/libopensc/reader-pcsc.c
--- opensc-0.22.0/src/libopensc/reader-pcsc.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/reader-pcsc.c	2022-11-29 09:34:43.000000000 +0100
@@ -182,8 +182,10 @@
 		return SC_ERROR_CARD_UNRESPONSIVE;
 	case SCARD_E_SHARING_VIOLATION:
 		return SC_ERROR_READER_LOCKED;
+#ifdef SCARD_E_NO_READERS_AVAILABLE
 	case SCARD_E_NO_READERS_AVAILABLE:
 		return SC_ERROR_NO_READERS_FOUND;
+#endif
 	case SCARD_E_UNKNOWN_READER:
 		return SC_ERROR_READER_DETACHED;
 
@@ -391,10 +393,7 @@
 				|| rv == (LONG)SCARD_E_NO_READERS_AVAILABLE
 #endif
 				|| rv == (LONG)SCARD_E_SERVICE_STOPPED) {
- 			if (old_flags & SC_READER_CARD_PRESENT) {
- 				reader->flags |= SC_READER_CARD_CHANGED;
- 			}
-			
+ 			reader->flags &= ~(SC_READER_CARD_PRESENT);
  			SC_FUNC_RETURN(reader->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
  		}
 
@@ -413,7 +412,8 @@
 		 * XXX: We'll hit it again, as no readers are removed currently.
 		 */
 		reader->flags &= ~(SC_READER_CARD_PRESENT);
-		return SC_ERROR_READER_DETACHED;
+		sc_log(reader->ctx, "Reader unknown: %s", sc_strerror(SC_ERROR_READER_DETACHED));
+		SC_FUNC_RETURN(reader->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
 	}
 
 	reader->flags &= ~(SC_READER_CARD_CHANGED|SC_READER_CARD_INUSE|SC_READER_CARD_EXCLUSIVE);
@@ -456,8 +456,6 @@
 		}
 	} else {
 		reader->flags &= ~SC_READER_CARD_PRESENT;
-		if (old_flags & SC_READER_CARD_PRESENT)
-			reader->flags |= SC_READER_CARD_CHANGED;
 	}
 	sc_log(reader->ctx, "card %s%s",
 			reader->flags & SC_READER_CARD_PRESENT ? "present" : "absent",
@@ -474,7 +472,12 @@
 	rv = refresh_attributes(reader);
 	if (rv != SC_SUCCESS)
 		LOG_FUNC_RETURN(reader->ctx, rv);
-	LOG_FUNC_RETURN(reader->ctx, reader->flags);
+
+	// Return 0 if the card is not present
+	if (reader->flags & SC_READER_CARD_PRESENT)
+		LOG_FUNC_RETURN(reader->ctx, reader->flags);
+	else
+		LOG_FUNC_RETURN(reader->ctx, 0);
 }
 
 static int check_forced_protocol(sc_reader_t *reader, DWORD *protocol)
@@ -669,7 +672,7 @@
 		LONG rv = priv->gpriv->SCardDisconnect(priv->pcsc_card, priv->gpriv->disconnect_action);
 		PCSC_TRACE(reader, "SCardDisconnect returned", rv);
 	}
-	reader->flags = 0;
+	reader->flags &= SC_READER_REMOVED;
 	return SC_SUCCESS;
 }
 
@@ -1132,19 +1135,8 @@
 	sc_context_t *ctx = reader->ctx;
 	struct pcsc_global_private_data *gpriv = (struct pcsc_global_private_data *) ctx->reader_drv_data;
 	struct pcsc_private_data *priv = reader->drv_data;
-	DWORD rcount, feature_len, i;
-	PCSC_TLV_STRUCTURE *pcsc_tlv;
-	union {
-		PCSC_TLV_STRUCTURE msg;
-		u8 buf[256];
-	} feature_buf;
-	union {
-#ifdef PIN_PROPERTIES_v5
-		PIN_PROPERTIES_STRUCTURE_v5 capsv5;
-#endif
-		PIN_PROPERTIES_STRUCTURE caps;
-		u8 buf[SC_MAX_APDU_BUFFER_SIZE];
-	} rbuf;
+	DWORD rcount, i;
+	u8 buf[256];
 	LONG rv;
 	const char *log_disabled = "but it's disabled in configuration file";
 	int id_vendor = 0, id_product = 0;
@@ -1156,43 +1148,41 @@
 	if (gpriv->SCardControl == NULL)
 		return;
 
-	rv = gpriv->SCardControl(card_handle, CM_IOCTL_GET_FEATURE_REQUEST, NULL, 0, feature_buf.buf, sizeof(feature_buf.buf), &feature_len);
+	rv = gpriv->SCardControl(card_handle, CM_IOCTL_GET_FEATURE_REQUEST, NULL, 0, buf, sizeof(buf), &rcount);
 	if (rv != SCARD_S_SUCCESS) {
 		PCSC_TRACE(reader, "SCardControl failed", rv);
 		return;
 	}
 
-	if ((feature_len % sizeof(PCSC_TLV_STRUCTURE)) != 0) {
+	if ((rcount % sizeof(PCSC_TLV_STRUCTURE)) != 0
+			|| rcount > sizeof buf) {
 		sc_log(ctx, "Inconsistent TLV from reader!");
 		return;
 	}
 
-	/* get the number of elements instead of the complete size */
-	feature_len /= sizeof(PCSC_TLV_STRUCTURE);
-
-	pcsc_tlv = &feature_buf.msg;
-	for (i = 0; i < feature_len; i++) {
-		sc_log(ctx, "Reader feature %02x found", pcsc_tlv[i].tag);
-		if (pcsc_tlv[i].tag == FEATURE_VERIFY_PIN_DIRECT) {
-			priv->verify_ioctl = ntohl(pcsc_tlv[i].value);
-		} else if (pcsc_tlv[i].tag == FEATURE_VERIFY_PIN_START) {
-			priv->verify_ioctl_start = ntohl(pcsc_tlv[i].value);
-		} else if (pcsc_tlv[i].tag == FEATURE_VERIFY_PIN_FINISH) {
-			priv->verify_ioctl_finish = ntohl(pcsc_tlv[i].value);
-		} else if (pcsc_tlv[i].tag == FEATURE_MODIFY_PIN_DIRECT) {
-			priv->modify_ioctl = ntohl(pcsc_tlv[i].value);
-		} else if (pcsc_tlv[i].tag == FEATURE_MODIFY_PIN_START) {
-			priv->modify_ioctl_start = ntohl(pcsc_tlv[i].value);
-		} else if (pcsc_tlv[i].tag == FEATURE_MODIFY_PIN_FINISH) {
-			priv->modify_ioctl_finish = ntohl(pcsc_tlv[i].value);
-		} else if (pcsc_tlv[i].tag == FEATURE_IFD_PIN_PROPERTIES) {
-			priv->pin_properties_ioctl = ntohl(pcsc_tlv[i].value);
-		} else if (pcsc_tlv[i].tag == FEATURE_GET_TLV_PROPERTIES)  {
-			priv->get_tlv_properties = ntohl(pcsc_tlv[i].value);
-		} else if (pcsc_tlv[i].tag == FEATURE_EXECUTE_PACE) {
-			priv->pace_ioctl = ntohl(pcsc_tlv[i].value);
+	for (i = 0; i < rcount; i += sizeof(PCSC_TLV_STRUCTURE)) {
+		PCSC_TLV_STRUCTURE *pcsc_tlv = (PCSC_TLV_STRUCTURE *)(buf+i);
+		sc_log(ctx, "Reader feature %02x found", pcsc_tlv->tag);
+		if (pcsc_tlv->tag == FEATURE_VERIFY_PIN_DIRECT) {
+			priv->verify_ioctl = ntohl(pcsc_tlv->value);
+		} else if (pcsc_tlv->tag == FEATURE_VERIFY_PIN_START) {
+			priv->verify_ioctl_start = ntohl(pcsc_tlv->value);
+		} else if (pcsc_tlv->tag == FEATURE_VERIFY_PIN_FINISH) {
+			priv->verify_ioctl_finish = ntohl(pcsc_tlv->value);
+		} else if (pcsc_tlv->tag == FEATURE_MODIFY_PIN_DIRECT) {
+			priv->modify_ioctl = ntohl(pcsc_tlv->value);
+		} else if (pcsc_tlv->tag == FEATURE_MODIFY_PIN_START) {
+			priv->modify_ioctl_start = ntohl(pcsc_tlv->value);
+		} else if (pcsc_tlv->tag == FEATURE_MODIFY_PIN_FINISH) {
+			priv->modify_ioctl_finish = ntohl(pcsc_tlv->value);
+		} else if (pcsc_tlv->tag == FEATURE_IFD_PIN_PROPERTIES) {
+			priv->pin_properties_ioctl = ntohl(pcsc_tlv->value);
+		} else if (pcsc_tlv->tag == FEATURE_GET_TLV_PROPERTIES)  {
+			priv->get_tlv_properties = ntohl(pcsc_tlv->value);
+		} else if (pcsc_tlv->tag == FEATURE_EXECUTE_PACE) {
+			priv->pace_ioctl = ntohl(pcsc_tlv->value);
 		} else {
-			sc_log(ctx, "Reader feature %02x is not supported", pcsc_tlv[i].tag);
+			sc_log(ctx, "Reader feature %02x is not supported", pcsc_tlv->tag);
 		}
 	}
 
@@ -1230,13 +1220,13 @@
 
 	/* Detect display */
 	if (priv->pin_properties_ioctl) {
-		rcount = sizeof(rbuf.buf);
+		rcount = sizeof(buf);
 		rv = gpriv->SCardControl(card_handle, priv->pin_properties_ioctl,
-			NULL, 0, rbuf.buf, sizeof(rbuf.buf), &rcount);
+			NULL, 0, buf, sizeof(buf), &rcount);
 		if (rv == SCARD_S_SUCCESS) {
 #ifdef PIN_PROPERTIES_v5
 			if (rcount == sizeof(PIN_PROPERTIES_STRUCTURE_v5)) {
-				PIN_PROPERTIES_STRUCTURE_v5 *caps = &rbuf.capsv5;
+				PIN_PROPERTIES_STRUCTURE_v5 *caps = (PIN_PROPERTIES_STRUCTURE_v5 *) &buf;
 				if (caps->wLcdLayout > 0) {
 					sc_log(ctx, "Reader has a display: %04X", caps->wLcdLayout);
 					reader->capabilities |= SC_READER_CAP_DISPLAY;
@@ -1245,7 +1235,7 @@
 			}
 #endif
 			if (rcount == sizeof(PIN_PROPERTIES_STRUCTURE)) {
-				PIN_PROPERTIES_STRUCTURE *caps = &rbuf.caps;
+				PIN_PROPERTIES_STRUCTURE *caps = (PIN_PROPERTIES_STRUCTURE *) buf;
 				if (caps->wLcdLayout > 0) {
 					sc_log(ctx, "Reader has a display: %04X", caps->wLcdLayout);
 					reader->capabilities |= SC_READER_CAP_DISPLAY;
@@ -1304,13 +1294,13 @@
 	}
 
 	if(gpriv->SCardGetAttrib != NULL) {
-		rcount = sizeof(rbuf.buf);
+		rcount = sizeof(buf);
 		if (gpriv->SCardGetAttrib(card_handle, SCARD_ATTR_VENDOR_NAME,
-					rbuf.buf, &rcount) == SCARD_S_SUCCESS
+					buf, &rcount) == SCARD_S_SUCCESS
 				&& rcount > 0) {
 			/* add NUL termination, just in case... */
-			rbuf.buf[(sizeof rbuf.buf)-1] = '\0';
-			reader->vendor = strdup((char *) rbuf.buf);
+			buf[(sizeof buf)-1] = '\0';
+			reader->vendor = strdup((char *) buf);
 		}
 
 		rcount = sizeof i;
@@ -1801,6 +1791,10 @@
 				/* no other event has been detected, yet */
 				*event_reader = gpriv->attached_reader;
 				*event = SC_EVENT_READER_ATTACHED;
+				/* If the card is present in the reader, report also this event */
+				if (gpriv->attached_reader->flags & SC_READER_CARD_PRESENT) {
+					*event |= SC_EVENT_CARD_INSERTED;
+				}
 				r = SC_SUCCESS;
 			}
 			gpriv->attached_reader = NULL;
@@ -2508,6 +2502,31 @@
 	reader->active_protocol = pcsc_proto_to_opensc(prot);
 }
 
+int
+pcsc_check_reader_handles(sc_context_t *ctx, sc_reader_t *reader, void * pcsc_context_handle, void * pcsc_card_handle)
+{
+	char reader_name[128];
+	DWORD reader_name_size = sizeof(reader_name);
+
+	if (NULL == reader)
+		return 1;
+
+	struct pcsc_private_data *priv = reader->drv_data;
+	memset(reader_name, 0, sizeof(reader_name));
+
+	/* check if new handles are for the same reader as old handles */
+	if (SCARD_S_SUCCESS != priv->gpriv->SCardGetAttrib(*(SCARDHANDLE *)pcsc_card_handle,
+				SCARD_ATTR_DEVICE_SYSTEM_NAME_A, (LPBYTE)
+				reader_name, &reader_name_size)
+			|| strcmp(reader_name, reader->name) != 0) {
+		sc_log(ctx, "Reader name changed from \"%s\" to \"%s\"", reader->name, reader_name);
+
+		return 1;
+	}
+
+	return 0;
+}
+
 int pcsc_use_reader(sc_context_t *ctx, void * pcsc_context_handle, void * pcsc_card_handle)
 {
 	SCARDHANDLE card_handle;
diff -Nru opensc-0.22.0/src/libopensc/sc.c opensc-0.23.0/src/libopensc/sc.c
--- opensc-0.22.0/src/libopensc/sc.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/sc.c	2022-11-29 09:34:43.000000000 +0100
@@ -82,8 +82,13 @@
 		else if ('A' <= c && c <= 'F')
 			nibble = c - 'A' + 10;
 		else {
-			if (strchr(sc_hex_to_bin_separators, (int) c))
+			if (strchr(sc_hex_to_bin_separators, (int) c)) {
+				if (byte_needs_nibble) {
+					r = SC_ERROR_INVALID_ARGUMENTS;
+					goto err;
+				}
 				continue;
+			}
 			r = SC_ERROR_INVALID_ARGUMENTS;
 			goto err;
 		}
@@ -337,6 +342,12 @@
 		LOG_FUNC_RETURN(reader->ctx, SC_ERROR_NOT_SUPPORTED);
 
 	r = reader->ops->detect_card_presence(reader);
+
+	// Check that we get sane return value from backend
+	// detect_card_presence should return 0 if no card is present.
+	if (r && !(r & SC_READER_CARD_PRESENT))
+		LOG_FUNC_RETURN(reader->ctx, SC_ERROR_INTERNAL);
+
 	LOG_FUNC_RETURN(reader->ctx, r);
 }
 
diff -Nru opensc-0.22.0/src/libopensc/sc-ossl-compat.h opensc-0.23.0/src/libopensc/sc-ossl-compat.h
--- opensc-0.22.0/src/libopensc/sc-ossl-compat.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/sc-ossl-compat.h	2022-11-29 09:34:43.000000000 +0100
@@ -30,250 +30,38 @@
 #include <openssl/opensslv.h>
 #include <openssl/opensslconf.h>
 /*
- * Provide backward compatibility to older versions of OpenSSL
- * while using most of OpenSSL 1.1  API
+ * Provide compatibility OpenSSL 1.1.1, 3.0.1 and LibreSSL 3.4.2
  *
  * LibreSSL is a fork of OpenSSL from 2014
  * In its version of openssl/opensslv.h it defines:
  * OPENSSL_VERSION_NUMBER  0x20000000L (Will not change)
- * LIBRESSL_VERSION_NUMBER  0x2050000fL (changes with its versions.
- * The LibreSSL appears to follow the OpenSSL-1.0.1 API
- *
- */
-
-/*
- * 1.1.0 deprecated ERR_load_crypto_strings(), SSL_load_error_strings(), ERR_free_strings()
- * and ENGINE_load_dynamic.EVP_CIPHER_CTX_cleanup and EVP_CIPHER_CTX_init are replaced
- * by EVP_CIPHER_CTX_reset.
- * But for compatibility with LibreSSL and older OpenSSL. OpenSC uses the older functions
- */
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L  && !defined(LIBRESSL_VERSION_NUMBER)
-# if defined(OPENSSL_API_COMPAT) && OPENSSL_API_COMPAT >= 0x10100000L
-#define ERR_load_crypto_strings(x) while (0) continue
-#define SSL_load_error_strings(x)  while (0) continue
-#define ERR_free_strings(x)        while (0) continue
-#define ENGINE_load_dynamic(x)     while (0) continue
-#define EVP_CIPHER_CTX_cleanup(x) EVP_CIPHER_CTX_reset(x)
-#define EVP_CIPHER_CTX_init(x) EVP_CIPHER_CTX_reset(x)
-# endif
-#endif
-
- 
-/*
- * 1.1 renames RSA_PKCS1_SSLeay to RSA_PKCS1_OpenSSL
- * use RSA_PKCS1_OpenSSL
- * Previous versions are missing a number of functions to access
- * some hidden structures. Define them here:
+ * LIBRESSL_VERSION_NUMBER  0x3040200fL (changes with its versions)
  */
 
-/*  EVP_PKEY_base_id introduced in 1.0.1 */
-#if OPENSSL_VERSION_NUMBER < 0x10001000L
-#define EVP_PKEY_base_id(x)		(x->type)
-#endif
-
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
-#define RSA_PKCS1_OpenSSL		RSA_PKCS1_SSLeay
-
+#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x30500000L
 #define X509_get_extension_flags(x)	(x->ex_flags)
 #define X509_get_key_usage(x)		(x->ex_kusage)
 #define X509_get_extended_key_usage(x)	(x->ex_xkusage)
-#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x2050300fL
-#define X509_up_ref(cert)		CRYPTO_add(&cert->references, 1, CRYPTO_LOCK_X509)
-#endif
-#if !defined(LIBRESSL_VERSION_NUMBER) || LIBRESSL_VERSION_NUMBER < 0x20700000L
-#define OPENSSL_malloc_init		CRYPTO_malloc_init
-#define EVP_PKEY_get0_RSA(x)		(x->pkey.rsa)
-#define EVP_PKEY_get0_EC_KEY(x)		(x->pkey.ec)
-#define EVP_PKEY_get0_DSA(x)		(x->pkey.dsa)
-#define EVP_PKEY_up_ref(user_key)	CRYPTO_add(&user_key->references, 1, CRYPTO_LOCK_EVP_PKEY)
-#define ASN1_STRING_get0_data(x)	ASN1_STRING_data(x)
-#endif
 #endif
 
-/* workaround unused value warning for a macro that does nothing */
-#if defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x20700000L
-#define OPENSSL_malloc_init()
+#if defined(LIBRESSL_VERSION_NUMBER)
+#define OPENSSL_malloc_init()			while(0) continue
+#if LIBRESSL_VERSION_NUMBER < 0x30500000L
+#define FIPS_mode()                             (0)
+#endif
+#define EVP_sha3_224()                          (NULL)
+#define EVP_sha3_256()                          (NULL)
+#define EVP_sha3_384()                          (NULL)
+#define EVP_sha3_512()                          (NULL)
+#define EVP_PKEY_new_raw_public_key(t, e, p, l) (NULL)
+#define EVP_PKEY_get_raw_public_key(p, pu, l)   (0)
 #endif
 
+/* OpenSSL 1.1.1 has FIPS_mode function */
 #if OPENSSL_VERSION_NUMBER >= 0x30000000L
-#define EC_POINT_get_affine_coordinates_GFp     EC_POINT_get_affine_coordinates
-#define EC_POINT_set_affine_coordinates_GFp     EC_POINT_set_affine_coordinates
+#define FIPS_mode()                             EVP_default_properties_is_fips_enabled(NULL)
 #endif
 
-/*
- * OpenSSL-1.1.0-pre5 has hidden the RSA and DSA structures
- * One can no longer use statements like rsa->n = ...
- * Macros and defines don't work on all systems, so use inline versions
- * If that is not good enough, versions could be added to libopensc
- */
-
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x20700000L)
-/* based on OpenSSL-1.1.0 e_os2.h */
-/* sc_ossl_inline: portable inline definition usable in public headers */
-# if !defined(inline) && !defined(__cplusplus)
-#  if defined(__STDC_VERSION__) && __STDC_VERSION__>=199901L
-   /* just use inline */
-#   define sc_ossl_inline inline
-#  elif defined(__GNUC__) && __GNUC__>=2
-#   define sc_ossl_inline __inline__
-#  elif defined(_MSC_VER)
-#   define sc_ossl_inline __inline
-#  else
-#   define sc_ossl_inline
-#  endif
-# else
-#  define sc_ossl_inline inline
-# endif
-#endif
-
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2050300fL)
-
-#define RSA_bits(R) (BN_num_bits(R->n))
-
-#include <openssl/bn.h>
-#ifndef OPENSSL_NO_RSA
-#include <openssl/rsa.h>
-#endif
-#ifndef OPENSSL_NO_DSA
-#include <openssl/dsa.h>
-#endif
-#ifndef OPENSSL_NO_EC
-#include <openssl/ecdsa.h>
-#endif
-
-#ifndef OPENSSL_NO_RSA
-static sc_ossl_inline int RSA_set0_key(RSA *r, BIGNUM *n, BIGNUM *e, BIGNUM *d)
-{
-    /* d is the private component and may be NULL */
-    if (n == NULL || e == NULL)
-        return 0;
-
-    BN_free(r->n);
-    BN_free(r->e);
-    BN_free(r->d);
-    r->n = n;
-    r->e = e;
-    r->d = d;
-
-    return 1;
-}
-
-static sc_ossl_inline int RSA_set0_factors(RSA *r, BIGNUM *p, BIGNUM *q)
-{
-    if (p == NULL || q == NULL)
-        return 0;
-
-    BN_free(r->p);
-    BN_free(r->q);
-    r->p = p;
-    r->q = q;
-
-    return 1;
-}
-
-static sc_ossl_inline int RSA_set0_crt_params(RSA *r, BIGNUM *dmp1, BIGNUM *dmq1, BIGNUM *iqmp)
-{
-    if (dmp1 == NULL || dmq1 == NULL || iqmp == NULL)
-        return 0;
-
-    BN_free(r->dmp1);
-    BN_free(r->dmq1);
-    BN_free(r->iqmp);
-    r->dmp1 = dmp1;
-    r->dmq1 = dmq1;
-    r->iqmp = iqmp;
-
-    return 1;
-}
-
-static sc_ossl_inline void RSA_get0_key(const RSA *r, const BIGNUM **n, const BIGNUM **e, const BIGNUM **d)
-{
-    if (n != NULL)
-        *n = r->n;
-    if (e != NULL)
-        *e = r->e;
-    if (d != NULL)
-        *d = r->d;
-}
-
-static sc_ossl_inline void RSA_get0_factors(const RSA *r, const BIGNUM **p, const BIGNUM **q)
-{
-    if (p != NULL)
-        *p = r->p;
-    if (q != NULL)
-        *q = r->q;
-}
-
-static sc_ossl_inline void RSA_get0_crt_params(const RSA *r,
-                         const BIGNUM **dmp1, const BIGNUM **dmq1, const BIGNUM **iqmp)
-{
-    if (dmp1 != NULL)
-        *dmp1 = r->dmp1;
-    if (dmq1 != NULL)
-        *dmq1 = r->dmq1;
-    if (iqmp != NULL)
-        *iqmp = r->iqmp;
-}
-
-#endif /* OPENSSL_NO_RSA */
-
-#ifndef OPENSSL_NO_DSA
-static sc_ossl_inline void DSA_get0_pqg(const DSA *d, const BIGNUM **p, const BIGNUM **q, const BIGNUM **g)
-{
-    if (p != NULL)
-        *p = d->p;
-    if (q != NULL)
-        *q = d->q;
-    if (g != NULL)
-        *g = d->g;
-}
-
-static sc_ossl_inline void DSA_get0_key(const DSA *d, const BIGNUM **pub_key, const BIGNUM **priv_key)
-{
-    if (pub_key != NULL)
-        *pub_key = d->pub_key;
-    if (priv_key != NULL)
-        *priv_key = d->priv_key;
-}
-
-/* NOTE: DSA_set0_*  functions not defined because they are not currently used in OpenSC */
-#endif /* OPENSSL_NO_DSA */
-
-
-#ifndef OPENSSL_NO_EC
-static sc_ossl_inline int ECDSA_SIG_set0(ECDSA_SIG *sig, BIGNUM *r, BIGNUM *s)
-{
-    if (r == NULL || s == NULL)
-        return 0;
-    BN_clear_free(sig->r);
-    BN_clear_free(sig->s);
-    sig->r = r;
-    sig->s = s;
-    return 1;
-}
-#endif /* OPENSSL_NO_EC */
-
-static sc_ossl_inline int CRYPTO_secure_malloc_init(size_t size, int minsize)
-{
-    return 0;
-}
-
-static sc_ossl_inline int CRYPTO_secure_malloc_initialized()
-{
-    return 0;
-}
-
-static sc_ossl_inline void CRYPTO_secure_malloc_done()
-{
-}
-
-#else
-
-#include <openssl/crypto.h>
-
-#endif /* OPENSSL_VERSION_NUMBER < 0x10100000L */
-
-
 #ifdef __cplusplus
 }
 #endif /* __cplusplus */
diff -Nru opensc-0.22.0/src/libopensc/sec.c opensc-0.23.0/src/libopensc/sec.c
--- opensc-0.22.0/src/libopensc/sec.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/sec.c	2022-11-29 09:34:43.000000000 +0100
@@ -37,7 +37,10 @@
 {
 	int r;
 
-	if (card == NULL || crgram == NULL || out == NULL) {
+	if (card == NULL) {
+		return SC_ERROR_INVALID_ARGUMENTS;
+	}
+	if (crgram == NULL || out == NULL) {
 		LOG_FUNC_RETURN(card->ctx, SC_ERROR_INVALID_ARGUMENTS);
 	}
 	LOG_FUNC_CALLED(card->ctx);
@@ -334,3 +337,35 @@
 
 	return i;
 }
+
+int
+sc_encrypt_sym(struct sc_card *card, const u8 *plaintext, size_t plaintext_len,
+		u8 *out, size_t *outlen)
+{
+	int r;
+
+	if (card == NULL)
+		return SC_ERROR_INVALID_ARGUMENTS;
+
+	LOG_FUNC_CALLED(card->ctx);
+	if (card->ops->encrypt_sym == NULL)
+		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
+	r = card->ops->encrypt_sym(card, plaintext, plaintext_len, out, outlen);
+	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
+}
+
+int
+sc_decrypt_sym(struct sc_card *card, const u8 *data, size_t data_len,
+		u8 *out, size_t *outlen)
+{
+	int r;
+
+	if (card == NULL)
+		return SC_ERROR_INVALID_ARGUMENTS;
+
+	LOG_FUNC_CALLED(card->ctx);
+	if (card->ops->decrypt_sym == NULL)
+		SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_NOT_SUPPORTED);
+	r = card->ops->decrypt_sym(card, data, data_len, out, outlen);
+	SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE, r);
+}
diff -Nru opensc-0.22.0/src/libopensc/sm.h opensc-0.23.0/src/libopensc/sm.h
--- opensc-0.22.0/src/libopensc/sm.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/sm.h	2022-11-29 09:34:43.000000000 +0100
@@ -88,6 +88,10 @@
 #define SM_GP_SECURITY_MAC		0x01
 #define SM_GP_SECURITY_ENC		0x03
 
+/* As in OpenSSL include/openssl/des.h */
+typedef unsigned char sm_des_cblock[8];
+typedef /* const */ unsigned char sm_const_des_cblock[8];
+
 /* Global Platform (SCP01) data types */
 /*
  * @struct sm_type_params_gp
diff -Nru opensc-0.22.0/src/libopensc/types.h opensc-0.23.0/src/libopensc/types.h
--- opensc-0.22.0/src/libopensc/types.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/libopensc/types.h	2022-11-29 09:34:43.000000000 +0100
@@ -49,6 +49,7 @@
 #define SC_MAX_SDO_ACLS			8
 #define SC_MAX_CRTS_IN_SE		12
 #define SC_MAX_SE_NUM			8
+#define SC_MAX_PKCS15_EMULATORS	48
 
 /* When changing this value, pay attention to the initialization of the ASN1
  * static variables that use this macro, like, for example,
diff -Nru opensc-0.22.0/src/minidriver/Makefile.am opensc-0.23.0/src/minidriver/Makefile.am
--- opensc-0.22.0/src/minidriver/Makefile.am	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/minidriver/Makefile.am	2022-11-29 09:34:43.000000000 +0100
@@ -27,4 +27,7 @@
 if ENABLE_MINIDRIVER
 install-exec-hook:
 	mv "$(DESTDIR)$(libdir)/opensc-minidriver at LIBRARY_BITNESS@.dll" "$(DESTDIR)$(bindir)/"
+
+uninstall-hook:
+	rm -f "$(DESTDIR)$(bindir)/opensc-minidriver at LIBRARY_BITNESS@.dll"
 endif
diff -Nru opensc-0.22.0/src/minidriver/Makefile.mak opensc-0.23.0/src/minidriver/Makefile.mak
--- opensc-0.22.0/src/minidriver/Makefile.mak	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/minidriver/Makefile.mak	2022-11-29 09:34:43.000000000 +0100
@@ -20,5 +20,5 @@
 	echo LIBRARY $* > $*.def
 	echo EXPORTS >> $*.def
 	type minidriver.exports >> $*.def
-	link /dll $(LINKFLAGS) /def:$*.def /out:$(TARGET) $(OBJECTS) $(LIBS) $(ZLIB_LIB) $(OPENPACE_LIB) $(OPENSSL_LIB) ws2_32.lib gdi32.lib Comctl32.lib advapi32.lib Crypt32.lib User32.lib bcrypt.lib DelayImp.lib Rpcrt4.lib Shell32.lib Comctl32.lib Winmm.lib /DELAYLOAD:bcrypt.dll
+	link /dll $(LINKFLAGS) /def:$*.def /out:$(TARGET) $(OBJECTS) $(LIBS) $(ZLIB_LIB) $(OPENPACE_LIB) $(OPENSSL_LIB) ws2_32.lib gdi32.lib Comctl32.lib advapi32.lib Crypt32.lib User32.lib bcrypt.lib DelayImp.lib Rpcrt4.lib Shell32.lib Comctl32.lib Winmm.lib shlwapi.lib /DELAYLOAD:bcrypt.dll
 	if EXIST $(TARGET).manifest mt -manifest $(TARGET).manifest -outputresource:$(TARGET);2
diff -Nru opensc-0.22.0/src/minidriver/minidriver.c opensc-0.23.0/src/minidriver/minidriver.c
--- opensc-0.22.0/src/minidriver/minidriver.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/minidriver/minidriver.c	2022-11-29 09:34:43.000000000 +0100
@@ -57,6 +57,7 @@
 #ifdef ENABLE_OPENSSL
 #include <openssl/opensslv.h>
 #include <openssl/pem.h>
+#include <openssl/crypto.h>
 #endif
 
 #ifdef ENABLE_OPENPACE
@@ -97,7 +98,7 @@
 #define NULLSTR(a) (a == NULL ? "<NULL>" : a)
 #define NULLWSTR(a) (a == NULL ? L"<NULL>" : a)
 
-#define MD_MAX_KEY_CONTAINERS 12
+#define MD_MAX_KEY_CONTAINERS 32
 #define MD_CARDID_SIZE 16
 
 #define MD_ROLE_USER_SIGN (ROLE_ADMIN + 1)
@@ -412,6 +413,7 @@
  * check if the card is OK, has been removed, or the
  * caller has changed the handles.
  * if so, then try to reinit card
+ * or if different handles but same reader, just use the handles
  */
 static DWORD
 check_card_reader_status(PCARD_DATA pCardData, const char *name)
@@ -444,12 +446,17 @@
 			(size_t)vs->hSCardCtx,
 			(size_t)vs->hScard);
 		if (vs->ctx) {
-			vs->hScard = pCardData->hScard;
-			vs->hSCardCtx = pCardData->hSCardCtx;
-			r = sc_ctx_use_reader(vs->ctx, &vs->hSCardCtx, &vs->hScard);
-			logprintf(pCardData, 1, "sc_ctx_use_reader returned %d\n", r);
-			if (r)
-			    MD_FUNC_RETURN(pCardData, 1, SCARD_F_INTERNAL_ERROR);
+			if (1 == pcsc_check_reader_handles(vs->ctx, vs->reader, &pCardData->hSCardCtx, &pCardData->hScard)) {
+				_sc_delete_reader(vs->ctx, vs->reader);
+				MD_FUNC_RETURN(pCardData, 1, reinit_card_for(pCardData, name));
+			} else {
+				vs->hScard = pCardData->hScard;
+				vs->hSCardCtx = pCardData->hSCardCtx;
+				r = sc_ctx_use_reader(vs->ctx, &vs->hSCardCtx, &vs->hScard);
+				logprintf(pCardData, 1, "sc_ctx_use_reader returned %d\n", r);
+				if (r)
+					MD_FUNC_RETURN(pCardData, 1, SCARD_F_INTERNAL_ERROR);
+			}
 		}
 	}
 
@@ -1438,9 +1445,11 @@
 	for(ii = 0; ii < cert_num; ii++)   {
 		struct sc_pkcs15_cert_info *cert_info = (struct sc_pkcs15_cert_info *) prkey_objs[ii]->data;
 		struct sc_pkcs15_cert *cert = NULL;
+		int private_obj;
 		PCCERT_CONTEXT wincert = NULL;
 		if (cert_info->authority) {
-			rv = sc_pkcs15_read_certificate(vs->p15card, cert_info, &cert);
+			private_obj = prkey_objs[ii]->flags & SC_PKCS15_CO_FLAG_PRIVATE;
+			rv = sc_pkcs15_read_certificate(vs->p15card, cert_info, private_obj, &cert);
 			if(rv)   {
 				logprintf(pCardData, 2, "Cannot read certificate idx:%i: sc-error %d\n", ii, rv);
 				continue;
@@ -1540,8 +1549,9 @@
 			struct sc_pkcs15_cert *cert = NULL;
 			struct sc_pkcs15_object *cert_obj = vs->p15_containers[idx].cert_obj;
 			struct sc_pkcs15_cert_info *cert_info = (struct sc_pkcs15_cert_info *)cert_obj->data;
+			int private_obj = cert_obj->flags & SC_PKCS15_CO_FLAG_PRIVATE;
 
-			rv = sc_pkcs15_read_certificate(vs->p15card, cert_info, &cert);
+			rv = sc_pkcs15_read_certificate(vs->p15card, cert_info, private_obj, &cert);
 			if(rv)   {
 				logprintf(pCardData, 2, "Cannot read certificate idx:%i: sc-error %d\n", idx, rv);
 				logprintf(pCardData, 2, "set cardcf from 'DATA' pkcs#15 object\n");
@@ -2781,7 +2791,8 @@
 		for (i = 0; i < count; i++) {
 			algo_info = vs->p15card->card->algorithms + i;
 			if (algo_info->algorithm == SC_ALGORITHM_EC) {
-				flag = SC_ALGORITHM_ECDH_CDH_RAW | SC_ALGORITHM_EXT_EC_NAMEDCURVE;
+				flag = SC_ALGORITHM_ECDH_CDH_RAW;
+				/* TODO  check if namedCurve matches Windows supported curves */
 				/* ECDHE */
 				if ((dwKeySpec == AT_ECDHE_P256) && (algo_info->key_length == 256) && (algo_info->flags & flag)) {
 					keysize = 256;
@@ -2796,11 +2807,12 @@
 					break;
 				}
 				/* ECDSA */
-				flag = SC_ALGORITHM_ECDSA_HASH_NONE|
+				flag = SC_ALGORITHM_ECDSA_RAW|
+						SC_ALGORITHM_ECDSA_HASH_NONE|
 						SC_ALGORITHM_ECDSA_HASH_SHA1|
 						SC_ALGORITHM_ECDSA_HASH_SHA224|
-						SC_ALGORITHM_ECDSA_HASH_SHA256|
-						SC_ALGORITHM_EXT_EC_NAMEDCURVE;
+						SC_ALGORITHM_ECDSA_HASH_SHA256;
+				/* TODO  check if namedCurve matches Windows supported curves */
 				if ((dwKeySpec == AT_ECDSA_P256) && (algo_info->key_length == 256) && (algo_info->flags & flag)) {
 					keysize = 256;
 					break;
@@ -3554,9 +3566,10 @@
 
 	if (!pubkey_der.value && cont->cert_obj)   {
 		struct sc_pkcs15_cert *cert = NULL;
+		int private_obj = cont->cert_obj->flags & SC_PKCS15_CO_FLAG_PRIVATE;
 
 		logprintf(pCardData, 1, "now read certificate '%.*s'\n", (int) sizeof cont->cert_obj->label, cont->cert_obj->label);
-		rv = sc_pkcs15_read_certificate(vs->p15card, (struct sc_pkcs15_cert_info *)(cont->cert_obj->data), &cert);
+		rv = sc_pkcs15_read_certificate(vs->p15card, (struct sc_pkcs15_cert_info *)(cont->cert_obj->data), private_obj, &cert);
 		if(!rv)   {
 			rv = sc_pkcs15_encode_pubkey(vs->ctx, cert->key, &pubkey_der.value, &pubkey_der.len);
 			if (rv)   {
@@ -3681,8 +3694,10 @@
 				memcpy(((PBYTE)publicKey) + sizeof(BCRYPT_ECCKEY_BLOB),  pubkey_der.value + 3,  pubkey_der.len -3);
 
 				logprintf(pCardData, 3,
-					  "return info on ECC SIGN_CONTAINER_INDEX %u\n",
-					  (unsigned int)bContainerIndex);
+					  "return info on ECC SIGN_CONTAINER_INDEX %u cbKey:%u dwMagic:%u\n",
+					  (unsigned int)bContainerIndex,
+					  (unsigned int)publicKey->cbKey,
+					  (unsigned int)publicKey->dwMagic);
 			}
 			if (cont->size_key_exchange)   {
 				sz = (DWORD) (sizeof(BCRYPT_ECCKEY_BLOB) +  pubkey_der.len -3);
@@ -3720,14 +3735,23 @@
 				memcpy(((PBYTE)publicKey) + sizeof(BCRYPT_ECCKEY_BLOB),  pubkey_der.value + 3,  pubkey_der.len -3);
 
 				logprintf(pCardData, 3,
-					  "return info on ECC KEYX_CONTAINER_INDEX %u\n",
-					  (unsigned int)bContainerIndex);
+					  "return info on ECC KEYX_CONTAINER_INDEX %u cbKey:%u dwMagic:%u\n",
+					  (unsigned int)bContainerIndex,
+					  (unsigned int)publicKey->cbKey,
+					  (unsigned int)publicKey->dwMagic);
 			}
 		}
 	}
 	logprintf(pCardData, 7, "returns container(idx:%u) info\n",
 		  (unsigned int)bContainerIndex);
 
+	logprintf(pCardData, 1,
+		  "CardGetContainerInfo bContainerIndex=%u, dwFlags=0x%08X, dwVersion=%lu, cbSigPublicKey=%lu, cbKeyExPublicKey=%lu\n",
+		  (unsigned int)bContainerIndex, (unsigned int)dwFlags,
+		  (unsigned long)pContainerInfo->dwVersion,
+		  (unsigned long)pContainerInfo->cbSigPublicKey,
+		  (unsigned long)pContainerInfo->cbKeyExPublicKey);
+
 err:
 	free(pubkey_der.value);
 	unlock(pCardData);
@@ -4572,7 +4596,7 @@
 
 	if (alg_info->flags & SC_ALGORITHM_RSA_RAW)   {
 		logprintf(pCardData, 2, "sc_pkcs15_decipher: using RSA-RAW mechanism\n");
-		r = sc_pkcs15_decipher(vs->p15card, pkey, opt_crypt_flags, pbuf, pInfo->cbData, pbuf2, pInfo->cbData);
+		r = sc_pkcs15_decipher(vs->p15card, pkey, opt_crypt_flags, pbuf, pInfo->cbData, pbuf2, pInfo->cbData, NULL);
 		logprintf(pCardData, 2, "sc_pkcs15_decipher returned %d\n", r);
 
 		if (r > 0) {
@@ -4608,7 +4632,7 @@
 	else if (alg_info->flags & SC_ALGORITHM_RSA_PAD_PKCS1)   {
 		logprintf(pCardData, 2, "sc_pkcs15_decipher: using RSA_PAD_PKCS1 mechanism\n");
 		r = sc_pkcs15_decipher(vs->p15card, pkey, opt_crypt_flags | SC_ALGORITHM_RSA_PAD_PKCS1,
-				pbuf, pInfo->cbData, pbuf2, pInfo->cbData);
+				pbuf, pInfo->cbData, pbuf2, pInfo->cbData, NULL);
 		logprintf(pCardData, 2, "sc_pkcs15_decipher returned %d\n", r);
 		if (r > 0) {
 			/* No padding info, or padding info none */
@@ -4920,7 +4944,7 @@
 			goto err;
 		}
 
-		r = sc_pkcs15_compute_signature(vs->p15card, pkey, opt_crypt_flags, dataToSign, dataToSignLen, pbuf, lg);
+		r = sc_pkcs15_compute_signature(vs->p15card, pkey, opt_crypt_flags, dataToSign, dataToSignLen, pbuf, lg, NULL);
 		logprintf(pCardData, 2, "sc_pkcs15_compute_signature return %d\n", r);
 		if(r < 0)   {
 			logprintf(pCardData, 2, "sc_pkcs15_compute_signature error %s\n", sc_strerror(r));
@@ -6277,7 +6301,8 @@
 		if (cbData < sizeof(*pKeySizes))
 			MD_FUNC_RETURN(pCardData, 1, ERROR_INSUFFICIENT_BUFFER);
 
-		dwret = md_query_key_sizes(pCardData, 0, pKeySizes);
+		/* dwFlags has key_type */
+		dwret = md_query_key_sizes(pCardData, dwFlags, pKeySizes);
 		if (dwret != SCARD_S_SUCCESS)
 			MD_FUNC_RETURN(pCardData, 1, dwret);
 	}
@@ -7154,7 +7179,7 @@
 	case DLL_PROCESS_DETACH:
 		sc_notify_close();
 		if (lpReserved == NULL) {
-#if defined(ENABLE_OPENSSL) && defined(OPENSSL_SECURE_MALLOC_SIZE)
+#if defined(ENABLE_OPENSSL) && defined(OPENSSL_SECURE_MALLOC_SIZE) && !defined(LIBRESSL_VERSION_NUMBER)
 			CRYPTO_secure_malloc_done();
 #endif
 #ifdef ENABLE_OPENPACE
diff -Nru opensc-0.22.0/src/pkcs11/framework-pkcs15.c opensc-0.23.0/src/pkcs11/framework-pkcs15.c
--- opensc-0.22.0/src/pkcs11/framework-pkcs15.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs11/framework-pkcs15.c	2022-11-29 09:34:43.000000000 +0100
@@ -30,6 +30,10 @@
 #include "common/compat_strnlen.h"
 #ifdef ENABLE_OPENSSL
 #include <openssl/sha.h>
+#include <openssl/crypto.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/evp.h>
+#endif
 #else
 #define SHA_DIGEST_LENGTH	20
 #endif
@@ -544,9 +548,8 @@
 {
 	struct sc_pkcs11_slot *slot;
 	struct pkcs15_fw_data *fw_data = NULL;
-	struct sc_pkcs15_card *p15card = NULL;
 	struct sc_pkcs15_object *auth;
-	struct sc_pkcs15_auth_info *pin_info;
+	const char *name;
 	CK_RV rv;
 
 	sc_log(context, "C_GetTokenInfo(%lx)", slotID);
@@ -577,12 +580,6 @@
 		rv = sc_to_cryptoki_error(SC_ERROR_INTERNAL, "C_GetTokenInfo");
 		goto out;
 	}
-	p15card = fw_data->p15_card;
-	if (!p15card) {
-		rv = sc_to_cryptoki_error(SC_ERROR_INVALID_CARD, "C_GetTokenInfo");
-		goto out;
-	}
-
 	/* User PIN flags are cleared before re-calculation */
 	slot->token_info.flags &= ~(CKF_USER_PIN_COUNT_LOW|CKF_USER_PIN_FINAL_TRY|CKF_USER_PIN_LOCKED);
 	auth = slot_data_auth(slot->fw_data);
@@ -590,8 +587,17 @@
 		"C_GetTokenInfo() auth. object %p, token-info flags 0x%lX", auth,
 		slot->token_info.flags);
 	if (auth) {
+		struct sc_pkcs15_card *p15card = NULL;
+		struct sc_pkcs15_auth_info *pin_info = NULL;
+
 		pin_info = (struct sc_pkcs15_auth_info*) auth->data;
 
+		p15card = fw_data->p15_card;
+		if (!p15card) {
+			rv = sc_to_cryptoki_error(SC_ERROR_INVALID_CARD, "C_GetTokenInfo");
+			goto out;
+		}
+
 		sc_pkcs15_get_pin_info(p15card, auth);
 
 		if (pin_info->tries_left >= 0) {
@@ -606,7 +612,12 @@
 	memcpy(pInfo, &slot->token_info, sizeof(CK_TOKEN_INFO));
 out:
 	sc_pkcs11_unlock();
-	sc_log(context, "C_GetTokenInfo(%lx) returns %s", slotID, lookup_enum(RV_T, rv));
+
+	name = lookup_enum(RV_T, rv);
+	if (name)
+		sc_log(context, "C_GetTokenInfo(%lx) returns %s", slotID, name);
+	else
+		sc_log(context, "C_GetTokenInfo(%lx) returns 0x%08lX", slotID, rv);
 	return rv;
 }
 
@@ -682,7 +693,7 @@
 		p15_cert = NULL;			/* will read cert when needed */
 	}
 	else    {
-		rv = sc_pkcs15_read_certificate(fw_data->p15_card, p15_info, &p15_cert);
+		rv = sc_pkcs15_read_certificate(fw_data->p15_card, p15_info, 0, &p15_cert);
 		if (rv < 0)
 			return rv;
 	}
@@ -828,7 +839,7 @@
 	return rv;
 }
 
-/* Note, that this is not actuall PKCS #15 object, but just bogus
+/* Note, that this is not an actual PKCS #15 object, but just a bogus
  * structure to create PKCS #11 object. There is no corresponding
  * PKCS #15 object. */
 static int
@@ -1017,13 +1028,15 @@
 {
 	struct pkcs15_pubkey_object *obj2;
 	int rv;
+	int private_obj;
 
 	if (!cert)
 		return SC_ERROR_OBJECT_NOT_FOUND;
 
 	if (cert->cert_data)
 		return 0;
-	rv = sc_pkcs15_read_certificate(fw_data->p15_card, cert->cert_info, &cert->cert_data);
+	private_obj = cert->cert_flags & SC_PKCS15_CO_FLAG_PRIVATE;
+	rv = sc_pkcs15_read_certificate(fw_data->p15_card, cert->cert_info, private_obj, &cert->cert_data);
 	if (rv < 0)
 		return rv;
 
@@ -1165,7 +1178,7 @@
 
 			if (pin_len) {
 				size_t tokeninfo_len = 0;
-				if (p15card->tokeninfo)
+				if (p15card->tokeninfo && p15card->tokeninfo->label)
 					tokeninfo_len = strlen(p15card->tokeninfo->label);
 				/* Print the possibly truncated token label with at least 4
 				 * characters followed by the PIN label in parenthesis */
@@ -1188,7 +1201,7 @@
 							")", 32 - max_tokeninfo_len-2-pin_len);
 				}
 			} else {
-				/* PIN label is empty or just says non-useful "PIN",
+				/* PIN label is empty or just says useless "PIN",
 				 * print only token label */
 				strcpy_bp(slot->token_info.label,
 						p15card->tokeninfo ? p15card->tokeninfo->label : "",
@@ -2210,6 +2223,7 @@
 	CK_KEY_TYPE key_type;
 	struct sc_pkcs15_prkey_rsa *rsa = NULL;
 	struct sc_pkcs15_prkey_gostr3410 *gost = NULL;
+	struct sc_pkcs15_prkey_ec *ec = NULL;
 	int rc;
 	CK_RV rv;
 	char label[SC_PKCS15_MAX_LABEL_SIZE];
@@ -2251,8 +2265,8 @@
 			return CKR_ATTRIBUTE_VALUE_INVALID;
 		case CKK_EC:
 			args.key.algorithm = SC_ALGORITHM_EC;
-			/* TODO: -DEE Do not have PKCS15 card with EC to test this */
-			/* fall through */
+			ec = &args.key.u.ec;
+			break;
 		default:
 			return CKR_ATTRIBUTE_VALUE_INVALID;
 	}
@@ -2290,6 +2304,17 @@
 		case CKA_VALUE:
 			if (key_type == CKK_GOSTR3410)
 				bn = &gost->d;
+			if (key_type == CKK_EC)
+				bn = &ec->privateD;
+			break;
+		case CKA_EC_PARAMS:
+			ec->params.der.value = calloc(1, attr->ulValueLen);
+			ec->params.der.len = attr->ulValueLen;
+			rv = attr_extract(attr, ec->params.der.value, &ec->params.der.len);
+			if (rv != CKR_OK)
+				goto out;
+			if (sc_pkcs15_fix_ec_parameters(p11card->card->ctx, &ec->params) != SC_SUCCESS)
+				return CKR_ATTRIBUTE_VALUE_INVALID;
 			break;
 		case CKA_SIGN:
 			args.usage |= pkcs15_check_bool_cka(attr, SC_PKCS15_PRKEY_USAGE_SIGN);
@@ -2342,6 +2367,12 @@
 			goto out;
 		}
 	}
+	else if (key_type == CKK_EC)   {
+		if (!ec->privateD.len || !ec->params.field_length)   {
+			sc_log(context, "Template to store the EC private key is incomplete");
+			return CKR_TEMPLATE_INCOMPLETE;
+		}
+	}
 
 	rc = sc_pkcs15init_store_private_key(fw_data->p15_card, profile, &args, &key_obj);
 	if (rc < 0) {
@@ -2358,7 +2389,6 @@
 out:	return rv;
 }
 
-
 /*
  * Secret key objects can be stored on card, if the card supports them
  *
@@ -2548,7 +2578,9 @@
 
 out:
 	free(args.key.data); /* if allocated */
-	if (temp_object)
+
+	/* on error, free key_obj, unless it's created by pkcs15init. if OK, let it live as part of key_any_obj. */
+	if (rv != CKR_OK && temp_object)
 		free(key_obj); /* do not free if the object was created by pkcs15init. It will be freed in C_Finalize */
 	return rv;
 }
@@ -2566,6 +2598,7 @@
 	struct sc_pkcs15_auth_info *pin = NULL;
 	CK_KEY_TYPE key_type;
 	struct sc_pkcs15_pubkey_rsa *rsa = NULL;
+	struct sc_pkcs15_pubkey_ec *ec = NULL;
 	int rc;
 	CK_RV rv;
 	char label[SC_PKCS15_MAX_LABEL_SIZE];
@@ -2593,6 +2626,9 @@
 			rsa = &args.key.u.rsa;
 			break;
 		case CKK_EC:
+			args.key.algorithm = SC_ALGORITHM_EC;
+			ec = &args.key.u.ec;
+			break;
 		case CKK_EC_EDWARDS:
 		case CKK_EC_MONTGOMERY:
 			/* TODO: -DEE Do not have real pkcs15 card with EC */
@@ -2637,6 +2673,19 @@
 		case CKA_WRAP:
 			args.usage |= pkcs15_check_bool_cka(attr, SC_PKCS15_PRKEY_USAGE_WRAP);
 			break;
+		case CKA_EC_POINT:
+			if (key_type == CKK_EC) {
+				if (sc_pkcs15_decode_pubkey_ec(p11card->card->ctx, ec, attr->pValue, attr->ulValueLen) < 0)
+					return CKR_ATTRIBUTE_VALUE_INVALID;
+			}
+			break;
+		case CKA_EC_PARAMS:
+			ec->params.der.value = calloc(1, attr->ulValueLen);
+			ec->params.der.len = attr->ulValueLen;
+			rv = attr_extract(attr, ec->params.der.value, &ec->params.der.len);
+			if (rv != CKR_OK)
+				return CKR_ATTRIBUTE_VALUE_INVALID;
+			break;
 		default:
 			/* ignore unknown attrs, or flag error? */
 			continue;
@@ -2650,8 +2699,16 @@
 		}
 	}
 
-	if (!rsa->modulus.len || !rsa->exponent.len)
-		return CKR_TEMPLATE_INCOMPLETE;
+	if (key_type == CKK_RSA) {
+		if (!rsa->modulus.len || !rsa->exponent.len)
+			return CKR_TEMPLATE_INCOMPLETE;
+	}
+	else if (key_type == CKK_EC) {
+		if (!ec->ecpointQ.len || !ec->params.der.value)   {
+			sc_log(context, "Template to store the EC public key is incomplete");
+			return CKR_TEMPLATE_INCOMPLETE;
+		}
+	}
 
 	rc = sc_pkcs15init_store_public_key(fw_data->p15_card, profile, &args, &key_obj);
 	if (rc < 0)
@@ -3781,6 +3838,7 @@
 	NULL,	/* sign */
 	NULL,	/* unwrap_key */
 	NULL,	/* decrypt */
+	NULL,	/* encrypt */
 	NULL,	/* derive */
 	NULL,	/* can_do */
 	NULL,	/* init_params */
@@ -4192,7 +4250,6 @@
 		/* The MGF parameter was already verified in SignInit() */
 		flags |= mgf2flags(((CK_RSA_PKCS_PSS_PARAMS*)pMechanism->pParameter)->mgf);
 
-		/* Assuming salt is the size of hash */
 		break;
 	case CKM_GOSTR3410:
 		flags = SC_ALGORITHM_GOSTR3410_HASH_NONE;
@@ -4237,7 +4294,7 @@
 	       "Selected flags %X. Now computing signature for %lu bytes. %lu bytes reserved.",
 	       flags, ulDataLen, *pulDataLen);
 	rc = sc_pkcs15_compute_signature(fw_data->p15_card, prkey->prv_p15obj, flags,
-			pData, ulDataLen, pSignature, *pulDataLen);
+			pData, ulDataLen, pSignature, *pulDataLen, pMechanism);
 	if (rc < 0 && !sc_pkcs11_conf.lock_login && !prkey_has_path) {
 		/* If private key PKCS#15 object do not have 'path' attribute,
 		 * and if PKCS#11 login session is not locked,
@@ -4247,7 +4304,7 @@
 		 */
 		if (reselect_app_df(fw_data->p15_card) == SC_SUCCESS)
 			rc = sc_pkcs15_compute_signature(fw_data->p15_card, prkey->prv_p15obj, flags,
-					pData, ulDataLen, pSignature, *pulDataLen);
+					pData, ulDataLen, pSignature, *pulDataLen, pMechanism);
 	}
 
 	sc_unlock(p11card->card);
@@ -4273,7 +4330,7 @@
 	struct	pkcs15_fw_data *fw_data = NULL;
 	struct	pkcs15_prkey_object *prkey = (struct pkcs15_prkey_object *) obj;
 	struct	pkcs15_any_object *targetKeyObj = (struct pkcs15_any_object *) targetKey;
-	int	rv;
+	int	rv, flags = 0;
 
 	sc_log(context, "Initiating unwrapping with private key.");
 
@@ -4299,8 +4356,6 @@
 
 	sc_log(context, "Using mechanism %lx.", pMechanism->mechanism);
 
-#if 0
-	/* FIXME https://github.com/OpenSC/OpenSC/issues/1595 */
 	/* Select the proper padding mechanism */
 	switch (pMechanism->mechanism) {
 	case CKM_RSA_PKCS:
@@ -4312,7 +4367,6 @@
 	default:
 		return CKR_MECHANISM_INVALID;
 	}
-#endif
 
 	rv = sc_lock(p11card->card);
 
@@ -4320,7 +4374,7 @@
 		return sc_to_cryptoki_error(rv, "C_UnwrapKey");
 
 	/* Call the card to do the unwrap operation */
-	rv = sc_pkcs15_unwrap(fw_data->p15_card, prkey->prv_p15obj, targetKeyObj->p15_object, 0,
+	rv = sc_pkcs15_unwrap(fw_data->p15_card, prkey->prv_p15obj, targetKeyObj->p15_object, flags,
 		pWrappedKey, ulWrappedKeyLen, NULL, 0);
 
 	sc_unlock(p11card->card);
@@ -4343,6 +4397,21 @@
 	unsigned char decrypted[512]; /* FIXME: Will not work for keys above 4096 bits */
 	int	buff_too_small, rv, flags = 0, prkey_has_path = 0;
 
+	if (pulDataLen == NULL) {
+		/* This is call from the C_DecyptInit function */
+		sc_log(context, "C_DecryptInit...");
+		return CKR_OK;
+	}
+	if (pEncryptedData == NULL && ulEncryptedDataLen == 0) {
+		/* This is call from the C_DecryptFinalize function */
+		sc_log(context, "C_DecryptFinalize...");
+		*pulDataLen = 0;
+		return CKR_OK;
+	}
+	/* DecryptUpdate: we assume this code is called only once per session, either
+	 * from the C_Decrypt function or from an application using the C_DecryptUpdate call
+	 */
+
 	sc_log(context, "Initiating decryption.");
 
 	if (!p11card)
@@ -4413,12 +4482,12 @@
 		return sc_to_cryptoki_error(rv, "C_Decrypt");
 
 	rv = sc_pkcs15_decipher(fw_data->p15_card, prkey->prv_p15obj, flags,
-			pEncryptedData, ulEncryptedDataLen, decrypted, sizeof(decrypted));
+			pEncryptedData, ulEncryptedDataLen, decrypted, sizeof(decrypted), pMechanism);
 
 	if (rv < 0 && !sc_pkcs11_conf.lock_login && !prkey_has_path)
 		if (reselect_app_df(fw_data->p15_card) == SC_SUCCESS)
 			rv = sc_pkcs15_decipher(fw_data->p15_card, prkey->prv_p15obj, flags,
-					pEncryptedData, ulEncryptedDataLen, decrypted, sizeof(decrypted));
+					pEncryptedData, ulEncryptedDataLen, decrypted, sizeof(decrypted), pMechanism);
 
 	sc_unlock(p11card->card);
 
@@ -4581,8 +4650,6 @@
 {
 	const CK_RSA_PKCS_PSS_PARAMS *pss_params;
 	unsigned int expected_hash = 0, i;
-	unsigned int expected_salt_len = 0;
-	const unsigned int salt_lens[5] = { 160, 256, 384, 512, 224 };
 	const unsigned int hashes[5] = { CKM_SHA_1, CKM_SHA256,
 		CKM_SHA384, CKM_SHA512, CKM_SHA224 };
 	const CK_RSA_PKCS_OAEP_PARAMS *oaep_params;
@@ -4608,24 +4675,18 @@
 		 */
 		if (pMechanism->mechanism == CKM_SHA1_RSA_PKCS_PSS) {
 			expected_hash = CKM_SHA_1;
-			expected_salt_len = 160;
 		} else if (pMechanism->mechanism == CKM_SHA224_RSA_PKCS_PSS) {
 			expected_hash = CKM_SHA224;
-			expected_salt_len = 224;
 		} else if (pMechanism->mechanism == CKM_SHA256_RSA_PKCS_PSS) {
 			expected_hash = CKM_SHA256;
-			expected_salt_len = 256;
 		} else if (pMechanism->mechanism == CKM_SHA384_RSA_PKCS_PSS) {
 			expected_hash = CKM_SHA384;
-			expected_salt_len = 384;
 		} else if (pMechanism->mechanism == CKM_SHA512_RSA_PKCS_PSS) {
 			expected_hash = CKM_SHA512;
-			expected_salt_len = 512;
 		} else if (pMechanism->mechanism == CKM_RSA_PKCS_PSS) {
 			for (i = 0; i < 5; ++i) {
 				if (hashes[i] == pss_params->hashAlg) {
 					expected_hash = hashes[i];
-					expected_salt_len = salt_lens[i];
 				}
 			}
 		}
@@ -4633,13 +4694,6 @@
 		if (expected_hash != pss_params->hashAlg)
 			return CKR_MECHANISM_PARAM_INVALID;
 
-		/* We're strict, and only do PSS signatures with a salt length that
-		 * matches the digest length (any shorter is rubbish, any longer
-		 * is useless). */
-		if (pss_params->sLen != expected_salt_len / 8)
-			return CKR_MECHANISM_PARAM_INVALID;
-
-		/* TODO support different salt lengths */
 		break;
 	case CKM_RSA_PKCS_OAEP:
 		if (!pMechanism->pParameter ||
@@ -4658,7 +4712,6 @@
 		default:
 			return CKR_MECHANISM_PARAM_INVALID;
 		}
-		/* TODO support different salt lengths */
 		/* TODO is there something more to check */
 		break;
 	}
@@ -4676,6 +4729,7 @@
 	pkcs15_prkey_sign,
 	pkcs15_prkey_unwrap,
 	pkcs15_prkey_decrypt,
+	NULL,	/* encrypt */
 	pkcs15_prkey_derive,
 	pkcs15_prkey_can_do,
 	pkcs15_prkey_init_params,
@@ -4935,6 +4989,7 @@
 	NULL,	/* sign */
 	NULL,	/* unwrap_key */
 	NULL,	/* decrypt */
+	NULL,	/* ecrypt */
 	NULL,	/* derive */
 	NULL,	/* can_do */
 	NULL,	/* init_params */
@@ -4969,6 +5024,7 @@
 	struct pkcs15_fw_data *fw_data = NULL;
 	struct sc_card *card;
 	int rv;
+	int private_obj;
 
 	if (!p11card)
 		return sc_to_cryptoki_error(SC_ERROR_INVALID_CARD, "C_GetAttributeValue");
@@ -4991,7 +5047,8 @@
 	if (rv < 0)
 		return sc_to_cryptoki_error(rv, "C_GetAttributeValue");
 
-	rv = sc_pkcs15_read_data_object(fw_data->p15_card, dobj->info, out_data);
+	private_obj = dobj->data_flags;
+	rv = sc_pkcs15_read_data_object(fw_data->p15_card, dobj->info, private_obj, out_data);
 
 	sc_unlock(card);
 	if (rv < 0)
@@ -5115,6 +5172,7 @@
 	NULL,	/* sign */
 	NULL,	/* unwrap_key */
 	NULL,	/* decrypt */
+	NULL,	/* encrypt */
 	NULL,	/* derive */
 	NULL,	/* can_do */
 	NULL,	/* init_params */
@@ -5180,6 +5238,7 @@
 	NULL,	/* sign */
 	NULL,	/* unwrap_key */
 	NULL,	/* decrypt */
+	NULL,	/* encrypt */
 	NULL,	/* derive */
 	NULL,	/* can_do */
 	NULL,	/* init_params */
@@ -5304,13 +5363,21 @@
 		check_attribute_buffer(attr, sizeof(CK_BBOOL));
 		*(CK_BBOOL*)attr->pValue = (skey->info->access_flags & SC_PKCS15_PRKEY_ACCESS_LOCAL) != 0;
 		break;
+	case CKA_ALWAYS_AUTHENTICATE:
+		check_attribute_buffer(attr, sizeof(CK_BBOOL));
+		*(CK_BBOOL *)attr->pValue = skey->base.p15_object->user_consent >= 1 ? CK_TRUE : CK_FALSE;
+		break;
 	case CKA_OPENSC_ALWAYS_AUTH_ANY_OBJECT:
 		check_attribute_buffer(attr, sizeof(CK_BBOOL));
 		*(CK_BBOOL*)attr->pValue = skey->base.p15_object->user_consent >= 1 ? CK_TRUE : CK_FALSE;
 		break;
 	case CKA_VALUE_LEN:
 		check_attribute_buffer(attr, sizeof(CK_ULONG));
-		*(CK_ULONG*)attr->pValue = skey->info->data.len;
+		if (skey->info->data.len) { /* Available only if the CKA_VALUE is present -- probably never */
+			*(CK_ULONG*)attr->pValue = skey->info->data.len;
+		} else { /* From standard secret key SKDF keyLen attribute (in bits) */
+			*(CK_ULONG*)attr->pValue = skey->info->value_len/8;
+		}
 		break;
 	case CKA_VALUE:
 		check_attribute_buffer(attr, skey->info->data.len);
@@ -5474,6 +5541,160 @@
 	return CKR_OK;
 }
 
+static CK_RV
+pkcs15_skey_encrypt(struct sc_pkcs11_session *session, void *obj,
+		CK_MECHANISM_PTR pMechanism,
+		CK_BYTE_PTR pData, CK_ULONG ulDataLen,
+		CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
+{
+	struct sc_pkcs11_card *p11card = session->slot->p11card;
+	struct pkcs15_fw_data *fw_data = NULL;
+	struct pkcs15_skey_object *skey = (struct pkcs15_skey_object *)obj;
+	int rv, flags = 0;
+	size_t lEncryptedDataLen, *lpEncryptedDataLen;
+
+	if (!p11card)
+		return sc_to_cryptoki_error(SC_ERROR_INVALID_CARD, "C_Encrypt...");
+	fw_data = (struct pkcs15_fw_data *)p11card->fws_data[session->slot->fw_data_idx];
+	if (!fw_data)
+		return sc_to_cryptoki_error(SC_ERROR_INTERNAL, "C_Encrypt...");
+	if (!fw_data->p15_card)
+		return sc_to_cryptoki_error(SC_ERROR_INVALID_CARD, "C_Encrypt...");
+
+	if (pMechanism == NULL) {
+		sc_log(context, "No mechanism specified\n");
+		return CKR_ARGUMENTS_BAD;
+	}
+
+	/* do not check NULL/0 in Data/EncryptedData here, this
+	   can be an init operation or final operation..*/
+
+	if (skey && !(skey->info->usage & SC_PKCS15_PRKEY_USAGE_ENCRYPT))
+		skey = NULL;
+
+	/* TODO: should we look for a compatible key automatically? prv_next not implemented yet. */
+	/* skey = skey->prv_next; */
+
+	if (skey == NULL)
+		return CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+	sc_log(context, "Using mechanism %lx.", pMechanism->mechanism);
+
+	switch (pMechanism->mechanism) {
+	case CKM_AES_ECB:
+		/* handle this in card driver
+		if (ulDataLen % 16)
+			return CKR_DATA_LEN_RANGE; */
+		flags |= SC_ALGORITHM_AES_ECB;
+		break;
+	case CKM_AES_CBC:
+		/* handle this in card driver
+		if (ulDataLen % 16)
+			return CKR_DATA_LEN_RANGE; */
+		flags |= SC_ALGORITHM_AES_CBC;
+		break;
+	case CKM_AES_CBC_PAD:
+		flags |= SC_ALGORITHM_AES_CBC_PAD;
+		break;
+	default:
+		return CKR_MECHANISM_INVALID;
+	}
+
+	rv = sc_lock(p11card->card);
+
+	if (rv < 0)
+		return sc_to_cryptoki_error(rv, "C_Encrypt...");
+
+	/* pointer CK_ULONG_PTR to size_t conversion */
+	lpEncryptedDataLen = pulEncryptedDataLen ? &lEncryptedDataLen : NULL;
+
+	rv = sc_pkcs15_encrypt_sym(fw_data->p15_card, skey->prv_p15obj, flags,
+			pData, ulDataLen, pEncryptedData, lpEncryptedDataLen,
+			pMechanism->pParameter, pMechanism->ulParameterLen);
+
+	if (pulEncryptedDataLen)
+		*pulEncryptedDataLen = *lpEncryptedDataLen;
+
+	sc_unlock(p11card->card);
+	return sc_to_cryptoki_error(rv, "C_Encrypt...");
+}
+
+static CK_RV
+pkcs15_skey_decrypt(struct sc_pkcs11_session *session, void *obj,
+		CK_MECHANISM_PTR pMechanism,
+		CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen,
+		CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
+{
+	struct sc_pkcs11_card *p11card = session->slot->p11card;
+	struct pkcs15_fw_data *fw_data = NULL;
+	struct pkcs15_skey_object *skey = (struct pkcs15_skey_object *)obj;
+	int rv, flags = 0;
+	size_t lDataLen, *lpDataLen;
+
+	if (!p11card)
+		return sc_to_cryptoki_error(SC_ERROR_INVALID_CARD, "C_Decrypt...");
+	fw_data = (struct pkcs15_fw_data *)p11card->fws_data[session->slot->fw_data_idx];
+	if (!fw_data)
+		return sc_to_cryptoki_error(SC_ERROR_INTERNAL, "C_Decrypt...");
+	if (!fw_data->p15_card)
+		return sc_to_cryptoki_error(SC_ERROR_INVALID_CARD, "C_Decrypt...");
+
+	if (pMechanism == NULL) {
+		sc_log(context, "No mechanism specified\n");
+		return CKR_ARGUMENTS_BAD;
+	}
+
+	/* do not check NULL/0 in Data/DecryptedData here, this
+	   can be an init operation or final operation..*/
+
+	if (skey && !(skey->info->usage & SC_PKCS15_PRKEY_USAGE_DECRYPT))
+		skey = NULL;
+
+	/* Please read comments in pkcs15_skey_unwrap() and pkcs15_skey_wrap() */
+
+	if (skey == NULL)
+		return CKR_KEY_FUNCTION_NOT_PERMITTED;
+
+	sc_log(context, "Using mechanism %lx.", pMechanism->mechanism);
+
+	switch (pMechanism->mechanism) {
+	case CKM_AES_ECB:
+		/* handle this in card driver
+		if (ulDataLen % 16)
+			return CKR_DATA_LEN_RANGE; */
+		flags |= SC_ALGORITHM_AES_ECB;
+		break;
+	case CKM_AES_CBC:
+		/* handle this in card driver
+		if (ulDataLen % 16)
+			return CKR_DATA_LEN_RANGE; */
+		flags |= SC_ALGORITHM_AES_CBC;
+		break;
+	case CKM_AES_CBC_PAD:
+		flags |= SC_ALGORITHM_AES_CBC_PAD;
+		break;
+	default:
+		return CKR_MECHANISM_INVALID;
+	}
+
+	rv = sc_lock(p11card->card);
+
+	if (rv < 0)
+		return sc_to_cryptoki_error(rv, "C_Decrypt...");
+
+	/* pointer CK_ULONG_PTR to size_t conversion */
+	lpDataLen = pulDataLen ? &lDataLen : NULL;
+
+	rv = sc_pkcs15_decrypt_sym(fw_data->p15_card, skey->prv_p15obj, flags,
+			pEncryptedData, ulEncryptedDataLen, pData, lpDataLen,
+			pMechanism->pParameter, pMechanism->ulParameterLen);
+
+	if (pulDataLen)
+		*pulDataLen = *lpDataLen;
+
+	sc_unlock(p11card->card);
+	return sc_to_cryptoki_error(rv, "C_Decrypt...");
+}
 
 /*
  *  Secret key objects, currently used only to retrieve derived session key
@@ -5487,7 +5708,8 @@
 	NULL,	/* get_size */
 	NULL,	/* sign */
 	pkcs15_skey_unwrap,
-	NULL,	/* decrypt */
+	pkcs15_skey_decrypt,	/* decrypt */
+	pkcs15_skey_encrypt,	/* encrypt */
 	NULL,	/* derive */
 	NULL,	/* can_do */
 	NULL,	/* init_params */
@@ -5753,29 +5975,32 @@
 
 	if (flags & SC_ALGORITHM_GOSTR3410_HASH_NONE) {
 		mt = sc_pkcs11_new_fw_mechanism(CKM_GOSTR3410,
-				&mech_info, CKK_GOSTR3410, NULL, NULL);
+				&mech_info, CKK_GOSTR3410, NULL, NULL, NULL);
 		if (!mt)
 			return CKR_HOST_MEMORY;
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 	}
 	if (flags & SC_ALGORITHM_GOSTR3410_HASH_GOSTR3411) {
 		mt = sc_pkcs11_new_fw_mechanism(CKM_GOSTR3410_WITH_GOSTR3411,
-				&mech_info, CKK_GOSTR3410, NULL, NULL);
+				&mech_info, CKK_GOSTR3410, NULL, NULL, NULL);
 		if (!mt)
 			return CKR_HOST_MEMORY;
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 	}
 	if (flags & SC_ALGORITHM_ONBOARD_KEY_GEN) {
 		mech_info.flags = CKF_HW | CKF_GENERATE_KEY_PAIR;
 		mt = sc_pkcs11_new_fw_mechanism(CKM_GOSTR3410_KEY_PAIR_GEN,
-				&mech_info, CKK_GOSTR3410, NULL, NULL);
+				&mech_info, CKK_GOSTR3410, NULL, NULL, NULL);
 		if (!mt)
 			return CKR_HOST_MEMORY;
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 	}
@@ -5788,7 +6013,7 @@
 		unsigned long ext_flags, CK_ULONG min_key_size, CK_ULONG max_key_size)
 {
 	CK_MECHANISM_INFO mech_info;
-	sc_pkcs11_mechanism_type_t *mt;
+	sc_pkcs11_mechanism_type_t *mt = NULL, *registered_mt = NULL;
 	CK_FLAGS ec_flags = 0;
 	CK_RV rc;
 
@@ -5812,98 +6037,115 @@
 
 	/* add mechs card or driver support */
 	if (flags & SC_ALGORITHM_ECDSA_RAW) {
-		mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA, &mech_info, CKK_EC, NULL, NULL);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA, &mech_info, CKK_EC, NULL, NULL, NULL);
 		if (!mt)
 			return CKR_HOST_MEMORY;
 		if (flags & SC_ALGORITHM_ECDSA_HASH_NONE) {
-			rc = sc_pkcs11_register_mechanism(p11card, mt);
+			rc = sc_pkcs11_register_mechanism(p11card, mt, &registered_mt);
+			sc_pkcs11_free_mechanism(&mt);
 			if (rc != CKR_OK)
 				return rc;
 		}
 
 #ifdef ENABLE_OPENSSL
 		/* if card supports RAW add sign_and_hash using RAW for mechs  card does not support */
-
+		sc_pkcs11_mechanism_type_t *sign_type = mt ? mt : registered_mt;
 		if (flags & SC_ALGORITHM_ECDSA_RAW) {
 			if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA1)) {
 				rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
-					CKM_ECDSA_SHA1, CKM_SHA_1, mt);
-				if (rc != CKR_OK)
+					CKM_ECDSA_SHA1, CKM_SHA_1, sign_type);
+				if (rc != CKR_OK) {
+					sc_pkcs11_free_mechanism(&mt);
 					return rc;
+				}
 			}
 
 			if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA224)) {
 				rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
-					CKM_ECDSA_SHA224, CKM_SHA224, mt);
-				if (rc != CKR_OK)
+					CKM_ECDSA_SHA224, CKM_SHA224, sign_type);
+				if (rc != CKR_OK) {
+					sc_pkcs11_free_mechanism(&mt);
 					return rc;
+				}
 			}
 
 			if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA256)) {
 				rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
-					CKM_ECDSA_SHA256, CKM_SHA256, mt);
-				if (rc != CKR_OK)
+					CKM_ECDSA_SHA256, CKM_SHA256, sign_type);
+				if (rc != CKR_OK) {
+					sc_pkcs11_free_mechanism(&mt);
 					return rc;
+				}
 			}
 
 			if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA384)) {
 				rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
-					CKM_ECDSA_SHA384, CKM_SHA384, mt);
-				if (rc != CKR_OK)
+					CKM_ECDSA_SHA384, CKM_SHA384, sign_type);
+				if (rc != CKR_OK) {
+					sc_pkcs11_free_mechanism(&mt);
 					return rc;
+				}
 			}
 
 			if (!(flags & SC_ALGORITHM_ECDSA_HASH_SHA512)) {
 				rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
-					CKM_ECDSA_SHA512, CKM_SHA512, mt);
-				if (rc != CKR_OK)
+					CKM_ECDSA_SHA512, CKM_SHA512, sign_type);
+				if (rc != CKR_OK) {
+					sc_pkcs11_free_mechanism(&mt);
 					return rc;
+				}
 			}
 		}
+		sc_pkcs11_free_mechanism(&mt);
 #endif
 	}
 
 	if (flags & SC_ALGORITHM_ECDSA_HASH_SHA1) {
-		mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA1, &mech_info, CKK_EC, NULL, NULL);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA1, &mech_info, CKK_EC, NULL, NULL, NULL);
 		if (!mt)
 			return CKR_HOST_MEMORY;
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 	}
 
 	if (flags & SC_ALGORITHM_ECDSA_HASH_SHA224) {
-		mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA224, &mech_info, CKK_EC, NULL, NULL);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA224, &mech_info, CKK_EC, NULL, NULL, NULL);
 		if (!mt)
 			return CKR_HOST_MEMORY;
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 	}
 
 	if (flags & SC_ALGORITHM_ECDSA_HASH_SHA256) {
-		mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA256, &mech_info, CKK_EC, NULL, NULL);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA256, &mech_info, CKK_EC, NULL, NULL, NULL);
 		if (!mt)
 			return CKR_HOST_MEMORY;
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 	}
 
 	if (flags & SC_ALGORITHM_ECDSA_HASH_SHA384) {
-		mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA384, &mech_info, CKK_EC, NULL, NULL);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA384, &mech_info, CKK_EC, NULL, NULL, NULL);
 		if (!mt)
 			return CKR_HOST_MEMORY;
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 	}
 
 	if (flags & SC_ALGORITHM_ECDSA_HASH_SHA512) {
-		mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA512, &mech_info, CKK_EC, NULL, NULL);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_ECDSA_SHA512, &mech_info, CKK_EC, NULL, NULL, NULL);
 		if (!mt)
 			return CKR_HOST_MEMORY;
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 	}
@@ -5914,17 +6156,19 @@
 		mech_info.flags &= ~(CKF_SIGN | CKF_VERIFY);
 		mech_info.flags |= CKF_DERIVE;
 
-		mt = sc_pkcs11_new_fw_mechanism(CKM_ECDH1_COFACTOR_DERIVE, &mech_info, CKK_EC, NULL, NULL);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_ECDH1_COFACTOR_DERIVE, &mech_info, CKK_EC, NULL, NULL, NULL);
 		if (!mt)
 			return CKR_HOST_MEMORY;
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 
-		mt = sc_pkcs11_new_fw_mechanism(CKM_ECDH1_DERIVE, &mech_info, CKK_EC, NULL, NULL);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_ECDH1_DERIVE, &mech_info, CKK_EC, NULL, NULL, NULL);
 		if (!mt)
 			return CKR_HOST_MEMORY;
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 	}
@@ -5932,10 +6176,11 @@
 	if (flags & SC_ALGORITHM_ONBOARD_KEY_GEN) {
 		mech_info.flags = CKF_HW | CKF_GENERATE_KEY_PAIR;
 		mech_info.flags |= ec_flags;
-		mt = sc_pkcs11_new_fw_mechanism(CKM_EC_KEY_PAIR_GEN, &mech_info, CKK_EC, NULL, NULL);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_EC_KEY_PAIR_GEN, &mech_info, CKK_EC, NULL, NULL, NULL);
 		if (!mt)
 			return CKR_HOST_MEMORY;
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 	}
@@ -5954,11 +6199,17 @@
 	mech_info.ulMinKeySize = min_key_size;
 	mech_info.ulMaxKeySize = max_key_size;
 
+#ifdef ENABLE_OPENSSL
+	/* TODO verification using EDDSA
+	mech_info.flags |= CKF_VERIFY;
+	*/
+#endif
 	if (flags & SC_ALGORITHM_EDDSA_RAW) {
-		mt = sc_pkcs11_new_fw_mechanism(CKM_EDDSA, &mech_info, CKK_EC_EDWARDS, NULL, NULL);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_EDDSA, &mech_info, CKK_EC_EDWARDS, NULL, NULL, NULL);
 		if (!mt)
 			return CKR_HOST_MEMORY;
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 	}
@@ -5966,10 +6217,11 @@
 	if (flags & SC_ALGORITHM_ONBOARD_KEY_GEN) {
 		mech_info.flags = CKF_HW | CKF_GENERATE_KEY_PAIR;
 		mt = sc_pkcs11_new_fw_mechanism(CKM_EC_EDWARDS_KEY_PAIR_GEN,
-			&mech_info, CKK_EC_EDWARDS, NULL, NULL);
+			&mech_info, CKK_EC_EDWARDS, NULL, NULL, NULL);
 		if (!mt)
 			return CKR_HOST_MEMORY;
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 	}
@@ -5989,10 +6241,11 @@
 	mech_info.ulMaxKeySize = max_key_size;
 
 	if (flags & SC_ALGORITHM_XEDDSA_RAW) {
-		mt = sc_pkcs11_new_fw_mechanism(CKM_XEDDSA, &mech_info, CKK_EC_MONTGOMERY, NULL, NULL);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_XEDDSA, &mech_info, CKK_EC_MONTGOMERY, NULL, NULL, NULL);
 		if (!mt)
 			return CKR_HOST_MEMORY;
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 	}
@@ -6003,20 +6256,22 @@
 		mech_info.flags |= CKF_DERIVE;
 
 		/* Montgomery curves derive function is defined only for CKM_ECDH1_DERIVE mechanism */
-		mt = sc_pkcs11_new_fw_mechanism(CKM_ECDH1_DERIVE, &mech_info, CKK_EC_MONTGOMERY, NULL, NULL);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_ECDH1_DERIVE, &mech_info, CKK_EC_MONTGOMERY, NULL, NULL, NULL);
 		if (!mt)
 			return CKR_HOST_MEMORY;
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 	}
 
 	if (flags & SC_ALGORITHM_ONBOARD_KEY_GEN) {
 		mech_info.flags = CKF_HW | CKF_GENERATE_KEY_PAIR;
-		mt = sc_pkcs11_new_fw_mechanism(CKM_EC_MONTGOMERY_KEY_PAIR_GEN, &mech_info, CKK_EC_MONTGOMERY, NULL, NULL);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_EC_MONTGOMERY_KEY_PAIR_GEN, &mech_info, CKK_EC_MONTGOMERY, NULL, NULL, NULL);
 		if (!mt)
 			return CKR_HOST_MEMORY;
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 	}
@@ -6041,24 +6296,27 @@
 	if ((card->caps & SC_CARD_CAP_WRAP_KEY) == SC_CARD_CAP_WRAP_KEY)
 		mech_info.flags |= CKF_WRAP;
 
-	mt = sc_pkcs11_new_fw_mechanism(CKM_AES_ECB, &mech_info, CKK_AES, NULL, NULL);
+	mt = sc_pkcs11_new_fw_mechanism(CKM_AES_ECB, &mech_info, CKK_AES, NULL, NULL, NULL);
 	if (!mt)
 		return CKR_HOST_MEMORY;
-	rc = sc_pkcs11_register_mechanism(p11card, mt);
+	rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+	sc_pkcs11_free_mechanism(&mt);
 	if (rc != CKR_OK)
 			return rc;
 
-	mt = sc_pkcs11_new_fw_mechanism(CKM_AES_CBC, &mech_info, CKK_AES, NULL, NULL);
+	mt = sc_pkcs11_new_fw_mechanism(CKM_AES_CBC, &mech_info, CKK_AES, NULL, NULL, NULL);
 	if (!mt)
 		return CKR_HOST_MEMORY;
-	rc = sc_pkcs11_register_mechanism(p11card, mt);
+	rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+	sc_pkcs11_free_mechanism(&mt);
 	if (rc != CKR_OK)
 			return rc;
 
-	mt = sc_pkcs11_new_fw_mechanism(CKM_AES_CBC_PAD, &mech_info, CKK_AES, NULL, NULL);
+	mt = sc_pkcs11_new_fw_mechanism(CKM_AES_CBC_PAD, &mech_info, CKK_AES, NULL, NULL, NULL);
 	if (!mt)
 		return CKR_HOST_MEMORY;
-	rc = sc_pkcs11_register_mechanism(p11card, mt);
+	rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+	sc_pkcs11_free_mechanism(&mt);
 	if (rc != CKR_OK)
 			return rc;
 
@@ -6079,7 +6337,7 @@
 	CK_ULONG ec_min_key_size, ec_max_key_size,
 		aes_min_key_size, aes_max_key_size;
 	unsigned long ec_ext_flags;
-	sc_pkcs11_mechanism_type_t *mt;
+	sc_pkcs11_mechanism_type_t *mt, *registered_mt;
 	unsigned int num;
 	int rsa_flags = 0, ec_flags = 0, eddsa_flags = 0, xeddsa_flags = 0;
 	int ec_found = 0, gostr_flags = 0, aes_flags = 0;
@@ -6185,8 +6443,9 @@
 
 	/* Check if we support raw RSA */
 	if (rsa_flags & SC_ALGORITHM_RSA_RAW) {
-		mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_X_509, &mech_info, CKK_RSA, NULL, NULL);
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_X_509, &mech_info, CKK_RSA, NULL, NULL, NULL);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 
@@ -6195,14 +6454,15 @@
 		rsa_flags |= SC_ALGORITHM_RSA_PAD_PKCS1;
 #ifdef ENABLE_OPENSSL
 		rsa_flags |= SC_ALGORITHM_RSA_PAD_PSS;
-		/* TODO support OAEP decryption & encryption using OpenSSL */
+		rsa_flags |= SC_ALGORITHM_RSA_PAD_OAEP;
 #endif
 	}
 
 	if (rsa_flags & SC_ALGORITHM_RSA_PAD_ISO9796) {
 		/* Supported in hardware only, if the card driver declares it. */
-		mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_9796, &mech_info, CKK_RSA, NULL, NULL);
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_9796, &mech_info, CKK_RSA, NULL, NULL, NULL);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 	}
@@ -6220,8 +6480,9 @@
 
 	/* No need to Check for PKCS1  We support it in software and turned it on above so always added it */
 	if (rsa_flags & SC_ALGORITHM_RSA_PAD_PKCS1) {
-		mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS, &mech_info, CKK_RSA, NULL, NULL);
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS, &mech_info, CKK_RSA, NULL, NULL, NULL);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, &registered_mt);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 
@@ -6232,43 +6493,43 @@
 
 		if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA1) {
 			rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
-				CKM_SHA1_RSA_PKCS, CKM_SHA_1, mt);
+				CKM_SHA1_RSA_PKCS, CKM_SHA_1, registered_mt);
 			if (rc != CKR_OK)
 				return rc;
 		}
 		if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA224) {
 			rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
-				CKM_SHA224_RSA_PKCS, CKM_SHA224, mt);
+				CKM_SHA224_RSA_PKCS, CKM_SHA224, registered_mt);
 			if (rc != CKR_OK)
 				return rc;
 		}
 		if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA256) {
 			rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
-				CKM_SHA256_RSA_PKCS, CKM_SHA256, mt);
+				CKM_SHA256_RSA_PKCS, CKM_SHA256, registered_mt);
 			if (rc != CKR_OK)
 				return rc;
 		}
 		if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA384) {
 			rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
-				CKM_SHA384_RSA_PKCS, CKM_SHA384, mt);
+				CKM_SHA384_RSA_PKCS, CKM_SHA384, registered_mt);
 			if (rc != CKR_OK)
 				return rc;
 		}
 		if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA512) {
 			rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
-				CKM_SHA512_RSA_PKCS, CKM_SHA512, mt);
+				CKM_SHA512_RSA_PKCS, CKM_SHA512, registered_mt);
 			if (rc != CKR_OK)
 				return rc;
 		}
-		if (rsa_flags & SC_ALGORITHM_RSA_HASH_MD5) {
+		if (!FIPS_mode() && rsa_flags & SC_ALGORITHM_RSA_HASH_MD5) {
 			rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
-				CKM_MD5_RSA_PKCS, CKM_MD5, mt);
+				CKM_MD5_RSA_PKCS, CKM_MD5, registered_mt);
 			if (rc != CKR_OK)
 				return rc;
 		}
-		if (rsa_flags & SC_ALGORITHM_RSA_HASH_RIPEMD160) {
+		if (!FIPS_mode() && rsa_flags & SC_ALGORITHM_RSA_HASH_RIPEMD160) {
 			rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
-				CKM_RIPEMD160_RSA_PKCS, CKM_RIPEMD160, mt);
+				CKM_RIPEMD160_RSA_PKCS, CKM_RIPEMD160, registered_mt);
 			if (rc != CKR_OK)
 				return rc;
 		}
@@ -6278,38 +6539,39 @@
 	if (rsa_flags & SC_ALGORITHM_RSA_PAD_PSS) {
 		CK_FLAGS old_flags = mech_info.flags;
 		mech_info.flags &= ~(CKF_DECRYPT|CKF_ENCRYPT);
-		mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS_PSS, &mech_info, CKK_RSA, NULL, NULL);
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS_PSS, &mech_info, CKK_RSA, NULL, NULL, NULL);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, &registered_mt);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 
 		if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA1) {
 			rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
-				CKM_SHA1_RSA_PKCS_PSS, CKM_SHA_1, mt);
+				CKM_SHA1_RSA_PKCS_PSS, CKM_SHA_1, registered_mt);
 			if (rc != CKR_OK)
 				return rc;
 		}
 		if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA224) {
 			rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
-				CKM_SHA224_RSA_PKCS_PSS, CKM_SHA224, mt);
+				CKM_SHA224_RSA_PKCS_PSS, CKM_SHA224, registered_mt);
 			if (rc != CKR_OK)
 				return rc;
 		}
 		if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA256) {
 			rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
-				CKM_SHA256_RSA_PKCS_PSS, CKM_SHA256, mt);
+				CKM_SHA256_RSA_PKCS_PSS, CKM_SHA256, registered_mt);
 			if (rc != CKR_OK)
 				return rc;
 		}
 		if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA384) {
 			rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
-				CKM_SHA384_RSA_PKCS_PSS, CKM_SHA384, mt);
+				CKM_SHA384_RSA_PKCS_PSS, CKM_SHA384, registered_mt);
 			if (rc != CKR_OK)
 				return rc;
 		}
 		if (rsa_flags & SC_ALGORITHM_RSA_HASH_SHA512) {
 			rc = sc_pkcs11_register_sign_and_hash_mechanism(p11card,
-				CKM_SHA512_RSA_PKCS_PSS, CKM_SHA512, mt);
+				CKM_SHA512_RSA_PKCS_PSS, CKM_SHA512, registered_mt);
 			if (rc != CKR_OK)
 				return rc;
 		}
@@ -6319,8 +6581,9 @@
 	if (rsa_flags & SC_ALGORITHM_RSA_PAD_OAEP) {
 		CK_FLAGS old_flags = mech_info.flags;
 		mech_info.flags &= ~(CKF_SIGN|CKF_VERIFY|CKF_SIGN_RECOVER|CKF_VERIFY_RECOVER);
-		mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS_OAEP, &mech_info, CKK_RSA, NULL, NULL);
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS_OAEP, &mech_info, CKK_RSA, NULL, NULL, NULL);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK) {
 			return rc;
 		}
@@ -6329,10 +6592,11 @@
 
 	if (rsa_flags & SC_ALGORITHM_ONBOARD_KEY_GEN) {
 		mech_info.flags = CKF_GENERATE_KEY_PAIR;
-		mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS_KEY_PAIR_GEN, &mech_info, CKK_RSA, NULL, NULL);
+		mt = sc_pkcs11_new_fw_mechanism(CKM_RSA_PKCS_KEY_PAIR_GEN, &mech_info, CKK_RSA, NULL, NULL, NULL);
 		if (!mt)
 			return CKR_HOST_MEMORY;
-		rc = sc_pkcs11_register_mechanism(p11card, mt);
+		rc = sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
 		if (rc != CKR_OK)
 			return rc;
 	}
diff -Nru opensc-0.22.0/src/pkcs11/Makefile.am opensc-0.23.0/src/pkcs11/Makefile.am
--- opensc-0.22.0/src/pkcs11/Makefile.am	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs11/Makefile.am	2022-11-29 09:34:43.000000000 +0100
@@ -3,8 +3,8 @@
 MAINTAINERCLEANFILES = $(srcdir)/Makefile.in $(srcdir)/versioninfo-pkcs11.rc $(srcdir)/versioninfo-pkcs11-spy.rc
 EXTRA_DIST = Makefile.mak versioninfo-pkcs11.rc.in versioninfo-pkcs11-spy.rc.in opensc-pkcs11.pc.in opensc-pkcs11.dll.manifest onepin-opensc-pkcs11.dll.manifest
 
-lib_LTLIBRARIES = opensc-pkcs11.la pkcs11-spy.la onepin-opensc-pkcs11.la
 if ENABLE_SHARED
+lib_LTLIBRARIES = opensc-pkcs11.la pkcs11-spy.la onepin-opensc-pkcs11.la
 else
 noinst_LTLIBRARIES = libopensc-pkcs11.la
 endif
@@ -23,6 +23,9 @@
 	$(top_builddir)/src/common/libscdl.la \
 	$(top_builddir)/src/common/libcompat.la \
 	$(OPENPACE_LIBS) $(OPTIONAL_OPENSSL_LIBS) $(PTHREAD_LIBS)
+if WIN32
+OPENSC_PKCS11_LIBS += -lshlwapi
+endif
 
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = opensc-pkcs11.pc
@@ -61,6 +64,7 @@
 if WIN32
 opensc_pkcs11_la_SOURCES += versioninfo-pkcs11.rc
 pkcs11_spy_la_SOURCES += versioninfo-pkcs11-spy.rc
+pkcs11_spy_la_LIBADD += -lshlwapi
 endif
 
 if WIN32
@@ -69,6 +73,11 @@
 	for l in opensc-pkcs11.dll pkcs11-spy.dll; do \
 		mv "$(DESTDIR)$(libdir)/$$l" "$(DESTDIR)$(bindir)/$$l"; \
 	done
+
+uninstall-hook:
+	for l in opensc-pkcs11.dll pkcs11-spy.dll; do \
+		rm -f "$(DESTDIR)$(bindir)/$$l"; \
+	done
 else
 # see http://wiki.cacert.org/wiki/Pkcs11TaskForce
 install-exec-hook:
@@ -78,6 +87,11 @@
 		$(LN_S) ../$$l "$(DESTDIR)$(pkcs11dir)/$$l"; \
 	done
 
+uninstall-hook:
+	for l in opensc-pkcs11$(DYN_LIB_EXT) onepin-opensc-pkcs11$(DYN_LIB_EXT) pkcs11-spy$(DYN_LIB_EXT); do \
+		rm -f "$(DESTDIR)$(pkcs11dir)/$$l"; \
+	done
+	rm -df "$(DESTDIR)$(pkcs11dir)" || true
 endif
 
 TIDY_FLAGS = $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) $(OPENSC_PKCS11_CFLAGS)
diff -Nru opensc-0.22.0/src/pkcs11/Makefile.mak opensc-0.23.0/src/pkcs11/Makefile.mak
--- opensc-0.22.0/src/pkcs11/Makefile.mak	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs11/Makefile.mak	2022-11-29 09:34:43.000000000 +0100
@@ -26,15 +26,15 @@
 !INCLUDE $(TOPDIR)\win32\Make.rules.mak
 
 $(TARGET1): $(OBJECTS) $(LIBS)
-	link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET1) $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) $(ZLIB_LIB) gdi32.lib Comctl32.lib Shell32.lib user32.lib advapi32.lib ws2_32.lib Shell32.lib Comctl32.lib
+	link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET1) $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) $(ZLIB_LIB) gdi32.lib Comctl32.lib Shell32.lib user32.lib advapi32.lib ws2_32.lib Shell32.lib Comctl32.lib shlwapi.lib
 	if EXIST $(TARGET1).manifest mt -manifest $(TARGET1).manifest -outputresource:$(TARGET1);2
 
 $(TARGET2): $(OBJECTS) $(LIBS)
 	del pkcs11-global.obj
 	cl $(CODE_OPTIMIZATION) $(COPTS) /DMODULE_APP_NAME=\"onepin-opensc-pkcs11\" /c pkcs11-global.c
-	link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET2) $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) $(ZLIB_LIB) gdi32.lib Comctl32.lib Shell32.lib user32.lib advapi32.lib ws2_32.lib Shell32.lib Comctl32.lib
+	link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET2) $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) $(ZLIB_LIB) gdi32.lib Comctl32.lib Shell32.lib user32.lib advapi32.lib ws2_32.lib Shell32.lib Comctl32.lib shlwapi.lib
 	if EXIST $(TARGET2).manifest mt -manifest $(TARGET2).manifest -outputresource:$(TARGET2);2
 
 $(TARGET3): $(OBJECTS3) $(LIBS3)
-	link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET3) $(OBJECTS3) $(LIBS3) $(OPENSSL_LIB) gdi32.lib advapi32.lib
+	link $(LINKFLAGS) /dll /implib:$*.lib /out:$(TARGET3) $(OBJECTS3) $(LIBS3) $(OPENSSL_LIB) gdi32.lib advapi32.lib shlwapi.lib
 	if EXIST $(TARGET3).manifest mt -manifest $(TARGET3).manifest -outputresource:$(TARGET3);2
diff -Nru opensc-0.22.0/src/pkcs11/mechanism.c opensc-0.23.0/src/pkcs11/mechanism.c
--- opensc-0.22.0/src/pkcs11/mechanism.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs11/mechanism.c	2022-11-29 09:34:43.000000000 +0100
@@ -31,40 +31,163 @@
 	CK_MECHANISM_TYPE	hash_mech;
 	CK_MECHANISM_TYPE	sign_mech;
 	sc_pkcs11_mechanism_type_t *hash_type;
-	sc_pkcs11_mechanism_type_t *sign_type;
 };
 
 /* Also used for verification and decryption data */
-struct signature_data {
+struct operation_data {
 	struct sc_pkcs11_object *key;
 	struct hash_signature_info *info;
-	sc_pkcs11_operation_t *	md;
-	CK_BYTE			buffer[4096/8];
+	sc_pkcs11_operation_t *md;
+	CK_BYTE			*buffer;
 	unsigned int	buffer_len;
 };
 
+static struct operation_data *
+new_operation_data()
+{
+	return calloc(1, sizeof(struct operation_data));
+}
+
+static void
+operation_data_release(struct operation_data *data)
+{
+	if (!data)
+		return;
+	sc_pkcs11_release_operation(&data->md);
+	sc_mem_secure_clear_free(data->buffer, data->buffer_len);
+	free(data);
+}
+
+static CK_RV
+signature_data_buffer_append(struct operation_data *data,
+		const CK_BYTE *in, unsigned int in_len)
+{
+	if (!data)
+		return CKR_ARGUMENTS_BAD;
+	if (in_len == 0)
+		return CKR_OK;
+
+	unsigned int new_len = data->buffer_len + in_len;
+	CK_BYTE *new_buffer = sc_mem_secure_alloc(new_len);
+	if (!new_buffer)
+		return CKR_HOST_MEMORY;
+
+	if (data->buffer_len != 0)
+		memcpy(new_buffer, data->buffer, data->buffer_len);
+	memcpy(new_buffer+data->buffer_len, in, in_len);
+
+	sc_mem_secure_clear_free(data->buffer, data->buffer_len);
+	data->buffer = new_buffer;
+	data->buffer_len = new_len;
+	return CKR_OK;
+}
+
+void _update_mech_info(CK_MECHANISM_INFO_PTR mech_info, CK_MECHANISM_INFO_PTR new_mech_info) {
+	if (new_mech_info->ulMaxKeySize > mech_info->ulMaxKeySize)
+		mech_info->ulMaxKeySize = new_mech_info->ulMaxKeySize;
+	if (new_mech_info->ulMinKeySize < mech_info->ulMinKeySize)
+		mech_info->ulMinKeySize = new_mech_info->ulMinKeySize;
+	mech_info->flags |= new_mech_info->flags;
+}
+
+/*
+ * Copy a mechanism
+ */
+static CK_RV
+sc_pkcs11_copy_mechanism(sc_pkcs11_mechanism_type_t *mt,
+				sc_pkcs11_mechanism_type_t **new_mt)
+{
+	int rv;
+
+	*new_mt = calloc(1, sizeof(sc_pkcs11_mechanism_type_t));
+	if (!(*new_mt))
+		return CKR_HOST_MEMORY;
+	
+	memcpy(*new_mt, mt, sizeof(sc_pkcs11_mechanism_type_t));
+	/* mech_data needs specific function for making copy*/
+	if (mt->copy_mech_data
+		&& (rv = mt->copy_mech_data(mt->mech_data, (void **) &(*new_mt)->mech_data)) != CKR_OK) {
+		free(*new_mt);
+		return rv;
+	}
+	
+	return CKR_OK;
+}
+
 /*
  * Register a mechanism
+ * Check whether the mechanism is already in p11card,
+ * if not, make a copy of the given mechanism and store it
+ * in p11card.
  */
 CK_RV
 sc_pkcs11_register_mechanism(struct sc_pkcs11_card *p11card,
-				sc_pkcs11_mechanism_type_t *mt)
+				sc_pkcs11_mechanism_type_t *mt, sc_pkcs11_mechanism_type_t **result_mt)
 {
+	sc_pkcs11_mechanism_type_t *existing_mt;
+	sc_pkcs11_mechanism_type_t *copy_mt = NULL;
 	sc_pkcs11_mechanism_type_t **p;
+	int i, rv;
 
 	if (mt == NULL)
 		return CKR_HOST_MEMORY;
 
+	if ((existing_mt = sc_pkcs11_find_mechanism(p11card, mt->mech, mt->mech_info.flags))) {
+		for (i = 0; i < MAX_KEY_TYPES; i++) {
+			if (existing_mt->key_types[i] == mt->key_types[0]) {
+				/* Mechanism already registered with the same key_type,
+				 * just update it's info */
+				_update_mech_info(&existing_mt->mech_info, &mt->mech_info);
+				return CKR_OK;
+			}
+			if (existing_mt->key_types[i] < 0) {
+				/* There is a free slot for new key type, let's add it and
+				 * update mechanism info */
+				_update_mech_info(&existing_mt->mech_info, &mt->mech_info);
+				/* XXX Should be changed to loop over mt->key_types, if
+				 * we allow to register mechanism with multiple key types
+				 * in one operation */
+				existing_mt->key_types[i] = mt->key_types[0];
+				if (i + 1 < MAX_KEY_TYPES) {
+					existing_mt->key_types[i + 1] = -1;
+				}
+				return CKR_OK;
+			}
+		}
+		sc_log(p11card->card->ctx, "Too many key types in mechanism 0x%lx, more than %d", mt->mech, MAX_KEY_TYPES);
+		return CKR_BUFFER_TOO_SMALL;
+	}
+
 	p = (sc_pkcs11_mechanism_type_t **) realloc(p11card->mechanisms,
 			(p11card->nmechanisms + 2) * sizeof(*p));
 	if (p == NULL)
 		return CKR_HOST_MEMORY;
+	if ((rv = sc_pkcs11_copy_mechanism(mt, &copy_mt)) != CKR_OK) {
+		free(p);
+		return rv;
+	}
 	p11card->mechanisms = p;
-	p[p11card->nmechanisms++] = mt;
+	p[p11card->nmechanisms++] = copy_mt;
 	p[p11card->nmechanisms] = NULL;
+	/* Return registered mechanism for further use */
+	if (result_mt)
+		*result_mt = copy_mt;
 	return CKR_OK;
 }
 
+
+CK_RV
+_validate_key_type(sc_pkcs11_mechanism_type_t *mech, CK_KEY_TYPE key_type) {
+	int i;
+	for (i = 0; i < MAX_KEY_TYPES; i++) {
+		if (mech->key_types[i] < 0)
+			break;
+		if ((CK_KEY_TYPE)mech->key_types[i] == key_type)
+			return CKR_OK;
+	}
+	return CKR_KEY_TYPE_INCONSISTENT;
+}
+
 /*
  * Look up a mechanism
  */
@@ -240,7 +363,7 @@
  */
 CK_RV
 sc_pkcs11_sign_init(struct sc_pkcs11_session *session, CK_MECHANISM_PTR pMechanism,
-		    struct sc_pkcs11_object *key, CK_MECHANISM_TYPE key_type)
+		    struct sc_pkcs11_object *key, CK_KEY_TYPE key_type)
 {
 	struct sc_pkcs11_card *p11card;
 	sc_pkcs11_operation_t *operation;
@@ -259,8 +382,9 @@
 		LOG_FUNC_RETURN(context, CKR_MECHANISM_INVALID);
 
 	/* See if compatible with key type */
-	if (mt->key_type != key_type)
-		LOG_FUNC_RETURN(context, CKR_KEY_TYPE_INCONSISTENT);
+	rv = _validate_key_type(mt, key_type);
+	if (rv != CKR_OK)
+		LOG_FUNC_RETURN(context, (int) rv);
 
 	if (pMechanism->pParameter &&
 	    pMechanism->ulParameterLen > sizeof(operation->mechanism_params))
@@ -369,12 +493,12 @@
 		struct sc_pkcs11_object *key)
 {
 	struct hash_signature_info *info;
-	struct signature_data *data;
+	struct operation_data *data;
 	CK_RV rv;
 	int can_do_it = 0;
 
 	LOG_FUNC_CALLED(context);
-	if (!(data = calloc(1, sizeof(*data))))
+	if (!(data = new_operation_data()))
 		LOG_FUNC_RETURN(context, CKR_HOST_MEMORY);
 	data->info = NULL;
 	data->key = key;
@@ -391,7 +515,7 @@
 		}
 		else  {
 			/* Mechanism recognised but cannot be performed by pkcs#15 card, or some general error. */
-			free(data);
+			operation_data_release(data);
 			LOG_FUNC_RETURN(context, (int) rv);
 		}
 	}
@@ -401,7 +525,7 @@
 		rv = key->ops->init_params(operation->session, &operation->mechanism);
 		if (rv != CKR_OK) {
 			/* Probably bad arguments */
-			free(data);
+			operation_data_release(data);
 			LOG_FUNC_RETURN(context, (int) rv);
 		}
 	}
@@ -409,7 +533,7 @@
 	/* If this is a signature with hash operation,
 	 * and card cannot perform itself signature with hash operation,
 	 * set up the hash operation */
-	info = (struct hash_signature_info *) operation->type->mech_data;
+	info = (struct hash_signature_info *)operation->type->mech_data;
 	if (info != NULL && !can_do_it) {
 		/* Initialize hash operation */
 
@@ -420,7 +544,7 @@
 			rv = info->hash_type->md_init(data->md);
 		if (rv != CKR_OK) {
 			sc_pkcs11_release_operation(&data->md);
-			free(data);
+			operation_data_release(data);
 			LOG_FUNC_RETURN(context, (int) rv);
 		}
 		data->info = info;
@@ -434,43 +558,44 @@
 sc_pkcs11_signature_update(sc_pkcs11_operation_t *operation,
 		CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
 {
-	struct signature_data *data;
+	struct operation_data *data;
+	CK_RV rv;
 
 	LOG_FUNC_CALLED(context);
 	sc_log(context, "data part length %li", ulPartLen);
-	data = (struct signature_data *) operation->priv_data;
+	data = (struct operation_data *)operation->priv_data;
 	if (data->md) {
-		CK_RV rv = data->md->type->md_update(data->md, pPart, ulPartLen);
+		rv = data->md->type->md_update(data->md, pPart, ulPartLen);
 		LOG_FUNC_RETURN(context, (int) rv);
 	}
 
 	/* This signature mechanism operates on the raw data */
-	if (data->buffer_len + ulPartLen > sizeof(data->buffer))
-		LOG_FUNC_RETURN(context, CKR_DATA_LEN_RANGE);
-	memcpy(data->buffer + data->buffer_len, pPart, ulPartLen);
-	data->buffer_len += ulPartLen;
-	LOG_FUNC_RETURN(context, CKR_OK);
+	rv = signature_data_buffer_append(data, pPart, ulPartLen);
+	LOG_FUNC_RETURN(context, (int) rv);
 }
 
 static CK_RV
 sc_pkcs11_signature_final(sc_pkcs11_operation_t *operation,
 		CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen)
 {
-	struct signature_data *data;
+	struct operation_data *data;
 	CK_RV rv;
 
 	LOG_FUNC_CALLED(context);
-	data = (struct signature_data *) operation->priv_data;
+	data = (struct operation_data *)operation->priv_data;
 	if (data->md) {
 		sc_pkcs11_operation_t	*md = data->md;
-		CK_ULONG len = sizeof(data->buffer);
+		CK_BYTE hash[64];
+		CK_ULONG len = sizeof(hash);
 
-		rv = md->type->md_final(md, data->buffer, &len);
+		rv = md->type->md_final(md, hash, &len);
 		if (rv == CKR_BUFFER_TOO_SMALL)
 			rv = CKR_FUNCTION_FAILED;
 		if (rv != CKR_OK)
 			LOG_FUNC_RETURN(context, (int) rv);
-		data->buffer_len = (unsigned int) len;
+		rv = signature_data_buffer_append(data, hash, len);
+		if (rv != CKR_OK)
+			LOG_FUNC_RETURN(context, (int) rv);
 	}
 
 	rv = data->key->ops->sign(operation->session, data->key, &operation->mechanism,
@@ -487,7 +612,7 @@
 	CK_ATTRIBUTE attr_key_type = { CKA_KEY_TYPE, &key_type, sizeof(key_type) };
 	CK_RV rv;
 
-	key = ((struct signature_data *) operation->priv_data)->key;
+	key = ((struct operation_data *)operation->priv_data)->key;
 	/*
 	 * EC and GOSTR do not have CKA_MODULUS_BITS attribute.
 	 * But other code in framework treats them as if they do.
@@ -525,16 +650,11 @@
 }
 
 static void
-sc_pkcs11_signature_release(sc_pkcs11_operation_t *operation)
+sc_pkcs11_operation_release(sc_pkcs11_operation_t *operation)
 {
-	struct signature_data *data;
-
-	data = (struct signature_data *) operation->priv_data;
-	if (!data)
+	if (!operation)
 	    return;
-	sc_pkcs11_release_operation(&data->md);
-	memset(data, 0, sizeof(*data));
-	free(data);
+	operation_data_release(operation->priv_data);
 }
 
 #ifdef ENABLE_OPENSSL
@@ -544,7 +664,7 @@
  */
 CK_RV
 sc_pkcs11_verif_init(struct sc_pkcs11_session *session, CK_MECHANISM_PTR pMechanism,
-		struct sc_pkcs11_object *key, CK_MECHANISM_TYPE key_type)
+		struct sc_pkcs11_object *key, CK_KEY_TYPE key_type)
 {
 	struct sc_pkcs11_card *p11card;
 	sc_pkcs11_operation_t *operation;
@@ -561,8 +681,9 @@
 		return CKR_MECHANISM_INVALID;
 
 	/* See if compatible with key type */
-	if (mt->key_type != key_type)
-		return CKR_KEY_TYPE_INCONSISTENT;
+	rv = _validate_key_type(mt, key_type);
+	if (rv != CKR_OK)
+		LOG_FUNC_RETURN(context, (int) rv);
 
 	rv = session_start_operation(session, SC_PKCS11_OPERATION_VERIFY, mt, &operation);
 	if (rv != CKR_OK)
@@ -640,10 +761,10 @@
 		    struct sc_pkcs11_object *key)
 {
 	struct hash_signature_info *info;
-	struct signature_data *data;
+	struct operation_data *data;
 	CK_RV rv;
 
-	if (!(data = calloc(1, sizeof(*data))))
+	if (!(data = new_operation_data()))
 		return CKR_HOST_MEMORY;
 
 	data->info = NULL;
@@ -698,9 +819,9 @@
 sc_pkcs11_verify_update(sc_pkcs11_operation_t *operation,
 		    CK_BYTE_PTR pPart, CK_ULONG ulPartLen)
 {
-	struct signature_data *data;
+	struct operation_data *data;
 
-	data = (struct signature_data *) operation->priv_data;
+	data = (struct operation_data *)operation->priv_data;
 	if (data->md) {
 		sc_pkcs11_operation_t	*md = data->md;
 
@@ -708,18 +829,15 @@
 	}
 
 	/* This verification mechanism operates on the raw data */
-	if (data->buffer_len + ulPartLen > sizeof(data->buffer))
-		return CKR_DATA_LEN_RANGE;
-	memcpy(data->buffer + data->buffer_len, pPart, ulPartLen);
-	data->buffer_len += ulPartLen;
-	return CKR_OK;
+	CK_RV rv = signature_data_buffer_append(data, pPart, ulPartLen);
+	LOG_FUNC_RETURN(context, (int) rv);
 }
 
 static CK_RV
 sc_pkcs11_verify_final(sc_pkcs11_operation_t *operation,
 			CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen)
 {
-	struct signature_data *data;
+	struct operation_data *data;
 	struct sc_pkcs11_object *key;
 	unsigned char *pubkey_value = NULL;
 	CK_KEY_TYPE key_type;
@@ -729,7 +847,7 @@
 	CK_ATTRIBUTE attr_key_params = {CKA_GOSTR3410_PARAMS, &params, sizeof(params)};
 	CK_RV rv;
 
-	data = (struct signature_data *) operation->priv_data;
+	data = (struct operation_data *)operation->priv_data;
 
 	if (pSignature == NULL)
 		return CKR_ARGUMENTS_BAD;
@@ -773,6 +891,132 @@
 	return rv;
 }
 #endif
+/*
+ * Initialize a encrypting context. When we get here, we know
+ * the key object is capable of encrypt _something_
+ */
+CK_RV
+sc_pkcs11_encr_init(struct sc_pkcs11_session *session,
+		CK_MECHANISM_PTR pMechanism,
+		struct sc_pkcs11_object *key,
+		CK_KEY_TYPE key_type)
+{
+	struct sc_pkcs11_card *p11card;
+	sc_pkcs11_operation_t *operation;
+	sc_pkcs11_mechanism_type_t *mt;
+	CK_RV rv;
+
+	if (!session || !session->slot || !(p11card = session->slot->p11card))
+		return CKR_ARGUMENTS_BAD;
+
+	/* See if we support this mechanism type */
+	mt = sc_pkcs11_find_mechanism(p11card, pMechanism->mechanism, CKF_ENCRYPT);
+	if (mt == NULL)
+		return CKR_MECHANISM_INVALID;
+
+	/* See if compatible with key type */
+	rv = _validate_key_type(mt, key_type);
+	if (rv != CKR_OK)
+		LOG_FUNC_RETURN(context, (int)rv);
+
+	rv = session_start_operation(session, SC_PKCS11_OPERATION_ENCRYPT, mt, &operation);
+	if (rv != CKR_OK)
+		return rv;
+
+	memcpy(&operation->mechanism, pMechanism, sizeof(CK_MECHANISM));
+	if (pMechanism->pParameter) {
+		memcpy(&operation->mechanism_params, pMechanism->pParameter,
+				pMechanism->ulParameterLen);
+		operation->mechanism.pParameter = &operation->mechanism_params;
+	}
+	rv = mt->encrypt_init(operation, key);
+	if (rv != CKR_OK)
+		goto out;
+
+	/* Validate the mechanism parameters */
+	if (key->ops->init_params) {
+		rv = key->ops->init_params(operation->session, &operation->mechanism);
+		if (rv != CKR_OK)
+			goto out;
+	}
+	LOG_FUNC_RETURN(context, (int)rv);
+out:
+	session_stop_operation(session, SC_PKCS11_OPERATION_ENCRYPT);
+	LOG_FUNC_RETURN(context, (int)rv);
+}
+
+CK_RV
+sc_pkcs11_encr(struct sc_pkcs11_session *session,
+		CK_BYTE_PTR pData, CK_ULONG ulDataLen,
+		CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
+{
+	sc_pkcs11_operation_t *op;
+	CK_RV rv;
+
+	rv = session_get_operation(session, SC_PKCS11_OPERATION_ENCRYPT, &op);
+	if (rv != CKR_OK)
+		return rv;
+
+	rv = op->type->encrypt(op, pData, ulDataLen,
+			pEncryptedData, pulEncryptedDataLen);
+
+	/* application is requesting buffer size ? */
+	if (pEncryptedData == NULL) {
+		/* do not terminate session for CKR_OK */
+		if (rv == CKR_OK)
+			LOG_FUNC_RETURN(context, CKR_OK);
+	} else if (rv == CKR_BUFFER_TOO_SMALL)
+		LOG_FUNC_RETURN(context, CKR_BUFFER_TOO_SMALL);
+
+	session_stop_operation(session, SC_PKCS11_OPERATION_ENCRYPT);
+	LOG_FUNC_RETURN(context, (int)rv);
+}
+
+CK_RV
+sc_pkcs11_encr_update(struct sc_pkcs11_session *session,
+		CK_BYTE_PTR pData, CK_ULONG ulDataLen,
+		CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
+{
+	sc_pkcs11_operation_t *op;
+	CK_RV rv;
+
+	rv = session_get_operation(session, SC_PKCS11_OPERATION_ENCRYPT, &op);
+	if (rv != CKR_OK)
+		return rv;
+
+	rv = op->type->encrypt_update(op, pData, ulDataLen,
+			pEncryptedData, pulEncryptedDataLen);
+
+	/* terminate session for any error except CKR_BUFFER_TOO_SMALL */
+	if (rv != CKR_OK && rv != CKR_BUFFER_TOO_SMALL)
+		session_stop_operation(session, SC_PKCS11_OPERATION_ENCRYPT);
+	LOG_FUNC_RETURN(context, (int)rv);
+}
+
+CK_RV
+sc_pkcs11_encr_final(struct sc_pkcs11_session *session,
+		CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
+{
+	sc_pkcs11_operation_t *op;
+	CK_RV rv;
+
+	rv = session_get_operation(session, SC_PKCS11_OPERATION_ENCRYPT, &op);
+	if (rv != CKR_OK)
+		return rv;
+
+	rv = op->type->encrypt_final(op, pEncryptedData, pulEncryptedDataLen);
+
+	/* application is requesting buffer size ? */
+	if (pEncryptedData == NULL) {
+		/* do not terminate session for CKR_OK */
+		if (rv == CKR_OK)
+			LOG_FUNC_RETURN(context, CKR_OK);
+	} else if (rv == CKR_BUFFER_TOO_SMALL)
+		LOG_FUNC_RETURN(context, CKR_BUFFER_TOO_SMALL);
+
+	session_stop_operation(session, SC_PKCS11_OPERATION_ENCRYPT);
+	LOG_FUNC_RETURN(context, (int)rv);
+}
 
 /*
  * Initialize a decryption context. When we get here, we know
@@ -782,7 +1026,7 @@
 sc_pkcs11_decr_init(struct sc_pkcs11_session *session,
 			CK_MECHANISM_PTR pMechanism,
 			struct sc_pkcs11_object *key,
-			CK_MECHANISM_TYPE key_type)
+			CK_KEY_TYPE key_type)
 {
 	struct sc_pkcs11_card *p11card;
 	sc_pkcs11_operation_t *operation;
@@ -799,8 +1043,9 @@
 		return CKR_MECHANISM_INVALID;
 
 	/* See if compatible with key type */
-	if (mt->key_type != key_type)
-		return CKR_KEY_TYPE_INCONSISTENT;
+	rv = _validate_key_type(mt, key_type);
+	if (rv != CKR_OK)
+		LOG_FUNC_RETURN(context, (int) rv);
 
 	rv = session_start_operation(session, SC_PKCS11_OPERATION_DECRYPT, mt, &operation);
 	if (rv != CKR_OK)
@@ -851,6 +1096,52 @@
 }
 
 CK_RV
+sc_pkcs11_decr_update(struct sc_pkcs11_session *session,
+		CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen,
+		CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
+{
+	sc_pkcs11_operation_t *op;
+	CK_RV rv;
+
+	rv = session_get_operation(session, SC_PKCS11_OPERATION_DECRYPT, &op);
+	if (rv != CKR_OK)
+		return rv;
+
+	rv = op->type->decrypt_update(op, pEncryptedData, ulEncryptedDataLen,
+			pData, pulDataLen);
+
+	/* terminate session for any error except CKR_BUFFER_TOO_SMALL */
+	if (rv != CKR_OK && rv != CKR_BUFFER_TOO_SMALL)
+		session_stop_operation(session, SC_PKCS11_OPERATION_DECRYPT);
+	LOG_FUNC_RETURN(context, (int)rv);
+}
+
+CK_RV
+sc_pkcs11_decr_final(struct sc_pkcs11_session *session,
+		CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
+{
+	sc_pkcs11_operation_t *op;
+	CK_RV rv;
+
+	rv = session_get_operation(session, SC_PKCS11_OPERATION_DECRYPT, &op);
+	if (rv != CKR_OK)
+		return rv;
+
+	rv = op->type->decrypt_final(op, pData, pulDataLen);
+
+	/* application is requesting buffer size ? */
+	if (pData == NULL) {
+		/* do not terminate session for CKR_OK */
+		if (rv == CKR_OK)
+			LOG_FUNC_RETURN(context, CKR_OK);
+	} else if (rv == CKR_BUFFER_TOO_SMALL)
+		LOG_FUNC_RETURN(context, CKR_BUFFER_TOO_SMALL);
+
+	session_stop_operation(session, SC_PKCS11_OPERATION_DECRYPT);
+	LOG_FUNC_RETURN(context, (int)rv);
+}
+
+CK_RV
 sc_pkcs11_wrap(struct sc_pkcs11_session *session,
 	CK_MECHANISM_PTR pMechanism,
 	struct sc_pkcs11_object *wrappingKey,	/* wrapping key */
@@ -873,9 +1164,9 @@
 		return CKR_MECHANISM_INVALID;
 
 	/* See if compatible with key type */
-	/* TODO: what if there are several mechanisms with different key types? Should we loop through them? */
-	if (mt->key_type != key_type)
-		return CKR_KEY_TYPE_INCONSISTENT;
+	rv = _validate_key_type(mt, key_type);
+	if (rv != CKR_OK)
+		LOG_FUNC_RETURN(context, (int) rv);
 
 	rv = session_start_operation(session, SC_PKCS11_OPERATION_WRAP, mt, &operation);
 	if (rv != CKR_OK)
@@ -919,9 +1210,9 @@
 		return CKR_MECHANISM_INVALID;
 
 	/* See if compatible with key type */
-	/* TODO: what if there are several mechanisms with different key types? Should we loop through them? */
-	if (mt->key_type != key_type)
-		return CKR_KEY_TYPE_INCONSISTENT;
+	rv = _validate_key_type(mt, key_type);
+	if (rv != CKR_OK)
+		LOG_FUNC_RETURN(context, (int) rv);
 
 	rv = session_start_operation(session, SC_PKCS11_OPERATION_UNWRAP, mt, &operation);
 	if (rv != CKR_OK)
@@ -946,8 +1237,6 @@
 	return rv;
 }
 
-
-
 /* Derive one key from another, and return results in created object */
 CK_RV
 sc_pkcs11_deri(struct sc_pkcs11_session *session,
@@ -981,9 +1270,9 @@
 		return CKR_MECHANISM_INVALID;
 
 	/* See if compatible with key type */
-	if (mt->key_type != key_type)
-		return CKR_KEY_TYPE_INCONSISTENT;
-
+	rv = _validate_key_type(mt, key_type);
+	if (rv != CKR_OK)
+		LOG_FUNC_RETURN(context, (int) rv);
 
 	rv = session_start_operation(session, SC_PKCS11_OPERATION_DERIVE, mt, &operation);
 	if (rv != CKR_OK)
@@ -1045,6 +1334,140 @@
 	return rv;
 }
 
+/*
+ * Initialize a encrypt operation
+ */
+static CK_RV
+sc_pkcs11_encrypt_init(sc_pkcs11_operation_t *operation,
+		struct sc_pkcs11_object *key)
+{
+	struct operation_data *data;
+	CK_RV rv;
+
+	if (!(data = new_operation_data()))
+		return CKR_HOST_MEMORY;
+
+	data->key = key;
+
+	if (key->ops->can_do) {
+		rv = key->ops->can_do(operation->session, key, operation->type->mech, CKF_ENCRYPT);
+		if ((rv == CKR_OK) || (rv == CKR_FUNCTION_NOT_SUPPORTED)) {
+			/* Mechanism recognized and can be performed by pkcs#15 card or algorithm references not supported */
+		} else {
+			/* Mechanism cannot be performed by pkcs#15 card, or some general error. */
+			free(data);
+			LOG_FUNC_RETURN(context, (int)rv);
+		}
+	}
+
+	operation->priv_data = data;
+
+	/* The last parameter is NULL - this is call to INIT code in underlying functions */
+	return key->ops->encrypt(operation->session,
+			key, &operation->mechanism, NULL, 0, NULL, NULL);
+}
+
+static CK_RV
+sc_pkcs11_encrypt(sc_pkcs11_operation_t *operation,
+		CK_BYTE_PTR pData, CK_ULONG ulDataLen,
+		CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen)
+{
+	struct operation_data *data;
+	struct sc_pkcs11_object *key;
+	CK_RV rv;
+	CK_ULONG ulEncryptedDataLen, ulLastEncryptedPartLen;
+
+	/* PKCS#11: If pBuf is not NULL_PTR, then *pulBufLen must contain the size in bytes.. */
+	if (pEncryptedData && !pulEncryptedDataLen)
+		return CKR_ARGUMENTS_BAD;
+
+	ulEncryptedDataLen = pulEncryptedDataLen ? *pulEncryptedDataLen : 0;
+	ulLastEncryptedPartLen = ulEncryptedDataLen;
+
+	data = (struct operation_data *)operation->priv_data;
+
+	key = data->key;
+
+	/* Encrypt (Update) */
+	rv = key->ops->encrypt(operation->session, key, &operation->mechanism,
+			pData, ulDataLen, pEncryptedData, &ulEncryptedDataLen);
+
+	if (pulEncryptedDataLen)
+		*pulEncryptedDataLen = ulEncryptedDataLen;
+
+	if (rv != CKR_OK)
+		return rv;
+
+	/* recalculate buffer space */
+	if (ulEncryptedDataLen <= ulLastEncryptedPartLen)
+		ulLastEncryptedPartLen -= ulEncryptedDataLen;
+	else
+		ulLastEncryptedPartLen = 0;
+
+	/* EncryptFinalize */
+	rv = key->ops->encrypt(operation->session, key, &operation->mechanism,
+			NULL, 0, pEncryptedData + ulEncryptedDataLen, &ulLastEncryptedPartLen);
+
+	if (pulEncryptedDataLen)
+		*pulEncryptedDataLen = ulEncryptedDataLen + ulLastEncryptedPartLen;
+	return rv;
+}
+
+static CK_RV
+sc_pkcs11_encrypt_update(sc_pkcs11_operation_t *operation,
+		CK_BYTE_PTR pPart, CK_ULONG ulPartLen,
+		CK_BYTE_PTR pEncryptedPart, CK_ULONG_PTR pulEncryptedPartLen)
+{
+	struct operation_data *data;
+	struct sc_pkcs11_object *key;
+	CK_RV rv;
+	CK_ULONG ulEncryptedPartLen;
+
+	/* PKCS#11: If pBuf is not NULL_PTR, then *pulBufLen must contain the size in bytes.. */
+	if (pEncryptedPart && !pulEncryptedPartLen)
+		return CKR_ARGUMENTS_BAD;
+
+	ulEncryptedPartLen = pulEncryptedPartLen ? *pulEncryptedPartLen : 0;
+
+	data = (struct operation_data *)operation->priv_data;
+
+	key = data->key;
+
+	rv = key->ops->encrypt(operation->session, key, &operation->mechanism,
+			pPart, ulPartLen, pEncryptedPart, &ulEncryptedPartLen);
+
+	if (pulEncryptedPartLen)
+		*pulEncryptedPartLen = ulEncryptedPartLen;
+	return rv;
+}
+
+static CK_RV
+sc_pkcs11_encrypt_final(sc_pkcs11_operation_t *operation,
+		CK_BYTE_PTR pLastEncryptedPart,
+		CK_ULONG_PTR pulLastEncryptedPartLen)
+{
+	struct operation_data *data;
+	struct sc_pkcs11_object *key;
+	CK_RV rv;
+	CK_ULONG ulLastEncryptedPartLen;
+
+	/* PKCS#11: If pBuf is not NULL_PTR, then *pulBufLen must contain the size in bytes.. */
+	if (pLastEncryptedPart && !pulLastEncryptedPartLen)
+		return CKR_ARGUMENTS_BAD;
+
+	ulLastEncryptedPartLen = pulLastEncryptedPartLen ? *pulLastEncryptedPartLen : 0;
+
+	data = (struct operation_data *)operation->priv_data;
+
+	key = data->key;
+
+	rv = key->ops->encrypt(operation->session, key, &operation->mechanism,
+			NULL, 0, pLastEncryptedPart, &ulLastEncryptedPartLen);
+
+	if (pulLastEncryptedPartLen)
+		*pulLastEncryptedPartLen = ulLastEncryptedPartLen;
+	return rv;
+}
 
 /*
  * Initialize a decrypt operation
@@ -1053,10 +1476,10 @@
 sc_pkcs11_decrypt_init(sc_pkcs11_operation_t *operation,
 			struct sc_pkcs11_object *key)
 {
-	struct signature_data *data;
+	struct operation_data *data;
 	CK_RV rv;
 
-	if (!(data = calloc(1, sizeof(*data))))
+	if (!(data = new_operation_data()))
 		return CKR_HOST_MEMORY;
 
 	data->key = key;
@@ -1072,9 +1495,11 @@
 			LOG_FUNC_RETURN(context, (int) rv);
 		}
 	}
-
 	operation->priv_data = data;
-	return CKR_OK;
+
+	/* The last parameter is NULL - this is call to INIT code in underlying functions */
+	return key->ops->decrypt(operation->session,
+			key, &operation->mechanism, NULL, 0, NULL, NULL);
 }
 
 static CK_RV
@@ -1082,16 +1507,104 @@
 		CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen,
 		CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen)
 {
-	struct signature_data *data;
+	struct operation_data *data;
 	struct sc_pkcs11_object *key;
+	CK_RV rv;
+	CK_ULONG ulDataLen, ulLastDataLen;
 
-	data = (struct signature_data*) operation->priv_data;
+	/* PKCS#11: If pBuf is not NULL_PTR, then *pulBufLen must contain the size in bytes.. */
+	if (pData && !pulDataLen)
+		return CKR_ARGUMENTS_BAD;
+
+	ulDataLen = pulDataLen ? *pulDataLen : 0;
+	ulLastDataLen = ulDataLen;
+
+	data = (struct operation_data *)operation->priv_data;
 
 	key = data->key;
-	return key->ops->decrypt(operation->session,
-				key, &operation->mechanism,
-				pEncryptedData, ulEncryptedDataLen,
-				pData, pulDataLen);
+
+	/* Decrypt */
+	rv = key->ops->decrypt(operation->session, key, &operation->mechanism,
+			pEncryptedData, ulEncryptedDataLen, pData, &ulDataLen);
+
+	if (pulDataLen)
+		*pulDataLen = ulDataLen;
+
+	if (rv != CKR_OK)
+		return rv;
+
+	/* recalculate buffer space */
+	if (ulDataLen <= ulLastDataLen)
+		ulLastDataLen -= ulDataLen;
+	else
+		ulLastDataLen = 0;
+
+	/* DecryptFinalize */
+	rv = key->ops->decrypt(operation->session, key, &operation->mechanism,
+			NULL, 0, pData + ulDataLen, &ulLastDataLen);
+	if (pulDataLen)
+		*pulDataLen = ulDataLen + ulLastDataLen;
+	return rv;
+}
+
+static CK_RV
+sc_pkcs11_decrypt_update(sc_pkcs11_operation_t *operation,
+		CK_BYTE_PTR pEncryptedPart, CK_ULONG ulEncryptedPartLen,
+		CK_BYTE_PTR pPart, CK_ULONG_PTR pulPartLen)
+{
+	struct operation_data *data;
+	struct sc_pkcs11_object *key;
+	CK_RV rv;
+	CK_ULONG ulPartLen;
+
+	/* PKCS#11: If pBuf is not NULL_PTR, then *pulBufLen must contain the size in bytes.. */
+	if (pPart && !pulPartLen)
+		return CKR_ARGUMENTS_BAD;
+
+	ulPartLen = pulPartLen ? *pulPartLen : 0;
+
+	data = (struct operation_data *)operation->priv_data;
+
+	key = data->key;
+
+	rv = key->ops->decrypt(operation->session,
+			key, &operation->mechanism,
+			pEncryptedPart, ulEncryptedPartLen,
+			pPart, &ulPartLen);
+
+	if (pulPartLen)
+		*pulPartLen = ulPartLen;
+	return rv;
+}
+
+static CK_RV
+sc_pkcs11_decrypt_final(sc_pkcs11_operation_t *operation,
+		CK_BYTE_PTR pLastPart,
+		CK_ULONG_PTR pulLastPartLen)
+{
+	struct operation_data *data;
+	struct sc_pkcs11_object *key;
+	CK_RV rv;
+	CK_ULONG ulLastPartLen;
+
+	/* PKCS#11: If pBuf is not NULL_PTR, then *pulBufLen must contain the size in bytes.. */
+	if (pLastPart && !pulLastPartLen)
+		return CKR_ARGUMENTS_BAD;
+
+	ulLastPartLen = pulLastPartLen ? *pulLastPartLen : 0;
+
+	data = (struct operation_data *)operation->priv_data;
+
+	key = data->key;
+
+	rv = key->ops->decrypt(operation->session,
+			key, &operation->mechanism,
+			NULL, 0,
+			pLastPart, &ulLastPartLen);
+
+	if (pulLastPartLen)
+		*pulLastPartLen = ulLastPartLen;
+	return rv;
 }
 
 static CK_RV
@@ -1150,7 +1663,8 @@
 				CK_MECHANISM_INFO_PTR pInfo,
 				CK_KEY_TYPE key_type,
 				const void *priv_data,
-				void (*free_priv_data)(const void *priv_data))
+				void (*free_priv_data)(const void *priv_data),
+				CK_RV (*copy_priv_data)(const void *mech_data, void **new_data))
 {
 	sc_pkcs11_mechanism_type_t *mt;
 
@@ -1159,12 +1673,14 @@
 		return mt;
 	mt->mech = mech;
 	mt->mech_info = *pInfo;
-	mt->key_type = key_type;
+	mt->key_types[0] = (int)key_type;
+	mt->key_types[1] = -1;
 	mt->mech_data = priv_data;
 	mt->free_mech_data = free_priv_data;
+	mt->copy_mech_data = copy_priv_data;
 	mt->obj_size = sizeof(sc_pkcs11_operation_t);
 
-	mt->release = sc_pkcs11_signature_release;
+	mt->release = sc_pkcs11_operation_release;
 
 	if (pInfo->flags & CKF_SIGN) {
 		mt->sign_init = sc_pkcs11_signature_init;
@@ -1189,11 +1705,29 @@
 	if (pInfo->flags & CKF_DECRYPT) {
 		mt->decrypt_init = sc_pkcs11_decrypt_init;
 		mt->decrypt = sc_pkcs11_decrypt;
+		mt->decrypt_update = sc_pkcs11_decrypt_update;
+		mt->decrypt_final = sc_pkcs11_decrypt_final;
+	}
+	if (pInfo->flags & CKF_ENCRYPT) {
+		mt->encrypt_init = sc_pkcs11_encrypt_init;
+		mt->encrypt = sc_pkcs11_encrypt;
+		mt->encrypt_update = sc_pkcs11_encrypt_update;
+		mt->encrypt_final = sc_pkcs11_encrypt_final;
 	}
 
 	return mt;
 }
 
+void sc_pkcs11_free_mechanism(sc_pkcs11_mechanism_type_t **mt)
+{
+	if (!mt || !(*mt))
+		return;
+	if ((*mt)->free_mech_data)
+		(*mt)->free_mech_data((*mt)->mech_data);
+	free(*mt);
+	*mt = NULL;
+}
+
 /*
  * Register generic mechanisms
  */
@@ -1211,6 +1745,19 @@
 	free((void *) info);
 }
 
+CK_RV copy_hash_signature_info(const void *mech_data, void **new_data)
+{
+	if (mech_data == NULL || new_data == NULL)
+		return CKR_ARGUMENTS_BAD;
+
+	*new_data = calloc(1, sizeof(struct hash_signature_info));
+	if (!(*new_data))
+		return CKR_HOST_MEMORY;
+	
+	memcpy(*new_data, mech_data, sizeof(struct hash_signature_info));
+	return CKR_OK;
+}
+
 /*
  * Register a sign+hash algorithm derived from an algorithm supported
  * by the token + a software hash mechanism
@@ -1223,9 +1770,13 @@
 {
 	sc_pkcs11_mechanism_type_t *hash_type, *new_type;
 	struct hash_signature_info *info;
-	CK_MECHANISM_INFO mech_info = sign_type->mech_info;
+	CK_MECHANISM_INFO mech_info;
 	CK_RV rv;
 
+	if (!sign_type)
+		return CKR_MECHANISM_INVALID;
+	mech_info = sign_type->mech_info;
+
 	if (!(hash_type = sc_pkcs11_find_mechanism(p11card, hash_mech, CKF_DIGEST)))
 		return CKR_MECHANISM_INVALID;
 
@@ -1237,22 +1788,18 @@
 		return CKR_HOST_MEMORY;
 
 	info->mech = mech;
-	info->sign_type = sign_type;
 	info->hash_type = hash_type;
 	info->sign_mech = sign_type->mech;
 	info->hash_mech = hash_mech;
 
-	new_type = sc_pkcs11_new_fw_mechanism(mech, &mech_info, sign_type->key_type, info, free_info);
+	new_type = sc_pkcs11_new_fw_mechanism(mech, &mech_info, sign_type->key_types[0], info, free_info, copy_hash_signature_info);
 	if (!new_type) {
 		free_info(info);
 		return CKR_HOST_MEMORY;
 	}
 
-	rv = sc_pkcs11_register_mechanism(p11card, new_type);
-	if (CKR_OK != rv) {
-		new_type->free_mech_data(new_type->mech_data);
-		free(new_type);
-	}
+	rv = sc_pkcs11_register_mechanism(p11card, new_type, NULL);
+	sc_pkcs11_free_mechanism(&new_type);
 
 	return rv;
 }
diff -Nru opensc-0.22.0/src/pkcs11/misc.c opensc-0.23.0/src/pkcs11/misc.c
--- opensc-0.22.0/src/pkcs11/misc.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs11/misc.c	2022-11-29 09:34:43.000000000 +0100
@@ -115,6 +115,8 @@
 		return CKR_DEVICE_MEMORY;
 	case SC_ERROR_MEMORY_FAILURE:	/* EEPROM has failed */
 		return CKR_DEVICE_ERROR;
+	case SC_ERROR_WRONG_PADDING:
+		return CKR_ENCRYPTED_DATA_INVALID;
 	}
 	return CKR_GENERAL_ERROR;
 }
@@ -216,8 +218,7 @@
 err:
 	if (login) {
 		if (login->pPin) {
-			sc_mem_clear(login->pPin, login->ulPinLen);
-			sc_mem_secure_free(login->pPin, login->ulPinLen);
+			sc_mem_secure_clear_free(login->pPin, login->ulPinLen);
 		}
 		free(login);
 	}
@@ -232,8 +233,7 @@
 		if (size > 0) {
 			struct sc_pkcs11_login *login = list_get_at(&slot->logins, size-1);
 			if (login) {
-				sc_mem_clear(login->pPin, login->ulPinLen);
-				sc_mem_secure_free(login->pPin, login->ulPinLen);
+				sc_mem_secure_clear_free(login->pPin, login->ulPinLen);
 				free(login);
 			}
 			if (0 > list_delete_at(&slot->logins, size-1))
@@ -247,8 +247,7 @@
 	if (sc_pkcs11_conf.atomic && slot) {
 		struct sc_pkcs11_login *login = list_fetch(&slot->logins);
 		while (login) {
-			sc_mem_clear(login->pPin, login->ulPinLen);
-			sc_mem_secure_free(login->pPin, login->ulPinLen);
+			sc_mem_secure_clear_free(login->pPin, login->ulPinLen);
 			free(login);
 			login = list_fetch(&slot->logins);
 		}
diff -Nru opensc-0.22.0/src/pkcs11/openssl.c opensc-0.23.0/src/pkcs11/openssl.c
--- opensc-0.22.0/src/pkcs11/openssl.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs11/openssl.c	2022-11-29 09:34:43.000000000 +0100
@@ -23,6 +23,7 @@
 
 #ifdef ENABLE_OPENSSL		/* empty file without openssl */
 #include <string.h>
+#include <limits.h>
 #include <openssl/bn.h>
 #include <openssl/evp.h>
 #include <openssl/rand.h>
@@ -31,6 +32,10 @@
 #include <openssl/x509.h>
 #include <openssl/conf.h>
 #include <openssl/opensslconf.h> /* for OPENSSL_NO_* */
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/core_names.h>
+#include <openssl/param_build.h>
+#endif
 #include "libopensc/sc-ossl-compat.h"
 #ifndef OPENSSL_NO_EC
 #include <openssl/ec.h>
@@ -53,7 +58,7 @@
 static sc_pkcs11_mechanism_type_t openssl_sha1_mech = {
 	CKM_SHA_1,
 	{ 0, 0, CKF_DIGEST },
-	0,
+	{ -1 },
 	sizeof(struct sc_pkcs11_operation),
 	sc_pkcs11_openssl_md_release,
 	sc_pkcs11_openssl_md_init,
@@ -61,18 +66,20 @@
 	sc_pkcs11_openssl_md_final,
 	NULL, NULL, NULL, NULL,	/* sign_* */
 	NULL, NULL, NULL,	/* verif_* */
-	NULL, NULL,		/* decrypt_* */
+	NULL, NULL, NULL,NULL,	/* decrypt_* */
+	NULL, NULL, NULL, NULL, /* encrypt */
 	NULL,			/* derive */
 	NULL,			/* wrap */
 	NULL,			/* unwrap */
 	NULL,			/* mech_data */
 	NULL,			/* free_mech_data */
+	NULL,			/* copy_mech_data */
 };
 
 static sc_pkcs11_mechanism_type_t openssl_sha224_mech = {
 	CKM_SHA224,
 	{ 0, 0, CKF_DIGEST },
-	0,
+	{ -1 },
 	sizeof(struct sc_pkcs11_operation),
 	sc_pkcs11_openssl_md_release,
 	sc_pkcs11_openssl_md_init,
@@ -80,18 +87,20 @@
 	sc_pkcs11_openssl_md_final,
 	NULL, NULL, NULL, NULL,	/* sign_* */
 	NULL, NULL, NULL,	/* verif_* */
-	NULL, NULL,		/* decrypt_* */
+	NULL, NULL, NULL, NULL,	/* decrypt_* */
+	NULL, NULL, NULL, NULL, /* encrypt */
 	NULL,			/* derive */
 	NULL,			/* wrap */
 	NULL,			/* unwrap */
 	NULL,			/* mech_data */
 	NULL,			/* free_mech_data */
+	NULL,			/* copy_mech_data */
 };
 
 static sc_pkcs11_mechanism_type_t openssl_sha256_mech = {
 	CKM_SHA256,
 	{ 0, 0, CKF_DIGEST },
-	0,
+	{ -1 },
 	sizeof(struct sc_pkcs11_operation),
 	sc_pkcs11_openssl_md_release,
 	sc_pkcs11_openssl_md_init,
@@ -99,18 +108,20 @@
 	sc_pkcs11_openssl_md_final,
 	NULL, NULL, NULL, NULL,	/* sign_* */
 	NULL, NULL, NULL,	/* verif_* */
-	NULL, NULL,		/* decrypt_* */
+	NULL, NULL, NULL, NULL,	/* decrypt_* */
+	NULL, NULL, NULL, NULL, /* encrypt */
 	NULL,			/* derive */
 	NULL,			/* wrap */
 	NULL,			/* unwrap */
 	NULL,			/* mech_data */
 	NULL,			/* free_mech_data */
+	NULL,			/* copy_mech_data */
 };
 
 static sc_pkcs11_mechanism_type_t openssl_sha384_mech = {
 	CKM_SHA384,
 	{ 0, 0, CKF_DIGEST },
-	0,
+	{ -1 },
 	sizeof(struct sc_pkcs11_operation),
 	sc_pkcs11_openssl_md_release,
 	sc_pkcs11_openssl_md_init,
@@ -118,18 +129,20 @@
 	sc_pkcs11_openssl_md_final,
 	NULL, NULL, NULL, NULL,	/* sign_* */
 	NULL, NULL, NULL,	/* verif_* */
-	NULL, NULL,		/* decrypt_* */
+	NULL, NULL, NULL, NULL,	/* decrypt_* */
+	NULL, NULL, NULL, NULL, /* encrypt */
 	NULL,			/* derive */
 	NULL,			/* wrap */
 	NULL,			/* unwrap */
 	NULL,			/* mech_data */
 	NULL,			/* free_mech_data */
+	NULL,			/* copy_mech_data */
 };
 
 static sc_pkcs11_mechanism_type_t openssl_sha512_mech = {
 	CKM_SHA512,
 	{ 0, 0, CKF_DIGEST },
-	0,
+	{ -1 },
 	sizeof(struct sc_pkcs11_operation),
 	sc_pkcs11_openssl_md_release,
 	sc_pkcs11_openssl_md_init,
@@ -137,18 +150,20 @@
 	sc_pkcs11_openssl_md_final,
 	NULL, NULL, NULL, NULL,	/* sign_* */
 	NULL, NULL, NULL,	/* verif_* */
-	NULL, NULL,		/* decrypt_* */
+	NULL, NULL, NULL, NULL,	/* decrypt_* */
+	NULL, NULL, NULL, NULL, /* encrypt */
 	NULL,			/* derive */
 	NULL,			/* wrap */
 	NULL,			/* unwrap */
 	NULL,			/* mech_data */
 	NULL,			/* free_mech_data */
+	NULL,			/* copy_mech_data */
 };
 
 static sc_pkcs11_mechanism_type_t openssl_gostr3411_mech = {
 	CKM_GOSTR3411,
 	{ 0, 0, CKF_DIGEST },
-	0,
+	{ -1 },
 	sizeof(struct sc_pkcs11_operation),
 	sc_pkcs11_openssl_md_release,
 	sc_pkcs11_openssl_md_init,
@@ -156,18 +171,20 @@
 	sc_pkcs11_openssl_md_final,
 	NULL, NULL, NULL, NULL,	/* sign_* */
 	NULL, NULL, NULL,	/* verif_* */
-	NULL, NULL,		/* decrypt_* */
+	NULL, NULL, NULL,NULL,	/* decrypt_* */
+	NULL, NULL, NULL, NULL, /* encrypt */
 	NULL,			/* derive */
 	NULL,			/* wrap */
 	NULL,			/* unwrap */
 	NULL,			/* mech_data */
 	NULL,			/* free_mech_data */
+	NULL,			/* copy_mech_data */
 };
 
 static sc_pkcs11_mechanism_type_t openssl_md5_mech = {
 	CKM_MD5,
 	{ 0, 0, CKF_DIGEST },
-	0,
+	{ -1 },
 	sizeof(struct sc_pkcs11_operation),
 	sc_pkcs11_openssl_md_release,
 	sc_pkcs11_openssl_md_init,
@@ -175,18 +192,20 @@
 	sc_pkcs11_openssl_md_final,
 	NULL, NULL, NULL, NULL,	/* sign_* */
 	NULL, NULL, NULL,	/* verif_* */
-	NULL, NULL,		/* decrypt_* */
+	NULL, NULL, NULL, NULL,	/* decrypt_* */
+	NULL, NULL, NULL, NULL, /* encrypt */
 	NULL,			/* derive */
 	NULL,			/* wrap */
 	NULL,			/* unwrap */
 	NULL,			/* mech_data */
 	NULL,			/* free_mech_data */
+	NULL,			/* copy_mech_data */
 };
 
 static sc_pkcs11_mechanism_type_t openssl_ripemd160_mech = {
 	CKM_RIPEMD160,
 	{ 0, 0, CKF_DIGEST },
-	0,
+	{ -1 },
 	sizeof(struct sc_pkcs11_operation),
 	sc_pkcs11_openssl_md_release,
 	sc_pkcs11_openssl_md_init,
@@ -194,12 +213,14 @@
 	sc_pkcs11_openssl_md_final,
 	NULL, NULL, NULL, NULL,	/* sign_* */
 	NULL, NULL, NULL,	/* verif_* */
-	NULL, NULL,		/* decrypt_* */
+	NULL, NULL, NULL, NULL,	/* decrypt_* */
+	NULL, NULL, NULL, NULL, /* encrypt */
 	NULL,			/* derive */
 	NULL,			/* wrap */
 	NULL,			/* unwrap */
 	NULL,			/* mech_data */
 	NULL,			/* free_mech_data */
+	NULL,			/* copy_mech_data */
 };
 
 static void * dup_mem(void *in, size_t in_len)
@@ -213,6 +234,12 @@
 void
 sc_pkcs11_register_openssl_mechanisms(struct sc_pkcs11_card *p11card)
 {
+	sc_pkcs11_mechanism_type_t *mt = NULL;
+/*
+ * Engine support is being deprecated in 3.0. OpenSC loads GOST as engine.
+ * When GOST developers convert to provider, we can load the provider
+ */
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 #if !defined(OPENSSL_NO_ENGINE)
 	ENGINE *e;
 /* crypto locking removed in 1.1 */
@@ -258,23 +285,50 @@
 		CRYPTO_set_locking_callback(locking_cb);
 #endif
 #endif /* !defined(OPENSSL_NO_ENGINE) */
+#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
 
 	openssl_sha1_mech.mech_data = EVP_sha1();
-	sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_sha1_mech, sizeof openssl_sha1_mech));
+	mt = dup_mem(&openssl_sha1_mech, sizeof openssl_sha1_mech);
+	sc_pkcs11_register_mechanism(p11card, mt, NULL);
+	sc_pkcs11_free_mechanism(&mt);
+
 	openssl_sha224_mech.mech_data = EVP_sha224();
-	sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_sha224_mech, sizeof openssl_sha224_mech));
+	mt = dup_mem(&openssl_sha224_mech, sizeof openssl_sha224_mech);
+	sc_pkcs11_register_mechanism(p11card, mt, NULL);
+	sc_pkcs11_free_mechanism(&mt);
+
 	openssl_sha256_mech.mech_data = EVP_sha256();
-	sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_sha256_mech, sizeof openssl_sha256_mech));
+	mt = dup_mem(&openssl_sha256_mech, sizeof openssl_sha256_mech);
+	sc_pkcs11_register_mechanism(p11card, mt, NULL);
+	sc_pkcs11_free_mechanism(&mt);
+
 	openssl_sha384_mech.mech_data = EVP_sha384();
-	sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_sha384_mech, sizeof openssl_sha384_mech));
+	mt = dup_mem(&openssl_sha384_mech, sizeof openssl_sha384_mech);
+	sc_pkcs11_register_mechanism(p11card, mt, NULL);
+	sc_pkcs11_free_mechanism(&mt);
+
 	openssl_sha512_mech.mech_data = EVP_sha512();
-	sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_sha512_mech, sizeof openssl_sha512_mech));
-	openssl_md5_mech.mech_data = EVP_md5();
-	sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_md5_mech, sizeof openssl_md5_mech));
-	openssl_ripemd160_mech.mech_data = EVP_ripemd160();
-	sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_ripemd160_mech, sizeof openssl_ripemd160_mech));
+	mt = dup_mem(&openssl_sha512_mech, sizeof openssl_sha512_mech);
+	sc_pkcs11_register_mechanism(p11card, mt, NULL);
+	sc_pkcs11_free_mechanism(&mt);
+
+	if (!FIPS_mode()) {
+		openssl_md5_mech.mech_data = EVP_md5();
+		mt = dup_mem(&openssl_md5_mech, sizeof openssl_md5_mech);
+		sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
+
+		openssl_ripemd160_mech.mech_data = EVP_ripemd160();
+		mt = dup_mem(&openssl_ripemd160_mech, sizeof openssl_ripemd160_mech);
+		sc_pkcs11_register_mechanism(p11card, mt, NULL);
+		sc_pkcs11_free_mechanism(&mt);
+
+	}
 	openssl_gostr3411_mech.mech_data = EVP_get_digestbynid(NID_id_GostR3411_94);
-	sc_pkcs11_register_mechanism(p11card, dup_mem(&openssl_gostr3411_mech, sizeof openssl_gostr3411_mech));
+	mt = dup_mem(&openssl_gostr3411_mech, sizeof openssl_gostr3411_mech);
+	sc_pkcs11_register_mechanism(p11card, mt, NULL);
+	sc_pkcs11_free_mechanism(&mt);
+
 }
 
 
@@ -367,13 +421,24 @@
 	EC_POINT *P;
 	BIGNUM *X, *Y;
 	ASN1_OCTET_STRING *octet = NULL;
-	const EC_GROUP *group = NULL;
 	char paramset[2] = "A";
 	int r = -1, ret_vrf = 0;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	const EC_GROUP *group = NULL;
+#else
+	EC_GROUP *group = NULL;
+	char group_name[256];
+	OSSL_PARAM *old_params = NULL, *new_params = NULL, *p = NULL;
+	OSSL_PARAM_BLD *bld = NULL;
+	unsigned char *buf = NULL;
+	size_t buf_len = 0;
+	EVP_PKEY *new_pkey = NULL;
+#endif
 
 	pkey = EVP_PKEY_new();
 	if (!pkey)
 		return CKR_HOST_MEMORY;
+
 	r = EVP_PKEY_set_type(pkey, NID_id_GostR3410_2001);
 	if (r == 1) {
 		pkey_ctx = EVP_PKEY_CTX_new(pkey, NULL);
@@ -393,8 +458,13 @@
 			r = EVP_PKEY_paramgen_init(pkey_ctx);
 		if (r == 1)
 			r = EVP_PKEY_paramgen(pkey_ctx, &pkey);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 		if (r == 1 && EVP_PKEY_get0(pkey) != NULL)
 			group = EC_KEY_get0_group(EVP_PKEY_get0(pkey));
+#else
+		EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME, group_name, sizeof(group_name), NULL);
+		group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(group_name));
+#endif
 		r = -1;
 		if (group)
 			octet = d2i_ASN1_OCTET_STRING(NULL, &pubkey, (long)pubkey_len);
@@ -406,12 +476,48 @@
 			ASN1_OCTET_STRING_free(octet);
 			P = EC_POINT_new(group);
 			if (P && X && Y)
-						r = EC_POINT_set_affine_coordinates_GFp(group,
+						r = EC_POINT_set_affine_coordinates(group,
 						P, X, Y, NULL);
 			BN_free(X);
 			BN_free(Y);
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 			if (r == 1 && EVP_PKEY_get0(pkey) && P)
 				r = EC_KEY_set_public_key(EVP_PKEY_get0(pkey), P);
+#else
+			EC_GROUP_free(group);
+
+			buf_len = EC_POINT_point2oct(group, P, POINT_CONVERSION_COMPRESSED, NULL, 0, NULL);
+			if (!(buf = malloc(buf_len)))
+				r = -1;
+			if (r == 1 && P)
+				r = EC_POINT_point2oct(group, P, POINT_CONVERSION_COMPRESSED, buf, buf_len, NULL);
+
+			if (EVP_PKEY_todata(pkey, EVP_PKEY_KEYPAIR, &old_params) != 1 ||
+				!(bld = OSSL_PARAM_BLD_new()) ||
+				OSSL_PARAM_BLD_push_octet_string(bld, "pub", buf, buf_len) != 1 ||
+				!(new_params = OSSL_PARAM_BLD_to_param(bld)) ||
+				!(p = OSSL_PARAM_merge(old_params, new_params))) {
+				r = -1;
+			}
+			free(buf);
+			OSSL_PARAM_BLD_free(bld);
+
+			if (r == 1) {
+				if (EVP_PKEY_fromdata_init(pkey_ctx) != 1 ||
+					EVP_PKEY_fromdata(pkey_ctx, &new_pkey, EVP_PKEY_KEYPAIR, p) != 1) {
+					r = -1;
+				}
+			}
+			OSSL_PARAM_free(old_params);
+			OSSL_PARAM_free(new_params);
+			OSSL_PARAM_free(p);
+
+			if (r == 1) {
+				EVP_PKEY_free(pkey);
+				pkey = new_pkey;
+			}
+#endif
 			EC_POINT_free(P);
 		}
 		if (r == 1) {
@@ -444,6 +550,7 @@
 	CK_RV rv = CKR_GENERAL_ERROR;
 	EVP_PKEY *pkey = NULL;
 	const unsigned char *pubkey_tmp = NULL;
+	int sLen;
 
 	if (mech->mechanism == CKM_GOSTR3410)
 	{
@@ -490,7 +597,7 @@
 		sc_log(context, "Trying to verify using EVP");
 		if (md_ctx) {
 
-			if (EVP_PKEY_get0_EC_KEY(pkey)) {
+			if (EVP_PKEY_base_id(pkey) == EVP_PKEY_EC) {
 				unsigned char *signat_tmp = NULL;
 				size_t signat_len_tmp;
 				int r;
@@ -518,26 +625,89 @@
 			sc_log(context, "EVP_VerifyFinal() returned %d\n", res);
 			return CKR_GENERAL_ERROR;
 		}
-	} else if (md == NULL && mech->mechanism == CKM_ECDSA) {
+	} else	/* If plain CKM_ECDSA (without any hashing) is used or card supports
+		 * on-card CKM_ECDSA_SHAx only we land here. Since for CKM_ECDSA_SHAx no
+		 * hashing happened in C_VerifyUpdate() we do it here instead.
+		 */
+		if (md == NULL && (mech->mechanism == CKM_ECDSA
+		    || mech->mechanism == CKM_ECDSA_SHA1
+		    || mech->mechanism == CKM_ECDSA_SHA224
+		    || mech->mechanism == CKM_ECDSA_SHA256
+		    || mech->mechanism == CKM_ECDSA_SHA384
+		    || mech->mechanism == CKM_ECDSA_SHA512)) {
 		size_t signat_len_tmp;
 		unsigned char *signat_tmp = NULL;
+		unsigned int mdbuf_len;
+		unsigned char *mdbuf = NULL;
 		EVP_PKEY_CTX *ctx;
-		const EC_KEY *eckey;
 		int r;
 
 		sc_log(context, "Trying to verify using EVP");
 
+		/* If needed, hash input first
+		 */
+		if (mech->mechanism == CKM_ECDSA_SHA1
+		    || mech->mechanism == CKM_ECDSA_SHA224
+		    || mech->mechanism == CKM_ECDSA_SHA256
+		    || mech->mechanism == CKM_ECDSA_SHA384
+		    || mech->mechanism == CKM_ECDSA_SHA512) {
+			EVP_MD_CTX *mdctx;
+			const EVP_MD *md;
+			switch (mech->mechanism) {
+				case CKM_ECDSA_SHA1:
+					md = EVP_sha1();
+					break;
+				case CKM_ECDSA_SHA224:
+					md = EVP_sha224();
+					break;
+				case CKM_ECDSA_SHA256:
+					md = EVP_sha256();
+					break;
+				case CKM_ECDSA_SHA384:
+					md = EVP_sha384();
+					break;
+				case CKM_ECDSA_SHA512:
+					md = EVP_sha512();
+					break;
+				default:
+					EVP_PKEY_free(pkey);
+					return CKR_GENERAL_ERROR;
+			}
+			mdbuf_len = EVP_MD_size(md);
+			mdbuf = calloc(1, mdbuf_len);
+			if (mdbuf == NULL) {
+				EVP_PKEY_free(pkey);
+				return CKR_DEVICE_MEMORY;
+			}
+			if ((mdctx = EVP_MD_CTX_new()) == NULL) {
+				free(mdbuf);
+				EVP_PKEY_free(pkey);
+				return CKR_GENERAL_ERROR;
+			}
+			if (!EVP_DigestInit(mdctx, md)
+				|| !EVP_DigestUpdate(mdctx, data, data_len)
+				|| !EVP_DigestFinal(mdctx, mdbuf, &mdbuf_len)) {
+				EVP_PKEY_free(pkey);
+				EVP_MD_CTX_free(mdctx);
+				free(mdbuf);
+				return CKR_GENERAL_ERROR;
+			}
+			EVP_MD_CTX_free(mdctx);
+			data = mdbuf;
+			data_len = mdbuf_len;
+		}
+
 		res = 0;
 		r = sc_asn1_sig_value_rs_to_sequence(NULL, signat, signat_len,
 						     &signat_tmp, &signat_len_tmp);
-		eckey = EVP_PKEY_get0_EC_KEY(pkey);
 		ctx = EVP_PKEY_CTX_new(pkey, NULL);
-		if (r == 0 && eckey && ctx && 1 == EVP_PKEY_verify_init(ctx))
+		if (r == 0 && EVP_PKEY_base_id(pkey) == EVP_PKEY_EC && ctx && EVP_PKEY_verify_init(ctx) == 1)
 			res = EVP_PKEY_verify(ctx, signat_tmp, signat_len_tmp, data, data_len);
 
 		EVP_PKEY_CTX_free(ctx);
 		EVP_PKEY_free(pkey);
 		free(signat_tmp);
+		free(mdbuf);
 
 		if (res == 1)
 			return CKR_OK;
@@ -547,9 +717,13 @@
 			return CKR_GENERAL_ERROR;
 
 	} else {
-		RSA *rsa;
 		unsigned char *rsa_out = NULL, pad;
-		int rsa_outlen = 0;
+		size_t rsa_outlen = 0;
+		EVP_PKEY_CTX *ctx = EVP_PKEY_CTX_new(pkey, NULL);
+		if (!ctx) {
+			EVP_PKEY_free(pkey);
+			return CKR_DEVICE_MEMORY;
+		}
 
 		sc_log(context, "Trying to verify using low-level API");
 		switch (mech->mechanism) {
@@ -571,28 +745,32 @@
 			break;
 		default:
 			EVP_PKEY_free(pkey);
+			EVP_PKEY_CTX_free(ctx);
 			return CKR_ARGUMENTS_BAD;
 		}
 
-		rsa = EVP_PKEY_get1_RSA(pkey);
-		EVP_PKEY_free(pkey);
-		if (rsa == NULL)
-			return CKR_DEVICE_MEMORY;
+		if ( EVP_PKEY_verify_recover_init(ctx) != 1 ||
+			EVP_PKEY_CTX_set_rsa_padding(ctx, pad) != 1) {
+			EVP_PKEY_CTX_free(ctx);
+			EVP_PKEY_free(pkey);
+			return CKR_GENERAL_ERROR;
+		}
 
-		rsa_out = calloc(1, RSA_size(rsa));
+		rsa_outlen = EVP_PKEY_size(pkey);
+		rsa_out = calloc(1, rsa_outlen);
 		if (rsa_out == NULL) {
-			RSA_free(rsa);
+			EVP_PKEY_free(pkey);
+			EVP_PKEY_CTX_free(ctx);
 			return CKR_DEVICE_MEMORY;
 		}
-
-		rsa_outlen = RSA_public_decrypt(signat_len, signat, rsa_out, rsa, pad);
-		if (rsa_outlen <= 0) {
-			RSA_free(rsa);
+		if (EVP_PKEY_verify_recover(ctx, rsa_out, &rsa_outlen, signat, signat_len) != 1) {
 			free(rsa_out);
-			sc_log(context, "RSA_public_decrypt() returned %d\n", rsa_outlen);
+			EVP_PKEY_free(pkey);
+			EVP_PKEY_CTX_free(ctx);
+			sc_log(context, "RSA_public_decrypt() returned %d\n", (int) rsa_outlen);
 			return CKR_GENERAL_ERROR;
 		}
-
+		EVP_PKEY_CTX_free(ctx);
 		/* For PSS mechanisms we can not simply compare the "decrypted"
 		 * data -- we need to verify the PSS padding is valid
 		 */
@@ -607,8 +785,8 @@
 			unsigned char digest[EVP_MAX_MD_SIZE];
 
 			if (mech->pParameter == NULL) {
-				RSA_free(rsa);
 				free(rsa_out);
+				EVP_PKEY_free(pkey);
 				sc_log(context, "PSS mechanism requires parameter");
 				return CKR_MECHANISM_PARAM_INVALID;
 			}
@@ -631,8 +809,8 @@
 				mgf_md = EVP_sha512();
 				break;
 			default:
-				RSA_free(rsa);
 				free(rsa_out);
+				EVP_PKEY_free(pkey);
 				return CKR_MECHANISM_PARAM_INVALID;
 			}
 
@@ -653,8 +831,8 @@
 				pss_md = EVP_sha512();
 				break;
 			default:
-				RSA_free(rsa);
 				free(rsa_out);
+				EVP_PKEY_free(pkey);
 				return CKR_MECHANISM_PARAM_INVALID;
 			}
 
@@ -668,30 +846,52 @@
 				unsigned int tmp_len;
 
 				if (!md_ctx || !EVP_DigestFinal(md_ctx, tmp, &tmp_len)) {
-					RSA_free(rsa);
 					free(rsa_out);
+					EVP_PKEY_free(pkey);
 					return CKR_GENERAL_ERROR;
 				}
 				data = tmp;
 				data_len = tmp_len;
 			}
 			rv = CKR_SIGNATURE_INVALID;
-			if (data_len == (unsigned int) EVP_MD_size(pss_md)
-					&& RSA_verify_PKCS1_PSS_mgf1(rsa, data, pss_md, mgf_md,
-						rsa_out, EVP_MD_size(pss_md)/*sLen*/) == 1)
+
+			/* special mode - autodetect sLen from signature */
+			/* https://github.com/openssl/openssl/blob/master/crypto/rsa/rsa_pss.c */
+			/* there is no way to pass negative value here, we using maximal value for this */
+			if (((CK_ULONG) 1 ) << (sizeof(CK_ULONG) * CHAR_BIT -1) == param->sLen)
+				sLen = -2;
+			else
+				sLen = param->sLen;
+
+			if ((ctx = EVP_PKEY_CTX_new(pkey, NULL)) == NULL ||
+				EVP_PKEY_verify_init(ctx) != 1 ||
+				EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PSS_PADDING) != 1 ||
+				EVP_PKEY_CTX_set_signature_md(ctx, pss_md) != 1 ||
+				EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, sLen) != 1 ||
+				EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, mgf_md) != 1) {
+				sc_log(context, "Failed to initialize EVP_PKEY_CTX");
+				free(rsa_out);
+				EVP_PKEY_free(pkey);
+				EVP_PKEY_CTX_free(ctx);
+				return rv;
+			}
+
+			if (data_len == (unsigned int) EVP_MD_size(pss_md) &&
+					EVP_PKEY_verify(ctx, signat, signat_len, data, data_len) == 1)
 				rv = CKR_OK;
-			RSA_free(rsa);
+			EVP_PKEY_free(pkey);
+			EVP_PKEY_CTX_free(ctx);
 			free(rsa_out);
 			sc_log(context, "Returning %lu", rv);
 			return rv;
+		} else {
+			EVP_PKEY_free(pkey);
 		}
-		RSA_free(rsa);
 
 		if ((unsigned int) rsa_outlen == data_len && memcmp(rsa_out, data, data_len) == 0)
 			rv = CKR_OK;
 		else
 			rv = CKR_SIGNATURE_INVALID;
-
 		free(rsa_out);
 	}
 
diff -Nru opensc-0.22.0/src/pkcs11/pkcs11-display.c opensc-0.23.0/src/pkcs11/pkcs11-display.c
--- opensc-0.22.0/src/pkcs11/pkcs11-display.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs11/pkcs11-display.c	2022-11-29 09:34:43.000000000 +0100
@@ -172,7 +172,7 @@
 			ascii_ptr++;
 		}
 
-		/* padd */
+		/* padding */
 		while (strlen(hex) < 3*16)
 			strcat(hex, "   ");
 		fprintf(f, "\n    %08X  %s %s", offset, hex, ascii);
@@ -864,7 +864,7 @@
 void
 show_error( FILE *f, char *str, CK_RV rc )
 {
-	fprintf(f, "%s returned:  %ld %s", str, (unsigned long) rc, lookup_enum ( RV_T, rc ));
+	fprintf(f, "%s returned:  %ld %s", str, (unsigned long) rc, lookup_enum (RV_T, rc ));
 	fprintf(f, "\n");
 }
 
@@ -1102,7 +1102,7 @@
 	};
 
 	fprintf(f, "      slotID:                  %ld\n",       info->slotID );
-	fprintf(f, "      state:                  '%32.32s'\n",  lookup_enum(STA_T, info->state));
+	fprintf(f, "      state:                   %0lx (%32.32s)\n", info->state, lookup_enum(STA_T, info->state));
 	fprintf(f, "      flags:                   %0lx\n",     info->flags );
 
 	for(i = 0; i < sizeof (ck_flags) / sizeof (*ck_flags); i++) {
diff -Nru opensc-0.22.0/src/pkcs11/pkcs11-global.c opensc-0.23.0/src/pkcs11/pkcs11-global.c
--- opensc-0.22.0/src/pkcs11/pkcs11-global.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs11/pkcs11-global.c	2022-11-29 09:34:43.000000000 +0100
@@ -37,7 +37,10 @@
 #include "sc-pkcs11.h"
 #include "ui/notify.h"
 
+#ifdef ENABLE_OPENSSL
+#include <openssl/crypto.h>
 #include "libopensc/sc-ossl-compat.h"
+#endif
 #ifdef ENABLE_OPENPACE
 #include <eac/eac.h>
 #endif
@@ -248,7 +251,7 @@
 int module_close()
 {
 	sc_notify_close();
-#if defined(ENABLE_OPENSSL) && defined(OPENSSL_SECURE_MALLOC_SIZE)
+#if defined(ENABLE_OPENSSL) && defined(OPENSSL_SECURE_MALLOC_SIZE) && !defined(LIBRESSL_VERSION_NUMBER)
 	CRYPTO_secure_malloc_done();
 #endif
 #ifdef ENABLE_OPENPACE
@@ -349,7 +352,7 @@
 
 out:
 	if (context != NULL)
-		sc_log(context, "C_Initialize() = %s", lookup_enum ( RV_T, rv ));
+		SC_LOG_RV("C_Initialize() = %s", rv);
 
 	if (rv != CKR_OK) {
 		if (context != NULL) {
@@ -591,6 +594,7 @@
 {
 	struct sc_pkcs11_slot *slot = NULL;
 	sc_timestamp_t now;
+	const char *name;
 	CK_RV rv;
 
 	if (pInfo == NULL_PTR)
@@ -613,7 +617,7 @@
 
 	rv = slot_get_slot(slotID, &slot);
 	DEBUG_VSS(slot, "C_GetSlotInfo found");
-	sc_log(context, "C_GetSlotInfo() get slot rv %s", lookup_enum( RV_T, rv));
+	SC_LOG_RV("C_GetSlotInfo() get slot rv %s", rv);
 	if (rv == CKR_OK) {
 		if (slot->reader == NULL) {
 			rv = CKR_TOKEN_NOT_PRESENT;
@@ -640,7 +644,12 @@
 		memcpy(pInfo, &slot->slot_info, sizeof(CK_SLOT_INFO));
 
 	sc_log(context, "C_GetSlotInfo() flags 0x%lX", pInfo->flags);
-	sc_log(context, "C_GetSlotInfo(0x%lx) = %s", slotID, lookup_enum( RV_T, rv));
+	
+	name = lookup_enum(RV_T, rv);
+	if (name)
+		sc_log(context, "C_GetSlotInfo(0x%lx) = %s", slotID, name);
+	else
+		sc_log(context, "C_GetSlotInfo(0x%lx) = 0x%08lX", slotID, rv);
 	sc_pkcs11_unlock();
 	return rv;
 }
@@ -802,7 +811,7 @@
 		sc_wait_for_event(context, 0, NULL, NULL, -1, &reader_states);
 	}
 
-	sc_log(context, "C_WaitForSlotEvent() = %s", lookup_enum (RV_T, rv));
+	SC_LOG_RV("C_WaitForSlotEvent() = %s", rv);
 	sc_pkcs11_unlock();
 	return rv;
 }
diff -Nru opensc-0.22.0/src/pkcs11/pkcs11.h opensc-0.23.0/src/pkcs11/pkcs11.h
--- opensc-0.22.0/src/pkcs11/pkcs11.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs11/pkcs11.h	2022-11-29 09:34:43.000000000 +0100
@@ -397,6 +397,7 @@
 #define CKA_TOKEN			(1UL)
 #define CKA_PRIVATE			(2UL)
 #define CKA_LABEL			(3UL)
+#define CKA_UNIQUE_ID		(4UL)
 #define CKA_APPLICATION			(0x10UL)
 #define CKA_VALUE			(0x11UL)
 #define CKA_OBJECT_ID			(0x12UL)
@@ -450,6 +451,7 @@
 #define CKA_ALWAYS_SENSITIVE		(0x165UL)
 #define CKA_KEY_GEN_MECHANISM		(0x166UL)
 #define CKA_MODIFIABLE			(0x170UL)
+#define CKA_DESTROYABLE			(0x172UL)
 #define CKA_ECDSA_PARAMS		(0x180UL)
 #define CKA_EC_PARAMS			(0x180UL)
 #define CKA_EC_POINT			(0x181UL)
@@ -552,6 +554,14 @@
 #define CKM_SHA512_RSA_PKCS_PSS		(0x45UL)
 #define CKM_SHA224_RSA_PKCS		(0x46UL)
 #define CKM_SHA224_RSA_PKCS_PSS		(0x47UL)
+#define CKM_SHA3_256_RSA_PKCS		(0x60UL)
+#define CKM_SHA3_384_RSA_PKCS		(0x61UL)
+#define CKM_SHA3_512_RSA_PKCS		(0x62UL)
+#define CKM_SHA3_256_RSA_PKCS_PSS	(0x63UL)
+#define CKM_SHA3_384_RSA_PKCS_PSS	(0x64UL)
+#define CKM_SHA3_512_RSA_PKCS_PSS	(0x65UL)
+#define CKM_SHA3_224_RSA_PKCS		(0x66UL)
+#define CKM_SHA3_224_RSA_PKCS_PSS	(0x67UL)
 #define CKM_RC2_KEY_GEN			(0x100UL)
 #define CKM_RC2_ECB			(0x101UL)
 #define	CKM_RC2_CBC			(0x102UL)
@@ -573,6 +583,7 @@
 #define CKM_DES3_MAC			(0x134UL)
 #define CKM_DES3_MAC_GENERAL		(0x135UL)
 #define CKM_DES3_CBC_PAD		(0x136UL)
+#define CKM_DES3_CMAC_GENERAL		(0x137UL)
 #define CKM_DES3_CMAC			(0x138UL)
 #define CKM_CDMF_KEY_GEN		(0x140UL)
 #define CKM_CDMF_ECB			(0x141UL)
@@ -610,15 +621,19 @@
 #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)
@@ -721,6 +736,10 @@
 #define CKM_ECDSA_SHA256		(0x1044UL)
 #define CKM_ECDSA_SHA384		(0x1045UL)
 #define CKM_ECDSA_SHA512		(0x1046UL)
+#define CKM_ECDSA_SHA3_224		(0x1047UL)
+#define CKM_ECDSA_SHA3_256		(0x1048UL)
+#define CKM_ECDSA_SHA3_384		(0x1049UL)
+#define CKM_ECDSA_SHA3_512		(0x104AUL)
 #define CKM_ECDH1_DERIVE		(0x1050UL)
 #define CKM_ECDH1_COFACTOR_DERIVE	(0x1051UL)
 #define CKM_ECMQV_DERIVE		(0x1052UL)
@@ -745,6 +764,10 @@
 #define CKM_AES_CCM				(0x1088UL)
 #define CKM_AES_CTS				(0x1089UL)
 #define CKM_AES_CMAC			(0x108AUL)
+#define CKM_AES_CMAC_GENERAL		(0x108BUL)
+#define CKM_AES_XCBC_MAC		(0x108CUL)
+#define CKM_AES_XCBC_MAC_96		(0x108DUL)
+#define CKM_AES_GMAC			(0x108EUL)
 #define CKM_BLOWFISH_KEY_GEN    (0x1090UL)
 #define CKM_BLOWFISH_CBC        (0x1091UL)
 #define CKM_TWOFISH_KEY_GEN     (0x1092UL)
@@ -780,11 +803,17 @@
 #define CKM_DSA_PARAMETER_GEN		(0x2000UL)
 #define CKM_DH_PKCS_PARAMETER_GEN	(0x2001UL)
 #define CKM_X9_42_DH_PARAMETER_GEN	(0x2002UL)
+#define CKM_AES_OFB			(0x2104UL)
+#define CKM_AES_CFB64			(0x2105UL)
+#define CKM_AES_CFB8			(0x2106UL)
+#define CKM_AES_CFB128			(0x2107UL)
 #define CKM_AES_KEY_WRAP		(0x2109UL)
+#define CKM_AES_KEY_WRAP_PAD		(0x210AUL)
 #define CKM_XEDDSA			(0x4029UL)
-#define CKM_VENDOR_DEFINED		(1UL << 31)
 
 
+#define CKM_VENDOR_DEFINED		(1UL << 31)
+
 struct ck_mechanism
 {
   ck_mechanism_type_t mechanism;
@@ -801,6 +830,14 @@
 };
 
 #define CKF_HW			(1UL << 0)
+
+#define CKF_MESSAGE_ENCRYPT	(1UL << 1)
+#define CKF_MESSAGE_DECRYPT	(1UL << 2)
+#define CKF_MESSAGE_SIGN	(1UL << 3)
+#define CKF_MESSAGE_VERIFY	(1UL << 4)
+#define CKF_MULTI_MESSAGE	(1UL << 5)
+#define CKF_FIND_OBJECTS	(1UL << 6)
+
 #define CKF_ENCRYPT		(1UL << 8)
 #define CKF_DECRYPT		(1UL << 9)
 #define CKF_DIGEST		(1UL << 10)
@@ -878,6 +915,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)
 
@@ -906,6 +947,13 @@
 
 typedef CK_XEDDSA_PARAMS *CK_XEDDSA_PARAMS_PTR;
 
+typedef struct CK_AES_CTR_PARAMS {
+    unsigned long ulCounterBits;
+    unsigned char cb[16];
+} CK_AES_CTR_PARAMS;
+
+typedef CK_AES_CTR_PARAMS *CK_AES_CTR_PARAMS_PTR;
+
 typedef unsigned long ck_rv_t;
 
 
@@ -1210,7 +1258,7 @@
 _CK_DECLARE_FUNCTION (C_GetInterface,
 		      (unsigned char *interface_name,
 		       struct ck_version *version,
-		       struct ck_interface **interface,
+		       struct ck_interface **interface_ptr,
 		       ck_flags_t flags));
 
 _CK_DECLARE_FUNCTION (C_LoginUser,
diff -Nru opensc-0.22.0/src/pkcs11/pkcs11-object.c opensc-0.23.0/src/pkcs11/pkcs11-object.c
--- opensc-0.22.0/src/pkcs11/pkcs11-object.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs11/pkcs11-object.c	2022-11-29 09:34:43.000000000 +0100
@@ -31,7 +31,7 @@
 static sc_pkcs11_mechanism_type_t find_mechanism = {
 	0,		/* mech */
 	{0,0,0},	/* mech_info */
-	0,		/* key_type */
+	{ -1 },		/* key_types */
 	sizeof(struct sc_pkcs11_find_operation),	/* obj_size */
 	sc_find_release,				/* release */
 	NULL,		/* md_init */
@@ -46,11 +46,18 @@
 	NULL,		/* verif_final */
 	NULL,		/* decrypt_init */
 	NULL,		/* decrypt */
+	NULL,		/* decrypt_update */
+	NULL,		/* decrypt_final */
 	NULL,		/* derive */
 	NULL,		/* wrap */
 	NULL,		/* unwrap */
+	NULL,		/* encrypt init */
+	NULL,		/* encrypt */
+	NULL,		/* ecnrypt_update */
+	NULL,		/* encrypt_final */
 	NULL,		/* mech_data */
 	NULL,		/* free_mech_data */
+	NULL,		/* copy_mech_data */
 };
 
 static void
@@ -145,7 +152,6 @@
 	return rv;
 }
 
-
 CK_RV
 C_CreateObject(CK_SESSION_HANDLE hSession,	/* the session's handle */
 		CK_ATTRIBUTE_PTR pTemplate,	/* the object's template */
@@ -239,6 +245,7 @@
 	CK_RV res;
 	CK_RV res_type;
 	unsigned int i;
+	const char *name;
 
 	if (pTemplate == NULL_PTR || ulCount == 0)
 		return CKR_ARGUMENTS_BAD;
@@ -281,8 +288,15 @@
 		}
 	}
 
-out:	sc_log(context, "C_GetAttributeValue(hSession=0x%lx, hObject=0x%lx) = %s",
-			hSession, hObject, lookup_enum ( RV_T, rv ));
+out:
+	name = lookup_enum (RV_T, rv );
+	if (name)
+		sc_log(context, "C_GetAttributeValue(hSession=0x%lx, hObject=0x%lx) = %s",
+			hSession, hObject, name);
+	else
+		sc_log(context, "C_GetAttributeValue(hSession=0x%lx, hObject=0x%lx) = 0x%lx",
+                        hSession, hObject, rv);
+
 	sc_pkcs11_unlock();
 	return rv;
 }
@@ -531,7 +545,7 @@
 	if (rv == CKR_OK)
 		rv = sc_pkcs11_md_init(session, pMechanism);
 
-	sc_log(context, "C_DigestInit() = %s", lookup_enum ( RV_T, rv ));
+	SC_LOG_RV("C_DigestInit() = %s", rv);
 	sc_pkcs11_unlock();
 	return rv;
 }
@@ -576,7 +590,7 @@
 		rv = sc_pkcs11_md_final(session, pDigest, pulDigestLen);
 
 out:
-	sc_log(context, "C_Digest() = %s", lookup_enum ( RV_T, rv ));
+	SC_LOG_RV("C_Digest = %s", rv);
 	sc_pkcs11_unlock();
 	return rv;
 }
@@ -598,7 +612,7 @@
 	if (rv == CKR_OK)
 		rv = sc_pkcs11_md_update(session, pPart, ulPartLen);
 
-	sc_log(context, "C_DigestUpdate() == %s", lookup_enum ( RV_T, rv ));
+	SC_LOG_RV("C_DigestUpdate() = %s", rv);
 	sc_pkcs11_unlock();
 	return rv;
 }
@@ -628,7 +642,7 @@
 	if (rv == CKR_OK)
 		rv = sc_pkcs11_md_final(session, pDigest, pulDigestLen);
 
-	sc_log(context, "C_DigestFinal() = %s", lookup_enum ( RV_T, rv ));
+	SC_LOG_RV("C_DigestFinal() = %s", rv);
 	sc_pkcs11_unlock();
 	return rv;
 }
@@ -680,7 +694,7 @@
 	rv = sc_pkcs11_sign_init(session, pMechanism, object, key_type);
 
 out:
-	sc_log(context, "C_SignInit() = %s", lookup_enum ( RV_T, rv ));
+	SC_LOG_RV("C_SignInit() = %s", rv);
 	sc_pkcs11_unlock();
 	return rv;
 }
@@ -728,7 +742,7 @@
 	}
 
 out:
-	sc_log(context, "C_Sign() = %s", lookup_enum ( RV_T, rv ));
+	SC_LOG_RV("C_Sign() = %s", rv);
 	sc_pkcs11_unlock();
 	return rv;
 }
@@ -750,7 +764,7 @@
 	if (rv == CKR_OK)
 		rv = sc_pkcs11_sign_update(session, pPart, ulPartLen);
 
-	sc_log(context, "C_SignUpdate() = %s", lookup_enum ( RV_T, rv ));
+	SC_LOG_RV("C_SignUpdate() = %s", rv);
 	sc_pkcs11_unlock();
 	return rv;
 }
@@ -792,7 +806,7 @@
 	}
 
 out:
-	sc_log(context, "C_SignFinal() = %s", lookup_enum ( RV_T, rv ));
+	SC_LOG_RV("C_SignFinal() = %s", rv);
 	sc_pkcs11_unlock();
 	return rv;
 }
@@ -823,7 +837,48 @@
 		CK_MECHANISM_PTR pMechanism,	/* the encryption mechanism */
 		CK_OBJECT_HANDLE hKey)		/* handle of encryption key */
 {
-	return CKR_FUNCTION_NOT_SUPPORTED;
+	CK_BBOOL can_encrypt;
+	CK_KEY_TYPE key_type;
+	CK_ATTRIBUTE encrypt_attribute = {CKA_ENCRYPT, &can_encrypt, sizeof(can_encrypt)};
+	CK_ATTRIBUTE key_type_attr = {CKA_KEY_TYPE, &key_type, sizeof(key_type)};
+	struct sc_pkcs11_session *session;
+	struct sc_pkcs11_object *object;
+	CK_RV rv;
+
+	if (pMechanism == NULL_PTR)
+		return CKR_ARGUMENTS_BAD;
+
+	rv = sc_pkcs11_lock();
+	if (rv != CKR_OK)
+		return rv;
+
+	rv = get_object_from_session(hSession, hKey, &session, &object);
+	if (rv != CKR_OK) {
+		if (rv == CKR_OBJECT_HANDLE_INVALID)
+			rv = CKR_KEY_HANDLE_INVALID;
+		goto out;
+	}
+
+	if (object->ops->encrypt == NULL_PTR) {
+		rv = CKR_KEY_TYPE_INCONSISTENT;
+		goto out;
+	}
+
+	rv = object->ops->get_attribute(session, object, &encrypt_attribute);
+	if (rv != CKR_OK || !can_encrypt) {
+		rv = CKR_KEY_TYPE_INCONSISTENT;
+		goto out;
+	}
+	rv = object->ops->get_attribute(session, object, &key_type_attr);
+	if (rv != CKR_OK) {
+		rv = CKR_KEY_TYPE_INCONSISTENT;
+		goto out;
+	}
+	rv = sc_pkcs11_encr_init(session, pMechanism, object, key_type);
+out:
+	SC_LOG_RV("C_EncryptInit() = %s", rv);
+	sc_pkcs11_unlock();
+	return rv;
 }
 
 
@@ -833,7 +888,24 @@
 		CK_BYTE_PTR pEncryptedData,	/* receives encrypted data */
 		CK_ULONG_PTR pulEncryptedDataLen)
 {				/* receives encrypted byte count */
-	return CKR_FUNCTION_NOT_SUPPORTED;
+	CK_RV rv;
+	struct sc_pkcs11_session *session;
+
+	rv = sc_pkcs11_lock();
+	if (rv != CKR_OK)
+		return rv;
+
+	rv = get_session(hSession, &session);
+	if (rv == CKR_OK) {
+		rv = restore_login_state(session->slot);
+		if (rv == CKR_OK)
+			rv = sc_pkcs11_encr(session, pData, ulDataLen, pEncryptedData, pulEncryptedDataLen);
+		rv = reset_login_state(session->slot, rv);
+	}
+
+	SC_LOG_RV("C_Encrypt() = %s", rv);
+	sc_pkcs11_unlock();
+	return rv;
 }
 
 CK_RV C_EncryptUpdate(CK_SESSION_HANDLE hSession,	/* the session's handle */
@@ -842,14 +914,45 @@
 		      CK_BYTE_PTR pEncryptedPart,	/* receives encrypted data */
 		      CK_ULONG_PTR pulEncryptedPartLen)
 {				/* receives encrypted byte count */
-	return CKR_FUNCTION_NOT_SUPPORTED;
+	CK_RV rv;
+	struct sc_pkcs11_session *session;
+
+	rv = sc_pkcs11_lock();
+	if (rv != CKR_OK)
+		return rv;
+
+	rv = get_session(hSession, &session);
+	if (rv == CKR_OK)
+		rv = sc_pkcs11_encr_update(session, pPart, ulPartLen,
+				pEncryptedPart, pulEncryptedPartLen);
+
+	SC_LOG_RV("C_EncryptUpdate() = %s", rv);
+	sc_pkcs11_unlock();
+	return rv;
 }
 
 CK_RV C_EncryptFinal(CK_SESSION_HANDLE hSession,	/* the session's handle */
 		     CK_BYTE_PTR pLastEncryptedPart,	/* receives encrypted last part */
 		     CK_ULONG_PTR pulLastEncryptedPartLen)
 {				/* receives byte count */
-	return CKR_FUNCTION_NOT_SUPPORTED;
+	CK_RV rv;
+	struct sc_pkcs11_session *session;
+
+	rv = sc_pkcs11_lock();
+	if (rv != CKR_OK)
+		return rv;
+
+	rv = get_session(hSession, &session);
+	if (rv == CKR_OK) {
+		rv = restore_login_state(session->slot);
+		if (rv == CKR_OK)
+			rv = sc_pkcs11_encr_final(session, pLastEncryptedPart, pulLastEncryptedPartLen);
+		rv = reset_login_state(session->slot, rv);
+	}
+
+	SC_LOG_RV("C_EncryptFinal() = %s", rv);
+	sc_pkcs11_unlock();
+	return rv;
 }
 
 CK_RV C_DecryptInit(CK_SESSION_HANDLE hSession,	/* the session's handle */
@@ -902,17 +1005,18 @@
 	rv = sc_pkcs11_decr_init(session, pMechanism, object, key_type);
 
 out:
-	sc_log(context, "C_DecryptInit() = %s", lookup_enum ( RV_T, rv ));
+	SC_LOG_RV("C_DecryptInit() = %s", rv);
 	sc_pkcs11_unlock();
 	return rv;
 }
 
-CK_RV C_Decrypt(CK_SESSION_HANDLE hSession,	/* the session's handle */
-		CK_BYTE_PTR pEncryptedData,	/* input encrypted data */
-		CK_ULONG ulEncryptedDataLen,	/* count of bytes of input */
-		CK_BYTE_PTR pData,	/* receives decrypted output */
-		CK_ULONG_PTR pulDataLen)
-{				/* receives decrypted byte count */
+CK_RV
+C_Decrypt(CK_SESSION_HANDLE hSession,	     /* the session's handle */
+		CK_BYTE_PTR pEncryptedData,  /* input encrypted data */
+		CK_ULONG ulEncryptedDataLen, /* count of bytes of input */
+		CK_BYTE_PTR pData,	     /* receives decrypted output */
+		CK_ULONG_PTR pulDataLen)     /* receives decrypted byte count */
+{
 	CK_RV rv;
 	struct sc_pkcs11_session *session;
 
@@ -930,25 +1034,61 @@
 		rv = reset_login_state(session->slot, rv);
 	}
 
-	sc_log(context, "C_Decrypt() = %s", lookup_enum ( RV_T, rv ));
+	SC_LOG_RV("C_Decrypt() = %s", rv);
 	sc_pkcs11_unlock();
 	return rv;
 }
 
-CK_RV C_DecryptUpdate(CK_SESSION_HANDLE hSession,	/* the session's handle */
-		      CK_BYTE_PTR pEncryptedPart,	/* input encrypted data */
-		      CK_ULONG ulEncryptedPartLen,	/* count of bytes of input */
-		      CK_BYTE_PTR pPart,	/* receives decrypted output */
-		      CK_ULONG_PTR pulPartLen)
-{				/* receives decrypted byte count */
-	return CKR_FUNCTION_NOT_SUPPORTED;
+CK_RV
+C_DecryptUpdate(CK_SESSION_HANDLE hSession,  /* the session's handle */
+		CK_BYTE_PTR pEncryptedPart,  /* input encrypted data */
+		CK_ULONG ulEncryptedPartLen, /* count of bytes of input */
+		CK_BYTE_PTR pPart,	     /* receives decrypted output */
+		CK_ULONG_PTR pulPartLen)     /* receives decrypted byte count */
+{
+	CK_RV rv;
+	struct sc_pkcs11_session *session;
+
+	rv = sc_pkcs11_lock();
+	if (rv != CKR_OK)
+		return rv;
+
+	rv = get_session(hSession, &session);
+	if (rv == CKR_OK)
+		rv = sc_pkcs11_decr_update(session, pEncryptedPart, ulEncryptedPartLen,
+				pPart, pulPartLen);
+
+	SC_LOG_RV("C_DecryptUpdate() = %s", rv);
+	sc_pkcs11_unlock();
+	return rv;
 }
 
-CK_RV C_DecryptFinal(CK_SESSION_HANDLE hSession,	/* the session's handle */
-		     CK_BYTE_PTR pLastPart,	/* receives decrypted output */
-		     CK_ULONG_PTR pulLastPartLen)
-{				/* receives decrypted byte count */
-	return CKR_FUNCTION_NOT_SUPPORTED;
+CK_RV
+C_DecryptFinal(CK_SESSION_HANDLE hSession,   /* the session's handle */
+		CK_BYTE_PTR pLastPart,	     /* receives decrypted output */
+		CK_ULONG_PTR pulLastPartLen) /* receives decrypted byte count */
+{
+	CK_RV rv;
+	struct sc_pkcs11_session *session;
+
+	rv = sc_pkcs11_lock();
+	if (rv != CKR_OK)
+		return rv;
+
+	rv = get_session(hSession, &session);
+	if (rv == CKR_OK) {
+		rv = restore_login_state(session->slot);
+		if (rv == CKR_OK) {
+			rv = sc_pkcs11_decr_final(session,
+					pLastPart,
+					pulLastPartLen);
+		}
+		rv = reset_login_state(session->slot, rv);
+	}
+
+	SC_LOG_RV("C_DecryptFinal() = %s", rv);
+	sc_pkcs11_unlock();
+	return rv;
 }
 
 CK_RV C_DigestEncryptUpdate(CK_SESSION_HANDLE hSession,	/* the session's handle */
@@ -1309,7 +1449,7 @@
 	}
 
 	sc_pkcs11_unlock();
-	sc_log(context, "C_GenerateRandom() = %s", lookup_enum ( RV_T, rv ));
+	SC_LOG_RV("C_GenerateRandom() = %s", rv);
 	return rv;
 }
 
@@ -1359,7 +1499,7 @@
 	rv = sc_pkcs11_verif_init(session, pMechanism, object, key_type);
 
 out:
-	sc_log(context, "C_VerifyInit() = %s", lookup_enum ( RV_T, rv ));
+	SC_LOG_RV("C_VerifyInit() = %s", rv);
 	sc_pkcs11_unlock();
 	return rv;
 #endif
@@ -1394,7 +1534,7 @@
 	}
 
 out:
-	sc_log(context, "C_Verify() = %s", lookup_enum ( RV_T, rv ));
+	SC_LOG_RV("C_Verify() = %s", rv);
 	sc_pkcs11_unlock();
 	return rv;
 #endif
@@ -1418,7 +1558,7 @@
 	if (rv == CKR_OK)
 		rv = sc_pkcs11_verif_update(session, pPart, ulPartLen);
 
-	sc_log(context, "C_VerifyUpdate() = %s", lookup_enum ( RV_T, rv ));
+	SC_LOG_RV("C_VerifyUpdate() = %s", rv);
 	sc_pkcs11_unlock();
 	return rv;
 #endif
@@ -1446,7 +1586,7 @@
 		rv = reset_login_state(session->slot, rv);
 	}
 
-	sc_log(context, "C_VerifyFinal() = %s", lookup_enum ( RV_T, rv ));
+	SC_LOG_RV("C_VerifyFinal() = %s", rv);
 	sc_pkcs11_unlock();
 	return rv;
 #endif
diff -Nru opensc-0.22.0/src/pkcs11/pkcs11-session.c opensc-0.23.0/src/pkcs11/pkcs11-session.c
--- opensc-0.22.0/src/pkcs11/pkcs11-session.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs11/pkcs11-session.c	2022-11-29 09:34:43.000000000 +0100
@@ -94,7 +94,7 @@
 	sc_log(context, "C_OpenSession handle: 0x%lx", session->handle);
 
 out:
-	sc_log(context, "C_OpenSession() = %s", lookup_enum(RV_T, rv));
+	SC_LOG_RV("C_OpenSession() = %s", rv);
 	sc_pkcs11_unlock();
 	return rv;
 }
@@ -126,6 +126,8 @@
 			slot->p11card->framework->logout(slot);
 		}
 	}
+	for (size_t i = 0; i < SC_PKCS11_OPERATION_MAX; i++)
+		sc_pkcs11_release_operation(&session->operation[i]);
 
 	if (list_delete(&sessions, session) != 0)
 		sc_log(context, "Could not delete session from list!");
@@ -250,7 +252,7 @@
 	CK_RV rv;
 	struct sc_pkcs11_session *session;
 	struct sc_pkcs11_slot *slot;
-	int logged_out;
+	const char *name;
 
 	if (pInfo == NULL_PTR)
 		return CKR_ARGUMENTS_BAD;
@@ -273,16 +275,16 @@
 	pInfo->ulDeviceError = 0;
 
 	slot = session->slot;
-	logged_out = (slot_get_logged_in_state(slot) == SC_PIN_STATE_LOGGED_OUT);
-	if (logged_out && slot->login_user >= 0) {
+	if (!sc_pkcs11_conf.atomic && slot->login_user >= 0 &&
+	    slot_get_logged_in_state(slot) == SC_PIN_STATE_LOGGED_OUT) {
 		slot->login_user = -1;
 		sc_pkcs11_close_all_sessions(session->slot->id);
 		rv = CKR_SESSION_HANDLE_INVALID;
 		goto out;
 	}
-	if (slot->login_user == CKU_SO && !logged_out) {
+	if (slot->login_user == CKU_SO) {
 		pInfo->state = CKS_RW_SO_FUNCTIONS;
-	} else if ((slot->login_user == CKU_USER && !logged_out) || (!(slot->token_info.flags & CKF_LOGIN_REQUIRED))) {
+	} else if (slot->login_user == CKU_USER || !(slot->token_info.flags & CKF_LOGIN_REQUIRED)) {
 		pInfo->state = (session->flags & CKF_RW_SESSION)
 		    ? CKS_RW_USER_FUNCTIONS : CKS_RO_USER_FUNCTIONS;
 	} else {
@@ -291,7 +293,11 @@
 	}
 
 out:
-	sc_log(context, "C_GetSessionInfo(0x%lx) = %s", hSession, lookup_enum(RV_T, rv));
+	name = lookup_enum(RV_T, rv);
+	if (name)
+		sc_log(context, "C_GetSessionInfo(0x%lx) = %s", hSession, name);
+	else
+		sc_log(context, "C_GetSessionInfo(0x%lx) = 0x%lx", hSession, rv);
 	sc_pkcs11_unlock();
 	return rv;
 }
diff -Nru opensc-0.22.0/src/pkcs11/pkcs11-spy.c opensc-0.23.0/src/pkcs11/pkcs11-spy.c
--- opensc-0.22.0/src/pkcs11/pkcs11-spy.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs11/pkcs11-spy.c	2022-11-29 09:34:43.000000000 +0100
@@ -332,7 +332,7 @@
 static CK_RV
 retne(CK_RV rv)
 {
-	fprintf(spy_output, "Returned:  %ld %s\n", (unsigned long) rv, lookup_enum ( RV_T, rv ));
+	fprintf(spy_output, "Returned:  %ld %s\n", (unsigned long) rv, lookup_enum (RV_T, rv ));
 	fflush(spy_output);
 	return rv;
 }
@@ -404,13 +404,26 @@
 spy_dump_mechanism_in(const char *name, CK_MECHANISM_PTR pMechanism)
 {
 	char param_name[64];
+	const char *mec_name;
 
 	if (!pMechanism) {
 		fprintf(spy_output, "[in] %s = NULL\n", name);
 		return;
 	}
 
-	fprintf(spy_output, "[in] %s->type = %s\n", name, lookup_enum(MEC_T, pMechanism->mechanism));
+	mec_name = lookup_enum(MEC_T, pMechanism->mechanism);
+	if (mec_name)
+		fprintf(spy_output, "[in] %s->type = %s\n", name, mec_name);
+	else {
+		size_t needed = snprintf(NULL, 0, "0x%08lX", pMechanism->mechanism) + 1;
+		char *buffer = malloc(needed);
+		if (buffer) {
+			sprintf(buffer, "0x%08lX", pMechanism->mechanism);
+			fprintf(spy_output, "[in] %s->type = %s\n", name, buffer);
+			free(buffer);
+		}
+	}
+
 	switch (pMechanism->mechanism) {
 	case CKM_AES_GCM:
 		if (pMechanism->pParameter != NULL) {
@@ -521,6 +534,22 @@
  	fprintf(spy_output, "[in] %s = %p\n", name, ptr);
 }
 
+#define FPRINTF_LOOKUP_ENUM(fmt, category, type)\
+do {\
+        const char *name = lookup_enum((category), (type));\
+        if (name)\
+                fprintf(spy_output, (fmt), (name));\
+        else {\
+                size_t needed = snprintf(NULL, 0, "0x%08lX", (type)) + 1;\
+                char *buffer = malloc(needed);\
+                if (buffer) {\
+                        sprintf(buffer, "0x%08lX", (type));\
+                        fprintf(spy_output, (fmt), buffer);\
+                        free(buffer);\
+                }\
+        }\
+} while(0)
+
 CK_RV C_GetFunctionList
 (CK_FUNCTION_LIST_PTR_PTR ppFunctionList)
 {
@@ -657,14 +686,10 @@
 		CK_MECHANISM_INFO_PTR pInfo)
 {
 	CK_RV rv;
-	const char *name = lookup_enum(MEC_T, type);
 
 	enter("C_GetMechanismInfo");
 	spy_dump_ulong_in("slotID", slotID);
-	if (name)
-		fprintf(spy_output, "[in] type = %30s\n", name);
-	else
-		fprintf(spy_output, "[in] type = Unknown Mechanism (%08lx)\n", type);
+	FPRINTF_LOOKUP_ENUM("[in] type = %s", MEC_T, type);
 
 	rv = po->C_GetMechanismInfo(slotID, type, pInfo);
 	if(rv == CKR_OK) {
@@ -807,8 +832,7 @@
 
 	enter("C_Login");
 	spy_dump_ulong_in("hSession", hSession);
-	fprintf(spy_output, "[in] userType = %s\n",
-			lookup_enum(USR_T, userType));
+	FPRINTF_LOOKUP_ENUM("[in] userType = %s\n", USR_T, userType);
 	spy_dump_string_in("pPin[ulPinLen]", pPin, ulPinLen);
 	rv = po->C_Login(hSession, userType, pPin, ulPinLen);
 	return retne(rv);
@@ -1612,7 +1636,11 @@
 	if (po->version.major < 3) {
 		fprintf(spy_output, "[compat]\n");
 	}
-	spy_dump_string_in("pInterfaceName", pInterfaceName, strlen((char *)pInterfaceName));
+	if (pInterfaceName != NULL) {
+		spy_dump_string_in("pInterfaceName", pInterfaceName, strlen((char *)pInterfaceName));
+	} else {
+		fprintf(spy_output, "[in] pInterfaceName = NULL\n");
+	}
 	if (pVersion != NULL) {
 		fprintf(spy_output, "[in] pVersion = %d.%d\n", pVersion->major, pVersion->minor);
 	} else {
@@ -1647,8 +1675,7 @@
 
 	enter("C_LoginUser");
 	spy_dump_ulong_in("hSession", hSession);
-	fprintf(spy_output, "[in] userType = %s\n",
-			lookup_enum(USR_T, userType));
+	FPRINTF_LOOKUP_ENUM("[in] userType = %s\n", USR_T, userType);
 	spy_dump_string_in("pPin[ulPinLen]", pPin, ulPinLen);
 	spy_dump_string_in("pUsername[ulUsernameLen]", pUsername, ulUsernameLen);
 	rv = po->C_LoginUser(hSession, userType, pPin, ulPinLen, pUsername, ulUsernameLen);
diff -Nru opensc-0.22.0/src/pkcs11/sc-pkcs11.h opensc-0.23.0/src/pkcs11/sc-pkcs11.h
--- opensc-0.22.0/src/pkcs11/sc-pkcs11.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs11/sc-pkcs11.h	2022-11-29 09:34:43.000000000 +0100
@@ -105,7 +105,10 @@
 			CK_MECHANISM_PTR,
 			CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen,
 			CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen);
-
+	CK_RV (*encrypt)(struct sc_pkcs11_session *, void *,
+			CK_MECHANISM_PTR,
+			CK_BYTE_PTR pData, CK_ULONG ulDataLen,
+			CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen);
 	CK_RV (*derive)(struct sc_pkcs11_session *, void *,
 			CK_MECHANISM_PTR,
 			CK_BYTE_PTR pSeedData, CK_ULONG ulSeedDataLen,
@@ -226,6 +229,22 @@
 };
 typedef struct sc_pkcs11_slot sc_pkcs11_slot_t;
 
+#define SC_LOG_RV(fmt, rv)\
+do {\
+        const char *name = lookup_enum(RV_T, (rv));\
+        if (name)\
+                sc_log(context, (fmt), name);\
+        else {\
+                size_t needed = snprintf(NULL, 0, "0x%08lX", (rv)) + 1;\
+                char *buffer = malloc(needed);\
+                if (buffer) {\
+                        sprintf(buffer, "0x%08lX", (rv));\
+                        sc_log(context, (fmt), buffer);\
+                        free(buffer);\
+                }\
+        }\
+} while(0)
+
 /* Debug virtual slots. S is slot to be highlighted or NULL
  * C is a comment format string and args It will be preceded by "VSS " */
 #define DEBUG_VSS(S, ...) do { sc_log(context,"VSS " __VA_ARGS__); _debug_virtual_slots(S); } while (0)
@@ -242,17 +261,20 @@
 	SC_PKCS11_OPERATION_VERIFY,
 	SC_PKCS11_OPERATION_DIGEST,
 	SC_PKCS11_OPERATION_DECRYPT,
+	SC_PKCS11_OPERATION_ENCRYPT,
 	SC_PKCS11_OPERATION_DERIVE,
 	SC_PKCS11_OPERATION_WRAP,
 	SC_PKCS11_OPERATION_UNWRAP,
 	SC_PKCS11_OPERATION_MAX
 };
 
+#define MAX_KEY_TYPES 2
+
 /* This describes a PKCS11 mechanism */
 struct sc_pkcs11_mechanism_type {
-	CK_MECHANISM_TYPE mech;		/* algorithm: md5, sha1, ... */
-	CK_MECHANISM_INFO mech_info;	/* mechanism info */
-	CK_MECHANISM_TYPE key_type;	/* for sign/decipher ops */
+	CK_MECHANISM_TYPE mech;				/* algorithm: md5, sha1, ... */
+	CK_MECHANISM_INFO mech_info;			/* mechanism info */
+	int 		  key_types[MAX_KEY_TYPES];	/* for sign/decipher ops */
 	unsigned int	  obj_size;
 
 	/* General management */
@@ -281,9 +303,24 @@
 					CK_BYTE_PTR, CK_ULONG);
 	CK_RV		  (*decrypt_init)(sc_pkcs11_operation_t *,
 					struct sc_pkcs11_object *);
+	CK_RV		  (*decrypt_update)(sc_pkcs11_operation_t *,
+					CK_BYTE_PTR, CK_ULONG,
+					CK_BYTE_PTR, CK_ULONG_PTR);
+	CK_RV		  (*decrypt_final)(sc_pkcs11_operation_t *,
+					CK_BYTE_PTR, CK_ULONG_PTR);
 	CK_RV		  (*decrypt)(sc_pkcs11_operation_t *,
 					CK_BYTE_PTR, CK_ULONG,
 					CK_BYTE_PTR, CK_ULONG_PTR);
+	CK_RV		  (*encrypt_init)(sc_pkcs11_operation_t *,
+					struct sc_pkcs11_object *);
+	CK_RV		  (*encrypt)(sc_pkcs11_operation_t *,
+					CK_BYTE_PTR, CK_ULONG,
+					CK_BYTE_PTR, CK_ULONG_PTR);
+	CK_RV		  (*encrypt_update)(sc_pkcs11_operation_t *,
+					CK_BYTE_PTR, CK_ULONG,
+					CK_BYTE_PTR, CK_ULONG_PTR);
+	CK_RV		  (*encrypt_final)(sc_pkcs11_operation_t *,
+					CK_BYTE_PTR, CK_ULONG_PTR);
 	CK_RV		  (*derive)(sc_pkcs11_operation_t *,
 					struct sc_pkcs11_object *,
 					CK_BYTE_PTR, CK_ULONG,
@@ -301,6 +338,7 @@
 	const void *  mech_data;
 	/* free mechanism specific data */
 	void		  (*free_mech_data)(const void *mech_data);
+	CK_RV		  (*copy_mech_data)(const void *mech_data, void **new_data);
 };
 typedef struct sc_pkcs11_mechanism_type sc_pkcs11_mechanism_type_t;
 
@@ -358,8 +396,9 @@
 CK_RV sc_to_cryptoki_error(int rc, const char *ctx);
 void sc_pkcs11_print_attrs(int level, const char *file, unsigned int line, const char *function,
 		const char *info, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount);
+void sc_pkcs11_card_free(struct sc_pkcs11_card *p11card);
 #define dump_template(level, info, pTemplate, ulCount) \
-		sc_pkcs11_print_attrs(level, __FILE__, __LINE__, __FUNCTION__, \
+		sc_pkcs11_print_attrs(level, FILENAME, __LINE__, __FUNCTION__, \
 				info, pTemplate, ulCount)
 
 /* Slot and card handling functions */
@@ -415,7 +454,7 @@
 
 /* Generic Mechanism functions */
 CK_RV sc_pkcs11_register_mechanism(struct sc_pkcs11_card *,
-				sc_pkcs11_mechanism_type_t *);
+				sc_pkcs11_mechanism_type_t *, sc_pkcs11_mechanism_type_t **);
 CK_RV sc_pkcs11_get_mechanism_list(struct sc_pkcs11_card *,
 				CK_MECHANISM_TYPE_PTR, CK_ULONG_PTR);
 CK_RV sc_pkcs11_get_mechanism_info(struct sc_pkcs11_card *, CK_MECHANISM_TYPE,
@@ -424,18 +463,26 @@
 CK_RV sc_pkcs11_md_update(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG);
 CK_RV sc_pkcs11_md_final(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG_PTR);
 CK_RV sc_pkcs11_sign_init(struct sc_pkcs11_session *, CK_MECHANISM_PTR,
-				struct sc_pkcs11_object *, CK_MECHANISM_TYPE);
+				struct sc_pkcs11_object *, CK_KEY_TYPE);
 CK_RV sc_pkcs11_sign_update(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG);
 CK_RV sc_pkcs11_sign_final(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG_PTR);
 CK_RV sc_pkcs11_sign_size(struct sc_pkcs11_session *, CK_ULONG_PTR);
 #ifdef ENABLE_OPENSSL
 CK_RV sc_pkcs11_verif_init(struct sc_pkcs11_session *, CK_MECHANISM_PTR,
-				struct sc_pkcs11_object *, CK_MECHANISM_TYPE);
+				struct sc_pkcs11_object *, CK_KEY_TYPE);
 CK_RV sc_pkcs11_verif_update(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG);
 CK_RV sc_pkcs11_verif_final(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG);
 #endif
-CK_RV sc_pkcs11_decr_init(struct sc_pkcs11_session *, CK_MECHANISM_PTR, struct sc_pkcs11_object *, CK_MECHANISM_TYPE);
+CK_RV sc_pkcs11_decr_init(struct sc_pkcs11_session *, CK_MECHANISM_PTR, struct sc_pkcs11_object *, CK_KEY_TYPE);
 CK_RV sc_pkcs11_decr(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR);
+CK_RV sc_pkcs11_decr_update(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR);
+CK_RV sc_pkcs11_decr_final(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG_PTR);
+
+CK_RV sc_pkcs11_encr_init(struct sc_pkcs11_session *, CK_MECHANISM_PTR, struct sc_pkcs11_object *, CK_MECHANISM_TYPE);
+CK_RV sc_pkcs11_encr(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR);
+CK_RV sc_pkcs11_encr_update(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG, CK_BYTE_PTR, CK_ULONG_PTR);
+CK_RV sc_pkcs11_encr_final(struct sc_pkcs11_session *, CK_BYTE_PTR, CK_ULONG_PTR);
+
 CK_RV sc_pkcs11_wrap(struct sc_pkcs11_session *,CK_MECHANISM_PTR, struct sc_pkcs11_object *, CK_KEY_TYPE, struct sc_pkcs11_object *, CK_BYTE_PTR, CK_ULONG_PTR);
 CK_RV sc_pkcs11_unwrap(struct sc_pkcs11_session *,CK_MECHANISM_PTR, struct sc_pkcs11_object *, CK_KEY_TYPE, CK_BYTE_PTR, CK_ULONG, struct sc_pkcs11_object *);
 CK_RV sc_pkcs11_deri(struct sc_pkcs11_session *, CK_MECHANISM_PTR,
@@ -445,7 +492,8 @@
 				CK_MECHANISM_TYPE, unsigned int);
 sc_pkcs11_mechanism_type_t *sc_pkcs11_new_fw_mechanism(CK_MECHANISM_TYPE,
 				CK_MECHANISM_INFO_PTR, CK_KEY_TYPE,
-				const void *, void (*)(const void *));
+				const void *, void (*)(const void *), CK_RV (*)(const void *, void **));
+void sc_pkcs11_free_mechanism(sc_pkcs11_mechanism_type_t **mt);
 sc_pkcs11_operation_t *sc_pkcs11_new_operation(sc_pkcs11_session_t *,
 				sc_pkcs11_mechanism_type_t *);
 void sc_pkcs11_release_operation(sc_pkcs11_operation_t **);
diff -Nru opensc-0.22.0/src/pkcs11/slot.c opensc-0.23.0/src/pkcs11/slot.c
--- opensc-0.22.0/src/pkcs11/slot.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs11/slot.c	2022-11-29 09:34:43.000000000 +0100
@@ -69,13 +69,15 @@
 	CK_UTF8CHAR slotDescription[64];
 	CK_UTF8CHAR manufacturerID[32];
 
+	if (reader == NULL)
+		return NULL;
 	strcpy_bp(slotDescription, reader->name, 64);
 	strcpy_bp(manufacturerID, reader->vendor, 32);
 
 	/* Locate a slot related to the reader */
 	for (i = 0; i<list_size(&virtual_slots); i++) {
 		sc_pkcs11_slot_t *slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
-		if (slot->reader == NULL && reader != NULL
+		if (slot->reader == NULL
 				&& 0 == memcmp(slot->slot_info.slotDescription, slotDescription, 64)
 				&& 0 == memcmp(slot->slot_info.manufacturerID, manufacturerID, 32)
 				&& slot->slot_info.hardwareVersion.major == reader->version_major
diff -Nru opensc-0.22.0/src/pkcs15init/isoApplet.profile opensc-0.23.0/src/pkcs15init/isoApplet.profile
--- opensc-0.22.0/src/pkcs15init/isoApplet.profile	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/isoApplet.profile	2022-11-29 09:34:43.000000000 +0100
@@ -14,7 +14,7 @@
 
 pkcs15 {
 	# Method to calculate ID of the crypto objects
-	#	mozilla: SHA1(modulus) for RSA, SHA1(pub) for DSA
+	#	mozilla: SHA1(modulus) for RSA
 	#	rfc2459: SHA1(SequenceASN1 of public key components as ASN1 integers)
 	#	native: 'E' + number_of_present_objects_of_the_same_type
 	# default value: 'native'
diff -Nru opensc-0.22.0/src/pkcs15init/jcop.profile opensc-0.23.0/src/pkcs15init/jcop.profile
--- opensc-0.22.0/src/pkcs15init/jcop.profile	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/jcop.profile	1970-01-01 01:00:00.000000000 +0100
@@ -1,69 +0,0 @@
-#
-# PKCS15 r/w profile for JCOP cards
-#
-cardinfo {
-    max-pin-length      = 16;
-    pin-encoding        = ascii-numeric;
-    pin-pad-char        = 0x00;
-}
-
-filesystem {
-    DF MF {
-        DF PKCS15-AppDF {
-            acl = *=NONE, CREATE=CHV3;
-            EF PKCS15-AODF {
-                file-id         = 502E;
-            }
-            EF PKCS15-PrKDF {
-                file-id         = 502C;
-            }
-            EF PKCS15-PuKDF {
-                file-id         = 502B;
-            }
-            EF PKCS15-CDF {
-                file-id         = 502D;
-            }
-            EF PKCS15-DODF {
-                file-id         = 502F;
-            }
-            template key-domain {
-                EF private-key {
-                    file-id         = 3000;
-                    acl             = *=NEVER, UPDATE=$PIN, CRYPTO=$PIN,
-                                      ERASE=$SOPIN;
-                }
-                EF extractable-key {
-                    file-id         = 3100;
-                    acl             = *=NEVER, READ=$PIN, UPDATE=$PIN, 
-                      ERASE=$SOPIN;
-                }
-                EF data {
-                    file-id         = 3200;
-                    acl             = *=NEVER, UPDATE=$PIN, READ=NONE, 
-                                      ERASE=$SOPIN;
-		}
-                EF privdata {
-                    file-id         = 3500;
-                    acl             = *=NEVER, UPDATE=$PIN, READ=$PIN, 
-                                      ERASE=$SOPIN;
-                }
-                EF public-key {
-                    file-id         = 3300;
-                    acl             = *=NEVER, UPDATE=$PIN, READ=NONE, 
-                                      ERASE=$SOPIN;
-                }
-                EF certificate {
-                    file-id         = 3400;
-                    acl             = *=NEVER, UPDATE=$PIN, READ=NONE, 
-                                      ERASE=$SOPIN;
-                }
-            }
-            EF temp-pubkey {
-                 file-id         = 0000;
-                 acl             = *=NEVER, UPDATE=$PIN, READ=NONE, 
-                                   ERASE=$SOPIN;
-            }
-        }
-    }
-}
-
diff -Nru opensc-0.22.0/src/pkcs15init/Makefile.am opensc-0.23.0/src/pkcs15init/Makefile.am
--- opensc-0.22.0/src/pkcs15init/Makefile.am	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/Makefile.am	2022-11-29 09:34:43.000000000 +0100
@@ -9,10 +9,8 @@
 	cyberflex.profile \
 	flex.profile \
 	gpk.profile \
-	miocos.profile \
 	cardos.profile \
 	incrypto34.profile \
-	jcop.profile \
 	oberthur.profile \
 	starcos.profile \
 	setcos.profile \
@@ -40,8 +38,8 @@
 libpkcs15init_la_SOURCES = \
 	pkcs15-lib.c profile.c \
 	pkcs15-westcos.c \
-	pkcs15-gpk.c pkcs15-miocos.c pkcs15-cflex.c \
-	pkcs15-cardos.c pkcs15-jcop.c pkcs15-starcos.c \
+	pkcs15-gpk.c pkcs15-cflex.c \
+	pkcs15-cardos.c pkcs15-starcos.c \
 	pkcs15-setcos.c pkcs15-incrypto34.c pkcs15-muscle.c \
 	pkcs15-asepcos.c pkcs15-rutoken.c \
 	pkcs15-entersafe.c pkcs15-epass2003.c \
diff -Nru opensc-0.22.0/src/pkcs15init/Makefile.mak opensc-0.23.0/src/pkcs15init/Makefile.mak
--- opensc-0.22.0/src/pkcs15init/Makefile.mak	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/Makefile.mak	2022-11-29 09:34:43.000000000 +0100
@@ -2,8 +2,8 @@
 
 TARGET = pkcs15init.lib
 OBJECTS = pkcs15-lib.obj profile.obj \
-          pkcs15-gpk.obj pkcs15-miocos.obj pkcs15-cflex.obj \
-          pkcs15-cardos.obj pkcs15-jcop.obj pkcs15-starcos.obj \
+          pkcs15-gpk.obj pkcs15-cflex.obj \
+          pkcs15-cardos.obj pkcs15-starcos.obj \
           pkcs15-oberthur.obj pkcs15-oberthur-awp.obj \
           pkcs15-setcos.obj pkcs15-incrypto34.obj \
           pkcs15-muscle.obj pkcs15-asepcos.obj pkcs15-rutoken.obj \
diff -Nru opensc-0.22.0/src/pkcs15init/miocos.profile opensc-0.23.0/src/pkcs15init/miocos.profile
--- opensc-0.22.0/src/pkcs15init/miocos.profile	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/miocos.profile	1970-01-01 01:00:00.000000000 +0100
@@ -1,53 +0,0 @@
-#
-# PKCS15 r/w profile for MioCOS cards
-#
-cardinfo {
-    max-pin-length	= 8;
-    pin-encoding	= ascii-numeric;
-    pin-pad-char	= 0x00;
-}
-
-# Define reasonable limits for PINs and PUK
-# Note that we do not set a file path or reference
-# here; that is done dynamically.
-PIN user-pin {
-    attempts	= 3;
-}
-PIN user-puk {
-    attempts	= 10;
-}
-
-# Additional filesystem info.
-# This is added to the file system info specified in the
-# main profile.
-filesystem {
-    DF MF {
-        DF PKCS15-AppDF {
-            EF template-private-key {
-		type		= internal-ef;
-    	        file-id		= 4B01;	# This is the base FileID
-		size		= 266;  # 266 is enough for 1024-bit keys
-    	        ACL		= *=NEVER, CRYPTO=$PIN, UPDATE=$PIN;
-            }
-	    EF template-public-key {
-		file-id		= 5501;
-		ACL		= *=NEVER, READ=NONE, UPDATE=$PIN;
-	    }
-	    EF template-certificate {
-		file-id		= 4301;
-		ACL		= *=NEVER, READ=NONE, UPDATE=$PIN;
-	    }
-            EF template-extractable-key {
-    	        file-id		= 7000;
-    	        ACL		= *=NEVER, READ=$PIN, UPDATE=$PIN;
-            }
-	}
-    }
-}
-
-# Define an SO pin
-# This PIN is not used yet.
-#PIN sopin {
-#    file	= sopinfile;
-#    reference	= 0;
-#}
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-asepcos.c opensc-0.23.0/src/pkcs15init/pkcs15-asepcos.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-asepcos.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-asepcos.c	2022-11-29 09:34:43.000000000 +0100
@@ -221,7 +221,7 @@
 {
 	sc_file_t *nfile = NULL;
 	u8  buf[64], sbuf[64], *p = buf, *q = sbuf;
-	int r, akn;
+	int r, akn = 0;
 
 	if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
 		return SC_ERROR_OBJECT_NOT_VALID;
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-entersafe.c opensc-0.23.0/src/pkcs15init/pkcs15-entersafe.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-entersafe.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-entersafe.c	2022-11-29 09:34:43.000000000 +0100
@@ -130,6 +130,8 @@
 
 
 		 /* fill file by 0 */
+		 if (size > MAX_FILE_SIZE)
+			 LOG_TEST_RET(card->ctx, SC_ERROR_INVALID_DATA, "Initialize EF(DIR) failed with file size too large");
 		 buff = calloc(1,size);
 		 if(!buff)
 			  SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_SUCCESS);
@@ -168,7 +170,7 @@
 		 memcpy(df_data.data.df.aid,df->name,df->namelen);
 
 		 ret = sc_card_ctl(card, SC_CARDCTL_ENTERSAFE_CREATE_FILE, &df_data);
-		 LOG_TEST_RET(card->ctx,ret,"Crate DF failed");
+		 LOG_TEST_RET(card->ctx,ret,"Create DF failed");
 	}
 
 	{/* GPKF */
@@ -356,7 +358,7 @@
 
 	if ( key->algorithm != SC_ALGORITHM_RSA )
 	{
-		 /* ignore DSA keys */
+		 /* ignore non-RSA keys */
 		 SC_FUNC_RETURN(card->ctx, SC_LOG_DEBUG_VERBOSE,SC_ERROR_INVALID_ARGUMENTS);
 	}
 
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-epass2003.c opensc-0.23.0/src/pkcs15init/pkcs15-epass2003.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-epass2003.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-epass2003.c	2022-11-29 09:34:43.000000000 +0100
@@ -298,6 +298,8 @@
 					  struct sc_pkcs15_prkey_info *prkey)
 {
 	SC_FUNC_CALLED(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE);
+	if (prkey->path.len == 0)
+		SC_FUNC_RETURN(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE, SC_ERROR_INVALID_ARGUMENTS);
 	prkey->key_reference = prkey->path.value[prkey->path.len - 1];
 	SC_FUNC_RETURN(p15card->card->ctx, SC_LOG_DEBUG_VERBOSE, SC_SUCCESS);
 }
@@ -307,7 +309,7 @@
 cosm_new_file(struct sc_profile *profile, struct sc_card *card,
 	      unsigned int type, unsigned int num, struct sc_file **out)
 {
-	struct sc_file *file;
+	struct sc_file *file = NULL;
 	const char *_template = NULL, *desc = NULL;
 	unsigned int structure = 0xFFFFFFFF;
 
@@ -317,12 +319,12 @@
 	while (1) {
 		switch (type) {
 		case SC_PKCS15_TYPE_PRKEY_EC:
-			desc = "RSA private key";
+			desc = "EC private key";
 			_template = "private-key";
 			structure = SC_CARDCTL_OBERTHUR_KEY_EC_CRT;
 			break;
 		case SC_PKCS15_TYPE_PUBKEY_EC:
-			desc = "RSA public key";
+			desc = "EC public key";
 			_template = "public-key";
 			structure = SC_CARDCTL_OBERTHUR_KEY_EC_PUBLIC;
 			break;
@@ -336,10 +338,6 @@
 			_template = "public-key";
 			structure = SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC;
 			break;
-		case SC_PKCS15_TYPE_PUBKEY_DSA:
-			desc = "DSA public key";
-			_template = "public-key";
-			break;
 		case SC_PKCS15_TYPE_PRKEY:
 			desc = "extractable private key";
 			_template = "extractable-key";
@@ -377,6 +375,11 @@
 		return SC_ERROR_NOT_SUPPORTED;
 	}
 
+	if (file->path.len < 1) {
+		sc_file_free(file);
+		return SC_ERROR_INTERNAL;
+	}
+
 	file->id &= 0xFF00;
 	file->id |= (num & 0x00FF);
 
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-gpk.c opensc-0.23.0/src/pkcs15init/pkcs15-gpk.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-gpk.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-gpk.c	2022-11-29 09:34:43.000000000 +0100
@@ -81,9 +81,6 @@
 static int	gpk_encode_rsa_key(sc_profile_t *, sc_card_t *,
 			struct sc_pkcs15_prkey_rsa *, struct pkdata *,
 			struct sc_pkcs15_prkey_info *);
-static int	gpk_encode_dsa_key(sc_profile_t *, sc_card_t *,
-			struct sc_pkcs15_prkey_dsa *, struct pkdata *,
-			struct sc_pkcs15_prkey_info *);
 static int	gpk_store_pk(struct sc_profile *, sc_pkcs15_card_t *,
 			sc_file_t *, struct pkdata *);
 static int	gpk_init_pinfile(sc_profile_t *, sc_pkcs15_card_t *, sc_file_t *);
@@ -433,8 +430,6 @@
 	switch (obj->type) {
 	case SC_PKCS15_TYPE_PRKEY_RSA:
 		algo = SC_ALGORITHM_RSA; break;
-	case SC_PKCS15_TYPE_PRKEY_DSA:
-		algo = SC_ALGORITHM_DSA; break;
 	default:
 		sc_log(p15card->card->ctx,  "Unsupported public key algorithm");
 		return SC_ERROR_NOT_SUPPORTED;
@@ -489,10 +484,6 @@
 					&data, key_info);
 		break;
 
-	case SC_ALGORITHM_DSA:
-		r = gpk_encode_dsa_key(profile, p15card->card, &key->u.dsa,
-					&data, key_info);
-		break;
 	default:
 		return SC_ERROR_NOT_SUPPORTED;
 	}
@@ -617,7 +608,6 @@
 {
 	switch (algo) {
 	case SC_ALGORITHM_RSA: *p = 0x00; return 0;
-	case SC_ALGORITHM_DSA: *p = 0x01; return 0;
 	}
 	return SC_ERROR_NOT_SUPPORTED;
 }
@@ -999,54 +989,6 @@
 
 	return 0;
 }
-
-/*
- * Encode a DSA key.
- * Confusingly, the GPK manual says that the GPK8000 can handle
- * DSA with 512 as well as 1024 bits, but all byte sizes shown
- * in the tables are 512 bits only...
- */
-static int gpk_encode_dsa_key(sc_profile_t *profile, sc_card_t *card,
-		struct sc_pkcs15_prkey_dsa *dsa, struct pkdata *p,
-		sc_pkcs15_prkey_info_t *info)
-{
-	if (!dsa->p.len || !dsa->q.len || !dsa->g.len
-	 || !dsa->pub.len || !dsa->priv.len) {
-		sc_log(card->ctx, 
-			"incomplete DSA public key");
-		return SC_ERROR_INVALID_ARGUMENTS;
-	}
-
-	memset(p, 0, sizeof(*p));
-	p->algo  = SC_ALGORITHM_RSA;
-	p->usage = info->usage;
-	p->bytes = dsa->q.len;
-	p->bits  = dsa->q.len << 3;
-
-	/* Make sure the key is either 512 or 1024 bits */
-	if (p->bytes <= 64) {
-		p->bits  = 512;
-		p->bytes = 64;
-	} else if (p->bytes <= 128) {
-		p->bits  = 1024;
-		p->bytes = 128;
-	} else {
-		sc_log(card->ctx, 
-			"incompatible DSA key size (%u bits)", p->bits);
-		return SC_ERROR_INVALID_ARGUMENTS;
-	}
-
-	/* Set up the list of public elements */
-	gpk_add_bignum(&p->_public, 0x09, &dsa->p, 0);
-	gpk_add_bignum(&p->_public, 0x0a, &dsa->q, 0);
-	gpk_add_bignum(&p->_public, 0x0b, &dsa->g, 0);
-	gpk_add_bignum(&p->_public, 0x0c, &dsa->pub, 0);
-
-	/* Set up the list of private elements */
-	gpk_add_bignum(&p->_private, 0x0d, &dsa->priv, 0);
-
-	return 0;
-}
 
 static int
 gpk_store_pk(struct sc_profile *profile, sc_pkcs15_card_t *p15card,
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-iasecc.c opensc-0.23.0/src/pkcs15init/pkcs15-iasecc.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-iasecc.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-iasecc.c	2022-11-29 09:34:43.000000000 +0100
@@ -125,7 +125,7 @@
 
 	LOG_FUNC_CALLED(ctx);
 
-	if (p15card->app->ddo.aid.len)   {
+	if (p15card->app && p15card->app->ddo.aid.len)   {
 		memset(&path, 0, sizeof(struct sc_path));
 		path.type = SC_PATH_TYPE_DF_NAME;
 		memcpy(path.value, p15card->app->ddo.aid.value, p15card->app->ddo.aid.len);
@@ -1473,7 +1473,7 @@
 	struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)key_obj->data;
 	unsigned char guid[40];
 	size_t guid_len;
-	int rv, ii, keys_num;
+	int rv, ii, keys_num, private_obj;
 
 	LOG_FUNC_CALLED(ctx);
 
@@ -1487,7 +1487,8 @@
 	if (rv == SC_ERROR_OBJECT_NOT_FOUND)
 		LOG_FUNC_RETURN(ctx, SC_SUCCESS);
 
-	rv = sc_pkcs15_read_data_object(p15card, (struct sc_pkcs15_data_info *)data_obj->data, &dod);
+	private_obj = data_obj->flags & SC_PKCS15_CO_FLAG_PRIVATE;
+	rv = sc_pkcs15_read_data_object(p15card, (struct sc_pkcs15_data_info *)data_obj->data, private_obj, &dod);
 	LOG_TEST_RET(ctx, rv, "Cannot read from 'CSP/'Default Key Container'");
 
 	if (guid_len != dod->data_len || memcmp(guid, dod->data, guid_len)) {
@@ -1776,43 +1777,43 @@
 	} while(0);
 
 	rv = iasecc_file_convert_acls(ctx, profile, file);
-	LOG_TEST_RET(ctx, rv, "iasecc_store_data_object() cannot convert profile ACLs");
+	LOG_TEST_GOTO_ERR(ctx, rv, "iasecc_store_data_object() cannot convert profile ACLs");
 
 	rv = sc_profile_get_parent(profile, "public-data", &parent);
-	LOG_TEST_RET(ctx, rv, "iasecc_store_data_object() cannot get object parent");
+	LOG_TEST_GOTO_ERR(ctx, rv, "iasecc_store_data_object() cannot get object parent");
 	sc_log(ctx, "iasecc_store_data_object() parent path '%s'\n", sc_print_path(&parent->path));
 
 	rv = sc_select_file(card, &parent->path, NULL);
-	LOG_TEST_RET(ctx, rv, "iasecc_store_data_object() cannot select parent");
+	LOG_TEST_GOTO_ERR(ctx, rv, "iasecc_store_data_object() cannot select parent");
 
 	rv = sc_select_file(card, &file->path, &cfile);
 	if (!rv)   {
 		rv = sc_pkcs15init_authenticate(profile, p15card, cfile, SC_AC_OP_DELETE);
-		LOG_TEST_RET(ctx, rv, "iasecc_store_data_object() DELETE authentication failed");
+		LOG_TEST_GOTO_ERR(ctx, rv, "iasecc_store_data_object() DELETE authentication failed");
 
 		rv = iasecc_pkcs15_delete_file(p15card, profile, cfile);
-		LOG_TEST_RET(ctx, rv, "s_pkcs15init_store_data_object() delete pkcs15 file error");
+		LOG_TEST_GOTO_ERR(ctx, rv, "s_pkcs15init_store_data_object() delete pkcs15 file error");
 	}
 	else if (rv != SC_ERROR_FILE_NOT_FOUND)   {
 		LOG_TEST_RET(ctx, rv, "iasecc_store_data_object() select file error");
 	}
 
 	rv = sc_pkcs15init_authenticate(profile, p15card, parent, SC_AC_OP_CREATE);
-	LOG_TEST_RET(ctx, rv, "iasecc_store_data_object() parent CREATE authentication failed");
+	LOG_TEST_GOTO_ERR(ctx, rv, "iasecc_store_data_object() parent CREATE authentication failed");
 
 	file->size = data->len;
 	rv = sc_create_file(card, file);
-	LOG_TEST_RET(ctx, rv, "iasecc_store_data_object() cannot create DATA file");
+	LOG_TEST_GOTO_ERR(ctx, rv, "iasecc_store_data_object() cannot create DATA file");
 
 	rv = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE);
-	LOG_TEST_RET(ctx, rv, "iasecc_store_data_object() data file UPDATE authentication failed");
+	LOG_TEST_GOTO_ERR(ctx, rv, "iasecc_store_data_object() data file UPDATE authentication failed");
 
 	rv = sc_update_binary(card, 0, data->value, data->len, 0);
-	LOG_TEST_RET(ctx, rv, "iasecc_store_data_object() update DATA file failed");
+	LOG_TEST_GOTO_ERR(ctx, rv, "iasecc_store_data_object() update DATA file failed");
 
 	if (path)
 		*path = file->path;
-
+err:
 	sc_file_free(parent);
 	sc_file_free(file);
 	sc_file_free(cfile);
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-init.h opensc-0.23.0/src/pkcs15init/pkcs15-init.h
--- opensc-0.22.0/src/pkcs15init/pkcs15-init.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-init.h	2022-11-29 09:34:43.000000000 +0100
@@ -428,11 +428,9 @@
 
 
 extern struct sc_pkcs15init_operations *sc_pkcs15init_get_gpk_ops(void);
-extern struct sc_pkcs15init_operations *sc_pkcs15init_get_miocos_ops(void);
 extern struct sc_pkcs15init_operations *sc_pkcs15init_get_cryptoflex_ops(void);
 extern struct sc_pkcs15init_operations *sc_pkcs15init_get_cyberflex_ops(void);
 extern struct sc_pkcs15init_operations *sc_pkcs15init_get_cardos_ops(void);
-extern struct sc_pkcs15init_operations *sc_pkcs15init_get_jcop_ops(void);
 extern struct sc_pkcs15init_operations *sc_pkcs15init_get_starcos_ops(void);
 extern struct sc_pkcs15init_operations *sc_pkcs15init_get_oberthur_ops(void);
 extern struct sc_pkcs15init_operations *sc_pkcs15init_get_setcos_ops(void);
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-isoApplet.c opensc-0.23.0/src/pkcs15init/pkcs15-isoApplet.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-isoApplet.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-isoApplet.c	2022-11-29 09:34:43.000000000 +0100
@@ -576,7 +576,12 @@
 			pubkey->u.ec.params.der.value = NULL;
 			pubkey->u.ec.params.der.len = 0;
 		}
-		if(r < 0 && pubkey->u.ec.ecpointQ.value)
+		if(pubkey->u.ec.params.named_curve)
+		{
+			free(pubkey->u.ec.params.named_curve);
+			pubkey->u.ec.params.named_curve = NULL;
+		}
+		if(pubkey->u.ec.ecpointQ.value)
 		{
 			free(pubkey->u.ec.ecpointQ.value);
 			pubkey->u.ec.ecpointQ.value = NULL;
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-jcop.c opensc-0.23.0/src/pkcs15init/pkcs15-jcop.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-jcop.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-jcop.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,357 +0,0 @@
-/*
- * JCOP specific operation for PKCS15 initialization
- *
- * Copyright 2003 Chaskiel Grundman <cg2v at andrew.cmu.edu>
- * Copyright (C) 2002 Olaf Kirch <okir at suse.de>
- *
- * 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
- */
-
-#include "config.h"
-
-#include <sys/types.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <stdarg.h>
-
-#include "libopensc/opensc.h"
-#include "libopensc/cardctl.h"
-#include "libopensc/log.h"
-#include "pkcs15-init.h"
-#include "profile.h"
-
-#define JCOP_MAX_PINS            3
-
-/*
- * Erase the card
- */
-static int
-jcop_erase_card(struct sc_profile *pro, sc_pkcs15_card_t *p15card) {
-     /* later */
-     return SC_ERROR_NOT_SUPPORTED;
-}
-
-
-static int
-jcop_create_dir(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *file)
-{
-     return SC_ERROR_NOT_SUPPORTED;
-};
-
-
-/*
- * Select a PIN reference
- */
-static int
-jcop_select_pin_reference(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
-                sc_pkcs15_auth_info_t *auth_info) {
-        int     preferred, current;
-
-	if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
-		return SC_ERROR_OBJECT_NOT_VALID;
-
-        if ((current = auth_info->attrs.pin.reference) < 0)
-                current = 0;
-
-        if (auth_info->attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
-	     preferred = 3;
-	} else {
-	     preferred = current;
-	      if (preferred < 1)
-		   preferred=1;
-	      if (preferred > 2)
-		   return SC_ERROR_TOO_MANY_OBJECTS;
-	}
-	if (current > preferred)
-	     return SC_ERROR_TOO_MANY_OBJECTS;
-        auth_info->attrs.pin.reference = preferred;
-        return 0;
-}
-
-/*
- * Store a PIN
- */
-static int
-jcop_create_pin(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_file_t *df,
-                sc_pkcs15_object_t *pin_obj,
-                const unsigned char *pin, size_t pin_len,
-                const unsigned char *puk, size_t puk_len)
-{
-        sc_pkcs15_auth_info_t *auth_info = (sc_pkcs15_auth_info_t *) pin_obj->data;
-	struct sc_pkcs15_pin_attributes *pin_attrs = &auth_info->attrs.pin;
-        unsigned char   nulpin[16];
-        unsigned char   padpin[16];
-        int             r;
-
-	if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
-		return SC_ERROR_OBJECT_NOT_VALID;
-
-        if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_SO_PIN) {
-                /* SO PIN reference must be 0 */
-                if (pin_attrs->reference != 3)
-                        return SC_ERROR_INVALID_ARGUMENTS;
-        } else {
-                if (pin_attrs->reference >= 3)
-                        return SC_ERROR_TOO_MANY_OBJECTS;
-        }
-        if (puk != NULL && puk_len > 0) {
-	     return SC_ERROR_NOT_SUPPORTED;
-	}
-	r = sc_select_file(p15card->card, &df->path, NULL);
-        if (r < 0)
-	     return r;
-
-	/* Current PIN is 00:00:00:00:00:00:00:00... */
-        memset(nulpin, 0, sizeof(nulpin));
-        memset(padpin, 0, sizeof(padpin));
-	memcpy(padpin, pin, pin_len);
-        r = sc_change_reference_data(p15card->card, SC_AC_CHV,
-                        pin_attrs->reference,
-                        nulpin, sizeof(nulpin),
-                        padpin, sizeof(padpin), NULL);
-        if (r < 0)
-                return r;
-
-	pin_attrs->flags &= ~SC_PKCS15_PIN_FLAG_LOCAL;
-        return r;
-}
-
-/*
- * Create a new key file
- */
-static int
-jcop_create_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card, sc_pkcs15_object_t *obj)
-{
-        sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
-        sc_file_t  *keyfile = NULL;
-        size_t          bytes, mod_len, prv_len;
-        int             r;
-
-        if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
-                sc_log(p15card->card->ctx,  "JCOP supports only RSA keys.");
-                return SC_ERROR_NOT_SUPPORTED;
-        }
-        /* The caller is supposed to have chosen a key file path for us */
-        if (key_info->path.len == 0 || key_info->modulus_length == 0)
-                return SC_ERROR_INVALID_ARGUMENTS;
-
-        /* Get the file we're supposed to create */
-        r = sc_profile_get_file_by_path(profile, &key_info->path, &keyfile);
-        if (r < 0)
-                return r;
-
-        mod_len = key_info->modulus_length / 8;
-        bytes   = mod_len / 2;
-        prv_len = 2 + 5 * bytes;
-        keyfile->size = prv_len;
-
-        /* Fix up PIN references in file ACL */
-        r = sc_pkcs15init_fixup_file(profile, p15card, keyfile);
-
-        if (r >= 0)
-                r = sc_pkcs15init_create_file(profile, p15card, keyfile);
-
-        sc_file_free(keyfile);
-        return r;
-}
-
-static void
-jcop_bn2bin(unsigned char *dest, sc_pkcs15_bignum_t *bn, unsigned int size)
-{
-        u8              *src;
-        unsigned int    n;
-
-        assert(bn->len <= size);
-        memset(dest, 0, size);
-        for (n = size-bn->len, src = bn->data; n < size; n++,src++)
-                dest[n] = *src;
-}
-
-/*
- * Store a private key
- * Private key file formats: (transparent file)
- * Non-CRT:
- * byte 0     0x05
- * byte 1     Modulus length (in byte/4)
- * byte 2     Modulus (n)
- * byte 2+x   private exponent (d)
- *
- * CRT:
- * byte 0     0x06
- * byte 1     component length (in byte/2; component length is half
- *            of modulus length
- * byte 2     Prime (p)
- * byte 2+x   Prime (q)
- * byte 2+2*x Exponent 1 (d mod (p-1))
- * byte 2+3*x Exponent 2 (d mod (q-1))
- * byte 2+4*x Coefficient ((p ^ -1) mod q
- *
- * We use the CRT format, since that's what key generation does.
- *
- * Numbers are stored big endian.
- */
-static int
-jcop_store_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
-                sc_pkcs15_object_t *obj,
-                sc_pkcs15_prkey_t *key)
-{
-        sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
-        sc_file_t       *keyfile;
-        unsigned char   keybuf[1024];
-        size_t          size,base;
-        int             r;
-
-        if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
-                sc_log(p15card->card->ctx,  "JCOP supports only RSA keys.");
-                return SC_ERROR_NOT_SUPPORTED;
-        }
-        r = sc_profile_get_file_by_path(profile, &key_info->path, &keyfile);
-        if (r < 0)
-                return r;
-	base=key_info->modulus_length / 16;
-	size=2+5*base;
-	keybuf[0]=6;
-	keybuf[1]=base/4;
-	jcop_bn2bin(&keybuf[2 + 0 * base], &key->u.rsa.p, base);
-	jcop_bn2bin(&keybuf[2 + 1 * base], &key->u.rsa.q, base);
-	jcop_bn2bin(&keybuf[2 + 2 * base], &key->u.rsa.dmp1, base);
-	jcop_bn2bin(&keybuf[2 + 3 * base], &key->u.rsa.dmq1, base);
-	jcop_bn2bin(&keybuf[2 + 4 * base], &key->u.rsa.iqmp, base);
-        r = sc_pkcs15init_update_file(profile, p15card, keyfile, keybuf, size);
-
-	sc_file_free(keyfile);
-	return r;
-}
-
-/*
- * Generate a key pair
- */
-static int
-jcop_generate_key(sc_profile_t *profile, sc_pkcs15_card_t *p15card,
-		  sc_pkcs15_object_t *obj,
-		  sc_pkcs15_pubkey_t *pubkey)
-{
-     sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
-     struct sc_cardctl_jcop_genkey args;
-     sc_file_t       *temppubfile=NULL, *keyfile=NULL;
-     unsigned char   *keybuf=NULL;
-     size_t          mod_len, exp_len, pub_len, keybits;
-     int             r,delete_ok=0;
-
-     if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
-	  sc_log(p15card->card->ctx,  "JCOP supports only RSA keys.");
-	  return SC_ERROR_NOT_SUPPORTED;
-     }
-
-     r=sc_profile_get_file(profile, "temp-pubkey", &temppubfile);
-     if (r < 0)
-	  goto out;
-
-     r = sc_select_file(p15card->card, &key_info->path, &keyfile);
-     if (r < 0)
-	  goto out;
-
-     mod_len = key_info->modulus_length / 8;
-     exp_len = 4;
-     pub_len = 2 + mod_len + exp_len;
-     temppubfile->size = pub_len;
-
-     r = sc_pkcs15init_fixup_file(profile, p15card, temppubfile);
-     if (r < 0)
-	  goto out;
-
-     r = sc_pkcs15init_create_file(profile, p15card, temppubfile);
-     if (r < 0)
-	  goto out;
-
-     delete_ok=1;
-     r = sc_pkcs15init_authenticate(profile, p15card, temppubfile, SC_AC_OP_UPDATE);
-     if (r < 0)
-	  goto out;
-     r = sc_pkcs15init_authenticate(profile, p15card, keyfile, SC_AC_OP_UPDATE);
-     if (r < 0)
-	  goto out;
-
-     keybits = key_info->modulus_length;
-
-     /* generate key */
-     /* keysize is _not_ passed to the card at any point. it appears to
-	infer it from the file size */
-     memset(&args, 0, sizeof(args));
-     args.exponent = 0x10001;
-     sc_append_file_id(&args.pub_file_ref, temppubfile->id);
-     sc_append_file_id(&args.pri_file_ref, keyfile->id);
-     keybuf = malloc(keybits / 8);
-     if (!keybuf) {
-	  r=SC_ERROR_OUT_OF_MEMORY;
-	  goto out;
-     }
-     args.pubkey = keybuf;
-     args.pubkey_len = keybits / 8;
-
-     r = sc_card_ctl(p15card->card, SC_CARDCTL_JCOP_GENERATE_KEY, (void *)&args);
-     if (r < 0)
-	  goto out;
-
-     /* extract public key */
-     pubkey->algorithm = SC_ALGORITHM_RSA;
-     pubkey->u.rsa.modulus.len   = keybits / 8;
-     pubkey->u.rsa.modulus.data  = keybuf;
-     pubkey->u.rsa.exponent.len  = 3;
-     pubkey->u.rsa.exponent.data = malloc(3);
-     if (!pubkey->u.rsa.exponent.data) {
-	  pubkey->u.rsa.modulus.data = NULL;
-	  r=SC_ERROR_OUT_OF_MEMORY;
-	  goto out;
-     }
-     memcpy(pubkey->u.rsa.exponent.data, "\x01\x00\x01", 3);
-
- out:
-     if (r < 0 && keybuf)
-	  free(keybuf);
-     if (delete_ok)
-	  sc_pkcs15init_rmdir(p15card, profile, temppubfile);
-	 sc_file_free(keyfile);
-	 sc_file_free(temppubfile);
-     return r;
-}
-
-
-
-static struct sc_pkcs15init_operations sc_pkcs15init_jcop_operations = {
-	jcop_erase_card,
-	NULL,				/* init_card     */
-	jcop_create_dir,
-	NULL,				/* create_domain */
-	jcop_select_pin_reference,
-	jcop_create_pin,
-	NULL,				/* select_key_reference */
-	jcop_create_key,
-	jcop_store_key,
-	jcop_generate_key,
-	NULL, NULL,			/* encode private/public key */
-	NULL,				/* finalize_card */
-	NULL, 				/* delete_object */
-	NULL, NULL, NULL, NULL, NULL,	/* pkcs15init emulation */
-	NULL				/* sanity_check */
-};
-
-struct sc_pkcs15init_operations *sc_pkcs15init_get_jcop_ops(void)
-{
-     return &sc_pkcs15init_jcop_operations;
-}
-
-
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-lib.c opensc-0.23.0/src/pkcs15init/pkcs15-lib.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-lib.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-lib.c	2022-11-29 09:34:43.000000000 +0100
@@ -141,12 +141,10 @@
 } profile_operations[] = {
 	{ "rutoken", (void *) sc_pkcs15init_get_rutoken_ops },
 	{ "gpk", (void *) sc_pkcs15init_get_gpk_ops },
-	{ "miocos", (void *) sc_pkcs15init_get_miocos_ops },
 	{ "flex", (void *) sc_pkcs15init_get_cryptoflex_ops },
 	{ "cyberflex", (void *) sc_pkcs15init_get_cyberflex_ops },
 	{ "cardos", (void *) sc_pkcs15init_get_cardos_ops },
 	{ "etoken", (void *) sc_pkcs15init_get_cardos_ops }, /* legacy */
-	{ "jcop", (void *) sc_pkcs15init_get_jcop_ops },
 	{ "starcos", (void *) sc_pkcs15init_get_starcos_ops },
 	{ "oberthur", (void *) sc_pkcs15init_get_oberthur_ops },
 	{ "openpgp", (void *) sc_pkcs15init_get_openpgp_ops },
@@ -177,8 +175,16 @@
 };
 
 
-static void sc_pkcs15init_empty_callback(void *ptr)
+static void sc_pkcs15init_free_ec_params(void *ptr)
 {
+	struct sc_ec_parameters *ecparams = (struct sc_ec_parameters *)ptr;
+	if (ecparams) {
+		if (ecparams->der.value)
+			free(ecparams->der.value);
+		if (ecparams->named_curve)
+			free(ecparams->named_curve);
+		free(ecparams);
+	}
 }
 
 /*
@@ -582,9 +588,9 @@
 	 * card (driver and profile) that uses self delete ACL.
 	 */
 	/* Select the file itself */
-        path = *file_path;
-        rv = sc_select_file(p15card->card, &path, &file);
-        LOG_TEST_RET(ctx, rv, "cannot select file to delete");
+	path = *file_path;
+	rv = sc_select_file(p15card->card, &path, &file);
+	LOG_TEST_RET(ctx, rv, "cannot select file to delete");
 
 	if (sc_file_get_acl_entry(file, SC_AC_OP_DELETE_SELF))   {
 		sc_log(ctx, "Found 'DELETE-SELF' acl");
@@ -603,12 +609,20 @@
 			/* Select the parent DF */
 			path.len -= 2;
 			rv = sc_select_file(p15card->card, &path, &parent);
+			if (rv < 0)
+				sc_file_free(file);
 			LOG_TEST_RET(ctx, rv, "Cannot select parent");
 
 			rv = sc_pkcs15init_authenticate(profile, p15card, parent, SC_AC_OP_DELETE);
 			sc_file_free(parent);
+			sc_file_free(file);
 			LOG_TEST_RET(ctx, rv, "parent 'DELETE' authentication failed");
 		}
+		else {
+			/* No 'DELETE' ACL of the file and not deleted for parent */
+			rv = SC_ERROR_INVALID_ARGUMENTS;
+			sc_file_free(file);
+		}
 	}
 	LOG_TEST_RET(ctx, rv, "'DELETE' authentication failed");
 
@@ -619,6 +633,10 @@
 
 	memset(&path, 0, sizeof(path));
 	path.type = SC_PATH_TYPE_FILE_ID;
+	if (file_path->len < 2) {
+		sc_file_free(file);
+		LOG_FUNC_RETURN(ctx, SC_ERROR_INVALID_ARGUMENTS);
+	}
 	path.value[0] = file_path->value[file_path->len - 2];
 	path.value[1] = file_path->value[file_path->len - 1];
 	path.len = 2;
@@ -633,6 +651,7 @@
 
 	sc_log(ctx, "Now really delete file");
 	rv = sc_delete_file(p15card->card, &path);
+	sc_file_free(file);
 	LOG_FUNC_RETURN(ctx, rv);
 }
 
@@ -838,25 +857,27 @@
 					pin_attrs->flags, pin_attrs->reference, sc_print_path(&pin_ainfo.path));
 
 			r = sc_pkcs15_add_object(p15card, pin_obj);
-			LOG_TEST_RET(ctx, r, "Failed to add 'SOPIN' AUTH object");
+			LOG_TEST_GOTO_ERR(ctx, r, "Failed to add 'SOPIN' AUTH object");
 		}
 	}
 
 	/* Perform card-specific initialization */
-
 	if (profile->ops->init_card)   {
 		r = profile->ops->init_card(profile, p15card);
 		if (r < 0 && pin_obj)   {
 			sc_pkcs15_remove_object(p15card, pin_obj);
-			sc_pkcs15_free_object(pin_obj);
 		}
-		LOG_TEST_RET(ctx, r, "Card specific init failed");
+		LOG_TEST_GOTO_ERR(ctx, r, "Card specific init failed");
 	}
 
 	/* Create the application directory */
-	if (profile->ops->create_dir)
+	if (profile->ops->create_dir) {
 		r = profile->ops->create_dir(profile, p15card, df);
-	LOG_TEST_RET(ctx, r, "Create 'DIR' error");
+		if (r < 0 && pin_obj)   {
+			sc_pkcs15_remove_object(p15card, pin_obj);
+		}
+		LOG_TEST_GOTO_ERR(ctx, r, "Create 'DIR' error");
+	}
 
 	/* Store SO PIN */
 	if (pin_obj && profile->ops->create_pin)
@@ -868,14 +889,14 @@
 		/* Remove 'virtual' AUTH object . */
 		sc_pkcs15_remove_object(p15card, pin_obj);
 
-	if (r < 0)
-		sc_pkcs15_free_object(pin_obj);
-	LOG_TEST_RET(ctx, r, "Card specific create application DF failed");
+	LOG_TEST_GOTO_ERR(ctx, r, "Card specific create application DF failed");
 
 	/* Store the PKCS15 information on the card */
 	app = (struct sc_app_info *)calloc(1, sizeof(*app));
-	if (app == NULL)
-		LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "Failed to allocate application info");
+	if (app == NULL) {
+		r = SC_ERROR_OUT_OF_MEMORY;
+		LOG_TEST_GOTO_ERR(ctx, r, "Failed to allocate application info");
+	}
 
 	app->path = p15card->file_app->path;
 	if (p15card->file_app->namelen <= SC_MAX_AID_SIZE) {
@@ -914,17 +935,33 @@
 		if (r >= 0) {
 			r = sc_pkcs15init_update_tokeninfo(p15card, profile);
 		} else {
-			/* FIXME: what to do if sc_pkcs15init_update_dir failed? */
-			free(app->label);
-			free(app); /* unused */
+			/* FIXED: what to do if sc_pkcs15init_update_dir failed? */
+			/* sc_pkcs15init_update_dir may add app to card->app[] */
+			int found = 0;
+			int i;
+			for (i = 0; i < card->app_count; i++) {
+				if (card->app[i] == app) {
+					found = 1;
+					break;
+				}
+			}
+			if (found == 0) { /* not in card->app[] free it */
+				free(app->label);
+				free(app); /* unused */
+			}
 		}
 	}
 	else {
 		free(app->label);
 		free(app); /* unused */
+		LOG_TEST_GOTO_ERR(ctx, r, "Failed to add pin object.");
 	}
 
 	sc_pkcs15init_write_info(p15card, profile, pin_obj);
+	pin_obj = NULL;
+
+err:
+	sc_pkcs15_free_object(pin_obj);
 	LOG_FUNC_RETURN(ctx, r);
 }
 
@@ -976,20 +1013,24 @@
 	auth_info->auth_id = args->puk_id;
 
 	/* Now store the PINs */
-	if (profile->ops->create_pin)
+	if (profile->ops->create_pin) {
 		r = sc_pkcs15init_create_pin(p15card, profile, pin_obj, args);
+		LOG_TEST_GOTO_ERR(ctx, r, "Failed to create PIN");
+	}
 	else {
-		sc_pkcs15_free_object(pin_obj);
-		LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "In Old API store PUK object is not supported");
+		r = SC_ERROR_NOT_SUPPORTED;
+		LOG_TEST_GOTO_ERR(ctx, r, "In Old API store PUK object is not supported");
 	}
 
-	if (r >= 0)
-		r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_AODF, pin_obj);
-	else
-		sc_pkcs15_free_object(pin_obj);
+	r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_AODF, pin_obj);
+	LOG_TEST_GOTO_ERR(ctx, r, "Add pin object error");
 
 	profile->dirty = 1;
 
+	pin_obj = NULL;
+
+err:
+	sc_pkcs15_free_object(pin_obj);
 	LOG_FUNC_RETURN(ctx, r);
 }
 
@@ -1037,21 +1078,26 @@
 
 	/* Now store the PINs */
 	sc_log(ctx, "Store PIN(%.*s,authID:%s)", (int) sizeof pin_obj->label, pin_obj->label, sc_pkcs15_print_id(&auth_info->auth_id));
-	r = sc_pkcs15init_create_pin(p15card, profile, pin_obj, args);
-	if (r < 0)
-		sc_pkcs15_free_object(pin_obj);
-	LOG_TEST_RET(ctx, r, "Card specific create PIN failed.");
+	if (profile->ops->create_pin) {
+		r = sc_pkcs15init_create_pin(p15card, profile, pin_obj, args);
+		LOG_TEST_GOTO_ERR(ctx, r, "Card specific create PIN failed.");
+	} else {
+		r = SC_ERROR_NOT_SUPPORTED;
+		LOG_TEST_GOTO_ERR(ctx, r, "Store PIN operation is not supported");
+	}
 
 	r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_AODF, pin_obj);
-	if (r < 0)
-		sc_pkcs15_free_object(pin_obj);
-	LOG_TEST_RET(ctx, r, "Failed to add PIN object");
+	LOG_TEST_GOTO_ERR(ctx, r, "Failed to add PIN object");
 
 	if (args->puk_id.len)
 		r = sc_pkcs15init_store_puk(p15card, profile, args);
 
 	profile->dirty = 1;
 
+	pin_obj = NULL;
+
+err:
+	sc_pkcs15_free_object(pin_obj);
 	LOG_FUNC_RETURN(ctx, r);
 }
 
@@ -1177,12 +1223,13 @@
 		struct sc_pkcs15_object **res_obj)
 {
 	struct sc_context *ctx = p15card->card->ctx;
-	struct sc_pkcs15_prkey_info *key_info;
+	struct sc_pkcs15_prkey_info *key_info = NULL;
 	struct sc_pkcs15_keyinfo_gostparams *keyinfo_gostparams;
 	struct sc_pkcs15_object *object = NULL;
 	const char	*label;
 	unsigned int	usage;
 	int		r = 0, key_type;
+	struct sc_ec_parameters *new_ecparams = NULL;
 
 	LOG_FUNC_CALLED(ctx);
 	if (!res_obj || !keybits) {
@@ -1209,8 +1256,10 @@
 	LOG_TEST_GOTO_ERR(ctx, r, "Unsupported key type");
 
 	object = sc_pkcs15init_new_object(key_type, label, &keyargs->auth_id, NULL);
-	if (object == NULL)
-		LOG_TEST_GOTO_ERR(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate new PrKey object");
+	if (object == NULL) {
+		r = SC_ERROR_OUT_OF_MEMORY;
+		LOG_TEST_GOTO_ERR(ctx, r, "Cannot allocate new PrKey object");
+	}
 
 	key_info = (struct sc_pkcs15_prkey_info *) object->data;
 	key_info->usage = usage;
@@ -1247,9 +1296,27 @@
 		keyinfo_gostparams->gost28147 = keyargs->params.gost.gost28147;
 	}
 	else if (key->algorithm == SC_ALGORITHM_EC)  {
+		/* keyargs->key.u.ec.params.der.value is allocated in keyargs, which is on stack */
 		struct sc_ec_parameters *ecparams = &keyargs->key.u.ec.params;
-		key_info->params.data = &keyargs->key.u.ec.params;
-		key_info->params.free_params = sc_pkcs15init_empty_callback;
+		new_ecparams = calloc(1, sizeof(struct sc_ec_parameters));
+		if (!new_ecparams) {
+			r = SC_ERROR_OUT_OF_MEMORY;
+			LOG_TEST_GOTO_ERR(ctx, r, "Cannot allocate memory for EC parameters");
+		}
+		/* copy ecparams into allocated one
+		 * it will be freed with the corresponding object */
+		memcpy(new_ecparams, ecparams, sizeof(struct sc_ec_parameters));
+
+		new_ecparams->named_curve = strdup(ecparams->named_curve);
+		new_ecparams->der.value = malloc(ecparams->der.len);
+		if (!new_ecparams->named_curve || !new_ecparams->der.value) {
+			r = SC_ERROR_OUT_OF_MEMORY;
+			LOG_TEST_GOTO_ERR(ctx, r, "Cannot allocate memory for EC parameters");
+		}
+		memcpy(new_ecparams->der.value, ecparams->der.value, ecparams->der.len);
+
+		key_info->params.data = new_ecparams;
+		key_info->params.free_params = sc_pkcs15init_free_ec_params;
 		key_info->field_length = ecparams->field_length;
 		key_info->modulus_length = 0;
 	}
@@ -1282,11 +1349,17 @@
 
 	*res_obj = object;
 	object = NULL;
+	new_ecparams = NULL;
 	r = SC_SUCCESS;
 
 err:
-	if (object)
-		sc_pkcs15init_free_object(object);
+	if (new_ecparams) {
+		free(new_ecparams->named_curve);
+		free(new_ecparams->der.value);
+		free(new_ecparams);
+		key_info->params.data = NULL;
+	}
+	sc_pkcs15init_free_object(object);
 	LOG_FUNC_RETURN(ctx, r);
 }
 
@@ -1328,8 +1401,10 @@
 	LOG_TEST_GOTO_ERR(ctx, r, "Unsupported key type");
 
 	object = sc_pkcs15init_new_object(key_type, label, &keyargs->auth_id, NULL);
-	if (object == NULL)
-		LOG_TEST_GOTO_ERR(ctx, SC_ERROR_OUT_OF_MEMORY, "Cannot allocate new SKey object");
+	if (object == NULL) {
+		r = SC_ERROR_OUT_OF_MEMORY;
+		LOG_TEST_GOTO_ERR(ctx, r, "Cannot allocate new SKey object");
+	}
 
 	key_info = (struct sc_pkcs15_skey_info *) object->data;
 	key_info->usage = usage;
@@ -1373,16 +1448,17 @@
 	LOG_TEST_GOTO_ERR(ctx, r, "Failed to select secret key object path");
 
 	/* See if we need to select a key reference for this object */
-	if (profile->ops->select_key_reference)
-		LOG_TEST_GOTO_ERR(ctx, SC_ERROR_NOT_SUPPORTED, "SKey keyreference selection not supported");
+	if (profile->ops->select_key_reference) {
+		r = SC_ERROR_NOT_SUPPORTED;
+		LOG_TEST_GOTO_ERR(ctx, r, "SKey keyreference selection not supported");
+	}
 
 	*res_obj = object;
 	object = NULL;
 	r = SC_SUCCESS;
 
 err:
-	if (object)
-		sc_pkcs15init_free_object(object);
+	sc_pkcs15init_free_object(object);
 	LOG_FUNC_RETURN(ctx, r);
 }
 
@@ -1456,43 +1532,51 @@
 	struct sc_pkcs15_prkey_info *key_info = NULL;
 	struct sc_pkcs15_pubkey *pubkey = NULL;
 	int r, caller_supplied_id = 0;
+	int algorithm = keygen_args->prkey_args.key.algorithm;
 
 	LOG_FUNC_CALLED(ctx);
 	/* check supported key size */
 	r = check_keygen_params_consistency(p15card->card,
-		keygen_args->prkey_args.key.algorithm, &keygen_args->prkey_args,
+		algorithm, &keygen_args->prkey_args,
 		&keybits);
 	LOG_TEST_RET(ctx, r, "Invalid key size");
 
-	if (check_key_compatibility(p15card, keygen_args->prkey_args.key.algorithm,
+	if (check_key_compatibility(p15card, algorithm,
 			&keygen_args->prkey_args.key, keygen_args->prkey_args.x509_usage,
-			keybits, SC_ALGORITHM_ONBOARD_KEY_GEN) != SC_SUCCESS)
-		LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Cannot generate key with the given parameters");
+			keybits, SC_ALGORITHM_ONBOARD_KEY_GEN) != SC_SUCCESS) {
+		r = SC_ERROR_NOT_SUPPORTED;
+		LOG_TEST_GOTO_ERR(ctx, r, "Cannot generate key with the given parameters");
+	}
 
-	if (profile->ops->generate_key == NULL)
-		LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "Key generation not supported");
+	if (profile->ops->generate_key == NULL) {
+		r = SC_ERROR_NOT_SUPPORTED;
+		LOG_TEST_GOTO_ERR(ctx, r, "Key generation not supported");
+	}
 
 	if (keygen_args->prkey_args.id.len)   {
 		caller_supplied_id = 1;
 
 		/* Make sure that private key's ID is the unique inside the PKCS#15 application */
 		r = sc_pkcs15_find_prkey_by_id(p15card, &keygen_args->prkey_args.id, NULL);
-		if (!r)
-			LOG_TEST_RET(ctx, SC_ERROR_NON_UNIQUE_ID, "Non unique ID of the private key object");
-		else if (r != SC_ERROR_OBJECT_NOT_FOUND)
-			LOG_TEST_RET(ctx, r, "Find private key error");
+		if (!r) {
+			r = SC_ERROR_NON_UNIQUE_ID;
+			LOG_TEST_GOTO_ERR(ctx, r, "Non unique ID of the private key object");
+		}
+		else if (r != SC_ERROR_OBJECT_NOT_FOUND) {
+			LOG_TEST_GOTO_ERR(ctx, r, "Find private key error");
+		}
 	}
 
 	/* Set up the PrKDF object */
 	r = sc_pkcs15init_init_prkdf(p15card, profile, &keygen_args->prkey_args,
 		&keygen_args->prkey_args.key, keybits, &object);
-	LOG_TEST_RET(ctx, r, "Set up private key object error");
+	LOG_TEST_GOTO_ERR(ctx, r, "Set up private key object error");
 
 	key_info = (struct sc_pkcs15_prkey_info *) object->data;
 
 	r = _pkcd15init_set_aux_md_data(p15card, &key_info->aux_data,
 			keygen_args->prkey_args.guid, keygen_args->prkey_args.guid_len);
-	LOG_TEST_RET(ctx, r, "Failed to set aux MD data");
+	LOG_TEST_GOTO_ERR(ctx, r, "Failed to set aux MD data");
 
 	/* Set up the PuKDF info. The public key will be filled in
 	 * by the card driver's generate_key function called below.
@@ -1503,23 +1587,33 @@
 	pubkey_args.usage = keygen_args->prkey_args.usage;
 	pubkey_args.x509_usage = keygen_args->prkey_args.x509_usage;
 
-	if (keygen_args->prkey_args.key.algorithm == SC_ALGORITHM_GOSTR3410)   {
+	if (algorithm == SC_ALGORITHM_GOSTR3410)   {
 		pubkey_args.params.gost = keygen_args->prkey_args.params.gost;
 		r = sc_copy_gost_params(&(pubkey_args.key.u.gostr3410.params), &(keygen_args->prkey_args.key.u.gostr3410.params));
-		LOG_TEST_RET(ctx, r, "Cannot allocate GOST parameters");
+		LOG_TEST_GOTO_ERR(ctx, r, "Cannot allocate GOST parameters");
 	}
-	else if (keygen_args->prkey_args.key.algorithm == SC_ALGORITHM_EC)   {
+	else if (algorithm == SC_ALGORITHM_EC)   {
+		/* needs to be freed in case of failure when pubkey is not set yet */
 		pubkey_args.key.u.ec.params = keygen_args->prkey_args.key.u.ec.params;
 		r = sc_copy_ec_params(&pubkey_args.key.u.ec.params, &keygen_args->prkey_args.key.u.ec.params);
-		LOG_TEST_RET(ctx, r, "Cannot allocate EC parameters");
+		LOG_TEST_GOTO_ERR(ctx, r, "Cannot allocate EC parameters");
 	}
 
 	/* Generate the private key on card */
 	r = profile->ops->create_key(profile, p15card, object);
-	LOG_TEST_RET(ctx, r, "Cannot generate key: create key failed");
+	if (r < 0 && algorithm == SC_ALGORITHM_EC) {
+		/* pubkey->alg_id->algorithm is not set yet, needs to be freed independently */
+		free(pubkey_args.key.u.ec.params.der.value);
+		free(pubkey_args.key.u.ec.params.named_curve);
+	}
+	LOG_TEST_GOTO_ERR(ctx, r, "Cannot generate key: create key failed");
 
 	r = profile->ops->generate_key(profile, p15card, object, &pubkey_args.key);
-	LOG_TEST_RET(ctx, r, "Failed to generate key");
+	if (r < 0 && algorithm == SC_ALGORITHM_EC) {
+		free(pubkey_args.key.u.ec.params.der.value);
+		free(pubkey_args.key.u.ec.params.named_curve);
+	}
+	LOG_TEST_GOTO_ERR(ctx, r, "Failed to generate key");
 
 	/* update PrKDF entry */
 	if (!caller_supplied_id)   {
@@ -1529,7 +1623,12 @@
 		 * if intrinsic ID can be calculated -- overwrite the native one */
 		memset(&iid, 0, sizeof(iid));
 		r = sc_pkcs15init_select_intrinsic_id(p15card, profile, SC_PKCS15_TYPE_PUBKEY, &iid, &pubkey_args.key);
-		LOG_TEST_RET(ctx, r, "Select intrinsic ID error");
+		if (r < 0 && algorithm == SC_ALGORITHM_EC) {
+			free(pubkey_args.key.u.ec.params.der.value);
+			free(pubkey_args.key.u.ec.params.named_curve);
+			free(pubkey_args.key.u.ec.ecpointQ.value); /* allocated in profile->ops->generate_key */
+		}
+		LOG_TEST_GOTO_ERR(ctx, r, "Select intrinsic ID error");
 
 		if (iid.len)
 			key_info->id = iid;
@@ -1538,8 +1637,14 @@
 	pubkey = &pubkey_args.key;
 	if (!pubkey->alg_id)   {
 		pubkey->alg_id = calloc(1, sizeof(struct sc_algorithm_id));
-		if (!pubkey->alg_id)
-			LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
+		if (!pubkey->alg_id) {
+			if (algorithm == SC_ALGORITHM_EC) {
+				free(pubkey_args.key.u.ec.params.der.value);
+				free(pubkey_args.key.u.ec.params.named_curve);
+			}
+			r = SC_ERROR_OUT_OF_MEMORY;
+			LOG_TEST_GOTO_ERR(ctx, r, "Can not allocate memory for algorithm id");
+		}
 
 		sc_init_oid(&pubkey->alg_id->oid);
 		pubkey->alg_id->algorithm = pubkey->algorithm;
@@ -1547,28 +1652,39 @@
 
 	pubkey_args.id = key_info->id;
 	r = sc_pkcs15_encode_pubkey(ctx, pubkey, &object->content.value, &object->content.len);
-	LOG_TEST_RET(ctx, r, "Failed to encode public key");
+	LOG_TEST_GOTO_ERR(ctx, r, "Failed to encode public key");
 
 	r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_PRKDF, object);
-	LOG_TEST_RET(ctx, r, "Failed to add generated private key object");
+	LOG_TEST_GOTO_ERR(ctx, r, "Failed to add generated private key object");
 
 	if (!r && profile->ops->emu_store_data)   {
 		r = profile->ops->emu_store_data(p15card, profile, object, NULL, NULL);
 		if (r == SC_ERROR_NOT_IMPLEMENTED)
 			r = SC_SUCCESS;
-		LOG_TEST_RET(ctx, r, "Card specific 'store data' failed");
+		LOG_TEST_GOTO_ERR(ctx, r, "Card specific 'store data' failed");
 	}
 
 	r = sc_pkcs15init_store_public_key(p15card, profile, &pubkey_args, NULL);
-	LOG_TEST_RET(ctx, r, "Failed to store public key");
+	if (r < 0)
+		sc_pkcs15_remove_object(p15card, object);
+	LOG_TEST_GOTO_ERR(ctx, r, "Failed to store public key");
 
 	if (res_obj)
 		*res_obj = object;
+	object = NULL;
 
-	sc_pkcs15_erase_pubkey(&pubkey_args.key);
+	sc_pkcs15_erase_pubkey(pubkey);
 
 	profile->dirty = 1;
 
+err:
+	sc_pkcs15_erase_pubkey(pubkey);
+	sc_pkcs15_free_object(object);
+	if (algorithm == SC_ALGORITHM_EC) {
+		/* allocated in check_keygen_params_consistency() */
+		free(keygen_args->prkey_args.key.u.ec.params.der.value);
+		keygen_args->prkey_args.key.u.ec.params.der.value = NULL;
+	}
 	LOG_FUNC_RETURN(ctx, r);
 }
 
@@ -1607,30 +1723,33 @@
 
 	/* Set up the SKDF object */
 	r = sc_pkcs15init_init_skdf(p15card, profile, skey_args, &object);
-	LOG_TEST_RET(ctx, r, "Set up secret key object error");
+	LOG_TEST_GOTO_ERR(ctx, r, "Set up secret key object error");
 
 	/* Generate the secret key on card */
 	r = profile->ops->create_key(profile, p15card, object);
-	LOG_TEST_RET(ctx, r, "Cannot generate key: create key failed");
+	LOG_TEST_GOTO_ERR(ctx, r, "Cannot generate key: create key failed");
 
 	r = profile->ops->generate_key(profile, p15card, object, NULL);
-	LOG_TEST_RET(ctx, r, "Failed to generate key");
+	LOG_TEST_GOTO_ERR(ctx, r, "Failed to generate key");
 
 	r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_SKDF, object);
-	LOG_TEST_RET(ctx, r, "Failed to add generated secret key object");
+	LOG_TEST_GOTO_ERR(ctx, r, "Failed to add generated secret key object");
 
 	if (!r && profile->ops->emu_store_data)   {
 		r = profile->ops->emu_store_data(p15card, profile, object, NULL, NULL);
 		if (r == SC_ERROR_NOT_IMPLEMENTED)
 			r = SC_SUCCESS;
-		LOG_TEST_RET(ctx, r, "Card specific 'store data' failed");
+		LOG_TEST_GOTO_ERR(ctx, r, "Card specific 'store data' failed");
 	}
 
 	if (res_obj)
 		*res_obj = object;
+	object = NULL;
 
 	profile->dirty = 1;
 
+err:
+	sc_pkcs15_free_object(object);
 	LOG_FUNC_RETURN(ctx, r);
 }
 
@@ -1683,40 +1802,43 @@
 	LOG_TEST_RET(ctx, r, "Failed to initialize private key object");
 
 	r = sc_pkcs15init_encode_prvkey_content(p15card, &key, object);
-	LOG_TEST_RET(ctx, r, "Failed to encode public key");
+	LOG_TEST_GOTO_ERR(ctx, r, "Failed to encode public key");
 
 	key_info = (struct sc_pkcs15_prkey_info *) object->data;
 	r = _pkcd15init_set_aux_md_data(p15card, &key_info->aux_data, keyargs->guid, keyargs->guid_len);
-	LOG_TEST_RET(ctx, r, "Failed to set aux MD data");
+	LOG_TEST_GOTO_ERR(ctx, r, "Failed to set aux MD data");
 
 	if (profile->ops->create_key)
 		r = profile->ops->create_key(profile, p15card, object);
-	LOG_TEST_RET(ctx, r, "Card specific 'create key' failed");
+	LOG_TEST_GOTO_ERR(ctx, r, "Card specific 'create key' failed");
 
 	if (profile->ops->store_key)
 		r = profile->ops->store_key(profile, p15card, object, &key);
-	LOG_TEST_RET(ctx, r, "Card specific 'store key' failed");
+	LOG_TEST_GOTO_ERR(ctx, r, "Card specific 'store key' failed");
 
 	sc_pkcs15_free_object_content(object);
 	r = sc_pkcs15init_encode_prvkey_content(p15card, &key, object);
-	LOG_TEST_RET(ctx, r, "Failed to encode public key");
+	LOG_TEST_GOTO_ERR(ctx, r, "Failed to encode public key");
 
 	/* Now update the PrKDF */
 	r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_PRKDF, object);
-	LOG_TEST_RET(ctx, r, "Failed to add new private key PKCS#15 object");
+	LOG_TEST_GOTO_ERR(ctx, r, "Failed to add new private key PKCS#15 object");
 
 	if (!r && profile->ops->emu_store_data)   {
 		r = profile->ops->emu_store_data(p15card, profile, object, NULL, NULL);
 		if (r == SC_ERROR_NOT_IMPLEMENTED)
 			r = SC_SUCCESS;
-		LOG_TEST_RET(ctx, r, "Card specific 'store data' failed");
+		LOG_TEST_GOTO_ERR(ctx, r, "Card specific 'store data' failed");
 	}
 
 	if (r >= 0 && res_obj)
 		*res_obj = object;
+	object = NULL;
 
 	profile->dirty = 1;
 
+err:
+	sc_pkcs15_free_object(object);
 	LOG_FUNC_RETURN(ctx, r);
 }
 
@@ -1750,12 +1872,6 @@
 		keybits = sc_pkcs15init_keybits(&key.u.rsa.modulus);
 		type = SC_PKCS15_TYPE_PUBKEY_RSA;
 		break;
-#ifdef SC_PKCS15_TYPE_PUBKEY_DSA
-	case SC_ALGORITHM_DSA:
-		keybits = sc_pkcs15init_keybits(&key.u.dsa.q);
-		type = SC_PKCS15_TYPE_PUBKEY_DSA;
-		break;
-#endif
 	case SC_ALGORITHM_GOSTR3410:
 		keybits = SC_PKCS15_GOSTR3410_KEYSIZE;
 		type = SC_PKCS15_TYPE_PUBKEY_GOSTR3410;
@@ -1864,16 +1980,16 @@
 	/* Update the PuKDF */
 	if (r >= 0)
 		r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_PUKDF, object);
+	LOG_TEST_GOTO_ERR(ctx, r, "Add object error");
 
 	if (r >= 0 && res_obj)
 		*res_obj = object;
+	object = NULL;
 
 	profile->dirty = 1;
 
 err:
-	if (r < 0)
-		sc_pkcs15init_free_object(object);
-
+	sc_pkcs15_free_object(object);
 	LOG_FUNC_RETURN(ctx, r);
 }
 
@@ -1921,7 +2037,7 @@
 
 	if (profile->ops->create_key)
 		r = profile->ops->create_key(profile, p15card, object);
-	LOG_TEST_RET(ctx, r, "Card specific 'create key' failed");
+	LOG_TEST_GOTO_ERR(ctx, r, "Card specific 'create key' failed");
 
 	/* If no key data, only an empty EF is created. 
 	 * It can be used to receive an unwrapped key later. */
@@ -1934,7 +2050,7 @@
 			r = profile->ops->store_key(profile, p15card, object, &key);
 		}
 	}
-	LOG_TEST_RET(ctx, r, "Card specific 'store key' failed");
+	LOG_TEST_GOTO_ERR(ctx, r, "Card specific 'store key' failed");
 
 	sc_pkcs15_free_object_content(object);
 
@@ -1945,21 +2061,24 @@
 	   but we don't want it to be written into SKDF. */
 	if (!object->session_object) {
 		r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_SKDF, object);
-		LOG_TEST_RET(ctx, r, "Failed to add new secret key PKCS#15 object");
+		LOG_TEST_GOTO_ERR(ctx, r, "Failed to add new secret key PKCS#15 object");
 	}
 
 	if (!r && profile->ops->emu_store_data && !object->session_object)   {
 		r = profile->ops->emu_store_data(p15card, profile, object, NULL, NULL);
 		if (r == SC_ERROR_NOT_IMPLEMENTED)
 			r = SC_SUCCESS;
-		LOG_TEST_RET(ctx, r, "Card specific 'store data' failed");
+		LOG_TEST_GOTO_ERR(ctx, r, "Card specific 'store data' failed");
 	}
 
 	if (r >= 0 && res_obj)
 		*res_obj = object;
+	object = NULL;
 
 	profile->dirty = 1;
 
+err:
+	sc_pkcs15_free_object(object);
 	LOG_FUNC_RETURN(ctx, r);
 }
 
@@ -2138,17 +2257,20 @@
 	sc_der_copy(&data_object_info->data, &args->der_encoded);
 
 	r = sc_pkcs15init_store_data(p15card, profile, object, &args->der_encoded, &data_object_info->path);
-	LOG_TEST_RET(ctx, r, "Store 'DATA' object error");
+	LOG_TEST_GOTO_ERR(ctx, r, "Store 'DATA' object error");
 
 	/* Now update the DDF */
 	r = sc_pkcs15init_add_object(p15card, profile, SC_PKCS15_DODF, object);
-	LOG_TEST_RET(ctx, r, "'DODF' update error");
+	LOG_TEST_GOTO_ERR(ctx, r, "'DODF' update error");
 
 	if (r >= 0 && res_obj)
 		*res_obj = object;
+	object = NULL;
 
 	profile->dirty = 1;
 
+err:
+	sc_pkcs15_free_object(object);
 	LOG_FUNC_RETURN(ctx, r);
 }
 
@@ -2376,6 +2498,10 @@
 		LOG_FUNC_RETURN(ctx, SC_SUCCESS);
 	}
 
+	if (alg == SC_ALGORITHM_EC && prkey)
+		/* allocated in sc_pkcs15_fix_ec_parameters */
+		free(prkey->key.u.ec.params.der.value);
+
 	LOG_FUNC_RETURN(ctx, SC_ERROR_NOT_SUPPORTED);
 }
 
@@ -2537,7 +2663,6 @@
 	switch (key->algorithm) {
 	case SC_ALGORITHM_RSA:
 		return prkey_fixup_rsa(p15card, &key->u.rsa);
-	case SC_ALGORITHM_DSA:
 	case SC_ALGORITHM_GOSTR3410:
 		/* for now */
 		return 0;
@@ -2554,8 +2679,6 @@
 	switch (key->algorithm) {
 	case SC_ALGORITHM_RSA:
 		return sc_pkcs15init_keybits(&key->u.rsa.modulus);
-	case SC_ALGORITHM_DSA:
-		return sc_pkcs15init_keybits(&key->u.dsa.q);
 	case SC_ALGORITHM_GOSTR3410:
 		if (sc_pkcs15init_keybits(&key->u.gostr3410.d) > SC_PKCS15_GOSTR3410_KEYSIZE) {
 			sc_log(ctx,
@@ -2586,8 +2709,6 @@
 	switch (algorithm) {
 	case SC_ALGORITHM_RSA:
 		return SC_PKCS15_TYPE_PRKEY_RSA;
-	case SC_ALGORITHM_DSA:
-		return SC_PKCS15_TYPE_PRKEY_DSA;
 	case SC_ALGORITHM_GOSTR3410:
 		return SC_PKCS15_TYPE_PRKEY_GOSTR3410;
 	case SC_ALGORITHM_EC:
@@ -2671,8 +2792,6 @@
 	/* Skip silently if key is not initialized. */
 	if (pubkey->algorithm == SC_ALGORITHM_RSA && !pubkey->u.rsa.modulus.len)
 		goto done;
-	else if (pubkey->algorithm == SC_ALGORITHM_DSA && !pubkey->u.dsa.pub.data)
-		goto done;
 	else if (pubkey->algorithm == SC_ALGORITHM_GOSTR3410 &&
 			!pubkey->u.gostr3410.xy.data)
 		goto done;
@@ -2688,8 +2807,6 @@
 	case SC_PKCS15INIT_ID_STYLE_MOZILLA:
 		if (pubkey->algorithm == SC_ALGORITHM_RSA)
 			SHA1(pubkey->u.rsa.modulus.data, pubkey->u.rsa.modulus.len, id.value);
-		else if (pubkey->algorithm == SC_ALGORITHM_DSA)
-			SHA1(pubkey->u.dsa.pub.data, pubkey->u.dsa.pub.len, id.value);
 		else if (pubkey->algorithm == SC_ALGORITHM_EC)
 			/* ID should be SHA1 of the X coordinate according to PKCS#15 v1.1 */
 			/* skip the 04 tag and get the X component */
@@ -2721,6 +2838,7 @@
 done:
 	memcpy(id_out, &id, sizeof(*id_out));
 	rv = id_out->len;
+
 err:
 	if (id_data)
 		free(id_data);
@@ -3066,6 +3184,8 @@
 		LOG_TEST_RET(ctx, r, "select object path failed");
 
 		r = sc_select_file(p15card->card, &last_update->path, &file);
+		if (r < 0)
+			free(buf);
 		LOG_TEST_RET(ctx, r, "select object path failed");
 
 		r = sc_pkcs15init_update_file(profile, p15card, file, buf, buflen);
@@ -3910,7 +4030,7 @@
 	r = sc_select_file(p15card->card, &path, parent);
 	/* If DF doesn't exist, create it (unless it's the MF,
 	 * but then something's badly broken anyway :-) */
-	if (r == SC_ERROR_FILE_NOT_FOUND && path.len != 2) {
+	if (r == SC_ERROR_FILE_NOT_FOUND && path.len > 2) {
 		r = sc_profile_get_file_by_path(profile, &path, parent);
 		if (r < 0) {
 			sc_log(ctx, "no profile template for DF %s", sc_print_path(&path));
@@ -3918,9 +4038,17 @@
 		}
 
 		r = sc_pkcs15init_create_file(profile, p15card, *parent);
+		if (r < 0) {
+			sc_file_free(*parent);
+			*parent = NULL;
+		}
 		LOG_TEST_RET(ctx, r, "Cannot create parent DF");
 
 		r = sc_select_file(p15card->card, &path, NULL);
+		if (r < 0) {
+			sc_file_free(*parent);
+			*parent = NULL;
+		}
 		LOG_TEST_RET(ctx, r, "Cannot select parent DF");
 	}
 	else if (r == SC_SUCCESS && !strcmp(p15card->card->name, "STARCOS")) {
@@ -3934,6 +4062,7 @@
 			LOG_FUNC_RETURN(ctx, r);
 		}
 	}
+
 	LOG_FUNC_RETURN(ctx, r);
 }
 
@@ -3957,20 +4086,21 @@
 	LOG_TEST_RET(ctx, r, "Cannot create file: select parent error");
 
 	r = sc_pkcs15init_authenticate(profile, p15card, parent, SC_AC_OP_CREATE);
-	LOG_TEST_RET(ctx, r, "Cannot create file: 'CREATE' authentication failed");
+	LOG_TEST_GOTO_ERR(ctx, r, "Cannot create file: 'CREATE' authentication failed");
 
 	/* Fix up the file's ACLs */
 	r = sc_pkcs15init_fixup_file(profile, p15card, file);
-	LOG_TEST_RET(ctx, r, "Cannot create file: file fixup failed");
+	LOG_TEST_GOTO_ERR(ctx, r, "Cannot create file: file fixup failed");
 
 	/* ensure we are in the correct lifecycle */
 	r = sc_pkcs15init_set_lifecycle(p15card->card, SC_CARDCTRL_LIFECYCLE_ADMIN);
 	if (r != SC_ERROR_NOT_SUPPORTED)
-		LOG_TEST_RET(ctx, r, "Cannot create file: failed to set lifecycle 'ADMIN'");
+		LOG_TEST_GOTO_ERR(ctx, r, "Cannot create file: failed to set lifecycle 'ADMIN'");
 
 	r = sc_create_file(p15card->card, file);
-	LOG_TEST_RET(ctx, r, "Create file failed");
+	LOG_TEST_GOTO_ERR(ctx, r, "Create file failed");
 
+err:
 	sc_file_free(parent);
 	LOG_FUNC_RETURN(ctx, r);
 }
@@ -4022,6 +4152,11 @@
 	else if (selected_file->size > datalen && need_to_zap) {
 		/* zero out the rest of the file - we may have shrunk
 		 * the file contents */
+		if (selected_file->size > MAX_FILE_SIZE) {
+			sc_file_free(selected_file);
+			LOG_FUNC_RETURN(ctx, SC_ERROR_INTERNAL);
+		}
+
 		copy = calloc(1, selected_file->size);
 		if (copy == NULL) {
 			sc_file_free(selected_file);
@@ -4276,6 +4411,8 @@
 	if (r >= 0) {
 		len = file->size;
 		sc_file_free(file);
+		if (len > MAX_FILE_SIZE)
+			return SC_ERROR_INTERNAL;
 		mem = malloc(len);
 		if (mem != NULL)
 			r = sc_read_binary(card, 0, mem, len, 0);
@@ -4284,6 +4421,7 @@
 	}
 	else   {
 		r = 0;
+		sc_file_free(file);
 	}
 
 	if (r >= 0)
@@ -4327,13 +4465,14 @@
 	const unsigned char *end;
 	unsigned int	nopts = 0;
 	size_t		n;
+	int	r = 0;
 
 	if ((p == NULL) || (len == 0))
 		return 0;
 
 	end = p + (len - 1);
 	while (p < end) {	/* more bytes to look at */
-		int	r = 0;
+		r = 0;
 
 		tag = *p; p++;
 		if ((tag == 0) || (tag == 0xff) || (p >= end))
@@ -4342,23 +4481,26 @@
 		n = *p;
 		p++;
 
-		if (p >= end || p + n > end) /* invalid length byte n */
+		if (p >= end || p + n > end) { /* invalid length byte n */
+			r = SC_ERROR_PKCS15INIT;
 			goto error;
+		}
 
 		switch (tag) {
 		case OPENSC_INFO_TAG_PROFILE:
 			r = set_info_string(&profile->name, p, n);
 			if (r < 0)
-				return r;
+				goto error;
 			break;
 		case OPENSC_INFO_TAG_OPTION:
 			if (nopts >= SC_PKCS15INIT_MAX_OPTIONS - 1) {
 				sc_log(card->ctx, "Too many options in OpenSC Info file");
-				return SC_ERROR_PKCS15INIT;
+				r = SC_ERROR_PKCS15INIT;
+				goto error;
 			}
 			r = set_info_string(&profile->options[nopts], p, n);
 			if (r < 0)
-				return r;
+				goto error;
 			profile->options[++nopts] = NULL;
 			break;
 		default:
@@ -4370,7 +4512,16 @@
 
 error:
 	sc_log(card->ctx, "OpenSC info file corrupted");
-	return SC_ERROR_PKCS15INIT;
+	if (profile->name) {
+		free(profile->name);
+		profile->name = NULL;
+	}
+	for (size_t i = 0; i < nopts; i++) {
+		if (profile->options[i])
+			free(profile->options[i]);
+		profile->options[i] = NULL;
+	}
+	return r;
 }
 
 
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-miocos.c opensc-0.23.0/src/pkcs15init/pkcs15-miocos.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-miocos.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-miocos.c	1970-01-01 01:00:00.000000000 +0100
@@ -1,288 +0,0 @@
-/*
- * MioCOS specific operation for PKCS15 initialization
- *
- * Copyright (C) 2002  Juha Yrjölä <juha.yrjola at iki.fi>
- *
- * 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
- */
-
-#include "config.h"
-
-#include <string.h>
-#include <sys/types.h>
-
-#include "libopensc/opensc.h"
-#include "libopensc/cardctl.h"
-#include "libopensc/log.h"
-#include "pkcs15-init.h"
-#include "profile.h"
-
-#define MIOCOS_PIN_ID_MIN 1
-#define MIOCOS_PIN_ID_MAX 15
-
-/*
- * Allocate a file
- */
-static int
-miocos_new_file(struct sc_profile *profile, sc_card_t *card,
-		unsigned int type, unsigned int num,
-		sc_file_t **out)
-{
-	struct sc_file	*file;
-	struct sc_path	*p;
-	char		name[64];
-	const char      *tag = NULL, *desc = NULL;
-
-	while (1) {
-		switch (type) {
-		case SC_PKCS15_TYPE_PRKEY_RSA:
-			desc = "RSA private key";
-			tag = "private-key";
-			break;
-		case SC_PKCS15_TYPE_PUBKEY_RSA:
-			desc = "RSA public key";
-			tag = "public-key";
-			break;
-		case SC_PKCS15_TYPE_PRKEY:
-			desc = "extractable private key";
-			tag = "extractable-key";
-			break;
-		case SC_PKCS15_TYPE_CERT:
-			desc = "certificate";
-			tag = "certificate";
-			break;
-		case SC_PKCS15_TYPE_DATA_OBJECT:
-			desc = "data object";
-			tag = "data";
-			break;
-		}
-		if (tag)
-			break;
-		/* If this is a specific type such as
-		 * SC_PKCS15_TYPE_CERT_FOOBAR, fall back to
-		 * the generic class (SC_PKCS15_TYPE_CERT)
-		 */
-		if (!(type & ~SC_PKCS15_TYPE_CLASS_MASK)) {
-			sc_log(card->ctx, 
-				"File type not supported by card driver");
-			return SC_ERROR_INVALID_ARGUMENTS;
-		}
-		type &= SC_PKCS15_TYPE_CLASS_MASK;
-	}
-
-	snprintf(name, sizeof(name), "template-%s", tag);
-	if (sc_profile_get_file(profile, name, &file) < 0) {
-		sc_log(card->ctx,  "Profile doesn't define %s template (%s)",
-				desc, name);
-		return SC_ERROR_NOT_SUPPORTED;
-	}
-
-	/* Now construct file from template */
-	file->id += num;
-
-	p = &file->path;
-	*p = profile->df_info->file->path;
-	p->value[p->len++] = file->id >> 8;
-	p->value[p->len++] = file->id;
-
-	*out = file;
-	return 0;
-}
-
-static int
-miocos_update_private_key(struct sc_profile *profile, sc_card_t *card,
-		struct sc_pkcs15_prkey_rsa *rsa)
-{
-	int r;
-	u8 buf[266];
-
-	memcpy(buf, "\x30\x82\x01\x06\x80\x81\x80", 7);
-	memcpy(buf + 7, rsa->modulus.data, 128);
-	memcpy(buf + 7 + 128, "\x82\x81\x80", 3);
-	memcpy(buf + 10 + 128, rsa->d.data, 128);
-	r = sc_update_binary(card, 0, buf, sizeof(buf), 0);
-
-	return r;
-}
-
-/*
- * Initialize the Application DF
- */
-static int
-miocos_create_dir(struct sc_profile *profile, sc_pkcs15_card_t *p15card,
-		struct sc_file *df)
-{
-	/* Create the application DF */
-	if (sc_pkcs15init_create_file(profile, p15card, profile->df_info->file))
-		return 1;
-
-	return 0;
-}
-
-/*
- * Validate PIN reference
- */
-static int
-miocos_select_pin_reference(struct sc_profile *profile, sc_pkcs15_card_t *p15card,
-		struct sc_pkcs15_auth_info *auth_info)
-{
-	if (auth_info->auth_type != SC_PKCS15_PIN_AUTH_TYPE_PIN)
-		return SC_ERROR_OBJECT_NOT_VALID;
-
-	if (auth_info->attrs.pin.reference < MIOCOS_PIN_ID_MIN)
-		auth_info->attrs.pin.reference = MIOCOS_PIN_ID_MIN;
-
-	return SC_SUCCESS;
-}
-
-/*
- * Create new PIN
- */
-static int
-miocos_create_pin(struct sc_profile *profile, sc_pkcs15_card_t *p15card, struct sc_file *df,
-		struct sc_pkcs15_object *pin_obj,
-		const u8 *pin, size_t pin_len,
-		const u8 *puk, size_t puk_len)
-{
-	struct sc_context *ctx = p15card->card->ctx;
-	struct sc_pkcs15_auth_info *auth_info = (struct sc_pkcs15_auth_info *)pin_obj->data;
-	struct sc_pkcs15_pin_attributes *pin_attrs = &auth_info->attrs.pin;
-	struct sc_pkcs15_auth_info tmpinfo;
-	struct sc_cardctl_miocos_ac_info ac_info;
-	int r;
-
-	SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
-	/* Ignore SOPIN */
-	if (pin_attrs->flags & SC_PKCS15_PIN_FLAG_SO_PIN)
-		return SC_SUCCESS;
-
-	auth_info->path = profile->df_info->file->path;
-	r = sc_select_file(p15card->card, &auth_info->path, NULL);
-	if (r)
-		return r;
-	memset(&ac_info, 0, sizeof(ac_info));
-	ac_info.ref = pin_attrs->reference;
-	sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PIN, &tmpinfo);
-	ac_info.max_tries = tmpinfo.tries_left;
-	sc_profile_get_pin_info(profile, SC_PKCS15INIT_USER_PUK, &tmpinfo);
-	ac_info.max_unblock_tries = tmpinfo.tries_left;
-	if (pin_len > 8)
-		pin_len = 8;
-	memcpy(ac_info.key_value, pin, pin_len);
-	if (puk_len > 8)
-		puk_len = 8;
-	strncpy((char *) ac_info.unblock_value, (const char *) puk, puk_len);
-	r = sc_card_ctl(p15card->card, SC_CARDCTL_MIOCOS_CREATE_AC, &ac_info);
-        LOG_TEST_RET(ctx, r, "Miocos create AC failed");
-
-	LOG_FUNC_RETURN(ctx, SC_SUCCESS);
-}
-
-
-/*
- * Create private key file
- */
-static int
-miocos_create_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
-		struct sc_pkcs15_object *object)
-{
-	struct sc_context *ctx = p15card->card->ctx;
-	struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data;
-	struct sc_file *file;
-	int r;
-
-	SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
-	if (object->type != SC_PKCS15_TYPE_PRKEY_RSA)
-        	LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "MioCOS supports only 1024-bit RSA keys.");
-
-	if (key_info->modulus_length != 1024)
-        	LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "MioCOS supports only 1024-bit RSA keys.");
-
-        sc_log(ctx,  "create private key ID:%s\n",  sc_pkcs15_print_id(&key_info->id));
-	r = miocos_new_file(profile, p15card->card, SC_PKCS15_TYPE_PRKEY_RSA, key_info->key_reference, &file);
-        LOG_TEST_RET(ctx, r, "Cannot create key: failed to allocate new key object");
-
-        memcpy(&file->path, &key_info->path, sizeof(file->path));
-        file->id = file->path.value[file->path.len - 2] * 0x100
-			+ file->path.value[file->path.len - 1];
-
-        sc_log(ctx,  "Path of private key file to create %s\n", sc_print_path(&file->path));
-
-	r = sc_pkcs15init_create_file(profile, p15card, file);
-	sc_file_free(file);
-
-	LOG_FUNC_RETURN(ctx, r);
-}
-
-
-/*
- * Store a private key
- */
-static int
-miocos_store_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
-		struct sc_pkcs15_object *object,
-		struct sc_pkcs15_prkey *key)
-{
-	struct sc_context *ctx = p15card->card->ctx;
-	struct sc_pkcs15_prkey_info *key_info = (struct sc_pkcs15_prkey_info *)object->data;
-	struct sc_pkcs15_prkey_rsa *rsa;
-	struct sc_file *file = NULL;
-	int r;
-
-	SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
-	if (object->type != SC_PKCS15_TYPE_PRKEY_RSA
-			|| key->algorithm != SC_ALGORITHM_RSA)
-		LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "MioCOS supports only 1024-bit RSA keys.");
-
-	rsa = &key->u.rsa;
-	if (rsa->modulus.len != 128)
-		LOG_TEST_RET(ctx, SC_ERROR_NOT_SUPPORTED, "MioCOS supports only 1024-bit RSA keys.");
-
-        sc_log(ctx,  "store key with ID:%s and path:%s\n", sc_pkcs15_print_id(&key_info->id),
-			sc_print_path(&key_info->path));
-
-	r = sc_select_file(p15card->card, &key_info->path, &file);
-	LOG_TEST_RET(ctx, r, "Cannot store key: select key file failed");
-
-	r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE);
-	LOG_TEST_RET(ctx, r, "No authorisation to store private key");
-
-	r = miocos_update_private_key(profile, p15card->card, rsa);
-
-	LOG_FUNC_RETURN(ctx, r);
-}
-
-static struct sc_pkcs15init_operations sc_pkcs15init_miocos_operations = {
-	NULL,				/* erase_card */
-	NULL,				/* init_card  */
-	miocos_create_dir,
-	NULL,				/* create_domain */
-	miocos_select_pin_reference,
-	miocos_create_pin,
-	NULL,				/* select_key_reference */
-	miocos_create_key,
-	miocos_store_key,
-	NULL,				/* generate_key */
-	NULL, NULL,			/* encode private/public key */
-	NULL,				/* finalize_card */
-	NULL, 				/* delete_object */
-	NULL, NULL, NULL, NULL, NULL,	/* pkcs15init emulation */
-	NULL				/* sanity_check */
-};
-
-struct sc_pkcs15init_operations *sc_pkcs15init_get_miocos_ops(void)
-{
-	return &sc_pkcs15init_miocos_operations;
-}
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-muscle.c opensc-0.23.0/src/pkcs15init/pkcs15-muscle.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-muscle.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-muscle.c	2022-11-29 09:34:43.000000000 +0100
@@ -49,8 +49,11 @@
 	sc_format_path("3F00", &path);
 	if ((r = sc_select_file(p15card->card, &path, &file)) < 0)
 		return r;
-	if ((r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_ERASE)) < 0)
+	if ((r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_ERASE)) < 0) {
+		sc_file_free(file);
 		return r;
+	}
+	sc_file_free(file);
 	if ((r = sc_delete_file(p15card->card, &path)) < 0)
 		return r;
 	return 0;
@@ -72,8 +75,12 @@
 	sc_format_path("3F00", &path);
 	if ((r = sc_select_file(p15card->card, &path, &file)) < 0)
 		return r;
-	if ((r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_CREATE)) < 0)
+	if ((r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_CREATE)) < 0) {
+		sc_file_free(file);
 		return r;
+	}
+	sc_file_free(file);
+
 	/* Create the application DF */
 	if ((r = sc_pkcs15init_create_file(profile, p15card, df)) < 0)
 		return r;
@@ -97,10 +104,13 @@
 
 	if ((r = sc_select_file(p15card->card, &df->path, &file)) < 0)
 		return r;
-	if ((r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_WRITE)) < 0)
+	if ((r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_WRITE)) < 0) {
+		sc_file_free(file);
 		return r;
+	}
 
 	auth_info->attrs.pin.flags &= ~SC_PKCS15_PIN_FLAG_LOCAL;
+	sc_file_free(file);
 	return 0;
 }
 
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-myeid.c opensc-0.23.0/src/pkcs15init/pkcs15-myeid.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-myeid.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-myeid.c	2022-11-29 09:34:43.000000000 +0100
@@ -168,6 +168,8 @@
 	/* ACLs are not actives if file is not in the operational state */
 	if (mf->status == SC_FILE_STATUS_ACTIVATED)
 		r = sc_pkcs15init_authenticate(profile, p15card, mf, SC_AC_OP_DELETE);
+	if (r < 0)
+		sc_file_free(mf);
 	LOG_TEST_RET(ctx, r, "'DELETE' authentication failed on MF");
 
 	data_obj.P1 = 0x01;
@@ -176,6 +178,7 @@
 	data_obj.DataLen = sizeof (data);
 
 	r = sc_card_ctl(p15card->card, SC_CARDCTL_MYEID_PUTDATA, &data_obj);
+	sc_file_free(mf);
 
 	LOG_FUNC_RETURN(p15card->card->ctx, r);
 }
@@ -414,6 +417,11 @@
 	file->id += num;
 	p = &file->path;
 	*p = profile->df_info->file->path;
+	if (p->len >= SC_MAX_PATH_SIZE - 2) {
+		sc_log(card->ctx, "Wrong path length");
+		sc_file_free(file);
+		return SC_ERROR_INTERNAL;
+	}
 	p->value[p->len++] = (u8) (file->id / 256);
 	p->value[p->len++] = (u8) (file->id % 256);
 
@@ -595,8 +603,10 @@
 	r = myeid_new_file(profile, card, object->type, *key_reference, &file);
 	LOG_TEST_RET(ctx, r, "Cannot get new MyEID key file");
 
-	if (!file || !file->path.len)
+	if (!file || !file->path.len || file->path.len > SC_MAX_PATH_SIZE) {
+		sc_file_free(file);
 		LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "Cannot determine key file");
+	}
 
 	sc_log(ctx, "Key file size %d", keybits);
 	file->size = keybits;
@@ -810,6 +820,8 @@
 	LOG_TEST_RET(ctx, r, "Cannot generate key: failed to select key file");
 
 	r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_GENERATE);
+	if (r < 0)
+		sc_file_free(file);
 	LOG_TEST_RET(ctx, r, "No authorisation to generate private key");
 
 	/* Fill in data structure */
@@ -826,6 +838,8 @@
 
 	/* Generate the key  */
 	r = sc_card_ctl(card, SC_CARDCTL_MYEID_GENERATE_STORE_KEY, &args);
+	if (r < 0)
+		sc_file_free(file);
 	LOG_TEST_RET(ctx, r, "Card control 'MYEID_GENERATE_STORE_KEY' failed");
 
 	/* Key pair generation -> collect public key info */
@@ -842,6 +856,8 @@
 
 			/* Get public key modulus */
 			r = sc_select_file(card, &file->path, NULL);
+			sc_file_free(file);
+			file = NULL;
 			LOG_TEST_RET(ctx, r, "Cannot get key modulus: select key file failed");
 
 			data_obj.P1 = 0x01;
@@ -867,6 +883,8 @@
 			pubkey->algorithm = SC_ALGORITHM_EC;
 
 			r = sc_select_file(card, &file->path, NULL);
+			sc_file_free(file);
+			file = NULL;
 			LOG_TEST_RET(ctx, r, "Cannot get public key: select key file failed");
 
 			data_obj.P1 = 0x01;
@@ -906,9 +924,14 @@
 			pubkey->u.ec.params.der.len = 0;
 
 			pubkey->u.ec.params.named_curve = strdup(ecparams->named_curve);
-			if (!pubkey->u.ec.params.named_curve)
+			if (!pubkey->u.ec.params.named_curve) {
+				free(pubkey->u.ec.ecpointQ.value);
 				LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
+			}
+
 			r = sc_pkcs15_fix_ec_parameters(ctx, &pubkey->u.ec.params);
+			if (r < 0)
+				free(pubkey->u.ec.ecpointQ.value);
 			LOG_TEST_RET(ctx, r, "Cannot fix EC parameters");
 		}
 	}
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-oberthur-awp.c opensc-0.23.0/src/pkcs15init/pkcs15-oberthur-awp.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-oberthur-awp.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-oberthur-awp.c	2022-11-29 09:34:43.000000000 +0100
@@ -769,10 +769,6 @@
 	int r = 0;
 
 	LOG_FUNC_CALLED(ctx);
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-	ERR_load_ERR_strings();
-#endif
-	ERR_load_crypto_strings();
 
 	key_info = (struct sc_pkcs15_prkey_info *)obj->data;
 
@@ -829,10 +825,6 @@
 
 	sc_log(ctx,  "cosm_encode_key_info() label:%s",ki->label.value);
 done:
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-	ERR_load_ERR_strings();
-#endif
-	ERR_load_crypto_strings();
 	LOG_FUNC_RETURN(ctx, r);
 }
 
@@ -937,11 +929,6 @@
 
 	LOG_FUNC_CALLED(ctx);
 
-#if OPENSSL_VERSION_NUMBER < 0x30000000L
-	ERR_load_ERR_strings();
-#endif
-	ERR_load_crypto_strings();
-
 	if (!obj || !ci)
 		LOG_TEST_RET(ctx, SC_ERROR_INVALID_ARGUMENTS, "AWP encode cert failed: invalid parameters");
 
@@ -1078,10 +1065,9 @@
 err:
 	ERR_print_errors_fp(stderr);
 	ERR_clear_error();
-	ERR_free_strings();
 	if (pubkey.exponent.data) free(pubkey.exponent.data);
 	if (pubkey.modulus.data) free(pubkey.modulus.data);
-	if (x) 		X509_free(x);
+	if (x) X509_free(x);
 	if (mem)	BIO_free(mem);
 	if (buff)	OPENSSL_free(buff);
 
@@ -1469,11 +1455,12 @@
 	rv = sc_pkcs15_find_cert_by_id(p15card, &key_info->id, &cert_obj);
 	if (!rv)   {
 		struct sc_pkcs15_cert_info *cert_info = (struct sc_pkcs15_cert_info *) cert_obj->data;
+		int private_obj = cert_obj->flags & SC_PKCS15_CO_FLAG_PRIVATE;
 
 		path = cert_info->path;
 		cc.cert_id = (path.value[path.len-1] & 0xFF) + (path.value[path.len-2] & 0xFF) * 0x100;
 
-		rv = sc_pkcs15_read_certificate(p15card, cert_info, &p15cert);
+		rv = sc_pkcs15_read_certificate(p15card, cert_info, private_obj, &p15cert);
 		SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE, rv, "AWP 'update private key' DF failed:  cannot get certificate");
 
 		rv = sc_pkcs15_allocate_object_content(ctx, cert_obj, p15cert->data.value, p15cert->data.len);
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-oberthur.c opensc-0.23.0/src/pkcs15init/pkcs15-oberthur.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-oberthur.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-oberthur.c	2022-11-29 09:34:43.000000000 +0100
@@ -1,7 +1,7 @@
 /*
  * Oberthur specific operation for PKCS #15 initialization
  *
- * Copyright (C) 2002  Juha Yrjölä <juha.yrjola at iki.fi>
+ * Copyright (C) 2002  Juha Yrjölä <juha.yrjola at iki.fi>
  * Copyright (C) 2009  Viktor Tarasov <viktor.tarasov at opentrust.com>,
  *                     OpenTrust <www.opentrust.com>
  *
@@ -277,7 +277,7 @@
 	};
 
 	SC_FUNC_CALLED(ctx, SC_LOG_DEBUG_VERBOSE);
-	sc_log(ctx, 
+	sc_log(ctx,
 		 "pin lens %"SC_FORMAT_LEN_SIZE_T"u/%"SC_FORMAT_LEN_SIZE_T"u",
 		 pin_len, puk_len);
 	if (!pin || pin_len>0x40)
@@ -497,10 +497,6 @@
 			_template = "template-public-key";
 			structure = SC_CARDCTL_OBERTHUR_KEY_RSA_PUBLIC;
 			break;
-		case SC_PKCS15_TYPE_PUBKEY_DSA:
-			desc = "DSA public key";
-			_template = "template-public-key";
-			break;
 		case SC_PKCS15_TYPE_CERT:
 			desc = "certificate";
 			_template = "template-certificate";
@@ -537,7 +533,7 @@
 		file->ef_structure = structure;
 	}
 
-	sc_log(card->ctx, 
+	sc_log(card->ctx,
 		 "cosm_new_file() file size %"SC_FORMAT_LEN_SIZE_T"u; ef type %i/%i; id %04X",
 		 file->size, file->type, file->ef_structure, file->id);
 	*out = file;
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-openpgp.c opensc-0.23.0/src/pkcs15init/pkcs15-openpgp.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-openpgp.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-openpgp.c	2022-11-29 09:34:43.000000000 +0100
@@ -443,6 +443,7 @@
 	case SC_PKCS15_TYPE_CERT:
 		cinfo = (sc_pkcs15_cert_info_t *) obj->data;
 		cid = &(cinfo->id);
+		unsigned int tag = 0x7F21;
 
 		if (cid->len != 1) {
 			sc_log(card->ctx, "ID=%s is not valid.", sc_dump_hex(cid->value, cid->len));
@@ -450,22 +451,37 @@
 		}
 
 		/* OpenPGP card v.2 contains only 1 certificate */
-		if (cid->value[0] != 3) {
+		if (cid->value[0] != 3 && p15card->card->type < SC_CARD_TYPE_OPENPGP_V3) {
 			sc_log(card->ctx,
 			       "This version does not support certificate ID = %d (only ID=3 is supported).",
 			       cid->value[0]);
 			LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
 		}
-		/* Just update the certificate DO */
+
+		/* OpenPGP card < v.3 does not support SELECT DATA calls */
+		if (p15card->card->type >= SC_CARD_TYPE_OPENPGP_V3) {
+			/* Mapping [3..1] passed --id to [0..2] for param */
+			u8 param = (u8) (2 - (cid->value[0] - 1));
+			/* check for unsigned underflow */
+			if (param > 2) {
+				LOG_FUNC_RETURN(card->ctx, SC_ERROR_NOT_SUPPORTED);
+			}
+
+			/* Just update the certificate DO */
+			r = sc_card_ctl(card, SC_CARDCTL_OPENPGP_SELECT_DATA, &param);
+			LOG_TEST_RET(card->ctx, r, "Failed OpenPGP - select data");
+		}
+
 		sc_format_path("7F21", path);
 		r = sc_select_file(card, path, &file);
+
 		LOG_TEST_RET(card->ctx, r, "Cannot select cert file");
 		r = sc_pkcs15init_authenticate(profile, p15card, file, SC_AC_OP_UPDATE);
 		sc_log(card->ctx,
 		       "Data to write is %"SC_FORMAT_LEN_SIZE_T"u long",
 		       content->len);
 		if (r >= 0 && content->len)
-			r = sc_put_data(p15card->card, 0x7F21, (const unsigned char *) content->value, content->len);
+			r = sc_put_data(p15card->card, tag, (const unsigned char *) content->value, content->len);
 		break;
 
 	case SC_PKCS15_TYPE_DATA_OBJECT:
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15.profile opensc-0.23.0/src/pkcs15init/pkcs15.profile
--- opensc-0.22.0/src/pkcs15init/pkcs15.profile	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15.profile	2022-11-29 09:34:43.000000000 +0100
@@ -24,7 +24,7 @@
     do-last-update	= yes;
     # Method to calculate ID of the crypto objects
     #     native: 'E' + number_of_present_objects_of_the_same_type
-    #     mozilla: SHA1(modulus) for RSA, SHA1(pub) for DSA
+    #     mozilla: SHA1(modulus) for RSA
     #     rfc2459: SHA1(SequenceASN1 of public key components as ASN1 integers)
     # default value: 'native'
     pkcs15-id-style	= mozilla;
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-rtecp.c opensc-0.23.0/src/pkcs15init/pkcs15-rtecp.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-rtecp.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-rtecp.c	2022-11-29 09:34:43.000000000 +0100
@@ -120,6 +120,8 @@
 	create_sysdf(profile, card, "Resrv2-DF");
 	create_sysdf(profile, card, "Resrv3-DF");
 	create_sysdf(profile, card, "Resrv4-DF");
+	create_sysdf(profile, card, "Resrv5-DF");
+	create_sysdf(profile, card, "Resrv6-DF");
 
 	return sc_select_file(card, sc_get_mf_path(), NULL);
 }
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-sc-hsm.c opensc-0.23.0/src/pkcs15init/pkcs15-sc-hsm.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-sc-hsm.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-sc-hsm.c	2022-11-29 09:34:43.000000000 +0100
@@ -265,8 +265,11 @@
 	memset(&cvc, 0, sizeof(cvc));
 
 	strlcpy(cvc.car, "UTCA00001", sizeof cvc.car);
-	strlcpy(cvc.chr, priv->serialno, sizeof cvc.chr);
+	cvc.carLen = strlen(cvc.car);
+	if (priv->serialno)
+		strlcpy(cvc.chr, priv->serialno, sizeof cvc.chr);
 	strlcat(cvc.chr, "00001", sizeof cvc.chr);
+	cvc.chrLen = strlen(cvc.chr);
 
 	switch(object->type) {
 	case SC_PKCS15_TYPE_PRKEY_RSA:
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-setcos.c opensc-0.23.0/src/pkcs15init/pkcs15-setcos.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-setcos.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-setcos.c	2022-11-29 09:34:43.000000000 +0100
@@ -181,10 +181,13 @@
 	/* sc_pkcs15init_create_pin() starts checking if -1 is an acceptable
 	 * pin reference, which isn't for the SetCOS cards. And since the
 	 * value 1 has been assigned to the SO pin, we'll jump to 2. */
-	else if (auth_info->attrs.pin.reference <= 0)
+	else if (auth_info->attrs.pin.reference <= 0) {
+		if (auth_info_prof.attrs.pin.reference != 1)
+			return SC_ERROR_INVALID_PIN_REFERENCE;
 		auth_info->attrs.pin.reference = auth_info_prof.attrs.pin.reference + 1;
+	}
 
-	return 0;
+	return SC_SUCCESS;
 }
 
 /*
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-starcos.c opensc-0.23.0/src/pkcs15init/pkcs15-starcos.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-starcos.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-starcos.c	2022-11-29 09:34:43.000000000 +0100
@@ -798,7 +798,7 @@
 	sc_starcos_wkey_data tkey;
 
 	if (key->algorithm != SC_ALGORITHM_RSA)
-		/* ignore DSA keys */
+		/* ignore non-RSA keys */
 		return SC_ERROR_INVALID_ARGUMENTS;
 
 	/* create sc_starcos_wkey_data */
diff -Nru opensc-0.22.0/src/pkcs15init/pkcs15-westcos.c opensc-0.23.0/src/pkcs15init/pkcs15-westcos.c
--- opensc-0.22.0/src/pkcs15init/pkcs15-westcos.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/pkcs15-westcos.c	2022-11-29 09:34:43.000000000 +0100
@@ -32,6 +32,9 @@
 #include <openssl/pem.h>
 #include <openssl/err.h>
 #include <openssl/bio.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+ #include <openssl/encoder.h>
+#endif
 #endif
 
 #include "libopensc/sc-ossl-compat.h"
@@ -217,42 +220,63 @@
 	long lg;
 	u8 *p;
 	sc_pkcs15_prkey_info_t *key_info = (sc_pkcs15_prkey_info_t *) obj->data;
-	RSA *rsa = NULL;
 	BIGNUM *bn = NULL;
 	BIO *mem = NULL;
-
+	EVP_PKEY *key = NULL;
+	EVP_PKEY_CTX *pctx = NULL;
 	sc_file_t *prkf = NULL;
 
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	OSSL_ENCODER_CTX *ectx = NULL;
+	int selection = 0;
+#endif
+
 	if (obj->type != SC_PKCS15_TYPE_PRKEY_RSA) {
 		return SC_ERROR_NOT_SUPPORTED;
 	}
 
-	rsa = RSA_new();
-	bn = BN_new();
+	pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
 	mem = BIO_new(BIO_s_mem());
-
-	if(rsa == NULL || bn == NULL || mem == NULL)
-	{
+	bn = BN_new();
+	if (pctx == NULL || mem == NULL || bn == NULL) {
 		r = SC_ERROR_OUT_OF_MEMORY;
 		goto out;
 	}
 
-	if(!BN_set_word(bn, RSA_F4) ||
-		!RSA_generate_key_ex(rsa, key_info->modulus_length, bn, NULL))
-	{
+	if (BN_set_word(bn, RSA_F4) != 1 ||
+	    EVP_PKEY_keygen_init(pctx) != 1 ||
+	    EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, key_info->modulus_length) != 1 ||
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	    EVP_PKEY_CTX_set1_rsa_keygen_pubexp(pctx, bn) != 1) {
+#else
+	    EVP_PKEY_CTX_set_rsa_keygen_pubexp(pctx, bn) != 1) {
+#endif
+		r = SC_ERROR_UNKNOWN;
+		goto out;
+	}
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	bn = NULL; /* pctx will free bn */
+#endif
+	if (EVP_PKEY_keygen(pctx, &key) != 1) {
 		r = SC_ERROR_UNKNOWN;
 		goto out;
 	}
 
-	RSA_set_method(rsa, RSA_PKCS1_OpenSSL());
-
-	if(pubkey != NULL)
-	{
-		if(!i2d_RSAPublicKey_bio(mem, rsa))
+	if(pubkey != NULL) {
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+		if(!i2d_RSAPublicKey_bio(mem, EVP_PKEY_get0_RSA(key)))
+#else
+		selection = OSSL_KEYMGMT_SELECT_PUBLIC_KEY;
+		ectx = OSSL_ENCODER_CTX_new_for_pkey(key, selection, "DER", "PublicKeyInfo", NULL);
+		if(ectx == NULL || OSSL_ENCODER_to_bio(ectx, mem) != 1)
+#endif
 		{
 			r = SC_ERROR_UNKNOWN;
 			goto out;
 		}
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	OSSL_ENCODER_CTX_free(ectx);
+#endif
 
 		lg = BIO_get_mem_data(mem, &p);
 
@@ -265,7 +289,7 @@
 
 	(void) BIO_reset(mem);
 
-	if(!i2d_RSAPrivateKey_bio(mem, rsa))
+	if (!i2d_PrivateKey_bio(mem, key))
 	{
 		r = SC_ERROR_UNKNOWN;
 		goto out;
@@ -299,10 +323,9 @@
 		BIO_free(mem);
 	if(bn)
 		BN_free(bn);
-	if(rsa)
-		RSA_free(rsa);
+	EVP_PKEY_CTX_free(pctx);
+	EVP_PKEY_free(key);
 	sc_file_free(prkf);
-
 	return r;
 #endif
 }
diff -Nru opensc-0.22.0/src/pkcs15init/profile.c opensc-0.23.0/src/pkcs15init/profile.c
--- opensc-0.22.0/src/pkcs15init/profile.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/profile.c	2022-11-29 09:34:43.000000000 +0100
@@ -50,7 +50,6 @@
 #include "profile.h"
 
 #define DEF_PRKEY_RSA_ACCESS	0x1D
-#define DEF_PRKEY_DSA_ACCESS	0x12
 #define DEF_PUBKEY_ACCESS	0x12
 
 #define TEMPLATE_FILEID_MIN_DIFF	0x20
@@ -309,9 +308,8 @@
 		p15card->file_unusedspace = init_file(SC_FILE_TYPE_WORKING_EF);
 	}
 
-	/* Assume card does RSA natively, but no DSA */
+	/* Assume card does RSA natively */
 	pro->rsa_access_flags = DEF_PRKEY_RSA_ACCESS;
-	pro->dsa_access_flags = DEF_PRKEY_DSA_ACCESS;
 	pro->pin_encoding = SC_PKCS15_PIN_TYPE_ASCII_NUMERIC;
 	pro->pin_minlen = 4;
 	pro->pin_maxlen = 8;
@@ -452,6 +450,8 @@
 
 	if (profile->name)
 		free(profile->name);
+	if (profile->driver)
+		free(profile->driver);
 
 	free_file_list(&profile->ef_list);
 
@@ -483,6 +483,10 @@
 		free(pi);
 	}
 
+	for (int i = 0; profile->options[i]; i++) {
+		free(profile->options[i]);
+	}
+
 	if (profile->p15_spec)
 		sc_pkcs15_card_free(profile->p15_spec);
 	free(profile);
@@ -574,7 +578,7 @@
 	if ((fi = sc_profile_find_file(profile, NULL, name)) == NULL)
 		LOG_FUNC_RETURN(ctx, SC_ERROR_FILE_NOT_FOUND);
 	sc_file_dup(&file, fi->file);
-	sc_log(ctx, "ident '%s'; parent '%s'", fi->ident, fi->parent->ident);
+	sc_log(ctx, "ident '%s'; parent '%s'", fi->ident, fi->parent ? fi->parent->ident : "(null)");
 	if (file == NULL)
 		LOG_FUNC_RETURN(ctx, SC_ERROR_OUT_OF_MEMORY);
 	sc_log(ctx, "file (type:%X, path:'%s')", file->type, sc_print_path(&file->path));
@@ -831,6 +835,7 @@
 static int
 do_card_driver(struct state *cur, int argc, char **argv)
 {
+	free(cur->profile->driver);
 	cur->profile->driver = strdup(argv[0]);
 	return 0;
 }
@@ -1059,19 +1064,34 @@
 
 	for (fi = templ->ef_list; fi; fi = fi->next) {
 		struct sc_path fi_path =  fi->file->path;
-		int fi_id = fi_path.value[fi_path.len - 2] * 0x100
-			+ fi_path.value[fi_path.len - 1];
+		int fi_id;
 
 		if (fi->file->type == SC_FILE_TYPE_BSO)
 			continue;
+
+		if (fi_path.len < 2) {
+			parse_error(cur, "Template insane: file-path length should not be less than 2 bytes");
+			return 1;
+		}
+
+		fi_id = fi_path.value[fi_path.len - 2] * 0x100
+				+ fi_path.value[fi_path.len - 1];
+
 		for (ffi = templ->ef_list; ffi; ffi = ffi->next) {
 			struct sc_path ffi_path =  ffi->file->path;
-			int dlt, ffi_id = ffi_path.value[ffi_path.len - 2] * 0x100
-				+ ffi_path.value[ffi_path.len - 1];
+			int dlt, ffi_id;
 
 			if (ffi->file->type == SC_FILE_TYPE_BSO)
 				continue;
 
+			if (ffi_path.len < 2) {
+				parse_error(cur, "Template insane: file-path length should not be less than 2 bytes");
+				return 1;
+			}
+
+			ffi_id = ffi_path.value[ffi_path.len - 2] * 0x100
+					+ ffi_path.value[ffi_path.len - 1];
+
 			dlt = fi_id > ffi_id ? fi_id - ffi_id : ffi_id - fi_id;
 			if (strcmp(ffi->ident, fi->ident))   {
 				if (dlt >= TEMPLATE_FILEID_MIN_DIFF)
@@ -1186,6 +1206,7 @@
 
 		if (fi->dont_free == 0)
 			sc_file_free(fi->file);
+		free(fi->profile_extension);
 		free(fi->ident);
 		free(fi);
 	}
@@ -1202,6 +1223,7 @@
 	struct file_info	*info;
 	sc_file_t	*file;
 	unsigned int	df_type = 0, dont_free = 0;
+	int	free_file = 0;
 
 	if ((info = sc_profile_find_file(profile, NULL, name)) != NULL)
 		return info;
@@ -1210,23 +1232,39 @@
 	 * by the PKCS15 logic */
 	if (strncasecmp(name, "PKCS15-", 7)) {
 		file = init_file(type);
+		free_file = 1;
 	} else if (!strcasecmp(name+7, "TokenInfo")) {
+		if (!profile->p15_spec) {
+			parse_error(cur, "no pkcs15 spec in profile");
+			return NULL;
+		}
 		file = profile->p15_spec->file_tokeninfo;
 		dont_free = 1;
 	} else if (!strcasecmp(name+7, "ODF")) {
+		if (!profile->p15_spec) {
+			parse_error(cur, "no pkcs15 spec in profile");
+			return NULL;
+		}
 		file = profile->p15_spec->file_odf;
 		dont_free = 1;
 	} else if (!strcasecmp(name+7, "UnusedSpace")) {
+		if (!profile->p15_spec) {
+			parse_error(cur, "no pkcs15 spec in profile");
+			return NULL;
+		}
 		file = profile->p15_spec->file_unusedspace;
 		dont_free = 1;
 	} else if (!strcasecmp(name+7, "AppDF")) {
 		file = init_file(SC_FILE_TYPE_DF);
+		free_file = 1;
 	} else {
-		if (map_str2int(cur, name+7, &df_type, pkcs15DfNames))
+		if (map_str2int(cur, name+7, &df_type, pkcs15DfNames)
+				|| df_type >= SC_PKCS15_DF_TYPE_COUNT)
 			return NULL;
 
 		file = init_file(SC_FILE_TYPE_WORKING_EF);
 		profile->df[df_type] = file;
+		free_file = 1;
 	}
 	assert(file);
 	if (file->type != type) {
@@ -1234,8 +1272,7 @@
 			file->type == SC_FILE_TYPE_DF
 				? "DF" : file->type == SC_FILE_TYPE_BSO
 					? "BS0" : "EF");
-		if (strncasecmp(name, "PKCS15-", 7) ||
-			!strcasecmp(name+7, "AppDF"))
+		if (free_file)
 			sc_file_free(file);
 		return NULL;
 	}
@@ -1254,6 +1291,11 @@
 {
 	unsigned int	type;
 
+	if (!cur->file) {
+		parse_error(cur, "Invalid state\n");
+		return 1;
+	}
+
 	if (map_str2int(cur, argv[0], &type, fileTypeNames))
 		return 1;
 	cur->file->file->type = type;
@@ -1263,8 +1305,15 @@
 static int
 do_file_path(struct state *cur, int argc, char **argv)
 {
-	struct sc_file	*file = cur->file->file;
-	struct sc_path	*path = &file->path;
+	struct sc_file	*file = NULL;
+	struct sc_path	*path = NULL;
+
+	if (!cur->file) {
+		parse_error(cur, "Invalid state\n");
+		return 1;
+	}
+	file = cur->file->file;
+	path = &file->path;
 
 	/* sc_format_path doesn't return an error indication
 	 * when it's unable to parse the path */
@@ -1281,8 +1330,15 @@
 do_fileid(struct state *cur, int argc, char **argv)
 {
 	struct file_info *fi;
-	struct sc_file	*df, *file = cur->file->file;
-	struct sc_path	temp, *path = &file->path;
+	struct sc_file	*df, *file = NULL;
+	struct sc_path	temp, *path = NULL;
+
+	if (!cur->file) {
+		parse_error(cur, "Invalid state\n");
+		return 1;
+	}
+	file = cur->file->file;
+	path = &file->path;
 
 	/* sc_format_path doesn't return an error indication
 	 * when it's unable to parse the path */
@@ -1304,6 +1360,10 @@
 		}
 		*path = df->path;
 	}
+	if (path->len + 2 > sizeof(path->value)) {
+		parse_error(cur, "File path too long\n");
+		return 1;
+	}
 	memcpy(path->value + path->len, temp.value, 2);
 	path->len += 2;
 
@@ -1316,6 +1376,11 @@
 {
 	unsigned int	ef_structure;
 
+	if (!cur->file) {
+		parse_error(cur, "Invalid state\n");
+		return 1;
+	}
+
 	if (map_str2int(cur, argv[0], &ef_structure, fileStructureNames))
 		return 1;
 	cur->file->file->ef_structure = ef_structure;
@@ -1327,6 +1392,11 @@
 {
 	unsigned int	size;
 
+	if (!cur->file) {
+		parse_error(cur, "Invalid state\n");
+		return 1;
+	}
+
 	if (get_uint_eval(cur, argc, argv, &size))
 		return 1;
 	cur->file->file->size = size;
@@ -1338,6 +1408,11 @@
 {
 	unsigned int	reclength;
 
+	if (!cur->file) {
+		parse_error(cur, "Invalid state\n");
+		return 1;
+	}
+
 	if (get_uint(cur, argv[0], &reclength))
 		return 1;
 	cur->file->file->record_length = reclength;
@@ -1347,10 +1422,18 @@
 static int
 do_content(struct state *cur, int argc, char **argv)
 {
-	struct sc_file *file = cur->file->file;
+	struct sc_file *file = NULL;
 	size_t len = (strlen(argv[0]) + 1) / 2;
 	int rv = 0;
 
+	if (!cur->file) {
+		parse_error(cur, "Invalid state\n");
+		return 1;
+	}
+	file = cur->file->file;
+
+	free(file->encoded_content);
+
 	file->encoded_content = malloc(len);
 	if (!file->encoded_content)
 		return 1;
@@ -1362,10 +1445,17 @@
 static int
 do_prop_attr(struct state *cur, int argc, char **argv)
 {
-	struct sc_file *file = cur->file->file;
+	struct sc_file *file = NULL;
 	size_t len = (strlen(argv[0]) + 1) / 2;
 	int rv = 0;
 
+	if (!cur->file) {
+		parse_error(cur, "Invalid state\n");
+		return 1;
+	}
+	file = cur->file->file;
+
+	free(file->prop_attr);
 	file->prop_attr = malloc(len);
 	if (!file->prop_attr)
 		return 1;
@@ -1377,11 +1467,17 @@
 static int
 do_aid(struct state *cur, int argc, char **argv)
 {
-	struct sc_file	*file = cur->file->file;
+	struct sc_file	*file = NULL;
 	const char	*name = argv[0];
 	unsigned int	len;
 	int		res = 0;
 
+	if (!cur->file) {
+		parse_error(cur, "Invalid state\n");
+		return 1;
+	}
+	file = cur->file->file;
+
 	if (*name == '=') {
 		len = strlen(++name);
 		if (len > sizeof(file->name)) {
@@ -1401,11 +1497,17 @@
 static int
 do_exclusive_aid(struct state *cur, int argc, char **argv)
 {
-	struct sc_file	*file = cur->file->file;
+	struct sc_file	*file = NULL;
 	const char	*name = argv[0];
 	unsigned int	len;
 	int		res = 0;
 
+	if (!cur->file) {
+		parse_error(cur, "Invalid state\n");
+		return 1;
+	}
+	file = cur->file->file;
+
 #ifdef DEBUG_PROFILE
 	printf("do_exclusive_aid(): exclusive-aid '%s'\n", name);
 	printf("do_exclusive_aid(): current file '%s' (path:%s)\n", cur->file->ident, sc_print_path(&file->path));
@@ -1444,6 +1546,10 @@
 static int
 do_profile_extension(struct state *cur, int argc, char **argv)
 {
+	if (!cur->file) {
+		parse_error(cur, "Invalid state\n");
+		return 1;
+	}
 	return setstr(&cur->file->profile_extension, argv[0]);
 }
 
@@ -1458,10 +1564,14 @@
 static int
 do_acl(struct state *cur, int argc, char **argv)
 {
-	struct sc_file	*file = cur->file->file;
+	struct sc_file	*file = NULL;
 	char		oper[64], *what = NULL;
-
 	memset(oper, 0, sizeof(oper));
+
+	if (!cur->file)
+		goto bad;
+	file = cur->file->file;
+
 	while (argc--) {
 		unsigned int	op, method, id;
 
@@ -1489,7 +1599,8 @@
 
 			if (map_str2int(cur, oper, &op, fileOpNames))
 				goto bad;
-			acl = sc_file_get_acl_entry(file, op);
+			if (!(acl = sc_file_get_acl_entry(file, op)))
+				goto bad;
 			if (acl->method == SC_AC_NEVER
 			 || acl->method == SC_AC_NONE
 			 || acl->method == SC_AC_UNKNOWN)
@@ -1583,6 +1694,7 @@
 static int
 do_pin_file(struct state *cur, int argc, char **argv)
 {
+	free(cur->pin->file_name);
 	cur->pin->file_name = strdup(argv[0]);
 	return 0;
 }
@@ -1717,7 +1829,7 @@
 
 	for (item = blk->items; item; item = item->next) {
 		name = item->key;
-		if (item->type != SCCONF_ITEM_TYPE_VALUE)
+		if (item->type != SCCONF_ITEM_TYPE_VALUE || !name)
 			continue;
 #ifdef DEBUG_PROFILE
 		printf("Defining %s\n", name);
@@ -1864,6 +1976,24 @@
 };
 
 static int
+check_macro_reference_loop(scconf_list *start, scconf_list *current, struct state *cur) {
+	sc_macro_t *mac = NULL;
+	const char *str = NULL;
+
+	if (!start || !current || !cur)
+		return 0;
+
+	str = current->data;
+	if (str[0] != '$')
+		return 0;
+	if (!(mac = find_macro(cur->profile, str + 1)))
+		return 0;
+	if (!strcmp(mac->name, start->data + 1))
+		return 1;
+	return check_macro_reference_loop(start, mac->value, cur);
+}
+
+static int
 build_argv(struct state *cur, const char *cmdname,
 		scconf_list *list, char **argv, unsigned int max)
 {
@@ -1891,6 +2021,12 @@
 			return SC_ERROR_SYNTAX_ERROR;
 		}
 
+		if (list == mac->value) {
+			return SC_ERROR_SYNTAX_ERROR;
+		}
+		if (check_macro_reference_loop(list, mac->value, cur)) {
+			return SC_ERROR_SYNTAX_ERROR;
+		}
 #ifdef DEBUG_PROFILE
 		{
 			scconf_list *list;
@@ -1970,6 +2106,10 @@
 		cmd = item->key;
 		if (item->type == SCCONF_ITEM_TYPE_COMMENT)
 			continue;
+		if (!cmd) {
+			parse_error(cur, "Command can not be processed.");
+			return SC_ERROR_SYNTAX_ERROR;
+		}
 		if (item->type == SCCONF_ITEM_TYPE_BLOCK) {
 			scconf_list *nlist;
 
@@ -2024,12 +2164,14 @@
 {
 	struct file_info	*fi;
 	unsigned int		len;
+	const u8			*value;
 
-	len = path? path->len : 0;
+	value = path ? path->value : (const u8*) "";
+	len = path ? path->len : 0;
 	for (fi = pro->ef_list; fi; fi = fi->next) {
 		sc_path_t *fpath = &fi->file->path;
 
-		if (!strcasecmp(fi->ident, name) && fpath->len >= len && !memcmp(fpath->value, path->value, len))
+		if (!strcasecmp(fi->ident, name) && fpath->len >= len && !memcmp(fpath->value, value, len))
 			return fi;
 	}
 	return NULL;
@@ -2232,7 +2374,7 @@
 	char **		argv;
 };
 
-static void	expr_eval(struct num_exp_ctx *, unsigned int *, unsigned int);
+static void	expr_eval(struct num_exp_ctx *, unsigned int *, unsigned int, int);
 
 static void
 expr_fail(struct num_exp_ctx *ctx)
@@ -2259,8 +2401,9 @@
 	}
 
 	ctx->j = 0;
+	s = ctx->str;
 	do {
-		if ((s = ctx->str) == NULL || *s == '\0') {
+		if (s == NULL || *s == '\0') {
 			if (ctx->argc == 0) {
 				if (eof_okay)
 					return NULL;
@@ -2319,14 +2462,19 @@
 		expr_fail(ctx);
 }
 
+#define MAX_BRACKETS 32
 static void
-expr_term(struct num_exp_ctx *ctx, unsigned int *vp)
+expr_term(struct num_exp_ctx *ctx, unsigned int *vp, int opening_brackets)
 {
 	char	*tok;
 
 	tok = expr_get(ctx);
 	if (*tok == '(') {
-		expr_eval(ctx, vp, 1);
+		if (opening_brackets + 1 > MAX_BRACKETS) {
+			parse_error(ctx->state, "Too many \"%s\" in expression", tok);
+			expr_fail(ctx);
+		}
+		expr_eval(ctx, vp, 1, opening_brackets + 1);
 		expr_expect(ctx, ')');
 	}
 	else if (isdigit((unsigned char)*tok)) {
@@ -2354,12 +2502,12 @@
 }
 
 static void
-expr_eval(struct num_exp_ctx *ctx, unsigned int *vp, unsigned int pri)
+expr_eval(struct num_exp_ctx *ctx, unsigned int *vp, unsigned int pri, int opening_brackets)
 {
 	unsigned int	left, right, new_pri;
 	char		*tok, op;
 
-	expr_term(ctx, &left);
+	expr_term(ctx, &left, opening_brackets);
 
 	while (1) {
 		tok = __expr_get(ctx, 1);
@@ -2396,10 +2544,13 @@
 		}
 		pri = new_pri;
 
-		expr_eval(ctx, &right, new_pri + 1);
+		expr_eval(ctx, &right, new_pri + 1, opening_brackets);
 		switch (op) {
 		case '*': left *= right; break;
-		case '/': left /= right; break;
+		case '/':
+			if (right == 0)
+				expr_fail(ctx);
+			left /= right; break;
 		case '+': left += right; break;
 		case '-': left -= right; break;
 		case '&': left &= right; break;
@@ -2426,7 +2577,7 @@
 		return SC_ERROR_SYNTAX_ERROR;
 	}
 
-	expr_eval(&ctx, vp, 0);
+	expr_eval(&ctx, vp, 0, 0);
 	if (ctx.str[0] || ctx.argc)
 		expr_fail(&ctx);
 
diff -Nru opensc-0.22.0/src/pkcs15init/profile.h opensc-0.23.0/src/pkcs15init/profile.h
--- opensc-0.22.0/src/pkcs15init/profile.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/profile.h	2022-11-29 09:34:43.000000000 +0100
@@ -120,7 +120,6 @@
 	unsigned int		pin_attempts;
 	unsigned int		puk_attempts;
 	unsigned int		rsa_access_flags;
-	unsigned int		dsa_access_flags;
 
 	struct {
 		unsigned int	direct_certificates;
diff -Nru opensc-0.22.0/src/pkcs15init/rutoken_ecp.profile opensc-0.23.0/src/pkcs15init/rutoken_ecp.profile
--- opensc-0.22.0/src/pkcs15init/rutoken_ecp.profile	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/rutoken_ecp.profile	2022-11-29 09:34:43.000000000 +0100
@@ -110,6 +110,14 @@
 
             DF Resrv1-DF {
                 file-id = 1001;
+
+                DF Resrv5-DF {
+                    file-id = 8001;
+                }
+
+                DF Resrv6-DF {
+                    file-id = 8002;
+                }
             }
             DF Resrv2-DF {
                 file-id = 1002;
diff -Nru opensc-0.22.0/src/pkcs15init/rutoken_lite.profile opensc-0.23.0/src/pkcs15init/rutoken_lite.profile
--- opensc-0.22.0/src/pkcs15init/rutoken_lite.profile	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/pkcs15init/rutoken_lite.profile	2022-11-29 09:34:43.000000000 +0100
@@ -90,6 +90,14 @@
 
             DF Resrv1-DF {
                 file-id = 1001;
+
+                DF Resrv5-DF {
+                    file-id = 8001;
+                }
+
+                DF Resrv6-DF {
+                    file-id = 8002;
+                }
             }
             DF Resrv2-DF {
                 file-id = 1002;
diff -Nru opensc-0.22.0/src/scconf/internal.h opensc-0.23.0/src/scconf/internal.h
--- opensc-0.22.0/src/scconf/internal.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/scconf/internal.h	2022-11-29 09:34:43.000000000 +0100
@@ -33,6 +33,8 @@
 #define TOKEN_TYPE_STRING	2
 #define TOKEN_TYPE_PUNCT	3
 
+#define DEPTH_LIMIT 16
+
 typedef struct _scconf_parser {
 	scconf_context *config;
 
@@ -49,11 +51,13 @@
 	unsigned int error:1;
 	unsigned int warnings:1;
 	char emesg[256];
+	size_t nested_blocks;
 } scconf_parser;
 
 extern int scconf_lex_parse(scconf_parser * parser, const char *filename);
 extern int scconf_lex_parse_string(scconf_parser * parser,
 				   const char *config_string);
+extern void scconf_skip_block(scconf_parser * parser);
 extern void scconf_parse_token(scconf_parser * parser, int token_type, const char *token);
 
 #ifdef __cplusplus
diff -Nru opensc-0.22.0/src/scconf/parse.c opensc-0.23.0/src/scconf/parse.c
--- opensc-0.22.0/src/scconf/parse.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/scconf/parse.c	2022-11-29 09:34:43.000000000 +0100
@@ -241,6 +241,12 @@
 	}
 }
 
+void scconf_skip_block(scconf_parser * parser)
+{
+	scconf_parse_error(parser, "too many nested blocks");
+	scconf_parse_reset_state(parser);
+}
+
 void scconf_parse_token(scconf_parser * parser, int token_type, const char *token)
 {
 	scconf_item *item;
@@ -298,7 +304,7 @@
 				/* name */
 				parser->state |= STATE_SET;
 				scconf_list_add(&parser->name, stoken);
-			} else if (parser->state == STATE_VALUE) {
+			} else if (parser->state == STATE_VALUE && parser->current_item->type == SCCONF_ITEM_TYPE_VALUE) {
 				/* value */
 				parser->state |= STATE_SET;
 				scconf_list_add(&parser->current_item->value.list,
@@ -320,10 +326,12 @@
 				scconf_parse_error_not_expect(parser, "{");
 				break;
 			}
+			parser->nested_blocks++;
 			scconf_block_add_internal(parser);
 			scconf_parse_reset_state(parser);
 			break;
 		case '}':
+			parser->nested_blocks--;
 			if (parser->state != 0) {
 				if ((parser->state & STATE_VALUE) == 0 ||
 				    (parser->state & STATE_SET) == 0) {
@@ -381,6 +389,7 @@
 	p.config = config;
 	p.block = config->root;
 	p.line = 1;
+	p.nested_blocks = 0;
 
 	if (!scconf_lex_parse(&p, config->filename)) {
 		snprintf(buffer, sizeof(buffer),
@@ -409,6 +418,7 @@
 	p.config = config;
 	p.block = config->root;
 	p.line = 1;
+	p.nested_blocks = 0;
 
 	if (!scconf_lex_parse_string(&p, string)) {
 		snprintf(buffer, sizeof(buffer),
@@ -421,6 +431,8 @@
 		r = 1;
 	}
 
+	scconf_parse_reset_state(&p);
+
 	if (r <= 0)
 		config->errmsg = buffer;
 	return r;
diff -Nru opensc-0.22.0/src/scconf/sclex.c opensc-0.23.0/src/scconf/sclex.c
--- opensc-0.22.0/src/scconf/sclex.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/scconf/sclex.c	2022-11-29 09:34:43.000000000 +0100
@@ -56,7 +56,7 @@
 
 static void buf_addch(BUFHAN * bp, char ch)
 {
-	if (bp->bufcur >= bp->bufmax) {
+	if (bp->bufcur + 1 >= bp->bufmax) {
 		char *p = (char *) realloc(bp->buf, bp->bufmax + 256);
 		if (!p)
 			return;
@@ -144,6 +144,12 @@
 			continue;
 		case ',':
 		case '{':
+			if (parser->nested_blocks >= DEPTH_LIMIT) {
+				/* reached the limit, this whole block */
+				scconf_skip_block(parser);
+				continue;
+			}
+			/* fall through */
 		case '}':
 		case '=':
 		case ';':
diff -Nru opensc-0.22.0/src/sm/Makefile.am opensc-0.23.0/src/sm/Makefile.am
--- opensc-0.22.0/src/sm/Makefile.am	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/sm/Makefile.am	2022-11-29 09:34:43.000000000 +0100
@@ -20,6 +20,8 @@
 AM_CPPFLAGS = -I$(top_srcdir)/src -I$(top_builddir)/src/include
 
 libsm_la_SOURCES = sm-common.c sm-common.h
+libsm_la_LIBADD = $(OPENSSL_LIBS)
+libsm_la_CFLAGS = $(OPENSSL_CFLAGS)
 
 libsmiso_la_SOURCES = sm-iso.c
 
diff -Nru opensc-0.22.0/src/sm/sm-common.c opensc-0.23.0/src/sm/sm-common.c
--- opensc-0.22.0/src/sm/sm-common.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/sm/sm-common.c	2022-11-29 09:34:43.000000000 +0100
@@ -54,30 +54,30 @@
 /*
  * From crypto/des/des_locl.h of OpenSSL .
  */
-#define c2l(c,l)	(l =((DES_LONG)(*((c)++)))	, \
-			 l|=((DES_LONG)(*((c)++)))<< 8L, \
-			 l|=((DES_LONG)(*((c)++)))<<16L, \
-			 l|=((DES_LONG)(*((c)++)))<<24L)
+#define c2l(c,l)	(l =((unsigned int)(*((c)++)))	, \
+			 l|=((unsigned int)(*((c)++)))<< 8L, \
+			 l|=((unsigned int)(*((c)++)))<<16L, \
+			 l|=((unsigned int)(*((c)++)))<<24L)
 
 #define c2ln(c,l1,l2,n)	{ \
 			c+=n; \
 			l1=l2=0; \
 			switch (n) { \
-			case 8: l2 =((DES_LONG)(*(--(c))))<<24L; \
+			case 8: l2 =((unsigned int)(*(--(c))))<<24L; \
 				/* fall through */ \
-			case 7: l2|=((DES_LONG)(*(--(c))))<<16L; \
+			case 7: l2|=((unsigned int)(*(--(c))))<<16L; \
 				/* fall through */ \
-			case 6: l2|=((DES_LONG)(*(--(c))))<< 8L; \
+			case 6: l2|=((unsigned int)(*(--(c))))<< 8L; \
 				/* fall through */ \
-			case 5: l2|=((DES_LONG)(*(--(c))));	 \
+			case 5: l2|=((unsigned int)(*(--(c))));	 \
 				/* fall through */ \
-			case 4: l1 =((DES_LONG)(*(--(c))))<<24L; \
+			case 4: l1 =((unsigned int)(*(--(c))))<<24L; \
 				/* fall through */ \
-			case 3: l1|=((DES_LONG)(*(--(c))))<<16L; \
+			case 3: l1|=((unsigned int)(*(--(c))))<<16L; \
 				/* fall through */ \
-			case 2: l1|=((DES_LONG)(*(--(c))))<< 8L; \
+			case 2: l1|=((unsigned int)(*(--(c))))<< 8L; \
 				/* fall through */ \
-			case 1: l1|=((DES_LONG)(*(--(c))));	 \
+			case 1: l1|=((unsigned int)(*(--(c))));	 \
 				} \
 			}
 
@@ -91,13 +91,13 @@
  * Inspired by or taken from OpenSSL crypto/des/cbc3_enc.c
  */
 static void
-DES_3cbc_encrypt(DES_cblock *input, DES_cblock *output, long length,
-		 DES_key_schedule *ks1, DES_key_schedule *ks2, DES_cblock *iv,
+DES_3cbc_encrypt(sm_des_cblock *input, sm_des_cblock *output, long length,
+		 DES_key_schedule *ks1, DES_key_schedule *ks2, sm_des_cblock *iv,
 		 int enc)
 	{
 	int off=((int)length-1)/8;
 	long l8=((length+7)/8)*8;
-	DES_cblock icv_out;
+	sm_des_cblock icv_out;
 
 	memset(&icv_out, 0, sizeof(icv_out));
 	if (enc == DES_ENCRYPT)   {
@@ -107,12 +107,12 @@
 				(unsigned char*)output,l8,ks2,iv,!enc);
 		DES_cbc_encrypt((unsigned char*)output,
 				(unsigned char*)output,l8,ks1,iv,enc);
-		if ((unsigned)length >= sizeof(DES_cblock))
-			memcpy(icv_out,output[off],sizeof(DES_cblock));
+		if ((unsigned)length >= sizeof(sm_des_cblock))
+			memcpy(icv_out,output[off],sizeof(sm_des_cblock));
 	}
 	else   {
-		if ((unsigned)length >= sizeof(DES_cblock))
-			memcpy(icv_out,input[off],sizeof(DES_cblock));
+		if ((unsigned)length >= sizeof(sm_des_cblock))
+			memcpy(icv_out,input[off],sizeof(sm_des_cblock));
 		DES_cbc_encrypt((unsigned char*)input,
 				(unsigned char*)output,l8,ks1,iv,enc);
 		DES_cbc_encrypt((unsigned char*)output,
@@ -120,7 +120,7 @@
 		DES_cbc_encrypt((unsigned char*)output,
 				(unsigned char*)output,length,ks1,iv,enc);
 	}
-	memcpy(*iv,icv_out,sizeof(DES_cblock));
+	memcpy(*iv,icv_out,sizeof(sm_des_cblock));
 }
 #else
 #include <openssl/provider.h>
@@ -128,22 +128,22 @@
 /* The single-DES algorithm is not available in the default provider anymore
  * so we need to load the legacy provider. This is not done on the application
  * start, but only as needed */
-OSSL_PROVIDER *legacy_provider = NULL;
+static OSSL_PROVIDER *legacy_provider = NULL;
 #endif
 
 
-DES_LONG
-DES_cbc_cksum_3des_emv96(const unsigned char *in, DES_cblock *output,
+unsigned int
+DES_cbc_cksum_3des_emv96(const unsigned char *in, sm_des_cblock *output,
 			   long length, unsigned char *key,
-			   const_DES_cblock *ivec)
+			   sm_const_des_cblock *ivec)
 {
 	register long l=length;
 	unsigned char *out = &(*output)[0];
 	const unsigned char *iv = &(*ivec)[0];
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
-	register DES_LONG tout0,tout1,tin0,tin1;
-	DES_LONG tin[2];
-	DES_cblock kk, k2;
+	register unsigned int tout0,tout1,tin0,tin1;
+	unsigned int tin[2];
+	sm_des_cblock kk, k2;
 	DES_key_schedule ks,ks2;
 
 	memcpy(&kk, key, 8);
@@ -165,7 +165,7 @@
 
 		tin0^=tout0; tin[0]=tin0;
 		tin1^=tout1; tin[1]=tin1;
-		DES_encrypt1((DES_LONG *)tin, &ks, DES_ENCRYPT);
+		DES_encrypt1((unsigned int *)tin, &ks, DES_ENCRYPT);
 		tout0=tin[0];
 		tout1=tin[1];
 	}
@@ -179,7 +179,7 @@
 
 	tin0^=tout0; tin[0]=tin0;
 	tin1^=tout1; tin[1]=tin1;
-	DES_encrypt3((DES_LONG *)tin, &ks, &ks2, &ks);
+	DES_encrypt3((unsigned int *)tin, &ks, &ks2, &ks);
 	tout1=tin[1];
 	if (out != NULL)
 		{
@@ -206,8 +206,11 @@
 
 	cctx = EVP_CIPHER_CTX_new();
 	if (l > 8) {
-		if (legacy_provider == NULL) {
-			 legacy_provider = OSSL_PROVIDER_load(NULL, "legacy");
+		if (!legacy_provider) {
+			if (!(legacy_provider = OSSL_PROVIDER_try_load(NULL, "legacy", 1))) {
+				EVP_CIPHER_CTX_free(cctx);
+				return SC_ERROR_INTERNAL;
+			}
 		}
 		if (!EVP_EncryptInit_ex2(cctx, EVP_des_cbc(), key, iv, NULL)) {
 			EVP_CIPHER_CTX_free(cctx);
@@ -256,18 +259,18 @@
 }
 
 
-DES_LONG
-DES_cbc_cksum_3des(const unsigned char *in, DES_cblock *output,
+unsigned int
+DES_cbc_cksum_3des(const unsigned char *in, sm_des_cblock *output,
 		       long length, unsigned char *key,
-		       const_DES_cblock *ivec)
+		       sm_const_des_cblock *ivec)
 {
 	register long l=length;
 	unsigned char *out = &(*output)[0];
 	const unsigned char *iv = &(*ivec)[0];
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
-	register DES_LONG tout0,tout1,tin0,tin1;
-	DES_LONG tin[2];
-	DES_cblock kk, k2;
+	register unsigned int tout0,tout1,tin0,tin1;
+	unsigned int tin[2];
+	sm_des_cblock kk, k2;
 	DES_key_schedule ks,ks2;
 
 	memcpy(&kk, key, 8);
@@ -290,7 +293,7 @@
 
 		tin0^=tout0; tin[0]=tin0;
 		tin1^=tout1; tin[1]=tin1;
-		DES_encrypt3((DES_LONG *)tin, &ks, &ks2, &ks);
+		DES_encrypt3((unsigned int *)tin, &ks, &ks2, &ks);
 		/* fix 15/10/91 eay - thanks to keithr at sco.COM */
 		tout0=tin[0];
 		tout1=tin[1];
@@ -313,7 +316,7 @@
 #else
 	EVP_CIPHER_CTX *cctx = NULL;
 	unsigned char outv[8];
-	int tmplen;
+	int tmplen = 0;
 
 	/* Prepare IV */
 	memcpy(outv, iv, sizeof outv);
@@ -353,7 +356,7 @@
 {
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
 	int ii;
-	DES_cblock kk,k2;
+	sm_des_cblock kk,k2;
 	DES_key_schedule ks,ks2;
 #else
 	EVP_CIPHER_CTX *cctx = NULL;
@@ -380,8 +383,8 @@
 	DES_set_key_unchecked(&k2,&ks2);
 
 	for (ii=0; ii<data_len; ii+=8)
-		DES_ecb2_encrypt( (DES_cblock *)(data + ii),
-				(DES_cblock *)(*out + ii), &ks, &ks2, DES_ENCRYPT);
+		DES_ecb2_encrypt( (sm_des_cblock *)(data + ii),
+				(sm_des_cblock *)(*out + ii), &ks, &ks2, DES_ENCRYPT);
 #else
 	cctx = EVP_CIPHER_CTX_new();
 	if (!EVP_EncryptInit_ex2(cctx, EVP_des_ede_ecb(), key, NULL, NULL)) {
@@ -414,9 +417,9 @@
 		unsigned char **out, size_t *out_len)
 {
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
-	DES_cblock kk,k2;
+	sm_des_cblock kk,k2;
 	DES_key_schedule ks,ks2;
-	DES_cblock icv={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+	sm_des_cblock icv={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
 	size_t st;
 #else
 	unsigned char icv[] = {0x00 ,0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
@@ -443,8 +446,8 @@
 	DES_set_key_unchecked(&k2,&ks2);
 
 	for (st=0; st<data_len; st+=8)
-		DES_3cbc_encrypt((DES_cblock *)(data + st),
-				(DES_cblock *)(*out + st), 8, &ks, &ks2, &icv, DES_DECRYPT);
+		DES_3cbc_encrypt((sm_des_cblock *)(data + st),
+				(sm_des_cblock *)(*out + st), 8, &ks, &ks2, &icv, DES_DECRYPT);
 #else
 	cctx = EVP_CIPHER_CTX_new();
 	if (!EVP_DecryptInit_ex2(cctx, EVP_des_ede_cbc(), key, icv, NULL)) {
@@ -469,16 +472,16 @@
 	SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_SM, SC_SUCCESS);
 }
 
-/* This function expects the data to be a multilpe of DES block size */
+/* This function expects the data to be a multiple of DES block size */
 int
 sm_encrypt_des_cbc3(struct sc_context *ctx, unsigned char *key,
 		const unsigned char *in, size_t in_len,
 		unsigned char **out, size_t *out_len, int not_force_pad)
 {
 #if OPENSSL_VERSION_NUMBER < 0x30000000L
-	DES_cblock kk,k2;
+	sm_des_cblock kk,k2;
 	DES_key_schedule ks,ks2;
-	DES_cblock icv={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+	sm_des_cblock icv={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
 	size_t st;
 #else
 	unsigned char icv[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
@@ -516,7 +519,7 @@
 	       data_len, sc_dump_hex(data, data_len));
 
 	*out_len = data_len;
-	*out = malloc(data_len + 8);
+	*out = calloc(data_len + 8, sizeof(unsigned char));
 	if (*out == NULL) {
 		free(data);
 		LOG_TEST_RET(ctx, SC_ERROR_OUT_OF_MEMORY, "SM encrypt_des_cbc3: failure");
@@ -530,22 +533,25 @@
 	DES_set_key_unchecked(&k2,&ks2);
 
 	for (st=0; st<data_len; st+=8)
-		DES_3cbc_encrypt((DES_cblock *)(data + st), (DES_cblock *)(*out + st), 8, &ks, &ks2, &icv, DES_ENCRYPT);
+		DES_3cbc_encrypt((sm_des_cblock *)(data + st), (sm_des_cblock *)(*out + st), 8, &ks, &ks2, &icv, DES_ENCRYPT);
 #else
 	cctx = EVP_CIPHER_CTX_new();
 	if (!EVP_EncryptInit_ex2(cctx, EVP_des_ede_cbc(), key, icv, NULL)) {
+		free(*out);
 		EVP_CIPHER_CTX_free(cctx);
 		SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_SM, SC_ERROR_INTERNAL);
 	}
 	/* Disable padding, otherwise it will fail to decrypt non-padded inputs */
 	EVP_CIPHER_CTX_set_padding(cctx, 0);
 	if (!EVP_EncryptUpdate(cctx, *out, &tmplen, data, data_len)) {
+		free(*out);
 		EVP_CIPHER_CTX_free(cctx);
 		SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_SM, SC_ERROR_INTERNAL);
 	}
 	*out_len = tmplen;
 
 	if (!EVP_EncryptFinal_ex(cctx, *out + *out_len, &tmplen)) {
+		free(*out);
 		EVP_CIPHER_CTX_free(cctx);
 		SC_FUNC_RETURN(ctx, SC_LOG_DEBUG_SM, SC_ERROR_INTERNAL);
 	}
diff -Nru opensc-0.22.0/src/sm/sm-common.h opensc-0.23.0/src/sm/sm-common.h
--- opensc-0.22.0/src/sm/sm-common.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/sm/sm-common.h	2022-11-29 09:34:43.000000000 +0100
@@ -30,11 +30,11 @@
 
 #include "libopensc/sm.h"
 
-DES_LONG DES_cbc_cksum_3des(const unsigned char *in, DES_cblock *output, long length,
-		unsigned char *key, const_DES_cblock *ivec);
-DES_LONG DES_cbc_cksum_3des_emv96(const unsigned char *in, DES_cblock *output,
+unsigned int DES_cbc_cksum_3des(const unsigned char *in, sm_des_cblock *output, long length,
+		unsigned char *key, sm_const_des_cblock *ivec);
+unsigned int DES_cbc_cksum_3des_emv96(const unsigned char *in, sm_des_cblock *output,
 		long length, unsigned char *key,
-		const_DES_cblock *ivec);
+		sm_const_des_cblock *ivec);
 int sm_encrypt_des_ecb3(unsigned char *key, unsigned char *data, int data_len,
 		unsigned char **out, int *out_len);
 int sm_encrypt_des_cbc3(struct sc_context *ctx, unsigned char *key,
diff -Nru opensc-0.22.0/src/sm/sm-eac.c opensc-0.23.0/src/sm/sm-eac.c
--- opensc-0.22.0/src/sm/sm-eac.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/sm/sm-eac.c	2022-11-29 09:34:43.000000000 +0100
@@ -59,6 +59,7 @@
 #include <eac/ca.h>
 #include <eac/cv_cert.h>
 #include <eac/eac.h>
+#include <eac/objects.h>
 #include <eac/pace.h>
 #include <eac/ta.h>
 #include <openssl/bio.h>
@@ -414,7 +415,11 @@
 	}
 
 	if (protocol) {
+#ifndef HAVE_EAC_OBJ_NID2OBJ
 		data->cryptographic_mechanism_reference = OBJ_nid2obj(protocol);
+#else
+		data->cryptographic_mechanism_reference = EAC_OBJ_nid2obj(protocol);
+#endif
 		if (!data->cryptographic_mechanism_reference) {
 			sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "Error setting Cryptographic mechanism reference of MSE:Set AT data");
 			r = SC_ERROR_INTERNAL;
@@ -1136,6 +1141,7 @@
 		sc_debug_hex(card->ctx, SC_LOG_DEBUG_SM, "EF.CardAccess", pace_output->ef_cardaccess,
 				pace_output->ef_cardaccess_length);
 
+		EAC_init();
 		eac_ctx = EAC_CTX_new();
 		if (!eac_ctx
 				|| !EAC_CTX_init_ef_cardaccess(pace_output->ef_cardaccess,
@@ -1164,8 +1170,9 @@
 			r = SC_ERROR_OUT_OF_MEMORY;
 			goto err;
 		}
-		r = eac_gen_auth_1_encrypted_nonce(card, (u8 **) &enc_nonce->data,
-				&enc_nonce->length);
+		p = (u8 *) enc_nonce->data;
+		r = eac_gen_auth_1_encrypted_nonce(card, &p, &enc_nonce->length);
+		enc_nonce->data = (char *) p;
 		if (r < 0) {
 			sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not get encrypted nonce from card "
 					"(General Authenticate step 1 failed).");
@@ -1198,8 +1205,10 @@
 			r = SC_ERROR_INTERNAL;
 			goto err;
 		}
+		p = (u8 *) mdata_opp->data;
 		r = eac_gen_auth_2_map_nonce(card, (u8 *) mdata->data, mdata->length,
-				(u8 **) &mdata_opp->data, &mdata_opp->length);
+				&p, &mdata_opp->length);
+		mdata_opp->data = (char *) p;
 		if (r < 0) {
 			sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not exchange mapping data with card "
 					"(General Authenticate step 2 failed).");
@@ -1224,8 +1233,10 @@
 			r = SC_ERROR_INTERNAL;
 			goto err;
 		}
+		p = (u8 *) pub_opp->data;
 		r = eac_gen_auth_3_perform_key_agreement(card, (u8 *) pub->data, pub->length,
-				(u8 **) &pub_opp->data, &pub_opp->length);
+				&p, &pub_opp->length);
+		pub_opp->data = (char *) p;
 		if (r < 0) {
 			sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not exchange ephemeral public key with card "
 					"(General Authenticate step 3 failed).");
@@ -1251,10 +1262,12 @@
 			r = SC_ERROR_INTERNAL;
 			goto err;
 		}
+		p = (u8 *) token_opp->data;
 		r = eac_gen_auth_4_mutual_authentication(card, (u8 *) token->data, token->length,
-				(u8 **) &token_opp->data, &token_opp->length,
+				&p, &token_opp->length,
 				&pace_output->recent_car, &pace_output->recent_car_length,
 				&pace_output->previous_car, &pace_output->previous_car_length);
+		token_opp->data = (char *) p;
 
 		if (r < 0) {
 			sc_debug(card->ctx, SC_LOG_DEBUG_VERBOSE, "Could not exchange authentication token with card "
@@ -1513,6 +1526,7 @@
 		 * seems valid. */
 		card->caps |= SC_CARD_CAP_APDU_EXT;
 
+		EAC_init();
 		eac_ctx = EAC_CTX_new();
 		if (!eac_ctx
 				|| !EAC_CTX_init_ef_cardaccess(ef_cardaccess,
diff -Nru opensc-0.22.0/src/sm/sm-iso.c opensc-0.23.0/src/sm/sm-iso.c
--- opensc-0.22.0/src/sm/sm-iso.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/sm/sm-iso.c	2022-11-29 09:34:43.000000000 +0100
@@ -181,13 +181,14 @@
 
 static int prefix_buf(u8 prefix, u8 *buf, size_t buflen, u8 **cat)
 {
-	u8 *p;
+	u8 *p = NULL;
+	int ptr_same = *cat == buf;
 
 	p = realloc(*cat, buflen + 1);
 	if (!p)
 		return SC_ERROR_OUT_OF_MEMORY;
 
-	if (*cat == buf) {
+	if (ptr_same) {
 		memmove(p + 1, p, buflen);
 	} else {
 		/* Flawfinder: ignore */
@@ -476,9 +477,13 @@
 	if (apdu->cse & SC_APDU_EXT) {
 		sm_apdu->cse = SC_APDU_CASE_4_EXT;
 		sm_apdu->resplen = 4 + 2 + mac_len + 2 + 3 + ((apdu->resplen+1)/ctx->block_length+1)*ctx->block_length;
+		if (sm_apdu->resplen > SC_MAX_EXT_APDU_RESP_SIZE)
+			sm_apdu->resplen = SC_MAX_EXT_APDU_RESP_SIZE;
 	} else {
 		sm_apdu->cse = SC_APDU_CASE_4_SHORT;
 		sm_apdu->resplen = 4 + 2 + mac_len + 2 + 2 + ((apdu->resplen+1)/ctx->block_length+1)*ctx->block_length;
+		if (sm_apdu->resplen > SC_MAX_APDU_RESP_SIZE)
+			sm_apdu->resplen = SC_MAX_APDU_RESP_SIZE;
 	}
 	resp_data = calloc(sm_apdu->resplen, 1);
 	if (!resp_data) {
diff -Nru opensc-0.22.0/src/sm/sslutil.h opensc-0.23.0/src/sm/sslutil.h
--- opensc-0.22.0/src/sm/sslutil.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/sm/sslutil.h	2022-11-29 09:34:43.000000000 +0100
@@ -28,11 +28,9 @@
 
 #define ssl_error(ctx) { \
 	unsigned long _r; \
-	ERR_load_crypto_strings(); \
 	for (_r = ERR_get_error(); _r; _r = ERR_get_error()) { \
 		sc_debug(ctx, SC_LOG_DEBUG_VERBOSE, "%s", ERR_error_string(_r, NULL)); \
 	} \
-	ERR_free_strings(); \
 }
 #endif
 
diff -Nru opensc-0.22.0/src/smm/Makefile.am opensc-0.23.0/src/smm/Makefile.am
--- opensc-0.22.0/src/smm/Makefile.am	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/smm/Makefile.am	2022-11-29 09:34:43.000000000 +0100
@@ -11,14 +11,16 @@
 	$(top_builddir)/src/common/libcompat.la
 
 if ENABLE_OPENSSL
+if ENABLE_SHARED
 lib_LTLIBRARIES = libsmm-local.la
 endif
+endif
 
 libsmm_local_la_SOURCES = smm-local.c sm-module.h \
 	sm-global-platform.c sm-cwa14890.c \
 	sm-card-authentic.c sm-card-iasecc.c \
 	smm-local.exports
-libsmm_local_la_LIBADD = $(OPTIONAL_OPENSSL_LIBS) ../libopensc/libopensc.la
+libsmm_local_la_LIBADD = $(OPTIONAL_OPENSSL_LIBS)
 libsmm_local_la_LDFLAGS = -module -shared -no-undefined -version-info @OPENSC_LT_CURRENT@:@OPENSC_LT_REVISION@:@OPENSC_LT_AGE@
 
 # noinst_HEADERS = sm.h
diff -Nru opensc-0.22.0/src/smm/Makefile.mak opensc-0.23.0/src/smm/Makefile.mak
--- opensc-0.22.0/src/smm/Makefile.mak	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/smm/Makefile.mak	2022-11-29 09:34:43.000000000 +0100
@@ -24,7 +24,7 @@
 	echo LIBRARY $* > $*.def
 	echo EXPORTS >> $*.def
 	type $*.exports >> $*.def
-	link /dll $(LINKFLAGS) /def:$*.def /out:$(TARGET) $(OBJECTS) $(LIBS) $(ZLIB_LIB) $(OPENPACE_LIB) $(OPENSSL_LIB) ws2_32.lib gdi32.lib advapi32.lib Crypt32.lib User32.lib Shell32.lib Comctl32.lib
+	link /dll $(LINKFLAGS) /def:$*.def /out:$(TARGET) $(OBJECTS) $(LIBS) $(ZLIB_LIB) $(OPENPACE_LIB) $(OPENSSL_LIB) ws2_32.lib gdi32.lib advapi32.lib Crypt32.lib User32.lib Shell32.lib Comctl32.lib shlwapi.lib
 	if EXIST $(TARGET).manifest mt -manifest $(TARGET).manifest -outputresource:$(TARGET);2
 
 !ELSE
diff -Nru opensc-0.22.0/src/smm/sm-common.exports opensc-0.23.0/src/smm/sm-common.exports
--- opensc-0.22.0/src/smm/sm-common.exports	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/smm/sm-common.exports	2022-11-29 09:34:43.000000000 +0100
@@ -1,3 +1,2 @@
-sm_cwa_get_mac
-sm_cwa_securize_apdu
-
+sm_cwa_get_mac
+sm_cwa_securize_apdu
diff -Nru opensc-0.22.0/src/smm/sm-cwa14890.c opensc-0.23.0/src/smm/sm-cwa14890.c
--- opensc-0.22.0/src/smm/sm-cwa14890.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/smm/sm-cwa14890.c	2022-11-29 09:34:43.000000000 +0100
@@ -46,8 +46,8 @@
 #include "sm-module.h"
 
 int
-sm_cwa_get_mac(struct sc_context *ctx, unsigned char *key, DES_cblock *icv,
-			unsigned char *in, int in_len, DES_cblock *out, int force_padding)
+sm_cwa_get_mac(struct sc_context *ctx, unsigned char *key, sm_des_cblock *icv,
+			unsigned char *in, int in_len, sm_des_cblock *out, int force_padding)
 {
 	unsigned char padding[8] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
 	unsigned char *buf;
@@ -122,8 +122,8 @@
 sm_cwa_decode_authentication_data(struct sc_context *ctx, struct sm_cwa_keyset *keyset,
 		struct sm_cwa_session *session_data, unsigned char *auth_data)
 {
-	DES_cblock icv = {0, 0, 0, 0, 0, 0, 0, 0};
-	DES_cblock cblock;
+	sm_des_cblock icv = {0, 0, 0, 0, 0, 0, 0, 0};
+	sm_des_cblock cblock;
 	unsigned char *decrypted = NULL;
 	size_t decrypted_len;
 	int rv;
@@ -230,7 +230,7 @@
 	struct sc_apdu *apdu = NULL;
 	unsigned char buf[0x100], *encrypted = NULL;
 	size_t encrypted_len;
-	DES_cblock icv = {0, 0, 0, 0, 0, 0, 0, 0}, cblock;
+	sm_des_cblock icv = {0, 0, 0, 0, 0, 0, 0, 0}, cblock;
 	int rv, offs;
 
 	LOG_FUNC_CALLED(ctx);
@@ -304,7 +304,7 @@
 	struct sm_cwa_session *session_data = &sm_info->session.cwa;
 	struct sc_apdu *apdu = &rapdu->apdu;
 	unsigned char sbuf[0x400];
-	DES_cblock cblock, icv;
+	sm_des_cblock cblock, icv;
 	unsigned char *encrypted = NULL, edfb_data[0x200], mac_data[0x200];
 	size_t encrypted_len, edfb_len = 0, mac_len = 0, offs;
 	int rv;
diff -Nru opensc-0.22.0/src/smm/sm-global-platform.c opensc-0.23.0/src/smm/sm-global-platform.c
--- opensc-0.22.0/src/smm/sm-global-platform.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/smm/sm-global-platform.c	2022-11-29 09:34:43.000000000 +0100
@@ -129,7 +129,7 @@
 		unsigned char *out, int out_len)
 {
 	unsigned char block[24];
-	DES_cblock cksum={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
+	sm_des_cblock cksum={0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
 
 	if (out_len!=8)
 		return SC_ERROR_INVALID_ARGUMENTS;
@@ -147,8 +147,8 @@
 
 
 int
-sm_gp_get_mac(unsigned char *key, DES_cblock *icv,
-		unsigned char *in, int in_len, DES_cblock *out)
+sm_gp_get_mac(unsigned char *key, sm_des_cblock *icv,
+		unsigned char *in, int in_len, sm_des_cblock *out)
 {
 	int len;
 	unsigned char *block;
@@ -244,7 +244,7 @@
 	struct sc_apdu *apdu = NULL;
 	unsigned char host_cryptogram[8], raw_apdu[SC_MAX_APDU_BUFFER_SIZE];
 	struct sm_gp_session *gp_session = &sm_info->session.gp;
-	DES_cblock mac;
+	sm_des_cblock mac;
 	int rv, offs = 0;
 
 	LOG_FUNC_CALLED(ctx);
@@ -344,7 +344,7 @@
 	struct sm_gp_session *gp_session = &sm_info->session.gp;
 	unsigned gp_level = sm_info->session.gp.params.level;
 	unsigned gp_index = sm_info->session.gp.params.index;
-	DES_cblock mac;
+	sm_des_cblock mac;
 	unsigned char *encrypted = NULL;
 	size_t encrypted_len = 0;
 	int rv;
diff -Nru opensc-0.22.0/src/smm/smm-local.exports opensc-0.23.0/src/smm/smm-local.exports
--- opensc-0.22.0/src/smm/smm-local.exports	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/smm/smm-local.exports	2022-11-29 09:34:43.000000000 +0100
@@ -1,6 +1,6 @@
-initialize
-get_apdus
-finalize
-module_cleanup
-module_init
-test
+initialize
+get_apdus
+finalize
+module_cleanup
+module_init
+test
diff -Nru opensc-0.22.0/src/smm/sm-module.h opensc-0.23.0/src/smm/sm-module.h
--- opensc-0.22.0/src/smm/sm-module.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/smm/sm-module.h	2022-11-29 09:34:43.000000000 +0100
@@ -34,8 +34,8 @@
 #include "sm/sm-common.h"
 
 /* Global Platform definitions */
-int sm_gp_get_mac(unsigned char *key, DES_cblock *icv, unsigned char *in, int in_len,
-		DES_cblock *out);
+int sm_gp_get_mac(unsigned char *key, sm_des_cblock *icv, unsigned char *in, int in_len,
+		sm_des_cblock *out);
 int sm_gp_get_cryptogram(unsigned char *session_key, unsigned char *left, unsigned char *right,
 		unsigned char *out, int out_len);
 int sm_gp_external_authentication(struct sc_context *ctx, struct sm_info *sm_info,
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_card/3676fcfa2dba95b7c439b6343228623ac0be93c4 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_card/3676fcfa2dba95b7c439b6343228623ac0be93c4 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_card/3e651eeafa4f5ad5bb6e21787ba4ba43af7c6f76 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_card/3e651eeafa4f5ad5bb6e21787ba4ba43af7c6f76 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_card/68446db83043eb66ce144ab42466b39b0675c42d und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_card/68446db83043eb66ce144ab42466b39b0675c42d sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_card/995545e7be2e433f450b87c2e9020ab480947bcf und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_card/995545e7be2e433f450b87c2e9020ab480947bcf sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_card/c62b44859dfb22dddcf8c19468b61587b02bbd5e und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_card/c62b44859dfb22dddcf8c19468b61587b02bbd5e sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_card/f117a2bbb1ea0617255c7e993914ef9062303580 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_card/f117a2bbb1ea0617255c7e993914ef9062303580 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_piv_tool/5cc15068920eb3c897b0129a6939e3b01574eb02 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_piv_tool/5cc15068920eb3c897b0129a6939e3b01574eb02 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_piv_tool/df81168351db4e248a9a915bb521c85dce1d17c8 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_piv_tool/df81168351db4e248a9a915bb521c85dce1d17c8 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs11/1dca0b7f951ad6c7cbb39e0e5fa1327ada85d4a5 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs11/1dca0b7f951ad6c7cbb39e0e5fa1327ada85d4a5 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs11/334176efba3f10cbbb96b23d04ae03240ed31e0a und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs11/334176efba3f10cbbb96b23d04ae03240ed31e0a sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs11/533432db786d023c678187d79db1860ca1c44056 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs11/533432db786d023c678187d79db1860ca1c44056 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs11/6ec181a01600525601900b9fe2b9eacf7d5df43d und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs11/6ec181a01600525601900b9fe2b9eacf7d5df43d sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs11/85bdf4bb93d2f4604fa3e21096d7da552cae8b97 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs11/85bdf4bb93d2f4604fa3e21096d7da552cae8b97 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs11/96ff9ea1b05bc5d0443305fae8ace07732c85359 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs11/96ff9ea1b05bc5d0443305fae8ace07732c85359 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs11/dff1ba4f2e96e390e03144ef40b06981c1a0cf8d und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs11/dff1ba4f2e96e390e03144ef40b06981c1a0cf8d sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs11/dffd29e0ce2df7e99122dc3e5c7de81d77ffbbb9 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs11/dffd29e0ce2df7e99122dc3e5c7de81d77ffbbb9 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_crypt/5f52a1ae6be6d75d0be546604b47759c6621f46f und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_crypt/5f52a1ae6be6d75d0be546604b47759c6621f46f sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_crypt/6d06b28c9e3743122056f32e09f4c6d77763f4ba und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_crypt/6d06b28c9e3743122056f32e09f4c6d77763f4ba sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_crypt/92f669ec651bb54b819db380603520c18b78297a und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_crypt/92f669ec651bb54b819db380603520c18b78297a sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_crypt/bfb749d844f7c304e004c52a46ce84eb3da7a7f3 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_crypt/bfb749d844f7c304e004c52a46ce84eb3da7a7f3 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_crypt/e52786b16a4202c5315c834788133b173bc141a6 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_crypt/e52786b16a4202c5315c834788133b173bc141a6 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_crypt/e9016daf00fb6713ea6f7fc18c55e85a4a33ea3a und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_crypt/e9016daf00fb6713ea6f7fc18c55e85a4a33ea3a sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_decode/0204f84aede3986d1add8909124e021cac32bec8 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_decode/0204f84aede3986d1add8909124e021cac32bec8 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_decode/0e9c8b959346f4894ea97d7e3f393c2442ee1e3d und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_decode/0e9c8b959346f4894ea97d7e3f393c2442ee1e3d sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_decode/6e580d278c33a530284dfef5dd9ffd617597bb68 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_decode/6e580d278c33a530284dfef5dd9ffd617597bb68 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_decode/8989be8baa0b0269c8128729062b31f91b131ba4 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_decode/8989be8baa0b0269c8128729062b31f91b131ba4 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_decode/b011d577451c835fd8f6052f0659337994273f3f und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_decode/b011d577451c835fd8f6052f0659337994273f3f sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_encode/741a0aae7b5b08c0ad2822ede5b3364302b28b31 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_encode/741a0aae7b5b08c0ad2822ede5b3364302b28b31 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_encode/7cf8e9b31dcee040ee438441aca2aecb523ed5e9 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_encode/7cf8e9b31dcee040ee438441aca2aecb523ed5e9 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_encode/830e1bf4c7f0c539e9686bc1517d6f87907d4bf8 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_encode/830e1bf4c7f0c539e9686bc1517d6f87907d4bf8 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_encode/9ad3fc3cb11967be927bad9263d326783c450e37 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_encode/9ad3fc3cb11967be927bad9263d326783c450e37 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_encode/b2b75c07a2c427c15ecd40ce47a9814279745b7d und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_encode/b2b75c07a2c427c15ecd40ce47a9814279745b7d sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_encode/cb50689bf49ccb45a2af690848517305dcf1e429 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_encode/cb50689bf49ccb45a2af690848517305dcf1e429 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_encode/de913ba454f894cfc38a16dd122ad673d32ac480 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_encode/de913ba454f894cfc38a16dd122ad673d32ac480 sind verschieden.
diff -Nru opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15init/6ce966ee0f311e1a63f2bb693caeba1b0fd1160e opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15init/6ce966ee0f311e1a63f2bb693caeba1b0fd1160e
--- opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15init/6ce966ee0f311e1a63f2bb693caeba1b0fd1160e	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15init/6ce966ee0f311e1a63f2bb693caeba1b0fd1160e	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,308 @@
+#
+# PKCS15 profile, generic information.
+# This profile is loaded before any card specific profile.
+#
+
+cardinfo {
+	label           = "MyEID";
+	manufacturer    = "Aventra Ltd.";
+	min-pin-length	= 4;
+	max-pin-length	= 8;
+	pin-encoding	= ascii-numeric;
+   	pin-pad-char	= 0xFF;
+}
+
+#
+# The following controls some aspects of the PKCS15 we put onto
+# the card.
+#
+pkcs15 {
+    # Put certificates into the CDF itself?
+    direct-certificates	= no;
+    # Put the DF length into the ODF file?
+    encode-df-length	= no;
+    # Have a lastUpdate field in the EF(TokenInfo)?
+    do-last-update	    = no;
+    # Method to calculate ID of the crypto objects
+    #     native: 'E' + number_of_present_objects_of_the_same_type
+    #     mozilla: SHA1(modulus) for RSA, SHA1(pub) for DSA
+    #     rfc2459: SHA1(SequenceASN1 of public key components as ASN1 integers)
+    # default value: 'native'
+    pkcs15-id-style	= mozilla;
+}
+
+# Default settings.
+# This option block will always be processed.
+option default {
+    macros {
+        protected	= *=$SOPIN, READ=NONE;
+        unprotected	= *=NONE;
+	so-pin-flags	= local, initialized, needs-padding, soPin;
+	so-min-pin-length = 6;
+	so-pin-attempts	= 2;
+	so-auth-id	= FF;
+	so-puk-attempts	= 4;
+	so-min-puk-length = 6;
+	unusedspace-size = 510;
+	odf-size	     = 255;
+	aodf-size	     = 255;
+	cdf-size	     = 1530;
+	cdf-trusted-size = 510;
+	prkdf-size	     = 1530;
+	pukdf-size	     = 1530;
+	skdf-size	     = 1530;
+	dodf-size	     = 1530;
+    }
+}
+
+# This option sets up the card so that a single
+# user PIN protects all files
+option onepin {
+    macros {
+        protected	= *=$PIN, READ=NONE;
+        unprotected	= *=NONE;
+	so-pin-flags	= local, initialized, needs-padding;
+	so-min-pin-length = 4;
+	so-pin-attempts	= 3;
+	so-auth-id	= 1;
+	so-puk-attempts	= 7;
+	so-min-puk-length = 4;
+    }
+}
+
+# This option is for cards with very little memory.
+# It sets the size of various PKCS15 directory files
+# to 128 or 256, respectively.
+option small {
+    macros {
+	odf-size	= 128;
+	aodf-size	= 128;
+	cdf-size	= 256;
+	prkdf-size	= 128;
+	pukdf-size	= 128;
+	dodf-size	= 128;
+    }
+}
+
+# This option tells pkcs15-init to use the direct option
+# when storing certificates on the card (i.e. put the
+# certificates into the CDF itself, rather than a
+# separate file)
+option direct-cert {
+    pkcs15 {
+        direct-certificates	= yes;
+	encode-df-length	= yes;
+    }
+    macros {
+	cdf-size	= 3192;
+    }
+}
+
+# Define reasonable limits for PINs and PUK
+# Note that we do not set a file path or reference
+# for the user pin; that is done dynamically.
+PIN user-pin {
+    reference  = 1;
+    min-length = 4;
+    max-length = 8;
+    attempts   = 3;
+    flags      = initialized, needs-padding;
+}
+PIN user-puk {
+    min-length = 4;
+    max-length = 8;
+    attempts   = 10;
+    flags      = needs-padding;
+}
+PIN so-pin {
+    reference  = 3;
+    auth-id    = FF;
+    min-length = 4;
+    max-length = 8;
+    attempts   = 3;
+    flags      = initialized, soPin, needs-padding;
+}
+PIN so-puk {
+    min-length = 4;
+    max-length = 8;
+    attempts   = 10;
+   flags       = needs-padding;
+}
+
+filesystem {
+    DF MF {
+        path	= 3F00;
+        type	= DF;
+		acl	  = CREATE=$PIN, DELETE=$SOPIN;
+
+	# This is the DIR file
+	EF DIR {
+	    type	= EF;
+	    file-id	= 2F00;
+		structure = transparent;
+	    size	= 128;
+	    acl	      = READ=NONE, UPDATE=$SOPIN, DELETE=$SOPIN;
+	}
+
+	# Here comes the application DF
+	DF PKCS15-AppDF {
+	    type	= DF;
+	    file-id	= 5015;
+	    aid		= A0:00:00:00:63:50:4B:43:53:2D:31:35;
+	    acl       = DELETE=$PIN, CREATE=$PIN;
+	    size	= 5000;
+
+	    EF PKCS15-ODF {
+	        file-id		= 5031;
+			size		= $odf-size;
+			structure = transparent;
+			acl       = READ=NONE, UPDATE=$PIN, DELETE=$SOPIN;
+	    }
+
+	    EF PKCS15-TokenInfo {
+        	file-id	  = 5032;
+        	size		  = 160;
+	        structure  = transparent;
+        	acl	      = READ=NONE, UPDATE=$SOPIN, DELETE=$SOPIN;
+	    }
+
+	    EF PKCS15-UnusedSpace {
+            file-id	  = 5033;
+            structure = transparent;
+            size	  = $unusedspace-size;
+            acl	      = READ=NONE, UPDATE=$SOPIN, DELETE=$SOPIN;
+	    }
+
+	    EF PKCS15-AODF {
+            file-id	  = 4401;
+            structure = transparent;
+            size	  = $aodf-size;
+            acl	      = READ=NONE, UPDATE=$SOPIN, DELETE=$SOPIN;
+	    }
+
+	    EF PKCS15-PrKDF {
+            file-id	  = 4402;
+            structure = transparent;
+            size	  = $prkdf-size;
+            acl	      = *=NEVER, READ=NONE, UPDATE=$PIN, DELETE=$SOPIN;
+	    }
+
+	    EF PKCS15-PuKDF {
+            file-id	  = 4404;
+            structure = transparent;
+            size	  = $pukdf-size;
+            acl	      = *=NEVER, READ=NONE, UPDATE=$PIN, DELETE=$SOPIN;
+	    }
+
+		EF PKCS15-SKDF {
+			file-id	  = 4407;
+			structure = transparent;
+			size	  = $skdf-size;
+			acl	      = *=NEVER, READ=NONE, UPDATE=$PIN, DELETE=$SOPIN;
+		}
+
+		EF PKCS15-CDF {
+			file-id	  = 4403;
+			structure = transparent;
+			size	  = $cdf-size;
+			acl	      = *=NEVER, READ=NONE, UPDATE=$PIN, DELETE=$SOPIN;
+		}
+
+		EF PKCS15-CDF-TRUSTED {
+			file-id	  = 4405;
+			structure = transparent;
+			size	  = $cdf-trusted-size;
+			acl	      = *=NEVER, READ=NONE, UPDATE=$PIN, DELETE=$SOPIN;
+		}
+
+		EF PKCS15-DODF {
+			file-id	  = 4406;
+			structure = transparent;
+			size	  = $dodf-size;
+			acl       = *=NEVER, READ=NONE, UPDATE=$PIN, DELETE=$SOPIN;
+		}
+
+		EF template-private-key {
+			type      = internal-ef;
+			file-id   = 4B01;
+			acl       = CRYPTO=$PIN, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
+		}
+		
+		EF template-secret-key {
+			type      = internal-ef;
+			file-id   = 4D01;
+			acl       = CRYPTO=$PIN, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
+		}
+		
+		EF template-public-key {
+			structure = transparent;
+			file-id	  = 5501;
+			acl	      = READ=NONE, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
+		}
+
+		EF template-certificate {
+			file-id   = 4301;
+			structure = transparent;
+			acl       = READ=NONE, UPDATE=$PIN, DELETE=$PIN;
+		}
+
+		template key-domain {
+			# This is a dummy entry - pkcs15-init insists that
+			# this is present
+			EF private-key {
+				file-id   = 4B01;
+				type      = internal-ef;
+				acl       = CRYPTO=$PIN, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
+			}
+			EF public-key {
+				file-id   = 5501;
+				structure = transparent;
+				acl       = READ=NONE, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
+			}
+			EF secret-key {
+				file-id   = 4D01;
+				type      = internal-ef;
+				acl       = CRYPTO=$PIN, UPDATE=$PIN, DELETE=$PIN, GENERATE=$PIN;
+			}
+	
+			# Certificate template
+			EF certificate {
+				file-id	  = 4301;
+				structure = transparent;
+				acl       = READ=NONE, UPDATE=$PIN, DELETE=$PIN;
+			}
+			EF privdata {
+				file-id   = 4501;
+				structure = transparent;
+				acl       = READ=$PIN, UPDATE=$PIN, DELETE=$PIN;
+			}
+			EF data {
+				file-id   = 4601;
+				structure = transparent;
+				acl       = READ=NONE, UPDATE=$PIN, DELETE=$PIN;
+			}
+		}
+
+	}
+    }
+}
+  ;õ–  �1þEMyEID) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  MyEID   U 0VX
� 
    À 	�  j‚ MyEID   U 0VX
�  o�ÿ‚8ƒ? †?ÿ… Š�  j†) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  j‚) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  �  o€ú‚ƒD†?ÿ…  Š�  j‚) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  �  o€ ÿ‚ƒP1†?ÿ…  Š�  �  j‚) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  �  o€ú‚ƒD†?ÿ…  Š�  o€ ÿ‚ƒP1†?ÿ…  Š�  �  j‚) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  �  o€ú‚ƒD†?ÿ…  Š�  o€ ÿ‚ƒP1†?ÿ…  Š�  �  j‚) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  �  o€ú‚ƒD†?ÿ…  Š�  o€ ÿ‚ƒP1†?ÿ…  Š�  �  j‚) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  �  o€þ‚ƒD†?ÿ…  Š�  o€ ÿ‚ƒP1†?ÿ…  Š�  �  j‚) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  �  o€ú‚ƒD†?ÿ…  Š�  o€ ÿ‚ƒP1†?ÿ…  Š�  �  �  MyEID   U 0VX+�  j‚) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  �  o€ ÿ‚ƒD†?ÿ…  Š�  �  o€ ÿ‚ƒP1†?ÿ…  Š�  �  j‚ j‚ o�ÿ‚8ƒ? †?ÿ… Š�  �  o€ €‚ƒ/ †?ÿ…  Š�  o€ €‚ƒ/ †?ÿ…  Š� ‚                                                                                                                                 �  o€ €‚ƒ/ †?ÿ…  Š�  �  j‚) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  �  o€ ´‚ƒP2†?ÿ…  Š�  �  j‚) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  �  o€ €‚ƒIF†?ÿ…  Š�  �  j†) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  o€ ÿ‚ƒP1†?ÿ…  Š�  
+0? PD¡
+0? PD£
+0? PD¤
+0? PD¥
+0? PD§
+0? PD¨
+0? PD                                                                                                                                                                           �  o€ ´‚ƒP2†?ÿ…  Š� ¶ 0�± 
+   U 0VX

Aventra Ltd.€MyEID0¢t0� 
	`†He 0‚ 
	`†He 0� 
	`†He) 0‚ 
	`†He* ¥20211220114021Z�  o€ ÿ‚ƒD†?ÿ…  Š� 0;0
Security Officer PINÀ0ÿ¡0 
+€ÿ                                                                                                                                                                                                  �  �  o€ ÿ‚ƒD†?ÿ…  Š�  �  o€ú‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 � ü                                                                                                                                                                                                                                                           �  j‚ j‚) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  �  o€ƒ‚ƒF†ÿ…  Š�  �  �  o€ú‚ƒD†?ÿ…  Š�  �  �  �  �  �  �  o€ú‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 � ü                                                                                                                                                                                                                                                           �  o€ú‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 � ü                                                                                                                                                                                                                                                           �  o€ú‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 � ü                                                                                                                                                                                                                                                           �  o€þ‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                �  j† j‚) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  �  o� ‚ƒK†ÿ…  Š� ‚ �
“2¢ÑmÿH\Ljì>]m•ó
mF�o5BØX/7ý˜Zpn[0 Š 1YÆs¤¨ê Ô
|
d©"1^’�Ü&Ó>y°’÷Šð–®öºUj �ZÃ;rf:Š<4žoë‰Iò?g ”¹¸ØîøñüÜ©ª§�ü÷ßÝÝÂú2òQ�  j† o� ‚ƒK†ÿ… Š� ‚ �
“2¢ÑmÿH\Ljì>]m•ó
mF�o5BØX/7ý˜Zpn[0 Š 1YÆs¤¨ê Ô
|
d©"1^’�Ü&Ó>y°’÷Šð–®öºUj �ZÃ;rf:Š<4žoë‰Iò?g ”¹¸ØîøñüÜ©ª§�ü÷ßÝÝÂú2òQ�  o€ú‚ƒD†?ÿ…  Š�  �  �  �  �  �  �  j‚ j‚) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  �  o€ Œ‚ƒU†ÿ…  Š�  �  o€ú‚ƒD†?ÿ…  Š�  �  �  �  �  �  �  o€ú‚ƒD†?ÿ…  Š� 0K0

Private KeyÀ0!=E´Ó�2š÷&R$H<
úv|yö ¸¡00? PK                                                                                                                                                                                    �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 � ü                                                                                                                                                                                                                                                           �  o€ú‚ƒD†?ÿ…  Š� 0G0

Private Key@0 =E´Ó�2š÷&R$H<
úv|yö  ¡00? PU                                                                                                                                                                                        �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 � ü                                                                                                                                                                                                                                                           �  o€ú‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 � ü                                                                                                                                                                                                                                                           �  o€þ‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                �  j† o� ‚ƒK†ÿ… Š�  j† j‚) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  �  o� ‚"ƒK†ÿ…  Š� E †A`p	\Ãv8Kónc?¼%“tã¥õ_å
Ó¶k‡åHª=c5S
çOаŽ4ËÎ"p ¯Í‡QmóeÊí •°—‚É�  j† o� ‚"ƒK†ÿ… Š� E †A`p	\Ãv8Kónc?¼%“tã¥õ_å
Ó¶k‡åHª=c5S
çOаŽ4ËÎ"p ¯Í‡QmóeÊí •°—‚É�  o€ú‚ƒD†?ÿ…  Š�  �  �  �  �  �  �  j‚ j‚) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  �  o€ [‚ƒU†ÿ…  Š�  �  o€ú‚ƒD†?ÿ…  Š�  �  �  �  �  �  �  o€ú‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 � ü                                                                                                                                                                                                                                                           �  o€ú‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 � ü                                                                                                                                                                                                                                                           �  o€ú‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 � ü                                                                                                                                                                                                                                                           �  o€þ‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                �  j† j‚ o€ú‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 � ü                                                                                                                                                                                                                                                           �  o€ú‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 � ü                                                                                                                                                                                                                                                           �  o€ú‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 � ü                                                                                                                                                                                                                                                           �  o€þ‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                �  j† j‚ o€ú‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 � ü                                                                                                                                                                                                                                                           �  o€ú‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 � ü                                                                                                                                                                                                                                                           �  o€ú‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                 � ü                                                                                                                                                                                                                                                           �  o€þ‚ƒD†?ÿ…  Š�                                                                                                                                                                                                                                                                 �                                                                                                                                                                                                                                                                �  j† j‚ �  j†) o%�ÿ‚8ƒP†ÿ… Š„
    cPKCS-15�  o€ ÿ‚ƒP1†?ÿ…  Š�  
+0? PD¡
+0? PD£
+0? PD¤
+0? PD¥
+0? PD§
+0? PD¨
+0? PD                                                                                                                                                                           �  o€ ´‚ƒP2†?ÿ…  Š� ¶ 0�± 
+   U 0VX

Aventra Ltd.€MyEID0¢t0� 
	`†He 0‚ 
	`†He 0� 
	`†He) 0‚ 
	`†He* ¥20211013154624Z�  o€ ÿ‚ƒD†?ÿ…  Š� 0;0
Security Officer PINÀ0ÿ¡0 
+€ÿ000
	Basic PINÀ0¡0

+€ÿ                                                                                                                                                �  o�ÿ‚8ƒ? †?ÿ… Š�  � 
\ Kein Zeilenumbruch am Dateiende.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_tool/580ffba4a6c4d24100dd3dc11ab0014be3de7a6b und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_tool/580ffba4a6c4d24100dd3dc11ab0014be3de7a6b sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_tool/5ccb89aff2634fc168e0758cb2005d6dcf0398bc und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_tool/5ccb89aff2634fc168e0758cb2005d6dcf0398bc sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_tool/69456a048f311376c4093ae2c613ac1f261c6207 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_tool/69456a048f311376c4093ae2c613ac1f261c6207 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_tool/a1e04ba21b4b54a1fdc048611c4f890405c9885d und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_tool/a1e04ba21b4b54a1fdc048611c4f890405c9885d sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_tool/a3289103f478310fe6013369adf1b1e0e44b14c2 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_tool/a3289103f478310fe6013369adf1b1e0e44b14c2 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_tool/ade754cf6e6f55b8873e6d6a12080e7f8b4366ee und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_tool/ade754cf6e6f55b8873e6d6a12080e7f8b4366ee sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_tool/c2e3f533efccdfbba6de4c3d2e4aea831f508034 und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_tool/c2e3f533efccdfbba6de4c3d2e4aea831f508034 sind verschieden.
Binärdateien /tmp/fwwyN0aaoU/opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_pkcs15_tool/f1cac4a34dcb285f87df7a4568fe8eb00f9a4cad und /tmp/MJ1fzeiQgB/opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_pkcs15_tool/f1cac4a34dcb285f87df7a4568fe8eb00f9a4cad sind verschieden.
diff -Nru opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_scconf_parse_string/497025125e0dfab0b9e16155ce16d6e25ec8ec6d opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_scconf_parse_string/497025125e0dfab0b9e16155ce16d6e25ec8ec6d
--- opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_scconf_parse_string/497025125e0dfab0b9e16155ce16d6e25ec8ec6d	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_scconf_parse_string/497025125e0dfab0b9e16155ce16d6e25ec8ec6d	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,183 @@
+app default {
+	debug = 3;
+	# Disable pop-ups of built-in GUI
+	disable_popups = true;
+	enable_default_driver = true;
+
+	ignored_readers = "CardMan 1021", "SPR 532";
+
+	# The following section shows definitions for PC/SC readers.
+	reader_driver pcsc {
+		max_send_size = 65535;
+		max_recv_size = 65536;
+		connect_exclusive = true;
+		disconnect_action = reset;
+		transaction_end_action = reset;
+		reconnect_action = reset;
+		enable_pinpad = false;
+		fixed_pinlength = 6;
+		enable_escape = true;
+		provider_library = @DEFAULT_PCSC_PROVIDER@
+	}
+
+	reader_driver openct {
+		readers = 5;
+
+		max_send_size = 255;
+		max_recv_size = 256;
+	}
+
+	reader_driver cryptotokenkit {
+		max_send_size = 65535;
+		max_recv_size = 65536;
+	}
+
+	card_drivers = old, internal;
+	card_driver customcos {
+		module = @LIBDIR@@LIB_PRE at card_customcos@DYN_LIB_EXT@;
+	}
+
+	card_driver npa {
+		can = 222222;
+		st_dv_certificate = ZZSTDVCA00001.cvcert;
+		st_certificate = ZZSTTERM00001.cvcert;
+		st_key = ZZSTTERM00001.pkcs8;
+	}
+	card_atr 3b:8c:80:01:59:75:62:69:6b:65:79:4e:45:4f:72:33:58 {
+		atrmask = "FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:FF:00:00";
+		name = "Yubikey Neo";
+		driver = "PIV-II";
+		flags = "keep_alive";
+	}
+
+	card_atr 3B:DD:18:00:81:31:FE:45:80:F9:A0:00:00:00:77:01:00:70:0A:90:00:8B {
+		type = 11100;
+		driver = "authentic";
+		name = "AuthentIC v3.1";
+		secure_messaging = local_authentic;
+	}
+	card_atr 3B:7F:96:00:00:00:31:B9:64:40:70:14:10:73:94:01:80:82:90:00 {
+		type = 25001;
+		driver = "iasecc";
+		name = "Gemalto MultiApp IAS/ECC v1.0.1";
+		secure_messaging = local_gemalto_iam;
+		secure_messaging = local_adele;
+		read_only = false;
+		md_supports_X509_enrollment = true;
+	}
+	card_atr 3B:7F:96:00:00:00:31:B8:64:40:70:14:10:73:94:01:80:82:90:00 {
+		type = 25001;
+		driver = "iasecc";
+		name = "Gemalto MultiApp IAS/ECC v1.0.1";
+		secure_messaging = local_gemalto_iam;
+		read_only = false;
+		md_supports_X509_enrollment = true;
+	}
+	card_atr 3B:DF:18:FF:81:91:FE:1F:C3:00:31:B8:64:0C:01:EC:C1:73:94:01:80:82:90:00:B3 {
+		type = 25004;
+		driver = "iasecc";
+		name = "Amos IAS/ECC v1.0.1";
+		read_only = false;
+		md_supports_X509_enrollment = true;
+		secure_messaging = local_amos;
+	}
+	# SmartCard-HSM with fingerprint sensor and PIN pad
+	card_atr 3B:80:80:01:01 {
+		force_protocol = "t1";
+		read_only = true;
+		md_supports_X509_enrollment = true;
+		md_supports_container_key_gen = true;
+		md_guid_as_label = true;
+		md_pinpad_dlg_main = "Fingerabdruck oder PIN eingeben";
+		md_pinpad_dlg_content_user = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN auf der Karte.";
+		md_pinpad_dlg_content_user_sign = "Bitte verifizieren Sie Ihren Fingarabdruck oder Ihre PIN für die digitale Signatur auf der Karte.";
+		md_pinpad_dlg_content_admin = "Bitte geben Sie Ihre PIN zum Entsperren der Nutzer-PIN auf dem PIN-Pad ein.";
+		md_pinpad_dlg_expanded = "Dieses Fenster wird automatisch geschlossen, wenn die PIN oder der Fingerabdruck verifiziert wurde (Timeout nach 30 Sekunden). Nutzen Sie das PIN-Pad, um die Eingabe abzubrechen.";
+		md_pinpad_dlg_timeout = 30;
+		notify_card_inserted = "GoID erkannt";
+		notify_card_inserted_text = "";
+		notify_card_removed = "GoID entfernt";
+		notify_pin_good = "Fingerabdruck bzw. PIN verifiziert";
+		notify_pin_good_text = "GoID ist entsperrt";
+		notify_pin_bad = "Fingerabdruck bzw. PIN nicht verifiziert";
+		notify_pin_bad_text = "GoID ist gesperrt";
+	}
+
+	secure_messaging local_authentic  {
+		module_path = @DEFAULT_SM_MODULE_PATH@;
+		mode = transmit;
+		flags = 0x78;
+		kmc = "00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00";
+	}
+
+	secure_messaging local_gemalto_iam  {
+		module_name = @DEFAULT_SM_MODULE@;
+		type = acl;	     # transmit, acl
+
+		ifd_serial = "11:22:33:44:55:66:77:88";
+		keyset_02_enc = "RW_PRIV_ENC_TEST";
+		keyset_02_mac = "RW_PRIV_MAC_TEST";
+		keyset_E828BD080FD2504543432D654944_01_enc = "RO_ENC_TEST_KEY_";
+		keyset_E828BD080FD2504543432D654944_01_mac = "RO_MAC_TEST_KEY_";
+		keyset_E828BD080FD2504543432D654944_03_enc = "RW_PUBL_ENC_TEST";
+		keyset_E828BD080FD2504543432D654944_03_mac = "RW_PUBL_MAC_TEST";
+	}
+
+	framework pkcs15 {
+		use_file_caching = true;
+		use_pin_caching = false;
+		pin_cache_counter = 3;
+		pin_cache_ignore_user_consent = true;
+		private_certificate = declassify;
+		enable_pkcs15_emulation = no;
+		try_emulation_first = yes;
+		enable_builtin_emulation = no;
+		builtin_emulators = old, internal;
+		emulate custom {
+			module = @LIBDIR@@LIB_PRE at p15emu_custom@DYN_LIB_EXT@;
+		}
+		application E828BD080FD25047656E65726963 {
+			type = generic;
+			model = "ECC Generic PKI";
+		}
+
+		application E828BD080FD2500000040301 {
+			type = generic;
+			model = "Adèle Générique";
+		}
+	}
+}
+
+app opensc-pkcs11 {
+	pkcs11 {
+		max_virtual_slots = 32;
+		slots_per_card = 2;
+		lock_login = true;
+		atomic = true;
+		init_sloppy = false;
+		user_pin_unblock_style = set_pin_in_unlogged_session;
+		create_puk_slot = true;
+		create_slots_for_pins = "user,sign";
+		create_slots_for_pins = "sign";
+		create_slots_for_pins = "user"
+	}
+}
+
+app onepin-opensc-pkcs11 {
+	pkcs11 {
+		slots_per_card = 1;
+	}
+}
+
+# Used by OpenSC.tokend on Mac OS X only
+app tokend {
+	framework tokend {
+		score = 10;
+		ignore_private_certificate = false;
+	}
+}
+
+# Used by OpenSC minidriver on Windows only
+app cardmod {
+}
+
diff -Nru opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_scconf_parse_string/fa7e8cb717af33932718d96a3c785268311d9c6f opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_scconf_parse_string/fa7e8cb717af33932718d96a3c785268311d9c6f
--- opensc-0.22.0/src/tests/fuzzing/corpus/fuzz_scconf_parse_string/fa7e8cb717af33932718d96a3c785268311d9c6f	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/fuzzing/corpus/fuzz_scconf_parse_string/fa7e8cb717af33932718d96a3c785268311d9c6f	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,10 @@
+app default {
+	debug = 0;
+	debug_file = stdout;
+	framework pkcs15 {
+		enable_builtin_emulation = yes;
+		builtin_emulators = old, jpki, dnie, gids, PIV-II;
+
+	}
+}
+
diff -Nru opensc-0.22.0/src/tests/fuzzing/fuzz_asn1_print.c opensc-0.23.0/src/tests/fuzzing/fuzz_asn1_print.c
--- opensc-0.22.0/src/tests/fuzzing/fuzz_asn1_print.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/fuzzing/fuzz_asn1_print.c	2022-11-29 09:34:43.000000000 +0100
@@ -23,7 +23,9 @@
 #include "libopensc/asn1.h"
 
 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
+#ifdef FUZZING_ENABLED
     fclose(stdout);
+#endif
     sc_asn1_print_tags(Data, Size);
     return 0;
 }
diff -Nru opensc-0.22.0/src/tests/fuzzing/fuzz_card.c opensc-0.23.0/src/tests/fuzzing/fuzz_card.c
--- opensc-0.22.0/src/tests/fuzzing/fuzz_card.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/fuzzing/fuzz_card.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,103 @@
+/*
+ * fuzz_card.c: Fuzzer for sc_* functions
+ *
+ * Copyright (C) 2022 Red Hat, Inc.
+ *
+ * Author: Veronika Hanulikova <vhanulik at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "fuzzer_reader.h"
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+	sc_context_t     *ctx = NULL;
+	sc_card_t        *card = NULL;
+	struct sc_reader *reader = NULL;
+	unsigned long     flag = 0;
+	const uint8_t    *ptr = NULL;
+	uint16_t          ptr_size = 0;
+	u8                files[SC_MAX_EXT_APDU_BUFFER_SIZE];
+	uint8_t           len = 0;
+	u8               *rnd = NULL, *wrap_buf = NULL, *unwrap_buf = NULL;
+	size_t            wrap_buf_len = 0, unwrap_buf_len = 0;
+	int               r = 0;
+
+#ifdef FUZZING_ENABLED
+	fclose(stdout);
+#endif
+
+	if (size <= sizeof(unsigned long) + 1)
+		return 0;
+
+	flag = *((unsigned long *) data);
+	len = *(data + sizeof(unsigned long));
+	data += (sizeof(unsigned long) + sizeof(uint8_t));
+	size -= (sizeof(unsigned long) + sizeof(uint8_t));
+
+	/* Establish context for fuzz app*/
+	sc_establish_context(&ctx, "fuzz");
+	if (!ctx)
+		return 0;
+
+	if (fuzz_connect_card(ctx, &card, &reader, data, size) != SC_SUCCESS)
+		goto err;
+
+	/* Wrap & Unwrap*/
+	if (!(wrap_buf = malloc(SC_MAX_APDU_BUFFER_SIZE)))
+		goto err;
+	wrap_buf_len = SC_MAX_APDU_BUFFER_SIZE;
+	sc_wrap(card, NULL, 0, wrap_buf, wrap_buf_len);
+
+	fuzz_get_chunk(reader, &ptr, &ptr_size);
+	if (!(unwrap_buf = malloc(ptr_size)))
+		goto err;
+	memcpy(unwrap_buf, ptr, ptr_size);
+	unwrap_buf_len = ptr_size;
+	sc_unwrap(card, unwrap_buf, unwrap_buf_len, NULL, 0);
+
+	/* Write binary  */
+	sc_write_binary(card, 0, ptr, ptr_size, flag);
+
+	/* Put data */
+	fuzz_get_chunk(reader, &ptr, &ptr_size);
+	sc_put_data(card, flag, ptr, ptr_size);
+
+	/* List files */
+	sc_list_files(card, files, sizeof(files));
+
+	/* Get challenge */
+	rnd = malloc(len);
+	if (rnd == NULL)
+		goto err;
+	if ((r = sc_get_challenge(card, rnd, len)) != SC_SUCCESS)
+		sc_log(ctx, "sc_get_challenge failed with rc = %d", r);
+
+	/* Append record */
+	sc_append_record(card, ptr, ptr_size, flag);
+
+err:
+	free(rnd);
+	free(wrap_buf);
+	free(unwrap_buf);
+	sc_disconnect_card(card);
+	sc_release_context(ctx);
+	return 0;
+}
diff -Nru opensc-0.22.0/src/tests/fuzzing/fuzzer.c opensc-0.23.0/src/tests/fuzzing/fuzzer.c
--- opensc-0.22.0/src/tests/fuzzing/fuzzer.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/fuzzing/fuzzer.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,67 @@
+/*
+ * fuzzer.c: Standalone main for fuzz target
+ *
+ * Copyright (C) 2021 Red Hat, Inc.
+ *
+ * Author: Veronika Hanulikova <vhanulik at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+
+int LLVMFuzzerTestOneInput (const unsigned char *data, size_t size);
+
+int main (int argc, char **argv)
+{
+    printf("Testing one input:\n");
+    FILE *fd = NULL;
+    long int len = 0;
+    unsigned char *buffer = NULL;
+    int r = 1;
+
+    if (argc < 2) {
+        fprintf(stderr, "No arguments, passing NULL\n");
+        len = 0;
+    } else {
+        if ((fd = fopen(argv[1], "r")) == NULL
+                || fseek(fd, 0, SEEK_END) != 0
+                || (len = ftell(fd)) < 0) {
+            fprintf(stderr, "fopen/fseek failed\n");
+            goto err;
+        }
+        rewind(fd);
+        if ((buffer = (unsigned char*) malloc(len)) == NULL) {
+            fprintf(stderr, "malloc failed\n");
+            goto err;
+        }
+
+        if (fread(buffer, 1, len, fd) != (size_t)len) {
+            fprintf(stderr, "fread failed\n");
+            goto err;
+        }
+    }
+
+    LLVMFuzzerTestOneInput(buffer, len);
+    r = 0;
+
+err:
+    if (fd)
+        fclose(fd);
+    if (buffer)
+        free(buffer);
+    printf("Done!\n");
+    return r;
+}
diff -Nru opensc-0.22.0/src/tests/fuzzing/fuzzer_reader.c opensc-0.23.0/src/tests/fuzzing/fuzzer_reader.c
--- opensc-0.22.0/src/tests/fuzzing/fuzzer_reader.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/fuzzing/fuzzer_reader.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,212 @@
+/*
+ * Copyright (C) 2019 Frank Morgner <frankmorgner at gmail.com>
+ *
+ * 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
+ */
+
+#include "fuzzer_reader.h"
+
+/* private data structures */
+struct driver_data {
+    const uint8_t *Data;
+    size_t Size;
+};
+
+static struct sc_reader_operations fuzz_ops = {0};
+static struct sc_reader_driver fuzz_drv = {
+    "Fuzzing reader",
+    "fuzz",
+    &fuzz_ops,
+    NULL
+};
+
+void fuzz_get_chunk(sc_reader_t *reader, const uint8_t **chunk, uint16_t *chunk_size)
+{
+    struct driver_data *data;
+    uint16_t c_size;
+    const uint8_t *c;
+
+    if (chunk)
+        *chunk = NULL;
+    if (chunk_size)
+        *chunk_size = 0;
+
+    if (!chunk || !chunk_size || !reader) {
+        if (reader)
+            sc_debug(reader->ctx, SC_LOG_DEBUG_VERBOSE_TOOL, "Invalid Arguments");
+        return;
+    }
+    data = reader->drv_data;
+    if (!data || !data->Data || data->Size < sizeof c_size) {
+        sc_debug(reader->ctx, SC_LOG_DEBUG_VERBOSE_TOOL, "Invalid Arguments");
+        return;
+    }
+    /* parse the length of the returned data on two bytes */
+    c_size = *((uint16_t *) data->Data);
+    /* consume two bytes from the fuzzing data */
+    data->Size -= sizeof c_size;
+    data->Data += sizeof c_size;
+
+    if (data->Size < c_size) {
+        c_size = data->Size;
+    }
+
+    /* consume the bytes from the fuzzing data */
+    c = data->Data;
+    data->Size -= c_size;
+    data->Data += c_size;
+
+    sc_debug_hex(reader->ctx, SC_LOG_DEBUG_VERBOSE_TOOL,
+        "Returning fuzzing chunk", c, c_size);
+
+    *chunk = c;
+    *chunk_size = c_size;
+}
+
+static int fuzz_reader_release(sc_reader_t *reader)
+{
+    if (reader) {
+        free(reader->drv_data);
+        reader->drv_data = NULL;
+    }
+
+    return SC_SUCCESS;
+}
+
+static int fuzz_reader_connect(sc_reader_t *reader)
+{
+    uint16_t chunk_size;
+    const uint8_t *chunk;
+
+    fuzz_get_chunk(reader, &chunk, &chunk_size);
+
+    if (chunk_size > SC_MAX_ATR_SIZE)
+        chunk_size = SC_MAX_ATR_SIZE;
+    else
+        reader->atr.len = chunk_size;
+
+    if (chunk_size > 0)
+        memcpy(reader->atr.value, chunk, chunk_size);
+
+    return SC_SUCCESS;
+}
+
+static int fuzz_reader_disconnect(sc_reader_t *reader)
+{
+    return SC_SUCCESS;
+}
+
+static int fuzz_reader_transmit(sc_reader_t *reader, sc_apdu_t *apdu)
+{
+    const uint8_t *chunk;
+    uint16_t chunk_size;
+
+    fuzz_get_chunk(reader, &chunk, &chunk_size);
+
+    if (chunk_size >= 2) {
+        /* set the SW1 and SW2 status bytes (the last two bytes of
+         * the response */
+        apdu->sw1 = (unsigned int)chunk[chunk_size - 2];
+        apdu->sw2 = (unsigned int)chunk[chunk_size - 1];
+        chunk_size -= 2;
+        /* set output length and copy the returned data if necessary */
+        if (chunk_size <= apdu->resplen)
+            apdu->resplen = chunk_size;
+
+        if (apdu->resplen != 0)
+            memcpy(apdu->resp, chunk, apdu->resplen);
+    } else {
+        apdu->sw1 = 0x6D;
+        apdu->sw2 = 0x00;
+        apdu->resplen = 0;
+    }
+
+    return SC_SUCCESS;
+}
+
+static int fuzz_reader_lock(sc_reader_t *reader)
+{
+    return 0;
+}
+
+static int fuzz_reader_unlock(sc_reader_t *reader)
+{
+    return 0;
+}
+
+struct sc_reader_driver *sc_get_fuzz_driver(void)
+{
+    fuzz_ops.release = fuzz_reader_release;
+    fuzz_ops.connect = fuzz_reader_connect;
+    fuzz_ops.disconnect = fuzz_reader_disconnect;
+    fuzz_ops.transmit = fuzz_reader_transmit;
+    fuzz_ops.lock = fuzz_reader_lock;
+    fuzz_ops.unlock = fuzz_reader_unlock;
+    return &fuzz_drv;
+}
+
+void fuzz_add_reader(struct sc_context *ctx, const uint8_t *Data, size_t Size)
+{
+    sc_reader_t	*reader;
+    struct driver_data *data;
+    char name[64] = {0};
+
+    if (!(reader = calloc(1, sizeof(*reader)))
+            || !(data = (calloc(1, sizeof(*data))))) {
+        free(reader);
+        return;
+    }
+
+    data->Data = Data;
+    data->Size = Size;
+
+    reader->driver = &fuzz_drv;
+    reader->ops = &fuzz_ops;
+    reader->drv_data = data;
+    snprintf(name, sizeof name - 1, "%zu random byte%s reader (%p)",
+            Size, Size == 1 ? "" : "s", Data);
+    reader->name = strdup(name);
+
+    reader->ctx = ctx;
+    list_append(&ctx->readers, reader);
+}
+
+int fuzz_connect_card(sc_context_t *ctx, sc_card_t **card, sc_reader_t **reader_out,
+                      const uint8_t *data, size_t size)
+{
+    struct sc_reader *reader = NULL;
+
+    /* Erase possible readers from ctx */
+    while (list_size(&ctx->readers)) {
+        sc_reader_t *rdr = (sc_reader_t *) list_get_at(&ctx->readers, 0);
+        _sc_delete_reader(ctx, rdr);
+    }
+    if (ctx->reader_driver->ops->finish != NULL)
+        ctx->reader_driver->ops->finish(ctx);
+
+    /* Create virtual reader */
+    ctx->reader_driver = sc_get_fuzz_driver();
+    fuzz_add_reader(ctx, data, size);
+    reader = sc_ctx_get_reader(ctx, 0);
+
+    /* Connect card */
+    if (sc_connect_card(reader, card))
+        return SC_ERROR_INTERNAL;
+
+    if (reader_out)
+        *reader_out = reader;
+
+    return SC_SUCCESS;
+}
diff -Nru opensc-0.22.0/src/tests/fuzzing/fuzzer_reader.h opensc-0.23.0/src/tests/fuzzing/fuzzer_reader.h
--- opensc-0.22.0/src/tests/fuzzing/fuzzer_reader.h	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/fuzzing/fuzzer_reader.h	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2019 Frank Morgner <frankmorgner at gmail.com>
+ *
+ * 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
+ */
+
+#ifndef FUZZER_READER_H
+#define FUZZER_READER_H
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include "libopensc/internal.h"
+
+void fuzz_get_chunk(sc_reader_t *reader, const uint8_t **chunk, uint16_t *chunk_size);
+struct sc_reader_driver *sc_get_fuzz_driver(void);
+void fuzz_add_reader(struct sc_context *ctx, const uint8_t *Data, size_t Size);
+int fuzz_connect_card(sc_context_t *ctx, sc_card_t **card, sc_reader_t **reader_out,
+                      const uint8_t *data, size_t size);
+
+#endif /* FUZZER_TOOL_H */
diff -Nru opensc-0.22.0/src/tests/fuzzing/fuzzer_tool.c opensc-0.23.0/src/tests/fuzzing/fuzzer_tool.c
--- opensc-0.22.0/src/tests/fuzzing/fuzzer_tool.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/fuzzing/fuzzer_tool.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,171 @@
+/*
+ * fuzzer_tool.c: Implementation of general tool-fuzzing functions
+ *
+ * Copyright (C) 2022 Red Hat, Inc.
+ *
+ * Author: Veronika Hanulikova <vhanulik at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "fuzzer_tool.h"
+#define MAX_ARGC 10000
+
+const uint8_t *get_word(const uint8_t *data, size_t size)
+{
+	/* Words are separated by one zero byte,
+	   return pointer to the next word if there is one */
+	const uint8_t *ptr = data;
+	if (!data || size == 0 || *data == 0)
+		return NULL;
+	
+	ptr = memchr(data, 0, size - 1);
+	return ptr ? ++ptr : NULL;
+}
+
+char *extract_word(const uint8_t **data, size_t *size)
+{
+	/* Find word and return its copy (needs to be freed) */
+	char *result = NULL;
+	const uint8_t *ptr = NULL;
+
+	if (*size < 2)
+		return NULL;
+
+	ptr = get_word(*data, *size);
+	if (!ptr)
+		return NULL;
+	result = strdup((const char *)*data);
+	*size -=(ptr - *data);
+	*data = ptr;
+
+	return result;
+}
+
+int get_fuzzed_argv(const char *app_name, const uint8_t *data, size_t size,
+                    char ***argv_out, int *argc_out, const uint8_t **reader_data, size_t *reader_data_size)
+{
+	const uint8_t *ptr = data, *help_ptr = data;
+	size_t ptr_size = size;
+	char **argv = NULL;
+	int argc = 1;
+
+	/* Count arguments until double zero bytes occurs*/
+	while(*ptr != 0) {
+		ptr = get_word(help_ptr, ptr_size);
+		if (!ptr)
+			return -1;
+		argc++;
+		ptr_size -= (ptr - help_ptr);
+		help_ptr = ptr;
+	}
+
+	if (argc > MAX_ARGC)
+		return -1;
+
+	argv = malloc((argc + 1) * sizeof(char*));
+	if (!argv)
+		return -1;
+
+	/* Copy arguments into argv */
+	ptr = data;
+	ptr_size = size;
+	argv[0] = strdup(app_name);
+	for (int i = 1; i < argc; i++) {
+		argv[i] = extract_word(&ptr, &ptr_size);
+	}
+	argv[argc] = NULL;
+
+	*argc_out = argc;
+	*argv_out = argv;
+	*reader_data = ptr + 1; /* there are two zero bytes at the end of argv */
+	*reader_data_size = ptr_size - 1;
+	return 0;
+}
+
+uint16_t get_buffer(const uint8_t **buf, size_t buf_len, const uint8_t **out, size_t *out_len, size_t max_size)
+{
+	/* Split buf into two parts according to length stored in first two bytes */
+	uint16_t len = 0;
+
+	if (!buf || !(*buf) || buf_len < sizeof(uint16_t))
+		return 0;
+
+	/* Get length of the result buffer*/
+	len = *((uint16_t *) *buf) % max_size;
+	(*buf) += 2;
+	buf_len -= 2;
+	if (buf_len <= len) {
+		*out = *buf;
+		*out_len = buf_len;
+		return 0;
+	}
+
+	/* Set out buffer to new reader data*/
+	*out = *buf + len;
+	*out_len = buf_len - len;
+	return len;
+}
+
+int create_input_file(char **filename_out, const uint8_t **data, size_t *size)
+{
+	const uint8_t *ptr = *data;
+	size_t file_size = 0, backup_size = *size;
+	int fd = 0;
+	size_t r = 0;
+	char *filename = NULL;
+	
+	/* Split data into file content and rest*/
+	file_size = get_buffer(&ptr, *size, data, size, 6000);
+	if (file_size == 0)
+		return 1;
+
+	filename = strdup("/tmp/input.XXXXXX");
+	fd = mkstemp(filename);
+	if (fd < 0) {
+		*data = ptr - 2;
+		*size = backup_size;
+		free(filename);
+		return 1;
+	}
+
+	r = write(fd, ptr, file_size);
+	close(fd);
+
+	if (r != file_size) {
+		*data = ptr - 2;
+		*size = backup_size;
+		remove_file(filename);
+		return 1;
+	}
+
+	*filename_out = filename;
+	return 0;
+}
+
+void remove_file(char *filename)
+{
+	if (filename) {
+		unlink(filename);
+		free(filename);
+	}
+}
+
+void free_arguments(int argc, char **argv)
+{
+	for (int i = 0; i < argc; i++) {
+		free(argv[i]);
+	}
+	free(argv);
+}
diff -Nru opensc-0.22.0/src/tests/fuzzing/fuzzer_tool.h opensc-0.23.0/src/tests/fuzzing/fuzzer_tool.h
--- opensc-0.22.0/src/tests/fuzzing/fuzzer_tool.h	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/fuzzing/fuzzer_tool.h	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,44 @@
+/*
+ * fuzzer_tool.c: Implementation of general tool-fuzzing functions
+ *
+ * Copyright (C) 2022 Red Hat, Inc.
+ *
+ * Author: Veronika Hanulikova <vhanulik at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef FUZZER_TOOL_H
+#define FUZZER_TOOL_H
+
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#define HALF_BYTE ((sizeof(uint8_t) * 8 * 8) / 2)
+
+const uint8_t *get_word(const uint8_t *, size_t);
+char *extract_word(const uint8_t **, size_t *);
+int get_fuzzed_argv(const char *, const uint8_t *, size_t ,
+                    char***, int *, const uint8_t **, size_t *);
+uint16_t get_buffer(const uint8_t **, size_t, const uint8_t **, size_t *, size_t);
+int create_input_file(char **, const uint8_t **, size_t *);
+void remove_file(char *);
+void free_arguments(int, char **);
+
+#endif /* FUZZER_TOOL_H */
diff -Nru opensc-0.22.0/src/tests/fuzzing/fuzz_piv_tool.c opensc-0.23.0/src/tests/fuzzing/fuzz_piv_tool.c
--- opensc-0.22.0/src/tests/fuzzing/fuzz_piv_tool.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/fuzzing/fuzz_piv_tool.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,175 @@
+/*
+ * fuzz_piv_tool.c: Fuzz target for piv-tool
+ *
+ * Copyright (C) 2022 Red Hat, Inc.
+ *
+ * Author: Veronika Hanulikova <vhanulik at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "libopensc/internal.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include "fuzzer_reader.h"
+#include "fuzzer_tool.h"
+#undef stderr
+#define stderr stdout
+
+/* Rename main for calling in fuzz target */
+#define main _main
+/* Connect to virtual reader instead of real card*/
+#define util_connect_card(ctx, card, id, do_wait, verbose) fuzz_util_connect_card(ctx, card)
+# include "tools/piv-tool.c"
+#undef main
+
+static const uint8_t *reader_data = NULL;
+static size_t reader_data_size = 0;
+
+/* Use instead of util_connect_card() */
+int fuzz_util_connect_card(struct sc_context *ctx, struct sc_card **card)
+{
+	return fuzz_connect_card(ctx, card, NULL, reader_data, reader_data_size);
+}
+
+void initilize_global()
+{
+	/* Global variables need to be reser between runs,
+	   fuzz target is called repetitively in one execution */
+	reader_data = NULL;
+	reader_data_size = 0;
+	ctx = NULL;
+	card = NULL;
+	bp = NULL;
+	evpkey = NULL;
+	opt_reader = NULL;
+	opt_apdus = NULL;
+	opt_apdu_count = 0;
+
+	optind = 0;
+	opterr = 0; /* do not print out error messages */
+	optopt = 0;
+}
+
+void test_load(char *op, const uint8_t *data, size_t size)
+{
+	char *filename = NULL;
+	char *argv[] = {"./fuzz_piv", op, NULL /*ref*/, "-i", NULL /*filename*/, "-A", NULL /*admin*/, NULL};
+	int argc = 7;
+	char *opt_ref = NULL, *opt_admin = NULL;
+
+	if (!(opt_ref = extract_word(&data, &size)))
+		return;
+	argv[2] = opt_ref;
+
+	if (!(opt_admin = extract_word(&data, &size))) {
+		free(opt_ref);
+		return;
+	}
+	argv[6] = opt_admin;
+
+	if (create_input_file(&filename, &data, &size) != 0) {
+		free(opt_ref);
+		free(opt_admin);
+		remove_file(filename);
+		return;
+	}
+	argv[4] = filename;
+
+	reader_data = data;
+	reader_data_size = size;
+	_main(argc, argv);
+
+	free(opt_ref);
+	free(opt_admin);
+	remove_file(filename);
+}
+
+/* Skip argv with option for output file */
+int present_outfile(int argc, char *argv[])
+{
+	const struct option _options[] = {
+		{ "out",1, NULL,'o' },
+		{ NULL, 0, NULL, 0 }
+	};
+	int c;
+	while ((c = getopt_long(argc, argv, "o:", _options, (int *) 0)) != -1) {
+		switch (c) {
+			case 'o':
+				return 1;
+			default:
+				continue;
+		}
+	}
+	optind = 0;
+	optopt = 0;
+	return 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+	uint8_t operation = 0;
+	char *filename = NULL;
+	char **argv = NULL;
+	int argc = 0;
+	char auth_path[50] = {0};
+
+#ifdef FUZZING_ENABLED
+	fclose(stdout);
+#endif
+	if (size < 10)
+		return 0;
+
+	initilize_global();
+	operation = data[0];
+	data++;
+	size--;
+
+	/* extract admin argument and set file with admin key */
+	if (create_input_file(&filename, &data, &size) != 0 || size < 3)
+		goto err;
+	sprintf(auth_path, "PIV_EXT_AUTH_KEY=%s", filename);
+	putenv(auth_path);
+
+	switch (operation) {
+		case 0:
+			test_load("-O", data, size);
+			break;
+		case 1:
+			test_load("-C", data, size);
+			break;
+		case 2:
+			test_load("-Z", data, size);
+			break;
+		default:
+			if (get_fuzzed_argv("./fuzz_piv", data, size, &argv, &argc, &reader_data, &reader_data_size) != 0)
+				goto err;
+			if (present_outfile(argc, argv)) {
+				free_arguments(argc, argv);
+				goto err;
+			}
+			_main(argc, argv);
+			free_arguments(argc, argv);
+	}
+err:
+	reader_data = NULL;
+	reader_data_size = 0;
+	remove_file(filename);
+	return 0;
+}
diff -Nru opensc-0.22.0/src/tests/fuzzing/fuzz_pkcs11.c opensc-0.23.0/src/tests/fuzzing/fuzz_pkcs11.c
--- opensc-0.22.0/src/tests/fuzzing/fuzz_pkcs11.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/fuzzing/fuzz_pkcs11.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,1085 @@
+/*
+ * fuzz_pkcs11.c: Fuzz target for PKCS #11 API
+ *
+ * Copyright (C) 2022 Red Hat, Inc.
+ *
+ * Author: Veronika Hanulikova <vhanulik at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "pkcs11/pkcs11.h"
+#include "pkcs11/pkcs11-opensc.h"
+#include "pkcs11/sc-pkcs11.h"
+#include "fuzzer_reader.h"
+#include "fuzzer_tool.h"
+
+#define SIG_LEN 512
+
+/* If disabled, card is connected only via C_Initialize */
+#define FUZZING 1
+
+extern CK_FUNCTION_LIST_3_0 pkcs11_function_list_3_0;
+static CK_FUNCTION_LIST_3_0_PTR p11 = NULL;
+
+/* Values used for key template*/
+static CK_BBOOL _true = TRUE;
+static CK_BBOOL _false = FALSE;
+
+/* Global parameters for key template */
+CK_ULONG key_type = 0;
+unsigned char ecparams[256];
+unsigned char *opt_object_label[256];
+CK_BYTE opt_object_id[100];
+CK_MECHANISM_TYPE opt_allowed_mechanisms[20];
+
+#if FUZZING 
+static int fuzz_card_connect(const uint8_t *data, size_t size, sc_pkcs11_slot_t **slot_out)
+{
+	/* Works in the same manner as card_detect() for only one slot and card with virtual reader */
+	struct sc_pkcs11_card *p11card = NULL;
+	struct sc_reader *reader = NULL;
+	struct sc_app_info *app_generic = NULL;
+	sc_pkcs11_slot_t *slot = NULL;
+	int rv = CKR_OK, free_p11card = 0;
+
+	/* Erase possible virtual slots*/
+	list_clear(&virtual_slots);
+
+	/* Erase possible readers from context */
+	while (list_size(&context->readers)) {
+		sc_reader_t *rdr = (sc_reader_t *) list_get_at(&context->readers, 0);
+		_sc_delete_reader(context, rdr);
+	}
+	if (context->reader_driver->ops->finish != NULL)
+		context->reader_driver->ops->finish(context);
+
+	/* Create virtual reader */
+	context->reader_driver = sc_get_fuzz_driver();
+	fuzz_add_reader(context, data, size);
+	reader = sc_ctx_get_reader(context, 0);
+
+	/* Add slot for reader */
+	if (create_slot(reader) != CKR_OK) {
+		goto fail;
+	}
+
+	/* Locate a slot related to the reader */
+	for (size_t i = 0; i < list_size(&virtual_slots); i++) {
+		slot = (sc_pkcs11_slot_t *) list_get_at(&virtual_slots, i);
+		if (slot->reader == reader) {
+			p11card = slot->p11card;
+			break;
+		}
+	}
+
+	/* Create p11card */
+	p11card = (struct sc_pkcs11_card *)calloc(1, sizeof(struct sc_pkcs11_card));
+	p11card->reader = reader;
+	free_p11card = 1;
+
+	/* Connect card to reader */
+	if ((rv = sc_connect_card(reader, &p11card->card)) != SC_SUCCESS) {
+		goto fail;
+	}
+	init_slot_info(&slot->slot_info, reader);
+
+	/* Instead of detecting framework*/
+	p11card->framework = &framework_pkcs15;
+
+	/* Bind 'generic' application or (emulated?) card without applications */
+	app_generic = sc_pkcs15_get_application_by_type(p11card->card, "generic");
+	if (app_generic || !p11card->card->app_count) {
+		scconf_block *conf_block = NULL;
+
+		conf_block = sc_match_atr_block(p11card->card->ctx, NULL, &p11card->reader->atr);
+		if (!conf_block) /* check default block */
+			conf_block = sc_get_conf_block(context, "framework", "pkcs15", 1);
+
+		rv = p11card->framework->bind(p11card, app_generic);
+		if (rv != CKR_TOKEN_NOT_RECOGNIZED && rv != CKR_OK)
+			goto fail;
+
+		rv = p11card->framework->create_tokens(p11card, app_generic);
+		if (rv != CKR_OK)
+			goto fail;
+		free_p11card = 0;
+	}
+	
+	/* Bind rest of application*/
+	for (int j = 0; j < p11card->card->app_count; j++)   {
+		struct sc_app_info *app_info = p11card->card->app[j];
+
+		if (app_generic && app_generic == p11card->card->app[j])
+			continue;
+
+		if (p11card->framework->bind(p11card, app_info) != CKR_OK) {
+			continue;
+		}
+		rv = p11card->framework->create_tokens(p11card, app_info);
+		if (rv != CKR_OK) {
+			goto fail;
+		}
+		free_p11card = 0;
+	}
+	if (slot_out)
+		*slot_out = slot;
+fail:
+	if (free_p11card) {
+		sc_pkcs11_card_free(p11card);
+	}
+	return rv;
+}
+#endif
+
+static int fuzz_pkcs11_initialize(const uint8_t *data, size_t size, sc_pkcs11_slot_t **slot_out, CK_SESSION_HANDLE *session)
+{
+	p11 = &pkcs11_function_list_3_0;
+
+	context = NULL;
+	memset(&sc_pkcs11_conf, 0, sizeof(struct sc_pkcs11_config));
+
+	p11->C_Initialize(NULL);
+
+	#if FUZZING
+	/* fuzz target can connect to real card via C_Initialize */
+	if (fuzz_card_connect(data, size, slot_out) != CKR_OK) {
+		p11->C_Finalize(NULL);
+		return CKR_GENERAL_ERROR;
+	}
+	#endif
+
+	if (p11->C_OpenSession(0, CKF_SERIAL_SESSION | CKF_RW_SESSION, NULL, NULL, session) != CKR_OK) {
+		p11->C_Finalize(NULL);
+		return CKR_GENERAL_ERROR;
+	}
+	return CKR_OK;
+}
+
+static int set_mechanism(const uint8_t **data, size_t *size, CK_MECHANISM *mech)
+{
+	if (*size < sizeof(unsigned long int))
+		return 1;
+
+	memset(mech, 0, sizeof(*mech));
+	(*mech).mechanism = *((unsigned long int *)*data);
+	*data += sizeof(unsigned long int);
+	*size -= sizeof(unsigned long int);
+	return 0;
+}
+
+static void test_change_pin(const unsigned char *data, size_t size)
+{
+	CK_SESSION_HANDLE session;
+	CK_TOKEN_INFO     info;
+	char             *pin = NULL;
+	char             *new_pin = NULL;
+	int               login_type = data[0];
+	data++; size--;
+
+	if (!(pin = extract_word(&data, &size)))
+		goto end;
+	if (!(new_pin = extract_word(&data, &size)))
+		goto end;
+
+	if (fuzz_pkcs11_initialize(data, size, NULL, &session) != CKR_OK)
+		goto end;
+	p11->C_GetTokenInfo(0, &info);
+	p11->C_Login(session, login_type, (CK_UTF8CHAR *) pin, pin == NULL ? 0 : strlen(pin));
+	p11->C_SetPIN(session,
+		(CK_UTF8CHAR *) pin, pin == NULL ? 0 : strlen(pin),
+		(CK_UTF8CHAR *) new_pin, new_pin == NULL ? 0 : strlen(new_pin));
+
+	p11->C_CloseSession(session);
+	p11->C_Finalize(NULL);
+end:
+	free(new_pin);
+	free(pin);
+}
+
+static void test_init_pin(const unsigned char *data, size_t size)
+{
+	CK_SESSION_HANDLE session;
+	CK_TOKEN_INFO     info;
+	char             *pin = NULL;
+	char             *so_pin = NULL;
+	int               login_type = data[0];
+	data++; size--;
+
+	if (!(pin = extract_word(&data, &size)))
+		goto end;
+	if (!(so_pin = extract_word(&data, &size)))
+		goto end;
+
+	if (fuzz_pkcs11_initialize(data, size, NULL, &session) != CKR_OK)
+		goto end;
+	p11->C_GetTokenInfo(0, &info);
+	p11->C_Login(session, login_type, (CK_UTF8CHAR *) so_pin, so_pin == NULL ? 0 : strlen(so_pin));
+	p11->C_InitPIN(session, (CK_UTF8CHAR *) pin, pin == NULL ? 0 : strlen(pin));
+
+	p11->C_CloseSession(session);
+	p11->C_Finalize(NULL);
+end:
+	free(pin);
+	free(so_pin);
+}
+
+static void test_init_token(const unsigned char *data, size_t size)
+{
+	CK_SESSION_HANDLE session;
+	char             *pin = NULL;
+	unsigned char    *label = NULL;
+	size_t            label_len = 0;
+	unsigned char     token_label[33];
+	sc_pkcs11_slot_t *slot = NULL;
+	/* token label must be padded with blank characters, and which must not be null-terminated*/
+	memset(token_label, ' ', sizeof(token_label));
+
+	if (!(pin = extract_word(&data, &size)))
+		goto end;
+	if (!(label = (unsigned char *) extract_word(&data, &size)))
+		goto end;
+	label_len = strlen((char *) label);
+	memcpy(token_label, label, label_len < 33 ? label_len : 32);
+
+	if (fuzz_pkcs11_initialize(data, size, &slot, &session) != CKR_OK)
+		goto end;
+	p11->C_InitToken(slot->id, (CK_UTF8CHAR *) pin, pin == NULL ? 0 : strlen(pin), token_label);
+
+	p11->C_CloseSession(session);
+	p11->C_Finalize(NULL);
+end:
+	free(pin);
+	free(label);
+}
+
+static void test_random(const unsigned char *data, size_t size)
+{
+	CK_SESSION_HANDLE session;
+	size_t            random_len = data[0];
+	CK_BYTE           buf[256];
+	data++; size--;
+
+	if (fuzz_pkcs11_initialize(data, size, NULL, &session) != CKR_OK)
+		return;
+
+	p11->C_GenerateRandom(session, buf, random_len);
+
+	p11->C_CloseSession(session);
+	p11->C_Finalize(NULL);
+}
+
+static void test_digest_update(const uint8_t *data, size_t size)
+{
+	CK_SESSION_HANDLE session;
+	const uint8_t    *dig_data = NULL;
+	size_t            dig_size = 0;
+	CK_MECHANISM      mech = {0, NULL_PTR, 0};
+	unsigned char     buffer[64] = {0};
+	CK_ULONG          hash_len = sizeof(buffer);
+	int               to_process = 0, rv = 0;
+
+	if (set_mechanism(&data, &size, &mech))
+		return;
+
+	/* Copy data for hashing*/
+	dig_data = data;
+	if ((dig_size = get_buffer(&dig_data, size, &data, &size, 6000)) == 0)
+		return;
+
+	if (fuzz_pkcs11_initialize(data, size, NULL, &session) != CKR_OK)
+		return;
+
+	if (p11->C_DigestInit(session, &mech) != CKR_OK)
+		goto end;
+
+	while (dig_size > 0) {
+		to_process = dig_size > sizeof(buffer) ? sizeof(buffer) : dig_size;
+		dig_size -= to_process;
+		memcpy(buffer, dig_data, to_process);
+		dig_data += to_process;
+
+		rv = p11->C_DigestUpdate(session, buffer, to_process);
+		if (rv != CKR_OK)
+			goto end;
+	}
+	hash_len = sizeof(buffer);
+	p11->C_DigestFinal(session, buffer, &hash_len);
+
+end:
+	p11->C_CloseSession(session);
+	p11->C_Finalize(NULL);
+}
+
+void test_digest(const uint8_t *data, size_t size)
+{
+	CK_SESSION_HANDLE session;
+	const uint8_t    *ptr = NULL;
+	unsigned char    *dig_data = NULL;
+	size_t            dig_size = 0;
+	CK_MECHANISM      mech = {0, NULL_PTR, 0};
+	unsigned char     buffer[64] = {0};
+	CK_ULONG          hash_len = sizeof(buffer);
+
+	if (set_mechanism(&data, &size, &mech))
+		return;
+
+	/* Copy data for hashing*/
+	ptr = data;
+	if ((dig_size = get_buffer(&ptr, size, &data, &size, 6000)) == 0)
+		return;
+	if (!(dig_data = malloc(dig_size)))
+		return;
+	memcpy(dig_data, ptr, dig_size);
+
+	if (fuzz_pkcs11_initialize(data, size, NULL, &session) != CKR_OK)
+		goto end;
+
+	if (p11->C_DigestInit(session, &mech) == CKR_OK)
+		p11->C_Digest(session, dig_data, dig_size, buffer, &hash_len);
+
+	p11->C_CloseSession(session);
+	p11->C_Finalize(NULL);
+end:
+	free(dig_data);
+}
+
+static int fuzz_find_object(CK_SESSION_HANDLE sess, CK_OBJECT_CLASS cls,
+		CK_OBJECT_HANDLE_PTR ret, const unsigned char *id, size_t id_len)
+{
+	/* taken from tools/pkcs11-tool.c */
+	CK_ATTRIBUTE attrs[2];
+	unsigned int nattrs = 0;
+	CK_ULONG     count = 0;
+
+	attrs[0].type = CKA_CLASS;
+	attrs[0].pValue = &cls;
+	attrs[0].ulValueLen = sizeof(cls);
+	nattrs++;
+	if (id) {
+		attrs[nattrs].type = CKA_ID;
+		attrs[nattrs].pValue = (void *) id;
+		attrs[nattrs].ulValueLen = id_len;
+		nattrs++;
+	}
+
+	if (p11->C_FindObjectsInit(sess, attrs, nattrs) != CKR_OK)
+		return -1;
+
+	if (p11->C_FindObjects(sess, ret, 1, &count) != CKR_OK)
+		return -1;
+
+	if (count == 0)
+		*ret = CK_INVALID_HANDLE;
+	p11->C_FindObjectsFinal(sess);
+	return count;
+}
+
+static void test_sign(const uint8_t *data, size_t size)
+{
+	CK_SESSION_HANDLE    session;
+	uint8_t              login_type = CKU_USER;
+	char                *pin = NULL;
+	const unsigned char *opt_id;
+	size_t               opt_id_len = 0;
+	const uint8_t       *sign_data = NULL;
+	size_t               sign_data_size = 0;
+	CK_OBJECT_HANDLE     key = CK_INVALID_HANDLE;
+	unsigned char        in_buffer[1025], sig_buffer[512];
+	CK_MECHANISM         mech = {0, NULL_PTR, 0};
+	CK_ULONG             sig_len = sizeof(sig_buffer);
+	size_t               to_process = 0;
+	CK_TOKEN_INFO        info;
+
+	/* Process options*/
+	if (set_mechanism(&data, &size, &mech) || size < 3)
+		return;
+	login_type = data[0];
+	data++; size--;
+	if (!(pin = extract_word(&data, &size)))
+		return;
+	opt_id = data;
+	opt_id_len = get_buffer(&opt_id, size, &data, &size, 256);
+
+	/* Prepare buffer for signing */
+	sign_data = data;
+	if ((sign_data_size = get_buffer(&sign_data, size, &data, &size, 6000)) == 0)
+		goto end;
+
+	/* Initialize */
+	if (fuzz_pkcs11_initialize(data, size, NULL, &session) != CKR_OK)
+		goto end;
+	p11->C_GetTokenInfo(0, &info);
+	p11->C_Login(session, login_type, (CK_UTF8CHAR *) pin, strlen(pin));
+	fuzz_find_object(session, CKO_PRIVATE_KEY, &key, opt_id_len ? opt_id : NULL, opt_id_len);
+
+	if (p11->C_SignInit(session, &mech, key) != CKR_OK)
+		goto fin;
+	p11->C_Login(session, CKU_CONTEXT_SPECIFIC, (CK_UTF8CHAR *) pin, strlen(pin));
+
+	if (sign_data_size <= sizeof(in_buffer)) {
+		memcpy(in_buffer, sign_data, sign_data_size);
+		p11->C_Sign(session, in_buffer, sign_data_size, sig_buffer, &sig_len);
+	} else {
+		while (sign_data_size > 0) {
+			to_process = sign_data_size < sizeof(in_buffer) ? sign_data_size : sizeof(in_buffer);
+			sign_data_size -= to_process;
+			memcpy(in_buffer, sign_data, to_process);
+			sign_data += to_process;
+
+			if (p11->C_SignUpdate(session, in_buffer, to_process) != CKR_OK)
+				goto fin;
+		}
+
+		sig_len = sizeof(sig_buffer);
+		p11->C_SignFinal(session, sig_buffer, &sig_len);
+	}
+
+fin:
+	p11->C_CloseSession(session);
+	p11->C_Finalize(NULL);
+end:
+	free(pin);
+}
+
+static void test_verify(const uint8_t *data, size_t size)
+{
+	CK_SESSION_HANDLE    session;
+	CK_MECHANISM         mech = {0, NULL_PTR, 0};
+	uint8_t              login_type = CKU_USER;
+	char                *pin = NULL;
+	const unsigned char *opt_id = NULL;
+	size_t               opt_id_len = 0;
+	const uint8_t       *verify_data = NULL, *sig_data = NULL;
+	size_t               verify_data_size = 0;
+	CK_OBJECT_HANDLE     key = CK_INVALID_HANDLE;
+	unsigned char        in_buffer[1025], sig_buffer[512];
+	CK_ULONG             sig_len = sizeof(sig_buffer);
+	size_t               to_process = 0;
+
+	/* Process options*/
+	if (set_mechanism(&data, &size, &mech) || size < 3)
+		return;
+	login_type = data[0];
+	data++; size--;
+	if (!(pin = extract_word(&data, &size)))
+		return;
+	opt_id = data;
+	opt_id_len = get_buffer(&opt_id, size, &data, &size, 256);
+
+	/* Prepare buffer with data */
+	verify_data = data;
+	if ((verify_data_size = get_buffer(&verify_data, size, &data, &size, 6000)) == 0)
+		goto end;
+	/* Get buffer with signature */
+	sig_data = data;
+	if ((sig_len = get_buffer(&sig_data, size, &data, &size, 512)) == 0)
+		goto end;
+	memcpy(sig_buffer, sig_data, sig_len);
+
+	/* Initialize */
+	if (fuzz_pkcs11_initialize(data, size, NULL, &session) != CKR_OK)
+		goto end;
+
+	p11->C_Login(session, login_type, (CK_UTF8CHAR *) pin, strlen(pin));
+
+	if (!fuzz_find_object(session, CKO_PUBLIC_KEY, &key, opt_id_len ? opt_id : NULL, opt_id_len)
+		&& !fuzz_find_object(session, CKO_CERTIFICATE, &key, opt_id_len ? opt_id : NULL, opt_id_len))
+		goto fin;
+
+	if (p11->C_VerifyInit(session, &mech, key) != CKR_OK)
+		goto fin;
+
+	if (verify_data_size <= sizeof(in_buffer)) {
+		memcpy(in_buffer, verify_data, verify_data_size);
+		p11->C_Verify(session, in_buffer, verify_data_size, sig_buffer, sig_len);
+	} else {
+		while (size > 0) {
+			to_process = verify_data_size < sizeof(in_buffer) ? verify_data_size : sizeof(in_buffer);
+			verify_data_size -= to_process;
+			memcpy(in_buffer, data, to_process);
+			verify_data += to_process;
+
+			if (p11->C_VerifyUpdate(session, in_buffer, to_process) != CKR_OK)
+				goto fin;
+		}
+
+		p11->C_VerifyFinal(session, sig_buffer, sig_len);
+	}
+fin:
+	p11->C_CloseSession(session);
+	p11->C_Finalize(NULL);
+end:
+	free(pin);
+}
+
+static void test_decrypt(const uint8_t *data, size_t size)
+{
+	CK_SESSION_HANDLE    session;
+	uint8_t              login_type = CKU_USER;
+	char                *pin = NULL;
+	const unsigned char *opt_id;
+	size_t               opt_id_len = 0;
+	const uint8_t       *dec_data = NULL;
+	size_t               dec_data_size = 0;
+	CK_OBJECT_HANDLE     key = CK_INVALID_HANDLE;
+	unsigned char        in_buffer[1024], out_buffer[1024];
+	CK_MECHANISM         mech = {0, NULL_PTR, 0};
+	size_t               out_len = 0;
+
+	/* Process options*/
+	if (set_mechanism(&data, &size, &mech) || size < 3)
+		return;
+	login_type = data[0];
+	data++; size--;
+	if (!(pin = extract_word(&data, &size)))
+		return;
+	opt_id = data;
+	opt_id_len = get_buffer(&opt_id, size, &data, &size, 256);
+
+	/* Prepare buffer for signing */
+	dec_data = data;
+	if ((dec_data_size = get_buffer(&dec_data, size, &data, &size, 1024)) == 0)
+		goto end;
+
+	/* Initialize */
+	if (fuzz_pkcs11_initialize(data, size, NULL, &session) != CKR_OK)
+		goto end;
+
+	p11->C_Login(session, login_type, (CK_UTF8CHAR *) pin, strlen(pin));
+	if (!fuzz_find_object(session, CKO_PRIVATE_KEY, &key, opt_id_len ? opt_id : NULL, opt_id_len)
+		&& !fuzz_find_object(session, CKO_SECRET_KEY, &key, opt_id_len ? opt_id : NULL, opt_id_len))
+		goto fin;
+
+	if (p11->C_DecryptInit(session, &mech, key) != CKR_OK)
+		goto fin;
+
+	p11->C_Login(session, CKU_CONTEXT_SPECIFIC, (CK_UTF8CHAR *) pin, strlen(pin));
+	out_len = sizeof(out_buffer);
+
+	memcpy(in_buffer, dec_data, dec_data_size);
+	p11->C_Decrypt(session, in_buffer, dec_data_size, out_buffer, &out_len);
+fin:
+	p11->C_CloseSession(session);
+	p11->C_Finalize(NULL);
+end:
+	free(pin);
+}
+
+static void test_wrap(const uint8_t *data, size_t size)
+{
+	CK_SESSION_HANDLE    session;
+	uint8_t              login_type = CKU_USER;
+	char                *pin = NULL;
+	CK_BYTE              pWrappedKey[4096];
+	CK_ULONG             pulWrappedKeyLen = sizeof(pWrappedKey);
+	CK_MECHANISM         mech = {0, NULL_PTR, 0};
+	CK_OBJECT_HANDLE     hWrappingKey;
+	CK_OBJECT_HANDLE     hkey;
+	const unsigned char *hkey_id;
+	const unsigned char *opt_id;
+	size_t               opt_id_len = 0, hkey_id_len = 0;
+
+	/* Set options */
+	if (set_mechanism(&data, &size, &mech) || size < 3)
+		return;
+	login_type = data[0];
+	data++; size--;
+	if (!(pin = extract_word(&data, &size)))
+		return;
+	opt_id = data;
+	opt_id_len = get_buffer(&opt_id, size, &data, &size, 256);
+	hkey_id = data;
+	hkey_id_len = get_buffer(&hkey_id, size, &data, &size, 256);
+
+	/* Initialize */
+	if (fuzz_pkcs11_initialize(data, size, NULL, &session) != CKR_OK)
+		goto end;
+
+	p11->C_Login(session, login_type, (CK_UTF8CHAR *) pin, strlen(pin));
+	if (!fuzz_find_object(session, CKO_SECRET_KEY, &hkey, hkey_id_len ? hkey_id : NULL, hkey_id_len))
+		goto fin;
+	if (!fuzz_find_object(session, CKO_PUBLIC_KEY, &hWrappingKey, opt_id_len ? opt_id : NULL, opt_id_len))
+		if (!fuzz_find_object(session, CKO_SECRET_KEY, &hWrappingKey, opt_id_len ? opt_id : NULL, opt_id_len))
+			goto fin;
+	p11->C_WrapKey(session, &mech, hWrappingKey, hkey, pWrappedKey, &pulWrappedKeyLen);
+
+fin:
+	p11->C_CloseSession(session);
+	p11->C_Finalize(NULL);
+end:
+	free(pin);
+}
+
+#define FILL_ATTR(attr, typ, val, len) do { \
+	(attr).type=(typ); \
+	(attr).pValue=(val); \
+	(attr).ulValueLen=len; \
+} while(0)
+
+void fill_bool_attr(CK_ATTRIBUTE **keyTemplate, int *n_attr, int type, int value)
+{
+	if (value) {
+		FILL_ATTR((*keyTemplate)[*n_attr], type, &_true, sizeof(_true));
+	}
+	else {
+		FILL_ATTR((*keyTemplate)[*n_attr], type, &_false, sizeof(_false));
+	}
+	
+	++(*n_attr);
+}
+
+int fill_key_template(CK_ATTRIBUTE **keyTemplate, int *n_attr, const uint8_t **data, size_t *size, CK_OBJECT_CLASS *class, int token)
+{
+	const unsigned char *ptr = NULL;
+	size_t               ecparams_size = 0;
+	size_t               opt_object_label_size = 0;
+	size_t               opt_object_id_len = 0;
+	size_t               opt_allowed_mechanisms_len = 0;
+	int bool_types[] = {CKA_MODULUS_BITS, CKA_PUBLIC_EXPONENT, CKA_VERIFY, CKA_SENSITIVE,
+						CKA_SIGN, CKA_ENCRYPT, CKA_DECRYPT, CKA_WRAP, CKA_UNWRAP,
+						CKA_DERIVE, CKA_PRIVATE, CKA_ALWAYS_AUTHENTICATE, CKA_EXTRACTABLE};
+
+	if (!(*keyTemplate = malloc(20 * sizeof(CK_ATTRIBUTE))))
+		return 1;
+	memset(*keyTemplate, 0, 20 * sizeof(CK_ATTRIBUTE));
+	FILL_ATTR((*keyTemplate)[0], CKA_CLASS, class, sizeof(CKA_CLASS));
+	*n_attr = 1;
+	fill_bool_attr(keyTemplate, n_attr, CKA_TOKEN, token);
+
+	for (int i = 0; i < 13; i++) {
+		/* ... | present -> 0/1 | value | ...*/
+		if (*size < 3)
+			return 1;
+		if ((*data)[0] % 2) {
+			fill_bool_attr(keyTemplate, n_attr, bool_types[i], (*data)[1] % 2);
+			(*data)++; (*size)--;
+		}
+		(*data)++; (*size)--;
+	}
+
+	if (*size > 2 && (*data)[0] % 2 && *n_attr < 20){
+		/* ... | present -> 0/1 | value | ...*/
+		key_type = (CK_ULONG) (*data)[1];
+		FILL_ATTR((*keyTemplate)[*n_attr], CKA_KEY_TYPE, &key_type, sizeof(key_type));
+		++(*n_attr);
+		(*data) += 2;
+		(*size) -= 2;
+	}
+
+	if (*size > 3 && (*data)[0] % 2 && *n_attr < 20){
+		/* ... | present -> 0/1 | len | len | data | ... */
+		(*data)++; (*size)--;
+		ptr = *data;
+		if ((ecparams_size = get_buffer(&ptr, *size, data, size, 256)) == 0)
+			return 1;
+		memcpy(ecparams, ptr, ecparams_size);
+		FILL_ATTR((*keyTemplate)[*n_attr], CKA_EC_PARAMS, ecparams, ecparams_size);
+		++(*n_attr);
+	}
+
+	if (*size > 3 && (*data)[0] % 2 && *n_attr < 20){
+		/* ... | present -> 0/1 | len | len | data | ... */
+		(*data)++; (*size)--;
+		ptr = *data;
+		if ((opt_object_label_size = get_buffer(&ptr, *size, data, size, 128)) == 0)
+			return 1;
+		memcpy(opt_object_label, ptr, opt_object_label_size);
+		FILL_ATTR((*keyTemplate)[*n_attr], CKA_LABEL, opt_object_label, opt_object_label_size);
+		++(*n_attr);
+	}
+
+	if (*size > 3 && (*data)[0] % 2 && *n_attr < 20){
+		/* ... | present -> 0/1 | len | len | data | ... */
+		(*data)++; (*size)--;
+		ptr = *data;
+		if ((opt_object_id_len = get_buffer(&ptr, *size, data, size, 100)) == 0)
+			return 1;
+		memcpy(opt_object_id, ptr, opt_object_id_len);
+		FILL_ATTR((*keyTemplate)[*n_attr], CKA_ID, opt_object_id, opt_object_id_len);
+		++(*n_attr);
+	}
+	if (*size > 4 && (*data)[0]  % 2 && *n_attr < 20){
+		/* ... | present -> 0/1 | len | mech1 | mech2 | ... | mechn | ... */
+		opt_allowed_mechanisms_len = (*data)[1] > 20 ? 20 : (*data)[1];
+		(*data) += 2;
+		(*size) -= 2;
+		for (size_t i = 0; i < opt_allowed_mechanisms_len; i++) {
+			if (*size <= sizeof(unsigned int))
+				return 1;
+			opt_allowed_mechanisms[i] = *((unsigned int *)data);
+			(*data) += sizeof(unsigned int);
+			(*size) -= sizeof(unsigned int);
+		}
+		FILL_ATTR((*keyTemplate)[*n_attr], CKA_ALLOWED_MECHANISMS, opt_allowed_mechanisms, opt_allowed_mechanisms_len);
+		++(*n_attr);
+	}
+	if (*size == 0)
+		return 1;
+	return 0;
+}
+
+static void test_unwrap(const uint8_t *data, size_t size)
+{
+	CK_SESSION_HANDLE    session;
+	CK_MECHANISM         mech = {0, NULL_PTR, 0};
+	uint8_t              login_type = CKU_USER;
+	char                *pin = NULL;
+	const unsigned char *opt_id, *wrapped_key;
+	size_t               opt_id_len;
+	CK_OBJECT_HANDLE     hUnwrappingKey;
+	CK_ULONG             wrapped_key_length;
+	CK_BYTE_PTR          pWrappedKey;
+	unsigned char        in_buffer[1024];
+	CK_OBJECT_CLASS      secret_key_class = CKO_SECRET_KEY;
+	CK_ATTRIBUTE        *keyTemplate = NULL;
+	int                  n_attr = 2;
+	CK_OBJECT_HANDLE     hSecretKey;
+
+	/* Set options */
+	if (set_mechanism(&data, &size, &mech) || size < 3)
+		goto end;
+	login_type = data[0];
+	data++; size--;
+	if (!(pin = extract_word(&data, &size)))
+		goto end;
+	opt_id = data;
+	opt_id_len = get_buffer(&opt_id, size, &data, &size, 256);
+	wrapped_key = data;
+	if ((wrapped_key_length = get_buffer(&wrapped_key, size, &data, &size, 1024)) == 0)
+		goto end;
+	memcpy(in_buffer, wrapped_key, wrapped_key_length);
+	pWrappedKey = in_buffer;
+
+	if (fill_key_template((CK_ATTRIBUTE **) &keyTemplate, &n_attr, &data, &size, &secret_key_class, true))
+		goto end;
+
+	/* Initialize */
+	if (fuzz_pkcs11_initialize(data, size, NULL, &session) != CKR_OK)
+		goto end;
+
+	p11->C_Login(session, login_type, (CK_UTF8CHAR *) pin, strlen(pin));
+	/* Find keys*/
+	if (!fuzz_find_object(session, CKO_PRIVATE_KEY, &hUnwrappingKey, opt_id_len ? opt_id : NULL, opt_id_len))
+		if (!fuzz_find_object(session, CKO_SECRET_KEY, &hUnwrappingKey, opt_id_len ? opt_id : NULL, opt_id_len))
+			goto fin;
+	p11->C_UnwrapKey(session, &mech, hUnwrappingKey, pWrappedKey, wrapped_key_length, keyTemplate, n_attr, &hSecretKey);
+
+fin:
+	p11->C_CloseSession(session);
+	p11->C_Finalize(NULL);
+end:
+	free(pin);
+	free(keyTemplate);
+}
+
+static void test_derive(const uint8_t *data, size_t size)
+{
+	CK_SESSION_HANDLE    session;
+	CK_OBJECT_HANDLE     key;
+	CK_MECHANISM         mech = {0, NULL_PTR, 0};
+	uint8_t              login_type = CKU_USER;
+	char                *pin = NULL;
+	const unsigned char *opt_id = NULL;
+	size_t               opt_id_len;
+	CK_OBJECT_HANDLE     newkey = 0;
+	CK_OBJECT_CLASS      newkey_class = CKO_SECRET_KEY;
+	CK_ATTRIBUTE        *keyTemplate = NULL;
+	int                  n_attrs = 2;
+
+	/* Set options */
+	if (set_mechanism(&data, &size, &mech) || size < 3)
+		goto end;
+	login_type = data[0];
+	data++; size--;
+	if (!(pin = extract_word(&data, &size)))
+		goto end;
+	opt_id = data;
+	opt_id_len = get_buffer(&opt_id, size, &data, &size, 256);
+	if (fill_key_template((CK_ATTRIBUTE **) &keyTemplate, &n_attrs, &data, &size, &newkey_class, false))
+		goto end;
+
+	/* Initialize */
+	if (fuzz_pkcs11_initialize(data, size, NULL, &session) != CKR_OK)
+		goto end;
+
+	p11->C_Login(session, login_type, (CK_UTF8CHAR *) pin, strlen(pin));
+	if (fuzz_find_object(session, CKO_PRIVATE_KEY, &key, opt_id_len ? opt_id : NULL, opt_id_len))
+		p11->C_DeriveKey(session, &mech, key, keyTemplate, n_attrs, &newkey);
+
+	p11->C_CloseSession(session);
+	p11->C_Finalize(NULL);
+end:
+	free(pin);
+	free(keyTemplate);
+}
+
+static void test_genkeypair(const uint8_t *data, size_t size)
+{
+	CK_SESSION_HANDLE session;
+	CK_OBJECT_HANDLE  hPublicKey;
+	CK_OBJECT_HANDLE  hPrivateKey;
+	CK_MECHANISM      mech = {0, NULL_PTR, 0};
+	uint8_t           login_type = CKU_USER;
+	char             *pin = NULL;
+	CK_OBJECT_CLASS   pubkey_class = CKO_PUBLIC_KEY;
+	CK_OBJECT_CLASS   privkey_class = CKO_PRIVATE_KEY;
+	int               n_pubkey_attr = 2;
+	int               n_privkey_attr = 2;
+	CK_ATTRIBUTE     *publicKeyTemplate = NULL;
+	CK_ATTRIBUTE     *privateKeyTemplate = NULL;
+
+	/* Process options*/
+	if (set_mechanism(&data, &size, &mech) || size < 3)
+		goto end;
+	login_type = data[0];
+	data++; size--;
+	if (!(pin = extract_word(&data, &size)))
+		goto end;
+
+	if (fill_key_template(&publicKeyTemplate, &n_pubkey_attr, &data, &size, &pubkey_class, true) != 0
+		|| fill_key_template(&privateKeyTemplate, &n_privkey_attr, &data, &size, &privkey_class, true) != 0)
+		goto end;
+
+	/* Initialize */
+	if (fuzz_pkcs11_initialize(data, size, NULL, &session) != CKR_OK)
+		goto end;
+
+	p11->C_Login(session, login_type, (CK_UTF8CHAR *) pin, strlen(pin));
+	p11->C_GenerateKeyPair(session, &mech, publicKeyTemplate, n_pubkey_attr,
+						   privateKeyTemplate, n_privkey_attr,
+						   &hPublicKey, &hPrivateKey);
+	p11->C_CloseSession(session);
+	p11->C_Finalize(NULL);
+
+end:
+	free(pin);
+	free(privateKeyTemplate);
+	free(publicKeyTemplate);
+}
+
+static void test_store_data(const uint8_t *data, size_t size)
+{
+	CK_SESSION_HANDLE session;
+	CK_OBJECT_HANDLE  data_obj;
+	CK_OBJECT_CLASS   class = CKO_DATA;
+	uint8_t           login_type = CKU_USER;
+	unsigned char     contents[5001];
+	int               contents_len = 0;
+	const uint8_t    *ptr = NULL;
+	CK_ATTRIBUTE     *data_templ = NULL;
+	int               n_data_attr = 0;
+	char             *pin = NULL;
+	unsigned char     app_id[256];
+	int               app_id_len = 0;
+
+	/* Create data template */
+	if (!(data_templ = malloc(20 * sizeof(CK_ATTRIBUTE))))
+		return;
+	memset(data_templ, 0, 20 * sizeof(CK_ATTRIBUTE));
+
+	/* Get PIN */
+	if (!(pin = extract_word(&data, &size)))
+		goto end;
+
+	/* Extract content from fuzzing input*/
+	memset(contents, 0, sizeof(contents));
+	ptr = data;
+	if ((contents_len = get_buffer(&ptr, size, &data, &size, 5000)) == 0)	
+		goto end;
+	memcpy(contents, ptr, contents_len);
+	contents[contents_len] = '\0';
+
+	/* Fill attributes to data template */
+	if (size < 4)
+		goto end;
+	FILL_ATTR(data_templ[n_data_attr], CKA_CLASS, &class, sizeof(class));
+	n_data_attr++;
+	FILL_ATTR(data_templ[n_data_attr], CKA_VALUE, &contents, contents_len);
+	n_data_attr++;
+	fill_bool_attr(&data_templ, &n_data_attr, CKA_TOKEN, *data % 2);
+	data++; size--;
+	fill_bool_attr(&data_templ, &n_data_attr, CKA_PRIVATE, *data % 2);
+	data++; size--;
+
+	/* Get application id*/
+	if (data[0] % 2){
+		data++; size--;
+		ptr = data;
+		if ((app_id_len = get_buffer(&ptr, size, &data, &size, 256)) == 0)
+			goto end;
+		memcpy(app_id, ptr, app_id_len);
+		FILL_ATTR(data_templ[n_data_attr], CKA_OBJECT_ID, app_id, app_id_len);
+		n_data_attr++;
+	}
+
+	/* Initialize */
+	if (fuzz_pkcs11_initialize(data, size, NULL, &session) != CKR_OK)
+		goto end;
+
+	p11->C_Login(session, login_type, (CK_UTF8CHAR *) pin, strlen(pin));
+	p11->C_CreateObject(session, data_templ, n_data_attr, &data_obj);
+	p11->C_CloseSession(session);
+	p11->C_Finalize(NULL);
+end:
+	free(data_templ);
+	free(pin);
+}
+
+static void test_store_cert(const uint8_t *data, size_t size)
+{
+	CK_SESSION_HANDLE   session;
+	CK_OBJECT_CLASS     class = CKO_CERTIFICATE;
+	uint8_t             login_type = CKU_USER;
+	unsigned char       contents[5000];
+	int                 contents_len = 0;
+	const uint8_t      *ptr = NULL;
+	CK_ATTRIBUTE       *cert_templ = NULL;
+	int                 n_cert_attr = 0;
+	char               *pin = NULL;
+	CK_OBJECT_HANDLE    cert_obj;
+	CK_CERTIFICATE_TYPE cert_type = CKC_X_509;
+
+	/* Create certificate template */
+	if (!(cert_templ = malloc(20 * sizeof(CK_ATTRIBUTE))))
+		return;
+	memset(cert_templ, 0, 20 * sizeof(CK_ATTRIBUTE));
+
+	/* Get PIN */
+	if (!(pin = extract_word(&data, &size)))
+		goto end;
+
+	/* Extract content from fuzzing input */
+	memset(contents, 0, sizeof(contents));
+	ptr = data;
+	if ((contents_len = get_buffer(&ptr, size, &data, &size, 5000)) == 0)	
+		goto end;
+	memcpy(contents, ptr, contents_len);
+	contents[contents_len] = '\0';
+
+	/* Fill attributes to certificate template */
+	if (size < 4)
+		goto end;
+	FILL_ATTR(cert_templ[n_cert_attr], CKA_CLASS, &class, sizeof(class));
+	n_cert_attr++;
+	FILL_ATTR(cert_templ[n_cert_attr], CKA_VALUE, contents, contents_len);
+	n_cert_attr++;
+	FILL_ATTR(cert_templ[n_cert_attr], CKA_CERTIFICATE_TYPE, &cert_type, sizeof(cert_type));
+	n_cert_attr++;
+	fill_bool_attr(&cert_templ, &n_cert_attr, CKA_TOKEN, *data % 2);
+	data++; size--;
+	fill_bool_attr(&cert_templ, &n_cert_attr, CKA_PRIVATE, *data % 2);
+	data++; size--;
+
+	/* Initialize */
+	if (fuzz_pkcs11_initialize(data, size, NULL, &session) != CKR_OK)
+		goto end;
+
+	p11->C_Login(session, login_type, (CK_UTF8CHAR *) pin, strlen(pin));
+	p11->C_CreateObject(session, cert_templ, n_cert_attr, &cert_obj);
+	p11->C_CloseSession(session);
+	p11->C_Finalize(NULL);
+end:
+	free(pin);
+	free(cert_templ);
+}
+
+static void test_store_key(const uint8_t *data, size_t size)
+{
+	CK_SESSION_HANDLE session;
+	CK_OBJECT_CLASS   class = CKO_SECRET_KEY;
+	uint8_t           login_type = CKU_USER;
+	unsigned char     contents[5000];
+	int               contents_len = 0;
+	const uint8_t    *ptr = NULL;
+	CK_ATTRIBUTE     *key_template = NULL;
+	int               n_key_attr = 0;
+	char             *pin = NULL;
+	CK_OBJECT_HANDLE  key_obj;
+
+	memset(contents, 0, sizeof(contents));
+	if (size < 3)
+		return;
+	class = *data;
+	data++; size--;
+
+	/* Get PIN */
+	if (!(pin = extract_word(&data, &size)))
+		goto end;
+
+	if (fill_key_template(&key_template, &n_key_attr, &data, &size, &class, true) != 0)
+		goto end;
+
+	if (size < 3)
+		goto end;
+	if (data[0] && n_key_attr < 20) {
+		data++; size--;
+		ptr = data;
+		if ((contents_len = get_buffer(&ptr, size, &data, &size, 5000)) == 0)	
+			goto end;
+		memcpy(contents, ptr, contents_len);
+		FILL_ATTR(key_template[n_key_attr], CKA_VALUE, contents, contents_len);
+		n_key_attr++;
+	}
+
+	/* Initialize */
+	if (fuzz_pkcs11_initialize(data, size, NULL, &session) != CKR_OK)
+		goto end;
+
+	p11->C_Login(session, login_type, (CK_UTF8CHAR *) pin, strlen(pin));
+	p11->C_CreateObject(session, key_template, n_key_attr, &key_obj);
+	p11->C_CloseSession(session);
+	p11->C_Finalize(NULL);
+end:
+	free(pin);
+	free(key_template);
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+	uint8_t operation = 0;
+	void (*func_ptr[])(const uint8_t*, size_t) = {
+		test_change_pin,
+		test_init_pin,
+		test_init_token,
+		test_random,
+		test_digest_update,
+		test_digest,
+		test_sign,
+		test_verify,
+		test_decrypt,
+		test_wrap,
+		test_unwrap,
+		test_derive,
+		test_genkeypair,
+		test_store_data,
+		test_store_cert,
+		test_store_key
+	};
+
+	if (size < 10)
+		return 0;
+
+	operation = *data % 16;
+	data++;
+	size--;
+
+	func_ptr[operation](data, size);
+
+	return 0;
+}
diff -Nru opensc-0.22.0/src/tests/fuzzing/fuzz_pkcs15_crypt.c opensc-0.23.0/src/tests/fuzzing/fuzz_pkcs15_crypt.c
--- opensc-0.22.0/src/tests/fuzzing/fuzz_pkcs15_crypt.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/fuzzing/fuzz_pkcs15_crypt.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,170 @@
+/*
+ * fuzz_pkcs15_crypt.c: Fuzz target for pkcs15-crypt
+ *
+ * Copyright (C) 2022 Red Hat, Inc.
+ *
+ * Author: Veronika Hanulikova <vhanulik at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "libopensc/internal.h"
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include "fuzzer_reader.h"
+#include "fuzzer_tool.h"
+#undef stderr
+#define stderr stdout
+
+/* Rename main to call it in fuzz target */
+#define main _main
+#define util_connect_card_ex(ctx, card, id, do_wait, do_lock, verbose) fuzz_util_connect_card(ctx, card)
+# include "tools/pkcs15-crypt.c"
+#undef main
+
+static const uint8_t *reader_data = NULL;
+static size_t reader_data_size = 0;
+
+/* Use instead of util_connect_card() */
+int fuzz_util_connect_card(sc_context_t *ctx, sc_card_t **card)
+{
+	opt_output = NULL; /* Do not create new outputfile */
+	return fuzz_connect_card(ctx, card, NULL, reader_data, reader_data_size);
+}
+
+void initialize_global()
+{
+	/* Global variables need to be reser between runs,
+	   fuzz target is called repetitively in one execution */
+	verbose = 0, opt_wait = 0, opt_raw = 0;
+	opt_reader = NULL;
+	opt_pincode = NULL, opt_key_id = NULL;
+	opt_input = NULL, opt_output = NULL;
+	opt_bind_to_aid = NULL;
+	opt_sig_format = NULL;
+	opt_crypt_flags = 0;
+	ctx = NULL;
+	card = NULL;
+	p15card = NULL;
+
+	optind = 0;
+	opterr = 0;
+	optopt = 0;
+}
+
+void test_operation(char *op, char *pin, const uint8_t *data, size_t size, char *filename,
+					char *hash, char *format, char *aid, char *id, uint8_t pad)
+{
+	char *argv[] = {"./fuzz_pkcs15_crypt", op, "-p", pin, "-i", filename,
+					hash, "-f", format, NULL, NULL, NULL, NULL, NULL, NULL};
+	int argc = 9;
+
+	if (aid) {
+		argv[argc++] = "--aid";
+		argv[argc++] = aid;
+	}
+	if (id) {
+		argv[argc++] = "-k";
+		argv[argc++] = id;
+	}
+	if (pad)
+		argv[argc++] = "--pkcs1";
+
+	reader_data = data;
+	reader_data_size = size;
+	_main(argc, argv);
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+	uint8_t operation = 0;
+	uint8_t hash = 0;
+	char *hash_options[] = {"--md5", "--sha-1", "--sha-224", "--sha-256", "--sha-384", "--sha-512"};
+	uint8_t pad = 0;
+	uint8_t format = 0;
+	char *formats[] = {"rs", "sequence", "openssl"};
+	uint8_t aid = 0;
+	char *opt_aid = NULL;
+	uint8_t id = 0;
+	char *opt_id = NULL;
+	char *pin = NULL;
+	char *filename = NULL;
+
+	if (size < 15)
+		return 0;
+
+#ifdef FUZZING_ENABLED
+	fclose(stdout);
+#endif
+
+	initialize_global();
+
+	operation = data[0] % 3;
+	data++; size--;
+
+	if (!(pin = extract_word(&data, &size)))
+		return 0;
+
+	if (operation == 0) { /* test random arguments */
+		char **argv = NULL;
+		int argc = 0;
+
+		/* setup pin and input file otherwise fuzz target waits for input from stdin */
+		opt_pincode = pin;
+		opt_input = "invalid_filename";
+
+		if (get_fuzzed_argv("./fuzz_pkcs15_crypt", data, size, &argv, &argc, &reader_data, &reader_data_size) != 0)
+			goto err;
+		_main(argc, argv);
+		free_arguments(argc, argv);
+	} else {
+		/* Set options */
+		if (size < 5)
+			goto err;
+		hash = data[0] % 6; data++; size--;
+		pad = data[0] % 2; data++; size--;
+		format = data[0] % 3; data++; size--;
+
+		aid = data[0] % 2; data++; size--;
+		if (aid) {
+			if (!(opt_aid = extract_word(&data, &size)))
+				goto err;
+		}
+		if (size < 3)
+			goto err;
+
+		id = data[0] % 2; data++; size--;
+		if (id) {
+			if (!(opt_id = extract_word(&data, &size)))
+				goto err;
+		}
+
+		if (create_input_file(&filename, &data, &size) != 0)
+			goto err;
+		test_operation(operation == 1 ? "-c" : "-s", pin, data, size, filename, hash_options[hash], formats[format], opt_aid, opt_id, pad);
+
+		remove_file(filename);
+	}
+
+err:
+	free(pin);
+	free(opt_aid);
+	free(opt_id);
+	return 0;
+}
diff -Nru opensc-0.22.0/src/tests/fuzzing/fuzz_pkcs15_decode.c opensc-0.23.0/src/tests/fuzzing/fuzz_pkcs15_decode.c
--- opensc-0.22.0/src/tests/fuzzing/fuzz_pkcs15_decode.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/fuzzing/fuzz_pkcs15_decode.c	2022-11-29 09:34:43.000000000 +0100
@@ -20,56 +20,98 @@
 #include "config.h"
 #endif
 
+#include "fuzzer_reader.h"
 #include "libopensc/pkcs15.h"
 #include "libopensc/internal.h"
-#include <stdlib.h>
-#include <string.h>
 
-static struct sc_context *ctx = NULL;
-static struct sc_pkcs15_card *p15card = NULL;
-static sc_card_t card = {0};
-
-int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
+uint16_t fuzz_get_buffer(const uint8_t **buf, size_t buf_len, const uint8_t **out, size_t *out_len)
 {
-    int (* decode_entries[])(struct sc_pkcs15_card *, struct sc_pkcs15_object *,
-            const u8 **nbuf, size_t *nbufsize) = {
-        sc_pkcs15_decode_prkdf_entry, sc_pkcs15_decode_pukdf_entry,
-        sc_pkcs15_decode_skdf_entry, sc_pkcs15_decode_cdf_entry,
-        sc_pkcs15_decode_dodf_entry, sc_pkcs15_decode_aodf_entry
-    };
-    size_t i;
-
-    if (!ctx)
-        sc_establish_context(&ctx, "fuzz");
-    if (!p15card) {
-        card.ctx = ctx;
-        p15card = sc_pkcs15_card_new();
-        if (p15card) {
-            p15card->card = &card;
-        }
-    }
-
-    for (i = 0; i < sizeof decode_entries/sizeof *decode_entries; i++) {
-        struct sc_pkcs15_object *obj;
-        const u8 *p = Data;
-        size_t len = Size;
-        obj = calloc(1, sizeof *obj);
-        while (SC_SUCCESS == decode_entries[i](p15card, obj, &p, &len)) {
-            sc_pkcs15_free_object(obj);
-            obj = calloc(1, sizeof *obj);
-        }
-        sc_pkcs15_free_object(obj);
-    }
-
-    struct sc_pkcs15_pubkey *pubkey = calloc(1, sizeof *pubkey);
-    sc_pkcs15_decode_pubkey(ctx, pubkey, Data, Size);
-    sc_pkcs15_free_pubkey(pubkey);
-
-    struct sc_pkcs15_tokeninfo *tokeninfo = sc_pkcs15_tokeninfo_new();
-    sc_pkcs15_parse_tokeninfo(ctx, tokeninfo, Data, Size);
-    sc_pkcs15_free_tokeninfo(tokeninfo);
+	uint16_t len = 0;
+
+	if (!buf || !(*buf) || buf_len < 2)
+		return 0;
 
-    sc_pkcs15_parse_unusedspace(Data, Size, p15card);
+	/* Get length of the result buffer*/
+	len = *((uint16_t *) *buf);
+	if (buf_len - 2 <= len)
+		return 0;
+	(*buf) += 2;
+	buf_len -= 2;
+	
+	/* Set out buffer to new reader data*/
+	*out = *buf + len;
+	*out_len = buf_len - len;
+	return len;
+}
 
-    return 0;
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
+{
+	size_t i = 0;
+	struct sc_reader *reader = NULL;
+	const uint8_t *buf = Data, *reader_data = NULL;
+	uint16_t buf_len = 0;
+	size_t reader_data_len = 0;
+	struct sc_context *ctx = NULL;
+	struct sc_pkcs15_card *p15card = NULL;
+	sc_card_t *card = NULL;
+	struct sc_pkcs15_tokeninfo *tokeninfo = NULL;
+	int (* decode_entries[])(struct sc_pkcs15_card *, struct sc_pkcs15_object *,
+			const u8 **nbuf, size_t *nbufsize) = {
+		sc_pkcs15_decode_prkdf_entry, sc_pkcs15_decode_pukdf_entry,
+		sc_pkcs15_decode_skdf_entry, sc_pkcs15_decode_cdf_entry,
+		sc_pkcs15_decode_dodf_entry, sc_pkcs15_decode_aodf_entry
+	};
+	int algorithms[] = { SC_ALGORITHM_RSA, SC_ALGORITHM_EC, SC_ALGORITHM_GOSTR3410, SC_ALGORITHM_EDDSA };
+
+	/* Split data into testing buffer and APDU for connecting */
+	if ((buf_len = fuzz_get_buffer(&buf, Size, &reader_data, &reader_data_len)) == 0)
+		return 0;
+
+	/* Establish context for fuzz app*/
+	sc_establish_context(&ctx, "fuzz");
+	if (!ctx)
+		return 0;
+
+	if (fuzz_connect_card(ctx, &card, &reader, reader_data, reader_data_len) != SC_SUCCESS)
+		goto err;
+
+	sc_pkcs15_bind(card, NULL, &p15card);
+	if (!p15card)
+		goto err;
+
+	for (i = 0; i < sizeof decode_entries/sizeof *decode_entries; i++) {
+		struct sc_pkcs15_object *obj;
+		const u8 *p = buf;
+		size_t len = (size_t) buf_len;
+		if (!(obj = calloc(1, sizeof *obj)))
+			goto err;
+		while (SC_SUCCESS == decode_entries[i](p15card, obj, &p, &len)) {
+			sc_pkcs15_free_object(obj);
+			if (!(obj = calloc(1, sizeof *obj)))
+				goto err;
+		}
+		sc_pkcs15_free_object(obj);
+	}
+
+	for (i = 0; i < 4; i++) {
+		struct sc_pkcs15_pubkey *pubkey = calloc(1, sizeof *pubkey);
+		if (!pubkey)
+			goto err;
+		pubkey->algorithm = algorithms[i];
+		sc_pkcs15_decode_pubkey(ctx, pubkey, buf, buf_len);
+		sc_pkcs15_free_pubkey(pubkey);
+	}
+
+	tokeninfo = sc_pkcs15_tokeninfo_new();
+	sc_pkcs15_parse_tokeninfo(ctx, tokeninfo, buf, buf_len);
+	sc_pkcs15_free_tokeninfo(tokeninfo);
+
+	sc_pkcs15_parse_unusedspace(buf, buf_len, p15card);
+
+	sc_pkcs15_card_free(p15card);
+
+err:
+	sc_disconnect_card(card);
+	sc_release_context(ctx);
+	return 0;
 }
diff -Nru opensc-0.22.0/src/tests/fuzzing/fuzz_pkcs15_encode.c opensc-0.23.0/src/tests/fuzzing/fuzz_pkcs15_encode.c
--- opensc-0.22.0/src/tests/fuzzing/fuzz_pkcs15_encode.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/fuzzing/fuzz_pkcs15_encode.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,89 @@
+/*
+ * fuzz_pkcs15_encode.c: Fuzzer for encoding functions
+ *
+ * Copyright (C) 2022 Red Hat, Inc.
+ *
+ * Author: Veronika Hanulikova <vhanulik at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "fuzzer_reader.h"
+#include "libopensc/pkcs15.h"
+#include "libopensc/internal.h"
+
+
+int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
+{
+	struct sc_context       *ctx = NULL;
+	struct sc_card          *card = NULL;
+	struct sc_pkcs15_card   *p15card = NULL;
+	struct sc_pkcs15_object *obj;
+	unsigned char           *unused_space = NULL;
+	size_t                   unused_space_len = 0;
+
+	sc_establish_context(&ctx, "fuzz");
+	if (!ctx)
+		return 0;
+
+	if (fuzz_connect_card(ctx, &card, NULL, Data, Size) != SC_SUCCESS)
+		goto err;
+
+	if (sc_pkcs15_bind(card, NULL, &p15card) != 0)
+		goto err;
+
+	for (obj = p15card->obj_list; obj != NULL; obj = obj->next) {
+		u8 *buf = NULL;
+		size_t buf_len = 0;
+		struct sc_pkcs15_object *key_object = NULL;
+		sc_pkcs15_pubkey_t *pkey = NULL;
+		switch (obj->type & SC_PKCS15_TYPE_CLASS_MASK) {
+		case SC_PKCS15_TYPE_PUBKEY:
+			sc_pkcs15_encode_pukdf_entry(ctx, obj, &buf, &buf_len);
+			sc_pkcs15_read_pubkey(p15card, obj, &pkey);
+			sc_pkcs15_free_pubkey(pkey);
+			break;
+		case SC_PKCS15_TYPE_PRKEY:
+			sc_pkcs15_encode_prkdf_entry(ctx, obj, &buf, &buf_len);
+			break;
+		case SC_PKCS15_TYPE_DATA_OBJECT:
+			sc_pkcs15_encode_dodf_entry(ctx, obj, &buf, &buf_len);
+			break;
+		case SC_PKCS15_TYPE_SKEY:
+			sc_pkcs15_encode_skdf_entry(ctx, obj, &buf, &buf_len);
+			break;
+		case SC_PKCS15_TYPE_AUTH:
+			sc_pkcs15_encode_aodf_entry(ctx, obj, &buf, &buf_len);
+			break;
+		case SC_PKCS15_TYPE_CERT:
+			sc_pkcs15_encode_cdf_entry(ctx, obj, &buf, &buf_len);
+			sc_pkcs15_prkey_attrs_from_cert(p15card, obj, &key_object);
+			break;
+		}
+		free(buf);
+	}
+	sc_pkcs15_encode_unusedspace(ctx, p15card, &unused_space, &unused_space_len);
+	free(unused_space);
+
+	sc_pkcs15_card_free(p15card);
+err:
+	sc_disconnect_card(card);
+	sc_release_context(ctx);
+
+	return 0;
+}
diff -Nru opensc-0.22.0/src/tests/fuzzing/fuzz_pkcs15init.c opensc-0.23.0/src/tests/fuzzing/fuzz_pkcs15init.c
--- opensc-0.22.0/src/tests/fuzzing/fuzz_pkcs15init.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/fuzzing/fuzz_pkcs15init.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,368 @@
+/*
+ * fuzz_pkcs15init.c: Fuzzer for functions processing pkcs15 init
+ *
+ * Copyright (C) 2022 Red Hat, Inc.
+ *
+ * Author: Veronika Hanulikova <vhanulik at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "fuzzer_reader.h"
+#include "pkcs15init/pkcs15-lib.c"
+#include "scconf/scconf.h"
+#include "pkcs15init/pkcs15-init.h"
+#include "pkcs15init/profile.c"
+#include "pkcs15init/profile.h"
+
+int fuzz_profile_load(struct sc_profile *profile, const uint8_t *data, size_t size)
+{
+    int rv = 0;
+    scconf_context	*conf = NULL;
+    conf = scconf_new(NULL);
+    if (!conf)
+        return 0;
+
+    if ((rv = scconf_parse_string(conf, (char *)data)) < 0) {
+        scconf_free(conf);
+        return rv;
+    }
+
+    rv = process_conf(profile, conf);
+    scconf_free(conf);
+    return rv;
+}
+
+void fuzz_pkcs15init_bind(struct sc_card *card, struct sc_profile **result,
+                          const uint8_t *data, size_t size)
+{
+    struct sc_profile *profile = NULL;
+    const char	      *driver;
+    struct sc_pkcs15init_operations * (* func)(void) = NULL;
+    int r = 0;
+
+    if (!card || !card->driver || !result)
+        return;
+
+    *result = NULL;
+
+    r = sc_pkcs15init_set_lifecycle(card, SC_CARDCTRL_LIFECYCLE_ADMIN);
+    if (r < 0 && r != SC_ERROR_NOT_SUPPORTED) {
+        return;
+    }
+
+	profile = sc_profile_new();
+    if (!profile)
+        return;
+    profile->card = card;
+    driver = card->driver->short_name;
+
+    for (int i = 0; profile_operations[i].name; i++) {
+		if (!strcasecmp(driver, profile_operations[i].name)) {
+			func = (struct sc_pkcs15init_operations *(*)(void)) profile_operations[i].func;
+			break;
+		}
+	}
+    if (func) {
+        profile->ops = func();
+    } else {
+        sc_profile_free(profile);
+        return;
+    }
+    profile->name = strdup("Fuzz profile");
+
+    r = sc_pkcs15init_read_info(card, profile);
+    if (r < 0) {
+		sc_profile_free(profile);
+        return;
+	}
+
+    if (fuzz_profile_load(profile, data, size) < 0) {
+        sc_profile_free(profile);
+        return;
+    }
+
+    if (sc_profile_finish(profile, NULL) < 0) {
+        sc_profile_free(profile);
+        return;
+    }
+    *result = profile;
+}
+
+int fuzz_get_reader_data(const uint8_t *from, size_t from_size, const uint8_t **to, size_t *to_size)
+{
+    size_t i = 0;
+    while(i < from_size - 1 && from[i] != '\0')
+        i++;
+        
+    if (from[i] != '\0')
+        return 0;
+
+    *to_size = from_size - (i + 1);
+    *to = from + (i + 1);
+    return 1;
+}
+
+void do_init_app(struct sc_profile *profile, struct sc_pkcs15_card *p15card, sc_card_t *card,
+                 unsigned char *so_pin, unsigned char *so_puk)
+{
+    struct sc_pkcs15init_initargs init_args;
+    sc_pkcs15_auth_info_t         info;
+    int                           so_puk_disabled = 0;
+
+    memset(&init_args, 0, sizeof(init_args));
+    sc_pkcs15init_get_pin_info(profile, SC_PKCS15INIT_SO_PIN, &info);
+    if ((info.attrs.pin.flags & SC_PKCS15_PIN_FLAG_UNBLOCK_DISABLED) &&
+        (info.attrs.pin.flags & SC_PKCS15_PIN_FLAG_SO_PIN))
+        so_puk_disabled = 1;
+
+    sc_pkcs15init_get_pin_info(profile, SC_PKCS15INIT_SO_PUK, &info);
+
+    init_args.so_pin = so_pin;
+    init_args.so_pin_len = 8;
+
+    if (!so_puk_disabled) {
+        init_args.so_puk = so_puk;
+        init_args.so_puk_len = 8;
+    }
+
+    sc_pkcs15init_add_app(card, profile, &init_args);
+}
+
+void do_store_pin(struct sc_profile *profile, struct sc_pkcs15_card *p15card, sc_card_t *card,
+                  unsigned char *pin, unsigned char *so_pin)
+{
+    struct sc_pkcs15init_pinargs pin_args;
+    char   pin_id[SC_PKCS15_MAX_ID_SIZE] = "1\0";
+    sc_pkcs15init_set_p15card(profile, p15card);
+    
+    memcpy(pin, "1234555678\0", 11); /* Set new pin */
+    memset(&pin_args, 0, sizeof(pin_args));
+
+    sc_pkcs15_format_id(pin_id, &pin_args.auth_id);
+    pin_args.pin = pin;
+    pin_args.pin_len = 6;
+    pin_args.label = "Basic PIN";
+
+    pin_args.puk = so_pin;
+    pin_args.puk_len = 8;
+
+    sc_pkcs15init_store_pin(p15card, profile, &pin_args);
+}
+
+void do_store_data_object(struct sc_profile *profile, struct sc_pkcs15_card *p15card, sc_card_t *card,
+                          uint8_t *buf, size_t len)
+{
+    struct sc_pkcs15init_dataargs args;
+    char value[SC_MAX_OBJECT_ID_OCTETS];
+
+    memcpy(value, buf, SC_MAX_OBJECT_ID_OCTETS);
+    value[len < SC_MAX_OBJECT_ID_OCTETS ? len : SC_MAX_OBJECT_ID_OCTETS - 1] = '\0';
+
+    memset(&args, 0, sizeof(args));
+    sc_init_oid(&args.app_oid);
+    args.label = "label";
+    args.app_label = "pkcs15-init";
+
+    sc_format_oid(&args.app_oid, value);
+
+    args.der_encoded.value = buf;
+    args.der_encoded.len = len;
+    sc_pkcs15init_store_data_object(p15card, profile, &args, NULL);
+}
+
+void do_generate_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card, sc_card_t *card)
+{
+    struct sc_pkcs15init_keygen_args keygen_args;
+    int algorithms[] = { SC_ALGORITHM_RSA, SC_ALGORITHM_EC };
+    unsigned int keybits[] = { 1024, 0 };
+
+    memset(&keygen_args, 0, sizeof(keygen_args));
+    sc_pkcs15_format_id("01", &(keygen_args.prkey_args.auth_id));
+    keygen_args.prkey_args.access_flags |=
+                    SC_PKCS15_PRKEY_ACCESS_SENSITIVE
+                | SC_PKCS15_PRKEY_ACCESS_ALWAYSSENSITIVE
+                | SC_PKCS15_PRKEY_ACCESS_NEVEREXTRACTABLE
+                | SC_PKCS15_PRKEY_ACCESS_LOCAL;
+
+    for (int i = 1; i < 2; i++) {
+        keygen_args.prkey_args.key.algorithm = algorithms[i];
+        if (algorithms[i] == SC_ALGORITHM_EC) /* strdup called also in parse_alg_spec() */
+            keygen_args.prkey_args.key.u.ec.params.named_curve = strdup("prime256v1");
+        sc_pkcs15init_generate_key(p15card, profile, &keygen_args, keybits[i], NULL);
+        if (algorithms[i] == SC_ALGORITHM_EC)
+            free(keygen_args.prkey_args.key.u.ec.params.named_curve);
+    }
+}
+
+void do_generate_skey(struct sc_profile *profile, struct sc_pkcs15_card *p15card, sc_card_t *card)
+{
+    struct sc_pkcs15init_skeyargs skey_args;
+    int algorithms[] = { SC_ALGORITHM_DES, SC_ALGORITHM_3DES, SC_ALGORITHM_AES };
+    unsigned int keybits[] = { 64, 192, 128 };
+
+    /* init keygen_args*/
+    memset(&skey_args, 0, sizeof(skey_args));
+    skey_args.label = "label";
+    skey_args.usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_DECRYPT;
+    skey_args.user_consent = 0;
+
+    for (int i = 0; i < 3; i++) {
+        skey_args.algorithm = algorithms[i];
+        skey_args.value_len = keybits[i];
+        sc_pkcs15init_generate_secret_key(p15card, profile, &skey_args, NULL);
+    }
+}
+
+void do_store_secret_key(struct sc_profile *profile, struct sc_pkcs15_card *p15card,
+                         sc_card_t *card, uint8_t *buf)
+{
+    struct sc_pkcs15init_skeyargs args;
+    int algorithms[] = { SC_ALGORITHM_AES, SC_ALGORITHM_DES, SC_ALGORITHM_3DES };
+    unsigned int keybits[] = { 128, 64, 192 };
+
+    memset(&args, 0, sizeof(args));
+    args.access_flags |= SC_PKCS15_PRKEY_ACCESS_EXTRACTABLE | SC_PKCS15_PRKEY_ACCESS_SENSITIVE;
+    args.usage |= SC_PKCS15_PRKEY_USAGE_ENCRYPT | SC_PKCS15_PRKEY_USAGE_DECRYPT;
+    sc_pkcs15_format_id("02", &(args.auth_id));
+
+    for (int i = 0; i < 3; i++) {
+        size_t keybytes = (keybits[i] + 7) / 8;
+        args.key.data = malloc(keybytes);
+        memcpy(args.key.data, buf, keybytes);
+        args.key.data_len = keybytes;
+        args.algorithm = algorithms[i];
+        args.value_len = keybits[i];
+
+        sc_pkcs15init_store_secret_key(p15card, profile, &args, NULL);
+        if (args.key.data)
+            free(args.key.data);
+    }
+}
+
+void do_erase(struct sc_profile *profile, sc_card_t *card)
+{
+    struct sc_pkcs15_card *p15card;
+
+    p15card = sc_pkcs15_card_new();
+    p15card->card = card;
+
+    sc_pkcs15init_erase_card(p15card, profile, NULL);
+    sc_pkcs15_card_free(p15card);
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+    sc_context_t          *ctx = NULL;
+    sc_card_t             *card = NULL;
+    struct sc_pkcs15_card *p15card = NULL;
+    struct sc_profile     *profile = NULL;
+    struct sc_reader      *reader = NULL;
+    const uint8_t         *reader_data = NULL;
+    size_t                 reader_data_size = 0;
+    uint8_t               *buf = NULL;
+    uint16_t               len = size < 256 ? size : 256;
+    unsigned char         *pin = NULL;
+    unsigned char         *so_pin = NULL;
+    unsigned char         *puk = NULL;
+    unsigned char         *so_puk = NULL;
+    struct sc_pkcs15_card *tmp_p15_data = NULL;
+
+#ifdef FUZZING_ENABLED
+    fclose(stdout);
+#endif
+
+    if (size == 0)
+        return 0;
+
+    if (!fuzz_get_reader_data(data, size, &reader_data, &reader_data_size)) {
+        return 0;
+    }
+
+    /* Establish context for fuzz app*/
+    sc_establish_context(&ctx, "fuzz");
+    if (!ctx)
+        return 0;
+
+    if (fuzz_connect_card(ctx, &card, &reader, reader_data, reader_data_size) != SC_SUCCESS)
+        goto end;
+
+    /* Load profile and bind with card */
+    fuzz_pkcs15init_bind(card, &profile, data, size - reader_data_size);
+
+    if(!profile)
+        goto end;
+
+    pin = malloc(11);
+    so_pin = malloc(9);
+    puk = malloc(9);
+    so_puk = malloc(9);
+    buf = malloc(len * sizeof(char));
+    if (!pin || !so_pin || !puk || !so_puk || !buf)
+        goto end_release;
+
+    memcpy(pin, "123456\0", 7);
+    memcpy(so_pin, "12345678\0", 9);
+    memcpy(puk, "12345678\0", 9);
+    memcpy(so_puk, "12345678\0", 9);
+    memcpy(buf, data, len);
+
+    /* test pkcs15-init functionality*/
+    do_init_app(profile, p15card, card, so_pin, so_puk);
+
+    if (!sc_pkcs15_bind(card, NULL, &p15card)) { /* First and only sc_pkcs15_bind calling, is omitted in next cases*/
+        do_store_pin(profile, p15card, card, pin, so_pin);
+    }
+
+    /* sc_pkcs15_bind failed, no point in testing next cases */
+    if (!p15card)
+        goto end_release;
+
+    do_store_data_object(profile, p15card, card, buf, len);
+    do_generate_key(profile, p15card, card);
+    do_generate_skey(profile, p15card, card);
+    do_store_secret_key(profile, p15card, card, buf);
+
+    sc_pkcs15init_finalize_card(card, profile);
+    sc_pkcs15init_sanity_check(p15card, profile);
+
+    do_erase(profile, card);
+
+end_release:
+    free(pin);
+    free(puk);
+    free(so_pin);
+    free(so_puk);
+    free(buf);
+
+end:
+	if (profile) {
+		tmp_p15_data = profile->p15_data;
+		sc_pkcs15init_unbind(profile);
+		if (tmp_p15_data != p15card)
+			sc_pkcs15_unbind(tmp_p15_data);
+	}
+	if (p15card) {
+		sc_pkcs15_unbind(p15card);
+	}
+    if (card)
+	    sc_disconnect_card(card);
+    sc_release_context(ctx);
+        
+    return 0;
+}
diff -Nru opensc-0.22.0/src/tests/fuzzing/fuzz_pkcs15_reader.c opensc-0.23.0/src/tests/fuzzing/fuzz_pkcs15_reader.c
--- opensc-0.22.0/src/tests/fuzzing/fuzz_pkcs15_reader.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/fuzzing/fuzz_pkcs15_reader.c	2022-11-29 09:34:43.000000000 +0100
@@ -20,196 +20,30 @@
 #include "config.h"
 #endif
 
+#include "fuzzer_reader.h"
 #include "libopensc/pkcs15.h"
-#include "libopensc/internal.h"
-#include <stdlib.h>
-#include <string.h>
 
 const char *__asan_default_options() {
   return "verbosity=0:mallocator_may_return_null=1";
 }
 
-/* private data structures */
-struct driver_data {
-    const uint8_t *Data;
-    size_t Size;
-};
-
-static struct sc_reader_operations fuzz_ops = {0};
-static struct sc_reader_driver fuzz_drv = {
-    "Fuzzing reader",
-    "fuzz",
-    &fuzz_ops,
-    NULL
-};
-
-void fuzz_get_chunk(sc_reader_t *reader, const uint8_t **chunk, uint16_t *chunk_size)
-{
-    struct driver_data *data;
-    uint16_t c_size;
-    const uint8_t *c;
-
-    if (chunk)
-        *chunk = NULL;
-    if (chunk_size)
-        *chunk_size = 0;
-
-    if (!chunk || !chunk_size || !reader) {
-        sc_debug(reader->ctx, SC_LOG_DEBUG_VERBOSE_TOOL, "Invalid Arguments");
-        return;
-    }
-    data = reader->drv_data;
-    if (!data || !data->Data || data->Size < sizeof c_size) {
-        sc_debug(reader->ctx, SC_LOG_DEBUG_VERBOSE_TOOL, "Invalid Arguments");
-        return;
-    }
-
-    /* parse the length of the returned data on two bytes */
-    c_size = *((uint16_t *) data->Data);
-    /* consume two bytes from the fuzzing data */
-    data->Size -= sizeof c_size;
-    data->Data += sizeof c_size;
-
-    if (data->Size < c_size) {
-        c_size = data->Size;
-    }
-
-    /* consume the bytes from the fuzzing data */
-    c = data->Data;
-    data->Size -= c_size;
-    data->Data += c_size;
-
-    sc_debug_hex(reader->ctx, SC_LOG_DEBUG_VERBOSE_TOOL,
-        "Returning fuzzing chunk", c, c_size);
-
-    *chunk = c;
-    *chunk_size = c_size;
-}
-
-static int fuzz_reader_release(sc_reader_t *reader)
-{
-    if (reader) {
-        free(reader->drv_data);
-        reader->drv_data = NULL;
-    }
-
-    return SC_SUCCESS;
-}
-
-static int fuzz_reader_connect(sc_reader_t *reader)
-{
-    uint16_t chunk_size;
-    const uint8_t *chunk;
-
-    fuzz_get_chunk(reader, &chunk, &chunk_size);
-
-    if (chunk_size > SC_MAX_ATR_SIZE)
-        chunk_size = SC_MAX_ATR_SIZE;
-    else
-        reader->atr.len = chunk_size;
-
-    if (chunk_size > 0)
-        memcpy(reader->atr.value, chunk, chunk_size);
-
-    return SC_SUCCESS;
-}
-
-static int fuzz_reader_disconnect(sc_reader_t *reader)
-{
-    return SC_SUCCESS;
-}
-
-static int fuzz_reader_transmit(sc_reader_t *reader, sc_apdu_t *apdu)
-{
-    const uint8_t *chunk;
-    uint16_t chunk_size;
-
-    fuzz_get_chunk(reader, &chunk, &chunk_size);
-
-    if (chunk_size >= 2) {
-        /* set the SW1 and SW2 status bytes (the last two bytes of
-         * the response */
-        apdu->sw1 = (unsigned int)chunk[chunk_size - 2];
-        apdu->sw2 = (unsigned int)chunk[chunk_size - 1];
-        chunk_size -= 2;
-        /* set output length and copy the returned data if necessary */
-        if (chunk_size <= apdu->resplen)
-            apdu->resplen = chunk_size;
-
-        if (apdu->resplen != 0)
-            memcpy(apdu->resp, chunk, apdu->resplen);
-    } else {
-        apdu->sw1 = 0x6D;
-        apdu->sw2 = 0x00;
-        apdu->resplen = 0;
-    }
-
-    return SC_SUCCESS;
-}
-
-struct sc_reader_driver *sc_get_fuzz_driver(void)
-{
-    fuzz_ops.release = fuzz_reader_release;
-    fuzz_ops.connect = fuzz_reader_connect;
-    fuzz_ops.disconnect = fuzz_reader_disconnect;
-    fuzz_ops.transmit = fuzz_reader_transmit;
-    return &fuzz_drv;
-}
-
-void fuzz_add_reader(struct sc_context *ctx, const uint8_t *Data, size_t Size)
-{
-    sc_reader_t	*reader;
-    struct driver_data *data;
-    char name[64] = {0};
-
-    if (!(reader = calloc(1, sizeof(*reader)))
-            || !(data = (calloc(1, sizeof(*data))))) {
-        free(reader);
-        return;
-    }
-
-    data->Data = Data;
-    data->Size = Size;
-
-    reader->driver = &fuzz_drv;
-    reader->ops = &fuzz_ops;
-    reader->drv_data = data;
-    snprintf(name, sizeof name - 1, "%zu random byte%s reader (%p)",
-            Size, Size == 1 ? "" : "s", Data);
-    reader->name = strdup(name);
-
-    reader->ctx = ctx;
-    list_append(&ctx->readers, reader);
-}
-
 int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
 {
     struct sc_context *ctx = NULL;
     struct sc_card *card = NULL;
     struct sc_pkcs15_card *p15card = NULL;
-    struct sc_reader *reader;
+    struct sc_reader *reader = NULL;
     struct sc_pkcs15_object *obj;
 
     sc_establish_context(&ctx, "fuzz");
     if (!ctx)
         return 0;
-    /* copied from sc_release_context() */
-    while (list_size(&ctx->readers)) {
-        sc_reader_t *rdr = (sc_reader_t *) list_get_at(&ctx->readers, 0);
-        _sc_delete_reader(ctx, rdr);
-    }
-    if (ctx->reader_driver->ops->finish != NULL)
-        ctx->reader_driver->ops->finish(ctx);
-
-    ctx->reader_driver = sc_get_fuzz_driver();
-
-    fuzz_add_reader(ctx, Data, Size);
 
-    reader = sc_ctx_get_reader(ctx, 0);
-    sc_connect_card(reader, &card);
-    sc_pkcs15_bind(card, NULL, &p15card);
+    if (fuzz_connect_card(ctx, &card, &reader, Data, Size) != SC_SUCCESS)
+        goto err;
 
-    if (p15card) {
+    if (SC_SUCCESS == sc_pkcs15_bind(card, NULL, &p15card)
+        && p15card) {
         const uint8_t *in, *param;
         uint16_t in_len, param_len;
         fuzz_get_chunk(reader, &in, &in_len);
@@ -223,7 +57,7 @@
                 SC_ALGORITHM_RSA_PAD_ISO9796};
             for (i = 0; i < sizeof decipher_flags/sizeof *decipher_flags; i++) {
                 sc_pkcs15_decipher(p15card, obj, decipher_flags[i],
-                        in, in_len, buf, sizeof buf);
+                        in, in_len, buf, sizeof buf, NULL);
             }
 
             i = sizeof buf;
@@ -236,7 +70,7 @@
                 /* see `pkcs15_create_secret_key` in
                  * `src/pkcs11/framework-pkc15.c` for creating a temporary
                  * secret key for wrapping/unwrapping */
-                unsigned long l = sizeof buf;
+                size_t l = sizeof buf;
                 struct sc_pkcs15_object target_key;
                 struct sc_pkcs15_skey_info skey_info;
                 uint16_t len;
@@ -277,7 +111,7 @@
             };
             for (i = 0; i < sizeof signature_flags/sizeof *signature_flags; i++) {
                 sc_pkcs15_compute_signature(p15card, obj, signature_flags[i],
-                        in, in_len, buf, sizeof buf);
+                        in, in_len, buf, sizeof buf, NULL);
             }
 
             if (obj->type == SC_PKCS15_TYPE_AUTH_PIN) {
@@ -290,6 +124,7 @@
         sc_pkcs15_card_free(p15card);
     }
 
+err:
     sc_disconnect_card(card);
     sc_release_context(ctx);
 
diff -Nru opensc-0.22.0/src/tests/fuzzing/fuzz_pkcs15_tool.c opensc-0.23.0/src/tests/fuzzing/fuzz_pkcs15_tool.c
--- opensc-0.22.0/src/tests/fuzzing/fuzz_pkcs15_tool.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/fuzzing/fuzz_pkcs15_tool.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,98 @@
+/*
+ * fuzz_pkcs15_tool.c: Fuzz target for pkcs15-tool
+ *
+ * Copyright (C) 2022 Red Hat, Inc.
+ *
+ * Author: Veronika Hanulikova <vhanulik at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#ifdef __APPLE__
+#define _XOPEN_SOURCE 600
+#else
+#define _XOPEN_SOURCE 500
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include "libopensc/internal.h"
+#include "fuzzer_reader.h"
+#include "fuzzer_tool.h"
+#undef stderr
+#define stderr stdout
+
+/* Rename main to call it in fuzz target */
+#define main _main
+#define util_connect_card_ex(ctx, card, id, do_wait, do_lock, verbose) fuzz_util_connect_card(ctx, card)
+# include "tools/pkcs15-tool.c"
+#undef main
+
+static const uint8_t *reader_data = NULL;
+static size_t reader_data_size = 0;
+
+/* Use instead of util_connect_card() */
+int fuzz_util_connect_card(sc_context_t *ctx, sc_card_t **card)
+{
+	return fuzz_connect_card(ctx, card, NULL, reader_data, reader_data_size);
+}
+
+void initialize_global()
+{
+	/* Global variables need to be reser between runs,
+	   fuzz target is called repetitively in one execution */
+	ctx = NULL;
+	card = NULL;
+	p15card = NULL;
+	opt_auth_id = NULL;
+	opt_reader = NULL;
+	opt_cert = NULL;
+	opt_data = NULL;
+	opt_pubkey = NULL;
+	opt_outfile = NULL;
+	opt_bind_to_aid = NULL;
+	opt_newpin = NULL;
+	opt_pin = NULL;
+	opt_puk = NULL;
+
+	optind = 0;
+	opterr = 0; /* do not print out error messages */
+	optopt = 0;
+}
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
+{
+	char **argv = NULL;
+	int argc = 0;
+
+	if (size < 10)
+		return 0;
+
+#ifdef FUZZING_ENABLED
+	fclose(stdout);
+#endif
+	initialize_global();
+
+	if (get_fuzzed_argv("./fuzz_pkcs15", data, size, &argv, &argc, &reader_data, &reader_data_size) != 0)
+		return 0;
+	_main(argc, argv);
+	free_arguments(argc, argv);
+
+	return 0;
+}
diff -Nru opensc-0.22.0/src/tests/fuzzing/fuzz_scconf_parse_string.c opensc-0.23.0/src/tests/fuzzing/fuzz_scconf_parse_string.c
--- opensc-0.22.0/src/tests/fuzzing/fuzz_scconf_parse_string.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/fuzzing/fuzz_scconf_parse_string.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,55 @@
+/*
+ * fuzz_scconf_parse_string.c: Fuzz target for scconf_parse_string
+ *
+ * Copyright (C) 2021 Red Hat, Inc.
+ *
+ * Author: Veronika Hanulikova <vhanulik at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#if HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "scconf/scconf.h"
+#include "libopensc/internal.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define MAX_SIZE 16000
+
+int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+    scconf_context *ctx = NULL;
+    char *buf = NULL;
+
+    if (size > MAX_SIZE)
+        return 0;
+
+    if (!(buf = malloc(size + 1)))
+        return 0;
+    if (!(ctx = scconf_new(NULL))) {
+        free(buf);
+        return 0;
+    }
+
+    memcpy(buf, data, size);
+    buf[size] = '\0';
+
+    scconf_parse_string(ctx, buf);
+
+    scconf_free(ctx);
+    free(buf);
+    return 0;
+}
diff -Nru opensc-0.22.0/src/tests/fuzzing/Makefile.am opensc-0.23.0/src/tests/fuzzing/Makefile.am
--- opensc-0.22.0/src/tests/fuzzing/Makefile.am	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/fuzzing/Makefile.am	2022-11-29 09:34:43.000000000 +0100
@@ -1,15 +1,57 @@
-AM_CPPFLAGS = -I$(top_srcdir)/src
+AM_CPPFLAGS = -I$(top_srcdir)/src -D'SC_PKCS15_PROFILE_DIRECTORY="$(pkgdatadir)"' \
+				-D'DEFAULT_PKCS11_PROVIDER="$(DEFAULT_PKCS11_PROVIDER)"'
 AM_CFLAGS = -g -O0 $(OPTIONAL_OPENSSL_CFLAGS) $(OPTIONAL_READLINE_CFLAGS) $(PTHREAD_CFLAGS)
-LIBS = $(FUZZING_LIBS) \
+LIBS = $(FUZZING_LIBS)\
 	$(top_builddir)/src/libopensc/libopensc.la \
 	$(top_builddir)/src/common/libscdl.la \
+	$(top_builddir)/src/pkcs15init/libpkcs15init.la \
 	$(top_builddir)/src/common/libcompat.la
 
-if ENABLE_FUZZING
-noinst_PROGRAMS = fuzz_asn1_print fuzz_asn1_sig_value fuzz_pkcs15_decode fuzz_pkcs15_reader
+noinst_PROGRAMS = fuzz_asn1_print fuzz_asn1_sig_value fuzz_pkcs15_decode fuzz_pkcs15_reader \
+					fuzz_scconf_parse_string fuzz_pkcs15_encode fuzz_card \
+					fuzz_pkcs15_tool fuzz_pkcs15_crypt
+
+if ENABLE_STATIC
+noinst_PROGRAMS += fuzz_pkcs15init
+endif
+
+if ENABLE_OPENSSL
+noinst_PROGRAMS += fuzz_piv_tool
+endif
+
+if !ENABLE_SHARED
+noinst_PROGRAMS += fuzz_pkcs11
+endif
+
+noinst_HEADERS = fuzzer_reader.h fuzzer_tool.h
+
+ADDITIONAL_SRC =
+if !ENABLE_FUZZING
+ADDITIONAL_SRC += fuzzer.c
 endif
 
-fuzz_asn1_print_SOURCES = fuzz_asn1_print.c
-fuzz_asn1_sig_value_SOURCES = fuzz_asn1_sig_value.c
-fuzz_pkcs15_decode_SOURCES = fuzz_pkcs15_decode.c
-fuzz_pkcs15_reader_SOURCES = fuzz_pkcs15_reader.c
+fuzz_asn1_print_SOURCES = fuzz_asn1_print.c $(ADDITIONAL_SRC)
+fuzz_asn1_sig_value_SOURCES = fuzz_asn1_sig_value.c $(ADDITIONAL_SRC)
+fuzz_pkcs15_decode_SOURCES = fuzz_pkcs15_decode.c fuzzer_reader.c $(ADDITIONAL_SRC)
+fuzz_pkcs15_reader_SOURCES = fuzz_pkcs15_reader.c fuzzer_reader.c $(ADDITIONAL_SRC)
+fuzz_scconf_parse_string_SOURCES = fuzz_scconf_parse_string.c $(ADDITIONAL_SRC)
+fuzz_pkcs15init_SOURCES = fuzz_pkcs15init.c fuzzer_reader.c $(ADDITIONAL_SRC)
+fuzz_pkcs15init_LDADD = $(OPTIONAL_OPENSSL_LIBS) $(OPENPACE_LIBS)
+fuzz_pkcs15init_LDFLAGS = -static
+fuzz_pkcs15_encode_SOURCES = fuzz_pkcs15_encode.c fuzzer_reader.c $(ADDITIONAL_SRC)
+fuzz_card_SOURCES = fuzz_card.c fuzzer_reader.c $(ADDITIONAL_SRC)
+fuzz_piv_tool_SOURCES = fuzz_piv_tool.c fuzzer_reader.c fuzzer_tool.c $(ADDITIONAL_SRC) \
+						 ../../tools/util.c
+fuzz_piv_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
+fuzz_pkcs15_tool_SOURCES = fuzz_pkcs15_tool.c fuzzer_reader.c fuzzer_tool.c $(ADDITIONAL_SRC) \
+							../../tools/util.c ../../pkcs11/pkcs11-display.c
+fuzz_pkcs15_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
+fuzz_pkcs15_crypt_SOURCES = fuzz_pkcs15_crypt.c fuzzer_reader.c fuzzer_tool.c $(ADDITIONAL_SRC) \
+							../../tools/util.c
+fuzz_pkcs15_crypt_LDADD = $(OPTIONAL_OPENSSL_LIBS)
+fuzz_pkcs11_SOURCES = fuzz_pkcs11.c fuzzer_reader.c fuzzer_tool.c $(ADDITIONAL_SRC)
+fuzz_pkcs11_CFLAGS = $(OPTIONAL_OPENSSL_CFLAGS) $(PTHREAD_CFLAGS)
+fuzz_pkcs11_LDADD = \
+	$(top_builddir)/src/common/libpkcs11.la \
+	$(OPTIONAL_OPENSSL_LIBS) \
+	$(top_builddir)/src/pkcs11/libopensc-pkcs11.la
diff -Nru opensc-0.22.0/src/tests/fuzzing/README.md opensc-0.23.0/src/tests/fuzzing/README.md
--- opensc-0.22.0/src/tests/fuzzing/README.md	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/fuzzing/README.md	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,188 @@
+# Fuzzing in OpenSC
+
+OpenSC is part of the [OSS-Fuzz project](https://google.github.io/oss-fuzz/), which provides continuous fuzzing support for open-source projects.
+Fuzzer [libFuzzer](https://llvm.org/docs/LibFuzzer.html) can be used for local testing.
+
+To the terms used, _fuzzer_ refers to a program that injects malformed inputs to the system under test; _fuzz target_ is a program that accepts data buffer, processes it and passes the data to the tested interface.
+
+## Building
+
+### Building for fuzzing
+Successful build of fuzz targets requires `./configure` run with correctly set CC, CFLAGS and FUZZING_LIBS. Note that some of the fuzz targets can be built only with the `--disable-shared` option.
+
+Example configuration for libFuzzer:
+```
+./configure --disable-optimization --disable-shared --disable-pcsc --enable-ctapi --enable-fuzzing CC=clang CFLAGS=-fsanitize=fuzzer-no-link FUZZING_LIBS=-fuzzer
+```
+
+To add some of the LLVM Sanitizers, modify `FUZZING_LIBS`:  
+```
+FUZZING_LIBS=-fuzzer,address,undefined
+```
+Sanitizers can also be modified by [flags](https://github.com/google/sanitizers/wiki/SanitizerCommonFlags).
+
+### Building without fuzzing support
+When fuzzing is not enabled explicitly by `--enable-fuzzing`, fuzz targets are built without fuzzing support. They can be used for local regression testing and accept one argument for filename with input for the testing functions.
+
+Example of testing without fuzzing:
+```
+./fuzz_pkcs15_reader ./input_file
+```
+
+## Fuzzing
+### libFuzzer
+See libFuzzer [documentation](https://llvm.org/docs/LibFuzzer.html) for details.
+
+Fuzzing with a predefined corpus can be run like this:
+```
+./fuzz_pkcs15_reader corpus/fuzz_pkcs15_reader 
+```
+Newly generated input files are stored in the corpus directory.
+
+By default, `stdout` is closed for fuzzing. However, some fuzz targets may output to `stderr`. You can suppress `stderr` with the `-close_fd_mask` option (see libFuzzer).
+
+To execute the fuzz target on one input, try:
+```
+./fuzz_pkcs15_reader ./test-case
+```
+
+## Corpus
+
+### Corpus for `fuzz_pkcs15_reader`
+
+The corpus files for the `fuzz_pkcs15_reader` are interpreted by the virtual
+reader as follows:
+
+ * first two bytes denote the block length N as an unsigned integer. The endianness
+   depends on the architecture
+ * the following block of the length N
+
+The first block is always the ATR of the card, which is very frequently used
+for card detection.
+
+All the other following blocks are used as replies from the emulated card.
+
+Example block:
+```
+0f 00
+ -- length indicator saying next block is 15 bytes long
+3b f5 96 00 00 81 31 fe 45 4d 79 45 49 44 14
+ -- the 15 bytes block (in this case ATR)
+
+29 00
+ -- the second block length of 41 bytes
+6f 25 81 02 7f ff 82 01 38 83 02 50 15 86 03 11
+1f ff 85 02 00 02 8a 01 01 84 0c a0 00 00 00 63
+50 4b 43 53 2d 31 35 90 00
+ -- 41 bytes data block (APDU response)
+```
+
+### How to generate corpus files from existing cards
+
+Modify the `src/libopensc/reader-pcsc.c` and uncomment the following line:
+```
+#define APDU_LOG_FILE "apdulog"
+```
+and rebuild OpenSC. Then run any OpenSC tool talking to the card. For example
+```
+./src/tools/pkcs11-tool -L --module ./src/pkcs11/.libs/opensc-pkcs11.so
+```
+Any APDU returned from the card is now logged into the file `apdulog` in the
+format expected by the `fuzz_pkcs15_reader`  fuzz target. It is also prefixed with
+the ATR of the connected card as expected by the fuzz target. This file can be used
+as a starting point that gets through the card detection but does not go into
+all the operations the fuzz target attempts later.
+
+### The pkcs15init fuzz target
+
+The pkcs15init fuzz target consists of two separate parts. The first one is parsing
+the profile file, which is separated from the rest of the input with a NULL
+byte (0x00). The rest is interpreted as in the case of the `fuzz_pkcs15_reader`.
+
+When creating a corpus for this fuzz target, stuff gets messier because:
+
+ * The first part is the profile file
+ * The `pkcs15-init` can do only one operation at a time, so we need to skip the
+   card init when concatenating the APDU traces
+
+So at first, erase the card and move away the apdulog:
+```
+./src/tools/pkcs15-init --erase-card --so-pin 12345678
+$ mv apdulog /tmp/apdu_erase
+```
+Then prepare the separate files for each operation in the fuzz target:
+```
+$ ./src/tools/pkcs15-init -C --pin 123456 --puk 12345678 --so-pin 12345678 --so-puk 12345678
+$ mv apdulog /tmp/apdu_create
+$ ./src/tools/pkcs15-init -P -a 1 -l "Basic PIN" --pin 1234555678 --puk 12345678
+$ mv apdulog /tmp/apdu_create_pin
+$ ./src/tools/pkcs15-init --store-data /path/to/any_file --label label
+$ mv apdulog /tmp/apdu_store_data
+$ ./src/tools/pkcs15-init --generate-key rsa:1024 --auth-id 01 --so-pin 12345678 --pin 1234555678
+$ mv apdulog /tmp/apdu_generate_rsa
+$ ./src/tools/pkcs15-init --generate-key ec:prime256v1 --auth-id 01 --so-pin 12345678 --pin 123455678
+$ mv apdulog /tmp/apdu_generate_ecdsa
+$ ./src/tools/pkcs15-init -F
+$ mv apdulog /tmp/apdu_finalize
+```
+
+Now, construct the corpus file:
+* insert profile and zero bytes as a delimiter
+* `apdu\_create` can be used as it is
+* from `apdu\_create\_pin` remove the part for connecting the card
+* from `apdu\_store\_data` remove some central parts since testing data is smaller than data used in apdu
+* `apdu_generate_*` and `apdu\_finalize` need to skip connecting card and `sc_pcks15_bind()`
+* symmetric key generation is not supported on the card; let's fill that part with some dummy values from generating RSA keys
+* `apdu\_erase` needs to skip part for connecting card
+
+```
+SKIP=1257
+( \
+  cat file.profile; printf "\x00"; \
+  cat tmp/apdu_create; \
+  dd if=tmp/apdu_create_pin bs=1 skip=421; \
+  dd if=tmp/apdu_store_data bs=1 skip=1257 count=1675; \
+  dd if=tmp/apdu_store_data bs=1 skip=3020; \
+  dd if=tmp/apdu_generate_rsa bs=1 skip=$SKIP; \
+  dd if=tmp/apdu_generate_ecdsa bs=1 skip=$SKIP; \
+  dd if=tmp/apdu_generate_rsa bs=1 skip=$SKIP count=5304; \
+  dd if=tmp/apdu_generate_rsa bs=1 skip=$SKIP count=5304; \
+  dd if=tmp/apdu_generate_rsa bs=1 skip=$SKIP count=5304; \
+  dd if=tmp/apdu_finalize bs=1 skip=$SKIP; \
+  dd if=tmp/apdu_erase bs=1 skip=421; \
+) > tmp/testcase
+```
+
+Now, let's try to feed the data into the fuzz target:
+```
+OPENSC_DEBUG=9 ./src/tests/fuzzing/fuzz_pkcs15init_profile /tmp/testcase
+```
+The debug log should show the card detection, which goes through and then some
+pkcs15init operations.
+
+### The piv-tool fuzz target
+
+The `fuzz_piv_tool` target allows testing operations of `piv-tool`. What operation is tested depends of first byte of the fuzzing input:
+
+* `\x00` tests loading of the object, the input looks as\
+`| \x00 | len1 | len2 | admin key | containerID | \x00 | admin_arg | \x00 | len1 | len2 | file content | APDU part |`[^1]
+* `\x01` tests loading of the certificate, the input looks as\
+`| \x01 | len1 | len2 | admin key | ref | \x00 | admin_arg | \x00 | len1 | len2 | file content | APDU part |`[^1]
+* `\x02` tests loading of the compressed certificate, the input looks as by loading of certificate
+* other values for first byte means that whole `argv` is taken from fuzzing input\
+`| > \x003 | arg_1 | \x00 | arg_2 | \x00 | ... | arg_n | \x00 | \x00 | APDU part |`
+
+### The pkcs15-tool fuzz target
+
+The `fuzz_pkcs15_tool` target allows testing operations of `pkcs15-tool`. The options are taken from fuzzing input, it is parsed as\
+`| arg_1 | \x00 | arg_2 | \x00 | ... | arg_n | \x00 | \x00 | APDU part |`
+
+[^1]: `len1` and `len2` refer to two bytes that are parsed as the length of the content of the file that is extracted from the input
+
+### The pkcs15-crypt fuzz target
+
+The `fuzz_pkcs15_crypt` target allows testing operations of `pkcs15-crypt`. What operation is tested depends of first byte of the fuzzing input:
+
+* the whole `argv` is taken from fuzzing input
+* the `-c` and `-s` options are tested with various combinations of other command-line options\
+`| op | hash type | padding | format | aid | aid value | \x00 | id | id value | \x00 | len1 |len2 |file content | APDU part |`
diff -Nru opensc-0.22.0/src/tests/opensc-minidriver-test.c opensc-0.23.0/src/tests/opensc-minidriver-test.c
--- opensc-0.22.0/src/tests/opensc-minidriver-test.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/opensc-minidriver-test.c	2022-11-29 09:34:43.000000000 +0100
@@ -607,7 +607,7 @@
 	if (pinEnv)
 		printf("Running tests using PIN=%s/len=%zd\n", pinEnv, strlen(pinEnv));
 	else
-		printf("Running tests wihtout any PIN\n");
+		printf("Running tests without any PIN\n");
 	memset(&cardData, 0, sizeof(cardData));
 	cardData.dwVersion = 7;
 	cardData.pwszCardName = L"TestCard";
diff -Nru opensc-0.22.0/src/tests/p11test/isoapplet_ref.json opensc-0.23.0/src/tests/p11test/isoapplet_ref.json
--- opensc-0.22.0/src/tests/p11test/isoapplet_ref.json	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/p11test/isoapplet_ref.json	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,362 @@
+{
+"time": 0,
+"results": [
+{
+	"test_id": "wait_test",
+	"result": "skip"
+},
+{
+	"test_id": "supported_mechanisms_test",
+	"data": [
+	[
+		"MECHANISM",
+		"MIN KEY",
+		"MAX KEY",
+		"FLAGS"
+	],
+	[
+		"SHA_1",
+		"0",
+		"0",
+		"CKF_DIGEST"
+	],
+	[
+		"SHA224",
+		"0",
+		"0",
+		"CKF_DIGEST"
+	],
+	[
+		"SHA256",
+		"0",
+		"0",
+		"CKF_DIGEST"
+	],
+	[
+		"SHA384",
+		"0",
+		"0",
+		"CKF_DIGEST"
+	],
+	[
+		"SHA512",
+		"0",
+		"0",
+		"CKF_DIGEST"
+	],
+	[
+		"MD5",
+		"0",
+		"0",
+		"CKF_DIGEST"
+	],
+	[
+		"RIPEMD160",
+		"0",
+		"0",
+		"CKF_DIGEST"
+	],
+	[
+		"GOSTR3411",
+		"0",
+		"0",
+		"CKF_DIGEST"
+	],
+	[
+		"ECDSA_SHA1",
+		"192",
+		"384",
+		"0x01902801"
+	],
+	[
+		"EC_KEY_PAIR_GEN",
+		"192",
+		"384",
+		"0x01910001"
+	],
+	[
+		"RSA_PKCS",
+		"2048",
+		"2048",
+		"0x00002A01"
+	],
+	[
+		"SHA1_RSA_PKCS",
+		"2048",
+		"2048",
+		"0x00002800"
+	],
+	[
+		"SHA224_RSA_PKCS",
+		"2048",
+		"2048",
+		"0x00002800"
+	],
+	[
+		"SHA256_RSA_PKCS",
+		"2048",
+		"2048",
+		"0x00002800"
+	],
+	[
+		"SHA384_RSA_PKCS",
+		"2048",
+		"2048",
+		"0x00002800"
+	],
+	[
+		"SHA512_RSA_PKCS",
+		"2048",
+		"2048",
+		"0x00002800"
+	],
+	[
+		"MD5_RSA_PKCS",
+		"2048",
+		"2048",
+		"0x00002800"
+	],
+	[
+		"RIPEMD160_RSA_PKCS",
+		"2048",
+		"2048",
+		"0x00002800"
+	],
+	[
+		"RSA_PKCS_KEY_PAIR_GEN",
+		"2048",
+		"2048",
+		"CKF_GENERATE_KEY_PAIR"
+	]],
+	"result": "pass"
+},
+{
+	"test_id": "interface_test",
+	"result": "pass"
+},
+{
+	"test_id": "readonly_tests",
+	"data": [
+	[
+		"KEY ID",
+		"MECHANISM",
+		"SIGN&VERIFY WORKS",
+		"ENCRYPT&DECRYPT WORKS"
+	],
+	[
+		"01",
+		"RSA_PKCS",
+		"YES",
+		"YES"
+	],
+	[
+		"01",
+		"SHA1_RSA_PKCS",
+		"YES",
+		""
+	],
+	[
+		"01",
+		"SHA224_RSA_PKCS",
+		"YES",
+		""
+	],
+	[
+		"01",
+		"SHA256_RSA_PKCS",
+		"YES",
+		""
+	],
+	[
+		"01",
+		"SHA384_RSA_PKCS",
+		"YES",
+		""
+	],
+	[
+		"01",
+		"SHA512_RSA_PKCS",
+		"YES",
+		""
+	],
+	[
+		"01",
+		"MD5_RSA_PKCS",
+		"YES",
+		""
+	],
+	[
+		"01",
+		"RIPEMD160_RSA_PKCS",
+		"YES",
+		""
+	],
+	[
+		"02",
+		"RSA_PKCS",
+		"",
+		"YES"
+	]],
+	"result": "pass"
+},
+{
+	"test_id": "multipart_tests",
+	"data": [
+	[
+		"KEY ID",
+		"MECHANISM",
+		"MULTIPART SIGN&VERIFY WORKS"
+	],
+	[
+		"01",
+		"RSA_PKCS",
+		"YES"
+	],
+	[
+		"01",
+		"SHA1_RSA_PKCS",
+		"YES"
+	],
+	[
+		"01",
+		"SHA224_RSA_PKCS",
+		"YES"
+	],
+	[
+		"01",
+		"SHA256_RSA_PKCS",
+		"YES"
+	],
+	[
+		"01",
+		"SHA384_RSA_PKCS",
+		"YES"
+	],
+	[
+		"01",
+		"SHA512_RSA_PKCS",
+		"YES"
+	],
+	[
+		"01",
+		"MD5_RSA_PKCS",
+		"YES"
+	],
+	[
+		"01",
+		"RIPEMD160_RSA_PKCS",
+		"YES"
+	]],
+	"result": "pass"
+},
+{
+	"test_id": "ec_sign_size_test",
+	"fail_reason": "Some signatures were not verified successfully. Please review the log",
+	"result": "fail"
+},
+{
+	"test_id": "usage_test",
+	"data": [
+	[
+		"KEY ID",
+		"LABEL",
+		"TYPE",
+		"BITS",
+		"VERIFY PUBKEY",
+		"SIGN",
+		"VERIFY",
+		"ENCRYPT",
+		"DECRYPT",
+		"WRAP",
+		"UNWRAP",
+		"DERIVE PUBLIC",
+		"DERIVE PRIVATE",
+		"ALWAYS AUTH"
+	],
+	[
+		"01",
+		"Private Key",
+		"RSA",
+		"2048",
+		"",
+		"YES",
+		"YES",
+		"YES",
+		"YES",
+		"YES",
+		"YES",
+		"",
+		"",
+		""
+	],
+	[
+		"02",
+		"Private Key",
+		"RSA",
+		"2048",
+		"",
+		"",
+		"",
+		"YES",
+		"YES",
+		"YES",
+		"YES",
+		"",
+		"",
+		""
+	],
+	[
+		"03",
+		"Private Key",
+		"EC",
+		"256",
+		"",
+		"YES",
+		"YES",
+		"",
+		"",
+		"",
+		"",
+		"",
+		"",
+		""
+	]],
+	"result": "pass"
+},
+{
+	"test_id": "pss_oaep_test",
+	"result": "unknown"
+},
+{
+	"test_id": "derive_tests",
+	"data": [
+	[
+		"KEY ID",
+		"MECHANISM",
+		"DERIVE WORKS"
+	]],
+	"result": "pass"
+},
+{
+	"test_id": "secret_tests",
+	"data": [
+	[
+		"KEY ID",
+		"MECHANISM",
+		"SIGN&VERIFY WORKS",
+		"ENCRYPT&DECRYPT WORKS"
+	]],
+	"result": "pass"
+},
+{
+	"test_id": "wrap_tests",
+	"data": [
+	[
+		"KEY ID",
+		"MECHANISM",
+		"WRAP WORKS",
+		"UNWRAP WORKS"
+	]],
+	"result": "pass"
+}]
+}
diff -Nru opensc-0.22.0/src/tests/p11test/Makefile.am opensc-0.23.0/src/tests/p11test/Makefile.am
--- opensc-0.22.0/src/tests/p11test/Makefile.am	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/p11test/Makefile.am	2022-11-29 09:34:43.000000000 +0100
@@ -15,6 +15,7 @@
 	p11test_case_usage.h p11test_case_wait.h \
 	p11test_case_pss_oaep.h p11test_helpers.h \
 	p11test_case_ec_derive.h p11test_case_interface.h \
+	p11test_case_wrap.h p11test_case_secret.h \
 	p11test_common.h
 
 AM_CPPFLAGS = -I$(top_srcdir)/src
@@ -30,9 +31,11 @@
 	p11test_case_wait.c \
 	p11test_case_pss_oaep.c \
 	p11test_case_interface.c \
+	p11test_case_wrap.c \
+	p11test_case_secret.c \
 	p11test_helpers.c
 p11test_CFLAGS = $(OPTIONAL_OPENSSL_CFLAGS) $(CMOCKA_CFLAGS)
-p11test_LDADD = $(OPTIONAL_OPENSSL_LIBS) $(CMOCKA_LIBS)
+p11test_LDADD = $(OPTIONAL_OPENSSL_LIBS) $(CMOCKA_LIBS) $(LDL_LIBS)
 
 if WIN32
 p11test_SOURCES += $(top_builddir)/win32/versioninfo.rc
diff -Nru opensc-0.22.0/src/tests/p11test/p11test.c opensc-0.23.0/src/tests/p11test/p11test.c
--- opensc-0.22.0/src/tests/p11test/p11test.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/p11test/p11test.c	2022-11-29 09:34:43.000000000 +0100
@@ -32,6 +32,8 @@
 #include "p11test_case_wait.h"
 #include "p11test_case_pss_oaep.h"
 #include "p11test_case_interface.h"
+#include "p11test_case_wrap.h"
+#include "p11test_case_secret.h"
 
 #define DEFAULT_P11LIB	"../../pkcs11/.libs/opensc-pkcs11.so"
 
@@ -49,6 +51,7 @@
 		"		-s slot_id		Slot ID with the card\n"
 		"		-i				Wait for the card before running the test (interactive)\n"
 		"		-o				File to write a log in JSON\n"
+		"		-v				Verbose log output\n"
 		"		-h				This help\n"
 		"\n");
 }
@@ -90,14 +93,21 @@
 		/* Verify that ECDH key derivation works */
 		cmocka_unit_test_setup_teardown(derive_tests,
 			user_login_setup, after_test_cleanup),
+
+		/* Verify that basic operations with secret keys work */
+		cmocka_unit_test_setup_teardown(secret_tests,
+			user_login_setup, after_test_cleanup),
+
+		/* Verify that key wrapping and unwrapping works */
+		cmocka_unit_test_setup_teardown(wrap_tests,
+			user_login_setup, after_test_cleanup),
 	};
 
-	token.library_path = NULL;
-	token.pin = NULL;
-	token.pin_length = 0;
-	token.interactive = 0;
+	/* Make sure it is initialized to sensible values */
+	memset(&token, 0, sizeof(token_info_t));
 	token.slot_id = (unsigned long) -1;
-	token.log.outfile = NULL;
+	token.verify_support = 1;
+	token.encrypt_support = 1;
 
 	while ((command = getopt(argc, argv, "?hm:s:p:io:v")) != -1) {
 		switch (command) {
@@ -139,10 +149,9 @@
 		return -1;
 	}
 
-	debug_print("Card info:\n\tPIN %s\n\tPIN LENGTH %lu\n\t",
+	debug_print("Card info:\n\tPIN %s\n\tPIN LENGTH %zu\n\t",
 		token.pin, token.pin_length);
 
 	return cmocka_run_group_tests(readonly_tests_without_initialization,
 		group_setup, group_teardown);
 }
-
diff -Nru opensc-0.22.0/src/tests/p11test/p11test_case_common.c opensc-0.23.0/src/tests/p11test/p11test_case_common.c
--- opensc-0.22.0/src/tests/p11test/p11test_case_common.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/p11test/p11test_case_common.c	2022-11-29 09:34:43.000000000 +0100
@@ -25,6 +25,13 @@
 char name_buffer[11];
 char flag_buffer[11];
 
+void test_certs_init(test_certs_t *objects)
+{
+	objects->alloc_count = 0;
+	objects->count = 0;
+	objects->data = NULL;
+}
+
 /**
  * If the object enforces re-authentication, do it now.
  */
@@ -51,15 +58,19 @@
 add_object(test_certs_t *objects, CK_ATTRIBUTE key_id, CK_ATTRIBUTE label)
 {
 	test_cert_t *o = NULL;
-	objects->count = objects->count+1;
-	objects->data = realloc(objects->data, objects->count * sizeof(test_cert_t));
-	if (objects->data == NULL)
-		return NULL;
+	objects->count = objects->count + 1;
+	if (objects->count > objects->alloc_count) {
+		objects->alloc_count += 8;
+		objects->data = realloc(objects->data, objects->alloc_count * sizeof(test_cert_t));
+		if (objects->data == NULL)
+			return NULL;
+	}
 
 	o = &(objects->data[objects->count - 1]);
 	o->private_handle = CK_INVALID_HANDLE;
 	o->public_handle = CK_INVALID_HANDLE;
 	o->always_auth = 0;
+	o->extractable = 0;
 	o->bits = 0;
 	o->verify_public = 0;
 	o->num_mechs = 0;
@@ -74,8 +85,8 @@
 	o->derive_pub = 0;
 	o->key_type = -1;
 	o->x509 = NULL; /* The "reuse" capability of d2i_X509() is strongly discouraged */
-	o->key.rsa = NULL;
-	o->key.ec = NULL;
+	o->key = NULL;
+	o->value = NULL;
 
 	/* Store the passed CKA_ID and CKA_LABEL */
 	o->key_id = malloc(key_id.ulValueLen);
@@ -111,12 +122,14 @@
 {
 	size_t i;
 
-	if (o->type == EVP_PK_RSA) {
+	if (o->type == EVP_PKEY_RSA) {
 		if (token.num_rsa_mechs > 0 ) {
 			/* Get supported mechanisms by token */
 			o->num_mechs = token.num_rsa_mechs;
 			for (i = 0; i < token.num_rsa_mechs; i++) {
 				o->mechs[i].mech = token.rsa_mechs[i].mech;
+				o->mechs[i].params = token.rsa_mechs[i].params;
+				o->mechs[i].params_len = token.rsa_mechs[i].params_len;
 				o->mechs[i].result_flags = 0;
 				o->mechs[i].usage_flags =
 					token.rsa_mechs[i].usage_flags;
@@ -125,15 +138,19 @@
 			/* Use the default list */
 			o->num_mechs = 1;
 			o->mechs[0].mech = CKM_RSA_PKCS;
+			o->mechs[0].params = NULL;
+			o->mechs[0].params_len = 0;
 			o->mechs[0].result_flags = 0;
 			o->mechs[0].usage_flags = CKF_SIGN | CKF_VERIFY
 				| CKF_ENCRYPT | CKF_DECRYPT;
 		}
-	} else if (o->type == EVP_PK_EC) {
+	} else if (o->type == EVP_PKEY_EC) {
 		if (token.num_ec_mechs > 0 ) {
 			o->num_mechs = token.num_ec_mechs;
 			for (i = 0; i < token.num_ec_mechs; i++) {
 				o->mechs[i].mech = token.ec_mechs[i].mech;
+				o->mechs[i].params = token.ec_mechs[i].params;
+				o->mechs[i].params_len = token.ec_mechs[i].params_len;
 				o->mechs[i].result_flags = 0;
 				o->mechs[i].usage_flags =
 					token.ec_mechs[i].usage_flags;
@@ -142,14 +159,19 @@
 			/* Use the default list */
 			o->num_mechs = 1;
 			o->mechs[0].mech = CKM_ECDSA;
+			o->mechs[0].params = NULL;
+			o->mechs[0].params_len = 0;
 			o->mechs[0].result_flags = 0;
 			o->mechs[0].usage_flags = CKF_SIGN | CKF_VERIFY;
 		}
+#ifdef EVP_PKEY_ED25519
 	} else if (o->type == EVP_PKEY_ED25519) {
 		if (token.num_ed_mechs > 0 ) {
 			o->num_mechs = token.num_ed_mechs;
 			for (i = 0; i < token.num_ed_mechs; i++) {
 				o->mechs[i].mech = token.ed_mechs[i].mech;
+				o->mechs[i].params = token.ed_mechs[i].params;
+				o->mechs[i].params_len = token.ed_mechs[i].params_len;
 				o->mechs[i].result_flags = 0;
 				o->mechs[i].usage_flags =
 					token.ed_mechs[i].usage_flags;
@@ -158,14 +180,20 @@
 			/* Use the default list */
 			o->num_mechs = 1;
 			o->mechs[0].mech = CKM_EDDSA;
+			o->mechs[0].params = NULL;
+			o->mechs[0].params_len = 0;
 			o->mechs[0].result_flags = 0;
 			o->mechs[0].usage_flags = CKF_SIGN | CKF_VERIFY;
 		}
+#endif
+#ifdef EVP_PKEY_X25519
 	} else if (o->type == EVP_PKEY_X25519) {
 		if (token.num_montgomery_mechs > 0 ) {
 			o->num_mechs = token.num_montgomery_mechs;
-			for (i = 0; i < token.num_ed_mechs; i++) {
+			for (i = 0; i < token.num_montgomery_mechs; i++) {
 				o->mechs[i].mech = token.montgomery_mechs[i].mech;
+				o->mechs[i].params = token.montgomery_mechs[i].params;
+				o->mechs[i].params_len = token.montgomery_mechs[i].params_len;
 				o->mechs[i].result_flags = 0;
 				o->mechs[i].usage_flags =
 					token.montgomery_mechs[i].usage_flags;
@@ -174,9 +202,32 @@
 			/* Use the default list */
 			o->num_mechs = 1;
 			o->mechs[0].mech = CKM_ECDH1_DERIVE;
+			o->mechs[0].params = NULL;
+			o->mechs[0].params_len = 0;
 			o->mechs[0].result_flags = 0;
 			o->mechs[0].usage_flags = CKF_DERIVE;
 		}
+#endif
+	/* Nothing in the above enum can be used for secret keys */
+	} else if (o->key_type == CKK_AES) {
+		if (token.num_aes_mechs > 0 ) {
+			o->num_mechs = token.num_aes_mechs;
+			for (i = 0; i < token.num_aes_mechs; i++) {
+				o->mechs[i].mech = token.aes_mechs[i].mech;
+				o->mechs[i].params = token.aes_mechs[i].params;
+				o->mechs[i].params_len = token.aes_mechs[i].params_len;
+				o->mechs[i].result_flags = 0;
+				o->mechs[i].usage_flags = token.aes_mechs[i].usage_flags;
+			}
+		} else {
+			/* Use the default list */
+			o->num_mechs = 1;
+			o->mechs[0].mech = CKM_AES_CBC;
+			o->mechs[0].params = NULL;
+			o->mechs[0].params_len = 0;
+			o->mechs[0].result_flags = 0;
+			o->mechs[0].usage_flags = CKF_ENCRYPT|CKF_DECRYPT|CKF_WRAP|CKF_UNWRAP;
+		}
 	}
 }
 
@@ -208,30 +259,20 @@
 	}
 
 	if (EVP_PKEY_base_id(evp) == EVP_PKEY_RSA) {
-		/* Extract public RSA key */
-		const RSA *rsa = EVP_PKEY_get0_RSA(evp);
-		if ((o->key.rsa = RSAPublicKey_dup((RSA *)rsa)) == NULL) {
-			fail_msg("RSAPublicKey_dup failed");
-			return -1;
-		}
-		o->type = EVP_PK_RSA;
+		o->key = evp;
+		o->type = EVP_PKEY_RSA;
 		o->bits = EVP_PKEY_bits(evp);
 
 	} else if (EVP_PKEY_base_id(evp) == EVP_PKEY_EC) {
-		/* Extract public EC key */
-		const EC_KEY *ec = EVP_PKEY_get0_EC_KEY(evp);
-		if ((o->key.ec = EC_KEY_dup(ec)) == NULL) {
-			fail_msg("EC_KEY_dup failed");
-			return -1;
-		}
-		o->type = EVP_PK_EC;
+		o->key = evp;
+		o->type = EVP_PKEY_EC;
 		o->bits = EVP_PKEY_bits(evp);
 
 	} else {
+		EVP_PKEY_free(evp);
 		fprintf(stderr, "[WARN %s ]evp->type = 0x%.4X (not RSA, EC)\n",
 			o->id_str, EVP_PKEY_id(evp));
 	}
-	EVP_PKEY_free(evp);
 
 	debug_print(" [  OK %s ] Certificate with label %s loaded successfully",
 		o->id_str, o->label);
@@ -280,6 +321,8 @@
 		? *((CK_BBOOL *) template[5].pValue) : CK_FALSE;
 	o->derive_priv = (template[6].ulValueLen != (CK_ULONG) -1)
 		? *((CK_BBOOL *) template[6].pValue) : CK_FALSE;
+	o->extractable = (template[8].ulValueLen != (CK_ULONG) -1)
+		? *((CK_BBOOL *) template[8].pValue) : CK_FALSE;
 
 	debug_print(" [  OK %s ] Private key loaded successfully S:%d D:%d T:%02lX",
 		o->id_str, o->sign, o->decrypt, o->key_type);
@@ -294,6 +337,11 @@
 {
 	test_cert_t *o = NULL;
 	char *key_id;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	EVP_PKEY_CTX *ctx = NULL;
+	OSSL_PARAM *params = NULL;
+	OSSL_PARAM_BLD *bld = NULL;
+#endif
 
 	/* Search for already stored certificate with same ID */
 	if ((o = search_certificate(objects, &(template[3]))) == NULL) {
@@ -328,30 +376,74 @@
 		BIGNUM *n = NULL, *e = NULL;
 		n = BN_bin2bn(template[4].pValue, template[4].ulValueLen, NULL);
 		e = BN_bin2bn(template[5].pValue, template[5].ulValueLen, NULL);
-		if (o->key.rsa != NULL) {
+		if (o->key != NULL) {
+			int rv;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 			const BIGNUM *cert_n = NULL, *cert_e = NULL;
-			RSA_get0_key(o->key.rsa, &cert_n, &cert_e, NULL);
-			if (BN_cmp(cert_n, n) != 0 ||
-				BN_cmp(cert_e, e) != 0) {
-				debug_print(" [WARN %s ] Got different public key then from the certificate",
-					o->id_str);
+			RSA *rsa = EVP_PKEY_get0_RSA(o->key);
+			RSA_get0_key(rsa, &cert_n, &cert_e, NULL);
+#else
+			BIGNUM *cert_n = NULL, *cert_e = NULL;
+			if ((EVP_PKEY_get_bn_param(o->key, OSSL_PKEY_PARAM_RSA_N, &cert_n) != 1) ||
+			    (EVP_PKEY_get_bn_param(o->key, OSSL_PKEY_PARAM_RSA_E, &cert_e) != 1)) {
+				fprintf(stderr, "Failed to extract RSA key parameters");
+				BN_free(cert_n);
 				BN_free(n);
 				BN_free(e);
-				return -1;
+				return -1; 
+			}
+#endif
+			rv = BN_cmp(cert_n, n) == 0 && BN_cmp(cert_e, e) == 0;
+			if (rv == 1) {
+				o->verify_public = 1;
+			} else {
+				debug_print(" [WARN %s ] Got different public key then from the certificate",
+					o->id_str);
 			}
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+			BN_free(cert_n);
+			BN_free(cert_e);
+#endif
 			BN_free(n);
 			BN_free(e);
-			o->verify_public = 1;
 		} else { /* store the public key for future use */
-			o->type = EVP_PK_RSA;
-			o->key.rsa = RSA_new();
-			if (RSA_set0_key(o->key.rsa, n, e, NULL) != 1) {
+			o->type = EVP_PKEY_RSA;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+			o->key = EVP_PKEY_new();
+			RSA *rsa = RSA_new();
+			if (RSA_set0_key(rsa, n, e, NULL) != 1 ||
+			    EVP_PKEY_set1_RSA(o->key, rsa) != 1) {
 				fail_msg("Unable to set key params");
 				return -1;
 			}
-			o->bits = RSA_bits(o->key.rsa);
-			n = NULL;
-			e = NULL;
+#else
+			if (!(ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)) ||
+				!(bld = OSSL_PARAM_BLD_new()) ||
+				OSSL_PARAM_BLD_push_BN(bld, "n", n) != 1 ||
+				OSSL_PARAM_BLD_push_BN(bld, "e", e) != 1 ||
+				!(params = OSSL_PARAM_BLD_to_param(bld))) {
+				EVP_PKEY_CTX_free(ctx);
+				BN_free(n);
+				BN_free(e);
+				OSSL_PARAM_BLD_free(bld);
+				fail_msg("Unable to set key params");
+				return -1;
+			}
+			OSSL_PARAM_BLD_free(bld);
+			if (EVP_PKEY_fromdata_init(ctx) != 1 ||
+				EVP_PKEY_fromdata(ctx, &o->key, EVP_PKEY_PUBLIC_KEY, params) != 1) {
+				EVP_PKEY_CTX_free(ctx);
+				BN_free(n);
+				BN_free(e);
+				OSSL_PARAM_free(params);
+			 	fail_msg("Unable to store key");
+				return -1;
+			}
+			OSSL_PARAM_free(params);
+			BN_free(n);
+			BN_free(e);
+#endif
+			o->bits = EVP_PKEY_bits(o->key);
 		}
 	} else if (o->key_type == CKK_EC) {
 		ASN1_OBJECT *oid = NULL;
@@ -398,8 +490,9 @@
 			return -1;
 		}
 
-		ecpoint = EC_POINT_bn2point(ecgroup, bn, NULL, NULL);
+		ecpoint = EC_POINT_hex2point(ecgroup, BN_bn2hex(bn), NULL, NULL);
 		BN_free(bn);
+		
 		if (ecpoint == NULL) {
 			debug_print(" [WARN %s ] Can not convert EC_POINT from"
 				" BIGNUM to OpenSSL format", o->id_str);
@@ -407,11 +500,39 @@
 			return -1;
 		}
 
-		if (o->key.ec != NULL) {
-			const EC_GROUP *cert_group = EC_KEY_get0_group(o->key.ec);
-			const EC_POINT *cert_point = EC_KEY_get0_public_key(o->key.ec);
+		if (o->key != NULL) {
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+			EC_KEY *ec = EVP_PKEY_get0_EC_KEY(o->key);
+			const EC_GROUP *cert_group = EC_KEY_get0_group(ec);
+			const EC_POINT *cert_point = EC_KEY_get0_public_key(ec);
 			int cert_nid = EC_GROUP_get_curve_name(cert_group);
-
+#else
+			EC_GROUP *cert_group = NULL;
+			EC_POINT *cert_point = NULL;
+			char curve_name[80]; size_t curve_name_len = 0;
+			unsigned char pubkey[80]; size_t pubkey_len = 0;
+			int cert_nid = 0;
+			if (EVP_PKEY_get_group_name(o->key, curve_name, sizeof(curve_name), &curve_name_len) != 1 ||
+				(cert_nid = OBJ_txt2nid(curve_name)) == NID_undef ||
+				(cert_group = EC_GROUP_new_by_curve_name(cert_nid)) == NULL) {
+				fprintf(stderr, "Can not get EC_GROUP from EVP_PKEY");
+				EC_GROUP_free(ecgroup);
+				EC_POINT_free(ecpoint);
+				EC_GROUP_free(cert_group);
+				return -1;
+			}
+			cert_point = EC_POINT_new(cert_group);
+			if (!cert_point ||
+				EVP_PKEY_get_octet_string_param(o->key, OSSL_PKEY_PARAM_PUB_KEY, pubkey, sizeof(pubkey), &pubkey_len) != 1 ||
+				EC_POINT_oct2point(cert_group, cert_point, pubkey, pubkey_len, NULL) != 1) {
+				fprintf(stderr, "Can not get EC_POINT from EVP_PKEY");
+				EC_GROUP_free(ecgroup);
+				EC_POINT_free(ecpoint);
+				EC_POINT_free(cert_point);
+				EC_GROUP_free(cert_group);
+				return -1;
+			}
+#endif
 			if (cert_nid != nid ||
 				EC_GROUP_cmp(cert_group, ecgroup, NULL) != 0 ||
 				EC_POINT_cmp(ecgroup, cert_point, ecpoint, NULL) != 0) {
@@ -426,11 +547,51 @@
 			EC_POINT_free(ecpoint);
 			o->verify_public = 1;
 		} else { /* store the public key for future use */
-			o->type = EVP_PK_EC;
-			o->key.ec = EC_KEY_new_by_curve_name(nid);
-			EC_KEY_set_public_key(o->key.ec, ecpoint);
-			EC_KEY_set_group(o->key.ec, ecgroup);
+			o->type = EVP_PKEY_EC;
+			o->key = EVP_PKEY_new();
 			o->bits = EC_GROUP_get_degree(ecgroup);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+			EC_KEY *ec = EC_KEY_new_by_curve_name(nid);
+			EC_KEY_set_public_key(ec, ecpoint);
+			EC_KEY_set_group(ec, ecgroup);
+			EVP_PKEY_set1_EC_KEY(o->key, ec);
+#else
+			ctx = EVP_PKEY_CTX_new_from_name(0, "EC", 0);
+			char curve_name[80]; size_t curve_name_len = 0;
+			unsigned char pubkey[80]; size_t pubkey_len = 0;
+			if (EVP_PKEY_get_group_name(o->key, curve_name, sizeof(curve_name), &curve_name_len)||
+				EVP_PKEY_get_octet_string_param(o->key, OSSL_PKEY_PARAM_PUB_KEY, pubkey, sizeof(pubkey), &pubkey_len) != 1) {
+				debug_print(" [WARN %s ] Can not get params from EVP_PKEY", o->id_str);
+				EC_GROUP_free(ecgroup);
+				EC_POINT_free(ecpoint);
+				return -1;
+			}
+			
+			if (!(bld = OSSL_PARAM_BLD_new()) ||
+				OSSL_PARAM_BLD_push_utf8_string(bld, "group", curve_name, curve_name_len) != 1 ||
+				OSSL_PARAM_BLD_push_octet_string(bld, "pub", pubkey, pubkey_len) != 1 ||
+				!(params = OSSL_PARAM_BLD_to_param(bld))) {
+				debug_print(" [WARN %s ] Can not set params from EVP_PKEY", o->id_str);
+				EC_GROUP_free(ecgroup);
+				EC_POINT_free(ecpoint);
+				OSSL_PARAM_BLD_free(bld);
+				EVP_PKEY_CTX_free(ctx);
+				return -1;
+			}
+			OSSL_PARAM_BLD_free(bld);
+
+			if (ctx == NULL || params == NULL ||
+				EVP_PKEY_fromdata_init(ctx) != 1 ||
+				EVP_PKEY_fromdata(ctx, &o->key, EVP_PKEY_PUBLIC_KEY, params) != 1) {
+				debug_print(" [WARN %s ] Can not set params for EVP_PKEY", o->id_str);
+				EC_GROUP_free(ecgroup);
+				EC_POINT_free(ecpoint);
+				EVP_PKEY_CTX_free(ctx);
+				return -1;
+			}
+			EVP_PKEY_CTX_free(ctx);
+			OSSL_PARAM_free(params);
+#endif
 		}
 	} else if (o->key_type == CKK_EC_EDWARDS
 		|| o->key_type == CKK_EC_MONTGOMERY) {
@@ -444,6 +605,7 @@
 		a = template[6].pValue;
 		if (d2i_ASN1_PRINTABLESTRING(&curve, &a, (long)template[6].ulValueLen) != NULL) {
 			switch (o->key_type) {
+#ifdef EVP_PKEY_ED25519
 			case CKK_EC_EDWARDS:
 				if (strcmp((char *)curve->data, "edwards25519")) {
 					debug_print(" [WARN %s ] Unknown curve name. "
@@ -451,6 +613,8 @@
 				}
 				evp_type = EVP_PKEY_ED25519;
 				break;
+#endif
+#ifdef EVP_PKEY_X25519
 			case CKK_EC_MONTGOMERY:
 				if (strcmp((char *)curve->data, "curve25519")) {
 					debug_print(" [WARN %s ] Unknown curve name. "
@@ -458,16 +622,20 @@
 				}
 				evp_type = EVP_PKEY_X25519;
 				break;
+#endif
 			default:
 				debug_print(" [WARN %s ] Unknown key type %lu", o->id_str, o->key_type);
 				return -1;
 			}
 			ASN1_PRINTABLESTRING_free(curve);
 		} else if (d2i_ASN1_OBJECT(&obj, &a, (long)template[6].ulValueLen) != NULL) {
+#if defined(EVP_PKEY_ED25519) || defined (EVP_PKEY_X25519)
 			int nid = OBJ_obj2nid(obj);
+#endif
 			ASN1_OBJECT_free(obj);
 
 			switch (o->key_type) {
+#ifdef EVP_PKEY_ED25519
 			case CKK_EC_EDWARDS:
 				if (nid != NID_ED25519) {
 					debug_print(" [WARN %s ] Unknown OID. "
@@ -475,6 +643,8 @@
 				}
 				evp_type = EVP_PKEY_ED25519;
 				break;
+#endif
+#ifdef EVP_PKEY_X25519
 			case CKK_EC_MONTGOMERY:
 				if (nid != NID_X25519) {
 					debug_print(" [WARN %s ] Unknown OID. "
@@ -482,6 +652,7 @@
 				}
 				evp_type = EVP_PKEY_X25519;
 				break;
+#endif
 			default:
 				debug_print(" [WARN %s ] Unknown key type %lu", o->id_str, o->key_type);
 				return -1;
@@ -511,13 +682,13 @@
 			ASN1_STRING_free(os);
 			return -1;
 		}
-		if (o->key.pkey != NULL) {
+		if (o->key != NULL) {
 			unsigned char *pub = NULL;
 			size_t publen = 0;
 
 			/* TODO check EVP_PKEY type */
 
-			if (EVP_PKEY_get_raw_public_key(o->key.pkey, NULL, &publen) != 1) {
+			if (EVP_PKEY_get_raw_public_key(o->key, NULL, &publen) != 1) {
 				debug_print(" [WARN %s ] Can not get size of the key", o->id_str);
 				ASN1_STRING_free(os);
 				return -1;
@@ -529,7 +700,7 @@
 				return -1;
 			}
 
-			if (EVP_PKEY_get_raw_public_key(o->key.pkey, pub, &publen) != 1 ||
+			if (EVP_PKEY_get_raw_public_key(o->key, pub, &publen) != 1 ||
 				publen != (size_t)os->length ||
 				memcmp(pub, os->data, publen) != 0) {
 				debug_print(" [WARN %s ] Got different public"
@@ -544,7 +715,7 @@
 			o->verify_public = 1;
 		} else { /* store the public key for future use */
 			o->type = evp_type;
-			o->key.pkey = key;
+			o->key = key;
 			o->bits = 255;
 		}
 		ASN1_STRING_free(os);
@@ -561,6 +732,59 @@
 	return 0;
 }
 
+/**
+ * Store any secret keys
+ */
+int callback_secret_keys(test_certs_t *objects,
+	CK_ATTRIBUTE template[], unsigned int template_size, CK_OBJECT_HANDLE object_handle)
+{
+	test_cert_t *o = NULL;
+
+	if ((o = add_object(objects, template[1], template[13])) == NULL)
+		return -1;
+
+	/* TODO generic secret
+	 * there is also no respective EVP_* for AES keys in OpenSSL ...
+	o->type = ??; */
+
+	/* Store attributes, flags and handles */
+	o->private_handle = object_handle;
+	/* For verification/encryption, we use the same key */
+	o->public_handle = object_handle;
+	o->key_type = (template[0].ulValueLen != (CK_ULONG) -1)
+		? *((CK_KEY_TYPE *) template[0].pValue) : (CK_KEY_TYPE) -1;
+	o->sign = (template[3].ulValueLen != (CK_ULONG) -1)
+		? *((CK_BBOOL *) template[3].pValue) : CK_FALSE;
+	o->sign = (template[4].ulValueLen != (CK_ULONG) -1)
+		? *((CK_BBOOL *) template[4].pValue) : CK_FALSE;
+	o->encrypt = (template[5].ulValueLen != (CK_ULONG) -1)
+		? *((CK_BBOOL *) template[5].pValue) : CK_FALSE;
+	o->decrypt = (template[6].ulValueLen != (CK_ULONG) -1)
+		? *((CK_BBOOL *) template[6].pValue) : CK_FALSE;
+	o->derive_priv = (template[7].ulValueLen != (CK_ULONG) -1)
+		? *((CK_BBOOL *) template[7].pValue) : CK_FALSE;
+	o->wrap = (template[8].ulValueLen != (CK_ULONG) -1)
+		? *((CK_BBOOL *) template[8].pValue) : CK_FALSE;
+	o->unwrap = (template[9].ulValueLen != (CK_ULONG) -1)
+		? *((CK_BBOOL *) template[9].pValue) : CK_FALSE;
+	o->extractable = (template[12].ulValueLen != (CK_ULONG) -1)
+		? *((CK_BBOOL *) template[12].pValue) : CK_FALSE;
+
+	if (template[10].ulValueLen > 0) {
+		/* pass the pointer to our structure */
+		o->value = template[10].pValue;
+		template[10].pValue = NULL;
+	}
+
+	o->bits = template[11].ulValueLen > 0 ? *((CK_ULONG *) template[11].pValue)*8 : 0;
+
+	add_supported_mechs(o);
+
+	debug_print(" [  OK %s ] Secret key loaded successfully T:%02lX", o->id_str, o->key_type);
+	return 0;
+}
+
+
 int search_objects(test_certs_t *objects, token_info_t *info,
 	CK_ATTRIBUTE filter[], CK_LONG filter_size, CK_ATTRIBUTE template[], CK_LONG template_size,
 	int (*callback)(test_certs_t *, CK_ATTRIBUTE[], unsigned int, CK_OBJECT_HANDLE))
@@ -622,7 +846,8 @@
 
 			rv = fp->C_GetAttributeValue(info->session_handle, object_handles[i],
 				&(template[j]), 1);
-			if (rv == CKR_ATTRIBUTE_TYPE_INVALID) {
+			if (rv == CKR_ATTRIBUTE_TYPE_INVALID ||
+			    rv == CKR_ATTRIBUTE_SENSITIVE) {
 				continue;
 			} else if (rv != CKR_OK) {
 				fail_msg("C_GetAttributeValue: rv = 0x%.8lX\n", rv);
@@ -664,6 +889,7 @@
 	CK_OBJECT_CLASS keyClass = CKO_CERTIFICATE;
 	CK_OBJECT_CLASS privateClass = CKO_PRIVATE_KEY;
 	CK_OBJECT_CLASS publicClass = CKO_PUBLIC_KEY;
+	CK_OBJECT_CLASS secretClass = CKO_SECRET_KEY;
 	CK_ATTRIBUTE filter[] = {
 			{CKA_CLASS, &keyClass, sizeof(keyClass)},
 	};
@@ -684,6 +910,7 @@
 			{ CKA_UNWRAP, NULL, 0}, // CK_BBOOL
 			{ CKA_DERIVE, NULL, 0}, // CK_BBOOL
 			{ CKA_LABEL, NULL_PTR, 0},
+			{ CKA_EXTRACTABLE, NULL, 0}, // CK_BBOOL
 	};
 	CK_ULONG private_attrs_size = sizeof (private_attrs) / sizeof (CK_ATTRIBUTE);
 	CK_ATTRIBUTE public_attrs[] = {
@@ -699,6 +926,23 @@
 			{ CKA_DERIVE, NULL, 0}, // CK_BBOOL
 	};
 	CK_ULONG public_attrs_size = sizeof (public_attrs) / sizeof (CK_ATTRIBUTE);
+	CK_ATTRIBUTE secret_attrs[] = {
+			{ CKA_KEY_TYPE, NULL, 0},
+			{ CKA_ID, NULL, 0},
+			{ CKA_TOKEN, NULL, 0}, // CK_BBOOL
+			{ CKA_SIGN, NULL, 0}, // CK_BBOOL
+			{ CKA_VERIFY, NULL, 0}, // CK_BBOOL
+			{ CKA_ENCRYPT, NULL, 0}, // CK_BBOOL
+			{ CKA_DECRYPT, NULL, 0}, // CK_BBOOL
+			{ CKA_DERIVE, NULL, 0}, // CK_BBOOL
+			{ CKA_WRAP, NULL, 0}, // CK_BBOOL
+			{ CKA_UNWRAP, NULL, 0}, // CK_BBOOL
+			{ CKA_VALUE, NULL, 0},
+			{ CKA_VALUE_LEN, NULL, 0},
+			{ CKA_EXTRACTABLE, NULL, 0}, // CK_BBOOL
+			{ CKA_LABEL, NULL_PTR, 0},
+	};
+	CK_ULONG secret_attrs_size = sizeof (secret_attrs) / sizeof (CK_ATTRIBUTE);
 
 	debug_print("\nSearch for all certificates on the card");
 	search_objects(objects, info, filter, filter_size,
@@ -716,6 +960,11 @@
 	filter[0].pValue = &publicClass;
 	search_objects(objects, info, filter, filter_size,
 		public_attrs, public_attrs_size, callback_public_keys);
+
+	debug_print("\nSearch for all secret keys");
+	filter[0].pValue = &secretClass;
+	search_objects(objects, info, filter, filter_size, secret_attrs, secret_attrs_size,
+	               callback_secret_keys);
 }
 
 void clean_all_objects(test_certs_t *objects) {
@@ -724,17 +973,9 @@
 		free(objects->data[i].key_id);
 		free(objects->data[i].id_str);
 		free(objects->data[i].label);
+		free(objects->data[i].value);
 		X509_free(objects->data[i].x509);
-		if (objects->data[i].key_type == CKK_RSA &&
-		    objects->data[i].key.rsa != NULL) {
-			RSA_free(objects->data[i].key.rsa);
-		} else if (objects->data[i].key_type == CKK_EC &&
-			objects->data[i].key.ec != NULL) {
-			EC_KEY_free(objects->data[i].key.ec);
-		} else if (objects->data[i].key_type == CKK_EC_EDWARDS &&
-			objects->data[i].key.pkey != NULL) {
-			EVP_PKEY_free(objects->data[i].key.pkey);
-		}
+		EVP_PKEY_free(objects->data[i].key);
 	}
 	free(objects->data);
 }
@@ -838,6 +1079,62 @@
 			return "SHA3_384";
 		case CKM_SHA3_512:
 			return "SHA3_512";
+		case CKM_AES_ECB:
+			return "AES_ECB";
+		case CKM_AES_ECB_ENCRYPT_DATA:
+			return "AES_ECB_ENCRYPT_DATA";
+		case CKM_AES_KEY_GEN:
+			return "AES_KEY_GEN";
+		case CKM_AES_CBC:
+			return "AES_CBC";
+		case CKM_AES_CBC_ENCRYPT_DATA:
+			return "AES_CBC_ENCRYPT_DATA";
+		case CKM_AES_CBC_PAD:
+			return "AES_CBC_PAD";
+		case CKM_AES_MAC:
+			return "AES_MAC";
+		case CKM_AES_MAC_GENERAL:
+			return "AES_MAC_GENERAL";
+		case CKM_AES_CFB64:
+			return "AES_CFB64";
+		case CKM_AES_CFB8:
+			return "AES_CFB8";
+		case CKM_AES_CFB128:
+			return "AES_CFB128";
+		case CKM_AES_OFB:
+			return "AES_OFB";
+		case CKM_AES_CTR:
+			return "AES_CTR";
+		case CKM_AES_GCM:
+			return "AES_GCM";
+		case CKM_AES_CCM:
+			return "AES_CCM";
+		case CKM_AES_CTS:
+			return "AES_CTS";
+		case CKM_AES_CMAC:
+			return "AES_CMAC";
+		case CKM_AES_CMAC_GENERAL:
+			return "AES_CMAC_GENERAL";
+		case CKM_DES3_CMAC:
+			return "DES3_CMAC";
+		case CKM_DES3_CMAC_GENERAL:
+			return "DES3_CMAC_GENERAL";
+		case CKM_DES3_ECB:
+			return "DES3_ECB";
+		case CKM_DES3_CBC:
+			return "DES3_CBC";
+		case CKM_DES3_CBC_PAD:
+			return "DES3_CBC_PAD";
+		case CKM_DES3_CBC_ENCRYPT_DATA:
+			return "DES3_CBC_ENCRYPT_DATA";
+		case CKM_AES_XCBC_MAC:
+			return "AES_XCBC_MAC";
+		case CKM_AES_XCBC_MAC_96:
+			return "AES_XCBC_MAC_96";
+		case CKM_AES_KEY_WRAP:
+			return "AES_KEY_WRAP";
+		case CKM_AES_KEY_WRAP_PAD:
+			return "AES_KEY_WRAP_PAD";
 		default:
 			sprintf(name_buffer, "0x%.8X", mech_id);
 			return name_buffer;
@@ -868,6 +1165,16 @@
 	switch (mech_id) {
 		case CKF_HW:
 			return "CKF_HW";
+		case CKF_MESSAGE_ENCRYPT:
+			return "CKF_MESSAGE_ENCRYPT";
+		case CKF_MESSAGE_DECRYPT:
+			return "CKF_MESSAGE_DECRYPT";
+		case CKF_MESSAGE_SIGN:
+			return "CKF_MESSAGE_SIGN";
+		case CKF_MESSAGE_VERIFY:
+			return "CKF_MESSAGE_VERIFY";
+		case CKF_MULTI_MESSAGE:
+			return "CKF_MULTI_MESSAGE";
 		case CKF_ENCRYPT:
 			return "CKF_ENCRYPT";
 		case CKF_DECRYPT:
diff -Nru opensc-0.22.0/src/tests/p11test/p11test_case_common.h opensc-0.23.0/src/tests/p11test/p11test_case_common.h
--- opensc-0.22.0/src/tests/p11test/p11test_case_common.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/p11test/p11test_case_common.h	2022-11-29 09:34:43.000000000 +0100
@@ -25,6 +25,11 @@
 #include <openssl/x509.h>
 #include <openssl/rsa.h>
 #include <openssl/err.h>
+#include <openssl/evp.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+# include <openssl/core_names.h>
+# include <openssl/param_build.h>
+#endif
 #include "p11test_common.h"
 
 typedef struct {
@@ -33,11 +38,7 @@
 	char		*id_str;
 	X509		*x509;
 	int		 type;
-	union {
-		RSA		*rsa;
-		EC_KEY	*ec;
-		EVP_PKEY	*pkey;
-	} key;
+	EVP_PKEY	*key;
 	CK_OBJECT_HANDLE private_handle;
 	CK_OBJECT_HANDLE public_handle;
 	CK_BBOOL	sign;
@@ -50,18 +51,23 @@
 	CK_BBOOL	derive_pub;
 	CK_KEY_TYPE	key_type;
 	CK_BBOOL	always_auth;
+	CK_BBOOL	extractable;
 	char		*label;
 	CK_ULONG 	 bits;
+	char 		*value;
 	int			verify_public;
 	test_mech_t	mechs[MAX_MECHS];
 	int			num_mechs;
 } test_cert_t;
 
 typedef struct {
+	unsigned int alloc_count;
 	unsigned int count;
 	test_cert_t *data;
 } test_certs_t;
 
+void test_certs_init(test_certs_t *objects);
+
 void always_authenticate(test_cert_t *o, token_info_t *info);
 
 int search_objects(test_certs_t *objects, token_info_t *info,
diff -Nru opensc-0.22.0/src/tests/p11test/p11test_case_ec_derive.c opensc-0.23.0/src/tests/p11test/p11test_case_ec_derive.c
--- opensc-0.22.0/src/tests/p11test/p11test_case_ec_derive.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/p11test/p11test_case_ec_derive.c	2022-11-29 09:34:43.000000000 +0100
@@ -89,6 +89,7 @@
 
 int test_derive_x25519(test_cert_t *o, token_info_t *info, test_mech_t *mech)
 {
+#ifdef EVP_PKEY_X25519
 	unsigned char *secret = NULL, *pkcs11_secret = NULL;
 	EVP_PKEY_CTX *pctx = NULL;
 	EVP_PKEY *pkey = NULL; /* This is peer key */
@@ -143,7 +144,7 @@
 		return 1;
 	}
 
-	rc = EVP_PKEY_derive_set_peer(pctx, o->key.pkey);
+	rc = EVP_PKEY_derive_set_peer(pctx, o->key);
 	if (rc != 1) {
 		debug_print(" [ KEY %s ] EVP_PKEY_derive_set_peer failed", o->id_str);
 		EVP_PKEY_CTX_free(pctx);
@@ -186,6 +187,7 @@
 	rc = EVP_PKEY_get_raw_public_key(pkey, pub, &pub_len);
 	if (rc != 1) {
 		debug_print(" [ KEY %s ] EVP_PKEY_get_raw_public_key failed", o->id_str);
+		free(pub);
 		EVP_PKEY_free(pkey);
 		free(secret);
 		return 1;
@@ -196,6 +198,7 @@
 	if (secret_len == pkcs11_secret_len && memcmp(secret, pkcs11_secret, secret_len) == 0) {
 		mech->result_flags |= FLAGS_DERIVE;
 		debug_print(" [ OK %s ] Derived secrets match", o->id_str);
+		free(pub);
 		EVP_PKEY_free(pkey);
 		free(secret);
 		free(pkcs11_secret);
@@ -208,30 +211,40 @@
 	free(secret);
 	free(pkcs11_secret);
 	return 1;
+#else
+	return 0;
+#endif
 }
 
 int test_derive(test_cert_t *o, token_info_t *info, test_mech_t *mech)
 {
-	int nid, field_size;
-	EC_KEY *key = NULL;
-	const EC_POINT *publickey = NULL;
-	const EC_GROUP *group = NULL;
 	unsigned char *secret = NULL, *pkcs11_secret = NULL;
 	unsigned char *pub = NULL;
 	size_t pub_len = 0, secret_len = 0, pkcs11_secret_len = 0;
+	int rv = 1;
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	int nid = 0;
+	const EC_GROUP *group = NULL;
+	const EC_POINT *publickey = NULL;
+	EC_KEY *key = NULL;
+#endif
+	EVP_PKEY_CTX *pctx = NULL;
+	EVP_PKEY *evp_pkey = NULL;
 
 	if (o->private_handle == CK_INVALID_HANDLE) {
 		debug_print(" [SKIP %s ] Missing private key", o->id_str);
 		return 1;
 	}
 
-	if (o->type != EVP_PK_EC) {
+	if (o->type != EVP_PKEY_EC) {
 		debug_print(" [ KEY %s ] Skip non-EC key for derive", o->id_str);
 		return 1;
 	}
 
 	debug_print(" [ KEY %s ] Trying EC derive using CKM_%s and %lu-bit key",
 	o->id_str, get_mechanism_name(mech->mech), o->bits);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 	if (o->bits == 256)
 		nid = NID_X9_62_prime256v1;
 	else if (o->bits == 384)
@@ -242,75 +255,119 @@
 		debug_print(" [ KEY %s ] Skip key of unknown size", o->id_str);
 		return 1;
 	}
+#endif
 
 	/* Generate the peer private key */
-	if ((key = EC_KEY_new_by_curve_name(nid)) == NULL ||
-			EC_KEY_generate_key(key) != 1) {
-		debug_print(" [ KEY %s ] Failed to generate peer private key", o->id_str);
-		EC_KEY_free(key);
+	if ((pctx = EVP_PKEY_CTX_new(o->key, NULL)) == NULL) {
+		debug_print(" [ KEY %s ] EVP_PKEY_CTX_new_id failed", o->id_str);
 		return 1;
 	}
 
-	/* Calculate the size of the buffer for the shared secret */
-	field_size = EC_GROUP_get_degree(EC_KEY_get0_group(key));
-	secret_len = (field_size+7)/8;
+	if (EVP_PKEY_keygen_init(pctx) != 1) {
+		debug_print(" [ KEY %s ] EVP_PKEY_keygen_init failed", o->id_str);
+		EVP_PKEY_CTX_free(pctx);
+		return 1;
+	}
+
+	if (EVP_PKEY_keygen(pctx, &evp_pkey) != 1) {
+		debug_print(" [ KEY %s ] EVP_PKEY_keygen failed", o->id_str);
+		EVP_PKEY_CTX_free(pctx);
+		return 1;
+	}
+	EVP_PKEY_CTX_free(pctx);
 
+	/* Start with key derivation in OpenSSL*/
+	pctx = EVP_PKEY_CTX_new(evp_pkey, NULL);
+	if (pctx == NULL ||
+		EVP_PKEY_derive_init(pctx) != 1 ||
+		EVP_PKEY_derive_set_peer(pctx, o->key) != 1) {
+		debug_print(" [ KEY %s ] Can not derive key", o->id_str);
+		EVP_PKEY_free(evp_pkey);
+		return 1;
+	}
+	
+	/* Get buffer length */
+	if (EVP_PKEY_derive(pctx, NULL, &secret_len) != 1) {
+		debug_print(" [ KEY %s ] EVP_PKEY_derive failed", o->id_str);
+		EVP_PKEY_CTX_free(pctx);
+		EVP_PKEY_free(evp_pkey);
+		return 1;
+	}
 	/* Allocate the memory for the shared secret */
-	if ((secret = OPENSSL_malloc(secret_len)) == NULL) {
+	if ((secret = malloc(secret_len)) == NULL) {
 		debug_print(" [ KEY %s ] Failed to allocate memory for secret", o->id_str);
-		EC_KEY_free(key);
+		EVP_PKEY_CTX_free(pctx);
+		EVP_PKEY_free(evp_pkey);
 		return 1;
 	}
-
-	/* Derive the shared secret locally */
-	secret_len = ECDH_compute_key(secret, secret_len,
-		EC_KEY_get0_public_key(o->key.ec), key, NULL);
-
+	
+	if (EVP_PKEY_derive(pctx, secret, &secret_len) != 1) {
+		debug_print(" [ KEY %s ] EVP_PKEY_derive failed", o->id_str);
+		EVP_PKEY_CTX_free(pctx);
+		EVP_PKEY_free(evp_pkey);
+		free(secret);
+		return 1;
+	}
+	EVP_PKEY_CTX_free(pctx);
+	
 	/* Try to do the same with the card key */
 
-	/* Convert the public key to the octet string */
-	group = EC_KEY_get0_group(key);
+	/* Get length of pub */
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	group = EC_GROUP_new_by_curve_name(nid);
+	key = EVP_PKEY_get0_EC_KEY(evp_pkey);
 	publickey = EC_KEY_get0_public_key(key);
+
 	pub_len = EC_POINT_point2oct(group, publickey,
 		POINT_CONVERSION_UNCOMPRESSED, NULL, 0, NULL);
+#else
+	EVP_PKEY_get_octet_string_param(evp_pkey, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0, &pub_len);
+#endif
+	/* Allocate memory for public key*/
 	if (pub_len == 0) {
 		debug_print(" [ KEY %s ] Failed to allocate memory for secret", o->id_str);
-		EC_KEY_free(key);
-		OPENSSL_free(secret);
+		free(secret);
+		EVP_PKEY_free(evp_pkey);
 		return 1;
 	}
+
 	pub = malloc(pub_len);
 	if (pub == NULL) {
 		debug_print(" [ OK %s ] Failed to allocate memory", o->id_str);
-		EC_KEY_free(key);
-		OPENSSL_free(secret);
+		free(secret);
+		EVP_PKEY_free(evp_pkey);
 		return 1;
 	}
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 	pub_len = EC_POINT_point2oct(group, publickey,
 		POINT_CONVERSION_UNCOMPRESSED, pub, pub_len, NULL);
+
 	if (pub_len == 0) {
-		debug_print(" [ KEY %s ] Failed to allocate memory for secret", o->id_str);
-		EC_KEY_free(key);
-		OPENSSL_free(secret);
+#else
+	if (EVP_PKEY_get_octet_string_param(evp_pkey, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, pub, pub_len, NULL) != 1) {
+#endif
+		debug_print(" [ KEY %s ] Can not get public key", o->id_str);
+		EVP_PKEY_free(evp_pkey);
+		free(secret);
 		free(pub);
 		return 1;
 	}
+	EVP_PKEY_free(evp_pkey);
 
 	pkcs11_secret_len = pkcs11_derive(o, info, pub, pub_len, mech, &pkcs11_secret);
-	free(pub);
 
 	if (secret_len == pkcs11_secret_len && memcmp(secret, pkcs11_secret, secret_len) == 0) {
 		mech->result_flags |= FLAGS_DERIVE;
 		debug_print(" [ OK %s ] Derived secrets match", o->id_str);
-		OPENSSL_free(secret);
-		free(pkcs11_secret);
-		return 0;
+		rv = 0;
+	} else {
+		debug_print(" [ KEY %s ] Derived secret does not match", o->id_str);
 	}
 
-	debug_print(" [ KEY %s ] Derived secret does not match", o->id_str);
-	OPENSSL_free(secret);
+	free(pub);
+	free(secret);
 	free(pkcs11_secret);
-	return 1;
+	return rv;
 }
 
 
@@ -319,10 +376,9 @@
 	int j;
 	int errors = 0;
 	token_info_t *info = (token_info_t *) *state;
-
 	test_certs_t objects;
-	objects.count = 0;
-	objects.data = NULL;
+
+	test_certs_init(&objects);
 
 	P11TEST_START(info);
 	search_for_all_objects(&objects, info);
@@ -335,8 +391,8 @@
 			continue;
 
 		for (j = 0; j < o->num_mechs; j++) {
-			if ((o->mechs[j].usage_flags & CKF_DERIVE) == 0
-				|| ! o->derive_priv)
+			if ((o->mechs[j].usage_flags & CKF_DERIVE) == 0 ||
+				! o->derive_priv)
 				continue;
 
 			switch (o->key_type) {
@@ -357,7 +413,7 @@
 
 	/* print summary */
 	printf("[KEY ID] [LABEL]\n");
-	printf("[ TYPE ] [ SIZE ]  [ PUBLIC ] [  DERIVE  ]\n");
+	printf("[ TYPE ] [ SIZE ] [ PUBLIC ] [  DERIVE  ]\n");
 	P11TEST_DATA_ROW(info, 3,
 		's', "KEY ID",
 		's', "MECHANISM",
@@ -371,7 +427,7 @@
 		printf("\n[%-6s] [%s]\n",
 			o->id_str,
 			o->label);
-		printf("[ %s ] [%6lu] [  %s  ]  [ %s%s ]\n",
+		printf("[ %s ] [%6lu] [  %s  ] [ %s%s ]\n",
 			(o->key_type == CKK_EC ? " EC " :
 				o->key_type == CKK_EC_MONTGOMERY ? "EC_M" : " ?? "),
 			o->bits,
@@ -391,19 +447,19 @@
 				/* not applicable mechanisms are skipped */
 				continue;
 			}
-			printf("  [ %-23s ] [   %s   ]\n",
+			printf("  [ %-22s ] [   %s   ]\n",
 				get_mechanism_name(mech->mech),
 				mech->result_flags & FLAGS_DERIVE ? "[./]" : "    ");
 			if ((mech->result_flags & FLAGS_DERIVE) == 0)
 				continue; /* skip empty rows for export */
-			P11TEST_DATA_ROW(info, 4,
+			P11TEST_DATA_ROW(info, 3,
 				's', o->id_str,
 				's', get_mechanism_name(mech->mech),
 				's', mech->result_flags & FLAGS_DERIVE ? "YES" : "");
 		}
 	}
-	printf(" Public == Cert -----^          ^\n");
-	printf(" ECDH Derive functionality -----'\n");
+	printf(" Public == Cert -----^            ^\n");
+	printf(" ECDH Derive functionality -------'\n");
 
 	clean_all_objects(&objects);
 	if (errors > 0)
diff -Nru opensc-0.22.0/src/tests/p11test/p11test_case_ec_sign.c opensc-0.23.0/src/tests/p11test/p11test_case_ec_sign.c
--- opensc-0.22.0/src/tests/p11test/p11test_case_ec_sign.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/p11test/p11test_case_ec_sign.c	2022-11-29 09:34:43.000000000 +0100
@@ -22,31 +22,45 @@
 
 void ec_sign_size_test(void **state) {
 	unsigned int i;
-	int min, max, j, l, errors = 0, rv;
+	int min, max, inc, j, l, errors = 0, rv;
 	token_info_t *info = (token_info_t *) *state;
+	test_certs_t objects;
+
+	test_certs_init(&objects);
 
 	P11TEST_START(info);
-	if (token.num_ec_mechs == 0 ) {
-		fprintf(stderr, "Token does not support any ECC mechanisms. Skipping.\n");
+	if (token.num_ec_mechs == 0 && token.num_ed_mechs == 0) {
+		fprintf(stderr, "Token does not support any ECC signature mechanisms. Skipping.\n");
 		P11TEST_SKIP(info);
 	}
 
-	test_certs_t objects;
-	objects.count = 0;
-	objects.data = NULL;
-
 	search_for_all_objects(&objects, info);
 
 	debug_print("\nCheck functionality of Sign&Verify on different data lengths");
 	for (i = 0; i < objects.count; i++) {
-		if (objects.data[i].key_type != CKK_EC)
+		switch (objects.data[i].key_type) {
+		case CKK_EC:
+			/* This tests just couple of sizes around the curve length
+			 * to verify they are properly truncated on input */
+			min = (objects.data[i].bits + 7) / 8 - 2;
+			max = (objects.data[i].bits + 7) / 8 + 2;
+			inc = 1;
+			break;
+		case CKK_EC_EDWARDS:
+			/* Tests larger inputs for EdDSA. Previously, we had hardcoded limit of 512
+			 * https://github.com/OpenSC/OpenSC/issues/2300 */
+			min = 128;
+			max = 1024;
+			inc = 128;
+			break;
+		default:
 			continue;
+		}
+
 		// sanity: Test all mechanisms
-		min = (objects.data[i].bits + 7) / 8 - 2;
-		max = (objects.data[i].bits + 7) / 8 + 2;
 		if (objects.data[i].sign && objects.data[i].verify) {
 			for (j = 0; j < objects.data[i].num_mechs; j++) {
-				for (l = min; l < max; l++) {
+				for (l = min; l < max; l += inc) {
 					rv = sign_verify_test(&(objects.data[i]), info,
 						&(objects.data[i].mechs[j]), l, 0);
 					if (rv == -1)
@@ -61,4 +75,3 @@
 		P11TEST_FAIL(info, "Some signatures were not verified successfully. Please review the log");
 	P11TEST_PASS(info);
 }
-
diff -Nru opensc-0.22.0/src/tests/p11test/p11test_case_mechs.c opensc-0.23.0/src/tests/p11test/p11test_case_mechs.c
--- opensc-0.22.0/src/tests/p11test/p11test_case_mechs.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/p11test/p11test_case_mechs.c	2022-11-29 09:34:43.000000000 +0100
@@ -123,6 +123,36 @@
 					P11TEST_FAIL(info, "Too many montgomery EC mechanisms (%d)", MAX_MECHS);
 			}
 
+			/* We list all known secret key mechanisms */
+			if (mechanism_list[i] == CKM_AES_ECB ||
+			    mechanism_list[i] == CKM_AES_ECB_ENCRYPT_DATA ||
+			    mechanism_list[i] == CKM_AES_CBC ||
+			    mechanism_list[i] == CKM_AES_CBC_ENCRYPT_DATA ||
+			    mechanism_list[i] == CKM_AES_CBC_PAD ||
+			    mechanism_list[i] == CKM_AES_MAC ||
+			    mechanism_list[i] == CKM_AES_MAC_GENERAL ||
+			    mechanism_list[i] == CKM_AES_CFB64 ||
+			    mechanism_list[i] == CKM_AES_CFB8 ||
+			    mechanism_list[i] == CKM_AES_CFB128 ||
+			    mechanism_list[i] == CKM_AES_OFB ||
+			    mechanism_list[i] == CKM_AES_CTR ||
+			    mechanism_list[i] == CKM_AES_GCM ||
+			    mechanism_list[i] == CKM_AES_CCM ||
+			    mechanism_list[i] == CKM_AES_CTS ||
+			    mechanism_list[i] == CKM_AES_KEY_WRAP ||
+			    mechanism_list[i] == CKM_AES_KEY_WRAP_PAD ||
+			    mechanism_list[i] == CKM_AES_CMAC ||
+			    mechanism_list[i] == CKM_AES_CMAC_GENERAL ||
+			    mechanism_list[i] == CKM_AES_XCBC_MAC ||
+			    mechanism_list[i] == CKM_AES_XCBC_MAC_96) {
+				if (token.num_aes_mechs < MAX_MECHS) {
+					mech = &token.aes_mechs[token.num_aes_mechs++];
+					mech->mech = mechanism_list[i];
+					mech->usage_flags = mechanism_info[i].flags;
+				} else
+					P11TEST_FAIL(info, "Too many AES mechanisms (%d)", MAX_MECHS);
+			}
+
 			if ((mechanism_info[i].flags & CKF_GENERATE_KEY_PAIR) != 0) {
 				if (token.num_keygen_mechs < MAX_MECHS) {
 					mech = &token.keygen_mechs[token.num_keygen_mechs++];
diff -Nru opensc-0.22.0/src/tests/p11test/p11test_case_multipart.c opensc-0.23.0/src/tests/p11test/p11test_case_multipart.c
--- opensc-0.22.0/src/tests/p11test/p11test_case_multipart.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/p11test/p11test_case_multipart.c	2022-11-29 09:34:43.000000000 +0100
@@ -28,8 +28,7 @@
 	int used, j;
 	test_certs_t objects;
 
-	objects.count = 0;
-	objects.data = NULL;
+	test_certs_init(&objects);
 
 	P11TEST_START(info);
 	search_for_all_objects(&objects, info);
@@ -41,7 +40,7 @@
 			objects.data[i].id_str);
 			continue;
 		}
-		if (objects.data[i].type == EVP_PK_EC) {
+		if (objects.data[i].type == EVP_PKEY_EC) {
 			debug_print(" [ SKIP %s ] EC keys do not support multi-part operations",
 			objects.data[i].id_str);
 			continue;
@@ -73,24 +72,24 @@
 		's', "MECHANISM",
 		's', "MULTIPART SIGN&VERIFY WORKS");
 	for (i = 0; i < objects.count; i++) {
-		if (objects.data[i].type == EVP_PK_EC)
+		test_cert_t *o = &objects.data[i];
+
+		if (o->key_type != CKK_RSA)
 			continue;
+
 		printf("[%-6s] [%s] [%6lu] [ %s ] [%s%s] [%s]\n",
-			objects.data[i].id_str,
-			(objects.data[i].key_type == CKK_RSA ? "RSA " :
-				objects.data[i].key_type == CKK_EC ? " EC " :
-				objects.data[i].key_type == CKK_EC_EDWARDS ? "EC_E" :
-				objects.data[i].key_type == CKK_EC_MONTGOMERY ? "EC_M" : " ?? "),
-			objects.data[i].bits,
-			objects.data[i].verify_public == 1 ? " ./ " : "    ",
-			objects.data[i].sign ? "[./] " : "[  ] ",
-			objects.data[i].verify ? " [./] " : " [  ] ",
-			objects.data[i].label);
-		if (objects.data[i].private_handle == CK_INVALID_HANDLE) {
+			o->id_str,
+			"RSA ",
+			o->bits,
+			o->verify_public == 1 ? " ./ " : "    ",
+			o->sign ? "[./] " : "[  ] ",
+			o->verify ? " [./] " : " [  ] ",
+			o->label);
+		if (o->private_handle == CK_INVALID_HANDLE) {
 			continue;
 		}
-		for (j = 0; j < objects.data[i].num_mechs; j++) {
-			test_mech_t *mech = &objects.data[i].mechs[j];
+		for (j = 0; j < o->num_mechs; j++) {
+			test_mech_t *mech = &o->mechs[j];
 			if ((mech->usage_flags & CKF_SIGN) == 0) {
 				/* not applicable mechanisms are skipped */
 				continue;
@@ -101,7 +100,7 @@
 			if ((mech->result_flags & FLAGS_SIGN_ANY) == 0)
 				continue; /* do not export unknown and non-working algorithms */
 			P11TEST_DATA_ROW(info, 3,
-				's', objects.data[i].id_str,
+				's', o->id_str,
 				's', get_mechanism_name(mech->mech),
 				's', mech->result_flags & FLAGS_SIGN_ANY ? "YES" : "");
 		}
diff -Nru opensc-0.22.0/src/tests/p11test/p11test_case_pss_oaep.c opensc-0.23.0/src/tests/p11test/p11test_case_pss_oaep.c
--- opensc-0.22.0/src/tests/p11test/p11test_case_pss_oaep.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/p11test/p11test_case_pss_oaep.c	2022-11-29 09:34:43.000000000 +0100
@@ -188,24 +188,45 @@
 CK_BYTE *hash_message(const CK_BYTE *message, size_t message_length,
     CK_MECHANISM_TYPE hash)
 {
+	CK_BYTE *out = NULL;
+	const EVP_MD *md = NULL;
+	size_t digest_len = 0;
+
 	switch (hash) {
 	case CKM_SHA224:
-		return SHA224(message, message_length, NULL);
+		digest_len = SHA224_DIGEST_LENGTH;
+		md = EVP_sha224();
+		break;
 
 	case CKM_SHA256:
-		return SHA256(message, message_length, NULL);
+		digest_len = SHA256_DIGEST_LENGTH;
+		md = EVP_sha256();
+		break;
 
 	case CKM_SHA384:
-		return SHA384(message, message_length, NULL);
+		digest_len = SHA384_DIGEST_LENGTH;
+		md = EVP_sha384();
+		break;
 
 	case CKM_SHA512:
-		return SHA512(message, message_length, NULL);
+		digest_len = SHA512_DIGEST_LENGTH;
+		md = EVP_sha512();
+		break;
 
 	case CKM_SHA_1:
 	default:
-		return SHA1(message, message_length, NULL);
+		digest_len = SHA_DIGEST_LENGTH;
+		md = EVP_sha1();
+		break;
+	}
 
+	out = malloc(digest_len);
+	if (!out ||
+		EVP_Digest(message, message_length, out, NULL, md, NULL) != 1) {
+		free(out);
+		return NULL;
 	}
+	return out;
 }
 
 int oaep_encrypt_message_openssl(test_cert_t *o, token_info_t *info, CK_BYTE *message,
@@ -216,20 +237,11 @@
 	EVP_PKEY_CTX *pctx = NULL;
 	const EVP_MD *md = EVP_md_null();
 	const EVP_MD *mgf1_md = EVP_md_null();
-	EVP_PKEY *key = NULL;
 
 	md = md_cryptoki_to_ossl(mech->hash);
 	mgf1_md = mgf_cryptoki_to_ossl(mech->mgf);
 
-	if ((key = EVP_PKEY_new()) == NULL
-		|| RSA_up_ref(o->key.rsa) < 1
-		|| EVP_PKEY_set1_RSA(key, o->key.rsa) != 1) {
-		fprintf(stderr, " [ ERROR %s ] Failed to initialize EVP_PKEY. Error: %s\n",
-			o->id_str, ERR_error_string(ERR_peek_last_error(), NULL));
-		goto out;
-	}
-
-	if ((pctx = EVP_PKEY_CTX_new(key, NULL)) == NULL
+	if ((pctx = EVP_PKEY_CTX_new(o->key, NULL)) == NULL
 		|| EVP_PKEY_encrypt_init(pctx) != 1
 		|| EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_OAEP_PADDING) != 1
 		|| EVP_PKEY_CTX_set_rsa_oaep_md(pctx, md) != 1
@@ -254,7 +266,6 @@
 	}
 out:
 	EVP_PKEY_CTX_free(pctx);
-	EVP_PKEY_free(key);
 	return enc_length;
 }
 
@@ -384,7 +395,7 @@
 		return 0;
 	}
 
-	if (o->type != EVP_PK_RSA) {
+	if (o->type != EVP_PKEY_RSA) {
 		debug_print(" [ KEY %s ] Skip non-RSA key for encryption", o->id_str);
 		return 0;
 	}
@@ -402,7 +413,7 @@
 	if (message_length < 0) {
 		mech->usage_flags &= ~CKF_DECRYPT;
 		debug_print(" [SKIP %s ] Too small modulus (%ld bits)"
-			" or too large hash %s (%lu B) for OAEP", o->id_str,
+			" or too large hash %s (%zu B) for OAEP", o->id_str,
 			o->bits, get_mechanism_name(mech->hash),
 			get_hash_length(mech->hash));
 		return 0;
@@ -536,31 +547,23 @@
 	CK_RV rv = -1;
 	EVP_PKEY_CTX *pctx = NULL;
 	const CK_BYTE *my_message;
+	CK_BYTE *free_message = NULL;
 	CK_ULONG my_message_length;
 	const EVP_MD *mgf_md = EVP_md_null();
 	const EVP_MD *md = EVP_md_null();
-	EVP_PKEY *key = NULL;
 
 	md = md_cryptoki_to_ossl(mech->hash);
 	mgf_md = mgf_cryptoki_to_ossl(mech->mgf);
 
 	if (mech->mech != CKM_RSA_PKCS_PSS) {
-		my_message = hash_message(message, message_length, mech->hash);
+		my_message = free_message = hash_message(message, message_length, mech->hash);
 		my_message_length = get_hash_length(mech->hash);
 	} else {
 		my_message = message;
 		my_message_length = message_length;
 	}
 
-	if ((key = EVP_PKEY_new()) == NULL
-		|| RSA_up_ref(o->key.rsa) < 1
-		|| EVP_PKEY_set1_RSA(key, o->key.rsa) != 1) {
-		fprintf(stderr, " [ ERROR %s ] Failed to initialize EVP_PKEY. Error: %s\n",
-			o->id_str, ERR_error_string(ERR_peek_last_error(), NULL));
-		goto out;
-	}
-
-	if ((pctx = EVP_PKEY_CTX_new(key, NULL)) == NULL
+	if ((pctx = EVP_PKEY_CTX_new(o->key, NULL)) == NULL
 		|| EVP_PKEY_verify_init(pctx) != 1
 		|| EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) != 1
 		|| EVP_PKEY_CTX_set_signature_md(pctx, md) != 1
@@ -580,9 +583,9 @@
 			o->id_str, ERR_error_string(ERR_peek_last_error(), NULL));
 		goto out;
 	}
+	free(free_message);
 out:
 	EVP_PKEY_CTX_free(pctx);
-	EVP_PKEY_free(key);
 	return rv;
 }
 
@@ -651,7 +654,7 @@
 		return 0;
 	}
 
-	if (o->type != EVP_PK_RSA) {
+	if (o->type != EVP_PKEY_RSA) {
 		debug_print(" [SKIP %s ] Skip non-RSA key", o->id_str);
 		return 0;
 	}
@@ -677,13 +680,17 @@
 		get_mgf_name(mech->mgf), mech->salt);
 	rv = pss_sign_message(o, info, message, message_length, mech, &sign);
 	if (rv <= 0) {
-		return rv;
+		goto out;
 	}
 	sign_length = (unsigned long) rv;
 
 	debug_print(" [ KEY %s ] Verify message signature", o->id_str);
 	rv = pss_verify_message(o, info, message, message_length, mech,
 		sign, sign_length);
+out:
+	if (mech->mech == CKM_RSA_PKCS_PSS) {
+		free(message);
+	}
 	free(sign);
 	return rv;
 }
@@ -757,6 +764,8 @@
 	int used, j;
 	test_certs_t objects;
 
+	test_certs_init(&objects);
+
 	P11TEST_START(info);
 
 	if (have_pss_oaep_mechanisms() == 0) {
@@ -764,8 +773,6 @@
 		skip();
 	}
 
-	objects.count = 0;
-	objects.data = NULL;
 	search_for_all_objects(&objects, info);
 
 	debug_print("\nCheck functionality of Sign&Verify and/or Encrypt&Decrypt");
@@ -820,7 +827,7 @@
 			continue;
 
 		/* Do not list non-RSA keys here */
-		if (o->type != EVP_PK_RSA)
+		if (o->type != EVP_PKEY_RSA)
 			continue;
 
 		printf("\n[%-6s] [%s]\n",
diff -Nru opensc-0.22.0/src/tests/p11test/p11test_case_readonly.c opensc-0.23.0/src/tests/p11test/p11test_case_readonly.c
--- opensc-0.22.0/src/tests/p11test/p11test_case_readonly.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/p11test/p11test_case_readonly.c	2022-11-29 09:34:43.000000000 +0100
@@ -24,29 +24,73 @@
 #include <openssl/sha.h>
 #include <openssl/md5.h>
 #include <openssl/ripemd.h>
-
-#define SHORT_MESSAGE_TO_SIGN "Simple message for signing & verifying. It needs to be little bit longer to fit also longer keys and allow the truncation.\n"
-#define SHORT_MESSAGE_DIGEST	"\x30\x21\x30\x09\x06\x05\x2b\x0e" \
-				"\x03\x02\x1a\x05\x00\x04\x14\xd9" \
-				"\xdd\xa3\x76\x44\x2f\x50\xe1\xec" \
-				"\xd3\x8b\xcd\x6f\xc6\xce\x4e\xfd" \
-				"\xd3\x1a\x3f"
+#include <openssl/rand.h>
+#include <openssl/evp.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+# include <openssl/provider.h>
+#endif
+
+#define MESSAGE_TO_SIGN "Simple message for signing & verifying. " \
+	"It needs to be little bit longer to fit also longer keys and allow the truncation.\n" \
+	"Simple message for signing & verifying. " \
+	"It needs to be little bit longer to fit also longer keys and allow the truncation.\n" \
+	"Simple message for signing & verifying. " \
+	"It needs to be little bit longer to fit also longer keys and allow the truncation.\n" \
+	"Simple message for signing & verifying. " \
+	"It needs to be little bit longer to fit also longer keys and allow the truncation.\n" \
+	"Simple message for signing & verifying. " \
+	"It needs to be little bit longer to fit also longer keys and allow the truncation.\n" \
+	"Simple message for signing & verifying. " \
+	"It needs to be little bit longer to fit also longer keys and allow the truncation.\n" \
+	"Simple message for signing & verifying. " \
+	"It needs to be little bit longer to fit also longer keys and allow the truncation.\n" \
+	"Simple message for signing & verifying. " \
+	"It needs to be little bit longer to fit also longer keys and allow the truncation.\n" \
+	"Simple message for signing & verifying. " \
+	"It needs to be little bit longer to fit also longer keys and allow the truncation.\n"
+#define MESSAGE_DIGEST	"\x30\x21\x30\x09\x06\x05\x2b\x0e" \
+			"\x03\x02\x1a\x05\x00\x04\x14\xd9" \
+			"\xdd\xa3\x76\x44\x2f\x50\xe1\xec" \
+			"\xd3\x8b\xcd\x6f\xc6\xce\x4e\xfd" \
+			"\xd3\x1a\x3f"
 #define BUFFER_SIZE		4096
 
-const unsigned char *const_message = (unsigned char *) SHORT_MESSAGE_TO_SIGN;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+OSSL_PROVIDER *legacy_provider = NULL;
+#endif
+
+const unsigned char *const_message = (unsigned char *) MESSAGE_TO_SIGN;
 
 static unsigned char *
 rsa_x_509_pad_message(const unsigned char *message,
 	unsigned long *message_length, test_cert_t *o, int encrypt)
 {
 	int pad_message_length = (o->bits+7)/8;
-	unsigned char *pad_message = malloc(pad_message_length);
-	if (!encrypt)
-		RSA_padding_add_PKCS1_type_1(pad_message, pad_message_length,
-		    message, *message_length);
-	else
-		RSA_padding_add_PKCS1_type_2(pad_message, pad_message_length,
-		    message, *message_length);
+	unsigned char *pad_message = NULL;
+	size_t padding_len = pad_message_length - (*message_length) - 3;
+
+	if (pad_message_length - (*message_length) <= 11) {
+		debug_print("Can not pad message - buffer to small");
+		return NULL;
+	}
+	if ((pad_message = malloc(pad_message_length)) == NULL) {
+		fprintf(stderr, "System error: unable to allocate memory\n");
+		return NULL;
+	}
+
+	pad_message[0] = 0x00;
+	pad_message[pad_message_length - 1] = 0x00;
+	if (!encrypt) {
+		pad_message[1] = 0x01;
+		memset(pad_message + 2, 0xff, padding_len);
+	} else {
+		pad_message[1] = 0x02;
+		if (RAND_bytes(pad_message + 2, padding_len) != 1) {
+			debug_print("Can not generate random bytes.");
+		}
+	}
+	memcpy(pad_message + 2 + padding_len, message, (*message_length) * sizeof(unsigned char));
+
 	*message_length = pad_message_length;
 	return pad_message;
 }
@@ -54,9 +98,12 @@
 int encrypt_message_openssl(test_cert_t *o, token_info_t *info, CK_BYTE *message,
     CK_ULONG message_length, test_mech_t *mech, unsigned char **enc_message)
 {
-	int rv, padding;
+	int rv = -1, padding;
+	size_t outlen = 0;
+	EVP_PKEY_CTX *ctx = NULL;
 
-	*enc_message = malloc(RSA_size(o->key.rsa));
+	outlen = EVP_PKEY_size(o->key);
+	*enc_message = malloc(outlen);
 	if (*enc_message == NULL) {
 		debug_print("malloc returned null");
 		return -1;
@@ -64,14 +111,20 @@
 
 	/* Prepare padding for RSA_X_509 */
 	padding = ((mech->mech == CKM_RSA_X_509) ? RSA_NO_PADDING : RSA_PKCS1_PADDING);
-	rv = RSA_public_encrypt(message_length, message,
-		*enc_message, o->key.rsa, padding);
-	if (rv < 0) {
+
+	ctx = EVP_PKEY_CTX_new(o->key, NULL);
+	if (!ctx || (rv = EVP_PKEY_encrypt_init(ctx)) <= 0 ||
+	    (rv = EVP_PKEY_CTX_set_rsa_padding(ctx, padding)) <= 0 ||
+	    (rv = EVP_PKEY_encrypt(ctx, *enc_message, &outlen, message, message_length)) <= 0) {
 		free(*enc_message);
-		debug_print("RSA_public_encrypt: rv = 0x%.8X\n", rv);
+		*enc_message = NULL;
+		EVP_PKEY_CTX_free(ctx);
+		fprintf(stderr, " [ ERROR %s ] OpenSSL encrypt failed: %s\n",
+			o->id_str, ERR_error_string(ERR_peek_last_error(), NULL));
 		return -1;
 	}
-	return rv;
+	EVP_PKEY_CTX_free(ctx);
+	return outlen;
 }
 
 int encrypt_message(test_cert_t *o, token_info_t *info, CK_BYTE *message,
@@ -79,18 +132,17 @@
 {
 	CK_RV rv;
 	CK_FUNCTION_LIST_PTR fp = info->function_pointer;
-	CK_MECHANISM enc_mechanism = { mech->mech, NULL_PTR, 0 };
+	CK_MECHANISM enc_mechanism = { mech->mech, mech->params, mech->params_len };
 	CK_ULONG enc_message_length;
-	static int encrypt_support = 1;
 
-	if (!encrypt_support)
+	if (!info->encrypt_support)
 		goto openssl_encrypt;
 
 	rv = fp->C_EncryptInit(info->session_handle, &enc_mechanism,
 		o->public_handle);
 	if (rv != CKR_OK) {
 		debug_print("   C_EncryptInit: rv = 0x%.8lX", rv);
-		encrypt_support = 0; /* avoid trying over and over again */
+		info->encrypt_support = 0; /* avoid trying over and over again */
 		goto openssl_encrypt;
 	}
 
@@ -111,7 +163,6 @@
 	rv = fp->C_Encrypt(info->session_handle, message, message_length,
 		*enc_message, &enc_message_length);
 	if (rv == CKR_OK) {
-		mech->result_flags |= FLAGS_SIGN;
 		return enc_message_length;
 	}
 	debug_print("   C_Encrypt: rv = 0x%.8lX", rv);
@@ -127,7 +178,7 @@
 {
 	CK_RV rv;
 	CK_FUNCTION_LIST_PTR fp = info->function_pointer;
-	CK_MECHANISM dec_mechanism = { mech->mech, NULL_PTR, 0 };
+	CK_MECHANISM dec_mechanism = { mech->mech, mech->params, mech->params_len };
 	CK_ULONG dec_message_length = BUFFER_SIZE;
 
 	rv = fp->C_DecryptInit(info->session_handle, &dec_mechanism,
@@ -179,8 +230,8 @@
 		return 0;
 	}
 
-	if (o->type != EVP_PK_RSA) {
-		debug_print(" [ KEY %s ] Skip non-RSA key for encryption", o->id_str);
+	if (o->type != EVP_PKEY_RSA) {
+		debug_print(" [SKIP %s ] Skip non-RSA key for encryption", o->id_str);
 		return 0;
 	}
 
@@ -196,11 +247,16 @@
 		return 0;
 	}
 
-	if (mech->mech == CKM_RSA_X_509)
-		message = rsa_x_509_pad_message(const_message,
-			&message_length, o, 1);
-	else
-		message = (CK_BYTE *) strdup(SHORT_MESSAGE_TO_SIGN);
+	if (mech->mech == CKM_RSA_X_509) {
+		if ((message = rsa_x_509_pad_message(const_message,
+			&message_length, o, 1)) == NULL) {
+			debug_print(" [SKIP %s ] Could not pad message", o->id_str);
+			return -1;
+		}
+	} else {
+		message = (CK_BYTE *) strdup(MESSAGE_TO_SIGN);
+	}
+
 
 	debug_print(" [ KEY %s ] Encrypt message using CKM_%s",
 		o->id_str, get_mechanism_name(mech->mech));
@@ -221,8 +277,8 @@
 		return -1;
 	}
 
-	if (memcmp(dec_message, message, dec_message_length) == 0
-			&& (unsigned int) dec_message_length == message_length) {
+	if ((unsigned int) dec_message_length == message_length &&
+	    memcmp(dec_message, message, dec_message_length) == 0) {
 		debug_print(" [  OK %s ] Text decrypted successfully.", o->id_str);
 		mech->result_flags |= FLAGS_DECRYPT;
 		rv = 1;
@@ -243,10 +299,17 @@
 {
 	CK_RV rv;
 	CK_FUNCTION_LIST_PTR fp = info->function_pointer;
-	CK_MECHANISM sign_mechanism = { mech->mech, NULL_PTR, 0 };
+	CK_MECHANISM sign_mechanism = { mech->mech, mech->params, mech->params_len };
 	CK_ULONG sign_length = 0;
 	char *name;
-
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	if (!legacy_provider) {
+		if (!(legacy_provider = OSSL_PROVIDER_try_load(NULL, "legacy", 1))) {
+			debug_print(" [SKIP %s ] Failed to load legacy provider", o->id_str);
+			return 0;
+		}
+	}
+#endif
 	rv = fp->C_SignInit(info->session_handle, &sign_mechanism,
 		o->private_handle);
 	if (rv == CKR_KEY_TYPE_INCONSISTENT) {
@@ -256,8 +319,8 @@
 		debug_print(" [SKIP %s ] Bad mechanism. Not supported?", o->id_str);
 		return 0;
 	} else if (rv != CKR_OK) {
-		debug_print("  C_SignInit: rv = 0x%.8lX\n", rv);
-		return -1;
+		debug_print(" [SKIP %s ] Not allowed to sign with this key?", o->id_str);
+		return 0;
 	}
 
 	always_authenticate(o, info);
@@ -330,96 +393,92 @@
 	CK_BYTE *cmp_message = NULL;
 	int cmp_message_length;
 
-	if (o->type == EVP_PK_RSA) {
-		int type;
+	if (o->type == EVP_PKEY_RSA) {
+		const EVP_MD *md = NULL;
+		EVP_MD_CTX *mdctx = NULL;
+		EVP_PKEY_CTX *ctx = NULL;
+		int padding = RSA_PKCS1_PADDING;
 
-		/* raw RSA mechanism */
-		if (mech->mech == CKM_RSA_PKCS || mech->mech == CKM_RSA_X_509) {
-			CK_BYTE dec_message[BUFFER_SIZE];
-			int padding = ((mech->mech == CKM_RSA_X_509)
-				? RSA_NO_PADDING : RSA_PKCS1_PADDING);
-			int dec_message_length = RSA_public_decrypt(sign_length, sign,
-				dec_message, o->key.rsa, padding);
-			if (dec_message_length < 0) {
-				fprintf(stderr, "RSA_public_decrypt: rv = %d: %s\n", dec_message_length,
-					ERR_error_string(ERR_peek_last_error(), NULL));
-				return -1;
-			}
-			if (memcmp(dec_message, message, dec_message_length) == 0
-					&& dec_message_length == (int) message_length) {
-				debug_print(" [  OK %s ] Signature is valid.", o->id_str);
-				mech->result_flags |= FLAGS_SIGN_OPENSSL;
-				return 1;
-			} else {
+		/* Digest mechanisms */
+		switch (mech->mech) {
+		case CKM_RSA_X_509:
+			padding = RSA_NO_PADDING;
+			/* fall through */
+		case CKM_RSA_PKCS:
+			if ((ctx = EVP_PKEY_CTX_new(o->key, NULL)) == NULL ||
+			    (rv = EVP_PKEY_verify_init(ctx)) <= 0 ||
+			    (rv = EVP_PKEY_CTX_set_rsa_padding(ctx, padding)) <= 0 ||
+			    (rv = EVP_PKEY_verify(ctx, sign, sign_length, message, message_length)) != 1) {
 				fprintf(stderr, " [ ERROR %s ] Signature is not valid. Error: %s\n",
 					o->id_str, ERR_error_string(ERR_peek_last_error(), NULL));
-				return 0;
+				EVP_PKEY_CTX_free(ctx);
+				return -1;
 			}
-		}
-
-		/* Digest mechanisms */
-		switch (mech->mech) {
+			mech->result_flags |= FLAGS_SIGN_OPENSSL;
+			debug_print(" [  OK %s ] Signature is valid.", o->id_str);
+			return 1;
+			break;
 		case CKM_SHA1_RSA_PKCS:
-			cmp_message = SHA1(message, message_length, NULL);
-			cmp_message_length = SHA_DIGEST_LENGTH;
-			type = NID_sha1;
+			md = EVP_sha1();
 			break;
 		case CKM_SHA224_RSA_PKCS:
-			cmp_message = SHA224(message, message_length, NULL);
-			cmp_message_length = SHA224_DIGEST_LENGTH;
-			type = NID_sha224;
+			md = EVP_sha224();
 			break;
 		case CKM_SHA256_RSA_PKCS:
-			cmp_message = SHA256(message, message_length, NULL);
-			cmp_message_length = SHA256_DIGEST_LENGTH;
-			type = NID_sha256;
+			md = EVP_sha256();
 			break;
 		case CKM_SHA384_RSA_PKCS:
-			cmp_message = SHA384(message, message_length, NULL);
-			cmp_message_length = SHA384_DIGEST_LENGTH;
-			type = NID_sha384;
+			md = EVP_sha384();
 			break;
 		case CKM_SHA512_RSA_PKCS:
-			cmp_message = SHA512(message, message_length, NULL);
-			cmp_message_length = SHA512_DIGEST_LENGTH;
-			type = NID_sha512;
+			md = EVP_sha512();
 			break;
 		case CKM_MD5_RSA_PKCS:
-			cmp_message = MD5(message, message_length, NULL);
-			cmp_message_length = MD5_DIGEST_LENGTH;
-			type = NID_md5;
+			md = EVP_md5();
 			break;
 		case CKM_RIPEMD160_RSA_PKCS:
-			cmp_message = RIPEMD160(message, message_length, NULL);
-			cmp_message_length = RIPEMD160_DIGEST_LENGTH;
-			type = NID_ripemd160;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+			if (!legacy_provider) {
+				if (!(legacy_provider = OSSL_PROVIDER_try_load(NULL, "legacy", 1))) {
+					debug_print(" [SKIP %s ] Failed to load legacy provider", o->id_str);
+					return 0;
+				}
+			}
+#endif
+			md = EVP_ripemd160();
 			break;
 		default:
 			debug_print(" [SKIP %s ] Skip verify of unknown mechanism", o->id_str);
 			return 0;
 		}
-		rv = RSA_verify(type, cmp_message, cmp_message_length,
-			sign, sign_length, o->key.rsa);
-		if (rv == 1) {
-			debug_print(" [  OK %s ] Signature is valid.", o->id_str);
-			mech->result_flags |= FLAGS_SIGN_OPENSSL;
-		 } else {
+
+		if ((mdctx = EVP_MD_CTX_new()) == NULL ||
+		    (rv = EVP_DigestVerifyInit(mdctx, NULL, md, NULL, o->key) <= 0) ||
+		    (rv = EVP_DigestVerify(mdctx, sign, sign_length, message, message_length)) != 1) {
 			fprintf(stderr, " [ ERROR %s ] Signature is not valid. Error: %s\n",
 				o->id_str, ERR_error_string(ERR_peek_last_error(), NULL));
+			EVP_MD_CTX_free(mdctx);
 			return -1;
 		}
-	} else if (o->type == EVP_PK_EC) {
+		mech->result_flags |= FLAGS_SIGN_OPENSSL;
+		debug_print(" [  OK %s ] Signature is valid.", o->id_str);
+		return 1;
+	} else if (o->type == EVP_PKEY_EC) {
 		unsigned int nlen;
 		ECDSA_SIG *sig = ECDSA_SIG_new();
 		BIGNUM *r = NULL, *s = NULL;
-		if (sig == NULL) {
-			fprintf(stderr, "ECDSA_SIG_new: failed");
+		EVP_PKEY_CTX *ctx = NULL;
+		ctx = EVP_PKEY_CTX_new(o->key, NULL);
+
+		if (!sig || !ctx) {
+			fprintf(stderr, "Verification failed");
 			return -1;
 		}
 		nlen = sign_length/2;
 		r = BN_bin2bn(&sign[0], nlen, NULL);
 		s = BN_bin2bn(&sign[nlen], nlen, NULL);
 		ECDSA_SIG_set0(sig, r, s);
+
 		switch (mech->mech) {
 		case CKM_ECDSA_SHA512:
 			cmp_message = SHA512(message, message_length, NULL);
@@ -445,24 +504,31 @@
 			debug_print(" [SKIP %s ] Skip verify of unknown mechanism", o->id_str);
 			return 0;
 		}
-		rv = ECDSA_do_verify(cmp_message, cmp_message_length, sig, o->key.ec);
+		int sig_asn1_len = 0;
+		unsigned char *sig_asn1 = NULL;
+		sig_asn1_len = i2d_ECDSA_SIG(sig, &sig_asn1);
+
+		if (EVP_PKEY_verify_init(ctx) != 1) {
+        	fprintf(stderr, "EVP_PKEY_verify_init\n");
+    	}
+
+		rv = EVP_PKEY_verify(ctx, sig_asn1, sig_asn1_len, cmp_message, cmp_message_length);
 		if (rv == 1) {
-			ECDSA_SIG_free(sig);
 			debug_print(" [  OK %s ] EC Signature of length %lu is valid.",
 				o->id_str, message_length);
 			mech->result_flags |= FLAGS_SIGN_OPENSSL;
 			return 1;
 		} else {
-			ECDSA_SIG_free(sig);
-			fprintf(stderr, " [FAIL %s ] ECDSA_do_verify: rv = %lu: %s\n", o->id_str,
+			fprintf(stderr, " [FAIL %s ] EVP_PKEY_verify: rv = %lu: %s\n", o->id_str,
 				rv, ERR_error_string(ERR_peek_last_error(), NULL));
 			return -1;
 		}
+#ifdef EVP_PKEY_ED25519
 	} else if (o->type == EVP_PKEY_ED25519) {
 		/* need to be created even though we do not do any MD */
 		EVP_MD_CTX *ctx = EVP_MD_CTX_create();
 
-		rv = EVP_DigestVerifyInit(ctx, NULL, NULL, NULL, o->key.pkey);
+		rv = EVP_DigestVerifyInit(ctx, NULL, NULL, NULL, o->key);
 		if (rv != 1) {
 			fprintf(stderr, " [FAIL %s ] EVP_DigestVerifyInit: rv = %lu: %s\n", o->id_str,
 				rv, ERR_error_string(ERR_peek_last_error(), NULL));
@@ -483,7 +549,7 @@
 			EVP_MD_CTX_free(ctx);
 			return -1;
 		}
-
+#endif
 	} else {
 		fprintf(stderr, " [ KEY %s ] Unknown type. Not verifying\n", o->id_str);
 	}
@@ -537,7 +603,7 @@
 	}
 	if (rv == CKR_OK) {
 		mech->result_flags |= FLAGS_SIGN;
-		debug_print(" [  OK %s ] Verification successful", o->id_str);
+		debug_print(" [  OK %s ] [PKCS11] Verification successful", o->id_str);
 		return 1;
 	}
 	debug_print("   %s: rv = 0x%.8lX", name, rv);
@@ -567,7 +633,7 @@
 	CK_ULONG sign_length = 0;
 	int rv = 0;
 
-	if (message_length > strlen(SHORT_MESSAGE_TO_SIGN)) {
+	if (message_length > strlen(MESSAGE_TO_SIGN)) {
 		fail_msg("Truncate is longer than the actual message");
 		return -1;
 	}
@@ -577,7 +643,11 @@
 		return 0;
 	}
 
-	if (o->type != EVP_PK_EC && o->type != EVP_PK_RSA && o->type != EVP_PKEY_ED25519) {
+	if (o->type != EVP_PKEY_EC && o->type != EVP_PKEY_RSA
+#ifdef EVP_PKEY_ED25519
+			&& o->type != EVP_PKEY_ED25519
+#endif
+			) {
 		debug_print(" [SKIP %s ] Skip non-RSA and non-EC key", o->id_str);
 		return 0;
 	}
@@ -595,9 +665,9 @@
 		/* DigestInfo + SHA1(message) */
 		message_length = 35;
 		message = malloc(message_length * sizeof(unsigned char));
-		memcpy(message, SHORT_MESSAGE_DIGEST, message_length);
+		memcpy(message, MESSAGE_DIGEST, message_length);
 	} else
-		message = (CK_BYTE *) strdup(SHORT_MESSAGE_TO_SIGN);
+		message = (CK_BYTE *) strdup(MESSAGE_TO_SIGN);
 
 	debug_print(" [ KEY %s ] Signing message of length %lu using CKM_%s",
 		o->id_str, message_length, get_mechanism_name(mech->mech));
@@ -623,8 +693,7 @@
 	int used, j;
 	test_certs_t objects;
 
-	objects.count = 0;
-	objects.data = NULL;
+	test_certs_init(&objects);
 
 	search_for_all_objects(&objects, info);
 
@@ -664,7 +733,7 @@
 
 	/* print summary */
 	printf("[KEY ID] [LABEL]\n");
-	printf("[ TYPE ] [ SIZE ] [PUBLIC] [SIGN&VERIFY] [ENC&DECRYPT] [WRAP&UNWR] [ DERIVE ]\n");
+	printf("[ TYPE ] [ SIZE ] [PUBLIC] [SIGN&VERIFY] [ENC&DECRYPT]\n");
 	P11TEST_DATA_ROW(info, 4,
 		's', "KEY ID",
 		's', "MECHANISM",
@@ -672,10 +741,17 @@
 		's', "ENCRYPT&DECRYPT WORKS");
 	for (i = 0; i < objects.count; i++) {
 		test_cert_t *o = &objects.data[i];
+
+		if (o->key_type != CKK_RSA &&
+		    o->key_type != CKK_EC &&
+		    o->key_type != CKK_EC_EDWARDS &&
+		    o->key_type != CKK_EC_MONTGOMERY)
+			continue;
+
 		printf("\n[%-6s] [%s]\n",
 			o->id_str,
 			o->label);
-		printf("[ %s ] [%6lu] [ %s ] [%s%s] [%s%s] [%s %s] [%s%s]\n",
+		printf("[ %s ] [%6lu] [ %s ] [%s%s] [%s%s]\n",
 			(o->key_type == CKK_RSA ? "RSA " :
 				o->key_type == CKK_EC ? " EC " :
 				o->key_type == CKK_EC_EDWARDS ? "EC_E" :
@@ -685,25 +761,21 @@
 			o->sign ? "[./] " : "[  ] ",
 			o->verify ? " [./] " : " [  ] ",
 			o->encrypt ? "[./] " : "[  ] ",
-			o->decrypt ? " [./] " : " [  ] ",
-			o->wrap ? "[./]" : "[  ]",
-			o->unwrap ? "[./]" : "[  ]",
-			o->derive_pub ? "[./]" : "[  ]",
-			o->derive_priv ? "[./]" : "[  ]");
+			o->decrypt ? " [./] " : " [  ] ");
 		if (!o->sign && !o->verify && !o->encrypt && !o->decrypt) {
 			printf("  no usable attributes found ... ignored\n");
 			continue;
 		}
-		if (objects.data[i].private_handle == CK_INVALID_HANDLE) {
+		if (o->private_handle == CK_INVALID_HANDLE) {
 			continue;
 		}
 		for (j = 0; j < o->num_mechs; j++) {
 			test_mech_t *mech = &o->mechs[j];
-			if ((mech->usage_flags & CKF_SIGN) == 0) {
+			if ((mech->usage_flags & (CKF_SIGN|CKF_DECRYPT)) == 0) {
 				/* not applicable mechanisms are skipped */
 				continue;
 			}
-			printf("  [ %-20s ] [   %s    ] [   %s    ] [         ] [        ]\n",
+			printf("  [ %-20s ] [   %s    ] [   %s    ]\n",
 				get_mechanism_name(mech->mech),
 				mech->result_flags & FLAGS_SIGN_ANY ? "[./]" : "    ",
 				mech->result_flags & FLAGS_DECRYPT_ANY ? "[./]" : "    ");
@@ -717,7 +789,7 @@
 				's', mech->result_flags & FLAGS_DECRYPT_ANY ? "YES" : "");
 		}
 	}
-	printf(" Public == Cert -----^       ^  ^  ^       ^  ^  ^       ^----^- Attributes\n");
+	printf(" Public == Cert -----^       ^  ^  ^       ^  ^  ^\n");
 	printf(" Sign Attribute -------------'  |  |       |  |  '---- Decrypt Attribute\n");
 	printf(" Sign&Verify functionality -----'  |       |  '------- Enc&Dec functionality\n");
 	printf(" Verify Attribute -----------------'       '---------- Encrypt Attribute\n");
diff -Nru opensc-0.22.0/src/tests/p11test/p11test_case_readonly.h opensc-0.23.0/src/tests/p11test/p11test_case_readonly.h
--- opensc-0.22.0/src/tests/p11test/p11test_case_readonly.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/p11test/p11test_case_readonly.h	2022-11-29 09:34:43.000000000 +0100
@@ -27,3 +27,13 @@
 int sign_verify_test(test_cert_t *o, token_info_t *info, test_mech_t *mech,
     CK_ULONG message_length, int multipart);
 
+int verify_message(test_cert_t *o, token_info_t *info, CK_BYTE *message,
+    CK_ULONG message_length, test_mech_t *mech, unsigned char *sign,
+    CK_ULONG sign_length, int multipart);
+int sign_message(test_cert_t *o, token_info_t *info, CK_BYTE *message,
+    CK_ULONG message_length, test_mech_t *mech, unsigned char **sign,
+    int multipart);
+int encrypt_message(test_cert_t *o, token_info_t *info, CK_BYTE *message,
+    CK_ULONG message_length, test_mech_t *mech, unsigned char **enc_message);
+int decrypt_message(test_cert_t *o, token_info_t *info, CK_BYTE *enc_message,
+    CK_ULONG enc_message_length, test_mech_t *mech, unsigned char **dec_message);
diff -Nru opensc-0.22.0/src/tests/p11test/p11test_case_secret.c opensc-0.23.0/src/tests/p11test/p11test_case_secret.c
--- opensc-0.22.0/src/tests/p11test/p11test_case_secret.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/p11test/p11test_case_secret.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,317 @@
+/*
+ * p11test_case_secret.c: Check the functionality of operations with secret keys
+ *
+ * Copyright (C) 2021 Red Hat, Inc.
+ *
+ * Author: Jakub Jelen <jjelen at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "p11test_case_secret.h"
+#include "p11test_case_readonly.h"
+
+#define MESSAGE_TO_SIGN "Simple message for signing & verifying. " \
+	"It needs to be little bit longer to fit also longer keys and allow the truncation.\n"
+
+const unsigned char *short_message = (unsigned char *) MESSAGE_TO_SIGN;
+
+static unsigned char *
+pkcs7_pad_message(const unsigned char *message, unsigned long message_length,
+                  unsigned long block_len, unsigned long *out_len)
+{
+	int pad_length = block_len - (message_length % block_len);
+	unsigned char *pad_message = malloc(message_length + pad_length);
+	if (pad_message == NULL) {
+		return NULL;
+	}
+	memcpy(pad_message, message, message_length);
+	memset(pad_message + message_length, pad_length, pad_length);
+	*out_len = message_length + pad_length;
+	return pad_message;
+}
+
+/* Perform encryption and decryption of a message using secret key referenced
+ * in the  o  object with mechanism defined by  mech.
+ *
+ * NONE of the reasonable mechanisms support multipart encryption/decryption
+ *
+ * Returns
+ *  * 1 for successful Encrypt&Decrypt sequence
+ *  * 0 for skipped test (unsupported mechanism, key, ...)
+ *  * -1 otherwise.
+ *  Serious errors terminate the execution.
+ */
+int test_secret_encrypt_decrypt(test_cert_t *o, token_info_t *info, test_mech_t *mech,
+	CK_ULONG message_length, int multipart)
+{
+	CK_BYTE *message = NULL;
+	CK_BYTE *dec_message = NULL;
+	CK_BYTE iv[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	                0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+	CK_AES_CTR_PARAMS ctr_params = { 64, {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	                                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+	CK_BYTE aad[] = {0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
+	CK_GCM_PARAMS gcm_params = {
+		.pIv = (void *)iv,
+		.ulIvLen = 16,
+		.ulIvBits = 64,
+		.pAAD = aad, /* TODO: SoftHSM crashes without AAD */
+		.ulAADLen = sizeof(aad),
+		.ulTagBits = 128,
+	};
+	int dec_message_length = 0;
+	unsigned char *enc_message = NULL;
+	int enc_message_length, rv;
+
+	if (o->private_handle == CK_INVALID_HANDLE) {
+		debug_print(" [SKIP %s ] Missing secret key", o->id_str);
+		return 0;
+	}
+
+	if (o->key_type != CKK_AES) {
+		debug_print(" [ KEY %s ] Skip non-AES key for encryption", o->id_str);
+		return 0;
+	}
+
+	/* The CBC mechanisms require parameter with IV */
+	mech->params = &iv;
+	mech->params_len = sizeof(iv);
+	if (mech->mech == CKM_AES_CBC || mech->mech == CKM_AES_ECB) {
+		/* This mechanism requires the blocks to be aligned to block size */
+		message = pkcs7_pad_message(short_message, message_length, 16, &message_length);
+	} else if (mech->mech == CKM_AES_CBC_PAD || mech->mech == CKM_AES_CTS) {
+		message = (CK_BYTE *) strndup(MESSAGE_TO_SIGN, message_length);
+	} else if (mech->mech == CKM_AES_CTR) {
+		/* The CTR requires counter block + counter bits */
+		mech->params = &ctr_params;
+		mech->params_len = sizeof(ctr_params);
+		message = (CK_BYTE *) strndup(MESSAGE_TO_SIGN, message_length);
+	} else if (mech->mech == CKM_AES_GCM) {
+		/* The GCM requires GCM parameter */
+		mech->params = &gcm_params;
+		mech->params_len = sizeof(gcm_params);
+		message = (CK_BYTE *) strndup(MESSAGE_TO_SIGN, message_length);
+	} else {
+		debug_print(" [SKIP %s ] Unknown mechanism", o->id_str);
+		return 0;
+	}
+
+	debug_print(" [ KEY %s ] Encrypt message using CKM_%s",
+		o->id_str, get_mechanism_name(mech->mech));
+	enc_message_length = encrypt_message(o, info, message, message_length,
+	    mech, &enc_message);
+	if (enc_message_length <= 0) {
+		mech->params = NULL;
+		mech->params_len = 0;
+		free(enc_message);
+		free(message);
+		return -1;
+	}
+
+	debug_print(" [ KEY %s ] Decrypt message", o->id_str);
+	dec_message_length = decrypt_message(o, info, enc_message,
+	    enc_message_length, mech, &dec_message);
+	free(enc_message);
+	if (dec_message_length <= 0) {
+		mech->params = NULL;
+		mech->params_len = 0;
+		free(message);
+		return -1;
+	}
+
+	if (memcmp(dec_message, message, dec_message_length) == 0
+			&& (unsigned int) dec_message_length == message_length) {
+		debug_print(" [  OK %s ] Text decrypted successfully.", o->id_str);
+		mech->result_flags |= FLAGS_DECRYPT;
+		rv = 1;
+	} else {
+		dec_message[dec_message_length] = '\0';
+		debug_print(" [ ERROR %s ] Text decryption failed. Recovered text: %s",
+			o->id_str, dec_message);
+		rv = 0;
+	}
+	mech->params = NULL;
+	mech->params_len = 0;
+	free(dec_message);
+	free(message);
+	return rv;
+}
+
+
+/* Perform signature and verification of a message using secret key referenced
+ * in the  o  object with mechanism defined by  mech. Message length can be
+ * specified using argument  message_length.
+ *
+ * Returns
+ *  * 1 for successful Sign&Verify sequence
+ *  * 0 for skipped test (unsupported mechanism, key, ...)
+ *  * -1 otherwise.
+ *  Serious errors terminate the execution.
+ */
+int test_secret_sign_verify(test_cert_t *o, token_info_t *info, test_mech_t *mech,
+    CK_ULONG message_length, int multipart)
+{
+	CK_BYTE *message = NULL;
+	CK_ULONG sig_len = 42;
+	CK_BYTE *sign = NULL;
+	CK_ULONG sign_length = 0;
+	int rv = 0;
+
+	if (message_length > strlen(MESSAGE_TO_SIGN)) {
+		fail_msg("Truncate (%lu) is longer than the actual message (%lu)",
+			message_length, strlen(MESSAGE_TO_SIGN));
+		return -1;
+	}
+
+	if (o->private_handle == CK_INVALID_HANDLE) {
+		debug_print(" [SKIP %s ] Missing secret key handle", o->id_str);
+		return 0;
+	}
+
+	if (o->key_type != CKK_AES) {
+		debug_print(" [SKIP %s ] Skip non-AES key", o->id_str);
+		return 0;
+	}
+
+	if (mech->mech == CKM_AES_CMAC) {
+		message = (CK_BYTE *) strndup(MESSAGE_TO_SIGN, message_length);
+	} else if (mech->mech == CKM_AES_CMAC_GENERAL) {
+		message = (CK_BYTE *) strndup(MESSAGE_TO_SIGN, message_length);
+		/* This mechanism requires parameter denoting the requested output length */
+		mech->params = &sig_len;
+		mech->params_len = sizeof(sig_len);
+	} else {
+		debug_print(" [SKIP %s ] Unknown mechanism", o->id_str);
+		return 0;
+	}
+
+	debug_print(" [ KEY %s ] Signing message of length %lu using CKM_%s",
+		o->id_str, message_length, get_mechanism_name(mech->mech));
+	rv = sign_message(o, info, message, message_length, mech, &sign, multipart);
+	if (rv <= 0) {
+		mech->params = NULL;
+		mech->params_len = 0;
+		free(message);
+		return rv;
+	}
+	sign_length = (unsigned long) rv;
+
+	debug_print(" [ KEY %s ] Verify message signature", o->id_str);
+	rv = verify_message(o, info, message, message_length, mech,
+		sign, sign_length, multipart);
+	mech->params = NULL;
+	mech->params_len = 0;
+	free(sign);
+	free(message);
+	return rv;
+}
+
+void secret_tests(void **state)
+{
+	unsigned int i;
+	int j;
+	int errors = 0;
+	token_info_t *info = (token_info_t *) *state;
+	test_certs_t objects;
+
+	test_certs_init(&objects);
+
+	P11TEST_START(info);
+	search_for_all_objects(&objects, info);
+
+	/* Make sure to try the pkcs11 functions */
+	info->verify_support = 1;
+	info->encrypt_support = 1;
+
+	debug_print("Check operations on secret keys.\n");
+	for (i = 0; i < objects.count; i++) {
+		test_cert_t *o = &objects.data[i];
+		/* Ignore if there is missing private key */
+		if (o->private_handle == CK_INVALID_HANDLE)
+			continue;
+
+		for (j = 0; j < o->num_mechs; j++) {
+			if (o->key_type == CKK_AES) {
+				if (o->mechs[j].usage_flags & CKF_SIGN) {
+					errors += test_secret_sign_verify(&(objects.data[i]),
+					                                  info, &(o->mechs[j]), 42, 0);
+				}
+				if (o->mechs[j].usage_flags & CKF_DECRYPT) {
+					errors += test_secret_encrypt_decrypt(&(objects.data[i]),
+					                                      info, &(o->mechs[j]), 42, 0);
+				}
+			}
+		}
+	}
+
+	/* print summary */
+	printf("[KEY ID] [LABEL]\n");
+	printf("[ TYPE ] [ SIZE ] [SIGN&VERIFY] [ENC&DECRYPT]\n");
+	P11TEST_DATA_ROW(info, 4,
+		's', "KEY ID",
+		's', "MECHANISM",
+		's', "SIGN&VERIFY WORKS",
+		's', "ENCRYPT&DECRYPT WORKS");
+	for (i = 0; i < objects.count; i++) {
+		test_cert_t *o = &objects.data[i];
+
+		if (o->key_type != CKK_AES)
+			continue;
+
+		printf("\n[%-6s] [%s]\n",
+			o->id_str,
+			o->label);
+		printf("[ %s ] [%6lu] [%s%s] [%s%s]\n",
+			"AES ",
+			o->bits,
+			o->sign ? "[./] " : "[  ] ",
+			o->verify ? " [./] " : " [  ] ",
+			o->encrypt ? "[./] " : "[  ] ",
+			o->decrypt ? " [./] " : " [  ] ");
+		if (!o->sign && !o->verify && !o->encrypt && !o->decrypt) {
+			printf("  no usable attributes found ... ignored\n");
+			continue;
+		}
+		if (o->private_handle == CK_INVALID_HANDLE) {
+			continue;
+		}
+		for (j = 0; j < o->num_mechs; j++) {
+			test_mech_t *mech = &o->mechs[j];
+			if ((mech->usage_flags & (CKF_SIGN|CKF_DECRYPT)) == 0) {
+				/* not applicable mechanisms are skipped */
+				continue;
+			}
+			printf("  [ %-11s ] [   %s    ] [   %s    ]\n",
+				get_mechanism_name(mech->mech),
+				mech->result_flags & FLAGS_SIGN_ANY ? "[./]" : "    ",
+				mech->result_flags & FLAGS_DECRYPT_ANY ? "[./]" : "    ");
+			if ((mech->result_flags & FLAGS_SIGN_ANY) == 0 &&
+				(mech->result_flags & FLAGS_DECRYPT_ANY) == 0)
+				continue; /* skip empty rows for export */
+			P11TEST_DATA_ROW(info, 4,
+				's', o->id_str,
+				's', get_mechanism_name(mech->mech),
+				's', mech->result_flags & FLAGS_SIGN_ANY ? "YES" : "",
+				's', mech->result_flags & FLAGS_DECRYPT_ANY ? "YES" : "");
+		}
+	}
+	printf(" Sign Attribute ----^  ^  ^       ^  ^  ^---- Decrypt Attribute\n");
+	printf(" Sign&Verify works ----'  |       |  '------- Enc&Dec works\n");
+	printf(" Verify Attribute --------'       '---------- Encrypt Attribute\n");
+
+	clean_all_objects(&objects);
+	if (errors > 0)
+		P11TEST_FAIL(info, "Not all the derive mechanisms worked.");
+	P11TEST_PASS(info);
+}
diff -Nru opensc-0.22.0/src/tests/p11test/p11test_case_secret.h opensc-0.23.0/src/tests/p11test/p11test_case_secret.h
--- opensc-0.22.0/src/tests/p11test/p11test_case_secret.h	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/p11test/p11test_case_secret.h	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,26 @@
+/*
+ * p11test_case_secret.h: Check the functionality of operations with secret keys
+ *
+ * Copyright (C) 2021 Red Hat, Inc.
+ *
+ * Author: Jakub Jelen <jjelen at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "p11test_case_common.h"
+#include "p11test_case_readonly.h"
+
+void secret_tests(void **state);
+
diff -Nru opensc-0.22.0/src/tests/p11test/p11test_case_usage.c opensc-0.23.0/src/tests/p11test/p11test_case_usage.c
--- opensc-0.22.0/src/tests/p11test/p11test_case_usage.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/p11test/p11test_case_usage.c	2022-11-29 09:34:43.000000000 +0100
@@ -24,10 +24,9 @@
 	unsigned int i;
 	int errors = 0;
 	token_info_t *info = (token_info_t *) *state;
-
 	test_certs_t objects;
-	objects.count = 0;
-	objects.data = NULL;
+
+	test_certs_init(&objects);
 
 	P11TEST_START(info);
 	search_for_all_objects(&objects, info);
@@ -90,48 +89,50 @@
 		's', "DERIVE PRIVATE",
 		's', "ALWAYS AUTH");
 	for (i = 0; i < objects.count; i++) {
-		printf("\n[%-6s] [%s]\n",
-			objects.data[i].id_str,
-			objects.data[i].label);
+		test_cert_t *o = &objects.data[i];
+
+		printf("\n[%-6s] [%s]\n", o->id_str, o->label);
 
 		/* Ignore if there is missing private key */
 		if (objects.data[i].private_handle == CK_INVALID_HANDLE)
 			continue;
 
 		printf("[ %s ] [%6lu] [ %s ] [%s%s] [%s%s] [%s %s] [%s%s] [    %s   ]\n",
-			(objects.data[i].key_type == CKK_RSA ? "RSA " :
-				objects.data[i].key_type == CKK_EC ? " EC " :
-				objects.data[i].key_type == CKK_EC_EDWARDS ? "EC_E" :
-				objects.data[i].key_type == CKK_EC_MONTGOMERY ? "EC_M" : " ?? "),
-			objects.data[i].bits,
-			objects.data[i].verify_public == 1 ? " ./ " : "    ",
-			objects.data[i].sign ? "[./] " : "[  ] ",
-			objects.data[i].verify ? " [./] " : " [  ] ",
-			objects.data[i].encrypt ? "[./] " : "[  ] ",
-			objects.data[i].decrypt ? " [./] " : " [  ] ",
-			objects.data[i].wrap ? "[./]" : "[  ]",
-			objects.data[i].unwrap ? "[./]" : "[  ]",
-			objects.data[i].derive_pub ? "[./]" : "[  ]",
-			objects.data[i].derive_priv ? "[./]" : "[  ]",
-			objects.data[i].always_auth ? "[./]" : "[  ]");
+			(o->key_type == CKK_RSA ? "RSA " :
+				o->key_type == CKK_EC ? " EC " :
+				o->key_type == CKK_EC_EDWARDS ? "EC_E" :
+				o->key_type == CKK_EC_MONTGOMERY ? "EC_M" :
+				o->key_type == CKK_AES ? "AES " : " ?? "),
+			o->bits,
+			o->verify_public == 1 ? " ./ " : "    ",
+			o->sign ? "[./] " : "[  ] ",
+			o->verify ? " [./] " : " [  ] ",
+			o->encrypt ? "[./] " : "[  ] ",
+			o->decrypt ? " [./] " : " [  ] ",
+			o->wrap ? "[./]" : "[  ]",
+			o->unwrap ? "[./]" : "[  ]",
+			o->derive_pub ? "[./]" : "[  ]",
+			o->derive_priv ? "[./]" : "[  ]",
+			o->always_auth ? "[./]" : "[  ]");
 		P11TEST_DATA_ROW(info, 14,
-			's', objects.data[i].id_str,
-			's', objects.data[i].label,
-			's', (objects.data[i].key_type == CKK_RSA ? "RSA" :
-				objects.data[i].key_type == CKK_EC ? "EC" :
-				objects.data[i].key_type == CKK_EC_EDWARDS ? "EC_E" :
-				objects.data[i].key_type == CKK_EC_MONTGOMERY ? "EC_M" : " ?? "),
-			'd', objects.data[i].bits,
-			's', objects.data[i].verify_public == 1 ? "YES" : "",
-			's', objects.data[i].sign ? "YES" : "",
-			's', objects.data[i].verify ? "YES" : "",
-			's', objects.data[i].encrypt ? "YES" : "",
-			's', objects.data[i].decrypt ? "YES" : "",
-			's', objects.data[i].wrap ? "YES" : "",
-			's', objects.data[i].unwrap ? "YES" : "",
-			's', objects.data[i].derive_pub ? "YES" : "",
-			's', objects.data[i].derive_priv ? "YES" : "",
-			's', objects.data[i].always_auth ? "YES" : "");
+			's', o->id_str,
+			's', o->label,
+			's', (o->key_type == CKK_RSA ? "RSA" :
+				o->key_type == CKK_EC ? "EC" :
+				o->key_type == CKK_EC_EDWARDS ? "EC_E" :
+				o->key_type == CKK_EC_MONTGOMERY ? "EC_M" :
+				o->key_type == CKK_AES ? "AES" : " ?? "),
+			'd', o->bits,
+			's', o->verify_public == 1 ? "YES" : "",
+			's', o->sign ? "YES" : "",
+			's', o->verify ? "YES" : "",
+			's', o->encrypt ? "YES" : "",
+			's', o->decrypt ? "YES" : "",
+			's', o->wrap ? "YES" : "",
+			's', o->unwrap ? "YES" : "",
+			's', o->derive_pub ? "YES" : "",
+			's', o->derive_priv ? "YES" : "",
+			's', o->always_auth ? "YES" : "");
 	}
 	printf(" Public == Cert -----^       ^-----^       ^-----^       ^----^      ^---^\n");
 	printf(" Sign & Verify Attributes ------'             |            |           |\n");
diff -Nru opensc-0.22.0/src/tests/p11test/p11test_case_wrap.c opensc-0.23.0/src/tests/p11test/p11test_case_wrap.c
--- opensc-0.22.0/src/tests/p11test/p11test_case_wrap.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/p11test/p11test_case_wrap.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,403 @@
+/*
+ * p11test_case_wrap.c: Check the functionality of wrap mechanisms
+ *
+ * Copyright (C) 2021 Red Hat, Inc.
+ *
+ * Author: Jakub Jelen <jjelen at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "p11test_case_wrap.h"
+
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+
+/* returns the new length of message after stripping the pkcs7 padding */
+static int
+strip_pkcs7_padding(const unsigned char *message, unsigned long message_length,
+                    unsigned long block_len)
+{
+	unsigned char pad_length = message[message_length - 1];
+
+	if (pad_length > block_len) {
+		return 0;
+	}
+
+	return message_length - pad_length;
+}
+
+static int test_wrap(test_cert_t *o, token_info_t *info, test_cert_t *key, test_mech_t *mech)
+{
+	CK_FUNCTION_LIST_PTR fp = info->function_pointer;
+	CK_MECHANISM mechanism = { mech->mech, NULL_PTR, 0 };
+	/* SoftHSM supports only SHA1 with OAEP encryption */
+	CK_RSA_PKCS_OAEP_PARAMS oaep_params = {CKM_SHA_1, CKG_MGF1_SHA1, CKZ_DATA_SPECIFIED, NULL, 0};
+	CK_BYTE iv[] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	                0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f};
+	CK_AES_CTR_PARAMS ctr_params = { 64, {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+	                                      0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+	CK_BYTE aad[] = {0x00, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80};
+	CK_GCM_PARAMS gcm_params = {
+		.pIv = (void *)iv,
+		.ulIvLen = 16,
+		.ulIvBits = 64,
+		.pAAD = aad, /* TODO: SoftHSM crashes without AAD */
+		.ulAADLen = sizeof(aad),
+		.ulTagBits = 128,
+	};
+	//unsigned char key[16];
+	CK_BYTE *wrapped = NULL;
+	CK_ULONG wrapped_len = 0;
+	CK_BYTE *plain = NULL;
+	CK_ULONG plain_len = 0;
+	CK_RV rv;
+
+	if (o->private_handle == CK_INVALID_HANDLE) {
+		debug_print(" [SKIP %s ] Missing private key", o->id_str);
+		return 1;
+	}
+
+	if (o->key_type != CKK_RSA && o->key_type != CKK_AES) {
+		debug_print(" [ KEY %s ] Skip non-RSA and non-AES key for wrapping", o->id_str);
+		return 1;
+	}
+
+	debug_print(" [ KEY %s ] Wrap a key [%s] using CKM_%s", o->id_str, key->id_str,
+	            get_mechanism_name(mech->mech));
+	/* RSA mechanisms */
+	if (mech->mech == CKM_RSA_X_509) {
+		if (o->bits < key->bits) {
+			debug_print(" [SKIP %s ] The wrapping key too small", o->id_str);
+			return 1;
+		}
+	} else if (mech->mech == CKM_RSA_PKCS) {
+		if (o->bits - 11 < key->bits) {
+			debug_print(" [SKIP %s ] The wrapping key too small", o->id_str);
+			return 1;
+		}
+	} else if (mech->mech == CKM_RSA_PKCS_OAEP) {
+		if (o->bits - 2 - 2*SHA_DIGEST_LENGTH < key->bits) {
+			debug_print(" [SKIP %s ] The wrapping key too small", o->id_str);
+			return 1;
+		}
+		mech->params = &oaep_params;
+		mech->params_len = sizeof(oaep_params);
+	/* AES mechanisms */
+	} else if (mech->mech == CKM_AES_CBC || mech->mech == CKM_AES_CBC_PAD || mech->mech == CKM_AES_ECB) {
+		mech->params = &iv;
+		mech->params_len = sizeof(iv);
+	} else if (mech->mech == CKM_AES_CTR) {
+		mech->params = &ctr_params;
+		mech->params_len = sizeof(ctr_params);
+	} else if (mech->mech == CKM_AES_GCM) {
+		mech->params = &gcm_params;
+		mech->params_len = sizeof(gcm_params);
+	} else if (mech->mech == CKM_AES_KEY_WRAP || mech->mech == CKM_AES_KEY_WRAP_PAD) {
+		/* Nothing special ... */
+	} else {
+		debug_print(" [ KEY %s ] Unknown wrapping mechanism %s",
+		            o->id_str, get_mechanism_name(mech->mech));
+		return 1;
+	}
+
+	/* Get the wrapped size */
+	mechanism.pParameter = mech->params;
+	mechanism.ulParameterLen = mech->params_len;
+	rv = fp->C_WrapKey(info->session_handle, &mechanism, o->public_handle, key->private_handle,
+	                   wrapped, &wrapped_len);
+	if (rv != CKR_OK) {
+		mech->params = NULL;
+		mech->params_len = 0;
+		fprintf(stderr, "  C_WrapKey: rv = 0x%.8lX\n", rv);
+		return -1;
+	}
+	wrapped = malloc(wrapped_len);
+	if (wrapped == NULL) {
+		mech->params = NULL;
+		mech->params_len = 0;
+		fprintf(stderr, "%s: malloc failed", __func__);
+		return -1;
+	}
+	/* Wrap the key using public RSA key through PKCS#11 */
+	rv = fp->C_WrapKey(info->session_handle, &mechanism, o->public_handle, key->private_handle,
+	                   wrapped, &wrapped_len);
+	if (rv != CKR_OK) {
+		mech->params = NULL;
+		mech->params_len = 0;
+		fprintf(stderr, "  C_WrapKey: rv = 0x%.8lX\n", rv);
+		free(wrapped);
+		return -1;
+	}
+
+	if (mech->mech == CKM_AES_KEY_WRAP || mech->mech == CKM_AES_KEY_WRAP_PAD) {
+		/* good enough for now -- I dont know how to check these */
+		goto out;
+	}
+	/* OK, we have wrapped key. Now, check it is really the key on the card.
+	 * We need to decipher the wrapped key with the wrapping key, which
+	 * should be generally the reverse operation to the wrapping for the
+	 * simple wrapping mechanisms and which should give us a plain key.
+	 */
+	rv = decrypt_message(o, info, wrapped, wrapped_len, mech, &plain);
+	free(wrapped);
+	mech->params = NULL;
+	mech->params_len = 0;
+	if (rv <= 0) {
+		debug_print(" [ KEY %s ] Unable to decrypt the wrapped key", o->id_str);
+		return -1;
+	}
+	plain_len = rv;
+	/*
+	 * Then we need need to check it against something to make sure we have
+	 * the right key. There are two ways:
+	 *  1) The key is publicly readable through CKA_VALUE (not the case most of the time)
+	 *  2) We encrypt something with a assumed key and decrypt it with the card key
+	 */
+	if (key->value) {
+/*
+		if (plain_len == key->bits/8 && memcmp(plain, key->value, plain_len) == 0) {
+			debug_print(" [  OK %s ] Wrapped key recovered correctly", o->id_str);
+		} else {
+			fprintf(stderr, " [ ERROR %s ] Wrapped key does not match\n", o->id_str);
+			return -1;
+		}
+	} else {*/
+		EVP_CIPHER_CTX *ctx = EVP_CIPHER_CTX_new();
+		const EVP_CIPHER *cipher = NULL;
+		unsigned char plaintext[42];
+		int plaintext_len = sizeof(plaintext);
+		unsigned char ciphertext[100];
+		int ciphertext_len = sizeof(ciphertext);
+		test_mech_t aes_mech = {.mech = CKM_AES_CBC, .params = &iv, .params_len = sizeof(iv)};
+		unsigned char *check = NULL;
+		int check_len = 0;
+		int rv, len;
+
+		/* First, do the encryption dance with OpenSSL */
+		if (ctx == NULL) {
+			fprintf(stderr, "  EVP_CIPHER_CTX_new failed\n");
+			return -1;
+		}
+
+		rv = RAND_bytes(plaintext, plaintext_len);
+		if (rv != 1) {
+			fprintf(stderr, "  RAND_bytes failed\n");
+			return -1;
+		}
+
+		if (key->key_type != CKK_AES) {
+			debug_print(" [SKIP %s ] Only AES for now", o->id_str);
+			return 1;
+		}
+		if (plain_len == 32) {
+			cipher = EVP_aes_256_cbc();
+		} else if (plain_len == 16) {
+			cipher = EVP_aes_128_cbc();
+		} else {
+			fprintf(stderr, "  Invalid key length %lu", plain_len);
+			return -1;
+		}
+		rv = EVP_EncryptInit_ex(ctx, cipher, NULL, plain, iv);
+		if (rv != 1) {
+			fprintf(stderr, "  EVP_EncryptInit_ex failed\n");
+			return -1;
+		}
+		rv = EVP_EncryptUpdate(ctx, ciphertext, &ciphertext_len, plaintext, plaintext_len);
+		if (rv != 1) {
+			fprintf(stderr, "  EVP_EncryptUpdate failed\n");
+			return -1;
+		}
+		rv = EVP_EncryptFinal_ex(ctx, ciphertext + ciphertext_len, &len);
+		if (rv != 1) {
+			fprintf(stderr, "  EVP_EncryptFinal_ex failed\n");
+			return -1;
+		}
+		ciphertext_len += len;
+		/* Now, decrypt with the PKCS#11 */
+		check_len = decrypt_message(key, info, ciphertext, ciphertext_len, &aes_mech, &check);
+		if (check_len < 0) {
+			fprintf(stderr, "  Cannot decrypt message\n");
+			return -1;
+		}
+
+		check_len = strip_pkcs7_padding(check, check_len, 16);
+		if (check_len <= 0) {
+			fprintf(stderr, "  Failed to strip PKCS#7 padding\n");
+			return -1;
+		}
+		if (check_len == plaintext_len && memcmp(plaintext, check, plaintext_len) == 0) {
+			debug_print(" [  OK %s ] Decrypted message matches", o->id_str);
+		} else {
+			printf(" [ ERROR %s ] Decrypted message does not match (%d, %d)\n", o->id_str,
+			       check_len, plaintext_len);
+			printf("\nplaintext:\n");
+			for (int i = 0; i < plaintext_len; i++) {
+				printf(":%x", plaintext[i]);
+			}
+			printf("\ncheck:\n");
+			for (int i = 0; i < check_len; i++) {
+				printf(":%x", check[i]);
+			}
+			printf("\n");
+			return -1;
+		}
+	}
+
+out:
+	debug_print(" [  OK %s ] Key wrapping works.", o->id_str);
+	if (key->key_type == CKK_AES) {
+		mech->result_flags |= FLAGS_WRAP_SYM;
+	} else {
+		mech->result_flags |= FLAGS_WRAP;
+	}
+	return 0;
+}
+
+void wrap_tests(void **state)
+{
+	unsigned int i;
+	int j;
+	int errors = 0;
+	token_info_t *info = (token_info_t *) *state;
+	test_certs_t objects;
+	test_cert_t *aes_key = NULL, *aes2_key = NULL;
+	test_cert_t *rsa_key = NULL, *rsa2_key = NULL;
+
+	test_certs_init(&objects);
+
+	P11TEST_START(info);
+	search_for_all_objects(&objects, info);
+
+	for (i = 0; i < objects.count; i++) {
+		test_cert_t *o = &objects.data[i];
+		if (aes_key == NULL && o->key_type == CKK_AES && o->extractable) {
+			aes_key = o;
+		} else if (aes2_key == NULL && o->key_type == CKK_AES && o->extractable) {
+			aes2_key = o;
+		} else if (rsa_key == NULL && o->key_type == CKK_RSA && o->extractable) {
+			rsa_key = o;
+		} else if (rsa2_key == NULL && o->key_type == CKK_RSA && o->extractable) {
+			rsa2_key = o;
+		}
+	}
+
+	debug_print("Check if the wrap operation works.\n");
+	for (i = 0; i < objects.count; i++) {
+		test_cert_t *o = &objects.data[i];
+		/* Ignore if there is missing private key */
+		if (o->private_handle == CK_INVALID_HANDLE)
+			continue;
+
+		for (j = 0; j < o->num_mechs; j++) {
+			/*
+			if ((o->mechs[j].usage_flags & CKF_WRAP) == 0 || !o->wrap)
+				continue;
+			if ((o->mechs[j].usage_flags & CKF_UNWRAP) == 0	|| !o->unwrap)
+				continue;
+			*/
+			if ((o->mechs[j].usage_flags & (CKF_WRAP|CKF_UNWRAP)) == 0)
+				continue;
+
+			switch (o->key_type) {
+			case CKK_RSA:
+				/* We probably can not wrap one key with itself */
+				if (rsa_key && o != rsa_key) {
+					errors += test_wrap(o, info, rsa_key, &(o->mechs[j]));
+				} else if (rsa2_key && o != rsa2_key) {
+					errors += test_wrap(o, info, rsa2_key, &(o->mechs[j]));
+				}
+				if (aes_key) {
+					errors += test_wrap(o, info, aes_key, &(o->mechs[j]));
+				}
+				break;
+			case CKK_AES:
+				/* We probably can not wrap one key with itself */
+				if (aes_key && o != aes_key) {
+					errors += test_wrap(o, info, aes_key, &(o->mechs[j]));
+				} else if (aes2_key && o != aes2_key) {
+					errors += test_wrap(o, info, aes2_key, &(o->mechs[j]));
+				}
+				if (rsa_key) {
+					errors += test_wrap(o, info, rsa_key, &(o->mechs[j]));
+				}
+				break;
+			default:
+				/* Other keys do not support derivation */
+				break;
+			}
+		}
+	}
+
+	/* print summary */
+	printf("[KEY ID] [EXTRACTABLE] [LABEL]\n");
+	printf("[ TYPE ] [ SIZE ]              [ WRAP ] [UNWRAP]\n");
+	P11TEST_DATA_ROW(info, 4,
+		's', "KEY ID",
+		's', "MECHANISM",
+		's', "WRAP WORKS",
+		's', "UNWRAP WORKS");
+	for (i = 0; i < objects.count; i++) {
+		test_cert_t *o = &objects.data[i];
+		if (o->key_type != CKK_RSA && o->key_type != CKK_AES)
+			continue;
+
+		printf("\n[%-6s] [     %s    ] [%s]\n",
+			o->id_str,
+			o->extractable ? "./" : "  ",
+			o->label);
+		printf("[ %s ] [%6lu]              [ [%s] ] [ [%s] ]\n",
+			(o->key_type == CKK_RSA ? "RSA " :
+				o->key_type == CKK_AES ? "AES " : " ?? "),
+			o->bits,
+			o->wrap ? "./" : "  ",
+			o->unwrap ? "./" : "  ");
+		/* the attributes are sometimes confusing
+		if (!o->wrap && !o->unwrap) {
+			printf("  no usable attributes found ... ignored\n");
+			continue;
+		} */
+		if (o->private_handle == CK_INVALID_HANDLE) {
+			continue;
+		}
+		for (j = 0; j < o->num_mechs; j++) {
+			test_mech_t *mech = &o->mechs[j];
+			if ((mech->usage_flags & (CKF_WRAP | CKF_UNWRAP)) == 0) {
+				/* not applicable mechanisms are skipped */
+				continue;
+			}
+			printf("  [ %-24s ] [%s][%s] [%s][%s]\n",
+				get_mechanism_name(mech->mech),
+				mech->result_flags & FLAGS_WRAP_SYM ? "./" : "  ",
+				mech->result_flags & FLAGS_WRAP ? "./" : "  ",
+				mech->result_flags & FLAGS_UNWRAP_SYM ? "./" : "  ",
+				mech->result_flags & FLAGS_UNWRAP ? "./" : "  ");
+			if ((mech->result_flags & (FLAGS_WRAP | FLAGS_UNWRAP)) == 0)
+				continue; /* skip empty rows for export */
+			P11TEST_DATA_ROW(info, 6,
+				's', o->id_str,
+				's', get_mechanism_name(mech->mech),
+				's', mech->result_flags & FLAGS_WRAP_SYM ? "YES" : "",
+				's', mech->result_flags & FLAGS_WRAP ? "YES" : "",
+				's', mech->result_flags & FLAGS_UNWRAP_SYM ? "YES" : "",
+				's', mech->result_flags & FLAGS_UNWRAP ? "YES" : "");
+		}
+	}
+	printf(" Wrapping symmetric key works --^   ^    ^   ^- Unwrapping asymmetric key works\n");
+	printf(" Wrapping asymmetric key works -----'    '------- Unwrapping symmetric key works\n");
+
+	clean_all_objects(&objects);
+	if (errors > 0)
+		P11TEST_FAIL(info, "Not all the wrap/unwrap mechanisms worked.");
+	P11TEST_PASS(info);
+}
diff -Nru opensc-0.22.0/src/tests/p11test/p11test_case_wrap.h opensc-0.23.0/src/tests/p11test/p11test_case_wrap.h
--- opensc-0.22.0/src/tests/p11test/p11test_case_wrap.h	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/p11test/p11test_case_wrap.h	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,27 @@
+/*
+ * p11test_case_wrap.h: Check the functionality of wrap mechanisms
+ *
+ * Copyright (C) 2021 Red Hat, Inc.
+ *
+ * Author: Jakub Jelen <jjelen at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "p11test_case_common.h"
+#include "p11test_case_readonly.h"
+
+void wrap_tests(void **state);
+
+
diff -Nru opensc-0.22.0/src/tests/p11test/p11test_common.h opensc-0.23.0/src/tests/p11test/p11test_common.h
--- opensc-0.22.0/src/tests/p11test/p11test_common.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/p11test/p11test_common.h	2022-11-29 09:34:43.000000000 +0100
@@ -40,13 +40,17 @@
 		} \
 	} while (0)
 
-#define FLAGS_SIGN		0x01
-#define FLAGS_SIGN_OPENSSL	0x02
+#define FLAGS_SIGN		0x001
+#define FLAGS_SIGN_OPENSSL	0x002
 #define FLAGS_SIGN_ANY		( FLAGS_SIGN | FLAGS_SIGN_OPENSSL )
-#define FLAGS_DECRYPT		0x04
-#define FLAGS_DECRYPT_OPENSSL	0x08
+#define FLAGS_DECRYPT		0x004
+#define FLAGS_DECRYPT_OPENSSL	0x008
 #define FLAGS_DECRYPT_ANY	( FLAGS_DECRYPT | FLAGS_DECRYPT_OPENSSL )
-#define FLAGS_DERIVE		0x10
+#define FLAGS_DERIVE		0x010
+#define FLAGS_WRAP		0x020
+#define FLAGS_WRAP_SYM		0x040
+#define FLAGS_UNWRAP		0x080
+#define FLAGS_UNWRAP_SYM	0x100
 
 typedef struct {
 	char *outfile;
@@ -59,9 +63,13 @@
 
 typedef struct {
 	CK_MECHANISM_TYPE mech;
+	/* RSA-PSS parameters */
 	CK_MECHANISM_TYPE hash;
 	CK_RSA_PKCS_MGF_TYPE mgf;
 	int salt;
+	/* generic parameters used for example for secret keys */
+	void *params;
+	unsigned long params_len;
 	int usage_flags;
 	int result_flags;
 } test_mech_t;
@@ -76,6 +84,9 @@
 	unsigned int interactive;
 	log_context_t log;
 
+	int verify_support;
+	int encrypt_support;
+
 	test_mech_t rsa_mechs[MAX_MECHS];
 	size_t  num_rsa_mechs;
 	test_mech_t	ec_mechs[MAX_MECHS];
@@ -84,6 +95,8 @@
 	size_t  num_ed_mechs;
 	test_mech_t	montgomery_mechs[MAX_MECHS];
 	size_t  num_montgomery_mechs;
+	test_mech_t	aes_mechs[MAX_MECHS];
+	size_t  num_aes_mechs;
 	test_mech_t	keygen_mechs[MAX_MECHS];
 	size_t  num_keygen_mechs;
 } token_info_t;
diff -Nru opensc-0.22.0/src/tests/p11test/runtest.sh opensc-0.23.0/src/tests/p11test/runtest.sh
--- opensc-0.22.0/src/tests/p11test/runtest.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/p11test/runtest.sh	2022-11-29 09:34:43.000000000 +0100
@@ -24,6 +24,24 @@
 export GNUTLS_PIN=$PIN 
 GENERATE_KEYS=1
 PKCS11_TOOL="../../tools/pkcs11-tool";
+PKCS15_INIT="../../tools/pkcs15-init";
+
+function generate_sym() {
+	TYPE="$1"
+	ID="$2"
+	LABEL="$3"
+
+	# Generate key
+	$PKCS11_TOOL --keygen --key-type="$TYPE" --login --pin=$PIN \
+		--extractable --module="$P11LIB" --label="$LABEL" --id=$ID
+
+	if [[ "$?" -ne "0" ]]; then
+		echo "Couldn't generate $TYPE key pair"
+		return 1
+	fi
+
+	p11tool --login --provider="$P11LIB" --list-all
+}
 
 function generate_cert() {
 	TYPE="$1"
@@ -33,7 +51,7 @@
 
 	# Generate key pair
 	$PKCS11_TOOL --keypairgen --key-type="$TYPE" --login --pin=$PIN \
-		--module="$P11LIB" --label="$LABEL" --id=$ID
+		--extractable --module="$P11LIB" --label="$LABEL" --id=$ID
 
 	if [[ "$?" -ne "0" ]]; then
 		echo "Couldn't generate $TYPE key pair"
@@ -69,6 +87,7 @@
 function card_setup() {
 	ECC_KEYS=1
 	EDDSA=1
+	SECRET=1
 	case $1 in
 		"softhsm")
 			P11LIB="/usr/lib64/pkcs11/libsofthsm2.so"
@@ -82,6 +101,7 @@
 			# Supports only RSA mechanisms
 			ECC_KEYS=0
 			EDDSA=0
+			SECRET=0
 			P11LIB="/usr/lib64/pkcs11/libopencryptoki.so"
 			SO_PIN=87654321
 			SLOT_ID=3 # swtok slot
@@ -107,10 +127,22 @@
 				P11LIB="../pkcs11/.libs/opensc-pkcs11.so"
 			fi
 			;;
+		"myeid")
+			GENERATE_KEYS=0 # we generate them directly here
+			P11LIB="../pkcs11/.libs/opensc-pkcs11.so"
+			PKCS15_INIT --erase-card --so-pin $SOPIN
+			PKCS15_INIT -C --pin $PIN --puk $SOPIN --so-pin $SOPIN --so-puk $SOPIN
+			PKCS15_INIT -P -a 1 -l "Basic PIN" --pin $PIN --puk $PIN
+			INIT=$PKCS15_INIT --auth-id 01 --so-pin $SOPIN --pin $PIN
+			INIT --generate-key ec:prime256v1 --id 01 --label="EC key"
+			INIT --generate-key rsa:2048 --id 02 --label="RSA key" --key-usage=sign,decrypt
+			INIT --store-secret-key /dev/urandom --secret-key-algorithm aes:256 --extractable --id 03 --label="AES key" --key-usage=sign,decrypt
+			PKCS15_INIT -F
+			;;
 		*)
 			echo "Error: Missing argument."
 			echo "    Usage:"
-			echo "        runtest.sh [softhsm|opencryptoki|readonly [pkcs-library.so]]"
+			echo "        runtest.sh [softhsm|opencryptoki|myeid|readonly [pkcs-library.so]]"
 			exit 1;
 			;;
 	esac
@@ -133,6 +165,12 @@
 			#generate_cert "EC:curve25519" "06" "Curve25519" 0
 			# not supported by softhsm either
 		fi
+		if [[ $SECRET -eq 1 ]]; then
+			# Generate AES 128 key
+			generate_sym "aes:16" "07" "AES128 key"
+			# Generate AES 256 key
+			generate_sym "aes:32" "08" "AES256 key"
+		fi
 	fi
 }
 
@@ -150,9 +188,9 @@
 if [[ "$PKCS11SPY" != "" ]]; then
 	export PKCS11SPY="$P11LIB"
 	$VALGRIND ./p11test -m ../../pkcs11/.libs/pkcs11-spy.so -p $PIN &> /tmp/spy.log
+	echo "Output stored in /tmp/spy.log"
 else
-	#bash
-	$VALGRIND ./p11test -m "$P11LIB" -o test.json -p $PIN
+	$VALGRIND ./p11test -v -m "$P11LIB" -o test.json -p $PIN
 fi
 
 card_cleanup "$@"
diff -Nru opensc-0.22.0/src/tests/p11test/virt_cacard_ref.json opensc-0.23.0/src/tests/p11test/virt_cacard_ref.json
--- opensc-0.22.0/src/tests/p11test/virt_cacard_ref.json	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/p11test/virt_cacard_ref.json	2022-11-29 09:34:43.000000000 +0100
@@ -3,7 +3,7 @@
 "results": [
 {
 	"test_id": "wait_test",
-	"result": "pass"
+	"result": "skip"
 },
 {
 	"test_id": "supported_mechanisms_test",
@@ -151,6 +151,12 @@
 		"1024",
 		"3072",
 		"0x00002800"
+	],
+	[
+		"RSA_PKCS_OAEP",
+		"1024",
+		"3072",
+		"0x00000201"
 	]],
 	"result": "pass"
 },
@@ -566,6 +572,15 @@
 		"RSA_PKCS_PSS",
 		"SHA_1",
 		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA_1",
 		"-1",
 		"YES",
 		""
@@ -574,6 +589,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -583,6 +616,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -592,6 +643,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -601,6 +670,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -609,6 +696,24 @@
 	[
 		"00:01",
 		"RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA224",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
 		"SHA224",
 		"MGF1_SHA_1",
 		"-1",
@@ -619,6 +724,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA224",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA224",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA224",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -628,6 +751,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA224",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA224",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA224",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -637,6 +778,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA224",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA224",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA224",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -646,6 +805,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA224",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA224",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA224",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -654,6 +831,24 @@
 	[
 		"00:01",
 		"RSA_PKCS_PSS",
+		"SHA224",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
 		"SHA256",
 		"MGF1_SHA_1",
 		"-1",
@@ -664,6 +859,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -673,6 +886,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -682,6 +913,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -691,6 +940,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -699,6 +966,24 @@
 	[
 		"00:01",
 		"RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
 		"SHA384",
 		"MGF1_SHA_1",
 		"-1",
@@ -709,6 +994,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -718,6 +1021,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -727,6 +1048,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -736,6 +1075,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -744,6 +1101,24 @@
 	[
 		"00:01",
 		"RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
 		"SHA512",
 		"MGF1_SHA_1",
 		"-1",
@@ -754,6 +1129,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -763,6 +1156,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -772,6 +1183,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -781,6 +1210,24 @@
 		"00:01",
 		"RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -788,6 +1235,24 @@
 	],
 	[
 		"00:01",
+		"RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
 		"SHA1_RSA_PKCS_PSS",
 		"SHA_1",
 		"MGF1_SHA_1",
@@ -799,6 +1264,24 @@
 		"00:01",
 		"SHA1_RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -808,6 +1291,24 @@
 		"00:01",
 		"SHA1_RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -817,6 +1318,24 @@
 		"00:01",
 		"SHA1_RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -826,6 +1345,24 @@
 		"00:01",
 		"SHA1_RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -833,6 +1370,24 @@
 	],
 	[
 		"00:01",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
 		"SHA256_RSA_PKCS_PSS",
 		"SHA256",
 		"MGF1_SHA_1",
@@ -844,6 +1399,24 @@
 		"00:01",
 		"SHA256_RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -853,6 +1426,24 @@
 		"00:01",
 		"SHA256_RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -862,6 +1453,24 @@
 		"00:01",
 		"SHA256_RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -871,6 +1480,24 @@
 		"00:01",
 		"SHA256_RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -878,6 +1505,24 @@
 	],
 	[
 		"00:01",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
 		"SHA384_RSA_PKCS_PSS",
 		"SHA384",
 		"MGF1_SHA_1",
@@ -889,6 +1534,24 @@
 		"00:01",
 		"SHA384_RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -898,6 +1561,24 @@
 		"00:01",
 		"SHA384_RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -907,6 +1588,24 @@
 		"00:01",
 		"SHA384_RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -916,6 +1615,24 @@
 		"00:01",
 		"SHA384_RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -923,6 +1640,24 @@
 	],
 	[
 		"00:01",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
 		"SHA512_RSA_PKCS_PSS",
 		"SHA512",
 		"MGF1_SHA_1",
@@ -934,6 +1669,24 @@
 		"00:01",
 		"SHA512_RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -943,6 +1696,24 @@
 		"00:01",
 		"SHA512_RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -952,6 +1723,24 @@
 		"00:01",
 		"SHA512_RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -961,12 +1750,93 @@
 		"00:01",
 		"SHA512_RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
 		""
 	],
 	[
+		"00:01",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:01",
+		"RSA_PKCS_OAEP",
+		"SHA_1",
+		"MGF1_SHA_1",
+		"0",
+		"",
+		"YES"
+	],
+	[
+		"00:01",
+		"RSA_PKCS_OAEP",
+		"SHA224",
+		"MGF1_SHA224",
+		"0",
+		"",
+		"YES"
+	],
+	[
+		"00:01",
+		"RSA_PKCS_OAEP",
+		"SHA256",
+		"MGF1_SHA256",
+		"0",
+		"",
+		"YES"
+	],
+	[
+		"00:01",
+		"RSA_PKCS_OAEP",
+		"SHA384",
+		"MGF1_SHA384",
+		"0",
+		"",
+		"YES"
+	],
+	[
+		"00:01",
+		"RSA_PKCS_OAEP",
+		"SHA512",
+		"MGF1_SHA512",
+		"0",
+		"",
+		"YES"
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA_1",
@@ -979,6 +1849,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -988,6 +1876,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -997,6 +1903,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -1006,6 +1930,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -1014,6 +1956,24 @@
 	[
 		"00:02",
 		"RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA224",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
 		"SHA224",
 		"MGF1_SHA_1",
 		"-1",
@@ -1024,6 +1984,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA224",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA224",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA224",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -1033,6 +2011,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA224",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA224",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA224",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -1042,6 +2038,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA224",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA224",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA224",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -1051,6 +2065,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA224",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA224",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA224",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -1059,6 +2091,24 @@
 	[
 		"00:02",
 		"RSA_PKCS_PSS",
+		"SHA224",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
 		"SHA256",
 		"MGF1_SHA_1",
 		"-1",
@@ -1069,6 +2119,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -1078,6 +2146,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -1087,6 +2173,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -1096,6 +2200,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -1104,6 +2226,24 @@
 	[
 		"00:02",
 		"RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
 		"SHA384",
 		"MGF1_SHA_1",
 		"-1",
@@ -1114,6 +2254,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -1123,6 +2281,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -1132,6 +2308,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -1141,6 +2335,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -1149,6 +2361,24 @@
 	[
 		"00:02",
 		"RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
 		"SHA512",
 		"MGF1_SHA_1",
 		"-1",
@@ -1159,6 +2389,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -1168,6 +2416,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -1177,6 +2443,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -1186,6 +2470,24 @@
 		"00:02",
 		"RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -1193,6 +2495,24 @@
 	],
 	[
 		"00:02",
+		"RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
 		"SHA1_RSA_PKCS_PSS",
 		"SHA_1",
 		"MGF1_SHA_1",
@@ -1204,6 +2524,24 @@
 		"00:02",
 		"SHA1_RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -1213,6 +2551,24 @@
 		"00:02",
 		"SHA1_RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -1222,6 +2578,24 @@
 		"00:02",
 		"SHA1_RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -1231,6 +2605,24 @@
 		"00:02",
 		"SHA1_RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -1238,6 +2630,24 @@
 	],
 	[
 		"00:02",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
 		"SHA256_RSA_PKCS_PSS",
 		"SHA256",
 		"MGF1_SHA_1",
@@ -1249,6 +2659,24 @@
 		"00:02",
 		"SHA256_RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -1258,6 +2686,24 @@
 		"00:02",
 		"SHA256_RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -1267,6 +2713,24 @@
 		"00:02",
 		"SHA256_RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -1276,6 +2740,24 @@
 		"00:02",
 		"SHA256_RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -1283,6 +2765,24 @@
 	],
 	[
 		"00:02",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
 		"SHA384_RSA_PKCS_PSS",
 		"SHA384",
 		"MGF1_SHA_1",
@@ -1294,6 +2794,24 @@
 		"00:02",
 		"SHA384_RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -1303,6 +2821,24 @@
 		"00:02",
 		"SHA384_RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -1312,6 +2848,24 @@
 		"00:02",
 		"SHA384_RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -1321,6 +2875,24 @@
 		"00:02",
 		"SHA384_RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -1328,6 +2900,24 @@
 	],
 	[
 		"00:02",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
 		"SHA512_RSA_PKCS_PSS",
 		"SHA512",
 		"MGF1_SHA_1",
@@ -1339,6 +2929,24 @@
 		"00:02",
 		"SHA512_RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -1348,6 +2956,24 @@
 		"00:02",
 		"SHA512_RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -1357,6 +2983,24 @@
 		"00:02",
 		"SHA512_RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -1366,12 +3010,93 @@
 		"00:02",
 		"SHA512_RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
 		""
 	],
 	[
+		"00:02",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:02",
+		"RSA_PKCS_OAEP",
+		"SHA_1",
+		"MGF1_SHA_1",
+		"0",
+		"",
+		"YES"
+	],
+	[
+		"00:02",
+		"RSA_PKCS_OAEP",
+		"SHA224",
+		"MGF1_SHA224",
+		"0",
+		"",
+		"YES"
+	],
+	[
+		"00:02",
+		"RSA_PKCS_OAEP",
+		"SHA256",
+		"MGF1_SHA256",
+		"0",
+		"",
+		"YES"
+	],
+	[
+		"00:02",
+		"RSA_PKCS_OAEP",
+		"SHA384",
+		"MGF1_SHA384",
+		"0",
+		"",
+		"YES"
+	],
+	[
+		"00:02",
+		"RSA_PKCS_OAEP",
+		"SHA512",
+		"MGF1_SHA512",
+		"0",
+		"",
+		"YES"
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA_1",
@@ -1384,6 +3109,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -1393,6 +3136,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -1402,6 +3163,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -1411,6 +3190,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -1419,6 +3216,24 @@
 	[
 		"00:03",
 		"RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA224",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
 		"SHA224",
 		"MGF1_SHA_1",
 		"-1",
@@ -1429,6 +3244,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA224",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA224",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA224",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -1438,6 +3271,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA224",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA224",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA224",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -1447,6 +3298,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA224",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA224",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA224",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -1456,6 +3325,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA224",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA224",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA224",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -1464,6 +3351,24 @@
 	[
 		"00:03",
 		"RSA_PKCS_PSS",
+		"SHA224",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
 		"SHA256",
 		"MGF1_SHA_1",
 		"-1",
@@ -1474,6 +3379,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -1483,6 +3406,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -1492,6 +3433,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -1501,6 +3460,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -1509,6 +3486,24 @@
 	[
 		"00:03",
 		"RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
 		"SHA384",
 		"MGF1_SHA_1",
 		"-1",
@@ -1519,6 +3514,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -1528,6 +3541,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -1537,6 +3568,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -1546,6 +3595,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -1554,6 +3621,24 @@
 	[
 		"00:03",
 		"RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
 		"SHA512",
 		"MGF1_SHA_1",
 		"-1",
@@ -1564,6 +3649,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -1573,6 +3676,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -1582,6 +3703,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -1591,6 +3730,24 @@
 		"00:03",
 		"RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -1598,6 +3755,24 @@
 	],
 	[
 		"00:03",
+		"RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
 		"SHA1_RSA_PKCS_PSS",
 		"SHA_1",
 		"MGF1_SHA_1",
@@ -1609,6 +3784,24 @@
 		"00:03",
 		"SHA1_RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -1618,6 +3811,24 @@
 		"00:03",
 		"SHA1_RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -1627,6 +3838,24 @@
 		"00:03",
 		"SHA1_RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -1636,6 +3865,24 @@
 		"00:03",
 		"SHA1_RSA_PKCS_PSS",
 		"SHA_1",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -1643,6 +3890,24 @@
 	],
 	[
 		"00:03",
+		"SHA1_RSA_PKCS_PSS",
+		"SHA_1",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
 		"SHA256_RSA_PKCS_PSS",
 		"SHA256",
 		"MGF1_SHA_1",
@@ -1654,6 +3919,24 @@
 		"00:03",
 		"SHA256_RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -1663,6 +3946,24 @@
 		"00:03",
 		"SHA256_RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -1672,6 +3973,24 @@
 		"00:03",
 		"SHA256_RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -1681,6 +4000,24 @@
 		"00:03",
 		"SHA256_RSA_PKCS_PSS",
 		"SHA256",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -1688,6 +4025,24 @@
 	],
 	[
 		"00:03",
+		"SHA256_RSA_PKCS_PSS",
+		"SHA256",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
 		"SHA384_RSA_PKCS_PSS",
 		"SHA384",
 		"MGF1_SHA_1",
@@ -1699,6 +4054,24 @@
 		"00:03",
 		"SHA384_RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -1708,6 +4081,24 @@
 		"00:03",
 		"SHA384_RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -1717,6 +4108,24 @@
 		"00:03",
 		"SHA384_RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -1726,6 +4135,24 @@
 		"00:03",
 		"SHA384_RSA_PKCS_PSS",
 		"SHA384",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
@@ -1733,6 +4160,24 @@
 	],
 	[
 		"00:03",
+		"SHA384_RSA_PKCS_PSS",
+		"SHA384",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA_1",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
 		"SHA512_RSA_PKCS_PSS",
 		"SHA512",
 		"MGF1_SHA_1",
@@ -1744,6 +4189,24 @@
 		"00:03",
 		"SHA512_RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA_1",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA224",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA224",
 		"-1",
 		"YES",
@@ -1753,6 +4216,24 @@
 		"00:03",
 		"SHA512_RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA224",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA256",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA256",
 		"-1",
 		"YES",
@@ -1762,6 +4243,24 @@
 		"00:03",
 		"SHA512_RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA256",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA384",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA384",
 		"-1",
 		"YES",
@@ -1771,10 +4270,82 @@
 		"00:03",
 		"SHA512_RSA_PKCS_PSS",
 		"SHA512",
+		"MGF1_SHA384",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA512",
+		"-2",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
 		"MGF1_SHA512",
 		"-1",
 		"YES",
 		""
+	],
+	[
+		"00:03",
+		"SHA512_RSA_PKCS_PSS",
+		"SHA512",
+		"MGF1_SHA512",
+		"0",
+		"YES",
+		""
+	],
+	[
+		"00:03",
+		"RSA_PKCS_OAEP",
+		"SHA_1",
+		"MGF1_SHA_1",
+		"0",
+		"",
+		"YES"
+	],
+	[
+		"00:03",
+		"RSA_PKCS_OAEP",
+		"SHA224",
+		"MGF1_SHA224",
+		"0",
+		"",
+		"YES"
+	],
+	[
+		"00:03",
+		"RSA_PKCS_OAEP",
+		"SHA256",
+		"MGF1_SHA256",
+		"0",
+		"",
+		"YES"
+	],
+	[
+		"00:03",
+		"RSA_PKCS_OAEP",
+		"SHA384",
+		"MGF1_SHA384",
+		"0",
+		"",
+		"YES"
+	],
+	[
+		"00:03",
+		"RSA_PKCS_OAEP",
+		"SHA512",
+		"MGF1_SHA512",
+		"0",
+		"",
+		"YES"
 	]],
 	"result": "pass"
 },
@@ -1787,5 +4358,27 @@
 		"DERIVE WORKS"
 	]],
 	"result": "pass"
+},
+{
+	"test_id": "secret_tests",
+	"data": [
+	[
+		"KEY ID",
+		"MECHANISM",
+		"SIGN&VERIFY WORKS",
+		"ENCRYPT&DECRYPT WORKS"
+	]],
+	"result": "pass"
+},
+{
+	"test_id": "wrap_tests",
+	"data": [
+	[
+		"KEY ID",
+		"MECHANISM",
+		"WRAP WORKS",
+		"UNWRAP WORKS"
+	]],
+	"result": "pass"
 }]
 }
diff -Nru opensc-0.22.0/src/tests/p15dump.c opensc-0.23.0/src/tests/p15dump.c
--- opensc-0.22.0/src/tests/p15dump.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/p15dump.c	2022-11-29 09:34:43.000000000 +0100
@@ -74,7 +74,7 @@
 	}
 	path.count = -1;
 
-	r = sc_pkcs15_read_file(p15card, &path, &buf, &buf_len);
+	r = sc_pkcs15_read_file(p15card, &path, &buf, &buf_len, 0);
 	if (r < 0) {
 		if (r == SC_ERROR_FILE_NOT_FOUND) {
 			printf("\nNo EF(UnusedSpace) file\n");
diff -Nru opensc-0.22.0/src/tests/print.c opensc-0.23.0/src/tests/print.c
--- opensc-0.22.0/src/tests/print.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/print.c	2022-11-29 09:34:43.000000000 +0100
@@ -236,14 +236,6 @@
 		printer = print_pubkey;
 		kind = "Public RSA key";
 		break;
-	case SC_PKCS15_TYPE_PRKEY_DSA:
-		printer = print_prkey;
-		kind = "Private DSA key";
-		break;
-	case SC_PKCS15_TYPE_PUBKEY_DSA:
-		printer = print_pubkey;
-		kind = "Public DSA key";
-		break;
 	case SC_PKCS15_TYPE_CERT_X509:
 		printer = print_cert_x509;
 		kind = "X.509 Certificate";
diff -Nru opensc-0.22.0/src/tests/unittests/asn1.c opensc-0.23.0/src/tests/unittests/asn1.c
--- opensc-0.22.0/src/tests/unittests/asn1.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/unittests/asn1.c	2022-11-29 09:34:43.000000000 +0100
@@ -587,6 +587,7 @@
 	assert_int_equal(rv, SC_SUCCESS);
 	assert_int_equal(outlen, sizeof(expected));
 	assert_memory_equal(expected, outptr, sizeof(expected));
+	free(outptr);
 
 	/* Context is not needed */
 	rv = sc_asn1_encode(NULL, asn1, &outptr, &outlen);
diff -Nru opensc-0.22.0/src/tests/unittests/decode_ecdsa_signature.c opensc-0.23.0/src/tests/unittests/decode_ecdsa_signature.c
--- opensc-0.22.0/src/tests/unittests/decode_ecdsa_signature.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/unittests/decode_ecdsa_signature.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,225 @@
+/*
+ * decode_ecdsa_signature.c: Unit tests for decode ASN.1 ECDSA signature
+ *
+ * Copyright (C) 2022 Red Hat, Inc.
+ *
+ * Author: Veronika Hanulikova <vhanulik at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "torture.h"
+#include "libopensc/log.c"
+#include "libopensc/asn1.c"
+
+static void torture_empty_rs(void **state)
+{
+	int r = 0;
+	size_t fieldsize = 24;
+	struct sc_context *ctx = NULL;
+	u8 *out = malloc(2);
+	char data[] = { 0x30, 0x04, 0x02, 0x00, 0x02, 0x00};
+
+	sc_establish_context(&ctx, "test");
+	r = sc_asn1_decode_ecdsa_signature(ctx, (u8 *) data, 6, fieldsize, (u8 ** ) &out, 2);
+	free(out);
+	assert_int_equal(r, SC_ERROR_INVALID_DATA);
+}
+
+static void torture_valid_format(void **state)
+{
+	int r = 0;
+	size_t fieldsize = 1;
+	struct sc_context *ctx = NULL;
+	u8 *out = malloc(2);
+	u8 result[2] = { 0x03, 0x04};
+	char data[] = { 0x30, 0x06, 0x02, 0x01, 0x03, 0x02, 0x01, 0x04};
+
+	if (!out)
+		return;
+
+	sc_establish_context(&ctx, "test");
+	r = sc_asn1_decode_ecdsa_signature(ctx, (u8 *) data, 8, fieldsize, (u8 **) &out, 2);
+
+	assert_int_equal(r, 2 * fieldsize);	
+	assert_memory_equal(result, out, 2);
+	free(out);
+}
+
+static void torture_valid_format_leading00(void **state)
+{
+	int r = 0;
+	size_t fieldsize = 1;
+	struct sc_context *ctx = NULL;
+	u8 *out = malloc(2);
+	u8 result[2] = { 0x03, 0x04};
+	char data[] = { 0x30, 0x07, 0x02, 0x02, 0x00, 0x03, 0x02, 0x01, 0x04};
+
+	if (!out)
+		return;
+
+	sc_establish_context(&ctx, "test");
+	r = sc_asn1_decode_ecdsa_signature(ctx, (u8 *) data, 9, fieldsize, (u8 **) &out, 2);
+
+	assert_int_equal(r, 2 * fieldsize);	
+	assert_memory_equal(result, out, 2);
+	free(out);
+}
+
+static void torture_valid_format_long_fieldsize(void **state)
+{
+	int r = 0;
+	size_t fieldsize = 3;
+	struct sc_context *ctx = NULL;
+	u8 *out = malloc(6);
+	u8 result[6] = { 0x00, 0x00, 0x03, 0x00, 0x00, 0x04};
+	char data[] = { 0x30, 0x06, 0x02, 0x01, 0x03, 0x02, 0x01, 0x04};
+
+	if (!out)
+		return;
+
+	sc_establish_context(&ctx, "test");
+	r = sc_asn1_decode_ecdsa_signature(ctx, (u8 *) data, 9, fieldsize, (u8 **) &out, 6);
+
+	assert_int_equal(r, 2 * fieldsize);	
+	assert_memory_equal(result, out, 6);
+	free(out);
+}
+
+static void torture_wrong_tag_len(void **state)
+{
+	int r = 0;
+	size_t fieldsize = 1;
+	struct sc_context *ctx = NULL;
+	u8 *out = malloc(2);
+	char data[] = { 0x30, 0x05, 0x02, 0x01, 0x03, 0x02, 0x01, 0x04};
+
+	if (!out)
+		return;
+
+	sc_establish_context(&ctx, "test");
+	r = sc_asn1_decode_ecdsa_signature(ctx, (u8 *) data, 8, fieldsize, (u8 **) &out, 2);
+
+	assert_int_equal(r, SC_ERROR_INVALID_DATA);	
+	free(out);
+}
+
+static void torture_wrong_integer_tag_len(void **state)
+{
+	int r = 0;
+	size_t fieldsize = 1;
+	struct sc_context *ctx = NULL;
+	u8 *out = malloc(2);
+	char data[] = { 0x30, 0x06, 0x02, 0x01, 0x03, 0x02, 0x02, 0x04};
+
+	if (!out)
+		return;
+
+	sc_establish_context(&ctx, "test");
+	r = sc_asn1_decode_ecdsa_signature(ctx, (u8 *) data, 8, fieldsize, (u8 **) &out, 2);
+
+	assert_int_equal(r, SC_ERROR_INVALID_DATA);	
+	free(out);
+}
+
+static void torture_small_fieldsize(void **state)
+{
+	int r = 0;
+	size_t fieldsize = 1;
+	struct sc_context *ctx = NULL;
+	u8 *out = malloc(3);
+	char data[] = { 0x30, 0x07, 0x02, 0x01, 0x03, 0x02, 0x02, 0x04, 0x05};
+
+	if (!out)
+		return;
+
+	sc_establish_context(&ctx, "test");
+	r = sc_asn1_decode_ecdsa_signature(ctx, (u8 *) data, 9, fieldsize, (u8 **) &out, 3);
+
+	assert_int_equal(r, SC_ERROR_INVALID_DATA);	
+	free(out);
+}
+
+static void torture_long_leading00(void **state)
+{
+	int r = 0;
+	size_t fieldsize = 1;
+	struct sc_context *ctx = NULL;
+	u8 *out = malloc(3);
+	char data[] = { 0x30, 0x07, 0x02, 0x03, 0x00, 0x00, 0x03, 0x02, 0x01, 0x04};
+
+	if (!out)
+		return;
+
+	sc_establish_context(&ctx, "test");
+	r = sc_asn1_decode_ecdsa_signature(ctx, (u8 *) data, 10, fieldsize, (u8 **) &out, 3);
+
+	assert_int_equal(r, SC_ERROR_INVALID_DATA);	
+	free(out);
+}
+
+static void torture_missing_tag(void **state)
+{
+	int r = 0;
+	size_t fieldsize = 1;
+	struct sc_context *ctx = NULL;
+	u8 *out = malloc(2);
+	char data[] = { 0x20, 0x07, 0x02, 0x01, 0x03, 0x02, 0x02, 0x04, 0x05};
+
+	if (!out)
+		return;
+
+	sc_establish_context(&ctx, "test");
+	r = sc_asn1_decode_ecdsa_signature(ctx, (u8 *) data, 9, fieldsize, (u8 **) &out, 2);
+
+	assert_int_equal(r, SC_ERROR_INVALID_DATA);	
+	free(out);
+}
+
+
+static void torture_missing_integer_tag(void **state)
+{
+	int r = 0;
+	size_t fieldsize = 1;
+	struct sc_context *ctx = NULL;
+	u8 *out = malloc(2);
+	char data[] = { 0x30, 0x07, 0x01, 0x01, 0x03, 0x02, 0x02, 0x04, 0x05};
+
+	if (!out)
+		return;
+
+	sc_establish_context(&ctx, "test");
+	r = sc_asn1_decode_ecdsa_signature(ctx, (u8 *) data, 9, fieldsize, (u8 **) &out, 2);
+
+	assert_int_equal(r, SC_ERROR_INVALID_DATA);	
+	free(out);
+}
+
+int main(void)
+{
+	const struct CMUnitTest tests[] = {
+		cmocka_unit_test(torture_empty_rs),
+		cmocka_unit_test(torture_valid_format),
+		cmocka_unit_test(torture_valid_format_leading00),
+		cmocka_unit_test(torture_valid_format_long_fieldsize),
+		cmocka_unit_test(torture_wrong_tag_len),
+		cmocka_unit_test(torture_wrong_integer_tag_len),
+		cmocka_unit_test(torture_small_fieldsize),
+		cmocka_unit_test(torture_long_leading00),
+		cmocka_unit_test(torture_missing_tag),
+		cmocka_unit_test(torture_missing_integer_tag),
+	};
+	return cmocka_run_group_tests(tests, NULL, NULL);
+}
+
diff -Nru opensc-0.22.0/src/tests/unittests/hextobin.c opensc-0.23.0/src/tests/unittests/hextobin.c
--- opensc-0.22.0/src/tests/unittests/hextobin.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/unittests/hextobin.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,125 @@
+/*
+ * hextobin.c: Test suite for sc_hex_to_bin()
+ *
+ * Copyright (C) 2022 Peter Popovec <popovec.peter at gmail.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include "libopensc/opensc.h"
+
+#define LEN 30
+
+#define C_END -1
+#define C_ERROR -3
+
+struct tst {
+	int result_len;
+	const char *input;
+	const char *output;
+};
+int main()
+{
+	struct tst *t;
+	struct tst test[] = {
+		{1, "0", "\x00"},
+		{1, " 0", "\x00"},
+		{1, "00", "\x00"},
+		{1, ":00", "\x00"},
+		{1, ":0", "\x00"},
+		{1, "d", "\x0d"},
+		{1, ":a", "\x0a"},
+		{1, "01", "\x01"},
+		{1, " 09", "\x09"},
+		{1, ":0a", "\x0a"},
+		{1, " :0b :", "\x0b"},
+		{1, "10", "\x10"},
+		{1, " 90", "\x90"},
+		{1, ":a0", "\xa0"},
+		{1, " :B0 :", "\xb0"},
+		{1, " 11:", "\x11"},
+		{1, " :11:", "\x11"},
+		{1, ":a1", "\xa1"},
+		{2, "01:10", "\x01\x10"},
+		{2, "10:10", "\x10\x10"},
+		{2, " 12ab", "\x12\xab"},
+		{3, "10:20:30", "\x10\x20\x30"},
+		{3, "1020:30", "\x10\x20\x30"},
+		{3, "1020: :30", "\x10\x20\x30"},
+		{3, "102030", "\x10\x20\x30"},
+		{3, ":102030", "\x10\x20\x30"},
+		{3, ":102030:", "\x10\x20\x30"},
+		{3, ":102030::", "\x10\x20\x30"},
+		{3, "b2:11 :22", "\xb2\x11\x22"},
+		{3, "b2 11 22", "\xb2\x11\x22"},
+		{9, "10:203040:5060708090", "\x10\x20\x30\x40\x50\x60\x70\x80\x90"},
+		{0, "::::", ""},
+		{0, ":", ""},
+		{0, " ", ""},
+		{0, "", ""},
+		{C_ERROR, " :0 :", ""},
+		{C_ERROR, " :b :", ""},
+		{C_ERROR, " :c ", ""},
+		{C_ERROR, "1:10", ""},
+		{C_ERROR, " :b:2 :", ""},
+		{C_ERROR, " ::1:2:a:b", ""},
+		{C_ERROR, "1:1", ""},
+		{C_ERROR, " :1 1:", ""},
+		{C_ERROR, "0:0 :", ""},
+		{C_ERROR, "1:234:56", ""},	/* odd number of characters between delimiters  (234) */
+		{C_ERROR, " :b:211 :", ""},
+		{C_ERROR, "02030", ""},	/* one char missing (to have full byte) */
+		{C_ERROR, "111", ""},
+		{C_ERROR, "b:211 :2", ""},
+		{C_ERROR, "G", ""},
+		{C_ERROR, " z", ""},
+		{C_ERROR, ":a1:1", ""},
+		{C_END, "", ""}
+	};
+	uint8_t res[LEN];
+	size_t len;
+	int rv, r;
+
+	for (t = test; t->result_len != C_END; t++) {
+		r = t->result_len;
+		len = LEN;
+		rv = sc_hex_to_bin(t->input, res, &len);
+		if (rv) {
+			if (r != C_ERROR) {
+				fprintf(stderr, "fail at string %s (return code %d, %d\n", t->input,
+					rv, r);
+				return 1;
+			}
+		} else {
+			if (r == C_ERROR) {
+				fprintf(stderr, "fail at string %s (return code %d, %d)\n",
+					t->input, rv, r);
+				return 2;
+			}
+			if ((int)len != r) {
+				fprintf(stderr, "fail at string %s (length %zu %d)\n", t->input,
+					len, r);
+				return 3;
+			}
+			if (memcmp(t->output, res, len)) {
+				fprintf(stderr, "fail at string %s (return value)\n", t->input);
+				return 4;
+			}
+		}
+	}
+	return 0;
+}
diff -Nru opensc-0.22.0/src/tests/unittests/Makefile.am opensc-0.23.0/src/tests/unittests/Makefile.am
--- opensc-0.22.0/src/tests/unittests/Makefile.am	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/unittests/Makefile.am	2022-11-29 09:34:43.000000000 +0100
@@ -6,13 +6,14 @@
 clean-local: code-coverage-clean
 distclean-local: code-coverage-dist-clean
 
-noinst_PROGRAMS = asn1 simpletlv cachedir
-TESTS = asn1 simpletlv cachedir
+noinst_PROGRAMS = asn1 simpletlv cachedir pkcs15filter openpgp-tool hextobin decode_ecdsa_signature
+TESTS = asn1 simpletlv cachedir pkcs15filter openpgp-tool hextobin decode_ecdsa_signature
 
 noinst_HEADERS = torture.h
 
 AM_CFLAGS = -I$(top_srcdir)/src/ \
 	$(CODE_COVERAGE_CFLAGS) \
+	$(OPTIONAL_OPENSSL_CFLAGS) \
 	$(CMOCKA_CFLAGS)
 AM_CPPFLAGS =$(CODE_COVERAGE_CPPFLAGS)
 LDADD = $(top_builddir)/src/libopensc/libopensc.la \
@@ -23,6 +24,10 @@
 asn1_SOURCES = asn1.c
 simpletlv_SOURCES = simpletlv.c
 cachedir_SOURCES = cachedir.c
+pkcs15filter_SOURCES = pkcs15-emulator-filter.c
+openpgp_tool_SOURCES = openpgp-tool.c $(top_builddir)/src/tools/openpgp-tool-helpers.c
+hextobin_SOURCES = hextobin.c
+decode_ecdsa_signature_SOURCES = decode_ecdsa_signature.c
 
 if ENABLE_ZLIB
 noinst_PROGRAMS += compression
diff -Nru opensc-0.22.0/src/tests/unittests/Makefile.mak opensc-0.23.0/src/tests/unittests/Makefile.mak
--- opensc-0.22.0/src/tests/unittests/Makefile.mak	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tests/unittests/Makefile.mak	2022-11-29 09:34:43.000000000 +0100
@@ -1,9 +1,10 @@
 TOPDIR = ..\..\..
 
-TARGETS = asn1 compression
+TARGETS = asn1 compression pkcs15filter
 
 OBJECTS = asn1.obj \
-	compression.obj
+	compression.obj \
+	pkcs15-emulator-filter.obj
 	$(TOPDIR)\win32\versioninfo.res
 
 all: $(TARGETS)
diff -Nru opensc-0.22.0/src/tests/unittests/openpgp-tool.c opensc-0.23.0/src/tests/unittests/openpgp-tool.c
--- opensc-0.22.0/src/tests/unittests/openpgp-tool.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/unittests/openpgp-tool.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,168 @@
+/*
+ * openpgp-tool.c: Test various functions of openpgp-tool
+ *
+ * Copyright (C) 2021  Vincent Pelletier <plr.vincent at gmail.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "torture.h"
+
+#include "tools/openpgp-tool-helpers.h"
+
+struct expectation {
+    const char *data;
+    size_t length;
+    const char *output;
+};
+
+static void torture_prettify(void **state, const struct expectation *cur, char *(prettify_func)(const u8 *data, size_t length))
+{
+	char *output;
+
+	while (cur->data != NULL) {
+		output = prettify_func((u8 *) cur->data, cur->length);
+		if (cur->output == NULL)
+			assert_null(output);
+		else {
+			assert_non_null(output);
+			assert_string_equal(output, cur->output);
+		}
+		cur++;
+	}
+}
+
+const struct expectation expectations_algorithm[] = {
+    { "", 0, NULL },
+    { "\x12\x2b\x06\x01\x04\x01\x97\x55\x01\x05\x01", 11, "ECDH" },
+    { "\x01\x08\x00\x00\x20\x00", 6, "RSA2048" },
+    { NULL, 0, NULL }
+};
+
+static void torture_prettify_algorithm(void **state)
+{
+	torture_prettify(state, expectations_algorithm, prettify_algorithm);
+}
+
+const struct expectation expectations_date[] = {
+    { "\x01\x02\x03", 3, NULL },
+    { "\x12\x34\x56\x78", 4, "1979-09-05 22:51:36" },
+    { "\x7f\xff\xff\xff", 4, "2038-01-19 03:14:07" },
+    /* XXX: probably not a feature */
+    { "\x80\x00\x00\x00", 4, "1901-12-13 20:45:52" },
+    { NULL, 0, NULL }
+};
+
+static void torture_prettify_date(void **state)
+{
+	torture_prettify(state, expectations_date, prettify_date);
+}
+
+const struct expectation expectations_version[] = {
+    { "\x01", 1, NULL },
+    { "\x03\x41", 2, "3.41" },
+    { NULL, 0, NULL }
+};
+
+static void torture_prettify_version(void **state)
+{
+	torture_prettify(state, expectations_version, prettify_version);
+}
+
+const struct expectation expectations_manufacturer[] = {
+    { "\x01", 1, NULL },
+    { "\xf5\x17", 2, "FSIJ" },
+    { "\xff\x00", 2, "unmanaged S/N range" },
+    { "\xff\x7f", 2, "unmanaged S/N range" },
+    { "\xff\xfe", 2, "unmanaged S/N range" },
+    { "\xff\xff", 2, "test card" },
+    /* Number picked by a fair dice roll among unregistered numbers */
+    { "\x81\x88", 2, "unknown" },
+    { NULL, 0, NULL }
+};
+
+static void torture_prettify_manufacturer(void **state)
+{
+	torture_prettify(state, expectations_manufacturer, prettify_manufacturer);
+}
+
+const struct expectation expectations_serialnumber[] = {
+    { "\x00\x00\x00", 3, NULL },
+    { "\x12\x34\x56\x78", 4, "12345678" },
+    { "\x80\x00\x00\x00", 4, "80000000" },
+    { NULL, 0, NULL }
+};
+
+static void torture_prettify_serialnumber(void **state)
+{
+	torture_prettify(state, expectations_serialnumber, prettify_serialnumber);
+}
+
+const struct expectation expectations_name[] = {
+    { "", 0, NULL },
+    { "John Doe", 8, "John Doe" },
+    { "John<Doe", 8, "John Doe" },
+    { "John<<Doe", 9, "John Doe" },
+    { NULL, 0, NULL }
+};
+
+static void torture_prettify_name(void **state)
+{
+	torture_prettify(state, expectations_name, prettify_name);
+}
+
+const struct expectation expectations_language[] = {
+    { "", 0, NULL },
+    { "en", 2, "en" },
+    { "end", 3, "en" },
+    { "deen", 4, "de,en" },
+    { NULL, 0, NULL }
+};
+
+static void torture_prettify_language(void **state)
+{
+	torture_prettify(state, expectations_language, prettify_language);
+}
+
+const struct expectation expectations_gender[] = {
+    { "", 0, NULL },
+    { "\x30", 1, "unknown" },
+    { "\x31", 1, "male" },
+    { "\x32", 1, "female" },
+    { "\x39", 1, "not announced" },
+    { NULL, 0, NULL }
+};
+
+static void torture_prettify_gender(void **state)
+{
+	torture_prettify(state, expectations_gender, prettify_gender);
+}
+
+int main(void)
+{
+	int rc;
+	struct CMUnitTest tests[] = {
+		cmocka_unit_test(torture_prettify_algorithm),
+		cmocka_unit_test(torture_prettify_date),
+		cmocka_unit_test(torture_prettify_version),
+		cmocka_unit_test(torture_prettify_manufacturer),
+		cmocka_unit_test(torture_prettify_serialnumber),
+		cmocka_unit_test(torture_prettify_name),
+		cmocka_unit_test(torture_prettify_language),
+		cmocka_unit_test(torture_prettify_gender),
+	};
+
+	rc = cmocka_run_group_tests(tests, NULL, NULL);
+	return rc;
+}
diff -Nru opensc-0.22.0/src/tests/unittests/pkcs15-emulator-filter.c opensc-0.23.0/src/tests/unittests/pkcs15-emulator-filter.c
--- opensc-0.22.0/src/tests/unittests/pkcs15-emulator-filter.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tests/unittests/pkcs15-emulator-filter.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,490 @@
+/*
+ * pkcs15-emulator-filter.c: Unit tests for PKCS15 emulator filter
+ *
+ * Copyright (C) 2021 Red Hat, Inc.
+ *
+ * Author: Veronika Hanulikova <vhanulik at redhat.com>
+ *
+ * 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 General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "torture.h"
+#include "libopensc/pkcs15-emulator-filter.c"
+
+int func(sc_pkcs15_card_t *card, struct sc_aid *aid) {
+	(void) card;
+	(void) aid;
+	return SC_SUCCESS;
+}
+
+struct sc_pkcs15_emulator_handler builtin[] = {
+	{ "openpgp",	&func },
+	{ "starcert",	&func },
+	{ NULL,	NULL }
+};
+struct sc_pkcs15_emulator_handler old[] = {
+	{ "westcos",	&func },
+	{ "cardos",		&func },
+	{ "jcop",		&func },
+	{ NULL, NULL }
+};
+
+/* add_emul */
+static void torture_null_add_emul(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators = { { &builtin[0] }, 1 };
+	int rv;
+
+	rv = add_emul(NULL, &builtin[0]);
+	assert_int_equal(rv, SC_ERROR_INVALID_ARGUMENTS);
+	rv = add_emul(&filtered_emulators, NULL);
+	assert_int_equal(rv, SC_ERROR_INVALID_ARGUMENTS);
+}
+
+static void torture_name_add_emul(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int rv;
+	filtered_emulators.ccount = 0;
+
+	rv = add_emul(&filtered_emulators, &builtin[0]);
+	assert_int_equal(rv, SC_SUCCESS);
+	assert_int_equal(filtered_emulators.ccount, 1);
+}
+
+static void torture_name_already_in_add_emul(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators = { { &builtin[0] }, 1 };
+	int rv;
+
+	rv = add_emul(&filtered_emulators, &builtin[0]);
+	assert_int_equal(rv, SC_SUCCESS);
+	assert_int_equal(filtered_emulators.ccount, 1);
+}
+
+static void torture_full_add_emul(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int i, rv;
+	filtered_emulators.ccount = SC_MAX_PKCS15_EMULATORS;
+	for (i = 0; i < SC_MAX_PKCS15_EMULATORS; i++) {
+		filtered_emulators.list_of_handlers[i] = &builtin[0];
+	}
+
+	rv = add_emul(&filtered_emulators, &old[0]);
+	assert_int_equal(rv, SC_ERROR_TOO_MANY_OBJECTS);
+	assert_int_equal(filtered_emulators.ccount, SC_MAX_PKCS15_EMULATORS);
+	assert_ptr_equal(filtered_emulators.list_of_handlers[SC_MAX_PKCS15_EMULATORS - 1], &builtin[0]);
+}
+
+static void torture_overfilled_add_emul(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int i, rv;
+	filtered_emulators.ccount = SC_MAX_PKCS15_EMULATORS + 1;
+	for (i = 0; i < SC_MAX_PKCS15_EMULATORS + 1; i++) {
+		filtered_emulators.list_of_handlers[i] = &builtin[0];
+	}
+
+	rv = add_emul(&filtered_emulators, &old[0]);
+	assert_int_equal(rv, SC_ERROR_INVALID_ARGUMENTS);
+	assert_int_equal(filtered_emulators.ccount, SC_MAX_PKCS15_EMULATORS + 1);
+}
+
+static void torture_invalid_handler_name_add_emul(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	struct sc_pkcs15_emulator_handler handler = { NULL, &func };
+	int rv;
+	filtered_emulators.ccount = 0;
+
+	rv = add_emul(&filtered_emulators, &handler);
+	assert_int_equal(rv, SC_ERROR_INVALID_ARGUMENTS);
+}
+
+static void torture_invalid_handler_func_add_emul(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	struct sc_pkcs15_emulator_handler handler = { "name", NULL };
+	int rv;
+	filtered_emulators.ccount = 0;
+
+	rv = add_emul(&filtered_emulators, &handler);
+	assert_int_equal(rv, SC_ERROR_INVALID_ARGUMENTS);
+}
+
+static void torture_invalid_emulator_list_add_emul(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators = { { NULL }, 1 };
+	struct sc_pkcs15_emulator_handler handler = { "name", &func };
+	int rv;
+
+	rv = add_emul(&filtered_emulators, &handler);
+	assert_int_equal(rv, SC_ERROR_OBJECT_NOT_VALID);
+}
+
+/* add_emul_list */
+static void torture_null_add_emul_list(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators = { { &builtin[0] }, 1 };
+	int rv;
+
+	rv = add_emul_list(NULL, builtin);
+	assert_int_equal(rv, SC_ERROR_INVALID_ARGUMENTS);
+	rv = add_emul_list(&filtered_emulators, NULL);
+	assert_int_equal(rv, SC_ERROR_INVALID_ARGUMENTS);
+}
+
+static void torture_internal_add_emul_list(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int i, rv;
+	filtered_emulators.ccount = 0;
+
+	rv = add_emul_list(&filtered_emulators, builtin);
+	assert_int_equal(rv, SC_SUCCESS);
+	for (i = 0; builtin[i].name; i++) {
+		assert_ptr_equal(&builtin[i], filtered_emulators.list_of_handlers[i]);
+	}
+	assert_int_equal(filtered_emulators.ccount, i);
+}
+
+static void torture_internal_already_name_add_emul_list(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators = { { &builtin[0] }, 1 };
+	int i, rv;
+
+	rv = add_emul_list(&filtered_emulators, builtin);
+	assert_int_equal(rv, SC_SUCCESS);
+	for (i = 0; builtin[i].name; i++) {
+		assert_ptr_equal(&builtin[i], filtered_emulators.list_of_handlers[i]);
+	}
+	assert_int_equal(filtered_emulators.ccount, i);
+}
+
+static void torture_internal_already_name2_add_emul_list(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators = { { &old[0] }, 1 };
+	int i, rv;
+
+	rv = add_emul_list(&filtered_emulators, builtin);
+	assert_int_equal(rv, SC_SUCCESS);
+	for (i = 0; builtin[i].name; i++) {
+		assert_ptr_equal(&builtin[i], filtered_emulators.list_of_handlers[i + 1]);
+	}
+	assert_int_equal(filtered_emulators.ccount, i + 1);
+}
+
+static void torture_full_add_emul_list(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int i, rv;
+	filtered_emulators.ccount = SC_MAX_PKCS15_EMULATORS;
+	for (i = 0; i < SC_MAX_PKCS15_EMULATORS; i++) {
+		filtered_emulators.list_of_handlers[i] = &builtin[1];
+	}
+
+	rv = add_emul_list(&filtered_emulators, builtin);
+	assert_int_equal(rv, SC_ERROR_TOO_MANY_OBJECTS);
+	assert_int_equal(filtered_emulators.ccount, SC_MAX_PKCS15_EMULATORS);
+}
+
+static void torture_one_to_full_add_emul_list(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int i, rv;
+	filtered_emulators.ccount = SC_MAX_PKCS15_EMULATORS - 1;
+	for (i = 0; i < SC_MAX_PKCS15_EMULATORS - 1; i++) {
+		filtered_emulators.list_of_handlers[i] = &builtin[0];
+	}
+
+	rv = add_emul_list(&filtered_emulators, old);
+	assert_int_equal(rv, SC_ERROR_TOO_MANY_OBJECTS);
+	assert_ptr_equal(filtered_emulators.list_of_handlers[SC_MAX_PKCS15_EMULATORS - 1], &old[0]);
+	assert_int_equal(filtered_emulators.ccount, SC_MAX_PKCS15_EMULATORS);
+	assert_ptr_not_equal(filtered_emulators.list_of_handlers[SC_MAX_PKCS15_EMULATORS], &old[0]);
+}
+
+static void torture_overfilled_add_emul_list(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int i, rv;
+	filtered_emulators.ccount = SC_MAX_PKCS15_EMULATORS + 1;
+	for (i = 0; i < SC_MAX_PKCS15_EMULATORS + 1; i++) {
+		filtered_emulators.list_of_handlers[i] = &builtin[0];
+	}
+
+	rv = add_emul_list(&filtered_emulators, old);
+	assert_int_equal(rv, SC_ERROR_INVALID_ARGUMENTS);
+	assert_ptr_equal(filtered_emulators.list_of_handlers[SC_MAX_PKCS15_EMULATORS - 1], &builtin[0]);
+	assert_int_equal(filtered_emulators.ccount, SC_MAX_PKCS15_EMULATORS + 1);
+}
+
+/* set_emulators */
+static void torture_non_existing(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int rv;
+	scconf_list list =  { NULL, "non" };
+	filtered_emulators.ccount = 0;
+
+	rv = set_emulators(NULL, &filtered_emulators, &list, builtin, old);
+	assert_int_equal(rv, SC_SUCCESS);
+	assert_null(filtered_emulators.list_of_handlers[0]);
+}
+
+static void torture_internal_only(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int i, rv;
+	scconf_list list =  { NULL, "internal" };
+	filtered_emulators.ccount = 0;
+
+	rv = set_emulators(NULL, &filtered_emulators, &list, builtin, old);
+	assert_int_equal(rv, SC_SUCCESS);
+	for (i = 0; builtin[i].name; i++) {
+		assert_ptr_equal(&builtin[i], filtered_emulators.list_of_handlers[i]);
+	}
+	assert_int_equal(filtered_emulators.ccount, 2);
+	assert_null(filtered_emulators.list_of_handlers[2]);
+	assert_null(builtin[i].name);
+}
+
+static void torture_old_only(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int i, rv;
+	scconf_list list =  { NULL, "old" };
+	filtered_emulators.ccount = 0;
+
+	rv = set_emulators(NULL, &filtered_emulators, &list, builtin, old);
+	assert_int_equal(rv, SC_SUCCESS);
+	for (i = 0; old[i].name; i++) {
+		assert_ptr_equal(&old[i], filtered_emulators.list_of_handlers[i]);
+	}
+	assert_null(filtered_emulators.list_of_handlers[i]);
+	assert_null(old[i].name);
+}
+
+static void torture_internal_name(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int rv;
+	scconf_list list =  { NULL, strdup(builtin[0].name) };
+	filtered_emulators.ccount = 0;
+
+	rv = set_emulators(NULL, &filtered_emulators, &list, builtin, old);
+	assert_int_equal(rv, SC_SUCCESS);
+	assert_ptr_equal(&builtin[0], filtered_emulators.list_of_handlers[0]);
+	assert_null(filtered_emulators.list_of_handlers[1]);
+}
+
+static void torture_old_name(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int rv;
+	scconf_list list =  { NULL, strdup(old[0].name) };
+	filtered_emulators.ccount = 0;
+
+	rv = set_emulators(NULL, &filtered_emulators, &list, builtin, old);
+	assert_int_equal(rv, SC_SUCCESS);
+	assert_ptr_equal(&old[0], filtered_emulators.list_of_handlers[0]);
+	assert_null(filtered_emulators.list_of_handlers[1]);
+}
+
+static void torture_internal_and_name(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int i, rv;
+	scconf_list list2 =  { NULL, "cardos" };
+	scconf_list list1 =  { &list2, "internal" };
+	filtered_emulators.ccount = 0;
+
+	rv = set_emulators(NULL, &filtered_emulators, &list1, builtin, old);
+	assert_int_equal(rv, SC_SUCCESS);
+	for (i = 0; builtin[i].name; i++) {
+		assert_ptr_equal(&builtin[i], filtered_emulators.list_of_handlers[i]);
+	}
+	assert_ptr_equal(&old[1], filtered_emulators.list_of_handlers[i]);
+	assert_null(filtered_emulators.list_of_handlers[i + 1]);
+}
+
+static void torture_name_and_internal(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int rv;
+	scconf_list list2 =  { NULL, "internal" };
+	scconf_list list1 =  { &list2, "starcert" };
+	filtered_emulators.ccount = 0;
+
+	rv = set_emulators(NULL, &filtered_emulators, &list1, builtin, old);
+	assert_int_equal(rv, SC_SUCCESS);
+	assert_ptr_equal(&builtin[1], filtered_emulators.list_of_handlers[0]);
+	assert_ptr_equal(&builtin[0], filtered_emulators.list_of_handlers[1]);
+	assert_null(filtered_emulators.list_of_handlers[2]);
+}
+
+static void torture_internal_and_nonexisting(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int i, rv;;
+	scconf_list list2 =  { NULL, "non" };
+	scconf_list list1 =  { &list2, "internal" };
+	filtered_emulators.ccount = 0;
+
+	rv = set_emulators(NULL, &filtered_emulators, &list1, builtin, old);
+	assert_int_equal(rv, SC_SUCCESS);
+	for (i = 0; builtin[i].name; i++) {
+		assert_ptr_equal(&builtin[i], filtered_emulators.list_of_handlers[i]);
+	}
+	assert_null(filtered_emulators.list_of_handlers[i]);
+	assert_null(builtin[i].name);
+}
+
+static void torture_nonexisting_and_internal(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int i, rv;
+	scconf_list list2 =  { NULL, "internal" };
+	scconf_list list1 =  { &list2, "non" };
+	filtered_emulators.ccount = 0;
+
+	rv = set_emulators(NULL, &filtered_emulators, &list1, builtin, old);
+	assert_int_equal(rv, SC_SUCCESS);
+	for (i = 0; builtin[i].name; i++) {
+		assert_ptr_equal(&builtin[i], filtered_emulators.list_of_handlers[i]);
+	}
+	assert_null(filtered_emulators.list_of_handlers[i]);
+	assert_null(builtin[i].name);
+}
+
+static void torture_null_set_emul(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators = { { &builtin[0] }, 1 };
+	int rv;
+	scconf_list list1 = { NULL, "internal" };
+
+	rv = set_emulators(NULL, NULL, &list1, builtin, old);
+	assert_int_equal(rv, SC_ERROR_INVALID_ARGUMENTS);
+	rv = set_emulators(NULL, &filtered_emulators, NULL, builtin, old);
+	assert_int_equal(rv, SC_ERROR_INVALID_ARGUMENTS);
+	rv = set_emulators(NULL, &filtered_emulators, &list1, NULL, old);
+	assert_int_equal(rv, SC_ERROR_INVALID_ARGUMENTS);
+	rv = set_emulators(NULL, &filtered_emulators, &list1, builtin, NULL);
+	assert_int_equal(rv, SC_ERROR_INVALID_ARGUMENTS);
+}
+
+static void torture_full_set_emul(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int i, rv;
+	filtered_emulators.ccount = SC_MAX_PKCS15_EMULATORS;
+	scconf_list list1 = { NULL, "old" };
+	for (i = 0; i < SC_MAX_PKCS15_EMULATORS; i++) {
+		filtered_emulators.list_of_handlers[i] = &builtin[0];
+	}
+
+	rv = set_emulators(NULL, &filtered_emulators, &list1, builtin, old);
+	assert_int_equal(rv, SC_ERROR_TOO_MANY_OBJECTS);
+	assert_non_null(filtered_emulators.list_of_handlers[SC_MAX_PKCS15_EMULATORS - 1]);
+	assert_null(filtered_emulators.list_of_handlers[SC_MAX_PKCS15_EMULATORS]);
+	assert_int_equal(filtered_emulators.ccount, SC_MAX_PKCS15_EMULATORS);
+}
+
+static void torture_one_to_full_set_emul(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int i, rv;
+	filtered_emulators.ccount = SC_MAX_PKCS15_EMULATORS - 1;
+	scconf_list list1 = { NULL, "old" };
+	for (i = 0; i < SC_MAX_PKCS15_EMULATORS - 1; i++) {
+		filtered_emulators.list_of_handlers[i] = &builtin[0];
+	}
+
+	rv = set_emulators(NULL, &filtered_emulators, &list1, builtin, old);
+	assert_int_equal(rv, SC_ERROR_TOO_MANY_OBJECTS);
+	assert_ptr_equal(filtered_emulators.list_of_handlers[SC_MAX_PKCS15_EMULATORS - 1], &old[0]);
+	assert_null(filtered_emulators.list_of_handlers[SC_MAX_PKCS15_EMULATORS]);
+	assert_int_equal(filtered_emulators.ccount, SC_MAX_PKCS15_EMULATORS);
+}
+
+static void torture_one_to_full2_set_emul(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int i, rv;
+	filtered_emulators.ccount = SC_MAX_PKCS15_EMULATORS - 1;
+	scconf_list list1 = { NULL, strdup(old[1].name) };
+	for (i = 0; i < SC_MAX_PKCS15_EMULATORS - 1; i++) {
+		filtered_emulators.list_of_handlers[i] = &builtin[0];
+	}
+
+	rv = set_emulators(NULL, &filtered_emulators, &list1, builtin, old);
+	assert_int_equal(rv, SC_SUCCESS);
+	assert_ptr_equal(filtered_emulators.list_of_handlers[SC_MAX_PKCS15_EMULATORS - 1], &old[1]);
+	assert_null(filtered_emulators.list_of_handlers[SC_MAX_PKCS15_EMULATORS]);
+	assert_int_equal(filtered_emulators.ccount, SC_MAX_PKCS15_EMULATORS);
+}
+
+static void torture_overfilled_set_emul(void **state)
+{
+	struct _sc_pkcs15_emulators filtered_emulators;
+	int i, rv;
+	filtered_emulators.ccount = SC_MAX_PKCS15_EMULATORS + 1;
+	scconf_list list1 = { NULL, strdup(old[1].name) };
+	for (i = 0; i < SC_MAX_PKCS15_EMULATORS + 1; i++) {
+		filtered_emulators.list_of_handlers[i] = &builtin[0];
+	}
+
+	rv = set_emulators(NULL, &filtered_emulators, &list1, builtin, old);
+	assert_int_equal(rv, SC_ERROR_INVALID_ARGUMENTS);
+}
+
+int main(void)
+{
+	const struct CMUnitTest tests[] = {
+		/* add_emul */
+		cmocka_unit_test(torture_null_add_emul),
+		cmocka_unit_test(torture_name_add_emul),
+		cmocka_unit_test(torture_name_already_in_add_emul),
+		cmocka_unit_test(torture_full_add_emul),
+		cmocka_unit_test(torture_overfilled_add_emul),
+		cmocka_unit_test(torture_invalid_handler_name_add_emul),
+		cmocka_unit_test(torture_invalid_handler_func_add_emul),
+		cmocka_unit_test(torture_invalid_emulator_list_add_emul),
+		/* add_emul_list */
+		cmocka_unit_test(torture_null_add_emul_list),
+		cmocka_unit_test(torture_internal_add_emul_list),
+		cmocka_unit_test(torture_internal_already_name_add_emul_list),
+		cmocka_unit_test(torture_internal_already_name2_add_emul_list),
+		cmocka_unit_test(torture_full_add_emul_list),
+		cmocka_unit_test(torture_one_to_full_add_emul_list),
+		cmocka_unit_test(torture_overfilled_add_emul_list),
+		/* set_emulators */
+		cmocka_unit_test(torture_non_existing),
+		cmocka_unit_test(torture_internal_only),
+		cmocka_unit_test(torture_old_only),
+		cmocka_unit_test(torture_internal_name),
+		cmocka_unit_test(torture_old_name),
+		cmocka_unit_test(torture_internal_and_name),
+		cmocka_unit_test(torture_name_and_internal),
+		cmocka_unit_test(torture_internal_and_nonexisting),
+		cmocka_unit_test(torture_nonexisting_and_internal),
+		cmocka_unit_test(torture_null_set_emul),
+		cmocka_unit_test(torture_full_set_emul),
+		cmocka_unit_test(torture_one_to_full_set_emul),
+		cmocka_unit_test(torture_one_to_full2_set_emul),
+		cmocka_unit_test(torture_overfilled_set_emul),
+	};
+	return cmocka_run_group_tests(tests, NULL, NULL);
+}
diff -Nru opensc-0.22.0/src/tools/cardos-tool.c opensc-0.23.0/src/tools/cardos-tool.c
--- opensc-0.22.0/src/tools/cardos-tool.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/cardos-tool.c	2022-11-29 09:34:43.000000000 +0100
@@ -36,12 +36,20 @@
 #ifdef ENABLE_OPENSSL
 #include <openssl/des.h>
 #include <openssl/sha.h>
+#include <openssl/evp.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+#include <openssl/provider.h>
+#endif
 #endif
 
 #include "libopensc/opensc.h"
 #include "libopensc/cards.h"
 #include "util.h"
 
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	static OSSL_PROVIDER *legacy_provider = NULL;
+#endif
+
 static const char *app_name = "cardos-tool";
 
 static int opt_wait = 0;
@@ -68,7 +76,7 @@
 	"Change Startkey with given APDU command",
 	"Uses reader number <arg> [0]",
 	"Wait for a card to be inserted",
-	"Verbose operation. Use several times to enable debug output.",
+	"Verbose operation, may be used several times",
 };
 
 static sc_context_t *ctx = NULL;
@@ -393,9 +401,11 @@
 	int plain_lc;	/* data size in orig APDU */
 	unsigned int mac_input_len, enc_input_len;
 	unsigned char *mac_input, *enc_input;
-	DES_key_schedule ks_a, ks_b;
-	DES_cblock des_in,des_out;
+	unsigned char des_in[8], des_out[8];
 	unsigned int i,j;
+	EVP_CIPHER_CTX *cctx = NULL;
+	int tmplen = 0;
+	unsigned char key1[8], key2[8]; 
 
 	if (keylen != 16) {
 		printf("key has wrong size, need 16 bytes, got %"SC_FORMAT_LEN_SIZE_T"d. aborting.\n",
@@ -427,27 +437,99 @@
 		memcpy(&mac_input[4],&in[5],plain_lc);
 	/* calloc already did the ansi padding: rest is 00 */
 
-	/* prepare des key using first 8 bytes of key */
-	DES_set_key((const_DES_cblock*) &key[0], &ks_a);
-	/* prepare des key using second 8 bytes of key */
-	DES_set_key((const_DES_cblock*) &key[8], &ks_b);
+	/* prepare des ctx */
+	memcpy(key1, key, 8);
+	memcpy(key2, key + 8, 8);
+	
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	if (!legacy_provider) {
+		if (!(legacy_provider = OSSL_PROVIDER_try_load(NULL, "legacy", 1))) {
+			printf("Failed to load legacy provider, aborting\n");
+			free(mac_input);
+			return 0;
+		}
+	}
+#endif
 
+	cctx = EVP_CIPHER_CTX_new();
+	if (!cctx ||
+		!EVP_EncryptInit_ex(cctx, EVP_des_ecb(), NULL, key1, NULL) ||
+		!EVP_CIPHER_CTX_set_padding(cctx, 0)) {
+		printf("Can not setup context, aborting\n");
+		free(mac_input);
+		EVP_CIPHER_CTX_free(cctx);
+		return 0;
+	}
+    
 	/* first block: XOR with IV and encrypt with key A IV is 8 bytes 00 */
 	for (i=0; i < 8; i++) des_in[i] = mac_input[i]^00;
-	DES_ecb_encrypt(&des_in, &des_out, &ks_a, 1);
+	if (!EVP_EncryptUpdate(cctx, des_out, &tmplen, des_in, 8)) {
+		printf("Can not setup context, aborting\n");
+		free(mac_input);
+		EVP_CIPHER_CTX_free(cctx);
+		return 0;
+	}
 
 	/* all other blocks: XOR with prev. result and encrypt with key A */
 	for (j=1; j < (mac_input_len / 8); j++) {
 		for (i=0; i < 8; i++) des_in[i] = mac_input[i+j*8]^des_out[i];
-		DES_ecb_encrypt(&des_in, &des_out, &ks_a, 1);
+		if (!EVP_EncryptUpdate(cctx, des_out, &tmplen, des_in, 8)) {
+			printf("Can not encrypt, aborting\n");
+			free(mac_input);
+			EVP_CIPHER_CTX_free(cctx);
+			return 0;
+		}
+	}
+	if (!EVP_EncryptFinal_ex(cctx, des_out + tmplen, &tmplen)) {
+		printf("Can not encrypt, aborting\n");
+		free(mac_input);
+		EVP_CIPHER_CTX_free(cctx);
+		return 0;
 	}
 
 	/* now decrypt with key B and encrypt with key A again */
 	/* (a noop if key A and B are the same, e.g. 8 bytes ff */
+	if (!EVP_DecryptInit_ex(cctx, EVP_des_ecb(), NULL, key2, NULL) ||
+		!EVP_CIPHER_CTX_set_padding(cctx, 0)) {
+		printf("Can not setup context, aborting\n");
+		free(mac_input);
+		EVP_CIPHER_CTX_free(cctx);
+		return 0;
+	}
 	for (i=0; i < 8; i++) des_in[i] = des_out[i];
-	DES_ecb_encrypt(&des_in, &des_out, &ks_b, 0);
+	if (!EVP_DecryptUpdate(cctx, des_out, &tmplen, des_in, 8)) {
+		printf("Can not setup context, aborting\n");
+		free(mac_input);
+		EVP_CIPHER_CTX_free(cctx);
+		return 0;
+	}
+	if (!EVP_EncryptFinal_ex(cctx, des_out + tmplen, &tmplen)) {
+		printf("Can not encrypt, aborting\n");
+		free(mac_input);
+		EVP_CIPHER_CTX_free(cctx);
+		return 0;
+	}
+
+	if (!EVP_EncryptInit_ex(cctx, EVP_des_ecb(), NULL, key1, NULL) ||
+		!EVP_CIPHER_CTX_set_padding(cctx, 0)) {
+		printf("Can not setup context, aborting\n");
+		free(mac_input);
+		EVP_CIPHER_CTX_free(cctx);
+		return 0;
+	}
 	for (i=0; i < 8; i++) des_in[i] = des_out[i];
-	DES_ecb_encrypt(&des_in, &des_out, &ks_a, 1);
+	if (!EVP_EncryptUpdate(cctx, des_out, &tmplen, des_in, 8)) {
+		printf("Can not encrypt, aborting\n");
+		free(mac_input);
+		EVP_CIPHER_CTX_free(cctx);
+		return 0;
+	}
+	if (!EVP_EncryptFinal_ex(cctx, des_out + tmplen, &tmplen)) {
+		printf("Can not encrypt, aborting\n");
+		free(mac_input);
+		EVP_CIPHER_CTX_free(cctx);
+		return 0;
+	}
 
 	/* now we want to enc:
  	 * orig APDU data plus mac (8 bytes) plus iso padding (1-8 bytes) */
@@ -480,12 +562,28 @@
 	out[4] = enc_input_len;	/* lc */
 
 	/* encrypt first block */
+	cctx = EVP_CIPHER_CTX_new();
+	if (!cctx ||
+		!EVP_EncryptInit_ex(cctx, EVP_des_ede_ecb(), NULL, key, NULL) ||
+		!EVP_CIPHER_CTX_set_padding(cctx, 0)) {
+		printf("Can not setup context, aborting\n");
+		free(mac_input);
+		free(enc_input);
+		EVP_CIPHER_CTX_free(cctx);
+		return 0;
+	}
 
 	/* xor data and IV (8 bytes 00) to get input data */
 	for (i=0; i < 8; i++) des_in[i] = enc_input[i] ^ 00;
 
 	/* encrypt with des2 (triple des, but using keys A-B-A) */
-	DES_ecb2_encrypt(&des_in, &des_out, &ks_a, &ks_b, 1);
+	if (!EVP_EncryptUpdate(cctx, des_out, &tmplen, des_in, 8)) {
+		printf("Can not encrypt, aborting\n");
+		free(mac_input);
+		free(enc_input);
+		EVP_CIPHER_CTX_free(cctx);
+		return 0;
+	}
 
 	/* copy encrypted bytes into output */
 	for (i=0; i < 8; i++) out[5+i] = des_out[i];
@@ -496,11 +594,19 @@
 		for (i=0; i < 8; i++) des_in[i] = enc_input[i+j*8] ^ des_out[i];
 
 		/* encrypt with des2 (triple des, but using keys A-B-A) */
-		DES_ecb2_encrypt(&des_in, &des_out, &ks_a, &ks_b, 1);
+		if (!EVP_EncryptUpdate(cctx, des_out, &tmplen, des_in, 8)) {
+			printf("Can not encrypt, aborting\n");
+			free(mac_input);
+			free(enc_input);
+			EVP_CIPHER_CTX_free(cctx);
+			return 0;
+		}
 
 		/* copy encrypted bytes into output */
 		for (i=0; i < 8; i++) out[5+8*j+i] = des_out[i];
 	}
+	
+	EVP_CIPHER_CTX_free(cctx);
 	if (verbose)	{
 		printf ("Unencrypted APDU:\n");
 		util_hex_dump_asc(stdout, in, inlen, -1);
diff -Nru opensc-0.22.0/src/tools/cryptoflex-tool.c opensc-0.23.0/src/tools/cryptoflex-tool.c
--- opensc-0.22.0/src/tools/cryptoflex-tool.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/cryptoflex-tool.c	2022-11-29 09:34:43.000000000 +0100
@@ -27,6 +27,12 @@
 #include <openssl/x509.h>
 #include <openssl/pem.h>
 #include <openssl/err.h>
+#include <openssl/evp.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+# include <openssl/param_build.h>
+# include <openssl/params.h>
+# include <openssl/decoder.h>
+#endif
 
 #include "libopensc/pkcs15.h"
 #include "common/compat_strlcpy.h"
@@ -82,7 +88,7 @@
 	"Modulus length to use in key generation [1024]",
 	"Uses reader <arg>",
 	"Wait for card insertion",
-	"Verbose operation. Use several times to enable debug output.",
+	"Verbose operation, may be used several times",
 };
 
 static sc_context_t *ctx = NULL;
@@ -196,12 +202,18 @@
 	return r;
 }
 
-static int parse_public_key(const u8 *key, size_t keysize, RSA *rsa)
+static int parse_public_key(const u8 *key, size_t keysize, EVP_PKEY *pkey)
 {
 	const u8 *p = key;
 	BIGNUM *n, *e;
 	int base;
-
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	RSA *rsa = NULL;
+#else
+	EVP_PKEY_CTX *ctx = NULL;
+	OSSL_PARAM *params = NULL;
+	OSSL_PARAM_BLD *bld = NULL;
+#endif
 	base = (keysize - 7) / 5;
 	if (base != 32 && base != 48 && base != 64 && base != 128) {
 		fprintf(stderr, "Invalid public key.\n");
@@ -219,17 +231,44 @@
 	if (e == NULL)
 		return -1;
 	cf2bn(p, 4, e);
-	if (RSA_set0_key(rsa, n, e, NULL) != 1)
-	    return -1;
+	
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	if (!(rsa = RSA_new()) || 
+		!(pkey = EVP_PKEY_new()) || 
+		RSA_set0_key(rsa, n, e, NULL) != 1 || 
+		EVP_PKEY_assign_RSA(pkey, rsa) != 1) {
+		RSA_free(rsa);
+		EVP_PKEY_free(pkey);
+		return -1;
+	}
+#else
+	ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
+	if (!ctx || 
+		!(bld = OSSL_PARAM_BLD_new()) || 
+		OSSL_PARAM_BLD_push_BN(bld, "n", n) != 1 || 
+		OSSL_PARAM_BLD_push_BN(bld, "e", e) != 1 || 
+		!(params = OSSL_PARAM_BLD_to_param(bld))) {
+		OSSL_PARAM_BLD_free(bld);
+		EVP_PKEY_CTX_free(ctx);
+		OSSL_PARAM_free(params);
+		return -1;
+	}
+	OSSL_PARAM_BLD_free(bld);
+
+	if (EVP_PKEY_fromdata_init(ctx) != 1 || 
+		EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) != 1) {
+		return -1;;
+	}
+	OSSL_PARAM_free(params);
+	EVP_PKEY_CTX_free(ctx);
+#endif
 	return 0;
 }
 
-static int gen_d(RSA *rsa)
+static int gen_d(BIGNUM **rsa_d_new, const BIGNUM *rsa_p, const BIGNUM *rsa_q, const BIGNUM *rsa_n, const BIGNUM *rsa_e)
 {
 	BN_CTX *bnctx;
 	BIGNUM *r0, *r1, *r2;
-	const BIGNUM *rsa_p, *rsa_q, *rsa_n, *rsa_e, *rsa_d;
-	BIGNUM *rsa_n_new, *rsa_e_new, *rsa_d_new;
 
 	bnctx = BN_CTX_new();
 	if (bnctx == NULL)
@@ -238,35 +277,40 @@
 	r0 = BN_CTX_get(bnctx);
 	r1 = BN_CTX_get(bnctx);
 	r2 = BN_CTX_get(bnctx);
-	RSA_get0_key(rsa, &rsa_n, &rsa_e, &rsa_d);
-	RSA_get0_factors(rsa, &rsa_p, &rsa_q);
 
 	BN_sub(r1, rsa_p, BN_value_one());
 	BN_sub(r2, rsa_q, BN_value_one());
 	BN_mul(r0, r1, r2, bnctx);
-	if ((rsa_d_new = BN_mod_inverse(NULL, rsa_e, r0, bnctx)) == NULL) {
+	if ((*rsa_d_new = BN_mod_inverse(NULL, rsa_e, r0, bnctx)) == NULL) {
 		fprintf(stderr, "BN_mod_inverse() failed.\n");
 		return -1;
 	}
 
-	/* RSA_set0_key will free previous value, and replace with new value
-	 * Thus the need to copy the contents of rsa_n and rsa_e
-	 */
-	rsa_n_new = BN_dup(rsa_n);
-	rsa_e_new = BN_dup(rsa_e);
-	if (RSA_set0_key(rsa, rsa_n_new, rsa_e_new, rsa_d_new) != 1)
-		return -1;
-
 	BN_CTX_end(bnctx);
 	BN_CTX_free(bnctx);
 	return 0;
 }
 
-static int parse_private_key(const u8 *key, size_t keysize, RSA *rsa)
+static int parse_private_key(const u8 *key, size_t keysize, EVP_PKEY *pkey)
 {
 	const u8 *p = key;
 	BIGNUM *bn_p, *q, *dmp1, *dmq1, *iqmp;
 	int base;
+	BIGNUM *rsa_d = NULL;
+	int rv = 0;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	const BIGNUM *rsa_n, *rsa_e;
+	BIGNUM *rsa_n_new, *rsa_e_new ;
+	RSA *rsa = NULL;
+	if (!(rsa = EVP_PKEY_get0_RSA(pkey)))
+		return -1;
+#else
+	OSSL_PARAM *params = NULL, *pkey_params = NULL, *new_params = NULL;
+	const OSSL_PARAM *e = NULL, *n = NULL;
+	BIGNUM *rsa_n, *rsa_e;
+	OSSL_PARAM_BLD *bld = NULL;
+	EVP_PKEY_CTX *ctx = NULL;
+#endif
 
 	base = (keysize - 3) / 5;
 	if (base != 32 && base != 48 && base != 64 && base != 128) {
@@ -302,18 +346,69 @@
 	if (dmq1 == NULL)
 		return -1;
 	cf2bn(p, base, dmq1);
-	
-	if (RSA_set0_factors(rsa, bn_p, q) != 1)
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
+
+	if (RSA_set0_factors(rsa, bn_p, q) != 1 || 
+		RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp) != 1 || 
+		gen_d(&rsa_d, bn_p, q, rsa_n, rsa_e) != 0)
 		return -1;
-	if (RSA_set0_crt_params(rsa, dmp1, dmq1, iqmp) != 1)
+
+	/* RSA_set0_key will free previous value, and replace with new value
+	 * Thus the need to copy the contents of rsa_n and rsa_e
+	 */
+	rsa_n_new = BN_dup(rsa_n);
+	rsa_e_new = BN_dup(rsa_e);
+	if (RSA_set0_key(rsa, rsa_n_new, rsa_e_new, rsa_d) != 1)
 		return -1;
-	if (gen_d(rsa))
+#else
+	/* Extract parameters from pkey */
+	if (EVP_PKEY_todata(pkey, EVP_PKEY_PUBLIC_KEY, &pkey_params) != 1) {
+		return -1;
+	 }
+	e = OSSL_PARAM_locate_const(pkey_params, "e");
+	n = OSSL_PARAM_locate_const(pkey_params, "n");
+	if (!e ||  !n) {
+		OSSL_PARAM_free(pkey_params);
+		return -1;
+	}
+	OSSL_PARAM_get_BN(e, &rsa_e);
+	OSSL_PARAM_get_BN(n, &rsa_n);
+	gen_d(&rsa_d, bn_p, q, rsa_n, rsa_e);
+	/* Merge params*/
+	if (!(bld = OSSL_PARAM_BLD_new()) || 
+		OSSL_PARAM_BLD_push_BN(bld, "d", rsa_d) != 1 || 
+		OSSL_PARAM_BLD_push_BN(bld, "rsa-factor1", bn_p) != 1 || 
+		OSSL_PARAM_BLD_push_BN(bld, "rsa-factor2", q) != 1 || 
+		OSSL_PARAM_BLD_push_BN(bld, "rsa-exponent1", dmp1) != 1 || 
+		OSSL_PARAM_BLD_push_BN(bld, "rsa-exponent2", dmq1) != 1 || 
+		OSSL_PARAM_BLD_push_BN(bld, "rsa-coefficient1", iqmp) != 1 || 
+		!(new_params = OSSL_PARAM_BLD_to_param(bld))) {
+		OSSL_PARAM_free(pkey_params);
+		OSSL_PARAM_BLD_free(bld);
+		return -1;
+	}
+	OSSL_PARAM_BLD_free(bld);
+	if (!(params = OSSL_PARAM_merge(pkey_params, new_params))) {
+		OSSL_PARAM_free(pkey_params);
+		OSSL_PARAM_free(new_params);
 		return -1;
+	}
 
-	return 0;
+	/* Create pkey from params */
+	if (!(ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)) || 
+		EVP_PKEY_fromdata_init(ctx) != 1 || 
+		EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_KEYPAIR, params) != 1)
+		rv = -1;
+	OSSL_PARAM_free(pkey_params);
+	OSSL_PARAM_free(new_params);
+	EVP_PKEY_CTX_free(ctx);
+#endif
+	return rv;
 }
 
-static int read_public_key(RSA *rsa)
+static int read_public_key(EVP_PKEY *pkey)
 {
 	int r;
 	sc_path_t path;
@@ -355,11 +450,11 @@
 		printf("Key number %d not found.\n", opt_key_num);
 		return 2;
 	}
-	return parse_public_key(p, keysize, rsa);
+	return parse_public_key(p, keysize, pkey);
 }
 
 
-static int read_private_key(RSA *rsa)
+static int read_private_key(EVP_PKEY *pkey)
 {
 	int r;
 	sc_path_t path;
@@ -406,22 +501,21 @@
 		printf("Key number %d not found.\n", opt_key_num);
 		return 2;
 	}
-	return parse_private_key(p, keysize, rsa);
+	return parse_private_key(p, keysize, pkey);
 }
 
 static int read_key(void)
 {
-	RSA *rsa = RSA_new();
+	EVP_PKEY *pkey = NULL;
 	u8 buf[1024], *p = buf;
 	u8 b64buf[2048];
 	int r;
 
-	if (rsa == NULL)
-		return -1;
-	r = read_public_key(rsa);
+	r = read_public_key(pkey);
 	if (r)
 		return r;
-	r = i2d_RSA_PUBKEY(rsa, &p);
+
+	r = i2d_PUBKEY(pkey, &p);
 	if (r <= 0) {
 		fprintf(stderr, "Error encoding public key.\n");
 		return -1;
@@ -433,13 +527,13 @@
 	}
 	printf("-----BEGIN PUBLIC KEY-----\n%s-----END PUBLIC KEY-----\n", b64buf);
 
-	r = read_private_key(rsa);
+	r = read_private_key(pkey);
 	if (r == 10)
 		return 0;
 	else if (r)
 		return r;
 	p = buf;
-	r = i2d_RSAPrivateKey(rsa, &p);
+	r = i2d_PrivateKey(pkey, &p);
 	if (r <= 0) {
 		fprintf(stderr, "Error encoding private key.\n");
 		return -1;
@@ -630,11 +724,17 @@
 	return 0;
 }
 
-static int read_rsa_privkey(RSA **rsa_out)
+static int read_rsa_privkey(EVP_PKEY **pkey_out)
 {
-	RSA *rsa = NULL;
+	EVP_PKEY *pkey = NULL;
 	BIO *in = NULL;
 	int r;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	RSA *rsa = NULL;
+	pkey = EVP_PKEY_new();
+#else
+	OSSL_DECODER_CTX *dctx;
+#endif
 
 	in = BIO_new(BIO_s_file());
 	if (opt_prkeyf == NULL) {
@@ -646,25 +746,37 @@
 		perror(opt_prkeyf);
 		return 2;
 	}
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 	rsa = PEM_read_bio_RSAPrivateKey(in, NULL, NULL, NULL);
 	if (rsa == NULL) {
 		fprintf(stderr, "Unable to load private key.\n");
 		return 2;
 	}
+	EVP_PKEY_assign_RSA(pkey, rsa);
+#else
+	dctx = OSSL_DECODER_CTX_new_for_pkey(&pkey, "PEM", NULL, "RSA", OSSL_KEYMGMT_SELECT_KEYPAIR, NULL, NULL);
+	OSSL_DECODER_from_bio(dctx, in);
+#endif
 	BIO_free(in);
-	*rsa_out = rsa;
+	*pkey_out = pkey;
 	return 0;
 }
 
-static int encode_private_key(RSA *rsa, u8 *key, size_t *keysize)
+static int encode_private_key(EVP_PKEY *pkey, u8 *key, size_t *keysize)
 {
 	u8 buf[1024], *p = buf;
 	u8 bnbuf[256];
 	int base = 0;
 	int r;
+	int rv = 0;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 	const BIGNUM *rsa_p, *rsa_q, *rsa_dmp1, *rsa_dmq1, *rsa_iqmp;
+	RSA *rsa = EVP_PKEY_get1_RSA(pkey);
+#else
+	BIGNUM *rsa_p = NULL, *rsa_q = NULL, *rsa_dmp1 = NULL, *rsa_dmq1 = NULL, *rsa_iqmp = NULL;
+#endif
 
-	switch (RSA_bits(rsa)) {
+	switch (EVP_PKEY_bits(pkey)) {
 	case 512:
 		base = 32;
 		break;
@@ -686,12 +798,22 @@
 	*p++ = (5 * base + 3) & 0xFF;
 	*p++ = opt_key_num;
 
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 	RSA_get0_factors(rsa, &rsa_p, &rsa_q);
+#else
+	if (EVP_PKEY_get_bn_param(pkey, "rsa-factor1", &rsa_p) != 1 || 
+		EVP_PKEY_get_bn_param(pkey, "rsa-factor2", &rsa_q) != 1) {
+		fprintf(stderr, "Invalid private key.\n");
+		rv = 2;
+		goto end;
+	}
+#endif
 
 	r = bn2cf(rsa_p, bnbuf);
 	if (r != base) {
 		fprintf(stderr, "Invalid private key.\n");
-		return 2;
+		rv = 2;
+		goto end;
 	}
 	memcpy(p, bnbuf, base);
 	p += base;
@@ -699,17 +821,28 @@
 	r = bn2cf(rsa_q, bnbuf);
 	if (r != base) {
 		fprintf(stderr, "Invalid private key.\n");
-		return 2;
+		rv = 2;
+		goto end;
 	}
 	memcpy(p, bnbuf, base);
 	p += base;
 
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 	RSA_get0_crt_params(rsa, &rsa_dmp1, &rsa_dmq1, &rsa_iqmp);
-
+#else
+	if (EVP_PKEY_get_bn_param(pkey, "rsa-exponent1", &rsa_dmp1) != 1 || 
+		EVP_PKEY_get_bn_param(pkey, "rsa-exponent2", &rsa_dmq1) != 1 || 
+		EVP_PKEY_get_bn_param(pkey, "rsa-coefficient1", &rsa_iqmp) != 1) {
+		fprintf(stderr, "Invalid private key.\n");
+		rv = 2;
+		goto end;
+	}
+#endif
 	r = bn2cf(rsa_iqmp, bnbuf);
 	if (r != base) {
 		fprintf(stderr, "Invalid private key.\n");
-		return 2;
+		rv = 2;
+		goto end;
 	}
 	memcpy(p, bnbuf, base);
 	p += base;
@@ -717,7 +850,8 @@
 	r = bn2cf(rsa_dmp1, bnbuf);
 	if (r != base) {
 		fprintf(stderr, "Invalid private key.\n");
-		return 2;
+		rv = 2;
+		goto end;
 	}
 	memcpy(p, bnbuf, base);
 	p += base;
@@ -725,7 +859,8 @@
 	r = bn2cf(rsa_dmq1, bnbuf);
 	if (r != base) {
 		fprintf(stderr, "Invalid private key.\n");
-		return 2;
+		rv = 2;
+		goto end;
 	}
 	memcpy(p, bnbuf, base);
 	p += base;
@@ -733,18 +868,34 @@
 	memcpy(key, buf, p - buf);
 	*keysize = p - buf;
 
-	return 0;
+end:
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	RSA_free(rsa);
+#else
+	BN_free(rsa_p);
+	BN_free(rsa_q);
+	BN_free(rsa_dmp1);
+	BN_free(rsa_dmq1);
+	BN_free(rsa_iqmp);
+#endif
+	return rv;
 }
 
-static int encode_public_key(RSA *rsa, u8 *key, size_t *keysize)
+static int encode_public_key(EVP_PKEY *pkey, u8 *key, size_t *keysize)
 {
 	u8 buf[1024], *p = buf;
 	u8 bnbuf[256];
 	int base = 0;
 	int r;
+	int rv = 0;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 	const BIGNUM *rsa_n, *rsa_e;
+	RSA *rsa = NULL;
+#else
+	BIGNUM *rsa_n = NULL, *rsa_e = NULL;
+#endif
 
-	switch (RSA_bits(rsa)) {
+	switch (EVP_PKEY_bits(pkey)) {
 	case 512:
 		base = 32;
 		break;
@@ -766,11 +917,21 @@
 	*p++ = (5 * base + 7) & 0xFF;
 	*p++ = opt_key_num;
 
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 	RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
+#else
+	if (EVP_PKEY_get_bn_param(pkey, "n", &rsa_n) != 1 || 
+		EVP_PKEY_get_bn_param(pkey, "e", &rsa_e) != 1) {
+		fprintf(stderr, "Invalid public key.\n");
+		rv = 2;
+		goto end;
+	}
+#endif
 	r = bn2cf(rsa_n, bnbuf);
 	if (r != 2*base) {
 		fprintf(stderr, "Invalid public key.\n");
-		return 2;
+		rv = 2;
+		goto end;
 	}
 	memcpy(p, bnbuf, 2*base);
 	p += 2*base;
@@ -784,15 +945,22 @@
 	r = bn2cf(rsa_e, bnbuf);
 	if (r != 4) {
 		fprintf(stderr, "Invalid exponent value.\n");
-		return 2;
+		rv = 2;
+		goto end;
 	}
 	memcpy(p, bnbuf, 4);
 	p += 4;
 
 	memcpy(key, buf, p - buf);
 	*keysize = p - buf;
-
-	return 0;
+end:
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	RSA_free(rsa);
+#else
+	BN_free(rsa_n);
+	BN_free(rsa_e);
+#endif
+	return rv;
 }
 
 static int update_public_key(const u8 *key, size_t keysize)
@@ -844,17 +1012,17 @@
 static int store_key(void)
 {
 	u8 prv[1024], pub[1024];
-	size_t prvsize, pubsize;
+	size_t prvsize = 0, pubsize = 0;
 	int r;
-	RSA *rsa;
+	EVP_PKEY *pkey = NULL;
 
-	r = read_rsa_privkey(&rsa);
+	r = read_rsa_privkey(&pkey);
 	if (r)
 		return r;
-	r = encode_private_key(rsa, prv, &prvsize);
+	r = encode_private_key(pkey, prv, &prvsize);
 	if (r)
 		return r;
-	r = encode_public_key(rsa, pub, &pubsize);
+	r = encode_public_key(pkey, pub, &pubsize);
 	if (r)
 		return r;
 	if (verbose)
diff -Nru opensc-0.22.0/src/tools/dnie-tool.c opensc-0.23.0/src/tools/dnie-tool.c
--- opensc-0.22.0/src/tools/dnie-tool.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/dnie-tool.c	2022-11-29 09:34:43.000000000 +0100
@@ -75,7 +75,7 @@
 	"Show DNIe number, Name, and SurName",
 	"Show DNIe serial number",
 	"Display all the information available",
-	"Verbose operation. Use several times to enable debug output."
+	"Verbose operation, may be used several times",
 };
 
 /*  Get DNIe device extra information  */
diff -Nru opensc-0.22.0/src/tools/gids-tool.c opensc-0.23.0/src/tools/gids-tool.c
--- opensc-0.22.0/src/tools/gids-tool.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/gids-tool.c	2022-11-29 09:34:43.000000000 +0100
@@ -87,7 +87,7 @@
 	"Define the new administrator key",
 	"Uses reader number <arg> [0]",
 	"Wait for a card to be inserted",
-	"Verbose operation. Use several times to enable debug output.",
+	"Verbose operation, may be used several times",
 };
 
 static int initialize(sc_card_t *card, const char *so_pin, const char *user_pin, const char* serial)
@@ -525,23 +525,7 @@
 		}
 	}
 
-
-	/* OpenSSL magic */
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
-	OPENSSL_config(NULL);
-#endif
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
-	OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS
-		| OPENSSL_INIT_ADD_ALL_CIPHERS
-		| OPENSSL_INIT_ADD_ALL_DIGESTS,
-               NULL);
-#else
 	/* OpenSSL magic */
-	OPENSSL_malloc_init();
-
-	ERR_load_crypto_strings();
-	OpenSSL_add_all_algorithms();
-#endif
 
 	memset(&ctx_param, 0, sizeof(sc_context_param_t));
 	ctx_param.app_name = app_name;
diff -Nru opensc-0.22.0/src/tools/goid-tool.c opensc-0.23.0/src/tools/goid-tool.c
--- opensc-0.22.0/src/tools/goid-tool.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/goid-tool.c	2022-11-29 09:34:43.000000000 +0100
@@ -598,9 +598,6 @@
             }
         }
 
-#ifdef ENABLE_OPENPACE
-        EAC_init();
-#endif
         SC_TEST_GOTO_ERR(ctx, SC_LOG_DEBUG_VERBOSE_TOOL,
                 perform_terminal_authentication(card,
                     (const unsigned char **) certs, certs_lens,
diff -Nru opensc-0.22.0/src/tools/iasecc-tool.c opensc-0.23.0/src/tools/iasecc-tool.c
--- opensc-0.22.0/src/tools/iasecc-tool.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/iasecc-tool.c	2022-11-29 09:34:43.000000000 +0100
@@ -68,7 +68,7 @@
 	"List the on-card PKCS#15 applications",
 	"List the SDOs with the <arg> tag in the current ADF",
 	"Wait for card insertion",
-	"Verbose operation. Use several times to enable debug output.",
+	"Verbose operation, may be used several times",
 	NULL
 };
 
diff -Nru opensc-0.22.0/src/tools/Makefile.am opensc-0.23.0/src/tools/Makefile.am
--- opensc-0.22.0/src/tools/Makefile.am	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/Makefile.am	2022-11-29 09:34:43.000000000 +0100
@@ -17,6 +17,7 @@
 	   -e 's,[@]PACKAGE_SUMMARY[@],$(PACKAGE_SUMMARY),g' \
 	   -e 's,[@]PACKAGE_VERSION[@],"$(PACKAGE_VERSION)",g' \
 	   -e 's,[@]DEFAULT_PKCS11_PROVIDER[@],"$(DEFAULT_PKCS11_PROVIDER)",g' \
+	   -e 's,[@]PKCS11_REGISTER_SKIP_FIREFOX[@],$(PKCS11_REGISTER_SKIP_FIREFOX),g' \
 	   -e 's,[@]VDFORMAT[@],$(VDFORMAT),g' \
 	   -e 's,[@]X509DIR[@],$(X509DIR),g'
 
@@ -25,18 +26,29 @@
 
 noinst_HEADERS = util.h fread_to_eof.h \
 	egk-tool-cmdline.h goid-tool-cmdline.h npa-tool-cmdline.h \
-	opensc-asn1-cmdline.h opensc-notify-cmdline.h pkcs11-register-cmdline.h
-noinst_PROGRAMS = sceac-example
-bin_PROGRAMS = opensc-tool opensc-explorer opensc-notify \
+	opensc-asn1-cmdline.h opensc-notify-cmdline.h pkcs11-register-cmdline.h \
+	openpgp-tool-helpers.h
+bin_PROGRAMS = opensc-tool opensc-explorer opensc-asn1 \
 	pkcs15-tool pkcs15-crypt pkcs11-tool pkcs11-register \
-	cardos-tool eidenv openpgp-tool iasecc-tool egk-tool opensc-asn1 goid-tool
+	cardos-tool eidenv openpgp-tool iasecc-tool egk-tool goid-tool
 if ENABLE_OPENSSL
 bin_PROGRAMS += cryptoflex-tool pkcs15-init netkey-tool piv-tool \
-	westcos-tool sc-hsm-tool dnie-tool gids-tool npa-tool
+	westcos-tool sc-hsm-tool dnie-tool gids-tool
+if ENABLE_OPENPACE
+bin_PROGRAMS += npa-tool
+endif
+endif
+
+if ENABLE_NOTIFY
+bin_PROGRAMS += opensc-notify
+endif
+
+if ENABLE_OPENPACE
+noinst_PROGRAMS = sceac-example
 endif
 
 # compile with $(PTHREAD_CFLAGS) to allow debugging with gdb
-AM_CFLAGS = $(OPTIONAL_OPENSSL_CFLAGS) $(OPTIONAL_READLINE_CFLAGS) $(PTHREAD_CFLAGS)
+AM_CFLAGS = $(OPTIONAL_OPENSSL_CFLAGS) $(OPTIONAL_READLINE_CFLAGS)
 AM_CPPFLAGS = -I$(top_srcdir)/src -D'DEFAULT_PKCS11_PROVIDER="$(DEFAULT_PKCS11_PROVIDER)"' -D'DEFAULT_ONEPIN_PKCS11_PROVIDER="$(DEFAULT_ONEPIN_PKCS11_PROVIDER)"'
 LIBS = \
 	$(top_builddir)/src/libopensc/libopensc.la \
@@ -58,7 +70,7 @@
 pkcs11_tool_CFLAGS = $(OPTIONAL_OPENSSL_CFLAGS) $(PTHREAD_CFLAGS)
 pkcs11_tool_LDADD = \
 	$(top_builddir)/src/common/libpkcs11.la \
-	$(OPTIONAL_OPENSSL_LIBS) $(PTHREAD_CFLAGS)
+	$(OPTIONAL_OPENSSL_LIBS)
 if ENABLE_SHARED
 else
 pkcs11_tool_LDADD += \
@@ -77,11 +89,11 @@
 netkey_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
 westcos_tool_SOURCES = westcos-tool.c util.c
 westcos_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
-openpgp_tool_SOURCES = openpgp-tool.c util.c
+openpgp_tool_SOURCES = openpgp-tool.c util.c openpgp-tool-helpers.c
 openpgp_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
 iasecc_tool_SOURCES = iasecc-tool.c util.c
 iasecc_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
-sc_hsm_tool_SOURCES = sc-hsm-tool.c util.c
+sc_hsm_tool_SOURCES = sc-hsm-tool.c util.c fread_to_eof.c
 sc_hsm_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
 dnie_tool_SOURCES = dnie-tool.c util.c
 dnie_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
@@ -89,53 +101,41 @@
 gids_tool_LDADD = $(OPTIONAL_OPENSSL_LIBS)
 
 npa_tool_SOURCES = npa-tool.c fread_to_eof.c util.c npa-tool-cmdline.c
-npa_tool_LDADD = $(top_builddir)/src/libopensc/libopensc.la \
-				 $(OPENPACE_LIBS)
-npa_tool_CFLAGS = -I$(top_srcdir)/src $(OPENPACE_CFLAGS) $(OPENSSL_CFLAGS)
-npa_tool_CFLAGS += -Wno-unused-but-set-variable
+npa_tool_LDADD = $(OPENPACE_LIBS)
+npa_tool_CFLAGS = $(OPENPACE_CFLAGS)
 if HAVE_UNKNOWN_WARNING_OPTION
 npa_tool_CFLAGS += -Wno-unknown-warning-option
 endif
 
 opensc_notify_SOURCES = opensc-notify.c opensc-notify-cmdline.c
-opensc_notify_LDADD = $(top_builddir)/src/libopensc/libopensc.la $(OPTIONAL_NOTIFY_LIBS)
-opensc_notify_CFLAGS = -I$(top_srcdir)/src $(PTHREAD_CFLAGS) $(OPTIONAL_NOTIFY_CFLAGS)
-opensc_notify_CFLAGS += -Wno-unused-but-set-variable
+opensc_notify_CFLAGS = $(PTHREAD_CFLAGS)
 if HAVE_UNKNOWN_WARNING_OPTION
 opensc_notify_CFLAGS += -Wno-unknown-warning-option
 endif
 
 egk_tool_SOURCES = egk-tool.c util.c egk-tool-cmdline.c
-egk_tool_LDADD = $(top_builddir)/src/libopensc/libopensc.la $(OPTIONAL_ZLIB_LIBS)
-egk_tool_CFLAGS = -I$(top_srcdir)/src $(OPTIONAL_ZLIB_CFLAGS)
-egk_tool_CFLAGS += -Wno-unused-but-set-variable
+egk_tool_LDADD = $(OPTIONAL_ZLIB_LIBS)
+egk_tool_CFLAGS = $(OPTIONAL_ZLIB_CFLAGS)
 if HAVE_UNKNOWN_WARNING_OPTION
 egk_tool_CFLAGS += -Wno-unknown-warning-option
 endif
 
 goid_tool_SOURCES = goid-tool.c util.c fread_to_eof.c goid-tool-cmdline.c
-goid_tool_LDADD = $(top_builddir)/src/libopensc/libopensc.la $(OPENPACE_LIBS)
-goid_tool_CFLAGS = -I$(top_srcdir)/src $(OPENPACE_CFLAGS)
-goid_tool_CFLAGS += -Wno-unused-but-set-variable
+goid_tool_LDADD = $(OPENPACE_LIBS)
+goid_tool_CFLAGS = $(OPENPACE_CFLAGS)
 if HAVE_UNKNOWN_WARNING_OPTION
 goid_tool_CFLAGS += -Wno-unknown-warning-option
 endif
 
 opensc_asn1_SOURCES = opensc-asn1.c fread_to_eof.c opensc-asn1-cmdline.c
-opensc_asn1_LDADD = $(top_builddir)/src/libopensc/libopensc.la $(OPTIONAL_ZLIB_LIBS)
-opensc_asn1_CFLAGS = -I$(top_srcdir)/src $(OPTIONAL_ZLIB_CFLAGS)
-opensc_asn1_CFLAGS += -Wno-unused-but-set-variable
 if HAVE_UNKNOWN_WARNING_OPTION
-opensc_asn1_CFLAGS += -Wno-unknown-warning-option
+opensc_asn1_CFLAGS = -Wno-unknown-warning-option
 endif
 
 pkcs11_register_SOURCES = pkcs11-register.c fread_to_eof.c pkcs11-register-cmdline.c
-pkcs11_register_CFLAGS = -I$(top_srcdir)/src
-pkcs11_register_CFLAGS += -Wno-unused-but-set-variable -Wno-unused-function
-pkcs11_register_LDADD = \
-	$(top_builddir)/src/common/libpkcs11.la
+pkcs11_register_LDADD =	$(top_builddir)/src/common/libpkcs11.la
 if HAVE_UNKNOWN_WARNING_OPTION
-pkcs11_register_CFLAGS += -Wno-unknown-warning-option
+pkcs11_register_CFLAGS = -Wno-unknown-warning-option
 endif
 
 .PHONY: cmdline
@@ -145,6 +145,7 @@
 	$(AM_V_GEN)$(GENGETOPT) --file-name=opensc-asn1-cmdline --output-dir=$(builddir) < opensc-asn1.ggo --unamed-opts
 
 if WIN32
+LIBS += -lshlwapi
 opensc_tool_SOURCES += versioninfo-tools.rc
 piv_tool_SOURCES += versioninfo-tools.rc
 opensc_explorer_SOURCES += versioninfo-tools.rc
diff -Nru opensc-0.22.0/src/tools/Makefile.mak opensc-0.23.0/src/tools/Makefile.mak
--- opensc-0.22.0/src/tools/Makefile.mak	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/Makefile.mak	2022-11-29 09:34:43.000000000 +0100
@@ -7,7 +7,7 @@
 TARGETS = opensc-tool.exe opensc-explorer.exe pkcs15-tool.exe pkcs15-crypt.exe \
 		pkcs11-tool.exe cardos-tool.exe eidenv.exe openpgp-tool.exe iasecc-tool.exe \
 		opensc-notify.exe egk-tool.exe goid-tool.exe paccess-tool.exe opensc-asn1.exe \
-		pkcs11-register.exe $(PROGRAMS_OPENSSL)
+		pkcs11-register.exe $(PROGRAMS_OPENSSL) $(PROGRAMS_OPENPACE)
 
 OBJECTS = util.obj versioninfo-tools.res
 
@@ -24,40 +24,50 @@
 
 opensc-notify.exe: opensc-notify-cmdline.obj versioninfo-opensc-notify.res $(LIBS)
 	cl $(COPTS) /c $*.c
-	link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj opensc-notify-cmdline.obj versioninfo-opensc-notify.res $(LIBS) gdi32.lib shell32.lib User32.lib ws2_32.lib
+	link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj opensc-notify-cmdline.obj versioninfo-opensc-notify.res $(LIBS) gdi32.lib shell32.lib User32.lib ws2_32.lib shlwapi.lib
 	mt -manifest exe.manifest -outputresource:$@;1
 
 npa-tool.exe: npa-tool-cmdline.obj fread_to_eof.obj $(OBJECTS) $(LIBS)
 	cl $(COPTS) /c $*.c
-	link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj npa-tool-cmdline.obj fread_to_eof.obj $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib
+	link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj npa-tool-cmdline.obj fread_to_eof.obj $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib shlwapi.lib
 	mt -manifest exe.manifest -outputresource:$@;1
 
 egk-tool.exe: egk-tool-cmdline.obj $(OBJECTS) $(LIBS)
 	cl $(COPTS) /c $*.c
-	link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj egk-tool-cmdline.obj $(OBJECTS) $(LIBS) $(ZLIB_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib
+	link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj egk-tool-cmdline.obj $(OBJECTS) $(LIBS) $(ZLIB_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib shlwapi.lib
 	mt -manifest exe.manifest -outputresource:$@;1
 
 goid-tool.exe: goid-tool-cmdline.obj fread_to_eof.obj $(OBJECTS) $(LIBS)
 	cl $(COPTS) /c $*.c
-	link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj goid-tool-cmdline.obj fread_to_eof.obj $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib
+	link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj goid-tool-cmdline.obj fread_to_eof.obj $(OBJECTS) $(LIBS) $(OPENPACE_LIB) $(OPENSSL_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib shlwapi.lib
 	mt -manifest exe.manifest -outputresource:$@;1
 
 opensc-asn1.exe: opensc-asn1-cmdline.obj fread_to_eof.obj versioninfo-tools.res $(LIBS)
 	cl $(COPTS) /c $*.c
-	link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj opensc-asn1-cmdline.obj fread_to_eof.obj versioninfo-tools.res $(LIBS) gdi32.lib shell32.lib User32.lib ws2_32.lib
+	link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj opensc-asn1-cmdline.obj fread_to_eof.obj versioninfo-tools.res $(LIBS) gdi32.lib shell32.lib User32.lib ws2_32.lib shlwapi.lib
 	mt -manifest exe.manifest -outputresource:$@;1
 
 pkcs11-register.exe: pkcs11-register-cmdline.obj fread_to_eof.obj $(LIBS)
 	cl $(COPTS) /c $*.c
-	link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj pkcs11-register-cmdline.obj fread_to_eof.obj versioninfo-tools.res $(LIBS) gdi32.lib shell32.lib User32.lib ws2_32.lib
+	link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj pkcs11-register-cmdline.obj fread_to_eof.obj versioninfo-tools.res $(LIBS) gdi32.lib shell32.lib User32.lib ws2_32.lib shlwapi.lib
 	mt -manifest exe.manifest -outputresource:$@;1
 
 pkcs15-tool.exe: pkcs15-tool.obj $(TOPDIR)\src\pkcs11\pkcs11-display.obj
 	cl $(COPTS) /c $*.c
-	link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj $(TOPDIR)\src\pkcs11\pkcs11-display.obj $(OBJECTS) $(LIBS) $(OPENSSL_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib
+	link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj $(TOPDIR)\src\pkcs11\pkcs11-display.obj $(OBJECTS) $(LIBS) $(OPENSSL_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib shlwapi.lib
+	mt -manifest exe.manifest -outputresource:$@;1
+
+openpgp-tool.exe: openpgp-tool-helpers.obj $(LIBS)
+	cl $(COPTS) /c $*.c
+	link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj openpgp-tool-helpers.obj $(OBJECTS) $(LIBS) gdi32.lib shell32.lib User32.lib ws2_32.lib shlwapi.lib
+	mt -manifest exe.manifest -outputresource:$@;1
+
+sc-hsm-tool.exe: sc-hsm-tool.obj fread_to_eof.obj $(OBJECTS) $(LIBS)
+	cl $(COPTS) /c $*.c
+	link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj sc-hsm-tool.obj fread_to_eof.obj $(OBJECTS) $(LIBS) $(OPENSSL_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib
 	mt -manifest exe.manifest -outputresource:$@;1
 
 .c.exe:
 	cl $(COPTS) /c $<
-	link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj $(OBJECTS) $(LIBS) $(OPENSSL_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib
+	link $(LINKFLAGS) /pdb:$*.pdb /out:$@ $*.obj $(OBJECTS) $(LIBS) $(OPENSSL_LIB) gdi32.lib shell32.lib User32.lib ws2_32.lib shlwapi.lib
 	mt -manifest exe.manifest -outputresource:$@;1
diff -Nru opensc-0.22.0/src/tools/npa-tool.c opensc-0.23.0/src/tools/npa-tool.c
--- opensc-0.22.0/src/tools/npa-tool.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/npa-tool.c	2022-11-29 09:34:43.000000000 +0100
@@ -21,13 +21,13 @@
 #include "config.h"
 #endif
 
-#ifdef ENABLE_OPENPACE
 #include "fread_to_eof.h"
 #include "npa-tool-cmdline.h"
 #include "sm/sm-eac.h"
 #include "sm/sslutil.h"
 #include "util.h"
 #include <eac/pace.h>
+#include <eac/objects.h>
 #include <libopensc/card-npa.h>
 #include <libopensc/log.h>
 #include <libopensc/opensc.h>
@@ -258,7 +258,11 @@
 		goto err;
 	}
 
+#ifndef HAVE_EAC_OBJ_NID2OBJ
 	template->type = OBJ_nid2obj(nid);
+#else
+	template->type = EAC_OBJ_nid2obj(nid);
+#endif
 	if (!template->type) {
 		r = SC_ERROR_INTERNAL;
 		goto err;
@@ -858,10 +862,4 @@
 
 	return -r;
 }
-#else
-int
-main (int argc, char **argv)
-{
-	return 1;
-}
-#endif
+
diff -Nru opensc-0.22.0/src/tools/openpgp-tool.c opensc-0.23.0/src/tools/openpgp-tool.c
--- opensc-0.22.0/src/tools/openpgp-tool.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/openpgp-tool.c	2022-11-29 09:34:43.000000000 +0100
@@ -49,6 +49,8 @@
 #include "libopensc/log.h"
 #include "libopensc/card-openpgp.h"
 
+#include "openpgp-tool-helpers.h"
+
 #define OPT_RAW     256
 #define OPT_PRETTY  257
 #define OPT_VERIFY  258
@@ -69,20 +71,11 @@
 	enum code_types type;
 	size_t offset;
 	size_t length;	/* exact length: 0 <=> potentially infinite */
-	char *(*prettify_value)(u8 *, size_t);
+	char *(*prettify_value)(const u8 *, size_t);
 };
 
 /* declare functions */
 static void show_version(void);
-static char *prettify_hex(u8 *data, size_t length, char *buffer, size_t buflen);
-static char *prettify_algorithm(u8 *data, size_t length);
-static char *prettify_date(u8 *data, size_t length);
-static char *prettify_version(u8 *data, size_t length);
-static char *prettify_manufacturer(u8 *data, size_t length);
-static char *prettify_serialnumber(u8 *data, size_t length);
-static char *prettify_name(u8 *data, size_t length);
-static char *prettify_language(u8 *data, size_t length);
-static char *prettify_gender(u8 *data, size_t length);
 static void display_data(const struct ef_name_map *mapping, u8 *data, size_t length);
 static int decode_options(int argc, char **argv);
 static int do_info(sc_card_t *card, const struct ef_name_map *map);
@@ -145,7 +138,7 @@
 /* G */ "Generate key",
 /* t */ "Key type (default: rsa2048)",
 /* h */	"Print this help message",
-/* v */	"Verbose operation. Use several times to enable debug output.",
+/* v */	"Verbose operation, may be used several times",
 /* V */	"Show version number",
 /* E */	"Erase (reset) the card",
 	"Verify PIN (CHV1, CHV2, CHV3...)",
@@ -200,204 +193,6 @@
 }
 
 
-/* prettify hex */
-static char *prettify_hex(u8 *data, size_t length, char *buffer, size_t buflen)
-{
-	if (data != NULL) {
-		int r = sc_bin_to_hex(data, length, buffer, buflen, ':');
-
-		if (r == SC_SUCCESS)
-			return buffer;
-	}
-	return NULL;
-}
-
-
-/* prettify algorithm parameters */
-static char *prettify_algorithm(u8 *data, size_t length)
-{
-	if (data != NULL && length >= 1) {
-		static char result[64];	/* large enough */
-
-		if (data[0] == 0x01 && length >= 5) {		/* RSA */
-			unsigned short modulus = (data[1] << 8) + data[2];
-			snprintf(result, sizeof(result), "RSA%u", modulus);
-			return result;
-		}
-		else if (data[0] == 0x12) {			/* ECDH */
-			strcpy(result, "ECDH");
-			return result;
-		}
-		else if (data[0] == 0x13) {			/* ECDSA */
-			strcpy(result, "ECDSA");
-			return result;
-		}
-	}
-	return NULL;
-}
-
-
-/* prettify date/time */
-static char *prettify_date(u8 *data, size_t length)
-{
-	if (data != NULL && length == 4) {
-		time_t time = (time_t) (data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]);
-		struct tm tm;
-		static char result[64];	/* large enough */
-
-#ifdef _WIN32
-		if (0 != gmtime_s(&tm, &time))
-			return NULL;
-#else
-		if (NULL == gmtime_r(&time, &tm))
-			return NULL;
-#endif
-		strftime(result, sizeof(result), "%Y-%m-%d %H:%M:%S", &tm);
-		return result;
-	}
-	return NULL;
-}
-
-
-#define BCD2CHAR(x) (((((x) & 0xF0) >> 4) * 10) + ((x) & 0x0F))
-
-/* prettify OpenPGP card version */
-static char *prettify_version(u8 *data, size_t length)
-{
-	if (data != NULL && length >= 2) {
-		static char result[10];	/* large enough for even 2*3 digits + separator */
-		int major = BCD2CHAR(data[0]);
-		int minor = BCD2CHAR(data[1]);
-
-		sprintf(result, "%d.%d", major, minor);
-		return result;
-	}
-	return NULL;
-}
-
-
-/* prettify manufacturer */
-static char *prettify_manufacturer(u8 *data, size_t length)
-{
-	if (data != NULL && length >= 2) {
-		unsigned int manuf = (data[0] << 8) + data[1];
-
-		switch (manuf) {
-			case 0x0001: return "PPC Card Systems";
-			case 0x0002: return "Prism";
-			case 0x0003: return "OpenFortress";
-			case 0x0004: return "Wewid";
-			case 0x0005: return "ZeitControl";
-			case 0x0006: return "Yubico";
-			case 0x0007: return "OpenKMS";
-			case 0x0008: return "LogoEmail";
-			case 0x0009: return "Fidesmo";
-			case 0x000A: return "Dangerous Things";
-			case 0x000B: return "Feitian Technologies";
-
-			case 0x002A: return "Magrathea";
-			case 0x0042: return "GnuPG e.V.";
-
-			case 0x1337: return "Warsaw Hackerspace";
-			case 0x2342: return "warpzone"; /* hackerspace Muenster.  */
-			case 0x4354: return "Confidential Technologies";   /* cotech.de */
-			case 0x5443: return "TIF-IT e.V.";
-			case 0x63AF: return "Trustica";
-			case 0xBA53: return "c-base e.V.";
-			case 0xBD0E: return "Paranoidlabs";
-			case 0xF517: return "FSIJ";
-			case 0xF5EC: return "F-Secure";
-
-			/* 0x0000 and 0xFFFF are defined as test cards per spec,
-			   0xFF00 to 0xFFFE are assigned for use with randomly created
-			   serial numbers.  */
-			case 0x0000:
-			case 0xffff: return "test card";
-			default: return (manuf & 0xff00) == 0xff00 ? "unmanaged S/N range" : "unknown";
-		}
-	}
-	return NULL;
-}
-
-
-/* prettify pure serial number */
-static char *prettify_serialnumber(u8 *data, size_t length)
-{
-	if (data != NULL && length >= 4) {
-		static char result[15];	/* large enough for even 2*3 digits + separator */
-		unsigned long serial = (unsigned long) (data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]);
-
-		sprintf(result, "%08lX", serial);
-		return result;
-	}
-	return NULL;
-}
-
-
-/* prettify card holder's name */
-static char *prettify_name(u8 *data, size_t length)
-{
-	if (data != NULL && length > 0) {
-		char *src = (char *) data;
-		char *dst = (char *) data;
-
-		while (*src != '\0' && length > 0) {
-			*dst = *src++;
-			length--;
-			if (*dst == '<') {
-				if (length > 0 && *src == '<') {
-					src++;
-					length--;
-				}
-				*dst = ' ';
-			}
-			dst++;
-		}
-		*dst = '\0';
-		return (char *) data;
-	}
-	return NULL;
-}
-
-
-/* prettify language */
-static char *prettify_language(u8 *data, size_t length)
-{
-	if (data != NULL && length > 0) {
-		char *str = (char *) data;
-
-		switch (strlen(str)) {
-			case 8: memmove(str+7, str+6, 1+strlen(str+6));
-				str[6] = ',';
-				/* fall through */
-			case 6: memmove(str+5, str+4, 1+strlen(str+4));
-				str[4] = ',';
-				/* fall through */
-			case 4: memmove(str+3, str+2, 1+strlen(str+2));
-				str[2] = ',';
-				/* fall through */
-			case 2: return str;
-		}
-	}
-	return NULL;
-}
-
-
-/* convert the raw ISO-5218 SEX value to an english word */
-static char *prettify_gender(u8 *data, size_t length)
-{
-	if (data != NULL && length > 0) {
-		switch (*data) {
-			case '0': return "unknown";
-			case '1': return "male";
-			case '2': return "female";
-			case '9': return "not announced";
-		}
-	}
-	return NULL;
-}
-
-
 #define INDENT	16
 
 static void display_data(const struct ef_name_map *map, u8 *data, size_t length)
diff -Nru opensc-0.22.0/src/tools/openpgp-tool-helpers.c opensc-0.23.0/src/tools/openpgp-tool-helpers.c
--- opensc-0.22.0/src/tools/openpgp-tool-helpers.c	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tools/openpgp-tool-helpers.c	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,227 @@
+/*
+ * openpgp-tool-helpers.c: OpenPGP card utility
+ *
+ * Copyright (C) 2012-2020 Peter Marschall <peter at adpm.de>
+ *
+ * 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
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <time.h>
+#include "openpgp-tool-helpers.h"
+#include "util.h"
+
+
+/* prettify hex */
+char *prettify_hex(const u8 *data, size_t length, char *buffer, size_t buflen)
+{
+	if (data != NULL) {
+		int r = sc_bin_to_hex(data, length, buffer, buflen, ':');
+
+		if (r == SC_SUCCESS)
+			return buffer;
+	}
+	return NULL;
+}
+
+
+/* prettify algorithm parameters */
+char *prettify_algorithm(const u8 *data, size_t length)
+{
+	if (data != NULL && length >= 1) {
+		static char result[64];	/* large enough */
+
+		if (data[0] == 0x01 && length >= 5) {		/* RSA */
+			unsigned short modulus = (data[1] << 8) + data[2];
+			snprintf(result, sizeof(result), "RSA%u", modulus);
+			return result;
+		}
+		else if (data[0] == 0x12) {			/* ECDH */
+			strcpy(result, "ECDH");
+			return result;
+		}
+		else if (data[0] == 0x13) {			/* ECDSA */
+			strcpy(result, "ECDSA");
+			return result;
+		}
+		else if (data[0] == 0x16) {			/* EDDSA */
+			strcpy(result, "EDDSA");
+			return result;
+		}
+	}
+	return NULL;
+}
+
+
+/* prettify date/time */
+char *prettify_date(const u8 *data, size_t length)
+{
+	if (data != NULL && length == 4) {
+		time_t time = (time_t) (data[0] << 24 | data[1] << 16 | data[2] << 8 | data[3]);
+		struct tm tm;
+		static char result[64];	/* large enough */
+
+#ifdef _WIN32
+		if (0 != gmtime_s(&tm, &time))
+			return NULL;
+#else
+		if (NULL == gmtime_r(&time, &tm))
+			return NULL;
+#endif
+		strftime(result, sizeof(result), "%Y-%m-%d %H:%M:%S", &tm);
+		return result;
+	}
+	return NULL;
+}
+
+
+#define BCD2CHAR(x) (((((x) & 0xF0) >> 4) * 10) + ((x) & 0x0F))
+
+/* prettify OpenPGP card version */
+char *prettify_version(const u8 *data, size_t length)
+{
+	if (data != NULL && length >= 2) {
+		static char result[10];	/* large enough for even 2*3 digits + separator */
+		int major = BCD2CHAR(data[0]);
+		int minor = BCD2CHAR(data[1]);
+
+		sprintf(result, "%d.%d", major, minor);
+		return result;
+	}
+	return NULL;
+}
+
+
+/* prettify manufacturer */
+char *prettify_manufacturer(const u8 *data, size_t length)
+{
+	if (data != NULL && length >= 2) {
+		unsigned int manuf = (data[0] << 8) + data[1];
+
+		switch (manuf) {
+			case 0x0001: return "PPC Card Systems";
+			case 0x0002: return "Prism";
+			case 0x0003: return "OpenFortress";
+			case 0x0004: return "Wewid";
+			case 0x0005: return "ZeitControl";
+			case 0x0006: return "Yubico";
+			case 0x0007: return "OpenKMS";
+			case 0x0008: return "LogoEmail";
+			case 0x0009: return "Fidesmo";
+			case 0x000A: return "Dangerous Things";
+			case 0x000B: return "Feitian Technologies";
+
+			case 0x002A: return "Magrathea";
+			case 0x0042: return "GnuPG e.V.";
+
+			case 0x1337: return "Warsaw Hackerspace";
+			case 0x2342: return "warpzone"; /* hackerspace Muenster.  */
+			case 0x4354: return "Confidential Technologies";   /* cotech.de */
+			case 0x5443: return "TIF-IT e.V.";
+			case 0x63AF: return "Trustica";
+			case 0xBA53: return "c-base e.V.";
+			case 0xBD0E: return "Paranoidlabs";
+			case 0xF517: return "FSIJ";
+			case 0xF5EC: return "F-Secure";
+
+			/* 0x0000 and 0xFFFF are defined as test cards per spec,
+			   0xFF00 to 0xFFFE are assigned for use with randomly created
+			   serial numbers.  */
+			case 0x0000:
+			case 0xffff: return "test card";
+			default: return (manuf & 0xff00) == 0xff00 ? "unmanaged S/N range" : "unknown";
+		}
+	}
+	return NULL;
+}
+
+
+/* prettify pure serial number */
+char *prettify_serialnumber(const u8 *data, size_t length)
+{
+	if (data != NULL && length >= 4) {
+		static char result[15];	/* large enough for even 2*3 digits + separator */
+		sprintf(result, "%02X%02X%02X%02X", data[0], data[1], data[2], data[3]);
+		return result;
+	}
+	return NULL;
+}
+
+
+/* prettify card holder's name */
+char *prettify_name(const u8 *data, size_t length)
+{
+	if (data != NULL && length > 0) {
+		static char result[100]; /* should be large enough */
+		char *src = (char *) data;
+		char *dst = result;
+		if (length > sizeof(result) - 1)
+		    length = sizeof(result) - 1;
+
+		while (*src != '\0' && length > 0) {
+			*dst = *src++;
+			length--;
+			if (*dst == '<') {
+				if (length > 0 && *src == '<') {
+					src++;
+					length--;
+				}
+				*dst = ' ';
+			}
+			dst++;
+		}
+		*dst = '\0';
+		return result;
+	}
+	return NULL;
+}
+
+
+/* prettify language */
+char *prettify_language(const u8 *data, size_t length)
+{
+	if (data != NULL && length > 0) {
+		static char result[12]; /* 8 chars, 3 separators, 1 null */
+		char *src = (char *) data;
+		size_t used_length = strnlen(src, length) >> 1;
+		int i = 0;
+
+		while (used_length) {
+			used_length--;
+			result[i++] = *src++;
+			result[i++] = *src++;
+			result[i++] = used_length ? ',' : '\0';
+		}
+		return result;
+	}
+	return NULL;
+}
+
+
+/* convert the raw ISO-5218 SEX value to an english word */
+char *prettify_gender(const u8 *data, size_t length)
+{
+	if (data != NULL && length > 0) {
+		switch (*data) {
+			case '0': return "unknown";
+			case '1': return "male";
+			case '2': return "female";
+			case '9': return "not announced";
+		}
+	}
+	return NULL;
+}
diff -Nru opensc-0.22.0/src/tools/openpgp-tool-helpers.h opensc-0.23.0/src/tools/openpgp-tool-helpers.h
--- opensc-0.22.0/src/tools/openpgp-tool-helpers.h	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/src/tools/openpgp-tool-helpers.h	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,38 @@
+/*
+ * openpgp-tool-helpers.h: OpenPGP card utility
+ *
+ * Copyright (C) 2012-2020 Peter Marschall <peter at adpm.de>
+ *
+ * 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
+ */
+
+#ifndef OPENPGP_TOOL_HELPERS_H
+#define OPENPGP_TOOL_HELPERS_H
+
+#include "util.h"
+
+
+char *prettify_hex(const u8 *data, size_t length, char *buffer, size_t buflen);
+char *prettify_algorithm(const u8 *data, size_t length);
+char *prettify_date(const u8 *data, size_t length);
+char *prettify_version(const u8 *data, size_t length);
+char *prettify_manufacturer(const u8 *data, size_t length);
+char *prettify_serialnumber(const u8 *data, size_t length);
+char *prettify_name(const u8 *data, size_t length);
+char *prettify_language(const u8 *data, size_t length);
+char *prettify_gender(const u8 *data, size_t length);
+
+
+#endif /* OPENPGP_TOOL_HELPERS_H */
diff -Nru opensc-0.22.0/src/tools/opensc-explorer.c opensc-0.23.0/src/tools/opensc-explorer.c
--- opensc-0.22.0/src/tools/opensc-explorer.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/opensc-explorer.c	2022-11-29 09:34:43.000000000 +0100
@@ -87,7 +87,7 @@
 	"Forces the use of driver <arg> [auto-detect; '?' for list]",
 	"Selects path <arg> on start-up, or none if empty [3F00]",
 	"Wait for card insertion",
-	"Verbose operation. Use several times to enable debug output.",
+	"Verbose operation, may be used several times",
 };
 
 
@@ -1858,7 +1858,7 @@
 
 static int do_random(int argc, char **argv)
 {
-	unsigned char buffer[SC_MAX_EXT_APDU_BUFFER_SIZE];
+	unsigned char buffer[SC_MAX_EXT_APDU_BUFFER_SIZE] = {0};
 	int r, count;
 	const char *filename = NULL;
 	FILE *outf = NULL;
@@ -1908,7 +1908,9 @@
 
 	if (argc == 2) {
 		/* outf is guaranteed to be non-NULL */
-		size_t written = fwrite(buffer, 1, count, outf);
+		size_t written = 0;
+		if (count > 0)
+			written = fwrite(buffer, 1, count, outf);
 
 		if (written < (size_t) count)
 			perror(filename);
@@ -2030,9 +2032,9 @@
 static int do_apdu(int argc, char **argv)
 {
 	sc_apdu_t apdu;
-	u8 buf[SC_MAX_EXT_APDU_BUFFER_SIZE];
+	u8 buf[SC_MAX_EXT_APDU_BUFFER_SIZE] = {0};
 	u8 rbuf[SC_MAX_EXT_APDU_BUFFER_SIZE];
-	size_t len, i;
+	size_t len = 0, i;
 	int r;
 
 	if (argc < 1)
@@ -2472,7 +2474,7 @@
 		char *line;
 		int cargc;
 		char *cargv[260];
-		int multiple;
+		int multiple = 0;
 		struct command *cmd;
 		char prompt[3*SC_MAX_PATH_STRING_SIZE];
 
diff -Nru opensc-0.22.0/src/tools/opensc-tool.c opensc-0.23.0/src/tools/opensc-tool.c
--- opensc-0.22.0/src/tools/opensc-tool.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/opensc-tool.c	2022-11-29 09:34:43.000000000 +0100
@@ -82,18 +82,18 @@
 	"Prints the ATR bytes of the card",
 	"Prints the card serial number",
 	"Identify the card and print its name",
-	"Get configuration key, format: section:name:key",
-	"Set configuration key, format: section:name:key:value",
+	"Get configuration, e.g. section:name:key",
+	"Set configuration, e.g. section:name:key:val",
 	"Lists readers",
 	"Lists all installed card drivers",
 	"Recursively lists files stored on card",
-	"Sends an APDU in format AA:BB:CC:DD:EE:FF...",
+	"Sends an APDU (may need '-c default')",
 	"Uses reader number <arg> [0]",
 	"Does card reset of type <cold|warm> [cold]",
-	"Forces the use of driver <arg> [auto-detect; '?' for list]",
+	"Forces a card driver (use '?' for list)",
 	"Lists algorithms supported by card",
 	"Wait for a card to be inserted",
-	"Verbose operation. Use several times to enable debug output.",
+	"Verbose operation, may be used several times",
 };
 
 static sc_context_t *ctx = NULL;
@@ -555,7 +555,6 @@
 
 	const id2str_t alg_type_names[] = {
 		{ SC_ALGORITHM_RSA,       "rsa"       },
-		{ SC_ALGORITHM_DSA,       "dsa"       },
 		{ SC_ALGORITHM_EC,        "ec"        },
 		{ SC_ALGORITHM_EDDSA,     "eddsa"     },
 		{ SC_ALGORITHM_GOSTR3410, "gostr3410" },
diff -Nru opensc-0.22.0/src/tools/piv-tool.c opensc-0.23.0/src/tools/piv-tool.c
--- opensc-0.22.0/src/tools/piv-tool.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/piv-tool.c	2022-11-29 09:34:43.000000000 +0100
@@ -38,6 +38,10 @@
 #include <openssl/conf.h>
 
 #include <openssl/rsa.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+# include <openssl/param_build.h>
+# include <openssl/params.h>
+#endif
 #if !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_ECDSA)
 #include <openssl/ec.h>
 #include <openssl/ecdsa.h>
@@ -99,7 +103,7 @@
 	"Sends an APDU in format AA:BB:CC:DD:EE:FF...",
 	"Uses reader number <arg> [0]",
 	"Wait for a card to be inserted",
-	"Verbose operation. Use several times to enable debug output.",
+	"Verbose operation, may be used several times",
 };
 
 static sc_context_t *ctx = NULL;
@@ -333,27 +337,54 @@
 		return r;
 	}
 
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 	evpkey = EVP_PKEY_new();
+#endif
 
 	if (keydata.key_bits > 0) { /* RSA key */
-		RSA * newkey = NULL;
 		BIGNUM *newkey_n, *newkey_e;
-
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+		RSA * newkey = NULL;
 		newkey = RSA_new();
 		if (newkey == NULL) {
+			EVP_PKEY_free(evpkey);
+			free(keydata.pubkey);
 			fprintf(stderr, "gen_key RSA_new failed %d\n",r);
 			return -1;
 		}
+#else
+		EVP_PKEY_CTX *ctx = NULL;
+		OSSL_PARAM_BLD *bld = NULL;
+		OSSL_PARAM *params = NULL;
+#endif
+
+		if (!keydata.pubkey) {
+			fprintf(stderr, "gen_key failed %d\n", r);
+			free(keydata.pubkey);
+			EVP_PKEY_free(evpkey);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+			RSA_free(newkey);
+#endif
+			return -1;
+		}
+
 		newkey_n = BN_bin2bn(keydata.pubkey, keydata.pubkey_len, NULL);
 		expl = keydata.exponent;
 		expc[3] = (u8) expl & 0xff;
 		expc[2] = (u8) (expl >>8) & 0xff;
 		expc[1] = (u8) (expl >>16) & 0xff;
 		expc[0] = (u8) (expl >>24) & 0xff;
-		newkey_e =  BN_bin2bn(expc, 4, NULL);
+		newkey_e = BN_bin2bn(expc, 4, NULL);
+		free(keydata.pubkey);
+		keydata.pubkey_len = 0;
 
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 		if (RSA_set0_key(newkey, newkey_n, newkey_e, NULL) != 1) {
 			fprintf(stderr, "gen_key unable to set RSA values");
+			EVP_PKEY_free(evpkey);
+			RSA_free(newkey);
+			BN_free(newkey_n);
+			BN_free(newkey_e);
 			return -1;
 		}
 
@@ -361,15 +392,58 @@
 			RSA_print_fp(stdout, newkey,0);
 
 		EVP_PKEY_assign_RSA(evpkey, newkey);
+#else
+		if (!(bld = OSSL_PARAM_BLD_new()) ||
+			OSSL_PARAM_BLD_push_BN(bld, "n", newkey_n) != 1 ||
+			OSSL_PARAM_BLD_push_BN(bld, "e", newkey_e) != 1 ||
+			!(params = OSSL_PARAM_BLD_to_param(bld))) {
+			OSSL_PARAM_BLD_free(bld);
+			BN_free(newkey_n);
+			BN_free(newkey_e);
+			return -1;
+		}
+		params = OSSL_PARAM_BLD_to_param(bld);
+		BN_free(newkey_n);
+		BN_free(newkey_e);
+
+		ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
+		if (!ctx ||
+			EVP_PKEY_fromdata_init(ctx) != 1 ||
+			EVP_PKEY_fromdata(ctx, &evpkey, EVP_PKEY_KEYPAIR, params) != 1) {
+			fprintf(stderr, "gen_key unable to gen RSA");
+			EVP_PKEY_CTX_free(ctx);
+			OSSL_PARAM_free(params);
+			return -1;
+		}
+		if (verbose)
+			EVP_PKEY_print_public_fp(stdout, evpkey, 0, NULL);
 
+		EVP_PKEY_CTX_free(ctx);
+		OSSL_PARAM_free(params);
+#endif
 	} else { /* EC key */
 #if !defined(OPENSSL_NO_EC)
 		int i;
 		BIGNUM *x;
 		BIGNUM *y;
-		EC_KEY * eckey = NULL;
 		EC_GROUP * ecgroup = NULL;
 		EC_POINT * ecpoint = NULL;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+		EC_KEY * eckey = NULL;
+#else
+		EVP_PKEY_CTX *ctx = NULL;
+		OSSL_PARAM_BLD *bld = NULL;
+		OSSL_PARAM *params = NULL;
+		size_t len = 0;
+		unsigned char * buf = NULL;
+		const char *group_name;
+#endif
+
+		if (!keydata.ecpoint) {
+			fprintf(stderr, "gen_key failed %d\n", r);
+			EVP_PKEY_free(evpkey);
+			return -1;
+		}
 
 		ecgroup = EC_GROUP_new_by_curve_name(nid);
 		EC_GROUP_set_asn1_flag(ecgroup, OPENSSL_EC_NAMED_CURVE);
@@ -379,20 +453,35 @@
 		i = (keydata.ecpoint_len - 1)/2;
 		x = BN_bin2bn(keydata.ecpoint + 1, i, NULL);
 		y = BN_bin2bn(keydata.ecpoint + 1 + i, i, NULL) ;
-		r = EC_POINT_set_affine_coordinates_GFp(ecgroup, ecpoint, x, y, NULL);
+		r = EC_POINT_set_affine_coordinates(ecgroup, ecpoint, x, y, NULL);
+
+		free(keydata.ecpoint);
+		keydata.ecpoint_len = 0;
+		BN_free(x);
+		BN_free(y);
+
 		if (r == 0) {
 			fprintf(stderr, "EC_POINT_set_affine_coordinates_GFp failed\n");
+			EVP_PKEY_free(evpkey);
+			EC_GROUP_free(ecgroup);
+			EC_POINT_free(ecpoint);
 			return -1;
 		}
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 		eckey = EC_KEY_new();
 		r = EC_KEY_set_group(eckey, ecgroup);
+		EC_GROUP_free(ecgroup);
 		if (r == 0) {
 			fprintf(stderr, "EC_KEY_set_group failed\n");
+			EVP_PKEY_free(evpkey);
+			EC_POINT_free(ecpoint);
 			return -1;
 		}
 		r = EC_KEY_set_public_key(eckey, ecpoint);
+		EC_POINT_free(ecpoint);
 		if (r == 0) {
 			fprintf(stderr, "EC_KEY_set_public_key failed\n");
+			EVP_PKEY_free(evpkey);
 			return -1;
 		}
 
@@ -401,6 +490,51 @@
 
 		EVP_PKEY_assign_EC_KEY(evpkey, eckey);
 #else
+		group_name = OBJ_nid2sn(nid);
+		len = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_COMPRESSED, NULL, 0, NULL);
+		if (!(buf = malloc(len))) {
+			fprintf(stderr, "EC_KEY_set_public_key out of memory\n");
+			EC_GROUP_free(ecgroup);
+			EC_POINT_free(ecpoint);
+			return -1;
+		}
+		if (EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_COMPRESSED, buf, len, NULL) == 0) {
+			fprintf(stderr, "EC_KEY_set_public_key failed\n");
+			EC_GROUP_free(ecgroup);
+			EC_POINT_free(ecpoint);
+			free(buf);
+			return -1;
+		}
+
+		EC_GROUP_free(ecgroup);
+		EC_POINT_free(ecpoint);
+
+		if (!(bld = OSSL_PARAM_BLD_new()) ||
+			OSSL_PARAM_BLD_push_utf8_string(bld, "group", group_name, sizeof(group_name)) != 1 ||
+			OSSL_PARAM_BLD_push_octet_string(bld, "pub", buf, len) != 1 ||
+			!(params = OSSL_PARAM_BLD_to_param(bld))) {
+			OSSL_PARAM_BLD_free(bld);
+			free(buf);
+			return -1;
+		}
+		free(buf);
+		OSSL_PARAM_BLD_free(bld);
+
+		ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL);
+		if (!ctx ||
+			EVP_PKEY_fromdata_init(ctx) != 1 ||
+			EVP_PKEY_fromdata(ctx, &evpkey, EVP_PKEY_KEYPAIR, params) != 1) {
+			fprintf(stderr, "gen_key unable to gen EC key");
+			EVP_PKEY_CTX_free(ctx);
+			OSSL_PARAM_free(params);
+			return -1;
+		}
+		if (verbose)
+			EVP_PKEY_print_public_fp(stdout, evpkey, 0, NULL);
+
+		EVP_PKEY_CTX_free(ctx);
+		OSSL_PARAM_free(params);
+#endif
 		fprintf(stderr, "This build of OpenSSL does not support EC keys\n");
 		r = 1;
 #endif /* OPENSSL_NO_EC */
@@ -551,29 +685,19 @@
 			opt_wait = 1;
 			break;
 		default:
-			util_print_usage_and_die(app_name, options, option_help, NULL);
+			util_print_usage(app_name, options, option_help, NULL);
+			if (opt_apdus)
+				free(opt_apdus);
+			return 2;
 		}
 	}
 
-	if (action_count == 0)
-		util_print_usage_and_die(app_name, options, option_help, NULL);
-
-
-//#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
-//	OPENSSL_config(NULL);
-//#endif
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !defined(LIBRESSL_VERSION_NUMBER)
-	OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS
-		| OPENSSL_INIT_ADD_ALL_CIPHERS
-		| OPENSSL_INIT_ADD_ALL_DIGESTS,
-		NULL);
-#else
-	/* OpenSSL magic */
-	OPENSSL_malloc_init();
-	ERR_load_crypto_strings();
-	OpenSSL_add_all_algorithms();
-
-#endif
+	if (action_count == 0) {
+		util_print_usage(app_name, options, option_help, NULL);
+		if (opt_apdus)
+			free(opt_apdus);
+		return 2;
+	}
 
 	if (out_file) {
 		bp = BIO_new(BIO_s_file());
@@ -659,6 +783,8 @@
 		sc_unlock(card);
 		sc_disconnect_card(card);
 	}
+	if (opt_apdus)
+		free(opt_apdus);
 	sc_release_context(ctx);
 
 	ERR_print_errors_fp(stderr);
diff -Nru opensc-0.22.0/src/tools/pkcs11-register.c opensc-0.23.0/src/tools/pkcs11-register.c
--- opensc-0.22.0/src/tools/pkcs11-register.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/pkcs11-register.c	2022-11-29 09:34:43.000000000 +0100
@@ -231,6 +231,7 @@
 		{"APPDATA", "Mozilla\\Firefox"},
 #else
 		{"HOME", ".mozilla/firefox"},
+		{"HOME", ".mozilla/firefox-esr"},
 #endif
 	};
 
diff -Nru opensc-0.22.0/src/tools/pkcs11-register.ggo.in opensc-0.23.0/src/tools/pkcs11-register.ggo.in
--- opensc-0.22.0/src/tools/pkcs11-register.ggo.in	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/pkcs11-register.ggo.in	2022-11-29 09:34:43.000000000 +0100
@@ -12,7 +12,7 @@
 
 option "skip-firefox" -
     "Don't install module to Firefox"
-    flag off
+    flag @PKCS11_REGISTER_SKIP_FIREFOX@
 
 option "skip-thunderbird" -
     "Don't install module to Thunderbird"
diff -Nru opensc-0.22.0/src/tools/pkcs11-tool.c opensc-0.23.0/src/tools/pkcs11-tool.c
--- opensc-0.22.0/src/tools/pkcs11-tool.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/pkcs11-tool.c	2022-11-29 09:34:43.000000000 +0100
@@ -23,7 +23,9 @@
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
+#include <stdint.h>
 #include <stdlib.h>
+#include <limits.h>
 
 #ifndef _WIN32
 #include <sys/types.h>
@@ -48,6 +50,11 @@
 #include <openssl/asn1t.h>
 #include <openssl/rsa.h>
 #include <openssl/pem.h>
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+# include <openssl/core_names.h>
+# include <openssl/param_build.h>
+#include <openssl/provider.h>
+#endif
 #if !defined(OPENSSL_NO_EC) && !defined(OPENSSL_NO_ECDSA)
 #include <openssl/ec.h>
 #include <openssl/ecdsa.h>
@@ -66,6 +73,10 @@
 #include "util.h"
 #include "libopensc/sc-ossl-compat.h"
 
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+	static OSSL_PROVIDER *legacy_provider = NULL;
+#endif
+
 #ifdef _WIN32
 #ifndef STDOUT_FILENO
 #define STDOUT_FILENO 1
@@ -109,6 +120,7 @@
 	{"prime384v1",		"1.3.132.0.34", "06052B81040022", 384, 0},
 	{"ansiX9p384r1",	"1.3.132.0.34", "06052B81040022", 384, 0},
 
+	{"prime521v1", "1.3.132.0.35", "06052B81040023", 521, 0},
 	{"secp521r1", "1.3.132.0.35", "06052B81040023", 521, 0},
 	{"nistp521",  "1.3.132.0.35", "06052B81040023", 521, 0},
 
@@ -121,6 +133,7 @@
 
 	{"secp192k1",		"1.3.132.0.31", "06052B8104001F", 192, 0},
 	{"secp256k1",		"1.3.132.0.10", "06052B8104000A", 256, 0},
+	{"secp521k1",		"1.3.132.0.35", "06052B81040023", 521, 0},
 
 	{"edwards25519","1.3.6.1.4.1159.15.1", "130c656477617264733235353139", 255, CKM_EC_EDWARDS_KEY_PAIR_GEN},
 	{"curve25519", "1.3.6.1.4.3029.1.5.1", "130b63757276653235353139", 255, CKM_EC_MONTGOMERY_KEY_PAIR_GEN},
@@ -154,15 +167,20 @@
 	OPT_PRIVATE,
 	OPT_SENSITIVE,
 	OPT_EXTRACTABLE,
+	OPT_UNDESTROYABLE,
 	OPT_TEST_HOTPLUG,
 	OPT_UNLOCK_PIN,
 	OPT_PUK,
 	OPT_NEW_PIN,
+	OPT_SESSION_RW,
 	OPT_LOGIN_TYPE,
 	OPT_TEST_EC,
 	OPT_DERIVE,
 	OPT_DERIVE_PASS_DER,
 	OPT_DECRYPT,
+	OPT_ENCRYPT,
+	OPT_UNWRAP,
+	OPT_WRAP,
 	OPT_TEST_FORK,
 #if defined(_WIN32) || defined(HAVE_PTHREAD)
 	OPT_TEST_THREADS,
@@ -180,7 +198,8 @@
 	OPT_ALLOWED_MECHANISMS,
 	OPT_OBJECT_INDEX,
 	OPT_ALLOW_SW,
-	OPT_LIST_INTERFACES
+	OPT_LIST_INTERFACES,
+	OPT_IV
 };
 
 static const struct option options[] = {
@@ -195,6 +214,9 @@
 	{ "sign",		0, NULL,		's' },
 	{ "verify",		0, NULL,		OPT_VERIFY },
 	{ "decrypt",		0, NULL,		OPT_DECRYPT },
+	{ "encrypt",		0, NULL,		OPT_ENCRYPT },
+	{ "unwrap",		0, NULL,		OPT_UNWRAP },
+	{ "wrap",		0, NULL,		OPT_WRAP },
 	{ "hash",		0, NULL,		'h' },
 	{ "derive",		0, NULL,		OPT_DERIVE },
 	{ "derive-pass-der",	0, NULL,		OPT_DERIVE_PASS_DER },
@@ -203,6 +225,7 @@
 	{ "mgf",		1, NULL,		OPT_MGF },
 	{ "salt-len",		1, NULL,		OPT_SALT },
 
+	{ "session-rw",		0, NULL,		OPT_SESSION_RW },
 	{ "login",		0, NULL,		'l' },
 	{ "login-type",		1, NULL,		OPT_LOGIN_TYPE },
 	{ "pin",		1, NULL,		'p' },
@@ -250,17 +273,19 @@
 	{ "private",		0, NULL,		OPT_PRIVATE },
 	{ "sensitive",		0, NULL,		OPT_SENSITIVE },
 	{ "extractable",	0, NULL,		OPT_EXTRACTABLE },
+	{ "undestroyable",	0, NULL,		OPT_UNDESTROYABLE },
 	{ "always-auth",	0, NULL,		OPT_ALWAYS_AUTH },
 	{ "test-ec",		0, NULL,		OPT_TEST_EC },
 #ifndef _WIN32
 	{ "test-fork",		0, NULL,		OPT_TEST_FORK },
 #endif
-	{ "use-locking",	0, NULL,		OPT_USE_LOCKING },
 #if defined(_WIN32) || defined(HAVE_PTHREAD)
+	{ "use-locking",	0, NULL,		OPT_USE_LOCKING },
 	{ "test-threads",	1, NULL,		OPT_TEST_THREADS },
 #endif
 	{ "generate-random",	1, NULL,		OPT_GENERATE_RANDOM },
 	{ "allow-sw",		0, NULL,		OPT_ALLOW_SW },
+	{ "iv",			1, NULL,		OPT_IV },
 
 	{ NULL, 0, NULL, 0 }
 };
@@ -277,6 +302,9 @@
 	"Sign some data",
 	"Verify a signature of some data",
 	"Decrypt some data",
+	"Encrypt some data",
+	"Unwrap key",
+	"Wrap key",
 	"Hash some data",
 	"Derive a secret key using another key and some data",
 	"Derive ECDHpass DER encoded pubkey for compatibility with some PKCS#11 implementations",
@@ -285,6 +313,7 @@
 	"Specify MGF (Message Generation Function) used for RSA-PSS signature and RSA-OAEP decryption (possible values are MGF1-SHA1 to MGF1-SHA512)",
 	"Specify how many bytes should be used for salt in RSA-PSS signatures (default is digest size)",
 
+	"Forces to open the PKCS#11 session with CKF_RW_SESSION",
 	"Log into the token first",
 	"Specify login type ('so', 'user', 'context-specific'; default:'user')",
 	"Supply User PIN on the command line (if used in scripts: careful!)",
@@ -299,7 +328,7 @@
 	"Key generation",
 	"Specify the type and length (bytes if symmetric) of the key to create, for example rsa:1024, EC:prime256v1, EC:ed25519, EC:curve25519, GOSTR3410-2012-256:B, AES:16 or GENERIC:64",
 	"Specify 'sign' key usage flag (sets SIGN in privkey, sets VERIFY in pubkey)",
-	"Specify 'decrypt' key usage flag (RSA only, set DECRYPT privkey, ENCRYPT in pubkey)",
+	"Specify 'decrypt' key usage flag (sets DECRYPT in privkey and ENCRYPT in pubkey for RSA, sets both DECRYPT and ENCRYPT for secret keys)",
 	"Specify 'derive' key usage flag (EC only)",
 	"Specify 'wrap' key usage flag",
 	"Write an object (key, cert, data) to the card",
@@ -332,6 +361,7 @@
 	"Set the CKA_PRIVATE attribute (object is only viewable after a login)",
 	"Set the CKA_SENSITIVE attribute (object cannot be revealed in plaintext)",
 	"Set the CKA_EXTRACTABLE attribute (object can be extracted)",
+	"Set the CKA_DESTROYABLE attribute to false (object cannot be destroyed)",
 	"Set the CKA_ALWAYS_AUTHENTICATE attribute to a key object (require PIN verification for each use)",
 	"Test EC (best used with the --login or --pin option)",
 #ifndef _WIN32
@@ -343,6 +373,7 @@
 #endif
 	"Generate given amount of random data",
 	"Allow using software mechanisms (without CKF_HW)",
+	"Initialization vector",
 };
 
 static const char *	app_name = "pkcs11-tool"; /* for utils.c */
@@ -385,6 +416,7 @@
 static int		opt_is_private = 0;
 static int		opt_is_sensitive = 0;
 static int		opt_is_extractable = 0;
+static int		opt_is_destroyable = 1;
 static int		opt_test_hotplug = 0;
 static int		opt_login_type = -1;
 static int		opt_key_usage_sign = 0;
@@ -400,6 +432,7 @@
 static int		opt_salt_len_given = 0; /* 0 - not given, 1 - given with input parameters */
 static int		opt_always_auth = 0;
 static CK_FLAGS		opt_allow_sw = CKF_HW;
+static const char *	opt_iv = NULL;
 
 static void *module = NULL;
 static CK_FUNCTION_LIST_3_0_PTR p11 = NULL;
@@ -429,10 +462,33 @@
 	CK_FLAGS	value;
 	const char *	name;
 };
+
+/*
+ * Flags for mech_info. These flags can provide meta-data for
+ * pkcs11 mechanisms and are tracked per mechanism. Thus for figuring
+ * out if sign is valid for this mechanism, one can query the mechanism
+ * table over having to build conditional statements.
+ *
+ * Note that the tool takes in raw 0x prefixed mechanisms that may not exist in
+ * the table, so we just assume MF_UNKOWN for flags.
+ *
+ * TODO these flags are only the tip of the iceberg, but can be filled out as time progresses.
+ */
+#define MF_UNKNOWN 0        /* Used to indicate additional information is not available */
+#define MF_SIGN    (1 << 0) /* C_Sign interface supported */
+#define MF_VERIFY  (1 << 1) /* C_verify interface supported */
+#define MF_HMAC    (1 << 2) /* Is an Hashed Message Authentication Code (HMAC) */
+#define MF_MGF     (1 << 3) /* Is an Mask Generation Function (MGF) */
+#define MF_CKO_SECRET_KEY (1 << 4) /* Uses a CKO_SECRET_KEY class object */
+
+/* Handy initializers */
+#define MF_GENERIC_HMAC_FLAGS (MF_SIGN | MF_VERIFY | MF_HMAC | MF_CKO_SECRET_KEY)
+
 struct mech_info {
 	CK_MECHANISM_TYPE mech;
 	const char *	name;
 	const char *	short_name;
+	uint16_t mf_flags;
 };
 struct x509cert_info {
 	unsigned char	subject[512];
@@ -485,18 +541,30 @@
 static void		sign_data(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE);
 static void		verify_signature(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE);
 static void		decrypt_data(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE);
+static void		encrypt_data(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE);
 static void		hash_data(CK_SLOT_ID, CK_SESSION_HANDLE);
 static void		derive_key(CK_SLOT_ID, CK_SESSION_HANDLE, CK_OBJECT_HANDLE);
 static int		gen_keypair(CK_SLOT_ID slot, CK_SESSION_HANDLE,
 				CK_OBJECT_HANDLE *, CK_OBJECT_HANDLE *, const char *);
 static int		gen_key(CK_SLOT_ID slot, CK_SESSION_HANDLE, CK_OBJECT_HANDLE *, const char *, char *);
+static int		unwrap_key(CK_SESSION_HANDLE session);
+static int		wrap_key(CK_SESSION_HANDLE session);
+
 static int		write_object(CK_SESSION_HANDLE session);
 static int		read_object(CK_SESSION_HANDLE session);
 static int		delete_object(CK_SESSION_HANDLE session);
 static void		set_id_attr(CK_SESSION_HANDLE session);
+static int		find_object_id_or_label(CK_SESSION_HANDLE sess, CK_OBJECT_CLASS cls,
+				CK_OBJECT_HANDLE_PTR ret,
+				const unsigned char *, size_t id_len,
+				const char *,
+				int obj_index);
 static int		find_object(CK_SESSION_HANDLE, CK_OBJECT_CLASS,
 				CK_OBJECT_HANDLE_PTR,
 				const unsigned char *, size_t id_len, int obj_index);
+static int		find_object_flags(CK_SESSION_HANDLE, uint16_t flags,
+				CK_OBJECT_HANDLE_PTR,
+				const unsigned char *, size_t id_len, int obj_index);
 static int		find_mechanism(CK_SLOT_ID, CK_FLAGS, CK_MECHANISM_TYPE_PTR, size_t, CK_MECHANISM_TYPE_PTR);
 static int		find_slot_by_description(const char *, CK_SLOT_ID_PTR);
 static int		find_slot_by_token_label(const char *, CK_SLOT_ID_PTR);
@@ -511,13 +579,15 @@
 static const char *	p11_flag_names(struct flag_info *, CK_FLAGS);
 static const char *	p11_mechanism_to_name(CK_MECHANISM_TYPE);
 static CK_MECHANISM_TYPE p11_name_to_mechanism(const char *);
+static uint16_t p11_mechanism_to_flags(CK_MECHANISM_TYPE mech);
 static const char *	p11_mgf_to_name(CK_RSA_PKCS_MGF_TYPE);
 static CK_MECHANISM_TYPE p11_name_to_mgf(const char *);
+static const char *	p11_profile_to_name(CK_ULONG);
 static void		p11_perror(const char *, CK_RV);
 static const char *	CKR2Str(CK_ULONG res);
 static int		p11_test(CK_SESSION_HANDLE session);
 static int test_card_detection(int);
-static int		hex_to_bin(const char *in, CK_BYTE *out, size_t *outlen);
+static CK_BYTE_PTR	get_iv(const char * iv_input, size_t *iv_size);
 static void		pseudo_randomize(unsigned char *data, size_t dataLen);
 static CK_SESSION_HANDLE test_kpgen_certwrite(CK_SLOT_ID slot, CK_SESSION_HANDLE session);
 static void		test_ec(CK_SLOT_ID slot, CK_SESSION_HANDLE session);
@@ -533,7 +603,7 @@
 #else
 static void *		test_threads_run(void * pttd);
 #endif
-#endif /* defined(_WIN32) || defiend(HAVE_PTHREAD) */
+#endif /* defined(_WIN32) || defined(HAVE_PTHREAD) */
 static void		generate_random(CK_SESSION_HANDLE session);
 static CK_RV		find_object_with_attributes(CK_SESSION_HANDLE session, CK_OBJECT_HANDLE *out,
 				CK_ATTRIBUTE *attrs, CK_ULONG attrsLen, CK_ULONG obj_index);
@@ -611,12 +681,14 @@
 ATTR_METHOD(VALUE_LEN, CK_ULONG);			/* getVALUE_LEN */
 ATTR_METHOD(PROFILE_ID, CK_ULONG);			/* getPROFILE_ID */
 VARATTR_METHOD(LABEL, char);				/* getLABEL */
+VARATTR_METHOD(UNIQUE_ID, char);			/* getUNIQUE_ID */
 VARATTR_METHOD(APPLICATION, char);			/* getAPPLICATION */
 VARATTR_METHOD(ID, unsigned char);			/* getID */
 VARATTR_METHOD(OBJECT_ID, unsigned char);		/* getOBJECT_ID */
 VARATTR_METHOD(MODULUS, CK_BYTE);			/* getMODULUS */
 #ifdef ENABLE_OPENSSL
 VARATTR_METHOD(SUBJECT, unsigned char);			/* getSUBJECT */
+VARATTR_METHOD(SERIAL_NUMBER, unsigned char);	/* getSERIAL_NUMBER */
 VARATTR_METHOD(PUBLIC_EXPONENT, CK_BYTE);		/* getPUBLIC_EXPONENT */
 #endif
 VARATTR_METHOD(VALUE, unsigned char);			/* getVALUE */
@@ -640,6 +712,9 @@
 	int do_sign = 0;
 	int do_verify = 0;
 	int do_decrypt = 0;
+	int do_encrypt = 0;
+	int do_unwrap = 0;
+	int do_wrap = 0;
 	int do_hash = 0;
 	int do_derive = 0;
 	int do_gen_keypair = 0;
@@ -678,14 +753,6 @@
 		util_fatal("Cannot set FMODE to O_BINARY");
 #endif
 
-#ifdef ENABLE_OPENSSL
-#if OPENSSL_VERSION_NUMBER < 0x10100000L || defined(LIBRESSL_VERSION_NUMBER)
-	OPENSSL_config(NULL);
-	/* OpenSSL magic */
-	OpenSSL_add_all_algorithms();
-	OPENSSL_malloc_init();
-#endif
-#endif
 	while (1) {
 		c = getopt_long(argc, argv, "ILMOTa:bd:e:hi:klm:o:p:scvf:ty:w:z:r",
 		                options, &long_optind);
@@ -749,7 +816,7 @@
 			need_session |= NEED_SESSION_RW;
 			do_set_id = 1;
 			new_object_id_len = sizeof(new_object_id);
-			if (!hex_to_bin(optarg, new_object_id, &new_object_id_len)) {
+			if (sc_hex_to_bin(optarg, new_object_id, &new_object_id_len)) {
 				fprintf(stderr, "Invalid ID \"%s\"\n", optarg);
 				util_print_usage_and_die(app_name, options, option_help, NULL);
 			}
@@ -777,7 +844,7 @@
 			break;
 		case 'd':
 			opt_object_id_len = sizeof(opt_object_id);
-			if (!hex_to_bin(optarg, opt_object_id, &opt_object_id_len)) {
+			if (sc_hex_to_bin(optarg, opt_object_id, &opt_object_id_len)) {
 				fprintf(stderr, "Invalid ID \"%s\"\n", optarg);
 				util_print_usage_and_die(app_name, options, option_help, NULL);
 			}
@@ -791,8 +858,11 @@
 		case OPT_SIGNATURE_FILE:
 			opt_signature_file = optarg;
 			break;
-		case 'l':
+		case OPT_SESSION_RW:
 			need_session |= NEED_SESSION_RW;
+			break;
+		case 'l':
+			need_session |= NEED_SESSION_RO;
 			opt_login = 1;
 			break;
 		case 'm':
@@ -813,7 +883,7 @@
 			opt_output = optarg;
 			break;
 		case 'p':
-			need_session |= NEED_SESSION_RW;
+			need_session |= NEED_SESSION_RO;
 			opt_login = 1;
 			util_get_pin(optarg, &opt_pin);
 			break;
@@ -828,7 +898,7 @@
 			action_count++;
 			break;
 		case 's':
-			need_session |= NEED_SESSION_RW;
+			need_session |= NEED_SESSION_RO;
 			do_sign = 1;
 			action_count++;
 			break;
@@ -838,10 +908,25 @@
 			action_count++;
 			break;
 		case OPT_DECRYPT:
-			need_session |= NEED_SESSION_RW;
+			need_session |= NEED_SESSION_RO;
 			do_decrypt = 1;
 			action_count++;
 			break;
+		case OPT_ENCRYPT:
+			need_session |= NEED_SESSION_RO;
+			do_encrypt = 1;
+			action_count++;
+			break;
+		case OPT_UNWRAP:
+			need_session |= NEED_SESSION_RW;
+			do_unwrap = 1;
+			action_count++;
+			break;
+		case OPT_WRAP:
+			need_session |= NEED_SESSION_RO;
+			do_wrap = 1;
+			action_count++;
+			break;
 		case 'f':
 			opt_sig_format = optarg;
 			break;
@@ -963,6 +1048,9 @@
 		case OPT_EXTRACTABLE:
 			opt_is_extractable = 1;
 			break;
+		case OPT_UNDESTROYABLE:
+			opt_is_destroyable = 0;
+			break;
 		case OPT_TEST_HOTPLUG:
 			opt_test_hotplug = 1;
 			action_count++;
@@ -985,10 +1073,10 @@
 			action_count++;
 			break;
 #endif
+#if defined(_WIN32) || defined(HAVE_PTHREAD)
 		case OPT_USE_LOCKING:
 			c_initialize_args_ptr = &c_initialize_args_OS;
 			break;
-#if defined(_WIN32) || defined(HAVE_PTHREAD)
 		case OPT_TEST_THREADS:
 			do_test_threads = 1;
 			if (test_threads_num < MAX_TEST_THREADS) {
@@ -1034,6 +1122,9 @@
 			do_list_interfaces = 1;
 			action_count++;
 			break;
+		case OPT_IV:
+			opt_iv = optarg;
+			break;
 		default:
 			util_print_usage_and_die(app_name, options, option_help, NULL);
 		}
@@ -1164,8 +1255,8 @@
 	if (do_list_mechs)
 		list_mechs(opt_slot);
 
-	if (do_sign || do_decrypt) {
-		CK_TOKEN_INFO	info;
+	if (do_sign || do_decrypt || do_encrypt || do_unwrap || do_wrap) {
+		CK_TOKEN_INFO info;
 
 		get_token_info(opt_slot, &info);
 		if (!(info.flags & CKF_TOKEN_INITIALIZED))
@@ -1221,15 +1312,75 @@
 		goto end;
 	}
 
-	if (do_sign || do_derive || do_decrypt) {
-		if (!find_object(session, CKO_PRIVATE_KEY, &object,
+	uint16_t mf_flags = MF_UNKNOWN;
+	if (opt_mechanism_used) {
+		mf_flags = p11_mechanism_to_flags(opt_mechanism);
+	}
+
+	if (do_sign || do_derive) {
+
+		/*
+		 * Newer mechanisms have their details in the mechanism table, however
+		 * if it's not known fall back to the old code always assuming it was a
+		 * CKO_PRIVATE_KEY.
+		 */
+		if (mf_flags != MF_UNKNOWN) {
+			/* this function dies on error via util_fatal */
+			find_object_flags(session, mf_flags, &object,
+				opt_object_id_len ? opt_object_id : NULL,
+				opt_object_id_len, 0);
+		} else if (!find_object(session, CKO_PRIVATE_KEY, &object,
 					opt_object_id_len ? opt_object_id : NULL,
 					opt_object_id_len, 0))
 			util_fatal("Private key not found");
 	}
 
+	if (do_decrypt) {
+		/*
+		 * Newer mechanisms have their details in the mechanism table, however
+		 * if it's not known fall back to the old code always assuming it was a
+		 * CKO_PUBLIC_KEY then a CKO_CERTIFICATE.
+		 */
+		if (mf_flags != MF_UNKNOWN) {
+			/* this function dies on error via util_fatal */
+			find_object_flags(session, mf_flags, &object,
+				opt_object_id_len ? opt_object_id : NULL,
+				opt_object_id_len, 0);
+		} else if (!find_object(session, CKO_PRIVATE_KEY, &object,
+				 opt_object_id_len ? opt_object_id : NULL, opt_object_id_len, 0))
+			if (!find_object(session, CKO_SECRET_KEY, &object,
+					 opt_object_id_len ? opt_object_id : NULL, opt_object_id_len, 0))
+				util_fatal("Private/secret key not found");
+	}
+
+	if (do_encrypt) {
+		/*
+		 * Newer mechanisms have their details in the mechanism table, however
+		 * if it's not known fall back to the old code always assuming it was a
+		 * CKO_PUBLIC_KEY then a CKO_CERTIFICATE.
+		 */
+		if (mf_flags != MF_UNKNOWN) {
+			/* this function dies on error via util_fatal */
+			find_object_flags(session, mf_flags, &object,
+				opt_object_id_len ? opt_object_id : NULL,
+				opt_object_id_len, 0);
+		} else if (!find_object(session, CKO_SECRET_KEY, &object,
+				 opt_object_id_len ? opt_object_id : NULL, opt_object_id_len, 0))
+			util_fatal("Secret key not found");
+	}
+
 	if (do_verify) {
-		if (!find_object(session, CKO_PUBLIC_KEY, &object,
+		/*
+		 * Newer mechanisms have their details in the mechanism table, however
+		 * if it's not known fall back to the old code always assuming it was a
+		 * CKO_PUBLIC_KEY then a CKO_CERTIFICATE.
+		 */
+		if (mf_flags != MF_UNKNOWN) {
+			/* this function dies on error via util_fatal */
+			find_object_flags(session, mf_flags, &object,
+				opt_object_id_len ? opt_object_id : NULL,
+				opt_object_id_len, 0);
+		} else if (!find_object(session, CKO_PUBLIC_KEY, &object,
 		        opt_object_id_len ? opt_object_id : NULL,
 		        opt_object_id_len, 0) &&
 		    !find_object(session, CKO_CERTIFICATE, &object,
@@ -1238,6 +1389,12 @@
 			util_fatal("Public key nor certificate not found");
 	}
 
+	if (do_unwrap)
+		unwrap_key(session);
+
+	if (do_wrap)
+		wrap_key(session);
+
 	/* before list objects, so we can see a derived key */
 	if (do_derive)
 		derive_key(opt_slot, session, object);
@@ -1254,6 +1411,9 @@
 	if (do_decrypt)
 		decrypt_data(opt_slot, session, object);
 
+	if (do_encrypt)
+		encrypt_data(opt_slot, session, object);
+
 	if (do_hash)
 		hash_data(opt_slot, session);
 
@@ -1298,8 +1458,8 @@
 	if (do_set_id) {
 		if (opt_object_class_str == NULL)
 			util_fatal("You should specify the object type with the -y option");
-		if (opt_object_id_len == 0)
-			util_fatal("You should specify the current ID with the -d option");
+		if (opt_object_id_len == 0 && opt_object_label == NULL)
+			util_fatal("You should specify the current object with the -d or -a option");
 		set_id_attr(session);
 	}
 
@@ -1334,7 +1494,7 @@
 #if defined(_WIN32) || defined(HAVE_PTHREAD)
 	if (do_test_threads)
 		test_threads_cleanup();
-#endif /* defined(_WIN32) || defiend(HAVE_PTHREAD) */
+#endif /* defined(_WIN32) || defined(HAVE_PTHREAD) */
 
 	if (p11)
 		p11->C_Finalize(NULL_PTR);
@@ -1908,15 +2068,19 @@
 		sLen = 20;
 		break;
 	case  CKM_SHA224:
+	case  CKM_SHA3_224:
 		sLen = 28;
 		break;
 	case  CKM_SHA256:
+	case  CKM_SHA3_256:
 		sLen = 32;
 		break;
 	case  CKM_SHA384:
+	case  CKM_SHA3_384:
 		sLen = 48;
 		break;
 	case  CKM_SHA512:
+	case  CKM_SHA3_512:
 		sLen = 64;
 		break;
 	default:
@@ -1960,6 +2124,18 @@
 		case CKM_SHA512:
 			pss_params->mgf = CKG_MGF1_SHA512;
 			break;
+		case CKM_SHA3_224:
+			pss_params->mgf = CKG_MGF1_SHA3_224;
+			break;
+		case CKM_SHA3_256:
+			pss_params->mgf = CKG_MGF1_SHA3_256;
+			break;
+		case CKM_SHA3_384:
+			pss_params->mgf = CKG_MGF1_SHA3_384;
+			break;
+		case CKM_SHA3_512:
+			pss_params->mgf = CKG_MGF1_SHA3_512;
+			break;
 		default:
 			/* the PSS should use SHA-1 if not specified */
 			pss_params->hashAlg = CKM_SHA_1;
@@ -1994,6 +2170,26 @@
 		pss_params->mgf = CKG_MGF1_SHA512;
 		break;
 
+	case CKM_SHA3_224_RSA_PKCS_PSS:
+		pss_params->hashAlg = CKM_SHA3_224;
+		pss_params->mgf = CKG_MGF1_SHA3_224;
+		break;
+
+	case CKM_SHA3_256_RSA_PKCS_PSS:
+		pss_params->hashAlg = CKM_SHA3_256;
+		pss_params->mgf = CKG_MGF1_SHA3_256;
+		break;
+
+	case CKM_SHA3_384_RSA_PKCS_PSS:
+		pss_params->hashAlg = CKM_SHA3_384;
+		pss_params->mgf = CKG_MGF1_SHA3_384;
+		break;
+
+	case CKM_SHA3_512_RSA_PKCS_PSS:
+		pss_params->hashAlg = CKM_SHA3_512;
+		pss_params->mgf = CKG_MGF1_SHA3_512;
+		break;
+
 	default: /* The non-RSA-PSS algorithms do not need any parameters */
 		return 0;
 	}
@@ -2007,10 +2203,6 @@
 
 		if (opt_salt_len_given == 1) { /* salt size explicitly given */
 			unsigned long modlen = 0;
-			if (opt_salt_len < 0 && opt_salt_len != -1 && opt_salt_len != -2)
-				util_fatal("Salt length must be greater or equal "
-				    "to zero, or equal to -1 (meaning: use digest size) "
-				    "or to -2 (meaning: use maximum permissible size");
 
 			modlen = (get_private_key_length(session, key) + 7) / 8;
 			switch (opt_salt_len) {
@@ -2018,9 +2210,15 @@
 				pss_params->sLen = hashlen;
 				break;
 			case -2: /* maximum permissible salt len */
-				pss_params->sLen = modlen - hashlen -2;
+			case -3:
+				pss_params->sLen = modlen - hashlen - 2;
 				break;
 			default: /* use given size but its value must be >= 0 */
+				if (opt_salt_len < 0)
+					util_fatal("Salt length must be greater or equal "
+						"to zero, or equal to -1 (meaning: use digest size) "
+						"or to -2 or -3 (meaning: use maximum permissible size");
+
 				pss_params->sLen = opt_salt_len;
 				break;
 			} /* end switch (opt_salt_len_given) */
@@ -2117,8 +2315,10 @@
 	}
 
 	if (opt_mechanism == CKM_ECDSA || opt_mechanism == CKM_ECDSA_SHA1 ||
-	    opt_mechanism == CKM_ECDSA_SHA256 || opt_mechanism == CKM_ECDSA_SHA384 ||
-	    opt_mechanism == CKM_ECDSA_SHA512 || opt_mechanism == CKM_ECDSA_SHA224) {
+		opt_mechanism == CKM_ECDSA_SHA256 || opt_mechanism == CKM_ECDSA_SHA384 ||
+		opt_mechanism == CKM_ECDSA_SHA512 || opt_mechanism == CKM_ECDSA_SHA224 ||
+		opt_mechanism == CKM_ECDSA_SHA3_224 || opt_mechanism == CKM_ECDSA_SHA3_256 ||
+		opt_mechanism == CKM_ECDSA_SHA3_384 || opt_mechanism == CKM_ECDSA_SHA3_512) {
 		if (opt_sig_format && (!strcmp(opt_sig_format, "openssl") ||
 		                       !strcmp(opt_sig_format, "sequence"))) {
 			unsigned char *seq;
@@ -2162,7 +2362,17 @@
 	memset(&mech, 0, sizeof(mech));
 	mech.mechanism = opt_mechanism;
 	hashlen = parse_pss_params(session, key, &mech, &pss_params);
-
+	if (hashlen && opt_salt_len_given) {
+		if (opt_salt_len == -2) {
+			/* openssl allow us to set sLen to -2 for autodetecting salt length
+			 * here maximal CK_ULONG value is used to pass this special code
+			 * to openssl. For non OpenSC PKCS#11 module this is minimal limitation
+			 * because there is no need to use extra long salt length.
+			 */
+			pss_params.sLen = ((CK_ULONG) 1 ) << (sizeof(CK_ULONG) * CHAR_BIT -1);
+			fprintf(stderr, "Warning, requesting salt length recovery from signature (supported only in in opensc pkcs11 module).\n");
+		}
+	}
 	/* Open a signature file */
 	if (opt_signature_file == NULL)
 		util_fatal("No file with signature provided. Use --signature-file");
@@ -2177,7 +2387,9 @@
 
 	if (opt_mechanism == CKM_ECDSA || opt_mechanism == CKM_ECDSA_SHA1 ||
 		opt_mechanism == CKM_ECDSA_SHA256 || opt_mechanism == CKM_ECDSA_SHA384 ||
-		opt_mechanism == CKM_ECDSA_SHA512 || opt_mechanism == CKM_ECDSA_SHA224) {
+		opt_mechanism == CKM_ECDSA_SHA512 || opt_mechanism == CKM_ECDSA_SHA224 ||
+		opt_mechanism == CKM_ECDSA_SHA3_224 || opt_mechanism == CKM_ECDSA_SHA3_256 ||
+		opt_mechanism == CKM_ECDSA_SHA3_384 || opt_mechanism == CKM_ECDSA_SHA3_512) {
 		if (opt_sig_format && (!strcmp(opt_sig_format, "openssl") ||
 							   !strcmp(opt_sig_format, "sequence"))) {
 
@@ -2267,7 +2479,6 @@
 		printf("Cryptoki returned error: %s\n", CKR2Str(rv));
 }
 
-
 static void decrypt_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
 		CK_OBJECT_HANDLE key)
 {
@@ -2276,7 +2487,10 @@
 	CK_RV		rv;
 	CK_RSA_PKCS_OAEP_PARAMS oaep_params;
 	CK_ULONG	in_len, out_len;
-	int		fd, r;
+	int		fd_in, fd_out;
+	int		r;
+	CK_BYTE_PTR	iv = NULL;
+	size_t		iv_size = 0;
 
 	if (!opt_mechanism_used)
 		if (!find_mechanism(slot, CKF_DECRYPT|opt_allow_sw, NULL, 0, &opt_mechanism))
@@ -2291,15 +2505,6 @@
 		util_fatal("The hash-algorithm is applicable only to "
                "RSA-PKCS-OAEP mechanism");
 
-	if (opt_input == NULL)
-		fd = 0;
-	else if ((fd = open(opt_input, O_RDONLY|O_BINARY)) < 0)
-		util_fatal("Cannot open %s: %m", opt_input);
-
-	r = read(fd, in_buffer, sizeof(in_buffer));
-	if (r < 0)
-		util_fatal("Cannot read from %s: %m", opt_input);
-	in_len = r;
 
 	/* set "default" MGF and hash algorithms. We can overwrite MGF later */
 	switch (opt_mechanism) {
@@ -2312,6 +2517,18 @@
 		case CKM_SHA224:
 			oaep_params.mgf = CKG_MGF1_SHA224;
 			break;
+		case CKM_SHA3_224:
+			oaep_params.mgf = CKG_MGF1_SHA3_224;
+			break;
+		case CKM_SHA3_256:
+			oaep_params.mgf = CKG_MGF1_SHA3_256;
+			break;
+		case CKM_SHA3_384:
+			oaep_params.mgf = CKG_MGF1_SHA3_384;
+			break;
+		case CKM_SHA3_512:
+			oaep_params.mgf = CKG_MGF1_SHA3_512;
+			break;
 		default:
 			oaep_params.hashAlg = CKM_SHA256;
 			/* fall through */
@@ -2328,9 +2545,17 @@
 		break;
 	case CKM_RSA_X_509:
 	case CKM_RSA_PKCS:
+	case CKM_AES_ECB:
 		mech.pParameter = NULL;
 		mech.ulParameterLen = 0;
 		break;
+	case CKM_AES_CBC:
+	case CKM_AES_CBC_PAD:
+		iv_size = 16;
+		iv = get_iv(opt_iv, &iv_size);
+		mech.pParameter = iv;
+		mech.ulParameterLen = iv_size;
+		break;
 	default:
 		util_fatal("Mechanism %s illegal or not supported\n", p11_mechanism_to_name(opt_mechanism));
 	}
@@ -2358,34 +2583,169 @@
 
 	}
 
-	rv = p11->C_DecryptInit(session, &mech, key);
-	if (rv != CKR_OK)
-		p11_fatal("C_DecryptInit", rv);
-	if (getALWAYS_AUTHENTICATE(session, key))
-		login(session,CKU_CONTEXT_SPECIFIC);
+	if (opt_input == NULL)
+		fd_in = 0;
+	else if ((fd_in = open(opt_input, O_RDONLY | O_BINARY)) < 0)
+		util_fatal("Cannot open %s: %m", opt_input);
 
-	out_len = sizeof(out_buffer);
-	rv = p11->C_Decrypt(session, in_buffer, in_len, out_buffer, &out_len);
-	if (rv != CKR_OK)
-		p11_fatal("C_Decrypt", rv);
+	if (opt_output == NULL) {
+		fd_out = 1;
+	} else {
+		fd_out = open(opt_output, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IRUSR | S_IWUSR);
+		if (fd_out < 0)
+			util_fatal("failed to open %s: %m", opt_output);
+	}
 
-	if (fd != 0)
-		close(fd);
+	r = read(fd_in, in_buffer, sizeof(in_buffer));
+	in_len = r;
 
-	if (opt_output == NULL)   {
-		fd = 1;
+	if (r < 0)
+		util_fatal("Cannot read from %s: %m", opt_input);
+
+	rv = CKR_CANCEL;
+	if (r < (int) sizeof(in_buffer)) {
+		out_len = sizeof(out_buffer);
+		rv = p11->C_DecryptInit(session, &mech, key);
+		if (rv != CKR_OK)
+			p11_fatal("C_DecryptInit", rv);
+		if (getALWAYS_AUTHENTICATE(session, key))
+			login(session, CKU_CONTEXT_SPECIFIC);
+		rv = p11->C_Decrypt(session, in_buffer, in_len, out_buffer, &out_len);
+	}
+	if (rv != CKR_OK) {
+		rv = p11->C_DecryptInit(session, &mech, key);
+		if (rv != CKR_OK)
+			p11_fatal("C_DecryptInit", rv);
+		if (getALWAYS_AUTHENTICATE(session, key))
+			login(session, CKU_CONTEXT_SPECIFIC);
+		do {
+			out_len = sizeof(out_buffer);
+			rv = p11->C_DecryptUpdate(session, in_buffer, in_len, out_buffer, &out_len);
+			if (rv != CKR_OK)
+				p11_fatal("C_DecryptUpdate", rv);
+			r = write(fd_out, out_buffer, out_len);
+			if (r != (int) out_len)
+				util_fatal("Cannot write to %s: %m", opt_output);
+			r = read(fd_in, in_buffer, sizeof(in_buffer));
+			in_len = r;
+		} while (r > 0);
+		out_len = sizeof(out_buffer);
+		rv = p11->C_DecryptFinal(session, out_buffer, &out_len);
+		if (rv != CKR_OK)
+			p11_fatal("C_DecryptFinal", rv);
 	}
-	else  {
-		fd = open(opt_output, O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, S_IRUSR|S_IWUSR);
-		if (fd < 0)
+	if (out_len) {
+		r = write(fd_out, out_buffer, out_len);
+		if (r != (int) out_len)
+			util_fatal("Cannot write to %s: %m", opt_output);
+	}
+	if (fd_in != 0)
+		close(fd_in);
+	if (fd_out != 1)
+		close(fd_out);
+
+	free(iv);
+}
+
+static void encrypt_data(CK_SLOT_ID slot, CK_SESSION_HANDLE session,
+		CK_OBJECT_HANDLE key)
+{
+	unsigned char	in_buffer[1024], out_buffer[1024];
+	CK_MECHANISM	mech;
+	CK_RV		rv;
+	CK_ULONG	in_len, out_len;
+	int		fd_in, fd_out;
+	int		r;
+	CK_BYTE_PTR	iv = NULL;
+	size_t		iv_size = 0;
+
+	if (!opt_mechanism_used)
+		if (!find_mechanism(slot, CKF_ENCRYPT | opt_allow_sw, NULL, 0, &opt_mechanism))
+			util_fatal("Encrypt mechanism not supported");
+
+	fprintf(stderr, "Using encrypt algorithm %s\n", p11_mechanism_to_name(opt_mechanism));
+	memset(&mech, 0, sizeof(mech));
+	mech.mechanism = opt_mechanism;
+
+	switch (opt_mechanism) {
+	case CKM_AES_ECB:
+		mech.pParameter = NULL;
+		mech.ulParameterLen = 0;
+		break;
+	case CKM_AES_CBC:
+	case CKM_AES_CBC_PAD:
+		iv_size = 16;
+		iv = get_iv(opt_iv, &iv_size);
+		mech.pParameter = iv;
+		mech.ulParameterLen = iv_size;
+		break;
+	default:
+		util_fatal("Mechanism %s illegal or not supported\n", p11_mechanism_to_name(opt_mechanism));
+	}
+
+	if (opt_input == NULL)
+		fd_in = 0;
+	else if ((fd_in = open(opt_input, O_RDONLY | O_BINARY)) < 0)
+		util_fatal("Cannot open %s: %m", opt_input);
+
+	if (opt_output == NULL) {
+		fd_out = 1;
+	} else {
+		fd_out = open(opt_output, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IRUSR | S_IWUSR);
+		if (fd_out < 0)
 			util_fatal("failed to open %s: %m", opt_output);
 	}
 
-	r = write(fd, out_buffer, out_len);
+	r = read(fd_in, in_buffer, sizeof(in_buffer));
+	in_len = r;
+
 	if (r < 0)
-		util_fatal("Failed to write to %s: %m", opt_output);
-	if (fd != 1)
-		close(fd);
+		util_fatal("Cannot read from %s: %m", opt_input);
+
+	rv = CKR_CANCEL;
+	if (r < (int) sizeof(in_buffer)) {
+		out_len = sizeof(out_buffer);
+		rv = p11->C_EncryptInit(session, &mech, key);
+		if (rv != CKR_OK)
+			p11_fatal("C_EncryptInit", rv);
+		if (getALWAYS_AUTHENTICATE(session, key))
+			login(session, CKU_CONTEXT_SPECIFIC);
+		out_len = sizeof(out_buffer);
+		rv = p11->C_Encrypt(session, in_buffer, in_len, out_buffer, &out_len);
+	}
+	if (rv != CKR_OK) {
+		rv = p11->C_EncryptInit(session, &mech, key);
+		if (rv != CKR_OK)
+			p11_fatal("C_EncryptInit", rv);
+		if (getALWAYS_AUTHENTICATE(session, key))
+			login(session, CKU_CONTEXT_SPECIFIC);
+		do {
+			out_len = sizeof(out_buffer);
+			rv = p11->C_EncryptUpdate(session, in_buffer, in_len, out_buffer, &out_len);
+			if (rv != CKR_OK)
+				p11_fatal("C_EncryptUpdate", rv);
+			r = write(fd_out, out_buffer, out_len);
+			if (r != (int) out_len)
+				util_fatal("Cannot write to %s: %m", opt_output);
+			r = read(fd_in, in_buffer, sizeof(in_buffer));
+			in_len = r;
+		} while (r > 0);
+		out_len = sizeof(out_buffer);
+		rv = p11->C_EncryptFinal(session, out_buffer, &out_len);
+		if (rv != CKR_OK)
+			p11_fatal("C_EncryptFinal", rv);
+	}
+	if (out_len) {
+		r = write(fd_out, out_buffer, out_len);
+		if (r != (int) out_len)
+			util_fatal("Cannot write to %s: %m", opt_output);
+	}
+	if (fd_in != 0)
+		close(fd_in);
+	if (fd_out != 1)
+		close(fd_out);
+
+	free(iv);
 }
 
 
@@ -2464,6 +2824,7 @@
 		{CKA_PRIVATE, &_true, sizeof(_true)},
 		{CKA_SENSITIVE, &_true, sizeof(_true)},
 	};
+	unsigned long int gost_key_type = -1;
 	int n_privkey_attr = 4;
 	unsigned char *ecparams = NULL;
 	size_t ecparams_size;
@@ -2482,7 +2843,7 @@
 					util_fatal("Generate RSA mechanism not supported");
 
 			if (size == NULL)
-				util_fatal("Unknown key type %s", type);
+				util_fatal("Unknown key pair type %s, expecting RSA:<nbytes>", type);
 			key_length = (unsigned long)atol(size);
 			if (key_length != 0)
 				modulusBits = key_length;
@@ -2563,7 +2924,7 @@
 			ecparams = malloc(ecparams_size);
 			if (!ecparams)
 				util_fatal("Allocation error", 0);
-			if (!hex_to_bin(ec_curve_infos[ii].ec_params, ecparams, &ecparams_size)) {
+			if (sc_hex_to_bin(ec_curve_infos[ii].ec_params, ecparams, &ecparams_size)) {
 				fprintf(stderr, "Cannot convert \"%s\"\n", ec_curve_infos[ii].ec_params);
 				util_print_usage_and_die(app_name, options, option_help, NULL);
 			}
@@ -2599,13 +2960,12 @@
 			const struct sc_aid GOST2012_512_PARAMSET_C_OID = { { 0x06, 0x09, 0x2A, 0x85, 0x03, 0x07, 0x01, 0x02, 0x01, 0x02, 0x03 }, 11 };
 			struct sc_aid key_paramset_encoded_oid;
 			struct sc_aid hash_paramset_encoded_oid;
-			unsigned long int gost_key_type = -1;
 			CK_MECHANISM_TYPE mtypes[] = {-1};
 			size_t mtypes_num = sizeof(mtypes)/sizeof(mtypes[0]);
 			const char *p_param_set = type + strlen("GOSTR3410");
 
 			if (p_param_set == NULL)
-				util_fatal("Unknown key type %s", type);
+				util_fatal("Unknown key pair type %s, expecting GOSTR3410:<nbytes>", type);
 
 			if (!strcmp(":A", p_param_set) || !strcmp("-2001:A", p_param_set)) {
 				gost_key_type = CKK_GOSTR3410;
@@ -2667,7 +3027,7 @@
 				hash_paramset_encoded_oid = GOST_HASH2012_512_PARAMSET_OID;
 			}
 			else
-				util_fatal("Unknown key type %s, valid key types for mechanism GOSTR3410 are GOSTR3410-2001:{A,B,C},"
+				util_fatal("Unknown key pair type %s, valid key types for mechanism GOSTR3410 are GOSTR3410-2001:{A,B,C},"
 					" GOSTR3410-2012-256:{A,B,C,D}, GOSTR3410-2012-512:{A,B,C}", type);
 
 			if (!opt_mechanism_used) {
@@ -2704,7 +3064,7 @@
 			}
 		}
 		else {
-			util_fatal("Unknown key type %s", type);
+			util_fatal("Unknown key pair type %s", type);
 		}
 
 		mechanism.mechanism = opt_mechanism;
@@ -2806,7 +3166,7 @@
 					util_fatal("Generate Key mechanism not supported\n");
 
 			if (size == NULL)
-				util_fatal("Unknown key type %s", type);
+				util_fatal("Unknown key type %s, expecting AES:<nbytes>", type);
 			key_length = (unsigned long)atol(size);
 			if (key_length == 0)
 				key_length = 32;
@@ -2826,7 +3186,7 @@
 					util_fatal("Generate Key mechanism not supported\n");
 
 			if (size == NULL)
-				util_fatal("Unknown key type %s", type);
+				util_fatal("Unknown key type %s, expecting DES:<nbytes>", type);
 			key_length = (unsigned long)atol(size);
 			if (key_length == 0)
 				key_length = 8;
@@ -2846,7 +3206,7 @@
 					util_fatal("Generate Key mechanism not supported\n");
 
 			if (size == NULL)
-				util_fatal("Unknown key type %s", type);
+				util_fatal("Unknown key type %s, expecting DES3:<nbytes>", type);
 			key_length = (unsigned long)atol(size);
 			if (key_length == 0)
 				key_length = 16;
@@ -2866,7 +3226,7 @@
 					util_fatal("Generate Key mechanism not supported\n");
 
 			if (size == NULL)
-				util_fatal("Unknown key type %s", type);
+				util_fatal("Unknown key type %s, expecting GENERIC:<nbytes>", type);
 			key_length = (unsigned long)atol(size);
 			if (key_length == 0)
 				key_length = 32;
@@ -2887,14 +3247,43 @@
 			n_attr++;
 		}
 
-		FILL_ATTR(keyTemplate[n_attr], CKA_ENCRYPT, &_true, sizeof(_true));
-		n_attr++;
-		FILL_ATTR(keyTemplate[n_attr], CKA_DECRYPT, &_true, sizeof(_true));
-		n_attr++;
-		FILL_ATTR(keyTemplate[n_attr], CKA_WRAP, &_true, sizeof(_true));
-		n_attr++;
-		FILL_ATTR(keyTemplate[n_attr], CKA_UNWRAP, &_true, sizeof(_true));
-		n_attr++;
+		if (opt_is_extractable != 0) {
+			FILL_ATTR(keyTemplate[n_attr], CKA_EXTRACTABLE, &_true, sizeof(_true));
+			n_attr++;
+		} else {
+			FILL_ATTR(keyTemplate[n_attr], CKA_EXTRACTABLE, &_false, sizeof(_false));
+			n_attr++;
+		}
+
+		if (opt_is_private != 0) {
+			FILL_ATTR(keyTemplate[n_attr], CKA_PRIVATE, &_true, sizeof(_true));
+			n_attr++;
+		} else {
+			FILL_ATTR(keyTemplate[n_attr], CKA_PRIVATE, &_false, sizeof(_false));
+			n_attr++;
+		}
+
+		if (opt_key_usage_default || opt_key_usage_decrypt) {
+			FILL_ATTR(keyTemplate[n_attr], CKA_ENCRYPT, &_true, sizeof(_true));
+			n_attr++;
+			FILL_ATTR(keyTemplate[n_attr], CKA_DECRYPT, &_true, sizeof(_true));
+			n_attr++;
+		}
+
+		if (opt_key_usage_wrap) {
+			FILL_ATTR(keyTemplate[n_attr], CKA_WRAP, &_true, sizeof(_true));
+			n_attr++;
+			FILL_ATTR(keyTemplate[n_attr], CKA_UNWRAP, &_true, sizeof(_true));
+			n_attr++;
+		}
+
+		if (opt_key_usage_sign != 0) {
+			FILL_ATTR(keyTemplate[n_attr], CKA_SIGN, &_true, sizeof(_true));
+			n_attr++;
+			FILL_ATTR(keyTemplate[n_attr], CKA_VERIFY, &_true, sizeof(_true));
+			n_attr++;
+		}
+
 		FILL_ATTR(keyTemplate[n_attr], CKA_VALUE_LEN, &key_length, sizeof(key_length));
 		n_attr++;
 
@@ -2931,6 +3320,211 @@
 	return 1;
 }
 
+static int
+unwrap_key(CK_SESSION_HANDLE session)
+{
+	CK_MECHANISM mechanism;
+	CK_OBJECT_CLASS secret_key_class = CKO_SECRET_KEY;
+	CK_BBOOL _true = TRUE;
+	CK_BBOOL _false = FALSE;
+	CK_KEY_TYPE key_type = CKK_AES;
+	CK_ULONG key_length;
+	const char *length;
+	CK_ATTRIBUTE keyTemplate[20] = {
+		{CKA_CLASS, &secret_key_class, sizeof(secret_key_class)},
+		{CKA_TOKEN, &_true, sizeof(_true)},
+	};
+	CK_OBJECT_HANDLE hSecretKey;
+	int n_attr = 2;
+	CK_RV rv;
+	int r, fd;
+	unsigned char in_buffer[1024];
+	CK_ULONG wrapped_key_length;
+	CK_BYTE_PTR pWrappedKey;
+	CK_BYTE_PTR iv = NULL;
+	size_t iv_size = 0;
+	CK_OBJECT_HANDLE hUnwrappingKey;
+
+	if (!find_object(session, CKO_PRIVATE_KEY, &hUnwrappingKey,
+			 opt_object_id_len ? opt_object_id : NULL, opt_object_id_len, 0))
+		if (!find_object(session, CKO_SECRET_KEY, &hUnwrappingKey,
+				 opt_object_id_len ? opt_object_id : NULL, opt_object_id_len, 0))
+			util_fatal("Private/secret key not found");
+
+	if (!opt_mechanism_used)
+		util_fatal("Unable to unwrap, no mechanism specified\n");
+
+	mechanism.mechanism = opt_mechanism;
+	mechanism.pParameter = NULL_PTR;
+	mechanism.ulParameterLen = 0;
+
+	if (opt_input == NULL)
+		fd = 0;
+	else if ((fd = open(opt_input, O_RDONLY | O_BINARY)) < 0)
+		util_fatal("Cannot open %s: %m", opt_input);
+
+	r = read(fd, in_buffer, sizeof(in_buffer));
+	if (r < 0)
+		util_fatal("Cannot read from %s: %m", opt_input);
+	wrapped_key_length = r;
+	if (fd != 0)
+		close(fd);
+	pWrappedKey = in_buffer;
+
+	if (opt_mechanism == CKM_AES_CBC || opt_mechanism == CKM_AES_CBC_PAD) {
+		iv_size = 16;
+		iv = get_iv(opt_iv, &iv_size);
+		mechanism.pParameter = iv;
+		mechanism.ulParameterLen = iv_size;
+	}
+
+	if (opt_key_type != NULL) {
+		if (strncasecmp(opt_key_type, "AES:", strlen("AES:")) == 0) {
+			length = opt_key_type + strlen("AES:");
+			key_type = CKK_AES;
+
+		} else if (strncasecmp(opt_key_type, "GENERIC:", strlen("GENERIC:")) == 0) {
+			length = opt_key_type + strlen("GENERIC:");
+			key_type = CKK_GENERIC_SECRET;
+
+		} else {
+			util_fatal("Unsupported key type %s", opt_key_type);
+		}
+
+		FILL_ATTR(keyTemplate[n_attr], CKA_KEY_TYPE, &key_type, sizeof(key_type));
+		n_attr++;
+
+		if (opt_is_sensitive != 0) {
+			FILL_ATTR(keyTemplate[n_attr], CKA_SENSITIVE, &_true, sizeof(_true));
+			n_attr++;
+		} else {
+			FILL_ATTR(keyTemplate[n_attr], CKA_SENSITIVE, &_false, sizeof(_false));
+			n_attr++;
+		}
+
+		if (opt_key_usage_default || opt_key_usage_decrypt) {
+			FILL_ATTR(keyTemplate[n_attr], CKA_ENCRYPT, &_true, sizeof(_true));
+			n_attr++;
+			FILL_ATTR(keyTemplate[n_attr], CKA_DECRYPT, &_true, sizeof(_true));
+			n_attr++;
+		}
+		if (opt_key_usage_wrap) {
+			FILL_ATTR(keyTemplate[n_attr], CKA_WRAP, &_true, sizeof(_true));
+			n_attr++;
+			FILL_ATTR(keyTemplate[n_attr], CKA_UNWRAP, &_true, sizeof(_true));
+			n_attr++;
+		}
+
+		if (opt_is_extractable != 0) {
+			FILL_ATTR(keyTemplate[n_attr], CKA_EXTRACTABLE, &_true, sizeof(_true));
+			n_attr++;
+		} else {
+			FILL_ATTR(keyTemplate[n_attr], CKA_EXTRACTABLE, &_false, sizeof(_true));
+			n_attr++;
+		}
+		/* softhsm2 does not allow to attribute CKA_VALUE_LEN, but MyEID card must have this attribute
+                   specified. We set CKA_VALUE_LEN only if the user sets it in the key specification. */
+		key_length = (unsigned long)atol(length);
+		if (key_length != 0) {
+			FILL_ATTR(keyTemplate[n_attr], CKA_VALUE_LEN, &key_length, sizeof(key_length));
+			n_attr++;
+		}
+	}
+
+	if (opt_application_label != NULL) {
+		FILL_ATTR(keyTemplate[n_attr], CKA_LABEL, opt_application_label, strlen(opt_application_label));
+		n_attr++;
+	}
+
+	if (opt_application_id != NULL) {
+		CK_BYTE object_id[100];
+		size_t id_len;
+
+		id_len = sizeof(object_id);
+		if (!sc_hex_to_bin(opt_application_id, object_id, &id_len)) {
+			FILL_ATTR(keyTemplate[n_attr], CKA_ID, object_id, id_len);
+			n_attr++;
+		}
+	}
+
+	if (opt_allowed_mechanisms_len > 0) {
+		FILL_ATTR(keyTemplate[n_attr], CKA_ALLOWED_MECHANISMS, opt_allowed_mechanisms,
+			  sizeof(CK_MECHANISM_TYPE) * opt_allowed_mechanisms_len);
+		n_attr++;
+	}
+	rv = p11->C_UnwrapKey(session, &mechanism, hUnwrappingKey,
+			      pWrappedKey, wrapped_key_length, keyTemplate, n_attr, &hSecretKey);
+	if (rv != CKR_OK)
+		p11_fatal("C_UnwrapKey", rv);
+
+	free(iv);
+	printf("Key unwrapped\n");
+	show_object(session, hSecretKey);
+	return 1;
+}
+
+static int
+wrap_key(CK_SESSION_HANDLE session)
+{
+	CK_BYTE pWrappedKey[4096];
+	CK_ULONG pulWrappedKeyLen = sizeof(pWrappedKey);
+	CK_MECHANISM mechanism;
+	CK_OBJECT_HANDLE hWrappingKey;	// wrapping key
+	CK_OBJECT_HANDLE hkey;	// key to be wrapped
+	CK_RV rv;
+	CK_BYTE hkey_id[100];
+	size_t hkey_id_len;
+	int fd, r;
+	CK_BYTE_PTR iv = NULL;
+	size_t iv_size = 0;
+
+	if (NULL == opt_application_id)
+		util_fatal("Use --application-id to specify secret key (to be wrapped)");
+	if (!opt_mechanism_used)
+		util_fatal("Unable to wrap, no mechanism specified\n");
+
+	mechanism.mechanism = opt_mechanism;
+	mechanism.pParameter = NULL_PTR;
+	mechanism.ulParameterLen = 0;
+	if (opt_mechanism == CKM_AES_CBC || opt_mechanism == CKM_AES_CBC_PAD) {
+		iv_size = 16;
+		iv = get_iv(opt_iv, &iv_size);
+		mechanism.pParameter = iv;
+		mechanism.ulParameterLen = iv_size;
+	}
+
+	hkey_id_len = sizeof(hkey_id);
+	if (sc_hex_to_bin(opt_application_id, hkey_id, &hkey_id_len))
+		util_fatal("Invalid application-id \"%s\"\n", opt_application_id);
+
+	if (!find_object(session, CKO_SECRET_KEY, &hkey, hkey_id_len ? hkey_id : NULL, hkey_id_len, 0))
+		util_fatal("Secret key (to be wrapped) not found");
+
+	if (!find_object(session, CKO_PUBLIC_KEY, &hWrappingKey,
+			 opt_object_id_len ? opt_object_id : NULL, opt_object_id_len, 0))
+		if (!find_object(session, CKO_SECRET_KEY, &hWrappingKey,
+				 opt_object_id_len ? opt_object_id : NULL, opt_object_id_len, 0))
+			util_fatal("Public/secret key (wrapping key) not found");
+
+	rv = p11->C_WrapKey(session, &mechanism, hWrappingKey, hkey, pWrappedKey, &pulWrappedKeyLen);
+	if (rv != CKR_OK)
+		p11_fatal("C_WrapKey", rv);
+	printf("Key wrapped\n");
+
+	if (opt_output == NULL)
+		fd = 1;
+	else if ((fd = open(opt_output, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IRUSR | S_IWUSR)) < 0)
+		util_fatal("failed to open %s: %m", opt_output);
+
+	r = write(fd, pWrappedKey, pulWrappedKeyLen);
+
+	if (r < 0)
+		util_fatal("Failed to write to %s: %m", opt_output);
+	if (fd != 1)
+		close(fd);
+	free(iv);
+	return 1;
+}
 
 #ifdef ENABLE_OPENSSL
 static void	parse_certificate(struct x509cert_info *cert,
@@ -3040,11 +3634,11 @@
 static int
 parse_rsa_pkey(EVP_PKEY *pkey, int private, struct rsakey_info *rsa)
 {
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 	RSA *r;
 	const BIGNUM *r_n, *r_e, *r_d;
 	const BIGNUM *r_p, *r_q;
 	const BIGNUM *r_dmp1, *r_dmq1, *r_iqmp;
-
 	r = EVP_PKEY_get1_RSA(pkey);
 	if (!r) {
 		if (private)
@@ -3054,25 +3648,59 @@
 	}
 
 	RSA_get0_key(r, &r_n, &r_e, NULL);
+#else
+	BIGNUM *r_n = NULL, *r_e = NULL, *r_d = NULL;
+	BIGNUM *r_p = NULL, *r_q = NULL;
+	BIGNUM *r_dmp1 = NULL, *r_dmq1 = NULL, *r_iqmp = NULL;
+	if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_N, &r_n) != 1 ||
+		EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_E, &r_e) != 1) {
+		if (private)
+			util_fatal("OpenSSL error during RSA private key parsing");
+		else
+			util_fatal("OpenSSL error during RSA public key parsing");
+	 }
+#endif
 	RSA_GET_BN(rsa, modulus, r_n);
 	RSA_GET_BN(rsa, public_exponent, r_e);
 
 	if (private) {
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 		RSA_get0_key(r, NULL, NULL, &r_d);
+		RSA_get0_factors(r, &r_p, &r_q);
+		RSA_get0_crt_params(r, &r_dmp1, &r_dmq1, &r_iqmp);
+#else
+		if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, &r_d) != 1 ||
+			EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR1, &r_p) != 1 ||
+			EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_FACTOR2, &r_q) != 1 ||
+			EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT1, &r_dmp1) != 1 ||
+			EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT2, &r_dmq1) != 1 ||
+			EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_RSA_EXPONENT3, &r_iqmp) != 1) {
+			util_fatal("OpenSSL error during RSA private key parsing");
+		}
+#endif
 		RSA_GET_BN(rsa, private_exponent, r_d);
 
-		RSA_get0_factors(r, &r_p, &r_q);
 		RSA_GET_BN(rsa, prime_1, r_p);
 		RSA_GET_BN(rsa, prime_2, r_q);
 
-		RSA_get0_crt_params(r, &r_dmp1, &r_dmq1, &r_iqmp);
 		RSA_GET_BN(rsa, exponent_1, r_dmp1);
 		RSA_GET_BN(rsa, exponent_2, r_dmq1);
 		RSA_GET_BN(rsa, coefficient, r_iqmp);
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+		BN_clear_free(r_d);
+		BN_clear_free(r_p);
+		BN_clear_free(r_q);
+		BN_clear_free(r_dmp1);
+		BN_clear_free(r_dmq1);
+		BN_clear_free(r_iqmp);
+#endif
 	}
-
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 	RSA_free(r);
-
+#else
+	BN_free(r_n);
+	BN_free(r_e);
+#endif
 	return 0;
 }
 
@@ -3080,17 +3708,30 @@
 static int
 parse_gost_pkey(EVP_PKEY *pkey, int private, struct gostkey_info *gost)
 {
-	EC_KEY *src = EVP_PKEY_get0(pkey);
 	unsigned char *pder;
-	const BIGNUM *bignum;
 	BIGNUM *X, *Y;
-	const EC_POINT *point;
 	int nid, rv;
-
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	const BIGNUM *bignum;
+	const EC_GROUP *group;
+	const EC_POINT *point;
+	EC_KEY *src = EVP_PKEY_get0(pkey);
 	if (!src)
 		return -1;
+	group = EC_KEY_get0_group(src);
+	nid = EC_GROUP_get_curve_name(group);
+#else
+	unsigned char *pubkey = NULL;
+	size_t pubkey_len = 0;
+	BIGNUM *bignum = NULL;
+	EC_GROUP *group = NULL;
+	EC_POINT *point = NULL;
+	char name[256]; size_t len = 0;
+	if (EVP_PKEY_get_group_name(pkey, name, sizeof(name), &len) != 1)
+		return -1;
 
-	nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(EVP_PKEY_get0(pkey)));
+	nid = OBJ_txt2nid(name);
+#endif
 	rv = i2d_ASN1_OBJECT(OBJ_nid2obj(nid), NULL);
 	if (rv < 0)
 		return -1;
@@ -3104,22 +3745,45 @@
 	gost->param_oid.len = rv;
 
 	if (private) {
-		bignum = EC_KEY_get0_private_key(EVP_PKEY_get0(pkey));
-
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+		bignum = EC_KEY_get0_private_key(src);
+#else
+		if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &bignum) != 1)
+			return -1;
+#endif
 		gost->private.len = BN_num_bytes(bignum);
 		gost->private.value = malloc(gost->private.len);
-		if (!gost->private.value)
+		if (!gost->private.value) {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+			BN_free(bignum);
+#endif
 			return -1;
+		}
 		BN_bn2bin(bignum, gost->private.value);
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+		BN_free(bignum);
+#endif
 	}
 	else {
 		X = BN_new();
 		Y = BN_new();
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 		point = EC_KEY_get0_public_key(src);
+#else
+		group = EC_GROUP_new_by_curve_name(nid);
+		EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, NULL, 0, &pubkey_len);
+		if (!(pubkey = malloc(pubkey_len)) ||
+			EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_PUB_KEY, pubkey, pubkey_len, NULL) != 1 ||
+			!(point = EC_POINT_new(group)) ||
+			EC_POINT_oct2point(group, point, pubkey, pubkey_len, NULL) != 1) {
+			EC_GROUP_free(group);
+			EC_POINT_free(point);
+			return -1;
+		}
+#endif
 		rv = -1;
-		if (X && Y && point && EC_KEY_get0_group(src))
-			rv = EC_POINT_get_affine_coordinates_GFp(EC_KEY_get0_group(src),
-					point, X, Y, NULL);
+		if (X && Y && point && group)
+			rv = EC_POINT_get_affine_coordinates(group, point, X, Y, NULL);
 		if (rv == 1) {
 			gost->public.len = BN_num_bytes(X) + BN_num_bytes(Y);
 			gost->public.value = malloc(gost->public.len);
@@ -3133,44 +3797,67 @@
 		}
 		BN_free(X);
 		BN_free(Y);
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+		EC_GROUP_free(group);
+		EC_POINT_free(point);
+#endif
 		if (rv != 1)
 			return -1;
 	}
-
 	return 0;
 }
 
 static int
 parse_ec_pkey(EVP_PKEY *pkey, int private, struct gostkey_info *gost)
 {
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 	const EC_KEY *src = EVP_PKEY_get0_EC_KEY(pkey);
 	const BIGNUM *bignum;
-
 	if (!src)
 		return -1;
-
 	gost->param_oid.len = i2d_ECParameters((EC_KEY *)src, &gost->param_oid.value);
-	if (gost->param_oid.len <= 0)
+#else
+	BIGNUM *bignum = NULL;
+	gost->param_oid.len = i2d_KeyParams(pkey, &gost->param_oid.value);
+#endif
+	if (gost->param_oid.len <= 0) {
 		return -1;
+	}
 
 	if (private) {
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 		bignum = EC_KEY_get0_private_key(src);
-
+#else
+		if (EVP_PKEY_get_bn_param(pkey, OSSL_PKEY_PARAM_PRIV_KEY, &bignum) != 1) {
+			return -1;
+		}
+#endif
 		gost->private.len = BN_num_bytes(bignum);
 		gost->private.value = malloc(gost->private.len);
-		if (!gost->private.value)
+		if (!gost->private.value) {
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+			BN_free(bignum);
+#endif
 			return -1;
+		}
 		BN_bn2bin(bignum, gost->private.value);
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+		BN_free(bignum);
+#endif
 	}
 	else {
 		unsigned char buf[512], *point;
-		int point_len, header_len;
+		size_t point_len, header_len;
 		const int MAX_HEADER_LEN = 3;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 		const EC_GROUP *ecgroup = EC_KEY_get0_group(src);
 		const EC_POINT *ecpoint = EC_KEY_get0_public_key(src);
 		if (!ecgroup || !ecpoint)
 			return -1;
 		point_len = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, buf, sizeof(buf), NULL);
+#else
+		EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, buf, sizeof(buf), &point_len);
+#endif
 		gost->public.value = malloc(MAX_HEADER_LEN+point_len);
 		if (!gost->public.value)
 			return -1;
@@ -3333,6 +4020,10 @@
 			FILL_ATTR(cert_templ[n_cert_attr], CKA_ID, opt_object_id, opt_object_id_len);
 			n_cert_attr++;
 		}
+		if (opt_is_destroyable == 0) {
+			FILL_ATTR(cert_templ[n_cert_attr], CKA_DESTROYABLE, &_false, sizeof(_false));
+			n_cert_attr++;
+		}
 #ifdef ENABLE_OPENSSL
 		/* according to PKCS #11 CKA_SUBJECT MUST be specified */
 		FILL_ATTR(cert_templ[n_cert_attr], CKA_SUBJECT, cert.subject, cert.subject_len);
@@ -3594,6 +4285,27 @@
 			n_seckey_attr++;
 		}
 
+		if (opt_key_usage_default || opt_key_usage_decrypt) {
+			FILL_ATTR(seckey_templ[n_seckey_attr], CKA_ENCRYPT, &_true, sizeof(_true));
+			n_seckey_attr++;
+			FILL_ATTR(seckey_templ[n_seckey_attr], CKA_DECRYPT, &_true, sizeof(_true));
+			n_seckey_attr++;
+		}
+
+		if (opt_key_usage_wrap) {
+			FILL_ATTR(seckey_templ[n_seckey_attr], CKA_WRAP, &_true, sizeof(_true));
+			n_seckey_attr++;
+			FILL_ATTR(seckey_templ[n_seckey_attr], CKA_UNWRAP, &_true, sizeof(_true));
+			n_seckey_attr++;
+		}
+
+		if (opt_key_usage_sign != 0) {
+			FILL_ATTR(seckey_templ[n_seckey_attr], CKA_SIGN, &_true, sizeof(_true));
+			n_seckey_attr++;
+			FILL_ATTR(seckey_templ[n_seckey_attr], CKA_VERIFY, &_true, sizeof(_true));
+			n_seckey_attr++;
+		}
+
 		if (opt_object_label != NULL) {
 			FILL_ATTR(seckey_templ[n_seckey_attr], CKA_LABEL, opt_object_label, strlen(opt_object_label));
 			n_seckey_attr++;
@@ -3704,8 +4416,8 @@
 	CK_ATTRIBUTE templ[] = {{CKA_ID, new_object_id, new_object_id_len}};
 	CK_RV rv;
 
-	if (!find_object(session, opt_object_class, &obj, opt_object_id, opt_object_id_len, 0)) {
-		fprintf(stderr, "set_id(): couldn't find the object\n");
+	if (!find_object_id_or_label(session, opt_object_class, &obj, opt_object_id, opt_object_id_len, opt_object_label, 0)) {
+		fprintf(stderr, "set_id(): couldn't find the object by id %s label\n", (opt_object_label && opt_object_id_len) ? "and" : "or");
 		return;
 	}
 
@@ -3768,11 +4480,13 @@
 }
 
 
-static int find_object(CK_SESSION_HANDLE sess, CK_OBJECT_CLASS cls,
+static int find_object_id_or_label(CK_SESSION_HANDLE sess, CK_OBJECT_CLASS cls,
 		CK_OBJECT_HANDLE_PTR ret,
-		const unsigned char *id, size_t id_len, int obj_index)
+		const unsigned char *id, size_t id_len,
+		const char *label,
+		int obj_index)
 {
-	CK_ATTRIBUTE attrs[2];
+	CK_ATTRIBUTE attrs[3];
 	unsigned int nattrs = 0;
 	CK_ULONG count;
 	CK_RV rv;
@@ -3782,12 +4496,18 @@
 	attrs[0].pValue = &cls;
 	attrs[0].ulValueLen = sizeof(cls);
 	nattrs++;
-	if (id) {
+	if (id && id_len) {
 		attrs[nattrs].type = CKA_ID;
 		attrs[nattrs].pValue = (void *) id;
 		attrs[nattrs].ulValueLen = id_len;
 		nattrs++;
 	}
+	if (label) {
+		attrs[nattrs].type = CKA_LABEL;
+		attrs[nattrs].pValue = (void *) label;
+		attrs[nattrs].ulValueLen = strlen(label);
+		nattrs++;
+	}
 
 	rv = p11->C_FindObjectsInit(sess, attrs, nattrs);
 	if (rv != CKR_OK)
@@ -3804,13 +4524,39 @@
 	if (rv != CKR_OK)
 		p11_fatal("C_FindObjects", rv);
 
-done:	if (count == 0)
+done:
+	if (count == 0)
 		*ret = CK_INVALID_HANDLE;
 	p11->C_FindObjectsFinal(sess);
 
 	return count;
 }
 
+static int find_object(CK_SESSION_HANDLE sess, CK_OBJECT_CLASS cls,
+		CK_OBJECT_HANDLE_PTR ret,
+		const unsigned char *id, size_t id_len, int obj_index)
+{
+	return find_object_id_or_label(sess, cls, ret, id, id_len, NULL, obj_index);
+}
+
+static int find_object_flags(CK_SESSION_HANDLE sess, uint16_t mf_flags,
+		CK_OBJECT_HANDLE_PTR ret,
+		const unsigned char *id, size_t id_len, int obj_index)
+{
+	int count;
+	char err_key_types[1024] = { 0 };
+
+	if (mf_flags & MF_CKO_SECRET_KEY) {
+		count = find_object(sess, CKO_SECRET_KEY, ret, id, id_len, obj_index);
+		if (count)
+			return count;
+
+		strncat(err_key_types, "Secret", sizeof(err_key_types)-1);
+	}
+
+	util_fatal("Could not find key of type: %s", err_key_types);
+}
+
 static CK_RV find_object_with_attributes(CK_SESSION_HANDLE session,
 			CK_OBJECT_HANDLE *out,
 			CK_ATTRIBUTE *attrs, CK_ULONG attrsLen,
@@ -3959,9 +4705,6 @@
 	CK_ECDH1_DERIVE_PARAMS ecdh_parms;
 	CK_RV rv;
 	BIO *bio_in = NULL;
-	EC_KEY  *eckey = NULL;
-	const EC_GROUP *ecgroup = NULL;
-	const EC_POINT *ecpoint = NULL;
 	unsigned char *buf = NULL;
 	size_t buf_size = 0;
 	CK_ULONG key_len = 0;
@@ -3969,6 +4712,16 @@
 	unsigned char * der = NULL;
 	unsigned char * derp = NULL;
 	size_t  der_size = 0;
+	EVP_PKEY *pkey = NULL;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	EC_KEY *eckey = NULL;
+	const EC_GROUP *ecgroup = NULL;
+	const EC_POINT *ecpoint = NULL;
+#else
+	EC_GROUP *ecgroup = NULL;
+	char name[256]; size_t len = 0;
+	int nid = 0;
+#endif
 
 	printf("Using derive algorithm 0x%8.8lx %s\n", opt_mechanism, p11_mechanism_to_name(mech_mech));
 	memset(&mech, 0, sizeof(mech));
@@ -3979,15 +4732,24 @@
 	if (BIO_read_filename(bio_in, opt_input) <= 0)
 		util_fatal("Cannot open %s: %m", opt_input);
 
-	eckey = d2i_EC_PUBKEY_bio(bio_in, NULL);
-	if (!eckey)
+	pkey = d2i_PUBKEY_bio(bio_in, NULL);
+
+	if (!pkey)
 		util_fatal("Cannot read EC key from %s", opt_input);
 
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	eckey = EVP_PKEY_get0_EC_KEY(pkey);
 	ecpoint = EC_KEY_get0_public_key(eckey);
 	ecgroup = EC_KEY_get0_group(eckey);
 
 	if (!ecpoint || !ecgroup)
 		util_fatal("Failed to parse other EC key from %s", opt_input);
+#else
+	if (EVP_PKEY_get_group_name(pkey, name, sizeof(name), &len) != 1
+	 || (nid = OBJ_txt2nid(name)) == NID_undef
+	 || (ecgroup = EC_GROUP_new_by_curve_name(nid)) == NULL)
+		util_fatal("Failed to parse other EC key from %s", opt_input);
+#endif
 
 	/* both eckeys must be same curve */
 	key_len = (EC_GROUP_get_degree(ecgroup) + 7) / 8;
@@ -4001,11 +4763,23 @@
 		n_attrs++;
 	}
 
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 	buf_size = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, NULL,	    0, NULL);
 	buf = (unsigned char *)malloc(buf_size);
 	if (buf == NULL)
 	    util_fatal("malloc() failure\n");
 	buf_size = EC_POINT_point2oct(ecgroup, ecpoint, POINT_CONVERSION_UNCOMPRESSED, buf, buf_size, NULL);
+#else
+	EC_GROUP_free(ecgroup);
+	EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0, &buf_size);
+	if ((buf = (unsigned char *)malloc(buf_size)) == NULL)
+	    util_fatal("malloc() failure\n");
+
+	if (EVP_PKEY_get_octet_string_param(pkey, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, buf, buf_size, NULL) != 1) {
+		free(buf);
+		util_fatal("Failed to parse other EC key from %s", opt_input);
+	}
+#endif
 
 	if (opt_derive_pass_der) {
 		octet = ASN1_OCTET_STRING_new();
@@ -4020,7 +4794,7 @@
 	}
 
 	BIO_free(bio_in);
-	EC_KEY_free(eckey);
+	EVP_PKEY_free(pkey);
 
 	memset(&ecdh_parms, 0, sizeof(ecdh_parms));
 	ecdh_parms.kdf = CKD_NULL;
@@ -4103,6 +4877,7 @@
 	unsigned char	*id, *oid, *value;
 	const char      *sepa;
 	char		*label;
+	char		*unique_id;
 	int		pub = 1;
 	int		sec = 0;
 
@@ -4418,6 +5193,10 @@
 			printf("\n");
 		}
 	}
+	if ((unique_id = getUNIQUE_ID(sess, obj, NULL)) != NULL) {
+		printf("  Unique ID:  %s\n", unique_id);
+		free(unique_id);
+	}
 
 	suppress_warn = 0;
 }
@@ -4428,8 +5207,10 @@
 	CK_ULONG	size;
 	unsigned char	*id;
 	char		*label;
+	char		*unique_id;
 #if defined(ENABLE_OPENSSL)
 	unsigned char	*subject;
+	unsigned char	*serial_number;
 #endif /* ENABLE_OPENSSL */
 
 	printf("Certificate Object; type = ");
@@ -4469,6 +5250,21 @@
 		}
 		free(subject);
 	}
+	if ((serial_number = getSERIAL_NUMBER(sess, obj, &size)) != NULL) {
+		ASN1_INTEGER* serial = NULL;
+		const unsigned char *tmp = serial_number;
+		serial = d2i_ASN1_INTEGER(NULL, &tmp, size);
+		if (serial) {
+			BIO *bio = BIO_new(BIO_s_file());
+			BIO_set_fp(bio, stdout, BIO_NOCLOSE);
+			BIO_printf(bio, "  serial:     ");
+			i2a_ASN1_INTEGER(bio, serial);
+			BIO_printf(bio, "\n");
+			BIO_free(bio);
+			ASN1_INTEGER_free(serial);
+		}
+		free(serial_number);
+	}
 #endif /* ENABLE_OPENSSL */
 
 	if ((id = getID(sess, obj, &size)) != NULL && size) {
@@ -4480,6 +5276,10 @@
 		printf("\n");
 		free(id);
 	}
+	if ((unique_id = getUNIQUE_ID(sess, obj, NULL)) != NULL) {
+		printf("  Unique ID:  %s\n", unique_id);
+		free(unique_id);
+	}
 }
 
 static void show_dobj(CK_SESSION_HANDLE sess, CK_OBJECT_HANDLE obj)
@@ -4548,7 +5348,7 @@
 	printf("Profile object %u\n", (unsigned int) obj);
 	printf("  profile_id:          ");
 	if ((id = getPROFILE_ID(sess, obj)) != 0) {
-		printf("'%lu'\n", id);
+		printf("%s (%lu)\n", p11_profile_to_name(id), id);
 	} else {
 		printf("<empty>\n");
 	}
@@ -4712,21 +5512,26 @@
 	if (clazz == CKO_PUBLIC_KEY) {
 #ifdef ENABLE_OPENSSL
 		long derlen;
+		EVP_PKEY *pkey = NULL;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+		EVP_PKEY_CTX *ctx = NULL;
+		OSSL_PARAM *params = NULL;
+		OSSL_PARAM_BLD *bld = NULL;
+#endif
+
 		BIO *pout = BIO_new(BIO_s_mem());
 		if (!pout)
 			util_fatal("out of memory");
 
 		type = getKEY_TYPE(session, obj);
 		if (type == CKK_RSA) {
-			RSA *rsa;
 			BIGNUM *rsa_n = NULL;
 			BIGNUM *rsa_e = NULL;
-
-
-			rsa = RSA_new();
-			if (rsa == NULL)
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+			RSA *rsa = RSA_new();
+			if (!rsa)
 				util_fatal("out of memory");
-
+#endif
 			if ((value = getMODULUS(session, obj, &len))) {
 				if (!(rsa_n = BN_bin2bn(value, len, NULL)))
 					util_fatal("cannot parse MODULUS");
@@ -4740,29 +5545,71 @@
 				free(value);
 			} else
 				util_fatal("cannot obtain PUBLIC_EXPONENT");
-
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 			if (RSA_set0_key(rsa, rsa_n, rsa_e, NULL) != 1)
 				util_fatal("cannot set RSA values");
 
 			if (!i2d_RSA_PUBKEY_bio(pout, rsa))
 				util_fatal("cannot convert RSA public key to DER");
 			RSA_free(rsa);
+#else
+			ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL);
+			if (!ctx)
+				util_fatal("out of memory");
+			if (!(bld = OSSL_PARAM_BLD_new()) ||
+				OSSL_PARAM_BLD_push_BN(bld, "n", rsa_n) != 1 ||
+				OSSL_PARAM_BLD_push_BN(bld, "e", rsa_e) != 1 ||
+				!(params = OSSL_PARAM_BLD_to_param(bld))) {
+				OSSL_PARAM_BLD_free(bld);
+				EVP_PKEY_CTX_free(ctx);
+				OSSL_PARAM_free(params);
+			 	util_fatal("cannot set RSA values");
+			}
+			OSSL_PARAM_BLD_free(bld);
+			if (EVP_PKEY_fromdata_init(ctx) != 1 ||
+				EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) != 1) {
+				EVP_PKEY_CTX_free(ctx);
+				OSSL_PARAM_free(params);
+			 	util_fatal("cannot set RSA values");
+			}
+			OSSL_PARAM_free(params);
+			if (i2d_PUBKEY_bio(pout, pkey) != 1) {
+				EVP_PKEY_CTX_free(ctx);
+				util_fatal("cannot convert RSA public key to DER");
+			}
+			EVP_PKEY_free(pkey);
+			EVP_PKEY_CTX_free(ctx);
+#endif
 #if !defined(OPENSSL_NO_EC)
 		} else if (type == CKK_EC) {
-			EC_KEY *ec;
 			CK_BYTE *params;
 			const unsigned char *a;
+			size_t a_len = 0;
 			ASN1_OCTET_STRING *os;
-			EC_KEY *success = NULL;
+			int success = 0;
+			EC_POINT *point = NULL;
 
-			ec = EC_KEY_new();
-			if (ec == NULL)
-				util_fatal("out of memory");
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+			const EC_GROUP *group = NULL;
+			EC_KEY *ec = EC_KEY_new();
+			pkey = EVP_PKEY_new();
+#else
+			EC_GROUP *group = NULL;
+			char group_name[80];
+			OSSL_PARAM *old = NULL, *new = NULL, *p = NULL;
+			OSSL_PARAM_BLD *bld = NULL;
+#endif
 
 			if ((params = getEC_PARAMS(session, obj, &len))) {
 				const unsigned char *a = params;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 				if (!d2i_ECParameters(&ec, &a, (long)len))
 					util_fatal("cannot parse EC_PARAMS");
+				EVP_PKEY_assign_EC_KEY(pkey, ec);
+#else
+				if (!d2i_KeyParams(EVP_PKEY_EC, &pkey, &a, len))
+					util_fatal("cannot parse EC_PARAMS");
+#endif
 				free(params);
 			} else
 				util_fatal("cannot obtain EC_PARAMS");
@@ -4771,21 +5618,73 @@
 			/* PKCS#11-compliant modules should return ASN1_OCTET_STRING */
 			a = value;
 			os = d2i_ASN1_OCTET_STRING(NULL, &a, (long)len);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+			group = EC_KEY_get0_group(EVP_PKEY_get0_EC_KEY(pkey));
+#else
+			if (EVP_PKEY_get_group_name(pkey, group_name, sizeof(group_name), NULL) != 1)
+				util_fatal("cannot obtain EC_PARAMS");
+			group = EC_GROUP_new_by_curve_name(OBJ_txt2nid(group_name));
+#endif
+			point = EC_POINT_new(group);
 			if (os) {
 				a = os->data;
-				success = o2i_ECPublicKey(&ec, &a, os->length);
-				ASN1_STRING_free(os);
+				a_len = os->length;
+				success = EC_POINT_oct2point(group, point, a, a_len, NULL);
 			}
 			if (!success) { /* Workaround for broken PKCS#11 modules */
+				ASN1_STRING_free(os);
 				a = value;
-				success = o2i_ECPublicKey(&ec, &a, len);
+				a_len = len;
+				if (!EC_POINT_oct2point(group, point, a, len, NULL)) {
+					free(value);
+					util_fatal("cannot obtain and parse EC_POINT");
+				}
 			}
+
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+			if (success)
+				ASN1_STRING_free(os);
+			free(value);
+			EC_KEY_set_public_key(EVP_PKEY_get0_EC_KEY(pkey), point);
+#else
+			if (!(bld = OSSL_PARAM_BLD_new()) ||
+				EVP_PKEY_todata(pkey, EVP_PKEY_PUBLIC_KEY, &old) != 1 ||
+				OSSL_PARAM_BLD_push_octet_string(bld, "pub", a, a_len) != 1 ||
+				!(new = OSSL_PARAM_BLD_to_param(bld)) ||
+				!(p = OSSL_PARAM_merge(old, new))) {
+					OSSL_PARAM_BLD_free(bld);
+					OSSL_PARAM_free(old);
+					OSSL_PARAM_free(new);
+					OSSL_PARAM_free(p);
+					if (success)
+						ASN1_STRING_free(os);
+					free(value);
+					util_fatal("cannot set OSSL_PARAM");
+			}
+			OSSL_PARAM_BLD_free(bld);
+			OSSL_PARAM_free(old);
+			OSSL_PARAM_free(new);
+			if (success)
+				ASN1_STRING_free(os);
 			free(value);
-			if (!success)
-				util_fatal("cannot obtain and parse EC_POINT");
-			if (!i2d_EC_PUBKEY_bio(pout, ec))
+
+			if (!(ctx = EVP_PKEY_CTX_new_from_name(NULL, "EC", NULL)) ||
+				EVP_PKEY_fromdata_init(ctx) != 1) {
+					OSSL_PARAM_free(p);
+					EVP_PKEY_CTX_free(ctx);
+					util_fatal("cannot set CTX");
+			}
+			EVP_PKEY_free(pkey);
+			pkey = NULL;
+			if (EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, p) != 1) {
+					OSSL_PARAM_free(p);
+					EVP_PKEY_CTX_free(ctx);
+					util_fatal("cannot create EVP_PKEY");
+			}
+
+#endif
+			if (!i2d_PUBKEY_bio(pout, pkey))
 				util_fatal("cannot convert EC public key to DER");
-			EC_KEY_free(ec);
 #endif
 #ifdef EVP_PKEY_ED25519
 		} else if (type == CKK_EC_EDWARDS) {
@@ -4979,22 +5878,24 @@
 	CK_ULONG        hashLen1, hashLen2;
 	CK_MECHANISM_TYPE firstMechType;
 	CK_SESSION_INFO sessionInfo;
-
 	CK_MECHANISM_TYPE mechTypes[] = {
 		CKM_MD5,
-		CKM_SHA_1,
 		CKM_RIPEMD160,
+		CKM_SHA_1,
+		CKM_SHA256,
 		0xffffff
 	};
 	unsigned char  *digests[] = {
 		(unsigned char *) "\x7a\x08\xb0\x7e\x84\x64\x17\x03\xe5\xf2\xc8\x36\xaa\x59\xa1\x70",
+		(unsigned char *) "\xda\x79\xa5\x8f\xb8\x83\x3d\x61\xf6\x32\x16\x17\xe3\xfd\xf0\x56\x26\x5f\xb7\xcd",
 		(unsigned char *) "\x29\xb0\xe7\x87\x82\x71\x64\x5f\xff\xb7\xee\xc7\xdb\x4a\x74\x73\xa1\xc0\x0b\xc1",
-		(unsigned char *) "\xda\x79\xa5\x8f\xb8\x83\x3d\x61\xf6\x32\x16\x17\xe3\xfd\xf0\x56\x26\x5f\xb7\xcd"
+		(unsigned char *) "\x9c\xfe\x7f\xaf\xf7\x5\x42\x98\xca\x87\x55\x7e\x15\xa1\x2\x62\xde\x8d\x3e\xee\x77\x82\x74\x17\xfb\xdf\xea\x1c\x41\xb9\xec\x23",
 	};
 	CK_ULONG        digestLens[] = {
 		16,
 		20,
-		20
+		20,
+		32,
 	};
 
 	rv = p11->C_GetSessionInfo(session, &sessionInfo);
@@ -5071,8 +5972,20 @@
 		for (j = 0; j < 10; j++)
 			data[10 * i + j] = (unsigned char) (0x30 + j);
 
-
-	for (i = 0; mechTypes[i] != 0xffffff; i++) {
+#ifdef ENABLE_OPENSSL
+	i = (FIPS_mode() ? 2 : 0);
+#else
+	i = 0;
+#endif
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+		if (!legacy_provider) {
+			if (!(legacy_provider = OSSL_PROVIDER_try_load(NULL, "legacy", 1))) {
+				printf("Failed to load legacy provider\n");
+				return errors;
+			}
+		}
+#endif
+	for (; mechTypes[i] != 0xffffff; i++) {
 		ck_mech.mechanism = mechTypes[i];
 
 		rv = p11->C_DigestInit(session, &ck_mech);
@@ -5139,9 +6052,15 @@
 	unsigned char  *pubkey;
 	const unsigned char *pubkey_c;
 	CK_ULONG        pubkeyLen;
-	EVP_PKEY       *pkey;
-	RSA            *rsa;
+	EVP_PKEY       *pkey = NULL;
 	BIGNUM *rsa_n, *rsa_e;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+	RSA				*rsa;
+#else
+	EVP_PKEY_CTX 	*ctx = NULL;
+	OSSL_PARAM_BLD	*bld = NULL;
+	OSSL_PARAM		*params = NULL;
+#endif
 
 	id = NULL;
 	id = getID(session, privKeyObject, &idLen);
@@ -5158,17 +6077,22 @@
 	free(id);
 
 	switch(getKEY_TYPE(session, pubkeyObject)) {
-		case CKK_RSA:
-			pkey = EVP_PKEY_new();
+		case CKK_RSA:;
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 			rsa = RSA_new();
-			mod = getMODULUS(session, pubkeyObject, &modLen);
-			exp = getPUBLIC_EXPONENT(session, pubkeyObject, &expLen);
-			if ( !pkey || !rsa || !mod || !exp) {
-				fprintf(stderr, "public key not extractable\n");
+			pkey = EVP_PKEY_new();
+			if (!rsa || !pkey) {
+			fprintf(stderr, "public key not extractable\n");
 				if (pkey)
 					EVP_PKEY_free(pkey);
 				if (rsa)
 					RSA_free(rsa);
+			}
+#endif
+			mod = getMODULUS(session, pubkeyObject, &modLen);
+			exp = getPUBLIC_EXPONENT(session, pubkeyObject, &expLen);
+			if (!mod || !exp) {
+				fprintf(stderr, "public key not extractable\n");
 				if (mod)
 					free(mod);
 				if (exp)
@@ -5177,12 +6101,33 @@
 			}
 			rsa_n = BN_bin2bn(mod, modLen, NULL);
 			rsa_e =	BN_bin2bn(exp, expLen, NULL);
+			free(mod);
+			free(exp);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 			if (RSA_set0_key(rsa, rsa_n, rsa_e, NULL) != 1)
 			    return NULL;
-
 			EVP_PKEY_assign_RSA(pkey, rsa);
-			free(mod);
-			free(exp);
+#else
+			if (!(bld = OSSL_PARAM_BLD_new()) ||
+				OSSL_PARAM_BLD_push_BN(bld, "n", rsa_n) != 1 ||
+				OSSL_PARAM_BLD_push_BN(bld, "e", rsa_e) != 1 ||
+				!(params = OSSL_PARAM_BLD_to_param(bld))) {
+				fprintf(stderr, "public key not extractable\n");
+				OSSL_PARAM_BLD_free(bld);
+				OSSL_PARAM_free(params);
+				return NULL;
+			}
+			OSSL_PARAM_BLD_free(bld);
+
+			if (!(ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", NULL)) ||
+				EVP_PKEY_fromdata_init(ctx) != 1 ||
+				EVP_PKEY_fromdata(ctx, &pkey, EVP_PKEY_PUBLIC_KEY, params) != 1) {
+				fprintf(stderr, "public key not extractable\n");
+				OSSL_PARAM_free(params);
+				return NULL;
+			}
+			OSSL_PARAM_free(params);
+#endif
 			return pkey;
 		case CKK_DSA:
 		case CKK_ECDSA:
@@ -5239,6 +6184,14 @@
 		EVP_sha256(),
 	};
 #endif
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(OPENSSL_NO_RIPEMD)
+	if (!legacy_provider) {
+		if (!(legacy_provider = OSSL_PROVIDER_try_load(NULL, "legacy", 1))) {
+			printf("Failed to load legacy provider");
+			return errors;
+		}
+	}
+#endif
 
 	rv = p11->C_SignInit(session, ck_mech, privKeyObject);
 	/* mechanism not implemented, don't test */
@@ -5752,7 +6705,7 @@
 	return errors;
 }
 
-#if OPENSC_VERSION_MAJOR == 0 && OPENSC_VERSION_MINOR <= 22
+#if OPENSC_VERSION_MAJOR == 0 && OPENSC_VERSION_MINOR <= 23
 #else
 #ifdef ENABLE_OPENSSL
 static int wrap_unwrap(CK_SESSION_HANDLE session,
@@ -5876,7 +6829,7 @@
  */
 static int test_unwrap(CK_SESSION_HANDLE sess)
 {
-#if OPENSC_VERSION_MAJOR == 0 && OPENSC_VERSION_MINOR <= 22
+#if OPENSC_VERSION_MAJOR == 0 && OPENSC_VERSION_MINOR <= 23
 	/* temporarily disable test, see https://github.com/OpenSC/OpenSC/issues/1796 */
 	return 0;
 #else
@@ -5937,7 +6890,8 @@
 #ifdef ENABLE_OPENSSL
 static int encrypt_decrypt(CK_SESSION_HANDLE session,
 		CK_MECHANISM_TYPE mech_type,
-		CK_OBJECT_HANDLE privKeyObject)
+		CK_OBJECT_HANDLE privKeyObject,
+		char *param, unsigned long param_len)
 {
 	EVP_PKEY       *pkey;
 	unsigned char	orig_data[512];
@@ -5998,6 +6952,18 @@
 		case CKM_SHA512:
 			mgf = CKG_MGF1_SHA512;
 			break;
+		case CKM_SHA3_224:
+			mgf = CKG_MGF1_SHA3_224;
+			break;
+		case CKM_SHA3_256:
+			mgf = CKG_MGF1_SHA3_256;
+			break;
+		case CKM_SHA3_384:
+			mgf = CKG_MGF1_SHA3_384;
+			break;
+		case CKM_SHA3_512:
+			mgf = CKG_MGF1_SHA3_512;
+			break;
 		}
 		if (opt_mgf != 0) {
 			mgf = opt_mgf;
@@ -6056,7 +7022,7 @@
 		return 0;
 	}
 	if (mech_type == CKM_RSA_PKCS_OAEP) {
-#if defined(EVP_PKEY_CTX_set_rsa_oaep_md) && defined(EVP_PKEY_CTX_set_rsa_mgf1_md)
+#if OPENSSL_VERSION_NUMBER >= 0x10002000L
 		const EVP_MD *md;
 		switch (hash_alg) {
 		case CKM_SHA_1:
@@ -6076,6 +7042,18 @@
 		case CKM_SHA512:
 			md = EVP_sha512();
 			break;
+		case CKM_SHA3_224:
+			md = EVP_sha3_224();
+			break;
+		case CKM_SHA3_256:
+			md = EVP_sha3_256();
+			break;
+		case CKM_SHA3_384:
+			md = EVP_sha3_384();
+			break;
+		case CKM_SHA3_512:
+			md = EVP_sha3_512();
+			break;
 		}
 		if (EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) <= 0) {
 			EVP_PKEY_CTX_free(ctx);
@@ -6103,6 +7081,18 @@
 		case CKG_MGF1_SHA512:
 			md = EVP_sha512();
 			break;
+		case CKG_MGF1_SHA3_224:
+			md = EVP_sha3_224();
+			break;
+		case CKG_MGF1_SHA3_256:
+			md = EVP_sha3_256();
+			break;
+		case CKG_MGF1_SHA3_384:
+			md = EVP_sha3_384();
+			break;
+		case CKG_MGF1_SHA3_512:
+			md = EVP_sha3_512();
+			break;
 		}
 		if (EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md) <= 0) {
 			EVP_PKEY_CTX_free(ctx);
@@ -6110,6 +7100,18 @@
 			printf("set mgf1 md failed, returning\n");
 			return 0;
 		}
+		if (param_len != 0 && param != NULL) {
+			/* label is in ownership of openssl, do not free this ptr! */
+			char *label = malloc(param_len);
+			memcpy(label, param, param_len);
+
+			if (EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, label, param_len) <= 0) {
+				EVP_PKEY_CTX_free(ctx);
+				EVP_PKEY_free(pkey);
+				printf("set OAEP label failed, returning\n");
+				return 0;
+			}
+		}
 #else
 		if (hash_alg != CKM_SHA_1) {
 			printf("This version of OpenSSL only supports SHA1 for OAEP, returning\n");
@@ -6135,21 +7137,28 @@
 		oaep_params.hashAlg = hash_alg;
 		oaep_params.mgf = mgf;
 
-		/* These settings are compatible with OpenSSL 1.0.2L and 1.1.0+ */
 		oaep_params.source = 0UL;  /* empty encoding parameter (label) */
 		oaep_params.pSourceData = NULL; /* PKCS#11 standard: this must be NULLPTR */
 		oaep_params.ulSourceDataLen = 0; /* PKCS#11 standard: this must be 0 */
 
-		/* If an RSA-OAEP mechanism, it needs parameters */
+		fprintf(stderr, "OAEP parameters: hashAlg=%s, mgf=%s, ",
+			p11_mechanism_to_name(oaep_params.hashAlg),
+			p11_mgf_to_name(oaep_params.mgf));
+
+		if (param != NULL && param_len > 0) {
+			oaep_params.source = CKZ_DATA_SPECIFIED;
+			oaep_params.pSourceData = param;
+			oaep_params.ulSourceDataLen = param_len;
+			fprintf(stderr, "encoding parameter (Label) present, length %ld\n", param_len);
+		} else {
+			fprintf(stderr, "encoding parameter (Label) not present\n");
+		}
+
 		mech.pParameter = &oaep_params;
 		mech.ulParameterLen = sizeof(oaep_params);
 
-		fprintf(stderr, "OAEP parameters: hashAlg=%s, mgf=%s, source_type=%lu, source_ptr=%p, source_len=%lu\n",
-			p11_mechanism_to_name(oaep_params.hashAlg),
-			p11_mgf_to_name(oaep_params.mgf),
-			oaep_params.source,
-			oaep_params.pSourceData,
-			oaep_params.ulSourceDataLen);
+
+
 		break;
 	case CKM_RSA_X_509:
 	case CKM_RSA_PKCS:
@@ -6268,16 +7277,17 @@
 #else
 		for (n = 0; n < num_mechs; n++) {
 			switch (mechs[n]) {
-			case CKM_RSA_PKCS:
 			case CKM_RSA_PKCS_OAEP:
+				/* one more OAEP test with param .. */
+				errors += encrypt_decrypt(sess, mechs[n], privKeyObject, "ABC", 3);
+				/* fall through */
+			case CKM_RSA_PKCS:
 			case CKM_RSA_X_509:
+				errors += encrypt_decrypt(sess, mechs[n], privKeyObject, NULL, 0);
 				break;
 			default:
 				printf(" -- mechanism can't be used to decrypt, skipping\n");
-				continue;
 			}
-
-			errors += encrypt_decrypt(sess, mechs[n], privKeyObject);
 		}
 #endif
 	}
@@ -6875,57 +7885,35 @@
 {
 	fprintf(stderr, "  ERR: %s failed: %s (0x%0x)\n", msg, CKR2Str(rv), (unsigned int) rv);
 }
-
-static int hex_to_bin(const char *in, unsigned char *out, size_t *outlen)
+static CK_BYTE_PTR get_iv(const char *iv_input, size_t *iv_size)
 {
-	size_t left, count = 0;
-	int nybbles = 2;
+	CK_BYTE_PTR iv;
+	size_t size = *iv_size;
 
-	if (in == NULL || *in == '\0') {
-		*outlen = 0;
-		return 1;
+	/* no IV supplied on command line */
+	if (!iv_input) {
+		*iv_size = 0;
+		return NULL;
 	}
 
-	left = *outlen;
+	iv = calloc(sizeof(CK_BYTE), *iv_size);
+	if (!iv) {
+		fprintf(stderr, "Warning, out of memory, IV will not be used.\n");
+		*iv_size = 0;
+		return NULL;
+	}
 
-	if (strlen(in) % 2)
-		nybbles = 1; // any leading zero in output should be in most-significant byte, not last one!
-	while (*in != '\0') {
-		int byte = 0;
-
-		while (nybbles-- && *in && *in != ':') {
-			char c;
-			byte <<= 4;
-			c = *in++;
-			if ('0' <= c && c <= '9')
-				c -= '0';
-			else
-			if ('a' <= c && c <= 'f')
-				c = c - 'a' + 10;
-			else
-			if ('A' <= c && c <= 'F')
-				c = c - 'A' + 10;
-			else {
-				fprintf(stderr, "hex_to_bin(): invalid char '%c' in hex string\n", c);
-				*outlen = 0;
-				return 0;
-			}
-			byte |= c;
-		}
-		if (*in == ':')
-			in++;
-		if (left <= 0) {
-			fprintf(stderr, "hex_to_bin(): hex string too long");
-			*outlen = 0;
-			return 0;
-		}
-		out[count++] = (unsigned char) byte;
-		left--;
-		nybbles = 2;
+	if (sc_hex_to_bin(iv_input, iv, &size)) {
+		fprintf(stderr, "Warning, unable to parse IV, IV will not be used.\n");
+		*iv_size = 0;
+		free(iv);
+		return NULL;
 	}
 
-	*outlen = count;
-	return 1;
+	if (*iv_size != size)
+		fprintf(stderr, "Warning: IV string is too short, IV will be padded from the right by zeros.\n");
+
+	return iv;
 }
 
 static void pseudo_randomize(unsigned char *data, size_t dataLen)
@@ -6940,249 +7928,284 @@
 }
 
 static struct mech_info	p11_mechanisms[] = {
-      { CKM_RSA_PKCS_KEY_PAIR_GEN,	"RSA-PKCS-KEY-PAIR-GEN", NULL },
-      { CKM_RSA_PKCS,		"RSA-PKCS",	NULL },
-      { CKM_RSA_9796,		"RSA-9796",	NULL },
-      { CKM_RSA_X_509,		"RSA-X-509",	NULL },
-      { CKM_MD2_RSA_PKCS,	"MD2-RSA-PKCS",	NULL },
-      { CKM_MD5_RSA_PKCS,	"MD5-RSA-PKCS",	"rsa-md5" },
-      { CKM_SHA1_RSA_PKCS,	"SHA1-RSA-PKCS",	"rsa-sha1" },
-      { CKM_SHA224_RSA_PKCS,	"SHA224-RSA-PKCS",	"rsa-sha224" },
-      { CKM_SHA256_RSA_PKCS,	"SHA256-RSA-PKCS",	"rsa-sha256" },
-      { CKM_SHA384_RSA_PKCS,	"SHA384-RSA-PKCS",	"rsa-sha384" },
-      { CKM_SHA512_RSA_PKCS,	"SHA512-RSA-PKCS",	"rsa-sha512" },
-      { CKM_RIPEMD128_RSA_PKCS,	"RIPEMD128-RSA-PKCS",	NULL },
-      { CKM_RIPEMD160_RSA_PKCS,	"RIPEMD160-RSA-PKCS",	"rsa-ripemd160" },
-      { CKM_RSA_PKCS_OAEP,	"RSA-PKCS-OAEP",	NULL },
-      { CKM_RSA_X9_31_KEY_PAIR_GEN,"RSA-X9-31-KEY-PAIR-GEN", NULL },
-      { CKM_RSA_X9_31,		"RSA-X9-31",	NULL },
-      { CKM_SHA1_RSA_X9_31,	"SHA1-RSA-X9-31",	NULL },
-      { CKM_RSA_PKCS_PSS,	"RSA-PKCS-PSS",	NULL },
-      { CKM_SHA1_RSA_PKCS_PSS,	"SHA1-RSA-PKCS-PSS",	"rsa-pss-sha1" },
-      { CKM_SHA224_RSA_PKCS_PSS,"SHA224-RSA-PKCS-PSS",	"rsa-pss-sha224" },
-      { CKM_SHA256_RSA_PKCS_PSS,"SHA256-RSA-PKCS-PSS",	"rsa-pss-sha256" },
-      { CKM_SHA384_RSA_PKCS_PSS,"SHA384-RSA-PKCS-PSS",	"rsa-pss-sha384" },
-      { CKM_SHA512_RSA_PKCS_PSS,"SHA512-RSA-PKCS-PSS",	"rsa-pss-sha512" },
-      { CKM_DSA_KEY_PAIR_GEN,	"DSA-KEY-PAIR-GEN",	NULL },
-      { CKM_DSA,		"DSA",	NULL },
-      { CKM_DSA_SHA1,		"DSA-SHA1", NULL },
-      { CKM_DSA_SHA224,		"DSA-SHA224", NULL },
-      { CKM_DSA_SHA256,		"DSA-SHA256", NULL },
-      { CKM_DSA_SHA384,		"DSA-SHA384", NULL },
-      { CKM_DSA_SHA512,		"DSA-SHA512", NULL },
-      { CKM_DH_PKCS_KEY_PAIR_GEN,"DH-PKCS-KEY-PAIR-GEN", NULL },
-      { CKM_DH_PKCS_DERIVE,	"DH-PKCS-DERIVE", NULL },
-      { CKM_X9_42_DH_KEY_PAIR_GEN,"X9-42-DH-KEY-PAIR-GEN", NULL },
-      { CKM_X9_42_DH_DERIVE,	"X9-42-DH-DERIVE", NULL },
-      { CKM_X9_42_DH_HYBRID_DERIVE,"X9-42-DH-HYBRID-DERIVE", NULL },
-      { CKM_X9_42_MQV_DERIVE,	"X9-42-MQV-DERIVE", NULL },
-      { CKM_RC2_KEY_GEN,	"RC2-KEY-GEN", NULL },
-      { CKM_RC2_ECB,		"RC2-ECB", NULL },
-      { CKM_RC2_CBC,		"RC2-CBC", NULL },
-      { CKM_RC2_MAC,		"RC2-MAC", NULL },
-      { CKM_RC2_MAC_GENERAL,	"RC2-MAC-GENERAL", NULL },
-      { CKM_RC2_CBC_PAD,	"RC2-CBC-PAD", NULL },
-      { CKM_RC4_KEY_GEN,	"RC4-KEY-GEN", NULL },
-      { CKM_RC4,		"RC4", NULL },
-      { CKM_DES_KEY_GEN,	"DES-KEY-GEN", NULL },
-      { CKM_DES_ECB,		"DES-ECB", NULL },
-      { CKM_DES_CBC,		"DES-CBC", NULL },
-      { CKM_DES_MAC,		"DES-MAC", NULL },
-      { CKM_DES_MAC_GENERAL,	"DES-MAC-GENERAL", NULL },
-      { CKM_DES_CBC_PAD,	"DES-CBC-PAD", NULL },
-      { CKM_DES2_KEY_GEN,	"DES2-KEY-GEN", NULL },
-      { CKM_DES3_KEY_GEN,	"DES3-KEY-GEN", NULL },
-      { CKM_DES3_ECB,		"DES3-ECB", NULL },
-      { CKM_DES3_CBC,		"DES3-CBC", NULL },
-      { CKM_DES3_MAC,		"DES3-MAC", NULL },
-      { CKM_DES3_MAC_GENERAL,	"DES3-MAC-GENERAL", NULL },
-      { CKM_DES3_CBC_PAD,	"DES3-CBC-PAD", NULL },
-      { CKM_DES3_CMAC,		"DES3-CMAC", NULL },
-      { CKM_CDMF_KEY_GEN,	"CDMF-KEY-GEN", NULL },
-      { CKM_CDMF_ECB,		"CDMF-ECB", NULL },
-      { CKM_CDMF_CBC,		"CDMF-CBC", NULL },
-      { CKM_CDMF_MAC,		"CDMF-MAC", NULL },
-      { CKM_CDMF_MAC_GENERAL,	"CDMF-MAC-GENERAL", NULL },
-      { CKM_CDMF_CBC_PAD,	"CDMF-CBC-PAD", NULL },
-      { CKM_MD2,		"MD2", NULL },
-      { CKM_MD2_HMAC,		"MD2-HMAC", NULL },
-      { CKM_MD2_HMAC_GENERAL,	"MD2-HMAC-GENERAL", NULL },
-      { CKM_MD5,		"MD5", NULL },
-      { CKM_MD5_HMAC,		"MD5-HMAC", NULL },
-      { CKM_MD5_HMAC_GENERAL,	"MD5-HMAC-GENERAL", NULL },
-      { CKM_SHA_1,		"SHA-1", NULL },
-      { CKM_SHA_1_HMAC,		"SHA-1-HMAC", NULL },
-      { CKM_SHA_1_HMAC_GENERAL,	"SHA-1-HMAC-GENERAL", NULL },
-      { CKM_SHA224,		"SHA224", NULL },
-      { CKM_SHA224_HMAC,	"SHA224-HMAC", NULL },
-      { CKM_SHA256,		"SHA256", NULL },
-      { CKM_SHA256_HMAC,	"SHA256-HMAC", NULL },
-      { CKM_SHA384,		"SHA384", NULL },
-      { CKM_SHA384_HMAC,	"SHA384-HMAC", NULL },
-      { CKM_SHA512,		"SHA512", NULL },
-      { CKM_SHA512_HMAC,	"SHA512-HMAC", NULL },
-      { CKM_RIPEMD128,		"RIPEMD128", NULL },
-      { CKM_RIPEMD128_HMAC,	"RIPEMD128-HMAC", NULL },
-      { CKM_RIPEMD128_HMAC_GENERAL,"RIPEMD128-HMAC-GENERAL", NULL },
-      { CKM_RIPEMD160,		"RIPEMD160", NULL },
-      { CKM_RIPEMD160_HMAC,	"RIPEMD160-HMAC", NULL },
-      { CKM_RIPEMD160_HMAC_GENERAL,"RIPEMD160-HMAC-GENERAL", NULL },
-      { CKM_CAST_KEY_GEN,	"CAST-KEY-GEN", NULL },
-      { CKM_CAST_ECB,		"CAST-ECB", NULL },
-      { CKM_CAST_CBC,		"CAST-CBC", NULL },
-      { CKM_CAST_MAC,		"CAST-MAC", NULL },
-      { CKM_CAST_MAC_GENERAL,	"CAST-MAC-GENERAL", NULL },
-      { CKM_CAST_CBC_PAD,	"CAST-CBC-PAD", NULL },
-      { CKM_CAST3_KEY_GEN,	"CAST3-KEY-GEN", NULL },
-      { CKM_CAST3_ECB,		"CAST3-ECB", NULL },
-      { CKM_CAST3_CBC,		"CAST3-CBC", NULL },
-      { CKM_CAST3_MAC,		"CAST3-MAC", NULL },
-      { CKM_CAST3_MAC_GENERAL,	"CAST3-MAC-GENERAL", NULL },
-      { CKM_CAST3_CBC_PAD,	"CAST3-CBC-PAD", NULL },
-      { CKM_CAST5_KEY_GEN,	"CAST5-KEY-GEN", NULL },
-      { CKM_CAST5_ECB,		"CAST5-ECB", NULL },
-      { CKM_CAST5_CBC,		"CAST5-CBC", NULL },
-      { CKM_CAST5_MAC,		"CAST5-MAC", NULL },
-      { CKM_CAST5_MAC_GENERAL,	"CAST5-MAC-GENERAL", NULL },
-      { CKM_CAST5_CBC_PAD,	"CAST5-CBC-PAD", NULL },
-      { CKM_RC5_KEY_GEN,	"RC5-KEY-GEN", NULL },
-      { CKM_RC5_ECB,		"RC5-ECB", NULL },
-      { CKM_RC5_CBC,		"RC5-CBC", NULL },
-      { CKM_RC5_MAC,		"RC5-MAC", NULL },
-      { CKM_RC5_MAC_GENERAL,	"RC5-MAC-GENERAL", NULL },
-      { CKM_RC5_CBC_PAD,	"RC5-CBC-PAD", NULL },
-      { CKM_IDEA_KEY_GEN,	"IDEA-KEY-GEN", NULL },
-      { CKM_IDEA_ECB,		"IDEA-ECB", NULL },
-      { CKM_IDEA_CBC,		"IDEA-CBC", NULL },
-      { CKM_IDEA_MAC,		"IDEA-MAC", NULL },
-      { CKM_IDEA_MAC_GENERAL,	"IDEA-MAC-GENERAL", NULL },
-      { CKM_IDEA_CBC_PAD,	"IDEA-CBC-PAD", NULL },
-      { CKM_GENERIC_SECRET_KEY_GEN,"GENERIC-SECRET-KEY-GEN", NULL },
-      { CKM_CONCATENATE_BASE_AND_KEY,"CONCATENATE-BASE-AND-KEY", NULL },
-      { CKM_CONCATENATE_BASE_AND_DATA,"CONCATENATE-BASE-AND-DATA", NULL },
-      { CKM_CONCATENATE_DATA_AND_BASE,"CONCATENATE-DATA-AND-BASE", NULL },
-      { CKM_XOR_BASE_AND_DATA,	"XOR-BASE-AND-DATA", NULL },
-      { CKM_EXTRACT_KEY_FROM_KEY,"EXTRACT-KEY-FROM-KEY", NULL },
-      { CKM_SSL3_PRE_MASTER_KEY_GEN,"SSL3-PRE-MASTER-KEY-GEN", NULL },
-      { CKM_SSL3_MASTER_KEY_DERIVE,"SSL3-MASTER-KEY-DERIVE", NULL },
-      { CKM_SSL3_KEY_AND_MAC_DERIVE,"SSL3-KEY-AND-MAC-DERIVE", NULL },
-      { CKM_SSL3_MASTER_KEY_DERIVE_DH,"SSL3-MASTER-KEY-DERIVE-DH", NULL },
-      { CKM_TLS_PRE_MASTER_KEY_GEN,"TLS-PRE-MASTER-KEY-GEN", NULL },
-      { CKM_TLS_MASTER_KEY_DERIVE,"TLS-MASTER-KEY-DERIVE", NULL },
-      { CKM_TLS_KEY_AND_MAC_DERIVE,"TLS-KEY-AND-MAC-DERIVE", NULL },
-      { CKM_TLS_MASTER_KEY_DERIVE_DH,"TLS-MASTER-KEY-DERIVE-DH", NULL },
-      { CKM_SSL3_MD5_MAC,	"SSL3-MD5-MAC", NULL },
-      { CKM_SSL3_SHA1_MAC,	"SSL3-SHA1-MAC", NULL },
-      { CKM_MD5_KEY_DERIVATION,	"MD5-KEY-DERIVATION", NULL },
-      { CKM_MD2_KEY_DERIVATION,	"MD2-KEY-DERIVATION", NULL },
-      { CKM_SHA1_KEY_DERIVATION,"SHA1-KEY-DERIVATION", NULL },
-      { CKM_PBE_MD2_DES_CBC,	"PBE-MD2-DES-CBC", NULL },
-      { CKM_PBE_MD5_DES_CBC,	"PBE-MD5-DES-CBC", NULL },
-      { CKM_PBE_MD5_CAST_CBC,	"PBE-MD5-CAST-CBC", NULL },
-      { CKM_PBE_MD5_CAST3_CBC,	"PBE-MD5-CAST3-CBC", NULL },
-      { CKM_PBE_MD5_CAST5_CBC,	"PBE-MD5-CAST5-CBC", NULL },
-      { CKM_PBE_SHA1_CAST5_CBC,	"PBE-SHA1-CAST5-CBC", NULL },
-      { CKM_PBE_SHA1_RC4_128,	"PBE-SHA1-RC4-128", NULL },
-      { CKM_PBE_SHA1_RC4_40,	"PBE-SHA1-RC4-40", NULL },
-      { CKM_PBE_SHA1_DES3_EDE_CBC,"PBE-SHA1-DES3-EDE-CBC", NULL },
-      { CKM_PBE_SHA1_DES2_EDE_CBC,"PBE-SHA1-DES2-EDE-CBC", NULL },
-      { CKM_PBE_SHA1_RC2_128_CBC,"PBE-SHA1-RC2-128-CBC", NULL },
-      { CKM_PBE_SHA1_RC2_40_CBC,"PBE-SHA1-RC2-40-CBC", NULL },
-      { CKM_PKCS5_PBKD2,	"PKCS5-PBKD2", NULL },
-      { CKM_PBA_SHA1_WITH_SHA1_HMAC,"PBA-SHA1-WITH-SHA1-HMAC", NULL },
-      { CKM_KEY_WRAP_LYNKS,	"KEY-WRAP-LYNKS", NULL },
-      { CKM_KEY_WRAP_SET_OAEP,	"KEY-WRAP-SET-OAEP", NULL },
-      { CKM_SKIPJACK_KEY_GEN,	"SKIPJACK-KEY-GEN", NULL },
-      { CKM_SKIPJACK_ECB64,	"SKIPJACK-ECB64", NULL },
-      { CKM_SKIPJACK_CBC64,	"SKIPJACK-CBC64", NULL },
-      { CKM_SKIPJACK_OFB64,	"SKIPJACK-OFB64", NULL },
-      { CKM_SKIPJACK_CFB64,	"SKIPJACK-CFB64", NULL },
-      { CKM_SKIPJACK_CFB32,	"SKIPJACK-CFB32", NULL },
-      { CKM_SKIPJACK_CFB16,	"SKIPJACK-CFB16", NULL },
-      { CKM_SKIPJACK_CFB8,	"SKIPJACK-CFB8", NULL },
-      { CKM_SKIPJACK_WRAP,	"SKIPJACK-WRAP", NULL },
-      { CKM_SKIPJACK_PRIVATE_WRAP,"SKIPJACK-PRIVATE-WRAP", NULL },
-      { CKM_SKIPJACK_RELAYX,	"SKIPJACK-RELAYX", NULL },
-      { CKM_KEA_KEY_PAIR_GEN,	"KEA-KEY-PAIR-GEN", NULL },
-      { CKM_KEA_KEY_DERIVE,	"KEA-KEY-DERIVE", NULL },
-      { CKM_FORTEZZA_TIMESTAMP,	"FORTEZZA-TIMESTAMP", NULL },
-      { CKM_BATON_KEY_GEN,	"BATON-KEY-GEN", NULL },
-      { CKM_BATON_ECB128,	"BATON-ECB128", NULL },
-      { CKM_BATON_ECB96,	"BATON-ECB96", NULL },
-      { CKM_BATON_CBC128,	"BATON-CBC128", NULL },
-      { CKM_BATON_COUNTER,	"BATON-COUNTER", NULL },
-      { CKM_BATON_SHUFFLE,	"BATON-SHUFFLE", NULL },
-      { CKM_BATON_WRAP,		"BATON-WRAP", NULL },
-      { CKM_ECDSA_KEY_PAIR_GEN,	"ECDSA-KEY-PAIR-GEN", NULL },
-      { CKM_ECDSA,		"ECDSA", NULL },
-      { CKM_ECDSA_SHA1,		"ECDSA-SHA1", NULL },
-      { CKM_ECDSA_SHA224,	"ECDSA-SHA224", NULL },
-      { CKM_ECDSA_SHA256,	"ECDSA-SHA256", NULL },
-      { CKM_ECDSA_SHA384,	"ECDSA-SHA384", NULL },
-      { CKM_ECDSA_SHA512,	"ECDSA-SHA512", NULL },
-      { CKM_ECDH1_DERIVE,	"ECDH1-DERIVE", NULL },
-      { CKM_ECDH1_COFACTOR_DERIVE,"ECDH1-COFACTOR-DERIVE", NULL },
-      { CKM_ECMQV_DERIVE,	"ECMQV-DERIVE", NULL },
-      { CKM_EC_EDWARDS_KEY_PAIR_GEN,"EC-EDWARDS-KEY-PAIR-GEN", NULL },
-      { CKM_EC_MONTGOMERY_KEY_PAIR_GEN,"EC-MONTGOMERY-KEY-PAIR-GEN", NULL },
-      { CKM_EDDSA,		"EDDSA", NULL },
-      { CKM_XEDDSA,		"XEDDSA", NULL },
-      { CKM_JUNIPER_KEY_GEN,	"JUNIPER-KEY-GEN", NULL },
-      { CKM_JUNIPER_ECB128,	"JUNIPER-ECB128", NULL },
-      { CKM_JUNIPER_CBC128,	"JUNIPER-CBC128", NULL },
-      { CKM_JUNIPER_COUNTER,	"JUNIPER-COUNTER", NULL },
-      { CKM_JUNIPER_SHUFFLE,	"JUNIPER-SHUFFLE", NULL },
-      { CKM_JUNIPER_WRAP,	"JUNIPER-WRAP", NULL },
-      { CKM_FASTHASH,		"FASTHASH", NULL },
-      { CKM_AES_KEY_GEN,	"AES-KEY-GEN", NULL },
-      { CKM_AES_ECB,		"AES-ECB", NULL },
-      { CKM_AES_CBC,		"AES-CBC", NULL },
-      { CKM_AES_MAC,		"AES-MAC", NULL },
-      { CKM_AES_MAC_GENERAL,	"AES-MAC-GENERAL", NULL },
-      { CKM_AES_CBC_PAD,	"AES-CBC-PAD", NULL },
-      { CKM_AES_CTR,		"AES-CTR", NULL },
-      { CKM_AES_GCM,		"AES-GCM", NULL },
-      { CKM_AES_CMAC,		"AES-CMAC", NULL },
-      { CKM_DES_ECB_ENCRYPT_DATA, "DES-ECB-ENCRYPT-DATA", NULL },
-      { CKM_DES_CBC_ENCRYPT_DATA, "DES-CBC-ENCRYPT-DATA", NULL },
-      { CKM_DES3_ECB_ENCRYPT_DATA, "DES3-ECB-ENCRYPT-DATA", NULL },
-      { CKM_DES3_CBC_ENCRYPT_DATA, "DES3-CBC-ENCRYPT-DATA", NULL },
-      { CKM_AES_ECB_ENCRYPT_DATA, "AES-ECB-ENCRYPT-DATA", NULL },
-      { CKM_AES_CBC_ENCRYPT_DATA, "AES-CBC-ENCRYPT-DATA", NULL },
-      { CKM_GOST28147_KEY_GEN,	"GOST28147-KEY-GEN", NULL },
-      { CKM_GOST28147_ECB,	"GOST28147-ECB", NULL },
-      { CKM_GOST28147,	"GOST28147", NULL },
-      { CKM_GOST28147_MAC,	"GOST28147-MAC", NULL },
-      { CKM_GOST28147_KEY_WRAP,	"GOST28147-KEY-WRAP", NULL },
-      { CKM_GOSTR3410_KEY_PAIR_GEN,"GOSTR3410-KEY-PAIR-GEN", NULL },
-      { CKM_GOSTR3410,		"GOSTR3410", NULL },
-      { CKM_GOSTR3410_DERIVE,	"GOSTR3410-DERIVE", NULL },
-      { CKM_GOSTR3410_WITH_GOSTR3411,"GOSTR3410-WITH-GOSTR3411", NULL },
-      { CKM_GOSTR3410_512_KEY_PAIR_GEN,	"GOSTR3410-512-KEY-PAIR-GEN", NULL },
-      { CKM_GOSTR3410_512,	"GOSTR3410_512", NULL },
-      { CKM_GOSTR3410_12_DERIVE,	"GOSTR3410-12-DERIVE", NULL },
-      { CKM_GOSTR3410_WITH_GOSTR3411_12_256,	"GOSTR3410-WITH-GOSTR3411-12-256", NULL },
-      { CKM_GOSTR3410_WITH_GOSTR3411_12_512,	"GOSTR3410-WITH-GOSTR3411-12-512", NULL },
-      { CKM_GOSTR3411,		"GOSTR3411", NULL },
-      { CKM_GOSTR3411_HMAC,	"GOSTR3411-HMAC", NULL },
-      { CKM_GOSTR3411_12_256,	"GOSTR3411-12-256", NULL },
-      { CKM_GOSTR3411_12_512,	"GOSTR3411-12-512", NULL },
-      { CKM_GOSTR3411_12_256_HMAC,	"GOSTR3411-12-256-HMAC", NULL },
-      { CKM_GOSTR3411_12_512_HMAC,	"GOSTR3411-12-512-HMAC", NULL },
-      { CKM_DSA_PARAMETER_GEN,	"DSA-PARAMETER-GEN", NULL },
-      { CKM_DH_PKCS_PARAMETER_GEN,"DH-PKCS-PARAMETER-GEN", NULL },
-      { CKM_X9_42_DH_PARAMETER_GEN,"X9-42-DH-PARAMETER-GEN", NULL },
-      { CKM_AES_KEY_WRAP,	"AES-KEY-WRAP", NULL},
-      { 0, NULL, NULL }
+      { CKM_RSA_PKCS_KEY_PAIR_GEN,	"RSA-PKCS-KEY-PAIR-GEN", NULL, MF_UNKNOWN },
+      { CKM_RSA_PKCS,		"RSA-PKCS",	NULL, MF_UNKNOWN },
+      { CKM_RSA_9796,		"RSA-9796",	NULL, MF_UNKNOWN },
+      { CKM_RSA_X_509,		"RSA-X-509",	NULL, MF_UNKNOWN },
+      { CKM_MD2_RSA_PKCS,	"MD2-RSA-PKCS",	NULL, MF_UNKNOWN },
+      { CKM_MD5_RSA_PKCS,	"MD5-RSA-PKCS",	"rsa-md5", MF_UNKNOWN },
+      { CKM_SHA1_RSA_PKCS,	"SHA1-RSA-PKCS",	"rsa-sha1", MF_UNKNOWN },
+      { CKM_SHA224_RSA_PKCS,	"SHA224-RSA-PKCS",	"rsa-sha224", MF_UNKNOWN },
+      { CKM_SHA256_RSA_PKCS,	"SHA256-RSA-PKCS",	"rsa-sha256", MF_UNKNOWN },
+      { CKM_SHA384_RSA_PKCS,	"SHA384-RSA-PKCS",	"rsa-sha384", MF_UNKNOWN },
+      { CKM_SHA512_RSA_PKCS,	"SHA512-RSA-PKCS",	"rsa-sha512", MF_UNKNOWN },
+      { CKM_SHA3_224_RSA_PKCS,	"SHA3-224-RSA-PKCS",	"rsa-sha3-224", MF_UNKNOWN },
+      { CKM_SHA3_256_RSA_PKCS,	"SHA3-256-RSA-PKCS",	"rsa-sha3-256", MF_UNKNOWN },
+      { CKM_SHA3_384_RSA_PKCS,	"SHA3-384-RSA-PKCS",	"rsa-sha3-384", MF_UNKNOWN },
+      { CKM_SHA3_512_RSA_PKCS,	"SHA3-512-RSA-PKCS",	"rsa-sha3-512", MF_UNKNOWN },
+      { CKM_RIPEMD128_RSA_PKCS,	"RIPEMD128-RSA-PKCS",	NULL, MF_UNKNOWN },
+      { CKM_RIPEMD160_RSA_PKCS,	"RIPEMD160-RSA-PKCS",	"rsa-ripemd160", MF_UNKNOWN },
+      { CKM_RSA_PKCS_OAEP,	"RSA-PKCS-OAEP",	NULL, MF_UNKNOWN },
+      { CKM_RSA_X9_31_KEY_PAIR_GEN,"RSA-X9-31-KEY-PAIR-GEN", NULL, MF_UNKNOWN },
+      { CKM_RSA_X9_31,		"RSA-X9-31",	NULL, MF_UNKNOWN },
+      { CKM_SHA1_RSA_X9_31,	"SHA1-RSA-X9-31",	NULL, MF_UNKNOWN },
+      { CKM_RSA_PKCS_PSS,	"RSA-PKCS-PSS",	NULL, MF_UNKNOWN },
+      { CKM_SHA1_RSA_PKCS_PSS,	"SHA1-RSA-PKCS-PSS",	"rsa-pss-sha1", MF_UNKNOWN },
+      { CKM_SHA224_RSA_PKCS_PSS,"SHA224-RSA-PKCS-PSS",	"rsa-pss-sha224", MF_UNKNOWN },
+      { CKM_SHA256_RSA_PKCS_PSS,"SHA256-RSA-PKCS-PSS",	"rsa-pss-sha256", MF_UNKNOWN },
+      { CKM_SHA384_RSA_PKCS_PSS,"SHA384-RSA-PKCS-PSS",	"rsa-pss-sha384", MF_UNKNOWN },
+      { CKM_SHA512_RSA_PKCS_PSS,"SHA512-RSA-PKCS-PSS",	"rsa-pss-sha512", MF_UNKNOWN },
+      { CKM_SHA3_224_RSA_PKCS_PSS,"SHA3-224-RSA-PKCS-PSS",	"rsa-pss-sha3-224", MF_UNKNOWN },
+      { CKM_SHA3_256_RSA_PKCS_PSS,"SHA3-256-RSA-PKCS-PSS",	"rsa-pss-sha3-256", MF_UNKNOWN },
+      { CKM_SHA3_384_RSA_PKCS_PSS,"SHA3-384-RSA-PKCS-PSS",	"rsa-pss-sha3-384", MF_UNKNOWN },
+      { CKM_SHA3_512_RSA_PKCS_PSS,"SHA3-512-RSA-PKCS-PSS",	"rsa-pss-sha3-512", MF_UNKNOWN },
+      { CKM_DSA_KEY_PAIR_GEN,	"DSA-KEY-PAIR-GEN",	NULL, MF_UNKNOWN },
+      { CKM_DSA,		"DSA",	NULL, MF_UNKNOWN },
+      { CKM_DSA_SHA1,		"DSA-SHA1", NULL, MF_UNKNOWN },
+      { CKM_DSA_SHA224,		"DSA-SHA224", NULL, MF_UNKNOWN },
+      { CKM_DSA_SHA256,		"DSA-SHA256", NULL, MF_UNKNOWN },
+      { CKM_DSA_SHA384,		"DSA-SHA384", NULL, MF_UNKNOWN },
+      { CKM_DSA_SHA512,		"DSA-SHA512", NULL, MF_UNKNOWN },
+      { CKM_DH_PKCS_KEY_PAIR_GEN,"DH-PKCS-KEY-PAIR-GEN", NULL, MF_UNKNOWN },
+      { CKM_DH_PKCS_DERIVE,	"DH-PKCS-DERIVE", NULL, MF_UNKNOWN },
+      { CKM_X9_42_DH_KEY_PAIR_GEN,"X9-42-DH-KEY-PAIR-GEN", NULL, MF_UNKNOWN },
+      { CKM_X9_42_DH_DERIVE,	"X9-42-DH-DERIVE", NULL, MF_UNKNOWN },
+      { CKM_X9_42_DH_HYBRID_DERIVE,"X9-42-DH-HYBRID-DERIVE", NULL, MF_UNKNOWN },
+      { CKM_X9_42_MQV_DERIVE,	"X9-42-MQV-DERIVE", NULL, MF_UNKNOWN },
+      { CKM_RC2_KEY_GEN,	"RC2-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_RC2_ECB,		"RC2-ECB", NULL, MF_UNKNOWN },
+      { CKM_RC2_CBC,		"RC2-CBC", NULL, MF_UNKNOWN },
+      { CKM_RC2_MAC,		"RC2-MAC", NULL, MF_UNKNOWN },
+      { CKM_RC2_MAC_GENERAL,	"RC2-MAC-GENERAL", NULL, MF_UNKNOWN },
+      { CKM_RC2_CBC_PAD,	"RC2-CBC-PAD", NULL, MF_UNKNOWN },
+      { CKM_RC4_KEY_GEN,	"RC4-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_RC4,		"RC4", NULL, MF_UNKNOWN },
+      { CKM_DES_KEY_GEN,	"DES-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_DES_ECB,		"DES-ECB", NULL, MF_UNKNOWN },
+      { CKM_DES_CBC,		"DES-CBC", NULL, MF_UNKNOWN },
+      { CKM_DES_MAC,		"DES-MAC", NULL, MF_UNKNOWN },
+      { CKM_DES_MAC_GENERAL,	"DES-MAC-GENERAL", NULL, MF_UNKNOWN },
+      { CKM_DES_CBC_PAD,	"DES-CBC-PAD", NULL, MF_UNKNOWN },
+      { CKM_DES2_KEY_GEN,	"DES2-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_DES3_KEY_GEN,	"DES3-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_DES3_ECB,		"DES3-ECB", NULL, MF_UNKNOWN },
+      { CKM_DES3_CBC,		"DES3-CBC", NULL, MF_UNKNOWN },
+      { CKM_DES3_MAC,		"DES3-MAC", NULL, MF_UNKNOWN },
+      { CKM_DES3_MAC_GENERAL,	"DES3-MAC-GENERAL", NULL, MF_UNKNOWN },
+      { CKM_DES3_CBC_PAD,	"DES3-CBC-PAD", NULL, MF_UNKNOWN },
+      { CKM_DES3_CMAC,		"DES3-CMAC", NULL, MF_UNKNOWN },
+      { CKM_CDMF_KEY_GEN,	"CDMF-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_CDMF_ECB,		"CDMF-ECB", NULL, MF_UNKNOWN },
+      { CKM_CDMF_CBC,		"CDMF-CBC", NULL, MF_UNKNOWN },
+      { CKM_CDMF_MAC,		"CDMF-MAC", NULL, MF_UNKNOWN },
+      { CKM_CDMF_MAC_GENERAL,	"CDMF-MAC-GENERAL", NULL, MF_UNKNOWN },
+      { CKM_CDMF_CBC_PAD,	"CDMF-CBC-PAD", NULL, MF_UNKNOWN },
+      { CKM_MD2,		"MD2", NULL, MF_UNKNOWN },
+      { CKM_MD2_HMAC,		"MD2-HMAC", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_MD2_HMAC_GENERAL,	"MD2-HMAC-GENERAL", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_MD5,		"MD5", NULL, MF_UNKNOWN },
+      { CKM_MD5_HMAC,		"MD5-HMAC", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_MD5_HMAC_GENERAL,	"MD5-HMAC-GENERAL", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_SHA_1,		"SHA-1", NULL, MF_UNKNOWN },
+      { CKM_SHA_1_HMAC,		"SHA-1-HMAC", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_SHA_1_HMAC_GENERAL,	"SHA-1-HMAC-GENERAL", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_SHA224,		"SHA224", NULL, MF_UNKNOWN },
+      { CKM_SHA224_HMAC,	"SHA224-HMAC", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_SHA256,		"SHA256", NULL, MF_UNKNOWN },
+      { CKM_SHA256_HMAC,	"SHA256-HMAC", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_SHA384,		"SHA384", NULL, MF_UNKNOWN },
+      { CKM_SHA384_HMAC,	"SHA384-HMAC", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_SHA512,		"SHA512", NULL, MF_UNKNOWN },
+      { CKM_SHA512_HMAC,	"SHA512-HMAC", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_SHA3_224,		"SHA3-224", NULL, MF_UNKNOWN },
+      { CKM_SHA3_224_HMAC,	"SHA3-224-HMAC", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_SHA3_256,		"SHA3-256", NULL, MF_UNKNOWN },
+      { CKM_SHA3_256_HMAC,	"SHA3-256-HMAC", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_SHA3_384,		"SHA3-384", NULL, MF_UNKNOWN },
+      { CKM_SHA3_384_HMAC,	"SHA3-384-HMAC", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_SHA3_512,		"SHA3-512", NULL, MF_UNKNOWN },
+      { CKM_SHA3_512_HMAC,	"SHA3-512-HMAC", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_RIPEMD128,		"RIPEMD128", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_RIPEMD128_HMAC,	"RIPEMD128-HMAC", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_RIPEMD128_HMAC_GENERAL,"RIPEMD128-HMAC-GENERAL", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_RIPEMD160,		"RIPEMD160", NULL, MF_UNKNOWN },
+      { CKM_RIPEMD160_HMAC,	"RIPEMD160-HMAC", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_RIPEMD160_HMAC_GENERAL,"RIPEMD160-HMAC-GENERAL", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_CAST_KEY_GEN,	"CAST-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_CAST_ECB,		"CAST-ECB", NULL, MF_UNKNOWN },
+      { CKM_CAST_CBC,		"CAST-CBC", NULL, MF_UNKNOWN },
+      { CKM_CAST_MAC,		"CAST-MAC", NULL, MF_UNKNOWN },
+      { CKM_CAST_MAC_GENERAL,	"CAST-MAC-GENERAL", NULL, MF_UNKNOWN },
+      { CKM_CAST_CBC_PAD,	"CAST-CBC-PAD", NULL, MF_UNKNOWN },
+      { CKM_CAST3_KEY_GEN,	"CAST3-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_CAST3_ECB,		"CAST3-ECB", NULL, MF_UNKNOWN },
+      { CKM_CAST3_CBC,		"CAST3-CBC", NULL, MF_UNKNOWN },
+      { CKM_CAST3_MAC,		"CAST3-MAC", NULL, MF_UNKNOWN },
+      { CKM_CAST3_MAC_GENERAL,	"CAST3-MAC-GENERAL", NULL, MF_UNKNOWN },
+      { CKM_CAST3_CBC_PAD,	"CAST3-CBC-PAD", NULL, MF_UNKNOWN },
+      { CKM_CAST5_KEY_GEN,	"CAST5-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_CAST5_ECB,		"CAST5-ECB", NULL, MF_UNKNOWN },
+      { CKM_CAST5_CBC,		"CAST5-CBC", NULL, MF_UNKNOWN },
+      { CKM_CAST5_MAC,		"CAST5-MAC", NULL, MF_UNKNOWN },
+      { CKM_CAST5_MAC_GENERAL,	"CAST5-MAC-GENERAL", NULL, MF_UNKNOWN },
+      { CKM_CAST5_CBC_PAD,	"CAST5-CBC-PAD", NULL, MF_UNKNOWN },
+      { CKM_RC5_KEY_GEN,	"RC5-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_RC5_ECB,		"RC5-ECB", NULL, MF_UNKNOWN },
+      { CKM_RC5_CBC,		"RC5-CBC", NULL, MF_UNKNOWN },
+      { CKM_RC5_MAC,		"RC5-MAC", NULL, MF_UNKNOWN },
+      { CKM_RC5_MAC_GENERAL,	"RC5-MAC-GENERAL", NULL, MF_UNKNOWN },
+      { CKM_RC5_CBC_PAD,	"RC5-CBC-PAD", NULL, MF_UNKNOWN },
+      { CKM_IDEA_KEY_GEN,	"IDEA-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_IDEA_ECB,		"IDEA-ECB", NULL, MF_UNKNOWN },
+      { CKM_IDEA_CBC,		"IDEA-CBC", NULL, MF_UNKNOWN },
+      { CKM_IDEA_MAC,		"IDEA-MAC", NULL, MF_UNKNOWN },
+      { CKM_IDEA_MAC_GENERAL,	"IDEA-MAC-GENERAL", NULL, MF_UNKNOWN },
+      { CKM_IDEA_CBC_PAD,	"IDEA-CBC-PAD", NULL, MF_UNKNOWN },
+      { CKM_GENERIC_SECRET_KEY_GEN,"GENERIC-SECRET-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_CONCATENATE_BASE_AND_KEY,"CONCATENATE-BASE-AND-KEY", NULL, MF_UNKNOWN },
+      { CKM_CONCATENATE_BASE_AND_DATA,"CONCATENATE-BASE-AND-DATA", NULL, MF_UNKNOWN },
+      { CKM_CONCATENATE_DATA_AND_BASE,"CONCATENATE-DATA-AND-BASE", NULL, MF_UNKNOWN },
+      { CKM_XOR_BASE_AND_DATA,	"XOR-BASE-AND-DATA", NULL, MF_UNKNOWN },
+      { CKM_EXTRACT_KEY_FROM_KEY,"EXTRACT-KEY-FROM-KEY", NULL, MF_UNKNOWN },
+      { CKM_SSL3_PRE_MASTER_KEY_GEN,"SSL3-PRE-MASTER-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_SSL3_MASTER_KEY_DERIVE,"SSL3-MASTER-KEY-DERIVE", NULL, MF_UNKNOWN },
+      { CKM_SSL3_KEY_AND_MAC_DERIVE,"SSL3-KEY-AND-MAC-DERIVE", NULL, MF_UNKNOWN },
+      { CKM_SSL3_MASTER_KEY_DERIVE_DH,"SSL3-MASTER-KEY-DERIVE-DH", NULL, MF_UNKNOWN },
+      { CKM_TLS_PRE_MASTER_KEY_GEN,"TLS-PRE-MASTER-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_TLS_MASTER_KEY_DERIVE,"TLS-MASTER-KEY-DERIVE", NULL, MF_UNKNOWN },
+      { CKM_TLS_KEY_AND_MAC_DERIVE,"TLS-KEY-AND-MAC-DERIVE", NULL, MF_UNKNOWN },
+      { CKM_TLS_MASTER_KEY_DERIVE_DH,"TLS-MASTER-KEY-DERIVE-DH", NULL, MF_UNKNOWN },
+      { CKM_SSL3_MD5_MAC,	"SSL3-MD5-MAC", NULL, MF_UNKNOWN },
+      { CKM_SSL3_SHA1_MAC,	"SSL3-SHA1-MAC", NULL, MF_UNKNOWN },
+      { CKM_MD5_KEY_DERIVATION,	"MD5-KEY-DERIVATION", NULL, MF_UNKNOWN },
+      { CKM_MD2_KEY_DERIVATION,	"MD2-KEY-DERIVATION", NULL, MF_UNKNOWN },
+      { CKM_SHA1_KEY_DERIVATION,"SHA1-KEY-DERIVATION", NULL, MF_UNKNOWN },
+      { CKM_PBE_MD2_DES_CBC,	"PBE-MD2-DES-CBC", NULL, MF_UNKNOWN },
+      { CKM_PBE_MD5_DES_CBC,	"PBE-MD5-DES-CBC", NULL, MF_UNKNOWN },
+      { CKM_PBE_MD5_CAST_CBC,	"PBE-MD5-CAST-CBC", NULL, MF_UNKNOWN },
+      { CKM_PBE_MD5_CAST3_CBC,	"PBE-MD5-CAST3-CBC", NULL, MF_UNKNOWN },
+      { CKM_PBE_MD5_CAST5_CBC,	"PBE-MD5-CAST5-CBC", NULL, MF_UNKNOWN },
+      { CKM_PBE_SHA1_CAST5_CBC,	"PBE-SHA1-CAST5-CBC", NULL, MF_UNKNOWN },
+      { CKM_PBE_SHA1_RC4_128,	"PBE-SHA1-RC4-128", NULL, MF_UNKNOWN },
+      { CKM_PBE_SHA1_RC4_40,	"PBE-SHA1-RC4-40", NULL, MF_UNKNOWN },
+      { CKM_PBE_SHA1_DES3_EDE_CBC,"PBE-SHA1-DES3-EDE-CBC", NULL, MF_UNKNOWN },
+      { CKM_PBE_SHA1_DES2_EDE_CBC,"PBE-SHA1-DES2-EDE-CBC", NULL, MF_UNKNOWN },
+      { CKM_PBE_SHA1_RC2_128_CBC,"PBE-SHA1-RC2-128-CBC", NULL, MF_UNKNOWN },
+      { CKM_PBE_SHA1_RC2_40_CBC,"PBE-SHA1-RC2-40-CBC", NULL, MF_UNKNOWN },
+      { CKM_PKCS5_PBKD2,	"PKCS5-PBKD2", NULL, MF_UNKNOWN },
+      { CKM_PBA_SHA1_WITH_SHA1_HMAC,"PBA-SHA1-WITH-SHA1-HMAC", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_KEY_WRAP_LYNKS,	"KEY-WRAP-LYNKS", NULL, MF_UNKNOWN },
+      { CKM_KEY_WRAP_SET_OAEP,	"KEY-WRAP-SET-OAEP", NULL, MF_UNKNOWN },
+      { CKM_SKIPJACK_KEY_GEN,	"SKIPJACK-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_SKIPJACK_ECB64,	"SKIPJACK-ECB64", NULL, MF_UNKNOWN },
+      { CKM_SKIPJACK_CBC64,	"SKIPJACK-CBC64", NULL, MF_UNKNOWN },
+      { CKM_SKIPJACK_OFB64,	"SKIPJACK-OFB64", NULL, MF_UNKNOWN },
+      { CKM_SKIPJACK_CFB64,	"SKIPJACK-CFB64", NULL, MF_UNKNOWN },
+      { CKM_SKIPJACK_CFB32,	"SKIPJACK-CFB32", NULL, MF_UNKNOWN },
+      { CKM_SKIPJACK_CFB16,	"SKIPJACK-CFB16", NULL, MF_UNKNOWN },
+      { CKM_SKIPJACK_CFB8,	"SKIPJACK-CFB8", NULL, MF_UNKNOWN },
+      { CKM_SKIPJACK_WRAP,	"SKIPJACK-WRAP", NULL, MF_UNKNOWN },
+      { CKM_SKIPJACK_PRIVATE_WRAP,"SKIPJACK-PRIVATE-WRAP", NULL, MF_UNKNOWN },
+      { CKM_SKIPJACK_RELAYX,	"SKIPJACK-RELAYX", NULL, MF_UNKNOWN },
+      { CKM_KEA_KEY_PAIR_GEN,	"KEA-KEY-PAIR-GEN", NULL, MF_UNKNOWN },
+      { CKM_KEA_KEY_DERIVE,	"KEA-KEY-DERIVE", NULL, MF_UNKNOWN },
+      { CKM_FORTEZZA_TIMESTAMP,	"FORTEZZA-TIMESTAMP", NULL, MF_UNKNOWN },
+      { CKM_BATON_KEY_GEN,	"BATON-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_BATON_ECB128,	"BATON-ECB128", NULL, MF_UNKNOWN },
+      { CKM_BATON_ECB96,	"BATON-ECB96", NULL, MF_UNKNOWN },
+      { CKM_BATON_CBC128,	"BATON-CBC128", NULL, MF_UNKNOWN },
+      { CKM_BATON_COUNTER,	"BATON-COUNTER", NULL, MF_UNKNOWN },
+      { CKM_BATON_SHUFFLE,	"BATON-SHUFFLE", NULL, MF_UNKNOWN },
+      { CKM_BATON_WRAP,		"BATON-WRAP", NULL, MF_UNKNOWN },
+      { CKM_ECDSA_KEY_PAIR_GEN,	"ECDSA-KEY-PAIR-GEN", NULL, MF_UNKNOWN },
+      { CKM_ECDSA,		"ECDSA", NULL, MF_UNKNOWN },
+      { CKM_ECDSA_SHA1,		"ECDSA-SHA1", NULL, MF_UNKNOWN },
+      { CKM_ECDSA_SHA224,	"ECDSA-SHA224", NULL, MF_UNKNOWN },
+      { CKM_ECDSA_SHA256,	"ECDSA-SHA256", NULL, MF_UNKNOWN },
+      { CKM_ECDSA_SHA384,	"ECDSA-SHA384", NULL, MF_UNKNOWN },
+      { CKM_ECDSA_SHA512,	"ECDSA-SHA512", NULL, MF_UNKNOWN },
+      { CKM_ECDSA_SHA3_224,	"ECDSA-SHA3-224", NULL, MF_UNKNOWN },
+      { CKM_ECDSA_SHA3_256,	"ECDSA-SHA3-256", NULL, MF_UNKNOWN },
+      { CKM_ECDSA_SHA3_384,	"ECDSA-SHA3-384", NULL, MF_UNKNOWN },
+      { CKM_ECDSA_SHA3_512,	"ECDSA-SHA3-512", NULL, MF_UNKNOWN },
+      { CKM_ECDH1_DERIVE,	"ECDH1-DERIVE", NULL, MF_UNKNOWN },
+      { CKM_ECDH1_COFACTOR_DERIVE,"ECDH1-COFACTOR-DERIVE", NULL, MF_UNKNOWN },
+      { CKM_ECMQV_DERIVE,	"ECMQV-DERIVE", NULL, MF_UNKNOWN },
+      { CKM_EC_EDWARDS_KEY_PAIR_GEN,"EC-EDWARDS-KEY-PAIR-GEN", NULL, MF_UNKNOWN },
+      { CKM_EC_MONTGOMERY_KEY_PAIR_GEN,"EC-MONTGOMERY-KEY-PAIR-GEN", NULL, MF_UNKNOWN },
+      { CKM_EDDSA,		"EDDSA", NULL, MF_UNKNOWN },
+      { CKM_XEDDSA,		"XEDDSA", NULL, MF_UNKNOWN },
+      { CKM_JUNIPER_KEY_GEN,	"JUNIPER-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_JUNIPER_ECB128,	"JUNIPER-ECB128", NULL, MF_UNKNOWN },
+      { CKM_JUNIPER_CBC128,	"JUNIPER-CBC128", NULL, MF_UNKNOWN },
+      { CKM_JUNIPER_COUNTER,	"JUNIPER-COUNTER", NULL, MF_UNKNOWN },
+      { CKM_JUNIPER_SHUFFLE,	"JUNIPER-SHUFFLE", NULL, MF_UNKNOWN },
+      { CKM_JUNIPER_WRAP,	"JUNIPER-WRAP", NULL, MF_UNKNOWN },
+      { CKM_FASTHASH,		"FASTHASH", NULL, MF_UNKNOWN },
+      { CKM_AES_KEY_GEN,	"AES-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_AES_ECB,		"AES-ECB", NULL, MF_UNKNOWN },
+      { CKM_AES_CBC,		"AES-CBC", NULL, MF_UNKNOWN },
+      { CKM_AES_MAC,		"AES-MAC", NULL, MF_UNKNOWN },
+      { CKM_AES_MAC_GENERAL,	"AES-MAC-GENERAL", NULL, MF_UNKNOWN },
+      { CKM_AES_CBC_PAD,	"AES-CBC-PAD", NULL, MF_UNKNOWN },
+      { CKM_AES_CTR,		"AES-CTR", NULL, MF_UNKNOWN },
+      { CKM_AES_GCM,		"AES-GCM", NULL, MF_UNKNOWN },
+      { CKM_AES_CMAC,		"AES-CMAC", NULL, MF_UNKNOWN },
+      { CKM_DES_ECB_ENCRYPT_DATA, "DES-ECB-ENCRYPT-DATA", NULL, MF_UNKNOWN },
+      { CKM_DES_CBC_ENCRYPT_DATA, "DES-CBC-ENCRYPT-DATA", NULL, MF_UNKNOWN },
+      { CKM_DES3_ECB_ENCRYPT_DATA, "DES3-ECB-ENCRYPT-DATA", NULL, MF_UNKNOWN },
+      { CKM_DES3_CBC_ENCRYPT_DATA, "DES3-CBC-ENCRYPT-DATA", NULL, MF_UNKNOWN },
+      { CKM_AES_ECB_ENCRYPT_DATA, "AES-ECB-ENCRYPT-DATA", NULL, MF_UNKNOWN },
+      { CKM_AES_CBC_ENCRYPT_DATA, "AES-CBC-ENCRYPT-DATA", NULL, MF_UNKNOWN },
+      { CKM_GOST28147_KEY_GEN,	"GOST28147-KEY-GEN", NULL, MF_UNKNOWN },
+      { CKM_GOST28147_ECB,	"GOST28147-ECB", NULL, MF_UNKNOWN },
+      { CKM_GOST28147,	"GOST28147", NULL, MF_UNKNOWN },
+      { CKM_GOST28147_MAC,	"GOST28147-MAC", NULL, MF_UNKNOWN },
+      { CKM_GOST28147_KEY_WRAP,	"GOST28147-KEY-WRAP", NULL, MF_UNKNOWN },
+      { CKM_GOSTR3410_KEY_PAIR_GEN,"GOSTR3410-KEY-PAIR-GEN", NULL, MF_UNKNOWN },
+      { CKM_GOSTR3410,		"GOSTR3410", NULL, MF_UNKNOWN },
+      { CKM_GOSTR3410_DERIVE,	"GOSTR3410-DERIVE", NULL, MF_UNKNOWN },
+      { CKM_GOSTR3410_WITH_GOSTR3411,"GOSTR3410-WITH-GOSTR3411", NULL, MF_UNKNOWN },
+      { CKM_GOSTR3410_512_KEY_PAIR_GEN,	"GOSTR3410-512-KEY-PAIR-GEN", NULL, MF_UNKNOWN },
+      { CKM_GOSTR3410_512,	"GOSTR3410_512", NULL, MF_UNKNOWN },
+      { CKM_GOSTR3410_12_DERIVE,	"GOSTR3410-12-DERIVE", NULL, MF_UNKNOWN },
+      { CKM_GOSTR3410_WITH_GOSTR3411_12_256,	"GOSTR3410-WITH-GOSTR3411-12-256", NULL, MF_UNKNOWN },
+      { CKM_GOSTR3410_WITH_GOSTR3411_12_512,	"GOSTR3410-WITH-GOSTR3411-12-512", NULL, MF_UNKNOWN },
+      { CKM_GOSTR3411,		"GOSTR3411", NULL, MF_UNKNOWN },
+      { CKM_GOSTR3411_HMAC,	"GOSTR3411-HMAC", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_GOSTR3411_12_256,	"GOSTR3411-12-256", NULL, MF_UNKNOWN },
+      { CKM_GOSTR3411_12_512,	"GOSTR3411-12-512", NULL, MF_UNKNOWN },
+      { CKM_GOSTR3411_12_256_HMAC,	"GOSTR3411-12-256-HMAC", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_GOSTR3411_12_512_HMAC,	"GOSTR3411-12-512-HMAC", NULL, MF_GENERIC_HMAC_FLAGS },
+      { CKM_DSA_PARAMETER_GEN,	"DSA-PARAMETER-GEN", NULL, MF_UNKNOWN },
+      { CKM_DH_PKCS_PARAMETER_GEN,"DH-PKCS-PARAMETER-GEN", NULL, MF_UNKNOWN },
+      { CKM_X9_42_DH_PARAMETER_GEN,"X9-42-DH-PARAMETER-GEN", NULL, MF_UNKNOWN },
+      { CKM_AES_KEY_WRAP,	"AES-KEY-WRAP", NULL, MF_UNKNOWN },
+      { 0, NULL, NULL, MF_UNKNOWN }
 };
 
 static struct mech_info	p11_mgf[] = {
-      { CKG_MGF1_SHA1,		"MGF1-SHA1", NULL },
-      { CKG_MGF1_SHA224,	"MGF1-SHA224", NULL },
-      { CKG_MGF1_SHA256,	"MGF1-SHA256", NULL },
-      { CKG_MGF1_SHA384,	"MGF1-SHA384", NULL },
-      { CKG_MGF1_SHA512,	"MGF1-SHA512", NULL },
-      { 0, NULL, NULL }
+      { CKG_MGF1_SHA1,		"MGF1-SHA1", NULL, MF_MGF },
+      { CKG_MGF1_SHA224,	"MGF1-SHA224", NULL, MF_MGF },
+      { CKG_MGF1_SHA256,	"MGF1-SHA256", NULL, MF_MGF },
+      { CKG_MGF1_SHA384,	"MGF1-SHA384", NULL, MF_MGF },
+      { CKG_MGF1_SHA512,	"MGF1-SHA512", NULL, MF_MGF },
+      { CKG_MGF1_SHA3_224,	"MGF1-SHA3_224", NULL, MF_MGF },
+      { CKG_MGF1_SHA3_256,	"MGF1-SHA3_256", NULL, MF_MGF },
+      { CKG_MGF1_SHA3_384,	"MGF1-SHA3_384", NULL, MF_MGF },
+      { CKG_MGF1_SHA3_512,	"MGF1-SHA3_512", NULL, MF_MGF },
+
+      { 0, NULL, NULL, MF_UNKNOWN }
+};
+
+static struct mech_info p11_profile[] = {
+	{ CKP_INVALID_ID,                "CKP_INVALID_ID",                NULL, MF_UNKNOWN },
+	{ CKP_BASELINE_PROVIDER,         "CKP_BASELINE_PROVIDER",         NULL, MF_UNKNOWN },
+	{ CKP_EXTENDED_PROVIDER,         "CKP_EXTENDED_PROVIDER",         NULL, MF_UNKNOWN },
+	{ CKP_AUTHENTICATION_TOKEN,      "CKP_AUTHENTICATION_TOKEN",      NULL, MF_UNKNOWN },
+	{ CKP_PUBLIC_CERTIFICATES_TOKEN, "CKP_PUBLIC_CERTIFICATES_TOKEN", NULL, MF_UNKNOWN },
+	{ CKP_VENDOR_DEFINED,            "CKP_VENDOR_DEFINED",            NULL, MF_UNKNOWN },
+	{ 0, NULL, NULL, MF_UNKNOWN }
 };
 
 static const char *p11_mechanism_to_name(CK_MECHANISM_TYPE mech)
@@ -7198,6 +8221,25 @@
 	return temp;
 }
 
+uint16_t p11_mechanism_to_flags(CK_MECHANISM_TYPE mech)
+{
+	struct mech_info *mi;
+	for (mi = p11_mechanisms; mi->name; mi++) {
+		if (mi->mech == mech)
+			return mi->mf_flags;
+	}
+
+	/*
+	 * XXX: Since populating the table is underway we won't warn until its done. Existing mechanisms function
+	 * as they used to. So guard this on verbose.
+	 */
+	if (verbose) {
+		util_warn("mechanism 0x%lx not found, consider adding it to mechanism table", mech);
+	}
+
+	return MF_UNKNOWN;
+}
+
 static CK_MECHANISM_TYPE p11_name_to_mechanism(const char *name)
 {
 	struct mech_info *mi;
@@ -7238,6 +8280,19 @@
 	return temp;
 }
 
+static const char *p11_profile_to_name(CK_ULONG profile)
+{
+	static char temp[64];
+	struct mech_info *mi;
+
+	for (mi = p11_profile; mi->name; mi++) {
+		if (mi->mech == profile)
+			return mi->name;
+	}
+	snprintf(temp, sizeof(temp), "profile-0x%lX", (unsigned long) profile);
+	return temp;
+}
+
 static const char * CKR2Str(CK_ULONG res)
 {
 	switch (res) {
@@ -7436,7 +8491,7 @@
 	/* call selected C_* routines with different options */
 	pctest = ttd-> tests;
 
-	/* series of two chatacter commands */
+	/* series of two character commands */
 	while (pctest && *pctest && *(pctest + 1)) {
 		ttd->state = state++;
 
@@ -7458,7 +8513,7 @@
 				ttd->rv = rv;
 				fprintf(stderr, "Test thread %d C_Initialize returned %s\n", ttd->tnum, CKR2Str(rv));
 			}
-			/* CL C_Initialize with CKF_OS_LOCKING_OK */
+			/* IL C_Initialize with CKF_OS_LOCKING_OK */
 			else if (*(pctest + 1) == 'L') {
 				fprintf(stderr, "Test thread %d C_Initialize CKF_OS_LOCKING_OK \n", ttd->tnum);
 				rv = p11->C_Initialize(&c_initialize_args_OS);
@@ -7506,10 +8561,12 @@
 		/* Tn Get token from slot_index n C_GetTokenInfo, where n is 0 to 9 */
 		else if (*pctest == 'T' && *(pctest + 1) >= '0' && *(pctest + 1) <= '9') {
 			fprintf(stderr, "Test thread %d C_GetTokenInfo from slot_index %d using show_token\n", ttd->tnum, (*(pctest + 1) - '0'));
-			if (l_slots) {
+			if (l_slots && (CK_ULONG)(*(pctest + 1) - '0') < l_p11_num_slots) {
 				show_token(l_p11_slots[(*(pctest + 1) - '0')]);
 			} else {
-				show_token(p11_slots[(*(pctest + 1) - '0')]);
+				fprintf(stderr, "Test thread %d slot not available, unable to call C_GetTokenInfo\n", ttd->tnum);
+				rv = CKR_TOKEN_NOT_PRESENT;
+				break;
 			}
 		}
 
@@ -7637,4 +8694,4 @@
 		test_threads_start(i);
 	}
 }
-#endif /* defined(_WIN32) || defiend(HAVE_PTHREAD) */
+#endif /* defined(_WIN32) || defined(HAVE_PTHREAD) */
diff -Nru opensc-0.22.0/src/tools/pkcs15-crypt.c opensc-0.23.0/src/tools/pkcs15-crypt.c
--- opensc-0.22.0/src/tools/pkcs15-crypt.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/pkcs15-crypt.c	2022-11-29 09:34:43.000000000 +0100
@@ -106,7 +106,7 @@
 	"Uses password (PIN) <arg> (use - for reading PIN from STDIN)",
 	"Specify AID of the on-card PKCS#15 application to be binded to (in hexadecimal form)",
 	"Wait for card insertion",
-	"Verbose operation. Use several times to enable debug output.",
+	"Verbose operation, may be used several times",
 };
 
 static sc_context_t *ctx = NULL;
@@ -237,7 +237,7 @@
 		return SC_ERROR_NOT_SUPPORTED;
 	}
 
-	r = sc_pkcs15_compute_signature(p15card, obj, opt_crypt_flags, buf, c, out, len);
+	r = sc_pkcs15_compute_signature(p15card, obj, opt_crypt_flags, buf, c, out, len, NULL);
 	if (r < 0) {
 		fprintf(stderr, "Compute signature failed: %s\n", sc_strerror(r));
 		return 1;
@@ -284,7 +284,7 @@
 		return SC_ERROR_NOT_SUPPORTED;
 	}
 
-	r = sc_pkcs15_decipher(p15card, obj, opt_crypt_flags & SC_ALGORITHM_RSA_PAD_PKCS1, buf, c, out, len);
+	r = sc_pkcs15_decipher(p15card, obj, opt_crypt_flags & SC_ALGORITHM_RSA_PAD_PKCS1, buf, c, out, len, NULL);
 	if (r < 0) {
 		fprintf(stderr, "Decrypt failed: %s\n", sc_strerror(r));
 		return 1;
@@ -389,8 +389,10 @@
 		c = getopt_long(argc, argv, "sck:r:i:o:f:Rp:vw", options, &long_optind);
 		if (c == -1)
 			break;
-		if (c == '?')
-			util_print_usage_and_die(app_name, options, option_help, NULL);
+		if (c == '?') {
+			util_print_usage(app_name, options, option_help, NULL);
+			return 2;
+		}
 		switch (c) {
 		case OPT_VERSION:
 			do_print_version = 1;
@@ -458,8 +460,10 @@
 			break;
 		}
 	}
-	if (action_count == 0)
-		util_print_usage_and_die(app_name, options, option_help, NULL);
+	if (action_count == 0) {
+		util_print_usage(app_name, options, option_help, NULL);
+		return 2;
+	}
 
 	if (do_print_version)   {
 		printf("%s\n", OPENSC_SCM_REVISION);
@@ -491,7 +495,8 @@
 		aid.len = sizeof(aid.value);
 		if (sc_hex_to_bin(opt_bind_to_aid, aid.value, &aid.len))   {
 			fprintf(stderr, "Invalid AID value: '%s'\n", opt_bind_to_aid);
-			return 1;
+			err = 1;
+			goto end;
 		}
 
 		r = sc_pkcs15_bind(card, &aid, &p15card);
diff -Nru opensc-0.22.0/src/tools/pkcs15-init.c opensc-0.23.0/src/tools/pkcs15-init.c
--- opensc-0.22.0/src/tools/pkcs15-init.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/pkcs15-init.c	2022-11-29 09:34:43.000000000 +0100
@@ -46,12 +46,15 @@
 #include <openssl/err.h>
 #include <openssl/rand.h>
 #include <openssl/rsa.h>
-#include <openssl/dsa.h>
 #include <openssl/bn.h>
 #include <openssl/pkcs12.h>
 #include <openssl/x509v3.h>
 #include <openssl/crypto.h>
 #include <openssl/opensslconf.h> /* for OPENSSL_NO_EC */
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L
+# include <openssl/core_names.h>
+# include <openssl/param_build.h>
+#endif
 #ifndef OPENSSL_NO_EC
 #include <openssl/ec.h>
 #endif /* OPENSSL_NO_EC */
@@ -279,7 +282,7 @@
 	"For a new key specify GUID for a MD container",
 	"Wait for card insertion",
 	"Display this message",
-	"Verbose operation. Use several times to enable debug output.",
+	"Verbose operation, may be used several times",
 
 	NULL,
 	NULL,
@@ -447,23 +450,8 @@
 {
 	struct sc_profile	*profile = NULL;
 	unsigned int		n;
-	int			r = 0;
-
-#if OPENSSL_VERSION_NUMBER < 0x10100000L
-	OPENSSL_config(NULL);
-#endif
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L && !(defined LIBRESSL_VERSION_NUMBER)
-	/* Openssl 1.1.0 magic */
-	OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS
-		| OPENSSL_INIT_ADD_ALL_CIPHERS
-		| OPENSSL_INIT_ADD_ALL_DIGESTS
-		| OPENSSL_INIT_LOAD_CONFIG,
-		NULL);
-#else
-	/* OpenSSL magic */
-	OpenSSL_add_all_algorithms();
-	OPENSSL_malloc_init();
-#endif
+	int					r = 0;
+	struct sc_pkcs15_card *tmp_p15_data = NULL;
 
 #ifdef RANDOM_POOL
 	if (!RAND_load_file(RANDOM_POOL, 32))
@@ -632,8 +620,13 @@
 	}
 
 out:
+	/* After erasing card profile->p15_data might change */
 	if (profile) {
+		tmp_p15_data = profile->p15_data;
 		sc_pkcs15init_unbind(profile);
+		if 	(tmp_p15_data != g_p15card) {
+ 			sc_pkcs15_unbind(tmp_p15_data);
+		}
 	}
 	if (g_p15card) {
 		sc_pkcs15_unbind(g_p15card);
@@ -727,7 +720,6 @@
 
 static const struct alg_spec alg_types_asym[] = {
 	{ "rsa",	SC_ALGORITHM_RSA,	1024 },
-	{ "dsa",	SC_ALGORITHM_DSA,	1024 },
 	{ "gost2001",	SC_ALGORITHM_GOSTR3410,	SC_PKCS15_GOSTR3410_KEYSIZE },
 	{ "ec",		SC_ALGORITHM_EC,	0 },
 	{ NULL, -1, 0 }
@@ -1159,6 +1151,7 @@
 
 	count = r;
 	for (i = 0; i < count; i++) {
+		int private_obj;
 		cinfo = (sc_pkcs15_cert_info_t *) objs[i]->data;
 
 		if (!cinfo->authority)
@@ -1168,7 +1161,8 @@
 		/* XXX we should also match the usage field here */
 
 		/* Compare the DER representation of the certificates */
-		r = sc_pkcs15_read_certificate(g_p15card, cinfo, &cert);
+		private_obj = objs[i]->flags & SC_PKCS15_CO_FLAG_PRIVATE;
+		r = sc_pkcs15_read_certificate(g_p15card, cinfo, private_obj, &cert);
 		if (r < 0 || !cert)
 			continue;
 
@@ -1336,24 +1330,15 @@
 	/* Compare the public keys, there's no high level openssl function for this(?) */
 	/* Yes there is in 1.0.2 and above EVP_PKEY_cmp */
 
-
 	r = SC_ERROR_INVALID_ARGUMENTS;
 	if (oldpk_type == newpk_type)
 	{
-#if  OPENSSL_VERSION_NUMBER >= 0x10002000L
-		if (EVP_PKEY_cmp(oldpk, newpk) == 1)
-			r = 0;
+#if OPENSSL_VERSION_NUMBER >= 0x30000000L && !defined(LIBRESSL_VERSION_NUMBER)
+		if (EVP_PKEY_eq(oldpk, newpk) == 1)
 #else
-		if ((oldpk_type == EVP_PKEY_DSA) &&
-			!BN_cmp(EVP_PKEY_get0_DSA(oldpk)->p, EVP_PKEY_get0_DSA(newpk)->p) &&
-			!BN_cmp(EVP_PKEY_get0_DSA(oldpk)->q, EVP_PKEY_get0_DSA(newpk)->q) &&
-			!BN_cmp(EVP_PKEY_get0_DSA(oldpk)->g, EVP_PKEY_get0_DSA(newpk)->g))
-				r = 0;
-		else if ((oldpk_type == EVP_PKEY_RSA) &&
-			!BN_cmp(EVP_PKEY_get0_RSA(oldpk)->n, EVP_PKEY_get0_RSA(newpk)->n) &&
-			!BN_cmp(EVP_PKEY_get0_RSA(oldpk)->e, EVP_PKEY_get0_RSA(newpk)->e))
-				r = 0;
+		if (EVP_PKEY_cmp(oldpk, newpk) == 1)
 #endif
+		r = 0;
 	}
 
 	EVP_PKEY_free(newpk);
@@ -1383,6 +1368,7 @@
 	sc_pkcs15_cert_t *oldcert = NULL;
 	sc_pkcs15_der_t newcert_raw;
 	int r;
+	int private_obj;
 
 	if (opt_objectid == NULL) {
 		util_error("no ID given for the cert: use --id");
@@ -1401,7 +1387,8 @@
 		return r;
 
 	certinfo = (sc_pkcs15_cert_info_t *) obj->data;
-	r = sc_pkcs15_read_certificate(g_p15card, certinfo, &oldcert);
+	private_obj = obj->flags & SC_PKCS15_CO_FLAG_PRIVATE;
+	r = sc_pkcs15_read_certificate(g_p15card, certinfo, private_obj, &oldcert);
 	if (r < 0)
 		goto err;
 
@@ -1498,12 +1485,14 @@
 	sc_pkcs15_object_t *otherobj;
 	sc_pkcs15_cert_t *othercert = NULL;
 	int r;
+	int private_obj;
 
 	*issuercert = NULL;
 	*has_sibling = 0;
 	*stop = 0;
 
-	r = sc_pkcs15_read_certificate(myp15card, (sc_pkcs15_cert_info_t *) certobj->data, &cert);
+	private_obj = certobj->flags & SC_PKCS15_CO_FLAG_PRIVATE;
+	r = sc_pkcs15_read_certificate(myp15card, (sc_pkcs15_cert_info_t *) certobj->data, private_obj, &cert);
 	if (r < 0)
 		return r;
 
@@ -1519,7 +1508,9 @@
 			sc_pkcs15_free_certificate(othercert);
 			othercert=NULL;
 		}
-		r = sc_pkcs15_read_certificate(myp15card, (sc_pkcs15_cert_info_t *) otherobj->data, &othercert);
+
+		private_obj = otherobj->flags & SC_PKCS15_CO_FLAG_PRIVATE;
+		r = sc_pkcs15_read_certificate(myp15card, (sc_pkcs15_cert_info_t *) otherobj->data, private_obj, &othercert);
 		if (r < 0 || !othercert)
 			goto done;
 		if ((cert->issuer_len == othercert->subject_len) &&
@@ -1778,6 +1769,7 @@
 	if (r == 0)
 		r = sc_pkcs15init_generate_key(g_p15card, profile, &keygen_args, keybits, NULL);
 	sc_unlock(g_p15card->card);
+	sc_pkcs15_free_prkey(&keygen_args.prkey_args.key);
 	return r;
 }
 
@@ -1793,13 +1785,14 @@
 
 	if ((r = init_skeyargs(&skey_args)) < 0)
 		return r;
-	skey_args.algorithm = algorithm;
 
 	algorithm = parse_alg_spec(alg_types_sym, spec, &keybits, 0);
 	if (algorithm < 0) {
 		util_error("Invalid symmetric key spec: \"%s\"", spec);
 		return SC_ERROR_INVALID_ARGUMENTS;
 	}
+
+	skey_args.algorithm = algorithm;
 	skey_args.value_len = keybits;
 
 	r = sc_lock(g_p15card->card);
@@ -1869,16 +1862,27 @@
 init_gost_params(struct sc_pkcs15init_keyarg_gost_params *params, EVP_PKEY *pkey)
 {
 #if !defined(OPENSSL_NO_EC)
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 	EC_KEY *key;
+#else
+	char name[256];
+#endif
+	int nid = NID_undef;
 
 	assert(pkey);
 	if (EVP_PKEY_id(pkey) == NID_id_GostR3410_2001) {
+		assert(params);
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 		key = EVP_PKEY_get0(pkey);
 		assert(key);
-		assert(params);
 		assert(EC_KEY_get0_group(key));
-		assert(EC_GROUP_get_curve_name(EC_KEY_get0_group(key)) > 0);
-		switch (EC_GROUP_get_curve_name(EC_KEY_get0_group(key))) {
+		nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(key));
+#else
+		assert(EVP_PKEY_get_group_name(pkey, name, sizeof(name), NULL));
+		nid = OBJ_txt2nid(name);
+#endif
+		assert(nid > 0);
+		switch (nid) {
 		case NID_id_GostR3410_2001_CryptoPro_A_ParamSet:
 			params->gostr3410 = SC_PKCS15_PARAMSET_GOSTR3410_A;
 			break;
@@ -2953,14 +2957,8 @@
 static void
 ossl_print_errors(void)
 {
-	static int	loaded = 0;
 	long		err;
 
-	if (!loaded) {
-		ERR_load_crypto_strings();
-		loaded = 1;
-	}
-
 	while ((err = ERR_get_error()) != 0)
 		fprintf(stderr, "%s\n", ERR_error_string(err, NULL));
 }
diff -Nru opensc-0.22.0/src/tools/pkcs15-tool.c opensc-0.23.0/src/tools/pkcs15-tool.c
--- opensc-0.22.0/src/tools/pkcs15-tool.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/pkcs15-tool.c	2022-11-29 09:34:43.000000000 +0100
@@ -193,7 +193,7 @@
 	"The auth ID of the PIN to use",
 	"Specify AID of the on-card PKCS#15 application to bind to (in hexadecimal form)",
 	"Wait for card insertion",
-	"Verbose operation. Use several times to enable debug output.",
+	"Verbose operation, may be used several times",
 	"Do not prompt the user; if no PINs supplied, pinpad will be used.",
 	NULL,
 	NULL
@@ -221,7 +221,7 @@
 	{0, NULL},
 };
 
-static const char *key_types[] = { "", "RSA", "DSA", "GOSTR3410", "EC", "EDDSA", "XEDDSA", "" };
+static const char *key_types[] = { "", "RSA", "", "GOSTR3410", "EC", "EDDSA", "XEDDSA", "" };
 
 static void
 print_access_rules(const struct sc_pkcs15_accessrule *rules, int num)
@@ -269,6 +269,7 @@
 	struct sc_pkcs15_cert_info *cert_info = (struct sc_pkcs15_cert_info *) obj->data;
 	struct sc_pkcs15_cert *cert_parsed = NULL;
 	int rv;
+	int private_obj;
 
 	if (compact) {
 		printf("\tPath:%s  ID:%s", sc_print_path(&cert_info->path),
@@ -286,7 +287,8 @@
 
 	print_access_rules(obj->access_rules, SC_PKCS15_MAX_ACCESS_RULES);
 
-	rv = sc_pkcs15_read_certificate(p15card, cert_info, &cert_parsed);
+	private_obj = obj->flags & SC_PKCS15_CO_FLAG_PRIVATE;
+	rv = sc_pkcs15_read_certificate(p15card, cert_info, private_obj, &cert_parsed);
 	if (rv >= 0 && cert_parsed)   {
 		printf("\tEncoded serial : %02X %02X ", *(cert_parsed->serial), *(cert_parsed->serial + 1));
 		util_hex_dump(stdout, cert_parsed->serial + 2, cert_parsed->serial_len - 2, "");
@@ -431,13 +433,15 @@
 	for (i = 0; i < count; i++) {
 		struct sc_pkcs15_cert_info *cinfo = (struct sc_pkcs15_cert_info *) objs[i]->data;
 		struct sc_pkcs15_cert *cert;
+		int private_obj;
 
 		if (sc_pkcs15_compare_id(&id, &cinfo->id) != 1)
 			continue;
 
 		if (verbose)
 			printf("Reading certificate with ID '%s'\n", opt_cert);
-		r = sc_pkcs15_read_certificate(p15card, cinfo, &cert);
+		private_obj = objs[i]->flags & SC_PKCS15_CO_FLAG_PRIVATE;
+		r = sc_pkcs15_read_certificate(p15card, cinfo, private_obj, &cert);
 		if (r) {
 			fprintf(stderr, "Certificate read failed: %s\n", sc_strerror(r));
 			return 1;
@@ -466,6 +470,7 @@
 	for (i = 0; i < count; i++) {
 		struct sc_pkcs15_data_info *cinfo = (struct sc_pkcs15_data_info *) objs[i]->data;
 		struct sc_pkcs15_data *data_object = NULL;
+		int private_obj;
 
 		if (!sc_format_oid(&oid, opt_data))   {
 			if (!sc_compare_oid(&oid, &cinfo->app_oid))
@@ -480,7 +485,8 @@
 			printf("Reading data object with label '%s'\n", opt_data);
 		r = authenticate(objs[i]);
 		if (r >= 0) {
-			r = sc_pkcs15_read_data_object(p15card, cinfo, &data_object);
+			private_obj = objs[i]->flags & SC_PKCS15_CO_FLAG_PRIVATE;
+			r = sc_pkcs15_read_data_object(p15card, cinfo, private_obj, &data_object);
 			if (r) {
 				fprintf(stderr, "Data object read failed: %s\n", sc_strerror(r));
 				if (r == SC_ERROR_FILE_NOT_FOUND)
@@ -527,7 +533,8 @@
 			}
 			if (objs[i]->auth_id.len == 0) {
 				struct sc_pkcs15_data *data_object;
-				r = sc_pkcs15_read_data_object(p15card, cinfo, &data_object);
+				int private_obj = objs[i]->flags & SC_PKCS15_CO_FLAG_PRIVATE;
+				r = sc_pkcs15_read_data_object(p15card, cinfo, private_obj, &data_object);
 				if (r) {
 					fprintf(stderr, "Data object read failed: %s\n", sc_strerror(r));
 					if (r == SC_ERROR_FILE_NOT_FOUND)
@@ -559,7 +566,8 @@
 		printf("\tPath:            %s\n", sc_print_path(&cinfo->path));
 		if (objs[i]->auth_id.len == 0) {
 			struct sc_pkcs15_data *data_object;
-			r = sc_pkcs15_read_data_object(p15card, cinfo, &data_object);
+			int private_obj = objs[i]->flags & SC_PKCS15_CO_FLAG_PRIVATE;
+			r = sc_pkcs15_read_data_object(p15card, cinfo, private_obj, &data_object);
 			if (r) {
 				fprintf(stderr, "Data object read failed: %s\n", sc_strerror(r));
 				if (r == SC_ERROR_FILE_NOT_FOUND)
@@ -802,11 +810,13 @@
 		r = sc_pkcs15_read_pubkey(p15card, obj, &pubkey);
 	} else if (r == SC_ERROR_OBJECT_NOT_FOUND) {
 		/* No pubkey - try if there's a certificate */
+		int private_obj;
 		r = sc_pkcs15_find_cert_by_id(p15card, &id, &obj);
 		if (r >= 0) {
 			if (verbose)
 				printf("Reading certificate with ID '%s'\n", opt_pubkey);
-			r = sc_pkcs15_read_certificate(p15card, (sc_pkcs15_cert_info_t *) obj->data, &cert);
+			private_obj = obj->flags & SC_PKCS15_CO_FLAG_PRIVATE;
+			r = sc_pkcs15_read_certificate(p15card, (sc_pkcs15_cert_info_t *) obj->data, private_obj, &cert);
 		}
 		if (r >= 0)
 			pubkey = cert->key;
@@ -976,11 +986,13 @@
 	}
 	else if (r == SC_ERROR_OBJECT_NOT_FOUND) {
 		/* No pubkey - try if there's a certificate */
+		int private_obj;
 		r = sc_pkcs15_find_cert_by_id(p15card, &id, &obj);
 		if (r >= 0) {
 			if (verbose)
 				fprintf(stderr,"Reading certificate with ID '%s'\n", opt_pubkey);
-			r = sc_pkcs15_read_certificate(p15card, (sc_pkcs15_cert_info_t *) obj->data, &cert);
+			private_obj = obj->flags & SC_PKCS15_CO_FLAG_PRIVATE;
+			r = sc_pkcs15_read_certificate(p15card, (sc_pkcs15_cert_info_t *) obj->data, private_obj, &cert);
 		}
 		if (r >= 0)
 			pubkey = cert->key;
@@ -1002,12 +1014,13 @@
 	if (pubkey->algorithm == SC_ALGORITHM_EDDSA) {
 		// SSH supports only ed25519 key now
 
-		char alg[20];
+		const char alg[] = "ssh-ed25519";
 		/* Large enough to fit the following:
 		 * 2 x 4B item length headers
 		 * max 11B algorithm name, 32B key data */
 		unsigned char buf[64];
-		unsigned int len, n;
+		unsigned int n;
+		int len;
 
 		n = pubkey->u.eddsa.pubkey.len;
 		if (n != 32) {
@@ -1015,12 +1028,12 @@
 			goto fail2;
 		}
 
+		len = strlen(alg);
 		buf[0] = 0;
 		buf[1] = 0;
 		buf[2] = 0;
-		len = snprintf((char *) buf+4, 20, "ssh-ed25519");
-		memcpy(alg, buf+4, 20);
 		buf[3] = len;
+		memcpy(buf+4, alg, len);
 		len += 4;
 
 		buf[len++] = 0;
@@ -1051,7 +1064,8 @@
 		 * 3 x 4B item length headers
 		 * max 20B algorithm name, 9B curve name, max 256B key data */
 		unsigned char buf[300];
-		unsigned int i, len, tmp, n;
+		unsigned int i, tmp, n;
+		int len;
 
 		for (n = 0,i = 0; ec_curves[i].curve_name != NULL; i++) {
 			if(sc_compare_oid (&ec_curves[i].curve_oid,&pubkey->u.ec.params.id))
@@ -1066,14 +1080,18 @@
 			goto fail2;
 		}
 
+		len = snprintf(alg, sizeof alg, "ecdsa-sha2-nistp%d", n);
+		if (len < 0) {
+			fprintf(stderr, "failed to write algorithm\n");
+			goto fail2;
+		}
 		buf[0] = 0;
 		buf[1] = 0;
 		buf[2] = 0;
-		len = snprintf((char *) buf+4, 20, "ecdsa-sha2-nistp%d", n);
-		memcpy(alg, buf+4, 20);
 		buf[3] = len;
-
+		memcpy(buf+4, alg, len);
 		len += 4;
+
 		buf[len++] = 0;
 		buf[len++] = 0;
 		buf[len++] = 0;
@@ -1151,97 +1169,6 @@
 		print_ssh_key(outf, "ssh-rsa", obj, buf, len);
 	}
 
-	if (pubkey->algorithm == SC_ALGORITHM_DSA) {
-		unsigned char buf[2048];
-		uint32_t len;
-		uint32_t n;
-
-		if (!pubkey->u.dsa.p.data || !pubkey->u.dsa.p.len ||
-				!pubkey->u.dsa.q.data || !pubkey->u.dsa.q.len ||
-				!pubkey->u.dsa.g.data || !pubkey->u.dsa.g.len ||
-				!pubkey->u.dsa.pub.data || !pubkey->u.dsa.pub.len)   {
-			fprintf(stderr, "Failed to decode DSA key.\n");
-			goto fail2;
-		}
-
-		buf[0]=0;
-		buf[1]=0;
-		buf[2]=0;
-		buf[3]=7;
-
-		len = sprintf((char *) buf+4,"ssh-dss");
-		len+=4;
-
-		if (sizeof(buf)-len < 5+pubkey->u.dsa.p.len)
-			goto fail;
-
-		n = pubkey->u.dsa.p.len;
-		if (pubkey->u.dsa.p.data[0] & 0x80)
-			n++;
-
-		buf[len++]=(n >>24) & 0xff;
-		buf[len++]=(n >>16) & 0xff;
-		buf[len++]=(n >>8) & 0xff;
-		buf[len++]=(n) & 0xff;
-		if (pubkey->u.dsa.p.data[0] & 0x80)
-			buf[len++]= 0;
-
-		memcpy(buf+len,pubkey->u.dsa.p.data, pubkey->u.dsa.p.len);
-		len += pubkey->u.dsa.p.len;
-
-		if (sizeof(buf)-len < 5+pubkey->u.dsa.q.len)
-			goto fail;
-
-		n = pubkey->u.dsa.q.len;
-		if (pubkey->u.dsa.q.data[0] & 0x80)
-			n++;
-
-		buf[len++]=(n >>24) & 0xff;
-		buf[len++]=(n >>16) & 0xff;
-		buf[len++]=(n >>8) & 0xff;
-		buf[len++]=(n) & 0xff;
-		if (pubkey->u.dsa.q.data[0] & 0x80)
-			buf[len++]= 0;
-
-		memcpy(buf+len,pubkey->u.dsa.q.data, pubkey->u.dsa.q.len);
-		len += pubkey->u.dsa.q.len;
-
-		if (sizeof(buf)-len < 5+pubkey->u.dsa.g.len)
-			goto fail;
-		n = pubkey->u.dsa.g.len;
-		if (pubkey->u.dsa.g.data[0] & 0x80)
-			n++;
-
-		buf[len++]=(n >>24) & 0xff;
-		buf[len++]=(n >>16) & 0xff;
-		buf[len++]=(n >>8) & 0xff;
-		buf[len++]=(n) & 0xff;
-		if (pubkey->u.dsa.g.data[0] & 0x80)
-			buf[len++]= 0;
-
-		memcpy(buf+len,pubkey->u.dsa.g.data, pubkey->u.dsa.g.len);
-		len += pubkey->u.dsa.g.len;
-
-		if (sizeof(buf)-len < 5+pubkey->u.dsa.pub.len)
-			goto fail;
-
-		n = pubkey->u.dsa.pub.len;
-		if (pubkey->u.dsa.pub.data[0] & 0x80)
-			n++;
-
-		buf[len++]=(n >>24) & 0xff;
-		buf[len++]=(n >>16) & 0xff;
-		buf[len++]=(n >>8) & 0xff;
-		buf[len++]=(n) & 0xff;
-		if (pubkey->u.dsa.pub.data[0] & 0x80)
-			buf[len++]= 0;
-
-		memcpy(buf+len,pubkey->u.dsa.pub.data, pubkey->u.dsa.pub.len);
-		len += pubkey->u.dsa.pub.len;
-
-		print_ssh_key(outf, "ssh-dss", obj, buf, len);
-	}
-
 	if (opt_outfile != NULL)
 		fclose(outf);
 	if (cert)
@@ -1462,7 +1389,7 @@
 	unsigned int  auth_method;
 	unsigned char		*pin;
 	int r;
-	unsigned char sessionpin[SC_MAX_PIN_SIZE];
+	unsigned char sessionpin[SC_MAX_PIN_SIZE] = {0};
 	size_t sessionpinlen = sizeof sessionpin;
 
 	if (!opt_auth_id)   {
@@ -1919,7 +1846,8 @@
 
 	if (pincode && strlen((char *) pincode) == 0) {
 		fprintf(stderr, "No PIN code supplied.\n");
-		free(pincode);
+		if (opt_pin == NULL)
+			free(pincode);
 		return 2;
 	}
 
@@ -1939,7 +1867,8 @@
 		if (newpin == NULL || strlen((char *) newpin) == 0)   {
 			fprintf(stderr, "No new PIN value supplied.\n");
 			free(newpin);
-			free(pincode);
+			if (opt_pin == NULL)
+				free(pincode);
 			return 2;
 		}
 
@@ -2044,8 +1973,11 @@
 			}
 			/* other tag */
 			i += 2 + rbuf[2+i+1]; /* length of this tag*/
+			if (2+i+1 >= apdu.resplen) {
+				break;
+			}
 		}
-		if (rbuf[2+i+1] < 9 || 2+i+2+9 > apdu.resplen) {
+		if (2+i+1 >= apdu.resplen || rbuf[2+i+1] < 9 || 2+i+2+9 > apdu.resplen) {
 			printf("select file returned short fci\n");
 			goto bad_fci;
 		}
@@ -2225,8 +2157,10 @@
 		c = getopt_long(argc, argv, "r:cuko:sva:LR:CwDTU", options, &long_optind);
 		if (c == -1)
 			break;
-		if (c == '?')
-			util_print_usage_and_die(app_name, options, option_help, NULL);
+		if (c == '?') {
+			util_print_usage(app_name, options, option_help, NULL);
+			return 2;
+		}
 		switch (c) {
 		case 'r':
 
@@ -2412,8 +2346,10 @@
 			break;
 		}
 	}
-	if (action_count == 0)
-		util_print_usage_and_die(app_name, options, option_help, NULL);
+	if (action_count == 0) {
+		util_print_usage(app_name, options, option_help, NULL);
+		return 2;
+	}
 
 	if (do_print_version)   {
 		printf("%s\n", OPENSC_SCM_REVISION);
@@ -2449,7 +2385,8 @@
 		aid.len = sizeof(aid.value);
 		if (sc_hex_to_bin(opt_bind_to_aid, aid.value, &aid.len))   {
 			fprintf(stderr, "Invalid AID value: '%s'\n", opt_bind_to_aid);
-			return 1;
+			err = 1;
+			goto end;
 		}
 
 		r = sc_pkcs15_bind(card, &aid, &p15card);
diff -Nru opensc-0.22.0/src/tools/sceac-example.c opensc-0.23.0/src/tools/sceac-example.c
--- opensc-0.22.0/src/tools/sceac-example.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/sceac-example.c	2022-11-29 09:34:43.000000000 +0100
@@ -26,7 +26,6 @@
 #include "config.h"
 #endif
 
-#ifdef ENABLE_OPENPACE
 #include "libopensc/sm.h"
 #include "sm/sm-iso.h"
 #include "sm/sm-eac.h"
@@ -80,10 +79,6 @@
 		exit(1);
 	}
 
-	/* initialize OpenPACE */
-	EAC_init();
-
-
 	/* Now we try to change the PIN. Therefore we need to establish a SM channel
 	 * with PACE.
 	 *
@@ -135,14 +130,7 @@
 	sc_reset(card, 1);
 	sc_disconnect_card(card);
 	sc_release_context(ctx);
-	EAC_cleanup();
 
 	return -r;
 }
-#else
-int
-main (int argc, char **argv)
-{
-	return 1;
-}
-#endif
+
diff -Nru opensc-0.22.0/src/tools/sc-hsm-tool.c opensc-0.23.0/src/tools/sc-hsm-tool.c
--- opensc-0.22.0/src/tools/sc-hsm-tool.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/sc-hsm-tool.c	2022-11-29 09:34:43.000000000 +0100
@@ -3,6 +3,7 @@
  *
  * Copyright (C) 2001  Juha Yrjölä <juha.yrjola at iki.fi>
  * Copyright (C) 2012 www.CardContact.de, Andreas Schwier, Minden, Germany
+ * Copyright (C) 2018-2019 GSMK - Gesellschaft für Sichere Mobile Kommunikation mbH
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -41,6 +42,7 @@
 #include <openssl/rand.h>
 #include <openssl/err.h>
 
+#include "fread_to_eof.h"
 #include "libopensc/sc-ossl-compat.h"
 #include "libopensc/opensc.h"
 #include "libopensc/cardctl.h"
@@ -88,6 +90,11 @@
 #endif
 	{ "wrap-key",				1, NULL,		'W' },
 	{ "unwrap-key",				1, NULL,		'U' },
+	{ "public-key-auth",		1, NULL,		'K' },
+	{ "required-pub-keys",		1, NULL,		'n' },
+	{ "export-for-pub-key-auth",1, NULL,		'e' },
+	{ "register-public-key",	1, NULL,		'g' },
+	{ "public-key-auth-status",	0, NULL,		'S' },
 	{ "dkek-shares",			1, NULL,		's' },
 	{ "so-pin",					1, NULL,		OPT_SO_PIN },
 	{ "pin",					1, NULL,		OPT_PIN },
@@ -115,6 +122,11 @@
 #endif
 	"Wrap key and save to <filename>",
 	"Unwrap key read from <filename>",
+	"Use public key authentication, set total number of public keys",
+	"Number of public keys required for authentication [1]",
+	"Export key for public key authentication",
+	"Register public key for public key authentication (PKA file)",
+	"Show status of public key authentication",
 	"Number of DKEK shares [No DKEK]",
 	"Define security officer PIN (SO-PIN)",
 	"Define user PIN",
@@ -124,12 +136,12 @@
 	"Define password for DKEK share",
 	"Define threshold for number of password shares required for reconstruction",
 	"Define number of password shares",
-	"Key reference for key wrap/unwrap",
+	"Key reference for key wrap/unwrap/export",
 	"Token label for --initialize",
 	"Force replacement of key and certificate",
 	"Uses reader number <arg> [0]",
 	"Wait for a card to be inserted",
-	"Verbose operation. Use several times to enable debug output.",
+	"Verbose operation, may be used several times",
 };
 
 typedef struct {
@@ -561,13 +573,26 @@
 
 
 
-static int initialize(sc_card_t *card, const char *so_pin, const char *user_pin, int retry_counter, const char *bio1, const char *bio2, int dkek_shares, const char *label)
+static int initialize(sc_card_t *card, const char *so_pin, const char *user_pin, int retry_counter, const char *bio1, const char *bio2, int dkek_shares, signed char num_of_pub_keys, u8 required_pub_keys, const char *label)
 {
 	sc_cardctl_sc_hsm_init_param_t param;
 	size_t len;
 	char *_so_pin = NULL, *_user_pin = NULL;
 	int r;
 
+	if (num_of_pub_keys != -1 && (num_of_pub_keys < 1 || num_of_pub_keys > 90)) {
+		fprintf(stderr, "Total number of public keys for authentication must be between 1 and 90\n");
+		return -1;
+	}
+	if (required_pub_keys < 1 || required_pub_keys > 90) {
+		fprintf(stderr, "Number of public keys required for authentication must be between 1 and 90\n");
+		return -1;
+	}
+	if (num_of_pub_keys != -1 && required_pub_keys > num_of_pub_keys) {
+		fprintf(stderr, "Required public keys must be <= total number of public keys\n");
+		return -1;
+	}
+
 	if (so_pin == NULL) {
 		printf("Enter SO-PIN (16 hexadecimal characters) : ");
 		util_getpass(&_so_pin, NULL, stdin);
@@ -655,6 +680,8 @@
 	}
 
 	param.dkek_shares = (char)dkek_shares;
+	param.num_of_pub_keys = (signed char)num_of_pub_keys; /* guaranteed in [-1,90] */
+	param.required_pub_keys = (u8)required_pub_keys; /* guaranteed in [1,90] */
 	param.label = (char *)label;
 
 	r = sc_card_ctl(card, SC_CARDCTL_SC_HSM_INITIALIZE, (void *)&param);
@@ -1667,6 +1694,189 @@
 }
 
 
+static int export_key(sc_card_t *card, int keyid, const char *outf)
+{
+	sc_path_t path;
+	FILE *outfp = NULL;
+	u8 fid[2];
+	u8 ef_cert[MAX_CERT];
+	u8 dev_aut_cert[MAX_CERT];
+	u8 dica[MAX_CERT];
+	u8 tag = SC_ASN1_TAG_CONSTRUCTED | SC_ASN1_TAG_SEQUENCE; /* 0x30 */
+	int r = 0, ef_cert_len, dev_aut_cert_len, dica_len, total_certs_len;
+	u8 *data = NULL, *out = NULL, *ptr;
+	size_t datalen, outlen;
+
+	if ((keyid < 1) || (keyid > 255)) {
+		fprintf(stderr, "Invalid key reference (must be 0 < keyid <= 255)\n");
+		return -1;
+	}
+
+	fid[0] = EE_CERTIFICATE_PREFIX;
+	fid[1] = (unsigned char)keyid;
+	ef_cert_len = 0;
+
+	/* Try to select a related EF containing the certificate for the key */
+	sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, sizeof(fid), 0, 0);
+	r = sc_select_file(card, &path, NULL);
+	if (r != SC_SUCCESS) {
+		fprintf(stderr, "Wrong key reference (-i %d)? Failed to select file: %s\n", keyid, sc_strerror(r));
+		return -1;
+	}
+
+	ef_cert_len = sc_read_binary(card, 0, ef_cert, sizeof(ef_cert), 0);
+	if (ef_cert_len < 0) {
+		fprintf(stderr, "Error reading certificate %s. Skipping\n", sc_strerror(ef_cert_len));
+		ef_cert_len = 0;
+	} else {
+		ef_cert_len = determineLength(ef_cert, ef_cert_len);
+	}
+
+	/* C_DevAut */
+	fid[0] = 0x2F;
+	fid[1] = 0x02;
+	dev_aut_cert_len = 0;
+
+	/* Read concatenation of both certificates */
+	sc_path_set(&path, SC_PATH_TYPE_FILE_ID, fid, sizeof(fid), 0, 0);
+	r = sc_select_file(card, &path, NULL);
+	if (r != SC_SUCCESS) {
+		fprintf(stderr, "Failed to select certificates: %s\n", sc_strerror(r));
+		return -1;
+	}
+
+	total_certs_len = sc_read_binary(card, 0, dev_aut_cert, sizeof(dev_aut_cert), 0);
+	if (total_certs_len < 0) {
+		fprintf(stderr, "Error reading certificate: %s\n", sc_strerror(total_certs_len));
+		return -1;
+	} else {
+		dev_aut_cert_len = determineLength(dev_aut_cert, total_certs_len);
+		dica_len = total_certs_len - dev_aut_cert_len;
+		memcpy(dica, dev_aut_cert + dev_aut_cert_len, dica_len);
+	}
+	if (dica_len == 0) {
+		fprintf(stderr, "Could not determine device issuer certificate\n");
+		return -1;
+	}
+
+	if ((outfp = fopen(outf, "r"))) {
+		fprintf(stderr, "Output file '%s' already exists\n", outf);
+		fclose(outfp);
+		return -1;
+	}
+	fprintf(stderr, "Warning: Device certificate chain not verified!\n");
+
+	datalen = ef_cert_len + dev_aut_cert_len + dica_len;
+	outlen = 8 + datalen;
+	if (!(data = malloc(datalen))) {
+		fprintf(stderr, "Malloc failed\n");
+		r = -1;
+		goto err;
+	}
+	if (!(out = malloc(outlen))) {
+		fprintf(stderr, "Malloc failed\n");
+		r = -1;
+		goto err;
+	}
+	memcpy(data, ef_cert, ef_cert_len);
+	memcpy(data + ef_cert_len, dev_aut_cert, dev_aut_cert_len);
+	memcpy(data + ef_cert_len + dev_aut_cert_len, dica, dica_len);
+
+	if ((r = sc_asn1_put_tag(tag, data, datalen, out, outlen, &ptr)) < 0) {
+		fprintf(stderr, "Error formatting ASN1 sequence: %s\n", sc_strerror(r));
+		r = -1;
+		goto err;
+	}
+	outlen = ptr - out;
+
+	if (!(outfp = fopen(outf, "wb"))) {
+		perror(outf);
+		r = -1;
+		goto err;
+	}
+
+	if (fwrite(out, 1, outlen, outfp) != (size_t)outlen) {
+		perror(outf);
+		r = -1;
+		goto err;
+	}
+
+err:
+	if (outfp)
+		fclose(outfp);
+	if (out)
+		free(out);
+	if (data)
+		free(data);
+
+	return r;
+}
+
+static void print_pka_status(const sc_cardctl_sc_hsm_pka_status_t *status)
+{
+	printf("Number of public keys:     %d\n", status->num_total);
+	printf("Missing public keys:       %d\n", status->num_missing);
+	printf("Required pubkeys for auth: %d\n", status->num_required);
+	printf("Authenticated public keys: %d\n", status->num_authenticated);
+}
+
+static int register_public_key(sc_context_t *ctx, sc_card_t *card, const char *inf)
+{
+	int r = 0;
+	sc_cardctl_sc_hsm_pka_register_t pka_register;
+
+	memset(&pka_register, 0, sizeof(pka_register));
+
+	if (!fread_to_eof(inf, &pka_register.buf, &pka_register.buflen)) {
+		r = -1;
+		goto err;
+	}
+
+	r = sc_card_ctl(card, SC_CARDCTL_SC_HSM_REGISTER_PUBLIC_KEY, &pka_register);
+	if (r == SC_ERROR_INS_NOT_SUPPORTED) { /* Not supported or not initialized for public key registration */
+		fprintf(stderr, "Card not initialized for public key registration\n");
+		r = -1;
+		goto err;
+	}
+	if (r < 0) {
+		fprintf(stderr, "sc_card_ctl(*, SC_CARDCTL_SC_HSM_REGISTER_PUBLIC_KEY, *) failed with %s\n", sc_strerror(r));
+		r = -1;
+		goto err;
+	}
+
+	print_pka_status(&pka_register.new_status);
+
+	r = 0;
+	/* fall-through */
+
+err:
+	free(pka_register.buf);
+	pka_register.buf = NULL;
+	return r;
+}
+
+
+
+static int public_key_auth_status(sc_context_t *ctx, sc_card_t *card)
+{
+	int r;
+	sc_cardctl_sc_hsm_pka_status_t status;
+
+	r = sc_card_ctl(card, SC_CARDCTL_SC_HSM_PUBLIC_KEY_AUTH_STATUS, &status);
+	if (r == SC_ERROR_INS_NOT_SUPPORTED) { /* Not supported or not initialized for public key registration */
+		fprintf(stderr, "Card not initialized for public key registration\n");
+		return -1;
+	}
+	if (r < 0) {
+		fprintf(stderr, "sc_card_ctl(*, SC_CARDCTL_SC_HSM_PUBLIC_KEY_AUTH_STATUS, *) failed with %s\n", sc_strerror(r));
+		return -1;
+	}
+
+	print_pka_status(&status);
+
+	return 0;
+}
+
 
 int main(int argc, char *argv[])
 {
@@ -1678,6 +1888,9 @@
 	int do_create_dkek_share = 0;
 	int do_wrap_key = 0;
 	int do_unwrap_key = 0;
+	int do_export_key = 0;
+	int do_register_public_key = 0;
+	int do_public_key_auth_status = 0;
 	sc_path_t path;
 	sc_file_t *file = NULL;
 	const char *opt_so_pin = NULL;
@@ -1687,6 +1900,8 @@
 	const char *opt_bio1 = NULL;
 	const char *opt_bio2 = NULL;
 	int opt_retry_counter = 3;
+	int opt_num_of_pub_keys = -1;
+	int opt_required_pub_keys = 1;
 	int opt_dkek_shares = -1;
 	int opt_key_reference = -1;
 	int opt_password_shares_threshold = -1;
@@ -1698,7 +1913,7 @@
 	sc_card_t *card = NULL;
 
 	while (1) {
-		c = getopt_long(argc, argv, "XC:I:P:W:U:s:i:fr:wv", options, &long_optind);
+		c = getopt_long(argc, argv, "XC:I:P:W:U:K:n:e:g:Ss:i:fr:wv", options, &long_optind);
 		if (c == -1)
 			break;
 		if (c == '?')
@@ -1733,6 +1948,26 @@
 			opt_filename = optarg;
 			action_count++;
 			break;
+		case 'K':
+			opt_num_of_pub_keys = atol(optarg);
+			break;
+		case 'n':
+			opt_required_pub_keys = atol(optarg);
+			break;
+		case 'e':
+			do_export_key = 1;
+			opt_filename = optarg;
+			action_count++;
+			break;
+		case 'g':
+			do_register_public_key = 1;
+			opt_filename = optarg;
+			action_count++;
+			break;
+		case 'S':
+			do_public_key_auth_status = 1;
+			action_count++;
+			break;
 		case OPT_PASSWORD:
 			util_get_pin(optarg, &opt_password);
 			break;
@@ -1781,16 +2016,66 @@
 		}
 	}
 
-#if OPENSSL_VERSION_NUMBER >= 0x10100000L || (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER >= 0x20700000L)
-	OPENSSL_init_crypto(OPENSSL_INIT_LOAD_CRYPTO_STRINGS
-		| OPENSSL_INIT_ADD_ALL_CIPHERS
-		| OPENSSL_INIT_ADD_ALL_DIGESTS,
-		NULL);
-#else
-	CRYPTO_malloc_init();
-	ERR_load_crypto_strings();
-	OpenSSL_add_all_algorithms();
-#endif
+	if (!do_initialize && opt_num_of_pub_keys != -1) {
+		fprintf(stderr, "Option -K (--public-key-auth) requires option -X\n");
+		exit(1);
+	}
+	if (!do_initialize && opt_required_pub_keys != 1) {
+		fprintf(stderr, "Option -n (--required-pub-keys) requires option -X\n");
+		exit(1);
+	}
+	if (do_initialize && do_export_key) {
+		fprintf(stderr, "Option -e (--export-for-pub-key-auth) excludes option -X\n");
+		exit(1);
+	}
+	if (do_wrap_key && do_export_key) {
+		fprintf(stderr, "Option -e (--export-for-pub-key-auth) excludes option -W\n");
+		exit(1);
+	}
+	if (do_unwrap_key && do_export_key) {
+		fprintf(stderr, "Option -e (--export-for-pub-key-auth) excludes option -U\n");
+		exit(1);
+	}
+	if (do_export_key && opt_key_reference == -1) {
+		fprintf(stderr, "Option -e (--export-for-pub-key-auth) requires option -i\n");
+		exit(1);
+	}
+	if (do_initialize && do_register_public_key) {
+		fprintf(stderr, "Option -g (--register-public-key) excludes option -X\n");
+		exit(1);
+	}
+	if (do_wrap_key && do_register_public_key) {
+		fprintf(stderr, "Option -g (--register-public-key) excludes option -W\n");
+		exit(1);
+	}
+	if (do_unwrap_key && do_register_public_key) {
+		fprintf(stderr, "Option -g (--register-public-key) excludes option -U\n");
+		exit(1);
+	}
+	if (do_export_key && do_register_public_key) {
+		fprintf(stderr, "Option -g (--register-public-key) excludes option -e\n");
+		exit(1);
+	}
+	if (do_initialize && do_public_key_auth_status) {
+		fprintf(stderr, "Option -S (--public-key-auth-status) excludes option -X\n");
+		exit(1);
+	}
+	if (do_wrap_key && do_public_key_auth_status) {
+		fprintf(stderr, "Option -S (--public-key-auth-status) excludes option -W\n");
+		exit(1);
+	}
+	if (do_unwrap_key && do_public_key_auth_status) {
+		fprintf(stderr, "Option -S (--public-key-auth-status) excludes option -U\n");
+		exit(1);
+	}
+	if (do_export_key && do_public_key_auth_status) {
+		fprintf(stderr, "Option -S (--public-key-auth-status) excludes option -e\n");
+		exit(1);
+	}
+	if (do_register_public_key && do_public_key_auth_status) {
+		fprintf(stderr, "Option -S (--public-key-auth-status) excludes option -g\n");
+		exit(1);
+	}
 
 	memset(&ctx_param, 0, sizeof(sc_context_param_t));
 	ctx_param.app_name = app_name;
@@ -1817,7 +2102,7 @@
 		goto fail;
 	}
 
-	if (do_initialize && initialize(card, opt_so_pin, opt_pin, opt_retry_counter, opt_bio1, opt_bio2, opt_dkek_shares, opt_label))
+	if (do_initialize && initialize(card, opt_so_pin, opt_pin, opt_retry_counter, opt_bio1, opt_bio2, opt_dkek_shares, opt_num_of_pub_keys, opt_required_pub_keys, opt_label))
 		goto fail;
 
 	if (do_create_dkek_share && create_dkek_share(card, opt_filename, opt_iter, opt_password, opt_password_shares_threshold, opt_password_shares_total))
@@ -1835,6 +2120,15 @@
 	if (do_unwrap_key && unwrap_key(card, opt_key_reference, opt_filename, opt_pin, opt_force))
 		goto fail;
 
+	if (do_export_key && export_key(card, opt_key_reference, opt_filename))
+		goto fail;
+
+	if (do_register_public_key && register_public_key(ctx, card, opt_filename))
+		goto fail;
+
+	if (do_public_key_auth_status && public_key_auth_status(ctx, card))
+		goto fail;
+
 	if (action_count == 0) {
 		print_info(card, file);
 	}
diff -Nru opensc-0.22.0/src/tools/util.c opensc-0.23.0/src/tools/util.c
--- opensc-0.22.0/src/tools/util.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/util.c	2022-11-29 09:34:43.000000000 +0100
@@ -65,11 +65,12 @@
 	}
 
 	if (do_wait) {
-		unsigned int event;
+		unsigned int event = 0;
 
 		if (sc_ctx_get_reader_count(ctx) == 0) {
 			fprintf(stderr, "Waiting for a reader to be attached...\n");
-			r = sc_wait_for_event(ctx, SC_EVENT_READER_ATTACHED, &found, &event, -1, NULL);
+			r = sc_wait_for_event(ctx, SC_EVENT_READER_ATTACHED|SC_EVENT_CARD_INSERTED,
+			                      &found, &event, -1, NULL);
 			if (r < 0) {
 				fprintf(stderr, "Error while waiting for a reader: %s\n", sc_strerror(r));
 				return r;
@@ -80,13 +81,17 @@
 				return r;
 			}
 		}
-		fprintf(stderr, "Waiting for a card to be inserted...\n");
-		r = sc_wait_for_event(ctx, SC_EVENT_CARD_INSERTED, &found, &event, -1, NULL);
-		if (r < 0) {
-			fprintf(stderr, "Error while waiting for a card: %s\n", sc_strerror(r));
-			return r;
+		if (event & SC_EVENT_CARD_INSERTED) {
+			*reader = found;
+		} else {
+			fprintf(stderr, "Waiting for a card to be inserted...\n");
+			r = sc_wait_for_event(ctx, SC_EVENT_CARD_INSERTED, &found, &event, -1, NULL);
+			if (r < 0) {
+				fprintf(stderr, "Error while waiting for a card: %s\n", sc_strerror(r));
+				return r;
+			}
+			*reader = found;
 		}
-		*reader = found;
 	}
 	else if (sc_ctx_get_reader_count(ctx) == 0) {
 		fprintf(stderr, "No smart card readers found.\n");
@@ -254,8 +259,8 @@
 	}
 }
 
-NORETURN void
-util_print_usage_and_die(const char *app_name, const struct option options[],
+void
+util_print_usage(const char *app_name, const struct option options[],
 	const char *option_help[], const char *args)
 {
 	int i;
@@ -301,7 +306,13 @@
 		}
 		printf("  %-28s  %s\n", buf, option_help[i]);
 	}
+}
 
+NORETURN void
+util_print_usage_and_die(const char *app_name, const struct option options[],
+	const char *option_help[], const char *args)
+{
+	util_print_usage(app_name, options, option_help, args);
 	exit(2);
 }
 
diff -Nru opensc-0.22.0/src/tools/util.h opensc-0.23.0/src/tools/util.h
--- opensc-0.22.0/src/tools/util.h	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/util.h	2022-11-29 09:34:43.000000000 +0100
@@ -39,6 +39,8 @@
 void util_print_binary(FILE *f, const u8 *buf, int count);
 void util_hex_dump(FILE *f, const u8 *in, int len, const char *sep);
 void util_hex_dump_asc(FILE *f, const u8 *in, size_t count, int addr);
+void util_print_usage(const char *app_name, const struct option options[],
+	const char *option_help[], const char *args);
 NORETURN void util_print_usage_and_die(const char *app_name, const struct option options[],
 	const char *option_help[], const char *args);
 int util_list_card_drivers(const sc_context_t *ctx);
diff -Nru opensc-0.22.0/src/tools/westcos-tool.c opensc-0.23.0/src/tools/westcos-tool.c
--- opensc-0.22.0/src/tools/westcos-tool.c	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/src/tools/westcos-tool.c	2022-11-29 09:34:43.000000000 +0100
@@ -79,7 +79,7 @@
 	"Read file <arg>",
 	"Write file <arg> (ex 0002 write file 0002 to 0002)",
 	"This message",
-	"Verbose operation. Use several times to enable debug output."
+	"Verbose operation, may be used several times",
 };
 
 
@@ -111,17 +111,10 @@
 	return 1;
 }
 
-static int	charge = 0;
 static void print_openssl_error(void)
 {
 	long r;
 
-	if (!charge)
-	{
-		ERR_load_crypto_strings();
-		charge = 1;
-	}
-
 	while ((r = ERR_get_error()) != 0)
 		printf("%s\n", ERR_error_string(r, NULL));
 }
@@ -368,7 +361,7 @@
 	sc_context_t *ctx = NULL;
 	sc_file_t *file = NULL;
 	sc_path_t path;
-	RSA	*rsa = NULL;
+	EVP_PKEY *pkey = NULL;
 	BIGNUM	*bn = NULL;
 	BIO	*mem = NULL;
 	static const char *pin = NULL;
@@ -578,32 +571,36 @@
 		struct sc_pkcs15_pubkey key;
 		struct sc_pkcs15_pubkey_rsa *dst = &(key.u.rsa);
 		u8 *pdata;
+		EVP_PKEY_CTX *pctx = NULL;
 
 		memset(&key, 0, sizeof(key));
 		key.algorithm = SC_ALGORITHM_RSA;
 
 		printf("Generate key of length %d.\n", keylen);
 
-		rsa = RSA_new();
 		bn = BN_new();
 		mem = BIO_new(BIO_s_mem());
+		pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_RSA, NULL);
 
-		if(rsa == NULL || bn == NULL || mem == NULL)
+		if(bn == NULL || mem == NULL || pctx == NULL)
 		{
 			printf("Not enough memory.\n");
+			if (pctx)
+				EVP_PKEY_CTX_free(pctx);
 			goto out;
 		}
 
-		if(!BN_set_word(bn, RSA_F4) ||
-			!RSA_generate_key_ex(rsa, keylen, bn, NULL))
+		if (EVP_PKEY_keygen_init(pctx) != 1 ||
+			EVP_PKEY_CTX_set_rsa_keygen_bits(pctx, keylen) != 1 ||
+			EVP_PKEY_keygen(pctx, &pkey) != 1)
 		{
-			printf("RSA_generate_key_ex return %ld\n", ERR_get_error());
+			printf("Key generation failed.\n");
+			EVP_PKEY_CTX_free(pctx);
 			goto out;
 		}
+		EVP_PKEY_CTX_free(pctx);
 
-		RSA_set_method(rsa, RSA_PKCS1_OpenSSL());
-
-		if(!i2d_RSAPrivateKey_bio(mem, rsa))
+		if(!i2d_PrivateKey_bio(mem, pkey))
 		{
 			printf("i2d_RSAPrivateKey_bio return %ld\n", ERR_get_error());
 			goto out;
@@ -667,17 +664,39 @@
 		if(r) goto out;
 
 		{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
 			const BIGNUM *rsa_n, *rsa_e;
-
+			RSA *rsa = NULL;
+			rsa = EVP_PKEY_get1_RSA(pkey);
 			RSA_get0_key(rsa, &rsa_n, &rsa_e, NULL);
-
-			if (!do_convert_bignum(&dst->modulus, rsa_n)
-			 || !do_convert_bignum(&dst->exponent, rsa_e))
-			{
+#else
+			BIGNUM *rsa_n = NULL, *rsa_e = NULL;
+			if (EVP_PKEY_get_bn_param(pkey, "n", &rsa_n) != 1 ||
+				EVP_PKEY_get_bn_param(pkey, "e", &rsa_e) != 1)
+			{
+				BN_free(rsa_n);
+			}
+#endif
+
+			if (!do_convert_bignum(&dst->modulus, rsa_n) ||
+				!do_convert_bignum(&dst->exponent, rsa_e))
+			{
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+				RSA_free(rsa);
+#else
+				BN_free(rsa_n);
+				BN_free(rsa_e);
+#endif
 				free(dst->modulus.data);
 				free(dst->exponent.data);
 				goto out;
 			}
+#if OPENSSL_VERSION_NUMBER < 0x30000000L
+			RSA_free(rsa);
+#else
+			BN_free(rsa_n);
+			BN_free(rsa_e);
+#endif
 		}
 
 		r = sc_pkcs15_encode_pubkey(ctx, &key, &pdata, &lg);
@@ -893,8 +912,8 @@
 		BIO_free(mem);
 	if(bn)
 		BN_free(bn);
-	if(rsa)
-		RSA_free(rsa);
+	if(pkey)
+		EVP_PKEY_free(pkey);
 
 	if(file)
 		sc_file_free(file);
diff -Nru opensc-0.22.0/tests/common.sh opensc-0.23.0/tests/common.sh
--- opensc-0.22.0/tests/common.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/tests/common.sh	2022-11-29 09:34:43.000000000 +0100
@@ -8,6 +8,7 @@
 softhsm_paths="/usr/local/lib/softhsm/libsofthsm2.so \
 	/usr/lib/softhsm/libsofthsm2.so
 	/usr/lib64/pkcs11/libsofthsm2.so \
+	/usr/lib/i386-linux-gnu/softhsm/libsofthsm2.so \
 	/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so"
 
 for LIB in $softhsm_paths; do
@@ -76,6 +77,9 @@
 	generate_key "EC:secp256r1" "03" "ECC_auth"
 	# Generate 521b ECC Key pair
 	generate_key "EC:secp521r1" "04" "ECC521"
+	# Generate an HMAC:SHA256 key
+	$PKCS11_TOOL --keypairgen --key-type="GENERIC:64" --login --pin=$PIN \
+		--module="$P11LIB" --label="HMAC-SHA256"
 }
 
 function softhsm_cleanup() {
diff -Nru opensc-0.22.0/tests/Makefile.am opensc-0.23.0/tests/Makefile.am
--- opensc-0.22.0/tests/Makefile.am	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/tests/Makefile.am	2022-11-29 09:34:43.000000000 +0100
@@ -13,7 +13,9 @@
                       test-pkcs11-tool-test.sh \
                       test-pkcs11-tool-test-threads.sh \
                       test-pkcs11-tool-sign-verify.sh \
-                      test-pkcs11-tool-allowed-mechanisms.sh
+                      test-pkcs11-tool-allowed-mechanisms.sh \
+                      test-pkcs11-tool-sym-crypt-test.sh\
+                      test-pkcs11-tool-unwrap-wrap-test.sh
 
 .NOTPARALLEL:
 TESTS = \
@@ -22,7 +24,9 @@
         test-pkcs11-tool-sign-verify.sh \
         test-pkcs11-tool-test.sh \
         test-pkcs11-tool-test-threads.sh \
-        test-pkcs11-tool-allowed-mechanisms.sh
+        test-pkcs11-tool-allowed-mechanisms.sh \
+        test-pkcs11-tool-sym-crypt-test.sh\
+        test-pkcs11-tool-unwrap-wrap-test.sh
 XFAIL_TESTS = \
         test-pkcs11-tool-test-threads.sh \
         test-pkcs11-tool-test.sh
diff -Nru opensc-0.22.0/tests/test-duplicate-symbols.sh opensc-0.23.0/tests/test-duplicate-symbols.sh
--- opensc-0.22.0/tests/test-duplicate-symbols.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/tests/test-duplicate-symbols.sh	2022-11-29 09:34:43.000000000 +0100
@@ -1,5 +1,5 @@
 #!/bin/bash
-SOURCE_PATH=${SOURCE_PATH:-../}
+SOURCE_PATH=${SOURCE_PATH:-..}
 
 EXPORTS=`find "${SOURCE_PATH}" -name "*exports"`
 
diff -Nru opensc-0.22.0/tests/test-manpage.sh opensc-0.23.0/tests/test-manpage.sh
--- opensc-0.22.0/tests/test-manpage.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/tests/test-manpage.sh	2022-11-29 09:34:43.000000000 +0100
@@ -1,5 +1,5 @@
 #!/bin/bash -x
-SOURCE_PATH=${SOURCE_PATH:-../}
+SOURCE_PATH=${SOURCE_PATH:-..}
 
 # find all the manual pages in doc/tools
 TOOLS=`find "${SOURCE_PATH}/doc/tools" -name "*.1.xml" | sed -E -e "s|.*/([a-z0-9-]*).*|\1|" | grep -v goid-tool`
diff -Nru opensc-0.22.0/tests/test-pkcs11-tool-allowed-mechanisms.sh opensc-0.23.0/tests/test-pkcs11-tool-allowed-mechanisms.sh
--- opensc-0.22.0/tests/test-pkcs11-tool-allowed-mechanisms.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/tests/test-pkcs11-tool-allowed-mechanisms.sh	2022-11-29 09:34:43.000000000 +0100
@@ -1,5 +1,5 @@
 #!/bin/bash
-SOURCE_PATH=${SOURCE_PATH:-../}
+SOURCE_PATH=${SOURCE_PATH:-..}
 
 source $SOURCE_PATH/tests/common.sh
 
@@ -7,7 +7,7 @@
 echo "Setup SoftHSM"
 echo "======================================================="
 if [[ ! -f $P11LIB ]]; then
-    echo "WARNINIG: The SoftHSM is not installed. Can not run this test"
+    echo "WARNING: The SoftHSM is not installed. Can not run this test"
     exit 77;
 fi
 # The Ubuntu has old softhsm version not supporting this feature
diff -Nru opensc-0.22.0/tests/test-pkcs11-tool-sign-verify.sh opensc-0.23.0/tests/test-pkcs11-tool-sign-verify.sh
--- opensc-0.22.0/tests/test-pkcs11-tool-sign-verify.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/tests/test-pkcs11-tool-sign-verify.sh	2022-11-29 09:34:43.000000000 +0100
@@ -1,5 +1,5 @@
 #!/bin/bash
-SOURCE_PATH=${SOURCE_PATH:-../}
+SOURCE_PATH=${SOURCE_PATH:-..}
 
 source $SOURCE_PATH/tests/common.sh
 
@@ -7,7 +7,7 @@
 echo "Setup SoftHSM"
 echo "======================================================="
 if [[ ! -f $P11LIB ]]; then
-    echo "WARNINIG: The SoftHSM is not installed. Can not run this test"
+    echo "WARNING: The SoftHSM is not installed. Can not run this test"
     exit 77;
 fi
 card_setup
@@ -145,6 +145,27 @@
 done
 
 echo "======================================================="
+echo "Test GENERIC keys"
+echo "======================================================="
+
+echo "Hello World" > data.msg
+
+for MECHANISM in "SHA-1-HMAC" "SHA256-HMAC" "SHA384-HMAC" "SHA512-HMAC"; do
+	echo
+	echo "======================================================="
+	echo "$MECHANISM: Sign & Verify (KEY (First Found))"
+	echo "======================================================="
+
+	$PKCS11_TOOL --login --pin=1234 --sign --mechanism=$MECHANISM \
+		--input-file=data.msg --output-file=data.sig
+	$PKCS11_TOOL --login --pin=1234 --verify --mechanism=$MECHANISM \
+		--input-file=data.msg --signature-file=data.sig
+	rm data.sig
+done;
+
+rm data.msg
+
+echo "======================================================="
 echo "Cleanup"
 echo "======================================================="
 card_cleanup
diff -Nru opensc-0.22.0/tests/test-pkcs11-tool-sym-crypt-test.sh opensc-0.23.0/tests/test-pkcs11-tool-sym-crypt-test.sh
--- opensc-0.22.0/tests/test-pkcs11-tool-sym-crypt-test.sh	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/tests/test-pkcs11-tool-sym-crypt-test.sh	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,155 @@
+#!/bin/bash
+
+source common.sh
+
+echo "======================================================="
+echo "Setup SoftHSM"
+echo "======================================================="
+if [[ ! -f $P11LIB ]]; then
+    echo "WARNING: The SoftHSM is not installed. Can not run this test"
+    exit 77;
+fi
+# The Ubuntu has old softhsm version not supporting this feature
+grep "Ubuntu 18.04" /etc/issue && echo "WARNING: Not supported on Ubuntu 18.04" && exit 77
+
+softhsm_initialize
+
+#echo "======================================================="
+#echo "Generate AES key"
+#echo "======================================================="
+#ID1="85"
+# Generate key
+#$PKCS11_TOOL --keygen --key-type="aes:32" --login --pin=$PIN \
+#	--module="$P11LIB" --label="gen_aes256" --id="$ID1"
+#assert $? "Failed to Generate AES key"
+
+echo "======================================================="
+echo "import AES key"
+echo "======================================================="
+ID2="86"
+echo -n "pppppppppppppppp" > aes_128.key
+# import key
+softhsm2-util --import aes_128.key --aes --token "SC test" --pin "$PIN" --label import_aes_128 --id "$ID2"
+assert $? "Fail, unable to import key"
+
+$PKCS11_TOOL --module="$P11LIB" --list-objects -l --pin=$PIN  2>/dev/null |tee > objects.list
+assert $? "Failed to list objects"
+
+VECTOR="00000000000000000000000000000000"
+echo "======================================================="
+echo " AES-CBC-PAD"
+echo " OpenSSL encrypt, pkcs11-tool decrypt"
+echo " pkcs11-tool encrypt, compare to openssl encrypt"
+echo "======================================================="
+
+echo "C_Encrypt"
+dd if=/dev/urandom bs=200 count=1 >aes_plain.data 2>/dev/null
+$PKCS11_TOOL --module="$P11LIB" --pin "$PIN" --encrypt --id "$ID2" -m AES-CBC-PAD --iv "${VECTOR}" \
+	--input-file aes_plain.data --output-file aes_ciphertext_pkcs11.data 2>/dev/null
+assert $? "Fail/pkcs11-tool encrypt"
+openssl enc -aes-128-cbc -in aes_plain.data -out aes_ciphertext_openssl.data -iv "${VECTOR}" -K "70707070707070707070707070707070"
+cmp aes_ciphertext_pkcs11.data aes_ciphertext_openssl.data >/dev/null 2>/dev/null
+assert $? "Fail, AES-CBC-PAD (C_Encrypt) - wrong encrypt"
+echo "C_Decrypt"
+$PKCS11_TOOL --module="$P11LIB" --pin "$PIN" --decrypt --id "$ID2" -m AES-CBC-PAD --iv "${VECTOR}" \
+	--input-file aes_ciphertext_pkcs11.data --output-file aes_plain_pkcs11.data 2>/dev/null
+assert $? "Fail/pkcs11-tool decrypt"
+cmp aes_plain.data aes_plain_pkcs11.data >/dev/null 2>/dev/null
+assert $? "Fail, AES-CBC-PAD (C_Decrypt) - wrong decrypt"
+
+echo "C_DecryptUpdate"
+dd if=/dev/urandom bs=8131 count=3 >aes_plain.data 2>/dev/null
+openssl enc -aes-128-cbc -in aes_plain.data -out aes_ciphertext_openssl.data -iv "${VECTOR}" -K "70707070707070707070707070707070"
+assert $? "Fail, OpenSSL"
+$PKCS11_TOOL --module="$P11LIB" --pin "$PIN" --decrypt --id "$ID2" -m AES-CBC-PAD --iv "${VECTOR}" \
+	--input-file aes_ciphertext_openssl.data --output-file aes_plain_test.data 2>/dev/null
+assert $? "Fail/pkcs11-tool (C_DecryptUpdate) decrypt"
+cmp aes_plain.data aes_plain_test.data >/dev/null 2>/dev/null
+assert $? "Fail, AES-CBC-PAD - wrong decrypt"
+echo "C_EncryptUpdate"
+$PKCS11_TOOL --module="$P11LIB" --pin "$PIN" --encrypt --id "$ID2" -m AES-CBC-PAD --iv "${VECTOR}" \
+	--input-file aes_plain.data --output-file aes_ciphertext_pkcs11.data 2>/dev/null
+assert $? "Fail/pkcs11-tool encrypt"
+cmp aes_ciphertext_pkcs11.data aes_ciphertext_openssl.data >/dev/null 2>/dev/null
+assert $? "Fail, AES-CBC-PAD (C_EncryptUpdate) - wrong encrypt"
+
+echo "======================================================="
+echo " AES-ECB, AES-CBC - must fail, because the length of   "
+echo " the input is not multiple od block size               "
+echo "======================================================="
+echo -n "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU" > aes_plain.data
+! $PKCS11_TOOL --module="$P11LIB" --pin "$PIN" --encrypt --id "$ID2" -m AES-ECB --input-file aes_plain.data --output-file aes_ciphertext_pkcs11.data 2>/dev/null
+assert $? "Fail, AES-ECB must not work if the input is not a multiple of the block size"
+! $PKCS11_TOOL --module="$P11LIB" --pin "$PIN" --encrypt --id "$ID2" -m AES-CBC --iv "${VECTOR}" \
+	--input-file aes_plain.data --output-file aes_ciphertext_pkcs11.data 2>/dev/null
+assert $? "Fail, AES-CBC must not work if the input is not a multiple of the block size"
+
+echo -n "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU" > aes_plain.data
+
+echo "======================================================="
+echo " AES-ECB"
+echo " OpenSSL encrypt, pkcs11-tool decrypt"
+echo " pkcs11-tool encrypt, compare to openssl encrypt"
+echo "======================================================="
+
+openssl enc -aes-128-ecb -nopad -in aes_plain.data -out aes_ciphertext_openssl.data  -K "70707070707070707070707070707070"
+assert $? "Fail/OpenSSL"
+$PKCS11_TOOL --module="$P11LIB" --pin "$PIN" --decrypt --id "$ID2" -m AES-ECB --input-file aes_ciphertext_openssl.data --output-file aes_plain_test.data 2>/dev/null
+assert $? "Fail/pkcs11-tool decrypt"
+cmp aes_plain.data aes_plain_test.data >/dev/null 2>/dev/null
+assert $? "Fail, AES-ECB - wrong decrypt"
+
+$PKCS11_TOOL --module="$P11LIB" --pin "$PIN" --encrypt --id "$ID2" -m AES-ECB --input-file aes_plain.data --output-file aes_ciphertext_pkcs11.data 2>/dev/null
+assert $? "Fail/pkcs11-tool encrypt"
+cmp aes_ciphertext_pkcs11.data aes_ciphertext_openssl.data >/dev/null 2>/dev/null
+assert $? "Fail, AES-ECB - wrong encrypt"
+
+echo "======================================================="
+echo " AES-CBC"
+echo " OpenSSL encrypt, pkcs11-tool decrypt"
+echo " pkcs11-tool encrypt, compare to openssl encrypt"
+echo "======================================================="
+
+openssl enc -aes-128-cbc -nopad -in aes_plain.data -out aes_ciphertext_openssl.data -iv "${VECTOR}" -K "70707070707070707070707070707070"
+assert $? "Fail/OpenSSL"
+$PKCS11_TOOL --module="$P11LIB" --pin "$PIN" --decrypt --id "$ID2" -m AES-CBC --iv "${VECTOR}" \
+	--input-file aes_ciphertext_openssl.data --output-file aes_plain_test.data 2>/dev/null
+assert $? "Fail/pkcs11-tool decrypt"
+cmp aes_plain.data aes_plain_test.data >/dev/null 2>/dev/null
+assert $? "Fail, AES-CBC - wrong decrypt"
+
+$PKCS11_TOOL --module="$P11LIB" --pin "$PIN" --encrypt --id "$ID2" -m AES-CBC --iv "${VECTOR}" \
+	--input-file aes_plain.data --output-file aes_ciphertext_pkcs11.data 2>/dev/null
+assert $? "Fail/pkcs11-tool encrypt"
+cmp  aes_ciphertext_pkcs11.data aes_ciphertext_openssl.data >/dev/null 2>/dev/null
+assert $? "Fail, AES-CBC - wrong encrypt"
+
+VECTOR="000102030405060708090a0b0c0d0e0f"
+echo "======================================================="
+echo " AES-CBC, another IV"
+echo " OpenSSL encrypt, pkcs11-tool decrypt"
+echo " pkcs11-tool encrypt, compare to openssl encrypt"
+echo "======================================================="
+
+openssl enc -aes-128-cbc -nopad -in aes_plain.data -out aes_ciphertext_openssl.data -iv "${VECTOR}" -K "70707070707070707070707070707070"
+assert $? "Fail/Openssl"
+$PKCS11_TOOL --module="$P11LIB" --pin "$PIN" --decrypt --id "$ID2" -m AES-CBC --iv "${VECTOR}" \
+	--input-file aes_ciphertext_openssl.data --output-file aes_plain_test.data 2>/dev/null
+assert $? "Fail/pkcs11-tool decrypt"
+cmp aes_plain.data aes_plain_test.data >/dev/null 2>/dev/null
+assert $? "Fail, AES-CBC - wrong decrypt"
+
+$PKCS11_TOOL --module="$P11LIB" --pin "$PIN" --encrypt --id "$ID2" -m AES-CBC --iv "${VECTOR}" \
+	--input-file aes_plain.data --output-file aes_ciphertext_pkcs11.data 2>/dev/null
+assert $? "Fail/pkcs11-tool encrypt"
+cmp  aes_ciphertext_pkcs11.data aes_ciphertext_openssl.data >/dev/null 2>/dev/null
+assert $? "Fail, AES-CBC - wrong encrypt"
+
+echo "======================================================="
+echo "Cleanup"
+echo "======================================================="
+softhsm_cleanup
+
+rm objects.list
+rm aes_128.key aes_plain.data aes_plain_test.data aes_ciphertext_openssl.data aes_ciphertext_pkcs11.data aes_plain_pkcs11.data
+exit $ERRORS
diff -Nru opensc-0.22.0/tests/test-pkcs11-tool-test.sh opensc-0.23.0/tests/test-pkcs11-tool-test.sh
--- opensc-0.22.0/tests/test-pkcs11-tool-test.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/tests/test-pkcs11-tool-test.sh	2022-11-29 09:34:43.000000000 +0100
@@ -1,5 +1,5 @@
 #!/bin/bash
-SOURCE_PATH=${SOURCE_PATH:-../}
+SOURCE_PATH=${SOURCE_PATH:-..}
 
 source $SOURCE_PATH/tests/common.sh
 
@@ -7,7 +7,7 @@
 echo "Setup SoftHSM"
 echo "======================================================="
 if [[ ! -f $P11LIB ]]; then
-    echo "WARNINIG: The SoftHSM is not installed. Can not run this test"
+    echo "WARNING: The SoftHSM is not installed. Can not run this test"
     exit 77;
 fi
 
diff -Nru opensc-0.22.0/tests/test-pkcs11-tool-test-threads.sh opensc-0.23.0/tests/test-pkcs11-tool-test-threads.sh
--- opensc-0.22.0/tests/test-pkcs11-tool-test-threads.sh	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/tests/test-pkcs11-tool-test-threads.sh	2022-11-29 09:34:43.000000000 +0100
@@ -1,34 +1,22 @@
 #!/bin/bash
-SOURCE_PATH=${SOURCE_PATH:-../}
+SOURCE_PATH=${SOURCE_PATH:-..}
 
 source $SOURCE_PATH/tests/common.sh
 
-echo "======================================================="
-echo "Setup SoftHSM"
-echo "======================================================="
-if [[ ! -f $P11LIB ]]; then
-    echo "WARNINIG: The SoftHSM is not installed. Can not run this test"
-    exit 77;
-fi
-
-card_setup
+# Test our PKCS #11 module here
+P11LIB="../src/pkcs11/.libs/opensc-pkcs11.so"
 
 echo "======================================================="
-echo "Test pkcs11 threads OSILGISLT0 "
+echo "Test pkcs11 threads IN "
 echo "======================================================="
-$PKCS11_TOOL --test-threads IN -L
+$PKCS11_TOOL --test-threads IN -L --module="$P11LIB"
 assert $? "Failed running tests"
 
 
 echo "======================================================="
-echo "Test pkcs11 threads OSILGISLT0 "
+echo "Test pkcs11 threads ILGISLT0 "
 echo "======================================================="
-$PKCS11_TOOL --test-threads OSILGISLT0 -L
+$PKCS11_TOOL --test-threads ILGISLT0 -L --module="$P11LIB"
 assert $? "Failed running tests"
 
-echo "======================================================="
-echo "Cleanup"
-echo "======================================================="
-card_cleanup
-
 exit $ERRORS
diff -Nru opensc-0.22.0/tests/test-pkcs11-tool-unwrap-wrap-test.sh opensc-0.23.0/tests/test-pkcs11-tool-unwrap-wrap-test.sh
--- opensc-0.22.0/tests/test-pkcs11-tool-unwrap-wrap-test.sh	1970-01-01 01:00:00.000000000 +0100
+++ opensc-0.23.0/tests/test-pkcs11-tool-unwrap-wrap-test.sh	2022-11-29 09:34:43.000000000 +0100
@@ -0,0 +1,83 @@
+#!/bin/bash
+source common.sh
+
+echo "======================================================="
+echo "Setup SoftHSM"
+echo "======================================================="
+if [[ ! -f $P11LIB ]]; then
+    echo "WARNING: The SoftHSM is not installed. Can not run this test"
+    exit 77;
+fi
+# The Ubuntu has old softhsm version not supporting this feature
+grep "Ubuntu 18.04" /etc/issue && echo "WARNING: Not supported on Ubuntu 18.04" && exit 77
+softhsm_initialize
+
+echo "======================================================="
+echo " Unwrap test"
+echo "======================================================="
+ID1="85"
+ID2="95"
+ID3="96"
+# Generate RSA key (this key is used to unwrap/wrap operation)
+$PKCS11_TOOL --module="$P11LIB" --login --pin=$PIN --keypairgen --key-type="rsa:1024" --id "$ID1" --usage-wrap
+assert $? "Failed to Generate RSA key"
+# export public key
+$PKCS11_TOOL --module="$P11LIB" --login --pin=$PIN --read-object --type pubkey --id="$ID1" -o rsa_pub.key
+assert $? "Failed to export public key"
+
+# create AES key
+KEY="70707070707070707070707070707070"
+
+echo -n $KEY|xxd -p -r > aes_plain_key
+# wrap AES key
+openssl rsautl -encrypt -pubin -keyform der -inkey rsa_pub.key -in aes_plain_key -out aes_wrapped_key
+assert $? "Failed wrap AES key"
+
+# unwrap key by pkcs11 interface
+$PKCS11_TOOL --module="$P11LIB" --login --pin=$PIN --unwrap --mechanism RSA-PKCS --id "$ID1" -i aes_wrapped_key --key-type GENERIC: \
+	--extractable --application-id "$ID3" --application-label "unwrap-generic-ex" 2>/dev/null
+assert $? "Unwrap failed"
+# because key is extractable, there is no problem to compare key value with original key
+$PKCS11_TOOL --module="$P11LIB" --login --pin=$PIN --id "$ID3" --read-object --type secrkey --output-file generic_extracted_key
+assert $? "unable to read key value"
+cmp generic_extracted_key aes_plain_key >/dev/null 2>/dev/null
+assert $? "extracted key does not match the input key"
+
+# unwrap AES key, not extractable
+$PKCS11_TOOL --module="$P11LIB" --login --pin=$PIN --unwrap --mechanism RSA-PKCS --id "$ID1" -i aes_wrapped_key --key-type AES: \
+	--application-id "$ID2" --application-label "unwrap-aes" 2>/dev/null
+assert $? "Unwrap failed"
+
+# To check if AES key was correctly unwrapped (non extractable), we need to encrypt some data by pkcs11 interface and by openssl
+# (with same key). If result is same, key was correctly unwrapped.
+VECTOR="00000000000000000000000000000000"
+echo -n "UUUUUUUUUUUUUUUUUUUUUUUUUUUUUUUU" > aes_plain.data
+
+openssl enc -aes-128-cbc -nopad -in aes_plain.data -out aes_ciphertext_openssl.data -iv "${VECTOR}" -K $KEY
+assert $? "Fail/Openssl"
+
+$PKCS11_TOOL --module="$P11LIB" --pin "$PIN" --encrypt --id "$ID2" -m AES-CBC --iv "${VECTOR}" \
+        --input-file aes_plain.data --output-file aes_ciphertext_pkcs11.data 2>/dev/null
+assert $? "Fail/pkcs11-tool encrypt"
+cmp aes_ciphertext_pkcs11.data aes_ciphertext_openssl.data >/dev/null 2>/dev/null
+assert $? "Fail, AES-CBC - wrong encrypt"
+
+echo "======================================================="
+echo " Wrap test"
+echo "======================================================="
+
+$PKCS11_TOOL --module="$P11LIB" --pin "$PIN" --wrap --mechanism RSA-PKCS --id "$ID1" --application-id  "$ID3" --output-file wrapped.key
+assert $? "Fail, unable to wrap"
+$PKCS11_TOOL --module="$P11LIB" --pin "$PIN" --decrypt --mechanism RSA-PKCS --id "$ID1" --input-file wrapped.key --output-file plain_wrapped.key
+assert $? "Fail, unable to decrypt wrapped key"
+cmp plain_wrapped.key aes_plain_key >/dev/null 2>/dev/null
+assert $? "wrapped key after decipher does not match the original key"
+
+echo "======================================================="
+echo "Cleanup"
+echo "======================================================="
+softhsm_cleanup
+
+rm rsa_pub.key aes_plain_key aes_wrapped_key aes_ciphertext_pkcs11.data aes_ciphertext_openssl.data aes_plain.data generic_extracted_key wrapped.key plain_wrapped.key
+
+exit $ERRORS
diff -Nru opensc-0.22.0/.travis.yml opensc-0.23.0/.travis.yml
--- opensc-0.22.0/.travis.yml	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/.travis.yml	1970-01-01 01:00:00.000000000 +0100
@@ -1,386 +0,0 @@
-language: c
-
-matrix:
-  include:
-    - compiler: clang
-      os: osx
-      osx_image: xcode9.4
-      env: DO_PUSH_ARTIFACT=yes
-    - compiler: clang
-      os: osx
-      osx_image: xcode12.2
-      env: DO_PUSH_ARTIFACT=yes
-    - compiler: clang
-      os: linux
-      dist: focal
-    - compiler: gcc
-      os: linux
-      dist: bionic
-      env:
-        - DO_SIMULATION=javacard
-        - ENABLE_DOC=--enable-doc
-    - compiler: gcc
-      os: linux
-      dist: focal
-      env:
-        - DO_SIMULATION=oseid
-    - env:
-        - HOST=x86_64-w64-mingw32
-        - DO_PUSH_ARTIFACT=yes
-    - env:
-        - HOST=i686-w64-mingw32
-        - DO_PUSH_ARTIFACT=yes
-    - env: DO_COVERITY_SCAN=yes
-    - compiler: gcc
-      os: linux
-      dist: bionic
-      env:
-        - DO_SIMULATION=cac
-
-env:
-  global:
-    # The next declaration are encrypted environment variables, created via the
-    # "travis encrypt" command using the project repo's public key
-    # COVERITY_SCAN_TOKEN
-    - secure: "UkHn7wy4im8V1nebCWbAetnDSOLRUbOlF6++ovk/7Bnso1/lnhXHelyzgRxfD/oI68wm9nnRV+RQEZ9+72Ug1CyvHxyyxxkwal/tPeHH4B/L+aGdPi0id+5OZSKIm77VP3m5s102sJMJgH7DFd03+nUd0K26p0tk8ad4j1geV4c="
-    # GH_TOKEN
-    - secure: "cUAvpN/XUPMIN5cgWAbIOhghRoLXyw7SCydzGaJ1Ucqb9Ml2v5iuLLuN57YbZHTiWw03vy6rYVzzwMDrHX8r3oUALsv7ViJHG4PzIe7fAFZsZpHECmGsp6SEnue7m7BNy3FT8KYbiXxnxDO0SxmFXlrPAYR0WMZCWx2TENYcafs="
-    - COVERITY_SCAN_BRANCH_PATTERN="(master|coverity.*)"
-    - COVERITY_SCAN_NOTIFICATION_EMAIL="viktor.tarasov at gmail.com"
-    - COVERITY_SCAN_BUILD_COMMAND="make -j 4"
-    - COVERITY_SCAN_PROJECT_NAME="$TRAVIS_REPO_SLUG"
-    - SOURCE_DATE_EPOCH=$(git log -1 --pretty=%ct)
-
-# Commented out because of a bug in travis images for Focal:
-# https://travis-ci.community/t/clang-10-was-recently-broken-on-linux-unmet-dependencies-for-clang-10-clang-tidy-10-valgrind/11527
-#addons:
-#  apt_packages:
-#    - binutils-mingw-w64-i686
-#    - binutils-mingw-w64-x86-64
-#    - docbook-xsl
-#    - gcc-mingw-w64-i686
-#    - gcc-mingw-w64-x86-64
-#    - libpcsclite-dev
-#    - mingw-w64
-#    - xsltproc
-#    - gengetopt
-#    - libcmocka-dev
-#    - help2man
-#    - pcscd
-#    - pcsc-tools
-#    - check
-#    - ant
-#    - socat
-#    - cmake
-#    - clang-tidy
-#    - softhsm2
-
-before_install:
-  # homebrew is dead slow in older images due to the many updates it would need to download and build.
-  # here, we build the additional dependencies manually to get around this
-  - if [ "$TRAVIS_OS_NAME" = "osx" ]; then
-        curl https://ftp.gnu.org/gnu/gengetopt/gengetopt-2.23.tar.xz -L --output gengetopt-2.23.tar.xz;
-        tar xfj gengetopt-2.23.tar.xz;
-        pushd gengetopt-2.23;
-        ./configure && make;
-        sudo make install;
-        popd;
-        curl https://ftp.gnu.org/gnu/help2man/help2man-1.47.16.tar.xz -L --output help2man-1.47.16.tar.xz;
-        tar xjf help2man-1.47.16.tar.xz;
-        pushd help2man-1.47.16;
-        ./configure && make;
-        sudo make install;
-        popd;
-        export PATH="/usr/local/opt/ccache/libexec:$PATH";
-        git clone https://github.com/frankmorgner/OpenSCToken.git;
-        sudo rm -rf /Library/Developer/CommandLineTools;
-    fi
-  - if [ "$TRAVIS_OS_NAME" = "osx" -a "$TRAVIS_PULL_REQUEST" = "false" -a -n "$encrypted_3b9f0b9d36d1_key" ]; then
-        openssl aes-256-cbc -K $encrypted_3b9f0b9d36d1_key -iv $encrypted_3b9f0b9d36d1_iv -in .github/secrets.tar.enc -out .github/secrets.tar -d;
-        .github/add_signing_key.sh;
-    else
-        unset CODE_SIGN_IDENTITY INSTALLER_SIGN_IDENTITY;
-    fi
-  - if [ "${DO_SIMULATION}" = "javacard" ]; then
-        sudo apt-get install -y openjdk-8-jdk;
-        sudo update-java-alternatives -s java-1.8.0-openjdk-amd64;
-        sudo update-alternatives --get-selections | grep ^java;
-        export PATH="/usr/lib/jvm/java-8-openjdk-amd64/bin/:$PATH";
-        export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/;
-        env | grep -i openjdk;
-    fi
-  - if [ "${DO_SIMULATION}" = "cac" ]; then
-        sudo apt-get install -y libglib2.0-dev libnss3-dev  pkgconf libtool make autoconf autoconf-archive automake libsofthsm2-dev softhsm2 softhsm2-common help2man gnutls-bin libcmocka-dev libusb-dev libudev-dev flex libnss3-tools libssl-dev libpcsclite1;
-        export PKG_CONFIG_PATH=/usr/local/lib/pkgconfig;
-    fi
-  - if [ -n "${HOST}" ]; then
-        sudo apt-get install -y wine;
-    fi
-  - if [ "$TRAVIS_DIST" == "focal" ]; then
-        sudo apt-get install -yq --allow-downgrades libc6=2.31-0ubuntu9.2 libc6-dev=2.31-0ubuntu9.2;
-    fi
-  - if [ "$TRAVIS_OS_NAME" == "linux" ]; then
-        sudo -E apt-get -yq --no-install-suggests --no-install-recommends --allow-downgrades --allow-remove-essential --allow-change-held-packages install binutils-mingw-w64-i686 binutils-mingw-w64-x86-64 docbook-xsl gcc-mingw-w64-i686 gcc-mingw-w64-x86-64 libpcsclite-dev mingw-w64 xsltproc gengetopt libcmocka-dev help2man pcscd pcsc-tools check ant socat cmake clang-tidy softhsm2;
-    fi
-
-before_script:
-  - if [ "$TRAVIS_BRANCH" = "master" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then
-      ./bootstrap;
-    fi
-  - if [ "$TRAVIS_BRANCH" = "master" -a "$TRAVIS_PULL_REQUEST" != "false" ]; then
-      ./bootstrap.ci -s "-pr$TRAVIS_PULL_REQUEST";
-    fi
-  - if [ "$TRAVIS_BRANCH" != "master" -a "$TRAVIS_PULL_REQUEST" = "false" ]; then
-      ./bootstrap.ci -s "-$TRAVIS_BRANCH";
-    fi
-  - if [ "$TRAVIS_BRANCH" != "master" -a "$TRAVIS_PULL_REQUEST" != "false" ]; then
-      ./bootstrap.ci -s "-$TRAVIS_BRANCH-pr$TRAVIS_PULL_REQUEST";
-    fi
-  - if [ -z "$HOST" ]; then
-      CFLAGS="-Werror" ./configure $ENABLE_DOC --enable-dnie-ui;
-    else
-      if [ ! -f "$(winepath 'C:/Program Files (x86)/Inno Setup 5/ISCC.exe')" ]; then
-        /sbin/start-stop-daemon --start --quiet --pidfile /tmp/custom_xvfb_99.pid --make-pidfile --background --exec /usr/bin/Xvfb -- :99 -ac -screen 0 1280x1024x16;
-        export DISPLAY=:99.0;
-        [ -d isetup ] || mkdir isetup;
-        pushd isetup;
-        [ -f isetup-5.5.6.exe ] || wget http://files.jrsoftware.org/is/5/isetup-5.5.6.exe;
-        wine isetup-5.5.6.exe /SILENT /VERYSILENT /SP- /SUPPRESSMSGBOXES /NORESTART;
-        popd;
-      fi;
-      unset CC;
-      unset CXX;
-      ./configure --host=$HOST --with-completiondir=/tmp --disable-openssl --disable-readline --disable-zlib --disable-notify --prefix=${TRAVIS_BUILD_DIR}/win32/opensc || cat config.log;
-    fi
-  # Optionally try to upload to Coverity Scan
-  # On error (probably quota is exhausted), just continue
-  - if [ "${DO_COVERITY_SCAN}" = "yes" ]; then curl -s 'https://scan.coverity.com/scripts/travisci_build_coverity_scan.sh' | bash || true; fi
-
-  - if [ "${DO_SIMULATION}" = "javacard" ]; then
-      set -ex;
-      git clone https://github.com/frankmorgner/vsmartcard.git;
-      cd vsmartcard/virtualsmartcard;
-      autoreconf -vis && ./configure && sudo make install;
-      cd $TRAVIS_BUILD_DIR;
-      sudo systemctl stop pcscd.service pcscd.socket;
-
-      git clone https://github.com/martinpaljak/oracle_javacard_sdks.git;
-      export JC_HOME=$PWD/oracle_javacard_sdks/jc222_kit;
-      export JC_CLASSIC_HOME=$PWD/oracle_javacard_sdks/jc305u3_kit;
-
-      git clone https://github.com/arekinath/jcardsim.git;
-      cd jcardsim;
-      env | grep -i openjdk;
-      export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/;
-      mvn initialize && mvn clean install;
-      cd $TRAVIS_BUILD_DIR;
-
-      git clone https://github.com/philipWendland/IsoApplet.git;
-      javac -classpath jcardsim/target/jcardsim-3.0.5-SNAPSHOT.jar IsoApplet/src/net/pwendland/javacard/pki/isoapplet/*.java;
-      echo "com.licel.jcardsim.card.applet.0.AID=F276A288BCFBA69D34F31001" > isoapplet_jcardsim.cfg;
-      echo "com.licel.jcardsim.card.applet.0.Class=net.pwendland.javacard.pki.isoapplet.IsoApplet" >> isoapplet_jcardsim.cfg;
-      echo "com.licel.jcardsim.card.ATR=3B80800101" >> isoapplet_jcardsim.cfg;
-      echo "com.licel.jcardsim.vsmartcard.host=localhost" >> isoapplet_jcardsim.cfg;
-      echo "com.licel.jcardsim.vsmartcard.port=35963" >> isoapplet_jcardsim.cfg;
-
-      git clone https://github.com/vletoux/GidsApplet.git;
-      javac -classpath jcardsim/target/jcardsim-3.0.5-SNAPSHOT.jar GidsApplet/src/com/mysmartlogon/gidsApplet/*.java;
-      echo "com.licel.jcardsim.card.applet.0.AID=A000000397425446590201" > gids_jcardsim.cfg;
-      echo "com.licel.jcardsim.card.applet.0.Class=com.mysmartlogon.gidsApplet.GidsApplet" >> gids_jcardsim.cfg;
-      echo "com.licel.jcardsim.card.ATR=3B80800101" >> gids_jcardsim.cfg;
-      echo "com.licel.jcardsim.vsmartcard.host=localhost" >> gids_jcardsim.cfg;
-      echo "com.licel.jcardsim.vsmartcard.port=35963" >> gids_jcardsim.cfg;
-
-      git clone --recursive https://github.com/Yubico/ykneo-openpgp.git;
-      cd ykneo-openpgp;
-      ant -DJAVACARD_HOME=${JC_HOME};
-      cd $TRAVIS_BUILD_DIR;
-      echo "com.licel.jcardsim.card.applet.0.AID=D2760001240102000000000000010000" > openpgp_jcardsim.cfg;
-      echo "com.licel.jcardsim.card.applet.0.Class=openpgpcard.OpenPGPApplet" >> openpgp_jcardsim.cfg;
-      echo "com.licel.jcardsim.card.ATR=3B80800101" >> openpgp_jcardsim.cfg;
-      echo "com.licel.jcardsim.vsmartcard.host=localhost" >> openpgp_jcardsim.cfg;
-      echo "com.licel.jcardsim.vsmartcard.port=35963" >> openpgp_jcardsim.cfg;
-
-      git clone --recursive https://github.com/arekinath/PivApplet.git;
-      cd PivApplet;
-      JC_HOME=${JC_CLASSIC_HOME} ant dist;
-      cd $TRAVIS_BUILD_DIR;
-
-      git clone https://github.com/Yubico/yubico-piv-tool.git;
-      cd yubico-piv-tool;
-      mkdir build; cd build;
-      cmake .. && make && sudo make install;
-      cd $TRAVIS_BUILD_DIR;
-      set +ex;
-    fi
-
-  - if [ "${DO_SIMULATION}" = "oseid" ]; then
-      git clone https://github.com/popovec/oseid;
-      cd oseid/src/;
-      make -f Makefile.console;
-      mkdir tmp;
-      socat -d -d pty,link=tmp/OsEIDsim.socket,raw,echo=0 "exec:build/console/console ...,pty,raw,echo=0" &
-      PID=$!;
-      sleep 1;
-      echo "# OsEIDsim" > tmp/reader.conf;
-      echo 'FRIENDLYNAME      "OsEIDsim"' >> tmp/reader.conf;
-      echo "DEVICENAME        ${TRAVIS_BUILD_DIR}/oseid/src/tmp/OsEIDsim.socket" >> tmp/reader.conf;
-      echo "LIBPATH           ${TRAVIS_BUILD_DIR}/oseid/src/build/console/libOsEIDsim.so.0.0.1" >> tmp/reader.conf;
-      echo "CHANNELID         1" >> tmp/reader.conf;
-      sudo mv tmp/reader.conf /etc/reader.conf.d/reader.conf;
-      cat /etc/reader.conf.d/reader.conf;
-      cd $TRAVIS_BUILD_DIR;
-
-      sudo /etc/init.d/pcscd restart;
-    fi
-
-  - if [ "${DO_SIMULATION}" = "cac" ]; then
-      git clone https://github.com/frankmorgner/vsmartcard.git;
-      cd vsmartcard/virtualsmartcard;
-      autoreconf -vis && ./configure && make -j4 && sudo make install;
-
-      cd $TRAVIS_BUILD_DIR;
-      git clone https://gitlab.freedesktop.org/spice/libcacard.git;
-      cd libcacard && ./autogen.sh --prefix=/usr && make -j4 && sudo make install;
-
-      cd $TRAVIS_BUILD_DIR;
-      git clone https://github.com/PL4typus/virt_cacard.git;
-      cd virt_cacard && ./autogen.sh && ./configure && make;
-
-      cd $TRAVIS_BUILD_DIR;
-      sudo /etc/init.d/pcscd restart;
-    fi
-
-script:
-  - if [ "${DO_COVERITY_SCAN}" != "yes" ]; then
-      if [ "${TRAVIS_OS_NAME}" = "osx" ]; then
-        ./MacOSX/build;
-      else
-        make -j 4;
-      fi;
-    fi
-  - if [ -z "$HOST" -a "${DO_COVERITY_SCAN}" != "yes" -a -z "$DO_SIMULATION" ]; then
-      make check && make distcheck || (cat tests/*log src/tests/unittests/*log && exit 1);
-    fi
-  - if [ ! -z "$HOST" -a "${DO_COVERITY_SCAN}" != "yes" ]; then
-      make install;
-      wine "C:/Program Files (x86)/Inno Setup 5/ISCC.exe" win32/OpenSC.iss;
-    fi
-
-  - if [ "${DO_SIMULATION}" = "javacard" ]; then
-      set -ex;
-      sudo make install;
-      export LD_LIBRARY_PATH=/usr/local/lib;
-
-      sudo /usr/sbin/pcscd -f &
-      PCSCD_PID=$!;
-
-      java -noverify -cp IsoApplet/src/:jcardsim/target/jcardsim-3.0.5-SNAPSHOT.jar com.licel.jcardsim.remote.VSmartCard isoapplet_jcardsim.cfg >/dev/null &
-      PID=$!;
-      sleep 5;
-      opensc-tool --card-driver default --send-apdu 80b800001a0cf276a288bcfba69d34f310010cf276a288bcfba69d34f3100100;
-      opensc-tool -n;
-      pkcs15-init --create-pkcs15 --so-pin 123456 --so-puk 0123456789abcdef;
-      pkcs15-tool --change-pin --pin 123456 --new-pin 654321;
-      pkcs15-tool --unblock-pin --puk 0123456789abcdef --new-pin 123456;
-      pkcs15-init --generate-key rsa/2048     --id 1 --key-usage decrypt,sign --auth-id FF --pin 123456;
-      pkcs15-init --generate-key rsa/2048     --id 2 --key-usage decrypt      --auth-id FF --pin 123456;
-      pkcs15-init --generate-key ec/secp256r1 --id 3 --key-usage sign         --auth-id FF --pin 123456;
-      pkcs15-tool -D;
-      pkcs11-tool -l -t -p 123456;
-      kill -9 $PID;
-
-      java -noverify -cp GidsApplet/src/:jcardsim/target/jcardsim-3.0.5-SNAPSHOT.jar com.licel.jcardsim.remote.VSmartCard gids_jcardsim.cfg >/dev/null &
-      PID=$!;
-      sleep 5;
-      opensc-tool --card-driver default --send-apdu 80b80000190bA0000003974254465902010bA00000039742544659020100;
-      opensc-tool -n;
-      gids-tool --initialize --pin 123456 --admin-key 000000000000000000000000000000000000000000000000 --serial 00000000000000000000000000000000;
-      kill -9 $PID;
-
-      java -noverify -cp ykneo-openpgp/applet/bin:jcardsim/target/jcardsim-3.0.5-SNAPSHOT.jar com.licel.jcardsim.remote.VSmartCard openpgp_jcardsim.cfg >/dev/null &
-      PID=$!;
-      sleep 5;
-      opensc-tool --card-driver default --send-apdu 80b800002210D276000124010200000000000001000010D276000124010200000000000001000000;
-      opensc-tool -n;
-      openpgp-tool --verify CHV3 --pin 12345678 --gen-key 2;
-      pkcs15-init --verify --auth-id 3 --pin 12345678 --delete-objects privkey,pubkey --id 2 --generate-key rsa/2048;
-      pkcs11-tool -l -t -p 123456;
-      kill -9 $PID;
-
-      java -noverify -cp PivApplet/bin/:jcardsim/target/jcardsim-3.0.5-SNAPSHOT.jar com.licel.jcardsim.remote.VSmartCard PivApplet/test/jcardsim.cfg >/dev/null &
-      PID=$!;
-      sleep 5;
-      opensc-tool --card-driver default --send-apdu 80b80000120ba000000308000010000100050000020F0F7f;
-      opensc-tool -n;
-      yubico-piv-tool -v 9999 -r 'Virtual PCD 00 00' -P 123456 -s 9e -a generate -A RSA2048;
-      yubico-piv-tool -v 9999 -r 'Virtual PCD 00 00' -P 123456 -s 9a -a generate -A ECCP256;
-      pkcs11-tool -l -t -p 123456;
-      kill -9 $PID;
-
-      sudo kill -9 $PCSCD_PID;
-
-      set +ex;
-    fi
-
-  - if [ "${DO_SIMULATION}" = "oseid" ]; then
-      set -ex;
-      sudo make install;
-      export LD_LIBRARY_PATH=/usr/local/lib;
-
-      cd oseid/tools;
-      echo | ./OsEID-tool INIT;
-      ./OsEID-tool RSA-CREATE-KEYS;
-      ./OsEID-tool RSA-UPLOAD-KEYS;
-      ./OsEID-tool RSA-DECRYPT-TEST;
-      ./OsEID-tool RSA-SIGN-PKCS11-TEST;
-      ./OsEID-tool EC-CREATE-KEYS;
-      ./OsEID-tool EC-UPLOAD-KEYS;
-      ./OsEID-tool EC-SIGN-TEST;
-      ./OsEID-tool EC-SIGN-PKCS11-TEST;
-      ./OsEID-tool EC-ECDH-TEST;
-      kill -9 $PID;
-
-      set +ex;
-    fi
-  - if [ "${DO_SIMULATION}" = "cac" ]; then
-      cd $TRAVIS_BUILD_DIR;
-      make check && sudo make install || (cat tests/*log src/tests/unittests/*log && exit 1);
-      export LD_LIBRARY_PATH=/usr/local/lib;
-      cd src/tests/p11test/;
-      ./p11test -s 0 -p 12345678 -i &
-      sleep 5;
-      cd $TRAVIS_BUILD_DIR/virt_cacard;
-      ./setup-softhsm2.sh;
-      export SOFTHSM2_CONF=$PWD/softhsm2.conf;
-      ./virt_cacard &
-      wait $(ps aux | grep '[p]11test'| awk '{print $2}');
-      kill -9 $(ps aux | grep '[v]irt_cacard'| awk '{print $2}');
-    fi
-
-after_script:
-  # kill process started during compilation to finish the build, see
-  # https://github.com/moodlerooms/moodle-plugin-ci/issues/33 for details
-  - if [ ! -z "$HOST" ]; then
-      killall services.exe;
-    fi
-
-  # keep in sync with appveyor.yml
-  - if [ "${DO_PUSH_ARTIFACT}" = "yes" -a "$TRAVIS_PULL_REQUEST" = "false" -a "$TRAVIS_REPO_SLUG" = "OpenSC/OpenSC" ]; then
-      git config --global user.email "builds at travis-ci.org";
-      git config --global user.name "Travis CI";
-      .github/push_artifacts.sh "Travis CI build ${TRAVIS_JOB_NUMBER}";
-    fi
-  - if [ "$TRAVIS_OS_NAME" = "osx" ]; then
-      .github/remove_signing_key.sh;
-      rm -f .github/secrets.tar;
-    fi
-
-cache:
-  apt: true
-  ccache: true
-  directories:
-    - $HOME/.m2/
-    - openssl_bin
-    - openpace_bin
-    - isetup
diff -Nru opensc-0.22.0/version.m4 opensc-0.23.0/version.m4
--- opensc-0.22.0/version.m4	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/version.m4	1970-01-01 01:00:00.000000000 +0100
@@ -1,5 +0,0 @@
-dnl version.m4 - source for version.m4.ci generated by bootstrap.ci
-dnl * bootstrap.ci generates version.m4.ci based on this file
-dnl * if version.m4.ci exists, it is included in configure.ac
-define([PACKAGE_SUFFIX], [])
-
diff -Nru opensc-0.22.0/win32/customactions.cpp opensc-0.23.0/win32/customactions.cpp
--- opensc-0.22.0/win32/customactions.cpp	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/win32/customactions.cpp	2022-11-29 09:34:43.000000000 +0100
@@ -49,8 +49,10 @@
 
 #define X86onX64_SC_DATABASE TEXT("SOFTWARE\\Wow6432Node\\Microsoft\\Cryptography\\Calais\\SmartCards")
 #define SC_DATABASE TEXT("SOFTWARE\\Microsoft\\Cryptography\\Calais\\SmartCards")
-#define BASE_CSP TEXT("OpenSC CSP")
+#define BASE_CSP TEXT("Microsoft Base Smart Card Crypto Provider")
 #define BASE_KSP TEXT("Microsoft Smart Card Key Storage Provider")
+#define BASE_INSTALLED_BY_KEY TEXT("InstalledBy")
+#define BASE_INSTALLED_BY_VALUE TEXT("OpenSC")
 
 typedef struct _MD_REGISTRATION
 {
@@ -69,8 +71,8 @@
  */
 
 MD_REGISTRATION minidriver_registration[] = {
-	{TEXT("ePass2003"),                       {0x3b,0x9f,0x95,0x81,0x31,0xfe,0x9f,0x00,0x66,0x46,0x53,0x05,0x01,0x00,0x11,0x71,0xdf,0x00,0x00,0x03,0x6a,0x82,0xf8},
-                                          23, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}},
+	{TEXT("ePass2003"),                       {0x3b,0x9f,0x95,0x81,0x31,0xfe,0x9f,0x00,0x66,0x46,0x53,0x05,0x00,0x00,0x00,0x71,0xdf,0x00,0x00,0x00,0x00,0x00,0x00},
+                                          23, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00}},
 	{TEXT("FTCOS/PK-01C"),                    {0x3b,0x9f,0x95,0x81,0x31,0xfe,0x9f,0x00,0x65,0x46,0x53,0x05,0x00,0x06,0x71,0xdf,0x00,0x00,0x00,0x00,0x00,0x00,0x00},
                                           23, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0xff,0xff,0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00}},
 	{TEXT("SmartCard-HSM"),                   {0x3b,0xfe,0x18,0x00,0x00,0x81,0x31,0xfe,0x45,0x80,0x31,0x81,0x54,0x48,0x53,0x4d,0x31,0x73,0x80,0x21,0x40,0x81,0x07,0xfa},
@@ -128,6 +130,9 @@
 	/* from card-cardos.c */
 	{TEXT("CardOS 4.0"),                      {0x3b,0xe2,0x00,0xff,0xc1,0x10,0x31,0xfe,0x55,0xc8,0x02,0x9c},
                                           12, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}},
+	/* note: */
+	{TEXT("CardOS 4.2+"),                     {0x3b,0xf2,0x08,0x00,0x00,0xc1,0x00,0x31,0xfe,0x00,0x00,0x00,0x00},
+                                          13, {0xff,0xff,0x0f,0xff,0x00,0xff,0x00,0xff,0xff,0x00,0x00,0x00,0x00}},
 	{TEXT("Italian CNS (a)"),                 {0x3b,0xe9,0x00,0xff,0xc1,0x10,0x31,0xfe,0x55,0x00,0x64,0x05,0x00,0xc8,0x02,0x31,0x80,0x00,0x47},
                                           19, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}},
 	{TEXT("Italian CNS (b)"),                 {0x3b,0xfb,0x98,0x00,0xff,0xc1,0x10,0x31,0xfe,0x55,0x00,0x64,0x05,0x20,0x47,0x03,0x31,0x80,0x00,0x90,0x00,0xf3},
@@ -136,6 +141,8 @@
                                           23, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}},
 	{TEXT("Italian CNS (d)"),                 {0x3b,0xff,0x18,0x00,0xff,0x81,0x31,0xfe,0x55,0x00,0x6b,0x02,0x09,0x03,0x03,0x01,0x01,0x01,0x43,0x4e,0x53,0x10,0x31,0x80,0x9d},
                                           25, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}},
+	{TEXT("Italian CNS (e)"),                 {0x3b,0xff,0x18,0x00,0x00,0x81,0x31,0xfe,0x45,0x00,0x6b,0x11,0x05,0x07,0x00,0x01,0x21,0x01,0x43,0x4e,0x53,0x10,0x31,0x80,0x4a},
+                                          25, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}},
 	{TEXT("CardOS 4.0 a"),                    {0x3b,0xf4,0x98,0x00,0xff,0xc1,0x10,0x31,0xfe,0x55,0x4d,0x34,0x63,0x76,0xb4},
                                           15, {0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff}},
 	{TEXT("Cardos M4"),                       {0x3b,0xf2,0x18,0x00,0x02,0xc1,0x0a,0x31,0xfe,0x58,0xc8,0x08,0x74},
@@ -197,7 +204,8 @@
 };
 
 
-/* remove a card in the database if and only if the CSP match the OpenSC CSP
+/* remove a card in the database if and only if the BASE_INSTALLED_BY_KEY is present and has value of BASE INSTALLED_BY_VALUE
+It also will not install drivers installed by other or modified by a user (who should have changed the BASE INSTALLED_BY_VALUE
 The program try to avoid any failure to not break the uninstall process */
 VOID RemoveKey(PTSTR szSubKey)
 {
@@ -224,13 +232,13 @@
 			lResult = RegOpenKeyEx (hKey, szName, 0, KEY_READ, &hTempKey);
 			if (lResult == ERROR_SUCCESS)
 			{
-				TCHAR szCSP[MAX_PATH] = {0};
+				TCHAR szIB[MAX_PATH] = {0};
 				dwSize = MAX_PATH;
-				lResult = RegQueryValueEx(hTempKey, TEXT("Crypto Provider"), NULL, NULL, (PBYTE) szCSP, &dwSize);
+				lResult = RegQueryValueEx(hTempKey, BASE_INSTALLED_BY_KEY, NULL, NULL, (PBYTE) szIB, &dwSize);
 				RegCloseKey(hTempKey);
 				if (lResult == ERROR_SUCCESS)
 				{
-					if ( _tcsstr(szCSP, TEXT("OpenSC CSP")) != 0)
+					if ( _tcsstr(szIB, BASE_INSTALLED_BY_VALUE) != 0)
 					{
 						lResult = RegDeleteKey(hKey, szName);
 						if (lResult != ERROR_SUCCESS)
@@ -301,6 +309,8 @@
 		RegSetValueEx( hTempKey,TEXT("80000001"),0, REG_SZ, (PBYTE)szPath,(DWORD) (sizeof(TCHAR) * _tcslen(szPath)));
 		RegSetValueEx( hTempKey,TEXT("ATR"),0, REG_BINARY, (PBYTE)pbATR, dwATRSize);
 		RegSetValueEx( hTempKey,TEXT("ATRMask"),0, REG_BINARY, (PBYTE)pbAtrMask, dwATRSize);
+		RegSetValueEx( hTempKey,BASE_INSTALLED_BY_KEY,0, REG_SZ, (PBYTE)BASE_INSTALLED_BY_VALUE,
+			sizeof(BASE_INSTALLED_BY_VALUE) - sizeof(TCHAR));
 		RegCloseKey(hTempKey);
 	}
 	else
@@ -314,6 +324,8 @@
 {
 	DWORD expanded_len = PATH_MAX;
 	TCHAR expanded_val[PATH_MAX];
+	BYTE  pbAtrReduced[256];
+	DWORD i;
 	PTSTR szPath = TEXT("C:\\Program Files\\OpenSC Project\\OpenSC\\minidriver\\opensc-minidriver.dll");
 
 	/* cope with x86 installation on x64 */
@@ -323,7 +335,17 @@
 	if (0 < expanded_len && expanded_len < sizeof expanded_val)
 		szPath = expanded_val;
 
-	RegisterCardWithKey(SC_DATABASE, registration->szName, szPath, registration->pbAtr, registration->dwAtrSize, registration->pbAtrMask );
+	/*
+	 * OpenSC definitions of ATR have been lax in "sc_atr_table" entries by allowing
+	 * 1 bits in the ATR that need to be 0 bits when used with Windows compare
+	 * Do the equivalent reduction of the table ATR done in card.c by "tbin[s] = (tbin[s] & mbin[s]);"
+	 * before adding to registry.
+	 */
+	for (i = 0; i < registration->dwAtrSize; i++) {
+		pbAtrReduced[i] = (registration->pbAtr[i] & registration->pbAtrMask[i]);
+	}
+
+	RegisterCardWithKey(SC_DATABASE, registration->szName, szPath, pbAtrReduced, registration->dwAtrSize, registration->pbAtrMask );
 }
 
 UINT WINAPI AddSmartCardConfiguration(MSIHANDLE hInstall)
diff -Nru opensc-0.22.0/win32/Makefile.am opensc-0.23.0/win32/Makefile.am
--- opensc-0.22.0/win32/Makefile.am	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/win32/Makefile.am	2022-11-29 09:34:43.000000000 +0100
@@ -22,4 +22,7 @@
 
 install-exec-hook:
 	mv "$(DESTDIR)$(libdir)/customactions at LIBRARY_BITNESS@.dll" "$(DESTDIR)$(bindir)/"
+
+uninstall-hook:
+	rm -f "$(DESTDIR)$(bindir)/customactions at LIBRARY_BITNESS@.dll"
 endif
diff -Nru opensc-0.22.0/win32/Make.rules.mak opensc-0.23.0/win32/Make.rules.mak
--- opensc-0.22.0/win32/Make.rules.mak	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/win32/Make.rules.mak	2022-11-29 09:34:43.000000000 +0100
@@ -81,7 +81,7 @@
 !ENDIF
 
 PROGRAMS_OPENSSL = cryptoflex-tool.exe pkcs15-init.exe netkey-tool.exe piv-tool.exe \
-	westcos-tool.exe sc-hsm-tool.exe dnie-tool.exe gids-tool.exe npa-tool.exe
+	westcos-tool.exe sc-hsm-tool.exe dnie-tool.exe gids-tool.exe
 OPENSC_FEATURES = $(OPENSC_FEATURES) openssl
 CANDLEFLAGS = -dOpenSSL="$(OPENSSL_DIR)" $(CANDLEFLAGS)
 !ENDIF
@@ -126,6 +126,10 @@
 !ENDIF
 OPENPACE_INCL_DIR = /I$(OPENPACE_DIR)\src
 OPENPACE_LIB = $(OPENPACE_DIR)\src\libeac.lib
+!IF "$(OPENSSL_DEF)" == "/DENABLE_OPENSSL"
+# Build only when OpenPACE and OpenSSL are available
+PROGRAMS_OPENPACE = npa-tool.exe
+!ENDIF
 CANDLEFLAGS = -dOpenPACE="$(OPENPACE_DIR)" $(CANDLEFLAGS)
 !ENDIF
 
diff -Nru opensc-0.22.0/win32/OpenSC.wxs.in opensc-0.23.0/win32/OpenSC.wxs.in
--- opensc-0.22.0/win32/OpenSC.wxs.in	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/win32/OpenSC.wxs.in	2022-11-29 09:34:43.000000000 +0100
@@ -86,6 +86,9 @@
               <!-- install an alias for the Base smart card CSP. Using a different CSP in minidriver installation deactivate the plug and play feature
                   but not all other components like the pin change screen available after ctrl+alt+del.
                   It is because the "80000001" entry is still returning the minidriver dll.-->
+              <!-- PR #2523 no longer uses "Provider = OpenSC CSP", but existing certificates in cert store 
+	          may have "Provider = OpenSC CSP" so we continue to add it for backward compatibility.
+		  Run: "certutil -Silent -store -user My" and look for "Provider = OpenSC CSP". -->
               <Component Id="openscBaseCSP" Guid="*" Win64="$(var.Win64YesNo)">
                 <RegistryKey Root="HKLM" Key="SOFTWARE\Microsoft\Cryptography\Defaults\Provider\OpenSC CSP">
                   <RegistryValue Type="string" Name="Image Path" Value="basecsp.dll" KeyPath="yes"/>
@@ -231,15 +234,9 @@
                 <Component Id="gpk.profile" Guid="*" Win64="$(var.Win64YesNo)">
                   <File Source="$(var.SOURCE_DIR)\src\pkcs15init\gpk.profile"/>
                 </Component>
-                <Component Id="miocos.profile" Guid="*" Win64="$(var.Win64YesNo)">
-                  <File Source="$(var.SOURCE_DIR)\src\pkcs15init\miocos.profile"/>
-                </Component>
                 <Component Id="incrypto34.profile" Guid="*" Win64="$(var.Win64YesNo)">
                   <File Source="$(var.SOURCE_DIR)\src\pkcs15init\incrypto34.profile"/>
                 </Component>
-                <Component Id="jcop.profile" Guid="*" Win64="$(var.Win64YesNo)">
-                  <File Source="$(var.SOURCE_DIR)\src\pkcs15init\jcop.profile"/>
-                </Component>
                 <Component Id="muscle.profile" Guid="*" Win64="$(var.Win64YesNo)">
                   <File Source="$(var.SOURCE_DIR)\src\pkcs15init\muscle.profile"/>
                 </Component>
@@ -410,9 +407,7 @@
           <ComponentRef Id="cyberflex.profile"/>
           <ComponentRef Id="flex.profile"/>
           <ComponentRef Id="gpk.profile"/>
-          <ComponentRef Id="miocos.profile"/>
           <ComponentRef Id="incrypto34.profile"/>
-          <ComponentRef Id="jcop.profile"/>
           <ComponentRef Id="muscle.profile"/>
           <ComponentRef Id="pkcs15.profile"/>
           <ComponentRef Id="asepcos.profile"/>
diff -Nru opensc-0.22.0/win32/winconfig.h.in opensc-0.23.0/win32/winconfig.h.in
--- opensc-0.22.0/win32/winconfig.h.in	2021-08-10 11:09:03.000000000 +0200
+++ opensc-0.23.0/win32/winconfig.h.in	2022-11-29 09:34:43.000000000 +0100
@@ -33,7 +33,7 @@
 #ifndef R_OK
 #define R_OK  4		/* test whether readable.  */
 #define W_OK  2		/* test whether writable.  */
-#define X_OK  1		/* test whether execubale. */
+#define X_OK  1		/* test whether executable. */
 #define F_OK  0		/* test whether exist.  */
 #endif
 


More information about the pkg-opensc-maint mailing list