pax_global_header00006660000000000000000000000064147527062370014527gustar00rootroot0000000000000052 comment=8f6b94409d4872265076df310492da1e5f6abdf7 pkcs11-provider-1.0/000077500000000000000000000000001475270623700143215ustar00rootroot00000000000000pkcs11-provider-1.0/.clang-format000066400000000000000000000041431475270623700166760ustar00rootroot00000000000000BasedOnStyle: LLVM ColumnLimit: 80 IndentWidth: 4 UseTab: Never BraceWrapping: AfterCaseLabel: false AfterClass: true AfterControlStatement: Never AfterEnum: false AfterFunction: true AfterNamespace: true AfterObjCDeclaration: false AfterStruct: false AfterUnion: false AfterExternBlock: false BeforeCatch: false BeforeElse: false BeforeLambdaBody: false BeforeWhile: false IndentBraces: false SplitEmptyFunction: true SplitEmptyRecord: true SplitEmptyNamespace: true BreakBeforeBinaryOperators: NonAssignment BreakBeforeConceptDeclarations: true BreakBeforeBraces: Linux BreakBeforeInheritanceComma: false BreakInheritanceList: BeforeColon BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: false BreakConstructorInitializers: BeforeColon BreakAfterJavaFieldAnnotations: false BreakStringLiterals: true AlignAfterOpenBracket: Align AlignEscapedNewlines: DontAlign AllowAllArgumentsOnNextLine: true AllowShortCaseLabelsOnASingleLine: false AllowShortIfStatementsOnASingleLine: true AllowAllParametersOfDeclarationOnNextLine: false BinPackArguments: true BinPackParameters: true #InsertTrailingCommas: Wrapped ReflowComments: false Cpp11BracedListStyle: false AlignArrayOfStructures: None AlignTrailingComments: false AllowShortFunctionsOnASingleLine: Empty AlwaysBreakBeforeMultilineStrings: false IndentGotoLabels: true SortIncludes: Never SpaceBeforeCpp11BracedList: true SpaceBeforeCtorInitializerColon: false SpaceBeforeInheritanceColon: false SpaceBeforeParensOptions: AfterControlStatements: true AfterForeachMacros: false AfterFunctionDefinitionName: false AfterFunctionDeclarationName: false AfterIfMacros: false AfterOverloadedOperator: false BeforeNonEmptyParentheses: false SpaceBeforeRangeBasedForLoopColon: false SpaceInEmptyBlock: false SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 2 SpacesInAngles: Never SpacesInConditionalStatement: false SpacesInContainerLiterals: false SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false SpaceBeforeSquareBrackets: false pkcs11-provider-1.0/.clang-format-ignore000066400000000000000000000000621475270623700201530ustar00rootroot00000000000000# Leave third party code untouched ./src/pkcs11.h pkcs11-provider-1.0/.github/000077500000000000000000000000001475270623700156615ustar00rootroot00000000000000pkcs11-provider-1.0/.github/ISSUE_TEMPLATE/000077500000000000000000000000001475270623700200445ustar00rootroot00000000000000pkcs11-provider-1.0/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000014121475270623700225340ustar00rootroot00000000000000--- name: Bug report about: Create a report to help us improve title: '' labels: '' assignees: '' --- **Describe the bug** A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' 4. See error **Expected behavior** A clear and concise description of what you expected to happen. **Operating environment (please complete the following information):** - OS: [e.g. Fedora] - Version [e.g. 36] **Token and application used (please complete the following information):** - Device: [e.g. ACME HSM Pro 1.7] - PKCS11 Driver version: [e.g. 1.3.4] - Application [e.g. Apache Httpd] - Version [e.g. 22] **Additional context** Add any other context about the problem here. pkcs11-provider-1.0/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000000331475270623700220300ustar00rootroot00000000000000blank_issues_enabled: true pkcs11-provider-1.0/.github/ISSUE_TEMPLATE/rfe.md000066400000000000000000000005561475270623700211500ustar00rootroot00000000000000--- name: Feature Request about: Ask for a feature title: '' labels: 'enhancement' assignees: '' --- **Describe the feature** A clear and concise description of what the request is. **Expected behavior** A clear and concise description of what you expect to happen. **Additional context** Add any other context about the environment the applies to this feature. pkcs11-provider-1.0/.github/PULL_REQUEST_TEMPLATE.md000066400000000000000000000020321475270623700214570ustar00rootroot00000000000000#### Description #### Checklist - [ ] Code modified for feature - [ ] Test suite updated with functionality tests - [ ] Test suite updated with negative tests - [ ] Documentation updated #### Reviewer's checklist: - [ ] Any issues marked for closing are addressed - [ ] There is a test suite reasonably covering new functionality or modifications - [ ] This feature/change has adequate documentation added - [ ] Code conform to coding style that today cannot yet be enforced via the check style test - [ ] Commits have short titles and sensible commit messages - [ ] Coverity Scan has run if needed (code PR) and no new defects were found pkcs11-provider-1.0/.github/scan-build.sh000077500000000000000000000002411475270623700202360ustar00rootroot00000000000000#!/bin/sh scan-build --html-title="PKCS#11 Provider ($GITHUB_SHA)" \ --keep-cc \ --status-bugs \ --keep-going \ "$@" pkcs11-provider-1.0/.github/sid.debug.list000066400000000000000000000000701475270623700204170ustar00rootroot00000000000000deb http://deb.debian.org/debian-debug/ sid-debug main pkcs11-provider-1.0/.github/workflows/000077500000000000000000000000001475270623700177165ustar00rootroot00000000000000pkcs11-provider-1.0/.github/workflows/address-sanitizer.yml000066400000000000000000000053361475270623700241030ustar00rootroot00000000000000--- name: Address sanitizer on: push: branches: ["main"] pull_request: branches: ["main"] jobs: build: name: CI with Address Sanitizer runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: name: [fedora, debian] include: - name: fedora container: fedora:latest - name: debian container: debian:sid container: ${{ matrix.container }} steps: - name: Checkout Repository uses: actions/checkout@v4 - name: Install Dependencies run: | if [ -f /etc/fedora-release ]; then dnf -y install git clang gcc pkgconf-pkg-config meson \ openssl-devel openssl diffutils expect \ softhsm opensc p11-kit-devel p11-kit-server gnutls-utils \ nss-softokn nss-tools nss-softokn-devel \ dnf-command\(debuginfo-install\) libasan dnf -y debuginfo-install openssl elif [ -f /etc/debian_version ]; then cat .github/sid.debug.list > /etc/apt/sources.list.d/debug.list apt-get -q update apt-get -yq install git gcc clang meson \ pkg-config libssl-dev openssl expect \ procps libnss3 libnss3-tools libnss3-dev softhsm2 opensc p11-kit \ libp11-kit-dev p11-kit-modules gnutls-bin \ openssl-dbgsym libssl3t64-dbgsym fi - name: Setup # The detection on debian works ok, but on Fedora, we get linker script, # that is not compatible with LD_PRELOAD so we force the absolute path. run: | if [ -f /etc/fedora-release ]; then CC=gcc \ meson setup builddir -Db_sanitize=address -Dpreload_libasan=/usr/lib64/libasan.so.8.0.0 elif [ -f /etc/debian_version ]; then CC=gcc \ meson setup builddir -Db_sanitize=address -Dpreload_libasan=/usr/lib/x86_64-linux-gnu/libasan.so.8.0.0 fi - name: Build and Test # note, that this intentionally does not initialize submodules as # the tlsfuzzer test does not work under address sanitizer well run: | meson compile -C builddir meson test --num-processes 1 -C builddir - uses: actions/upload-artifact@v4 if: failure() with: name: Address sanitizer logs on ${{ matrix.name }} path: | builddir/meson-logs/ builddir/tests/*.log builddir/tests/softhsm/p11prov-debug.log builddir/tests/softhsm/testvars builddir/tests/softhsm/openssl.cnf builddir/tests/softtokn/p11prov-debug.log builddir/tests/softtokn/testvars builddir/tests/softtokn/openssl.cnf pkcs11-provider-1.0/.github/workflows/build.yml000066400000000000000000000153451475270623700215500ustar00rootroot00000000000000--- name: Build on: push: branches: ["main"] pull_request: branches: ["main"] jobs: build: name: CI with software token runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: name: [fedora, debian, centos9, centos10, ubuntu] compiler: [gcc, clang] token: [softokn, softhsm] include: - name: fedora container: fedora:latest - name: debian container: debian:sid - name: centos9 container: quay.io/centos/centos:stream9 - name: centos10 container: quay.io/centos/centos:stream10 - name: ubuntu container: ubuntu:latest container: ${{ matrix.container }} steps: - name: Install Dependencies run: | if [ "${{ matrix.name }}" = "centos9" -o "${{ matrix.name }}" = "centos10" ]; then dnf_opts="--enablerepo=crb" fi if [ -f /etc/redhat-release ]; then dnf -y install $dnf_opts \ git ${{ matrix.compiler }} meson which \ pkgconf-pkg-config openssl-devel openssl \ diffutils expect valgrind opensc gnutls-utils python3-six if [ "${{ matrix.token }}" = "softokn" ]; then dnf -y install nss-softokn nss-tools nss-softokn-devel \ nss-devel elif [ "${{ matrix.token }}" = "softhsm" ]; then dnf -y install softhsm p11-kit-devel fi elif [ -f /etc/debian_version ]; then apt-get -q update apt-get -yq install git ${{ matrix.compiler }} meson \ pkg-config libssl-dev openssl expect \ valgrind procps opensc gnutls-bin python3-six if [ "${{ matrix.token }}" = "softokn" ]; then apt-get -yq install libnss3 libnss3-tools libnss3-dev elif [ "${{ matrix.token }}" = "softhsm" ]; then apt-get -yq install softhsm2 p11-kit libp11-kit-dev \ p11-kit-modules fi fi - name: Check NSS version id: nss-version-check run: | if [ "${{ matrix.name }}" = "centos9" -o "${{ matrix.name }}" = "centos10" ]; then if [ "${{ matrix.token }}" = "softokn" ]; then NSSMINVER=`nss-config --version nss | cut -d '.' -f 2` if [ $NSSMINVER -lt 101 ]; then echo "skiptest=true" >> $GITHUB_OUTPUT fi fi fi - name: Checkout Repository if : ( steps.nss-version-check.outputs.skiptest != 'true' ) uses: actions/checkout@v4 - name: Setup if : ( steps.nss-version-check.outputs.skiptest != 'true' ) run: | git config --global --add safe.directory \ /__w/pkcs11-provider/pkcs11-provider git submodule update --init if [ -f /etc/redhat-release ]; then CC=${{ matrix.compiler }} meson setup builddir else CC=${{ matrix.compiler }} meson setup builddir -Denable_explicit_EC_test=true fi - name: Build and Test if : ( steps.nss-version-check.outputs.skiptest != 'true' ) run: | meson compile -C builddir meson test --num-processes 1 -C builddir - uses: actions/upload-artifact@v4 if: failure() with: name: Test logs ${{ matrix.name }}, ${{ matrix.compiler }}, ${{ matrix.token }} path: | builddir/meson-logs/ builddir/tests/${{ matrix.token }}/p11prov-debug.log builddir/tests/${{ matrix.token }}/testvars builddir/tests/${{ matrix.token }}/openssl.cnf - name: Run tests with valgrind if : ( steps.nss-version-check.outputs.skiptest != 'true' ) run: | if [ "${{ matrix.compiler }}" = "gcc" ]; then meson test --num-processes 1 -C builddir --setup=valgrind fi - uses: actions/upload-artifact@v4 if: failure() with: name: Test valgrind logs ${{ matrix.name }}, ${{ matrix.compiler }}, ${{ matrix.token }} path: | builddir/meson-logs/ builddir/tests/${{ matrix.token }}/p11prov-debug.log builddir/tests/${{ matrix.token }}/testvars builddir/tests/${{ matrix.token }}/openssl.cnf - name: Run tests in FIPS Mode (on CentOS + gcc only) if : ( steps.nss-version-check.outputs.skiptest != 'true' ) run: | if [ "${{ matrix.compiler }}" = "gcc" -a \( "${{ matrix.name }}" = "centos9" -o "${{ matrix.name }}" = "centos10" \) ]; then OPENSSL_FORCE_FIPS_MODE=1 \ meson test --num-processes 1 -C builddir fi - uses: actions/upload-artifact@v4 if: failure() with: name: Test FIPS Mode logs ${{ matrix.name }}, ${{ matrix.compiler }}, ${{ matrix.token }} path: | builddir/meson-logs/ builddir/tests/${{ matrix.token }}/p11prov-debug.log builddir/tests/${{ matrix.token }}/testvars builddir/tests/${{ matrix.token }}/openssl.cnf build-macos: name: CI with software token runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [macos-14] token: [softokn] steps: - name: Install Dependencies run: | brew update brew install \ meson \ openssl@3 \ opensc \ p11-kit \ six if [ "${{ matrix.token }}" = "softokn" ]; then brew install nss elif [ "${{ matrix.token }}" = "softhsm" ]; then brew install softhsm fi - name: Checkout Repository uses: actions/checkout@v4 - name: Setup run: | git config --global --add safe.directory \ /__w/pkcs11-provider/pkcs11-provider git submodule update --init export PKG_CONFIG_PATH=$(brew --prefix openssl@3)/lib/pkgconfig export PATH=$(brew --prefix openssl@3)/bin:$PATH CC=clang meson setup builddir - name: Build and Test run: | export PATH=$(brew --prefix openssl@3)/bin:$PATH meson compile -j$(sysctl -n hw.ncpu || echo 2) -C builddir meson test --num-processes 1 -C builddir - uses: actions/upload-artifact@v4 if: failure() with: name: Test logs on macOS-14 with ${{ matrix.token }} path: | builddir/meson-logs/* builddir/tests/*.log builddir/tests/${{ matrix.token }}/p11prov-debug.log builddir/tests/${{ matrix.token }}/testvars builddir/tests/${{ matrix.token }}/openssl.cnf pkcs11-provider-1.0/.github/workflows/coverity-scan.yml000066400000000000000000000112071475270623700232300ustar00rootroot00000000000000--- name: Coverity Scan on: pull_request_target: branches: ["main"] types: - synchronize - labeled schedule: - cron: '41 3 * * 0' jobs: scheduled: if: ${{ github.event_name == 'schedule' }} name: Recurrent Coverity Scan runs-on: ubuntu-22.04 container: fedora:latest steps: - name: Install Dependencies run: | dnf -y install git gcc meson pkgconf-pkg-config \ openssl-devel openssl \ nss-softokn nss-tools nss-softokn-devel - name: Checkout Repository uses: actions/checkout@v4 - name: Setup run: | meson setup builddir env: CC: gcc - name: Check for changes run: | echo "RUN_COV=0" >> $GITHUB_ENV; git config --global --add safe.directory \ /__w/pkcs11-provider/pkcs11-provider DIFF=`git log --since=1week | wc -l` if [ x${DIFF} != "x0" ]; then echo "RUN_COV=1" >> $GITHUB_ENV; fi - name: Coverity Scan if: env.RUN_COV == 1 uses: vapier/coverity-scan-action@v1 with: project: "PKCS%2311+Provider" email: ${{ secrets.COVERITY_SCAN_EMAIL }} token: ${{ secrets.COVERITY_SCAN_TOKEN }} on-labeled-pr: if: ${{ contains(github.event.action, 'labeled') && contains(github.event.*.labels.*.name, 'covscan') }} name: Coverity Scan on PR runs-on: ubuntu-latest permissions: pull-requests: write container: fedora:latest steps: - name: Install Dependencies run: | dnf -y install git gcc meson pkgconf-pkg-config \ openssl-devel openssl \ nss-softokn nss-tools nss-softokn-devel \ gh - name: Checkout Repository uses: actions/checkout@v4 with: ref: ${{github.event.pull_request.head.sha}} - name: Setup run: | meson setup builddir env: CC: gcc - name: Coverity Scan uses: vapier/coverity-scan-action@v1 with: project: "PKCS%2311+Provider" email: ${{ secrets.COVERITY_SCAN_EMAIL }} token: ${{ secrets.COVERITY_SCAN_TOKEN }} - name: Remove Label if: always() env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} NUMBER: ${{ github.event.number }} run: gh pr edit "$NUMBER" --remove-label "covscan" on-no-covscan-labeled-pr: if: ${{ contains(github.event.action, 'labeled') && contains(github.event.*.labels.*.name, 'covscan-ok') }} name: Coverity Scan on PR runs-on: ubuntu-latest steps: - name: Coverity Scan Marked Successful run: echo "Dummy action to report all ok and mark covscan as handled" on-synchronize-no-source-changes: if: ${{ contains(github.event.action, 'synchronize') && ! contains(github.event.*.labels.*.name, 'covscan-ok') }} name: Coverity Scan on PR runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Check changed files id: changed-sources uses: tj-actions/changed-files@v44 with: files: | src/** - name: Coverity Scan not needed if: steps.changed-sources.outputs.any_changed == 'false' run: | echo "No Source files changed, no covscan needed" - name: Coverity Scan is needed if: steps.changed-sources.outputs.any_changed == 'true' run: | echo "Source files changed, covscan is needed" on-synchronize-covscan-ok: if: ${{ contains(github.event.action, 'synchronize') && contains(github.event.*.labels.*.name, 'covscan-ok') }} name: Coverity Scan on PR runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Check changed files id: changed-sources uses: tj-actions/changed-files@v44 with: base_sha: ${{ github.event.before }} files: | src/** continue-on-error: true - name: Coverity Scan not needed if: ${{ steps.changed-sources.outcome == 'success' && steps.changed-sources.outputs.any_changed == 'false' }} run: echo "Dummy action to report all ok and mark covscan as handled" - name: Coverity Scan is needed if: ${{ steps.changed-sources.outcome == 'failure' || steps.changed-sources.outputs.any_changed == 'true' }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} GH_REPO: ${{ github.repository }} NUMBER: ${{ github.event.number }} run: | gh pr edit "$NUMBER" --remove-label "covscan" false pkcs11-provider-1.0/.github/workflows/distcheck.yml000066400000000000000000000042631475270623700224070ustar00rootroot00000000000000--- name: Distribution checks on: pull_request: branches: ["main"] jobs: distcheck: name: Test make distcheck and RPM Build runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: name: [fedora, debian, centos] include: - name: fedora container: fedora:latest - name: debian container: debian:sid - name: centos container: quay.io/centos/centos:stream9 container: ${{ matrix.container }} steps: - name: Install Dependencies run: | if [ "${{ matrix.name }}" = centos ]; then dnf_opts="--enablerepo=crb" fi if [ -f /etc/redhat-release ]; then dnf -y install $dnf_opts \ git gcc meson expect python3 python3-six which \ pkgconf-pkg-config openssl-devel openssl xz \ nss-softokn nss-tools nss-softokn-devel \ softhsm opensc p11-kit-devel p11-kit-server \ rpm-build nss-devel gnutls-utils elif [ -f /etc/debian_version ]; then apt-get -q update apt-get -yq install git gcc meson expect \ pkg-config libssl-dev openssl \ xz-utils libnss3 libnss3-tools libnss3-dev \ softhsm2 opensc p11-kit libp11-kit-dev p11-kit-modules \ gnutls-bin fi - name: Checkout Repository uses: actions/checkout@v4 - name: Setup run: | git config --global --add safe.directory \ /__w/pkcs11-provider/pkcs11-provider git submodule update --init meson setup builddir - name: Distcheck run: | git config --global --add safe.directory \ /__w/pkcs11-provider/pkcs11-provider git ls-files meson.build meson dist --no-tests -C builddir - name: RPM Build if: ${{ matrix.name == 'fedora' }} run: | mkdir -p rpmbuild/SOURCES cp builddir/meson-dist/pkcs11-provider*tar.xz rpmbuild/SOURCES/ rpmbuild --define "_topdir $PWD/rpmbuild" -ba \ packaging/pkcs11-provider.spec pkcs11-provider-1.0/.github/workflows/integration.yml000066400000000000000000000062131475270623700227660ustar00rootroot00000000000000--- name: Integration tests on: push: branches: ["main"] pull_request: branches: ["main"] jobs: test-libssh-httpd: runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: test: [libssh, httpd] name: ${{ matrix.test }} container: fedora:latest env: PKCS11_MODULE: /usr/lib64/ossl-modules/pkcs11.so steps: - name: Get Date for DNF cache entry id: get-date run: | echo "date=$(/bin/date -u "+%Y%V")" >> $GITHUB_OUTPUT shell: bash - name: DNF cache uses: actions/cache@v4 with: path: | /var/cache/dnf key: ${{ runner.os }}-dnf-${{ steps.get-date.outputs.date }} - name: Install Build Requirements run: dnf -y install gcc git meson openssl-devel - name: Checkout Repository uses: actions/checkout@v4 - name: Setup, Build and Install pkcs11-provider run: | meson setup -Dlibdir=/usr/lib64 builddir meson compile -C builddir meson install -C builddir - name: Test ${{ matrix.test }} with softhsm run: | pushd tests/integration && bash -e ${{ matrix.test }}.sh test-bind: name: bind runs-on: ubuntu-22.04 container: fedora:latest steps: - name: Get Date for DNF cache entry id: get-date run: | echo "date=$(/bin/date -u "+%Y%V")" >> $GITHUB_OUTPUT shell: bash - name: DNF cache uses: actions/cache@v4 with: path: | /var/cache/dnf key: ${{ runner.os }}-dnf-${{ steps.get-date.outputs.date }} - name: Install Dependencies run: | dnf -y install clang git meson cargo expect pkgconf-pkg-config \ openssl-devel openssl opensc p11-kit-devel gnutls-utils \ gcc g++ sqlite-devel httpd bind9-next softhsm - name: Checkout Repository uses: actions/checkout@v4 - name: Get Kryoptic id: kryoptic_setup run: | git clone https://github.com/latchset/kryoptic.git cd kryoptic echo "KRYOPTIC=${PWD}" >> "$GITHUB_OUTPUT" - name: Generate lock file run: | cd kryoptic cargo generate-lockfile - name: Cache Rust dependencies uses: actions/cache@v4 with: path: | ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ kryoptic/target/ key: ${{ runner.os }}-cargo-${{ hashFiles('kryoptic/**/Cargo.lock') }} - name: Build Kryoptic run: | cd kryoptic cargo build --features dynamic,standard - name: Setup, Build and Install pkcs11-provider run: | meson setup -Dlibdir=/usr/lib64 builddir meson compile -C builddir meson install -C builddir - name: Test bind with kryoptic env: PKCS11_MODULE: /usr/lib64/ossl-modules/pkcs11.so KRYOPTIC: ${{ steps.kryoptic_setup.outputs.KRYOPTIC }} run: | pushd tests/integration && bash -e bind.sh kryoptic ; popd pkcs11-provider-1.0/.github/workflows/kryoptic.yml000066400000000000000000000050021475270623700223020ustar00rootroot00000000000000--- name: Kryoptic on: push: branches: ["main"] pull_request: branches: ["main"] jobs: build: name: CI with kryoptic token runs-on: ubuntu-22.04 container: fedora:latest steps: - name: Get Date for DNF cache entry id: get-date run: | echo "date=$(/bin/date -u "+%Y%V")" >> $GITHUB_OUTPUT shell: bash - name: DNF cache uses: actions/cache@v4 with: path: | /var/cache/dnf key: ${{ runner.os }}-dnf-${{ steps.get-date.outputs.date }} - name: Install Dependencies run: | dnf -y install clang git meson cargo expect pkgconf-pkg-config \ openssl-devel openssl opensc p11-kit-devel gnutls-utils \ gcc g++ sqlite-devel python3-six which - name: Checkout Repository uses: actions/checkout@v4 - name: Get Kryoptic id: kryoptic_setup run: | git clone https://github.com/latchset/kryoptic.git cd kryoptic echo "KRYOPTIC=${PWD}" >> "$GITHUB_OUTPUT" - name: Generate lock file run: | cd kryoptic cargo generate-lockfile - name: Cache Rust dependencies uses: actions/cache@v4 with: path: | ~/.cargo/bin/ ~/.cargo/registry/index/ ~/.cargo/registry/cache/ ~/.cargo/git/db/ kryoptic/target/ key: ${{ runner.os }}-cargo-${{ hashFiles('kryoptic/**/Cargo.lock') }} - name: Build Kryoptic run: | cd kryoptic cargo build --features dynamic,standard,nssdb cargo test --features dynamic,standard,nssdb | tee testout.log 2>&1 grep -q "0 failed" testout.log - name: Setup run: | git config --global --add safe.directory \ /__w/pkcs11-provider/pkcs11-provider git submodule update --init meson setup builddir - name: Build run: meson compile -C builddir - name: Test env: KRYOPTIC: ${{ steps.kryoptic_setup.outputs.KRYOPTIC }} run: meson test --num-processes 1 -C builddir - uses: actions/upload-artifact@v4 if: failure() with: name: Test logs kryoptic path: | builddir/meson-logs/ builddir/tests/kryoptic*/p11prov-debug.log builddir/tests/kryoptic*/testvars builddir/tests/kryoptic*/openssl.cnf builddir/tests/*.log pkcs11-provider-1.0/.github/workflows/reuse.yml000066400000000000000000000003321475270623700215620ustar00rootroot00000000000000--- name: REUSE Compliance Check on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: REUSE Compliance Check uses: fsfe/reuse-action@v1 pkcs11-provider-1.0/.github/workflows/scan-build.yml000066400000000000000000000013611475270623700224630ustar00rootroot00000000000000--- name: Scan Build on: pull_request: branches: ["main"] jobs: build: name: CI with softoken runs-on: ubuntu-22.04 container: fedora:latest steps: - name: Install Dependencies run: | dnf -y install $COMPILER meson pkgconf-pkg-config \ git openssl-devel clang-analyzer - uses: actions/checkout@v4 name: Checkout Repository - name: Setup run: | meson setup builddir - name: Scan Build run: | SCANBUILD=$PWD/.github/scan-build.sh ninja -C builddir scan-build - uses: actions/upload-artifact@v4 if: failure() with: name: Scan Build logs path: | builddir/meson-logs/scanbuild/ pkcs11-provider-1.0/.github/workflows/shellcheck.yml000066400000000000000000000016111475270623700225450ustar00rootroot00000000000000--- name: Shellcheck permissions: {} on: push: branches: ["main"] pull_request: branches: ["main"] jobs: shellcheck: name: Shellcheck runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Run ShellCheck uses: ludeeus/action-shellcheck@master with: additional_files: >- tbasic tcerts tdemoca tdigest tecc tecdh tecxc tedwards test-wrapper thkdf toaepsha2 top_state tpem_encoder tpubkey trand trsapss ttls turi check_together: 'yes' env: # The expressions in the ossl macro are not expanded # We use tests as default source path SHELLCHECK_OPTS: -e SC2016 -P tests pkcs11-provider-1.0/.github/workflows/style.yml000066400000000000000000000024331475270623700216030ustar00rootroot00000000000000--- name: Check Style on: pull_request: branches: ["main"] jobs: build: name: Check Style runs-on: ubuntu-22.04 container: fedora:latest steps: - name: Install Dependencies run: | dnf -y install gcc meson pkgconf-pkg-config \ git openssl-devel clang-tools-extra \ python3-pip codespell - name: Checkout Repository uses: actions/checkout@v4 - name: Setup if: ${{ github.event.pull_request.base.sha }} run: | git config --global --add safe.directory \ /__w/pkcs11-provider/pkcs11-provider git fetch origin main ${{ github.event.pull_request.base.sha }} - name: Generate Makefile run: | meson setup builddir - name: Run Clang Tidy run: | run-clang-tidy \ -checks=-*,readability-braces-around-statements \ -config "{WarningsAsErrors: '*'}" \ -header-filter "src/pkcs11.h" \ -quiet -p builddir - name: Check the Style run: make check-style || (make check-style-show; exit -1) - name: Check spelling run: codespell --ignore-words-list="sorce,clen,adin" *.md Makefile \ meson.build meson_options.txt src tests -S src/pkcs11.h pkcs11-provider-1.0/.gitignore000066400000000000000000000011231475270623700163060ustar00rootroot00000000000000# project-specific ignore patterns tests/openssl.cnf tests/openssl.cnf.softhsm tests/softhsm tests/softokn tests/kryoptic tests/kryoptic.nss tests/tdigests tests/tdigest_dupctx tests/tsession tests/tgenkey tests/treadkeys tests/pinfile.txt tests/*.log tests/*.trs tests/pincache tests/tfork tests/tfork_deadlock tests/tlsctx tests/tcmpkeys /pkcs11-provider-?.?/ /pkcs11-provider-?.?.tar.?z # generic ignore patterns (c, autotools, etc) *.o *~ test-driver tags .tags !tags/ TAGS .TAGS !TAGS/ gtags.files GTAGS GRTAGS GPATH GSYMS cscope.files cscope.out cscope.in.out cscope.po.out __pycache__/ pkcs11-provider-1.0/.gitmodules000066400000000000000000000004401475270623700164740ustar00rootroot00000000000000[submodule "tlsfuzzer"] path = tlsfuzzer url = https://github.com/tlsfuzzer/tlsfuzzer.git [submodule "python-ecdsa"] path = python-ecdsa url = https://github.com/tlsfuzzer/python-ecdsa.git [submodule "tlslite-ng"] path = tlslite-ng url = https://github.com/tlsfuzzer/tlslite-ng.git pkcs11-provider-1.0/.reuse/000077500000000000000000000000001475270623700155225ustar00rootroot00000000000000pkcs11-provider-1.0/.reuse/dep5000066400000000000000000000022421475270623700163020ustar00rootroot00000000000000Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: PKCS#11 Provider Upstream-Contact: Simo Sorce Source: https://github.com/latchset/pkcs11-provider/ # # Build system, data files from tests, and misc cruft # Files: .github/* .gitignore .gitmodules Makefile meson.build meson_options.txt *.md src/meson.build src/provider.map src/*.gen.c tests/README tests/openssl.cnf.in tests/explicit_ec.* tests/meson.build .clang-format .clang-format-ignore packaging/pkcs11-provider.spec packaging/sbom.cdx.json docs/* tests/lsan.supp tools/openssl*.cnf tests/*.pem tests/cert.json.in tests/cert.json.rsa.in tests/cert.json.rsapss.in tests/cert.json.ecdsa.in tests/cert.json.ed25519.in tests/cert.json.ed448.in scripts/clean-dist.sh Copyright: (C) 2022 - 2024 Simo Sorce License: Apache-2.0 # # Public Domain PKCS#11 headers # Files: src/pkcs11.h Copyright: 2023 Public Domain License: LicenseRef-Public-Domain-PKCS11-Headers pkcs11-provider-1.0/AUTHORS000066400000000000000000000000001475270623700153570ustar00rootroot00000000000000pkcs11-provider-1.0/BUILD.md000066400000000000000000000024141475270623700155030ustar00rootroot00000000000000## Build & Installation ### Prerequisites This package requires the following: - OpenSSL 3.0.7+ libraries and development headers - OpenSSL tools (for testing) - NSS softoken, tools and development headers (for testing) - a C compiler that supports at least C11 semantics - meson - pkg-config - p11-kit, p11-kit-server, p11-kit-devel, opensc and softhsm (for testing) - Kryoptic softoken (for testing) ### Build The usual command to build are: - `meson setup builddir` - `meson compile -C builddir` - `meson test -C builddir` To link with OpenSSL installed in a custom path, set `PKG_CONFIG_PATH`, or `CFLAGS`/`LDFLAGS` envvars accordingly at the `meson setup` step. For example, let's assume OpenSSL is installed under an absolute path `$OPENSSL_DIR`. If you rely on pkg-config, point `PKG_CONFIG_PATH` to a directory where `libcrypto.pc` or `openssl.pc` can be found. - `PKG_CONFIG_PATH="$OPENSSL_DIR/lib64/pkgconfig" meson setup builddir` Otherwise, you can set `CFLAGS`/`LDFLAGS`: - `CFLAGS="-I$OPENSSL_DIR/include" LDFLAGS="-L$OPENSSL_DIR/lib64" meson setup builddir` ### Installation The usual command to install is: - `meson install -C builddir` Or simply copy the `src/pkcs11.so` (or `src/pkcs11.dylib` on Mac) in the appropriate directory for your OpenSSL installation. pkcs11-provider-1.0/CODE_OF_CONDUCT.md000066400000000000000000000121401475270623700171160ustar00rootroot00000000000000# Contributor Covenant Code of Conduct ## Our Pledge We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socioeconomic status, nationality, personal appearance, race, religion, or sexual identity and orientation. We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community. ## Our Standards Examples of behavior that contributes to a positive environment for our community include: * Demonstrating empathy and kindness toward other people * Being respectful of differing opinions, viewpoints, and experiences * Giving and gracefully accepting constructive feedback * Accepting responsibility and apologizing to those affected by our mistakes, and learning from the experience * Focusing on what is best not just for us as individuals, but for the overall community Examples of unacceptable behavior include: * The use of sexualized language or imagery, and sexual attention or advances of any kind * Trolling, insulting or derogatory comments, and personal or political attacks * Public or private harassment * Publishing others' private information, such as a physical or email address, without their explicit permission * Other conduct which could reasonably be considered inappropriate in a professional setting ## Enforcement Responsibilities Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful. Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate. ## Scope This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at simo@redhat.com. All complaints will be reviewed and investigated promptly and fairly. All community leaders are obligated to respect the privacy and security of the reporter of any incident. ## Enforcement Guidelines Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct: ### 1. Correction **Community Impact**: Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community. **Consequence**: A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested. ### 2. Warning **Community Impact**: A violation through a single incident or series of actions. **Consequence**: A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban. ### 3. Temporary Ban **Community Impact**: A serious violation of community standards, including sustained inappropriate behavior. **Consequence**: A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban. ### 4. Permanent Ban **Community Impact**: Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals. **Consequence**: A permanent ban from any sort of public interaction within the community. ## Attribution This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 2.0, available at https://www.contributor-covenant.org/version/2/0/code_of_conduct.html. Community Impact Guidelines were inspired by [Mozilla's code of conduct enforcement ladder](https://github.com/mozilla/diversity). [homepage]: https://www.contributor-covenant.org For answers to common questions about this code of conduct, see the FAQ at https://www.contributor-covenant.org/faq. Translations are available at https://www.contributor-covenant.org/translations. pkcs11-provider-1.0/CONTRIBUTING.md000066400000000000000000000051471475270623700165610ustar00rootroot00000000000000# Contributing to pkcs11-provider :+1::tada: First off, thanks for considering to contribute! :tada::+1: ## Code of Conduct This project and everyone participating in it is governed by our [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to abide by the code. ## What should I know before I get started? If you want to contribute code you need to understand the [PKCS#11](https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=pkcs11) Specifications and the OpenSSL 3.0 provider APIs. Useful links to learn about these are: - [PKCS#11 2.4 Base Specification](https://docs.oasis-open.org/pkcs11/pkcs11-base/v2.40/pkcs11-base-v2.40.html) - [PKCS#11 3.1 Spec](https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/csd01/pkcs11-spec-v3.1-csd01.html) - [Providers Corner](https://github.com/provider-corner) - [OpenSC wiki](https://github.com/OpenSC/OpenSC/wiki) ## How Can I Contribute? ### Reporting Bugs Before reporting bugs please insure that you have checked the latest changes to see if a bug has already been reported and corrected. Peruse your distribution repositories and bug report system to find out if the bug has been reported there first. * Provide a description of the behavior experienced, as well as what you expected. * Provide that make/model/version of the token used, including for software tokens. * provide steps to repdouce the issue * Use a clear and descriptive title ### Suggesting Enhancements Before suggesting an enhancement please check if it has been reported and accept/denied before. * Include a clear description of what benefit this enhancemnt would provide and its impact * If it affects a specific token please provide a statament on whether you are willing to test changes and report results * Use a clear and descriptive title ### Contributing code We accept code contributions via Pull Requests. * Use a clear and descriptive title * Unless it is obvious provide a description of the contribution about why and what is being proposed. * Split your submission in logical, self contained commits. - Ideally each commit compile and pass tests on its own. - Each commit should have a commit message that describes the contents. * for whole new features please add tests that exercise it. * Use make check to test your code * Use make check-style to verify your submission * Monitor the CI jobs and fix issues proactively * We use a rebase workflow - You can submit "fixup" commits if changes are complex in order to go through the review. - You are expected to rebase and provide logical commits before final merging. * Each commit should be Signed-off-by the author. pkcs11-provider-1.0/COPYING000066400000000000000000000010541475270623700153540ustar00rootroot00000000000000Copyright 2022 simo@redhat.com Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. pkcs11-provider-1.0/ChangeLog000066400000000000000000000000001475270623700160610ustar00rootroot00000000000000pkcs11-provider-1.0/HOWTO.md000066400000000000000000000053561475270623700155540ustar00rootroot00000000000000## How To use the PKCS#11 provider ### Configuration via openssl.cnf Once you have installed the module you need to change OpenSSL's configuration to be able to load the provider and a pkcs#11 driver. The specific pkcs#11 driver name will depend on what token you are using. In openssl.cnf add the following section: ``` [pkcs11_sect] module = /path/to/pkcs11.so pkcs11-module-path = /path/to/pkcs11-driver.so activate = 1 ``` Optionally add a path to a file containing the user's PIN: ``` pkcs11-module-token-pin = file:/path/to/userpin.txt ``` If a user PIN is not provided it should be requested interactively by most openssl utilities. Some pkcs11-drivers accept/require an initialization string (for example NSS softokn), if that is needed add it as follow: ``` pkcs11-module-init-args = ``` Once the section is properly constructed add the following statement to the provider section. If a provider section does not exist make sure to create one with all the needed providers (at least the default provider will be needed - remember to activate it, otherwise the _openssl_ command will not behave correctly): ``` [openssl_init] providers = provider_sect [provider_sect] default = default_sect pkcs11 = pkcs11_sect [default_sect] activate = 1 ``` See CONFIG(5OSSL) manpage for more information on the openssl.cnf file. ### Driver specification via environment variable In some cases it may be preferable to specify the pkcs11-driver module via an environment variable instead of via openssl.cnf file. This may be useful when the system can use multiple different tokens and the user/admin wants to start different applications pointing them at distinct tokens. If this is preferred, remove the pkcs11-module-path directive from openssl.cnf and instead insure the driver is specified via the PKCS11_PROVIDER_MODULE environment variable. Example: ``` $ export PKCS11_PROVIDER_MODULE=/path/to/pkcs11-driver.so $ openssl pkey -in pkcs11:id=%01 -pubin -pubout -text ``` ### Specifying keys When the pkcs11-provider is in use keys are specified using pkcs11 URIs as defined in RFC7512. In general keys are either identified by a percent-encoded binary ID, or by a label (called "object" in pkcs11 URIs). The command `pkcs11-tool --module /path/to/pkcs11-driver.so --list-objects` can be used to find identifiers for your keys. Example: ``` pkcs11:object=my-rsa-key;type=public ``` A pkcs11 URI can also specify a User PIN used to unlock the key, this can be used instead of storing the PIN in the openssl.cnf file or using interactive prompting. ### Key generation On some tokens it is possible to create on the token using openssl with non-standard parameters. Nevertheless, we recommend using tools working with pkcs11 directly such as p11tool. pkcs11-provider-1.0/LICENSES/000077500000000000000000000000001475270623700155265ustar00rootroot00000000000000pkcs11-provider-1.0/LICENSES/Apache-2.0.txt000066400000000000000000000261361475270623700177550ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. pkcs11-provider-1.0/LICENSES/LicenseRef-Public-Domain-PKCS11-Headers.txt000066400000000000000000000001221475270623700251730ustar00rootroot00000000000000This file is in the Public Domain See https://github.com/latchset/pkcs11-headers pkcs11-provider-1.0/Makefile000066400000000000000000000030551475270623700157640ustar00rootroot00000000000000.PHONY: all check check-style check-style-show check-style-fix clean generate-code generate-docs all: if [ ! -d "builddir" ]; then \ meson setup builddir; \ fi; \ meson compile -C builddir pkcs11 check: meson test -C builddir clean: rm -rf builddir check-style: @lines=`git diff -U0 --no-color --relative origin/main -- ':!src/pkcs11.h' | clang-format-diff -p1 |wc -l`; \ if [ "$$lines" != "0" ]; then \ echo "Coding Style issues detected"; \ exit 1; \ else \ echo "Coding Styles checks out"; \ fi check-style-show: git diff -U0 --no-color --relative origin/main -- ':!src/pkcs11.h' | clang-format-diff -p1 check-style-fix: git diff -U0 --no-color --relative origin/main -- ':!src/pkcs11.h' | clang-format-diff -i -p1 generate-code: for pfile in src/*.pre; do \ gfile=`echo $${pfile} | sed s/\.pre/\.gen\.c/`; \ echo "/* DO NOT EDIT, autogenerated from $${pfile} */" > "$${gfile}"; \ echo "/* Modify $${pfile} then run make generate-code */" >> "$${gfile}"; \ cat $${pfile} | $(CC) -E - | grep -v "^#" > "$${gfile}.tmp"; \ sed -i -n -e '/^BEGIN:$$/,$$p' "$${gfile}.tmp"; \ sed -i 's/^BEGIN:$$//' "$${gfile}.tmp"; \ cat "$${gfile}.tmp" >> $${gfile}; \ clang-format -i --verbose "$${gfile}"; \ rm "$${gfile}.tmp"; \ done generate-docs: for mdfile in docs/*.md; do \ echo "Processing $${mdfile}"; \ manfile=`echo $${mdfile} | sed s/\.md//`; \ pandoc --standalone --to man $${mdfile} -o $${manfile}; \ done dist: rm -fr distdir meson setup distdir meson compile -C distdir pkcs11 meson test -C distdir meson dist -C distdir pkcs11-provider-1.0/NEWS000066400000000000000000000000001475270623700150060ustar00rootroot00000000000000pkcs11-provider-1.0/README000077700000000000000000000000001475270623700164532README.mdustar00rootroot00000000000000pkcs11-provider-1.0/README.md000066400000000000000000000024071475270623700156030ustar00rootroot00000000000000[![Build](https://github.com/latchset/pkcs11-provider/actions/workflows/build.yml/badge.svg)](https://github.com/latchset/pkcs11-provider/actions/workflows/build.yml) [![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0) # pkcs11-provider This is an OpenSSL 3.x provider to access Hardware and Software Tokens using the PKCS#11 Cryptographic Token Interface. Access to tokens depends on loading an appropriate PKCS#11 driver that knows how to talk to the specific token. The PKCS#11 provider is a connector that allows OpenSSL to make proper use of such drivers. This code targets PKCS#11 version 3.1 but is backwards compatible to version 3.0 and 2.40 as well. To report Security Vulnerabilities, please use the "Report a Security Vulnerability" template in the issues reporting page. ### Installation See [BUILD](BUILD.md) for more details about building and installing the provider. ### Usage Configuration directives for the provider are documented in [provider-pkcs11(7)](docs/provider-pkcs11.7.md) man page. Example configurations and basic use cases can be found in [HOWTO](HOWTO.md). ### Notes * [PKCS #11 Specification Version 3.1](https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/pkcs11-spec-v3.1.html) pkcs11-provider-1.0/SECURITY.md000066400000000000000000000010201475270623700161030ustar00rootroot00000000000000# Security Policy ## Supported Versions None yet This table will specify which versions are supported: | Version | Supported | | ------- | ------------------ | | X.Y | :white_check_mark: | | X.Y | :x: | | ------- | ------------------ | ## Reporting a Vulnerability To report security vulnerabilities please either select the "Report a vulnerability" template from the "New issue" workflow, or email simo@redhat.com directly. Please DO NOT open a generic issue for security vulnerabilities. pkcs11-provider-1.0/docs/000077500000000000000000000000001475270623700152515ustar00rootroot00000000000000pkcs11-provider-1.0/docs/meson.build000066400000000000000000000000411475270623700174060ustar00rootroot00000000000000install_man('provider-pkcs11.7') pkcs11-provider-1.0/docs/provider-pkcs11.7000066400000000000000000000247531475270623700203060ustar00rootroot00000000000000.\" Automatically generated by Pandoc 3.1.11.1 .\" .TH "provider\-pkcs11" "7" "" "" "Configuration directives" .SH NAME pkcs11\-provider \- An OpenSSL provider that allows to directly interface with pkcs11 drivers. .SH DESCRIPTION Starting with version 3.0 the OpenSSL project introduced a new modular system to extend OpenSSL that replaces the deprecated Engines modules. .PP Providers(1) are loaded via configuration directives in the openssl configuration file (or directly loaded by applications). .PP The pkcs11 provider allows applications linked to openssl to use keys and cryptographic operations from a hardware or software token via their PKCS#11(2) driver and the use of pkcs11 URIs(3). .PP The pkcs11 provider can be configured to be automatically loaded via openssl.cnf .SH CONFIGURATION Configuration options recognized by the provider .SS pkcs11\-module\-path A file path to the pkcs11 driver to be used .PP Default: If compiled with p11\-kit defaults to its proxy driver, otherwise none. .PP NOTE: See also PKCS11_PROVIDER_MODULE in the environment variables section. .PP Example: .PP \f[CR]pkcs11\-module\-path = /usr/lib64/opensc\-pkcs11.so\f[R] .SS pkcs11\-module\-init\-args Non\-standard initialization arguments some pkcs11 driver may need. Generally not used, but some software tokens like NSS\[cq]s softokn require this. .PP Default: None .PP Example: .PP \f[CR]pkcs11\-module\-init\-args = configDir=/etc/pki/token\f[R] .SS pkcs11\-module\-token\-pin The user PIN to be used with the token. If a PIN is not set in configuration it can be asked interactively (if the application uses prompters), or it can be specified together with the key identifiers in the pkcs11 URI directly. When a file is specified the file must be a text file containing just the PIN on the first line and a terminator. .PP Default: None .PP Example: .PP \f[CR]pkcs11\-module\-token\-pin = file:/etc/pki/pin.txt\f[R] .IP .EX cat /etc/pki/pin.txt 123456 .EE .SS pkcs11\-module\-allow\-export Whether the pkcs11 provider will allow to export public keys through OpenSSL. OpenSSL often tries to export public keys from non\-default providers to the default provider, and then use OpenSSL own functions to handle whatever operation is associated with the public key. This option can be useful to force public key operations to be executed on the token, for example in case the pkcs11 is an accelerator that has better performance on signature checking or asymmetric encryption than OpenSSL\[cq]s code. .PP Default: 0 (Allow Export) .PP Example: .PP \f[CR]pkcs11\-module\-allow\-export = 1\f[R] (This disallows export of public keys) .SS pkcs11\-module\-cache\-keys Whether the pkcs11\-provider should ask the token to cache token keys in the session. This is used in some tokens as a performance optimizations. For example software tokens that store keys encrypted can keep a copy of the key in the session to speed up access. Or Networked HSMs that allow exporting key material can cache the key in the session instead of re\-requesting it over the network. .PP Two options are available: * true * false .PP Default: true (Note: if the token does not support session caching, then caching will be auto\-disabled after the first attempt) .PP Example: .PP \f[CR]pkcs11\-module\-cache\-keys = false\f[R] (Disable any attempt of caching keys in the session) .SS pkcs11\-module\-cache\-pins Whether the pkcs11\-provider should cache a pin entered interactively. This is useful to allow starting a service and providing the pin only manually, yet let the service perform multiple logins as needed, for example after forking. .PP Only one option is currently available: * cache: Caches the PIN .PP Default: unset (No caching) .PP Example: .PP \f[CR]pkcs11\-module\-cache\-pins = cache\f[R] (Will cache a pin that has been entered manually) .SS pkcs11\-module\-cache\-sessions Allows to tune how many pkcs11 sessions may be kept open and cached for rapid use. This parameter is adjusted based on the maximum number of sessions the token declares as supported. Note that the login session is always cached to keep the token operable. .PP Default: 5 .PP Example: .PP \f[CR]pkcs11\-module\-cache\-sessions = 0\f[R] (Disables caching) .SS pkcs11\-module\-login\-behavior Whether the pkcs11 provider will attempt to login to the token when a public key is being requested. .PP Three options are available: * auto: Try without but fallback to login behavior if no keys are found * always: Always login before trying to load public keys (this is required by some HSMs) * never: Never login for public keys .PP Default: \[lq]auto\[rq] .PP Example: .PP \f[CR]pkcs11\-module\-login\-behavior = always\f[R] (Always tries to login before loading public keys) .SS pkcs11\-module\-load\-behavior Whether the pkcs11\-provider immediately loads an initializes the pkcs11 module as soon as OpenSSL loads the provider (generally at application startup), or defer initialization until the first time a pkcs11 key is loaded (or some other operation explicitly requiring the pkcs11 provider is requested). .PP Only one option is available: * early: Loads the pkcs11 module immediately .PP Default: unset (Loads only at first use) .PP Example: .PP \f[CR]pkcs11\-module\-load\-behavior = early\f[R] (Loads pkcs11 module immediately at application startup) .SS pkcs11\-module\-quirks Workarounds that may be needed to deal with some tokens and cannot be autodetcted yet are not appropriate defaults. .SS no\-deinit It prevents de\-initing when OpenSSL winds down the provider. NOTE this option may leak memory and may cause some modules to misbehave if the application intentionally unloads and reloads them. .SS no\-operation\-state OpenSSL by default assumes contexts with operations in flight can be easily duplicated. That is only possible if the tokens support getting and setting the operation state. If the quirk is enabled the context duplication is not performed. .SS no\-session\-callbacks Some implementatations of PKCS11 don\[cq]t allow setting \f[CR]pApplication\f[R] and \f[CR]Notify\f[R] callback functions in \f[CR]C_OpenSession\f[R]. This option sets NULL values for both callbacks. .SS no\-allowed\-mechanisms Some implementatations of PKCS11 don\[cq]t support \f[CR]CKA_ALLOWED_MECHANISMS\f[R] attribute on keys. Setting this quirk prevents the provider from attempting to set and read this attribute. .PP Default: none .PP Example: .PP \f[CR]pkcs11\-module\-quirks = no\-deinit no\-operation\-state\f[R] (Disables deinitialization, blocks context duplication) .SS pkcs11\-module\-block\-operations Allows to block specific \[lq]provider operations\[rq] even if the token actually supports the necessary mechanisms. This is useful to work around cases where one wants to enforce use of the token for all operations by setting ?provider=pkcs11 in the default properties but wants an exception for a specific type of operation like digests. NOTE: some operations may depend on others or may be fundamental to the correct working of the provider, so not all configurations of this parameter will work. Use carefully. .PP Default: none .PP Example: \f[CR]pkcs11\-module\-block\-operations = digest\f[R] (Disables digest mechanisms, which will be instead routed to the OpenSSL default provider in most configurtions) .SS pkcs11\-module\-assume\-fips Assume the token used by the PKCS#11 module is FIPS certified. .PP Due to the incomplete specification for signalization of the certification from the pkcs11 modules, this can not be determined automatically. If you know your token is FIPS certified, you need to set this configuration option to true. Otherwise the pkcs11\-provider will not work in FIPS Mode. .PP Default: False .PP Example: .PP \f[CR]pkcs11\-module\-assume\-fips = true\f[R] .SH ENVIRONMENT VARIABLES Environment variables recognized by the provider .SS PKCS11_PROVIDER_MODULE This variable can be used to set a different pkcs11 driver to be used. It is useful when an application needs to use a different driver than the rest of the system. This environment variable \f[B]overrides\f[R] the pkcs11\-module\-path option sets in openssl.cnf .PP Example: .PP \f[CR]PKCS11_PROVIDER_MODULE = /usr/lib64/opensc\-pkcs11.so\f[R] .SS PKCS11_PROVIDER_DEBUG This variable can be set to obtain debug information. Two sub\-options can be specified: file, level .PP The normal debug_level is 1, if a higher level is provider then additional information (like all supported mechanism info for each slot) is printed in the specified debug file. The comma character separates options, and the colon character is used to separate an option and its value. There is no escape character, therefore the characters `,' and `:' cannot be used in values. .PP Examples: .PP \f[CR]PKCS11_PROVIDER_DEBUG=file:/tmp/debug.log\f[R] .PP \f[CR]PKCS11_PROVIDER_DEBUG=file:/dev/stderr,level:2\f[R] .SH USE IN OLDER APPLICATIONS (URIs in PEM files) It is strongly suggested to update applications to use the new OSSL_STORE API provided by OpenSSL 3.0 which accepts URIs to transparenly load keys from either files or any other supported mechanism including PKCS#11 URIs. .PP However, for those applications that cannot yet be changed, there is tool to generate a \[lq]wrapper\[rq] PEM file that contains the PKCS#11 URI needed to identify a key on the a token. .PP This PEM file can be loaded via the clasic methods used to parse PEM/DER representations of keys and will trigger the use of the pkcs11\-provider decoders when the provider is loaded. An error will be returned if the provider is not pre\-loaded or an older version of OpenSSL is used. .PP In tools/uri2pem.py there is a sample python script that can take a key URI and produce a PEM file that references it. Note that storing PINs within these PEM files is not secure. These files are not encrypted. .PP The follwing command can be used to list all keys on a token and print their identifying URI: .IP .EX openssl storeutl \-keys \-text pkcs11: .EE .SH EXAMPLES openssl.cnf: .IP .EX HOME = . # Use this in order to automatically load providers. openssl_conf = openssl_init [openssl_init] providers = provider_sect [provider_sect] default = default_sect pkcs11 = pkcs11_sect [default_sect] activate = 1 [pkcs11_sect] module = /usr/lib64/ossl\-modules/pkcs11.so pkcs11\-module\-path = /usr/lib64/pkcs11/vendor_pkcs11.so pkcs11\-module\-token\-pin = /etc/ssl/pinfile.txt activate = 1 .EE .SH SEE ALSO .IP "1." 3 PROVIDER(7) man page \- https://www.openssl.org/docs/manmaster/man7/provider.html .IP "2." 3 PKCS#11 Technical committe and standards \- https://www.oasis\-open.org/committees/tc_home.php?wg_abbrev=pkcs11 .IP "3." 3 PKCS#11 URI Scheme \- RFC 7512 \- https://www.rfc\-editor.org/rfc/rfc7512 pkcs11-provider-1.0/docs/provider-pkcs11.7.md000066400000000000000000000242061475270623700206760ustar00rootroot00000000000000% provider-pkcs11(7) | Configuration directives NAME ==== pkcs11-provider - An OpenSSL provider that allows to directly interface with pkcs11 drivers. DESCRIPTION =========== Starting with version 3.0 the OpenSSL project introduced a new modular system to extend OpenSSL that replaces the deprecated Engines modules. Providers(1) are loaded via configuration directives in the openssl configuration file (or directly loaded by applications). The pkcs11 provider allows applications linked to openssl to use keys and cryptographic operations from a hardware or software token via their PKCS#11(2) driver and the use of pkcs11 URIs(3). The pkcs11 provider can be configured to be automatically loaded via openssl.cnf CONFIGURATION ============= Configuration options recognized by the provider ## pkcs11-module-path A file path to the pkcs11 driver to be used Default: If compiled with p11-kit defaults to its proxy driver, otherwise none. NOTE: See also PKCS11_PROVIDER_MODULE in the environment variables section. Example: ```pkcs11-module-path = /usr/lib64/opensc-pkcs11.so``` ## pkcs11-module-init-args Non-standard initialization arguments some pkcs11 driver may need. Generally not used, but some software tokens like NSS's softokn require this. Default: None Example: ```pkcs11-module-init-args = configDir=/etc/pki/token``` ## pkcs11-module-token-pin The user PIN to be used with the token. If a PIN is not set in configuration it can be asked interactively (if the application uses prompters), or it can be specified together with the key identifiers in the pkcs11 URI directly. When a file is specified the file must be a text file containing just the PIN on the first line and a \n terminator. Default: None Example: ```pkcs11-module-token-pin = file:/etc/pki/pin.txt``` ``` cat /etc/pki/pin.txt 123456 ``` ## pkcs11-module-allow-export Whether the pkcs11 provider will allow to export public keys through OpenSSL. OpenSSL often tries to export public keys from non-default providers to the default provider, and then use OpenSSL own functions to handle whatever operation is associated with the public key. This option can be useful to force public key operations to be executed on the token, for example in case the pkcs11 is an accelerator that has better performance on signature checking or asymmetric encryption than OpenSSL's code. Default: 0 (Allow Export) Example: ```pkcs11-module-allow-export = 1``` (This disallows export of public keys) ## pkcs11-module-cache-keys Whether the pkcs11-provider should ask the token to cache token keys in the session. This is used in some tokens as a performance optimizations. For example software tokens that store keys encrypted can keep a copy of the key in the session to speed up access. Or Networked HSMs that allow exporting key material can cache the key in the session instead of re-requesting it over the network. Two options are available: * true * false Default: true (Note: if the token does not support session caching, then caching will be auto-disabled after the first attempt) Example: ```pkcs11-module-cache-keys = false``` (Disable any attempt of caching keys in the session) ## pkcs11-module-cache-pins Whether the pkcs11-provider should cache a pin entered interactively. This is useful to allow starting a service and providing the pin only manually, yet let the service perform multiple logins as needed, for example after forking. Only one option is currently available: * cache: Caches the PIN Default: unset (No caching) Example: ```pkcs11-module-cache-pins = cache``` (Will cache a pin that has been entered manually) ## pkcs11-module-cache-sessions Allows to tune how many pkcs11 sessions may be kept open and cached for rapid use. This parameter is adjusted based on the maximum number of sessions the token declares as supported. Note that the login session is always cached to keep the token operable. Default: 5 Example: ```pkcs11-module-cache-sessions = 0``` (Disables caching) ## pkcs11-module-login-behavior Whether the pkcs11 provider will attempt to login to the token when a public key is being requested. Three options are available: * auto: Try without but fallback to login behavior if no keys are found * always: Always login before trying to load public keys (this is required by some HSMs) * never: Never login for public keys Default: "auto" Example: ```pkcs11-module-login-behavior = always``` (Always tries to login before loading public keys) ## pkcs11-module-load-behavior Whether the pkcs11-provider immediately loads an initializes the pkcs11 module as soon as OpenSSL loads the provider (generally at application startup), or defer initialization until the first time a pkcs11 key is loaded (or some other operation explicitly requiring the pkcs11 provider is requested). Only one option is available: * early: Loads the pkcs11 module immediately Default: unset (Loads only at first use) Example: ```pkcs11-module-load-behavior = early``` (Loads pkcs11 module immediately at application startup) ## pkcs11-module-quirks Workarounds that may be needed to deal with some tokens and cannot be autodetcted yet are not appropriate defaults. ### no-deinit It prevents de-initing when OpenSSL winds down the provider. NOTE this option may leak memory and may cause some modules to misbehave if the application intentionally unloads and reloads them. ### no-operation-state OpenSSL by default assumes contexts with operations in flight can be easily duplicated. That is only possible if the tokens support getting and setting the operation state. If the quirk is enabled the context duplication is not performed. ### no-session-callbacks Some implementatations of PKCS11 don't allow setting `pApplication` and `Notify` callback functions in `C_OpenSession`. This option sets NULL values for both callbacks. ### no-allowed-mechanisms Some implementatations of PKCS11 don't support `CKA_ALLOWED_MECHANISMS` attribute on keys. Setting this quirk prevents the provider from attempting to set and read this attribute. Default: none Example: ```pkcs11-module-quirks = no-deinit no-operation-state``` (Disables deinitialization, blocks context duplication) ## pkcs11-module-block-operations Allows to block specific "provider operations" even if the token actually supports the necessary mechanisms. This is useful to work around cases where one wants to enforce use of the token for all operations by setting ?provider=pkcs11 in the default properties but wants an exception for a specific type of operation like digests. NOTE: some operations may depend on others or may be fundamental to the correct working of the provider, so not all configurations of this parameter will work. Use carefully. Default: none Example: ```pkcs11-module-block-operations = digest``` (Disables digest mechanisms, which will be instead routed to the OpenSSL default provider in most configurtions) ## pkcs11-module-assume-fips Assume the token used by the PKCS#11 module is FIPS certified. Due to the incomplete specification for signalization of the certification from the pkcs11 modules, this can not be determined automatically. If you know your token is FIPS certified, you need to set this configuration option to true. Otherwise the pkcs11-provider will not work in FIPS Mode. Default: False Example: ```pkcs11-module-assume-fips = true``` ENVIRONMENT VARIABLES ===================== Environment variables recognized by the provider ## PKCS11_PROVIDER_MODULE This variable can be used to set a different pkcs11 driver to be used. It is useful when an application needs to use a different driver than the rest of the system. This environment variable **overrides** the pkcs11-module-path option sets in openssl.cnf Example: ```PKCS11_PROVIDER_MODULE = /usr/lib64/opensc-pkcs11.so``` ## PKCS11_PROVIDER_DEBUG This variable can be set to obtain debug information. Two sub-options can be specified: file, level The normal debug_level is 1, if a higher level is provider then additional information (like all supported mechanism info for each slot) is printed in the specified debug file. The comma character separates options, and the colon character is used to separate an option and its value. There is no escape character, therefore the characters ',' and ':' cannot be used in values. Examples: ```PKCS11_PROVIDER_DEBUG=file:/tmp/debug.log``` ```PKCS11_PROVIDER_DEBUG=file:/dev/stderr,level:2``` USE IN OLDER APPLICATIONS (URIs in PEM files) ============================================= It is strongly suggested to update applications to use the new OSSL_STORE API provided by OpenSSL 3.0 which accepts URIs to transparenly load keys from either files or any other supported mechanism including PKCS#11 URIs. However, for those applications that cannot yet be changed, there is tool to generate a "wrapper" PEM file that contains the PKCS#11 URI needed to identify a key on the a token. This PEM file can be loaded via the clasic methods used to parse PEM/DER representations of keys and will trigger the use of the pkcs11-provider decoders when the provider is loaded. An error will be returned if the provider is not pre-loaded or an older version of OpenSSL is used. In tools/uri2pem.py there is a sample python script that can take a key URI and produce a PEM file that references it. Note that storing PINs within these PEM files is not secure. These files are not encrypted. The follwing command can be used to list all keys on a token and print their identifying URI: openssl storeutl -keys -text pkcs11: EXAMPLES ======== openssl.cnf: HOME = . # Use this in order to automatically load providers. openssl_conf = openssl_init [openssl_init] providers = provider_sect [provider_sect] default = default_sect pkcs11 = pkcs11_sect [default_sect] activate = 1 [pkcs11_sect] module = /usr/lib64/ossl-modules/pkcs11.so pkcs11-module-path = /usr/lib64/pkcs11/vendor_pkcs11.so pkcs11-module-token-pin = /etc/ssl/pinfile.txt activate = 1 SEE ALSO ======== 1. PROVIDER(7) man page - https://www.openssl.org/docs/manmaster/man7/provider.html 2. PKCS#11 Technical committe and standards - https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=pkcs11 3. PKCS#11 URI Scheme - RFC 7512 - https://www.rfc-editor.org/rfc/rfc7512 pkcs11-provider-1.0/meson.build000066400000000000000000000047361475270623700164750ustar00rootroot00000000000000project( 'pkcs11-provider', 'c', version: '1.0', meson_version: '>= 0.57', default_options: ['c_std=c11'], ) version_arr = meson.project_version().split('.') major_version = version_arr[0].to_int() minor_version = version_arr[1].to_int() cc = meson.get_compiler('c') warning_c_args = [ '-Wwrite-strings', '-Wpointer-arith', '-Wno-missing-field-initializers', '-Wformat', '-Wshadow', # Temporarily disable unused parameter until the implementation is complete '-Wno-unused-parameter', # These should be always errors '-Werror=implicit-function-declaration', '-Werror=missing-prototypes', '-Werror=format-security', '-Werror=parentheses', '-Werror=implicit', '-Werror=strict-prototypes', ] extra_c_args = [ '-fno-strict-aliasing', '-fno-delete-null-pointer-checks', '-fdiagnostics-show-option', ] add_project_arguments(cc.get_supported_arguments(warning_c_args + extra_c_args), language: 'c') configinc = include_directories('.') conf = configuration_data() conf.set_quoted('PACKAGE_NAME', meson.project_name()) conf.set('PACKAGE_MAJOR', major_version) conf.set('PACKAGE_MINOR', minor_version) libcrypto = dependency('libcrypto', version: '>= 3.0.7') provider_path = libcrypto.get_variable(pkgconfig: 'modulesdir') libssl = dependency('libssl', version: '>= 3.0.7') host_system = host_machine.system() if host_system == 'windows' shlext = '.dll' elif host_system == 'darwin' # On macOS, loadable modules typically use .so as filename extension, but # both NSS softokn and OpenSSL providers ignore this rule and use .dylib for # loadable modules anyway. Note that p11-kit correctly uses .so, though, so # be careful when using this variable, as it might not be correct on macOS. shlext = '.dylib' else shlext = '.so' endif if host_machine.endian() == 'big' conf.set('WORDS_BIGENDIAN', 1) endif p11_kit = dependency('p11-kit-1', required: false) default_pkcs11_module = get_option('default_pkcs11_module') if default_pkcs11_module == '' and p11_kit.found() default_pkcs11_module = p11_kit.get_variable(pkgconfig: 'proxy_module') endif if default_pkcs11_module != '' conf.set_quoted('DEFAULT_PKCS11_MODULE', default_pkcs11_module) endif headers = [ 'dlfcn.h', ] foreach h : headers if cc.has_header(h) conf.set('HAVE_' + h.underscorify().to_upper(), 1) endif endforeach configure_file(output: 'config.h', configuration: conf) meson.add_dist_script('scripts/clean-dist.sh') subdir('src') subdir('docs') subdir('tests') pkcs11-provider-1.0/meson_options.txt000066400000000000000000000005671475270623700177660ustar00rootroot00000000000000option('preload_libasan', type: 'string', value: 'no', description: 'Path to libasan.so to preload') option('enable_explicit_EC_test', type: 'boolean', value: false, description: 'Enable explicit EC tests') option('default_pkcs11_module', type : 'string', value : '', description : 'Path to the default PKCS11 module') pkcs11-provider-1.0/packaging/000077500000000000000000000000001475270623700162455ustar00rootroot00000000000000pkcs11-provider-1.0/packaging/pkcs11-provider.spec000066400000000000000000000031031475270623700220500ustar00rootroot00000000000000#Enable gpg signature verification %bcond_with gpgcheck Name: pkcs11-provider Version: 1.0 Release: %autorelease Summary: A PKCS#11 provider for OpenSSL 3.0+ License: Apache-2.0 URL: https://github.com/latchset/pkcs11-provider Source0: %{url}/releases/download/v%{version}/%{name}-%{version}.tar.xz %if %{with gpgcheck} Source1: %{url}/releases/download/v%{version}/%{name}-%{version}.tar.xz.asc Source2: https://people.redhat.com/~ssorce/simo_redhat.asc %endif BuildRequires: openssl-devel >= 3.0.7 BuildRequires: gcc BuildRequires: meson %if %{with gpgcheck} BuildRequires: gnupg2 %endif # for tests BuildRequires: nss-devel BuildRequires: nss-softokn BuildRequires: nss-softokn-devel BuildRequires: nss-tools BuildRequires: openssl BuildRequires: softhsm BuildRequires: opensc BuildRequires: p11-kit-devel BuildRequires: gnutls-utils BuildRequires: xz BuildRequires: expect %description This is an Openssl 3.x provider to access Hardware or Software Tokens using the PKCS#11 Cryptographic Token Interface. This code targets version 3.0 of the interface but should be backwards compatible to previous versions as well. %prep %if %{with gpgcheck} %{gpgverify} --keyring='%{SOURCE2}' --signature='%{SOURCE1}' --data='%{SOURCE0}' %endif %autosetup -p1 %build %meson %meson_build %install %meson_install %check # do not run them in parrallel with %{?_smp_mflags} %meson_test --num-processes 1 %files %license COPYING %{_mandir}/man7/provider-pkcs11.* %doc README.md %{_libdir}/ossl-modules/pkcs11.so %changelog %autochangelog pkcs11-provider-1.0/packaging/sbom.cdx.json000066400000000000000000000023451475270623700206610ustar00rootroot00000000000000{ "bomFormat": "CycloneDX", "specVersion": "1.6", "version": 1, "metadata": { "authors": [ { "name": "@VCS_SBOM_AUTHORS@" } ] }, "components": [ { "type": "library", "bom-ref": "pkg:github/latchset/pkcs11-provider@@VCS_TAG@", "cpe": "cpe:2.3:a:latchset:pkcs11-provider:@VCS_TAG@:*:*:*:*:*:*:*", "name": "pkcs11-provider", "version": "@VCS_VERSION@", "description": "OpenSSL 3.x provider to access Hardware and Software Tokens using the PKCS#11 Cryptographic Token Interface", "supplier": { "name": "pkcs11-provider developers" }, "authors": [ { "name": "@VCS_AUTHORS@" } ], "licenses": [ { "license": { "id": "Apache-2.0" } } ], "externalReferences": [ { "type": "vcs", "url": "https://github.com/latchset/pkcs11-provider" } ] } ] } pkcs11-provider-1.0/python-ecdsa/000077500000000000000000000000001475270623700167175ustar00rootroot00000000000000pkcs11-provider-1.0/scripts/000077500000000000000000000000001475270623700160105ustar00rootroot00000000000000pkcs11-provider-1.0/scripts/clean-dist.sh000077500000000000000000000001501475270623700203660ustar00rootroot00000000000000#!/bin/bash -e cd "$MESON_DIST_ROOT" # Remove the submodules rm -rf tlsfuzzer python-ecdsa tlslite-ng pkcs11-provider-1.0/src/000077500000000000000000000000001475270623700151105ustar00rootroot00000000000000pkcs11-provider-1.0/src/asymmetric_cipher.c000066400000000000000000000612141475270623700207670ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include #include "openssl/prov_ssl.h" #include "openssl/rsa.h" #include "openssl/rand.h" DISPATCH_RSAENC_FN(newctx); DISPATCH_RSAENC_FN(freectx); DISPATCH_RSAENC_FN(dupctx); DISPATCH_RSAENC_FN(encrypt_init); DISPATCH_RSAENC_FN(encrypt); DISPATCH_RSAENC_FN(decrypt_init); DISPATCH_RSAENC_FN(decrypt); DISPATCH_RSAENC_FN(get_ctx_params); DISPATCH_RSAENC_FN(set_ctx_params); DISPATCH_RSAENC_FN(gettable_ctx_params); DISPATCH_RSAENC_FN(settable_ctx_params); struct tls_padding { bool enabled; CK_BYTE client_ver_major; CK_BYTE client_ver_minor; CK_BYTE alt_ver_major; CK_BYTE alt_ver_minor; }; struct p11prov_rsaenc_ctx { P11PROV_CTX *provctx; P11PROV_OBJ *key; CK_MECHANISM_TYPE mechtype; CK_RSA_PKCS_OAEP_PARAMS oaep_params; /* RSA_PKCS1_WITH_TLS_PADDING parameters */ struct tls_padding tls_padding; }; static void *p11prov_rsaenc_newctx(void *provctx) { P11PROV_CTX *ctx = (P11PROV_CTX *)provctx; struct p11prov_rsaenc_ctx *encctx; encctx = OPENSSL_zalloc(sizeof(struct p11prov_rsaenc_ctx)); if (encctx == NULL) { return NULL; } encctx->provctx = ctx; /* PKCS1.5 is the default */ encctx->mechtype = CKM_RSA_PKCS; return encctx; } static void p11prov_rsaenc_freectx(void *ctx) { struct p11prov_rsaenc_ctx *encctx = (struct p11prov_rsaenc_ctx *)ctx; if (encctx == NULL) { return; } p11prov_obj_free(encctx->key); OPENSSL_free(encctx->oaep_params.pSourceData); OPENSSL_clear_free(encctx, sizeof(struct p11prov_rsaenc_ctx)); } static void *p11prov_rsaenc_dupctx(void *ctx) { struct p11prov_rsaenc_ctx *encctx = (struct p11prov_rsaenc_ctx *)ctx; struct p11prov_rsaenc_ctx *newctx; if (encctx == NULL) { return NULL; } newctx = p11prov_rsaenc_newctx(encctx->provctx); if (newctx == NULL) { return NULL; } newctx->key = p11prov_obj_ref(encctx->key); newctx->mechtype = encctx->mechtype; newctx->oaep_params = encctx->oaep_params; if (encctx->oaep_params.pSourceData) { CK_RSA_PKCS_OAEP_PARAMS_PTR src = &encctx->oaep_params; CK_RSA_PKCS_OAEP_PARAMS_PTR dst = &newctx->oaep_params; dst->pSourceData = OPENSSL_memdup(src->pSourceData, src->ulSourceDataLen); if (dst->pSourceData == NULL) { p11prov_rsaenc_freectx(newctx); return NULL; } dst->ulSourceDataLen = src->ulSourceDataLen; } newctx->tls_padding = encctx->tls_padding; return newctx; } static int p11prov_rsaenc_set_mechanism(void *ctx, CK_MECHANISM *mechanism) { struct p11prov_rsaenc_ctx *encctx = (struct p11prov_rsaenc_ctx *)ctx; mechanism->mechanism = encctx->mechtype; mechanism->pParameter = NULL; mechanism->ulParameterLen = 0; if (mechanism->mechanism == CKM_RSA_PKCS_OAEP) { encctx->oaep_params.source = CKZ_DATA_SPECIFIED; mechanism->pParameter = &encctx->oaep_params; mechanism->ulParameterLen = sizeof(encctx->oaep_params); } return CKR_OK; } static int p11prov_rsaenc_encrypt_init(void *ctx, void *provkey, const OSSL_PARAM params[]) { struct p11prov_rsaenc_ctx *encctx = (struct p11prov_rsaenc_ctx *)ctx; P11PROV_OBJ *key = (P11PROV_OBJ *)provkey; CK_RV ret; P11PROV_debug("encrypt init (ctx=%p, key=%p, params=%p)", ctx, provkey, params); ret = p11prov_ctx_status(encctx->provctx); if (ret != CKR_OK) { return RET_OSSL_ERR; } encctx->key = p11prov_obj_ref(key); if (encctx->key == NULL) { return RET_OSSL_ERR; } return p11prov_rsaenc_set_ctx_params(ctx, params); } static int p11prov_rsaenc_encrypt(void *ctx, unsigned char *out, size_t *outlen, size_t outsize, const unsigned char *in, size_t inlen) { struct p11prov_rsaenc_ctx *encctx = (struct p11prov_rsaenc_ctx *)ctx; CK_MECHANISM mechanism; P11PROV_SESSION *session; CK_SESSION_HANDLE sess; CK_SLOT_ID slotid; CK_OBJECT_HANDLE handle; CK_ULONG out_size = *outlen; int result = RET_OSSL_ERR; CK_RV ret; P11PROV_debug("encrypt (ctx=%p)", ctx); if (out == NULL) { CK_ULONG size = p11prov_obj_get_key_size(encctx->key); if (size == CK_UNAVAILABLE_INFORMATION) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); return RET_OSSL_ERR; } *outlen = size; return RET_OSSL_OK; } slotid = p11prov_obj_get_slotid(encctx->key); if (slotid == CK_UNAVAILABLE_INFORMATION) { P11PROV_raise(encctx->provctx, CKR_SLOT_ID_INVALID, "Provided key has invalid slot"); return RET_OSSL_ERR; } handle = p11prov_obj_get_handle(encctx->key); if (handle == CK_INVALID_HANDLE) { P11PROV_raise(encctx->provctx, CKR_KEY_HANDLE_INVALID, "Provided key has invalid handle"); return RET_OSSL_ERR; } ret = p11prov_rsaenc_set_mechanism(encctx, &mechanism); if (ret != CKR_OK) { return RET_OSSL_ERR; } ret = p11prov_get_session(encctx->provctx, &slotid, NULL, NULL, mechanism.mechanism, NULL, NULL, false, false, &session); if (ret != CKR_OK) { P11PROV_raise(encctx->provctx, ret, "Failed to open session on slot %lu", slotid); return RET_OSSL_ERR; } sess = p11prov_session_handle(session); ret = p11prov_EncryptInit(encctx->provctx, sess, &mechanism, handle); if (ret != CKR_OK) { if (ret == CKR_MECHANISM_INVALID || ret == CKR_MECHANISM_PARAM_INVALID) { ERR_raise(ERR_LIB_PROV, PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE); } goto endsess; } ret = p11prov_Encrypt(encctx->provctx, sess, (void *)in, inlen, out, &out_size); if (ret != CKR_OK) { goto endsess; } *outlen = out_size; result = RET_OSSL_OK; endsess: p11prov_return_session(session); return result; } static int p11prov_rsaenc_decrypt_init(void *ctx, void *provkey, const OSSL_PARAM params[]) { struct p11prov_rsaenc_ctx *encctx = (struct p11prov_rsaenc_ctx *)ctx; P11PROV_OBJ *key = (P11PROV_OBJ *)provkey; CK_RV ret; P11PROV_debug("encrypt init (ctx=%p, key=%p, params=%p)", ctx, provkey, params); ret = p11prov_ctx_status(encctx->provctx); if (ret != CKR_OK) { return RET_OSSL_ERR; } encctx->key = p11prov_obj_ref(key); if (encctx->key == NULL) { return RET_OSSL_ERR; } if (p11prov_obj_get_class(encctx->key) != CKO_PRIVATE_KEY) { P11PROV_raise(encctx->provctx, CKR_ARGUMENTS_BAD, "Invalid key class"); return RET_OSSL_ERR; } return p11prov_rsaenc_set_ctx_params(ctx, params); } /* we are guaranteed to have enough space in buf for our checks */ static int p11prov_tls_constant_time_depadding(struct p11prov_rsaenc_ctx *encctx, unsigned char *out, unsigned char *buf, CK_ULONG *out_size, CK_ULONG *ret_cond) { unsigned char randbuf[SSL_MAX_MASTER_KEY_LENGTH]; CK_ULONG ver_cond = 0; CK_ULONG cond = 0; CK_ULONG length = SSL_MAX_MASTER_KEY_LENGTH; int err; /* always generate a random buffer, to constant_time swap in * in case any of the tests fails */ err = RAND_priv_bytes_ex(p11prov_ctx_get_libctx(encctx->provctx), randbuf, sizeof(randbuf), 0); if (err != RET_OSSL_OK) { /* it is ok to bail out here because the error is completely * unrelated to the computations and is not a controllable * side-channel */ ERR_raise(ERR_LIB_RSA, ERR_R_INTERNAL_ERROR); return RET_OSSL_ERR; } cond = constant_equal(*out_size, length); ver_cond = constant_equal(buf[0], encctx->tls_padding.client_ver_major); ver_cond &= constant_equal(buf[1], encctx->tls_padding.client_ver_minor); /* this conditional is ok because it does not depend on the outcome of * the decryption or any other private data */ if (encctx->tls_padding.alt_ver_major != 0) { CK_ULONG alt_cond = 0; alt_cond = constant_equal(buf[0], encctx->tls_padding.alt_ver_major); alt_cond &= constant_equal(buf[1], encctx->tls_padding.alt_ver_minor); ver_cond |= alt_cond; } cond &= ver_cond; constant_select_buf(cond, length, out, buf, randbuf); *out_size = length; *ret_cond = cond; return RET_OSSL_OK; } static int p11prov_rsaenc_decrypt(void *ctx, unsigned char *out, size_t *outlen, size_t outsize, const unsigned char *in, size_t inlen) { struct p11prov_rsaenc_ctx *encctx = (struct p11prov_rsaenc_ctx *)ctx; CK_MECHANISM mechanism; P11PROV_SESSION *session = NULL; CK_SESSION_HANDLE sess; CK_SLOT_ID slotid; CK_OBJECT_HANDLE handle; CK_ULONG key_size = CK_UNAVAILABLE_INFORMATION; unsigned char *tmpbuf = NULL; unsigned char *outbuf = out; CK_ULONG out_size = outsize; int result = RET_OSSL_ERR; bool always_auth = false; bool tls_padding = encctx->tls_padding.enabled; CK_RV ret; P11PROV_debug("decrypt (ctx=%p)", ctx); key_size = p11prov_obj_get_key_size(encctx->key); if (key_size == CK_UNAVAILABLE_INFORMATION) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY); return RET_OSSL_ERR; } if (out == NULL) { if (encctx->tls_padding.enabled) { *outlen = SSL_MAX_MASTER_KEY_LENGTH; } else { *outlen = key_size; } return RET_OSSL_OK; } if (outsize < key_size) { if (tls_padding) { if (outsize < SSL_MAX_MASTER_KEY_LENGTH) { ERR_raise(ERR_LIB_PROV, PROV_R_BAD_LENGTH); return RET_OSSL_ERR; } } else { ERR_raise(ERR_LIB_PROV, PROV_R_BAD_LENGTH); return RET_OSSL_ERR; } } if (tls_padding) { tmpbuf = OPENSSL_zalloc(key_size); if (!tmpbuf) { return RET_OSSL_ERR; } outbuf = tmpbuf; out_size = key_size; } slotid = p11prov_obj_get_slotid(encctx->key); if (slotid == CK_UNAVAILABLE_INFORMATION) { P11PROV_raise(encctx->provctx, CKR_SLOT_ID_INVALID, "Provided key has invalid slot"); result = RET_OSSL_ERR; goto done; } handle = p11prov_obj_get_handle(encctx->key); if (handle == CK_INVALID_HANDLE) { P11PROV_raise(encctx->provctx, CKR_KEY_HANDLE_INVALID, "Provided key has invalid handle"); result = RET_OSSL_ERR; goto done; } ret = p11prov_rsaenc_set_mechanism(encctx, &mechanism); if (ret != CKR_OK) { result = RET_OSSL_ERR; goto done; } ret = p11prov_get_session(encctx->provctx, &slotid, NULL, NULL, mechanism.mechanism, NULL, NULL, true, false, &session); if (ret != CKR_OK) { P11PROV_raise(encctx->provctx, ret, "Failed to open session on slot %lu", slotid); result = RET_OSSL_ERR; goto done; } sess = p11prov_session_handle(session); ret = p11prov_DecryptInit(encctx->provctx, sess, &mechanism, handle); if (ret != CKR_OK) { if (ret == CKR_MECHANISM_INVALID || ret == CKR_MECHANISM_PARAM_INVALID) { ERR_raise(ERR_LIB_PROV, PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE); } result = RET_OSSL_ERR; goto done; } always_auth = p11prov_obj_get_bool(encctx->key, CKA_ALWAYS_AUTHENTICATE, false); if (always_auth) { ret = p11prov_context_specific_login(session, NULL, NULL, NULL); if (ret != CKR_OK) { result = RET_OSSL_ERR; goto done; } } /* Special handling against PKCS#1 1.5 side channel leaking */ if (mechanism.mechanism == CKM_RSA_PKCS) { CK_ULONG cond; ret = side_channel_free_Decrypt(encctx->provctx, sess, (void *)in, inlen, outbuf, &out_size); /* the error case need to be handled in a side-channel free way, so * conditionals need to be constant time. Always setting outlen is * fine because out_size is initialized to the value of outlen * and the value should not matter in an error condition anyway */ cond = constant_equal(ret, CKR_OK); /* this conditional is ok because it is not dependent on the * decryption computation or any private data */ if (tls_padding) { CK_ULONG tls_cond = 0; result = p11prov_tls_constant_time_depadding(encctx, out, tmpbuf, &out_size, &tls_cond); /* this conditional is ok because only fatal failures * unrelated to the computation are returned this way. * Like allocation failures or rng failures. */ if (result != RET_OSSL_OK) { goto done; } cond &= tls_cond; } result = constant_select_int(cond, RET_OSSL_OK, RET_OSSL_ERR); *outlen = out_size; goto done; } ret = p11prov_Decrypt(encctx->provctx, sess, (void *)in, inlen, out, &out_size); if (ret != CKR_OK) { result = RET_OSSL_ERR; goto done; } *outlen = out_size; result = RET_OSSL_OK; done: p11prov_return_session(session); OPENSSL_clear_free(tmpbuf, key_size); return result; } static struct { CK_MECHANISM_TYPE type; int ossl_id; const char *string; } padding_map[] = { { CKM_RSA_X_509, RSA_NO_PADDING, OSSL_PKEY_RSA_PAD_MODE_NONE }, { CKM_RSA_PKCS, RSA_PKCS1_PADDING, OSSL_PKEY_RSA_PAD_MODE_PKCSV15 }, { CKM_RSA_PKCS, RSA_PKCS1_WITH_TLS_PADDING, OSSL_PKEY_RSA_PAD_MODE_PKCSV15 }, { CKM_RSA_PKCS_OAEP, RSA_PKCS1_OAEP_PADDING, OSSL_PKEY_RSA_PAD_MODE_OAEP }, { CKM_RSA_X9_31, RSA_X931_PADDING, OSSL_PKEY_RSA_PAD_MODE_X931 }, { CK_UNAVAILABLE_INFORMATION, 0, NULL }, }; /* only the ones we can support */ static struct { CK_MECHANISM_TYPE digest; CK_RSA_PKCS_MGF_TYPE mgf; } mfg_map[] = { { CKM_SHA3_512, CKG_MGF1_SHA3_512 }, { CKM_SHA3_384, CKG_MGF1_SHA3_384 }, { CKM_SHA3_256, CKG_MGF1_SHA3_256 }, { CKM_SHA3_224, CKG_MGF1_SHA3_224 }, { CKM_SHA512, CKG_MGF1_SHA512 }, { CKM_SHA384, CKG_MGF1_SHA384 }, { CKM_SHA256, CKG_MGF1_SHA256 }, { CKM_SHA224, CKG_MGF1_SHA224 }, { CKM_SHA_1, CKG_MGF1_SHA1 }, { CK_UNAVAILABLE_INFORMATION, 0 }, }; static const char *p11prov_rsaenc_mgf_name(CK_RSA_PKCS_MGF_TYPE mgf) { for (int i = 0; mfg_map[i].digest != CK_UNAVAILABLE_INFORMATION; i++) { if (mfg_map[i].mgf == mgf) { const char *name; CK_RV rv; rv = p11prov_digest_get_name(mfg_map[i].digest, &name); if (rv != CKR_OK) { return NULL; } return name; } } return NULL; } static CK_RSA_PKCS_MGF_TYPE p11prov_rsaenc_map_mgf(const char *digest_name) { CK_MECHANISM_TYPE digest; CK_RV rv; rv = p11prov_digest_get_by_name(digest_name, &digest); if (rv != CKR_OK) { return CK_UNAVAILABLE_INFORMATION; } for (int i = 0; mfg_map[i].digest != CK_UNAVAILABLE_INFORMATION; i++) { if (mfg_map[i].digest == digest) { return mfg_map[i].mgf; } } return CK_UNAVAILABLE_INFORMATION; } static int p11prov_rsaenc_get_ctx_params(void *ctx, OSSL_PARAM *params) { struct p11prov_rsaenc_ctx *encctx = (struct p11prov_rsaenc_ctx *)ctx; OSSL_PARAM *p; int ret; P11PROV_debug("rsaenc get ctx params (ctx=%p, params=%p)", ctx, params); if (params == NULL) { return RET_OSSL_OK; } p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_PAD_MODE); if (p) { ret = RET_OSSL_ERR; for (int i = 0; padding_map[i].string != NULL; i++) { if (padding_map[i].type == encctx->mechtype) { switch (p->data_type) { case OSSL_PARAM_INTEGER: ret = OSSL_PARAM_set_int(p, padding_map[i].ossl_id); break; case OSSL_PARAM_UTF8_STRING: ret = OSSL_PARAM_set_utf8_string(p, padding_map[i].string); break; } break; } } if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST); if (p) { const char *digest; CK_RV rv; rv = p11prov_digest_get_name(encctx->oaep_params.hashAlg, &digest); if (rv != CKR_OK) { return RET_OSSL_ERR; } ret = OSSL_PARAM_set_utf8_string(p, digest); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST); if (p) { const char *name; name = p11prov_rsaenc_mgf_name(encctx->oaep_params.mgf); if (!name) { return RET_OSSL_ERR; } ret = OSSL_PARAM_set_utf8_string(p, name); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL); if (p) { ret = OSSL_PARAM_set_octet_ptr(p, encctx->oaep_params.pSourceData, encctx->oaep_params.ulSourceDataLen); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION); if (p) { ret = OSSL_PARAM_set_uint( p, (((unsigned int)encctx->tls_padding.client_ver_major) << 8) + encctx->tls_padding.client_ver_minor); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION); if (p) { ret = OSSL_PARAM_set_uint( p, (((unsigned int)encctx->tls_padding.alt_ver_major) << 8) + encctx->tls_padding.alt_ver_minor); if (ret != RET_OSSL_OK) { return ret; } } return RET_OSSL_OK; } static int p11prov_rsaenc_set_ctx_params(void *ctx, const OSSL_PARAM params[]) { struct p11prov_rsaenc_ctx *encctx = (struct p11prov_rsaenc_ctx *)ctx; const OSSL_PARAM *p; int ret; P11PROV_debug("rsaenc set ctx params (ctx=%p, params=%p)", ctx, params); if (params == NULL) { return RET_OSSL_OK; } p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_PAD_MODE); if (p) { CK_MECHANISM_TYPE mechtype = CK_UNAVAILABLE_INFORMATION; if (p->data_type == OSSL_PARAM_INTEGER) { int pad_mode; /* legacy pad mode number */ ret = OSSL_PARAM_get_int(p, &pad_mode); if (ret != RET_OSSL_OK) { return ret; } for (int i = 0; padding_map[i].string != NULL; i++) { if (padding_map[i].ossl_id == pad_mode) { mechtype = padding_map[i].type; break; } } if (pad_mode == RSA_PKCS1_WITH_TLS_PADDING) { encctx->tls_padding.enabled = true; } } else if (p->data_type == OSSL_PARAM_UTF8_STRING) { if (p->data) { for (int i = 0; padding_map[i].string != NULL; i++) { if (strcmp(p->data, padding_map[i].string) == 0) { mechtype = padding_map[i].type; break; } } } } else { return RET_OSSL_ERR; } if (mechtype == CK_UNAVAILABLE_INFORMATION) { ERR_raise(ERR_LIB_PROV, PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE); return RET_OSSL_ERR; } encctx->mechtype = mechtype; P11PROV_debug_mechanism(encctx->provctx, p11prov_obj_get_slotid(encctx->key), encctx->mechtype); } p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST); if (p) { const char *digest = NULL; CK_RV rv; ret = OSSL_PARAM_get_utf8_string_ptr(p, &digest); if (ret != RET_OSSL_OK) { return ret; } rv = p11prov_digest_get_by_name(digest, &encctx->oaep_params.hashAlg); if (rv != CKR_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return RET_OSSL_ERR; } } p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST); if (p) { const char *digest = NULL; ret = OSSL_PARAM_get_utf8_string_ptr(p, &digest); if (ret != RET_OSSL_OK) { return ret; } encctx->oaep_params.mgf = p11prov_rsaenc_map_mgf(digest); if (encctx->oaep_params.mgf == CK_UNAVAILABLE_INFORMATION) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MGF1_MD); return RET_OSSL_ERR; } } p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL); if (p) { void *label = NULL; size_t len; ret = OSSL_PARAM_get_octet_string(p, &label, 0, &len); if (ret != RET_OSSL_OK) { return ret; } /* just in case it was previously set */ OPENSSL_free(encctx->oaep_params.pSourceData); encctx->oaep_params.pSourceData = label; encctx->oaep_params.ulSourceDataLen = len; } p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION); if (p) { unsigned int client_ver; ret = OSSL_PARAM_get_uint(p, &client_ver); if (ret != RET_OSSL_OK) { return ret; } encctx->tls_padding.client_ver_major = (client_ver >> 8) & 0xff; encctx->tls_padding.client_ver_minor = client_ver & 0xff; } p = OSSL_PARAM_locate_const(params, OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION); if (p) { unsigned int alt_ver; ret = OSSL_PARAM_get_uint(p, &alt_ver); if (ret != RET_OSSL_OK) { return ret; } encctx->tls_padding.alt_ver_major = (alt_ver >> 8) & 0xff; encctx->tls_padding.alt_ver_minor = alt_ver & 0xff; } return RET_OSSL_OK; } static const OSSL_PARAM *p11prov_rsaenc_gettable_ctx_params(void *ctx, void *prov) { static const OSSL_PARAM params[] = { OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, NULL, 0), OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST, NULL, 0), OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST, NULL, 0), OSSL_PARAM_octet_string(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, NULL, 0), OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION, NULL), OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION, NULL), OSSL_PARAM_END, }; return params; } static const OSSL_PARAM *p11prov_rsaenc_settable_ctx_params(void *ctx, void *prov) { static const OSSL_PARAM params[] = { OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_PAD_MODE, NULL, 0), OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_OAEP_DIGEST, NULL, 0), OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST, NULL, 0), OSSL_PARAM_utf8_string(OSSL_ASYM_CIPHER_PARAM_MGF1_DIGEST_PROPS, NULL, 0), OSSL_PARAM_octet_string(OSSL_ASYM_CIPHER_PARAM_OAEP_LABEL, NULL, 0), OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION, NULL), OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_NEGOTIATED_VERSION, NULL), OSSL_PARAM_END, }; return params; } const OSSL_DISPATCH p11prov_rsa_asym_cipher_functions[] = { DISPATCH_RSAENC_ELEM(NEWCTX, newctx), DISPATCH_RSAENC_ELEM(FREECTX, freectx), DISPATCH_RSAENC_ELEM(DUPCTX, dupctx), DISPATCH_RSAENC_ELEM(ENCRYPT_INIT, encrypt_init), DISPATCH_RSAENC_ELEM(ENCRYPT, encrypt), DISPATCH_RSAENC_ELEM(DECRYPT_INIT, decrypt_init), DISPATCH_RSAENC_ELEM(DECRYPT, decrypt), DISPATCH_RSAENC_ELEM(GET_CTX_PARAMS, get_ctx_params), DISPATCH_RSAENC_ELEM(GETTABLE_CTX_PARAMS, gettable_ctx_params), DISPATCH_RSAENC_ELEM(SET_CTX_PARAMS, set_ctx_params), DISPATCH_RSAENC_ELEM(SETTABLE_CTX_PARAMS, settable_ctx_params), }; pkcs11-provider-1.0/src/asymmetric_cipher.h000066400000000000000000000007421475270623700207730ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _ASYM_CIPH_H #define _ASYM_CIPH_H /* rsa encrypt/decrypt */ #define DISPATCH_RSAENC_FN(name) \ DECL_DISPATCH_FUNC(asym_cipher, p11prov_rsaenc, name) #define DISPATCH_RSAENC_ELEM(NAME, name) \ { \ OSSL_FUNC_ASYM_CIPHER_##NAME, (void (*)(void))p11prov_rsaenc_##name \ } extern const OSSL_DISPATCH p11prov_rsa_asym_cipher_functions[]; #endif /* _ASYM_CIPH_H */ pkcs11-provider-1.0/src/debug.c000066400000000000000000000615611475270623700163530ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ /* for strndup we need to define POSIX_C_SOURCE */ #define _POSIX_C_SOURCE 200809L #include "provider.h" #include int debug_level = -1; FILE *stddebug = NULL; /* this function relies on being called by P11PROV_debug, after * an __atomic_compare_exchange_n sets debug_lazy_init to -1, * This allows only 1 thread to ever init, as any other thread * would see debugging as disabled. This means some debugging may * be lost but will not risk multiplt thread stopming on each * other to open the debug file */ void p11prov_debug_init(void) { /* The ',' character should not be used in the path as it will * break tokenization, we do not provide any escaping, kiss */ const char *env = getenv("PKCS11_PROVIDER_DEBUG"); const char *next; char fname[1024]; int dbg_level = 0; int orig; if (env) { do { next = strchr(env, ','); if (strncmp(env, "file:", 5) == 0) { int len; if (stddebug != NULL && stddebug != stderr) { fclose(stddebug); } if (next) { len = next - env - 5; } else { len = strlen(env + 5); } memcpy(fname, env + 5, len); fname[len] = '\0'; stddebug = fopen(fname, "a"); if (stddebug == NULL) { goto done; } } else if (strncmp(env, "level:", 6) == 0) { dbg_level = atoi(env + 6); } if (next) { env = next + 1; } } while (next); if (dbg_level < 1) { dbg_level = 1; } if (stddebug == NULL) { stddebug = stderr; } } done: /* set value to debug_level atomically */ __atomic_exchange(&debug_level, &dbg_level, &orig, __ATOMIC_SEQ_CST); } void p11prov_debug(const char *file, int line, const char *func, const char *fmt, ...) { const char newline[] = "\n"; va_list args; if (file) { fprintf(stddebug, "[%s:%d] ", file, line); } if (func) { fprintf(stddebug, "%s(): ", func); } va_start(args, fmt); vfprintf(stddebug, fmt, args); va_end(args); fwrite(newline, 1, 1, stddebug); fflush(stddebug); } struct ckmap { CK_ULONG value; const char *name; }; extern struct ckmap mechanism_names[]; extern struct ckmap mechanism_flags[]; void p11prov_debug_mechanism(P11PROV_CTX *ctx, CK_SLOT_ID slotid, CK_MECHANISM_TYPE type) { CK_MECHANISM_INFO info = { 0 }; const char *mechname = "UNKNOWN"; CK_RV ret; if (debug_level < 1) { return; } for (int i = 0; mechanism_names[i].name != NULL; i++) { if (type == mechanism_names[i].value) { mechname = mechanism_names[i].name; } } /* set error mark so we can clear spurious errors */ p11prov_set_error_mark(ctx); ret = p11prov_GetMechanismInfo(ctx, slotid, type, &info); if (ret != CKR_OK) { p11prov_debug(NULL, 0, NULL, "C_GetMechanismInfo for %s(%lu) failed %lu", mechname, type, ret); } else { p11prov_debug(NULL, 0, NULL, "Mechanism Info:\n" " name: %s (%lu):\n" " min key length: %lu\n" " max key length: %lu\n" " flags (%#08lx):\n", mechname, type, info.ulMinKeySize, info.ulMaxKeySize, info.flags); for (int i = 0; mechanism_flags[i].name != NULL; i++) { if (info.flags & mechanism_flags[i].value) { p11prov_debug(NULL, 0, NULL, " %-25s (%#08lx)", mechanism_flags[i].name, mechanism_flags[i].value); } } } /* if there was any error, remove it, this is just a debug function */ p11prov_pop_error_to_mark(ctx); } extern struct ckmap token_flags[]; static void p11prov_debug_token_info(CK_TOKEN_INFO *info) { p11prov_debug(NULL, 0, NULL, "Token Info:\n" " Label: [%.32s]\n" " Manufacturer ID: [%.32s]\n" " Model: [%.16s]\n" " Serial Number: [%.16s]\n" " Flags (%#08lx):\n", info->label, info->manufacturerID, info->model, info->serialNumber, info->flags); for (int i = 0; token_flags[i].name != NULL; i++) { if (info->flags & token_flags[i].value) { p11prov_debug(NULL, 0, NULL, " %-35s (%#08lx)", token_flags[i].name, token_flags[i].value); } } p11prov_debug(NULL, 0, NULL, " Session Count Max: %3lu Current: %3lu\n" " R/W Session Count Max: %3lu Current: %3lu\n" " Pin Len Range: %lu-%lu\n" " Public Memory Total: %6lu Free: %6lu\n" " Private Memory Total: %6lu Free: %6lu\n" " Hardware Version: %d.%d\n" " Firmware Version: %d.%d\n" " UTC Time: [%.16s]\n", info->ulMaxSessionCount, info->ulSessionCount, info->ulMaxRwSessionCount, info->ulRwSessionCount, info->ulMinPinLen, info->ulMaxPinLen, info->ulTotalPublicMemory, info->ulFreePublicMemory, info->ulTotalPrivateMemory, info->ulFreePrivateMemory, info->hardwareVersion.major, info->hardwareVersion.minor, info->firmwareVersion.major, info->firmwareVersion.minor, info->utcTime); } extern struct ckmap slot_flags[]; extern struct ckmap profile_ids[]; void p11prov_debug_slot(P11PROV_CTX *ctx, CK_SLOT_ID slotid, CK_SLOT_INFO *slot, CK_TOKEN_INFO *token, CK_MECHANISM_TYPE *mechs, CK_ULONG mechs_num, CK_ULONG *profiles) { p11prov_debug(NULL, 0, NULL, "Slot Info:\n" " ID: %lu\n" " Description: [%.64s]\n" " Manufacturer ID: [%.32s]\n" " Flags (%#08lx):\n", slotid, slot->slotDescription, slot->manufacturerID, slot->flags); for (int i = 0; slot_flags[i].name != NULL; i++) { if (slot->flags & slot_flags[i].value) { p11prov_debug(NULL, 0, NULL, " %-25s (%#08lx)", slot_flags[i].name, slot_flags[i].value); } } p11prov_debug(NULL, 0, NULL, " Hardware Version: %d.%d\n" " Firmware Version: %d.%d\n", slot->hardwareVersion.major, slot->hardwareVersion.minor, slot->firmwareVersion.major, slot->firmwareVersion.minor); if (slot->flags & CKF_TOKEN_PRESENT) { p11prov_debug_token_info(token); } if (debug_level > 1) { for (CK_ULONG i = 0; i < mechs_num; i++) { p11prov_debug_mechanism(ctx, slotid, mechs[i]); } } if (profiles[0] != CKP_INVALID_ID) { p11prov_debug(NULL, 0, NULL, " Available profiles:\n"); for (int c = 0; c < 5 && profiles[c] != CKP_INVALID_ID; c++) { for (int i = 0; profile_ids[i].name != NULL; i++) { if (profiles[c] == profile_ids[i].value) { p11prov_debug(NULL, 0, NULL, " %-35s (%#08lx)", profile_ids[i].name, profile_ids[i].value); } } } } else { p11prov_debug(NULL, 0, NULL, " No profiles specified\n"); } } #define MECH_ENTRY(_m) \ { \ _m, #_m \ } struct ckmap mechanism_names[] = { MECH_ENTRY(CKM_RSA_PKCS_KEY_PAIR_GEN), MECH_ENTRY(CKM_RSA_PKCS), MECH_ENTRY(CKM_RSA_9796), MECH_ENTRY(CKM_RSA_X_509), MECH_ENTRY(CKM_MD2_RSA_PKCS), MECH_ENTRY(CKM_MD5_RSA_PKCS), MECH_ENTRY(CKM_SHA1_RSA_PKCS), MECH_ENTRY(CKM_RIPEMD128_RSA_PKCS), MECH_ENTRY(CKM_RIPEMD160_RSA_PKCS), MECH_ENTRY(CKM_RSA_PKCS_OAEP), MECH_ENTRY(CKM_RSA_X9_31_KEY_PAIR_GEN), MECH_ENTRY(CKM_RSA_X9_31), MECH_ENTRY(CKM_SHA1_RSA_X9_31), MECH_ENTRY(CKM_RSA_PKCS_PSS), MECH_ENTRY(CKM_SHA1_RSA_PKCS_PSS), MECH_ENTRY(CKM_DSA_KEY_PAIR_GEN), MECH_ENTRY(CKM_DSA), MECH_ENTRY(CKM_DSA_SHA1), MECH_ENTRY(CKM_DSA_SHA224), MECH_ENTRY(CKM_DSA_SHA256), MECH_ENTRY(CKM_DSA_SHA384), MECH_ENTRY(CKM_DSA_SHA512), MECH_ENTRY(CKM_DSA_SHA3_224), MECH_ENTRY(CKM_DSA_SHA3_256), MECH_ENTRY(CKM_DSA_SHA3_384), MECH_ENTRY(CKM_DSA_SHA3_512), MECH_ENTRY(CKM_DH_PKCS_KEY_PAIR_GEN), MECH_ENTRY(CKM_DH_PKCS_DERIVE), MECH_ENTRY(CKM_X9_42_DH_KEY_PAIR_GEN), MECH_ENTRY(CKM_X9_42_DH_DERIVE), MECH_ENTRY(CKM_X9_42_DH_HYBRID_DERIVE), MECH_ENTRY(CKM_X9_42_MQV_DERIVE), MECH_ENTRY(CKM_SHA256_RSA_PKCS), MECH_ENTRY(CKM_SHA384_RSA_PKCS), MECH_ENTRY(CKM_SHA512_RSA_PKCS), MECH_ENTRY(CKM_SHA256_RSA_PKCS_PSS), MECH_ENTRY(CKM_SHA384_RSA_PKCS_PSS), MECH_ENTRY(CKM_SHA512_RSA_PKCS_PSS), MECH_ENTRY(CKM_SHA224_RSA_PKCS), MECH_ENTRY(CKM_SHA224_RSA_PKCS_PSS), MECH_ENTRY(CKM_SHA512_224), MECH_ENTRY(CKM_SHA512_224_HMAC), MECH_ENTRY(CKM_SHA512_224_HMAC_GENERAL), MECH_ENTRY(CKM_SHA512_224_KEY_DERIVATION), MECH_ENTRY(CKM_SHA512_256), MECH_ENTRY(CKM_SHA512_256_HMAC), MECH_ENTRY(CKM_SHA512_256_HMAC_GENERAL), MECH_ENTRY(CKM_SHA512_256_KEY_DERIVATION), MECH_ENTRY(CKM_SHA512_T), MECH_ENTRY(CKM_SHA512_T_HMAC), MECH_ENTRY(CKM_SHA512_T_HMAC_GENERAL), MECH_ENTRY(CKM_SHA512_T_KEY_DERIVATION), MECH_ENTRY(CKM_SHA3_256_RSA_PKCS), MECH_ENTRY(CKM_SHA3_384_RSA_PKCS), MECH_ENTRY(CKM_SHA3_512_RSA_PKCS), MECH_ENTRY(CKM_SHA3_256_RSA_PKCS_PSS), MECH_ENTRY(CKM_SHA3_384_RSA_PKCS_PSS), MECH_ENTRY(CKM_SHA3_512_RSA_PKCS_PSS), MECH_ENTRY(CKM_SHA3_224_RSA_PKCS), MECH_ENTRY(CKM_SHA3_224_RSA_PKCS_PSS), MECH_ENTRY(CKM_RC2_KEY_GEN), MECH_ENTRY(CKM_RC2_ECB), MECH_ENTRY(CKM_RC2_CBC), MECH_ENTRY(CKM_RC2_MAC), MECH_ENTRY(CKM_RC2_MAC_GENERAL), MECH_ENTRY(CKM_RC2_CBC_PAD), MECH_ENTRY(CKM_RC4_KEY_GEN), MECH_ENTRY(CKM_RC4), MECH_ENTRY(CKM_DES_KEY_GEN), MECH_ENTRY(CKM_DES_ECB), MECH_ENTRY(CKM_DES_CBC), MECH_ENTRY(CKM_DES_MAC), MECH_ENTRY(CKM_DES_MAC_GENERAL), MECH_ENTRY(CKM_DES_CBC_PAD), MECH_ENTRY(CKM_DES2_KEY_GEN), MECH_ENTRY(CKM_DES3_KEY_GEN), MECH_ENTRY(CKM_DES3_ECB), MECH_ENTRY(CKM_DES3_CBC), MECH_ENTRY(CKM_DES3_MAC), MECH_ENTRY(CKM_DES3_MAC_GENERAL), MECH_ENTRY(CKM_DES3_CBC_PAD), MECH_ENTRY(CKM_DES3_CMAC_GENERAL), MECH_ENTRY(CKM_DES3_CMAC), MECH_ENTRY(CKM_CDMF_KEY_GEN), MECH_ENTRY(CKM_CDMF_ECB), MECH_ENTRY(CKM_CDMF_CBC), MECH_ENTRY(CKM_CDMF_MAC), MECH_ENTRY(CKM_CDMF_MAC_GENERAL), MECH_ENTRY(CKM_CDMF_CBC_PAD), MECH_ENTRY(CKM_DES_OFB64), MECH_ENTRY(CKM_DES_OFB8), MECH_ENTRY(CKM_DES_CFB64), MECH_ENTRY(CKM_DES_CFB8), MECH_ENTRY(CKM_MD2), MECH_ENTRY(CKM_MD2_HMAC), MECH_ENTRY(CKM_MD2_HMAC_GENERAL), MECH_ENTRY(CKM_MD5), MECH_ENTRY(CKM_MD5_HMAC), MECH_ENTRY(CKM_MD5_HMAC_GENERAL), MECH_ENTRY(CKM_SHA_1), MECH_ENTRY(CKM_SHA_1_HMAC), MECH_ENTRY(CKM_SHA_1_HMAC_GENERAL), MECH_ENTRY(CKM_RIPEMD128), MECH_ENTRY(CKM_RIPEMD128_HMAC), MECH_ENTRY(CKM_RIPEMD128_HMAC_GENERAL), MECH_ENTRY(CKM_RIPEMD160), MECH_ENTRY(CKM_RIPEMD160_HMAC), MECH_ENTRY(CKM_RIPEMD160_HMAC_GENERAL), MECH_ENTRY(CKM_SHA256), MECH_ENTRY(CKM_SHA256_HMAC), MECH_ENTRY(CKM_SHA256_HMAC_GENERAL), MECH_ENTRY(CKM_SHA224), MECH_ENTRY(CKM_SHA224_HMAC), MECH_ENTRY(CKM_SHA224_HMAC_GENERAL), MECH_ENTRY(CKM_SHA384), MECH_ENTRY(CKM_SHA384_HMAC), MECH_ENTRY(CKM_SHA384_HMAC_GENERAL), MECH_ENTRY(CKM_SHA512), MECH_ENTRY(CKM_SHA512_HMAC), MECH_ENTRY(CKM_SHA512_HMAC_GENERAL), MECH_ENTRY(CKM_SECURID_KEY_GEN), MECH_ENTRY(CKM_SECURID), MECH_ENTRY(CKM_HOTP_KEY_GEN), MECH_ENTRY(CKM_HOTP), MECH_ENTRY(CKM_ACTI), MECH_ENTRY(CKM_ACTI_KEY_GEN), MECH_ENTRY(CKM_SHA3_256), MECH_ENTRY(CKM_SHA3_256_HMAC), MECH_ENTRY(CKM_SHA3_256_HMAC_GENERAL), MECH_ENTRY(CKM_SHA3_256_KEY_GEN), MECH_ENTRY(CKM_SHA3_224), MECH_ENTRY(CKM_SHA3_224_HMAC), MECH_ENTRY(CKM_SHA3_224_HMAC_GENERAL), MECH_ENTRY(CKM_SHA3_224_KEY_GEN), MECH_ENTRY(CKM_SHA3_384), MECH_ENTRY(CKM_SHA3_384_HMAC), MECH_ENTRY(CKM_SHA3_384_HMAC_GENERAL), MECH_ENTRY(CKM_SHA3_384_KEY_GEN), MECH_ENTRY(CKM_SHA3_512), MECH_ENTRY(CKM_SHA3_512_HMAC), MECH_ENTRY(CKM_SHA3_512_HMAC_GENERAL), MECH_ENTRY(CKM_SHA3_512_KEY_GEN), MECH_ENTRY(CKM_CAST_KEY_GEN), MECH_ENTRY(CKM_CAST_ECB), MECH_ENTRY(CKM_CAST_CBC), MECH_ENTRY(CKM_CAST_MAC), MECH_ENTRY(CKM_CAST_MAC_GENERAL), MECH_ENTRY(CKM_CAST_CBC_PAD), MECH_ENTRY(CKM_CAST3_KEY_GEN), MECH_ENTRY(CKM_CAST3_ECB), MECH_ENTRY(CKM_CAST3_CBC), MECH_ENTRY(CKM_CAST3_MAC), MECH_ENTRY(CKM_CAST3_MAC_GENERAL), MECH_ENTRY(CKM_CAST3_CBC_PAD), MECH_ENTRY(CKM_CAST128_KEY_GEN), MECH_ENTRY(CKM_CAST128_ECB), MECH_ENTRY(CKM_CAST128_CBC), MECH_ENTRY(CKM_CAST128_MAC), MECH_ENTRY(CKM_CAST128_MAC_GENERAL), MECH_ENTRY(CKM_CAST128_CBC_PAD), MECH_ENTRY(CKM_RC5_KEY_GEN), MECH_ENTRY(CKM_RC5_ECB), MECH_ENTRY(CKM_RC5_CBC), MECH_ENTRY(CKM_RC5_MAC), MECH_ENTRY(CKM_RC5_MAC_GENERAL), MECH_ENTRY(CKM_RC5_CBC_PAD), MECH_ENTRY(CKM_IDEA_KEY_GEN), MECH_ENTRY(CKM_IDEA_ECB), MECH_ENTRY(CKM_IDEA_CBC), MECH_ENTRY(CKM_IDEA_MAC), MECH_ENTRY(CKM_IDEA_MAC_GENERAL), MECH_ENTRY(CKM_IDEA_CBC_PAD), MECH_ENTRY(CKM_GENERIC_SECRET_KEY_GEN), MECH_ENTRY(CKM_CONCATENATE_BASE_AND_KEY), MECH_ENTRY(CKM_CONCATENATE_BASE_AND_DATA), MECH_ENTRY(CKM_CONCATENATE_DATA_AND_BASE), MECH_ENTRY(CKM_XOR_BASE_AND_DATA), MECH_ENTRY(CKM_EXTRACT_KEY_FROM_KEY), MECH_ENTRY(CKM_SSL3_PRE_MASTER_KEY_GEN), MECH_ENTRY(CKM_SSL3_MASTER_KEY_DERIVE), MECH_ENTRY(CKM_SSL3_KEY_AND_MAC_DERIVE), MECH_ENTRY(CKM_SSL3_MASTER_KEY_DERIVE_DH), MECH_ENTRY(CKM_TLS_PRE_MASTER_KEY_GEN), MECH_ENTRY(CKM_TLS_MASTER_KEY_DERIVE), MECH_ENTRY(CKM_TLS_KEY_AND_MAC_DERIVE), MECH_ENTRY(CKM_TLS_MASTER_KEY_DERIVE_DH), MECH_ENTRY(CKM_TLS_PRF), MECH_ENTRY(CKM_SSL3_MD5_MAC), MECH_ENTRY(CKM_SSL3_SHA1_MAC), MECH_ENTRY(CKM_MD5_KEY_DERIVATION), MECH_ENTRY(CKM_MD2_KEY_DERIVATION), MECH_ENTRY(CKM_SHA1_KEY_DERIVATION), MECH_ENTRY(CKM_SHA256_KEY_DERIVATION), MECH_ENTRY(CKM_SHA384_KEY_DERIVATION), MECH_ENTRY(CKM_SHA512_KEY_DERIVATION), MECH_ENTRY(CKM_SHA224_KEY_DERIVATION), MECH_ENTRY(CKM_SHA3_256_KEY_DERIVATION), MECH_ENTRY(CKM_SHA3_224_KEY_DERIVATION), MECH_ENTRY(CKM_SHA3_384_KEY_DERIVATION), MECH_ENTRY(CKM_SHA3_512_KEY_DERIVATION), MECH_ENTRY(CKM_SHAKE_128_KEY_DERIVATION), MECH_ENTRY(CKM_SHAKE_256_KEY_DERIVATION), MECH_ENTRY(CKM_PBE_MD2_DES_CBC), MECH_ENTRY(CKM_PBE_MD5_DES_CBC), MECH_ENTRY(CKM_PBE_MD5_CAST_CBC), MECH_ENTRY(CKM_PBE_MD5_CAST3_CBC), MECH_ENTRY(CKM_PBE_MD5_CAST128_CBC), MECH_ENTRY(CKM_PBE_SHA1_CAST128_CBC), MECH_ENTRY(CKM_PBE_SHA1_RC4_128), MECH_ENTRY(CKM_PBE_SHA1_RC4_40), MECH_ENTRY(CKM_PBE_SHA1_DES3_EDE_CBC), MECH_ENTRY(CKM_PBE_SHA1_DES2_EDE_CBC), MECH_ENTRY(CKM_PBE_SHA1_RC2_128_CBC), MECH_ENTRY(CKM_PBE_SHA1_RC2_40_CBC), MECH_ENTRY(CKM_PKCS5_PBKD2), MECH_ENTRY(CKM_PBA_SHA1_WITH_SHA1_HMAC), MECH_ENTRY(CKM_WTLS_PRE_MASTER_KEY_GEN), MECH_ENTRY(CKM_WTLS_MASTER_KEY_DERIVE), MECH_ENTRY(CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC), MECH_ENTRY(CKM_WTLS_PRF), MECH_ENTRY(CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE), MECH_ENTRY(CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE), MECH_ENTRY(CKM_TLS12_MAC), MECH_ENTRY(CKM_TLS12_KDF), MECH_ENTRY(CKM_TLS12_MASTER_KEY_DERIVE), MECH_ENTRY(CKM_TLS12_KEY_AND_MAC_DERIVE), MECH_ENTRY(CKM_TLS12_MASTER_KEY_DERIVE_DH), MECH_ENTRY(CKM_TLS12_KEY_SAFE_DERIVE), MECH_ENTRY(CKM_TLS_MAC), MECH_ENTRY(CKM_TLS_KDF), MECH_ENTRY(CKM_KEY_WRAP_LYNKS), MECH_ENTRY(CKM_KEY_WRAP_SET_OAEP), MECH_ENTRY(CKM_CMS_SIG), MECH_ENTRY(CKM_KIP_DERIVE), MECH_ENTRY(CKM_KIP_WRAP), MECH_ENTRY(CKM_KIP_MAC), MECH_ENTRY(CKM_CAMELLIA_KEY_GEN), MECH_ENTRY(CKM_CAMELLIA_ECB), MECH_ENTRY(CKM_CAMELLIA_CBC), MECH_ENTRY(CKM_CAMELLIA_MAC), MECH_ENTRY(CKM_CAMELLIA_MAC_GENERAL), MECH_ENTRY(CKM_CAMELLIA_CBC_PAD), MECH_ENTRY(CKM_CAMELLIA_ECB_ENCRYPT_DATA), MECH_ENTRY(CKM_CAMELLIA_CBC_ENCRYPT_DATA), MECH_ENTRY(CKM_CAMELLIA_CTR), MECH_ENTRY(CKM_ARIA_KEY_GEN), MECH_ENTRY(CKM_ARIA_ECB), MECH_ENTRY(CKM_ARIA_CBC), MECH_ENTRY(CKM_ARIA_MAC), MECH_ENTRY(CKM_ARIA_MAC_GENERAL), MECH_ENTRY(CKM_ARIA_CBC_PAD), MECH_ENTRY(CKM_ARIA_ECB_ENCRYPT_DATA), MECH_ENTRY(CKM_ARIA_CBC_ENCRYPT_DATA), MECH_ENTRY(CKM_SEED_KEY_GEN), MECH_ENTRY(CKM_SEED_ECB), MECH_ENTRY(CKM_SEED_CBC), MECH_ENTRY(CKM_SEED_MAC), MECH_ENTRY(CKM_SEED_MAC_GENERAL), MECH_ENTRY(CKM_SEED_CBC_PAD), MECH_ENTRY(CKM_SEED_ECB_ENCRYPT_DATA), MECH_ENTRY(CKM_SEED_CBC_ENCRYPT_DATA), MECH_ENTRY(CKM_SKIPJACK_KEY_GEN), MECH_ENTRY(CKM_SKIPJACK_ECB64), MECH_ENTRY(CKM_SKIPJACK_CBC64), MECH_ENTRY(CKM_SKIPJACK_OFB64), MECH_ENTRY(CKM_SKIPJACK_CFB64), MECH_ENTRY(CKM_SKIPJACK_CFB32), MECH_ENTRY(CKM_SKIPJACK_CFB16), MECH_ENTRY(CKM_SKIPJACK_CFB8), MECH_ENTRY(CKM_SKIPJACK_WRAP), MECH_ENTRY(CKM_SKIPJACK_PRIVATE_WRAP), MECH_ENTRY(CKM_SKIPJACK_RELAYX), MECH_ENTRY(CKM_KEA_KEY_PAIR_GEN), MECH_ENTRY(CKM_KEA_KEY_DERIVE), MECH_ENTRY(CKM_KEA_DERIVE), MECH_ENTRY(CKM_FORTEZZA_TIMESTAMP), MECH_ENTRY(CKM_BATON_KEY_GEN), MECH_ENTRY(CKM_BATON_ECB128), MECH_ENTRY(CKM_BATON_ECB96), MECH_ENTRY(CKM_BATON_CBC128), MECH_ENTRY(CKM_BATON_COUNTER), MECH_ENTRY(CKM_BATON_SHUFFLE), MECH_ENTRY(CKM_BATON_WRAP), MECH_ENTRY(CKM_EC_KEY_PAIR_GEN), MECH_ENTRY(CKM_ECDSA), MECH_ENTRY(CKM_ECDSA_SHA1), MECH_ENTRY(CKM_ECDSA_SHA224), MECH_ENTRY(CKM_ECDSA_SHA256), MECH_ENTRY(CKM_ECDSA_SHA384), MECH_ENTRY(CKM_ECDSA_SHA512), MECH_ENTRY(CKM_EC_KEY_PAIR_GEN_W_EXTRA_BITS), MECH_ENTRY(CKM_ECDH1_DERIVE), MECH_ENTRY(CKM_ECDH1_COFACTOR_DERIVE), MECH_ENTRY(CKM_ECMQV_DERIVE), MECH_ENTRY(CKM_ECDH_AES_KEY_WRAP), MECH_ENTRY(CKM_RSA_AES_KEY_WRAP), MECH_ENTRY(CKM_JUNIPER_KEY_GEN), MECH_ENTRY(CKM_JUNIPER_ECB128), MECH_ENTRY(CKM_JUNIPER_CBC128), MECH_ENTRY(CKM_JUNIPER_COUNTER), MECH_ENTRY(CKM_JUNIPER_SHUFFLE), MECH_ENTRY(CKM_JUNIPER_WRAP), MECH_ENTRY(CKM_FASTHASH), MECH_ENTRY(CKM_AES_XTS), MECH_ENTRY(CKM_AES_XTS_KEY_GEN), MECH_ENTRY(CKM_AES_KEY_GEN), MECH_ENTRY(CKM_AES_ECB), MECH_ENTRY(CKM_AES_CBC), MECH_ENTRY(CKM_AES_MAC), MECH_ENTRY(CKM_AES_MAC_GENERAL), MECH_ENTRY(CKM_AES_CBC_PAD), MECH_ENTRY(CKM_AES_CTR), MECH_ENTRY(CKM_AES_GCM), MECH_ENTRY(CKM_AES_CCM), MECH_ENTRY(CKM_AES_CTS), MECH_ENTRY(CKM_AES_CMAC), MECH_ENTRY(CKM_AES_CMAC_GENERAL), MECH_ENTRY(CKM_AES_XCBC_MAC), MECH_ENTRY(CKM_AES_XCBC_MAC_96), MECH_ENTRY(CKM_AES_GMAC), MECH_ENTRY(CKM_BLOWFISH_KEY_GEN), MECH_ENTRY(CKM_BLOWFISH_CBC), MECH_ENTRY(CKM_TWOFISH_KEY_GEN), MECH_ENTRY(CKM_TWOFISH_CBC), MECH_ENTRY(CKM_BLOWFISH_CBC_PAD), MECH_ENTRY(CKM_TWOFISH_CBC_PAD), MECH_ENTRY(CKM_DES_ECB_ENCRYPT_DATA), MECH_ENTRY(CKM_DES_CBC_ENCRYPT_DATA), MECH_ENTRY(CKM_DES3_ECB_ENCRYPT_DATA), MECH_ENTRY(CKM_DES3_CBC_ENCRYPT_DATA), MECH_ENTRY(CKM_AES_ECB_ENCRYPT_DATA), MECH_ENTRY(CKM_AES_CBC_ENCRYPT_DATA), MECH_ENTRY(CKM_GOSTR3410_KEY_PAIR_GEN), MECH_ENTRY(CKM_GOSTR3410), MECH_ENTRY(CKM_GOSTR3410_WITH_GOSTR3411), MECH_ENTRY(CKM_GOSTR3410_KEY_WRAP), MECH_ENTRY(CKM_GOSTR3410_DERIVE), MECH_ENTRY(CKM_GOSTR3411), MECH_ENTRY(CKM_GOSTR3411_HMAC), MECH_ENTRY(CKM_GOST28147_KEY_GEN), MECH_ENTRY(CKM_GOST28147_ECB), MECH_ENTRY(CKM_GOST28147), MECH_ENTRY(CKM_GOST28147_MAC), MECH_ENTRY(CKM_GOST28147_KEY_WRAP), MECH_ENTRY(CKM_CHACHA20_KEY_GEN), MECH_ENTRY(CKM_CHACHA20), MECH_ENTRY(CKM_POLY1305_KEY_GEN), MECH_ENTRY(CKM_POLY1305), MECH_ENTRY(CKM_DSA_PARAMETER_GEN), MECH_ENTRY(CKM_DH_PKCS_PARAMETER_GEN), MECH_ENTRY(CKM_X9_42_DH_PARAMETER_GEN), MECH_ENTRY(CKM_DSA_PROBABILISTIC_PARAMETER_GEN), MECH_ENTRY(CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN), MECH_ENTRY(CKM_DSA_FIPS_G_GEN), MECH_ENTRY(CKM_AES_OFB), MECH_ENTRY(CKM_AES_CFB64), MECH_ENTRY(CKM_AES_CFB8), MECH_ENTRY(CKM_AES_CFB128), MECH_ENTRY(CKM_AES_CFB1), MECH_ENTRY(CKM_AES_KEY_WRAP), MECH_ENTRY(CKM_AES_KEY_WRAP_PAD), MECH_ENTRY(CKM_AES_KEY_WRAP_KWP), MECH_ENTRY(CKM_RSA_PKCS_TPM_1_1), MECH_ENTRY(CKM_RSA_PKCS_OAEP_TPM_1_1), MECH_ENTRY(CKM_SHA_1_KEY_GEN), MECH_ENTRY(CKM_SHA224_KEY_GEN), MECH_ENTRY(CKM_SHA256_KEY_GEN), MECH_ENTRY(CKM_SHA384_KEY_GEN), MECH_ENTRY(CKM_SHA512_KEY_GEN), MECH_ENTRY(CKM_SHA512_224_KEY_GEN), MECH_ENTRY(CKM_SHA512_256_KEY_GEN), MECH_ENTRY(CKM_SHA512_T_KEY_GEN), MECH_ENTRY(CKM_NULL), MECH_ENTRY(CKM_BLAKE2B_160), MECH_ENTRY(CKM_BLAKE2B_160_HMAC), MECH_ENTRY(CKM_BLAKE2B_160_HMAC_GENERAL), MECH_ENTRY(CKM_BLAKE2B_160_KEY_DERIVE), MECH_ENTRY(CKM_BLAKE2B_160_KEY_GEN), MECH_ENTRY(CKM_BLAKE2B_256), MECH_ENTRY(CKM_BLAKE2B_256_HMAC), MECH_ENTRY(CKM_BLAKE2B_256_HMAC_GENERAL), MECH_ENTRY(CKM_BLAKE2B_256_KEY_DERIVE), MECH_ENTRY(CKM_BLAKE2B_256_KEY_GEN), MECH_ENTRY(CKM_BLAKE2B_384), MECH_ENTRY(CKM_BLAKE2B_384_HMAC), MECH_ENTRY(CKM_BLAKE2B_384_HMAC_GENERAL), MECH_ENTRY(CKM_BLAKE2B_384_KEY_DERIVE), MECH_ENTRY(CKM_BLAKE2B_384_KEY_GEN), MECH_ENTRY(CKM_BLAKE2B_512), MECH_ENTRY(CKM_BLAKE2B_512_HMAC), MECH_ENTRY(CKM_BLAKE2B_512_HMAC_GENERAL), MECH_ENTRY(CKM_BLAKE2B_512_KEY_DERIVE), MECH_ENTRY(CKM_BLAKE2B_512_KEY_GEN), MECH_ENTRY(CKM_SALSA20), MECH_ENTRY(CKM_CHACHA20_POLY1305), MECH_ENTRY(CKM_SALSA20_POLY1305), MECH_ENTRY(CKM_X3DH_INITIALIZE), MECH_ENTRY(CKM_X3DH_RESPOND), MECH_ENTRY(CKM_X2RATCHET_INITIALIZE), MECH_ENTRY(CKM_X2RATCHET_RESPOND), MECH_ENTRY(CKM_X2RATCHET_ENCRYPT), MECH_ENTRY(CKM_X2RATCHET_DECRYPT), MECH_ENTRY(CKM_XEDDSA), MECH_ENTRY(CKM_HKDF_DERIVE), MECH_ENTRY(CKM_HKDF_DATA), MECH_ENTRY(CKM_HKDF_KEY_GEN), MECH_ENTRY(CKM_SALSA20_KEY_GEN), MECH_ENTRY(CKM_ECDSA_SHA3_224), MECH_ENTRY(CKM_ECDSA_SHA3_256), MECH_ENTRY(CKM_ECDSA_SHA3_384), MECH_ENTRY(CKM_ECDSA_SHA3_512), MECH_ENTRY(CKM_EC_EDWARDS_KEY_PAIR_GEN), MECH_ENTRY(CKM_EC_MONTGOMERY_KEY_PAIR_GEN), MECH_ENTRY(CKM_EDDSA), MECH_ENTRY(CKM_SP800_108_COUNTER_KDF), MECH_ENTRY(CKM_SP800_108_FEEDBACK_KDF), MECH_ENTRY(CKM_SP800_108_DOUBLE_PIPELINE_KDF), { 0, NULL }, }; struct ckmap mechanism_flags[] = { MECH_ENTRY(CKF_HW), MECH_ENTRY(CKF_MESSAGE_ENCRYPT), MECH_ENTRY(CKF_MESSAGE_DECRYPT), MECH_ENTRY(CKF_MESSAGE_SIGN), MECH_ENTRY(CKF_MESSAGE_VERIFY), MECH_ENTRY(CKF_MULTI_MESSAGE), MECH_ENTRY(CKF_FIND_OBJECTS), MECH_ENTRY(CKF_ENCRYPT), MECH_ENTRY(CKF_DECRYPT), MECH_ENTRY(CKF_DIGEST), MECH_ENTRY(CKF_SIGN), MECH_ENTRY(CKF_SIGN_RECOVER), MECH_ENTRY(CKF_VERIFY), MECH_ENTRY(CKF_VERIFY_RECOVER), MECH_ENTRY(CKF_GENERATE), MECH_ENTRY(CKF_GENERATE_KEY_PAIR), MECH_ENTRY(CKF_WRAP), MECH_ENTRY(CKF_UNWRAP), MECH_ENTRY(CKF_DERIVE), MECH_ENTRY(CKF_EC_F_P), MECH_ENTRY(CKF_EC_F_2M), MECH_ENTRY(CKF_EC_ECPARAMETERS), MECH_ENTRY(CKF_EC_OID), MECH_ENTRY(CKF_EC_UNCOMPRESS), MECH_ENTRY(CKF_EC_COMPRESS), MECH_ENTRY(CKF_EC_CURVENAME), { 0, NULL }, }; struct ckmap token_flags[] = { MECH_ENTRY(CKF_RNG), MECH_ENTRY(CKF_WRITE_PROTECTED), MECH_ENTRY(CKF_LOGIN_REQUIRED), MECH_ENTRY(CKF_USER_PIN_INITIALIZED), MECH_ENTRY(CKF_RESTORE_KEY_NOT_NEEDED), MECH_ENTRY(CKF_CLOCK_ON_TOKEN), MECH_ENTRY(CKF_PROTECTED_AUTHENTICATION_PATH), MECH_ENTRY(CKF_DUAL_CRYPTO_OPERATIONS), MECH_ENTRY(CKF_TOKEN_INITIALIZED), MECH_ENTRY(CKF_SECONDARY_AUTHENTICATION), MECH_ENTRY(CKF_USER_PIN_COUNT_LOW), MECH_ENTRY(CKF_USER_PIN_FINAL_TRY), MECH_ENTRY(CKF_USER_PIN_LOCKED), MECH_ENTRY(CKF_USER_PIN_TO_BE_CHANGED), MECH_ENTRY(CKF_SO_PIN_COUNT_LOW), MECH_ENTRY(CKF_SO_PIN_FINAL_TRY), MECH_ENTRY(CKF_SO_PIN_LOCKED), MECH_ENTRY(CKF_SO_PIN_TO_BE_CHANGED), MECH_ENTRY(CKF_ERROR_STATE), { 0, NULL }, }; struct ckmap slot_flags[] = { MECH_ENTRY(CKF_TOKEN_PRESENT), MECH_ENTRY(CKF_REMOVABLE_DEVICE), MECH_ENTRY(CKF_HW_SLOT), { 0, NULL }, }; struct ckmap profile_ids[] = { MECH_ENTRY(CKP_INVALID_ID), MECH_ENTRY(CKP_BASELINE_PROVIDER), MECH_ENTRY(CKP_EXTENDED_PROVIDER), MECH_ENTRY(CKP_AUTHENTICATION_TOKEN), MECH_ENTRY(CKP_PUBLIC_CERTIFICATES_TOKEN), MECH_ENTRY(CKP_VENDOR_DEFINED), { 0, NULL }, }; pkcs11-provider-1.0/src/debug.h000066400000000000000000000033751475270623700163570ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _DEBUG_H #define _DEBUG_H /* Debugging */ extern int debug_level; #define P11PROV_debug(...) \ do { \ if (debug_level < 0) { \ p11prov_debug_init(); \ } \ if (debug_level > 0) { \ p11prov_debug(OPENSSL_FILE, OPENSSL_LINE, OPENSSL_FUNC, \ __VA_ARGS__); \ } \ } while (0) #define P11PROV_debug_mechanism(...) \ do { \ if (debug_level < 0) { \ p11prov_debug_init(); \ } \ if (debug_level > 0) { \ p11prov_debug_mechanism(__VA_ARGS__); \ } \ } while (0) #define P11PROV_debug_slot(...) \ do { \ if (debug_level < 0) { \ p11prov_debug_init(); \ } \ if (debug_level > 0) { \ p11prov_debug_slot(__VA_ARGS__); \ } \ } while (0) #define P11PROV_debug_once(...) \ do { \ if (debug_level < 0) { \ p11prov_debug_init(); \ } \ if (debug_level > 0) { \ static int called = 0; \ if (!called) { \ P11PROV_debug(__VA_ARGS__); \ called = 1; \ } \ } \ } while (0) void p11prov_debug_init(void); void p11prov_debug(const char *file, int line, const char *func, const char *fmt, ...); void p11prov_debug_mechanism(P11PROV_CTX *ctx, CK_SLOT_ID slotid, CK_MECHANISM_TYPE type); void p11prov_debug_slot(P11PROV_CTX *ctx, CK_SLOT_ID slotid, CK_SLOT_INFO *slot, CK_TOKEN_INFO *token, CK_MECHANISM_TYPE *mechs, CK_ULONG mechs_num, CK_ULONG *profiles); #endif /* _DEBUG_H */ pkcs11-provider-1.0/src/decoder.c000066400000000000000000000133601475270623700166640ustar00rootroot00000000000000/* Copyright (C) 2023 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include "decoder.h" #include "store.h" #include "util.h" #include "pk11_uri.h" #include #include typedef struct p11prov_decoder_ctx { P11PROV_CTX *provctx; } P11PROV_DECODER_CTX; static void *p11prov_decoder_newctx(void *provctx) { P11PROV_DECODER_CTX *dctx; dctx = OPENSSL_zalloc(sizeof(P11PROV_DECODER_CTX)); if (!dctx) { return NULL; } dctx->provctx = provctx; return dctx; } static void p11prov_decoder_freectx(void *ctx) { OPENSSL_clear_free(ctx, sizeof(P11PROV_DECODER_CTX)); } static int obj_desc_verify(P11PROV_PK11_URI *obj) { const char *desc = NULL; int desc_len; desc = (const char *)ASN1_STRING_get0_data(obj->desc); desc_len = ASN1_STRING_length(obj->desc); if (!desc || desc_len <= 0) { P11PROV_debug("Failed to get description"); return RET_OSSL_ERR; } if (desc_len != (sizeof(P11PROV_DESCS_URI_FILE) - 1) || 0 != strncmp(desc, P11PROV_DESCS_URI_FILE, desc_len)) { P11PROV_debug("Description string does not match"); return RET_OSSL_ERR; } return RET_OSSL_OK; } static char *obj_uri_get1(P11PROV_PK11_URI *obj) { const unsigned char *uri = ASN1_STRING_get0_data(obj->uri); int uri_len = ASN1_STRING_length(obj->uri); if (!uri || uri_len <= 0) { P11PROV_debug("Failed to get URI"); return NULL; } return p11prov_alloc_sprintf(uri_len, "%*s", uri_len, uri); } struct desired_data_type_cbdata { const char *desired_data_type; OSSL_CALLBACK *cb; void *cbarg; }; static int filter_for_desired_data_type(const OSSL_PARAM params[], void *arg) { struct desired_data_type_cbdata *cbdata = arg; const OSSL_PARAM *p = OSSL_PARAM_locate_const(params, OSSL_OBJECT_PARAM_DATA_TYPE); const char *data_type = NULL; if (p && OSSL_PARAM_get_utf8_string_ptr(p, &data_type) && 0 == strcmp(cbdata->desired_data_type, data_type)) { return cbdata->cb(params, cbdata->cbarg); } return RET_OSSL_CARRY_ON_DECODING; } static int load_obj(const P11PROV_DECODER_CTX *ctx, const unsigned char *der, long der_len, struct desired_data_type_cbdata *cbdata, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) { P11PROV_PK11_URI *obj = NULL; char *uri = NULL; obj = d2i_P11PROV_PK11_URI(NULL, &der, der_len); if (!obj) { P11PROV_debug("P11 KEY DECODER d2i_P11PROV_PK11_URI failed"); goto done; } if (!obj_desc_verify(obj)) { goto done; } uri = obj_uri_get1(obj); if (!uri) { goto done; } p11prov_store_direct_fetch(ctx->provctx, uri, filter_for_desired_data_type, cbdata, pw_cb, pw_cbarg); done: OPENSSL_free(uri); P11PROV_PK11_URI_free(obj); return RET_OSSL_CARRY_ON_DECODING; } static int p11prov_der_decoder_p11prov_obj_decode( const char *desired_data_type, void *inctx, OSSL_CORE_BIO *cin, int selection, OSSL_CALLBACK *object_cb, void *object_cbarg, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) { const P11PROV_DECODER_CTX *ctx = inctx; BIO *bin; unsigned char *der = NULL; long der_len; int ret = RET_OSSL_CARRY_ON_DECODING; bin = BIO_new_from_core_bio(p11prov_ctx_get_libctx(ctx->provctx), cin); if (!bin) { P11PROV_debug("P11 DECODER BIO_new_from_core_bio failed"); goto done; } der_len = BIO_get_mem_data(bin, &der); if (der_len <= 0) { P11PROV_debug("P11 DECODER BIO_get_mem_data failed"); goto done; } struct desired_data_type_cbdata cbdata = { .desired_data_type = desired_data_type, .cb = object_cb, .cbarg = object_cbarg, }; ret = load_obj(ctx, der, der_len, &cbdata, pw_cb, pw_cbarg); done: BIO_free(bin); P11PROV_debug("der decoder (carry on:%d)", ret); return ret; } static int p11prov_pem_decoder_p11prov_der_decode( void *inctx, OSSL_CORE_BIO *cin, int selection, OSSL_CALLBACK *object_cb, void *object_cbarg, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) { BIO *bin; char *pem_label; char *pem_header; unsigned char *der_data; long der_len; OSSL_PARAM params[3]; int ret = RET_OSSL_CARRY_ON_DECODING; P11PROV_DECODER_CTX *ctx = inctx; bin = BIO_new_from_core_bio(p11prov_ctx_get_libctx(ctx->provctx), cin); if (!bin) { P11PROV_debug("BIO_new_from_core_bio failed"); return RET_OSSL_CARRY_ON_DECODING; } P11PROV_debug("PEM_read_bio (fpos:%u)", BIO_tell(bin)); if (PEM_read_bio(bin, &pem_label, &pem_header, &der_data, &der_len) > 0 && strcmp(pem_label, P11PROV_PEM_LABEL) == 0) { params[0] = OSSL_PARAM_construct_octet_string(OSSL_OBJECT_PARAM_DATA, der_data, der_len); params[1] = OSSL_PARAM_construct_utf8_string( OSSL_OBJECT_PARAM_DATA_STRUCTURE, (char *)P11PROV_DER_STRUCTURE, 0); params[2] = OSSL_PARAM_construct_end(); ret = object_cb(params, object_cbarg); } OPENSSL_free(pem_label); OPENSSL_free(pem_header); OPENSSL_free(der_data); BIO_free(bin); P11PROV_debug("pem decoder (carry on:%d)", ret); return ret; } P11PROV_DER_COMMON_DECODE_FN(P11PROV_NAME_RSA, rsa) P11PROV_DER_COMMON_DECODE_FN(P11PROV_NAME_EC, ec) P11PROV_DER_COMMON_DECODE_FN(P11PROV_NAME_ED25519, ed25519) P11PROV_DER_COMMON_DECODE_FN(P11PROV_NAME_ED448, ed448) DISPATCH_DECODER_FN_LIST(pem, p11prov, der); DISPATCH_DECODER_FN_LIST(der, p11prov, rsa); DISPATCH_DECODER_FN_LIST(der, p11prov, ec); DISPATCH_DECODER_FN_LIST(der, p11prov, ed25519); DISPATCH_DECODER_FN_LIST(der, p11prov, ed448); pkcs11-provider-1.0/src/decoder.h000066400000000000000000000035161475270623700166730ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _DECODER_H #define _DECODER_H #include #define RET_OSSL_CARRY_ON_DECODING 1 #define RET_OSSL_STOP_DECODING 0 /* DECODERs */ #define DISPATCH_BASE_DECODER_ELEM(NAME, name) \ { \ OSSL_FUNC_DECODER_##NAME, (void (*)(void))p11prov_decoder_##name \ } #define DISPATCH_DECODER_ELEM(NAME, type, structure, format, name) \ { \ OSSL_FUNC_DECODER_##NAME, \ (void (*)( \ void))p11prov_##type##_decoder_##structure##_##format##_##name \ } #define DISPATCH_DECODER_FN_LIST(type, structure, format) \ const OSSL_DISPATCH \ p11prov_##type##_decoder_##structure##_##format##_functions[] = { \ DISPATCH_BASE_DECODER_ELEM(NEWCTX, newctx), \ DISPATCH_BASE_DECODER_ELEM(FREECTX, freectx), \ DISPATCH_DECODER_ELEM(DECODE, type, structure, format, decode), \ { 0, NULL } \ }; #define P11PROV_DER_COMMON_DECODE_FN(FORMAT_NAME, format) \ static int p11prov_der_decoder_p11prov_##format##_decode( \ void *inctx, OSSL_CORE_BIO *cin, int selection, \ OSSL_CALLBACK *object_cb, void *object_cbarg, \ OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) \ { \ return p11prov_der_decoder_p11prov_obj_decode( \ FORMAT_NAME, inctx, cin, selection, object_cb, object_cbarg, \ pw_cb, pw_cbarg); \ } extern const OSSL_DISPATCH p11prov_pem_decoder_p11prov_der_functions[]; extern const OSSL_DISPATCH p11prov_der_decoder_p11prov_rsa_functions[]; extern const OSSL_DISPATCH p11prov_der_decoder_p11prov_ec_functions[]; extern const OSSL_DISPATCH p11prov_der_decoder_p11prov_ed25519_functions[]; extern const OSSL_DISPATCH p11prov_der_decoder_p11prov_ed448_functions[]; #endif /* _DECODER_H */ pkcs11-provider-1.0/src/digests.c000066400000000000000000000353301475270623700167220ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include /* General Digest Mapping functions */ static struct { CK_MECHANISM_TYPE digest; size_t block_size; size_t digest_size; const char *names[5]; /* must give a size for initialization ... */ } digest_map[] = { { CKM_SHA_1, 64, 20, { "SHA1", "SHA-1", "SSL3-SHA1", "1.3.14.3.2.26", NULL } }, { CKM_SHA224, 64, 28, { "SHA2-224", "SHA-224", "SHA224", "2.16.840.1.101.3.4.2.4", NULL } }, { CKM_SHA256, 64, 32, { "SHA2-256", "SHA-256", "SHA256", "2.16.840.1.101.3.4.2.1", NULL } }, { CKM_SHA384, 128, 48, { "SHA2-384", "SHA-384", "SHA384", "2.16.840.1.101.3.4.2.2", NULL } }, { CKM_SHA512, 128, 64, { "SHA2-512", "SHA-512", "SHA512", "2.16.840.1.101.3.4.2.3", NULL } }, { CKM_SHA512_224, 128, 28, { "SHA2-512/224", "SHA-512/224", "SHA512-224", "2.16.840.1.101.3.4.2.5", NULL } }, { CKM_SHA512_256, 128, 32, { "SHA2-512/256", "SHA-512/256", "SHA512-256", "2.16.840.1.101.3.4.2.6", NULL } }, { CKM_SHA3_224, (1600 - 224 * 2) / 8, 28, { "SHA3-224", "2.16.840.1.101.3.4.2.7", NULL } }, { CKM_SHA3_256, (1600 - 256 * 2) / 8, 32, { "SHA3-256", "2.16.840.1.101.3.4.2.8", NULL } }, { CKM_SHA3_384, (1600 - 384 * 2) / 8, 48, { "SHA3-384", "2.16.840.1.101.3.4.2.9", NULL } }, { CKM_SHA3_512, (1600 - 512 * 2) / 8, 64, { "SHA3-512", "2.16.840.1.101.3.4.2.10", NULL } }, { CK_UNAVAILABLE_INFORMATION, 0, 0, { NULL } }, }; CK_RV p11prov_digest_get_block_size(CK_MECHANISM_TYPE digest, size_t *block_size) { for (int i = 0; digest_map[i].digest != CK_UNAVAILABLE_INFORMATION; i++) { if (digest_map[i].digest == digest) { *block_size = digest_map[i].block_size; return CKR_OK; } } return CKR_MECHANISM_INVALID; } CK_RV p11prov_digest_get_digest_size(CK_MECHANISM_TYPE digest, size_t *digest_size) { for (int i = 0; digest_map[i].digest != CK_UNAVAILABLE_INFORMATION; i++) { if (digest_map[i].digest == digest) { *digest_size = digest_map[i].digest_size; return CKR_OK; } } return CKR_MECHANISM_INVALID; } CK_RV p11prov_digest_get_name(CK_MECHANISM_TYPE digest, const char **name) { for (int i = 0; digest_map[i].digest != CK_UNAVAILABLE_INFORMATION; i++) { if (digest_map[i].digest == digest) { *name = digest_map[i].names[0]; return CKR_OK; } } return CKR_MECHANISM_INVALID; } CK_RV p11prov_digest_get_by_name(const char *name, CK_MECHANISM_TYPE *digest) { for (int i = 0; digest_map[i].digest != CK_UNAVAILABLE_INFORMATION; i++) { for (int j = 0; digest_map[i].names[j] != NULL; j++) { if (OPENSSL_strcasecmp(name, digest_map[i].names[j]) == 0) { *digest = digest_map[i].digest; return CKR_OK; } } } return CKR_MECHANISM_INVALID; } struct p11prov_digest_ctx { P11PROV_CTX *provctx; CK_MECHANISM_TYPE mechtype; P11PROV_SESSION *session; }; typedef struct p11prov_digest_ctx P11PROV_DIGEST_CTX; #define DISPATCH_DIGEST_NEWCTX_FN(mech, digest) \ static void *p11prov_##digest##_newctx(void *provctx) \ { \ P11PROV_DIGEST_CTX *dctx = OPENSSL_zalloc(sizeof(P11PROV_DIGEST_CTX)); \ if (dctx == NULL) { \ return NULL; \ } \ dctx->provctx = provctx; \ dctx->mechtype = mech; \ dctx->session = CK_INVALID_HANDLE; \ return dctx; \ } DISPATCH_DIGEST_NEWCTX_FN(CKM_SHA_1, sha1); DISPATCH_DIGEST_NEWCTX_FN(CKM_SHA224, sha224); DISPATCH_DIGEST_NEWCTX_FN(CKM_SHA256, sha256); DISPATCH_DIGEST_NEWCTX_FN(CKM_SHA384, sha384); DISPATCH_DIGEST_NEWCTX_FN(CKM_SHA512, sha512); DISPATCH_DIGEST_NEWCTX_FN(CKM_SHA512_224, sha512_224); DISPATCH_DIGEST_NEWCTX_FN(CKM_SHA512_256, sha512_256); DISPATCH_DIGEST_NEWCTX_FN(CKM_SHA3_224, sha3_224); DISPATCH_DIGEST_NEWCTX_FN(CKM_SHA3_256, sha3_256); DISPATCH_DIGEST_NEWCTX_FN(CKM_SHA3_384, sha3_384); DISPATCH_DIGEST_NEWCTX_FN(CKM_SHA3_512, sha3_512); DISPATCH_DIGEST_COMMON_FN(dupctx); DISPATCH_DIGEST_COMMON_FN(freectx); DISPATCH_DIGEST_COMMON_FN(init); DISPATCH_DIGEST_COMMON_FN(update); DISPATCH_DIGEST_COMMON_FN(final); DISPATCH_DIGEST_COMMON_FN(gettable_params); static void *p11prov_digest_dupctx(void *ctx) { P11PROV_DIGEST_CTX *dctx = (P11PROV_DIGEST_CTX *)ctx; P11PROV_DIGEST_CTX *newctx; CK_SLOT_ID slotid = CK_UNAVAILABLE_INFORMATION; CK_SESSION_HANDLE sess = CK_INVALID_HANDLE; CK_BYTE_PTR state = NULL; CK_ULONG state_len; CK_RV ret; P11PROV_debug("digest dupctx, ctx=%p", ctx); if (dctx == NULL) { return NULL; } newctx = OPENSSL_zalloc(sizeof(P11PROV_DIGEST_CTX)); if (newctx == NULL) { return NULL; } newctx->provctx = dctx->provctx; newctx->mechtype = dctx->mechtype; if (dctx->session == NULL) { return newctx; } /* This is not really funny. OpenSSL by default assumes contexts with * operations in flight can be easily duplicated, with all the * cryptographic status and then both context can keep going * independently. We'll try to save/restore state here, but on failure * we just 'move' the the session to the new context and hope there is no * need for the old context which will have no session and just return * errors if an update is attempted. */ sess = p11prov_session_handle(dctx->session); /* move old session to new context, we swap because often openssl continues * on the duplicated context by default */ newctx->session = dctx->session; dctx->session = NULL; /* NOTE: most tokens will probably return errors trying to do this on digest * sessions. If GetOperationState fails we don't even try to duplicate the * context. */ ret = p11prov_GetOperationState(dctx->provctx, sess, NULL_PTR, &state_len); if (ret != CKR_OK) { goto done; } state = OPENSSL_malloc(state_len); if (state == NULL) { goto done; } ret = p11prov_GetOperationState(dctx->provctx, sess, state, &state_len); if (ret != CKR_OK) { goto done; } ret = p11prov_get_session(dctx->provctx, &slotid, NULL, NULL, dctx->mechtype, NULL, NULL, false, false, &dctx->session); if (ret != CKR_OK) { P11PROV_raise(dctx->provctx, ret, "Failed to open new session"); goto done; } sess = p11prov_session_handle(dctx->session); ret = p11prov_SetOperationState(dctx->provctx, sess, state, state_len, CK_INVALID_HANDLE, CK_INVALID_HANDLE); if (ret != CKR_OK) { p11prov_return_session(dctx->session); dctx->session = NULL; } done: OPENSSL_free(state); return newctx; } static void p11prov_digest_freectx(void *ctx) { P11PROV_DIGEST_CTX *dctx = (P11PROV_DIGEST_CTX *)ctx; P11PROV_debug("digest freectx, ctx=%p", ctx); if (!ctx) { return; } p11prov_return_session(dctx->session); OPENSSL_clear_free(dctx, sizeof(P11PROV_DIGEST_CTX)); } static int p11prov_digest_init(void *ctx, const OSSL_PARAM params[]) { P11PROV_DIGEST_CTX *dctx = (P11PROV_DIGEST_CTX *)ctx; CK_SLOT_ID slotid = CK_UNAVAILABLE_INFORMATION; CK_SESSION_HANDLE sess = CK_INVALID_HANDLE; CK_MECHANISM mechanism = { 0 }; CK_RV ret; P11PROV_debug("digest init, ctx=%p", ctx); if (ctx == NULL) { return RET_OSSL_ERR; } ret = p11prov_ctx_status(dctx->provctx); if (ret != CKR_OK) { return RET_OSSL_ERR; } if (params != NULL) { const OSSL_PARAM *p; int err; p = OSSL_PARAM_locate_const(params, P11PROV_PARAM_SLOT_ID); if (p) { err = OSSL_PARAM_get_ulong(p, &slotid); if (err != RET_OSSL_OK) { P11PROV_raise(dctx->provctx, CKR_GENERAL_ERROR, "Invalid PARAM_SLOT_ID"); return err; } P11PROV_debug("Set PARAM_SLOT_ID to %lu", slotid); } } ret = p11prov_get_session(dctx->provctx, &slotid, NULL, NULL, dctx->mechtype, NULL, NULL, false, false, &dctx->session); if (ret != CKR_OK) { P11PROV_raise(dctx->provctx, ret, "Failed to open new session"); return RET_OSSL_ERR; } sess = p11prov_session_handle(dctx->session); mechanism.mechanism = dctx->mechtype; ret = p11prov_DigestInit(dctx->provctx, sess, &mechanism); if (ret != CKR_OK) { p11prov_return_session(dctx->session); dctx->session = NULL; return RET_OSSL_ERR; } return RET_OSSL_OK; } static int p11prov_digest_update(void *ctx, const unsigned char *data, size_t len) { P11PROV_DIGEST_CTX *dctx = (P11PROV_DIGEST_CTX *)ctx; CK_SESSION_HANDLE sess = CK_INVALID_HANDLE; CK_RV ret; P11PROV_debug("digest update, ctx=%p", ctx); if (ctx == NULL) { return RET_OSSL_ERR; } if (len == 0) { return RET_OSSL_OK; } sess = p11prov_session_handle(dctx->session); ret = p11prov_DigestUpdate(dctx->provctx, sess, (void *)data, len); if (ret != CKR_OK) { return RET_OSSL_ERR; } return RET_OSSL_OK; } static int p11prov_digest_final(void *ctx, unsigned char *out, size_t *size, size_t buf_size) { P11PROV_DIGEST_CTX *dctx = (P11PROV_DIGEST_CTX *)ctx; CK_SESSION_HANDLE sess = CK_INVALID_HANDLE; size_t digest_size; CK_ULONG digest_len; CK_RV ret; P11PROV_debug("digest update, ctx=%p", ctx); if (ctx == NULL) { return RET_OSSL_ERR; } ret = p11prov_digest_get_digest_size(dctx->mechtype, &digest_size); if (ret != CKR_OK) { P11PROV_raise(dctx->provctx, ret, "Unexpected get_digest_size error"); return RET_OSSL_ERR; } /* probing for buffer size to alloc */ if (buf_size == 0) { *size = digest_size; return RET_OSSL_OK; } else if (buf_size < digest_size) { P11PROV_raise(dctx->provctx, CKR_ARGUMENTS_BAD, "Digest output buffer too small %zd < %zd", buf_size, digest_size); return RET_OSSL_OK; } digest_len = digest_size; sess = p11prov_session_handle(dctx->session); ret = p11prov_DigestFinal(dctx->provctx, sess, out, &digest_len); if (ret != CKR_OK) { return RET_OSSL_ERR; } *size = digest_len; return RET_OSSL_OK; } static int p11prov_digest_get_params(CK_MECHANISM_TYPE digest, OSSL_PARAM params[]) { OSSL_PARAM *p = NULL; CK_RV ret; P11PROV_debug("digest get params: digest=%lX, params=%p", digest, params); p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_BLOCK_SIZE); if (p) { size_t block_size; ret = p11prov_digest_get_block_size(digest, &block_size); if (ret != CKR_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return RET_OSSL_ERR; } ret = OSSL_PARAM_set_size_t(p, block_size); if (ret != RET_OSSL_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); return RET_OSSL_ERR; } P11PROV_debug("block_size = %zd", block_size); } p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_SIZE); if (p) { size_t digest_size; ret = p11prov_digest_get_digest_size(digest, &digest_size); if (ret != CKR_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return RET_OSSL_ERR; } ret = OSSL_PARAM_set_size_t(p, digest_size); if (ret != RET_OSSL_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); return RET_OSSL_ERR; } P11PROV_debug("digest_size = %zd", digest_size); } p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_XOF); if (p) { ret = OSSL_PARAM_set_int(p, 0); if (ret != RET_OSSL_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); return RET_OSSL_ERR; } } p = OSSL_PARAM_locate(params, OSSL_DIGEST_PARAM_ALGID_ABSENT); if (p) { ret = OSSL_PARAM_set_int(p, 1); if (ret != RET_OSSL_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); return RET_OSSL_ERR; } } return RET_OSSL_OK; } #define DISPATCH_DIGEST_GET_PARAMS_FN(mech, digest) \ static int p11prov_##digest##_get_params(OSSL_PARAM params[]) \ { \ return p11prov_digest_get_params(mech, params); \ } DISPATCH_DIGEST_GET_PARAMS_FN(CKM_SHA_1, sha1); DISPATCH_DIGEST_GET_PARAMS_FN(CKM_SHA224, sha224); DISPATCH_DIGEST_GET_PARAMS_FN(CKM_SHA256, sha256); DISPATCH_DIGEST_GET_PARAMS_FN(CKM_SHA384, sha384); DISPATCH_DIGEST_GET_PARAMS_FN(CKM_SHA512, sha512); DISPATCH_DIGEST_GET_PARAMS_FN(CKM_SHA512_224, sha512_224); DISPATCH_DIGEST_GET_PARAMS_FN(CKM_SHA512_256, sha512_256); DISPATCH_DIGEST_GET_PARAMS_FN(CKM_SHA3_224, sha3_224); DISPATCH_DIGEST_GET_PARAMS_FN(CKM_SHA3_256, sha3_256); DISPATCH_DIGEST_GET_PARAMS_FN(CKM_SHA3_384, sha3_384); DISPATCH_DIGEST_GET_PARAMS_FN(CKM_SHA3_512, sha3_512); static const OSSL_PARAM *p11prov_digest_gettable_params(void *provctx) { P11PROV_debug("digest gettable params, ctx=%p", provctx); static const OSSL_PARAM digest_params[] = { OSSL_PARAM_size_t(OSSL_DIGEST_PARAM_BLOCK_SIZE, NULL), OSSL_PARAM_size_t(OSSL_DIGEST_PARAM_SIZE, NULL), OSSL_PARAM_int(OSSL_DIGEST_PARAM_XOF, NULL), OSSL_PARAM_int(OSSL_DIGEST_PARAM_ALGID_ABSENT, NULL), OSSL_PARAM_END, }; return digest_params; } #define DISPATCH_FUNCTION_TABLE(digest) \ const OSSL_DISPATCH p11prov_##digest##_digest_functions[] = { \ DISPATCH_DIGEST_ELEM(digest, NEWCTX, newctx), \ DISPATCH_DIGEST_COMMON(DUPCTX, dupctx), \ DISPATCH_DIGEST_COMMON(FREECTX, freectx), \ DISPATCH_DIGEST_COMMON(INIT, init), \ DISPATCH_DIGEST_COMMON(UPDATE, update), \ DISPATCH_DIGEST_COMMON(FINAL, final), \ DISPATCH_DIGEST_ELEM(digest, GET_PARAMS, get_params), \ DISPATCH_DIGEST_COMMON(GETTABLE_PARAMS, gettable_params), \ { 0, NULL }, \ } DISPATCH_FUNCTION_TABLE(sha1); DISPATCH_FUNCTION_TABLE(sha224); DISPATCH_FUNCTION_TABLE(sha256); DISPATCH_FUNCTION_TABLE(sha384); DISPATCH_FUNCTION_TABLE(sha512); DISPATCH_FUNCTION_TABLE(sha512_224); DISPATCH_FUNCTION_TABLE(sha512_256); DISPATCH_FUNCTION_TABLE(sha3_224); DISPATCH_FUNCTION_TABLE(sha3_256); DISPATCH_FUNCTION_TABLE(sha3_384); DISPATCH_FUNCTION_TABLE(sha3_512); pkcs11-provider-1.0/src/digests.h000066400000000000000000000063321475270623700167270ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _DIGESTS_H #define _DIGESTS_H /* Digests */ #define DISPATCH_DIGEST_COMMON_FN(name) \ DECL_DISPATCH_FUNC(digest, p11prov_digest, name) #define DISPATCH_DIGEST_COMMON(NAME, name) \ { \ OSSL_FUNC_DIGEST_##NAME, (void (*)(void))p11prov_digest_##name \ } #define DISPATCH_DIGEST_FN(type, name) \ DECL_DISPATCH_FUNC(digest, p11prov_##type, name) #define DISPATCH_DIGEST_ELEM(digest, NAME, name) \ { \ OSSL_FUNC_DIGEST_##NAME, (void (*)(void))p11prov_##digest##_##name \ } extern const OSSL_DISPATCH p11prov_sha1_digest_functions[]; extern const OSSL_DISPATCH p11prov_sha224_digest_functions[]; extern const OSSL_DISPATCH p11prov_sha256_digest_functions[]; extern const OSSL_DISPATCH p11prov_sha384_digest_functions[]; extern const OSSL_DISPATCH p11prov_sha512_digest_functions[]; extern const OSSL_DISPATCH p11prov_sha512_224_digest_functions[]; extern const OSSL_DISPATCH p11prov_sha512_256_digest_functions[]; extern const OSSL_DISPATCH p11prov_sha3_224_digest_functions[]; extern const OSSL_DISPATCH p11prov_sha3_256_digest_functions[]; extern const OSSL_DISPATCH p11prov_sha3_384_digest_functions[]; extern const OSSL_DISPATCH p11prov_sha3_512_digest_functions[]; #define P11PROV_NAMES_SHA1 "SHA1:SHA-1:SSL3-SHA1:1.3.14.3.2.26" #define P11PROV_DESCS_SHA1 "PKCS11 SHA1 Implementation" #define P11PROV_NAMES_SHA2_224 "SHA2-224:SHA-224:SHA224:2.16.840.1.101.3.4.2.4" #define P11PROV_DESCS_SHA2_224 "PKCS11 SHA2-224 Implementation" #define P11PROV_NAMES_SHA2_256 "SHA2-256:SHA-256:SHA256:2.16.840.1.101.3.4.2.1" #define P11PROV_DESCS_SHA2_256 "PKCS11 SHA2-256 Implementation" #define P11PROV_NAMES_SHA2_384 "SHA2-384:SHA-384:SHA384:2.16.840.1.101.3.4.2.2" #define P11PROV_DESCS_SHA2_384 "PKCS11 SHA2-384 Implementation" #define P11PROV_NAMES_SHA2_512 "SHA2-512:SHA-512:SHA512:2.16.840.1.101.3.4.2.3" #define P11PROV_DESCS_SHA2_512 "PKCS11 SHA2-512 Implementation" #define P11PROV_NAMES_SHA2_512_224 \ "SHA2-512/224:SHA-512/224:SHA512-224:2.16.840.1.101.3.4.2.5" #define P11PROV_DESCS_SHA2_512_224 "PKCS11 SHA2-512/224 Implementation" #define P11PROV_NAMES_SHA2_512_256 \ "SHA2-512/256:SHA-512/256:SHA512-256:2.16.840.1.101.3.4.2.6" #define P11PROV_DESCS_SHA2_512_256 "PKCS11 SHA2-512/224 Implementation" #define P11PROV_NAMES_SHA3_224 "SHA3-224:2.16.840.1.101.3.4.2.7" #define P11PROV_DESCS_SHA3_224 "PKCS11 SHA3-224 Implementation" #define P11PROV_NAMES_SHA3_256 "SHA3-256:2.16.840.1.101.3.4.2.8" #define P11PROV_DESCS_SHA3_256 "PKCS11 SHA3-256 Implementation" #define P11PROV_NAMES_SHA3_384 "SHA3-384:2.16.840.1.101.3.4.2.9" #define P11PROV_DESCS_SHA3_384 "PKCS11 SHA3-384 Implementation" #define P11PROV_NAMES_SHA3_512 "SHA3-512:2.16.840.1.101.3.4.2.10" #define P11PROV_DESCS_SHA3_512 "PKCS11 SHA3-512 Implementation" CK_RV p11prov_digest_get_block_size(CK_MECHANISM_TYPE digest, size_t *block_size); CK_RV p11prov_digest_get_digest_size(CK_MECHANISM_TYPE digest, size_t *digest_size); CK_RV p11prov_digest_get_name(CK_MECHANISM_TYPE digest, const char **name); CK_RV p11prov_digest_get_by_name(const char *name, CK_MECHANISM_TYPE *digest); #endif /* _DIGESTS_H */ pkcs11-provider-1.0/src/encoder.c000066400000000000000000000775371475270623700167160ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include "pk11_uri.h" #include #include #include static int p11prov_print_bn(BIO *out, const OSSL_PARAM *p, const char *str, int indent) { BIGNUM *bn = NULL; int ret; ret = OSSL_PARAM_get_BN(p, &bn); if (ret != RET_OSSL_OK) { return RET_OSSL_ERR; } ASN1_bn_print(out, str, bn, NULL, indent); BN_free(bn); return RET_OSSL_OK; } static int p11prov_print_buf(BIO *out, const OSSL_PARAM *p, const char *str, int indent) { if (p->data_type != OSSL_PARAM_OCTET_STRING) { return RET_OSSL_ERR; } BIO_printf(out, "%s\n", str); ASN1_buf_print(out, p->data, p->data_size, indent); return RET_OSSL_OK; } DISPATCH_BASE_ENCODER_FN(newctx); DISPATCH_BASE_ENCODER_FN(freectx); DISPATCH_ENCODER_FN(common, priv_key_info, pem, does_selection); struct p11prov_encoder_ctx { P11PROV_CTX *provctx; }; static void *p11prov_encoder_newctx(void *provctx) { struct p11prov_encoder_ctx *ctx; ctx = OPENSSL_zalloc(sizeof(struct p11prov_encoder_ctx)); if (!ctx) { P11PROV_raise(provctx, CKR_HOST_MEMORY, "Allocation failed"); return NULL; } ctx->provctx = provctx; return ctx; } static void p11prov_encoder_freectx(void *ctx) { OPENSSL_free(ctx); } DISPATCH_TEXT_ENCODER_FN(rsa, encode); static int p11prov_rsa_print_public_key(const OSSL_PARAM *params, void *bio) { BIO *out = (BIO *)bio; const OSSL_PARAM *p; int ret; /* Modulus */ p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_N); if (p) { ret = p11prov_print_bn(out, p, "Modulus:", 0); if (ret != RET_OSSL_OK) { return RET_OSSL_ERR; } } /* Exponent */ p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_E); if (p) { ret = p11prov_print_bn(out, p, "Exponent:", 0); if (ret != RET_OSSL_OK) { return RET_OSSL_ERR; } } return RET_OSSL_OK; } static int p11prov_rsa_encoder_encode_text(void *inctx, OSSL_CORE_BIO *cbio, const void *inkey, const OSSL_PARAM key_abstract[], int selection, OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) { struct p11prov_encoder_ctx *ctx = (struct p11prov_encoder_ctx *)inctx; P11PROV_OBJ *key = (P11PROV_OBJ *)inkey; CK_KEY_TYPE type; CK_OBJECT_CLASS class; CK_ULONG keysize; char *uri = NULL; BIO *out; int ret; P11PROV_debug("RSA Text Encoder"); type = p11prov_obj_get_key_type(key); if (type != CKK_RSA) { P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Invalid Key Type"); return RET_OSSL_ERR; } class = p11prov_obj_get_class(key); out = BIO_new_from_core_bio(p11prov_ctx_get_libctx(ctx->provctx), cbio); if (!out) { P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Failed to init BIO"); return RET_OSSL_ERR; } keysize = p11prov_obj_get_key_bit_size(key); if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { if (class != CKO_PRIVATE_KEY) { BIO_printf(out, "[Error: Invalid key data]\n"); goto done; } BIO_printf(out, "PKCS11 RSA Private Key (%lu bits)\n", keysize); BIO_printf(out, "[Can't export and print private key data]\n"); } if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { if (class != CKO_PUBLIC_KEY) { P11PROV_OBJ *assoc; assoc = p11prov_obj_find_associated(key, CKO_PUBLIC_KEY); if (!assoc) { BIO_printf(out, "[Error: Failed to source public key data]\n"); goto done; } /* replace key before printing the rest */ key = assoc; } BIO_printf(out, "PKCS11 RSA Public Key (%lu bits)\n", keysize); ret = p11prov_obj_export_public_key(key, CKK_RSA, true, false, p11prov_rsa_print_public_key, out); if (ret != RET_OSSL_OK) { BIO_printf(out, "[Error: Failed to decode public key data]\n"); } } uri = p11prov_key_to_uri(ctx->provctx, key); if (uri) { BIO_printf(out, "URI %s\n", uri); OPENSSL_free(uri); } done: if (key != inkey) { p11prov_obj_free(key); } BIO_free(out); return RET_OSSL_OK; } const OSSL_DISPATCH p11prov_rsa_encoder_text_functions[] = { DISPATCH_BASE_ENCODER_ELEM(NEWCTX, newctx), DISPATCH_BASE_ENCODER_ELEM(FREECTX, freectx), DISPATCH_TEXT_ENCODER_ELEM(ENCODE, rsa, encode_text), { 0, NULL }, }; #include "encoder.gen.c" static int p11prov_rsa_set_asn1key_data(const OSSL_PARAM *params, void *key) { P11PROV_RSA_PUBKEY *asn1key = (P11PROV_RSA_PUBKEY *)key; const OSSL_PARAM *p; void *aret = NULL; BIGNUM *n = NULL; BIGNUM *e = NULL; int ret; /* Modulus */ p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_N); if (!p) { ret = RET_OSSL_ERR; goto done; } ret = OSSL_PARAM_get_BN(p, &n); if (ret != RET_OSSL_OK) { goto done; } aret = BN_to_ASN1_INTEGER(n, asn1key->n); if (!aret) { ret = RET_OSSL_ERR; goto done; } /* Exponent */ p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_E); if (!p) { ret = RET_OSSL_ERR; goto done; } ret = OSSL_PARAM_get_BN(p, &e); if (ret != RET_OSSL_OK) { return ret; } aret = BN_to_ASN1_INTEGER(e, asn1key->e); if (!aret) { ret = RET_OSSL_ERR; goto done; } ret = RET_OSSL_OK; done: BN_free(n); BN_free(e); return ret; } static P11PROV_RSA_PUBKEY *p11prov_rsa_pubkey_to_asn1(P11PROV_OBJ *key) { P11PROV_RSA_PUBKEY *asn1key; int ret; asn1key = P11PROV_RSA_PUBKEY_new(); if (!asn1key) { return NULL; } ret = p11prov_obj_export_public_key(key, CKK_RSA, true, false, p11prov_rsa_set_asn1key_data, asn1key); if (ret != RET_OSSL_OK) { P11PROV_RSA_PUBKEY_free(asn1key); return NULL; } return asn1key; } static int p11prov_rsa_pubkey_to_der(P11PROV_OBJ *key, unsigned char **der, int *derlen) { P11PROV_RSA_PUBKEY *asn1key; asn1key = p11prov_rsa_pubkey_to_asn1(key); if (!asn1key) { return RET_OSSL_ERR; } *derlen = i2d_P11PROV_RSA_PUBKEY(asn1key, der); if (*derlen < 0) { return RET_OSSL_ERR; } P11PROV_RSA_PUBKEY_free(asn1key); return RET_OSSL_OK; } static X509_PUBKEY *p11prov_rsa_pubkey_to_x509(P11PROV_OBJ *key) { X509_PUBKEY *pubkey; unsigned char *der = NULL; int derlen = 0; int ret, nid, ptype; ASN1_STRING *pval = NULL; ret = p11prov_rsa_pubkey_to_der(key, &der, &derlen); if (ret != RET_OSSL_OK) { return NULL; } pubkey = X509_PUBKEY_new(); if (!pubkey) { OPENSSL_free(der); return NULL; } if (p11prov_obj_is_rsa_pss(key)) { nid = NID_rsassaPss; /* This is RSA-PSS key without additional restrictions */ pval = NULL; ptype = V_ASN1_UNDEF; /* TODO implement restrictions here based on ALLOWED_MECHANISMS */ } else { /* this is generic RSA key without restrictions */ nid = NID_rsaEncryption; ptype = V_ASN1_NULL; } ret = X509_PUBKEY_set0_param(pubkey, OBJ_nid2obj(nid), ptype, pval, der, derlen); if (ret != RET_OSSL_OK) { OPENSSL_free(der); X509_PUBKEY_free(pubkey); return NULL; } return pubkey; } DISPATCH_ENCODER_FN(rsa, pkcs1, der, does_selection); static int p11prov_rsa_encoder_pkcs1_der_does_selection(void *inctx, int selection) { return RET_OSSL_ERR; } static int p11prov_rsa_encoder_pkcs1_der_encode( void *inctx, OSSL_CORE_BIO *cbio, const void *inkey, const OSSL_PARAM key_abstract[], int selection, OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) { return RET_OSSL_ERR; } const OSSL_DISPATCH p11prov_rsa_encoder_pkcs1_der_functions[] = { DISPATCH_BASE_ENCODER_ELEM(NEWCTX, newctx), DISPATCH_BASE_ENCODER_ELEM(FREECTX, freectx), DISPATCH_ENCODER_ELEM(DOES_SELECTION, rsa, pkcs1, der, does_selection), DISPATCH_ENCODER_ELEM(ENCODE, rsa, pkcs1, der, encode), { 0, NULL }, }; DISPATCH_ENCODER_FN(rsa, pkcs1, pem, does_selection); static int p11prov_rsa_encoder_pkcs1_pem_does_selection(void *inctx, int selection) { return RET_OSSL_ERR; } static int p11prov_rsa_encoder_pkcs1_pem_encode( void *inctx, OSSL_CORE_BIO *cbio, const void *inkey, const OSSL_PARAM key_abstract[], int selection, OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) { return RET_OSSL_ERR; } const OSSL_DISPATCH p11prov_rsa_encoder_pkcs1_pem_functions[] = { DISPATCH_BASE_ENCODER_ELEM(NEWCTX, newctx), DISPATCH_BASE_ENCODER_ELEM(FREECTX, freectx), DISPATCH_ENCODER_ELEM(DOES_SELECTION, rsa, pkcs1, pem, does_selection), DISPATCH_ENCODER_ELEM(ENCODE, rsa, pkcs1, pem, encode), { 0, NULL }, }; /* SubjectPublicKeyInfo DER Encode */ DISPATCH_ENCODER_FN(rsa, spki, der, does_selection); static int p11prov_rsa_encoder_spki_der_does_selection(void *inctx, int selection) { if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { return RET_OSSL_OK; } return RET_OSSL_ERR; } static int p11prov_rsa_encoder_spki_der_encode(void *inctx, OSSL_CORE_BIO *cbio, const void *inkey, const OSSL_PARAM key_abstract[], int selection, OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) { struct p11prov_encoder_ctx *ctx = (struct p11prov_encoder_ctx *)inctx; P11PROV_OBJ *key = (P11PROV_OBJ *)inkey; CK_KEY_TYPE type; X509_PUBKEY *pubkey = NULL; BIO *out = NULL; int ret; P11PROV_debug("RSA SubjectPublicKeyInfo DER Encoder"); /* we only return public key info */ if (!(selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY)) { return RET_OSSL_ERR; } type = p11prov_obj_get_key_type(key); if (type != CKK_RSA) { P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Invalid Key Type"); ret = RET_OSSL_ERR; goto done; } out = BIO_new_from_core_bio(p11prov_ctx_get_libctx(ctx->provctx), cbio); if (!out) { P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Failed to init BIO"); ret = RET_OSSL_ERR; goto done; } pubkey = p11prov_rsa_pubkey_to_x509(key); if (!pubkey) { ret = RET_OSSL_ERR; goto done; } ret = i2d_X509_PUBKEY_bio(out, pubkey); done: X509_PUBKEY_free(pubkey); BIO_free(out); return ret; } const OSSL_DISPATCH p11prov_rsa_encoder_spki_der_functions[] = { DISPATCH_BASE_ENCODER_ELEM(NEWCTX, newctx), DISPATCH_BASE_ENCODER_ELEM(FREECTX, freectx), DISPATCH_ENCODER_ELEM(DOES_SELECTION, rsa, spki, der, does_selection), DISPATCH_ENCODER_ELEM(ENCODE, rsa, spki, der, encode), { 0, NULL }, }; /* SubjectPublicKeyInfo PEM Encode */ DISPATCH_ENCODER_FN(rsa, spki, pem, does_selection); static int p11prov_rsa_encoder_spki_pem_does_selection(void *inctx, int selection) { if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { return RET_OSSL_OK; } return RET_OSSL_ERR; } static int p11prov_rsa_encoder_spki_pem_encode(void *inctx, OSSL_CORE_BIO *cbio, const void *inkey, const OSSL_PARAM key_abstract[], int selection, OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) { struct p11prov_encoder_ctx *ctx = (struct p11prov_encoder_ctx *)inctx; P11PROV_OBJ *key = (P11PROV_OBJ *)inkey; CK_KEY_TYPE type; P11PROV_RSA_PUBKEY *asn1key = NULL; BIO *out = NULL; int ret; P11PROV_debug("RSA PKCS1 PEM Encoder"); /* we only return public key info */ if (!(selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY)) { return RET_OSSL_ERR; } type = p11prov_obj_get_key_type(key); if (type != CKK_RSA) { P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Invalid Key Type"); ret = RET_OSSL_ERR; goto done; } asn1key = p11prov_rsa_pubkey_to_asn1(key); if (!asn1key) { ret = RET_OSSL_ERR; goto done; } out = BIO_new_from_core_bio(p11prov_ctx_get_libctx(ctx->provctx), cbio); if (!out) { P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Failed to init BIO"); ret = RET_OSSL_ERR; goto done; } ret = PEM_write_bio_P11PROV_RSA_PUBKEY(out, asn1key); done: P11PROV_RSA_PUBKEY_free(asn1key); BIO_free(out); return ret; } const OSSL_DISPATCH p11prov_rsa_encoder_spki_pem_functions[] = { DISPATCH_BASE_ENCODER_ELEM(NEWCTX, newctx), DISPATCH_BASE_ENCODER_ELEM(FREECTX, freectx), DISPATCH_ENCODER_ELEM(DOES_SELECTION, rsa, spki, pem, does_selection), DISPATCH_ENCODER_ELEM(ENCODE, rsa, spki, pem, encode), { 0, NULL }, }; static P11PROV_PK11_URI *p11prov_encoder_private_key_to_asn1(P11PROV_CTX *pctx, P11PROV_OBJ *key) { P11PROV_PK11_URI *out = NULL; char *uri = NULL; size_t uri_len; int ret = RET_OSSL_ERR; uri = p11prov_key_to_uri(pctx, key); if (!uri) { goto done; } uri_len = strlen(uri); P11PROV_debug("uri=%s", uri); out = P11PROV_PK11_URI_new(); if (!out) { goto done; } if (!ASN1_STRING_set(out->desc, P11PROV_DESCS_URI_FILE, sizeof(P11PROV_DESCS_URI_FILE) - 1)) { goto done; } if (!ASN1_STRING_set(out->uri, uri, uri_len)) { goto done; } ret = RET_OSSL_OK; done: OPENSSL_free(uri); if (ret != RET_OSSL_OK) { P11PROV_PK11_URI_free(out); out = NULL; } return out; } static int p11prov_encoder_private_key_write_pem( CK_KEY_TYPE expected_key_type, void *inctx, OSSL_CORE_BIO *cbio, const void *inkey, const OSSL_PARAM key_abstract[], int selection, OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) { struct p11prov_encoder_ctx *ctx = (struct p11prov_encoder_ctx *)inctx; P11PROV_OBJ *key = (P11PROV_OBJ *)inkey; CK_KEY_TYPE key_type; P11PROV_PK11_URI *asn1 = NULL; BIO *out = NULL; int ret; key_type = p11prov_obj_get_key_type(key); if (key_type != expected_key_type) { P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Key type mismatch (actual:%lu,expected:%lu)", key_type, expected_key_type); ret = RET_OSSL_ERR; goto done; } asn1 = p11prov_encoder_private_key_to_asn1(ctx->provctx, key); if (!asn1) { P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Failed to encode private key"); ret = RET_OSSL_ERR; goto done; } out = BIO_new_from_core_bio(p11prov_ctx_get_libctx(ctx->provctx), cbio); if (!out) { P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Failed to init BIO"); ret = RET_OSSL_ERR; goto done; } ret = PEM_write_bio_P11PROV_PK11_URI(out, asn1); if (ret != RET_OSSL_OK) { P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Failed to write BIO PEM"); goto done; } done: P11PROV_PK11_URI_free(asn1); BIO_free(out); return ret; } static int p11prov_rsa_encoder_priv_key_info_pem_encode( void *inctx, OSSL_CORE_BIO *cbio, const void *inkey, const OSSL_PARAM key_abstract[], int selection, OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) { return p11prov_encoder_private_key_write_pem( CKK_RSA, inctx, cbio, inkey, key_abstract, selection, cb, cbarg); } const OSSL_DISPATCH p11prov_rsa_encoder_priv_key_info_pem_functions[] = { DISPATCH_BASE_ENCODER_ELEM(NEWCTX, newctx), DISPATCH_BASE_ENCODER_ELEM(FREECTX, freectx), DISPATCH_ENCODER_ELEM(DOES_SELECTION, common, priv_key_info, pem, does_selection), DISPATCH_ENCODER_ELEM(ENCODE, rsa, priv_key_info, pem, encode), { 0, NULL }, }; /* ECDSA */ struct ecdsa_key_point { union { ASN1_OBJECT *object; ASN1_STRING *sequence; } curve; unsigned char *octet; int curve_type; size_t octet_len; }; static void ecdsa_key_point_free(struct ecdsa_key_point *k) { if (k->curve_type == V_ASN1_SEQUENCE) { ASN1_STRING_free(k->curve.sequence); } else if (k->curve_type == V_ASN1_OBJECT) { ASN1_OBJECT_free(k->curve.object); } k->curve.object = NULL; k->curve_type = V_ASN1_UNDEF; if (k->octet) { OPENSSL_free(k->octet); k->octet = NULL; } k->octet_len = 0; } static int p11prov_ec_set_keypoint_data(const OSSL_PARAM *params, void *key) { struct ecdsa_key_point *keypoint = (struct ecdsa_key_point *)key; const OSSL_PARAM *p; p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME); if (p) { if (p->data_type != OSSL_PARAM_UTF8_STRING) { return RET_OSSL_ERR; } keypoint->curve.object = OBJ_txt2obj(p->data, 0); if (!keypoint->curve.object) { return RET_OSSL_ERR; } keypoint->curve_type = V_ASN1_OBJECT; } else { EC_GROUP *group = EC_GROUP_new_from_params(params, NULL, NULL); if (!group) { return RET_OSSL_ERR; } ASN1_STRING *pstr = NULL; pstr = ASN1_STRING_new(); if (pstr == NULL) { EC_GROUP_free(group); return RET_OSSL_ERR; } pstr->length = i2d_ECPKParameters(group, &pstr->data); EC_GROUP_free(group); if (pstr->length <= 0) { ASN1_STRING_free(pstr); return RET_OSSL_ERR; } keypoint->curve.sequence = pstr; keypoint->curve_type = V_ASN1_SEQUENCE; } p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY); if (!p) { return RET_OSSL_ERR; } if (p->data_type != OSSL_PARAM_OCTET_STRING) { return RET_OSSL_ERR; } keypoint->octet = OPENSSL_memdup(p->data, p->data_size); if (!keypoint->octet) { return RET_OSSL_ERR; } keypoint->octet_len = p->data_size; return RET_OSSL_OK; } static X509_PUBKEY *p11prov_ec_pubkey_to_x509(P11PROV_OBJ *key) { struct ecdsa_key_point keypoint = { 0 }; X509_PUBKEY *pubkey; int ret; ret = p11prov_obj_export_public_key( key, CKK_EC, true, false, p11prov_ec_set_keypoint_data, &keypoint); if (ret != RET_OSSL_OK) { ecdsa_key_point_free(&keypoint); return NULL; } pubkey = X509_PUBKEY_new(); if (!pubkey) { ecdsa_key_point_free(&keypoint); return NULL; } ret = X509_PUBKEY_set0_param(pubkey, OBJ_nid2obj(NID_X9_62_id_ecPublicKey), keypoint.curve_type, keypoint.curve.object, keypoint.octet, keypoint.octet_len); if (ret != RET_OSSL_OK) { ecdsa_key_point_free(&keypoint); X509_PUBKEY_free(pubkey); return NULL; } return pubkey; } DISPATCH_ENCODER_FN(ec, pkcs1, der, does_selection); static int p11prov_ec_encoder_pkcs1_der_does_selection(void *inctx, int selection) { return RET_OSSL_ERR; } static int p11prov_ec_encoder_pkcs1_der_encode(void *inctx, OSSL_CORE_BIO *cbio, const void *inkey, const OSSL_PARAM key_abstract[], int selection, OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) { return RET_OSSL_ERR; } const OSSL_DISPATCH p11prov_ec_encoder_pkcs1_der_functions[] = { DISPATCH_BASE_ENCODER_ELEM(NEWCTX, newctx), DISPATCH_BASE_ENCODER_ELEM(FREECTX, freectx), DISPATCH_ENCODER_ELEM(DOES_SELECTION, ec, pkcs1, der, does_selection), DISPATCH_ENCODER_ELEM(ENCODE, ec, pkcs1, der, encode), { 0, NULL }, }; DISPATCH_ENCODER_FN(ec, pkcs1, pem, does_selection); static int p11prov_ec_encoder_pkcs1_pem_does_selection(void *inctx, int selection) { return RET_OSSL_ERR; } static int p11prov_ec_encoder_pkcs1_pem_encode(void *inctx, OSSL_CORE_BIO *cbio, const void *inkey, const OSSL_PARAM key_abstract[], int selection, OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) { return RET_OSSL_ERR; } const OSSL_DISPATCH p11prov_ec_encoder_pkcs1_pem_functions[] = { DISPATCH_BASE_ENCODER_ELEM(NEWCTX, newctx), DISPATCH_BASE_ENCODER_ELEM(FREECTX, freectx), DISPATCH_ENCODER_ELEM(DOES_SELECTION, ec, pkcs1, pem, does_selection), DISPATCH_ENCODER_ELEM(ENCODE, ec, pkcs1, pem, encode), { 0, NULL }, }; /* SubjectPublicKeyInfo DER Encode */ DISPATCH_ENCODER_FN(ec, spki, der, does_selection); static int p11prov_ec_encoder_spki_der_does_selection(void *inctx, int selection) { if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { return RET_OSSL_OK; } return RET_OSSL_ERR; } static int p11prov_ec_encoder_spki_der_encode(void *inctx, OSSL_CORE_BIO *cbio, const void *inkey, const OSSL_PARAM key_abstract[], int selection, OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) { struct p11prov_encoder_ctx *ctx = (struct p11prov_encoder_ctx *)inctx; P11PROV_OBJ *key = (P11PROV_OBJ *)inkey; CK_KEY_TYPE type; X509_PUBKEY *pubkey = NULL; BIO *out = NULL; int ret; P11PROV_debug("EC SubjectPublicKeyInfo DER Encoder"); /* we only return public key info */ if (!(selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY)) { return RET_OSSL_ERR; } type = p11prov_obj_get_key_type(key); if (type != CKK_EC) { P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Invalid Key Type"); ret = RET_OSSL_ERR; goto done; } out = BIO_new_from_core_bio(p11prov_ctx_get_libctx(ctx->provctx), cbio); if (!out) { P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Failed to init BIO"); ret = RET_OSSL_ERR; goto done; } pubkey = p11prov_ec_pubkey_to_x509(key); if (!pubkey) { ret = RET_OSSL_ERR; goto done; } ret = i2d_X509_PUBKEY_bio(out, pubkey); done: X509_PUBKEY_free(pubkey); BIO_free(out); return ret; } const OSSL_DISPATCH p11prov_ec_encoder_spki_der_functions[] = { DISPATCH_BASE_ENCODER_ELEM(NEWCTX, newctx), DISPATCH_BASE_ENCODER_ELEM(FREECTX, freectx), DISPATCH_ENCODER_ELEM(DOES_SELECTION, ec, spki, der, does_selection), DISPATCH_ENCODER_ELEM(ENCODE, ec, spki, der, encode), { 0, NULL }, }; DISPATCH_TEXT_ENCODER_FN(ec, encode); static int p11prov_ec_print_public_key(const OSSL_PARAM *params, void *bio) { BIO *out = (BIO *)bio; const OSSL_PARAM *p; int ret; /* Pub key */ p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY); if (p) { ret = p11prov_print_buf(out, p, "Pub:", 4); if (ret != RET_OSSL_OK) { return RET_OSSL_ERR; } } /* Name */ p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME); if (p) { const char *name; int nid; ret = OSSL_PARAM_get_utf8_string_ptr(p, &name); if (ret != RET_OSSL_OK) { return RET_OSSL_ERR; } BIO_printf(out, "ASN1 OID: %s\n", name); /* Print also NIST name if any */ nid = OBJ_txt2nid(name); if (nid != NID_undef) { name = EC_curve_nid2nist(nid); if (name) { BIO_printf(out, "NIST CURVE: %s\n", name); } } } return RET_OSSL_OK; } static int p11prov_ec_encoder_encode_text(void *inctx, OSSL_CORE_BIO *cbio, const void *inkey, const OSSL_PARAM key_abstract[], int selection, OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) { struct p11prov_encoder_ctx *ctx = (struct p11prov_encoder_ctx *)inctx; P11PROV_OBJ *key = (P11PROV_OBJ *)inkey; CK_KEY_TYPE type; CK_OBJECT_CLASS class; CK_ULONG keysize; char *uri = NULL; BIO *out; int ret; P11PROV_debug("EC Text Encoder"); type = p11prov_obj_get_key_type(key); if (type != CKK_EC) { P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Invalid Key Type"); return RET_OSSL_ERR; } class = p11prov_obj_get_class(key); out = BIO_new_from_core_bio(p11prov_ctx_get_libctx(ctx->provctx), cbio); if (!out) { P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Failed to init BIO"); return RET_OSSL_ERR; } keysize = p11prov_obj_get_key_bit_size(key); if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { if (class != CKO_PRIVATE_KEY) { BIO_printf(out, "[Error: Invalid key data]\n"); goto done; } BIO_printf(out, "PKCS11 EC Private Key (%lu bits)\n", keysize); BIO_printf(out, "[Can't export and print private key data]\n"); } if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { if (class != CKO_PUBLIC_KEY) { P11PROV_OBJ *assoc; assoc = p11prov_obj_find_associated(key, CKO_PUBLIC_KEY); if (!assoc) { BIO_printf(out, "[Error: Failed to source public key data]\n"); goto done; } /* replace key before printing the rest */ key = assoc; } BIO_printf(out, "PKCS11 EC Public Key (%lu bits)\n", keysize); ret = p11prov_obj_export_public_key(key, CKK_EC, true, false, p11prov_ec_print_public_key, out); if (ret != RET_OSSL_OK) { BIO_printf(out, "[Error: Failed to decode public key data]\n"); } } uri = p11prov_key_to_uri(ctx->provctx, key); if (uri) { BIO_printf(out, "URI %s\n", uri); OPENSSL_free(uri); } done: if (key != inkey) { p11prov_obj_free(key); } BIO_free(out); return RET_OSSL_OK; } const OSSL_DISPATCH p11prov_ec_encoder_text_functions[] = { DISPATCH_BASE_ENCODER_ELEM(NEWCTX, newctx), DISPATCH_BASE_ENCODER_ELEM(FREECTX, freectx), DISPATCH_TEXT_ENCODER_ELEM(ENCODE, ec, encode_text), { 0, NULL }, }; static int p11prov_ec_encoder_priv_key_info_pem_encode( void *inctx, OSSL_CORE_BIO *cbio, const void *inkey, const OSSL_PARAM key_abstract[], int selection, OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) { return p11prov_encoder_private_key_write_pem( CKK_EC, inctx, cbio, inkey, key_abstract, selection, cb, cbarg); } const OSSL_DISPATCH p11prov_ec_encoder_priv_key_info_pem_functions[] = { DISPATCH_BASE_ENCODER_ELEM(NEWCTX, newctx), DISPATCH_BASE_ENCODER_ELEM(FREECTX, freectx), DISPATCH_ENCODER_ELEM(DOES_SELECTION, common, priv_key_info, pem, does_selection), DISPATCH_ENCODER_ELEM(ENCODE, ec, priv_key_info, pem, encode), { 0, NULL }, }; static int p11prov_ec_edwards_encoder_priv_key_info_pem_encode( void *inctx, OSSL_CORE_BIO *cbio, const void *inkey, const OSSL_PARAM key_abstract[], int selection, OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) { return p11prov_encoder_private_key_write_pem( CKK_EC_EDWARDS, inctx, cbio, inkey, key_abstract, selection, cb, cbarg); } const OSSL_DISPATCH p11prov_ec_edwards_encoder_priv_key_info_pem_functions[] = { DISPATCH_BASE_ENCODER_ELEM(NEWCTX, newctx), DISPATCH_BASE_ENCODER_ELEM(FREECTX, freectx), DISPATCH_ENCODER_ELEM(DOES_SELECTION, common, priv_key_info, pem, does_selection), DISPATCH_ENCODER_ELEM(ENCODE, ec_edwards, priv_key_info, pem, encode), { 0, NULL }, }; static int p11prov_common_encoder_priv_key_info_pem_does_selection(void *inctx, int selection) { if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { return RET_OSSL_OK; } return RET_OSSL_ERR; } DISPATCH_TEXT_ENCODER_FN(ec_edwards, encode); static int p11prov_ec_edwards_encoder_encode_text( void *inctx, OSSL_CORE_BIO *cbio, const void *inkey, const OSSL_PARAM key_abstract[], int selection, OSSL_PASSPHRASE_CALLBACK *cb, void *cbarg) { struct p11prov_encoder_ctx *ctx = (struct p11prov_encoder_ctx *)inctx; P11PROV_OBJ *key = (P11PROV_OBJ *)inkey; CK_KEY_TYPE type; CK_OBJECT_CLASS class; CK_ULONG keysize; const char *type_name = ED25519; char *uri = NULL; BIO *out; int ret; P11PROV_debug("EdDSA Text Encoder"); type = p11prov_obj_get_key_type(key); if (type != CKK_EC_EDWARDS) { P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Invalid Key Type"); return RET_OSSL_ERR; } class = p11prov_obj_get_class(key); out = BIO_new_from_core_bio(p11prov_ctx_get_libctx(ctx->provctx), cbio); if (!out) { P11PROV_raise(ctx->provctx, CKR_GENERAL_ERROR, "Failed to init BIO"); return RET_OSSL_ERR; } keysize = p11prov_obj_get_key_bit_size(key); if (keysize == ED448_BIT_SIZE) { type_name = ED448; } if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { if (class != CKO_PRIVATE_KEY) { BIO_printf(out, "[Error: Invalid key data]\n"); goto done; } BIO_printf(out, "PKCS11 %s Private Key (%lu bits)\n", type_name, keysize); BIO_printf(out, "[Can't export and print private key data]\n"); } if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { if (class != CKO_PUBLIC_KEY) { P11PROV_OBJ *assoc; assoc = p11prov_obj_find_associated(key, CKO_PUBLIC_KEY); if (!assoc) { BIO_printf(out, "[Error: Failed to source public key data]\n"); goto done; } /* replace key before printing the rest */ key = assoc; } BIO_printf(out, "PKCS11 %s Public Key (%lu bits)\n", type_name, keysize); ret = p11prov_obj_export_public_key(key, CKK_EC_EDWARDS, true, false, p11prov_ec_print_public_key, out); /* FIXME if we want print in different format */ if (ret != RET_OSSL_OK) { BIO_printf(out, "[Error: Failed to decode public key data]\n"); } } uri = p11prov_key_to_uri(ctx->provctx, key); if (uri) { BIO_printf(out, "URI %s\n", uri); OPENSSL_free(uri); } done: if (key != inkey) { p11prov_obj_free(key); } BIO_free(out); return RET_OSSL_OK; } const OSSL_DISPATCH p11prov_ec_edwards_encoder_text_functions[] = { DISPATCH_BASE_ENCODER_ELEM(NEWCTX, newctx), DISPATCH_BASE_ENCODER_ELEM(FREECTX, freectx), DISPATCH_TEXT_ENCODER_ELEM(ENCODE, ec_edwards, encode_text), { 0, NULL }, }; pkcs11-provider-1.0/src/encoder.gen.c000066400000000000000000000050571475270623700174520ustar00rootroot00000000000000/* DO NOT EDIT, autogenerated from src/encoder.pre */ /* Modify src/encoder.pre then run make generate-code */ typedef struct { ASN1_INTEGER *n; ASN1_INTEGER *e; } P11PROV_RSA_PUBKEY; extern P11PROV_RSA_PUBKEY *P11PROV_RSA_PUBKEY_new(void); extern void P11PROV_RSA_PUBKEY_free(P11PROV_RSA_PUBKEY *a); extern P11PROV_RSA_PUBKEY *d2i_P11PROV_RSA_PUBKEY(P11PROV_RSA_PUBKEY **a, const unsigned char **in, long len); extern int i2d_P11PROV_RSA_PUBKEY(const P11PROV_RSA_PUBKEY *a, unsigned char **out); extern const ASN1_ITEM *P11PROV_RSA_PUBKEY_it(void); P11PROV_RSA_PUBKEY *d2i_P11PROV_RSA_PUBKEY(P11PROV_RSA_PUBKEY **a, const unsigned char **in, long len) { return (P11PROV_RSA_PUBKEY *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, (P11PROV_RSA_PUBKEY_it())); } int i2d_P11PROV_RSA_PUBKEY(const P11PROV_RSA_PUBKEY *a, unsigned char **out) { return ASN1_item_i2d((const ASN1_VALUE *)a, out, (P11PROV_RSA_PUBKEY_it())); } P11PROV_RSA_PUBKEY *P11PROV_RSA_PUBKEY_new(void) { return (P11PROV_RSA_PUBKEY *)ASN1_item_new((P11PROV_RSA_PUBKEY_it())); } void P11PROV_RSA_PUBKEY_free(P11PROV_RSA_PUBKEY *a) { ASN1_item_free((ASN1_VALUE *)a, (P11PROV_RSA_PUBKEY_it())); } static const ASN1_TEMPLATE P11PROV_RSA_PUBKEY_seq_tt[] = { { (0), (0), __builtin_offsetof(P11PROV_RSA_PUBKEY, n), "n", (ASN1_INTEGER_it) }, { (0), (0), __builtin_offsetof(P11PROV_RSA_PUBKEY, e), "e", (ASN1_INTEGER_it) }, }; const ASN1_ITEM *P11PROV_RSA_PUBKEY_it(void) { static const ASN1_ITEM local_it = { 0x1, 16, P11PROV_RSA_PUBKEY_seq_tt, sizeof(P11PROV_RSA_PUBKEY_seq_tt) / sizeof(ASN1_TEMPLATE), ((void *)0), sizeof(P11PROV_RSA_PUBKEY), "P11PROV_RSA_PUBKEY" }; return &local_it; } extern int PEM_write_bio_P11PROV_RSA_PUBKEY(BIO *out, const P11PROV_RSA_PUBKEY *x); int PEM_write_bio_P11PROV_RSA_PUBKEY(BIO *out, const P11PROV_RSA_PUBKEY *x) { return PEM_ASN1_write_bio((i2d_of_void *)i2d_P11PROV_RSA_PUBKEY, "RSA PUBLIC KEY", out, x, ((void *)0), ((void *)0), 0, ((void *)0), ((void *)0)); } pkcs11-provider-1.0/src/encoder.h000066400000000000000000000037541475270623700167110ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _ENCODER_H #define _ENCODER_H /* Encoders */ #define DISPATCH_TEXT_ENCODER_FN(type, name) \ static OSSL_FUNC_encoder_##name##_fn p11prov_##type##_encoder_##name##_text #define DISPATCH_TEXT_ENCODER_ELEM(NAME, type, name) \ { \ OSSL_FUNC_ENCODER_##NAME, \ (void (*)(void))p11prov_##type##_encoder_##name \ } #define DISPATCH_BASE_ENCODER_FN(name) \ DECL_DISPATCH_FUNC(encoder, p11prov_encoder, name) #define DISPATCH_BASE_ENCODER_ELEM(NAME, name) \ { \ OSSL_FUNC_ENCODER_##NAME, (void (*)(void))p11prov_encoder_##name \ } #define DISPATCH_ENCODER_FN(type, structure, format, name) \ DECL_DISPATCH_FUNC(encoder, \ p11prov_##type##_encoder_##structure##_##format, name) #define DISPATCH_ENCODER_ELEM(NAME, type, structure, format, name) \ { \ OSSL_FUNC_ENCODER_##NAME, \ (void (*)( \ void))p11prov_##type##_encoder_##structure##_##format##_##name \ } extern const OSSL_DISPATCH p11prov_rsa_encoder_text_functions[]; extern const OSSL_DISPATCH p11prov_rsa_encoder_pkcs1_der_functions[]; extern const OSSL_DISPATCH p11prov_rsa_encoder_pkcs1_pem_functions[]; extern const OSSL_DISPATCH p11prov_rsa_encoder_spki_der_functions[]; extern const OSSL_DISPATCH p11prov_rsa_encoder_spki_pem_functions[]; extern const OSSL_DISPATCH p11prov_rsa_encoder_priv_key_info_pem_functions[]; extern const OSSL_DISPATCH p11prov_ec_encoder_text_functions[]; extern const OSSL_DISPATCH p11prov_ec_encoder_pkcs1_der_functions[]; extern const OSSL_DISPATCH p11prov_ec_encoder_pkcs1_pem_functions[]; extern const OSSL_DISPATCH p11prov_ec_encoder_spki_der_functions[]; extern const OSSL_DISPATCH p11prov_ec_encoder_priv_key_info_pem_functions[]; extern const OSSL_DISPATCH p11prov_ec_edwards_encoder_priv_key_info_pem_functions[]; extern const OSSL_DISPATCH p11prov_ec_edwards_encoder_text_functions[]; #endif /* _ENCODER_H */ pkcs11-provider-1.0/src/encoder.pre000066400000000000000000000013021475270623700172330ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include #include BEGIN: typedef struct { ASN1_INTEGER *n; ASN1_INTEGER *e; } P11PROV_RSA_PUBKEY; DECLARE_ASN1_FUNCTIONS(P11PROV_RSA_PUBKEY) IMPLEMENT_ASN1_FUNCTIONS(P11PROV_RSA_PUBKEY) ASN1_SEQUENCE(P11PROV_RSA_PUBKEY) = { ASN1_SIMPLE(P11PROV_RSA_PUBKEY, n, ASN1_INTEGER), ASN1_SIMPLE(P11PROV_RSA_PUBKEY, e, ASN1_INTEGER), } ASN1_SEQUENCE_END(P11PROV_RSA_PUBKEY) DECLARE_PEM_write_bio(P11PROV_RSA_PUBKEY, P11PROV_RSA_PUBKEY) IMPLEMENT_PEM_write_bio(P11PROV_RSA_PUBKEY, P11PROV_RSA_PUBKEY, PEM_STRING_RSA_PUBLIC, P11PROV_RSA_PUBKEY) pkcs11-provider-1.0/src/exchange.c000066400000000000000000000467051475270623700170520ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include #include struct p11prov_exch_ctx { P11PROV_CTX *provctx; P11PROV_OBJ *key; P11PROV_OBJ *peer_key; CK_MECHANISM_TYPE mechtype; CK_MECHANISM_TYPE digest; CK_ECDH1_DERIVE_PARAMS ecdh_params; CK_ULONG kdf_outlen; void *kdfctx; }; typedef struct p11prov_exch_ctx P11PROV_EXCH_CTX; #define DM_ELEM_SHA(bits) \ { \ .digest = CKM_SHA##bits, .kdf = CKD_SHA##bits##_KDF \ } #define DM_ELEM_SHA3(bits) \ { \ .digest = CKM_SHA3_##bits, .kdf = CKD_SHA3_##bits##_KDF \ } /* only the ones we can support */ static struct { CK_MECHANISM_TYPE digest; CK_RSA_PKCS_MGF_TYPE kdf; } kdf_map[] = { DM_ELEM_SHA3(256), DM_ELEM_SHA3(512), DM_ELEM_SHA3(384), DM_ELEM_SHA3(224), DM_ELEM_SHA(256), DM_ELEM_SHA(512), DM_ELEM_SHA(384), DM_ELEM_SHA(224), { CKM_SHA_1, CKD_SHA1_KDF }, { CK_UNAVAILABLE_INFORMATION, 0 }, }; static CK_ULONG p11prov_ecdh_digest_to_kdf(CK_MECHANISM_TYPE digest) { for (int i = 0; kdf_map[i].digest != CK_UNAVAILABLE_INFORMATION; i++) { if (digest == kdf_map[i].digest) { return kdf_map[i].kdf; } } return CK_UNAVAILABLE_INFORMATION; } DISPATCH_ECDH_FN(newctx); DISPATCH_ECDH_FN(dupctx); DISPATCH_ECDH_FN(freectx); DISPATCH_ECDH_FN(init); DISPATCH_ECDH_FN(set_peer); DISPATCH_ECDH_FN(derive); DISPATCH_ECDH_FN(set_ctx_params); DISPATCH_ECDH_FN(settable_ctx_params); DISPATCH_ECDH_FN(get_ctx_params); DISPATCH_ECDH_FN(gettable_ctx_params); static void *p11prov_ecdh_newctx(void *provctx) { P11PROV_CTX *ctx = (P11PROV_CTX *)provctx; P11PROV_EXCH_CTX *ecdhctx; ecdhctx = OPENSSL_zalloc(sizeof(P11PROV_EXCH_CTX)); if (ecdhctx == NULL) { return NULL; } ecdhctx->provctx = ctx; /* default mechanism */ ecdhctx->mechtype = CKM_ECDH1_DERIVE; /* default KDF */ ecdhctx->ecdh_params.kdf = CKD_NULL; return ecdhctx; } static void *p11prov_ecdh_dupctx(void *ctx) { P11PROV_EXCH_CTX *ecdhctx = (P11PROV_EXCH_CTX *)ctx; P11PROV_EXCH_CTX *newctx; if (ecdhctx == NULL) { return NULL; } newctx = p11prov_ecdh_newctx(ecdhctx->provctx); if (newctx == NULL) { return NULL; } newctx->key = p11prov_obj_ref(ecdhctx->key); newctx->peer_key = p11prov_obj_ref(ecdhctx->peer_key); newctx->mechtype = ecdhctx->mechtype; /* copy ecdh params */ newctx->ecdh_params.kdf = ecdhctx->ecdh_params.kdf; if (ecdhctx->ecdh_params.ulSharedDataLen > 0) { newctx->ecdh_params.ulSharedDataLen = ecdhctx->ecdh_params.ulSharedDataLen; newctx->ecdh_params.pSharedData = OPENSSL_memdup(ecdhctx->ecdh_params.pSharedData, ecdhctx->ecdh_params.ulSharedDataLen); if (newctx->ecdh_params.pSharedData == NULL) { p11prov_ecdh_freectx(newctx); return NULL; } } if (ecdhctx->ecdh_params.ulPublicDataLen > 0) { newctx->ecdh_params.ulPublicDataLen = ecdhctx->ecdh_params.ulPublicDataLen; newctx->ecdh_params.pPublicData = OPENSSL_memdup(ecdhctx->ecdh_params.pPublicData, ecdhctx->ecdh_params.ulPublicDataLen); if (newctx->ecdh_params.pPublicData == NULL) { p11prov_ecdh_freectx(newctx); return NULL; } } return newctx; } static void p11prov_ecdh_freectx(void *ctx) { P11PROV_EXCH_CTX *ecdhctx = (P11PROV_EXCH_CTX *)ctx; if (ecdhctx == NULL) { return; } p11prov_obj_free(ecdhctx->key); p11prov_obj_free(ecdhctx->peer_key); OPENSSL_clear_free(ecdhctx->ecdh_params.pSharedData, ecdhctx->ecdh_params.ulSharedDataLen); OPENSSL_clear_free(ecdhctx, sizeof(P11PROV_EXCH_CTX)); } static int p11prov_ecdh_init(void *ctx, void *provkey, const OSSL_PARAM params[]) { P11PROV_EXCH_CTX *ecdhctx = (P11PROV_EXCH_CTX *)ctx; P11PROV_OBJ *key = (P11PROV_OBJ *)provkey; CK_RV ret; if (ctx == NULL || provkey == NULL) { return RET_OSSL_ERR; } ret = p11prov_ctx_status(ecdhctx->provctx); if (ret != CKR_OK) { return RET_OSSL_ERR; } p11prov_obj_free(ecdhctx->key); ecdhctx->key = p11prov_obj_ref(key); if (ecdhctx->key == NULL) { P11PROV_raise(ecdhctx->provctx, CKR_ARGUMENTS_BAD, "Invalid object"); return RET_OSSL_ERR; } if (p11prov_obj_get_class(ecdhctx->key) != CKO_PRIVATE_KEY) { P11PROV_raise(ecdhctx->provctx, CKR_ARGUMENTS_BAD, "Invalid key class"); return RET_OSSL_ERR; } return p11prov_ecdh_set_ctx_params(ctx, params); } static int p11prov_ecdh_set_peer(void *ctx, void *provkey) { P11PROV_EXCH_CTX *ecdhctx = (P11PROV_EXCH_CTX *)ctx; P11PROV_OBJ *key = (P11PROV_OBJ *)provkey; if (ctx == NULL || provkey == NULL) { return RET_OSSL_ERR; } p11prov_obj_free(ecdhctx->peer_key); ecdhctx->peer_key = p11prov_obj_ref(key); if (ecdhctx->peer_key == NULL) { P11PROV_raise(ecdhctx->provctx, CKR_ARGUMENTS_BAD, "Invalid object"); return RET_OSSL_ERR; } if (p11prov_obj_get_class(ecdhctx->peer_key) != CKO_PUBLIC_KEY) { P11PROV_raise(ecdhctx->provctx, CKR_ARGUMENTS_BAD, "Invalid key class"); return RET_OSSL_ERR; } return RET_OSSL_OK; } static int p11prov_ecdh_derive(void *ctx, unsigned char *secret, size_t *psecretlen, size_t outlen) { P11PROV_EXCH_CTX *ecdhctx = (P11PROV_EXCH_CTX *)ctx; CK_ATTRIBUTE *ec_point; CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; CK_KEY_TYPE key_type = CKK_GENERIC_SECRET; CK_BBOOL val_true = CK_TRUE; CK_BBOOL val_false = CK_FALSE; CK_ULONG key_size = outlen; CK_ATTRIBUTE key_template[6] = { { CKA_CLASS, &key_class, sizeof(key_class) }, { CKA_KEY_TYPE, &key_type, sizeof(key_type) }, { CKA_SENSITIVE, &val_false, sizeof(val_false) }, { CKA_EXTRACTABLE, &val_true, sizeof(val_true) }, { CKA_VALUE_LEN, &key_size, sizeof(key_size) }, { CKA_TOKEN, &val_false, sizeof(val_false) }, }; CK_MECHANISM mechanism; P11PROV_SESSION *session = NULL; CK_OBJECT_HANDLE handle; CK_OBJECT_HANDLE secret_handle; CK_SLOT_ID slotid; struct fetch_attrs attrs[1]; int num = 0; CK_RV ret; if (ecdhctx->key == NULL || ecdhctx->peer_key == NULL) { ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); return RET_OSSL_ERR; } if (secret == NULL) { *psecretlen = p11prov_obj_get_key_size(ecdhctx->key); return RET_OSSL_OK; } /* set up mechanism */ if (ecdhctx->ecdh_params.kdf == CKF_DIGEST) { ecdhctx->ecdh_params.kdf = p11prov_ecdh_digest_to_kdf(ecdhctx->digest); if (ecdhctx->ecdh_params.kdf == CK_UNAVAILABLE_INFORMATION) { return RET_OSSL_ERR; } } ec_point = p11prov_obj_get_ec_public_raw(ecdhctx->peer_key); if (ec_point == NULL) { return RET_OSSL_ERR; } ecdhctx->ecdh_params.pPublicData = ec_point->pValue; ecdhctx->ecdh_params.ulPublicDataLen = ec_point->ulValueLen; mechanism.mechanism = ecdhctx->mechtype; mechanism.pParameter = &ecdhctx->ecdh_params; mechanism.ulParameterLen = sizeof(ecdhctx->ecdh_params); /* complete key template */ if (ecdhctx->kdf_outlen) { if (ecdhctx->kdf_outlen < outlen) { key_size = ecdhctx->kdf_outlen; } } handle = p11prov_obj_get_handle(ecdhctx->key); if (handle == CK_INVALID_HANDLE) { P11PROV_raise(ecdhctx->provctx, CKR_KEY_HANDLE_INVALID, "Provided key has invalid handle"); return RET_OSSL_ERR; } slotid = p11prov_obj_get_slotid(ecdhctx->key); if (slotid == CK_UNAVAILABLE_INFORMATION) { P11PROV_raise(ecdhctx->provctx, CKR_SLOT_ID_INVALID, "Provided key has invalid slot"); return RET_OSSL_ERR; } ret = p11prov_derive_key(ecdhctx->provctx, slotid, &mechanism, handle, key_template, 6, &session, &secret_handle); if (ret != CKR_OK) { return RET_OSSL_ERR; } P11PROV_debug("ECDH derived hey handle: %lu", secret_handle); FA_SET_BUF_VAL(attrs, num, CKA_VALUE, secret, key_size, true); ret = p11prov_fetch_attributes(ecdhctx->provctx, session, secret_handle, attrs, num); p11prov_return_session(session); if (ret != CKR_OK) { P11PROV_debug("ecdh failed to retrieve secret %lu", ret); return RET_OSSL_ERR; } FA_GET_LEN(attrs, 0, *psecretlen); return RET_OSSL_OK; } static int p11prov_ecdh_set_ctx_params(void *ctx, const OSSL_PARAM params[]) { P11PROV_EXCH_CTX *ecdhctx = (P11PROV_EXCH_CTX *)ctx; const OSSL_PARAM *p; int ret; P11PROV_debug("ecdh set ctx params (ctx=%p, params=%p)", ecdhctx, params); if (params == NULL) { return RET_OSSL_OK; } p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE); if (p) { int mode; ret = OSSL_PARAM_get_int(p, &mode); if (ret != RET_OSSL_OK) { return ret; } if (mode < -1 || mode > 1) { return RET_OSSL_ERR; } if (mode == 0) { ecdhctx->mechtype = CKM_ECDH1_DERIVE; } else { ecdhctx->mechtype = CKM_ECDH1_COFACTOR_DERIVE; } } p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_TYPE); if (p) { const char *name = NULL; ret = OSSL_PARAM_get_utf8_string_ptr(p, &name); if (ret != RET_OSSL_OK) { return ret; } if (name[0] == '\0') { ecdhctx->ecdh_params.kdf = CKD_NULL; } else if (strcmp(name, OSSL_KDF_NAME_X963KDF) == 0) { /* not really a KDF, but signals that a digest * KDF will need to be used. Need to set a signal * because openssl allows digest to set in any order * so we need to know that an actual KDF is wanted * as opposed to a malformed case where a digest was * set, but ultimately KDF_NULL was chosen * * CKF_DIGEST works here as it is a much higher value * than any CKD so it won't conflict, and just error * if mistakenly passed into a token. * */ ecdhctx->ecdh_params.kdf = CKF_DIGEST; } else { return RET_OSSL_ERR; } } p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST); if (p) { const char *digest = NULL; CK_RV rv; ret = OSSL_PARAM_get_utf8_string_ptr(p, &digest); if (ret != RET_OSSL_OK) { return ret; } rv = p11prov_digest_get_by_name(digest, &ecdhctx->digest); if (rv != CKR_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return RET_OSSL_ERR; } } p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN); if (p) { size_t outlen; ret = OSSL_PARAM_get_size_t(p, &outlen); if (ret != RET_OSSL_OK) { return ret; } ecdhctx->kdf_outlen = outlen; } p = OSSL_PARAM_locate_const(params, OSSL_EXCHANGE_PARAM_KDF_UKM); if (p) { void *ukm = NULL; size_t ukm_len; ret = OSSL_PARAM_get_octet_string(p, &ukm, 0, &ukm_len); if (ret != RET_OSSL_OK) { return ret; } OPENSSL_free(ecdhctx->ecdh_params.pSharedData); ecdhctx->ecdh_params.pSharedData = ukm; ecdhctx->ecdh_params.ulSharedDataLen = ukm_len; } return RET_OSSL_OK; } static const OSSL_PARAM *p11prov_ecdh_settable_ctx_params(void *ctx, void *prov) { static const OSSL_PARAM params[] = { OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, NULL), OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0), OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0), OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0), OSSL_PARAM_END, }; return params; } static int p11prov_ecdh_get_ctx_params(void *ctx, OSSL_PARAM *params) { P11PROV_EXCH_CTX *ecdhctx = (P11PROV_EXCH_CTX *)ctx; OSSL_PARAM *p; int ret; P11PROV_debug("ecdh get ctx params (ctx=%p, params=%p)", ctx, params); p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE); if (p) { int mode = (ecdhctx->mechtype == CKM_ECDH1_DERIVE) ? 0 : 1; ret = OSSL_PARAM_set_int(p, mode); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_TYPE); if (p) { if (ecdhctx->ecdh_params.kdf == CKD_NULL) { ret = OSSL_PARAM_set_utf8_string(p, ""); } else { ret = OSSL_PARAM_set_utf8_string(p, OSSL_KDF_NAME_X963KDF); } if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_DIGEST); if (p) { const char *digest; CK_RV rv; rv = p11prov_digest_get_name(ecdhctx->digest, &digest); if (rv != CKR_OK) { return RET_OSSL_ERR; } ret = OSSL_PARAM_set_utf8_string(p, digest); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_OUTLEN); if (p) { ret = OSSL_PARAM_set_size_t(p, ecdhctx->kdf_outlen); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_EXCHANGE_PARAM_KDF_UKM); if (p) { ret = OSSL_PARAM_set_octet_ptr(p, ecdhctx->ecdh_params.pSharedData, ecdhctx->ecdh_params.ulSharedDataLen); if (ret != RET_OSSL_OK) { return ret; } } return RET_OSSL_OK; } static const OSSL_PARAM *p11prov_ecdh_gettable_ctx_params(void *ctx, void *prov) { static const OSSL_PARAM params[] = { OSSL_PARAM_int(OSSL_EXCHANGE_PARAM_EC_ECDH_COFACTOR_MODE, NULL), OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_TYPE, NULL, 0), OSSL_PARAM_utf8_string(OSSL_EXCHANGE_PARAM_KDF_DIGEST, NULL, 0), OSSL_PARAM_size_t(OSSL_EXCHANGE_PARAM_KDF_OUTLEN, NULL), OSSL_PARAM_octet_string(OSSL_EXCHANGE_PARAM_KDF_UKM, NULL, 0), OSSL_PARAM_END, }; return params; } const OSSL_DISPATCH p11prov_ecdh_exchange_functions[] = { DISPATCH_ECDH_ELEM(ecdh, NEWCTX, newctx), DISPATCH_ECDH_ELEM(ecdh, DUPCTX, dupctx), DISPATCH_ECDH_ELEM(ecdh, FREECTX, freectx), DISPATCH_ECDH_ELEM(ecdh, INIT, init), DISPATCH_ECDH_ELEM(ecdh, DERIVE, derive), DISPATCH_ECDH_ELEM(ecdh, SET_PEER, set_peer), DISPATCH_ECDH_ELEM(ecdh, SET_CTX_PARAMS, set_ctx_params), DISPATCH_ECDH_ELEM(ecdh, SETTABLE_CTX_PARAMS, settable_ctx_params), DISPATCH_ECDH_ELEM(ecdh, GET_CTX_PARAMS, get_ctx_params), DISPATCH_ECDH_ELEM(ecdh, GETTABLE_CTX_PARAMS, gettable_ctx_params), { 0, NULL }, }; /* unclear why OpenSSL makes KDFs go through a middle "exchange" layer * when there is a direct KDF facility. I can only assume this is * because for some reason they want the command line -derive command * to be able to handle both key exchanges like ECDH and symmetric key * derivation done by KDFs via the -kdf selector */ DISPATCH_EXCHHKDF_FN(newctx); DISPATCH_EXCHHKDF_FN(freectx); DISPATCH_EXCHHKDF_FN(init); DISPATCH_EXCHHKDF_FN(derive); DISPATCH_EXCHHKDF_FN(set_ctx_params); DISPATCH_EXCHHKDF_FN(settable_ctx_params); static void *p11prov_exch_hkdf_newctx(void *provctx) { P11PROV_CTX *ctx = (P11PROV_CTX *)provctx; P11PROV_EXCH_CTX *hkdfctx; EVP_KDF *kdf = NULL; P11PROV_debug("hkdf exchange newctx"); hkdfctx = OPENSSL_zalloc(sizeof(P11PROV_EXCH_CTX)); if (hkdfctx == NULL) { return NULL; } hkdfctx->provctx = ctx; /* mark with mechanism type */ hkdfctx->mechtype = CKM_HKDF_DERIVE; kdf = EVP_KDF_fetch(NULL, "HKDF", P11PROV_DEFAULT_PROPERTIES); if (kdf == NULL) { OPENSSL_free(hkdfctx); return NULL; } hkdfctx->kdfctx = EVP_KDF_CTX_new(kdf); EVP_KDF_free(kdf); if (hkdfctx->kdfctx == NULL) { OPENSSL_free(hkdfctx); return NULL; } return hkdfctx; } static void p11prov_exch_hkdf_freectx(void *ctx) { P11PROV_EXCH_CTX *hkdfctx = (P11PROV_EXCH_CTX *)ctx; P11PROV_debug("hkdf exchange freectx"); if (hkdfctx == NULL) { return; } EVP_KDF_CTX_free(hkdfctx->kdfctx); p11prov_obj_free(hkdfctx->key); OPENSSL_clear_free(hkdfctx, sizeof(P11PROV_EXCH_CTX)); } static int p11prov_exch_hkdf_init(void *ctx, void *provkey, const OSSL_PARAM params[]) { P11PROV_EXCH_CTX *hkdfctx = (P11PROV_EXCH_CTX *)ctx; P11PROV_OBJ *key = (P11PROV_OBJ *)provkey; CK_RV ret; P11PROV_debug("hkdf exchange init (ctx:%p key:%p params:%p)", ctx, key, params); if (ctx == NULL || provkey == NULL) { return RET_OSSL_ERR; } ret = p11prov_ctx_status(hkdfctx->provctx); if (ret != CKR_OK) { return RET_OSSL_ERR; } if (provkey != &p11prov_hkdf_static_ctx) { p11prov_obj_free(hkdfctx->key); hkdfctx->key = p11prov_obj_ref(key); if (hkdfctx->key == NULL) { P11PROV_raise(hkdfctx->provctx, CKR_ARGUMENTS_BAD, "Invalid object"); return RET_OSSL_ERR; } if (p11prov_obj_get_class(hkdfctx->key) != CKO_PRIVATE_KEY) { P11PROV_raise(hkdfctx->provctx, CKR_ARGUMENTS_BAD, "Invalid key class"); return RET_OSSL_ERR; } } return p11prov_exch_hkdf_set_ctx_params(ctx, params); } static int p11prov_exch_hkdf_derive(void *ctx, unsigned char *secret, size_t *secretlen, size_t outlen) { P11PROV_EXCH_CTX *hkdfctx = (P11PROV_EXCH_CTX *)ctx; P11PROV_debug("hkdf exchange derive (ctx:%p)", ctx); if (secret == NULL) { *secretlen = EVP_KDF_CTX_get_kdf_size(hkdfctx->kdfctx); return 1; } return EVP_KDF_derive(hkdfctx->kdfctx, secret, outlen, NULL); } static int p11prov_exch_hkdf_set_ctx_params(void *ctx, const OSSL_PARAM params[]) { P11PROV_EXCH_CTX *hkdfctx = (P11PROV_EXCH_CTX *)ctx; P11PROV_debug("hkdf exchange set ctx params (ctx:%p, params:%p)", ctx, params); return EVP_KDF_CTX_set_params(hkdfctx->kdfctx, params); } static const OSSL_PARAM *p11prov_exch_hkdf_settable_ctx_params(void *ctx, void *provctx) { const OSSL_PARAM *params; EVP_KDF *kdf; kdf = EVP_KDF_fetch(NULL, "HKDF", P11PROV_DEFAULT_PROPERTIES); if (kdf == NULL) { return NULL; } params = EVP_KDF_settable_ctx_params(kdf); EVP_KDF_free(kdf); return params; } const OSSL_DISPATCH p11prov_hkdf_exchange_functions[] = { DISPATCH_EXCHHKDF_ELEM(exch_hkdf, NEWCTX, newctx), DISPATCH_EXCHHKDF_ELEM(exch_hkdf, FREECTX, freectx), DISPATCH_EXCHHKDF_ELEM(exch_hkdf, INIT, init), DISPATCH_EXCHHKDF_ELEM(exch_hkdf, DERIVE, derive), DISPATCH_EXCHHKDF_ELEM(exch_hkdf, SET_CTX_PARAMS, set_ctx_params), DISPATCH_EXCHHKDF_ELEM(exch_hkdf, SETTABLE_CTX_PARAMS, settable_ctx_params), { 0, NULL }, }; pkcs11-provider-1.0/src/exchange.h000066400000000000000000000014271475270623700170470ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _EXCHANGE_H #define _EXCHANGE_H /* ecdh derivation */ #define DISPATCH_ECDH_FN(name) DECL_DISPATCH_FUNC(keyexch, p11prov_ecdh, name) #define DISPATCH_ECDH_ELEM(prefix, NAME, name) \ { \ OSSL_FUNC_KEYEXCH_##NAME, (void (*)(void))p11prov_##prefix##_##name \ } extern const OSSL_DISPATCH p11prov_ecdh_exchange_functions[]; /* HKDF exchange fns */ #define DISPATCH_EXCHHKDF_FN(name) \ DECL_DISPATCH_FUNC(keyexch, p11prov_exch_hkdf, name) #define DISPATCH_EXCHHKDF_ELEM(prefix, NAME, name) \ { \ OSSL_FUNC_KEYEXCH_##NAME, (void (*)(void))p11prov_##prefix##_##name \ } extern const OSSL_DISPATCH p11prov_hkdf_exchange_functions[]; #endif /* _EXCHANGE_H */ pkcs11-provider-1.0/src/interface.c000066400000000000000000000334761475270623700172310ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include #include /* Wrapper Interface on top of PKCS#11 interfaces. * This allows us to support multiple versions of PKCS#11 drivers * at runtime by emulating or returning the proper error if a 3.0 * only function is used on a 2.40 token. */ struct p11prov_module_ctx { P11PROV_CTX *provctx; char *path; char *init_args; void *dlhandle; P11PROV_INTERFACE *interface; CK_INFO ck_info; pthread_mutex_t lock; bool initialized; bool reinit; }; /* This structure is effectively equivalent to CK_FUNCTION_LIST_3_0 * however we list only the symbols we are actually using in the * code plus flags */ struct p11prov_interface { CK_VERSION version; CK_FLAGS flags; CK_C_Initialize Initialize; CK_C_Finalize Finalize; CK_C_GetInfo GetInfo; CK_C_GetFunctionList GetFunctionList; CK_C_GetSlotList GetSlotList; CK_C_GetSlotInfo GetSlotInfo; CK_C_GetTokenInfo GetTokenInfo; CK_C_GetMechanismList GetMechanismList; CK_C_GetMechanismInfo GetMechanismInfo; CK_C_OpenSession OpenSession; CK_C_CloseSession CloseSession; CK_C_GetSessionInfo GetSessionInfo; CK_C_GetOperationState GetOperationState; CK_C_SetOperationState SetOperationState; CK_C_Login Login; CK_C_CreateObject CreateObject; CK_C_CopyObject CopyObject; CK_C_DestroyObject DestroyObject; CK_C_GetAttributeValue GetAttributeValue; CK_C_SetAttributeValue SetAttributeValue; CK_C_FindObjectsInit FindObjectsInit; CK_C_FindObjects FindObjects; CK_C_FindObjectsFinal FindObjectsFinal; CK_C_EncryptInit EncryptInit; CK_C_Encrypt Encrypt; CK_C_DecryptInit DecryptInit; CK_C_Decrypt Decrypt; CK_C_DigestInit DigestInit; CK_C_DigestUpdate DigestUpdate; CK_C_DigestFinal DigestFinal; CK_C_SignInit SignInit; CK_C_Sign Sign; CK_C_SignUpdate SignUpdate; CK_C_SignFinal SignFinal; CK_C_VerifyInit VerifyInit; CK_C_Verify Verify; CK_C_VerifyUpdate VerifyUpdate; CK_C_VerifyFinal VerifyFinal; CK_C_GenerateKeyPair GenerateKeyPair; CK_C_DeriveKey DeriveKey; CK_C_SeedRandom SeedRandom; CK_C_GenerateRandom GenerateRandom; CK_C_GetInterface GetInterface; }; #include "interface.gen.c" static CK_RV p11prov_NO_GetInterface(CK_UTF8CHAR_PTR pInterfaceName, CK_VERSION_PTR pVersion, CK_INTERFACE_PTR_PTR ppInterface, CK_FLAGS flags) { return CKR_FUNCTION_NOT_SUPPORTED; } #define ASSIGN_FN(name) intf->name = list.fns->C_##name #define ASSIGN_FN_3_0(name) intf->name = list.fns_3_0->C_##name static void populate_interface(P11PROV_INTERFACE *intf, CK_INTERFACE *ck_intf) { union { CK_FUNCTION_LIST_PTR fns; CK_FUNCTION_LIST_3_0_PTR fns_3_0; } list; list.fns = (CK_FUNCTION_LIST_PTR)ck_intf->pFunctionList; P11PROV_debug("Populating Interfaces with '%s', version %d.%d", ck_intf->pInterfaceName, list.fns->version.major, list.fns->version.minor); intf->version = list.fns->version; intf->flags = ck_intf->flags; ASSIGN_FN(Initialize); ASSIGN_FN(Finalize); ASSIGN_FN(GetInfo); ASSIGN_FN(GetMechanismList); ASSIGN_FN(GetFunctionList); ASSIGN_FN(GetSlotList); ASSIGN_FN(GetSlotInfo); ASSIGN_FN(GetTokenInfo); ASSIGN_FN(GetMechanismList); ASSIGN_FN(GetMechanismInfo); ASSIGN_FN(OpenSession); ASSIGN_FN(CloseSession); ASSIGN_FN(GetSessionInfo); ASSIGN_FN(GetOperationState); ASSIGN_FN(SetOperationState); ASSIGN_FN(Login); ASSIGN_FN(CreateObject); ASSIGN_FN(CopyObject); ASSIGN_FN(DestroyObject); ASSIGN_FN(GetAttributeValue); ASSIGN_FN(SetAttributeValue); ASSIGN_FN(FindObjectsInit); ASSIGN_FN(FindObjects); ASSIGN_FN(FindObjectsFinal); ASSIGN_FN(EncryptInit); ASSIGN_FN(Encrypt); ASSIGN_FN(DecryptInit); ASSIGN_FN(Decrypt); ASSIGN_FN(DigestInit); ASSIGN_FN(DigestUpdate); ASSIGN_FN(DigestFinal); ASSIGN_FN(SignInit); ASSIGN_FN(Sign); ASSIGN_FN(SignUpdate); ASSIGN_FN(SignFinal); ASSIGN_FN(VerifyInit); ASSIGN_FN(Verify); ASSIGN_FN(VerifyUpdate); ASSIGN_FN(VerifyFinal); ASSIGN_FN(GenerateKeyPair); ASSIGN_FN(DeriveKey); ASSIGN_FN(SeedRandom); ASSIGN_FN(GenerateRandom); if (intf->version.major == 3) { ASSIGN_FN_3_0(GetInterface); } } static CK_RV p11prov_interface_init(P11PROV_MODULE *mctx) { /* Try to get 3.0 interface by default */ P11PROV_INTERFACE *intf; CK_UTF8CHAR_PTR intf_name = (CK_UTF8CHAR_PTR) "PKCS 11"; CK_VERSION version = { 3, 0 }; CK_INTERFACE *ck_interface; CK_RV ret; intf = OPENSSL_zalloc(sizeof(struct p11prov_interface)); if (!intf) { return CKR_HOST_MEMORY; } intf->GetInterface = dlsym(mctx->dlhandle, "C_GetInterface"); if (!intf->GetInterface) { char *err = dlerror(); P11PROV_debug( "C_GetInterface() not available. Falling back to " "C_GetFunctionList(): %s", err); intf->GetInterface = p11prov_NO_GetInterface; } ret = intf->GetInterface(intf_name, &version, &ck_interface, 0); if (ret != CKR_OK && ret != CKR_FUNCTION_NOT_SUPPORTED) { /* retry without asking for specific version */ ret = intf->GetInterface(NULL, NULL, &ck_interface, 0); } if (ret == CKR_FUNCTION_NOT_SUPPORTED) { /* assume fallback to 2.40 */ static CK_INTERFACE deflt = { .pInterfaceName = (CK_UTF8CHAR_PTR) "Internal defaults", .flags = 0, }; intf->GetFunctionList = dlsym(mctx->dlhandle, "C_GetFunctionList"); if (intf->GetFunctionList) { ret = intf->GetFunctionList( (CK_FUNCTION_LIST_PTR_PTR)&deflt.pFunctionList); if (ret == CKR_OK) { ck_interface = &deflt; } } else { char *err = dlerror(); P11PROV_debug("dlsym() failed: %s", err); ret = CKR_GENERAL_ERROR; } } if (ret == CKR_OK) { populate_interface(intf, ck_interface); mctx->interface = intf; } else { OPENSSL_free(intf); } return ret; } CK_RV p11prov_module_new(P11PROV_CTX *ctx, const char *path, const char *init_args, P11PROV_MODULE **_mctx) { struct p11prov_module_ctx *mctx; const char *env_module; CK_RV ret; mctx = OPENSSL_zalloc(sizeof(struct p11prov_module_ctx)); if (!mctx) { return CKR_HOST_MEMORY; } mctx->provctx = ctx; /* The environment variable has the highest precedence */ env_module = getenv("PKCS11_PROVIDER_MODULE"); if (env_module && *env_module) { mctx->path = OPENSSL_strdup(env_module); } else if (path) { mctx->path = OPENSSL_strdup(path); } else { /* If the module is not specified in the configuration file, * use the p11-kit proxy */ #ifdef DEFAULT_PKCS11_MODULE mctx->path = OPENSSL_strdup(DEFAULT_PKCS11_MODULE); #else P11PROV_raise(ctx, CKR_ARGUMENTS_BAD, "No PKCS#11 module specified."); p11prov_module_free(mctx); return CKR_ARGUMENTS_BAD; #endif } if (!mctx->path) { p11prov_module_free(mctx); return CKR_HOST_MEMORY; } if (init_args) { mctx->init_args = OPENSSL_strdup(init_args); if (!mctx->init_args) { p11prov_module_free(mctx); return CKR_HOST_MEMORY; } } ret = MUTEX_INIT(mctx); if (ret != CKR_OK) { p11prov_module_free(mctx); return ret; } *_mctx = mctx; return CKR_OK; } #if !defined(RTLD_DEEPBIND) #define RTLD_DEEPBIND 0 #endif CK_RV p11prov_module_init(P11PROV_MODULE *mctx) { P11PROV_SLOTS_CTX *slots; CK_C_INITIALIZE_ARGS args = { 0 }; CK_RV ret; if (!mctx) { return CKR_GENERAL_ERROR; } ret = MUTEX_LOCK(mctx); if (ret != CKR_OK) { return ret; } /* LOCKED SECTION ------------- */ if (mctx->initialized) { ret = CKR_OK; goto done; } P11PROV_debug("PKCS#11: Initializing the module: %s", mctx->path); dlerror(); mctx->dlhandle = dlopen(mctx->path, P11PROV_DLOPEN_FLAGS); if (!mctx->dlhandle) { char *err = dlerror(); ret = CKR_GENERAL_ERROR; P11PROV_debug("dlopen(%s) failed: %s", mctx->path, err); goto done; } ret = p11prov_interface_init(mctx); if (ret != CKR_OK) { goto done; } args.flags = CKF_OS_LOCKING_OK; args.pReserved = (void *)mctx->init_args; ret = p11prov_Initialize(mctx->provctx, &args); if (ret && ret != CKR_CRYPTOKI_ALREADY_INITIALIZED) { goto done; } ret = p11prov_GetInfo(mctx->provctx, &mctx->ck_info); if (ret) { goto done; } trim(mctx->ck_info.manufacturerID); trim(mctx->ck_info.libraryDescription); P11PROV_debug("Module Info: ck_ver:%d.%d lib: '%s' '%s' ver:%d.%d", (int)mctx->ck_info.cryptokiVersion.major, (int)mctx->ck_info.cryptokiVersion.minor, mctx->ck_info.manufacturerID, mctx->ck_info.libraryDescription, (int)mctx->ck_info.libraryVersion.major, (int)mctx->ck_info.libraryVersion.minor); ret = p11prov_init_slots(mctx->provctx, &slots); if (ret) { goto done; } p11prov_ctx_set_slots(mctx->provctx, slots); ret = CKR_OK; done: (void)MUTEX_UNLOCK(mctx); /* ------------- LOCKED SECTION */ return ret; } P11PROV_INTERFACE *p11prov_module_get_interface(P11PROV_MODULE *mctx) { if (!mctx) { return NULL; } return mctx->interface; } void p11prov_module_free(P11PROV_MODULE *mctx) { if (!mctx) { return; } if (mctx->dlhandle) { p11prov_Finalize(mctx->provctx, NULL); dlclose(mctx->dlhandle); } OPENSSL_free(mctx->interface); OPENSSL_free(mctx->path); OPENSSL_free(mctx->init_args); OPENSSL_free(mctx); } /* should only be called by the fork handler */ void p11prov_module_mark_reinit(P11PROV_MODULE *mctx) { mctx->reinit = true; } CK_RV p11prov_module_reinit(P11PROV_MODULE *mctx) { CK_C_INITIALIZE_ARGS args = { 0 }; CK_INFO ck_info = { 0 }; CK_RV ret; if (!mctx) { return CKR_GENERAL_ERROR; } ret = MUTEX_LOCK(mctx); if (ret != CKR_OK) { return ret; } /* LOCKED SECTION ------------- */ if (!mctx->reinit) { /* another thread already did it */ goto done; } P11PROV_debug("PKCS#11: Re-initializing the module: %s", mctx->path); (void)p11prov_Finalize(mctx->provctx, NULL); args.flags = CKF_OS_LOCKING_OK; args.pReserved = (void *)mctx->init_args; ret = p11prov_Initialize(mctx->provctx, &args); if (ret == CKR_CRYPTOKI_ALREADY_INITIALIZED) { ret = CKR_OK; } if (ret != CKR_OK) { P11PROV_debug("PKCS#11: Re-init failed: %lx", ret); goto done; } /* clear reinit flag as we just did re-initialize */ mctx->reinit = false; ret = p11prov_GetInfo(mctx->provctx, &ck_info); if (ret != CKR_OK) { goto done; } trim(ck_info.manufacturerID); trim(ck_info.libraryDescription); if (ck_info.cryptokiVersion.major != mctx->ck_info.cryptokiVersion.major || ck_info.cryptokiVersion.minor != mctx->ck_info.cryptokiVersion.minor || strncmp((const char *)ck_info.manufacturerID, (const char *)mctx->ck_info.manufacturerID, 32) != 0 || ck_info.flags != mctx->ck_info.flags || strncmp((const char *)ck_info.libraryDescription, (const char *)mctx->ck_info.libraryDescription, 32) != 0 || ck_info.libraryVersion.major != mctx->ck_info.libraryVersion.major || ck_info.libraryVersion.minor != mctx->ck_info.libraryVersion.minor) { P11PROV_debug("PKCS#11: Re-init module mismatch"); P11PROV_debug("Original Info: ck_ver:%d.%d lib: '%s' '%s' ver:%d.%d", (int)mctx->ck_info.cryptokiVersion.major, (int)mctx->ck_info.cryptokiVersion.minor, mctx->ck_info.manufacturerID, mctx->ck_info.libraryDescription, (int)mctx->ck_info.libraryVersion.major, (int)mctx->ck_info.libraryVersion.minor); P11PROV_debug("Recovered Info: ck_ver:%d.%d lib: '%s' '%s' ver:%d.%d", (int)ck_info.cryptokiVersion.major, (int)ck_info.cryptokiVersion.minor, ck_info.manufacturerID, ck_info.libraryDescription, (int)ck_info.libraryVersion.major, (int)ck_info.libraryVersion.minor); ret = CKR_GENERAL_ERROR; } done: (void)MUTEX_UNLOCK(mctx); /* ------------- LOCKED SECTION */ return ret; } /* This is needed to avoid side channels in the PKCS 1.5 decryption case */ CK_RV side_channel_free_Decrypt(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } P11PROV_debug("Calling C_Decrypt"); /* Must not add any conditionals based on return value, so we just return * straight */ return intf->Decrypt(hSession, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); } CK_INFO p11prov_module_ck_info(P11PROV_MODULE *mctx) { return mctx->ck_info; } pkcs11-provider-1.0/src/interface.gen.c000066400000000000000000001076321475270623700177750ustar00rootroot00000000000000/* DO NOT EDIT, autogenerated from src/interface.pre */ /* Modify src/interface.pre then run make generate-code */ CK_RV p11prov_Initialize(P11PROV_CTX *ctx, CK_VOID_PTR pInitArgs) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_Initialize)) { P11PROV_debug("C_%s is blocked", "Initialize"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "Initialize"); ret = intf->Initialize(pInitArgs); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "Initialize", ret); } return ret; } CK_RV p11prov_Finalize(P11PROV_CTX *ctx, CK_VOID_PTR pReserved) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_Finalize)) { P11PROV_debug("C_%s is blocked", "Finalize"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "Finalize"); ret = intf->Finalize(pReserved); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "Finalize", ret); } return ret; } CK_RV p11prov_GetInfo(P11PROV_CTX *ctx, CK_INFO_PTR pInfo) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_GetInfo)) { P11PROV_debug("C_%s is blocked", "GetInfo"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "GetInfo"); ret = intf->GetInfo(pInfo); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "GetInfo", ret); } return ret; } CK_RV p11prov_GetInterface(P11PROV_CTX *ctx, CK_UTF8CHAR_PTR pInterfaceName, CK_VERSION_PTR pVersion, CK_INTERFACE_PTR_PTR ppInterface, CK_FLAGS flags) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_GetInterface)) { P11PROV_debug("C_%s is blocked", "GetInterface"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "GetInterface"); ret = intf->GetInterface(pInterfaceName, pVersion, ppInterface, flags); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "GetInterface", ret); } return ret; } CK_RV p11prov_GetFunctionList(P11PROV_CTX *ctx, CK_FUNCTION_LIST_PTR_PTR ppFunctionList) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_GetFunctionList)) { P11PROV_debug("C_%s is blocked", "GetFunctionList"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "GetFunctionList"); ret = intf->GetFunctionList(ppFunctionList); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "GetFunctionList", ret); } return ret; } CK_RV p11prov_GetSlotList(P11PROV_CTX *ctx, CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_GetSlotList)) { P11PROV_debug("C_%s is blocked", "GetSlotList"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "GetSlotList"); ret = intf->GetSlotList(tokenPresent, pSlotList, pulCount); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "GetSlotList", ret); } return ret; } CK_RV p11prov_GetSlotInfo(P11PROV_CTX *ctx, CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_GetSlotInfo)) { P11PROV_debug("C_%s is blocked", "GetSlotInfo"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "GetSlotInfo"); ret = intf->GetSlotInfo(slotID, pInfo); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "GetSlotInfo", ret); } return ret; } CK_RV p11prov_GetTokenInfo(P11PROV_CTX *ctx, CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_GetTokenInfo)) { P11PROV_debug("C_%s is blocked", "GetTokenInfo"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "GetTokenInfo"); ret = intf->GetTokenInfo(slotID, pInfo); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "GetTokenInfo", ret); } return ret; } CK_RV p11prov_GetMechanismList(P11PROV_CTX *ctx, CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_GetMechanismList)) { P11PROV_debug("C_%s is blocked", "GetMechanismList"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "GetMechanismList"); ret = intf->GetMechanismList(slotID, pMechanismList, pulCount); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "GetMechanismList", ret); } return ret; } CK_RV p11prov_GetMechanismInfo(P11PROV_CTX *ctx, CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_GetMechanismInfo)) { P11PROV_debug("C_%s is blocked", "GetMechanismInfo"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "GetMechanismInfo"); ret = intf->GetMechanismInfo(slotID, type, pInfo); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "GetMechanismInfo", ret); } return ret; } CK_RV p11prov_OpenSession(P11PROV_CTX *ctx, CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_OpenSession)) { P11PROV_debug("C_%s is blocked", "OpenSession"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "OpenSession"); ret = intf->OpenSession(slotID, flags, pApplication, Notify, phSession); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "OpenSession", ret); } return ret; } CK_RV p11prov_CloseSession(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_CloseSession)) { P11PROV_debug("C_%s is blocked", "CloseSession"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "CloseSession"); ret = intf->CloseSession(hSession); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "CloseSession", ret); } return ret; } CK_RV p11prov_GetSessionInfo(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_GetSessionInfo)) { P11PROV_debug("C_%s is blocked", "GetSessionInfo"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "GetSessionInfo"); ret = intf->GetSessionInfo(hSession, pInfo); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "GetSessionInfo", ret); } return ret; } CK_RV p11prov_GetOperationState(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG_PTR pulOperationStateLen) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_GetOperationState)) { P11PROV_debug("C_%s is blocked", "GetOperationState"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "GetOperationState"); ret = intf->GetOperationState(hSession, pOperationState, pulOperationStateLen); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "GetOperationState", ret); } return ret; } CK_RV p11prov_SetOperationState(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_SetOperationState)) { P11PROV_debug("C_%s is blocked", "SetOperationState"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "SetOperationState"); ret = intf->SetOperationState(hSession, pOperationState, ulOperationStateLen, hEncryptionKey, hAuthenticationKey); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "SetOperationState", ret); } return ret; } CK_RV p11prov_Login(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_Login)) { P11PROV_debug("C_%s is blocked", "Login"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "Login"); ret = intf->Login(hSession, userType, pPin, ulPinLen); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "Login", ret); } return ret; } CK_RV p11prov_CreateObject(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_CreateObject)) { P11PROV_debug("C_%s is blocked", "CreateObject"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "CreateObject"); ret = intf->CreateObject(hSession, pTemplate, ulCount, phObject); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "CreateObject", ret); } return ret; } CK_RV p11prov_CopyObject(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_CopyObject)) { P11PROV_debug("C_%s is blocked", "CopyObject"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "CopyObject"); ret = intf->CopyObject(hSession, hObject, pTemplate, ulCount, phNewObject); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "CopyObject", ret); } return ret; } CK_RV p11prov_DestroyObject(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_DestroyObject)) { P11PROV_debug("C_%s is blocked", "DestroyObject"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "DestroyObject"); ret = intf->DestroyObject(hSession, hObject); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "DestroyObject", ret); } return ret; } CK_RV p11prov_GetAttributeValue(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_GetAttributeValue)) { P11PROV_debug("C_%s is blocked", "GetAttributeValue"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "GetAttributeValue"); ret = intf->GetAttributeValue(hSession, hObject, pTemplate, ulCount); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "GetAttributeValue", ret); } return ret; } CK_RV p11prov_SetAttributeValue(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_SetAttributeValue)) { P11PROV_debug("C_%s is blocked", "SetAttributeValue"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "SetAttributeValue"); ret = intf->SetAttributeValue(hSession, hObject, pTemplate, ulCount); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "SetAttributeValue", ret); } return ret; } CK_RV p11prov_FindObjectsInit(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_FindObjectsInit)) { P11PROV_debug("C_%s is blocked", "FindObjectsInit"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "FindObjectsInit"); ret = intf->FindObjectsInit(hSession, pTemplate, ulCount); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "FindObjectsInit", ret); } return ret; } CK_RV p11prov_FindObjects(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_FindObjects)) { P11PROV_debug("C_%s is blocked", "FindObjects"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "FindObjects"); ret = intf->FindObjects(hSession, phObject, ulMaxObjectCount, pulObjectCount); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "FindObjects", ret); } return ret; } CK_RV p11prov_FindObjectsFinal(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_FindObjectsFinal)) { P11PROV_debug("C_%s is blocked", "FindObjectsFinal"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "FindObjectsFinal"); ret = intf->FindObjectsFinal(hSession); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "FindObjectsFinal", ret); } return ret; } CK_RV p11prov_EncryptInit(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_EncryptInit)) { P11PROV_debug("C_%s is blocked", "EncryptInit"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "EncryptInit"); ret = intf->EncryptInit(hSession, pMechanism, hKey); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "EncryptInit", ret); } return ret; } CK_RV p11prov_Encrypt(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_Encrypt)) { P11PROV_debug("C_%s is blocked", "Encrypt"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "Encrypt"); ret = intf->Encrypt(hSession, pData, ulDataLen, pEncryptedData, pulEncryptedDataLen); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "Encrypt", ret); } return ret; } CK_RV p11prov_DecryptInit(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_DecryptInit)) { P11PROV_debug("C_%s is blocked", "DecryptInit"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "DecryptInit"); ret = intf->DecryptInit(hSession, pMechanism, hKey); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "DecryptInit", ret); } return ret; } CK_RV p11prov_Decrypt(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_Decrypt)) { P11PROV_debug("C_%s is blocked", "Decrypt"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "Decrypt"); ret = intf->Decrypt(hSession, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "Decrypt", ret); } return ret; } CK_RV p11prov_DigestInit(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_DigestInit)) { P11PROV_debug("C_%s is blocked", "DigestInit"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "DigestInit"); ret = intf->DigestInit(hSession, pMechanism); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "DigestInit", ret); } return ret; } CK_RV p11prov_DigestUpdate(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_DigestUpdate)) { P11PROV_debug("C_%s is blocked", "DigestUpdate"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "DigestUpdate"); ret = intf->DigestUpdate(hSession, pPart, ulPartLen); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "DigestUpdate", ret); } return ret; } CK_RV p11prov_DigestFinal(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_DigestFinal)) { P11PROV_debug("C_%s is blocked", "DigestFinal"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "DigestFinal"); ret = intf->DigestFinal(hSession, pDigest, pulDigestLen); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "DigestFinal", ret); } return ret; } CK_RV p11prov_SignInit(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_SignInit)) { P11PROV_debug("C_%s is blocked", "SignInit"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "SignInit"); ret = intf->SignInit(hSession, pMechanism, hKey); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "SignInit", ret); } return ret; } CK_RV p11prov_Sign(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_Sign)) { P11PROV_debug("C_%s is blocked", "Sign"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "Sign"); ret = intf->Sign(hSession, pData, ulDataLen, pSignature, pulSignatureLen); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "Sign", ret); } return ret; } CK_RV p11prov_SignUpdate(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_SignUpdate)) { P11PROV_debug("C_%s is blocked", "SignUpdate"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "SignUpdate"); ret = intf->SignUpdate(hSession, pPart, ulPartLen); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "SignUpdate", ret); } return ret; } CK_RV p11prov_SignFinal(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_SignFinal)) { P11PROV_debug("C_%s is blocked", "SignFinal"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "SignFinal"); ret = intf->SignFinal(hSession, pSignature, pulSignatureLen); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "SignFinal", ret); } return ret; } CK_RV p11prov_VerifyInit(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_VerifyInit)) { P11PROV_debug("C_%s is blocked", "VerifyInit"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "VerifyInit"); ret = intf->VerifyInit(hSession, pMechanism, hKey); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "VerifyInit", ret); } return ret; } CK_RV p11prov_Verify(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_Verify)) { P11PROV_debug("C_%s is blocked", "Verify"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "Verify"); ret = intf->Verify(hSession, pData, ulDataLen, pSignature, ulSignatureLen); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "Verify", ret); } return ret; } CK_RV p11prov_VerifyUpdate(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_VerifyUpdate)) { P11PROV_debug("C_%s is blocked", "VerifyUpdate"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "VerifyUpdate"); ret = intf->VerifyUpdate(hSession, pPart, ulPartLen); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "VerifyUpdate", ret); } return ret; } CK_RV p11prov_VerifyFinal(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_VerifyFinal)) { P11PROV_debug("C_%s is blocked", "VerifyFinal"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "VerifyFinal"); ret = intf->VerifyFinal(hSession, pSignature, ulSignatureLen); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "VerifyFinal", ret); } return ret; } CK_RV p11prov_GenerateKeyPair( P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_GenerateKeyPair)) { P11PROV_debug("C_%s is blocked", "GenerateKeyPair"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "GenerateKeyPair"); ret = intf->GenerateKeyPair(hSession, pMechanism, pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, phPublicKey, phPrivateKey); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "GenerateKeyPair", ret); } return ret; } CK_RV p11prov_DeriveKey(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_DeriveKey)) { P11PROV_debug("C_%s is blocked", "DeriveKey"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "DeriveKey"); ret = intf->DeriveKey(hSession, pMechanism, hBaseKey, pTemplate, ulAttributeCount, phKey); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "DeriveKey", ret); } return ret; } CK_RV p11prov_SeedRandom(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSeed, CK_ULONG ulSeedLen) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_SeedRandom)) { P11PROV_debug("C_%s is blocked", "SeedRandom"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "SeedRandom"); ret = intf->SeedRandom(hSession, pSeed, ulSeedLen); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "SeedRandom", ret); } return ret; } CK_RV p11prov_GenerateRandom(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR RandomData, CK_ULONG ulRandomLen) { P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); CK_RV ret = CKR_GENERAL_ERROR; if (!intf) { P11PROV_raise(ctx, ret, "Can't get module interfaces"); return ret; } if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_GenerateRandom)) { P11PROV_debug("C_%s is blocked", "GenerateRandom"); return CKR_FUNCTION_NOT_SUPPORTED; } P11PROV_debug("Calling C_" "GenerateRandom"); ret = intf->GenerateRandom(hSession, RandomData, ulRandomLen); if (ret != CKR_OK) { P11PROV_debug("Error %ld returned by C_" "GenerateRandom", ret); } return ret; } pkcs11-provider-1.0/src/interface.h000066400000000000000000000265651475270623700172370ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _INTERFACE_H #define _INTERFACE_H #if P11PROV_ADDRESS_SANITIZER /* address sanitizer does not play well with the RTLD_DEEPBIND */ #define P11PROV_DLOPEN_FLAGS RTLD_NOW | RTLD_LOCAL #else #define P11PROV_DLOPEN_FLAGS RTLD_NOW | RTLD_LOCAL | RTLD_DEEPBIND #endif /* interface declarations for PKCS#11 wrapper functions */ CK_RV p11prov_module_new(P11PROV_CTX *ctx, const char *path, const char *init_args, P11PROV_MODULE **_mctx); CK_RV p11prov_module_init(P11PROV_MODULE *mctx); P11PROV_INTERFACE *p11prov_module_get_interface(P11PROV_MODULE *mctx); void p11prov_module_free(P11PROV_MODULE *mctx); void p11prov_module_mark_reinit(P11PROV_MODULE *mctx); CK_RV p11prov_module_reinit(P11PROV_MODULE *mctx); CK_RV p11prov_Initialize(P11PROV_CTX *ctx, CK_VOID_PTR pInitArgs); CK_RV p11prov_Finalize(P11PROV_CTX *ctx, CK_VOID_PTR pReserved); CK_RV p11prov_GetInfo(P11PROV_CTX *ctx, CK_INFO_PTR pInfo); CK_RV p11prov_GetInterface(P11PROV_CTX *ctx, CK_UTF8CHAR_PTR pInterfaceName, CK_VERSION_PTR pVersion, CK_INTERFACE_PTR_PTR ppInterface, CK_FLAGS flags); CK_RV p11prov_GetFunctionList(P11PROV_CTX *ctx, CK_FUNCTION_LIST_PTR_PTR ppFunctionList); CK_RV p11prov_GetSlotList(P11PROV_CTX *ctx, CK_BBOOL tokenPresent, CK_SLOT_ID_PTR pSlotList, CK_ULONG_PTR pulCount); CK_RV p11prov_GetSlotInfo(P11PROV_CTX *ctx, CK_SLOT_ID slotID, CK_SLOT_INFO_PTR pInfo); CK_RV p11prov_GetTokenInfo(P11PROV_CTX *ctx, CK_SLOT_ID slotID, CK_TOKEN_INFO_PTR pInfo); CK_RV p11prov_GetMechanismList(P11PROV_CTX *ctx, CK_SLOT_ID slotID, CK_MECHANISM_TYPE_PTR pMechanismList, CK_ULONG_PTR pulCount); CK_RV p11prov_GetMechanismInfo(P11PROV_CTX *ctx, CK_SLOT_ID slotID, CK_MECHANISM_TYPE type, CK_MECHANISM_INFO_PTR pInfo); CK_RV p11prov_OpenSession(P11PROV_CTX *ctx, CK_SLOT_ID slotID, CK_FLAGS flags, CK_VOID_PTR pApplication, CK_NOTIFY Notify, CK_SESSION_HANDLE_PTR phSession); CK_RV p11prov_CloseSession(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession); CK_RV p11prov_GetSessionInfo(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_SESSION_INFO_PTR pInfo); CK_RV p11prov_GetOperationState(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG_PTR pulOperationStateLen); CK_RV p11prov_SetOperationState(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pOperationState, CK_ULONG ulOperationStateLen, CK_OBJECT_HANDLE hEncryptionKey, CK_OBJECT_HANDLE hAuthenticationKey); CK_RV p11prov_Login(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_USER_TYPE userType, CK_UTF8CHAR_PTR pPin, CK_ULONG ulPinLen); CK_RV p11prov_CreateObject(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phObject); CK_RV p11prov_CopyObject(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount, CK_OBJECT_HANDLE_PTR phNewObject); CK_RV p11prov_DestroyObject(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject); CK_RV p11prov_GetAttributeValue(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount); CK_RV p11prov_SetAttributeValue(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE hObject, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount); CK_RV p11prov_FindObjectsInit(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulCount); CK_RV p11prov_FindObjects(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_OBJECT_HANDLE_PTR phObject, CK_ULONG ulMaxObjectCount, CK_ULONG_PTR pulObjectCount); CK_RV p11prov_FindObjectsFinal(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession); CK_RV p11prov_EncryptInit(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); CK_RV p11prov_Encrypt(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pEncryptedData, CK_ULONG_PTR pulEncryptedDataLen); CK_RV p11prov_DecryptInit(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); CK_RV p11prov_Decrypt(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen); CK_RV p11prov_DigestInit(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism); CK_RV p11prov_DigestUpdate(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen); CK_RV p11prov_DigestFinal(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pDigest, CK_ULONG_PTR pulDigestLen); CK_RV p11prov_SignInit(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); CK_RV p11prov_Sign(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen); CK_RV p11prov_SignUpdate(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen); CK_RV p11prov_SignFinal(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG_PTR pulSignatureLen); CK_RV p11prov_VerifyInit(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hKey); CK_RV p11prov_Verify(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pData, CK_ULONG ulDataLen, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen); CK_RV p11prov_VerifyUpdate(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pPart, CK_ULONG ulPartLen); CK_RV p11prov_VerifyFinal(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pSignature, CK_ULONG ulSignatureLen); CK_RV p11prov_GenerateKeyPair( P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_ATTRIBUTE_PTR pPublicKeyTemplate, CK_ULONG ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR pPrivateKeyTemplate, CK_ULONG ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR phPublicKey, CK_OBJECT_HANDLE_PTR phPrivateKey); CK_RV p11prov_DeriveKey(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_MECHANISM_PTR pMechanism, CK_OBJECT_HANDLE hBaseKey, CK_ATTRIBUTE_PTR pTemplate, CK_ULONG ulAttributeCount, CK_OBJECT_HANDLE_PTR phKey); CK_RV p11prov_SeedRandom(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR SeedData, CK_ULONG ulSeedLen); CK_RV p11prov_GenerateRandom(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR RandomData, CK_ULONG ulRandomLen); /* Special side-channel free path against PKCS#1 1.5 side channel leaking */ CK_RV side_channel_free_Decrypt(P11PROV_CTX *ctx, CK_SESSION_HANDLE hSession, CK_BYTE_PTR pEncryptedData, CK_ULONG ulEncryptedDataLen, CK_BYTE_PTR pData, CK_ULONG_PTR pulDataLen); CK_INFO p11prov_module_ck_info(P11PROV_MODULE *mctx); /* The following defines are needed for a generic mask for any of the functions * we generate via interface.pre, however there is no need to assign a blocking * value until we'll have a configuration option that allows to set blocks, so * most of these are defined to 0 which won't block anything. * Additionally we reserve the lower 4 bits to future "group" blocking. For * example we may introduce a way to block all the PCS#11 v3 function calls to * simulate a 2.40 token */ #define P11PROV_BLOCK_Initialize 0b0000000000000000 #define P11PROV_BLOCK_Finalize 0b0000000000000000 #define P11PROV_BLOCK_GetInfo 0b0000000000000000 #define P11PROV_BLOCK_GetFunctionList 0b0000000000000000 #define P11PROV_BLOCK_GetSlotList 0b0000000000000000 #define P11PROV_BLOCK_GetSlotInfo 0b0000000000000000 #define P11PROV_BLOCK_GetTokenInfo 0b0000000000000000 #define P11PROV_BLOCK_GetMechanismList 0b0000000000000000 #define P11PROV_BLOCK_GetMechanismInfo 0b0000000000000000 #define P11PROV_BLOCK_OpenSession 0b0000000000000000 #define P11PROV_BLOCK_CloseSession 0b0000000000000000 #define P11PROV_BLOCK_GetSessionInfo 0b0000000000000000 #define P11PROV_BLOCK_GetOperationState 0b0000000000001000 #define P11PROV_BLOCK_SetOperationState 0b0000000000001000 #define P11PROV_BLOCK_Login 0b0000000000000000 #define P11PROV_BLOCK_Logout 0b0000000000000000 #define P11PROV_BLOCK_CreateObject 0b0000000000000000 #define P11PROV_BLOCK_CopyObject 0b0000000000000000 #define P11PROV_BLOCK_DestroyObject 0b0000000000000000 #define P11PROV_BLOCK_GetAttributeValue 0b0000000000000000 #define P11PROV_BLOCK_SetAttributeValue 0b0000000000000000 #define P11PROV_BLOCK_FindObjectsInit 0b0000000000000000 #define P11PROV_BLOCK_FindObjects 0b0000000000000000 #define P11PROV_BLOCK_FindObjectsFinal 0b0000000000000000 #define P11PROV_BLOCK_EncryptInit 0b0000000000000000 #define P11PROV_BLOCK_Encrypt 0b0000000000000000 #define P11PROV_BLOCK_EncryptUpdate 0b0000000000000000 #define P11PROV_BLOCK_EncryptFinal 0b0000000000000000 #define P11PROV_BLOCK_DecryptInit 0b0000000000000000 #define P11PROV_BLOCK_Decrypt 0b0000000000000000 #define P11PROV_BLOCK_DecryptUpdate 0b0000000000000000 #define P11PROV_BLOCK_DecryptFinal 0b0000000000000000 #define P11PROV_BLOCK_DigestInit 0b0000000000000000 #define P11PROV_BLOCK_Digest 0b0000000000000000 #define P11PROV_BLOCK_DigestUpdate 0b0000000000000000 #define P11PROV_BLOCK_DigestKey 0b0000000000000000 #define P11PROV_BLOCK_DigestFinal 0b0000000000000000 #define P11PROV_BLOCK_SignInit 0b0000000000000000 #define P11PROV_BLOCK_Sign 0b0000000000000000 #define P11PROV_BLOCK_SignUpdate 0b0000000000000000 #define P11PROV_BLOCK_SignFinal 0b0000000000000000 #define P11PROV_BLOCK_VerifyInit 0b0000000000000000 #define P11PROV_BLOCK_Verify 0b0000000000000000 #define P11PROV_BLOCK_VerifyUpdate 0b0000000000000000 #define P11PROV_BLOCK_VerifyFinal 0b0000000000000000 #define P11PROV_BLOCK_GenerateKeyPair 0b0000000000000000 #define P11PROV_BLOCK_DeriveKey 0b0000000000000000 #define P11PROV_BLOCK_SeedRandom 0b0000000000000000 #define P11PROV_BLOCK_GenerateRandom 0b0000000000000000 /* 3.x functions: */ #define P11PROV_BLOCK_GetInterface 0b0000000000000000 #endif /* _INTERFACE_H */ pkcs11-provider-1.0/src/interface.pre000066400000000000000000000226031475270623700175630ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ BEGIN: #define IMPL_CALL_PROLOG(name) \ P11PROV_INTERFACE *intf = p11prov_ctx_get_interface(ctx); \ CK_RV ret = CKR_GENERAL_ERROR; \ if (!intf) { \ P11PROV_raise(ctx, ret, "Can't get module interfaces"); \ return ret; \ } \ if (p11prov_ctx_is_call_blocked(ctx, P11PROV_BLOCK_##name)) { \ P11PROV_debug("C_%s is blocked", #name); \ return CKR_FUNCTION_NOT_SUPPORTED; \ } \ P11PROV_debug("Calling C_" #name); #define IMPL_CALL_EPILOG(name) \ if (ret != CKR_OK) { \ P11PROV_debug("Error %ld returned by C_" #name, ret); \ } \ return ret; #define IMPL_INTERFACE_FN_1_ARG(name, t1, a1) \ CK_RV p11prov_##name(P11PROV_CTX *ctx, t1 a1) \ { \ IMPL_CALL_PROLOG(name) \ ret = intf->name(a1); \ IMPL_CALL_EPILOG(name) \ } #define IMPL_INTERFACE_FN_2_ARG(name, t1, a1, t2, a2) \ CK_RV p11prov_##name(P11PROV_CTX *ctx, t1 a1, t2 a2) \ { \ IMPL_CALL_PROLOG(name) \ ret = intf->name(a1, a2); \ IMPL_CALL_EPILOG(name) \ } #define IMPL_INTERFACE_FN_3_ARG(name, t1, a1, t2, a2, t3, a3) \ CK_RV p11prov_##name(P11PROV_CTX *ctx, t1 a1, t2 a2, t3 a3) \ { \ IMPL_CALL_PROLOG(name) \ ret = intf->name(a1, a2, a3); \ IMPL_CALL_EPILOG(name) \ } #define IMPL_INTERFACE_FN_4_ARG(name, t1, a1, t2, a2, t3, a3, t4, a4) \ CK_RV p11prov_##name(P11PROV_CTX *ctx, t1 a1, t2 a2, t3 a3, t4 a4) \ { \ IMPL_CALL_PROLOG(name) \ ret = intf->name(a1, a2, a3, a4); \ IMPL_CALL_EPILOG(name) \ } #define IMPL_INTERFACE_FN_5_ARG(name, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5) \ CK_RV p11prov_##name(P11PROV_CTX *ctx, t1 a1, t2 a2, t3 a3, t4 a4, t5 a5) \ { \ IMPL_CALL_PROLOG(name) \ ret = intf->name(a1, a2, a3, a4, a5); \ IMPL_CALL_EPILOG(name) \ } #define IMPL_INTERFACE_FN_6_ARG(name, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5, \ t6, a6) \ CK_RV p11prov_##name(P11PROV_CTX *ctx, t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, \ t6 a6) \ { \ IMPL_CALL_PROLOG(name) \ ret = intf->name(a1, a2, a3, a4, a5, a6); \ IMPL_CALL_EPILOG(name) \ } #define IMPL_INTERFACE_FN_8_ARG(name, t1, a1, t2, a2, t3, a3, t4, a4, t5, a5, \ t6, a6, t7, a7, t8, a8) \ CK_RV p11prov_##name(P11PROV_CTX *ctx, t1 a1, t2 a2, t3 a3, t4 a4, t5 a5, \ t6 a6, t7 a7, t8 a8) \ { \ IMPL_CALL_PROLOG(name) \ ret = intf->name(a1, a2, a3, a4, a5, a6, a7, a8); \ IMPL_CALL_EPILOG(name) \ } IMPL_INTERFACE_FN_1_ARG(Initialize, CK_VOID_PTR, pInitArgs) IMPL_INTERFACE_FN_1_ARG(Finalize, CK_VOID_PTR, pReserved) IMPL_INTERFACE_FN_1_ARG(GetInfo, CK_INFO_PTR, pInfo) IMPL_INTERFACE_FN_4_ARG(GetInterface, CK_UTF8CHAR_PTR, pInterfaceName, CK_VERSION_PTR, pVersion, CK_INTERFACE_PTR_PTR, ppInterface, CK_FLAGS, flags) IMPL_INTERFACE_FN_1_ARG(GetFunctionList, CK_FUNCTION_LIST_PTR_PTR, ppFunctionList) IMPL_INTERFACE_FN_3_ARG(GetSlotList, CK_BBOOL, tokenPresent, CK_SLOT_ID_PTR, pSlotList, CK_ULONG_PTR, pulCount) IMPL_INTERFACE_FN_2_ARG(GetSlotInfo, CK_SLOT_ID, slotID, CK_SLOT_INFO_PTR, pInfo) IMPL_INTERFACE_FN_2_ARG(GetTokenInfo, CK_SLOT_ID, slotID, CK_TOKEN_INFO_PTR, pInfo) IMPL_INTERFACE_FN_3_ARG(GetMechanismList, CK_SLOT_ID, slotID, CK_MECHANISM_TYPE_PTR, pMechanismList, CK_ULONG_PTR, pulCount) IMPL_INTERFACE_FN_3_ARG(GetMechanismInfo, CK_SLOT_ID, slotID, CK_MECHANISM_TYPE, type, CK_MECHANISM_INFO_PTR, pInfo) IMPL_INTERFACE_FN_5_ARG(OpenSession, CK_SLOT_ID, slotID, CK_FLAGS, flags, CK_VOID_PTR, pApplication, CK_NOTIFY, Notify, CK_SESSION_HANDLE_PTR, phSession) IMPL_INTERFACE_FN_1_ARG(CloseSession, CK_SESSION_HANDLE, hSession) IMPL_INTERFACE_FN_2_ARG(GetSessionInfo, CK_SESSION_HANDLE, hSession, CK_SESSION_INFO_PTR, pInfo) IMPL_INTERFACE_FN_3_ARG(GetOperationState, CK_SESSION_HANDLE, hSession, CK_BYTE_PTR, pOperationState, CK_ULONG_PTR, pulOperationStateLen) IMPL_INTERFACE_FN_5_ARG(SetOperationState, CK_SESSION_HANDLE, hSession, CK_BYTE_PTR, pOperationState, CK_ULONG, ulOperationStateLen, CK_OBJECT_HANDLE, hEncryptionKey, CK_OBJECT_HANDLE, hAuthenticationKey) IMPL_INTERFACE_FN_4_ARG(Login, CK_SESSION_HANDLE, hSession, CK_USER_TYPE, userType, CK_UTF8CHAR_PTR, pPin, CK_ULONG, ulPinLen) IMPL_INTERFACE_FN_4_ARG(CreateObject, CK_SESSION_HANDLE, hSession, CK_ATTRIBUTE_PTR, pTemplate, CK_ULONG, ulCount, CK_OBJECT_HANDLE_PTR, phObject) IMPL_INTERFACE_FN_5_ARG(CopyObject, CK_SESSION_HANDLE, hSession, CK_OBJECT_HANDLE, hObject, CK_ATTRIBUTE_PTR, pTemplate, CK_ULONG, ulCount, CK_OBJECT_HANDLE_PTR, phNewObject) IMPL_INTERFACE_FN_2_ARG(DestroyObject, CK_SESSION_HANDLE, hSession, CK_OBJECT_HANDLE, hObject) IMPL_INTERFACE_FN_4_ARG(GetAttributeValue, CK_SESSION_HANDLE, hSession, CK_OBJECT_HANDLE, hObject, CK_ATTRIBUTE_PTR, pTemplate, CK_ULONG, ulCount) IMPL_INTERFACE_FN_4_ARG(SetAttributeValue, CK_SESSION_HANDLE, hSession, CK_OBJECT_HANDLE, hObject, CK_ATTRIBUTE_PTR, pTemplate, CK_ULONG, ulCount) IMPL_INTERFACE_FN_3_ARG(FindObjectsInit, CK_SESSION_HANDLE, hSession, CK_ATTRIBUTE_PTR, pTemplate, CK_ULONG, ulCount) IMPL_INTERFACE_FN_4_ARG(FindObjects, CK_SESSION_HANDLE, hSession, CK_OBJECT_HANDLE_PTR, phObject, CK_ULONG, ulMaxObjectCount, CK_ULONG_PTR, pulObjectCount) IMPL_INTERFACE_FN_1_ARG(FindObjectsFinal, CK_SESSION_HANDLE, hSession) IMPL_INTERFACE_FN_3_ARG(EncryptInit, CK_SESSION_HANDLE, hSession, CK_MECHANISM_PTR, pMechanism, CK_OBJECT_HANDLE, hKey) IMPL_INTERFACE_FN_5_ARG(Encrypt, CK_SESSION_HANDLE, hSession, CK_BYTE_PTR, pData, CK_ULONG, ulDataLen, CK_BYTE_PTR, pEncryptedData, CK_ULONG_PTR, pulEncryptedDataLen) IMPL_INTERFACE_FN_3_ARG(DecryptInit, CK_SESSION_HANDLE, hSession, CK_MECHANISM_PTR, pMechanism, CK_OBJECT_HANDLE, hKey) IMPL_INTERFACE_FN_5_ARG(Decrypt, CK_SESSION_HANDLE, hSession, CK_BYTE_PTR, pEncryptedData, CK_ULONG, ulEncryptedDataLen, CK_BYTE_PTR, pData, CK_ULONG_PTR, pulDataLen) IMPL_INTERFACE_FN_2_ARG(DigestInit, CK_SESSION_HANDLE, hSession, CK_MECHANISM_PTR, pMechanism) IMPL_INTERFACE_FN_3_ARG(DigestUpdate, CK_SESSION_HANDLE, hSession, CK_BYTE_PTR, pPart, CK_ULONG, ulPartLen) IMPL_INTERFACE_FN_3_ARG(DigestFinal, CK_SESSION_HANDLE, hSession, CK_BYTE_PTR, pDigest, CK_ULONG_PTR, pulDigestLen) IMPL_INTERFACE_FN_3_ARG(SignInit, CK_SESSION_HANDLE, hSession, CK_MECHANISM_PTR, pMechanism, CK_OBJECT_HANDLE, hKey) IMPL_INTERFACE_FN_5_ARG(Sign, CK_SESSION_HANDLE, hSession, CK_BYTE_PTR, pData, CK_ULONG, ulDataLen, CK_BYTE_PTR, pSignature, CK_ULONG_PTR, pulSignatureLen) IMPL_INTERFACE_FN_3_ARG(SignUpdate, CK_SESSION_HANDLE, hSession, CK_BYTE_PTR, pPart, CK_ULONG, ulPartLen) IMPL_INTERFACE_FN_3_ARG(SignFinal, CK_SESSION_HANDLE, hSession, CK_BYTE_PTR, pSignature, CK_ULONG_PTR, pulSignatureLen) IMPL_INTERFACE_FN_3_ARG(VerifyInit, CK_SESSION_HANDLE, hSession, CK_MECHANISM_PTR, pMechanism, CK_OBJECT_HANDLE, hKey) IMPL_INTERFACE_FN_5_ARG(Verify, CK_SESSION_HANDLE, hSession, CK_BYTE_PTR, pData, CK_ULONG, ulDataLen, CK_BYTE_PTR, pSignature, CK_ULONG, ulSignatureLen) IMPL_INTERFACE_FN_3_ARG(VerifyUpdate, CK_SESSION_HANDLE, hSession, CK_BYTE_PTR, pPart, CK_ULONG, ulPartLen) IMPL_INTERFACE_FN_3_ARG(VerifyFinal, CK_SESSION_HANDLE, hSession, CK_BYTE_PTR, pSignature, CK_ULONG, ulSignatureLen) IMPL_INTERFACE_FN_8_ARG(GenerateKeyPair, CK_SESSION_HANDLE, hSession, CK_MECHANISM_PTR, pMechanism, CK_ATTRIBUTE_PTR, pPublicKeyTemplate, CK_ULONG, ulPublicKeyAttributeCount, CK_ATTRIBUTE_PTR, pPrivateKeyTemplate, CK_ULONG, ulPrivateKeyAttributeCount, CK_OBJECT_HANDLE_PTR, phPublicKey, CK_OBJECT_HANDLE_PTR, phPrivateKey) IMPL_INTERFACE_FN_6_ARG(DeriveKey, CK_SESSION_HANDLE, hSession, CK_MECHANISM_PTR, pMechanism, CK_OBJECT_HANDLE, hBaseKey, CK_ATTRIBUTE_PTR, pTemplate, CK_ULONG, ulAttributeCount, CK_OBJECT_HANDLE_PTR, phKey) IMPL_INTERFACE_FN_3_ARG(SeedRandom, CK_SESSION_HANDLE, hSession, CK_BYTE_PTR, pSeed, CK_ULONG, ulSeedLen) IMPL_INTERFACE_FN_3_ARG(GenerateRandom, CK_SESSION_HANDLE, hSession, CK_BYTE_PTR, RandomData, CK_ULONG, ulRandomLen) pkcs11-provider-1.0/src/kdf.c000066400000000000000000000611651475270623700160310ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include "platform/endian.h" #include #include struct p11prov_kdf_ctx { P11PROV_CTX *provctx; P11PROV_OBJ *key; CK_MECHANISM_TYPE mechtype; int mode; CK_MECHANISM_TYPE hash_mech; CK_ULONG salt_type; uint8_t *salt; size_t saltlen; uint8_t *info; size_t infolen; uint8_t *prefix; uint8_t *label; uint8_t *data; size_t prefixlen; size_t labellen; size_t datalen; P11PROV_SESSION *session; bool is_tls13_kdf; }; typedef struct p11prov_kdf_ctx P11PROV_KDF_CTX; DISPATCH_HKDF_FN(newctx); DISPATCH_HKDF_FN(freectx); DISPATCH_HKDF_FN(reset); DISPATCH_HKDF_FN(derive); DISPATCH_HKDF_FN(set_ctx_params); DISPATCH_HKDF_FN(settable_ctx_params); DISPATCH_HKDF_FN(get_ctx_params); DISPATCH_HKDF_FN(gettable_ctx_params); static void *p11prov_hkdf_newctx(void *provctx) { P11PROV_CTX *ctx = (P11PROV_CTX *)provctx; P11PROV_KDF_CTX *hkdfctx; CK_RV ret; P11PROV_debug("hkdf newctx"); ret = p11prov_ctx_status(ctx); if (ret != CKR_OK) { return RET_OSSL_ERR; } hkdfctx = OPENSSL_zalloc(sizeof(P11PROV_KDF_CTX)); if (hkdfctx == NULL) { return NULL; } hkdfctx->provctx = ctx; /* default mechanism */ hkdfctx->mechtype = CKM_HKDF_DATA; return hkdfctx; } static void p11prov_hkdf_freectx(void *ctx) { P11PROV_debug("hkdf freectx (ctx:%p)", ctx); p11prov_hkdf_reset(ctx); OPENSSL_free(ctx); } static void p11prov_hkdf_reset(void *ctx) { P11PROV_KDF_CTX *hkdfctx = (P11PROV_KDF_CTX *)ctx; /* save provider context */ void *provctx = hkdfctx->provctx; P11PROV_debug("hkdf reset (ctx:%p)", ctx); /* free all allocated resources */ p11prov_obj_free(hkdfctx->key); if (hkdfctx->session) { p11prov_return_session(hkdfctx->session); hkdfctx->session = NULL; } OPENSSL_clear_free(hkdfctx->salt, hkdfctx->saltlen); OPENSSL_clear_free(hkdfctx->info, hkdfctx->infolen); OPENSSL_clear_free(hkdfctx->prefix, hkdfctx->prefixlen); OPENSSL_clear_free(hkdfctx->label, hkdfctx->labellen); OPENSSL_clear_free(hkdfctx->data, hkdfctx->datalen); /* zero all */ memset(hkdfctx, 0, sizeof(*hkdfctx)); /* restore defaults */ hkdfctx->provctx = provctx; hkdfctx->mechtype = CKM_HKDF_DATA; } static CK_RV inner_pkcs11_key(P11PROV_KDF_CTX *hkdfctx, const uint8_t *key, size_t keylen, P11PROV_OBJ **keyobj) { CK_SLOT_ID slotid = CK_UNAVAILABLE_INFORMATION; CK_RV ret; if (hkdfctx->session == NULL) { ret = p11prov_get_session(hkdfctx->provctx, &slotid, NULL, NULL, hkdfctx->mechtype, NULL, NULL, false, false, &hkdfctx->session); if (ret != CKR_OK) { return ret; } } if (hkdfctx->session == NULL) { return CKR_SESSION_HANDLE_INVALID; } *keyobj = p11prov_create_secret_key(hkdfctx->provctx, hkdfctx->session, true, (void *)key, keylen); if (*keyobj == NULL) { return CKR_KEY_HANDLE_INVALID; } return CKR_OK; } static int inner_extract_key_value(P11PROV_CTX *ctx, P11PROV_SESSION *session, CK_OBJECT_HANDLE dkey_handle, unsigned char *key, size_t keylen) { CK_ULONG key_size; struct fetch_attrs attrs[1]; int num = 0; CK_RV ret; P11PROV_debug("HKDF derived key handle: %lu", dkey_handle); FA_SET_BUF_VAL(attrs, num, CKA_VALUE, key, keylen, true); ret = p11prov_fetch_attributes(ctx, session, dkey_handle, attrs, num); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Failed to retrieve derived key"); return ret; } FA_GET_LEN(attrs, 0, key_size); if (key_size != keylen) { ret = CKR_GENERAL_ERROR; P11PROV_raise(ctx, ret, "Expected derived key of len %zu, but got %lu", keylen, key_size); return ret; } return CKR_OK; } static int inner_derive_key(P11PROV_CTX *ctx, P11PROV_OBJ *key, P11PROV_SESSION **session, CK_MECHANISM *mechanism, size_t keylen, CK_OBJECT_HANDLE *dkey_handle) { CK_OBJECT_CLASS class = CKO_DATA; CK_BBOOL val_false = CK_FALSE; CK_ULONG key_size = keylen; CK_ATTRIBUTE key_template[3] = { { CKA_CLASS, &class, sizeof(class) }, { CKA_TOKEN, &val_false, sizeof(val_false) }, { CKA_VALUE_LEN, &key_size, sizeof(key_size) }, }; CK_OBJECT_HANDLE pkey_handle; CK_SLOT_ID slotid; CK_RV ret; pkey_handle = p11prov_obj_get_handle(key); if (pkey_handle == CK_INVALID_HANDLE) { ret = CKR_KEY_HANDLE_INVALID; P11PROV_raise(ctx, ret, "Invalid key handle"); return ret; } slotid = p11prov_obj_get_slotid(key); if (slotid == CK_UNAVAILABLE_INFORMATION) { ret = CKR_SLOT_ID_INVALID; P11PROV_raise(ctx, ret, "Invalid key slotid"); return ret; } return p11prov_derive_key(ctx, slotid, mechanism, pkey_handle, key_template, 3, session, dkey_handle); } static int p11prov_hkdf_derive(void *ctx, unsigned char *key, size_t keylen, const OSSL_PARAM params[]) { P11PROV_KDF_CTX *hkdfctx = (P11PROV_KDF_CTX *)ctx; CK_HKDF_PARAMS ck_params = { .bExtract = (hkdfctx->mode == EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND || hkdfctx->mode == EVP_KDF_HKDF_MODE_EXTRACT_ONLY) ? CK_TRUE : CK_FALSE, .bExpand = (hkdfctx->mode == EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND || hkdfctx->mode == EVP_KDF_HKDF_MODE_EXPAND_ONLY) ? CK_TRUE : CK_FALSE, .prfHashMechanism = hkdfctx->hash_mech, .ulSaltType = hkdfctx->salt_type, .pSalt = hkdfctx->salt, .ulSaltLen = hkdfctx->saltlen, .hSaltKey = CK_INVALID_HANDLE, .pInfo = hkdfctx->info, .ulInfoLen = hkdfctx->infolen, }; CK_MECHANISM mechanism = { .mechanism = hkdfctx->mechtype, .pParameter = &ck_params, .ulParameterLen = sizeof(ck_params), }; CK_OBJECT_HANDLE dkey_handle; CK_RV ret; P11PROV_debug("hkdf derive (ctx:%p, key:%p[%zu], params:%p)", ctx, key, keylen, params); ret = p11prov_hkdf_set_ctx_params(ctx, params); if (ret != RET_OSSL_OK) { P11PROV_raise(hkdfctx->provctx, ret, "Invalid params"); return RET_OSSL_ERR; } if (hkdfctx->key == NULL || key == NULL) { ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); return RET_OSSL_ERR; } if (keylen == 0) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); return RET_OSSL_ERR; } /* no salt ? */ if (hkdfctx->salt_type == 0) { ck_params.ulSaltType = CKF_HKDF_SALT_NULL; } ret = inner_derive_key(hkdfctx->provctx, hkdfctx->key, &hkdfctx->session, &mechanism, keylen, &dkey_handle); if (ret != CKR_OK) { return RET_OSSL_ERR; } ret = inner_extract_key_value(hkdfctx->provctx, hkdfctx->session, dkey_handle, key, keylen); if (ret != CKR_OK) { return RET_OSSL_ERR; } return RET_OSSL_OK; } /* ref: RFC 8446 - 7.1 Key Schedule * Citation: * HKDF-Expand-Label(Secret, Label, Context, Length) = HKDF-Expand(Secret, HkdfLabel, Length) * * Where HkdfLabel is specified as: * * struct { * uint16 length = Length; * opaque label<7..255> = "tls13 " + Label; * opaque context<0..255> = Context; * } HkdfLabel; */ #define TLS13_HL_KEY_SIZE 2 #define TLS13_HL_KEY_MAX_LENGTH 65535 #define TLS13_HL_LABEL_SIZE 1 #define TLS13_HL_LABEL_MAX_LENGTH 255 #define TLS13_HL_CONTEXT_SIZE 1 #define TLS13_HL_CONTEXT_MAX_LENGTH 255 #define TLS13_HKDF_LABEL_MAX_SIZE \ (TLS13_HL_KEY_SIZE + TLS13_HL_LABEL_SIZE + TLS13_HL_LABEL_MAX_LENGTH \ + TLS13_HL_CONTEXT_SIZE + TLS13_HL_CONTEXT_MAX_LENGTH) static CK_RV p11prov_tls13_expand_label(P11PROV_KDF_CTX *hkdfctx, P11PROV_OBJ *keyobj, uint8_t *prefix, size_t prefixlen, uint8_t *label, size_t labellen, uint8_t *data, size_t datalen, size_t keylen, CK_OBJECT_HANDLE *dkey_handle) { CK_HKDF_PARAMS params = { .bExtract = CK_FALSE, .bExpand = CK_TRUE, .prfHashMechanism = hkdfctx->hash_mech, .ulSaltType = 0, .pSalt = NULL, .ulSaltLen = 0, .hSaltKey = CK_INVALID_HANDLE, }; CK_MECHANISM mechanism = { .mechanism = hkdfctx->mechtype, .pParameter = ¶ms, .ulParameterLen = sizeof(params), }; uint8_t info[TLS13_HKDF_LABEL_MAX_SIZE]; size_t i; uint16_t keysize; CK_RV ret; P11PROV_debug( "tls13 expand label (prefix:%p[%zu], label:%p[%zu], data:%p[%zu])", prefix, prefixlen, label, labellen, data, datalen); if (prefix == NULL || prefixlen == 0 || label == NULL || labellen == 0 || (prefixlen + labellen > TLS13_HL_LABEL_MAX_LENGTH) || (datalen > 0 && data == NULL) || (datalen == 0 && data != NULL) || (datalen > TLS13_HL_CONTEXT_MAX_LENGTH) || (keylen > TLS13_HL_KEY_MAX_LENGTH)) { return CKR_ARGUMENTS_BAD; } params.pInfo = info; params.ulInfoLen = 2 + 1 + prefixlen + labellen + 1 + datalen; if (params.ulInfoLen > TLS13_HKDF_LABEL_MAX_SIZE) { return CKR_ARGUMENTS_BAD; } i = 0; keysize = htobe16(keylen); memcpy(&info[i], &keysize, sizeof(keysize)); i += sizeof(keysize); info[i] = prefixlen + labellen; i += 1; memcpy(&info[i], prefix, prefixlen); i += prefixlen; memcpy(&info[i], label, labellen); i += labellen; info[i] = datalen; i += 1; if (datalen > 0) { memcpy(&info[i], data, datalen); i += datalen; } if (params.ulInfoLen != i) { OPENSSL_cleanse(params.pInfo, TLS13_HKDF_LABEL_MAX_SIZE); return CKR_HOST_MEMORY; } ret = inner_derive_key(hkdfctx->provctx, keyobj, &hkdfctx->session, &mechanism, keylen, dkey_handle); OPENSSL_cleanse(params.pInfo, params.ulInfoLen); return ret; } static CK_RV p11prov_tls13_derive_secret(P11PROV_KDF_CTX *hkdfctx, P11PROV_OBJ *keyobj, size_t keylen, CK_OBJECT_HANDLE *dkey_handle) { P11PROV_OBJ *zerokey = NULL; CK_HKDF_PARAMS params = { .bExtract = CK_TRUE, .bExpand = CK_FALSE, .prfHashMechanism = hkdfctx->hash_mech, .ulSaltType = CKF_HKDF_SALT_DATA, .hSaltKey = CK_INVALID_HANDLE, .pInfo = NULL, .ulInfoLen = 0, }; CK_MECHANISM mechanism = { .mechanism = CKM_HKDF_DATA, .pParameter = ¶ms, .ulParameterLen = sizeof(params), }; uint8_t saltbuf[EVP_MAX_MD_SIZE] = { 0 }; uint8_t zerobuf[EVP_MAX_MD_SIZE] = { 0 }; size_t saltlen; size_t hashlen; CK_RV ret; ret = p11prov_digest_get_digest_size(hkdfctx->hash_mech, &hashlen); if (ret != CKR_OK) { return ret; } saltlen = hashlen; if (hkdfctx->salt) { P11PROV_OBJ *ek = NULL; unsigned char info[hashlen]; const char *mdname; data_buffer digest_data[1] = { 0 }; /* intentionally empty */ data_buffer digest = { .data = info, .length = hashlen }; CK_OBJECT_HANDLE skey_handle; /* OpenSSL special cases this in an odd way and regenerates a hash as * if an empty message was received. */ ret = p11prov_digest_get_name(hkdfctx->hash_mech, &mdname); if (ret != CKR_OK) { return ret; } ret = p11prov_digest_util(hkdfctx->provctx, mdname, NULL, digest_data, &digest); if (ret != CKR_OK) { return ret; } /* In OpenSSL the salt is used as the derivation key */ ret = inner_pkcs11_key(hkdfctx, hkdfctx->salt, hkdfctx->saltlen, &ek); if (ret != CKR_OK) { return ret; } ret = p11prov_tls13_expand_label( hkdfctx, ek, hkdfctx->prefix, hkdfctx->prefixlen, hkdfctx->label, hkdfctx->labellen, info, hashlen, hashlen, &skey_handle); p11prov_obj_free(ek); if (ret != CKR_OK) { return ret; } ret = inner_extract_key_value(hkdfctx->provctx, hkdfctx->session, skey_handle, saltbuf, saltlen); if (ret != CKR_OK) { return ret; } } params.pSalt = saltbuf; params.ulSaltLen = saltlen; if (!keyobj) { ret = inner_pkcs11_key(hkdfctx, zerobuf, hashlen, &zerokey); if (ret != CKR_OK) { return ret; } keyobj = zerokey; } ret = inner_derive_key(hkdfctx->provctx, keyobj, &hkdfctx->session, &mechanism, keylen, dkey_handle); p11prov_obj_free(zerokey); return ret; } static int p11prov_tls13_kdf_derive(void *ctx, unsigned char *key, size_t keylen, const OSSL_PARAM params[]) { P11PROV_KDF_CTX *hkdfctx = (P11PROV_KDF_CTX *)ctx; CK_OBJECT_HANDLE dkey_handle; CK_RV ret; P11PROV_debug("tls13 hkdf derive (ctx:%p, key:%p[%zu], params:%p)", ctx, key, keylen, params); ret = p11prov_hkdf_set_ctx_params(ctx, params); if (ret != RET_OSSL_OK) { P11PROV_raise(hkdfctx->provctx, ret, "Invalid params"); return RET_OSSL_ERR; } if (key == NULL) { ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); return RET_OSSL_ERR; } if (keylen == 0) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_KEY_LENGTH); return RET_OSSL_ERR; } switch (hkdfctx->mode) { case EVP_KDF_HKDF_MODE_EXPAND_ONLY: if (hkdfctx->key == NULL) { ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_KEY); return RET_OSSL_ERR; } ret = p11prov_tls13_expand_label( hkdfctx, hkdfctx->key, hkdfctx->prefix, hkdfctx->prefixlen, hkdfctx->label, hkdfctx->labellen, hkdfctx->data, hkdfctx->datalen, keylen, &dkey_handle); if (ret != CKR_OK) { return RET_OSSL_ERR; } break; case EVP_KDF_HKDF_MODE_EXTRACT_ONLY: /* key can be null here */ ret = p11prov_tls13_derive_secret(hkdfctx, hkdfctx->key, keylen, &dkey_handle); if (ret != CKR_OK) { return RET_OSSL_ERR; } break; default: return RET_OSSL_ERR; } ret = inner_extract_key_value(hkdfctx->provctx, hkdfctx->session, dkey_handle, key, keylen); if (ret != CKR_OK) { return RET_OSSL_ERR; } return RET_OSSL_OK; } static int p11prov_hkdf_set_ctx_params(void *ctx, const OSSL_PARAM params[]) { P11PROV_KDF_CTX *hkdfctx = (P11PROV_KDF_CTX *)ctx; const OSSL_PARAM *p; int ret; P11PROV_debug("hkdf set ctx params (ctx=%p, params=%p)", hkdfctx, params); if (params == NULL) { return RET_OSSL_OK; } /* params common to HKDF and TLS13_KDF first */ p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DIGEST); if (p) { const char *digest = NULL; CK_RV rv; ret = OSSL_PARAM_get_utf8_string_ptr(p, &digest); if (ret != RET_OSSL_OK) { return ret; } rv = p11prov_digest_get_by_name(digest, &hkdfctx->hash_mech); if (rv != CKR_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return RET_OSSL_ERR; } P11PROV_debug("set digest to %lu", hkdfctx->hash_mech); } p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_MODE); if (p) { if (p->data_type == OSSL_PARAM_UTF8_STRING) { if (OPENSSL_strcasecmp(p->data, "EXTRACT_AND_EXPAND") == 0) { hkdfctx->mode = EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND; } else if (OPENSSL_strcasecmp(p->data, "EXTRACT_ONLY") == 0) { hkdfctx->mode = EVP_KDF_HKDF_MODE_EXTRACT_ONLY; } else if (OPENSSL_strcasecmp(p->data, "EXPAND_ONLY") == 0) { hkdfctx->mode = EVP_KDF_HKDF_MODE_EXPAND_ONLY; } else { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); return RET_OSSL_ERR; } } else { ret = OSSL_PARAM_get_int(p, &hkdfctx->mode); if (ret != RET_OSSL_OK) { return ret; } } switch (hkdfctx->mode) { case EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND: break; case EVP_KDF_HKDF_MODE_EXTRACT_ONLY: break; case EVP_KDF_HKDF_MODE_EXPAND_ONLY: break; default: ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); return RET_OSSL_ERR; } P11PROV_debug("set mode to mode:%d", hkdfctx->mode); } p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY); if (p) { const void *secret = NULL; size_t secret_len; ret = OSSL_PARAM_get_octet_string_ptr(p, &secret, &secret_len); if (ret != RET_OSSL_OK) { return ret; } /* Create Session and key from key material */ p11prov_obj_free(hkdfctx->key); ret = inner_pkcs11_key(hkdfctx, secret, secret_len, &hkdfctx->key); if (ret != CKR_OK) { return RET_OSSL_ERR; } } p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT); if (p) { OPENSSL_clear_free(hkdfctx->salt, hkdfctx->saltlen); hkdfctx->salt = NULL; ret = OSSL_PARAM_get_octet_string(p, (void **)&hkdfctx->salt, 0, &hkdfctx->saltlen); if (ret != RET_OSSL_OK) { return ret; } hkdfctx->salt_type = CKF_HKDF_SALT_DATA; P11PROV_debug("set salt (len:%lu)", hkdfctx->saltlen); } if (hkdfctx->is_tls13_kdf) { if (hkdfctx->mode == EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); return RET_OSSL_ERR; } OPENSSL_clear_free(hkdfctx->info, hkdfctx->infolen); hkdfctx->info = NULL; hkdfctx->infolen = 0; p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_PREFIX); if (p) { OPENSSL_clear_free(hkdfctx->prefix, hkdfctx->prefixlen); hkdfctx->prefix = NULL; hkdfctx->prefixlen = 0; ret = OSSL_PARAM_get_octet_string(p, (void **)&hkdfctx->prefix, 0, &hkdfctx->prefixlen); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_LABEL); if (p) { OPENSSL_clear_free(hkdfctx->label, hkdfctx->labellen); hkdfctx->label = NULL; hkdfctx->labellen = 0; ret = OSSL_PARAM_get_octet_string(p, (void **)&hkdfctx->label, 0, &hkdfctx->labellen); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_DATA); if (p) { OPENSSL_clear_free(hkdfctx->data, hkdfctx->datalen); hkdfctx->data = NULL; hkdfctx->datalen = 0; ret = OSSL_PARAM_get_octet_string(p, (void **)&hkdfctx->data, 0, &hkdfctx->datalen); if (ret != RET_OSSL_OK) { return ret; } } return RET_OSSL_OK; } p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_INFO); if (p) { OPENSSL_clear_free(hkdfctx->info, hkdfctx->infolen); hkdfctx->info = NULL; hkdfctx->infolen = 0; } /* can be multiple parameters, which will be all concatenated */ for (; p; p = OSSL_PARAM_locate_const(p + 1, OSSL_KDF_PARAM_INFO)) { uint8_t *ptr; size_t len; if (p->data_size == 0 || p->data == NULL) { return RET_OSSL_ERR; } len = hkdfctx->infolen + p->data_size; ptr = OPENSSL_realloc(hkdfctx->info, len); if (ptr == NULL) { OPENSSL_clear_free(hkdfctx->info, hkdfctx->infolen); hkdfctx->info = NULL; hkdfctx->infolen = 0; return RET_OSSL_ERR; } memcpy(ptr + hkdfctx->infolen, p->data, p->data_size); hkdfctx->info = ptr; hkdfctx->infolen = len; P11PROV_debug("set info (len:%lu)", hkdfctx->infolen); } return RET_OSSL_OK; } static const OSSL_PARAM *p11prov_hkdf_settable_ctx_params(void *ctx, void *prov) { static const OSSL_PARAM params[] = { OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MODE, NULL, 0), OSSL_PARAM_int(OSSL_KDF_PARAM_MODE, NULL), OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0), OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0), OSSL_PARAM_octet_string(OSSL_KDF_PARAM_INFO, NULL, 0), OSSL_PARAM_END, }; return params; } static int p11prov_hkdf_get_ctx_params(void *ctx, OSSL_PARAM *params) { P11PROV_KDF_CTX *hkdfctx = (P11PROV_KDF_CTX *)ctx; OSSL_PARAM *p; P11PROV_debug("hkdf get ctx params (ctx=%p, params=%p)", hkdfctx, params); if (params == NULL) { return RET_OSSL_OK; } p = OSSL_PARAM_locate(params, OSSL_KDF_PARAM_SIZE); if (p) { size_t ret_size = 0; if (hkdfctx->mode != EVP_KDF_HKDF_MODE_EXTRACT_ONLY) { ret_size = SIZE_MAX; } else { CK_RV rv; rv = p11prov_digest_get_digest_size(hkdfctx->hash_mech, &ret_size); if (rv != CKR_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return RET_OSSL_ERR; } } if (ret_size != 0) { return OSSL_PARAM_set_size_t(p, ret_size); } ERR_raise(ERR_LIB_PROV, PROV_R_MISSING_MESSAGE_DIGEST); return RET_OSSL_ERR; } return RET_OSSL_OK; } static const OSSL_PARAM *p11prov_hkdf_gettable_ctx_params(void *ctx, void *prov) { static const OSSL_PARAM params[] = { OSSL_PARAM_size_t(OSSL_KDF_PARAM_SIZE, NULL), OSSL_PARAM_END, }; return params; } const OSSL_DISPATCH p11prov_hkdf_kdf_functions[] = { DISPATCH_HKDF_ELEM(hkdf, NEWCTX, newctx), DISPATCH_HKDF_ELEM(hkdf, FREECTX, freectx), DISPATCH_HKDF_ELEM(hkdf, RESET, reset), DISPATCH_HKDF_ELEM(hkdf, DERIVE, derive), DISPATCH_HKDF_ELEM(hkdf, SET_CTX_PARAMS, set_ctx_params), DISPATCH_HKDF_ELEM(hkdf, SETTABLE_CTX_PARAMS, settable_ctx_params), DISPATCH_HKDF_ELEM(hkdf, GET_CTX_PARAMS, get_ctx_params), DISPATCH_HKDF_ELEM(hkdf, GETTABLE_CTX_PARAMS, gettable_ctx_params), { 0, NULL }, }; static void *p11prov_tls13_kdf_newctx(void *provctx) { P11PROV_KDF_CTX *ctx = (P11PROV_KDF_CTX *)p11prov_hkdf_newctx(provctx); ctx->is_tls13_kdf = true; return ctx; } static const OSSL_PARAM *p11prov_tls13_kdf_settable_ctx_params(void *ctx, void *prov) { static const OSSL_PARAM params[] = { OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_MODE, NULL, 0), OSSL_PARAM_int(OSSL_KDF_PARAM_MODE, NULL), OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_PROPERTIES, NULL, 0), OSSL_PARAM_utf8_string(OSSL_KDF_PARAM_DIGEST, NULL, 0), OSSL_PARAM_octet_string(OSSL_KDF_PARAM_KEY, NULL, 0), OSSL_PARAM_octet_string(OSSL_KDF_PARAM_SALT, NULL, 0), OSSL_PARAM_octet_string(OSSL_KDF_PARAM_PREFIX, NULL, 0), OSSL_PARAM_octet_string(OSSL_KDF_PARAM_LABEL, NULL, 0), OSSL_PARAM_octet_string(OSSL_KDF_PARAM_DATA, NULL, 0), OSSL_PARAM_END, }; return params; } const OSSL_DISPATCH p11prov_tls13_kdf_functions[] = { DISPATCH_HKDF_ELEM(tls13_kdf, NEWCTX, newctx), DISPATCH_HKDF_ELEM(hkdf, FREECTX, freectx), DISPATCH_HKDF_ELEM(hkdf, RESET, reset), DISPATCH_HKDF_ELEM(tls13_kdf, DERIVE, derive), DISPATCH_HKDF_ELEM(hkdf, SET_CTX_PARAMS, set_ctx_params), DISPATCH_HKDF_ELEM(tls13_kdf, SETTABLE_CTX_PARAMS, settable_ctx_params), DISPATCH_HKDF_ELEM(hkdf, GET_CTX_PARAMS, get_ctx_params), DISPATCH_HKDF_ELEM(hkdf, GETTABLE_CTX_PARAMS, gettable_ctx_params), { 0, NULL }, }; pkcs11-provider-1.0/src/kdf.h000066400000000000000000000010301475270623700160170ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _KDF_H #define _KDF_H /* HKDF kdf fns */ #define DISPATCH_HKDF_FN(name) DECL_DISPATCH_FUNC(kdf, p11prov_hkdf, name) #define DISPATCH_HKDF_ELEM(prefix, NAME, name) \ { \ OSSL_FUNC_KDF_##NAME, (void (*)(void))p11prov_##prefix##_##name \ } extern const void *p11prov_hkdf_static_ctx; extern const OSSL_DISPATCH p11prov_hkdf_kdf_functions[]; extern const OSSL_DISPATCH p11prov_tls13_kdf_functions[]; #endif /* _KDF_H */ pkcs11-provider-1.0/src/keymgmt.c000066400000000000000000002121311475270623700167310ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include "platform/endian.h" #include "openssl/rand.h" #include #define DFLT_DIGEST "SHA256" DISPATCH_KEYMGMT_FN(common, gen_set_params); DISPATCH_KEYMGMT_FN(common, gen_cleanup); DISPATCH_KEYMGMT_FN(rsa, new); DISPATCH_KEYMGMT_FN(rsa, gen_init); DISPATCH_KEYMGMT_FN(rsa, gen); DISPATCH_KEYMGMT_FN(rsa, gen_settable_params); DISPATCH_KEYMGMT_FN(rsa, load); DISPATCH_KEYMGMT_FN(rsa, free); DISPATCH_KEYMGMT_FN(rsa, has); DISPATCH_KEYMGMT_FN(rsa, match); DISPATCH_KEYMGMT_FN(rsa, import); DISPATCH_KEYMGMT_FN(rsa, import_types); DISPATCH_KEYMGMT_FN(rsa, export); DISPATCH_KEYMGMT_FN(rsa, export_types); DISPATCH_KEYMGMT_FN(rsa, query_operation_name); DISPATCH_KEYMGMT_FN(rsa, get_params); DISPATCH_KEYMGMT_FN(rsa, gettable_params); #define X962_PRIME_OID 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x03, 0x01 #define X962_PRIME_OID_LEN 7 #define SECG_OID 0x2B, 0x81, 0x04, 0x00 #define SECG_OID_LEN 4 #define OID_ID 0x06 #define DEF_EC_PARAM(cname, base, num) \ const CK_BYTE cname##_param[] = { OID_ID, base##_LEN + 1, base, num } #define NAME_TO_PARAM(cname) \ { \ .name = #cname, .ec_param = cname##_param, \ .ec_param_size = sizeof(cname##_param) \ } #define ALIAS_TO_PARAM(alias, cname) \ { \ .name = alias, .ec_param = cname##_param, \ .ec_param_size = sizeof(cname##_param) \ } DEF_EC_PARAM(secp112r1, SECG_OID, 0x06); DEF_EC_PARAM(secp112r2, SECG_OID, 0x07); DEF_EC_PARAM(secp128r1, SECG_OID, 0x1C); DEF_EC_PARAM(secp128r2, SECG_OID, 0x1D); DEF_EC_PARAM(secp160k1, SECG_OID, 0x09); DEF_EC_PARAM(secp160r1, SECG_OID, 0x08); DEF_EC_PARAM(secp160r2, SECG_OID, 0x1E); DEF_EC_PARAM(secp192k1, SECG_OID, 0x1F); DEF_EC_PARAM(secp224k1, SECG_OID, 0x20); DEF_EC_PARAM(secp224r1, SECG_OID, 0x21); DEF_EC_PARAM(secp256k1, SECG_OID, 0x0A); DEF_EC_PARAM(secp384r1, SECG_OID, 0x22); DEF_EC_PARAM(secp521r1, SECG_OID, 0x23); DEF_EC_PARAM(prime192v1, X962_PRIME_OID, 0x01); DEF_EC_PARAM(prime192v2, X962_PRIME_OID, 0x02); DEF_EC_PARAM(prime192v3, X962_PRIME_OID, 0x03); DEF_EC_PARAM(prime239v1, X962_PRIME_OID, 0x04); DEF_EC_PARAM(prime239v2, X962_PRIME_OID, 0x05); DEF_EC_PARAM(prime239v3, X962_PRIME_OID, 0x06); DEF_EC_PARAM(prime256v1, X962_PRIME_OID, 0x07); struct { const char *name; const CK_BYTE *ec_param; CK_ULONG ec_param_size; } ec_name_to_params[] = { /* secg curves */ NAME_TO_PARAM(secp112r1), NAME_TO_PARAM(secp112r2), NAME_TO_PARAM(secp128r1), NAME_TO_PARAM(secp128r2), NAME_TO_PARAM(secp160k1), NAME_TO_PARAM(secp160r1), NAME_TO_PARAM(secp160r2), NAME_TO_PARAM(secp192k1), NAME_TO_PARAM(secp224k1), NAME_TO_PARAM(secp224r1), NAME_TO_PARAM(secp256k1), NAME_TO_PARAM(secp384r1), NAME_TO_PARAM(secp521r1), /* X9.62 prime curves */ NAME_TO_PARAM(prime192v1), NAME_TO_PARAM(prime192v2), NAME_TO_PARAM(prime192v3), NAME_TO_PARAM(prime239v1), NAME_TO_PARAM(prime239v2), NAME_TO_PARAM(prime239v3), NAME_TO_PARAM(prime256v1), /* NIST aliases */ ALIAS_TO_PARAM("P-192", prime192v1), ALIAS_TO_PARAM("P-224", secp224r1), ALIAS_TO_PARAM("P-256", prime256v1), ALIAS_TO_PARAM("P-384", secp384r1), ALIAS_TO_PARAM("P-521", secp521r1), { NULL, NULL, 0 }, }; struct key_generator { P11PROV_CTX *provctx; CK_KEY_TYPE type; P11PROV_URI *uri; char *key_usage; CK_MECHANISM mechanism; union { struct { CK_ULONG modulus_bits; CK_BYTE exponent[8]; CK_ULONG exponent_size; CK_MECHANISM_TYPE *allowed_types; CK_ULONG allowed_types_size; } rsa; struct { const CK_BYTE *ec_params; CK_ULONG ec_params_size; } ec; } data; OSSL_CALLBACK *cb_fn; void *cb_arg; }; const CK_MECHANISM_TYPE p11prov_rsapss_mechs[P11PROV_N_RSAPSS_MECHS] = { CKM_SHA1_RSA_PKCS_PSS, CKM_SHA224_RSA_PKCS_PSS, CKM_SHA256_RSA_PKCS_PSS, CKM_SHA384_RSA_PKCS_PSS, CKM_SHA512_RSA_PKCS_PSS, CKM_SHA3_224_RSA_PKCS_PSS, CKM_SHA3_256_RSA_PKCS_PSS, CKM_SHA3_384_RSA_PKCS_PSS, CKM_SHA3_512_RSA_PKCS_PSS, CKM_RSA_PKCS_PSS }; static int p11prov_common_gen_set_params(void *genctx, const OSSL_PARAM params[]) { struct key_generator *ctx = (struct key_generator *)genctx; const OSSL_PARAM *p; int ret; if (!ctx) { return RET_OSSL_ERR; } if (params == NULL) { return RET_OSSL_OK; } p = OSSL_PARAM_locate_const(params, P11PROV_PARAM_URI); if (p) { if (p->data_type != OSSL_PARAM_UTF8_STRING) { return RET_OSSL_ERR; } if (!p->data || p->data_size == 0) { return RET_OSSL_ERR; } if (ctx->uri) { p11prov_uri_free(ctx->uri); } ctx->uri = p11prov_parse_uri(ctx->provctx, (const char *)p->data); if (!ctx->uri) { return RET_OSSL_ERR; } } p = OSSL_PARAM_locate_const(params, P11PROV_PARAM_KEY_USAGE); if (p) { if (p->data_type != OSSL_PARAM_UTF8_STRING) { return RET_OSSL_ERR; } ret = OSSL_PARAM_get_utf8_string(p, &ctx->key_usage, 0); if (ret != RET_OSSL_OK) { return ret; } } switch (ctx->type) { case CKK_RSA: p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_BITS); if (p) { size_t nbits; ret = OSSL_PARAM_get_size_t(p, &nbits); if (ret != RET_OSSL_OK) { return ret; } ctx->data.rsa.modulus_bits = nbits; } p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_PRIMES); if (p) { size_t primes; ret = OSSL_PARAM_get_size_t(p, &primes); if (ret != RET_OSSL_OK) { return ret; } if (primes != 2) { P11PROV_raise(ctx->provctx, CKR_ARGUMENTS_BAD, "No multi-prime support"); return RET_OSSL_ERR; } } p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_E); if (p) { if (p->data_type == OSSL_PARAM_UNSIGNED_INTEGER) { if (p->data_size > 8) { P11PROV_raise(ctx->provctx, CKR_ARGUMENTS_BAD, "Unsupported RSA exponent size"); return RET_OSSL_ERR; } /* fix byte order if necessary while copying */ byteswap_buf(p->data, ctx->data.rsa.exponent, p->data_size); ctx->data.rsa.exponent_size = p->data_size; } else { P11PROV_raise(ctx->provctx, CKR_ARGUMENTS_BAD, "Only unsigned integers for RSA Exponent"); return RET_OSSL_ERR; } } break; case CKK_EC: p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_GROUP_NAME); if (p) { int i; if (p->data_type != OSSL_PARAM_UTF8_STRING) { return RET_OSSL_ERR; } for (i = 0; ec_name_to_params[i].name != NULL; i++) { if (strcmp(ec_name_to_params[i].name, p->data) == 0) { break; } } if (ec_name_to_params[i].name == NULL) { P11PROV_raise(ctx->provctx, CKR_ARGUMENTS_BAD, "Unknown Curve %*s", (int)p->data_size, (char *)p->data); return RET_OSSL_ERR; } ctx->data.ec.ec_params = ec_name_to_params[i].ec_param; ctx->data.ec.ec_params_size = ec_name_to_params[i].ec_param_size; } break; case CKK_EC_EDWARDS: p = OSSL_PARAM_locate_const(params, "p11prov_edname"); if (p) { if (p->data_type != OSSL_PARAM_UTF8_STRING) { return RET_OSSL_ERR; } if (strcmp(p->data, ED25519) == 0) { ctx->data.ec.ec_params = ed25519_ec_params; ctx->data.ec.ec_params_size = ED25519_EC_PARAMS_LEN; } else if (strcmp(p->data, ED448) == 0) { ctx->data.ec.ec_params = ed448_ec_params; ctx->data.ec.ec_params_size = ED448_EC_PARAMS_LEN; } else { P11PROV_raise(ctx->provctx, CKR_ARGUMENTS_BAD, "Unknown edwards curve '%*s'", (int)p->data_size, (char *)p->data); return RET_OSSL_ERR; } } break; default: P11PROV_raise(ctx->provctx, CKR_ARGUMENTS_BAD, "Invalid key gen type %lu", ctx->type); return RET_OSSL_ERR; } return RET_OSSL_OK; } static CK_RV common_gen_callback(void *cbarg) { struct key_generator *ctx = (struct key_generator *)cbarg; OSSL_PARAM params[] = { OSSL_PARAM_END, OSSL_PARAM_END, OSSL_PARAM_END }; int data = 0; int ret; if (!ctx->cb_fn) { return CKR_OK; } params[0] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_POTENTIAL, &data); params[1] = OSSL_PARAM_construct_int(OSSL_GEN_PARAM_ITERATION, &data); ret = ctx->cb_fn(params, ctx->cb_arg); if (ret != RET_OSSL_OK) { return CKR_CANCEL; } return CKR_OK; } /* Common attributes that may currently be added to the template * CKA_ID * CKA_LABEL */ #define COMMON_TMPL_SIZE 2 const CK_BBOOL val_true = CK_TRUE; const CK_BBOOL val_false = CK_FALSE; #define DISCARD_CONST(x) (void *)(x) static void set_bool_val(CK_ATTRIBUTE *attr, bool val) { if (val) { attr->pValue = DISCARD_CONST(&val_true); } else { attr->pValue = DISCARD_CONST(&val_false); } } static void common_key_usage_set_attrs(CK_ATTRIBUTE *template, int tsize, bool enc, bool sig, bool der, bool wrap) { for (int i = 0; i < tsize; i++) { switch (template[i].type) { case CKA_ENCRYPT: case CKA_DECRYPT: set_bool_val(&template[i], enc); break; case CKA_VERIFY: case CKA_VERIFY_RECOVER: case CKA_SIGN: case CKA_SIGN_RECOVER: set_bool_val(&template[i], sig); break; case CKA_DERIVE: set_bool_val(&template[i], der); break; case CKA_WRAP: case CKA_UNWRAP: set_bool_val(&template[i], wrap); break; default: break; } } } /* * Takes a Key Usage string, which must be a space separated list of tokens. * The tokens are the Key usage flag names as defined in ISO/IEC 9594-8 (X.509) * Only the following tokens are recognized: * - dataEncipherment * - digitalSignature * - keyAgreement * - keyEncipherment * uses: Table 25 from pkcs#11 3.1 spec for mappings for public keys * and an analogous mapping for private keys */ static CK_RV common_key_usage_to_tmpl(struct key_generator *ctx, CK_ATTRIBUTE *pubtmpl, CK_ATTRIBUTE *privtmpl, int pubtsize, int privtsize) { const char *str = NULL; size_t len = 0; bool enc = false; bool sig = false; bool der = false; bool wrap = false; if (!ctx->key_usage) { /* leave defaults as set by templates */ return CKR_OK; } str = ctx->key_usage; len = strlen(ctx->key_usage); while (str) { const char *tok = str; size_t toklen = len; const char *p = strchr(str, ' '); if (p) { toklen = p - str; len -= toklen + 1; p += 1; } str = p; if (strncmp(tok, "dataEncipherment", toklen) == 0) { enc = true; } else if (strncmp(tok, "digitalSignature", toklen) == 0) { sig = true; } else if (strncmp(tok, "keyAgreement", toklen) == 0) { der = true; } else if (strncmp(tok, "keyEncipherment", toklen) == 0) { wrap = true; } else { return CKR_ARGUMENTS_BAD; } } common_key_usage_set_attrs(pubtmpl, pubtsize, enc, sig, der, wrap); common_key_usage_set_attrs(privtmpl, privtsize, enc, sig, der, wrap); return CKR_OK; } static int p11prov_common_gen(struct key_generator *ctx, CK_ATTRIBUTE *pubkey_template, CK_ATTRIBUTE *privkey_template, int pubtsize, int privtsize, OSSL_CALLBACK *cb_fn, void *cb_arg, void **key) { CK_SLOT_ID slotid = CK_UNAVAILABLE_INFORMATION; CK_BYTE id[16]; CK_OBJECT_HANDLE privkey; CK_OBJECT_HANDLE pubkey; P11PROV_SESSION *session = NULL; CK_SESSION_HANDLE sh; P11PROV_OBJ *pub_key = NULL; P11PROV_OBJ *priv_key = NULL; CK_ATTRIBUTE cka_id = { 0 }; CK_ATTRIBUTE label = { 0 }; CK_RV ret; ret = common_key_usage_to_tmpl(ctx, pubkey_template, privkey_template, pubtsize, privtsize); if (ret != CKR_OK) { P11PROV_raise(ctx->provctx, ret, "Failed to map Key Usage"); return ret; } if (ctx->uri) { cka_id = p11prov_uri_get_id(ctx->uri); label = p11prov_uri_get_label(ctx->uri); } ret = p11prov_get_session(ctx->provctx, &slotid, NULL, ctx->uri, ctx->mechanism.mechanism, NULL, NULL, true, true, &session); if (ret != CKR_OK) { return ret; } if (cb_fn) { ctx->cb_fn = cb_fn; ctx->cb_arg = cb_arg; p11prov_session_set_callback(session, common_gen_callback, ctx); } sh = p11prov_session_handle(session); if (cka_id.ulValueLen == 0) { int err = RET_OSSL_ERR; /* generate unique id for the key */ err = RAND_bytes_ex(p11prov_ctx_get_libctx(ctx->provctx), id, sizeof(id), 0); if (err != RET_OSSL_OK) { ret = CKR_GENERAL_ERROR; P11PROV_raise(ctx->provctx, ret, "Failed to source random buffer"); goto done; } cka_id.type = CKA_ID; cka_id.pValue = id; cka_id.ulValueLen = 16; } pubkey_template[pubtsize] = cka_id; pubtsize++; privkey_template[privtsize] = cka_id; privtsize++; if (label.ulValueLen != 0) { pubkey_template[pubtsize] = label; pubtsize++; privkey_template[privtsize] = label; privtsize++; } ret = p11prov_GenerateKeyPair(ctx->provctx, sh, &ctx->mechanism, pubkey_template, pubtsize, privkey_template, privtsize, &pubkey, &privkey); if (ret != CKR_OK) { goto done; } ret = p11prov_obj_from_handle(ctx->provctx, session, pubkey, &pub_key); if (ret != CKR_OK) { goto done; } ret = p11prov_obj_from_handle(ctx->provctx, session, privkey, &priv_key); if (ret != CKR_OK) { goto done; } /* set the public key object as associated object of the private key, * this way a public key can always be found from the private key and * operations that assume an EVP_PKEY represent both can find what * they need. * This operation takes a reference so we can safely free pub_key */ p11prov_obj_set_associated(priv_key, pub_key); done: if (ret != CKR_OK) { p11prov_obj_free(priv_key); priv_key = NULL; } p11prov_return_session(session); p11prov_obj_free(pub_key); *key = priv_key; return ret; } static void p11prov_common_gen_cleanup(void *genctx) { struct key_generator *ctx = (struct key_generator *)genctx; P11PROV_debug("common gen_cleanup %p", genctx); OPENSSL_free(ctx->key_usage); p11prov_uri_free(ctx->uri); if (ctx->type == CKK_RSA) { if (ctx->data.rsa.allowed_types_size) { OPENSSL_free(ctx->data.rsa.allowed_types); } } OPENSSL_clear_free(genctx, sizeof(struct key_generator)); } static void *p11prov_common_load(const void *reference, size_t reference_sz, CK_KEY_TYPE key_type) { P11PROV_OBJ *key; /* the contents of the reference is the address to our object */ key = p11prov_obj_from_reference(reference, reference_sz); if (key) { CK_KEY_TYPE type = CK_UNAVAILABLE_INFORMATION; type = p11prov_obj_get_key_type(key); if (type == key_type) { /* add ref count */ key = p11prov_obj_ref_no_cache(key); } else { key = NULL; } } return key; } static int p11prov_common_match(const void *keydata1, const void *keydata2, CK_KEY_TYPE type, int selection) { P11PROV_OBJ *key1 = (P11PROV_OBJ *)keydata1; P11PROV_OBJ *key2 = (P11PROV_OBJ *)keydata2; int cmp_type = OBJ_CMP_KEY_TYPE; if (key1 == key2) { return RET_OSSL_OK; } if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { cmp_type |= OBJ_CMP_KEY_PUBLIC; } if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { cmp_type |= OBJ_CMP_KEY_PRIVATE; } return p11prov_obj_key_cmp(key1, key2, type, cmp_type); } /* RSA gen key */ static void *p11prov_rsa_gen_init(void *provctx, int selection, const OSSL_PARAM params[]) { struct key_generator *ctx = NULL; /* big endian 65537 */ unsigned char def_e[] = { 0x01, 0x00, 0x01 }; int ret; P11PROV_debug("rsa gen_init %p", provctx); ret = p11prov_ctx_status(provctx); if (ret != CKR_OK) { return NULL; } if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) == 0) { P11PROV_raise(provctx, CKR_ARGUMENTS_BAD, "Unsupported selection"); return NULL; } ctx = OPENSSL_zalloc(sizeof(struct key_generator)); if (ctx == NULL) { P11PROV_raise(provctx, CKR_HOST_MEMORY, "Failed to get key_generator"); return NULL; } ctx->provctx = (P11PROV_CTX *)provctx; ctx->type = CKK_RSA; /* set defaults */ ctx->mechanism.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN; ctx->data.rsa.modulus_bits = 2048; ctx->data.rsa.exponent_size = sizeof(def_e); memcpy(ctx->data.rsa.exponent, def_e, ctx->data.rsa.exponent_size); ret = p11prov_common_gen_set_params(ctx, params); if (ret != RET_OSSL_OK) { p11prov_common_gen_cleanup(ctx); ctx = NULL; } return ctx; } static int p11prov_rsa_gen_internal(void *genctx, OSSL_CALLBACK *cb_fn, void *cb_arg, void **key, bool add_allow_mechs) { struct key_generator *ctx = (struct key_generator *)genctx; /* always leave space for CKA_ID and CKA_LABEL */ #define RSA_PUBKEY_TMPL_SIZE 6 CK_ATTRIBUTE pubkey_template[RSA_PUBKEY_TMPL_SIZE + COMMON_TMPL_SIZE] = { { CKA_ENCRYPT, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, { CKA_VERIFY, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, { CKA_WRAP, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, { CKA_TOKEN, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, { CKA_MODULUS_BITS, &ctx->data.rsa.modulus_bits, sizeof(ctx->data.rsa.modulus_bits) }, { CKA_PUBLIC_EXPONENT, &ctx->data.rsa.exponent, ctx->data.rsa.exponent_size }, }; #define RSA_PRIVKEY_TMPL_SIZE 6 #define RSA_PRIVKEY_MAX RSA_PRIVKEY_TMPL_SIZE + 1 + COMMON_TMPL_SIZE CK_ATTRIBUTE privkey_template[RSA_PRIVKEY_MAX] = { { CKA_TOKEN, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, { CKA_PRIVATE, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, { CKA_SENSITIVE, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, { CKA_DECRYPT, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, { CKA_SIGN, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, { CKA_UNWRAP, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, /* 7. Optional CKA_ALLOWED_MECHANISMS */ /* TODO? * CKA_SUBJECT * CKA_COPYABLE = true ? */ }; int pubtsize = RSA_PUBKEY_TMPL_SIZE; int privtsize = RSA_PRIVKEY_TMPL_SIZE; if (add_allow_mechs) { privkey_template[privtsize].type = CKA_ALLOWED_MECHANISMS; privkey_template[privtsize].pValue = DISCARD_CONST(ctx->data.rsa.allowed_types); privkey_template[privtsize].ulValueLen = ctx->data.rsa.allowed_types_size; privtsize++; } P11PROV_debug("rsa gen %p %p %p", genctx, cb_fn, cb_arg); return p11prov_common_gen(ctx, pubkey_template, privkey_template, pubtsize, privtsize, cb_fn, cb_arg, key); } static void *p11prov_rsa_gen(void *genctx, OSSL_CALLBACK *cb_fn, void *cb_arg) { struct key_generator *ctx = (struct key_generator *)genctx; void *key; CK_RV ret; ret = p11prov_rsa_gen_internal(genctx, cb_fn, cb_arg, &key, false); if (ret != CKR_OK) { P11PROV_raise(ctx->provctx, ret, "RSA Key Gen failed"); return NULL; } return key; } static const OSSL_PARAM *p11prov_rsa_gen_settable_params(void *genctx, void *provctx) { static OSSL_PARAM p11prov_rsa_params[] = { OSSL_PARAM_utf8_string(P11PROV_PARAM_URI, NULL, 0), OSSL_PARAM_size_t(OSSL_PKEY_PARAM_RSA_BITS, NULL), OSSL_PARAM_size_t(OSSL_PKEY_PARAM_RSA_PRIMES, NULL), OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_E, NULL, 0), OSSL_PARAM_END, }; return p11prov_rsa_params; } static void *p11prov_rsa_new(void *provctx) { P11PROV_CTX *ctx = (P11PROV_CTX *)provctx; CK_RV ret; P11PROV_debug("rsa new"); ret = p11prov_ctx_status(ctx); if (ret != CKR_OK) { return NULL; } return p11prov_obj_new(provctx, CK_UNAVAILABLE_INFORMATION, CK_P11PROV_IMPORTED_HANDLE, CK_UNAVAILABLE_INFORMATION); } static void p11prov_rsa_free(void *key) { P11PROV_debug("rsa free %p", key); p11prov_obj_free((P11PROV_OBJ *)key); } static void *p11prov_rsa_load(const void *reference, size_t reference_sz) { P11PROV_debug("rsa load %p, %ld", reference, reference_sz); return p11prov_common_load(reference, reference_sz, CKK_RSA); } static int p11prov_rsa_has(const void *keydata, int selection) { P11PROV_OBJ *key = (P11PROV_OBJ *)keydata; P11PROV_debug("rsa has %p %d", key, selection); if (key == NULL) { return RET_OSSL_ERR; } if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { if (p11prov_obj_get_class(key) != CKO_PRIVATE_KEY) { return RET_OSSL_ERR; } } /* We always return OK when asked for a PUBLIC KEY, even if we only have a * private key, as we can try to fetch the associated public key as needed * if asked for an export (main reason to do this), or other operations */ return RET_OSSL_OK; } static int p11prov_rsa_match(const void *keydata1, const void *keydata2, int selection) { P11PROV_debug("rsa match %p %p %d", keydata1, keydata2, selection); return p11prov_common_match(keydata1, keydata2, CKK_RSA, selection); } static int p11prov_rsa_import(void *keydata, int selection, const OSSL_PARAM params[]) { P11PROV_OBJ *key = (P11PROV_OBJ *)keydata; CK_OBJECT_CLASS class = CKO_PUBLIC_KEY; CK_RV rv; P11PROV_debug("rsa import %p", key); if (!key) { return RET_OSSL_ERR; } if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { class = CKO_PRIVATE_KEY; } /* NOTE: the following is needed because of bug: * https://github.com/openssl/openssl/issues/21596 * it can be removed once we can depend on a recent enough version * after it is fixed */ if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { const OSSL_PARAM *p; p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_D); if (!p) { /* not really a private key */ class = CKO_PUBLIC_KEY; } } rv = p11prov_obj_import_key(key, CKK_RSA, class, params); if (rv != CKR_OK) { return RET_OSSL_ERR; } return RET_OSSL_OK; } #define PUBLIC_PARAMS \ OSSL_KEYMGMT_SELECT_PUBLIC_KEY | OSSL_KEYMGMT_SELECT_ALL_PARAMETERS static int p11prov_rsa_export(void *keydata, int selection, OSSL_CALLBACK *cb_fn, void *cb_arg) { P11PROV_OBJ *key = (P11PROV_OBJ *)keydata; P11PROV_CTX *ctx = p11prov_obj_get_prov_ctx(key); CK_OBJECT_CLASS class = p11prov_obj_get_class(key); P11PROV_debug("rsa export %p, selection= %d", keydata, selection); if (key == NULL) { return RET_OSSL_ERR; } if (p11prov_ctx_allow_export(ctx) & DISALLOW_EXPORT_PUBLIC) { return RET_OSSL_ERR; } /* if anything else is asked for we can't provide it, so be strict */ if ((class == CKO_PUBLIC_KEY) || (selection & ~(PUBLIC_PARAMS)) == 0) { return p11prov_obj_export_public_key(key, CKK_RSA, true, false, cb_fn, cb_arg); } return RET_OSSL_ERR; } #define RSA_KEY_ATTRS_SIZE 2 static const OSSL_PARAM p11prov_rsa_key_types[RSA_KEY_ATTRS_SIZE + 1] = { OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_N, NULL, 0), OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_E, NULL, 0), OSSL_PARAM_END, }; static const OSSL_PARAM *p11prov_rsa_import_types(int selection) { P11PROV_debug("rsa import types"); if (selection == OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { return p11prov_rsa_key_types; } return NULL; } static const OSSL_PARAM *p11prov_rsa_export_types(int selection) { P11PROV_debug("rsa export types"); if (selection == OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { return p11prov_rsa_key_types; } return NULL; } static const char *p11prov_rsa_query_operation_name(int operation_id) { return P11PROV_NAME_RSA; } static int p11prov_rsa_secbits(int bits) { /* common values from various NIST documents */ switch (bits) { case 2048: return 112; case 3072: return 128; case 4096: return 152; case 6144: return 176; case 7680: return 192; case 8192: return 200; case 15360: return 256; } /* TODO: do better calculations, * see ossl_ifc_ffc_compute_security_bits() */ /* NOLINTBEGIN(readability-braces-around-statements) */ if (bits >= 15360) return 256; if (bits >= 8192) return 200; if (bits >= 7680) return 192; if (bits >= 6144) return 176; if (bits >= 4096) return 152; if (bits >= 3072) return 128; if (bits >= 2048) return 112; /* NOLINTEND(readability-braces-around-statements) */ return 0; } static int p11prov_rsa_get_params(void *keydata, OSSL_PARAM params[]) { P11PROV_OBJ *key = (P11PROV_OBJ *)keydata; CK_ATTRIBUTE *modulus; OSSL_PARAM *p; int ret; P11PROV_debug("rsa get params %p", keydata); if (key == NULL) { return RET_OSSL_ERR; } modulus = p11prov_obj_get_attr(key, CKA_MODULUS); if (!modulus) { return RET_OSSL_ERR; } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS); if (p) { /* TODO: may want to try to get CKA_MODULUS_BITS, * and fallback only if unavailable */ ret = OSSL_PARAM_set_int(p, modulus->ulValueLen * 8); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS); if (p) { /* TODO: as above, plus use log() for intermediate values */ int secbits = p11prov_rsa_secbits(modulus->ulValueLen * 8); ret = OSSL_PARAM_set_int(p, secbits); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE); if (p) { ret = OSSL_PARAM_set_int(p, modulus->ulValueLen); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DEFAULT_DIGEST); if (p) { ret = OSSL_PARAM_set_utf8_string(p, DFLT_DIGEST); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_RSA_N); if (p) { if (p->data_type != OSSL_PARAM_UNSIGNED_INTEGER) { return RET_OSSL_ERR; } p->return_size = modulus->ulValueLen; if (p->data) { if (p->data_size < modulus->ulValueLen) { return RET_OSSL_ERR; } byteswap_buf(modulus->pValue, p->data, modulus->ulValueLen); p->data_size = modulus->ulValueLen; } } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_RSA_E); if (p) { CK_ATTRIBUTE *exp; if (p->data_type != OSSL_PARAM_UNSIGNED_INTEGER) { return RET_OSSL_ERR; } exp = p11prov_obj_get_attr(key, CKA_PUBLIC_EXPONENT); if (!exp) { return RET_OSSL_ERR; } p->return_size = exp->ulValueLen; if (p->data) { if (p->data_size < exp->ulValueLen) { return RET_OSSL_ERR; } byteswap_buf(exp->pValue, p->data, exp->ulValueLen); p->data_size = exp->ulValueLen; } } return RET_OSSL_OK; } static const OSSL_PARAM *p11prov_rsa_gettable_params(void *provctx) { static const OSSL_PARAM params[] = { OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_DEFAULT_DIGEST, NULL, 0), OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_N, NULL, 0), OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_E, NULL, 0), /* PKCS#11 does not have restrictions associated to keys so * we can't support OSSL_PKEY_PARAM_MANDATORY_DIGEST yet */ OSSL_PARAM_END, }; return params; } const OSSL_DISPATCH p11prov_rsa_keymgmt_functions[] = { DISPATCH_KEYMGMT_ELEM(rsa, NEW, new), DISPATCH_KEYMGMT_ELEM(rsa, GEN_INIT, gen_init), DISPATCH_KEYMGMT_ELEM(rsa, GEN, gen), DISPATCH_KEYMGMT_ELEM(common, GEN_SET_PARAMS, gen_set_params), DISPATCH_KEYMGMT_ELEM(rsa, GEN_SETTABLE_PARAMS, gen_settable_params), DISPATCH_KEYMGMT_ELEM(common, GEN_CLEANUP, gen_cleanup), DISPATCH_KEYMGMT_ELEM(rsa, LOAD, load), DISPATCH_KEYMGMT_ELEM(rsa, FREE, free), DISPATCH_KEYMGMT_ELEM(rsa, HAS, has), DISPATCH_KEYMGMT_ELEM(rsa, MATCH, match), DISPATCH_KEYMGMT_ELEM(rsa, IMPORT, import), DISPATCH_KEYMGMT_ELEM(rsa, IMPORT_TYPES, import_types), DISPATCH_KEYMGMT_ELEM(rsa, EXPORT, export), DISPATCH_KEYMGMT_ELEM(rsa, EXPORT_TYPES, export_types), DISPATCH_KEYMGMT_ELEM(rsa, QUERY_OPERATION_NAME, query_operation_name), DISPATCH_KEYMGMT_ELEM(rsa, GET_PARAMS, get_params), DISPATCH_KEYMGMT_ELEM(rsa, GETTABLE_PARAMS, gettable_params), { 0, NULL }, }; DISPATCH_KEYMGMT_FN(rsapss, gen); DISPATCH_KEYMGMT_FN(rsa, gen_settable_params); static CK_RV set_default_rsapss_mechanisms(struct key_generator *ctx) { size_t mechs_size = sizeof(CK_MECHANISM_TYPE) * P11PROV_N_RSAPSS_MECHS; ctx->data.rsa.allowed_types = OPENSSL_malloc(mechs_size); if (ctx->data.rsa.allowed_types == NULL) { P11PROV_raise(ctx->provctx, CKR_HOST_MEMORY, "Allocating data"); return CKR_HOST_MEMORY; } memcpy(ctx->data.rsa.allowed_types, p11prov_rsapss_mechs, mechs_size); ctx->data.rsa.allowed_types_size = mechs_size; return CKR_OK; } static void *p11prov_rsapss_gen(void *genctx, OSSL_CALLBACK *cb_fn, void *cb_arg) { struct key_generator *ctx = (struct key_generator *)genctx; CK_BBOOL token_supports_allowed_mechs = CK_TRUE; bool set_quirk = false; void *key = NULL; CK_RV ret; /* check if we can add CKA_ALLOWED_MECHANISMS at all */ ret = p11prov_token_sup_attr(ctx->provctx, p11prov_obj_get_slotid(key), GET_ATTR, CKA_ALLOWED_MECHANISMS, &token_supports_allowed_mechs); if (ret != CKR_OK) { P11PROV_raise(ctx->provctx, ret, "Failed to probe CKA_ALLOWED_MECHANISMS quirk"); goto done; } if (token_supports_allowed_mechs) { /* We always want to restrict PSS keys to just the PSS mechanisms. * If a specific restriction is not already set then set defaults */ if (!ctx->data.rsa.allowed_types) { ret = set_default_rsapss_mechanisms(ctx); if (ret != CKR_OK) { P11PROV_raise(ctx->provctx, ret, "Failed to set default pss params"); goto done; } } ret = p11prov_rsa_gen_internal(genctx, cb_fn, cb_arg, &key, true); switch (ret) { case CKR_OK: break; case CKR_ATTRIBUTE_TYPE_INVALID: /* Failed: This may be because the token does not support * CKA_ALLOWED_MECHANISMS, so we retry again later without it. */ P11PROV_debug("Failed to Generate PSS key with restrictions"); token_supports_allowed_mechs = CK_FALSE; /* if the quirk has never been set we'll get back what we * defaulted to, if that is the case then set the quirk. * Otherwise the quirk was successfully probed earlier * and we'll ignore setting anything as this may also be * a fluke or a key specific failure */ ret = p11prov_token_sup_attr( ctx->provctx, p11prov_obj_get_slotid(key), GET_ATTR, CKA_ALLOWED_MECHANISMS, &token_supports_allowed_mechs); if (ret != CKR_OK) { P11PROV_raise(ctx->provctx, ret, "Failed to probe quirk"); } else if (token_supports_allowed_mechs == CK_FALSE) { /* The previous check didn't hit a stored quirk, so * signal to set one later based on the outcome of the * next attempt. */ set_quirk = true; } break; default: /* In theory we should consider this error fatal, but given * NSS sotoken returns CKR_GENERAL_ERROR just because it does * not understand one attribute in the template we better * retry anyway, as other tokens may return other errors too. * The only penalty is that we won't set the quirk and keep * retrying because we can't be sure the attribute is not * valid in general ... */ break; } } if (!key) { ret = p11prov_rsa_gen_internal(genctx, cb_fn, cb_arg, &key, false); if (ret != CKR_OK) { goto done; } if (set_quirk) { token_supports_allowed_mechs = CK_FALSE; (void)p11prov_token_sup_attr( ctx->provctx, p11prov_obj_get_slotid(key), SET_ATTR, CKA_ALLOWED_MECHANISMS, &token_supports_allowed_mechs); } } ret = CKR_OK; done: if (ret != CKR_OK) { P11PROV_raise(ctx->provctx, ret, "Failed to generate RSA-PSS key"); return NULL; } return key; } static int p11prov_rsapss_gen_set_params(void *genctx, const OSSL_PARAM params[]) { struct key_generator *ctx = (struct key_generator *)genctx; const OSSL_PARAM *p; int ret; if (!ctx) { return RET_OSSL_ERR; } if (params == NULL) { return RET_OSSL_OK; } p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_DIGEST); if (p) { CK_MECHANISM_TYPE digest_mech = CK_UNAVAILABLE_INFORMATION; CK_MECHANISM_TYPE allowed_mech = CK_UNAVAILABLE_INFORMATION; const char *digest = NULL; CK_RV rv; ret = OSSL_PARAM_get_utf8_string_ptr(p, &digest); if (ret != RET_OSSL_OK) { return ret; } rv = p11prov_digest_get_by_name(digest, &digest_mech); if (rv != CKR_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return RET_OSSL_ERR; } allowed_mech = p11prov_digest_to_rsapss_mech(digest_mech); P11PROV_debug("Restrict RSAPSS DIGEST to %s (mech: %lu)", digest, allowed_mech); if (allowed_mech == CK_UNAVAILABLE_INFORMATION) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return RET_OSSL_ERR; } /* overwrites any previous setting */ ctx->data.rsa.allowed_types_size = sizeof(CK_MECHANISM_TYPE); ctx->data.rsa.allowed_types = OPENSSL_realloc( ctx->data.rsa.allowed_types, ctx->data.rsa.allowed_types_size); if (!ctx->data.rsa.allowed_types) { ctx->data.rsa.allowed_types_size = 0; ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_SET_PARAMETER); return RET_OSSL_ERR; } ctx->data.rsa.allowed_types[0] = allowed_mech; } return p11prov_common_gen_set_params(genctx, params); } static const OSSL_PARAM *p11prov_rsapss_gen_settable_params(void *genctx, void *provctx) { static OSSL_PARAM p11prov_rsapss_params[] = { OSSL_PARAM_utf8_string(P11PROV_PARAM_URI, NULL, 0), OSSL_PARAM_size_t(OSSL_PKEY_PARAM_RSA_BITS, NULL), OSSL_PARAM_size_t(OSSL_PKEY_PARAM_RSA_PRIMES, NULL), OSSL_PARAM_BN(OSSL_PKEY_PARAM_RSA_E, NULL, 0), OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_RSA_DIGEST, NULL, 0), /* unsupportable yet: * OSSL_PKEY_PARAM_RSA_DIGEST_PROPS * OSSL_PKEY_PARAM_RSA_MASKGENFUNC * OSSL_PKEY_PARAM_RSA_MGF1_DIGEST * OSSL_PKEY_PARAM_RSA_PSS_SALTLEN */ OSSL_PARAM_END, }; return p11prov_rsapss_params; } const OSSL_DISPATCH p11prov_rsapss_keymgmt_functions[] = { DISPATCH_KEYMGMT_ELEM(rsa, NEW, new), DISPATCH_KEYMGMT_ELEM(rsa, GEN_INIT, gen_init), DISPATCH_KEYMGMT_ELEM(rsapss, GEN, gen), DISPATCH_KEYMGMT_ELEM(rsapss, GEN_SET_PARAMS, gen_set_params), DISPATCH_KEYMGMT_ELEM(rsapss, GEN_SETTABLE_PARAMS, gen_settable_params), DISPATCH_KEYMGMT_ELEM(common, GEN_CLEANUP, gen_cleanup), DISPATCH_KEYMGMT_ELEM(rsa, LOAD, load), DISPATCH_KEYMGMT_ELEM(rsa, FREE, free), DISPATCH_KEYMGMT_ELEM(rsa, HAS, has), DISPATCH_KEYMGMT_ELEM(rsa, MATCH, match), DISPATCH_KEYMGMT_ELEM(rsa, IMPORT, import), DISPATCH_KEYMGMT_ELEM(rsa, IMPORT_TYPES, import_types), DISPATCH_KEYMGMT_ELEM(rsa, EXPORT, export), DISPATCH_KEYMGMT_ELEM(rsa, EXPORT_TYPES, export_types), DISPATCH_KEYMGMT_ELEM(rsa, QUERY_OPERATION_NAME, query_operation_name), DISPATCH_KEYMGMT_ELEM(rsa, GET_PARAMS, get_params), DISPATCH_KEYMGMT_ELEM(rsa, GETTABLE_PARAMS, gettable_params), { 0, NULL }, }; DISPATCH_KEYMGMT_FN(ec, new); DISPATCH_KEYMGMT_FN(ec, gen_init); DISPATCH_KEYMGMT_FN(ec, gen); DISPATCH_KEYMGMT_FN(ec, gen_settable_params); DISPATCH_KEYMGMT_FN(ec, load); DISPATCH_KEYMGMT_FN(ec, free); DISPATCH_KEYMGMT_FN(ec, has); DISPATCH_KEYMGMT_FN(ec, match); DISPATCH_KEYMGMT_FN(ec, import); DISPATCH_KEYMGMT_FN(ec, import_types); DISPATCH_KEYMGMT_FN(ec, export); DISPATCH_KEYMGMT_FN(ec, export_types); DISPATCH_KEYMGMT_FN(ec, query_operation_name); DISPATCH_KEYMGMT_FN(ec, get_params); DISPATCH_KEYMGMT_FN(ec, gettable_params); DISPATCH_KEYMGMT_FN(ec, set_params); DISPATCH_KEYMGMT_FN(ec, settable_params); static void *p11prov_ec_new(void *provctx) { P11PROV_CTX *ctx = (P11PROV_CTX *)provctx; CK_RV ret; P11PROV_debug("ec new"); ret = p11prov_ctx_status(ctx); if (ret != CKR_OK) { return NULL; } return p11prov_obj_new(provctx, CK_UNAVAILABLE_INFORMATION, CK_P11PROV_IMPORTED_HANDLE, CK_UNAVAILABLE_INFORMATION); } static void *p11prov_ec_gen_init(void *provctx, int selection, const OSSL_PARAM params[]) { struct key_generator *ctx = NULL; int ret; P11PROV_debug("ec gen_init %p", provctx); ret = p11prov_ctx_status(provctx); if (ret != CKR_OK) { return NULL; } /* we need to allow to initialize a generation of just domain parameters, * as this is used by OpenSSL for ECDH, to set the expected parameters * first and then import the received public peer key */ if ((selection & OSSL_KEYMGMT_SELECT_ALL) == 0) { P11PROV_raise(provctx, CKR_ARGUMENTS_BAD, "Unsupported selection"); return NULL; } ctx = OPENSSL_zalloc(sizeof(struct key_generator)); if (ctx == NULL) { P11PROV_raise(provctx, CKR_HOST_MEMORY, "Failed to get key_generator"); return NULL; } ctx->provctx = (P11PROV_CTX *)provctx; ctx->type = CKK_EC; if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { ctx->mechanism.mechanism = CKM_EC_KEY_PAIR_GEN; } else { ctx->mechanism.mechanism = CK_UNAVAILABLE_INFORMATION; } /* set defaults */ ctx->data.ec.ec_params = prime256v1_param; ctx->data.ec.ec_params_size = sizeof(prime256v1_param); ret = p11prov_common_gen_set_params(ctx, params); if (ret != RET_OSSL_OK) { p11prov_common_gen_cleanup(ctx); ctx = NULL; } return ctx; } static void *p11prov_ec_gen(void *genctx, OSSL_CALLBACK *cb_fn, void *cb_arg) { struct key_generator *ctx = (struct key_generator *)genctx; void *key; CK_RV ret; if (ctx->mechanism.mechanism == CK_UNAVAILABLE_INFORMATION) { /* OpenSSL asked for a paramgen, basically it wants an * empty key of a specific group that it will be filling * up with public params later */ CK_ATTRIBUTE ec_params = { .type = CKA_EC_PARAMS, .pValue = (CK_VOID_PTR)ctx->data.ec.ec_params, .ulValueLen = (CK_ULONG)ctx->data.ec.ec_params_size, }; return mock_pub_ec_key(ctx->provctx, ctx->type, &ec_params); } /* always leave space for CKA_ID and CKA_LABEL */ #define EC_PUBKEY_TMPL_SIZE 5 CK_ATTRIBUTE pubkey_template[EC_PUBKEY_TMPL_SIZE + COMMON_TMPL_SIZE] = { { CKA_TOKEN, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, { CKA_DERIVE, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, { CKA_VERIFY, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, { CKA_WRAP, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, { CKA_EC_PARAMS, (CK_BYTE *)ctx->data.ec.ec_params, ctx->data.ec.ec_params_size }, }; #define EC_PRIVKEY_TMPL_SIZE 6 CK_ATTRIBUTE privkey_template[EC_PRIVKEY_TMPL_SIZE + COMMON_TMPL_SIZE] = { { CKA_TOKEN, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, { CKA_DERIVE, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, { CKA_PRIVATE, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, { CKA_SENSITIVE, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, { CKA_SIGN, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, { CKA_UNWRAP, DISCARD_CONST(&val_true), sizeof(CK_BBOOL) }, /* TODO? * CKA_SUBJECT * CKA_COPYABLE = true ? */ }; int pubtsize = EC_PUBKEY_TMPL_SIZE; int privtsize = EC_PRIVKEY_TMPL_SIZE; P11PROV_debug("ec gen %p %p %p", ctx, cb_fn, cb_arg); ret = p11prov_common_gen(ctx, pubkey_template, privkey_template, pubtsize, privtsize, cb_fn, cb_arg, &key); if (ret != CKR_OK) { P11PROV_raise(ctx->provctx, ret, "EC Key generation failed"); return NULL; } return key; } static const OSSL_PARAM *p11prov_ec_gen_settable_params(void *genctx, void *provctx) { static OSSL_PARAM p11prov_ec_params[] = { OSSL_PARAM_utf8_string(P11PROV_PARAM_URI, NULL, 0), OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0), OSSL_PARAM_END, }; return p11prov_ec_params; } static void p11prov_ec_free(void *key) { P11PROV_debug("ec free %p", key); p11prov_obj_free((P11PROV_OBJ *)key); } static void *p11prov_ec_load(const void *reference, size_t reference_sz) { P11PROV_debug("ec load %p, %ld", reference, reference_sz); return p11prov_common_load(reference, reference_sz, CKK_EC); } static int p11prov_ec_has(const void *keydata, int selection) { P11PROV_OBJ *key = (P11PROV_OBJ *)keydata; P11PROV_debug("ec has %p %d", key, selection); if (key == NULL) { return RET_OSSL_ERR; } if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { if (p11prov_obj_get_class(key) != CKO_PRIVATE_KEY) { return RET_OSSL_ERR; } } /* We always return OK when asked for a PUBLIC KEY, even if we only have a * private key, as we can try to fetch the associated public key as needed * if asked for an export (main reason to do this), or other operations */ return RET_OSSL_OK; } static int p11prov_ec_match(const void *keydata1, const void *keydata2, int selection) { P11PROV_debug("ec match %p %p %d", keydata1, keydata2, selection); return p11prov_common_match(keydata1, keydata2, CKK_EC, selection); } static int p11prov_ec_import_genr(CK_KEY_TYPE key_type, void *keydata, int selection, const OSSL_PARAM params[]) { P11PROV_OBJ *key = (P11PROV_OBJ *)keydata; CK_OBJECT_CLASS class = CK_UNAVAILABLE_INFORMATION; CK_RV rv; P11PROV_debug("ec import %p", key); if (!key) { return RET_OSSL_ERR; } if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { class = CKO_PRIVATE_KEY; } else if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { class = CKO_PUBLIC_KEY; } else if (selection & OSSL_KEYMGMT_SELECT_DOMAIN_PARAMETERS) { class = CKO_DOMAIN_PARAMETERS; } /* NOTE: the following is needed because of bug: * https://github.com/openssl/openssl/issues/21596 * it can be removed once we can depend on a recent enough version * after it is fixed */ if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { const OSSL_PARAM *p; p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY); if (!p) { /* not really a private key */ class = CKO_PUBLIC_KEY; } } if (class == CKO_DOMAIN_PARAMETERS && key_type != CKK_EC) { /* There are no Domain parameters associated with an * ECX or RSA key in OpenSSL, so there is nothing really * we can import */ return RET_OSSL_ERR; } rv = p11prov_obj_import_key(key, key_type, class, params); if (rv != CKR_OK) { return RET_OSSL_ERR; } return RET_OSSL_OK; } static int p11prov_ec_import(void *keydata, int selection, const OSSL_PARAM params[]) { return p11prov_ec_import_genr(CKK_EC, keydata, selection, params); } static int p11prov_ec_export(void *keydata, int selection, OSSL_CALLBACK *cb_fn, void *cb_arg) { P11PROV_OBJ *key = (P11PROV_OBJ *)keydata; P11PROV_CTX *ctx = p11prov_obj_get_prov_ctx(key); bool params_only = true; P11PROV_debug("ec export %p", keydata); if (key == NULL) { return RET_OSSL_ERR; } if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { /* can't export private keys */ return RET_OSSL_ERR; } if (p11prov_ctx_allow_export(ctx) & DISALLOW_EXPORT_PUBLIC) { return RET_OSSL_ERR; } if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { params_only = false; } return p11prov_obj_export_public_key(key, CKK_EC, true, params_only, cb_fn, cb_arg); } static const OSSL_PARAM p11prov_ec_key_types[] = { OSSL_PARAM_END, }; static const OSSL_PARAM *p11prov_ec_import_types(int selection) { P11PROV_debug("ec import types"); if (selection == OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { return p11prov_ec_key_types; } return NULL; } static const OSSL_PARAM *p11prov_ec_export_types(int selection) { P11PROV_debug("ec export types"); if (selection == OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { return p11prov_ec_key_types; } return NULL; } static const char *p11prov_ec_query_operation_name(int operation_id) { switch (operation_id) { case OSSL_OP_SIGNATURE: return P11PROV_NAME_ECDSA; case OSSL_OP_KEYEXCH: return P11PROV_NAME_ECDH; } return NULL; } #define CURVE_521_BITS 521 #define MAX_CURVE_BITS CURVE_521_BITS #define MAX_CURVE_SIZE ((MAX_CURVE_BITS + 7) / 8) static int p11prov_ec_secbits(int bits) { /* common values from various NIST documents */ if (bits < 224) { return 0; } if (bits < 256) { return 112; } if (bits < 384) { return 128; } if (bits < 512) { return 192; } return 256; } static int p11prov_ec_get_params(void *keydata, OSSL_PARAM params[]) { P11PROV_OBJ *key = (P11PROV_OBJ *)keydata; OSSL_PARAM *p; CK_ULONG group_size; int ret; P11PROV_debug("ec get params %p", keydata); if (key == NULL) { return RET_OSSL_ERR; } group_size = p11prov_obj_get_key_bit_size(key); if (group_size == CK_UNAVAILABLE_INFORMATION) { return RET_OSSL_ERR; } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS); if (p) { ret = OSSL_PARAM_set_int(p, group_size); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS); if (p) { /* TODO: as above, plus use log() for intermediate values */ int secbits = p11prov_ec_secbits(group_size); ret = OSSL_PARAM_set_int(p, secbits); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE); if (p) { /* add room for ECDSA Signature DER overhead */ CK_ULONG size = p11prov_obj_get_key_size(key); if (size > MAX_CURVE_SIZE) { /* coverity started looking for silly integer overflows */ return RET_OSSL_ERR; } ret = OSSL_PARAM_set_int(p, 3 + (size + 4) * 2); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_GROUP_NAME); if (p) { const char *curve_name = p11prov_obj_get_ec_group_name(key); if (curve_name == NULL) { return RET_OSSL_ERR; } ret = OSSL_PARAM_set_utf8_string(p, curve_name); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_DEFAULT_DIGEST); if (p) { ret = OSSL_PARAM_set_utf8_string(p, DFLT_DIGEST); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_EC_PUB_X); if (p) { CK_ATTRIBUTE *pub_x; if (p->data_type != OSSL_PARAM_UNSIGNED_INTEGER) { return RET_OSSL_ERR; } ret = p11prov_obj_get_ec_public_x_y(key, &pub_x, NULL); if (ret != RET_OSSL_OK) { return ret; } p->return_size = pub_x->ulValueLen; if (p->data) { if (p->data_size < pub_x->ulValueLen) { return RET_OSSL_ERR; } memcpy(p->data, pub_x->pValue, pub_x->ulValueLen); p->data_size = pub_x->ulValueLen; } } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_EC_PUB_Y); if (p) { CK_ATTRIBUTE *pub_y; if (p->data_type != OSSL_PARAM_UNSIGNED_INTEGER) { return RET_OSSL_ERR; } ret = p11prov_obj_get_ec_public_x_y(key, NULL, &pub_y); if (ret != RET_OSSL_OK) { return ret; } p->return_size = pub_y->ulValueLen; if (p->data) { if (p->data_size < pub_y->ulValueLen) { return RET_OSSL_ERR; } memcpy(p->data, pub_y->pValue, pub_y->ulValueLen); p->data_size = pub_y->ulValueLen; } } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY); if (p) { CK_ATTRIBUTE *pub_key; if (p->data_type != OSSL_PARAM_OCTET_STRING) { return RET_OSSL_ERR; } pub_key = p11prov_obj_get_ec_public_raw(key); if (!pub_key) { return RET_OSSL_ERR; } p->return_size = pub_key->ulValueLen; if (p->data) { if (p->data_size < pub_key->ulValueLen) { return RET_OSSL_ERR; } memcpy(p->data, pub_key->pValue, pub_key->ulValueLen); } } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT); if (p) { bool compressed = p11prov_obj_get_ec_compressed(key); if (compressed) { ret = OSSL_PARAM_set_utf8_string(p, "compressed"); } else { ret = OSSL_PARAM_set_utf8_string(p, "uncompressed"); } if (ret != RET_OSSL_OK) { return ret; } } return RET_OSSL_OK; } static const OSSL_PARAM *p11prov_ec_gettable_params(void *provctx) { static const OSSL_PARAM params[] = { OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0), OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_DEFAULT_DIGEST, NULL, 0), OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_PUB_X, NULL, 0), OSSL_PARAM_BN(OSSL_PKEY_PARAM_EC_PUB_Y, NULL, 0), OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0), OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT, NULL, 0), /* * OSSL_PKEY_PARAM_EC_DECODED_FROM_EXPLICIT_PARAM * OSSL_PKEY_PARAM_EC_ENCODING * OSSL_PKEY_PARAM_EC_FIELD_TYPE * OSSL_PKEY_PARAM_EC_P * OSSL_PKEY_PARAM_EC_A * OSSL_PKEY_PARAM_EC_B * OSSL_PKEY_PARAM_EC_GENERATOR * OSSL_PKEY_PARAM_EC_ORDER * OSSL_PKEY_PARAM_EC_COFACTOR * OSSL_PKEY_PARAM_EC_SEED * OSSL_PKEY_PARAM_PUB_KEY * OSSL_PKEY_PARAM_PRIV_KEY * OSSL_PKEY_PARAM_USE_COFACTOR_ECDH * OSSL_PKEY_PARAM_EC_INCLUDE_PUBLIC */ OSSL_PARAM_END, }; return params; } static int p11prov_ec_set_params(void *keydata, const OSSL_PARAM params[]) { P11PROV_OBJ *key = (P11PROV_OBJ *)keydata; const OSSL_PARAM *p; P11PROV_debug("ec set params %p", keydata); if (key == NULL) { return RET_OSSL_ERR; } p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY); if (p) { if (p->data_type != OSSL_PARAM_OCTET_STRING) { return RET_OSSL_ERR; } if (p11prov_obj_set_ec_encoded_public_key(key, p->data, p->data_size) != CKR_OK) { return RET_OSSL_ERR; } } return RET_OSSL_OK; } static const OSSL_PARAM *p11prov_ec_settable_params(void *provctx) { static const OSSL_PARAM params[] = { OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_ENCODED_PUBLIC_KEY, NULL, 0), OSSL_PARAM_END, }; return params; } const OSSL_DISPATCH p11prov_ec_keymgmt_functions[] = { DISPATCH_KEYMGMT_ELEM(ec, NEW, new), DISPATCH_KEYMGMT_ELEM(ec, GEN_INIT, gen_init), DISPATCH_KEYMGMT_ELEM(ec, GEN, gen), DISPATCH_KEYMGMT_ELEM(common, GEN_CLEANUP, gen_cleanup), DISPATCH_KEYMGMT_ELEM(common, GEN_SET_PARAMS, gen_set_params), DISPATCH_KEYMGMT_ELEM(ec, GEN_SETTABLE_PARAMS, gen_settable_params), DISPATCH_KEYMGMT_ELEM(ec, LOAD, load), DISPATCH_KEYMGMT_ELEM(ec, FREE, free), DISPATCH_KEYMGMT_ELEM(ec, HAS, has), DISPATCH_KEYMGMT_ELEM(ec, MATCH, match), DISPATCH_KEYMGMT_ELEM(ec, IMPORT, import), DISPATCH_KEYMGMT_ELEM(ec, IMPORT_TYPES, import_types), DISPATCH_KEYMGMT_ELEM(ec, EXPORT, export), DISPATCH_KEYMGMT_ELEM(ec, EXPORT_TYPES, export_types), DISPATCH_KEYMGMT_ELEM(ec, QUERY_OPERATION_NAME, query_operation_name), DISPATCH_KEYMGMT_ELEM(ec, GET_PARAMS, get_params), DISPATCH_KEYMGMT_ELEM(ec, GETTABLE_PARAMS, gettable_params), DISPATCH_KEYMGMT_ELEM(ec, SET_PARAMS, set_params), DISPATCH_KEYMGMT_ELEM(ec, SETTABLE_PARAMS, settable_params), { 0, NULL }, }; DISPATCH_KEYMGMT_FN(ed25519, gen_init); DISPATCH_KEYMGMT_FN(ed448, gen_init); DISPATCH_KEYMGMT_FN(ed, gen_settable_params); DISPATCH_KEYMGMT_FN(ed, load); DISPATCH_KEYMGMT_FN(ed, match); DISPATCH_KEYMGMT_FN(ed, import_types); DISPATCH_KEYMGMT_FN(ed, export); DISPATCH_KEYMGMT_FN(ed, export_types); DISPATCH_KEYMGMT_FN(ed, get_params); DISPATCH_KEYMGMT_FN(ed, gettable_params); DISPATCH_KEYMGMT_FN(ed, set_params); DISPATCH_KEYMGMT_FN(ed, settable_params); static void *p11prov_ed25519_gen_init(void *provctx, int selection, const OSSL_PARAM params[]) { struct key_generator *ctx = NULL; const OSSL_PARAM curve[] = { OSSL_PARAM_utf8_string("p11prov_edname", (void *)ED25519, sizeof(ED25519)), OSSL_PARAM_END }; int ret; P11PROV_debug("ed25519 gen_init %p", provctx); ret = p11prov_ctx_status(provctx); if (ret != CKR_OK) { return NULL; } /* we need to allow to initialize a generation of just domain parameters, * as this is used by OpenSSL for ECDH, to set the expected parameters * first and then import the received public peer key */ if ((selection & OSSL_KEYMGMT_SELECT_ALL) == 0) { P11PROV_raise(provctx, CKR_ARGUMENTS_BAD, "Unsupported selection"); return NULL; } ctx = OPENSSL_zalloc(sizeof(struct key_generator)); if (ctx == NULL) { P11PROV_raise(provctx, CKR_HOST_MEMORY, "Failed to get key_generator"); return NULL; } ctx->provctx = (P11PROV_CTX *)provctx; ctx->type = CKK_EC_EDWARDS; if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { ctx->mechanism.mechanism = CKM_EC_EDWARDS_KEY_PAIR_GEN; } /* set defaults */ ret = p11prov_common_gen_set_params(ctx, curve); if (ret != RET_OSSL_OK) { p11prov_common_gen_cleanup(ctx); return NULL; } ret = p11prov_common_gen_set_params(ctx, params); if (ret != RET_OSSL_OK) { p11prov_common_gen_cleanup(ctx); return NULL; } return ctx; } static void *p11prov_ed448_gen_init(void *provctx, int selection, const OSSL_PARAM params[]) { struct key_generator *ctx = NULL; const OSSL_PARAM curve[] = { OSSL_PARAM_utf8_string("p11prov_edname", (void *)ED448, sizeof(ED448)), OSSL_PARAM_END }; int ret; P11PROV_debug("ed448 gen_init %p", provctx); ret = p11prov_ctx_status(provctx); if (ret != CKR_OK) { return NULL; } /* we need to allow to initialize a generation of just domain parameters, * as this is used by OpenSSL for ECDH, to set the expected parameters * first and then import the received public peer key */ if ((selection & OSSL_KEYMGMT_SELECT_ALL) == 0) { P11PROV_raise(provctx, CKR_ARGUMENTS_BAD, "Unsupported selection"); return NULL; } ctx = OPENSSL_zalloc(sizeof(struct key_generator)); if (ctx == NULL) { P11PROV_raise(provctx, CKR_HOST_MEMORY, "Failed to get key_generator"); return NULL; } ctx->provctx = (P11PROV_CTX *)provctx; ctx->type = CKK_EC_EDWARDS; if ((selection & OSSL_KEYMGMT_SELECT_KEYPAIR) != 0) { ctx->mechanism.mechanism = CKM_EC_EDWARDS_KEY_PAIR_GEN; } /* set defaults */ ret = p11prov_common_gen_set_params(ctx, curve); if (ret != RET_OSSL_OK) { p11prov_common_gen_cleanup(ctx); return NULL; } ret = p11prov_common_gen_set_params(ctx, params); if (ret != RET_OSSL_OK) { p11prov_common_gen_cleanup(ctx); return NULL; } return ctx; } static const OSSL_PARAM *p11prov_ed_gen_settable_params(void *genctx, void *provctx) { static OSSL_PARAM p11prov_ed_params[] = { OSSL_PARAM_utf8_string(P11PROV_PARAM_URI, NULL, 0), OSSL_PARAM_END, }; return p11prov_ed_params; } static void *p11prov_ed_load(const void *reference, size_t reference_sz) { P11PROV_debug("ed load %p, %ld", reference, reference_sz); return p11prov_common_load(reference, reference_sz, CKK_EC_EDWARDS); } static int p11prov_ed_match(const void *keydata1, const void *keydata2, int selection) { P11PROV_debug("ed match %p %p %d", keydata1, keydata2, selection); return p11prov_common_match(keydata1, keydata2, CKK_EC_EDWARDS, selection); } static int p11prov_ed_export(void *keydata, int selection, OSSL_CALLBACK *cb_fn, void *cb_arg) { P11PROV_OBJ *key = (P11PROV_OBJ *)keydata; P11PROV_CTX *ctx = p11prov_obj_get_prov_ctx(key); bool params_only = true; P11PROV_debug("ed export %p", keydata); if (key == NULL) { return RET_OSSL_ERR; } if (selection & OSSL_KEYMGMT_SELECT_PRIVATE_KEY) { /* can't export private keys */ return RET_OSSL_ERR; } if (p11prov_ctx_allow_export(ctx) & DISALLOW_EXPORT_PUBLIC) { return RET_OSSL_ERR; } if (selection & OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { params_only = false; } return p11prov_obj_export_public_key(key, CKK_EC_EDWARDS, true, params_only, cb_fn, cb_arg); } static int p11prov_ed_import(void *keydata, int selection, const OSSL_PARAM params[]) { return p11prov_ec_import_genr(CKK_EC_EDWARDS, keydata, selection, params); } static const OSSL_PARAM *p11prov_ed_import_types(int selection) { static const OSSL_PARAM p11prov_ed_imp_key_types[] = { OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PRIV_KEY, NULL, 0), OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), OSSL_PARAM_END, }; P11PROV_debug("ed import types"); if (selection & OSSL_KEYMGMT_SELECT_KEYPAIR) { return p11prov_ed_imp_key_types; } return NULL; } static const OSSL_PARAM *p11prov_ed_export_types(int selection) { static const OSSL_PARAM p11prov_ed_exp_key_types[] = { OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), OSSL_PARAM_END, }; P11PROV_debug("ed export types"); if (selection == OSSL_KEYMGMT_SELECT_PUBLIC_KEY) { return p11prov_ed_exp_key_types; } return NULL; } static const char *p11prov_ed25519_query_operation_name(int operation_id) { if (operation_id == OSSL_OP_SIGNATURE) { return P11PROV_NAME_ED25519; } return NULL; } static const char *p11prov_ed448_query_operation_name(int operation_id) { if (operation_id == OSSL_OP_SIGNATURE) { return P11PROV_NAME_ED448; } return NULL; } static int p11prov_ed_get_params(void *keydata, OSSL_PARAM params[]) { P11PROV_OBJ *key = (P11PROV_OBJ *)keydata; OSSL_PARAM *p; CK_ULONG group_size; int ret; P11PROV_debug("ed get params %p", keydata); if (key == NULL) { return RET_OSSL_ERR; } group_size = p11prov_obj_get_key_bit_size(key); if (group_size == CK_UNAVAILABLE_INFORMATION) { return RET_OSSL_ERR; } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_BITS); if (p) { ret = OSSL_PARAM_set_int(p, group_size); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_SECURITY_BITS); if (p) { int secbits; if (group_size == ED448_BIT_SIZE) { secbits = ED448_SEC_BITS; } else if (group_size == ED25519_BIT_SIZE) { secbits = ED25519_SEC_BITS; } else { return RET_OSSL_ERR; } ret = OSSL_PARAM_set_int(p, secbits); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MAX_SIZE); if (p) { int sigsize; if (group_size == ED448_BIT_SIZE) { sigsize = ED448_SIG_SIZE; } else if (group_size == ED25519_BIT_SIZE) { sigsize = ED25519_SIG_SIZE; } else { return RET_OSSL_ERR; } ret = OSSL_PARAM_set_int(p, sigsize); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_MANDATORY_DIGEST); if (p) { ret = OSSL_PARAM_set_utf8_string(p, ""); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_PKEY_PARAM_PUB_KEY); if (p) { CK_ATTRIBUTE *pub; if (p->data_type != OSSL_PARAM_OCTET_STRING) { return RET_OSSL_ERR; } ret = p11prov_obj_get_ed_pub_key(key, &pub); if (ret != RET_OSSL_OK) { return ret; } p->return_size = pub->ulValueLen; if (p->data) { if (p->data_size < pub->ulValueLen) { return RET_OSSL_ERR; } memcpy(p->data, pub->pValue, pub->ulValueLen); p->data_size = pub->ulValueLen; } } return RET_OSSL_OK; } static const OSSL_PARAM *p11prov_ed_gettable_params(void *provctx) { static const OSSL_PARAM params[] = { OSSL_PARAM_octet_string(OSSL_PKEY_PARAM_PUB_KEY, NULL, 0), OSSL_PARAM_int(OSSL_PKEY_PARAM_BITS, NULL), OSSL_PARAM_int(OSSL_PKEY_PARAM_SECURITY_BITS, NULL), OSSL_PARAM_int(OSSL_PKEY_PARAM_MAX_SIZE, NULL), OSSL_PARAM_utf8_string(OSSL_PKEY_PARAM_MANDATORY_DIGEST, NULL, 0), OSSL_PARAM_END, }; return params; } static int p11prov_ed_set_params(void *keydata, const OSSL_PARAM params[]) { return RET_OSSL_OK; } static const OSSL_PARAM *p11prov_ed_settable_params(void *provctx) { static const OSSL_PARAM params[] = { OSSL_PARAM_END, }; return params; } const OSSL_DISPATCH p11prov_ed25519_keymgmt_functions[] = { DISPATCH_KEYMGMT_ELEM(ec, NEW, new), DISPATCH_KEYMGMT_ELEM(ed25519, GEN_INIT, gen_init), DISPATCH_KEYMGMT_ELEM(ec, GEN, gen), DISPATCH_KEYMGMT_ELEM(common, GEN_CLEANUP, gen_cleanup), DISPATCH_KEYMGMT_ELEM(common, GEN_SET_PARAMS, gen_set_params), DISPATCH_KEYMGMT_ELEM(ed, GEN_SETTABLE_PARAMS, gen_settable_params), DISPATCH_KEYMGMT_ELEM(ed, LOAD, load), DISPATCH_KEYMGMT_ELEM(ec, FREE, free), DISPATCH_KEYMGMT_ELEM(ec, HAS, has), DISPATCH_KEYMGMT_ELEM(ed, MATCH, match), DISPATCH_KEYMGMT_ELEM(ed, IMPORT, import), DISPATCH_KEYMGMT_ELEM(ed, IMPORT_TYPES, import_types), DISPATCH_KEYMGMT_ELEM(ed, EXPORT, export), DISPATCH_KEYMGMT_ELEM(ed, EXPORT_TYPES, export_types), DISPATCH_KEYMGMT_ELEM(ed25519, QUERY_OPERATION_NAME, query_operation_name), DISPATCH_KEYMGMT_ELEM(ed, GET_PARAMS, get_params), DISPATCH_KEYMGMT_ELEM(ed, GETTABLE_PARAMS, gettable_params), DISPATCH_KEYMGMT_ELEM(ed, SET_PARAMS, set_params), DISPATCH_KEYMGMT_ELEM(ed, SETTABLE_PARAMS, settable_params), /* TODO: validate, dup? */ { 0, NULL }, }; const OSSL_DISPATCH p11prov_ed448_keymgmt_functions[] = { DISPATCH_KEYMGMT_ELEM(ec, NEW, new), DISPATCH_KEYMGMT_ELEM(ed448, GEN_INIT, gen_init), DISPATCH_KEYMGMT_ELEM(ec, GEN, gen), DISPATCH_KEYMGMT_ELEM(common, GEN_CLEANUP, gen_cleanup), DISPATCH_KEYMGMT_ELEM(common, GEN_SET_PARAMS, gen_set_params), DISPATCH_KEYMGMT_ELEM(ed, GEN_SETTABLE_PARAMS, gen_settable_params), DISPATCH_KEYMGMT_ELEM(ed, LOAD, load), DISPATCH_KEYMGMT_ELEM(ec, FREE, free), DISPATCH_KEYMGMT_ELEM(ec, HAS, has), DISPATCH_KEYMGMT_ELEM(ed, MATCH, match), DISPATCH_KEYMGMT_ELEM(ed, IMPORT, import), DISPATCH_KEYMGMT_ELEM(ed, IMPORT_TYPES, import_types), DISPATCH_KEYMGMT_ELEM(ed, EXPORT, export), DISPATCH_KEYMGMT_ELEM(ed, EXPORT_TYPES, export_types), DISPATCH_KEYMGMT_ELEM(ed448, QUERY_OPERATION_NAME, query_operation_name), DISPATCH_KEYMGMT_ELEM(ed, GET_PARAMS, get_params), DISPATCH_KEYMGMT_ELEM(ed, GETTABLE_PARAMS, gettable_params), DISPATCH_KEYMGMT_ELEM(ed, SET_PARAMS, set_params), DISPATCH_KEYMGMT_ELEM(ed, SETTABLE_PARAMS, settable_params), /* TODO: validate, dup? */ { 0, NULL }, }; DISPATCH_KEYMGMT_FN(hkdf, new); DISPATCH_KEYMGMT_FN(hkdf, free); DISPATCH_KEYMGMT_FN(hkdf, query_operation_name); DISPATCH_KEYMGMT_FN(hkdf, has); const void *p11prov_hkdf_static_ctx = NULL; static void *p11prov_hkdf_new(void *provctx) { P11PROV_CTX *ctx = (P11PROV_CTX *)provctx; CK_RV ret; P11PROV_debug("hkdf keymgmt new"); ret = p11prov_ctx_status(ctx); if (ret != CKR_OK) { return NULL; } return (void *)&p11prov_hkdf_static_ctx; } static void p11prov_hkdf_free(void *kdfdata) { P11PROV_debug("hkdf keymgmt free %p", kdfdata); if (kdfdata != &p11prov_hkdf_static_ctx) { P11PROV_debug("Invalid HKDF Keymgmt context: %p != %p", kdfdata, &p11prov_hkdf_static_ctx); } } static const char *p11prov_hkdf_query_operation_name(int operation_id) { P11PROV_debug("hkdf keymgmt query op name %d", operation_id); return P11PROV_NAME_HKDF; } static int p11prov_hkdf_has(const void *kdfdata, int selection) { P11PROV_debug("hkdf keymgmt has"); if (kdfdata != &p11prov_hkdf_static_ctx) { P11PROV_debug("Invalid HKDF Keymgmt context: %p != %p", kdfdata, &p11prov_hkdf_static_ctx); return RET_OSSL_ERR; } return RET_OSSL_OK; } const OSSL_DISPATCH p11prov_hkdf_keymgmt_functions[] = { DISPATCH_KEYMGMT_ELEM(hkdf, NEW, new), DISPATCH_KEYMGMT_ELEM(hkdf, FREE, free), DISPATCH_KEYMGMT_ELEM(hkdf, QUERY_OPERATION_NAME, query_operation_name), DISPATCH_KEYMGMT_ELEM(hkdf, HAS, has), { 0, NULL }, }; pkcs11-provider-1.0/src/keymgmt.h000066400000000000000000000015721475270623700167430ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _KEYMGMT_H #define _KEYMGMT_H /* keymgmt */ #define P11PROV_N_RSAPSS_MECHS 10 extern const CK_MECHANISM_TYPE p11prov_rsapss_mechs[P11PROV_N_RSAPSS_MECHS]; #define DISPATCH_KEYMGMT_FN(type, name) \ DECL_DISPATCH_FUNC(keymgmt, p11prov_##type, name) #define DISPATCH_KEYMGMT_ELEM(type, NAME, name) \ { \ OSSL_FUNC_KEYMGMT_##NAME, (void (*)(void))p11prov_##type##_##name \ } extern const OSSL_DISPATCH p11prov_rsa_keymgmt_functions[]; extern const OSSL_DISPATCH p11prov_rsapss_keymgmt_functions[]; extern const OSSL_DISPATCH p11prov_ec_keymgmt_functions[]; extern const OSSL_DISPATCH p11prov_hkdf_keymgmt_functions[]; extern const OSSL_DISPATCH p11prov_ed25519_keymgmt_functions[]; extern const OSSL_DISPATCH p11prov_ed448_keymgmt_functions[]; #endif /* _KEYMGMT_H */ pkcs11-provider-1.0/src/meson.build000066400000000000000000000014061475270623700172530ustar00rootroot00000000000000pkcs11_provider_sources = [ 'asymmetric_cipher.c', 'debug.c', 'encoder.c', 'decoder.c', 'digests.c', 'exchange.c', 'kdf.c', 'keymgmt.c', 'pk11_uri.c', 'interface.c', 'objects.c', 'provider.c', 'random.c', 'session.c', 'signature.c', 'slot.c', 'store.c', 'tls.c', 'util.c', ] pkcs11_provider_map = meson.current_source_dir() / 'provider.map' pkcs11_provider_ldflags = cc.get_supported_link_arguments([ '-Wl,--version-script,' + pkcs11_provider_map ]) pkcs11_provider = shared_module( 'pkcs11', pkcs11_provider_sources, name_prefix: '', dependencies: [libcrypto], include_directories: [configinc], link_depends: [pkcs11_provider_map], link_args: pkcs11_provider_ldflags, install: true, install_dir: provider_path, ) pkcs11-provider-1.0/src/objects.c000066400000000000000000003776111475270623700167240ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include #include #include #include #include #include #include "platform/endian.h" #define CKA_P11PROV_CURVE_NAME CKA_P11PROV_BASE + 1 #define CKA_P11PROV_CURVE_NID CKA_P11PROV_BASE + 2 #define CKA_P11PROV_PUB_KEY CKA_P11PROV_BASE + 3 #define CKA_P11PROV_PUB_KEY_X CKA_P11PROV_BASE + 4 #define CKA_P11PROV_PUB_KEY_Y CKA_P11PROV_BASE + 5 struct p11prov_key { CK_KEY_TYPE type; CK_BBOOL always_auth; CK_ULONG bit_size; CK_ULONG size; }; struct p11prov_crt { CK_CERTIFICATE_TYPE type; CK_CERTIFICATE_CATEGORY category; CK_BBOOL trusted; }; struct p11prov_obj { P11PROV_CTX *ctx; bool raf; /* re-init after fork */ CK_SLOT_ID slotid; CK_OBJECT_HANDLE handle; CK_OBJECT_CLASS class; CK_OBJECT_HANDLE cached; CK_BBOOL cka_copyable; CK_BBOOL cka_token; P11PROV_URI *refresh_uri; union { struct p11prov_key key; struct p11prov_crt crt; } data; CK_ATTRIBUTE *attrs; int numattrs; int refcnt; int poolid; P11PROV_OBJ *assoc_obj; }; struct p11prov_obj_pool { P11PROV_CTX *provctx; CK_SLOT_ID slotid; P11PROV_OBJ **objects; int size; int num; int first_free; pthread_mutex_t lock; }; CK_RV p11prov_obj_pool_init(P11PROV_CTX *ctx, CK_SLOT_ID id, P11PROV_OBJ_POOL **_pool) { P11PROV_OBJ_POOL *pool; int ret; P11PROV_debug("Creating new object pool"); pool = OPENSSL_zalloc(sizeof(P11PROV_OBJ_POOL)); if (!pool) { return CKR_HOST_MEMORY; } pool->provctx = ctx; pool->slotid = id; ret = MUTEX_INIT(pool); if (ret != CKR_OK) { OPENSSL_free(pool); return ret; } P11PROV_debug("New object pool %p created", pool); *_pool = pool; return CKR_OK; } void p11prov_obj_pool_free(P11PROV_OBJ_POOL *pool) { P11PROV_debug("Freeing object pool %p", pool); if (!pool) { return; } if (MUTEX_LOCK(pool) == CKR_OK) { /* LOCKED SECTION ------------- */ if (pool->num != 0) { P11PROV_debug("%d objects still in pool", pool->num); } OPENSSL_free(pool->objects); (void)MUTEX_UNLOCK(pool); /* ------------- LOCKED SECTION */ } else { P11PROV_debug("Failed to lock object pool, leaking it!"); return; } (void)MUTEX_DESTROY(pool); OPENSSL_clear_free(pool, sizeof(P11PROV_OBJ_POOL)); } void p11prov_obj_pool_fork_reset(P11PROV_OBJ_POOL *pool) { P11PROV_debug("Resetting objects in pool %p", pool); if (!pool) { return; } if (MUTEX_LOCK(pool) == CKR_OK) { /* LOCKED SECTION ------------- */ for (int i = 0; i < pool->size; i++) { P11PROV_OBJ *obj = pool->objects[i]; if (!obj) { continue; } obj->raf = true; obj->handle = CK_INVALID_HANDLE; obj->cached = CK_INVALID_HANDLE; } (void)MUTEX_UNLOCK(pool); /* ------------- LOCKED SECTION */ } else { P11PROV_debug("Failed to reset objects in pool"); } } #define POOL_ALLOC_SIZE 32 #define POOL_MAX_SIZE (POOL_ALLOC_SIZE * (1 << 16)) static CK_RV obj_add_to_pool(P11PROV_OBJ *obj) { P11PROV_OBJ_POOL *pool; CK_RV ret; ret = p11prov_slot_get_obj_pool(obj->ctx, obj->slotid, &pool); if (ret != CKR_OK) { return ret; } ret = MUTEX_LOCK(pool); if (ret != CKR_OK) { return ret; } /* LOCKED SECTION ------------- */ if (pool->num >= pool->size) { P11PROV_OBJ **tmp; if (pool->size >= POOL_MAX_SIZE) { ret = CKR_HOST_MEMORY; P11PROV_raise(pool->provctx, ret, "Too many objects in pool"); goto done; } tmp = OPENSSL_realloc(pool->objects, (pool->size + POOL_ALLOC_SIZE) * sizeof(P11PROV_OBJ *)); if (tmp == NULL) { ret = CKR_HOST_MEMORY; P11PROV_raise(pool->provctx, ret, "Failed to re-allocate objects array"); goto done; } memset(&tmp[pool->size], 0, POOL_ALLOC_SIZE * sizeof(P11PROV_OBJ *)); pool->objects = tmp; pool->size += POOL_ALLOC_SIZE; } if (pool->first_free >= pool->size) { pool->first_free = 0; } for (int i = 0; i < pool->size; i++) { int idx = (i + pool->first_free) % pool->size; if (pool->objects[idx] == NULL) { pool->objects[idx] = obj; pool->num++; obj->poolid = idx; pool->first_free = idx + 1; ret = CKR_OK; goto done; } } /* if we couldn't find a free pool spot at this point, * something clearly went wrong, bail out */ ret = CKR_GENERAL_ERROR; P11PROV_raise(pool->provctx, ret, "Objects pool in inconsistent state"); done: (void)MUTEX_UNLOCK(pool); /* ------------- LOCKED SECTION */ return ret; } static void obj_rm_from_pool(P11PROV_OBJ *obj) { P11PROV_OBJ_POOL *pool; CK_RV ret; if (obj->slotid == CK_UNAVAILABLE_INFORMATION) { /* a mock object */ return; } ret = p11prov_slot_get_obj_pool(obj->ctx, obj->slotid, &pool); if (ret != CKR_OK) { return; } ret = MUTEX_LOCK(pool); if (ret != CKR_OK) { return; } /* LOCKED SECTION ------------- */ if (obj->poolid >= pool->size || pool->objects[obj->poolid] != obj) { ret = CKR_GENERAL_ERROR; P11PROV_raise(pool->provctx, ret, "Objects pool in inconsistent state"); goto done; } pool->objects[obj->poolid] = NULL; pool->num--; if (pool->first_free > obj->poolid) { pool->first_free = obj->poolid; } obj->poolid = 0; done: (void)MUTEX_UNLOCK(pool); /* ------------- LOCKED SECTION */ } static CK_RV p11prov_obj_store_public_key(P11PROV_OBJ *key); P11PROV_OBJ *p11prov_obj_new(P11PROV_CTX *ctx, CK_SLOT_ID slotid, CK_OBJECT_HANDLE handle, CK_OBJECT_CLASS class) { P11PROV_OBJ *obj; CK_RV ret; obj = OPENSSL_zalloc(sizeof(P11PROV_OBJ)); if (obj == NULL) { return NULL; } obj->ctx = ctx; obj->slotid = slotid; obj->handle = handle; obj->class = class; obj->cached = CK_INVALID_HANDLE; obj->refcnt = 1; if (handle == CK_P11PROV_IMPORTED_HANDLE) { /* mock object, return w/o adding to pool */ return obj; } ret = obj_add_to_pool(obj); if (ret != CKR_OK) { OPENSSL_free(obj); obj = NULL; } return obj; } static void destroy_key_cache(P11PROV_OBJ *obj, P11PROV_SESSION *session) { P11PROV_SESSION *_session = NULL; CK_SESSION_HANDLE sess; CK_RV ret; if (obj->cached == CK_INVALID_HANDLE) { return; } if (session) { sess = p11prov_session_handle(session); } else { ret = p11prov_take_login_session(obj->ctx, obj->slotid, &_session); if (ret != CKR_OK) { P11PROV_debug("Failed to get login session. Error %lx", ret); return; } sess = p11prov_session_handle(_session); } ret = p11prov_DestroyObject(obj->ctx, sess, obj->cached); if (ret != CKR_OK) { P11PROV_debug("Failed to destroy cached key. Error %lx", ret); } obj->cached = CK_INVALID_HANDLE; if (_session) { p11prov_return_session(_session); } } static CK_RV supports_caching(P11PROV_CTX *ctx, CK_SLOT_ID id, int action, CK_BBOOL *data) { CK_ULONG data_size = sizeof(CK_BBOOL); void *data_ptr = &data; const char *name = "Caching Supported"; switch (action) { case GET_ATTR: return p11prov_ctx_get_quirk(ctx, id, name, data_ptr, &data_size); case SET_ATTR: return p11prov_ctx_set_quirk(ctx, id, name, data, data_size); default: return CKR_ARGUMENTS_BAD; } } static void cache_key(P11PROV_OBJ *obj) { P11PROV_SESSION *session = NULL; CK_BBOOL val_false = CK_FALSE; CK_ATTRIBUTE template[] = { { CKA_TOKEN, &val_false, sizeof(val_false) } }; CK_SESSION_HANDLE sess; CK_BBOOL can_cache = CK_TRUE; CK_RV ret; int cache_keys; /* check whether keys should be cached at all */ cache_keys = p11prov_ctx_cache_keys(obj->ctx); if (cache_keys == P11PROV_CACHE_KEYS_NEVER) { return; } /* We cache only keys on the token */ if ((obj->class != CKO_PRIVATE_KEY && obj->class != CKO_PUBLIC_KEY) || obj->cka_token != CK_TRUE || obj->cka_copyable != CK_TRUE) { return; } ret = supports_caching(obj->ctx, obj->slotid, GET_ATTR, &can_cache); if (ret != CKR_OK) { P11PROV_raise(obj->ctx, ret, "Failed to get quirk"); } if (can_cache != CK_TRUE) { /* switch copyable so we do not try again */ obj->cka_copyable = CK_FALSE; return; } ret = p11prov_take_login_session(obj->ctx, obj->slotid, &session); if (ret != CKR_OK || session == NULL) { P11PROV_debug("Failed to get login session. Error %lx", ret); return; } /* If already cached, release and re-cache */ destroy_key_cache(obj, session); sess = p11prov_session_handle(session); ret = p11prov_CopyObject(obj->ctx, sess, p11prov_obj_get_handle(obj), template, 1, &obj->cached); if (ret != CKR_OK) { P11PROV_raise(obj->ctx, ret, "Failed to cache key"); if (ret == CKR_FUNCTION_NOT_SUPPORTED) { can_cache = CK_FALSE; ret = supports_caching(obj->ctx, obj->slotid, SET_ATTR, &can_cache); if (ret != CKR_OK) { P11PROV_raise(obj->ctx, ret, "Failed to set quirk"); } } /* switch copyable so we do not try again */ obj->cka_copyable = CK_FALSE; } else { P11PROV_debug("Key %lu:%lu cached as %lu:%lu", obj->slotid, obj->handle, sess, obj->cached); } p11prov_return_session(session); return; } P11PROV_OBJ *p11prov_obj_ref_no_cache(P11PROV_OBJ *obj) { P11PROV_debug("Ref Object: %p (handle:%lu)", obj, obj ? obj->handle : CK_INVALID_HANDLE); if (obj && __atomic_fetch_add(&obj->refcnt, 1, __ATOMIC_SEQ_CST) > 0) { return obj; } return NULL; } P11PROV_OBJ *p11prov_obj_ref(P11PROV_OBJ *obj) { obj = p11prov_obj_ref_no_cache(obj); if (!obj) { return NULL; } /* When referenced it means we are likely going to try to use the key in * some operation, let's try to cache it in the tokens volatile memory for * those tokens that support the operation. This will result in much faster * key operations with some tokens as the keys are unencrypted in volatile * memory */ if (obj->cached == CK_INVALID_HANDLE) { cache_key(obj); } return obj; } void p11prov_obj_free(P11PROV_OBJ *obj) { P11PROV_debug("Free Object: %p (handle:%lu)", obj, obj ? obj->handle : CK_INVALID_HANDLE); if (obj == NULL) { return; } if (__atomic_sub_fetch(&obj->refcnt, 1, __ATOMIC_SEQ_CST) != 0) { P11PROV_debug("object free: reference held"); return; } obj_rm_from_pool(obj); destroy_key_cache(obj, NULL); for (int i = 0; i < obj->numattrs; i++) { OPENSSL_free(obj->attrs[i].pValue); } OPENSSL_free(obj->attrs); p11prov_uri_free(obj->refresh_uri); p11prov_obj_free(obj->assoc_obj); OPENSSL_clear_free(obj, sizeof(P11PROV_OBJ)); } CK_SLOT_ID p11prov_obj_get_slotid(P11PROV_OBJ *obj) { if (obj) { return obj->slotid; } return CK_UNAVAILABLE_INFORMATION; } static void p11prov_obj_refresh(P11PROV_OBJ *obj); CK_OBJECT_HANDLE p11prov_obj_get_handle(P11PROV_OBJ *obj) { if (obj) { if (obj->raf) { p11prov_obj_refresh(obj); } if (obj->cached != CK_INVALID_HANDLE) { return obj->cached; } if (obj->handle == CK_P11PROV_IMPORTED_HANDLE) { /* This was a mock imported public key, * but we are being asked for the actual key handle * so it means we need to actually add the key to the * session in order to be able to perform operations * with the token */ int rv; rv = p11prov_obj_store_public_key(obj); if (rv != CKR_OK) { return CK_INVALID_HANDLE; } } return obj->handle; } return CK_INVALID_HANDLE; } CK_OBJECT_CLASS p11prov_obj_get_class(P11PROV_OBJ *obj) { if (obj) { return obj->class; } return CK_UNAVAILABLE_INFORMATION; } CK_ATTRIBUTE *p11prov_obj_get_attr(P11PROV_OBJ *obj, CK_ATTRIBUTE_TYPE type) { if (!obj) { return NULL; } for (int i = 0; i < obj->numattrs; i++) { if (obj->attrs[i].type == type) { return &obj->attrs[i]; } } return NULL; } bool p11prov_obj_get_bool(P11PROV_OBJ *obj, CK_ATTRIBUTE_TYPE type, bool def) { CK_ATTRIBUTE *attr = NULL; if (!obj) { return def; } for (int i = 0; i < obj->numattrs; i++) { if (obj->attrs[i].type == type) { attr = &obj->attrs[i]; } } if (!attr || !attr->pValue) { return def; } if (attr->ulValueLen == sizeof(CK_BBOOL)) { if (*((CK_BBOOL *)attr->pValue) == CK_FALSE) { return false; } else { return true; } } return def; } CK_KEY_TYPE p11prov_obj_get_key_type(P11PROV_OBJ *obj) { if (obj) { switch (obj->class) { case CKO_PRIVATE_KEY: case CKO_PUBLIC_KEY: return obj->data.key.type; } } return CK_UNAVAILABLE_INFORMATION; } bool p11prov_obj_is_rsa_pss(P11PROV_OBJ *obj) { CK_ATTRIBUTE *am = p11prov_obj_get_attr(obj, CKA_ALLOWED_MECHANISMS); CK_MECHANISM_TYPE *allowed; int am_nmechs; if (am == NULL || am->ulValueLen == 0) { /* no limitations or no support for allowed mechs * TODO we can try also certificate restrictions */ return false; } allowed = (CK_MECHANISM_TYPE *)am->pValue; am_nmechs = am->ulValueLen / sizeof(CK_MECHANISM_TYPE); for (int i = 0; i < am_nmechs; i++) { bool found = false; for (int j = 0; j < P11PROV_N_RSAPSS_MECHS; j++) { if (allowed[i] == p11prov_rsapss_mechs[j]) { found = true; break; } } if (!found) { /* this is not a RSA-PSS mechanism. We can not enforce any * limitations */ return false; } } /* all allowed mechanisms fit into the list of RSA-PSS ones */ return true; } CK_ULONG p11prov_obj_get_key_bit_size(P11PROV_OBJ *obj) { if (obj) { switch (obj->class) { case CKO_PRIVATE_KEY: case CKO_PUBLIC_KEY: return obj->data.key.bit_size; } } return CK_UNAVAILABLE_INFORMATION; } CK_ULONG p11prov_obj_get_key_size(P11PROV_OBJ *obj) { if (obj) { switch (obj->class) { case CKO_PRIVATE_KEY: case CKO_PUBLIC_KEY: return obj->data.key.size; } } return CK_UNAVAILABLE_INFORMATION; } void p11prov_obj_to_store_reference(P11PROV_OBJ *obj, void **reference, size_t *reference_sz) { /* The store context keeps reference to this object so we will not free * it while the store context is alive. When the applications wants to * reference the object, it will get its own reference through * p11prov_common_load(). After closing the store, the user should * not be able to use this reference anymore. */ *reference = obj; *reference_sz = sizeof(P11PROV_OBJ); } P11PROV_OBJ *p11prov_obj_from_reference(const void *reference, size_t reference_sz) { if (!reference || reference_sz != sizeof(P11PROV_OBJ)) { return NULL; } return (P11PROV_OBJ *)reference; } P11PROV_CTX *p11prov_obj_get_prov_ctx(P11PROV_OBJ *obj) { if (!obj) { return NULL; } return obj->ctx; } P11PROV_OBJ *p11prov_obj_get_associated(P11PROV_OBJ *obj) { return obj->assoc_obj; } void p11prov_obj_set_associated(P11PROV_OBJ *obj, P11PROV_OBJ *assoc) { if (obj == NULL) { return; } p11prov_obj_free(obj->assoc_obj); obj->assoc_obj = NULL; if (assoc == NULL) { return; } obj->assoc_obj = p11prov_obj_ref_no_cache(assoc); } /* CKA_ID * CKA_LABEL * CKA_ALWAYS_AUTHENTICATE * CKA_ALLOWED_MECHANISMS see p11prov_obj_from_handle() */ #define BASE_KEY_ATTRS_NUM 4 #define RSA_ATTRS_NUM (BASE_KEY_ATTRS_NUM + 2) static int fetch_rsa_key(P11PROV_CTX *ctx, P11PROV_SESSION *session, CK_OBJECT_HANDLE object, P11PROV_OBJ *key) { struct fetch_attrs attrs[RSA_ATTRS_NUM]; CK_ATTRIBUTE *mod; int num; int ret; key->attrs = OPENSSL_zalloc(RSA_ATTRS_NUM * sizeof(CK_ATTRIBUTE)); if (key->attrs == NULL) { return CKR_HOST_MEMORY; } num = 0; FA_SET_BUF_ALLOC(attrs, num, CKA_MODULUS, true); FA_SET_BUF_ALLOC(attrs, num, CKA_PUBLIC_EXPONENT, true); FA_SET_BUF_ALLOC(attrs, num, CKA_ID, false); FA_SET_BUF_ALLOC(attrs, num, CKA_LABEL, false); if (key->class == CKO_PRIVATE_KEY) { FA_SET_BUF_ALLOC(attrs, num, CKA_ALWAYS_AUTHENTICATE, false); } ret = p11prov_fetch_attributes(ctx, session, object, attrs, num); if (ret != CKR_OK) { /* free any allocated memory */ p11prov_fetch_attrs_free(attrs, num); if (key->class == CKO_PRIVATE_KEY) { /* A private key may not always return these */ return CKR_OK; } return ret; } key->numattrs = 0; p11prov_move_alloc_attrs(attrs, num, key->attrs, &key->numattrs); mod = p11prov_obj_get_attr(key, CKA_MODULUS); if (!mod) { P11PROV_raise(key->ctx, CKR_GENERAL_ERROR, "Missing Modulus"); return CKR_GENERAL_ERROR; } key->data.key.size = mod->ulValueLen; key->data.key.bit_size = key->data.key.size * 8; return CKR_OK; } static CK_RV decode_ec_point(CK_KEY_TYPE key_type, CK_ATTRIBUTE *attr, struct data_buffer *ec_point) { ASN1_OCTET_STRING *octet; const unsigned char *val; CK_RV ret = CKR_GENERAL_ERROR; int err; /* in d2i functions 'in' is overwritten to return the remainder of * the buffer after parsing, so we always need to avoid passing in * our pointer holders, to avoid having them clobbered */ val = attr->pValue; octet = d2i_ASN1_OCTET_STRING(NULL, (const unsigned char **)&val, attr->ulValueLen); if (!octet) { /* 3.1 spec says CKA_EC_POINT is not DER encoded for Edwards and * Montgomery curves so do not fail in that case and just take * the value as is */ if (key_type == CKK_EC) { return CKR_KEY_INDIGESTIBLE; } else { octet = ASN1_OCTET_STRING_new(); if (!octet) { return CKR_HOST_MEMORY; } /* makes a copy of the value */ err = ASN1_OCTET_STRING_set(octet, attr->pValue, attr->ulValueLen); if (err != RET_OSSL_OK) { ret = CKR_HOST_MEMORY; goto done; } } } ec_point->data = octet->data; ec_point->length = octet->length; /* moved octet data, do not free it */ octet->data = NULL; octet->length = 0; ret = CKR_OK; done: ASN1_OCTET_STRING_free(octet); return ret; } const CK_BYTE ed25519_ec_params[] = { ED25519_EC_PARAMS }; const CK_BYTE ed448_ec_params[] = { ED448_EC_PARAMS }; #define KEY_EC_PARAMS 3 static CK_RV pre_process_ec_key_data(P11PROV_OBJ *key) { CK_ATTRIBUTE *attr; CK_KEY_TYPE type; const unsigned char *val; CK_BYTE *buffer; int buffer_size; const char *curve_name = NULL; int curve_nid; struct data_buffer ec_point = { 0 }; CK_RV ret; attr = p11prov_obj_get_attr(key, CKA_EC_PARAMS); if (!attr) { key->data.key.bit_size = CK_UNAVAILABLE_INFORMATION; key->data.key.size = CK_UNAVAILABLE_INFORMATION; return CKR_KEY_INDIGESTIBLE; } type = p11prov_obj_get_key_type(key); if (type == CKK_EC) { EC_GROUP *group = NULL; /* in d2i functions 'in' is overwritten to return the remainder of * the buffer after parsing, so we always need to avoid passing in * our pointer holders, to avoid having them clobbered */ val = attr->pValue; group = d2i_ECPKParameters(NULL, &val, attr->ulValueLen); if (group == NULL) { return CKR_KEY_INDIGESTIBLE; } curve_nid = EC_GROUP_get_curve_name(group); if (curve_nid != NID_undef) { curve_name = OSSL_EC_curve_nid2name(curve_nid); if (curve_name == NULL) { EC_GROUP_free(group); return CKR_KEY_INDIGESTIBLE; } } key->data.key.bit_size = EC_GROUP_order_bits(group); key->data.key.size = (key->data.key.bit_size + 7) / 8; EC_GROUP_free(group); } else if (type == CKK_EC_EDWARDS) { if (attr->ulValueLen == ED25519_EC_PARAMS_LEN && memcmp(attr->pValue, ed25519_ec_params, ED25519_EC_PARAMS_LEN) == 0) { curve_name = ED25519; curve_nid = NID_ED25519; key->data.key.bit_size = ED25519_BIT_SIZE; key->data.key.size = ED25519_BYTE_SIZE; } else if (attr->ulValueLen == ED448_EC_PARAMS_LEN && memcmp(attr->pValue, ed448_ec_params, ED448_EC_PARAMS_LEN) == 0) { curve_name = ED448; curve_nid = NID_ED448; key->data.key.bit_size = ED448_BIT_SIZE; key->data.key.size = ED448_BYTE_SIZE; } else { const unsigned char *p = attr->pValue; ASN1_OBJECT *asn1_obj = d2i_ASN1_OBJECT(NULL, &p, attr->ulValueLen); if (asn1_obj == NULL) { return CKR_KEY_INDIGESTIBLE; } int nid = OBJ_obj2nid(asn1_obj); ASN1_OBJECT_free(asn1_obj); if (nid == NID_ED25519) { curve_name = ED25519; curve_nid = NID_ED25519; key->data.key.bit_size = ED25519_BIT_SIZE; key->data.key.size = ED25519_BYTE_SIZE; } else if (nid == NID_ED448) { curve_name = ED448; curve_nid = NID_ED448; key->data.key.bit_size = ED448_BIT_SIZE; key->data.key.size = ED448_BYTE_SIZE; } else { return CKR_KEY_INDIGESTIBLE; } } } else { return CKR_KEY_INDIGESTIBLE; } buffer_size = sizeof(curve_nid); buffer = OPENSSL_zalloc(buffer_size); if (!buffer) { return CKR_HOST_MEMORY; } memcpy(buffer, &curve_nid, buffer_size); CKATTR_ASSIGN(key->attrs[key->numattrs], CKA_P11PROV_CURVE_NID, buffer, buffer_size); key->numattrs++; if (curve_name != NULL) { buffer_size = strlen(curve_name) + 1; buffer = (CK_BYTE *)OPENSSL_strdup(curve_name); if (!buffer) { return CKR_HOST_MEMORY; } CKATTR_ASSIGN(key->attrs[key->numattrs], CKA_P11PROV_CURVE_NAME, buffer, buffer_size); key->numattrs++; } attr = p11prov_obj_get_attr(key, CKA_EC_POINT); if (!attr) { /* not available on private keys, so not fatal if absent */ return CKR_OK; } ret = decode_ec_point(type, attr, &ec_point); if (ret != CKR_OK) { return ret; } /* takes the data allocated in ec_point */ CKATTR_ASSIGN(key->attrs[key->numattrs], CKA_P11PROV_PUB_KEY, ec_point.data, ec_point.length); key->numattrs++; return CKR_OK; } #define EC_ATTRS_NUM (BASE_KEY_ATTRS_NUM + KEY_EC_PARAMS + 2) static CK_RV fetch_ec_key(P11PROV_CTX *ctx, P11PROV_SESSION *session, CK_OBJECT_HANDLE object, P11PROV_OBJ *key) { struct fetch_attrs attrs[EC_ATTRS_NUM]; int num; CK_RV ret; key->attrs = OPENSSL_zalloc(EC_ATTRS_NUM * sizeof(CK_ATTRIBUTE)); if (key->attrs == NULL) { return CKR_HOST_MEMORY; } num = 0; FA_SET_BUF_ALLOC(attrs, num, CKA_EC_PARAMS, true); if (key->class == CKO_PUBLIC_KEY) { FA_SET_BUF_ALLOC(attrs, num, CKA_EC_POINT, true); } else { /* known vendor optimization to avoid storing * EC public key on HSM; can avoid * p11prov_obj_find_associated later */ FA_SET_BUF_ALLOC(attrs, num, CKA_EC_POINT, false); FA_SET_BUF_ALLOC(attrs, num, CKA_ALWAYS_AUTHENTICATE, false); } FA_SET_BUF_ALLOC(attrs, num, CKA_ID, false); FA_SET_BUF_ALLOC(attrs, num, CKA_LABEL, false); ret = p11prov_fetch_attributes(ctx, session, object, attrs, num); if (ret != CKR_OK) { /* free any allocated memory */ p11prov_fetch_attrs_free(attrs, num); return CKR_KEY_INDIGESTIBLE; } key->numattrs = 0; p11prov_move_alloc_attrs(attrs, num, key->attrs, &key->numattrs); /* decode CKA_EC_PARAMS and store some extra attrs for convenience */ ret = pre_process_ec_key_data(key); return ret; } #define CERT_ATTRS_NUM 9 static CK_RV fetch_certificate(P11PROV_CTX *ctx, P11PROV_SESSION *session, CK_OBJECT_HANDLE object, P11PROV_OBJ *crt) { struct fetch_attrs attrs[CERT_ATTRS_NUM]; int num; CK_RV ret; crt->attrs = OPENSSL_zalloc(CERT_ATTRS_NUM * sizeof(CK_ATTRIBUTE)); if (crt->attrs == NULL) { P11PROV_raise(ctx, CKR_HOST_MEMORY, "failed to allocate cert attrs"); return CKR_HOST_MEMORY; } num = 0; FA_SET_VAR_VAL(attrs, num, CKA_CERTIFICATE_TYPE, crt->data.crt.type, true); FA_SET_VAR_VAL(attrs, num, CKA_TRUSTED, crt->data.crt.trusted, false); FA_SET_VAR_VAL(attrs, num, CKA_CERTIFICATE_CATEGORY, crt->data.crt.category, false); FA_SET_BUF_ALLOC(attrs, num, CKA_SUBJECT, true); FA_SET_BUF_ALLOC(attrs, num, CKA_ID, false); FA_SET_BUF_ALLOC(attrs, num, CKA_ISSUER, false); FA_SET_BUF_ALLOC(attrs, num, CKA_SERIAL_NUMBER, false); FA_SET_BUF_ALLOC(attrs, num, CKA_VALUE, false); FA_SET_BUF_ALLOC(attrs, num, CKA_PUBLIC_KEY_INFO, false); ret = p11prov_fetch_attributes(ctx, session, object, attrs, num); if (ret != CKR_OK) { P11PROV_debug("Failed to query certificate attributes (%lu)", ret); p11prov_fetch_attrs_free(attrs, num); return ret; } crt->numattrs = 0; p11prov_move_alloc_attrs(attrs, num, crt->attrs, &crt->numattrs); return CKR_OK; } /* TODO: may want to have a hashmap with cached objects */ CK_RV p11prov_obj_from_handle(P11PROV_CTX *ctx, P11PROV_SESSION *session, CK_OBJECT_HANDLE handle, P11PROV_OBJ **object) { P11PROV_OBJ *obj; struct fetch_attrs attrs[4]; int num; CK_BBOOL token_supports_allowed_mechs = CK_TRUE; CK_RV ret; if (object) { *object = NULL; } else { return CKR_ARGUMENTS_BAD; } obj = p11prov_obj_new(ctx, p11prov_session_slotid(session), handle, CK_UNAVAILABLE_INFORMATION); if (obj == NULL) { return CKR_HOST_MEMORY; } obj->handle = handle; obj->slotid = p11prov_session_slotid(session); obj->data.key.type = CK_UNAVAILABLE_INFORMATION; num = 0; FA_SET_VAR_VAL(attrs, num, CKA_CLASS, obj->class, true); FA_SET_VAR_VAL(attrs, num, CKA_KEY_TYPE, obj->data.key.type, false); FA_SET_VAR_VAL(attrs, num, CKA_COPYABLE, obj->cka_copyable, false); FA_SET_VAR_VAL(attrs, num, CKA_TOKEN, obj->cka_token, false); ret = p11prov_fetch_attributes(ctx, session, handle, attrs, num); if (ret != CKR_OK) { P11PROV_debug("Failed to query object attributes (%lu)", ret); p11prov_obj_free(obj); return ret; } switch (obj->class) { case CKO_CERTIFICATE: ret = fetch_certificate(ctx, session, handle, obj); if (ret != CKR_OK) { p11prov_obj_free(obj); return ret; } break; case CKO_PUBLIC_KEY: case CKO_PRIVATE_KEY: switch (obj->data.key.type) { case CKK_RSA: ret = fetch_rsa_key(ctx, session, handle, obj); if (ret != CKR_OK) { p11prov_obj_free(obj); return ret; } break; case CKK_EC: case CKK_EC_EDWARDS: ret = fetch_ec_key(ctx, session, handle, obj); if (ret != CKR_OK) { p11prov_obj_free(obj); return ret; } break; default: /* unknown key type, we can't handle it */ P11PROV_debug("Unsupported key type (%lu)", obj->data.key.type); p11prov_obj_free(obj); return CKR_ARGUMENTS_BAD; } /* do this at the end as it often won't be a supported attribute */ ret = p11prov_token_sup_attr(ctx, obj->slotid, GET_ATTR, CKA_ALLOWED_MECHANISMS, &token_supports_allowed_mechs); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Failed to probe quirk"); } else if (token_supports_allowed_mechs == CK_TRUE) { struct fetch_attrs a[1]; CK_ULONG an = 0; FA_SET_BUF_ALLOC(a, an, CKA_ALLOWED_MECHANISMS, false); ret = p11prov_fetch_attributes(ctx, session, handle, a, 1); if (ret == CKR_OK) { obj->attrs[obj->numattrs] = a[0].attr; obj->numattrs++; } else if (ret == CKR_ATTRIBUTE_TYPE_INVALID) { token_supports_allowed_mechs = CK_FALSE; (void)p11prov_token_sup_attr(ctx, obj->slotid, SET_ATTR, CKA_ALLOWED_MECHANISMS, &token_supports_allowed_mechs); } } break; default: if (obj->class & CKO_VENDOR_DEFINED) { P11PROV_debug("Vendor defined object %ld", obj->class); } else { P11PROV_debug("Unknown object class %ld", obj->class); } p11prov_obj_free(obj); return CKR_CANCEL; } *object = obj; return CKR_OK; } #define OBJS_PER_SEARCH 64 #define MAX_OBJS_IN_STORE OBJS_PER_SEARCH * 16 /* 1024 */ CK_RV p11prov_obj_find(P11PROV_CTX *provctx, P11PROV_SESSION *session, CK_SLOT_ID slotid, P11PROV_URI *uri, store_obj_callback cb, void *cb_ctx) { CK_SESSION_HANDLE sess = CK_INVALID_HANDLE; CK_OBJECT_CLASS class = p11prov_uri_get_class(uri); CK_ATTRIBUTE id = p11prov_uri_get_id(uri); CK_ATTRIBUTE label = p11prov_uri_get_label(uri); CK_ATTRIBUTE template[3] = { 0 }; CK_OBJECT_HANDLE *objects = NULL; CK_ULONG tsize = 0; CK_ULONG objcount = 0; CK_ULONG total = 0; CK_RV result = CKR_GENERAL_ERROR; CK_RV ret; P11PROV_debug("Find objects [class=%lu, id-len=%lu, label=%s]", class, id.ulValueLen, label.type == CKA_LABEL ? (char *)label.pValue : "None"); switch (class) { case CKO_CERTIFICATE: case CKO_PUBLIC_KEY: case CKO_PRIVATE_KEY: CKATTR_ASSIGN(template[tsize], CKA_CLASS, &class, sizeof(class)); tsize++; break; case CK_UNAVAILABLE_INFORMATION: break; default: /* nothing to find for us */ return CKR_OK; } if (id.ulValueLen != 0) { template[tsize] = id; tsize++; } if (label.ulValueLen != 0) { template[tsize] = label; tsize++; } sess = p11prov_session_handle(session); ret = p11prov_FindObjectsInit(provctx, sess, template, tsize); if (ret != CKR_OK) { return ret; } do { CK_OBJECT_HANDLE *tmp; objcount = 0; tmp = OPENSSL_realloc(objects, (total + OBJS_PER_SEARCH) * sizeof(CK_OBJECT_HANDLE)); if (tmp == NULL) { OPENSSL_free(objects); (void)p11prov_FindObjectsFinal(provctx, sess); return CKR_HOST_MEMORY; } objects = tmp; ret = p11prov_FindObjects(provctx, sess, &objects[total], OBJS_PER_SEARCH, &objcount); if (ret != CKR_OK || objcount == 0) { result = ret; break; } total += objcount; } while (total < MAX_OBJS_IN_STORE); if (objcount != 0 && total >= MAX_OBJS_IN_STORE) { P11PROV_debug("Too many objects in store, results truncated to %d", MAX_OBJS_IN_STORE); } ret = p11prov_FindObjectsFinal(provctx, sess); if (ret != CKR_OK) { /* this is not fatal */ P11PROV_raise(provctx, ret, "Failed to terminate object search"); } for (CK_ULONG k = 0; k < total; k++) { P11PROV_OBJ *obj = NULL; ret = p11prov_obj_from_handle(provctx, session, objects[k], &obj); if (ret == CKR_CANCEL) { /* unknown object or other recoverable error to ignore */ continue; } else if (ret == CKR_OK) { /* keep a copy of the URI for refreshes as it may contain * things like a PIN necessary to log in */ obj->refresh_uri = p11prov_copy_uri(uri); ret = cb(cb_ctx, obj); } if (ret != CKR_OK) { P11PROV_raise(provctx, ret, "Failed to store object"); result = ret; break; } } P11PROV_debug("Find objects: found %lu objects; Returning %lx", total, result); OPENSSL_free(objects); return result; } P11PROV_OBJ *p11prov_obj_find_associated(P11PROV_OBJ *obj, CK_OBJECT_CLASS class) { CK_ATTRIBUTE template[2] = { 0 }; CK_ATTRIBUTE *id; CK_SLOT_ID slotid = CK_UNAVAILABLE_INFORMATION; P11PROV_SESSION *session = NULL; CK_SESSION_HANDLE sess = CK_INVALID_HANDLE; CK_OBJECT_HANDLE handle; CK_ULONG objcount = 0; P11PROV_OBJ *retobj = NULL; CK_RV ret, fret; P11PROV_debug("Find associated object"); /* check if we have one already */ retobj = p11prov_obj_get_associated(obj); if (retobj) { if (p11prov_obj_get_class(retobj) == class) { /* BINGO */ return p11prov_obj_ref_no_cache(retobj); } else { retobj = NULL; } } id = p11prov_obj_get_attr(obj, CKA_ID); if (!id || id->ulValueLen == 0) { P11PROV_raise(obj->ctx, CKR_GENERAL_ERROR, "No CKA_ID in source object"); goto done; } CKATTR_ASSIGN(template[0], CKA_CLASS, &class, sizeof(class)); template[1] = *id; slotid = p11prov_obj_get_slotid(obj); ret = p11prov_get_session(obj->ctx, &slotid, NULL, NULL, CK_UNAVAILABLE_INFORMATION, NULL, NULL, true, false, &session); if (ret != CKR_OK) { goto done; } sess = p11prov_session_handle(session); ret = p11prov_FindObjectsInit(obj->ctx, sess, template, 2); if (ret != CKR_OK) { goto done; } /* we expect a single entry */ ret = p11prov_FindObjects(obj->ctx, sess, &handle, 1, &objcount); fret = p11prov_FindObjectsFinal(obj->ctx, sess); if (fret != CKR_OK) { /* this is not fatal */ P11PROV_raise(obj->ctx, fret, "Failed to terminate object search"); } if (ret != CKR_OK) { goto done; } if (objcount != 1) { P11PROV_raise(obj->ctx, ret, "Error in C_FindObjects (count=%ld)", objcount); goto done; } ret = p11prov_obj_from_handle(obj->ctx, session, handle, &retobj); if (ret != CKR_OK) { P11PROV_raise(obj->ctx, ret, "Failed to get object from handle"); } /* associate it so we do not have to search again on repeat calls */ if (retobj && obj->assoc_obj == NULL) { obj->assoc_obj = p11prov_obj_ref_no_cache(retobj); } done: p11prov_return_session(session); return retobj; } static void p11prov_obj_refresh(P11PROV_OBJ *obj) { int login_behavior; bool login = false; CK_SLOT_ID slotid = CK_UNAVAILABLE_INFORMATION; P11PROV_SESSION *session = NULL; CK_SESSION_HANDLE sess = CK_INVALID_HANDLE; CK_ATTRIBUTE template[3] = { 0 }; CK_ATTRIBUTE *attr; int anum; CK_OBJECT_HANDLE handle; CK_ULONG objcount = 0; P11PROV_OBJ *tmp = NULL; CK_RV ret; P11PROV_debug("Refresh object %p", obj); if (obj->class == CKO_PRIVATE_KEY) { login = true; } login_behavior = p11prov_ctx_login_behavior(obj->ctx); if (login_behavior == PUBKEY_LOGIN_ALWAYS) { login = true; } slotid = p11prov_obj_get_slotid(obj); ret = p11prov_get_session(obj->ctx, &slotid, NULL, obj->refresh_uri, CK_UNAVAILABLE_INFORMATION, NULL, NULL, login, false, &session); if (ret != CKR_OK) { P11PROV_debug("Failed to get session to refresh object %p", obj); return; } sess = p11prov_session_handle(session); anum = 0; CKATTR_ASSIGN(template[anum], CKA_CLASS, &(obj->class), sizeof(obj->class)); anum++; /* use CKA_ID if available */ attr = p11prov_obj_get_attr(obj, CKA_ID); if (attr) { template[anum] = *attr; anum++; } /* use Label if available */ attr = p11prov_obj_get_attr(obj, CKA_LABEL); if (attr) { template[anum] = *attr; anum++; } ret = p11prov_FindObjectsInit(obj->ctx, sess, template, anum); if (ret != CKR_OK) { goto done; } /* we expect a single entry */ ret = p11prov_FindObjects(obj->ctx, sess, &handle, 1, &objcount); /* Finalizing is not fatal so ignore result */ p11prov_FindObjectsFinal(obj->ctx, sess); if (ret != CKR_OK || objcount == 0) { P11PROV_raise(obj->ctx, ret, "Failed to find refresh object %p (count=%ld)", obj, objcount); goto done; } if (objcount != 1) { P11PROV_raise(obj->ctx, ret, "Too many objects found on refresh (count=%ld)", objcount); goto done; } ret = p11prov_obj_from_handle(obj->ctx, session, handle, &tmp); if (ret != CKR_OK) { P11PROV_raise(obj->ctx, ret, "Failed to get object from handle"); goto done; } /* move over all the object data, then free the tmp */ obj->handle = tmp->handle; obj->cached = tmp->cached; obj->cka_copyable = tmp->cka_copyable; obj->cka_token = tmp->cka_token; switch (obj->class) { case CKO_CERTIFICATE: obj->data.crt = tmp->data.crt; break; case CKO_PUBLIC_KEY: case CKO_PRIVATE_KEY: obj->data.key = tmp->data.key; break; default: break; } /* FIXME: How do we refresh attrs? What happens if a pointer * to an attr value was saved somewhere? Freeing ->attrs would * cause use-after-free issues */ p11prov_obj_free(tmp); obj->raf = false; /* Refresh the associated object too if there is one */ if (obj->assoc_obj && obj->assoc_obj->raf) { p11prov_obj_refresh(obj->assoc_obj); } done: p11prov_return_session(session); } #define SECRET_KEY_ATTRS 2 P11PROV_OBJ *p11prov_create_secret_key(P11PROV_CTX *provctx, P11PROV_SESSION *session, bool session_key, unsigned char *secret, size_t secretlen) { CK_SESSION_HANDLE sess = CK_INVALID_HANDLE; CK_SESSION_INFO session_info; CK_OBJECT_CLASS key_class = CKO_SECRET_KEY; CK_KEY_TYPE key_type = CKK_GENERIC_SECRET; CK_BBOOL val_true = CK_TRUE; CK_BBOOL val_token = session_key ? CK_FALSE : CK_TRUE; CK_ATTRIBUTE key_template[5] = { { CKA_CLASS, &key_class, sizeof(key_class) }, { CKA_KEY_TYPE, &key_type, sizeof(key_type) }, { CKA_TOKEN, &val_token, sizeof(val_token) }, { CKA_DERIVE, &val_true, sizeof(val_true) }, { CKA_VALUE, (void *)secret, secretlen }, }; CK_OBJECT_HANDLE key_handle; P11PROV_OBJ *obj; struct fetch_attrs attrs[SECRET_KEY_ATTRS]; int num; CK_RV ret; sess = p11prov_session_handle(session); P11PROV_debug("keys: create secret key (session:%lu secret:%p[%zu])", sess, secret, secretlen); ret = p11prov_GetSessionInfo(provctx, sess, &session_info); if (ret != CKR_OK) { return NULL; } if (((session_info.flags & CKF_RW_SESSION) == 0) && val_token == CK_TRUE) { P11PROV_debug("Invalid read only session for token key request"); return NULL; } ret = p11prov_CreateObject(provctx, sess, key_template, 5, &key_handle); if (ret != CKR_OK) { return NULL; } obj = p11prov_obj_new(provctx, session_info.slotID, key_handle, key_class); if (obj == NULL) { return NULL; } obj->data.key.type = key_type; obj->data.key.size = secretlen; obj->attrs = OPENSSL_zalloc(SECRET_KEY_ATTRS * sizeof(CK_ATTRIBUTE)); if (obj->attrs == NULL) { P11PROV_raise(provctx, CKR_HOST_MEMORY, "Allocation failure"); p11prov_obj_free(obj); return NULL; } num = 0; FA_SET_BUF_ALLOC(attrs, num, CKA_ID, false); FA_SET_BUF_ALLOC(attrs, num, CKA_LABEL, false); ret = p11prov_fetch_attributes(provctx, session, key_handle, attrs, num); if (ret == CKR_OK) { obj->numattrs = 0; p11prov_move_alloc_attrs(attrs, num, obj->attrs, &obj->numattrs); } else { P11PROV_debug("Failed to query object attributes (%lu)", ret); p11prov_fetch_attrs_free(attrs, num); p11prov_obj_free(obj); obj = NULL; } return obj; } CK_RV p11prov_derive_key(P11PROV_CTX *ctx, CK_SLOT_ID slotid, CK_MECHANISM *mechanism, CK_OBJECT_HANDLE handle, CK_ATTRIBUTE *template, CK_ULONG nattrs, P11PROV_SESSION **session, CK_OBJECT_HANDLE *key) { bool first_pass = true; P11PROV_SESSION *s = *session; CK_RV ret; again: if (!s) { ret = p11prov_get_session(ctx, &slotid, NULL, NULL, mechanism->mechanism, NULL, NULL, false, false, &s); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Failed to open session on slot %lu", slotid); return ret; } } ret = p11prov_DeriveKey(ctx, p11prov_session_handle(s), mechanism, handle, template, nattrs, key); switch (ret) { case CKR_OK: *session = s; return CKR_OK; case CKR_SESSION_CLOSED: case CKR_SESSION_HANDLE_INVALID: if (first_pass) { first_pass = false; /* TODO: Explicitly mark handle invalid */ p11prov_return_session(s); s = *session = NULL; goto again; } /* fallthrough */ default: if (*session == NULL) { p11prov_return_session(s); } return ret; } } CK_RV p11prov_obj_set_attributes(P11PROV_CTX *ctx, P11PROV_SESSION *session, P11PROV_OBJ *obj, CK_ATTRIBUTE *template, CK_ULONG tsize) { P11PROV_SESSION *s = session; CK_SLOT_ID slotid = obj->slotid; CK_RV ret; if (!s) { ret = p11prov_get_session(ctx, &slotid, NULL, NULL, CK_UNAVAILABLE_INFORMATION, NULL, NULL, false, true, &s); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Failed to open session on slot %lu", slotid); return ret; } } ret = p11prov_SetAttributeValue(ctx, p11prov_session_handle(s), p11prov_obj_get_handle(obj), template, tsize); if (obj->cached != CK_INVALID_HANDLE) { /* try to re-cache key to maintain matching attributes */ cache_key(obj); } /* TODO: should we retry iterating value by value on each element of * template to be able to set as much as we can and return which attribute * exactly the token is refusing ? */ if (s != session) { p11prov_return_session(s); } return ret; } #define MAX_KEY_ATTRS 2 static CK_RV get_all_from_cert(P11PROV_OBJ *crt, CK_ATTRIBUTE *attrs, int num) { OSSL_PARAM params[MAX_KEY_ATTRS + 1] = { 0 }; CK_ATTRIBUTE_TYPE types[MAX_KEY_ATTRS]; CK_ATTRIBUTE *type; CK_ATTRIBUTE *value; const unsigned char *val; X509 *x509 = NULL; EVP_PKEY *pkey; int attrnum = 0; int ret; CK_RV rv; /* if CKA_CERTIFICATE_TYPE is not present assume CKC_X_509 */ type = p11prov_obj_get_attr(crt, CKA_CERTIFICATE_TYPE); if (type) { CK_CERTIFICATE_TYPE crt_type = CKC_X_509; if (type->ulValueLen != sizeof(CK_CERTIFICATE_TYPE) || memcmp(type->pValue, &crt_type, type->ulValueLen) != 0) { return CKR_OBJECT_HANDLE_INVALID; } } value = p11prov_obj_get_attr(crt, CKA_VALUE); if (!value) { return CKR_GENERAL_ERROR; } val = value->pValue; x509 = d2i_X509(NULL, &val, value->ulValueLen); if (!x509) { return CKR_GENERAL_ERROR; } pkey = X509_get0_pubkey(x509); if (!pkey) { rv = CKR_GENERAL_ERROR; goto done; } if (EVP_PKEY_is_a(pkey, "RSA")) { for (int i = 0; i < num; i++) { switch (attrs[i].type) { case CKA_MODULUS: types[attrnum] = CKA_MODULUS; params[attrnum] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_N, NULL, 0); attrnum++; break; case CKA_PUBLIC_EXPONENT: types[attrnum] = CKA_PUBLIC_EXPONENT; params[attrnum] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_E, NULL, 0); attrnum++; break; } } } else if (EVP_PKEY_is_a(pkey, "EC")) { for (int i = 0; i < num; i++) { switch (attrs[i].type) { case CKA_P11PROV_CURVE_NAME: types[attrnum] = CKA_P11PROV_CURVE_NAME; params[attrnum] = OSSL_PARAM_construct_utf8_string( OSSL_PKEY_PARAM_GROUP_NAME, NULL, 0); attrnum++; break; case CKA_P11PROV_PUB_KEY: types[attrnum] = CKA_P11PROV_PUB_KEY; params[attrnum] = OSSL_PARAM_construct_octet_string( OSSL_PKEY_PARAM_PUB_KEY, NULL, 0); attrnum++; break; } } } else if (EVP_PKEY_is_a(pkey, ED25519) || EVP_PKEY_is_a(pkey, ED448)) { for (int i = 0; i < num; i++) { switch (attrs[i].type) { case CKA_P11PROV_PUB_KEY: types[attrnum] = CKA_P11PROV_PUB_KEY; params[attrnum] = OSSL_PARAM_construct_octet_string( OSSL_PKEY_PARAM_PUB_KEY, NULL, 0); attrnum++; break; } } } else { rv = CKR_OBJECT_HANDLE_INVALID; goto done; } if (attrnum == 0) { rv = CKR_ARGUMENTS_BAD; goto done; } params[attrnum] = OSSL_PARAM_construct_end(); ret = EVP_PKEY_get_params(pkey, params); if (ret != RET_OSSL_OK) { rv = CKR_GENERAL_ERROR; goto done; } ret = OSSL_PARAM_modified(params); if (ret != RET_OSSL_OK) { rv = CKR_GENERAL_ERROR; goto done; } for (int i = 0; i < attrnum; i++) { if (params[i].return_size == 0) { rv = CKR_GENERAL_ERROR; goto done; } /* allocate one more byte as null terminator to avoid buffer overruns * when this is converted to the OSSL_PARAM as utf8 string */ params[i].data = OPENSSL_zalloc(params[i].return_size + 1); if (!params[i].data) { rv = CKR_HOST_MEMORY; goto done; } params[i].data_size = params[i].return_size; params[i].return_size = OSSL_PARAM_UNMODIFIED; } ret = EVP_PKEY_get_params(pkey, params); if (ret != RET_OSSL_OK) { rv = CKR_GENERAL_ERROR; goto done; } ret = OSSL_PARAM_modified(params); if (ret != RET_OSSL_OK) { rv = CKR_GENERAL_ERROR; goto done; } for (int i = 0; i < num; i++) { bool found = false; for (int j = 0; j < attrnum; j++) { if (attrs[i].type == types[j]) { if (!params[j].data) { rv = CKR_GENERAL_ERROR; goto done; } attrs[i].pValue = params[j].data; attrs[i].ulValueLen = params[j].data_size; params[j].data = NULL; found = true; break; } } if (!found) { rv = CKR_ARGUMENTS_BAD; goto done; } } rv = CKR_OK; done: /* just in case caller didn't fetch all */ for (int i = 0; i < attrnum; i++) { OPENSSL_free(params[i].data); } if (rv != CKR_OK) { for (int i = 0; i < num; i++) { OPENSSL_free(attrs[i].pValue); attrs[i].pValue = NULL; attrs[i].ulValueLen = 0; } } X509_free(x509); return rv; } static CK_RV get_all_attrs(P11PROV_OBJ *obj, CK_ATTRIBUTE *attrs, int num) { CK_ATTRIBUTE *res[num]; CK_RV rv; for (int i = 0; i < num; i++) { res[i] = p11prov_obj_get_attr(obj, attrs[i].type); if (!res[i]) { return CKR_CANCEL; } } for (int i = 0; i < num; i++) { rv = p11prov_copy_attr(&attrs[i], res[i]); if (rv != CKR_OK) { for (i--; i >= 0; i--) { OPENSSL_free(attrs[i].pValue); attrs[i].ulValueLen = 0; attrs[i].pValue = NULL; } return rv; } } return CKR_OK; } static CK_RV get_public_attrs(P11PROV_OBJ *obj, CK_ATTRIBUTE *attrs, int num) { P11PROV_OBJ *tmp = NULL; CK_RV rv; P11PROV_debug("Get Public Attributes (obj=%p, atrs=%p, num=%d)", obj, attrs, num); /* we couldn't get all of them, start fallback logic */ switch (obj->class) { case CKO_PUBLIC_KEY: return get_all_attrs(obj, attrs, num); case CKO_PRIVATE_KEY: rv = get_all_attrs(obj, attrs, num); if (rv == CKR_OK) { return rv; } /* public attributes unavailable, try to find public key */ tmp = p11prov_obj_find_associated(obj, CKO_PUBLIC_KEY); if (tmp) { rv = get_all_attrs(tmp, attrs, num); p11prov_obj_free(tmp); return rv; } /* no public key, try to find certificate */ tmp = p11prov_obj_find_associated(obj, CKO_CERTIFICATE); if (tmp) { rv = get_all_from_cert(tmp, attrs, num); p11prov_obj_free(tmp); return rv; } break; case CKO_CERTIFICATE: return get_all_from_cert(obj, attrs, num); default: break; } return CKR_CANCEL; } /* Tokens return data in bigendian order, while openssl * wants it in host order, so we may need to fix the * endianness of the buffer. * Src and Dest, can be the same area, but not partially * overlapping memory areas */ #define RSA_PUB_ATTRS 2 static int p11prov_obj_export_public_rsa_key(P11PROV_OBJ *obj, OSSL_CALLBACK *cb_fn, void *cb_arg) { CK_ATTRIBUTE attrs[RSA_PUB_ATTRS] = { 0 }; OSSL_PARAM params[RSA_PUB_ATTRS + 2]; CK_RV rv; int ret, n = 0; if (p11prov_obj_get_key_type(obj) != CKK_RSA) { return RET_OSSL_ERR; } attrs[0].type = CKA_MODULUS; attrs[1].type = CKA_PUBLIC_EXPONENT; rv = get_public_attrs(obj, attrs, RSA_PUB_ATTRS); if (rv != CKR_OK) { P11PROV_raise(obj->ctx, rv, "Failed to get public key attributes"); return RET_OSSL_ERR; } byteswap_buf(attrs[0].pValue, attrs[0].pValue, attrs[0].ulValueLen); params[n++] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_N, attrs[0].pValue, attrs[0].ulValueLen); byteswap_buf(attrs[1].pValue, attrs[1].pValue, attrs[1].ulValueLen); params[n++] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_E, attrs[1].pValue, attrs[1].ulValueLen); /* If this is an RSA-PSS limited key, OpenSSL need some more signs here. * The PKCS#11 specification is not compatible with what OpenSSL expects * (unless we would have just one mechanisms specified in * ALLOWED_MECHANISMS) */ if (p11prov_obj_is_rsa_pss(obj)) { params[n++] = OSSL_PARAM_construct_utf8_string( OSSL_PKEY_PARAM_RSA_MASKGENFUNC, (char *)SN_mgf1, strlen(SN_mgf1)); /* TODO add the other params if restricted? */ } params[n++] = OSSL_PARAM_construct_end(); ret = cb_fn(params, cb_arg); for (int i = 0; i < RSA_PUB_ATTRS; i++) { OPENSSL_free(attrs[i].pValue); } return ret; } const char *p11prov_obj_get_ec_group_name(P11PROV_OBJ *obj) { CK_ATTRIBUTE *attr; attr = p11prov_obj_get_attr(obj, CKA_P11PROV_CURVE_NAME); if (!attr) { /* this should never happen */ P11PROV_raise(obj->ctx, CKR_GENERAL_ERROR, "Failed to get curve name"); return NULL; } return (const char *)attr->pValue; } bool p11prov_obj_get_ec_compressed(P11PROV_OBJ *obj) { CK_ATTRIBUTE *pub_key; uint8_t *buf; pub_key = p11prov_obj_get_attr(obj, CKA_P11PROV_PUB_KEY); if (!pub_key) { obj = p11prov_obj_get_associated(obj); if (obj) { pub_key = p11prov_obj_get_attr(obj, CKA_P11PROV_PUB_KEY); } if (!pub_key) { return false; } } buf = pub_key->pValue; return (buf[0] & 0x01) == 0x01; } static int ossl_param_construct_bn(P11PROV_CTX *provctx, OSSL_PARAM *param, const char *key, const BIGNUM *val) { size_t bsize; void *buf; if (BN_is_negative(val)) { P11PROV_raise(provctx, CKR_GENERAL_ERROR, "Negative big numbers are unsupported for %s", key); return 0; } bsize = (size_t)BN_num_bytes(val); /* We make sure that at least one byte is used, so zero is properly set */ if (bsize == 0) { bsize++; } buf = OPENSSL_malloc(bsize); if (buf == NULL) { P11PROV_raise(provctx, CKR_HOST_MEMORY, "Allocating data for %s", key); return 0; } if (BN_bn2nativepad(val, buf, bsize) < 0) { return 0; } *param = OSSL_PARAM_construct_BN(key, buf, bsize); return 1; } static int ec_group_explicit_to_params(P11PROV_OBJ *obj, const EC_GROUP *group, OSSL_PARAM *params, int *nparam, BN_CTX *bnctx) { int fid; const char *field_type; BIGNUM *p, *a, *b; const BIGNUM *order, *cofactor; const EC_POINT *generator; point_conversion_form_t genform; size_t bsize; void *buf; unsigned char *seed; size_t seed_len; fid = EC_GROUP_get_field_type(group); if (fid == NID_X9_62_prime_field) { field_type = SN_X9_62_prime_field; } else if (fid == NID_X9_62_characteristic_two_field) { field_type = SN_X9_62_characteristic_two_field; } else { P11PROV_raise(obj->ctx, CKR_GENERAL_ERROR, "Invalid EC field"); return RET_OSSL_ERR; } params[(*nparam)++] = OSSL_PARAM_construct_utf8_string( OSSL_PKEY_PARAM_EC_FIELD_TYPE, (char *)field_type, 0); p = BN_CTX_get(bnctx); a = BN_CTX_get(bnctx); b = BN_CTX_get(bnctx); if (b == NULL) { return RET_OSSL_ERR; } if (!EC_GROUP_get_curve(group, p, a, b, bnctx)) { P11PROV_raise(obj->ctx, CKR_GENERAL_ERROR, "Invalid curve"); return RET_OSSL_ERR; } if (!ossl_param_construct_bn(obj->ctx, ¶ms[(*nparam)++], OSSL_PKEY_PARAM_EC_P, p) || !ossl_param_construct_bn(obj->ctx, ¶ms[(*nparam)++], OSSL_PKEY_PARAM_EC_A, a) || !ossl_param_construct_bn(obj->ctx, ¶ms[(*nparam)++], OSSL_PKEY_PARAM_EC_B, b)) { return RET_OSSL_ERR; } order = EC_GROUP_get0_order(group); if (order == NULL) { P11PROV_raise(obj->ctx, CKR_GENERAL_ERROR, "Invalid group order"); return RET_OSSL_ERR; } if (!ossl_param_construct_bn(obj->ctx, ¶ms[(*nparam)++], OSSL_PKEY_PARAM_EC_ORDER, order)) { return RET_OSSL_ERR; } generator = EC_GROUP_get0_generator(group); genform = EC_GROUP_get_point_conversion_form(group); if (generator == NULL) { P11PROV_raise(obj->ctx, CKR_GENERAL_ERROR, "Invalid group generator"); return RET_OSSL_ERR; } bsize = EC_POINT_point2oct(group, generator, genform, NULL, 0, bnctx); buf = OPENSSL_malloc(bsize); if (buf == NULL) { return RET_OSSL_ERR; } bsize = EC_POINT_point2oct(group, generator, genform, buf, bsize, bnctx); params[(*nparam)++] = OSSL_PARAM_construct_octet_string( OSSL_PKEY_PARAM_EC_GENERATOR, buf, bsize); cofactor = EC_GROUP_get0_cofactor(group); if (cofactor == NULL) { P11PROV_raise(obj->ctx, CKR_GENERAL_ERROR, "Invalid group cofactor"); return RET_OSSL_ERR; } if (!ossl_param_construct_bn(obj->ctx, ¶ms[(*nparam)++], OSSL_PKEY_PARAM_EC_COFACTOR, cofactor)) { return RET_OSSL_ERR; } seed = EC_GROUP_get0_seed(group); seed_len = EC_GROUP_get_seed_len(group); if (seed != NULL && seed_len > 0) { params[(*nparam)++] = OSSL_PARAM_construct_octet_string( OSSL_PKEY_PARAM_EC_SEED, seed, seed_len); } return RET_OSSL_OK; } /* Common: * CKA_P11PROV_PUB_KEY -> OSSL_PKEY_PARAM_PUB_KEY * Named curves: * CKA_P11PROV_CURVE_NAME -> OSSL_PKEY_PARAM_GROUP_NAME * Explicit curves: * CKA_EC_PARAMS -> OSSL_PKEY_PARAM_EC_FIELD_TYPE, * OSSL_PKEY_PARAM_EC_A, * OSSL_PKEY_PARAM_EC_B, * OSSL_PKEY_PARAM_EC_P, * OSSL_PKEY_PARAM_EC_GENERATOR, * OSSL_PKEY_PARAM_EC_ORDER, * OSSL_PKEY_PARAM_EC_COFACTOR, * OSSL_PKEY_PARAM_EC_SEED */ #define EC_MAX_PUB_ATTRS 2 #define EC_MAX_OSSL_PARAMS 9 static int p11prov_obj_export_public_ec_key(P11PROV_OBJ *obj, bool params_only, OSSL_CALLBACK *cb_fn, void *cb_arg) { CK_ATTRIBUTE attrs[EC_MAX_PUB_ATTRS] = { 0 }; OSSL_PARAM params[EC_MAX_OSSL_PARAMS + 1] = { 0 }; CK_KEY_TYPE key_type; int pub_key_attr = 0; int nattr = 0; int nparam = 0; CK_RV rv; int ret; EC_GROUP *group = NULL; int curve_nid = NID_undef; key_type = p11prov_obj_get_key_type(obj); switch (key_type) { case CKK_EC: attrs[0].type = CKA_P11PROV_CURVE_NID; rv = get_public_attrs(obj, attrs, 1); if (rv != CKR_OK) { P11PROV_raise(obj->ctx, rv, "Failed to get EC key curve nid"); return RET_OSSL_ERR; } curve_nid = *(int *)attrs[0].pValue; OPENSSL_free(attrs[0].pValue); if (curve_nid == NID_undef) { attrs[0].type = CKA_EC_PARAMS; } else { attrs[0].type = CKA_P11PROV_CURVE_NAME; } nattr = 1; break; case CKK_EC_EDWARDS: break; default: return RET_OSSL_ERR; } if (!params_only) { pub_key_attr = nattr; attrs[nattr].type = CKA_P11PROV_PUB_KEY; nattr++; } rv = get_public_attrs(obj, attrs, nattr); if (rv != CKR_OK) { P11PROV_raise(obj->ctx, rv, "Failed to get public key attributes"); return RET_OSSL_ERR; } if (!params_only) { params[nparam] = OSSL_PARAM_construct_octet_string( OSSL_PKEY_PARAM_PUB_KEY, attrs[pub_key_attr].pValue, attrs[pub_key_attr].ulValueLen); nparam++; } if (key_type == CKK_EC) { if (curve_nid == NID_undef) { BN_CTX *bnctx; /* in d2i functions 'in' is overwritten to return the remainder of * the buffer after parsing, so we always need to avoid passing in * our pointer holders, to avoid having them clobbered */ const unsigned char *val = attrs[0].pValue; group = d2i_ECPKParameters(NULL, &val, attrs[0].ulValueLen); if (group == NULL) { ret = RET_OSSL_ERR; goto done; } bnctx = BN_CTX_new_ex(p11prov_ctx_get_libctx(obj->ctx)); if (bnctx == NULL) { ret = RET_OSSL_ERR; goto done; } BN_CTX_start(bnctx); ret = ec_group_explicit_to_params(obj, group, params, &nparam, bnctx); BN_CTX_end(bnctx); BN_CTX_free(bnctx); if (ret != RET_OSSL_OK) { goto done; } } else { params[nparam] = OSSL_PARAM_construct_utf8_string( OSSL_PKEY_PARAM_GROUP_NAME, attrs[0].pValue, attrs[0].ulValueLen); nparam++; } } params[nparam] = OSSL_PARAM_construct_end(); ret = cb_fn(params, cb_arg); done: /* must be freed after callback */ EC_GROUP_free(group); for (int i = 0; i < nparam; i++) { if (strcmp(params[i].key, OSSL_PKEY_PARAM_PUB_KEY) && strcmp(params[i].key, OSSL_PKEY_PARAM_GROUP_NAME) && strcmp(params[i].key, OSSL_PKEY_PARAM_EC_FIELD_TYPE)) { OPENSSL_free(params[i].data); } } for (int i = 0; i < nattr; i++) { OPENSSL_free(attrs[i].pValue); } return ret; } int p11prov_obj_export_public_key(P11PROV_OBJ *obj, CK_KEY_TYPE key_type, bool search_related, bool params_only, OSSL_CALLBACK *cb_fn, void *cb_arg) { if (obj == NULL) { return RET_OSSL_ERR; } if (obj->class != CKO_PRIVATE_KEY && obj->class != CKO_PUBLIC_KEY) { P11PROV_raise(obj->ctx, CKR_GENERAL_ERROR, "Invalid Object Class"); return RET_OSSL_ERR; } if (key_type != CK_UNAVAILABLE_INFORMATION) { if (key_type != obj->data.key.type) { P11PROV_raise(obj->ctx, CKR_GENERAL_ERROR, "Invalid Key Type"); return RET_OSSL_ERR; } } if (!search_related && obj->class != CKO_PUBLIC_KEY) { P11PROV_raise(obj->ctx, CKR_GENERAL_ERROR, "Not a public Key"); return RET_OSSL_ERR; } switch (obj->data.key.type) { case CKK_RSA: return p11prov_obj_export_public_rsa_key(obj, cb_fn, cb_arg); case CKK_EC: case CKK_EC_EDWARDS: return p11prov_obj_export_public_ec_key(obj, params_only, cb_fn, cb_arg); default: P11PROV_raise(obj->ctx, CKR_GENERAL_ERROR, "Unsupported key type"); return RET_OSSL_ERR; } } int p11prov_obj_get_ed_pub_key(P11PROV_OBJ *obj, CK_ATTRIBUTE **pub) { CK_ATTRIBUTE *a; P11PROV_debug("get ed pubkey %p", obj); if (!obj) { return RET_OSSL_ERR; } if (obj->class != CKO_PRIVATE_KEY && obj->class != CKO_PUBLIC_KEY) { P11PROV_raise(obj->ctx, CKR_GENERAL_ERROR, "Invalid Object Class"); return RET_OSSL_ERR; } if (obj->data.key.type != CKK_EC_EDWARDS) { P11PROV_raise(obj->ctx, CKR_GENERAL_ERROR, "Unsupported key type"); return RET_OSSL_ERR; } /* check if we have a pub key associated to a private key */ if (obj->class == CKO_PRIVATE_KEY) { P11PROV_OBJ *pobj = p11prov_obj_get_associated(obj); if (pobj && pobj->class == CKO_PUBLIC_KEY) { /* replace obj with the public one */ obj = pobj; } } /* See if we have cached attributes first */ a = p11prov_obj_get_attr(obj, CKA_P11PROV_PUB_KEY); if (!a) { return RET_OSSL_ERR; } if (pub) { *pub = a; } return RET_OSSL_OK; } int p11prov_obj_get_ec_public_x_y(P11PROV_OBJ *obj, CK_ATTRIBUTE **pub_x, CK_ATTRIBUTE **pub_y) { const unsigned char *val; void *tmp_ptr; CK_ATTRIBUTE *ec_params; CK_ATTRIBUTE *pub_key; EC_POINT *pub_point = NULL; EC_GROUP *group = NULL; CK_ATTRIBUTE *a_x; CK_ATTRIBUTE *a_y; BN_CTX *bnctx = NULL; BIGNUM *x; BIGNUM *y; int len; int ret; if (!obj) { return RET_OSSL_ERR; } if (obj->class != CKO_PRIVATE_KEY && obj->class != CKO_PUBLIC_KEY) { P11PROV_raise(obj->ctx, CKR_GENERAL_ERROR, "Invalid Object Class"); return RET_OSSL_ERR; } if (obj->data.key.type != CKK_EC) { P11PROV_raise(obj->ctx, CKR_GENERAL_ERROR, "Unsupported key type"); return RET_OSSL_ERR; } /* check if we have a pub key associated to a private key */ if (obj->class == CKO_PRIVATE_KEY) { P11PROV_OBJ *pub = p11prov_obj_get_associated(obj); if (pub && pub->class == CKO_PUBLIC_KEY) { /* replace obj with the public one */ obj = pub; } } /* See if we have cached attributes first */ a_x = p11prov_obj_get_attr(obj, CKA_P11PROV_PUB_KEY_X); a_y = p11prov_obj_get_attr(obj, CKA_P11PROV_PUB_KEY_Y); if (a_x && a_y) { if (pub_x) { *pub_x = a_x; } if (pub_y) { *pub_y = a_y; } return RET_OSSL_OK; } ec_params = p11prov_obj_get_attr(obj, CKA_EC_PARAMS); if (!ec_params) { return RET_OSSL_ERR; } pub_key = p11prov_obj_get_attr(obj, CKA_P11PROV_PUB_KEY); if (!pub_key) { return RET_OSSL_ERR; } bnctx = BN_CTX_new(); if (!bnctx) { ret = RET_OSSL_ERR; goto done; } /* prevent modification of the attribute pointer */ val = ec_params->pValue; group = d2i_ECPKParameters(NULL, &val, ec_params->ulValueLen); if (!group) { ret = RET_OSSL_ERR; goto done; } x = BN_CTX_get(bnctx); y = BN_CTX_get(bnctx); if (!y) { ret = RET_OSSL_ERR; goto done; } pub_point = EC_POINT_new(group); if (!pub_point) { ret = RET_OSSL_ERR; goto done; } ret = EC_POINT_oct2point(group, pub_point, pub_key->pValue, pub_key->ulValueLen, bnctx); if (ret != RET_OSSL_OK) { goto done; } ret = EC_POINT_get_affine_coordinates(group, pub_point, x, y, bnctx); if (ret != RET_OSSL_OK) { goto done; } /* cache values */ tmp_ptr = OPENSSL_realloc(obj->attrs, sizeof(CK_ATTRIBUTE) * (obj->numattrs + 2)); if (!tmp_ptr) { ret = RET_OSSL_ERR; goto done; } obj->attrs = tmp_ptr; /* do x */ a_x = &obj->attrs[obj->numattrs]; a_x->type = CKA_P11PROV_PUB_KEY_X; a_x->ulValueLen = BN_num_bytes(x); a_x->pValue = OPENSSL_malloc(a_x->ulValueLen); if (!a_x->pValue) { ret = RET_OSSL_ERR; goto done; } len = BN_bn2nativepad(x, a_x->pValue, a_x->ulValueLen); if (len == -1) { OPENSSL_free(a_x->pValue); ret = RET_OSSL_ERR; goto done; } obj->numattrs++; /* do y */ a_y = &obj->attrs[obj->numattrs]; a_y->type = CKA_P11PROV_PUB_KEY_Y; a_y->ulValueLen = BN_num_bytes(y); a_y->pValue = OPENSSL_malloc(a_y->ulValueLen); if (!a_y->pValue) { OPENSSL_free(a_y->pValue); ret = RET_OSSL_ERR; goto done; } len = BN_bn2nativepad(y, a_y->pValue, a_y->ulValueLen); if (len == -1) { ret = RET_OSSL_ERR; goto done; } obj->numattrs++; if (pub_x) { *pub_x = a_x; } if (pub_y) { *pub_y = a_y; } ret = RET_OSSL_OK; done: EC_POINT_free(pub_point); EC_GROUP_free(group); BN_CTX_free(bnctx); return ret; } CK_ATTRIBUTE *p11prov_obj_get_ec_public_raw(P11PROV_OBJ *key) { CK_ATTRIBUTE *pub_key; if (!key) { return NULL; } if (key->data.key.type != CKK_EC) { P11PROV_raise(key->ctx, CKR_GENERAL_ERROR, "Unsupported key type"); return NULL; } if (key->class != CKO_PRIVATE_KEY && key->class != CKO_PUBLIC_KEY) { P11PROV_raise(key->ctx, CKR_GENERAL_ERROR, "Invalid Object Class"); return NULL; } /* check if we have a pub key associated to a private key */ if (key->class == CKO_PRIVATE_KEY) { P11PROV_OBJ *pub = p11prov_obj_get_associated(key); if (pub && pub->class == CKO_PUBLIC_KEY) { /* replace obj with the public one */ key = pub; } } pub_key = p11prov_obj_get_attr(key, CKA_P11PROV_PUB_KEY); if (!pub_key) { CK_ATTRIBUTE *ec_point; ec_point = p11prov_obj_get_attr(key, CKA_EC_POINT); if (ec_point) { struct data_buffer data = { 0 }; void *tmp_ptr; CK_RV ret; ret = decode_ec_point(key->data.key.type, ec_point, &data); if (ret != CKR_OK) { P11PROV_raise(key->ctx, ret, "Failed to decode EC_POINT"); return NULL; } tmp_ptr = OPENSSL_realloc(key->attrs, sizeof(CK_ATTRIBUTE) * (key->numattrs + 1)); if (!tmp_ptr) { P11PROV_raise(key->ctx, CKR_HOST_MEMORY, "Failed to allocate memory key attributes"); OPENSSL_free(data.data); return NULL; } key->attrs = tmp_ptr; /* takes the data allocated in data */ CKATTR_ASSIGN(key->attrs[key->numattrs], CKA_P11PROV_PUB_KEY, data.data, data.length); key->numattrs++; pub_key = &key->attrs[key->numattrs - 1]; } } if (!pub_key) { P11PROV_debug("ECC Public Point not found"); } return pub_key; } static int cmp_attr(P11PROV_OBJ *key1, P11PROV_OBJ *key2, CK_ATTRIBUTE_TYPE attr) { CK_ATTRIBUTE *x1, *x2; x1 = p11prov_obj_get_attr(key1, attr); x2 = p11prov_obj_get_attr(key2, attr); if (!x1 || !x2) { return RET_OSSL_ERR; } if (x1->ulValueLen != x2->ulValueLen) { return RET_OSSL_ERR; } if (memcmp(x1->pValue, x2->pValue, x1->ulValueLen) != 0) { return RET_OSSL_ERR; } return RET_OSSL_OK; } static int cmp_public_key_values(P11PROV_OBJ *pub_key1, P11PROV_OBJ *pub_key2) { int ret; switch (pub_key1->data.key.type) { case CKK_RSA: /* pub_key1 pub_key2 could be CKO_PRIVATE_KEY here but * nevertheless contain these two attributes */ ret = cmp_attr(pub_key1, pub_key2, CKA_MODULUS); if (ret == RET_OSSL_ERR) { break; } ret = cmp_attr(pub_key1, pub_key2, CKA_PUBLIC_EXPONENT); break; case CKK_EC: case CKK_EC_EDWARDS: ret = cmp_attr(pub_key1, pub_key2, CKA_P11PROV_PUB_KEY); break; default: ret = RET_OSSL_ERR; } return ret; } static int match_key_with_cert(P11PROV_OBJ *priv_key, P11PROV_OBJ *pub_key) { P11PROV_OBJ *cert; CK_ATTRIBUTE attrs[2] = { 0 }; CK_ATTRIBUTE *x; int num = 0; int ret = RET_OSSL_ERR; cert = p11prov_obj_find_associated(priv_key, CKO_CERTIFICATE); if (!cert) { P11PROV_raise(priv_key->ctx, CKR_GENERAL_ERROR, "Could not find associated certificate object"); return RET_OSSL_ERR; } switch (pub_key->data.key.type) { case CKK_RSA: attrs[0].type = CKA_MODULUS; attrs[1].type = CKA_PUBLIC_EXPONENT; num = 2; break; case CKK_EC: case CKK_EC_EDWARDS: attrs[0].type = CKA_P11PROV_PUB_KEY; num = 1; break; } ret = get_all_from_cert(cert, attrs, num); if (ret != CKR_OK) { P11PROV_raise(priv_key->ctx, ret, "Failed to get public attrs from cert"); ret = RET_OSSL_ERR; goto done; } switch (pub_key->data.key.type) { case CKK_RSA: x = p11prov_obj_get_attr(pub_key, CKA_MODULUS); if (!x || x->ulValueLen != attrs[0].ulValueLen || memcmp(x->pValue, attrs[0].pValue, x->ulValueLen) != 0) { ret = RET_OSSL_ERR; goto done; } x = p11prov_obj_get_attr(pub_key, CKA_PUBLIC_EXPONENT); if (!x || x->ulValueLen != attrs[1].ulValueLen || memcmp(x->pValue, attrs[1].pValue, x->ulValueLen) != 0) { ret = RET_OSSL_ERR; goto done; } ret = RET_OSSL_OK; break; case CKK_EC: case CKK_EC_EDWARDS: x = p11prov_obj_get_attr(pub_key, CKA_P11PROV_PUB_KEY); if (!x || x->ulValueLen != attrs[0].ulValueLen || memcmp(x->pValue, attrs[0].pValue, x->ulValueLen) != 0) { ret = RET_OSSL_ERR; goto done; } ret = RET_OSSL_OK; break; } done: for (int i = 0; i < num; i++) { OPENSSL_free(attrs[i].pValue); } p11prov_obj_free(cert); return ret; } static int match_public_keys(P11PROV_OBJ *key1, P11PROV_OBJ *key2) { P11PROV_OBJ *pub_key, *assoc_pub_key; P11PROV_OBJ *priv_key; int ret = RET_OSSL_ERR; /* avoid round-trip to HSM if keys have enough * attributes to do the logical comparison * CKK_RSA: MODULUS / PUBLIC_EXPONENT * CKK_EC: EC_POINT */ ret = cmp_public_key_values(key1, key2); if (ret != RET_OSSL_ERR) { return ret; } /* one of the keys or both are private */ if (key1->class == CKO_PUBLIC_KEY && key2->class == CKO_PRIVATE_KEY) { pub_key = key1; priv_key = key2; } else if (key1->class == CKO_PRIVATE_KEY && key2->class == CKO_PUBLIC_KEY) { pub_key = key2; priv_key = key1; } else { P11PROV_debug("We can't really match private keys"); return RET_OSSL_ERR; } assoc_pub_key = p11prov_obj_find_associated(priv_key, CKO_PUBLIC_KEY); if (!assoc_pub_key) { P11PROV_raise(priv_key->ctx, CKR_GENERAL_ERROR, "Could not find associated public key object"); /* some tokens only store the public key in a cert and not in a * separate public key object */ return match_key_with_cert(priv_key, pub_key); } if (assoc_pub_key->data.key.type != pub_key->data.key.type) { goto done; } ret = cmp_public_key_values(pub_key, assoc_pub_key); done: p11prov_obj_free(assoc_pub_key); return ret; } static int p11prov_obj_get_ed_nid(CK_ATTRIBUTE *ecp) { const unsigned char *val = ecp->pValue; ASN1_OBJECT *obj = d2i_ASN1_OBJECT(NULL, &val, ecp->ulValueLen); if (obj) { int nid = OBJ_obj2nid(obj); ASN1_OBJECT_free(obj); if (nid != NID_undef) { return nid; } } /* it might be the parameters are encoded printable string * for EdDSA which OpenSSL does not understand */ if (ecp->ulValueLen == ED25519_EC_PARAMS_LEN && memcmp(ecp->pValue, ed25519_ec_params, ED25519_EC_PARAMS_LEN) == 0) { return NID_ED25519; } else if (ecp->ulValueLen == ED448_EC_PARAMS_LEN && memcmp(ecp->pValue, ed448_ec_params, ED448_EC_PARAMS_LEN) == 0) { return NID_ED448; } return NID_undef; } int p11prov_obj_key_cmp(P11PROV_OBJ *key1, P11PROV_OBJ *key2, CK_KEY_TYPE type, int cmp_type) { int ret; /* immediate shortcircuit if it is the same handle */ if (key1->slotid == key2->slotid && key1->handle == key2->handle) { return RET_OSSL_OK; } if (key1->class != CKO_PRIVATE_KEY && key1->class != CKO_PUBLIC_KEY) { /* not a key at all */ return RET_OSSL_ERR; } if (key2->class != CKO_PRIVATE_KEY && key2->class != CKO_PUBLIC_KEY) { /* not a key at all */ return RET_OSSL_ERR; } if (type != CK_UNAVAILABLE_INFORMATION && type != key1->data.key.type) { return RET_OSSL_ERR; } if (key1->data.key.type != key2->data.key.type) { return RET_OSSL_ERR; } if (key1->data.key.bit_size != key2->data.key.bit_size) { return RET_OSSL_ERR; } if (cmp_type & OBJ_CMP_KEY_PRIVATE) { if (key1->class != key2->class) { /* can't have private with differing key types */ return RET_OSSL_ERR; } if (key1->class != CKO_PRIVATE_KEY) { return RET_OSSL_ERR; } } switch (key1->data.key.type) { case CKK_RSA: if (cmp_type & OBJ_CMP_KEY_PRIVATE) { /* unfortunately we can't really read private attributes * and there is no comparison function int he PKCS11 API. * Generally you do not have 2 identical keys stored in to two * separate objects so the initial shortcircuit that matches if * slotid/handle are identical will often cover this. When that * fails we have no option but to fail for now. */ P11PROV_debug("We can't really match private keys"); /* OTOH if modulus and exponent match either this is a broken key * or the private key must also match */ cmp_type = OBJ_CMP_KEY_PUBLIC; } break; case CKK_EC: ret = cmp_attr(key1, key2, CKA_EC_PARAMS); if (ret != RET_OSSL_OK) { /* If EC_PARAMS do not match it may be due to encoding. * Fall back to slower conversions and compare via EC_GROUP */ CK_ATTRIBUTE *ec_p; const unsigned char *val; EC_GROUP *group1 = NULL; EC_GROUP *group2 = NULL; BN_CTX *bnctx = NULL; ec_p = p11prov_obj_get_attr(key1, CKA_EC_PARAMS); if (!ec_p) { ret = RET_OSSL_ERR; goto out; } val = ec_p->pValue; group1 = d2i_ECPKParameters(NULL, &val, ec_p->ulValueLen); if (!group1) { ret = RET_OSSL_ERR; goto out; } ec_p = p11prov_obj_get_attr(key2, CKA_EC_PARAMS); if (!ec_p) { ret = RET_OSSL_ERR; goto out; } val = ec_p->pValue; group2 = d2i_ECPKParameters(NULL, &val, ec_p->ulValueLen); if (!group2) { ret = RET_OSSL_ERR; goto out; } bnctx = BN_CTX_new_ex(p11prov_ctx_get_libctx(key1->ctx)); if (!bnctx) { ret = RET_OSSL_ERR; goto out; } ret = EC_GROUP_cmp(group1, group2, bnctx); if (ret == 0) { ret = RET_OSSL_OK; } else { ret = RET_OSSL_ERR; } out: EC_GROUP_free(group1); EC_GROUP_free(group2); BN_CTX_free(bnctx); if (ret != RET_OSSL_OK) { return ret; } } if (cmp_type & OBJ_CMP_KEY_PRIVATE) { /* unfortunately we can't really read private attributes * and there is no comparison function int he PKCS11 API. * Generally you do not have 2 identical keys stored in to two * separate objects so the initial shortcircuit that matches if * slotid/handle are identical will often cover this. When that * fails we have no option but to fail for now. */ P11PROV_debug("We can't really match private keys"); /* OTOH if group and pub point match either this is a broken key * or the private key must also match */ cmp_type = OBJ_CMP_KEY_PUBLIC; } break; case CKK_EC_EDWARDS: /* The EdDSA params can be encoded as printable string, which is * not recognized by OpenSSL and does not have respective EC_GROUP */ ret = cmp_attr(key1, key2, CKA_EC_PARAMS); if (ret != RET_OSSL_OK) { /* If EC_PARAMS do not match it may be due to encoding. */ CK_ATTRIBUTE *ec_p; int nid1; int nid2; ec_p = p11prov_obj_get_attr(key1, CKA_EC_PARAMS); if (!ec_p) { return RET_OSSL_ERR; } nid1 = p11prov_obj_get_ed_nid(ec_p); if (nid1 == NID_undef) { return RET_OSSL_ERR; } ec_p = p11prov_obj_get_attr(key2, CKA_EC_PARAMS); if (!ec_p) { return RET_OSSL_ERR; } nid2 = p11prov_obj_get_ed_nid(ec_p); if (nid2 == NID_undef) { return RET_OSSL_ERR; } if (nid1 != nid2) { return RET_OSSL_ERR; } } if (cmp_type & OBJ_CMP_KEY_PRIVATE) { /* unfortunately we can't really read private attributes * and there is no comparison function int he PKCS11 API. * Generally you do not have 2 identical keys stored in to two * separate objects so the initial shortcircuit that matches if * slotid/handle are identical will often cover this. When that * fails we have no option but to fail for now. */ P11PROV_debug("We can't really match private keys"); /* OTOH if group and pub point match either this is a broken key * or the private key must also match */ cmp_type = OBJ_CMP_KEY_PUBLIC; } break; default: return RET_OSSL_ERR; } if (cmp_type & OBJ_CMP_KEY_PUBLIC) { ret = match_public_keys(key1, key2); if (ret != RET_OSSL_OK) { return ret; } } /* if nothing fails it is a match */ return RET_OSSL_OK; } static bool obj_match_attrs(P11PROV_OBJ *obj, CK_ATTRIBUTE *attrs, int numattrs) { CK_ATTRIBUTE *x; for (int i = 0; i < numattrs; i++) { x = p11prov_obj_get_attr(obj, attrs[i].type); if (!x) { return false; } if (x->ulValueLen != attrs[i].ulValueLen) { return false; } if (memcmp(x->pValue, attrs[i].pValue, x->ulValueLen) != 0) { return false; } } /* match found */ return true; } #define MAX_ATTRS_SIZE 4 struct pool_find_ctx { CK_KEY_TYPE type; CK_OBJECT_CLASS class; CK_ULONG key_size; CK_ULONG bit_size; CK_ATTRIBUTE attrs[MAX_ATTRS_SIZE]; int numattrs; P11PROV_OBJ *found; }; static bool pool_find_callback(void *pctx, P11PROV_OBJ_POOL *pool) { struct pool_find_ctx *ctx = (struct pool_find_ctx *)pctx; P11PROV_OBJ *obj; CK_RV ret; if (!pool) { return false; } ret = MUTEX_LOCK(pool); if (ret != CKR_OK) { return false; } /* LOCKED SECTION ------------- */ for (int i = 0; i < pool->num; i++) { obj = pool->objects[i]; if (!obj) { continue; } if (obj->class != ctx->class) { continue; } if (obj->data.key.type != ctx->type) { continue; } if (obj->data.key.bit_size != ctx->bit_size) { continue; } if (obj_match_attrs(obj, ctx->attrs, ctx->numattrs)) { ctx->found = obj; break; } } (void)MUTEX_UNLOCK(pool); /* ------------- LOCKED SECTION */ return (ctx->found != NULL); } static CK_RV param_to_attr(P11PROV_CTX *ctx, const OSSL_PARAM params[], const char *param_key, CK_ATTRIBUTE *dst, CK_ATTRIBUTE_TYPE type, bool byteswap) { const OSSL_PARAM *p; CK_ATTRIBUTE tmp; CK_RV rv; p = OSSL_PARAM_locate_const(params, param_key); if (!p) { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Missing %s", param_key); return CKR_KEY_INDIGESTIBLE; } tmp.type = type; tmp.ulValueLen = p->data_size; tmp.pValue = p->data; rv = p11prov_copy_attr(dst, &tmp); if (rv != CKR_OK) { P11PROV_raise(ctx, CKR_HOST_MEMORY, "No space for %s", param_key); return CKR_HOST_MEMORY; } if (byteswap) { byteswap_buf(dst->pValue, dst->pValue, dst->ulValueLen); } return CKR_OK; } static CK_RV prep_rsa_find(P11PROV_CTX *ctx, const OSSL_PARAM params[], struct pool_find_ctx *findctx) { data_buffer digest_data[5]; data_buffer digest = { 0 }; const OSSL_PARAM *p; size_t key_size; CK_RV rv; if (findctx->numattrs != MAX_ATTRS_SIZE) { return CKR_ARGUMENTS_BAD; } findctx->numattrs = 0; switch (findctx->class) { case CKO_PUBLIC_KEY: rv = param_to_attr(ctx, params, OSSL_PKEY_PARAM_RSA_N, &findctx->attrs[0], CKA_MODULUS, true); if (rv != CKR_OK) { return rv; } findctx->numattrs++; key_size = findctx->attrs[0].ulValueLen; rv = param_to_attr(ctx, params, OSSL_PKEY_PARAM_RSA_E, &findctx->attrs[1], CKA_PUBLIC_EXPONENT, true); if (rv != CKR_OK) { return rv; } findctx->numattrs++; break; case CKO_PRIVATE_KEY: /* A Token would never allow us to search by private exponent, * so we store a hash of the private key in CKA_ID */ /* prefix */ digest_data[0].data = (uint8_t *)"PrivKey"; digest_data[0].length = 7; p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_N); if (!p) { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Missing %s", OSSL_PKEY_PARAM_RSA_N); return CKR_KEY_INDIGESTIBLE; } digest_data[1].data = p->data; digest_data[1].length = p->data_size; key_size = p->data_size; p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_E); if (!p) { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Missing %s", OSSL_PKEY_PARAM_RSA_E); return CKR_KEY_INDIGESTIBLE; } digest_data[2].data = p->data; digest_data[2].length = p->data_size; p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_RSA_D); if (!p) { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Missing %s", OSSL_PKEY_PARAM_RSA_D); return CKR_KEY_INDIGESTIBLE; } digest_data[3].data = p->data; digest_data[3].length = p->data_size; digest_data[4].data = NULL; rv = p11prov_digest_util(ctx, "sha256", NULL, digest_data, &digest); if (rv != CKR_OK) { return rv; } findctx->attrs[0].type = CKA_ID; findctx->attrs[0].pValue = digest.data; findctx->attrs[0].ulValueLen = digest.length; findctx->numattrs++; break; default: return CKR_GENERAL_ERROR; } findctx->key_size = key_size; findctx->bit_size = key_size * 8; return CKR_OK; } /* P-521 ~ 133 bytes, this should suffice */ #define MAX_EC_PUB_KEY_SIZE 150 static CK_RV prep_ec_find(P11PROV_CTX *ctx, const OSSL_PARAM params[], struct pool_find_ctx *findctx) { EC_GROUP *group = NULL; EC_POINT *point = NULL; BN_CTX *bn_ctx = NULL; OSSL_PARAM tmp; const OSSL_PARAM *p; OSSL_PARAM pub_key[2] = { 0 }; uint8_t pub_data[MAX_EC_PUB_KEY_SIZE]; data_buffer digest_data[5]; data_buffer digest = { 0 }; const char *curve_name = NULL; int curve_nid; unsigned char *ecparams = NULL; int len, i; CK_RV rv; if (findctx->numattrs != MAX_ATTRS_SIZE) { return CKR_ARGUMENTS_BAD; } findctx->numattrs = 0; group = EC_GROUP_new_from_params(params, p11prov_ctx_get_libctx(ctx), NULL); if (!group) { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Unable to decode ec group"); rv = CKR_KEY_INDIGESTIBLE; goto done; } curve_nid = EC_GROUP_get_curve_name(group); if (curve_nid != NID_undef) { curve_name = OSSL_EC_curve_nid2name(curve_nid); if (!curve_name) { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Unknown curve"); rv = CKR_KEY_INDIGESTIBLE; goto done; } } len = i2d_ECPKParameters(group, &ecparams); if (len < 0) { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Failed to encode EC params"); rv = CKR_KEY_INDIGESTIBLE; goto done; } switch (findctx->class) { case CKO_PUBLIC_KEY: p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY); if (!p) { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Missing %s", OSSL_PKEY_PARAM_PUB_KEY); EC_GROUP_free(group); rv = CKR_KEY_INDIGESTIBLE; goto done; } /* Providers may export in any format - OpenSSL < 3.0.8 * ignores the "point-format" OSSL_PARAM and unconditionally uses * compressed format: * - https://github.com/openssl/openssl/pull/16624 * - https://github.com/openssl/openssl/issues/16595 * * Convert from compressed to uncompressed if necessary */ if (((char *)p->data)[0] == '\x02' || ((char *)p->data)[0] == '\x03') { int ret, plen; P11PROV_debug( "OpenSSL 3.0.7 BUG - received compressed EC public key"); pub_key[0].key = OSSL_PKEY_PARAM_PUB_KEY; pub_key[0].data_type = p->data_type; pub_key[0].data = pub_data; point = EC_POINT_new(group); bn_ctx = BN_CTX_new(); ret = EC_POINT_oct2point(group, point, p->data, p->data_size, bn_ctx); if (!ret) { rv = CKR_KEY_INDIGESTIBLE; goto done; } plen = EC_POINT_point2oct( group, point, POINT_CONVERSION_UNCOMPRESSED, pub_key[0].data, MAX_EC_PUB_KEY_SIZE, bn_ctx); if (!plen) { rv = CKR_KEY_INDIGESTIBLE; goto done; } pub_key[0].data_size = plen; rv = param_to_attr(ctx, pub_key, OSSL_PKEY_PARAM_PUB_KEY, &findctx->attrs[0], CKA_P11PROV_PUB_KEY, false); if (rv != CKR_OK) { goto done; } } else { rv = param_to_attr(ctx, params, OSSL_PKEY_PARAM_PUB_KEY, &findctx->attrs[0], CKA_P11PROV_PUB_KEY, false); if (rv != CKR_OK) { goto done; } } findctx->numattrs++; break; case CKO_PRIVATE_KEY: /* A Token would never allow us to search by private exponent, * so we store a hash of the private key in CKA_ID */ p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY); if (!p) { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Missing %s", OSSL_PKEY_PARAM_PRIV_KEY); return CKR_KEY_INDIGESTIBLE; } i = 0; /* prefix */ digest_data[i].data = (uint8_t *)"PrivKey"; digest_data[i].length = 7; i++; if (curve_name) { digest_data[i].data = (uint8_t *)curve_name; digest_data[i].length = strlen(curve_name); i++; } digest_data[i].data = ecparams; digest_data[i].length = len; i++; digest_data[i].data = p->data; digest_data[i].length = p->data_size; i++; digest_data[i].data = NULL; rv = p11prov_digest_util(ctx, "sha256", NULL, digest_data, &digest); if (rv != CKR_OK) { return rv; } findctx->attrs[0].type = CKA_ID; findctx->attrs[0].pValue = digest.data; findctx->attrs[0].ulValueLen = digest.length; findctx->numattrs++; break; default: return CKR_GENERAL_ERROR; } /* common params */ tmp.key = "EC Params"; tmp.data = ecparams; tmp.data_size = len; rv = param_to_attr(ctx, &tmp, tmp.key, &findctx->attrs[findctx->numattrs], CKA_EC_PARAMS, false); if (rv != CKR_OK) { goto done; } findctx->numattrs++; tmp.key = "EC Group"; tmp.data = &curve_nid; tmp.data_size = sizeof(curve_nid); rv = param_to_attr(ctx, &tmp, tmp.key, &findctx->attrs[findctx->numattrs], CKA_P11PROV_CURVE_NID, false); if (rv != CKR_OK) { goto done; } findctx->numattrs++; if (curve_name) { tmp.key = "EC Curve Name"; tmp.data = (void *)curve_name; tmp.data_size = strlen(curve_name) + 1; rv = param_to_attr(ctx, &tmp, tmp.key, &findctx->attrs[findctx->numattrs], CKA_P11PROV_CURVE_NAME, false); if (rv != CKR_OK) { goto done; } findctx->numattrs++; } findctx->bit_size = EC_GROUP_order_bits(group); findctx->key_size = (findctx->bit_size + 7) / 8; rv = CKR_OK; done: OPENSSL_free(ecparams); EC_GROUP_free(group); EC_POINT_free(point); BN_CTX_free(bn_ctx); return rv; } static CK_RV prep_ed_find(P11PROV_CTX *ctx, const OSSL_PARAM params[], struct pool_find_ctx *findctx) { OSSL_PARAM tmp; const OSSL_PARAM *p; data_buffer digest_data[4]; data_buffer digest = { 0 }; const unsigned char *ecparams = NULL; int len, i; CK_RV rv; if (findctx->numattrs != MAX_ATTRS_SIZE) { return CKR_ARGUMENTS_BAD; } findctx->numattrs = 0; switch (findctx->class) { case CKO_PUBLIC_KEY: p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PUB_KEY); if (!p) { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Missing %s", OSSL_PKEY_PARAM_PUB_KEY); rv = CKR_KEY_INDIGESTIBLE; goto done; } if (p->data_size == ED25519_BYTE_SIZE) { ecparams = ed25519_ec_params; len = ED25519_EC_PARAMS_LEN; findctx->bit_size = ED25519_BIT_SIZE; findctx->key_size = ED25519_BYTE_SIZE; } else if (p->data_size == ED448_BYTE_SIZE) { ecparams = ed448_ec_params; len = ED448_EC_PARAMS_LEN; findctx->bit_size = ED448_BIT_SIZE; findctx->key_size = ED448_BYTE_SIZE; } else { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Public key of unknown length %lu", p->data_size); rv = CKR_KEY_INDIGESTIBLE; goto done; } rv = param_to_attr(ctx, params, OSSL_PKEY_PARAM_PUB_KEY, &findctx->attrs[0], CKA_P11PROV_PUB_KEY, false); if (rv != CKR_OK) { goto done; } findctx->numattrs++; break; case CKO_PRIVATE_KEY: /* A Token would never allow us to search by private exponent, * so we store a hash of the private key in CKA_ID */ p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY); if (!p) { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Missing %s", OSSL_PKEY_PARAM_PRIV_KEY); return CKR_KEY_INDIGESTIBLE; } i = 0; if (p->data_size == ED25519_BYTE_SIZE) { ecparams = ed25519_ec_params; len = ED25519_EC_PARAMS_LEN; findctx->bit_size = ED25519_BIT_SIZE; findctx->key_size = ED25519_BYTE_SIZE; } else if (p->data_size == ED448_BYTE_SIZE) { ecparams = ed448_ec_params; len = ED448_EC_PARAMS_LEN; findctx->bit_size = ED448_BIT_SIZE; findctx->key_size = ED448_BYTE_SIZE; } else { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Private key of unknown length %lu", p->data_size); rv = CKR_KEY_INDIGESTIBLE; goto done; } /* prefix */ digest_data[i].data = (uint8_t *)"PrivKey"; digest_data[i].length = 7; i++; digest_data[i].data = (CK_BYTE *)ecparams; digest_data[i].length = len; i++; digest_data[i].data = p->data; digest_data[i].length = p->data_size; i++; digest_data[i].data = NULL; rv = p11prov_digest_util(ctx, "sha256", NULL, digest_data, &digest); if (rv != CKR_OK) { return rv; } findctx->attrs[0].type = CKA_ID; findctx->attrs[0].pValue = digest.data; findctx->attrs[0].ulValueLen = digest.length; findctx->numattrs++; break; default: return CKR_GENERAL_ERROR; } /* common params */ tmp.key = "EC Params"; tmp.data = (CK_BYTE *)ecparams; tmp.data_size = len; rv = param_to_attr(ctx, &tmp, tmp.key, &findctx->attrs[findctx->numattrs], CKA_EC_PARAMS, false); if (rv != CKR_OK) { goto done; } findctx->numattrs++; rv = CKR_OK; done: return rv; } static CK_RV return_dup_key(P11PROV_OBJ *dst, P11PROV_OBJ *src) { CK_RV rv; dst->slotid = src->slotid; dst->handle = src->handle; dst->class = src->class; dst->cka_copyable = src->cka_copyable; dst->cka_token = src->cka_token; dst->data.key = src->data.key; /* Free existing attributes if any */ for (int i = 0; i < dst->numattrs; i++) { OPENSSL_free(dst->attrs[i].pValue); } OPENSSL_free(dst->attrs); dst->attrs = OPENSSL_zalloc(sizeof(CK_ATTRIBUTE) * src->numattrs); if (!dst->attrs) { rv = CKR_HOST_MEMORY; P11PROV_raise(dst->ctx, rv, "Failed allocation"); return rv; } dst->numattrs = 0; for (int i = 0; i < src->numattrs; i++) { rv = p11prov_copy_attr(&dst->attrs[i], &src->attrs[i]); if (rv != CKR_OK) { rv = CKR_HOST_MEMORY; P11PROV_raise(dst->ctx, rv, "Failed attr copy"); return rv; } dst->numattrs++; } return CKR_OK; } static CK_RV fix_ec_key_import(P11PROV_OBJ *key, int allocattrs) { CK_ATTRIBUTE *pub; ASN1_OCTET_STRING oct; unsigned char *der = NULL; int len; if (key->numattrs >= allocattrs) { P11PROV_raise(key->ctx, CKR_GENERAL_ERROR, "Too many attributes?? %d >= %d", key->numattrs, allocattrs); return CKR_GENERAL_ERROR; } pub = p11prov_obj_get_attr(key, CKA_P11PROV_PUB_KEY); if (!pub) { P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE, "No public key found"); return CKR_KEY_INDIGESTIBLE; } oct.data = pub->pValue; oct.length = pub->ulValueLen; oct.flags = 0; len = i2d_ASN1_OCTET_STRING(&oct, &der); if (len < 0) { P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE, "Failure to encode EC point to DER"); return CKR_KEY_INDIGESTIBLE; } key->attrs[key->numattrs].type = CKA_EC_POINT; key->attrs[key->numattrs].pValue = der; key->attrs[key->numattrs].ulValueLen = len; key->numattrs++; return CKR_OK; } static CK_RV p11prov_obj_import_public_key(P11PROV_OBJ *key, CK_KEY_TYPE type, const OSSL_PARAM params[]) { P11PROV_CTX *ctx; struct pool_find_ctx findctx = { .type = type, .class = CKO_PUBLIC_KEY, .bit_size = 0, .attrs = { { 0 } }, .numattrs = MAX_ATTRS_SIZE, .found = NULL, }; int allocattrs = 0; CK_RV rv; ctx = p11prov_obj_get_prov_ctx(key); if (!ctx) { return CKR_GENERAL_ERROR; } switch (type) { case CKK_RSA: rv = prep_rsa_find(ctx, params, &findctx); if (rv != CKR_OK) { goto done; } allocattrs = RSA_ATTRS_NUM; break; case CKK_EC: rv = prep_ec_find(ctx, params, &findctx); if (rv != CKR_OK) { goto done; } allocattrs = EC_ATTRS_NUM; break; case CKK_EC_EDWARDS: rv = prep_ed_find(ctx, params, &findctx); if (rv != CKR_OK) { goto done; } allocattrs = EC_ATTRS_NUM; break; default: P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE, "Unsupported key type: %08lx", type); rv = CKR_KEY_INDIGESTIBLE; goto done; } if (allocattrs < findctx.numattrs) { allocattrs = findctx.numattrs; } /* A common case with openssl is the request to import a key we already * actually have on the token. This happens because OpenSSL is greedy * and tries to export keys to its default provider before it even knows * what kind of operation it needs to do. Sometimes the operation ends up * being something that needs to be performed on the token. So try to see * if we already have this key */ rv = p11prov_slot_find_obj_pool(ctx, pool_find_callback, &findctx); if (rv != CKR_OK) { P11PROV_raise(key->ctx, CKR_GENERAL_ERROR, "Failed to search pools"); rv = CKR_GENERAL_ERROR; goto done; } if (findctx.found) { rv = return_dup_key(key, findctx.found); goto done; } /* * FIXME: * For things like ECDH we can get away with a mock object that just holds * data for now, but is not backed by an actual handle and key in the token. * Once this is not sufficient, we'll probably need to change functions to * pass in a valid session when requesting a handle from an object, so that * the key can be imported on the fly in the correct slot at the time the * operation needs to be performed. */ /* move data */ key->class = findctx.class; key->data.key.type = findctx.type; key->data.key.size = findctx.key_size; key->data.key.bit_size = findctx.bit_size; key->attrs = OPENSSL_malloc(sizeof(CK_ATTRIBUTE) * allocattrs); if (!key->attrs) { P11PROV_raise(key->ctx, CKR_HOST_MEMORY, "Failed allocation"); rv = CKR_HOST_MEMORY; goto done; } for (int i = 0; i < findctx.numattrs; i++) { key->attrs[i] = findctx.attrs[i]; findctx.attrs[i].pValue = NULL; } key->numattrs = findctx.numattrs; findctx.numattrs = 0; if (type == CKK_EC || type == CKK_EC_EDWARDS) { rv = fix_ec_key_import(key, allocattrs); } done: for (int i = 0; i < findctx.numattrs; i++) { OPENSSL_free(findctx.attrs[i].pValue); } return rv; } static CK_RV p11prov_store_rsa_public_key(P11PROV_OBJ *key) { CK_BBOOL val_true = CK_TRUE; CK_BBOOL val_false = CK_FALSE; CK_ATTRIBUTE template[] = { { CKA_CLASS, &key->class, sizeof(CK_OBJECT_CLASS) }, { CKA_KEY_TYPE, &key->data.key.type, sizeof(CK_KEY_TYPE) }, /* we allow all operations as we do not know what is * the purpose of this key at import time */ { CKA_ENCRYPT, &val_true, sizeof(val_true) }, { CKA_VERIFY, &val_true, sizeof(val_true) }, { CKA_WRAP, &val_true, sizeof(val_true) }, /* public key part */ { CKA_MODULUS, NULL, 0 }, /* 5 */ { CKA_PUBLIC_EXPONENT, NULL, 0 }, /* 6 */ /* TODO RSA PSS Params */ { CKA_TOKEN, &val_false, sizeof(val_false) }, }; int na = sizeof(template) / sizeof(CK_ATTRIBUTE); CK_ATTRIBUTE *a; P11PROV_SLOTS_CTX *slots = NULL; CK_SLOT_ID slot = CK_UNAVAILABLE_INFORMATION; P11PROV_SESSION *session = NULL; CK_RV rv = CKR_GENERAL_ERROR; a = p11prov_obj_get_attr(key, CKA_MODULUS); if (!a) { return CKR_GENERAL_ERROR; } template[5].pValue = a->pValue; template[5].ulValueLen = a->ulValueLen; a = p11prov_obj_get_attr(key, CKA_PUBLIC_EXPONENT); if (!a) { return CKR_GENERAL_ERROR; } template[6].pValue = a->pValue; template[6].ulValueLen = a->ulValueLen; slots = p11prov_ctx_get_slots(key->ctx); if (!slots) { rv = CKR_GENERAL_ERROR; goto done; } slot = p11prov_get_default_slot(slots); if (slot == CK_UNAVAILABLE_INFORMATION) { rv = CKR_GENERAL_ERROR; goto done; } rv = p11prov_take_login_session(key->ctx, slot, &session); if (rv != CKR_OK) { goto done; } rv = p11prov_CreateObject(key->ctx, p11prov_session_handle(session), template, na, &key->handle); if (rv != CKR_OK) { goto done; } key->slotid = slot; rv = CKR_OK; done: p11prov_return_session(session); return rv; } static CK_RV p11prov_store_ec_public_key(P11PROV_OBJ *key) { CK_BBOOL val_true = CK_TRUE; CK_BBOOL val_false = CK_FALSE; CK_ATTRIBUTE template[] = { { CKA_CLASS, &key->class, sizeof(CK_OBJECT_CLASS) }, { CKA_KEY_TYPE, &key->data.key.type, sizeof(CK_KEY_TYPE) }, /* we allow all operations as we do not know what is * the purpose of this key at import time */ { CKA_DERIVE, &val_true, sizeof(val_true) }, { CKA_VERIFY, &val_true, sizeof(val_true) }, /* public part */ { CKA_EC_PARAMS, NULL, 0 }, /* 4 */ { CKA_EC_POINT, NULL, 0 }, /* 5 */ { CKA_TOKEN, &val_false, sizeof(val_false) }, }; int na = sizeof(template) / sizeof(CK_ATTRIBUTE); CK_ATTRIBUTE *a; P11PROV_SLOTS_CTX *slots = NULL; CK_SLOT_ID slot = CK_UNAVAILABLE_INFORMATION; P11PROV_SESSION *session = NULL; CK_RV rv = CKR_GENERAL_ERROR; a = p11prov_obj_get_attr(key, CKA_EC_PARAMS); if (!a) { return CKR_GENERAL_ERROR; } template[4].pValue = a->pValue; template[4].ulValueLen = a->ulValueLen; a = p11prov_obj_get_attr(key, CKA_EC_POINT); if (!a) { return CKR_GENERAL_ERROR; } template[5].pValue = a->pValue; template[5].ulValueLen = a->ulValueLen; slots = p11prov_ctx_get_slots(key->ctx); if (!slots) { rv = CKR_GENERAL_ERROR; goto done; } slot = p11prov_get_default_slot(slots); if (slot == CK_UNAVAILABLE_INFORMATION) { rv = CKR_GENERAL_ERROR; goto done; } rv = p11prov_take_login_session(key->ctx, slot, &session); if (rv != CKR_OK) { goto done; } rv = p11prov_CreateObject(key->ctx, p11prov_session_handle(session), template, na, &key->handle); if (rv != CKR_OK) { goto done; } key->slotid = slot; rv = CKR_OK; done: p11prov_return_session(session); return rv; } static CK_RV p11prov_obj_store_public_key(P11PROV_OBJ *key) { int rv; P11PROV_debug("Store imported public key=%p", key); if (key->class != CKO_PUBLIC_KEY) { P11PROV_raise(key->ctx, CKR_OBJECT_HANDLE_INVALID, "Invalid key type"); return CKR_OBJECT_HANDLE_INVALID; } switch (key->data.key.type) { case CKK_RSA: rv = p11prov_store_rsa_public_key(key); break; case CKK_EC: case CKK_EC_EDWARDS: rv = p11prov_store_ec_public_key(key); break; default: P11PROV_raise(key->ctx, CKR_GENERAL_ERROR, "Unsupported key type: %08lx, should NOT happen", key->data.key.type); rv = CKR_GENERAL_ERROR; } if (rv == CKR_OK) { /* this is a real object now, add it to the pool, but do not * fail if the operation goes haywire for some reason */ (void)obj_add_to_pool(key); } return rv; } static CK_RV get_bn(const OSSL_PARAM *p, CK_ATTRIBUTE *attr) { BIGNUM *bn = NULL; int bnlen; int err = 0; CK_RV ret; if (p == NULL) { return CKR_KEY_INDIGESTIBLE; } /* FIXME: investigate if this needs to be done in constant time * See BN_FLG_CONSTTIME */ err = OSSL_PARAM_get_BN(p, &bn); if (err != RET_OSSL_OK) { return CKR_KEY_INDIGESTIBLE; } bnlen = BN_num_bytes(bn); attr->pValue = OPENSSL_malloc(bnlen); if (!attr->pValue) { ret = CKR_HOST_MEMORY; goto done; } attr->ulValueLen = BN_bn2bin(bn, attr->pValue); if (attr->ulValueLen == 0 || attr->ulValueLen > bnlen) { attr->ulValueLen = bnlen; ret = CKR_KEY_INDIGESTIBLE; goto done; } ret = CKR_OK; done: if (ret != CKR_OK) { OPENSSL_clear_free(attr->pValue, bnlen); attr->pValue = NULL; } BN_free(bn); return ret; } static CK_RV p11prov_store_rsa_private_key(P11PROV_OBJ *key, struct pool_find_ctx *findctx, const OSSL_PARAM params[]) { CK_BBOOL val_true = CK_TRUE; CK_BBOOL val_false = CK_FALSE; CK_ATTRIBUTE template[] = { { CKA_CLASS, &findctx->class, sizeof(CK_OBJECT_CLASS) }, { CKA_KEY_TYPE, &findctx->type, sizeof(CK_KEY_TYPE) }, { CKA_ID, findctx->attrs[0].pValue, findctx->attrs[0].ulValueLen }, /* 2 */ { CKA_SENSITIVE, &val_true, sizeof(val_true) }, { CKA_EXTRACTABLE, &val_false, sizeof(val_false) }, { CKA_TOKEN, &val_false, sizeof(val_false) }, /* we allow all operations as we do not know what is * the purpose of this key at import time */ { CKA_DECRYPT, &val_true, sizeof(val_true) }, { CKA_SIGN, &val_true, sizeof(val_true) }, { CKA_UNWRAP, &val_true, sizeof(val_true) }, /* public key part */ { CKA_MODULUS, NULL, 0 }, /* 9 */ { CKA_PUBLIC_EXPONENT, NULL, 0 }, /* 10 */ /* private key part */ { CKA_PRIVATE_EXPONENT, NULL, 0 }, { CKA_PRIME_1, NULL, 0 }, /* optional from here */ { CKA_PRIME_2, NULL, 0 }, { CKA_EXPONENT_1, NULL, 0 }, { CKA_EXPONENT_2, NULL, 0 }, { CKA_COEFFICIENT, NULL, 0 }, /* TODO RSA PSS Params */ }; int na = 9; /* minimum will be 12, up to 17 */ const char *required[] = { OSSL_PKEY_PARAM_RSA_N, OSSL_PKEY_PARAM_RSA_E, OSSL_PKEY_PARAM_RSA_D, }; const char *optional[] = { OSSL_PKEY_PARAM_RSA_FACTOR1, OSSL_PKEY_PARAM_RSA_FACTOR2, OSSL_PKEY_PARAM_RSA_EXPONENT1, OSSL_PKEY_PARAM_RSA_EXPONENT2, OSSL_PKEY_PARAM_RSA_COEFFICIENT1, }; const OSSL_PARAM *p; P11PROV_SLOTS_CTX *slots = NULL; CK_SLOT_ID slot = CK_UNAVAILABLE_INFORMATION; P11PROV_SESSION *session = NULL; CK_RV rv = CKR_GENERAL_ERROR; /* required params */ for (int i = 0; i < 3; i++) { p = OSSL_PARAM_locate_const(params, required[i]); rv = get_bn(p, &template[na]); if (rv != CKR_OK) { goto done; } na++; } /* optional */ for (int i = 0; i < 5; i++) { p = OSSL_PARAM_locate_const(params, optional[i]); if (p) { rv = get_bn(p, &template[na]); if (rv == CKR_OK) { na++; } } else { /* we must have all or none of the optional, * if any is missing we pretend none of them were given */ for (; i >= 0; i--) { na--; OPENSSL_clear_free(template[na].pValue, template[na].ulValueLen); } break; } } slots = p11prov_ctx_get_slots(key->ctx); if (!slots) { rv = CKR_GENERAL_ERROR; goto done; } slot = p11prov_get_default_slot(slots); if (slot == CK_UNAVAILABLE_INFORMATION) { rv = CKR_GENERAL_ERROR; goto done; } rv = p11prov_take_login_session(key->ctx, slot, &session); if (rv != CKR_OK) { goto done; } rv = p11prov_CreateObject(key->ctx, p11prov_session_handle(session), template, na, &key->handle); if (rv != CKR_OK) { goto done; } key->slotid = slot; key->class = findctx->class; key->data.key.type = findctx->type; key->data.key.size = findctx->key_size; key->data.key.bit_size = findctx->bit_size; key->attrs = OPENSSL_zalloc(sizeof(CK_ATTRIBUTE) * 3); if (!key->attrs) { rv = CKR_HOST_MEMORY; goto done; } key->numattrs = 0; /* cka_id */ rv = p11prov_copy_attr(&key->attrs[key->numattrs], &template[2]); if (rv != CKR_OK) { goto done; } key->numattrs += 1; /* steal modulus */ key->attrs[key->numattrs] = template[9]; template[9].pValue = NULL; key->numattrs += 1; /* steal public exponent */ key->attrs[key->numattrs] = template[10]; template[10].pValue = NULL; key->numattrs += 1; rv = CKR_OK; done: p11prov_return_session(session); for (int i = 9; i < na; i++) { OPENSSL_clear_free(template[i].pValue, template[i].ulValueLen); } return rv; } static CK_RV p11prov_store_ec_private_key(P11PROV_OBJ *key, struct pool_find_ctx *findctx, const OSSL_PARAM params[]) { CK_BBOOL val_true = CK_TRUE; CK_BBOOL val_false = CK_FALSE; CK_ATTRIBUTE template[] = { { CKA_CLASS, &findctx->class, sizeof(CK_OBJECT_CLASS) }, { CKA_KEY_TYPE, &findctx->type, sizeof(CK_KEY_TYPE) }, { CKA_ID, findctx->attrs[0].pValue, findctx->attrs[0].ulValueLen }, /* 2 */ { CKA_SENSITIVE, &val_true, sizeof(val_true) }, { CKA_EXTRACTABLE, &val_false, sizeof(val_false) }, { CKA_TOKEN, &val_false, sizeof(val_false) }, /* we allow all operations as we do not know what is * the purpose of this key at import time */ { CKA_DERIVE, &val_true, sizeof(val_true) }, { CKA_SIGN, &val_true, sizeof(val_true) }, /* public part */ { CKA_EC_PARAMS, findctx->attrs[1].pValue, findctx->attrs[1].ulValueLen }, /* 8 */ /* private key part */ { CKA_VALUE, NULL, 0 }, /* 9 */ }; int na = 10; const OSSL_PARAM *p; P11PROV_SLOTS_CTX *slots = NULL; CK_SLOT_ID slot = CK_UNAVAILABLE_INFORMATION; P11PROV_SESSION *session = NULL; CK_RV rv = CKR_GENERAL_ERROR; p = OSSL_PARAM_locate_const(params, OSSL_PKEY_PARAM_PRIV_KEY); rv = get_bn(p, &template[9]); if (rv != CKR_OK) { goto done; } slots = p11prov_ctx_get_slots(key->ctx); if (!slots) { rv = CKR_GENERAL_ERROR; goto done; } slot = p11prov_get_default_slot(slots); if (slot == CK_UNAVAILABLE_INFORMATION) { rv = CKR_GENERAL_ERROR; goto done; } rv = p11prov_take_login_session(key->ctx, slot, &session); if (rv != CKR_OK) { goto done; } rv = p11prov_CreateObject(key->ctx, p11prov_session_handle(session), template, na, &key->handle); if (rv != CKR_OK) { goto done; } key->slotid = slot; key->class = findctx->class; key->data.key.type = findctx->type; key->data.key.size = findctx->key_size; key->data.key.bit_size = findctx->bit_size; key->attrs = OPENSSL_zalloc(sizeof(CK_ATTRIBUTE) * findctx->numattrs); if (!key->attrs) { rv = CKR_HOST_MEMORY; goto done; } key->numattrs = 0; for (int i = 0; i < findctx->numattrs; i++) { rv = p11prov_copy_attr(&key->attrs[i], &findctx->attrs[i]); if (rv != CKR_OK) { rv = CKR_HOST_MEMORY; P11PROV_raise(key->ctx, rv, "Failed attr copy"); goto done; } key->numattrs++; } rv = CKR_OK; done: p11prov_return_session(session); OPENSSL_clear_free(template[9].pValue, template[9].ulValueLen); return rv; } static CK_RV p11prov_obj_import_private_key(P11PROV_OBJ *key, CK_KEY_TYPE type, const OSSL_PARAM params[]) { P11PROV_CTX *ctx; struct pool_find_ctx findctx = { .type = type, .class = CKO_PRIVATE_KEY, .attrs = { { 0 } }, .numattrs = MAX_ATTRS_SIZE, .found = NULL, }; CK_RV rv; ctx = p11prov_obj_get_prov_ctx(key); if (!ctx) { return CKR_GENERAL_ERROR; } switch (type) { case CKK_RSA: rv = prep_rsa_find(ctx, params, &findctx); if (rv != CKR_OK) { goto done; } break; case CKK_EC: rv = prep_ec_find(ctx, params, &findctx); if (rv != CKR_OK) { goto done; } break; case CKK_EC_EDWARDS: rv = prep_ed_find(ctx, params, &findctx); if (rv != CKR_OK) { goto done; } break; default: P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE, "Unsupported key type: %08lx", type); rv = CKR_KEY_INDIGESTIBLE; goto done; } /* The only case for private keys is an application loading a key from * a file or other mean and then asking (explicitly or implicitly) a * pkcs11-provider mechanism to use it. There is no other case because * tokens do not allow to export private keys. * * However we may have had the request to load this key before so we * still need to check if we have previously uploaded this key as a * session key before. If not we will compute a hash of the private * key to store in CKA_ID for future lockup and store it in the token * on the long lived login session. */ rv = p11prov_slot_find_obj_pool(ctx, pool_find_callback, &findctx); if (rv != CKR_OK) { P11PROV_raise(key->ctx, CKR_GENERAL_ERROR, "Failed to search pools"); rv = CKR_GENERAL_ERROR; goto done; } if (findctx.found) { rv = return_dup_key(key, findctx.found); goto done; } /* * No cached object found, create a session key on the login session so * that its handle will live long enough for multiple operations. */ switch (type) { case CKK_RSA: rv = p11prov_store_rsa_private_key(key, &findctx, params); break; case CKK_EC: case CKK_EC_EDWARDS: rv = p11prov_store_ec_private_key(key, &findctx, params); break; default: P11PROV_raise(key->ctx, CKR_GENERAL_ERROR, "Unsupported key type: %08lx, should NOT happen", type); rv = CKR_GENERAL_ERROR; } done: for (int i = 0; i < findctx.numattrs; i++) { OPENSSL_free(findctx.attrs[i].pValue); } return rv; } static CK_RV import_ec_params(P11PROV_OBJ *key, const OSSL_PARAM params[]) { P11PROV_CTX *ctx; EC_GROUP *group = NULL; const char *curve_name = NULL; int curve_nid; unsigned char *ecparams = NULL; CK_ATTRIBUTE *cka_ec_params; CK_ATTRIBUTE *cka_nid; CK_ATTRIBUTE *cka_name; CK_ATTRIBUTE tmp; int add_attrs = 0; int len; CK_RV rv; ctx = p11prov_obj_get_prov_ctx(key); if (!ctx) { return CKR_GENERAL_ERROR; } group = EC_GROUP_new_from_params(params, p11prov_ctx_get_libctx(ctx), NULL); if (!group) { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Unable to decode ec group"); rv = CKR_KEY_INDIGESTIBLE; goto done; } curve_nid = EC_GROUP_get_curve_name(group); if (curve_nid == NID_undef) { curve_name = OSSL_EC_curve_nid2name(curve_nid); if (!curve_name) { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Unknown curve"); rv = CKR_KEY_INDIGESTIBLE; goto done; } } len = i2d_ECPKParameters(group, &ecparams); if (len < 0) { P11PROV_raise(ctx, CKR_KEY_INDIGESTIBLE, "Failed to encode EC params"); rv = CKR_KEY_INDIGESTIBLE; goto done; } cka_ec_params = p11prov_obj_get_attr(key, CKA_EC_PARAMS); if (!cka_ec_params) { add_attrs += 1; } cka_nid = p11prov_obj_get_attr(key, CKA_P11PROV_CURVE_NID); if (!cka_nid) { add_attrs += 1; } cka_name = p11prov_obj_get_attr(key, CKA_P11PROV_CURVE_NAME); if (!cka_name && curve_name) { add_attrs += 1; } if (add_attrs > 0) { void *tmp_ptr; tmp_ptr = OPENSSL_realloc( key->attrs, sizeof(CK_ATTRIBUTE) * (key->numattrs + add_attrs)); if (!tmp_ptr) { rv = CKR_HOST_MEMORY; goto done; } key->attrs = tmp_ptr; } /* EC Params */ if (cka_ec_params) { OPENSSL_free(cka_ec_params->pValue); } else { cka_ec_params = &key->attrs[key->numattrs]; key->numattrs++; } cka_ec_params->type = CKA_EC_PARAMS; cka_ec_params->pValue = ecparams; ecparams = NULL; cka_ec_params->ulValueLen = len; /* Curve Nid */ if (cka_nid) { OPENSSL_free(cka_nid->pValue); } else { cka_nid = &key->attrs[key->numattrs]; key->numattrs++; } cka_nid->pValue = NULL; tmp.type = CKA_P11PROV_CURVE_NID; tmp.pValue = &curve_nid; tmp.ulValueLen = sizeof(curve_nid); rv = p11prov_copy_attr(cka_nid, &tmp); if (rv != CKR_OK) { goto done; } /* Curve name */ if (cka_name) { OPENSSL_free(cka_name->pValue); cka_name->type = CK_UNAVAILABLE_INFORMATION; cka_name->pValue = NULL; cka_name->ulValueLen = 0; } if (curve_name) { if (!cka_name) { cka_name = &key->attrs[key->numattrs]; key->numattrs++; } tmp.type = CKA_P11PROV_CURVE_NAME; tmp.pValue = (void *)curve_name; tmp.ulValueLen = strlen(curve_name) + 1; rv = p11prov_copy_attr(cka_name, &tmp); if (rv != CKR_OK) { goto done; } } /* This is geneally the first call when importing keys from OpenSSL, * so ensure the other common object parameters are correct as well */ key->data.key.type = CKK_EC; key->data.key.bit_size = EC_GROUP_order_bits(group); key->data.key.size = (key->data.key.bit_size + 7) / 8; done: OPENSSL_free(ecparams); EC_GROUP_free(group); return rv; } static CK_RV p11prov_obj_set_domain_params(P11PROV_OBJ *key, CK_KEY_TYPE type, const OSSL_PARAM params[]) { switch (type) { case CKK_EC: /* EC_PARAMS */ return import_ec_params(key, params); default: P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE, "Unsupported key type: %08lx", type); return CKR_KEY_INDIGESTIBLE; } } CK_RV p11prov_obj_import_key(P11PROV_OBJ *key, CK_KEY_TYPE type, CK_OBJECT_CLASS class, const OSSL_PARAM params[]) { /* This operation available only on new objects, can't import over an * existing one */ if (key->class != CK_UNAVAILABLE_INFORMATION) { P11PROV_raise(key->ctx, CKR_ARGUMENTS_BAD, "Non empty object"); return CKR_ARGUMENTS_BAD; } switch (class) { case CKO_PUBLIC_KEY: return p11prov_obj_import_public_key(key, type, params); case CKO_PRIVATE_KEY: return p11prov_obj_import_private_key(key, type, params); case CKO_DOMAIN_PARAMETERS: return p11prov_obj_set_domain_params(key, type, params); default: P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE, "Invalid object class or key type"); return CKR_KEY_INDIGESTIBLE; } } CK_RV p11prov_obj_set_ec_encoded_public_key(P11PROV_OBJ *key, const void *pubkey, size_t pubkey_len) { CK_RV rv; CK_ATTRIBUTE *pub; CK_ATTRIBUTE *ecpoint; CK_ATTRIBUTE new_pub; ASN1_OCTET_STRING oct; unsigned char *der = NULL; int add_attrs = 0; int len; if (key->handle != CK_P11PROV_IMPORTED_HANDLE) { /* * not a mock object, cannot set public key to a token object backed by * an actual handle. */ /* not matching, error out */ P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE, "Cannot change public key of a token object"); return CKR_KEY_INDIGESTIBLE; } if (key->class == CK_UNAVAILABLE_INFORMATION) { key->class = CKO_PUBLIC_KEY; } switch (key->data.key.type) { case CKK_EC: case CKK_EC_EDWARDS: /* check that this is a public key */ if (key->class != CKO_PUBLIC_KEY) { P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE, "Invalid Key type, not a public key"); return CKR_KEY_INDIGESTIBLE; } break; default: P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE, "Invalid Key type, not an EC/ED key"); return CKR_KEY_INDIGESTIBLE; } pub = p11prov_obj_get_attr(key, CKA_P11PROV_PUB_KEY); if (!pub) { add_attrs += 1; } ecpoint = p11prov_obj_get_attr(key, CKA_EC_POINT); if (!ecpoint) { add_attrs += 1; } if (add_attrs > 0) { void *ptr = OPENSSL_realloc( key->attrs, sizeof(CK_ATTRIBUTE) * (key->numattrs + add_attrs)); if (!ptr) { P11PROV_raise(key->ctx, CKR_HOST_MEMORY, "Failed to store key public key"); return CKR_HOST_MEMORY; } key->attrs = ptr; } if (!pub) { pub = &key->attrs[key->numattrs]; key->numattrs += 1; } else { OPENSSL_free(pub->pValue); } /* always memset as realloc does not guarantee zeroed data */ memset(pub, 0, sizeof(CK_ATTRIBUTE)); if (!ecpoint) { ecpoint = &key->attrs[key->numattrs]; key->numattrs += 1; } else { OPENSSL_free(ecpoint->pValue); } /* always memset as realloc does not guarantee zeroed data */ memset(ecpoint, 0, sizeof(CK_ATTRIBUTE)); new_pub.type = CKA_P11PROV_PUB_KEY; new_pub.pValue = (CK_VOID_PTR)pubkey; new_pub.ulValueLen = (CK_ULONG)pubkey_len; rv = p11prov_copy_attr(pub, &new_pub); if (rv != CKR_OK) { return rv; } oct.data = (unsigned char *)pubkey; oct.length = (int)pubkey_len; oct.flags = 0; len = i2d_ASN1_OCTET_STRING(&oct, &der); if (len < 0) { P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE, "Failure to encode EC point to DER"); return CKR_KEY_INDIGESTIBLE; } ecpoint->type = CKA_EC_POINT; ecpoint->pValue = der; ecpoint->ulValueLen = len; return CKR_OK; } CK_RV p11prov_obj_copy_specific_attr(P11PROV_OBJ *pub_key, P11PROV_OBJ *priv_key, CK_ATTRIBUTE_TYPE type) { CK_ATTRIBUTE *attr = NULL; CK_RV ret = CKR_OK; if (!pub_key || !priv_key) { return CKR_ARGUMENTS_BAD; } attr = p11prov_obj_get_attr(pub_key, type); if (!attr) { P11PROV_debug("Failed to fetch the specific attribute"); return CKR_GENERAL_ERROR; } ret = p11prov_copy_attr(&priv_key->attrs[priv_key->numattrs], attr); if (ret != CKR_OK) { P11PROV_raise(priv_key->ctx, ret, "Failed attr copy"); return CKR_GENERAL_ERROR; } priv_key->numattrs++; return ret; } /* creates an empty (no public point) Public EC Key, (OpenSSL paramgen * function), that will later be filled in with a public EC key obtained * by a peer (generally for ECDH, but we don't have that context in the * code) */ P11PROV_OBJ *mock_pub_ec_key(P11PROV_CTX *ctx, CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *ec_params) { P11PROV_OBJ *key; CK_RV ret; key = p11prov_obj_new(ctx, CK_UNAVAILABLE_INFORMATION, CK_P11PROV_IMPORTED_HANDLE, CK_UNAVAILABLE_INFORMATION); if (!key) { return NULL; } key->class = CKO_PUBLIC_KEY; key->data.key.type = type; /* at this stage we have EC_PARAMS and the preprocessing * function will add CKA_P11PROV_CURVE_NID and * CKA_P11PROV_CURVE_NAME */ key->attrs = OPENSSL_zalloc(KEY_EC_PARAMS * sizeof(CK_ATTRIBUTE)); if (key->attrs == NULL) { P11PROV_raise(key->ctx, CKR_HOST_MEMORY, "Failed to generate mock ec key"); p11prov_obj_free(key); return NULL; } ret = p11prov_copy_attr(&key->attrs[0], ec_params); if (ret != CKR_OK) { P11PROV_raise(key->ctx, ret, "Failed to copy mock key attribute"); p11prov_obj_free(key); return NULL; } key->numattrs++; /* verify params are ok */ ret = pre_process_ec_key_data(key); if (ret != CKR_OK) { P11PROV_raise(key->ctx, ret, "Failed to process mock key data"); p11prov_obj_free(key); return NULL; } return key; } pkcs11-provider-1.0/src/objects.h000066400000000000000000000123041475270623700167120ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _OBJECTS_H #define _OBJECTS_H /* Set the base to Vendor + 'OPP' for OpenSSL PKCS11 Provider */ #define CKA_P11PROV_BASE CKA_VENDOR_DEFINED + 0x4F5050 /* Special value for "imported key handle" */ #define CK_P11PROV_IMPORTED_HANDLE (CK_UNAVAILABLE_INFORMATION - 1) /* Objects */ CK_RV p11prov_obj_pool_init(P11PROV_CTX *ctx, CK_SLOT_ID id, P11PROV_OBJ_POOL **_pool); void p11prov_obj_pool_free(P11PROV_OBJ_POOL *pool); void p11prov_obj_pool_fork_reset(P11PROV_OBJ_POOL *pool); P11PROV_OBJ *p11prov_obj_new(P11PROV_CTX *ctx, CK_SLOT_ID slotid, CK_OBJECT_HANDLE handle, CK_OBJECT_CLASS class); P11PROV_OBJ *p11prov_obj_ref_no_cache(P11PROV_OBJ *obj); P11PROV_OBJ *p11prov_obj_ref(P11PROV_OBJ *obj); void p11prov_obj_free(P11PROV_OBJ *obj); CK_SLOT_ID p11prov_obj_get_slotid(P11PROV_OBJ *obj); CK_OBJECT_HANDLE p11prov_obj_get_handle(P11PROV_OBJ *obj); CK_OBJECT_CLASS p11prov_obj_get_class(P11PROV_OBJ *obj); CK_ATTRIBUTE *p11prov_obj_get_attr(P11PROV_OBJ *obj, CK_ATTRIBUTE_TYPE type); bool p11prov_obj_get_bool(P11PROV_OBJ *obj, CK_ATTRIBUTE_TYPE type, bool def); CK_KEY_TYPE p11prov_obj_get_key_type(P11PROV_OBJ *obj); CK_ULONG p11prov_obj_get_key_bit_size(P11PROV_OBJ *obj); CK_ULONG p11prov_obj_get_key_size(P11PROV_OBJ *obj); void p11prov_obj_to_store_reference(P11PROV_OBJ *obj, void **reference, size_t *reference_sz); P11PROV_OBJ *p11prov_obj_from_reference(const void *reference, size_t reference_sz); P11PROV_CTX *p11prov_obj_get_prov_ctx(P11PROV_OBJ *obj); P11PROV_OBJ *p11prov_obj_get_associated(P11PROV_OBJ *obj); void p11prov_obj_set_associated(P11PROV_OBJ *obj, P11PROV_OBJ *assoc); typedef CK_RV (*store_obj_callback)(void *, P11PROV_OBJ *); CK_RV p11prov_obj_from_handle(P11PROV_CTX *ctx, P11PROV_SESSION *session, CK_OBJECT_HANDLE handle, P11PROV_OBJ **object); CK_RV p11prov_obj_find(P11PROV_CTX *provctx, P11PROV_SESSION *session, CK_SLOT_ID slotid, P11PROV_URI *uri, store_obj_callback cb, void *cb_ctx); P11PROV_OBJ *p11prov_create_secret_key(P11PROV_CTX *provctx, P11PROV_SESSION *session, bool session_key, unsigned char *secret, size_t secretlen); CK_RV p11prov_derive_key(P11PROV_CTX *ctx, CK_SLOT_ID slotid, CK_MECHANISM *mechanism, CK_OBJECT_HANDLE handle, CK_ATTRIBUTE *template, CK_ULONG nattrs, P11PROV_SESSION **session, CK_OBJECT_HANDLE *key); CK_RV p11prov_obj_set_attributes(P11PROV_CTX *ctx, P11PROV_SESSION *session, P11PROV_OBJ *obj, CK_ATTRIBUTE *template, CK_ULONG tsize); const char *p11prov_obj_get_ec_group_name(P11PROV_OBJ *obj); bool p11prov_obj_get_ec_compressed(P11PROV_OBJ *obj); int p11prov_obj_export_public_key(P11PROV_OBJ *obj, CK_KEY_TYPE key_type, bool search_related, bool params_only, OSSL_CALLBACK *cb_fn, void *cb_arg); int p11prov_obj_get_ec_public_x_y(P11PROV_OBJ *obj, CK_ATTRIBUTE **pub_x, CK_ATTRIBUTE **pub_y); int p11prov_obj_get_ed_pub_key(P11PROV_OBJ *obj, CK_ATTRIBUTE **pub); CK_ATTRIBUTE *p11prov_obj_get_ec_public_raw(P11PROV_OBJ *key); P11PROV_OBJ *mock_pub_ec_key(P11PROV_CTX *ctx, CK_ATTRIBUTE_TYPE type, CK_ATTRIBUTE *ec_params); bool p11prov_obj_is_rsa_pss(P11PROV_OBJ *obj); #define OBJ_CMP_KEY_TYPE 0x00 #define OBJ_CMP_KEY_PUBLIC 0x01 #define OBJ_CMP_KEY_PRIVATE 0x02 int p11prov_obj_key_cmp(P11PROV_OBJ *obj1, P11PROV_OBJ *obj2, CK_KEY_TYPE type, int cmp_type); CK_RV p11prov_obj_import_key(P11PROV_OBJ *key, CK_KEY_TYPE type, CK_OBJECT_CLASS class, const OSSL_PARAM params[]); CK_RV p11prov_obj_set_ec_encoded_public_key(P11PROV_OBJ *key, const void *pubkey, size_t pubkey_len); CK_RV p11prov_obj_copy_specific_attr(P11PROV_OBJ *pub_key, P11PROV_OBJ *priv_key, CK_ATTRIBUTE_TYPE type); P11PROV_OBJ *p11prov_obj_find_associated(P11PROV_OBJ *obj, CK_OBJECT_CLASS class); #define ED25519 "ED25519" #define ED25519_BIT_SIZE 256 #define ED25519_BYTE_SIZE ED25519_BIT_SIZE / 8 #define ED25519_SEC_BITS 128 #define ED25519_SIG_SIZE 64 #define ED25519_EC_PARAMS \ 0x13, 0x0c, 0x65, 0x64, 0x77, 0x61, 0x72, 0x64, 0x73, 0x32, 0x35, 0x35, \ 0x31, 0x39 #define ED25519_EC_PARAMS_LEN 14 #define ED448 "ED448" #define ED448_BIT_SIZE 456 #define ED448_BYTE_SIZE ED448_BIT_SIZE / 8 #define ED448_SEC_BITS 224 #define ED448_SIG_SIZE 114 #define ED448_EC_PARAMS \ 0x13, 0x0a, 0x65, 0x64, 0x77, 0x61, 0x72, 0x64, 0x73, 0x34, 0x34, 0x38 #define ED448_EC_PARAMS_LEN 12 extern const CK_BYTE ed25519_ec_params[]; extern const CK_BYTE ed448_ec_params[]; #endif /* _OBJECTS_H */ pkcs11-provider-1.0/src/pk11_uri.c000066400000000000000000000002501475270623700167040ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "pk11_uri.h" #include #include "pk11_uri.gen.c" pkcs11-provider-1.0/src/pk11_uri.gen.c000066400000000000000000000054231475270623700174630ustar00rootroot00000000000000/* DO NOT EDIT, autogenerated from src/pk11_uri.pre */ /* Modify src/pk11_uri.pre then run make generate-code */ extern P11PROV_PK11_URI *P11PROV_PK11_URI_new(void); extern void P11PROV_PK11_URI_free(P11PROV_PK11_URI *a); extern P11PROV_PK11_URI * d2i_P11PROV_PK11_URI(P11PROV_PK11_URI **a, const unsigned char **in, long len); extern int i2d_P11PROV_PK11_URI(const P11PROV_PK11_URI *a, unsigned char **out); extern const ASN1_ITEM *P11PROV_PK11_URI_it(void); P11PROV_PK11_URI *d2i_P11PROV_PK11_URI(P11PROV_PK11_URI **a, const unsigned char **in, long len) { return (P11PROV_PK11_URI *)ASN1_item_d2i((ASN1_VALUE **)a, in, len, (P11PROV_PK11_URI_it())); } int i2d_P11PROV_PK11_URI(const P11PROV_PK11_URI *a, unsigned char **out) { return ASN1_item_i2d((const ASN1_VALUE *)a, out, (P11PROV_PK11_URI_it())); } P11PROV_PK11_URI *P11PROV_PK11_URI_new(void) { return (P11PROV_PK11_URI *)ASN1_item_new((P11PROV_PK11_URI_it())); } void P11PROV_PK11_URI_free(P11PROV_PK11_URI *a) { ASN1_item_free((ASN1_VALUE *)a, (P11PROV_PK11_URI_it())); } static const ASN1_TEMPLATE P11PROV_PK11_URI_seq_tt[] = { { (0), (0), __builtin_offsetof(P11PROV_PK11_URI, desc), "desc", (ASN1_VISIBLESTRING_it) }, { (0), (0), __builtin_offsetof(P11PROV_PK11_URI, uri), "uri", (ASN1_UTF8STRING_it) }, }; const ASN1_ITEM *P11PROV_PK11_URI_it(void) { static const ASN1_ITEM local_it = { 0x1, 16, P11PROV_PK11_URI_seq_tt, sizeof(P11PROV_PK11_URI_seq_tt) / sizeof(ASN1_TEMPLATE), ((void *)0), sizeof(P11PROV_PK11_URI), "P11PROV_PK11_URI" }; return &local_it; } extern int PEM_write_bio_P11PROV_PK11_URI(BIO *out, const P11PROV_PK11_URI *x); int PEM_write_bio_P11PROV_PK11_URI(BIO *out, const P11PROV_PK11_URI *x) { return PEM_ASN1_write_bio((i2d_of_void *)i2d_P11PROV_PK11_URI, P11PROV_PEM_LABEL, out, x, ((void *)0), ((void *)0), 0, ((void *)0), ((void *)0)); } extern P11PROV_PK11_URI *PEM_read_bio_P11PROV_PK11_URI(BIO *out, P11PROV_PK11_URI **x, pem_password_cb *cb, void *u); P11PROV_PK11_URI *PEM_read_bio_P11PROV_PK11_URI(BIO *bp, P11PROV_PK11_URI **x, pem_password_cb *cb, void *u) { return PEM_ASN1_read_bio((d2i_of_void *)d2i_P11PROV_PK11_URI, P11PROV_PEM_LABEL, bp, (void **)x, cb, u); } pkcs11-provider-1.0/src/pk11_uri.h000066400000000000000000000017411475270623700167170ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _PK11_URI_H #define _PK11_URI_H #include #define P11PROV_DER_STRUCTURE "pk11-uri" #define P11PROV_PEM_LABEL "PKCS#11 PROVIDER URI" #define P11PROV_DESCS_URI_FILE "PKCS#11 Provider URI v1.0" typedef struct { ASN1_VISIBLESTRING *desc; ASN1_UTF8STRING *uri; } P11PROV_PK11_URI; extern P11PROV_PK11_URI *P11PROV_PK11_URI_new(void); extern void P11PROV_PK11_URI_free(P11PROV_PK11_URI *a); extern P11PROV_PK11_URI * d2i_P11PROV_PK11_URI(P11PROV_PK11_URI **a, const unsigned char **in, long len); extern P11PROV_PK11_URI *PEM_read_bio_P11PROV_PK11_URI(BIO *out, P11PROV_PK11_URI **x, pem_password_cb *cb, void *u); extern int PEM_write_bio_P11PROV_PK11_URI(BIO *out, const P11PROV_PK11_URI *x); #endif pkcs11-provider-1.0/src/pk11_uri.pre000066400000000000000000000014251475270623700172550ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include #include BEGIN: DECLARE_ASN1_FUNCTIONS(P11PROV_PK11_URI) IMPLEMENT_ASN1_FUNCTIONS(P11PROV_PK11_URI) ASN1_SEQUENCE(P11PROV_PK11_URI) = { ASN1_SIMPLE(P11PROV_PK11_URI, desc, ASN1_VISIBLESTRING), ASN1_SIMPLE(P11PROV_PK11_URI, uri, ASN1_UTF8STRING), } ASN1_SEQUENCE_END(P11PROV_PK11_URI) DECLARE_PEM_write_bio(P11PROV_PK11_URI, P11PROV_PK11_URI) IMPLEMENT_PEM_write_bio(P11PROV_PK11_URI, P11PROV_PK11_URI, P11PROV_PEM_LABEL, P11PROV_PK11_URI) DECLARE_PEM_read_bio(P11PROV_PK11_URI, P11PROV_PK11_URI) IMPLEMENT_PEM_read_bio(P11PROV_PK11_URI, P11PROV_PK11_URI, P11PROV_PEM_LABEL, P11PROV_PK11_URI) pkcs11-provider-1.0/src/pkcs11.h000066400000000000000000002500261475270623700163700ustar00rootroot00000000000000/* This file is in the Public Domain */ #ifndef _PD_PKCS11_ #define _PD_PKCS11_ #define CRYPTOKI_VERSION_MAJOR 3 #define CRYPTOKI_VERSION_MINOR 1 #define CRYPTOKI_VERSION_AMENDMENT 0 /* Basic types */ typedef unsigned char CK_BBOOL; typedef unsigned char CK_BYTE; typedef unsigned char CK_CHAR; typedef unsigned char CK_UTF8CHAR; typedef unsigned long int CK_ULONG; typedef CK_BBOOL * CK_BBOOL_PTR; typedef CK_BYTE * CK_BYTE_PTR; typedef CK_CHAR * CK_CHAR_PTR; typedef CK_UTF8CHAR * CK_UTF8CHAR_PTR; typedef CK_ULONG * CK_ULONG_PTR; /* Basic defines */ #define NULL_PTR ((void *)0) typedef void * CK_VOID_PTR; typedef void ** CK_VOID_PTR_PTR; #define CK_EFFECTIVELY_INFINITE 0UL #define CK_UNAVAILABLE_INFORMATION ~0UL #define CK_INVALID_HANDLE 0UL #define CK_TRUE 1 #define CK_FALSE 0 /* CK_ types in alphabetical order */ #define ULONGDEF(__name__) \ typedef CK_ULONG __name__; \ typedef __name__ * __name__ ## _PTR; ULONGDEF(CK_ATTRIBUTE_TYPE); ULONGDEF(CK_CERTIFICATE_CATEGORY); ULONGDEF(CK_CERTIFICATE_TYPE); ULONGDEF(CK_EC_KDF_TYPE); ULONGDEF(CK_EXTRACT_PARAMS); ULONGDEF(CK_FLAGS); ULONGDEF(CK_GENERATOR_FUNCTION); ULONGDEF(CK_HSS_LEVELS); ULONGDEF(CK_HW_FEATURE_TYPE); ULONGDEF(CK_JAVA_MIDP_SECURITY_DOMAIN); ULONGDEF(CK_KEY_TYPE); ULONGDEF(CK_LMS_TYPE); ULONGDEF(CK_LMOTS_TYPE); ULONGDEF(CK_MAC_GENERAL_PARAMS); ULONGDEF(CK_MECHANISM_TYPE); ULONGDEF(CK_NOTIFICATION); ULONGDEF(CK_OBJECT_CLASS); ULONGDEF(CK_OBJECT_HANDLE); ULONGDEF(CK_OTP_PARAM_TYPE); ULONGDEF(CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE); ULONGDEF(CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE); ULONGDEF(CK_PRF_DATA_TYPE); ULONGDEF(CK_PROFILE_ID); ULONGDEF(CK_RC2_PARAMS); ULONGDEF(CK_RSA_PKCS_MGF_TYPE); ULONGDEF(CK_RSA_PKCS_OAEP_SOURCE_TYPE); ULONGDEF(CK_RV); ULONGDEF(CK_SESSION_HANDLE); ULONGDEF(CK_SLOT_ID); ULONGDEF(CK_SP800_108_DKM_LENGTH_METHOD); ULONGDEF(CK_STATE); ULONGDEF(CK_USER_TYPE); ULONGDEF(CK_X2RATCHET_KDF_TYPE); ULONGDEF(CK_X3DH_KDF_TYPE); ULONGDEF(CK_X9_42_DH_KDF_TYPE); ULONGDEF(CK_XEDDSA_HASH_TYPE); /* domain specific values and constants */ /* CK (certificate) */ #define CK_CERTIFICATE_CATEGORY_UNSPECIFIED 0UL #define CK_CERTIFICATE_CATEGORY_TOKEN_USER 1UL #define CK_CERTIFICATE_CATEGORY_AUTHORITY 2UL #define CK_CERTIFICATE_CATEGORY_OTHER_ENTITY 3UL /* CK (OTP) */ #define CK_OTP_VALUE 0UL #define CK_OTP_PIN 1UL #define CK_OTP_CHALLENGE 2UL #define CK_OTP_TIME 3UL #define CK_OTP_COUNTER 4UL #define CK_OTP_FLAGS 5UL #define CK_OTP_OUTPUT_LENGTH 6UL #define CK_OTP_OUTPUT_FORMAT 7UL /* CK (OTP format) */ #define CK_OTP_FORMAT_DECIMAL 0UL #define CK_OTP_FORMAT_HEXADECIMAL 1UL #define CK_OTP_FORMAT_ALPHANUMERIC 2UL #define CK_OTP_FORMAT_BINARY 3UL /* CK (OTP requirement) */ #define CK_OTP_PARAM_IGNORED 0UL #define CK_OTP_PARAM_OPTIONAL 1UL #define CK_OTP_PARAM_MANDATORY 2UL /* CK (security) */ #define CK_SECURITY_DOMAIN_UNSPECIFIED 0UL #define CK_SECURITY_DOMAIN_MANUFACTURER 1UL #define CK_SECURITY_DOMAIN_OPERATOR 2UL #define CK_SECURITY_DOMAIN_THIRD_PARTY 3UL /* CK (SP800 KDF) */ #define CK_SP800_108_ITERATION_VARIABLE 0x00000001UL #define CK_SP800_108_OPTIONAL_COUNTER 0x00000002UL #define CK_SP800_108_COUNTER 0x00000002UL #define CK_SP800_108_DKM_LENGTH 0x00000003UL #define CK_SP800_108_BYTE_ARRAY 0x00000004UL /* CK (SP800 DKM) */ #define CK_SP800_108_DKM_LENGTH_SUM_OF_KEYS 0x00000001UL #define CK_SP800_108_DKM_LENGTH_SUM_OF_SEGMENTS 0x00000002UL /* CKA */ #define CKA_CLASS 0x00000000UL #define CKA_TOKEN 0x00000001UL #define CKA_PRIVATE 0x00000002UL #define CKA_LABEL 0x00000003UL #define CKA_UNIQUE_ID 0x00000004UL #define CKA_APPLICATION 0x00000010UL #define CKA_VALUE 0x00000011UL #define CKA_OBJECT_ID 0x00000012UL #define CKA_CERTIFICATE_TYPE 0x00000080UL #define CKA_ISSUER 0x00000081UL #define CKA_SERIAL_NUMBER 0x00000082UL #define CKA_AC_ISSUER 0x00000083UL #define CKA_OWNER 0x00000084UL #define CKA_ATTR_TYPES 0x00000085UL #define CKA_TRUSTED 0x00000086UL #define CKA_CERTIFICATE_CATEGORY 0x00000087UL #define CKA_JAVA_MIDP_SECURITY_DOMAIN 0x00000088UL #define CKA_URL 0x00000089UL #define CKA_HASH_OF_SUBJECT_PUBLIC_KEY 0x0000008AUL #define CKA_HASH_OF_ISSUER_PUBLIC_KEY 0x0000008BUL #define CKA_NAME_HASH_ALGORITHM 0x0000008CUL #define CKA_CHECK_VALUE 0x00000090UL #define CKA_KEY_TYPE 0x00000100UL #define CKA_SUBJECT 0x00000101UL #define CKA_ID 0x00000102UL #define CKA_SENSITIVE 0x00000103UL #define CKA_ENCRYPT 0x00000104UL #define CKA_DECRYPT 0x00000105UL #define CKA_WRAP 0x00000106UL #define CKA_UNWRAP 0x00000107UL #define CKA_SIGN 0x00000108UL #define CKA_SIGN_RECOVER 0x00000109UL #define CKA_VERIFY 0x0000010AUL #define CKA_VERIFY_RECOVER 0x0000010BUL #define CKA_DERIVE 0x0000010CUL #define CKA_START_DATE 0x00000110UL #define CKA_END_DATE 0x00000111UL #define CKA_MODULUS 0x00000120UL #define CKA_MODULUS_BITS 0x00000121UL #define CKA_PUBLIC_EXPONENT 0x00000122UL #define CKA_PRIVATE_EXPONENT 0x00000123UL #define CKA_PRIME_1 0x00000124UL #define CKA_PRIME_2 0x00000125UL #define CKA_EXPONENT_1 0x00000126UL #define CKA_EXPONENT_2 0x00000127UL #define CKA_COEFFICIENT 0x00000128UL #define CKA_PUBLIC_KEY_INFO 0x00000129UL #define CKA_PRIME 0x00000130UL #define CKA_SUBPRIME 0x00000131UL #define CKA_BASE 0x00000132UL #define CKA_PRIME_BITS 0x00000133UL #define CKA_SUBPRIME_BITS 0x00000134UL #define CKA_SUB_PRIME_BITS 0x00000134UL #define CKA_VALUE_BITS 0x00000160UL #define CKA_VALUE_LEN 0x00000161UL #define CKA_EXTRACTABLE 0x00000162UL #define CKA_LOCAL 0x00000163UL #define CKA_NEVER_EXTRACTABLE 0x00000164UL #define CKA_ALWAYS_SENSITIVE 0x00000165UL #define CKA_KEY_GEN_MECHANISM 0x00000166UL #define CKA_MODIFIABLE 0x00000170UL #define CKA_COPYABLE 0x00000171UL #define CKA_DESTROYABLE 0x00000172UL #define CKA_EC_PARAMS 0x00000180UL #define CKA_EC_POINT 0x00000181UL #define CKA_ALWAYS_AUTHENTICATE 0x00000202UL #define CKA_WRAP_WITH_TRUSTED 0x00000210UL #define CKA_OTP_FORMAT 0x00000220UL #define CKA_OTP_LENGTH 0x00000221UL #define CKA_OTP_TIME_INTERVAL 0x00000222UL #define CKA_OTP_USER_FRIENDLY_MODE 0x00000223UL #define CKA_OTP_CHALLENGE_REQUIREMENT 0x00000224UL #define CKA_OTP_TIME_REQUIREMENT 0x00000225UL #define CKA_OTP_COUNTER_REQUIREMENT 0x00000226UL #define CKA_OTP_PIN_REQUIREMENT 0x00000227UL #define CKA_OTP_COUNTER 0x0000022EUL #define CKA_OTP_TIME 0x0000022FUL #define CKA_OTP_USER_IDENTIFIER 0x0000022AUL #define CKA_OTP_SERVICE_IDENTIFIER 0x0000022BUL #define CKA_OTP_SERVICE_LOGO 0x0000022CUL #define CKA_OTP_SERVICE_LOGO_TYPE 0x0000022DUL #define CKA_GOSTR3410_PARAMS 0x00000250UL #define CKA_GOSTR3411_PARAMS 0x00000251UL #define CKA_GOST28147_PARAMS 0x00000252UL #define CKA_HW_FEATURE_TYPE 0x00000300UL #define CKA_RESET_ON_INIT 0x00000301UL #define CKA_HAS_RESET 0x00000302UL #define CKA_PIXEL_X 0x00000400UL #define CKA_PIXEL_Y 0x00000401UL #define CKA_RESOLUTION 0x00000402UL #define CKA_CHAR_ROWS 0x00000403UL #define CKA_CHAR_COLUMNS 0x00000404UL #define CKA_COLOR 0x00000405UL #define CKA_BITS_PER_PIXEL 0x00000406UL #define CKA_CHAR_SETS 0x00000480UL #define CKA_ENCODING_METHODS 0x00000481UL #define CKA_MIME_TYPES 0x00000482UL #define CKA_MECHANISM_TYPE 0x00000500UL #define CKA_REQUIRED_CMS_ATTRIBUTES 0x00000501UL #define CKA_DEFAULT_CMS_ATTRIBUTES 0x00000502UL #define CKA_SUPPORTED_CMS_ATTRIBUTES 0x00000503UL #define CKA_PROFILE_ID 0x00000601UL #define CKA_X2RATCHET_BAG 0x00000602UL #define CKA_X2RATCHET_BAGSIZE 0x00000603UL #define CKA_X2RATCHET_BOBS1STMSG 0x00000604UL #define CKA_X2RATCHET_CKR 0x00000605UL #define CKA_X2RATCHET_CKS 0x00000606UL #define CKA_X2RATCHET_DHP 0x00000607UL #define CKA_X2RATCHET_DHR 0x00000608UL #define CKA_X2RATCHET_DHS 0x00000609UL #define CKA_X2RATCHET_HKR 0x0000060AUL #define CKA_X2RATCHET_HKS 0x0000060BUL #define CKA_X2RATCHET_ISALICE 0x0000060CUL #define CKA_X2RATCHET_NHKR 0x0000060DUL #define CKA_X2RATCHET_NHKS 0x0000060EUL #define CKA_X2RATCHET_NR 0x0000060FUL #define CKA_X2RATCHET_NS 0x00000610UL #define CKA_X2RATCHET_PNS 0x00000611UL #define CKA_X2RATCHET_RK 0x00000612UL #define CKA_HSS_LEVELS 0x00000617UL #define CKA_HSS_LMS_TYPE 0x00000618UL #define CKA_HSS_LMOTS_TYPE 0x00000619UL #define CKA_HSS_LMS_TYPES 0x0000061AUL #define CKA_HSS_LMOTS_TYPES 0x0000061BUL #define CKA_HSS_KEYS_REMAINING 0x0000061CUL #define CKA_VENDOR_DEFINED 0x80000000UL /* Array attributes */ #define CKA_WRAP_TEMPLATE 0x40000211UL #define CKA_UNWRAP_TEMPLATE 0x40000212UL #define CKA_DERIVE_TEMPLATE 0x40000213UL #define CKA_ALLOWED_MECHANISMS 0x40000600UL /* Deprecated */ #ifdef PKCS11_DEPRECATED #define CKA_ECDSA_PARAMS 0x00000180UL #define CKA_SECONDARY_AUTH 0x00000200UL #define CKA_AUTH_PIN_FLAGS 0x00000201UL #endif /* CKC */ #define CKC_X_509 0x00000000UL #define CKC_X_509_ATTR_CERT 0x00000001UL #define CKC_WTLS 0x00000002UL #define CKC_VENDOR_DEFINED 0x80000000UL /* CKD */ #define CKD_NULL 0x00000001UL #define CKD_SHA1_KDF 0x00000002UL #define CKD_SHA1_KDF_ASN1 0x00000003UL #define CKD_SHA1_KDF_CONCATENATE 0x00000004UL #define CKD_SHA224_KDF 0x00000005UL #define CKD_SHA256_KDF 0x00000006UL #define CKD_SHA384_KDF 0x00000007UL #define CKD_SHA512_KDF 0x00000008UL #define CKD_CPDIVERSIFY_KDF 0x00000009UL #define CKD_SHA3_224_KDF 0x0000000AUL #define CKD_SHA3_256_KDF 0x0000000BUL #define CKD_SHA3_384_KDF 0x0000000CUL #define CKD_SHA3_512_KDF 0x0000000DUL #define CKD_SHA1_KDF_SP800 0x0000000EUL #define CKD_SHA224_KDF_SP800 0x0000000FUL #define CKD_SHA256_KDF_SP800 0x00000010UL #define CKD_SHA384_KDF_SP800 0x00000011UL #define CKD_SHA512_KDF_SP800 0x00000012UL #define CKD_SHA3_224_KDF_SP800 0x00000013UL #define CKD_SHA3_256_KDF_SP800 0x00000014UL #define CKD_SHA3_384_KDF_SP800 0x00000015UL #define CKD_SHA3_512_KDF_SP800 0x00000016UL #define CKD_BLAKE2B_160_KDF 0x00000017UL #define CKD_BLAKE2B_256_KDF 0x00000018UL #define CKD_BLAKE2B_384_KDF 0x00000019UL #define CKD_BLAKE2B_512_KDF 0x0000001AUL /* CFK (array attributes) */ #define CKF_ARRAY_ATTRIBUTE 0x40000000UL /* CKF (capabilities) */ #define CKF_LIBRARY_CANT_CREATE_OS_THREADS 0x00000001UL #define CKF_OS_LOCKING_OK 0x00000002UL /* CKF (HKDF) */ #define CKF_HKDF_SALT_NULL 0x00000001UL #define CKF_HKDF_SALT_DATA 0x00000002UL #define CKF_HKDF_SALT_KEY 0x00000004UL /* CKF (interface) */ #define CKF_INTERFACE_FORK_SAFE 0x00000001UL /* CKF (mechanism) */ #define CKF_HW 0x00000001UL #define CKF_MESSAGE_ENCRYPT 0x00000002UL #define CKF_MESSAGE_DECRYPT 0x00000004UL #define CKF_MESSAGE_SIGN 0x00000008UL #define CKF_MESSAGE_VERIFY 0x00000010UL #define CKF_MULTI_MESSAGE 0x00000020UL #define CKF_MULTI_MESSGE 0x00000020UL #define CKF_FIND_OBJECTS 0x00000040UL #define CKF_ENCRYPT 0x00000100UL #define CKF_DECRYPT 0x00000200UL #define CKF_DIGEST 0x00000400UL #define CKF_SIGN 0x00000800UL #define CKF_SIGN_RECOVER 0x00001000UL #define CKF_VERIFY 0x00002000UL #define CKF_VERIFY_RECOVER 0x00004000UL #define CKF_GENERATE 0x00008000UL #define CKF_GENERATE_KEY_PAIR 0x00010000UL #define CKF_WRAP 0x00020000UL #define CKF_UNWRAP 0x00040000UL #define CKF_DERIVE 0x00080000UL #define CKF_EC_F_P 0x00100000UL #define CKF_EC_F_2M 0x00200000UL #define CKF_EC_ECPARAMETERS 0x00400000UL #define CKF_EC_OID 0x00800000UL #define CKF_EC_UNCOMPRESS 0x01000000UL #define CKF_EC_COMPRESS 0x02000000UL #define CKF_EC_CURVENAME 0x04000000UL #define CKF_EXTENSION 0x80000000UL /* Deprecated */ #ifdef PKCS11_DEPRECATED #define CKF_EC_NAMEDCURVE 0x00800000U #endif /* CKF (message) */ #define CKF_END_OF_MESSAGE 0x00000001UL /* CKF (OTP) */ #define CKF_NEXT_OTP 0x00000001UL #define CKF_EXCLUDE_TIME 0x00000002UL #define CKF_EXCLUDE_COUNTER 0x00000004UL #define CKF_EXCLUDE_CHALLENGE 0x00000008UL #define CKF_EXCLUDE_PIN 0x00000010UL #define CKF_USER_FRIENDLY_OTP 0x00000020UL /* CKF (paramters to functions) */ #define CKF_DONT_BLOCK 1 /* CKF (session) */ #define CKF_RW_SESSION 0x00000002UL #define CKF_SERIAL_SESSION 0x00000004UL /* CFK (slot) */ #define CKF_TOKEN_PRESENT 0x00000001UL #define CKF_REMOVABLE_DEVICE 0x00000002UL #define CKF_HW_SLOT 0x00000004UL /* CKF (token) */ #define CKF_RNG 0x00000001UL #define CKF_WRITE_PROTECTED 0x00000002UL #define CKF_LOGIN_REQUIRED 0x00000004UL #define CKF_USER_PIN_INITIALIZED 0x00000008UL #define CKF_RESTORE_KEY_NOT_NEEDED 0x00000020UL #define CKF_CLOCK_ON_TOKEN 0x00000040UL #define CKF_PROTECTED_AUTHENTICATION_PATH 0x00000100UL #define CKF_DUAL_CRYPTO_OPERATIONS 0x00000200UL #define CKF_TOKEN_INITIALIZED 0x00000400UL #define CKF_SECONDARY_AUTHENTICATION 0x00000800UL #define CKF_USER_PIN_COUNT_LOW 0x00010000UL #define CKF_USER_PIN_FINAL_TRY 0x00020000UL #define CKF_USER_PIN_LOCKED 0x00040000UL #define CKF_USER_PIN_TO_BE_CHANGED 0x00080000UL #define CKF_SO_PIN_COUNT_LOW 0x00100000UL #define CKF_SO_PIN_FINAL_TRY 0x00200000UL #define CKF_SO_PIN_LOCKED 0x00400000UL #define CKF_SO_PIN_TO_BE_CHANGED 0x00800000UL #define CKF_ERROR_STATE 0x01000000UL /* CKG (GCM) */ #define CKG_NO_GENERATE 0x00000000UL #define CKG_GENERATE 0x00000001UL #define CKG_GENERATE_COUNTER 0x00000002UL #define CKG_GENERATE_RANDOM 0x00000003UL #define CKG_GENERATE_COUNTER_XOR 0x00000004UL /* CKG (MFG) */ #define CKG_MGF1_SHA1 0x00000001UL #define CKG_MGF1_SHA256 0x00000002UL #define CKG_MGF1_SHA384 0x00000003UL #define CKG_MGF1_SHA512 0x00000004UL #define CKG_MGF1_SHA224 0x00000005UL #define CKG_MGF1_SHA3_224 0x00000006UL #define CKG_MGF1_SHA3_256 0x00000007UL #define CKG_MGF1_SHA3_384 0x00000008UL #define CKG_MGF1_SHA3_512 0x00000009UL /* CKH */ #define CKH_MONOTONIC_COUNTER 0x00000001UL #define CKH_CLOCK 0x00000002UL #define CKH_USER_INTERFACE 0x00000003UL #define CKH_VENDOR_DEFINED 0x80000000UL /* CKK */ #define CKK_RSA 0x00000000UL #define CKK_DSA 0x00000001UL #define CKK_DH 0x00000002UL #define CKK_EC 0x00000003UL #define CKK_X9_42_DH 0x00000004UL #define CKK_KEA 0x00000005UL #define CKK_GENERIC_SECRET 0x00000010UL #define CKK_RC2 0x00000011UL #define CKK_RC4 0x00000012UL #define CKK_DES 0x00000013UL #define CKK_DES2 0x00000014UL #define CKK_DES3 0x00000015UL #define CKK_CAST 0x00000016UL #define CKK_CAST3 0x00000017UL #define CKK_CAST128 0x00000018UL #define CKK_RC5 0x00000019UL #define CKK_IDEA 0x0000001AUL #define CKK_SKIPJACK 0x0000001BUL #define CKK_BATON 0x0000001CUL #define CKK_JUNIPER 0x0000001DUL #define CKK_CDMF 0x0000001EUL #define CKK_AES 0x0000001FUL #define CKK_BLOWFISH 0x00000020UL #define CKK_TWOFISH 0x00000021UL #define CKK_SECURID 0x00000022UL #define CKK_HOTP 0x00000023UL #define CKK_ACTI 0x00000024UL #define CKK_CAMELLIA 0x00000025UL #define CKK_ARIA 0x00000026UL #define CKK_MD5_HMAC 0x00000027UL #define CKK_SHA_1_HMAC 0x00000028UL #define CKK_RIPEMD128_HMAC 0x00000029UL #define CKK_RIPEMD160_HMAC 0x0000002AUL #define CKK_SHA256_HMAC 0x0000002BUL #define CKK_SHA384_HMAC 0x0000002CUL #define CKK_SHA512_HMAC 0x0000002DUL #define CKK_SHA224_HMAC 0x0000002EUL #define CKK_SEED 0x0000002FUL #define CKK_GOSTR3410 0x00000030UL #define CKK_GOSTR3411 0x00000031UL #define CKK_GOST28147 0x00000032UL #define CKK_CHACHA20 0x00000033UL #define CKK_POLY1305 0x00000034UL #define CKK_AES_XTS 0x00000035UL #define CKK_SHA3_224_HMAC 0x00000036UL #define CKK_SHA3_256_HMAC 0x00000037UL #define CKK_SHA3_384_HMAC 0x00000038UL #define CKK_SHA3_512_HMAC 0x00000039UL #define CKK_BLAKE2B_160_HMAC 0x0000003AUL #define CKK_BLAKE2B_256_HMAC 0x0000003BUL #define CKK_BLAKE2B_384_HMAC 0x0000003CUL #define CKK_BLAKE2B_512_HMAC 0x0000003DUL #define CKK_SALSA20 0x0000003EUL #define CKK_X2RATCHET 0x0000003FUL #define CKK_EC_EDWARDS 0x00000040UL #define CKK_EC_MONTGOMERY 0x00000041UL #define CKK_HKDF 0x00000042UL #define CKK_SHA512_224_HMAC 0x00000043UL #define CKK_SHA512_256_HMAC 0x00000044UL #define CKK_SHA512_T_HMAC 0x00000045UL #define CKK_HSS 0x00000046UL #define CKK_VENDOR_DEFINED 0x80000000UL /* Deprecated */ #ifdef PKCS11_DEPRECATED #define CKK_ECDSA 0x00000003UL #define CKK_CAST5 0x00000018UL #endif /* CKM */ #define CKM_RSA_PKCS_KEY_PAIR_GEN 0x00000000UL #define CKM_RSA_PKCS 0x00000001UL #define CKM_RSA_9796 0x00000002UL #define CKM_RSA_X_509 0x00000003UL #define CKM_MD2_RSA_PKCS 0x00000004UL #define CKM_MD5_RSA_PKCS 0x00000005UL #define CKM_SHA1_RSA_PKCS 0x00000006UL #define CKM_RIPEMD128_RSA_PKCS 0x00000007UL #define CKM_RIPEMD160_RSA_PKCS 0x00000008UL #define CKM_RSA_PKCS_OAEP 0x00000009UL #define CKM_RSA_X9_31_KEY_PAIR_GEN 0x0000000AUL #define CKM_RSA_X9_31 0x0000000BUL #define CKM_SHA1_RSA_X9_31 0x0000000CUL #define CKM_RSA_PKCS_PSS 0x0000000DUL #define CKM_SHA1_RSA_PKCS_PSS 0x0000000EUL #define CKM_DSA_KEY_PAIR_GEN 0x00000010UL #define CKM_DSA 0x00000011UL #define CKM_DSA_SHA1 0x00000012UL #define CKM_DSA_SHA224 0x00000013UL #define CKM_DSA_SHA256 0x00000014UL #define CKM_DSA_SHA384 0x00000015UL #define CKM_DSA_SHA512 0x00000016UL #define CKM_DSA_SHA3_224 0x00000018UL #define CKM_DSA_SHA3_256 0x00000019UL #define CKM_DSA_SHA3_384 0x0000001AUL #define CKM_DSA_SHA3_512 0x0000001BUL #define CKM_DH_PKCS_KEY_PAIR_GEN 0x00000020UL #define CKM_DH_PKCS_DERIVE 0x00000021UL #define CKM_X9_42_DH_KEY_PAIR_GEN 0x00000030UL #define CKM_X9_42_DH_DERIVE 0x00000031UL #define CKM_X9_42_DH_HYBRID_DERIVE 0x00000032UL #define CKM_X9_42_MQV_DERIVE 0x00000033UL #define CKM_SHA256_RSA_PKCS 0x00000040UL #define CKM_SHA384_RSA_PKCS 0x00000041UL #define CKM_SHA512_RSA_PKCS 0x00000042UL #define CKM_SHA256_RSA_PKCS_PSS 0x00000043UL #define CKM_SHA384_RSA_PKCS_PSS 0x00000044UL #define CKM_SHA512_RSA_PKCS_PSS 0x00000045UL #define CKM_SHA224_RSA_PKCS 0x00000046UL #define CKM_SHA224_RSA_PKCS_PSS 0x00000047UL #define CKM_SHA512_224 0x00000048UL #define CKM_SHA512_224_HMAC 0x00000049UL #define CKM_SHA512_224_HMAC_GENERAL 0x0000004AUL #define CKM_SHA512_224_KEY_DERIVATION 0x0000004BUL #define CKM_SHA512_256 0x0000004CUL #define CKM_SHA512_256_HMAC 0x0000004DUL #define CKM_SHA512_256_HMAC_GENERAL 0x0000004EUL #define CKM_SHA512_256_KEY_DERIVATION 0x0000004FUL #define CKM_SHA512_T 0x00000050UL #define CKM_SHA512_T_HMAC 0x00000051UL #define CKM_SHA512_T_HMAC_GENERAL 0x00000052UL #define CKM_SHA512_T_KEY_DERIVATION 0x00000053UL #define CKM_SHA3_256_RSA_PKCS 0x00000060UL #define CKM_SHA3_384_RSA_PKCS 0x00000061UL #define CKM_SHA3_512_RSA_PKCS 0x00000062UL #define CKM_SHA3_256_RSA_PKCS_PSS 0x00000063UL #define CKM_SHA3_384_RSA_PKCS_PSS 0x00000064UL #define CKM_SHA3_512_RSA_PKCS_PSS 0x00000065UL #define CKM_SHA3_224_RSA_PKCS 0x00000066UL #define CKM_SHA3_224_RSA_PKCS_PSS 0x00000067UL #define CKM_RC2_KEY_GEN 0x00000100UL #define CKM_RC2_ECB 0x00000101UL #define CKM_RC2_CBC 0x00000102UL #define CKM_RC2_MAC 0x00000103UL #define CKM_RC2_MAC_GENERAL 0x00000104UL #define CKM_RC2_CBC_PAD 0x00000105UL #define CKM_RC4_KEY_GEN 0x00000110UL #define CKM_RC4 0x00000111UL #define CKM_DES_KEY_GEN 0x00000120UL #define CKM_DES_ECB 0x00000121UL #define CKM_DES_CBC 0x00000122UL #define CKM_DES_MAC 0x00000123UL #define CKM_DES_MAC_GENERAL 0x00000124UL #define CKM_DES_CBC_PAD 0x00000125UL #define CKM_DES2_KEY_GEN 0x00000130UL #define CKM_DES3_KEY_GEN 0x00000131UL #define CKM_DES3_ECB 0x00000132UL #define CKM_DES3_CBC 0x00000133UL #define CKM_DES3_MAC 0x00000134UL #define CKM_DES3_MAC_GENERAL 0x00000135UL #define CKM_DES3_CBC_PAD 0x00000136UL #define CKM_DES3_CMAC_GENERAL 0x00000137UL #define CKM_DES3_CMAC 0x00000138UL #define CKM_CDMF_KEY_GEN 0x00000140UL #define CKM_CDMF_ECB 0x00000141UL #define CKM_CDMF_CBC 0x00000142UL #define CKM_CDMF_MAC 0x00000143UL #define CKM_CDMF_MAC_GENERAL 0x00000144UL #define CKM_CDMF_CBC_PAD 0x00000145UL #define CKM_DES_OFB64 0x00000150UL #define CKM_DES_OFB8 0x00000151UL #define CKM_DES_CFB64 0x00000152UL #define CKM_DES_CFB8 0x00000153UL #define CKM_MD2 0x00000200UL #define CKM_MD2_HMAC 0x00000201UL #define CKM_MD2_HMAC_GENERAL 0x00000202UL #define CKM_MD5 0x00000210UL #define CKM_MD5_HMAC 0x00000211UL #define CKM_MD5_HMAC_GENERAL 0x00000212UL #define CKM_SHA_1 0x00000220UL #define CKM_SHA_1_HMAC 0x00000221UL #define CKM_SHA_1_HMAC_GENERAL 0x00000222UL #define CKM_RIPEMD128 0x00000230UL #define CKM_RIPEMD128_HMAC 0x00000231UL #define CKM_RIPEMD128_HMAC_GENERAL 0x00000232UL #define CKM_RIPEMD160 0x00000240UL #define CKM_RIPEMD160_HMAC 0x00000241UL #define CKM_RIPEMD160_HMAC_GENERAL 0x00000242UL #define CKM_SHA256 0x00000250UL #define CKM_SHA256_HMAC 0x00000251UL #define CKM_SHA256_HMAC_GENERAL 0x00000252UL #define CKM_SHA224 0x00000255UL #define CKM_SHA224_HMAC 0x00000256UL #define CKM_SHA224_HMAC_GENERAL 0x00000257UL #define CKM_SHA384 0x00000260UL #define CKM_SHA384_HMAC 0x00000261UL #define CKM_SHA384_HMAC_GENERAL 0x00000262UL #define CKM_SHA512 0x00000270UL #define CKM_SHA512_HMAC 0x00000271UL #define CKM_SHA512_HMAC_GENERAL 0x00000272UL #define CKM_SECURID_KEY_GEN 0x00000280UL #define CKM_SECURID 0x00000282UL #define CKM_HOTP_KEY_GEN 0x00000290UL #define CKM_HOTP 0x00000291UL #define CKM_ACTI 0x000002A0UL #define CKM_ACTI_KEY_GEN 0x000002A1UL #define CKM_SHA3_256 0x000002B0UL #define CKM_SHA3_256_HMAC 0x000002B1UL #define CKM_SHA3_256_HMAC_GENERAL 0x000002B2UL #define CKM_SHA3_256_KEY_GEN 0x000002B3UL #define CKM_SHA3_224 0x000002B5UL #define CKM_SHA3_224_HMAC 0x000002B6UL #define CKM_SHA3_224_HMAC_GENERAL 0x000002B7UL #define CKM_SHA3_224_KEY_GEN 0x000002B8UL #define CKM_SHA3_384 0x000002C0UL #define CKM_SHA3_384_HMAC 0x000002C1UL #define CKM_SHA3_384_HMAC_GENERAL 0x000002C2UL #define CKM_SHA3_384_KEY_GEN 0x000002C3UL #define CKM_SHA3_512 0x000002D0UL #define CKM_SHA3_512_HMAC 0x000002D1UL #define CKM_SHA3_512_HMAC_GENERAL 0x000002D2UL #define CKM_SHA3_512_KEY_GEN 0x000002D3UL #define CKM_CAST_KEY_GEN 0x00000300UL #define CKM_CAST_ECB 0x00000301UL #define CKM_CAST_CBC 0x00000302UL #define CKM_CAST_MAC 0x00000303UL #define CKM_CAST_MAC_GENERAL 0x00000304UL #define CKM_CAST_CBC_PAD 0x00000305UL #define CKM_CAST3_KEY_GEN 0x00000310UL #define CKM_CAST3_ECB 0x00000311UL #define CKM_CAST3_CBC 0x00000312UL #define CKM_CAST3_MAC 0x00000313UL #define CKM_CAST3_MAC_GENERAL 0x00000314UL #define CKM_CAST3_CBC_PAD 0x00000315UL #define CKM_CAST128_KEY_GEN 0x00000320UL #define CKM_CAST5_ECB 0x00000321UL #define CKM_CAST128_ECB 0x00000321UL #define CKM_CAST128_MAC 0x00000323UL #define CKM_CAST128_CBC 0x00000322UL #define CKM_CAST128_MAC_GENERAL 0x00000324UL #define CKM_CAST128_CBC_PAD 0x00000325UL #define CKM_RC5_KEY_GEN 0x00000330UL #define CKM_RC5_ECB 0x00000331UL #define CKM_RC5_CBC 0x00000332UL #define CKM_RC5_MAC 0x00000333UL #define CKM_RC5_MAC_GENERAL 0x00000334UL #define CKM_RC5_CBC_PAD 0x00000335UL #define CKM_IDEA_KEY_GEN 0x00000340UL #define CKM_IDEA_ECB 0x00000341UL #define CKM_IDEA_CBC 0x00000342UL #define CKM_IDEA_MAC 0x00000343UL #define CKM_IDEA_MAC_GENERAL 0x00000344UL #define CKM_IDEA_CBC_PAD 0x00000345UL #define CKM_GENERIC_SECRET_KEY_GEN 0x00000350UL #define CKM_CONCATENATE_BASE_AND_KEY 0x00000360UL #define CKM_CONCATENATE_BASE_AND_DATA 0x00000362UL #define CKM_CONCATENATE_DATA_AND_BASE 0x00000363UL #define CKM_XOR_BASE_AND_DATA 0x00000364UL #define CKM_EXTRACT_KEY_FROM_KEY 0x00000365UL #define CKM_SSL3_PRE_MASTER_KEY_GEN 0x00000370UL #define CKM_SSL3_MASTER_KEY_DERIVE 0x00000371UL #define CKM_SSL3_KEY_AND_MAC_DERIVE 0x00000372UL #define CKM_SSL3_MASTER_KEY_DERIVE_DH 0x00000373UL #define CKM_TLS_PRE_MASTER_KEY_GEN 0x00000374UL #define CKM_TLS_MASTER_KEY_DERIVE 0x00000375UL #define CKM_TLS_KEY_AND_MAC_DERIVE 0x00000376UL #define CKM_TLS_MASTER_KEY_DERIVE_DH 0x00000377UL #define CKM_TLS_PRF 0x00000378UL #define CKM_SSL3_MD5_MAC 0x00000380UL #define CKM_SSL3_SHA1_MAC 0x00000381UL #define CKM_MD5_KEY_DERIVATION 0x00000390UL #define CKM_MD2_KEY_DERIVATION 0x00000391UL #define CKM_SHA1_KEY_DERIVATION 0x00000392UL #define CKM_SHA256_KEY_DERIVATION 0x00000393UL #define CKM_SHA384_KEY_DERIVATION 0x00000394UL #define CKM_SHA512_KEY_DERIVATION 0x00000395UL #define CKM_SHA224_KEY_DERIVATION 0x00000396UL #define CKM_SHA3_256_KEY_DERIVATION 0x00000397UL #define CKM_SHA3_256_KEY_DERIVE 0x00000397UL #define CKM_SHA3_224_KEY_DERIVATION 0x00000398UL #define CKM_SHA3_224_KEY_DERIVE 0x00000398UL #define CKM_SHA3_384_KEY_DERIVATION 0x00000399UL #define CKM_SHA3_384_KEY_DERIVE 0x00000399UL #define CKM_SHA3_512_KEY_DERIVATION 0x0000039AUL #define CKM_SHA3_512_KEY_DERIVE 0x0000039AUL #define CKM_SHAKE_128_KEY_DERIVATION 0x0000039BUL #define CKM_SHAKE_128_KEY_DERIVE 0x0000039BUL #define CKM_SHAKE_256_KEY_DERIVATION 0x0000039CUL #define CKM_SHAKE_256_KEY_DERIVE 0x0000039CUL #define CKM_PBE_MD2_DES_CBC 0x000003A0UL #define CKM_PBE_MD5_DES_CBC 0x000003A1UL #define CKM_PBE_MD5_CAST_CBC 0x000003A2UL #define CKM_PBE_MD5_CAST3_CBC 0x000003A3UL #define CKM_PBE_MD5_CAST128_CBC 0x000003A4UL #define CKM_PBE_SHA1_CAST128_CBC 0x000003A5UL #define CKM_PBE_SHA1_RC4_128 0x000003A6UL #define CKM_PBE_SHA1_RC4_40 0x000003A7UL #define CKM_PBE_SHA1_DES3_EDE_CBC 0x000003A8UL #define CKM_PBE_SHA1_DES2_EDE_CBC 0x000003A9UL #define CKM_PBE_SHA1_RC2_128_CBC 0x000003AAUL #define CKM_PBE_SHA1_RC2_40_CBC 0x000003ABUL #define CKM_PKCS5_PBKD2 0x000003B0UL #define CKM_PBA_SHA1_WITH_SHA1_HMAC 0x000003C0UL #define CKM_WTLS_PRE_MASTER_KEY_GEN 0x000003D0UL #define CKM_WTLS_MASTER_KEY_DERIVE 0x000003D1UL #define CKM_WTLS_MASTER_KEY_DERIVE_DH_ECC 0x000003D2UL #define CKM_WTLS_PRF 0x000003D3UL #define CKM_WTLS_SERVER_KEY_AND_MAC_DERIVE 0x000003D4UL #define CKM_WTLS_CLIENT_KEY_AND_MAC_DERIVE 0x000003D5UL #define CKM_TLS10_MAC_SERVER 0x000003D6UL #define CKM_TLS10_MAC_CLIENT 0x000003D7UL #define CKM_TLS12_MAC 0x000003D8UL #define CKM_TLS12_KDF 0x000003D9UL #define CKM_TLS12_MASTER_KEY_DERIVE 0x000003E0UL #define CKM_TLS12_KEY_AND_MAC_DERIVE 0x000003E1UL #define CKM_TLS12_MASTER_KEY_DERIVE_DH 0x000003E2UL #define CKM_TLS12_KEY_SAFE_DERIVE 0x000003E3UL #define CKM_TLS_MAC 0x000003E4UL #define CKM_TLS_KDF 0x000003E5UL #define CKM_KEY_WRAP_LYNKS 0x00000400UL #define CKM_KEY_WRAP_SET_OAEP 0x00000401UL #define CKM_CMS_SIG 0x00000500UL #define CKM_KIP_DERIVE 0x00000510UL #define CKM_KIP_WRAP 0x00000511UL #define CKM_KIP_MAC 0x00000512UL #define CKM_CAMELLIA_KEY_GEN 0x00000550UL #define CKM_CAMELLIA_ECB 0x00000551UL #define CKM_CAMELLIA_CBC 0x00000552UL #define CKM_CAMELLIA_MAC 0x00000553UL #define CKM_CAMELLIA_MAC_GENERAL 0x00000554UL #define CKM_CAMELLIA_CBC_PAD 0x00000555UL #define CKM_CAMELLIA_ECB_ENCRYPT_DATA 0x00000556UL #define CKM_CAMELLIA_CBC_ENCRYPT_DATA 0x00000557UL #define CKM_CAMELLIA_CTR 0x00000558UL #define CKM_ARIA_KEY_GEN 0x00000560UL #define CKM_ARIA_ECB 0x00000561UL #define CKM_ARIA_CBC 0x00000562UL #define CKM_ARIA_MAC 0x00000563UL #define CKM_ARIA_MAC_GENERAL 0x00000564UL #define CKM_ARIA_CBC_PAD 0x00000565UL #define CKM_ARIA_ECB_ENCRYPT_DATA 0x00000566UL #define CKM_ARIA_CBC_ENCRYPT_DATA 0x00000567UL #define CKM_SEED_KEY_GEN 0x00000650UL #define CKM_SEED_ECB 0x00000651UL #define CKM_SEED_CBC 0x00000652UL #define CKM_SEED_MAC 0x00000653UL #define CKM_SEED_MAC_GENERAL 0x00000654UL #define CKM_SEED_CBC_PAD 0x00000655UL #define CKM_SEED_ECB_ENCRYPT_DATA 0x00000656UL #define CKM_SEED_CBC_ENCRYPT_DATA 0x00000657UL #define CKM_SKIPJACK_KEY_GEN 0x00001000UL #define CKM_SKIPJACK_ECB64 0x00001001UL #define CKM_SKIPJACK_CBC64 0x00001002UL #define CKM_SKIPJACK_OFB64 0x00001003UL #define CKM_SKIPJACK_CFB64 0x00001004UL #define CKM_SKIPJACK_CFB32 0x00001005UL #define CKM_SKIPJACK_CFB16 0x00001006UL #define CKM_SKIPJACK_CFB8 0x00001007UL #define CKM_SKIPJACK_WRAP 0x00001008UL #define CKM_SKIPJACK_PRIVATE_WRAP 0x00001009UL #define CKM_SKIPJACK_RELAYX 0x0000100AUL #define CKM_KEA_KEY_PAIR_GEN 0x00001010UL #define CKM_KEA_KEY_DERIVE 0x00001011UL #define CKM_KEA_DERIVE 0x00001012UL #define CKM_FORTEZZA_TIMESTAMP 0x00001020UL #define CKM_BATON_KEY_GEN 0x00001030UL #define CKM_BATON_ECB128 0x00001031UL #define CKM_BATON_ECB96 0x00001032UL #define CKM_BATON_CBC128 0x00001033UL #define CKM_BATON_COUNTER 0x00001034UL #define CKM_BATON_SHUFFLE 0x00001035UL #define CKM_BATON_WRAP 0x00001036UL #define CKM_EC_KEY_PAIR_GEN 0x00001040UL #define CKM_ECDSA 0x00001041UL #define CKM_ECDSA_SHA1 0x00001042UL #define CKM_ECDSA_SHA224 0x00001043UL #define CKM_ECDSA_SHA256 0x00001044UL #define CKM_ECDSA_SHA384 0x00001045UL #define CKM_ECDSA_SHA512 0x00001046UL #define CKM_EC_KEY_PAIR_GEN_W_EXTRA_BITS 0x0000140BUL #define CKM_ECDH1_DERIVE 0x00001050UL #define CKM_ECDH1_COFACTOR_DERIVE 0x00001051UL #define CKM_ECMQV_DERIVE 0x00001052UL #define CKM_ECDH_AES_KEY_WRAP 0x00001053UL #define CKM_RSA_AES_KEY_WRAP 0x00001054UL #define CKM_JUNIPER_KEY_GEN 0x00001060UL #define CKM_JUNIPER_ECB128 0x00001061UL #define CKM_JUNIPER_CBC128 0x00001062UL #define CKM_JUNIPER_COUNTER 0x00001063UL #define CKM_JUNIPER_SHUFFLE 0x00001064UL #define CKM_JUNIPER_WRAP 0x00001065UL #define CKM_FASTHASH 0x00001070UL #define CKM_AES_XTS 0x00001071UL #define CKM_AES_XTS_KEY_GEN 0x00001072UL #define CKM_AES_KEY_GEN 0x00001080UL #define CKM_AES_ECB 0x00001081UL #define CKM_AES_CBC 0x00001082UL #define CKM_AES_MAC 0x00001083UL #define CKM_AES_MAC_GENERAL 0x00001084UL #define CKM_AES_CBC_PAD 0x00001085UL #define CKM_AES_CTR 0x00001086UL #define CKM_AES_GCM 0x00001087UL #define CKM_AES_CCM 0x00001088UL #define CKM_AES_CTS 0x00001089UL #define CKM_AES_CMAC 0x0000108AUL #define CKM_AES_CMAC_GENERAL 0x0000108BUL #define CKM_AES_XCBC_MAC 0x0000108CUL #define CKM_AES_XCBC_MAC_96 0x0000108DUL #define CKM_AES_GMAC 0x0000108EUL #define CKM_BLOWFISH_KEY_GEN 0x00001090UL #define CKM_BLOWFISH_CBC 0x00001091UL #define CKM_TWOFISH_KEY_GEN 0x00001092UL #define CKM_TWOFISH_CBC 0x00001093UL #define CKM_BLOWFISH_CBC_PAD 0x00001094UL #define CKM_TWOFISH_CBC_PAD 0x00001095UL #define CKM_DES_ECB_ENCRYPT_DATA 0x00001100UL #define CKM_DES_CBC_ENCRYPT_DATA 0x00001101UL #define CKM_DES3_ECB_ENCRYPT_DATA 0x00001102UL #define CKM_DES3_CBC_ENCRYPT_DATA 0x00001103UL #define CKM_AES_ECB_ENCRYPT_DATA 0x00001104UL #define CKM_AES_CBC_ENCRYPT_DATA 0x00001105UL #define CKM_GOSTR3410_KEY_PAIR_GEN 0x00001200UL #define CKM_GOSTR3410 0x00001201UL #define CKM_GOSTR3410_WITH_GOSTR3411 0x00001202UL #define CKM_GOSTR3410_KEY_WRAP 0x00001203UL #define CKM_GOSTR3410_DERIVE 0x00001204UL #define CKM_GOSTR3411 0x00001210UL #define CKM_GOSTR3411_HMAC 0x00001211UL #define CKM_GOST28147_KEY_GEN 0x00001220UL #define CKM_GOST28147_ECB 0x00001221UL #define CKM_GOST28147 0x00001222UL #define CKM_GOST28147_MAC 0x00001223UL #define CKM_GOST28147_KEY_WRAP 0x00001224UL #define CKM_CHACHA20_KEY_GEN 0x00001225UL #define CKM_CHACHA20 0x00001226UL #define CKM_POLY1305_KEY_GEN 0x00001227UL #define CKM_POLY1305 0x00001228UL #define CKM_DSA_PARAMETER_GEN 0x00002000UL #define CKM_DH_PKCS_PARAMETER_GEN 0x00002001UL #define CKM_X9_42_DH_PARAMETER_GEN 0x00002002UL #define CKM_DSA_PROBABILISTIC_PARAMETER_GEN 0x00002003UL #define CKM_DSA_PROBABLISTIC_PARAMETER_GEN 0x00002003UL #define CKM_DSA_SHAWE_TAYLOR_PARAMETER_GEN 0x00002004UL #define CKM_DSA_FIPS_G_GEN 0x00002005UL #define CKM_AES_OFB 0x00002104UL #define CKM_AES_CFB64 0x00002105UL #define CKM_AES_CFB8 0x00002106UL #define CKM_AES_CFB128 0x00002107UL #define CKM_AES_CFB1 0x00002108UL #define CKM_AES_KEY_WRAP 0x00002109UL #define CKM_AES_KEY_WRAP_PAD 0x0000210AUL #define CKM_AES_KEY_WRAP_KWP 0x0000210BUL #define CKM_AES_KEY_WRAP_PKCS7 0x0000210CUL #define CKM_RSA_PKCS_TPM_1_1 0x00004001UL #define CKM_RSA_PKCS_OAEP_TPM_1_1 0x00004002UL #define CKM_SHA_1_KEY_GEN 0x00004003UL #define CKM_SHA224_KEY_GEN 0x00004004UL #define CKM_SHA256_KEY_GEN 0x00004005UL #define CKM_SHA384_KEY_GEN 0x00004006UL #define CKM_SHA512_KEY_GEN 0x00004007UL #define CKM_SHA512_224_KEY_GEN 0x00004008UL #define CKM_SHA512_256_KEY_GEN 0x00004009UL #define CKM_SHA512_T_KEY_GEN 0x0000400AUL #define CKM_NULL 0x0000400BUL #define CKM_BLAKE2B_160 0x0000400CUL #define CKM_BLAKE2B_160_HMAC 0x0000400DUL #define CKM_BLAKE2B_160_HMAC_GENERAL 0x0000400EUL #define CKM_BLAKE2B_160_KEY_DERIVE 0x0000400FUL #define CKM_BLAKE2B_160_KEY_GEN 0x00004010UL #define CKM_BLAKE2B_256 0x00004011UL #define CKM_BLAKE2B_256_HMAC 0x00004012UL #define CKM_BLAKE2B_256_HMAC_GENERAL 0x00004013UL #define CKM_BLAKE2B_256_KEY_DERIVE 0x00004014UL #define CKM_BLAKE2B_256_KEY_GEN 0x00004015UL #define CKM_BLAKE2B_384 0x00004016UL #define CKM_BLAKE2B_384_HMAC 0x00004017UL #define CKM_BLAKE2B_384_HMAC_GENERAL 0x00004018UL #define CKM_BLAKE2B_384_KEY_DERIVE 0x00004019UL #define CKM_BLAKE2B_384_KEY_GEN 0x0000401AUL #define CKM_BLAKE2B_512 0x0000401BUL #define CKM_BLAKE2B_512_HMAC 0x0000401CUL #define CKM_BLAKE2B_512_HMAC_GENERAL 0x0000401DUL #define CKM_BLAKE2B_512_KEY_DERIVE 0x0000401EUL #define CKM_BLAKE2B_512_KEY_GEN 0x0000401FUL #define CKM_SALSA20 0x00004020UL #define CKM_CHACHA20_POLY1305 0x00004021UL #define CKM_SALSA20_POLY1305 0x00004022UL #define CKM_X3DH_INITIALIZE 0x00004023UL #define CKM_X3DH_RESPOND 0x00004024UL #define CKM_X2RATCHET_INITIALIZE 0x00004025UL #define CKM_X2RATCHET_RESPOND 0x00004026UL #define CKM_X2RATCHET_ENCRYPT 0x00004027UL #define CKM_X2RATCHET_DECRYPT 0x00004028UL #define CKM_XEDDSA 0x00004029UL #define CKM_HKDF_DERIVE 0x0000402AUL #define CKM_HKDF_DATA 0x0000402BUL #define CKM_HKDF_KEY_GEN 0x0000402CUL #define CKM_SALSA20_KEY_GEN 0x0000402DUL #define CKM_ECDSA_SHA3_224 0x00001047UL #define CKM_ECDSA_SHA3_256 0x00001048UL #define CKM_ECDSA_SHA3_384 0x00001049UL #define CKM_ECDSA_SHA3_512 0x0000104AUL #define CKM_EC_EDWARDS_KEY_PAIR_GEN 0x00001055UL #define CKM_EC_MONTGOMERY_KEY_PAIR_GEN 0x00001056UL #define CKM_EDDSA 0x00001057UL #define CKM_SP800_108_COUNTER_KDF 0x000003ACUL #define CKM_SP800_108_FEEDBACK_KDF 0x000003ADUL #define CKM_SP800_108_DOUBLE_PIPELINE_KDF 0x000003AEUL #define CKM_IKE2_PRF_PLUS_DERIVE 0x0000402EUL #define CKM_IKE_PRF_DERIVE 0x0000402FUL #define CKM_IKE1_PRF_DERIVE 0x00004030UL #define CKM_IKE1_EXTENDED_DERIVE 0x00004031UL #define CKM_HSS_KEY_PAIR_GEN 0x00004032UL #define CKM_HSS 0x00004033UL #define CKM_VENDOR_DEFINED 0x80000000UL /* Deprecated */ #ifdef PKCS11_DEPRECATED #define CKM_CAST5_KEY_GEN 0x00000320UL #define CKM_CAST5_CBC 0x00000322UL #define CKM_CAST5_MAC 0x00000323UL #define CKM_CAST5_MAC_GENERAL 0x00000324UL #define CKM_CAST5_CBC_PAD 0x00000325UL #define CKM_PBE_MD5_CAST5_CBC 0x000003A4UL #define CKM_PBE_SHA1_CAST5_CBC 0x000003A5UL #define CKM_ECDSA_KEY_PAIR_GEN 0x00001040UL #endif /* CKN */ #define CKN_SURRENDER 0UL #define CKN_OTP_CHANGED 1UL /* CKO */ #define CKO_DATA 0x00000000UL #define CKO_CERTIFICATE 0x00000001UL #define CKO_PUBLIC_KEY 0x00000002UL #define CKO_PRIVATE_KEY 0x00000003UL #define CKO_SECRET_KEY 0x00000004UL #define CKO_HW_FEATURE 0x00000005UL #define CKO_DOMAIN_PARAMETERS 0x00000006UL #define CKO_MECHANISM 0x00000007UL #define CKO_OTP_KEY 0x00000008UL #define CKO_PROFILE 0x00000009UL #define CKO_VENDOR_DEFINED 0x80000000UL /* CKP (profile) */ #define CKP_INVALID_ID 0x00000000UL #define CKP_BASELINE_PROVIDER 0x00000001UL #define CKP_EXTENDED_PROVIDER 0x00000002UL #define CKP_AUTHENTICATION_TOKEN 0x00000003UL #define CKP_PUBLIC_CERTIFICATES_TOKEN 0x00000004UL #define CKP_COMPLETE_PROVIDER 0x00000005UL #define CKP_HKDF_TLS_TOKEN 0x00000006UL #define CKP_VENDOR_DEFINED 0x80000000UL /* CKP (PBKD2) */ #define CKP_PKCS5_PBKD2_HMAC_SHA1 0x00000001UL #define CKP_PKCS5_PBKD2_HMAC_GOSTR3411 0x00000002UL #define CKP_PKCS5_PBKD2_HMAC_SHA224 0x00000003UL #define CKP_PKCS5_PBKD2_HMAC_SHA256 0x00000004UL #define CKP_PKCS5_PBKD2_HMAC_SHA384 0x00000005UL #define CKP_PKCS5_PBKD2_HMAC_SHA512 0x00000006UL #define CKP_PKCS5_PBKD2_HMAC_SHA512_224 0x00000007UL #define CKP_PKCS5_PBKD2_HMAC_SHA512_256 0x00000008UL /* CKR */ #define CKR_OK 0x00000000UL #define CKR_CANCEL 0x00000001UL #define CKR_HOST_MEMORY 0x00000002UL #define CKR_SLOT_ID_INVALID 0x00000003UL #define CKR_GENERAL_ERROR 0x00000005UL #define CKR_FUNCTION_FAILED 0x00000006UL #define CKR_ARGUMENTS_BAD 0x00000007UL #define CKR_NO_EVENT 0x00000008UL #define CKR_NEED_TO_CREATE_THREADS 0x00000009UL #define CKR_CANT_LOCK 0x0000000AUL #define CKR_ATTRIBUTE_READ_ONLY 0x00000010UL #define CKR_ATTRIBUTE_SENSITIVE 0x00000011UL #define CKR_ATTRIBUTE_TYPE_INVALID 0x00000012UL #define CKR_ATTRIBUTE_VALUE_INVALID 0x00000013UL #define CKR_ACTION_PROHIBITED 0x0000001BUL #define CKR_DATA_INVALID 0x00000020UL #define CKR_DATA_LEN_RANGE 0x00000021UL #define CKR_DEVICE_ERROR 0x00000030UL #define CKR_DEVICE_MEMORY 0x00000031UL #define CKR_DEVICE_REMOVED 0x00000032UL #define CKR_ENCRYPTED_DATA_INVALID 0x00000040UL #define CKR_ENCRYPTED_DATA_LEN_RANGE 0x00000041UL #define CKR_AEAD_DECRYPT_FAILED 0x00000042UL #define CKR_FUNCTION_CANCELED 0x00000050UL #define CKR_FUNCTION_NOT_PARALLEL 0x00000051UL #define CKR_FUNCTION_NOT_SUPPORTED 0x00000054UL #define CKR_KEY_HANDLE_INVALID 0x00000060UL #define CKR_KEY_SIZE_RANGE 0x00000062UL #define CKR_KEY_TYPE_INCONSISTENT 0x00000063UL #define CKR_KEY_NOT_NEEDED 0x00000064UL #define CKR_KEY_CHANGED 0x00000065UL #define CKR_KEY_NEEDED 0x00000066UL #define CKR_KEY_INDIGESTIBLE 0x00000067UL #define CKR_KEY_FUNCTION_NOT_PERMITTED 0x00000068UL #define CKR_KEY_NOT_WRAPPABLE 0x00000069UL #define CKR_KEY_UNEXTRACTABLE 0x0000006AUL #define CKR_MECHANISM_INVALID 0x00000070UL #define CKR_MECHANISM_PARAM_INVALID 0x00000071UL #define CKR_OBJECT_HANDLE_INVALID 0x00000082UL #define CKR_OPERATION_ACTIVE 0x00000090UL #define CKR_OPERATION_NOT_INITIALIZED 0x00000091UL #define CKR_PIN_INCORRECT 0x000000A0UL #define CKR_PIN_INVALID 0x000000A1UL #define CKR_PIN_LEN_RANGE 0x000000A2UL #define CKR_PIN_EXPIRED 0x000000A3UL #define CKR_PIN_LOCKED 0x000000A4UL #define CKR_SESSION_CLOSED 0x000000B0UL #define CKR_SESSION_COUNT 0x000000B1UL #define CKR_SESSION_HANDLE_INVALID 0x000000B3UL #define CKR_SESSION_PARALLEL_NOT_SUPPORTED 0x000000B4UL #define CKR_SESSION_READ_ONLY 0x000000B5UL #define CKR_SESSION_EXISTS 0x000000B6UL #define CKR_SESSION_READ_ONLY_EXISTS 0x000000B7UL #define CKR_SESSION_READ_WRITE_SO_EXISTS 0x000000B8UL #define CKR_SIGNATURE_INVALID 0x000000C0UL #define CKR_SIGNATURE_LEN_RANGE 0x000000C1UL #define CKR_TEMPLATE_INCOMPLETE 0x000000D0UL #define CKR_TEMPLATE_INCONSISTENT 0x000000D1UL #define CKR_TOKEN_NOT_PRESENT 0x000000E0UL #define CKR_TOKEN_NOT_RECOGNIZED 0x000000E1UL #define CKR_TOKEN_WRITE_PROTECTED 0x000000E2UL #define CKR_UNWRAPPING_KEY_HANDLE_INVALID 0x000000F0UL #define CKR_UNWRAPPING_KEY_SIZE_RANGE 0x000000F1UL #define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT 0x000000F2UL #define CKR_USER_ALREADY_LOGGED_IN 0x00000100UL #define CKR_USER_NOT_LOGGED_IN 0x00000101UL #define CKR_USER_PIN_NOT_INITIALIZED 0x00000102UL #define CKR_USER_TYPE_INVALID 0x00000103UL #define CKR_USER_ANOTHER_ALREADY_LOGGED_IN 0x00000104UL #define CKR_USER_TOO_MANY_TYPES 0x00000105UL #define CKR_WRAPPED_KEY_INVALID 0x00000110UL #define CKR_WRAPPED_KEY_LEN_RANGE 0x00000112UL #define CKR_WRAPPING_KEY_HANDLE_INVALID 0x00000113UL #define CKR_WRAPPING_KEY_SIZE_RANGE 0x00000114UL #define CKR_WRAPPING_KEY_TYPE_INCONSISTENT 0x00000115UL #define CKR_RANDOM_SEED_NOT_SUPPORTED 0x00000120UL #define CKR_RANDOM_NO_RNG 0x00000121UL #define CKR_DOMAIN_PARAMS_INVALID 0x00000130UL #define CKR_CURVE_NOT_SUPPORTED 0x00000140UL #define CKR_BUFFER_TOO_SMALL 0x00000150UL #define CKR_SAVED_STATE_INVALID 0x00000160UL #define CKR_INFORMATION_SENSITIVE 0x00000170UL #define CKR_STATE_UNSAVEABLE 0x00000180UL #define CKR_CRYPTOKI_NOT_INITIALIZED 0x00000190UL #define CKR_CRYPTOKI_ALREADY_INITIALIZED 0x00000191UL #define CKR_MUTEX_BAD 0x000001A0UL #define CKR_MUTEX_NOT_LOCKED 0x000001A1UL #define CKR_NEW_PIN_MODE 0x000001B0UL #define CKR_NEXT_OTP 0x000001B1UL #define CKR_EXCEEDED_MAX_ITERATIONS 0x000001B5UL #define CKR_FIPS_SELF_TEST_FAILED 0x000001B6UL #define CKR_LIBRARY_LOAD_FAILED 0x000001B7UL #define CKR_PIN_TOO_WEAK 0x000001B8UL #define CKR_PUBLIC_KEY_INVALID 0x000001B9UL #define CKR_FUNCTION_REJECTED 0x00000200UL #define CKR_TOKEN_RESOURCE_EXCEEDED 0x00000201UL #define CKR_OPERATION_CANCEL_FAILED 0x00000202UL #define CKR_KEY_EXHAUSTED 0x00000203UL #define CKR_VENDOR_DEFINED 0x80000000UL /* CKS */ #define CKS_RO_PUBLIC_SESSION 0UL #define CKS_RO_USER_FUNCTIONS 1UL #define CKS_RW_PUBLIC_SESSION 2UL #define CKS_RW_USER_FUNCTIONS 3UL #define CKS_RW_SO_FUNCTIONS 4UL /* CKU */ #define CKU_SO 0UL #define CKU_USER 1UL #define CKU_CONTEXT_SPECIFIC 2UL /* CKZ (data) */ #define CKZ_DATA_SPECIFIED 0x00000001UL /* CKZ (salt) */ #define CKZ_SALT_SPECIFIED 0x00000001UL /* Sundry structures type definition in alphabetical order */ #define STRUCTDEF(__name__) \ struct __name__; \ typedef struct __name__ __name__; \ typedef struct __name__ * __name__ ## _PTR; \ typedef struct __name__ ** __name__ ## _PTR_PTR; STRUCTDEF(CK_ATTRIBUTE); STRUCTDEF(CK_C_INITIALIZE_ARGS); STRUCTDEF(CK_DATE); STRUCTDEF(CK_DERIVED_KEY); STRUCTDEF(CK_FUNCTION_LIST); STRUCTDEF(CK_FUNCTION_LIST_3_0); STRUCTDEF(CK_INFO); STRUCTDEF(CK_INTERFACE); STRUCTDEF(CK_MECHANISM); STRUCTDEF(CK_MECHANISM_INFO); STRUCTDEF(CK_SESSION_INFO); STRUCTDEF(CK_SLOT_INFO); STRUCTDEF(CK_TOKEN_INFO); STRUCTDEF(CK_VERSION); /* Function type definitions */ typedef CK_RV (* CK_NOTIFY)(CK_SESSION_HANDLE, CK_NOTIFICATION, void *); typedef CK_RV (* CK_CREATEMUTEX)(void **); typedef CK_RV (* CK_DESTROYMUTEX)(void *); typedef CK_RV (* CK_LOCKMUTEX)(void *); typedef CK_RV (* CK_UNLOCKMUTEX)(void *); /* General Structure definitions */ struct CK_ATTRIBUTE { CK_ATTRIBUTE_TYPE type; void * pValue; CK_ULONG ulValueLen; }; struct CK_C_INITIALIZE_ARGS { CK_CREATEMUTEX CreateMutex; CK_DESTROYMUTEX DestroyMutex; CK_LOCKMUTEX LockMutex; CK_UNLOCKMUTEX UnlockMutex; CK_FLAGS flags; void * pReserved; }; struct CK_DATE{ CK_CHAR year[4]; CK_CHAR month[2]; CK_CHAR day[2]; }; struct CK_DERIVED_KEY { CK_ATTRIBUTE * pTemplate; CK_ULONG ulAttributeCount; CK_OBJECT_HANDLE * phKey; }; struct CK_VERSION { CK_BYTE major; CK_BYTE minor; }; struct CK_INFO { struct CK_VERSION cryptokiVersion; CK_UTF8CHAR manufacturerID[32]; CK_FLAGS flags; CK_UTF8CHAR libraryDescription[32]; struct CK_VERSION libraryVersion; }; struct CK_INTERFACE { CK_CHAR * pInterfaceName; void * pFunctionList; CK_FLAGS flags; }; struct CK_MECHANISM { CK_MECHANISM_TYPE mechanism; void * pParameter; CK_ULONG ulParameterLen; }; struct CK_MECHANISM_INFO { CK_ULONG ulMinKeySize; CK_ULONG ulMaxKeySize; CK_FLAGS flags; }; struct CK_SESSION_INFO { CK_SLOT_ID slotID; CK_STATE state; CK_FLAGS flags; CK_ULONG ulDeviceError; }; struct CK_SLOT_INFO { CK_UTF8CHAR slotDescription[64]; CK_UTF8CHAR manufacturerID[32]; CK_FLAGS flags; CK_VERSION hardwareVersion; CK_VERSION firmwareVersion; }; struct CK_TOKEN_INFO { CK_UTF8CHAR label[32]; CK_UTF8CHAR manufacturerID[32]; CK_UTF8CHAR model[16]; CK_CHAR serialNumber[16]; CK_FLAGS flags; CK_ULONG ulMaxSessionCount; CK_ULONG ulSessionCount; CK_ULONG ulMaxRwSessionCount; CK_ULONG ulRwSessionCount; CK_ULONG ulMaxPinLen; CK_ULONG ulMinPinLen; CK_ULONG ulTotalPublicMemory; CK_ULONG ulFreePublicMemory; CK_ULONG ulTotalPrivateMemory; CK_ULONG ulFreePrivateMemory; CK_VERSION hardwareVersion; CK_VERSION firmwareVersion; CK_CHAR utcTime[16]; }; /* Param Structure definitions in alphabetical order */ STRUCTDEF(CK_AES_CBC_ENCRYPT_DATA_PARAMS); STRUCTDEF(CK_AES_CCM_PARAMS); STRUCTDEF(CK_AES_CTR_PARAMS); STRUCTDEF(CK_AES_GCM_PARAMS); STRUCTDEF(CK_ARIA_CBC_ENCRYPT_DATA_PARAMS); STRUCTDEF(CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS); STRUCTDEF(CK_CAMELLIA_CTR_PARAMS); STRUCTDEF(CK_CCM_MESSAGE_PARAMS); STRUCTDEF(CK_CCM_PARAMS); STRUCTDEF(CK_CHACHA20_PARAMS); STRUCTDEF(CK_CMS_SIG_PARAMS); STRUCTDEF(CK_DES_CBC_ENCRYPT_DATA_PARAMS); STRUCTDEF(CK_DSA_PARAMETER_GEN_PARAM); STRUCTDEF(CK_ECDH_AES_KEY_WRAP_PARAMS); STRUCTDEF(CK_ECDH1_DERIVE_PARAMS); STRUCTDEF(CK_ECDH2_DERIVE_PARAMS); STRUCTDEF(CK_ECMQV_DERIVE_PARAMS); STRUCTDEF(CK_EDDSA_PARAMS); STRUCTDEF(CK_GCM_MESSAGE_PARAMS); STRUCTDEF(CK_GCM_PARAMS); STRUCTDEF(CK_GOSTR3410_DERIVE_PARAMS); STRUCTDEF(CK_GOSTR3410_KEY_WRAP_PARAMS); STRUCTDEF(CK_HKDF_PARAMS); STRUCTDEF(CK_IKE_PRF_DERIVE_PARAMS); STRUCTDEF(CK_IKE1_EXTENDED_DERIVE_PARAMS); STRUCTDEF(CK_IKE1_PRF_DERIVE_PARAMS); STRUCTDEF(CK_IKE2_PRF_PLUS_DERIVE_PARAMS); STRUCTDEF(CK_KEA_DERIVE_PARAMS); STRUCTDEF(CK_KEY_DERIVATION_STRING_DATA); STRUCTDEF(CK_KEY_WRAP_SET_OAEP_PARAMS); STRUCTDEF(CK_KIP_PARAMS); STRUCTDEF(CK_OTP_PARAM); STRUCTDEF(CK_OTP_PARAMS); STRUCTDEF(CK_OTP_SIGNATURE_INFO); STRUCTDEF(CK_PBE_PARAMS); STRUCTDEF(CK_PKCS5_PBKD2_PARAMS); STRUCTDEF(CK_PKCS5_PBKD2_PARAMS2); STRUCTDEF(CK_PRF_DATA_PARAM); STRUCTDEF(CK_RC2_CBC_PARAMS); STRUCTDEF(CK_RC2_MAC_GENERAL_PARAMS); STRUCTDEF(CK_RC5_CBC_PARAMS); STRUCTDEF(CK_RC5_MAC_GENERAL_PARAMS); STRUCTDEF(CK_RC5_PARAMS); STRUCTDEF(CK_RSA_AES_KEY_WRAP_PARAMS); STRUCTDEF(CK_RSA_PKCS_OAEP_PARAMS); STRUCTDEF(CK_RSA_PKCS_PSS_PARAMS); STRUCTDEF(CK_SALSA20_CHACHA20_POLY1305_MSG_PARAMS); STRUCTDEF(CK_SALSA20_CHACHA20_POLY1305_PARAMS); STRUCTDEF(CK_SALSA20_PARAMS); STRUCTDEF(CK_SEED_CBC_ENCRYPT_DATA_PARAMS); STRUCTDEF(CK_SKIPJACK_PRIVATE_WRAP_PARAMS); STRUCTDEF(CK_SKIPJACK_RELAYX_PARAMS); STRUCTDEF(CK_SP800_108_COUNTER_FORMAT); STRUCTDEF(CK_SP800_108_DKM_LENGTH_FORMAT); STRUCTDEF(CK_SP800_108_FEEDBACK_KDF_PARAMS); STRUCTDEF(CK_SP800_108_KDF_PARAMS); STRUCTDEF(CK_X2RATCHET_INITIALIZE_PARAMS); STRUCTDEF(CK_X2RATCHET_RESPOND_PARAMS); STRUCTDEF(CK_X3DH_INITIATE_PARAMS); STRUCTDEF(CK_X3DH_RESPOND_PARAMS); STRUCTDEF(CK_X9_42_DH1_DERIVE_PARAMS); STRUCTDEF(CK_X9_42_DH2_DERIVE_PARAMS); STRUCTDEF(CK_X9_42_MQV_DERIVE_PARAMS); STRUCTDEF(CK_XEDDSA_PARAMS); STRUCTDEF(specifiedParams); struct CK_AES_CBC_ENCRYPT_DATA_PARAMS { CK_BYTE iv[16]; CK_BYTE * pData; CK_ULONG length; }; struct CK_AES_CCM_PARAMS { CK_ULONG ulDataLen; CK_BYTE * pNonce; CK_ULONG ulNonceLen; CK_BYTE * pAAD; CK_ULONG ulAADLen; CK_ULONG ulMACLen; }; struct CK_AES_CTR_PARAMS { CK_ULONG ulCounterBits; CK_BYTE cb[16]; }; struct CK_AES_GCM_PARAMS { CK_BYTE * pIv; CK_ULONG ulIvLen; CK_ULONG ulIvBits; CK_BYTE * pAAD; CK_ULONG ulAADLen; CK_ULONG ulTagBits; }; struct CK_ARIA_CBC_ENCRYPT_DATA_PARAMS { CK_BYTE iv[16]; CK_BYTE * pData; CK_ULONG length; }; struct CK_CAMELLIA_CBC_ENCRYPT_DATA_PARAMS { CK_BYTE iv[16]; CK_BYTE * pData; CK_ULONG length; }; struct CK_CAMELLIA_CTR_PARAMS { CK_ULONG ulCounterBits; CK_BYTE cb[16]; }; struct CK_CCM_MESSAGE_PARAMS { CK_ULONG ulDataLen; CK_BYTE * pNonce; CK_ULONG ulNonceLen; CK_ULONG ulNonceFixedBits; CK_GENERATOR_FUNCTION nonceGenerator; CK_BYTE * pMAC; CK_ULONG ulMACLen; }; struct CK_CCM_PARAMS { CK_ULONG ulDataLen; CK_BYTE * pNonce; CK_ULONG ulNonceLen; CK_BYTE * pAAD; CK_ULONG ulAADLen; CK_ULONG ulMACLen; }; struct CK_CHACHA20_PARAMS { CK_BYTE * pBlockCounter; CK_ULONG blockCounterBits; CK_BYTE * pNonce; CK_ULONG ulNonceBits; }; struct CK_CMS_SIG_PARAMS { CK_OBJECT_HANDLE certificateHandle; CK_MECHANISM * pSigningMechanism; CK_MECHANISM * pDigestMechanism; CK_UTF8CHAR * pContentType; CK_BYTE * pRequestedAttributes; CK_ULONG ulRequestedAttributesLen; CK_BYTE * pRequiredAttributes; CK_ULONG ulRequiredAttributesLen; }; struct CK_DES_CBC_ENCRYPT_DATA_PARAMS { CK_BYTE iv[8]; CK_BYTE * pData; CK_ULONG length; }; struct CK_DSA_PARAMETER_GEN_PARAM { CK_MECHANISM_TYPE hash; CK_BYTE * pSeed; CK_ULONG ulSeedLen; CK_ULONG ulIndex; }; struct CK_ECDH_AES_KEY_WRAP_PARAMS { CK_ULONG ulAESKeyBits; CK_EC_KDF_TYPE kdf; CK_ULONG ulSharedDataLen; CK_BYTE * pSharedData; }; struct CK_ECDH1_DERIVE_PARAMS { CK_EC_KDF_TYPE kdf; CK_ULONG ulSharedDataLen; CK_BYTE * pSharedData; CK_ULONG ulPublicDataLen; CK_BYTE * pPublicData; }; struct CK_ECDH2_DERIVE_PARAMS { CK_EC_KDF_TYPE kdf; CK_ULONG ulSharedDataLen; CK_BYTE * pSharedData; CK_ULONG ulPublicDataLen; CK_BYTE * pPublicData; CK_ULONG ulPrivateDataLen; CK_OBJECT_HANDLE hPrivateData; CK_ULONG ulPublicDataLen2; CK_BYTE * pPublicData2; }; struct CK_ECMQV_DERIVE_PARAMS { CK_EC_KDF_TYPE kdf; CK_ULONG ulSharedDataLen; CK_BYTE * pSharedData; CK_ULONG ulPublicDataLen; CK_BYTE * pPublicData; CK_ULONG ulPrivateDataLen; CK_OBJECT_HANDLE hPrivateData; CK_ULONG ulPublicDataLen2; CK_BYTE * pPublicData2; CK_OBJECT_HANDLE publicKey; }; struct CK_EDDSA_PARAMS { CK_BBOOL phFlag; CK_ULONG ulContextDataLen; CK_BYTE * pContextData; }; struct CK_GCM_MESSAGE_PARAMS { CK_BYTE * pIv; CK_ULONG ulIvLen; CK_ULONG ulIvFixedBits; CK_GENERATOR_FUNCTION ivGenerator; CK_BYTE * pTag; CK_ULONG ulTagBits; }; struct CK_GCM_PARAMS { CK_BYTE * pIv; CK_ULONG ulIvLen; CK_ULONG ulIvBits; CK_BYTE * pAAD; CK_ULONG ulAADLen; CK_ULONG ulTagBits; }; struct CK_GOSTR3410_DERIVE_PARAMS { CK_EC_KDF_TYPE kdf; CK_BYTE * pPublicData; CK_ULONG ulPublicDataLen; CK_BYTE * pUKM; CK_ULONG ulUKMLen; }; struct CK_GOSTR3410_KEY_WRAP_PARAMS { CK_BYTE * pWrapOID; CK_ULONG ulWrapOIDLen; CK_BYTE * pUKM; CK_ULONG ulUKMLen; CK_OBJECT_HANDLE hKey; }; struct CK_HKDF_PARAMS { CK_BBOOL bExtract; CK_BBOOL bExpand; CK_MECHANISM_TYPE prfHashMechanism; CK_ULONG ulSaltType; CK_BYTE * pSalt; CK_ULONG ulSaltLen; CK_OBJECT_HANDLE hSaltKey; CK_BYTE * pInfo; CK_ULONG ulInfoLen; }; struct CK_IKE_PRF_DERIVE_PARAMS { CK_MECHANISM_TYPE prfMechanism; CK_BBOOL bDataAsKey; CK_BBOOL bRekey; CK_BYTE * pNi; CK_ULONG ulNiLen; CK_BYTE * pNr; CK_ULONG ulNrLen; CK_OBJECT_HANDLE hNewKey; }; struct CK_IKE1_EXTENDED_DERIVE_PARAMS { CK_MECHANISM_TYPE prfMechanism; CK_BBOOL bHasKeygxy; CK_OBJECT_HANDLE hKeygxy; CK_BYTE * pExtraData; CK_ULONG ulExtraDataLen; }; struct CK_IKE1_PRF_DERIVE_PARAMS { CK_MECHANISM_TYPE prfMechanism; CK_BBOOL bHasPrevKey; CK_OBJECT_HANDLE hKeygxy; CK_OBJECT_HANDLE hPrevKey; CK_BYTE * pCKYi; CK_ULONG ulCKYiLen; CK_BYTE * pCKYr; CK_ULONG ulCKYrLen; CK_BYTE keyNumber; }; struct CK_IKE2_PRF_PLUS_DERIVE_PARAMS { CK_MECHANISM_TYPE prfMechanism; CK_BBOOL bHasSeedKey; CK_OBJECT_HANDLE hSeedKey; CK_BYTE * pSeedData; CK_ULONG ulSeedDataLen; }; struct CK_KEA_DERIVE_PARAMS { CK_BBOOL isSender; CK_ULONG ulRandomLen; CK_BYTE * RandomA; CK_BYTE * RandomB; CK_ULONG ulPublicDataLen; CK_BYTE * PublicData; }; struct CK_KEY_DERIVATION_STRING_DATA { CK_BYTE * pData; CK_ULONG ulLen; }; struct CK_KEY_WRAP_SET_OAEP_PARAMS { CK_BYTE bBC; CK_BYTE * pX; CK_ULONG ulXLen; }; struct CK_KIP_PARAMS { CK_MECHANISM * pMechanism; CK_OBJECT_HANDLE hKey; CK_BYTE * pSeed; CK_ULONG ulSeedLen; }; struct CK_OTP_PARAM { CK_OTP_PARAM_TYPE type; void * pValue; CK_ULONG ulValueLen; }; struct CK_OTP_PARAMS { CK_OTP_PARAM * pParams; CK_ULONG ulCount; }; struct CK_OTP_SIGNATURE_INFO { CK_OTP_PARAM * pParams; CK_ULONG ulCount; }; struct CK_PBE_PARAMS { CK_BYTE * pInitVector; CK_UTF8CHAR * pPassword; CK_ULONG ulPasswordLen; CK_BYTE * pSalt; CK_ULONG ulSaltLen; CK_ULONG ulIteration; }; struct CK_PKCS5_PBKD2_PARAMS { CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource; void * pSaltSourceData; CK_ULONG ulSaltSourceDataLen; CK_ULONG iterations; CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf; void * pPrfData; CK_ULONG ulPrfDataLen; CK_UTF8CHAR * pPassword; CK_ULONG * ulPasswordLen; }; struct CK_PKCS5_PBKD2_PARAMS2 { CK_PKCS5_PBKDF2_SALT_SOURCE_TYPE saltSource; void * pSaltSourceData; CK_ULONG ulSaltSourceDataLen; CK_ULONG iterations; CK_PKCS5_PBKD2_PSEUDO_RANDOM_FUNCTION_TYPE prf; void * pPrfData; CK_ULONG ulPrfDataLen; CK_UTF8CHAR * pPassword; CK_ULONG ulPasswordLen; }; struct CK_PRF_DATA_PARAM { CK_PRF_DATA_TYPE type; void * pValue; CK_ULONG ulValueLen; }; struct CK_RC2_CBC_PARAMS { CK_ULONG ulEffectiveBits; CK_BYTE iv[8]; }; struct CK_RC2_MAC_GENERAL_PARAMS { CK_ULONG ulEffectiveBits; CK_ULONG ulMacLength; }; struct CK_RC5_CBC_PARAMS { CK_ULONG ulWordsize; CK_ULONG ulRounds; CK_BYTE * pIv; CK_ULONG ulIvLen; }; struct CK_RC5_MAC_GENERAL_PARAMS { CK_ULONG ulWordsize; CK_ULONG ulRounds; CK_ULONG ulMacLength; }; struct CK_RC5_PARAMS { CK_ULONG ulWordsize; CK_ULONG ulRounds; }; struct CK_RSA_AES_KEY_WRAP_PARAMS { CK_ULONG ulAESKeyBits; CK_RSA_PKCS_OAEP_PARAMS * pOAEPParams; }; struct CK_RSA_PKCS_OAEP_PARAMS { CK_MECHANISM_TYPE hashAlg; CK_RSA_PKCS_MGF_TYPE mgf; CK_RSA_PKCS_OAEP_SOURCE_TYPE source; void * pSourceData; CK_ULONG ulSourceDataLen; }; struct CK_RSA_PKCS_PSS_PARAMS { CK_MECHANISM_TYPE hashAlg; CK_RSA_PKCS_MGF_TYPE mgf; CK_ULONG sLen; }; struct CK_SALSA20_CHACHA20_POLY1305_MSG_PARAMS { CK_BYTE * pNonce; CK_ULONG ulNonceLen; CK_BYTE * pTag; }; struct CK_SALSA20_CHACHA20_POLY1305_PARAMS { CK_BYTE * pNonce; CK_ULONG ulNonceLen; CK_BYTE * pAAD; CK_ULONG ulAADLen; }; struct CK_SALSA20_PARAMS { CK_BYTE * pBlockCounter; CK_BYTE * pNonce; CK_ULONG ulNonceBits; }; struct CK_SEED_CBC_ENCRYPT_DATA_PARAMS { CK_BYTE iv[16]; CK_BYTE * pData; CK_ULONG length; }; struct CK_SKIPJACK_PRIVATE_WRAP_PARAMS { CK_ULONG ulPasswordLen; CK_BYTE * pPassword; CK_ULONG ulPublicDataLen; CK_BYTE * pPublicData; CK_ULONG ulPAndGLen; CK_ULONG ulQLen; CK_ULONG ulRandomLen; CK_BYTE * pRandomA; CK_BYTE * pPrimeP; CK_BYTE * pBaseG; CK_BYTE * pSubprimeQ; }; struct CK_SKIPJACK_RELAYX_PARAMS { CK_ULONG ulOldWrappedXLen; CK_BYTE * pOldWrappedX; CK_ULONG ulOldPasswordLen; CK_BYTE * pOldPassword; CK_ULONG ulOldPublicDataLen; CK_BYTE * pOldPublicData; CK_ULONG ulOldRandomLen; CK_BYTE * pOldRandomA; CK_ULONG ulNewPasswordLen; CK_BYTE * pNewPassword; CK_ULONG ulNewPublicDataLen; CK_BYTE * pNewPublicData; CK_ULONG ulNewRandomLen; CK_BYTE * pNewRandomA; }; struct CK_SP800_108_COUNTER_FORMAT { CK_BBOOL bLittleEndian; CK_ULONG ulWidthInBits; }; struct CK_SP800_108_DKM_LENGTH_FORMAT { CK_SP800_108_DKM_LENGTH_METHOD dkmLengthMethod; CK_BBOOL bLittleEndian; CK_ULONG ulWidthInBits; }; typedef CK_MECHANISM_TYPE CK_SP800_108_PRF_TYPE; struct CK_SP800_108_FEEDBACK_KDF_PARAMS { CK_SP800_108_PRF_TYPE prfType; CK_ULONG ulNumberOfDataParams; CK_PRF_DATA_PARAM * pDataParams; CK_ULONG ulIVLen; CK_BYTE * pIV; CK_ULONG ulAdditionalDerivedKeys; CK_DERIVED_KEY * pAdditionalDerivedKeys; }; struct CK_SP800_108_KDF_PARAMS { CK_SP800_108_PRF_TYPE prfType; CK_ULONG ulNumberOfDataParams; CK_PRF_DATA_PARAM * pDataParams; CK_ULONG ulAdditionalDerivedKeys; CK_DERIVED_KEY * pAdditionalDerivedKeys; }; struct CK_X2RATCHET_INITIALIZE_PARAMS { CK_BYTE * sk; CK_OBJECT_HANDLE peer_public_prekey; CK_OBJECT_HANDLE peer_public_identity; CK_OBJECT_HANDLE own_public_identity; CK_BBOOL bEncryptedHeader; CK_ULONG eCurve; CK_MECHANISM_TYPE aeadMechanism; CK_X2RATCHET_KDF_TYPE kdfMechanism; }; struct CK_X2RATCHET_RESPOND_PARAMS { CK_BYTE * sk; CK_OBJECT_HANDLE own_prekey; CK_OBJECT_HANDLE initiator_identity; CK_OBJECT_HANDLE own_public_identity; CK_BBOOL bEncryptedHeader; CK_ULONG eCurve; CK_MECHANISM_TYPE aeadMechanism; CK_X2RATCHET_KDF_TYPE kdfMechanism; }; struct CK_X3DH_INITIATE_PARAMS { CK_X3DH_KDF_TYPE kdf; CK_OBJECT_HANDLE pPeer_identity; CK_OBJECT_HANDLE pPeer_prekey; CK_BYTE * pPrekey_signature; CK_BYTE * pOnetime_key; CK_OBJECT_HANDLE pOwn_identity; CK_OBJECT_HANDLE pOwn_ephemeral; }; struct CK_X3DH_RESPOND_PARAMS { CK_X3DH_KDF_TYPE kdf; CK_BYTE * pIdentity_id; CK_BYTE * pPrekey_id; CK_BYTE * pOnetime_id; CK_OBJECT_HANDLE pInitiator_identity; CK_BYTE * pInitiator_ephemeral; }; struct CK_X9_42_DH1_DERIVE_PARAMS { CK_X9_42_DH_KDF_TYPE kdf; CK_ULONG ulOtherInfoLen; CK_BYTE * pOtherInfo; CK_ULONG ulPublicDataLen; CK_BYTE * pPublicData; }; struct CK_X9_42_DH2_DERIVE_PARAMS { CK_X9_42_DH_KDF_TYPE kdf; CK_ULONG ulOtherInfoLen; CK_BYTE * pOtherInfo; CK_ULONG ulPublicDataLen; CK_BYTE * pPublicData; CK_ULONG ulPrivateDataLen; CK_OBJECT_HANDLE hPrivateData; CK_ULONG ulPublicDataLen2; CK_BYTE * pPublicData2; }; struct CK_X9_42_MQV_DERIVE_PARAMS { CK_X9_42_DH_KDF_TYPE kdf; CK_ULONG ulOtherInfoLen; CK_BYTE * OtherInfo; CK_ULONG ulPublicDataLen; CK_BYTE * PublicData; CK_ULONG ulPrivateDataLen; CK_OBJECT_HANDLE hPrivateData; CK_ULONG ulPublicDataLen2; CK_BYTE * PublicData2; CK_OBJECT_HANDLE publicKey; }; struct CK_XEDDSA_PARAMS { CK_XEDDSA_HASH_TYPE hash; }; struct specifiedParams { CK_HSS_LEVELS levels; CK_LMS_TYPE lm_type[8]; CK_LMOTS_TYPE lm_ots_type[8]; }; /* TLS related structure definitions */ STRUCTDEF(CK_SSL3_KEY_MAT_OUT); STRUCTDEF(CK_SSL3_KEY_MAT_PARAMS); STRUCTDEF(CK_SSL3_MASTER_KEY_DERIVE_PARAMS); STRUCTDEF(CK_SSL3_RANDOM_DATA); STRUCTDEF(CK_TLS_KDF_PARAMS); STRUCTDEF(CK_TLS_MAC_PARAMS); STRUCTDEF(CK_TLS_PRF_PARAMS); STRUCTDEF(CK_TLS12_KEY_MAT_PARAMS); STRUCTDEF(CK_TLS12_MASTER_KEY_DERIVE_PARAMS); STRUCTDEF(CK_WTLS_KEY_MAT_OUT); STRUCTDEF(CK_WTLS_KEY_MAT_PARAMS); STRUCTDEF(CK_WTLS_MASTER_KEY_DERIVE_PARAMS); STRUCTDEF(CK_WTLS_PRF_PARAMS); STRUCTDEF(CK_WTLS_RANDOM_DATA); struct CK_SSL3_KEY_MAT_OUT { CK_OBJECT_HANDLE hClientMacSecret; CK_OBJECT_HANDLE hServerMacSecret; CK_OBJECT_HANDLE hClientKey; CK_OBJECT_HANDLE hServerKey; CK_BYTE * pIVClient; CK_BYTE * pIVServer; }; struct CK_SSL3_RANDOM_DATA { CK_BYTE * pClientRandom; CK_ULONG ulClientRandomLen; CK_BYTE * pServerRandom; CK_ULONG ulServerRandomLen; }; struct CK_SSL3_KEY_MAT_PARAMS { CK_ULONG ulMacSizeInBits; CK_ULONG ulKeySizeInBits; CK_ULONG ulIVSizeInBits; CK_BBOOL bIsExport; CK_SSL3_RANDOM_DATA RandomInfo; CK_SSL3_KEY_MAT_OUT * pReturnedKeyMaterial; }; struct CK_SSL3_MASTER_KEY_DERIVE_PARAMS { CK_SSL3_RANDOM_DATA RandomInfo; CK_VERSION * pVersion; }; struct CK_TLS_KDF_PARAMS { CK_MECHANISM_TYPE prfMechanism; CK_BYTE * pLabel; CK_ULONG ulLabelLength; CK_SSL3_RANDOM_DATA RandomInfo; CK_BYTE * pContextData; CK_ULONG ulContextDataLength; }; struct CK_TLS_MAC_PARAMS { CK_MECHANISM_TYPE prfHashMechanism; CK_ULONG ulMacLength; CK_ULONG ulServerOrClient; }; struct CK_TLS_PRF_PARAMS { CK_BYTE * pSeed; CK_ULONG ulSeedLen; CK_BYTE * pLabel; CK_ULONG ulLabelLen; CK_BYTE * pOutput; CK_ULONG * pulOutputLen; }; struct CK_TLS12_KEY_MAT_PARAMS { CK_ULONG ulMacSizeInBits; CK_ULONG ulKeySizeInBits; CK_ULONG ulIVSizeInBits; CK_BBOOL bIsExport; CK_SSL3_RANDOM_DATA RandomInfo; CK_SSL3_KEY_MAT_OUT * pReturnedKeyMaterial; CK_MECHANISM_TYPE prfHashMechanism; }; struct CK_TLS12_MASTER_KEY_DERIVE_PARAMS { CK_SSL3_RANDOM_DATA RandomInfo; CK_VERSION * pVersion; CK_MECHANISM_TYPE prfHashMechanism; }; struct CK_WTLS_KEY_MAT_OUT { CK_OBJECT_HANDLE hMacSecret; CK_OBJECT_HANDLE hKey; CK_BYTE * pIV; }; struct CK_WTLS_RANDOM_DATA { CK_BYTE * pClientRandom; CK_ULONG ulClientRandomLen; CK_BYTE * pServerRandom; CK_ULONG ulServerRandomLen; }; struct CK_WTLS_KEY_MAT_PARAMS { CK_MECHANISM_TYPE DigestMechanism; CK_ULONG ulMacSizeInBits; CK_ULONG ulKeySizeInBits; CK_ULONG ulIVSizeInBits; CK_ULONG ulSequenceNumber; CK_BBOOL bIsExport; CK_WTLS_RANDOM_DATA RandomInfo; CK_WTLS_KEY_MAT_OUT * pReturnedKeyMaterial; }; struct CK_WTLS_MASTER_KEY_DERIVE_PARAMS { CK_MECHANISM_TYPE DigestMechanism; CK_WTLS_RANDOM_DATA RandomInfo; CK_BYTE * pVersion; }; struct CK_WTLS_PRF_PARAMS { CK_MECHANISM_TYPE DigestMechanism; CK_BYTE * pSeed; CK_ULONG ulSeedLen; CK_BYTE * pLabel; CK_ULONG ulLabelLen; CK_BYTE * pOutput; CK_ULONG * pulOutputLen; }; /* PKCS11 Functions */ extern CK_RV C_Initialize(void *); extern CK_RV C_Finalize(void *); extern CK_RV C_GetInfo(CK_INFO *); extern CK_RV C_GetFunctionList(CK_FUNCTION_LIST **); extern CK_RV C_GetSlotList(CK_BBOOL, CK_SLOT_ID *, CK_ULONG *); extern CK_RV C_GetSlotInfo(CK_SLOT_ID, CK_SLOT_INFO *); extern CK_RV C_GetTokenInfo(CK_SLOT_ID, CK_TOKEN_INFO *); extern CK_RV C_GetMechanismList(CK_SLOT_ID, CK_MECHANISM_TYPE *, CK_ULONG *); extern CK_RV C_GetMechanismInfo(CK_SLOT_ID, CK_MECHANISM_TYPE, CK_MECHANISM_INFO *); extern CK_RV C_InitToken(CK_SLOT_ID, CK_UTF8CHAR *, CK_ULONG, CK_UTF8CHAR *); extern CK_RV C_InitPIN(CK_SESSION_HANDLE, CK_UTF8CHAR *, CK_ULONG); extern CK_RV C_SetPIN(CK_SESSION_HANDLE, CK_UTF8CHAR *, CK_ULONG, CK_UTF8CHAR *, CK_ULONG); extern CK_RV C_OpenSession(CK_SLOT_ID, CK_FLAGS, void *, CK_NOTIFY, CK_SESSION_HANDLE *); extern CK_RV C_CloseSession(CK_SESSION_HANDLE); extern CK_RV C_CloseAllSessions(CK_SLOT_ID); extern CK_RV C_GetSessionInfo(CK_SESSION_HANDLE, CK_SESSION_INFO *); extern CK_RV C_GetOperationState(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG *); extern CK_RV C_SetOperationState(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE); extern CK_RV C_Login(CK_SESSION_HANDLE, CK_USER_TYPE, CK_UTF8CHAR *, CK_ULONG); extern CK_RV C_Logout(CK_SESSION_HANDLE); extern CK_RV C_CreateObject(CK_SESSION_HANDLE, CK_ATTRIBUTE *, CK_ULONG, CK_OBJECT_HANDLE *); extern CK_RV C_CopyObject(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_ATTRIBUTE *, CK_ULONG, CK_OBJECT_HANDLE *); extern CK_RV C_DestroyObject(CK_SESSION_HANDLE, CK_OBJECT_HANDLE); extern CK_RV C_GetObjectSize(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_ULONG *); extern CK_RV C_GetAttributeValue(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_ATTRIBUTE *, CK_ULONG); extern CK_RV C_SetAttributeValue(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_ATTRIBUTE *, CK_ULONG); extern CK_RV C_FindObjectsInit(CK_SESSION_HANDLE, CK_ATTRIBUTE *, CK_ULONG); extern CK_RV C_FindObjects(CK_SESSION_HANDLE, CK_OBJECT_HANDLE *, CK_ULONG, CK_ULONG *); extern CK_RV C_FindObjectsFinal(CK_SESSION_HANDLE); extern CK_RV C_EncryptInit(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); extern CK_RV C_Encrypt(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); extern CK_RV C_EncryptUpdate(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); extern CK_RV C_EncryptFinal(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG *); extern CK_RV C_DecryptInit(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); extern CK_RV C_Decrypt(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); extern CK_RV C_DecryptUpdate(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); extern CK_RV C_DecryptFinal(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG *); extern CK_RV C_DigestInit(CK_SESSION_HANDLE, CK_MECHANISM *); extern CK_RV C_Digest(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); extern CK_RV C_DigestUpdate(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG); extern CK_RV C_DigestKey(CK_SESSION_HANDLE, CK_OBJECT_HANDLE); extern CK_RV C_DigestFinal(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG *); extern CK_RV C_SignInit(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); extern CK_RV C_Sign(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); extern CK_RV C_SignUpdate(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG); extern CK_RV C_SignFinal(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG *); extern CK_RV C_SignRecoverInit(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); extern CK_RV C_SignRecover(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); extern CK_RV C_VerifyInit(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); extern CK_RV C_Verify(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG); extern CK_RV C_VerifyUpdate(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG); extern CK_RV C_VerifyFinal(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG); extern CK_RV C_VerifyRecoverInit(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); extern CK_RV C_VerifyRecover(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); extern CK_RV C_DigestEncryptUpdate(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); extern CK_RV C_DecryptDigestUpdate(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); extern CK_RV C_SignEncryptUpdate(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); extern CK_RV C_DecryptVerifyUpdate(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); extern CK_RV C_GenerateKey(CK_SESSION_HANDLE, CK_MECHANISM *, CK_ATTRIBUTE *, CK_ULONG, CK_OBJECT_HANDLE *); extern CK_RV C_GenerateKeyPair(CK_SESSION_HANDLE, CK_MECHANISM *, CK_ATTRIBUTE *, CK_ULONG, CK_ATTRIBUTE *, CK_ULONG, CK_OBJECT_HANDLE *, CK_OBJECT_HANDLE *); extern CK_RV C_WrapKey(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE, CK_BYTE *, CK_ULONG *); extern CK_RV C_UnwrapKey(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE, CK_BYTE *, CK_ULONG *, CK_ATTRIBUTE *, CK_ULONG, CK_OBJECT_HANDLE *); extern CK_RV C_DeriveKey(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE, CK_ATTRIBUTE *, CK_ULONG, CK_OBJECT_HANDLE *); extern CK_RV C_SeedRandom(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG); extern CK_RV C_GenerateRandom(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG); extern CK_RV C_GetFunctionStatus(CK_SESSION_HANDLE); extern CK_RV C_CancelFunction(CK_SESSION_HANDLE); extern CK_RV C_WaitForSlotEvent(CK_FLAGS, CK_SLOT_ID *, void *); extern CK_RV C_GetInterfaceList(CK_INTERFACE *, CK_ULONG *); extern CK_RV C_GetInterface(CK_UTF8CHAR *, CK_VERSION *, CK_INTERFACE **, CK_FLAGS); extern CK_RV C_LoginUser(CK_SESSION_HANDLE, CK_USER_TYPE, CK_UTF8CHAR *, CK_ULONG, CK_UTF8CHAR *, CK_ULONG); extern CK_RV C_SessionCancel(CK_SESSION_HANDLE, CK_FLAGS); extern CK_RV C_MessageEncryptInit(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); extern CK_RV C_EncryptMessage(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); extern CK_RV C_EncryptMessageBegin(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG); extern CK_RV C_EncryptMessageNext(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, CK_FLAGS); extern CK_RV C_MessageEncryptFinal(CK_SESSION_HANDLE); extern CK_RV C_MessageDecryptInit(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); extern CK_RV C_DecryptMessage(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); extern CK_RV C_DecryptMessageBegin(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG); extern CK_RV C_DecryptMessageNext(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, CK_FLAGS); extern CK_RV C_MessageDecryptFinal(CK_SESSION_HANDLE); extern CK_RV C_MessageSignInit(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); extern CK_RV C_SignMessage(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); extern CK_RV C_SignMessageBegin(CK_SESSION_HANDLE, void *, CK_ULONG); extern CK_RV C_SignMessageNext(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); extern CK_RV C_MessageSignFinal(CK_SESSION_HANDLE); extern CK_RV C_MessageVerifyInit(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); extern CK_RV C_VerifyMessage(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG); extern CK_RV C_VerifyMessageBegin(CK_SESSION_HANDLE, void *, CK_ULONG); extern CK_RV C_VerifyMessageNext(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG); extern CK_RV C_MessageVerifyFinal(CK_SESSION_HANDLE); typedef CK_RV (* CK_C_Initialize)(void *); typedef CK_RV (* CK_C_Finalize)(void *); typedef CK_RV (* CK_C_GetInfo)(CK_INFO *); typedef CK_RV (* CK_C_GetFunctionList)(CK_FUNCTION_LIST **); typedef CK_RV (* CK_C_GetSlotList)(CK_BBOOL, CK_SLOT_ID *, CK_ULONG *); typedef CK_RV (* CK_C_GetSlotInfo)(CK_SLOT_ID, CK_SLOT_INFO *); typedef CK_RV (* CK_C_GetTokenInfo)(CK_SLOT_ID, CK_TOKEN_INFO *); typedef CK_RV (* CK_C_GetMechanismList)(CK_SLOT_ID, CK_MECHANISM_TYPE *, CK_ULONG *); typedef CK_RV (* CK_C_GetMechanismInfo)(CK_SLOT_ID, CK_MECHANISM_TYPE, CK_MECHANISM_INFO *); typedef CK_RV (* CK_C_InitToken)(CK_SLOT_ID, CK_UTF8CHAR *, CK_ULONG, CK_UTF8CHAR *); typedef CK_RV (* CK_C_InitPIN)(CK_SESSION_HANDLE, CK_UTF8CHAR *, CK_ULONG); typedef CK_RV (* CK_C_SetPIN)(CK_SESSION_HANDLE, CK_UTF8CHAR *, CK_ULONG, CK_UTF8CHAR *, CK_ULONG); typedef CK_RV (* CK_C_OpenSession)(CK_SLOT_ID, CK_FLAGS, void *, CK_NOTIFY, CK_SESSION_HANDLE *); typedef CK_RV (* CK_C_CloseSession)(CK_SESSION_HANDLE); typedef CK_RV (* CK_C_CloseAllSessions)(CK_SLOT_ID); typedef CK_RV (* CK_C_GetSessionInfo)(CK_SESSION_HANDLE, CK_SESSION_INFO *); typedef CK_RV (* CK_C_GetOperationState)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_SetOperationState)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE); typedef CK_RV (* CK_C_Login)(CK_SESSION_HANDLE, CK_USER_TYPE, CK_UTF8CHAR *, CK_ULONG); typedef CK_RV (* CK_C_Logout)(CK_SESSION_HANDLE); typedef CK_RV (* CK_C_CreateObject)(CK_SESSION_HANDLE, CK_ATTRIBUTE *, CK_ULONG, CK_OBJECT_HANDLE *); typedef CK_RV (* CK_C_CopyObject)(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_ATTRIBUTE *, CK_ULONG, CK_OBJECT_HANDLE *); typedef CK_RV (* CK_C_DestroyObject)(CK_SESSION_HANDLE, CK_OBJECT_HANDLE); typedef CK_RV (* CK_C_GetObjectSize)(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_ULONG *); typedef CK_RV (* CK_C_GetAttributeValue)(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_ATTRIBUTE *, CK_ULONG); typedef CK_RV (* CK_C_SetAttributeValue)(CK_SESSION_HANDLE, CK_OBJECT_HANDLE, CK_ATTRIBUTE *, CK_ULONG); typedef CK_RV (* CK_C_FindObjectsInit)(CK_SESSION_HANDLE, CK_ATTRIBUTE *, CK_ULONG); typedef CK_RV (* CK_C_FindObjects)(CK_SESSION_HANDLE, CK_OBJECT_HANDLE *, CK_ULONG, CK_ULONG *); typedef CK_RV (* CK_C_FindObjectsFinal)(CK_SESSION_HANDLE); typedef CK_RV (* CK_C_EncryptInit)(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); typedef CK_RV (* CK_C_Encrypt)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_EncryptUpdate)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_EncryptFinal)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_DecryptInit)(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); typedef CK_RV (* CK_C_Decrypt)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_DecryptUpdate)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_DecryptFinal)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_DigestInit)(CK_SESSION_HANDLE, CK_MECHANISM *); typedef CK_RV (* CK_C_Digest)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_DigestUpdate)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG); typedef CK_RV (* CK_C_DigestKey)(CK_SESSION_HANDLE, CK_OBJECT_HANDLE); typedef CK_RV (* CK_C_DigestFinal)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_SignInit)(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); typedef CK_RV (* CK_C_Sign)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_SignUpdate)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG); typedef CK_RV (* CK_C_SignFinal)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_SignRecoverInit)(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); typedef CK_RV (* CK_C_SignRecover)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_VerifyInit)(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); typedef CK_RV (* CK_C_Verify)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG); typedef CK_RV (* CK_C_VerifyUpdate)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG); typedef CK_RV (* CK_C_VerifyFinal)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG); typedef CK_RV (* CK_C_VerifyRecoverInit)(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); typedef CK_RV (* CK_C_VerifyRecover)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_DigestEncryptUpdate)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_DecryptDigestUpdate)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_SignEncryptUpdate)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_DecryptVerifyUpdate)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_GenerateKey)(CK_SESSION_HANDLE, CK_MECHANISM *, CK_ATTRIBUTE *, CK_ULONG, CK_OBJECT_HANDLE *); typedef CK_RV (* CK_C_GenerateKeyPair)(CK_SESSION_HANDLE, CK_MECHANISM *, CK_ATTRIBUTE *, CK_ULONG, CK_ATTRIBUTE *, CK_ULONG, CK_OBJECT_HANDLE *, CK_OBJECT_HANDLE *); typedef CK_RV (* CK_C_WrapKey)(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE, CK_OBJECT_HANDLE, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_UnwrapKey)(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE, CK_BYTE *, CK_ULONG, CK_ATTRIBUTE *, CK_ULONG, CK_OBJECT_HANDLE *); typedef CK_RV (* CK_C_DeriveKey)(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE, CK_ATTRIBUTE *, CK_ULONG, CK_OBJECT_HANDLE *); typedef CK_RV (* CK_C_SeedRandom)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG); typedef CK_RV (* CK_C_GenerateRandom)(CK_SESSION_HANDLE, CK_BYTE *, CK_ULONG); typedef CK_RV (* CK_C_GetFunctionStatus)(CK_SESSION_HANDLE); typedef CK_RV (* CK_C_CancelFunction)(CK_SESSION_HANDLE); typedef CK_RV (* CK_C_WaitForSlotEvent)(CK_FLAGS, CK_SLOT_ID *, void *); typedef CK_RV (* CK_C_GetInterfaceList)(CK_INTERFACE *, CK_ULONG *); typedef CK_RV (* CK_C_GetInterface)(CK_UTF8CHAR *, CK_VERSION *, CK_INTERFACE **, CK_FLAGS); typedef CK_RV (* CK_C_LoginUser)(CK_SESSION_HANDLE, CK_USER_TYPE, CK_UTF8CHAR *, CK_ULONG, CK_UTF8CHAR *, CK_ULONG); typedef CK_RV (* CK_C_SessionCancel)(CK_SESSION_HANDLE, CK_FLAGS); typedef CK_RV (* CK_C_MessageEncryptInit)(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); typedef CK_RV (* CK_C_EncryptMessage)(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_EncryptMessageBegin)(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG); typedef CK_RV (* CK_C_EncryptMessageNext)(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, CK_FLAGS); typedef CK_RV (* CK_C_MessageEncryptFinal)(CK_SESSION_HANDLE); typedef CK_RV (* CK_C_MessageDecryptInit)(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); typedef CK_RV (* CK_C_DecryptMessage)(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_DecryptMessageBegin)(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG); typedef CK_RV (* CK_C_DecryptMessageNext)(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *, CK_FLAGS); typedef CK_RV (* CK_C_MessageDecryptFinal)(CK_SESSION_HANDLE); typedef CK_RV (* CK_C_MessageSignInit)(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); typedef CK_RV (* CK_C_SignMessage)(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_SignMessageBegin)(CK_SESSION_HANDLE, void *, CK_ULONG); typedef CK_RV (* CK_C_SignMessageNext)(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG *); typedef CK_RV (* CK_C_MessageSignFinal)(CK_SESSION_HANDLE); typedef CK_RV (* CK_C_MessageVerifyInit)(CK_SESSION_HANDLE, CK_MECHANISM *, CK_OBJECT_HANDLE); typedef CK_RV (* CK_C_VerifyMessage)(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG); typedef CK_RV (* CK_C_VerifyMessageBegin)(CK_SESSION_HANDLE, void *, CK_ULONG); typedef CK_RV (* CK_C_VerifyMessageNext)(CK_SESSION_HANDLE, void *, CK_ULONG, CK_BYTE *, CK_ULONG, CK_BYTE *, CK_ULONG); typedef CK_RV (* CK_C_MessageVerifyFinal)(CK_SESSION_HANDLE); struct CK_FUNCTION_LIST_3_0 { CK_VERSION version; CK_C_Initialize C_Initialize; CK_C_Finalize C_Finalize; CK_C_GetInfo C_GetInfo; CK_C_GetFunctionList C_GetFunctionList; CK_C_GetSlotList C_GetSlotList; CK_C_GetSlotInfo C_GetSlotInfo; CK_C_GetTokenInfo C_GetTokenInfo; CK_C_GetMechanismList C_GetMechanismList; CK_C_GetMechanismInfo C_GetMechanismInfo; CK_C_InitToken C_InitToken; CK_C_InitPIN C_InitPIN; CK_C_SetPIN C_SetPIN; CK_C_OpenSession C_OpenSession; CK_C_CloseSession C_CloseSession; CK_C_CloseAllSessions C_CloseAllSessions; CK_C_GetSessionInfo C_GetSessionInfo; CK_C_GetOperationState C_GetOperationState; CK_C_SetOperationState C_SetOperationState; CK_C_Login C_Login; CK_C_Logout C_Logout; CK_C_CreateObject C_CreateObject; CK_C_CopyObject C_CopyObject; CK_C_DestroyObject C_DestroyObject; CK_C_GetObjectSize C_GetObjectSize; CK_C_GetAttributeValue C_GetAttributeValue; CK_C_SetAttributeValue C_SetAttributeValue; CK_C_FindObjectsInit C_FindObjectsInit; CK_C_FindObjects C_FindObjects; CK_C_FindObjectsFinal C_FindObjectsFinal; CK_C_EncryptInit C_EncryptInit; CK_C_Encrypt C_Encrypt; CK_C_EncryptUpdate C_EncryptUpdate; CK_C_EncryptFinal C_EncryptFinal; CK_C_DecryptInit C_DecryptInit; CK_C_Decrypt C_Decrypt; CK_C_DecryptUpdate C_DecryptUpdate; CK_C_DecryptFinal C_DecryptFinal; CK_C_DigestInit C_DigestInit; CK_C_Digest C_Digest; CK_C_DigestUpdate C_DigestUpdate; CK_C_DigestKey C_DigestKey; CK_C_DigestFinal C_DigestFinal; CK_C_SignInit C_SignInit; CK_C_Sign C_Sign; CK_C_SignUpdate C_SignUpdate; CK_C_SignFinal C_SignFinal; CK_C_SignRecoverInit C_SignRecoverInit; CK_C_SignRecover C_SignRecover; CK_C_VerifyInit C_VerifyInit; CK_C_Verify C_Verify; CK_C_VerifyUpdate C_VerifyUpdate; CK_C_VerifyFinal C_VerifyFinal; CK_C_VerifyRecoverInit C_VerifyRecoverInit; CK_C_VerifyRecover C_VerifyRecover; CK_C_DigestEncryptUpdate C_DigestEncryptUpdate; CK_C_DecryptDigestUpdate C_DecryptDigestUpdate; CK_C_SignEncryptUpdate C_SignEncryptUpdate; CK_C_DecryptVerifyUpdate C_DecryptVerifyUpdate; CK_C_GenerateKey C_GenerateKey; CK_C_GenerateKeyPair C_GenerateKeyPair; CK_C_WrapKey C_WrapKey; CK_C_UnwrapKey C_UnwrapKey; CK_C_DeriveKey C_DeriveKey; CK_C_SeedRandom C_SeedRandom; CK_C_GenerateRandom C_GenerateRandom; CK_C_GetFunctionStatus C_GetFunctionStatus; CK_C_CancelFunction C_CancelFunction; CK_C_WaitForSlotEvent C_WaitForSlotEvent; CK_C_GetInterfaceList C_GetInterfaceList; CK_C_GetInterface C_GetInterface; CK_C_LoginUser C_LoginUser; CK_C_SessionCancel C_SessionCancel; CK_C_MessageEncryptInit C_MessageEncryptInit; CK_C_EncryptMessage C_EncryptMessage; CK_C_EncryptMessageBegin C_EncryptMessageBegin; CK_C_EncryptMessageNext C_EncryptMessageNext; CK_C_MessageEncryptFinal C_MessageEncryptFinal; CK_C_MessageDecryptInit C_MessageDecryptInit; CK_C_DecryptMessage C_DecryptMessage; CK_C_DecryptMessageBegin C_DecryptMessageBegin; CK_C_DecryptMessageNext C_DecryptMessageNext; CK_C_MessageDecryptFinal C_MessageDecryptFinal; CK_C_MessageSignInit C_MessageSignInit; CK_C_SignMessage C_SignMessage; CK_C_SignMessageBegin C_SignMessageBegin; CK_C_SignMessageNext C_SignMessageNext; CK_C_MessageSignFinal C_MessageSignFinal; CK_C_MessageVerifyInit C_MessageVerifyInit; CK_C_VerifyMessage C_VerifyMessage; CK_C_VerifyMessageBegin C_VerifyMessageBegin; CK_C_VerifyMessageNext C_VerifyMessageNext; CK_C_MessageVerifyFinal C_MessageVerifyFinal; }; struct CK_FUNCTION_LIST { CK_VERSION version; CK_C_Initialize C_Initialize; CK_C_Finalize C_Finalize; CK_C_GetInfo C_GetInfo; CK_C_GetFunctionList C_GetFunctionList; CK_C_GetSlotList C_GetSlotList; CK_C_GetSlotInfo C_GetSlotInfo; CK_C_GetTokenInfo C_GetTokenInfo; CK_C_GetMechanismList C_GetMechanismList; CK_C_GetMechanismInfo C_GetMechanismInfo; CK_C_InitToken C_InitToken; CK_C_InitPIN C_InitPIN; CK_C_SetPIN C_SetPIN; CK_C_OpenSession C_OpenSession; CK_C_CloseSession C_CloseSession; CK_C_CloseAllSessions C_CloseAllSessions; CK_C_GetSessionInfo C_GetSessionInfo; CK_C_GetOperationState C_GetOperationState; CK_C_SetOperationState C_SetOperationState; CK_C_Login C_Login; CK_C_Logout C_Logout; CK_C_CreateObject C_CreateObject; CK_C_CopyObject C_CopyObject; CK_C_DestroyObject C_DestroyObject; CK_C_GetObjectSize C_GetObjectSize; CK_C_GetAttributeValue C_GetAttributeValue; CK_C_SetAttributeValue C_SetAttributeValue; CK_C_FindObjectsInit C_FindObjectsInit; CK_C_FindObjects C_FindObjects; CK_C_FindObjectsFinal C_FindObjectsFinal; CK_C_EncryptInit C_EncryptInit; CK_C_Encrypt C_Encrypt; CK_C_EncryptUpdate C_EncryptUpdate; CK_C_EncryptFinal C_EncryptFinal; CK_C_DecryptInit C_DecryptInit; CK_C_Decrypt C_Decrypt; CK_C_DecryptUpdate C_DecryptUpdate; CK_C_DecryptFinal C_DecryptFinal; CK_C_DigestInit C_DigestInit; CK_C_Digest C_Digest; CK_C_DigestUpdate C_DigestUpdate; CK_C_DigestKey C_DigestKey; CK_C_DigestFinal C_DigestFinal; CK_C_SignInit C_SignInit; CK_C_Sign C_Sign; CK_C_SignUpdate C_SignUpdate; CK_C_SignFinal C_SignFinal; CK_C_SignRecoverInit C_SignRecoverInit; CK_C_SignRecover C_SignRecover; CK_C_VerifyInit C_VerifyInit; CK_C_Verify C_Verify; CK_C_VerifyUpdate C_VerifyUpdate; CK_C_VerifyFinal C_VerifyFinal; CK_C_VerifyRecoverInit C_VerifyRecoverInit; CK_C_VerifyRecover C_VerifyRecover; CK_C_DigestEncryptUpdate C_DigestEncryptUpdate; CK_C_DecryptDigestUpdate C_DecryptDigestUpdate; CK_C_SignEncryptUpdate C_SignEncryptUpdate; CK_C_DecryptVerifyUpdate C_DecryptVerifyUpdate; CK_C_GenerateKey C_GenerateKey; CK_C_GenerateKeyPair C_GenerateKeyPair; CK_C_WrapKey C_WrapKey; CK_C_UnwrapKey C_UnwrapKey; CK_C_DeriveKey C_DeriveKey; CK_C_SeedRandom C_SeedRandom; CK_C_GenerateRandom C_GenerateRandom; CK_C_GetFunctionStatus C_GetFunctionStatus; CK_C_CancelFunction C_CancelFunction; CK_C_WaitForSlotEvent C_WaitForSlotEvent; }; #endif pkcs11-provider-1.0/src/platform/000077500000000000000000000000001475270623700167345ustar00rootroot00000000000000pkcs11-provider-1.0/src/platform/endian.h000066400000000000000000000101571475270623700203470ustar00rootroot00000000000000/* Copyright (C) Internet Systems Consortium, Inc. ("ISC") SPDX-License-Identifier: Apache-2.0 */ #ifndef _P11PROV_ENDIAN_H #define _P11PROV_ENDIAN_H #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || \ defined(__OpenBSD__) || defined(__bsdi__) #include /* * Recent BSDs should have [bl]e{16,32,64}toh() defined in . * Older ones might not, but these should have the alternatively named * [bl]etoh{16,32,64}() functions defined. */ #ifndef be16toh #define be16toh(x) betoh16(x) #define le16toh(x) letoh16(x) #define be32toh(x) betoh32(x) #define le32toh(x) letoh32(x) #define be64toh(x) betoh64(x) #define le64toh(x) letoh64(x) #endif /* !be16toh */ #elif defined __APPLE__ /* * macOS has its own byte-swapping routines, so use these. */ #include #define htobe16(x) OSSwapHostToBigInt16(x) #define htole16(x) OSSwapHostToLittleInt16(x) #define be16toh(x) OSSwapBigToHostInt16(x) #define le16toh(x) OSSwapLittleToHostInt16(x) #define htobe32(x) OSSwapHostToBigInt32(x) #define htole32(x) OSSwapHostToLittleInt32(x) #define be32toh(x) OSSwapBigToHostInt32(x) #define le32toh(x) OSSwapLittleToHostInt32(x) #define htobe64(x) OSSwapHostToBigInt64(x) #define htole64(x) OSSwapHostToLittleInt64(x) #define be64toh(x) OSSwapBigToHostInt64(x) #define le64toh(x) OSSwapLittleToHostInt64(x) #elif defined(sun) || defined(__sun) || defined(__SVR4) /* * For Solaris, rely on the fallback definitions below, though use * Solaris-specific versions of bswap_{16,32,64}(). */ #include #define bswap_16(x) BSWAP_16(x) #define bswap_32(x) BSWAP_32(x) #define bswap_64(x) BSWAP_64(x) #elif defined(__ANDROID__) || defined(__CYGWIN__) || defined(__GNUC__) || \ defined(__GNU__) #include #include #else /* if defined(__DragonFly__) || defined(__FreeBSD__) || \ * defined(__NetBSD__) || defined(__OpenBSD__) || defined(__bsdi__) */ #endif /* Specific platform support */ /* * Fallback definitions. */ #include #ifndef bswap_16 #define bswap_16(x) \ ((uint16_t)((((uint16_t)(x)&0xff00) >> 8) | \ (((uint16_t)(x)&0x00ff) << 8))) #endif /* !bswap_16 */ #ifndef bswap_32 #define bswap_32(x) \ ((uint32_t)((((uint32_t)(x)&0xff000000) >> 24) | \ (((uint32_t)(x)&0x00ff0000) >> 8) | \ (((uint32_t)(x)&0x0000ff00) << 8) | \ (((uint32_t)(x)&0x000000ff) << 24))) #endif /* !bswap_32 */ #ifndef bswap_64 #define bswap_64(x) \ ((uint64_t)((((uint64_t)(x)&0xff00000000000000ULL) >> 56) | \ (((uint64_t)(x)&0x00ff000000000000ULL) >> 40) | \ (((uint64_t)(x)&0x0000ff0000000000ULL) >> 24) | \ (((uint64_t)(x)&0x000000ff00000000ULL) >> 8) | \ (((uint64_t)(x)&0x00000000ff000000ULL) << 8) | \ (((uint64_t)(x)&0x0000000000ff0000ULL) << 24) | \ (((uint64_t)(x)&0x000000000000ff00ULL) << 40) | \ (((uint64_t)(x)&0x00000000000000ffULL) << 56))) #endif /* !bswap_64 */ #ifndef htobe16 #if WORDS_BIGENDIAN #define htobe16(x) (x) #define htole16(x) bswap_16(x) #define be16toh(x) (x) #define le16toh(x) bswap_16(x) #else /* WORDS_BIGENDIAN */ #define htobe16(x) bswap_16(x) #define htole16(x) (x) #define be16toh(x) bswap_16(x) #define le16toh(x) (x) #endif /* WORDS_BIGENDIAN */ #endif /* !htobe16 */ #ifndef htobe32 #if WORDS_BIGENDIAN #define htobe32(x) (x) #define htole32(x) bswap_32(x) #define be32toh(x) (x) #define le32toh(x) bswap_32(x) #else /* WORDS_BIGENDIAN */ #define htobe32(x) bswap_32(x) #define htole32(x) (x) #define be32toh(x) bswap_32(x) #define le32toh(x) (x) #endif /* WORDS_BIGENDIAN */ #endif /* !htobe32 */ #ifndef htobe64 #if WORDS_BIGENDIAN #define htobe64(x) (x) #define htole64(x) bswap_64(x) #define be64toh(x) (x) #define le64toh(x) bswap_64(x) #else /* WORDS_BIGENDIAN */ #define htobe64(x) bswap_64(x) #define htole64(x) (x) #define be64toh(x) bswap_64(x) #define le64toh(x) (x) #endif /* WORDS_BIGENDIAN */ #endif /* !htobe64 */ void byteswap_buf(unsigned char *src, unsigned char *dest, size_t len); #endif /* _P11PROV_ENDIAN_H */ pkcs11-provider-1.0/src/provider.c000066400000000000000000001620521475270623700171140ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include "decoder.h" #include #include struct p11prov_interface; struct quirk; struct p11prov_ctx { enum { P11PROV_UNINITIALIZED = 0, P11PROV_INITIALIZED, P11PROV_NEEDS_REINIT, P11PROV_NO_DEINIT, P11PROV_IN_ERROR, } status; /* Provider handles */ const OSSL_CORE_HANDLE *handle; OSSL_LIB_CTX *libctx; /* Configuration */ char *pin; int allow_export; int login_behavior; bool cache_pins; int cache_keys; int cache_sessions; bool encode_pkey_as_pk11_uri; bool assume_fips; /* TODO: ui_method */ /* TODO: fork id */ /* cfg quirks */ bool no_deinit; bool no_allowed_mechanisms; bool no_session_callbacks; uint64_t blocked_calls; bool blocked_ops[OSSL_OP__HIGHEST + 1]; /* module handles and data */ P11PROV_MODULE *module; P11PROV_SLOTS_CTX *slots; OSSL_ALGORITHM *op_digest; OSSL_ALGORITHM *op_kdf; OSSL_ALGORITHM *op_random; OSSL_ALGORITHM *op_exchange; OSSL_ALGORITHM *op_signature; OSSL_ALGORITHM *op_asym_cipher; OSSL_ALGORITHM *op_encoder; OSSL_ALGORITHM *op_decoder; OSSL_ALGORITHM *op_keymgmt; OSSL_ALGORITHM *op_store; pthread_rwlock_t quirk_lock; struct quirk *quirks; int nquirks; }; static struct p11prov_context_pool { struct p11prov_ctx **contexts; int num; pthread_rwlock_t rwlock; } ctx_pool = { .contexts = NULL, .num = 0, .rwlock = PTHREAD_RWLOCK_INITIALIZER, }; static void fork_prepare(void) { int err; err = pthread_rwlock_rdlock(&ctx_pool.rwlock); if (err != 0) { err = errno; P11PROV_debug("Can't lock contexts pool (error=%d)", err); } for (int i = 0; i < ctx_pool.num; i++) { if (ctx_pool.contexts[i]->status == P11PROV_INITIALIZED) { p11prov_slot_fork_prepare(ctx_pool.contexts[i]->slots); } } } static void fork_parent(void) { int err; for (int i = 0; i < ctx_pool.num; i++) { if (ctx_pool.contexts[i]->status == P11PROV_INITIALIZED) { p11prov_slot_fork_release(ctx_pool.contexts[i]->slots); } } err = pthread_rwlock_unlock(&ctx_pool.rwlock); if (err != 0) { err = errno; P11PROV_debug("Failed to release context pool (errno:%d)", err); } } static void fork_child(void) { int err; /* rwlock, saves TID internally, so we need to reset * after fork in the child */ p11prov_force_rwlock_reinit(&ctx_pool.rwlock); /* This is running in the fork handler, so there should be no * way to have other threads running, but just in case some * crazy library creates threads in their child handler */ err = pthread_rwlock_wrlock(&ctx_pool.rwlock); if (err != 0) { err = errno; P11PROV_debug("Failed to get slots lock (errno:%d)", err); return; } for (int i = 0; i < ctx_pool.num; i++) { if (ctx_pool.contexts[i]->status == P11PROV_INITIALIZED) { /* can't re-init in the fork handler, mark it */ ctx_pool.contexts[i]->status = P11PROV_NEEDS_REINIT; p11prov_module_mark_reinit(ctx_pool.contexts[i]->module); p11prov_slot_fork_reset(ctx_pool.contexts[i]->slots); } } err = pthread_rwlock_unlock(&ctx_pool.rwlock); if (err != 0) { err = errno; P11PROV_debug("Failed to release context pool (errno:%d)", err); } } #define CTX_POOL_ALLOC 4 static void context_add_pool(struct p11prov_ctx *ctx) { int err; /* init static pool for atfork/atexit handling */ err = pthread_rwlock_wrlock(&ctx_pool.rwlock); if (err != 0) { /* just warn */ err = errno; P11PROV_raise(ctx, CKR_CANT_LOCK, "Failed to lock ctx pool (error:%d)", err); return; } /* WRLOCKED ------------------------------------------------- */ if (ctx_pool.contexts == NULL) { ctx_pool.contexts = OPENSSL_zalloc(CTX_POOL_ALLOC * sizeof(P11PROV_CTX *)); if (!ctx_pool.contexts) { P11PROV_raise(ctx, CKR_HOST_MEMORY, "Failed to alloc ctx pool"); goto done; } err = pthread_atfork(fork_prepare, fork_parent, fork_child); if (err != 0) { /* just warn, nothing much we can do */ P11PROV_raise(ctx, CKR_GENERAL_ERROR, "Failed to register fork handlers (error:%d)", err); } } else { if (ctx_pool.num % CTX_POOL_ALLOC == 0) { P11PROV_CTX **tmp; tmp = OPENSSL_realloc(ctx_pool.contexts, (ctx_pool.num + CTX_POOL_ALLOC) * sizeof(P11PROV_CTX *)); if (!tmp) { P11PROV_raise(ctx, CKR_HOST_MEMORY, "Failed to realloc ctx pool"); goto done; } ctx_pool.contexts = tmp; } } ctx_pool.contexts[ctx_pool.num] = ctx; ctx_pool.num++; done: /* ------------------------------------------------- WRLOCKED */ (void)pthread_rwlock_unlock(&ctx_pool.rwlock); return; } static void context_rm_pool(struct p11prov_ctx *ctx) { int found = false; int err; /* init static pool for atfork/atexit handling */ err = pthread_rwlock_wrlock(&ctx_pool.rwlock); if (err != 0) { /* just warn */ err = errno; P11PROV_raise(ctx, CKR_CANT_LOCK, "Failed to lock ctx pool (error:%d)", err); return; } /* WRLOCKED ------------------------------------------------- */ for (int i = 0; i < ctx_pool.num; i++) { if (!found) { if (ctx_pool.contexts[i] == ctx) { ctx_pool.contexts[i] = NULL; found = true; } } else { ctx_pool.contexts[i - 1] = ctx_pool.contexts[i]; if (i == ctx_pool.num - 1) { ctx_pool.contexts[i] = NULL; } } } if (found) { ctx_pool.num--; if (ctx_pool.num == 0) { /* This was the last context, free ctx_pool.contexts to avoid * leaking memory. */ OPENSSL_free(ctx_pool.contexts); ctx_pool.contexts = NULL; } } else { P11PROV_debug("Context not found in pool ?!"); } /* ------------------------------------------------- WRLOCKED */ (void)pthread_rwlock_unlock(&ctx_pool.rwlock); return; } struct quirk { CK_SLOT_ID id; char *name; union { void *ptr; CK_ULONG ulong; } data; CK_ULONG size; }; CK_RV p11prov_ctx_get_quirk(P11PROV_CTX *ctx, CK_SLOT_ID id, const char *name, void **data, CK_ULONG *size) { int lock; CK_RV ret; lock = pthread_rwlock_rdlock(&ctx->quirk_lock); if (lock != 0) { ret = CKR_CANT_LOCK; P11PROV_raise(ctx, ret, "Failure to rdlock! (%d)", errno); return ret; } for (int i = 0; i < ctx->nquirks; i++) { if (id != ctx->quirks[i].id) { continue; } if (strcmp(name, ctx->quirks[i].name) != 0) { continue; } /* return only if requested and if ancillary data exists */ if (data && ctx->quirks[i].size > 0) { if (*size == 0) { *data = OPENSSL_malloc(ctx->quirks[i].size); if (!*data) { ret = CKR_HOST_MEMORY; goto done; } } else { if (*size < ctx->quirks[i].size) { ret = CKR_BUFFER_TOO_SMALL; goto done; } } if (ctx->quirks[i].size > sizeof(CK_ULONG)) { memcpy(*data, ctx->quirks[i].data.ptr, ctx->quirks[i].size); } else { memcpy(*data, &ctx->quirks[i].data.ulong, ctx->quirks[i].size); } *size = ctx->quirks[i].size; } break; } ret = CKR_OK; done: lock = pthread_rwlock_unlock(&ctx->quirk_lock); if (lock != 0) { P11PROV_raise(ctx, CKR_CANT_LOCK, "Failure to unlock! (%d)", errno); /* we do not return an error in this case, as we got the info */ } return ret; } #define DATA_SWAP(t, d, s) \ do { \ t _tmp = d; \ d = s; \ s = _tmp; \ } while (0) #define QUIRK_ALLOC 4 CK_RV p11prov_ctx_set_quirk(P11PROV_CTX *ctx, CK_SLOT_ID id, const char *name, void *data, CK_ULONG size) { char *_name = NULL; void *_data = NULL; CK_ULONG _ulong = 0; CK_ULONG _size = size; int lock; CK_RV ret; bool found = false; int i; /* do potentially costly memory allocation operations before locking */ _name = OPENSSL_strdup(name); if (!_name) { ret = CKR_HOST_MEMORY; P11PROV_raise(ctx, ret, "Failure to copy name"); return ret; } if (_size > 0) { if (_size > sizeof(CK_ULONG)) { _data = OPENSSL_malloc(_size); if (!_data) { ret = CKR_HOST_MEMORY; P11PROV_raise(ctx, ret, "Failure to allocate for data"); goto failed; } } else { _data = &_ulong; } memcpy(_data, data, _size); } lock = pthread_rwlock_wrlock(&ctx->quirk_lock); if (lock != 0) { ret = CKR_CANT_LOCK; P11PROV_raise(ctx, ret, "Failure to wrlock! (%d)", errno); goto failed; } /* first see if we are replacing quirk data */ for (i = 0; i < ctx->nquirks; i++) { if (id != ctx->quirks[i].id) { continue; } if (strcmp(_name, ctx->quirks[i].name) != 0) { continue; } found = true; /* free previous data */ break; } if (!found) { if ((ctx->nquirks % QUIRK_ALLOC) == 0) { size_t asize = sizeof(struct quirk) * (ctx->nquirks + QUIRK_ALLOC); struct quirk *q = OPENSSL_realloc(ctx->quirks, asize); if (!q) { ret = CKR_HOST_MEMORY; goto done; } ctx->quirks = q; memset(&ctx->quirks[ctx->nquirks], 0, asize); i = ctx->nquirks; ctx->nquirks++; } } ctx->quirks[i].id = id; /* swap so that we free the old data at fn exit, where * precopied data is also freed in case of error */ DATA_SWAP(char *, ctx->quirks[i].name, _name); if (_size > sizeof(CK_ULONG)) { DATA_SWAP(void *, ctx->quirks[i].data.ptr, _data); } else { ctx->quirks[i].data.ulong = _ulong; _data = NULL; } DATA_SWAP(CK_ULONG, ctx->quirks[i].size, _size); ret = CKR_OK; done: P11PROV_debug("Set quirk '%s' of size %lu", name, size); lock = pthread_rwlock_unlock(&ctx->quirk_lock); if (lock != 0) { P11PROV_raise(ctx, CKR_CANT_LOCK, "Failure to unlock! (%d)", errno); /* we do not return an error in this case, as we got the info */ } failed: OPENSSL_free(_name); if (_data != &_ulong) { OPENSSL_clear_free(_data, _size); } return ret; } CK_RV p11prov_token_sup_attr(P11PROV_CTX *ctx, CK_SLOT_ID id, int action, CK_ATTRIBUTE_TYPE attr, CK_BBOOL *data) { CK_ULONG data_size = sizeof(CK_BBOOL); void *data_ptr = &data; char alloc_name[32]; const char *name; int err; switch (attr) { case CKA_ALLOWED_MECHANISMS: if (ctx->no_allowed_mechanisms) { if (action == GET_ATTR) { *data = false; } return CKR_OK; } name = "sup_attr_CKA_ALLOWED_MECHANISMS"; break; default: err = snprintf(alloc_name, 32, "sup_attr_%016lx", attr); if (err < 0 || err >= 32) { return CKR_HOST_MEMORY; } name = alloc_name; } switch (action) { case GET_ATTR: return p11prov_ctx_get_quirk(ctx, id, name, data_ptr, &data_size); case SET_ATTR: return p11prov_ctx_set_quirk(ctx, id, name, data, data_size); default: return CKR_ARGUMENTS_BAD; } } P11PROV_INTERFACE *p11prov_ctx_get_interface(P11PROV_CTX *ctx) { if (ctx->status == P11PROV_NO_DEINIT) { /* This is a quirk to handle modules that do funny things * with openssl and have issues when called in the openssl * destructors. Prevent any call to finalize or otherwise * use the module. */ return NULL; } return p11prov_module_get_interface(ctx->module); } P11PROV_SLOTS_CTX *p11prov_ctx_get_slots(P11PROV_CTX *ctx) { return ctx->slots; } void p11prov_ctx_set_slots(P11PROV_CTX *ctx, P11PROV_SLOTS_CTX *slots) { if (ctx->slots) { p11prov_free_slots(ctx->slots); } ctx->slots = slots; } OSSL_LIB_CTX *p11prov_ctx_get_libctx(P11PROV_CTX *ctx) { return ctx->libctx; } static CK_RV operations_init(P11PROV_CTX *ctx); CK_RV p11prov_ctx_status(P11PROV_CTX *ctx) { CK_RV ret; switch (ctx->status) { case P11PROV_UNINITIALIZED: ret = p11prov_module_init(ctx->module); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Module initialization failed!"); ctx->status = P11PROV_IN_ERROR; break; } ret = operations_init(ctx); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Operations initialization failed!"); ctx->status = P11PROV_IN_ERROR; break; } ctx->status = P11PROV_INITIALIZED; break; case P11PROV_INITIALIZED: case P11PROV_NO_DEINIT: ret = CKR_OK; break; case P11PROV_NEEDS_REINIT: ret = p11prov_module_reinit(ctx->module); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Module re-initialization failed!"); ctx->status = P11PROV_IN_ERROR; break; } ctx->status = P11PROV_INITIALIZED; break; case P11PROV_IN_ERROR: P11PROV_raise(ctx, CKR_GENERAL_ERROR, "Module in error state!"); ret = CKR_GENERAL_ERROR; break; default: ret = CKR_GENERAL_ERROR; } return ret; } CK_UTF8CHAR_PTR p11prov_ctx_pin(P11PROV_CTX *ctx) { return (CK_UTF8CHAR_PTR)ctx->pin; } static void p11prov_ctx_free(P11PROV_CTX *ctx) { int ret; if (ctx->no_deinit) { ctx->status = P11PROV_NO_DEINIT; } OPENSSL_free(ctx->op_digest); OPENSSL_free(ctx->op_kdf); OPENSSL_free(ctx->op_random); OPENSSL_free(ctx->op_exchange); OPENSSL_free(ctx->op_signature); OPENSSL_free(ctx->op_asym_cipher); OPENSSL_free(ctx->op_encoder); OPENSSL_free(ctx->op_decoder); OPENSSL_free(ctx->op_keymgmt); OPENSSL_free(ctx->op_store); OSSL_LIB_CTX_free(ctx->libctx); ctx->libctx = NULL; p11prov_free_slots(ctx->slots); ctx->slots = NULL; if (ctx->pin) { OPENSSL_clear_free(ctx->pin, strlen(ctx->pin)); } p11prov_module_free(ctx->module); ctx->module = NULL; ret = pthread_rwlock_wrlock(&ctx->quirk_lock); if (ret != 0) { P11PROV_raise(ctx, CKR_CANT_LOCK, "Failure to wrlock! Data corruption may happen (%d)", errno); } if (ctx->quirks) { for (int i = 0; i < ctx->nquirks; i++) { OPENSSL_free(ctx->quirks[i].name); if (ctx->quirks[i].size > sizeof(CK_ULONG)) { OPENSSL_clear_free(ctx->quirks[i].data.ptr, ctx->quirks[i].size); } } OPENSSL_free(ctx->quirks); } ret = pthread_rwlock_unlock(&ctx->quirk_lock); if (ret != 0) { P11PROV_raise(ctx, CKR_CANT_LOCK, "Failure to unlock! Data corruption may happen (%d)", errno); } ret = pthread_rwlock_destroy(&ctx->quirk_lock); if (ret != 0) { P11PROV_raise(ctx, CKR_CANT_LOCK, "Failure to free lock! Data corruption may happen (%d)", errno); } /* remove from pool */ context_rm_pool(ctx); OPENSSL_clear_free(ctx, sizeof(P11PROV_CTX)); } int p11prov_ctx_allow_export(P11PROV_CTX *ctx) { P11PROV_debug("allow_export = %d", ctx->allow_export); return ctx->allow_export; } int p11prov_ctx_login_behavior(P11PROV_CTX *ctx) { P11PROV_debug("login_behavior = %d", ctx->login_behavior); return ctx->login_behavior; } bool p11prov_ctx_cache_pins(P11PROV_CTX *ctx) { P11PROV_debug("cache_pins = %s", ctx->cache_pins ? "true" : "false"); return ctx->cache_pins; } int p11prov_ctx_cache_keys(P11PROV_CTX *ctx) { P11PROV_debug("cache_keys = %d", ctx->cache_keys); return ctx->cache_keys; } int p11prov_ctx_cache_sessions(P11PROV_CTX *ctx) { P11PROV_debug("cache_sessions = %d", ctx->cache_sessions); return ctx->cache_sessions; } bool p11prov_ctx_is_call_blocked(P11PROV_CTX *ctx, uint64_t mask) { return (ctx->blocked_calls & mask) != 0; } bool p11prov_ctx_no_session_callbacks(P11PROV_CTX *ctx) { return ctx->no_session_callbacks; } CK_INFO p11prov_ctx_get_ck_info(P11PROV_CTX *ctx) { if (!ctx->module) { CK_INFO info = { 0 }; return info; } return p11prov_module_ck_info(ctx->module); } static void p11prov_teardown(void *ctx) { p11prov_ctx_free((P11PROV_CTX *)ctx); } static OSSL_FUNC_core_get_params_fn *core_get_params = NULL; static OSSL_FUNC_core_new_error_fn *core_new_error = NULL; static OSSL_FUNC_core_set_error_debug_fn *core_set_error_debug = NULL; static OSSL_FUNC_core_vset_error_fn *core_vset_error = NULL; static OSSL_FUNC_core_set_error_mark_fn *core_set_error_mark = NULL; static OSSL_FUNC_core_clear_last_error_mark_fn *core_clear_last_error_mark = NULL; static OSSL_FUNC_core_pop_error_to_mark_fn *core_pop_error_to_mark = NULL; static void p11prov_get_core_dispatch_funcs(const OSSL_DISPATCH *in) { const OSSL_DISPATCH *iter_in; for (iter_in = in; iter_in->function_id != 0; iter_in++) { switch (iter_in->function_id) { case OSSL_FUNC_CORE_GET_PARAMS: core_get_params = OSSL_FUNC_core_get_params(iter_in); break; case OSSL_FUNC_CORE_NEW_ERROR: core_new_error = OSSL_FUNC_core_new_error(iter_in); break; case OSSL_FUNC_CORE_SET_ERROR_DEBUG: core_set_error_debug = OSSL_FUNC_core_set_error_debug(iter_in); break; case OSSL_FUNC_CORE_VSET_ERROR: core_vset_error = OSSL_FUNC_core_vset_error(iter_in); break; case OSSL_FUNC_CORE_SET_ERROR_MARK: core_set_error_mark = OSSL_FUNC_core_set_error_mark(iter_in); break; case OSSL_FUNC_CORE_CLEAR_LAST_ERROR_MARK: core_clear_last_error_mark = OSSL_FUNC_core_clear_last_error_mark(iter_in); break; case OSSL_FUNC_CORE_POP_ERROR_TO_MARK: core_pop_error_to_mark = OSSL_FUNC_core_pop_error_to_mark(iter_in); break; default: /* Just ignore anything we don't understand */ continue; } } } void p11prov_raise(P11PROV_CTX *ctx, const char *file, int line, const char *func, int errnum, const char *fmt, ...) { va_list args; if (!core_new_error || !core_vset_error) { return; } va_start(args, fmt); core_new_error(ctx->handle); core_set_error_debug(ctx->handle, file, line, func); core_vset_error(ctx->handle, errnum, fmt, args); va_end(args); } int p11prov_set_error_mark(P11PROV_CTX *ctx) { return core_set_error_mark(ctx->handle); } int p11prov_clear_last_error_mark(P11PROV_CTX *ctx) { return core_clear_last_error_mark(ctx->handle); } int p11prov_pop_error_to_mark(P11PROV_CTX *ctx) { return core_pop_error_to_mark(ctx->handle); } /* Parameters we provide to the core */ static const OSSL_PARAM p11prov_param_types[] = { OSSL_PARAM_DEFN(OSSL_PROV_PARAM_NAME, OSSL_PARAM_UTF8_PTR, NULL, 0), OSSL_PARAM_DEFN(OSSL_PROV_PARAM_VERSION, OSSL_PARAM_UTF8_PTR, NULL, 0), OSSL_PARAM_DEFN(OSSL_PROV_PARAM_BUILDINFO, OSSL_PARAM_UTF8_PTR, NULL, 0), OSSL_PARAM_DEFN(OSSL_PROV_PARAM_STATUS, OSSL_PARAM_INTEGER, NULL, 0), OSSL_PARAM_END, }; static const OSSL_PARAM *p11prov_gettable_params(void *provctx) { return p11prov_param_types; } static int p11prov_get_params(void *provctx, OSSL_PARAM params[]) { OSSL_PARAM *p; int ret; p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_NAME); if (p != NULL) { ret = OSSL_PARAM_set_utf8_ptr(p, "PKCS#11 Provider"); if (ret == 0) { return RET_OSSL_ERR; } } p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_VERSION); if (p != NULL) { /* temporarily return the OpenSSL build version */ ret = OSSL_PARAM_set_utf8_ptr(p, OPENSSL_VERSION_STR); if (ret == 0) { return RET_OSSL_ERR; } } p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_BUILDINFO); if (p != NULL) { /* temporarily return the OpenSSL build version */ ret = OSSL_PARAM_set_utf8_ptr(p, OPENSSL_FULL_VERSION_STR); if (ret == 0) { return RET_OSSL_ERR; } } p = OSSL_PARAM_locate(params, OSSL_PROV_PARAM_STATUS); if (p != NULL) { /* return 1 for now, * return 0 in future if there are module issues? */ ret = OSSL_PARAM_set_int(p, 1); if (ret == 0) { return RET_OSSL_ERR; } } return RET_OSSL_OK; } /* TODO: this needs to be made dynamic, * based on what the pkcs11 module supports */ #define ALGOS_ALLOC 4 static CK_RV alg_set_op(OSSL_ALGORITHM **op, int idx, OSSL_ALGORITHM *alg) { if (idx % ALGOS_ALLOC == 0) { OSSL_ALGORITHM *tmp = OPENSSL_realloc(*op, sizeof(OSSL_ALGORITHM) * (idx + ALGOS_ALLOC)); if (!tmp) { return CKR_HOST_MEMORY; } *op = tmp; } (*op)[idx] = *alg; return CKR_OK; } #define ADD_ALGO_EXT(NAME, operation, prop, func) \ do { \ CK_RV alg_ret; \ OSSL_ALGORITHM alg = { P11PROV_NAMES_##NAME, prop, func, \ P11PROV_DESCS_##NAME }; \ alg_ret = alg_set_op(&ctx->op_##operation, operation##_idx, &alg); \ if (alg_ret != CKR_OK) { \ P11PROV_raise(ctx, alg_ret, "Failed to store mech algo"); \ return RET_OSSL_ERR; \ } \ operation##_idx++; \ } while (0) #define ADD_ALGO(NAME, name, operation, prop) \ ADD_ALGO_EXT(NAME, operation, prop, \ p11prov_##name##_##operation##_functions) #define TERM_ALGO(operation) \ if (operation##_idx > 0) { \ CK_RV alg_ret; \ OSSL_ALGORITHM alg = { NULL, NULL, NULL, NULL }; \ alg_ret = alg_set_op(&ctx->op_##operation, operation##_idx, &alg); \ if (alg_ret != CKR_OK) { \ P11PROV_raise(ctx, alg_ret, "Failed to terminate mech algo"); \ return RET_OSSL_ERR; \ } \ } \ operation##_idx = 0 #define DIGEST_MECHS \ CKM_SHA_1, CKM_SHA224, CKM_SHA256, CKM_SHA384, CKM_SHA512, CKM_SHA512_224, \ CKM_SHA512_256, CKM_SHA3_224, CKM_SHA3_256, CKM_SHA3_384, CKM_SHA3_512 #define RSA_SIG_MECHS \ CKM_RSA_PKCS, CKM_SHA1_RSA_PKCS, CKM_SHA224_RSA_PKCS, CKM_SHA256_RSA_PKCS, \ CKM_SHA384_RSA_PKCS, CKM_SHA512_RSA_PKCS, CKM_SHA3_224_RSA_PKCS, \ CKM_SHA3_256_RSA_PKCS, CKM_SHA3_384_RSA_PKCS, CKM_SHA3_512_RSA_PKCS #define RSAPSS_SIG_MECHS \ CKM_RSA_PKCS_PSS, CKM_SHA1_RSA_PKCS_PSS, CKM_SHA224_RSA_PKCS_PSS, \ CKM_SHA256_RSA_PKCS_PSS, CKM_SHA384_RSA_PKCS_PSS, \ CKM_SHA512_RSA_PKCS_PSS, CKM_SHA3_224_RSA_PKCS_PSS, \ CKM_SHA3_256_RSA_PKCS_PSS, CKM_SHA3_384_RSA_PKCS_PSS, \ CKM_SHA3_512_RSA_PKCS_PSS #define RSA_ENC_MECHS \ CKM_RSA_PKCS, CKM_RSA_PKCS_OAEP, CKM_RSA_X_509, CKM_RSA_X9_31 #define ECDSA_SIG_MECHS \ CKM_ECDSA, CKM_ECDSA_SHA1, CKM_ECDSA_SHA224, CKM_ECDSA_SHA256, \ CKM_ECDSA_SHA384, CKM_ECDSA_SHA512, CKM_ECDSA_SHA3_224, \ CKM_ECDSA_SHA3_256, CKM_ECDSA_SHA3_384, CKM_ECDSA_SHA3_512 static void alg_rm_mechs(CK_ULONG *checklist, CK_ULONG *rmlist, int *clsize, int rmsize) { CK_ULONG tmplist[*clsize]; int t = 0; for (int i = 0; i < *clsize; i++) { tmplist[t] = checklist[i]; for (int j = 0; j < rmsize; j++) { if (tmplist[t] == rmlist[j]) { tmplist[t] = CK_UNAVAILABLE_INFORMATION; break; } } if (tmplist[t] != CK_UNAVAILABLE_INFORMATION) { t++; } } memcpy(checklist, tmplist, t * sizeof(CK_ULONG)); *clsize = t; } #define UNCHECK_MECHS(...) \ do { \ CK_ULONG rmlist[] = { __VA_ARGS__ }; \ int rmsize = sizeof(rmlist) / sizeof(CK_ULONG); \ alg_rm_mechs(checklist, rmlist, &cl_size, rmsize); \ } while (0); static const char *get_default_properties(P11PROV_CTX *ctx) { if (ctx->assume_fips) { return P11PROV_FIPS_PROPERTIES; } return P11PROV_DEFAULT_PROPERTIES; } static CK_RV operations_init(P11PROV_CTX *ctx) { P11PROV_SLOTS_CTX *slots; P11PROV_SLOT *slot; CK_ULONG checklist[] = { CKM_RSA_PKCS_KEY_PAIR_GEN, RSA_SIG_MECHS, RSAPSS_SIG_MECHS, RSA_ENC_MECHS, CKM_EC_KEY_PAIR_GEN, ECDSA_SIG_MECHS, CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE, CKM_HKDF_DERIVE, DIGEST_MECHS, CKM_EDDSA }; bool add_rsasig = false; bool add_rsaenc = false; int cl_size = sizeof(checklist) / sizeof(CK_ULONG); int digest_idx = 0; int kdf_idx = 0; int random_idx = 0; int exchange_idx = 0; int signature_idx = 0; int asym_cipher_idx = 0; int slot_idx = 0; const char *prop = get_default_properties(ctx); CK_RV ret; ret = p11prov_take_slots(ctx, &slots); if (ret != CKR_OK) { return ret; } for (slot = p11prov_fetch_slot(slots, &slot_idx); slot != NULL; slot = p11prov_fetch_slot(slots, &slot_idx)) { CK_MECHANISM_TYPE *mechs; int nmechs; nmechs = p11prov_slot_get_mechanisms(slot, &mechs); for (int ms = 0; ms < nmechs; ms++) { CK_ULONG mech = CK_UNAVAILABLE_INFORMATION; if (cl_size == 0) { /* we are done*/ break; } for (int cl = 0; cl < cl_size; cl++) { if (mechs[ms] == checklist[cl]) { mech = mechs[ms]; /* found */ break; } } switch (mech) { case CK_UNAVAILABLE_INFORMATION: continue; case CKM_RSA_PKCS_KEY_PAIR_GEN: UNCHECK_MECHS(CKM_RSA_PKCS_KEY_PAIR_GEN); break; case CKM_RSA_PKCS: add_rsasig = true; add_rsaenc = true; UNCHECK_MECHS(CKM_RSA_PKCS_KEY_PAIR_GEN, RSA_SIG_MECHS); UNCHECK_MECHS(CKM_RSA_PKCS_KEY_PAIR_GEN, RSA_ENC_MECHS); break; case CKM_SHA1_RSA_PKCS: case CKM_SHA224_RSA_PKCS: case CKM_SHA256_RSA_PKCS: case CKM_SHA384_RSA_PKCS: case CKM_SHA512_RSA_PKCS: case CKM_SHA3_224_RSA_PKCS: case CKM_SHA3_256_RSA_PKCS: case CKM_SHA3_384_RSA_PKCS: case CKM_SHA3_512_RSA_PKCS: add_rsasig = true; UNCHECK_MECHS(CKM_RSA_PKCS_KEY_PAIR_GEN, RSA_SIG_MECHS); break; case CKM_RSA_PKCS_PSS: case CKM_SHA1_RSA_PKCS_PSS: case CKM_SHA224_RSA_PKCS_PSS: case CKM_SHA256_RSA_PKCS_PSS: case CKM_SHA384_RSA_PKCS_PSS: case CKM_SHA512_RSA_PKCS_PSS: case CKM_SHA3_224_RSA_PKCS_PSS: case CKM_SHA3_256_RSA_PKCS_PSS: case CKM_SHA3_384_RSA_PKCS_PSS: case CKM_SHA3_512_RSA_PKCS_PSS: add_rsasig = true; UNCHECK_MECHS(CKM_RSA_PKCS_KEY_PAIR_GEN, RSAPSS_SIG_MECHS); break; case CKM_RSA_PKCS_OAEP: case CKM_RSA_X_509: case CKM_RSA_X9_31: add_rsaenc = true; UNCHECK_MECHS(CKM_RSA_PKCS_KEY_PAIR_GEN, RSA_ENC_MECHS); break; case CKM_EC_KEY_PAIR_GEN: UNCHECK_MECHS(CKM_EC_KEY_PAIR_GEN); break; case CKM_ECDSA: case CKM_ECDSA_SHA1: case CKM_ECDSA_SHA224: case CKM_ECDSA_SHA256: case CKM_ECDSA_SHA384: case CKM_ECDSA_SHA512: case CKM_ECDSA_SHA3_224: case CKM_ECDSA_SHA3_256: case CKM_ECDSA_SHA3_384: case CKM_ECDSA_SHA3_512: ADD_ALGO(ECDSA, ecdsa, signature, prop); UNCHECK_MECHS(CKM_EC_KEY_PAIR_GEN, ECDSA_SIG_MECHS); break; case CKM_ECDH1_DERIVE: case CKM_ECDH1_COFACTOR_DERIVE: ADD_ALGO(ECDH, ecdh, exchange, prop); UNCHECK_MECHS(CKM_EC_KEY_PAIR_GEN, CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE); break; case CKM_HKDF_DERIVE: ADD_ALGO(HKDF, hkdf, kdf, prop); ADD_ALGO(TLS13_KDF, tls13, kdf, prop); ADD_ALGO(HKDF, hkdf, exchange, prop); UNCHECK_MECHS(CKM_HKDF_DERIVE); break; case CKM_SHA_1: ADD_ALGO(SHA1, sha1, digest, prop); UNCHECK_MECHS(CKM_SHA_1); break; case CKM_SHA224: ADD_ALGO(SHA2_224, sha224, digest, prop); UNCHECK_MECHS(CKM_SHA224); break; case CKM_SHA256: ADD_ALGO(SHA2_256, sha256, digest, prop); UNCHECK_MECHS(CKM_SHA256); break; case CKM_SHA384: ADD_ALGO(SHA2_384, sha384, digest, prop); UNCHECK_MECHS(CKM_SHA384); break; case CKM_SHA512: ADD_ALGO(SHA2_512, sha512, digest, prop); UNCHECK_MECHS(CKM_SHA512); break; case CKM_SHA512_224: ADD_ALGO(SHA2_512_224, sha512_224, digest, prop); UNCHECK_MECHS(CKM_SHA512_224); break; case CKM_SHA512_256: ADD_ALGO(SHA2_512_256, sha512_256, digest, prop); UNCHECK_MECHS(CKM_SHA512_256); break; case CKM_SHA3_224: ADD_ALGO(SHA3_224, sha3_224, digest, prop); UNCHECK_MECHS(CKM_SHA3_224); break; case CKM_SHA3_256: ADD_ALGO(SHA3_256, sha3_256, digest, prop); UNCHECK_MECHS(CKM_SHA3_256); break; case CKM_SHA3_384: ADD_ALGO(SHA3_384, sha3_384, digest, prop); UNCHECK_MECHS(CKM_SHA3_384); break; case CKM_SHA3_512: ADD_ALGO(SHA3_512, sha3_512, digest, prop); UNCHECK_MECHS(CKM_SHA3_512); break; case CKM_EDDSA: ADD_ALGO_EXT(ED25519, signature, prop, p11prov_eddsa_signature_functions); ADD_ALGO_EXT(ED448, signature, prop, p11prov_eddsa_signature_functions); UNCHECK_MECHS(CKM_EC_EDWARDS_KEY_PAIR_GEN, CKM_EDDSA); break; default: P11PROV_raise(ctx, CKR_GENERAL_ERROR, "Unhandled mechianism %lu", mech); break; } } } p11prov_return_slots(slots); if (add_rsasig) { ADD_ALGO(RSA, rsa, signature, prop); } if (add_rsaenc) { ADD_ALGO(RSA, rsa, asym_cipher, prop); } /* terminations */ TERM_ALGO(digest); TERM_ALGO(kdf); TERM_ALGO(exchange); TERM_ALGO(signature); TERM_ALGO(asym_cipher); /* handle random */ ret = p11prov_check_random(ctx); if (ret == CKR_OK) { ADD_ALGO_EXT(RAND, random, prop, p11prov_rand_functions); TERM_ALGO(random); } return CKR_OK; } static CK_RV static_operations_init(P11PROV_CTX *ctx) { int encoder_idx = 0; int decoder_idx = 0; int store_idx = 0; int keymgmt_idx = 0; const char *prop = get_default_properties(ctx); /* encoder */ #define DEFAULT_PROPERTY(prop) \ (ctx->assume_fips ? P11PROV_FIPS_PROPERTIES prop \ : P11PROV_DEFAULT_PROPERTIES prop) ADD_ALGO_EXT(RSA, encoder, DEFAULT_PROPERTY(",output=text"), p11prov_rsa_encoder_text_functions); ADD_ALGO_EXT(RSA, encoder, DEFAULT_PROPERTY(",output=der,structure=pkcs1"), p11prov_rsa_encoder_pkcs1_der_functions); ADD_ALGO_EXT(RSA, encoder, DEFAULT_PROPERTY(",output=pem,structure=pkcs1"), p11prov_rsa_encoder_pkcs1_pem_functions); ADD_ALGO_EXT(RSA, encoder, DEFAULT_PROPERTY(",output=der,structure=SubjectPublicKeyInfo"), p11prov_rsa_encoder_spki_der_functions); ADD_ALGO_EXT(RSA, encoder, DEFAULT_PROPERTY(",output=pem,structure=SubjectPublicKeyInfo"), p11prov_rsa_encoder_spki_pem_functions); ADD_ALGO_EXT(RSAPSS, encoder, DEFAULT_PROPERTY(",output=text"), p11prov_rsa_encoder_text_functions); ADD_ALGO_EXT(RSAPSS, encoder, DEFAULT_PROPERTY(",output=der,structure=pkcs1"), p11prov_rsa_encoder_pkcs1_der_functions); ADD_ALGO_EXT(RSAPSS, encoder, DEFAULT_PROPERTY(",output=pem,structure=pkcs1"), p11prov_rsa_encoder_pkcs1_pem_functions); ADD_ALGO_EXT(RSAPSS, encoder, DEFAULT_PROPERTY(",output=der,structure=SubjectPublicKeyInfo"), p11prov_rsa_encoder_spki_der_functions); ADD_ALGO_EXT(RSAPSS, encoder, DEFAULT_PROPERTY(",output=pem,structure=SubjectPublicKeyInfo"), p11prov_rsa_encoder_spki_pem_functions); ADD_ALGO_EXT(EC, encoder, DEFAULT_PROPERTY(",output=text"), p11prov_ec_encoder_text_functions); ADD_ALGO_EXT(EC, encoder, DEFAULT_PROPERTY(",output=der,structure=pkcs1"), p11prov_ec_encoder_pkcs1_der_functions); ADD_ALGO_EXT(EC, encoder, DEFAULT_PROPERTY(",output=pem,structure=pkcs1"), p11prov_ec_encoder_pkcs1_pem_functions); ADD_ALGO_EXT(EC, encoder, DEFAULT_PROPERTY(",output=der,structure=SubjectPublicKeyInfo"), p11prov_ec_encoder_spki_der_functions); ADD_ALGO_EXT(ED25519, encoder, DEFAULT_PROPERTY(",output=text"), p11prov_ec_edwards_encoder_text_functions); ADD_ALGO_EXT(ED448, encoder, DEFAULT_PROPERTY(",output=text"), p11prov_ec_edwards_encoder_text_functions); if (ctx->encode_pkey_as_pk11_uri) { ADD_ALGO_EXT(RSA, encoder, DEFAULT_PROPERTY(",output=pem,structure=PrivateKeyInfo"), p11prov_rsa_encoder_priv_key_info_pem_functions); ADD_ALGO_EXT(RSAPSS, encoder, DEFAULT_PROPERTY(",output=pem,structure=PrivateKeyInfo"), p11prov_rsa_encoder_priv_key_info_pem_functions); ADD_ALGO_EXT(EC, encoder, DEFAULT_PROPERTY(",output=pem,structure=PrivateKeyInfo"), p11prov_ec_encoder_priv_key_info_pem_functions); ADD_ALGO_EXT(ED25519, encoder, DEFAULT_PROPERTY(",output=pem,structure=PrivateKeyInfo"), p11prov_ec_edwards_encoder_priv_key_info_pem_functions); ADD_ALGO_EXT(ED448, encoder, DEFAULT_PROPERTY(",output=pem,structure=PrivateKeyInfo"), p11prov_ec_edwards_encoder_priv_key_info_pem_functions); } TERM_ALGO(encoder); #define DER_DECODER_PROP ",input=der,structure=" P11PROV_DER_STRUCTURE /* decoder */ ADD_ALGO_EXT(DER, decoder, DEFAULT_PROPERTY(",input=pem"), p11prov_pem_decoder_p11prov_der_functions); ADD_ALGO_EXT(RSA, decoder, DEFAULT_PROPERTY(DER_DECODER_PROP), p11prov_der_decoder_p11prov_rsa_functions); ADD_ALGO_EXT(RSAPSS, decoder, DEFAULT_PROPERTY(DER_DECODER_PROP), p11prov_der_decoder_p11prov_rsa_functions); ADD_ALGO_EXT(EC, decoder, DEFAULT_PROPERTY(DER_DECODER_PROP), p11prov_der_decoder_p11prov_ec_functions); ADD_ALGO_EXT(ED25519, decoder, DEFAULT_PROPERTY(DER_DECODER_PROP), p11prov_der_decoder_p11prov_ed25519_functions); ADD_ALGO_EXT(ED448, decoder, DEFAULT_PROPERTY(DER_DECODER_PROP), p11prov_der_decoder_p11prov_ed448_functions); TERM_ALGO(decoder); #undef DEFAULT_PROPERTY /* store */ ADD_ALGO_EXT(URI, store, prop, p11prov_store_functions); TERM_ALGO(store); /* keymgmt */ ADD_ALGO(RSA, rsa, keymgmt, prop); ADD_ALGO(RSAPSS, rsapss, keymgmt, prop); ADD_ALGO(EC, ec, keymgmt, prop); ADD_ALGO(HKDF, hkdf, keymgmt, prop); ADD_ALGO_EXT(ED25519, keymgmt, prop, p11prov_ed25519_keymgmt_functions); ADD_ALGO_EXT(ED448, keymgmt, prop, p11prov_ed448_keymgmt_functions); TERM_ALGO(keymgmt); return CKR_OK; } static const char *p11prov_block_ops_names[OSSL_OP__HIGHEST + 1] = { [OSSL_OP_DIGEST] = "digest", [OSSL_OP_CIPHER] = "cipher", [OSSL_OP_MAC] = "mac", [OSSL_OP_KDF] = "kdf", [OSSL_OP_RAND] = "rand", [OSSL_OP_KEYMGMT] = "keymgmt", [OSSL_OP_KEYEXCH] = "keyexch", [OSSL_OP_SIGNATURE] = "signature", [OSSL_OP_ASYM_CIPHER] = "asym-cipher", [OSSL_OP_KEM] = "kem", [OSSL_OP_ENCODER] = "encoder", [OSSL_OP_DECODER] = "decoder", [OSSL_OP_STORE] = "store", }; static const OSSL_ALGORITHM * p11prov_query_operation(void *provctx, int operation_id, int *no_cache) { P11PROV_CTX *ctx = (P11PROV_CTX *)provctx; if (operation_id > OSSL_OP__HIGHEST) { P11PROV_debug("Invalid op id %d > OSSL_OP__HIGHEST", operation_id); *no_cache = 0; return NULL; } if (ctx->blocked_ops[operation_id]) { P11PROV_debug("Blocked operation: %s (%d)", p11prov_block_ops_names[operation_id], operation_id); *no_cache = 0; return NULL; } switch (operation_id) { case OSSL_OP_DIGEST: *no_cache = ctx->status == P11PROV_UNINITIALIZED ? 1 : 0; return ctx->op_digest; case OSSL_OP_KDF: *no_cache = ctx->status == P11PROV_UNINITIALIZED ? 1 : 0; return ctx->op_kdf; case OSSL_OP_RAND: *no_cache = ctx->status == P11PROV_UNINITIALIZED ? 1 : 0; return ctx->op_random; case OSSL_OP_KEYMGMT: *no_cache = 0; return ctx->op_keymgmt; case OSSL_OP_KEYEXCH: *no_cache = ctx->status == P11PROV_UNINITIALIZED ? 1 : 0; return ctx->op_exchange; case OSSL_OP_SIGNATURE: *no_cache = ctx->status == P11PROV_UNINITIALIZED ? 1 : 0; return ctx->op_signature; case OSSL_OP_ASYM_CIPHER: *no_cache = ctx->status == P11PROV_UNINITIALIZED ? 1 : 0; return ctx->op_asym_cipher; case OSSL_OP_ENCODER: *no_cache = 0; return ctx->op_encoder; case OSSL_OP_DECODER: *no_cache = 0; return ctx->op_decoder; case OSSL_OP_STORE: *no_cache = 0; return ctx->op_store; } *no_cache = 0; return NULL; } static int p11prov_get_capabilities(void *provctx, const char *capability, OSSL_CALLBACK *cb, void *arg) { int ret = RET_OSSL_OK; if (OPENSSL_strcasecmp(capability, "TLS-GROUP") == 0) { ret = tls_group_capabilities(cb, arg); } return ret; } static const OSSL_ITEM *p11prov_get_reason_strings(void *provctx) { #define C(str) (void *)(str) static const OSSL_ITEM reason_strings[] = { { CKR_HOST_MEMORY, C("Host out of memory error") }, { CKR_SLOT_ID_INVALID, C("The specified slot ID is not valid") }, { CKR_GENERAL_ERROR, C("General Error") }, { CKR_FUNCTION_FAILED, C("The requested function could not be performed") }, { CKR_ARGUMENTS_BAD, C("Invalid or improper arguments were provided to the " "invoked function") }, { CKR_CANT_LOCK, C("Internal locking failure") }, { CKR_ATTRIBUTE_READ_ONLY, C("Attempted to set or modify an attribute that is Read " "Only for applications") }, { CKR_ATTRIBUTE_TYPE_INVALID, C("Invalid attribute type specified in a template") }, { CKR_ATTRIBUTE_VALUE_INVALID, C("Invalid value specified for attribute in a template") }, { CKR_DATA_INVALID, C("The plaintext input data to a cryptographic " "operation is invalid") }, { CKR_DATA_LEN_RANGE, C("The size of plaintext input data to a cryptographic " "operation is invalid (Out of range)") }, { CKR_DEVICE_ERROR, C("Some problem has occurred with the token and/or slot") }, { CKR_DEVICE_MEMORY, C("The token does not have sufficient memory to perform " "the requested function") }, { CKR_DEVICE_REMOVED, C("The token was removed from its slot during the " "execution of the function") }, { CKR_FUNCTION_CANCELED, C("The function was canceled in mid-execution") }, { CKR_KEY_HANDLE_INVALID, C("The specified key handle is not valid") }, { CKR_KEY_SIZE_RANGE, C("Unable to handle the specified key size (Out of range)") }, { CKR_KEY_NEEDED, C("This operation requires a key (missing)") }, { CKR_KEY_TYPE_INCONSISTENT, C("The specified key is not the correct type of key to " "use with the specified mechanism") }, { CKR_KEY_FUNCTION_NOT_PERMITTED, C("The key attributes do not allow this operation to " "be executed") }, { CKR_MECHANISM_INVALID, C("An invalid mechanism was specified to the " "cryptographic operation") }, { CKR_MECHANISM_PARAM_INVALID, C("Invalid mechanism parameters were supplied") }, { CKR_OPERATION_ACTIVE, C("There is already an active operation that prevents " "executing the requested function") }, { CKR_OPERATION_NOT_INITIALIZED, C("There is no active operation of appropriate type " "in the specified session") }, { CKR_PIN_INCORRECT, C("The specified PIN is incorrect") }, { CKR_PIN_INVALID, C("The specified PIN is invalid") }, { CKR_PIN_EXPIRED, C("The specified PIN has expired") }, { CKR_PIN_LOCKED, C("The specified PIN is locked, and cannot be used") }, { CKR_SESSION_CLOSED, C("Session is already closed") }, { CKR_SESSION_COUNT, C("Too many sessions open") }, { CKR_SESSION_HANDLE_INVALID, C("Invalid Session Handle") }, { CKR_SESSION_PARALLEL_NOT_SUPPORTED, C("Parallel sessions not supported") }, { CKR_SESSION_READ_ONLY, C("Session is Read Only") }, { CKR_SESSION_EXISTS, C("Session already exists") }, { CKR_SESSION_READ_ONLY_EXISTS, C("A read-only session already exists") }, { CKR_SESSION_READ_WRITE_SO_EXISTS, C("A read/write SO session already exists") }, { CKR_TEMPLATE_INCOMPLETE, C("The template to create an object is incomplete") }, { CKR_TEMPLATE_INCONSISTENT, C("The template to create an object has conflicting attributes") }, { CKR_TOKEN_NOT_PRESENT, C("The token was not present in its slot when the " "function was invoked") }, { CKR_TOKEN_NOT_RECOGNIZED, C("The token in the slot is not recognized") }, { CKR_TOKEN_WRITE_PROTECTED, C("Action denied because the token is write-protected") }, { CKR_TOKEN_WRITE_PROTECTED, C("Can't perform action because the token is write-protected") }, { CKR_USER_NOT_LOGGED_IN, C("The desired action cannot be performed because an " "appropriate user is not logged in") }, { CKR_USER_PIN_NOT_INITIALIZED, C("The user PIN is not initialized") }, { CKR_USER_TYPE_INVALID, C("An invalid user type was specified") }, { CKR_USER_ANOTHER_ALREADY_LOGGED_IN, C("Another user is already logged in") }, { CKR_USER_TOO_MANY_TYPES, C("Attempted to log in more users than the token can support") }, { CKR_OPERATION_CANCEL_FAILED, C("The operation cannot be cancelled") }, { CKR_DOMAIN_PARAMS_INVALID, C("Invalid or unsupported domain parameters were " "supplied to the function") }, { CKR_CURVE_NOT_SUPPORTED, C("The specified curve is not supported by this token") }, { CKR_BUFFER_TOO_SMALL, C("The output of the function is too large to fit in " "the supplied buffer") }, { CKR_SAVED_STATE_INVALID, C("The supplied saved cryptographic operations state is invalid") }, { CKR_STATE_UNSAVEABLE, C("The cryptographic operations state of the specified " "session cannot be saved") }, { CKR_CRYPTOKI_NOT_INITIALIZED, C("PKCS11 Module has not been initialized yet") }, { 0, NULL }, }; return reason_strings; #undef C } /* Functions we provide to the core */ static const OSSL_DISPATCH p11prov_dispatch_table[] = { { OSSL_FUNC_PROVIDER_TEARDOWN, (void (*)(void))p11prov_teardown }, { OSSL_FUNC_PROVIDER_GETTABLE_PARAMS, (void (*)(void))p11prov_gettable_params }, { OSSL_FUNC_PROVIDER_GET_PARAMS, (void (*)(void))p11prov_get_params }, { OSSL_FUNC_PROVIDER_QUERY_OPERATION, (void (*)(void))p11prov_query_operation }, { OSSL_FUNC_PROVIDER_GET_CAPABILITIES, (void (*)(void))p11prov_get_capabilities }, { OSSL_FUNC_PROVIDER_GET_REASON_STRINGS, (void (*)(void))p11prov_get_reason_strings }, { 0, NULL }, }; enum p11prov_cfg_enum { P11PROV_CFG_PATH = 0, P11PROV_CFG_INIT_ARGS, P11PROV_CFG_TOKEN_PIN, P11PROV_CFG_ALLOW_EXPORT, P11PROV_CFG_LOGIN_BEHAVIOR, P11PROV_CFG_LOAD_BEHAVIOR, P11PROV_CFG_CACHE_PINS, P11PROV_CFG_CACHE_KEYS, P11PROV_CFG_QUIRKS, P11PROV_CFG_CACHE_SESSIONS, P11PROV_CFG_ENCODE_PROVIDER_URI_TO_PEM, P11PROV_CFG_BLOCK_OPS, P11PROV_CFG_ASSUME_FIPS, P11PROV_CFG_SIZE, }; static struct p11prov_cfg_names { const char *name; } p11prov_cfg_names[P11PROV_CFG_SIZE] = { { "pkcs11-module-path" }, { "pkcs11-module-init-args" }, { "pkcs11-module-token-pin" }, { "pkcs11-module-allow-export" }, { "pkcs11-module-login-behavior" }, { "pkcs11-module-load-behavior" }, { "pkcs11-module-cache-pins" }, { "pkcs11-module-cache-keys" }, { "pkcs11-module-quirks" }, { "pkcs11-module-cache-sessions" }, { "pkcs11-module-encode-provider-uri-to-pem" }, { "pkcs11-module-block-operations" }, { "pkcs11-module-assume-fips" }, }; int OSSL_provider_init(const OSSL_CORE_HANDLE *handle, const OSSL_DISPATCH *in, const OSSL_DISPATCH **out, void **provctx) { const char *cfg[P11PROV_CFG_SIZE] = { 0 }; OSSL_PARAM core_params[P11PROV_CFG_SIZE + 1]; P11PROV_CTX *ctx; bool show_quirks = false; int ret; *provctx = NULL; p11prov_get_core_dispatch_funcs(in); ctx = OPENSSL_zalloc(sizeof(P11PROV_CTX)); if (ctx == NULL) { return RET_OSSL_ERR; } ctx->handle = handle; ret = pthread_rwlock_init(&ctx->quirk_lock, NULL); if (ret != 0) { ret = errno; P11PROV_debug("rwlock init failed (%d)", ret); OPENSSL_free(ctx); return RET_OSSL_ERR; } ctx->libctx = OSSL_LIB_CTX_new_from_dispatch(handle, in); if (ctx->libctx == NULL) { OPENSSL_free(ctx); return RET_OSSL_ERR; } for (int i = 0; i < P11PROV_CFG_SIZE; i++) { core_params[i] = OSSL_PARAM_construct_utf8_ptr( p11prov_cfg_names[i].name, (char **)&cfg[i], sizeof(void *)); } core_params[P11PROV_CFG_SIZE] = OSSL_PARAM_construct_end(); ret = core_get_params(handle, core_params); if (ret != RET_OSSL_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_FAILED_TO_GET_PARAMETER); p11prov_ctx_free(ctx); return ret; } P11PROV_debug("Provided config params:"); for (int i = 0; i < P11PROV_CFG_SIZE; i++) { const char none[] = "[none]"; const char pin[] = "[****]"; const char *val = none; if (i == P11PROV_CFG_TOKEN_PIN) { val = pin; } else if (cfg[i]) { val = cfg[i]; } P11PROV_debug(" %s: %s", p11prov_cfg_names[i].name, val); } ret = p11prov_module_new(ctx, cfg[P11PROV_CFG_PATH], cfg[P11PROV_CFG_INIT_ARGS], &ctx->module); if (ret != CKR_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_IN_ERROR_STATE); p11prov_ctx_free(ctx); return RET_OSSL_ERR; } if (cfg[P11PROV_CFG_TOKEN_PIN] != NULL) { ret = p11prov_get_pin(ctx, cfg[P11PROV_CFG_TOKEN_PIN], &ctx->pin); if (ret != 0) { ERR_raise(ERR_LIB_PROV, PROV_R_IN_ERROR_STATE); p11prov_ctx_free(ctx); return RET_OSSL_ERR; } } P11PROV_debug("PIN %savailable", ctx->pin ? "" : "not "); if (cfg[P11PROV_CFG_ALLOW_EXPORT] != NULL) { char *end = NULL; errno = 0; ctx->allow_export = (int)strtol(cfg[P11PROV_CFG_ALLOW_EXPORT], &end, 0); if (errno != 0 || *end != '\0') { P11PROV_raise(ctx, CKR_GENERAL_ERROR, "Invalid value for %s: (%s)", p11prov_cfg_names[P11PROV_CFG_ALLOW_EXPORT].name, cfg[P11PROV_CFG_ALLOW_EXPORT]); p11prov_ctx_free(ctx); return RET_OSSL_ERR; } } P11PROV_debug("Export %sallowed", ctx->allow_export == 1 ? "not " : ""); if (cfg[P11PROV_CFG_LOGIN_BEHAVIOR] != NULL) { if (strcmp(cfg[P11PROV_CFG_LOGIN_BEHAVIOR], "auto") == 0) { ctx->login_behavior = PUBKEY_LOGIN_AUTO; } else if (strcmp(cfg[P11PROV_CFG_LOGIN_BEHAVIOR], "always") == 0) { ctx->login_behavior = PUBKEY_LOGIN_ALWAYS; } else if (strcmp(cfg[P11PROV_CFG_LOGIN_BEHAVIOR], "never") == 0) { ctx->login_behavior = PUBKEY_LOGIN_NEVER; } else { P11PROV_raise(ctx, CKR_GENERAL_ERROR, "Invalid value for %s: (%s)", p11prov_cfg_names[P11PROV_CFG_LOGIN_BEHAVIOR].name, cfg[P11PROV_CFG_LOGIN_BEHAVIOR]); p11prov_ctx_free(ctx); return RET_OSSL_ERR; } } switch (ctx->login_behavior) { case PUBKEY_LOGIN_AUTO: P11PROV_debug("Login behavior: auto"); break; case PUBKEY_LOGIN_ALWAYS: P11PROV_debug("Login behavior: always"); break; case PUBKEY_LOGIN_NEVER: P11PROV_debug("Login behavior: never"); break; default: P11PROV_debug("Login behavior: "); break; } if (cfg[P11PROV_CFG_CACHE_PINS] != NULL && strcmp(cfg[P11PROV_CFG_CACHE_PINS], "cache") == 0) { ctx->cache_pins = true; } P11PROV_debug("PINs will %sbe cached", ctx->cache_pins ? "" : "not "); if (cfg[P11PROV_CFG_CACHE_KEYS] != NULL) { if (strcmp(cfg[P11PROV_CFG_CACHE_KEYS], "true") == 0) { ctx->cache_keys = P11PROV_CACHE_KEYS_IN_SESSION; } else if (strcmp(cfg[P11PROV_CFG_CACHE_KEYS], "false") == 0) { ctx->cache_keys = P11PROV_CACHE_KEYS_NEVER; } } else { /* defaults to session */ ctx->cache_keys = P11PROV_CACHE_KEYS_IN_SESSION; } switch (ctx->cache_keys) { case P11PROV_CACHE_KEYS_NEVER: P11PROV_debug("Key caching: never"); break; case P11PROV_CACHE_KEYS_IN_SESSION: P11PROV_debug("Key caching: in session object"); break; } if (cfg[P11PROV_CFG_QUIRKS] != NULL) { const char *str; const char *sep; size_t len = strlen(cfg[P11PROV_CFG_QUIRKS]); size_t toklen; str = cfg[P11PROV_CFG_QUIRKS]; while (str) { sep = strchr(str, ' '); if (sep) { toklen = sep - str; } else { toklen = len; } if (strncmp(str, "no-deinit", toklen) == 0) { show_quirks = true; ctx->no_deinit = true; } else if (strncmp(str, "no-allowed-mechanisms", toklen) == 0) { show_quirks = true; ctx->no_allowed_mechanisms = true; } else if (strncmp(str, "no-operation-state", toklen) == 0) { show_quirks = true; ctx->blocked_calls |= P11PROV_BLOCK_GetOperationState; } else if (strncmp(str, "no-session-callbacks", toklen) == 0) { show_quirks = true; ctx->no_session_callbacks = true; } len -= toklen; if (sep) { str = sep + 1; len--; } else { str = NULL; } } } if (show_quirks) { P11PROV_debug("Quirks:"); if (ctx->no_deinit) { P11PROV_debug(" No finalization on de-initialization"); } if (ctx->no_allowed_mechanisms) { P11PROV_debug(" No CKA_ALLOWED_MECHANISM use"); } if (ctx->no_session_callbacks) { P11PROV_debug(" No session callbacks"); } if (ctx->blocked_calls) { P11PROV_debug(" Blocked calls: [%08lx]", ctx->blocked_calls); } } else { P11PROV_debug("No quirks"); } if (cfg[P11PROV_CFG_CACHE_SESSIONS] != NULL) { CK_ULONG val; ret = parse_ulong(ctx, cfg[P11PROV_CFG_CACHE_SESSIONS], strlen(cfg[P11PROV_CFG_CACHE_SESSIONS]), (void **)&val); if (ret != 0 || val > MAX_CONCURRENT_SESSIONS) { P11PROV_raise(ctx, CKR_GENERAL_ERROR, "Invalid value for %s: (%s)", p11prov_cfg_names[P11PROV_CFG_CACHE_SESSIONS].name, cfg[P11PROV_CFG_CACHE_SESSIONS]); p11prov_ctx_free(ctx); return RET_OSSL_ERR; } ctx->cache_sessions = val; } else { ctx->cache_sessions = MAX_CACHE_SESSIONS; } P11PROV_debug("Cache Sessions: %d", ctx->cache_sessions); if (cfg[P11PROV_CFG_ASSUME_FIPS] != NULL && strcmp(cfg[P11PROV_CFG_ASSUME_FIPS], "true") == 0) { ctx->assume_fips = true; } else { ctx->assume_fips = false; } P11PROV_debug("Assuming FIPS token is%s used", ctx->assume_fips ? "" : " not"); if (cfg[P11PROV_CFG_ENCODE_PROVIDER_URI_TO_PEM] != NULL && strcmp(cfg[P11PROV_CFG_ENCODE_PROVIDER_URI_TO_PEM], "true") == 0) { ctx->encode_pkey_as_pk11_uri = true; } else { ctx->encode_pkey_as_pk11_uri = false; } P11PROV_debug("PK11-URI will %sbe written instead of PrivateKeyInfo", ctx->encode_pkey_as_pk11_uri ? "" : "not "); if (cfg[P11PROV_CFG_BLOCK_OPS] != NULL) { const char *str; const char *sep; size_t len = strlen(cfg[P11PROV_CFG_BLOCK_OPS]); size_t tokl; bool match = false; P11PROV_debug("Blocked Operations:"); str = cfg[P11PROV_CFG_BLOCK_OPS]; while (str) { sep = strchr(str, ' '); if (sep) { tokl = sep - str; } else { tokl = len; } match = false; for (int i = 0; i < OSSL_OP__HIGHEST; i++) { if (p11prov_block_ops_names[i] && strncmp(str, p11prov_block_ops_names[i], tokl) == 0) { match = true; P11PROV_debug(" %s", p11prov_block_ops_names[i]); ctx->blocked_ops[i] = true; break; } } if (!match) { P11PROV_debug(" **invalid token: [%.*s]", (int)tokl, str); } len -= tokl; if (sep) { str = sep + 1; len--; } else { str = NULL; } } } else { P11PROV_debug("Blocked Operations: None"); } /* These operations need to be initialized when we return here for OpenSSL * to work. They do not need the token so they will not slow down * initialization. */ ret = static_operations_init(ctx); if (ret != CKR_OK) { p11prov_ctx_free(ctx); return RET_OSSL_ERR; } /* PAY ATTENTION: do this as the last thing */ if (cfg[P11PROV_CFG_LOAD_BEHAVIOR] != NULL && strcmp(cfg[P11PROV_CFG_LOAD_BEHAVIOR], "early") == 0) { /* this triggers early module loading */ ret = p11prov_ctx_status(ctx); if (ret != CKR_OK) { p11prov_ctx_free(ctx); return RET_OSSL_ERR; } } P11PROV_debug("Load behavior: %s", ctx->status == P11PROV_UNINITIALIZED ? "default" : "early"); /* done */ ret = RET_OSSL_OK; context_add_pool(ctx); *out = p11prov_dispatch_table; *provctx = ctx; return ret; } pkcs11-provider-1.0/src/provider.h000066400000000000000000000135311475270623700171160ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _PROVIDER_H #define _PROVIDER_H /* We need at least -D_XOPEN_SOURCE=700 for strnlen. */ #define _XOPEN_SOURCE 700 #include "config.h" #include #include #include "pkcs11.h" #include #include #include #include #include #include #include #include #include #include #include #define UNUSED __attribute__((unused)) #define RET_OSSL_OK 1 #define RET_OSSL_ERR 0 #define RET_OSSL_BAD -1 #define P11PROV_DEFAULT_PROPERTIES "provider=pkcs11" #define P11PROV_FIPS_PROPERTIES "provider=pkcs11,fips=yes" #define P11PROV_NAME_RSA "RSA" #define P11PROV_NAMES_RSA "RSA:rsaEncryption:1.2.840.113549.1.1.1" #define P11PROV_DESCS_RSA "PKCS11 RSA Implementation" #define P11PROV_NAME_RSAPSS "RSA-PSS" #define P11PROV_NAMES_RSAPSS "RSA-PSS:RSASSA-PSS:1.2.840.113549.1.1.10" #define P11PROV_DESCS_RSAPSS "PKCS11 RSA PSS Implementation" #define P11PROV_NAME_EC "EC" #define P11PROV_NAMES_EC "EC:id-ecPublicKey:1.2.840.10045.2.1" #define P11PROV_DESCS_EC "PKCS11 EC Implementation" #define P11PROV_NAME_ECDSA "ECDSA" #define P11PROV_NAMES_ECDSA P11PROV_NAME_ECDSA #define P11PROV_DESCS_ECDSA "PKCS11 ECDSA Implementation" #define P11PROV_NAME_ECDH "ECDH" #define P11PROV_NAMES_ECDH P11PROV_NAME_ECDH #define P11PROV_DESCS_ECDH "PKCS11 ECDH Implementation" #define P11PROV_NAME_HKDF "HKDF" #define P11PROV_NAMES_HKDF P11PROV_NAME_HKDF #define P11PROV_DESCS_HKDF "PKCS11 HKDF Implementation" #define P11PROV_NAMES_ED25519 "ED25519:1.3.101.112" #define P11PROV_NAME_ED25519 "ED25519" #define P11PROV_DESCS_ED25519 "PKCS11 ED25519 Implementation" #define P11PROV_NAMES_ED448 "ED448:1.3.101.113" #define P11PROV_NAME_ED448 "ED448" #define P11PROV_DESCS_ED448 "PKCS11 ED448 Implementation" #define P11PROV_NAMES_RAND "PKCS11-RAND" #define P11PROV_DESCS_RAND "PKCS11 Random Generator" #define P11PROV_NAME_CERTIFICATE "CERTIFICATE" #define P11PROV_NAME_TLS13_KDF "TLS13-KDF" #define P11PROV_NAMES_TLS13_KDF P11PROV_NAME_TLS13_KDF #define P11PROV_DESCS_TLS13_KDF "PKCS11 TLS 1.3 HKDF Implementation" #define P11PROV_NAMES_DER "DER" #define P11PROV_DESCS_DER "DER decoder implementation in PKCS11 provider" #define P11PROV_NAMES_URI "pkcs11" #define P11PROV_DESCS_URI "PKCS11 URI Store" #define P11PROV_PARAM_URI "pkcs11_uri" #define P11PROV_PARAM_KEY_USAGE "pkcs11_key_usage" #define P11PROV_PARAM_SLOT_ID "pkcs11_slot_id" typedef struct p11prov_ctx P11PROV_CTX; typedef struct p11prov_module_ctx P11PROV_MODULE; typedef struct p11prov_interface P11PROV_INTERFACE; typedef struct p11prov_uri P11PROV_URI; typedef struct p11prov_obj P11PROV_OBJ; typedef struct p11prov_slot P11PROV_SLOT; typedef struct p11prov_slots_ctx P11PROV_SLOTS_CTX; typedef struct p11prov_session P11PROV_SESSION; typedef struct p11prov_session_pool P11PROV_SESSION_POOL; typedef struct p11prov_obj_pool P11PROV_OBJ_POOL; #if __SANITIZE_ADDRESS__ #define P11PROV_ADDRESS_SANITIZER 1 #endif #if defined(__has_feature) #if __has_feature(address_sanitizer) #define P11PROV_ADDRESS_SANITIZER 1 #endif #endif /* Provider ctx */ P11PROV_INTERFACE *p11prov_ctx_get_interface(P11PROV_CTX *ctx); CK_UTF8CHAR_PTR p11prov_ctx_pin(P11PROV_CTX *ctx); OSSL_LIB_CTX *p11prov_ctx_get_libctx(P11PROV_CTX *ctx); CK_RV p11prov_ctx_status(P11PROV_CTX *ctx); P11PROV_SLOTS_CTX *p11prov_ctx_get_slots(P11PROV_CTX *ctx); void p11prov_ctx_set_slots(P11PROV_CTX *ctx, P11PROV_SLOTS_CTX *slots); CK_RV p11prov_ctx_get_quirk(P11PROV_CTX *ctx, CK_SLOT_ID id, const char *name, void **data, CK_ULONG *size); CK_RV p11prov_ctx_set_quirk(P11PROV_CTX *ctx, CK_SLOT_ID id, const char *name, void *data, CK_ULONG size); #define GET_ATTR 0 #define SET_ATTR 1 CK_RV p11prov_token_sup_attr(P11PROV_CTX *ctx, CK_SLOT_ID id, int action, CK_ATTRIBUTE_TYPE attr, CK_BBOOL *data); #define ALLOW_EXPORT_PUBLIC 0 #define DISALLOW_EXPORT_PUBLIC 1 int p11prov_ctx_allow_export(P11PROV_CTX *ctx); #define PUBKEY_LOGIN_AUTO 0 #define PUBKEY_LOGIN_ALWAYS 1 #define PUBKEY_LOGIN_NEVER 2 int p11prov_ctx_login_behavior(P11PROV_CTX *ctx); bool p11prov_ctx_cache_pins(P11PROV_CTX *ctx); enum p11prov_cache_keys { P11PROV_CACHE_KEYS_NEVER = 0, P11PROV_CACHE_KEYS_IN_SESSION, }; int p11prov_ctx_cache_keys(P11PROV_CTX *ctx); int p11prov_ctx_cache_sessions(P11PROV_CTX *ctx); bool p11prov_ctx_is_call_blocked(P11PROV_CTX *ctx, uint64_t mask); bool p11prov_ctx_no_session_callbacks(P11PROV_CTX *ctx); CK_INFO p11prov_ctx_get_ck_info(P11PROV_CTX *ctx); #include "debug.h" /* Errors */ void p11prov_raise(P11PROV_CTX *ctx, const char *file, int line, const char *func, int errnum, const char *fmt, ...); #define P11PROV_raise(ctx, errnum, format, ...) \ do { \ p11prov_raise((ctx), OPENSSL_FILE, OPENSSL_LINE, OPENSSL_FUNC, \ (errnum), format, ##__VA_ARGS__); \ P11PROV_debug("Error: 0x%08lX; " format, (unsigned long)(errnum), \ ##__VA_ARGS__); \ } while (0) int p11prov_set_error_mark(P11PROV_CTX *ctx); int p11prov_clear_last_error_mark(P11PROV_CTX *ctx); int p11prov_pop_error_to_mark(P11PROV_CTX *ctx); /* dispatching */ #define DECL_DISPATCH_FUNC(type, prefix, name) \ static OSSL_FUNC_##type##_##name##_fn prefix##_##name #include "interface.h" #include "objects.h" #include "keymgmt.h" #include "store.h" #include "signature.h" #include "asymmetric_cipher.h" #include "exchange.h" #include "kdf.h" #include "encoder.h" #include "digests.h" #include "util.h" #include "session.h" #include "slot.h" #include "random.h" #include "pk11_uri.h" /* TLS */ int tls_group_capabilities(OSSL_CALLBACK *cb, void *arg); #endif /* _PROVIDER_H */ pkcs11-provider-1.0/src/provider.map000066400000000000000000000000611475270623700174360ustar00rootroot00000000000000{ global: OSSL_provider_init; local: *; }; pkcs11-provider-1.0/src/random.c000066400000000000000000000135111475270623700165350ustar00rootroot00000000000000/* Copyright (C) 2023 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" DISPATCH_RAND_FN(newctx); /* required */ DISPATCH_RAND_FN(freectx); /* required */ DISPATCH_RAND_FN(instantiate); /* required */ DISPATCH_RAND_FN(uninstantiate); /* required */ DISPATCH_RAND_FN(generate); /* required */ DISPATCH_RAND_FN(reseed); DISPATCH_RAND_FN(get_ctx_params); /* required */ /* following functions are optional only in theory, * openssl depends on them */ DISPATCH_RAND_FN(enable_locking); DISPATCH_RAND_FN(lock); DISPATCH_RAND_FN(unlock); struct p11prov_rand_ctx { P11PROV_CTX *provctx; CK_SLOT_ID slotid; }; static void *p11prov_rand_newctx(void *provctx, void *parent, const OSSL_DISPATCH *parent_dispatch) { P11PROV_CTX *ctx = (P11PROV_CTX *)provctx; struct p11prov_rand_ctx *rctx; P11PROV_debug("rand newctx"); rctx = OPENSSL_zalloc(sizeof(struct p11prov_rand_ctx)); if (!rctx) { return NULL; } rctx->provctx = ctx; rctx->slotid = CK_UNAVAILABLE_INFORMATION; return rctx; } static void p11prov_rand_freectx(void *pctx) { P11PROV_debug("rand: freectx"); OPENSSL_free(pctx); } static int p11prov_rand_instantiate(void *pctx, unsigned int strength, int prediction_resistance, const unsigned char *pstr, size_t pstr_len, const OSSL_PARAM params[]) { struct p11prov_rand_ctx *ctx = (struct p11prov_rand_ctx *)pctx; CK_RV ret; P11PROV_debug("rand: instantiate"); ret = p11prov_ctx_status(ctx->provctx); if (ret != CKR_OK) { return RET_OSSL_ERR; } return RET_OSSL_OK; } static int p11prov_rand_uninstantiate(void *pctx) { P11PROV_debug("rand: uninstantiate"); return RET_OSSL_OK; } static int p11prov_rand_generate(void *pctx, unsigned char *out, size_t outlen, unsigned int strength, int prediction_resistance, const unsigned char *adin, size_t adin_len) { struct p11prov_rand_ctx *ctx = (struct p11prov_rand_ctx *)pctx; P11PROV_SESSION *session = NULL; CK_RV ret; int res = RET_OSSL_ERR; P11PROV_debug("rand: generate (add bytes: %zu)", adin_len); ret = p11prov_get_session(ctx->provctx, &ctx->slotid, NULL, NULL, CK_UNAVAILABLE_INFORMATION, NULL, NULL, false, false, &session); if (ret != CKR_OK) { return res; } if (adin && adin_len > 0) { /* we ignore the result, as this is optional */ (void)p11prov_SeedRandom(ctx->provctx, p11prov_session_handle(session), (CK_BYTE *)adin, adin_len); } ret = p11prov_GenerateRandom(ctx->provctx, p11prov_session_handle(session), (CK_BYTE *)out, outlen); if (ret == CKR_OK) { res = RET_OSSL_OK; } p11prov_return_session(session); return res; } static int p11prov_rand_reseed(void *pctx, int prediction_resistance, const unsigned char *entropy, size_t ent_len, const unsigned char *adin, size_t adin_len) { struct p11prov_rand_ctx *ctx = (struct p11prov_rand_ctx *)pctx; P11PROV_SESSION *session = NULL; CK_RV ret; int res = RET_OSSL_ERR; P11PROV_debug("rand: reseed (ent bytes: %zu, add bytes: %zu)", ent_len, adin_len); ret = p11prov_get_session(ctx->provctx, &ctx->slotid, NULL, NULL, CK_UNAVAILABLE_INFORMATION, NULL, NULL, false, false, &session); if (ret != CKR_OK) { return res; } if (entropy && ent_len > 0) { /* we ignore the result, as this is optional */ (void)p11prov_SeedRandom(ctx->provctx, p11prov_session_handle(session), (CK_BYTE *)entropy, ent_len); } if (adin && adin_len > 0) { /* we ignore the result, as this is optional */ (void)p11prov_SeedRandom(ctx->provctx, p11prov_session_handle(session), (CK_BYTE *)adin, adin_len); } p11prov_return_session(session); return res; } #define MAX_RAND_REQUEST INT_MAX static int p11prov_rand_get_ctx_params(void *pctx, OSSL_PARAM params[]) { OSSL_PARAM *p; int ret; P11PROV_debug("rand: get_ctx_params"); p = OSSL_PARAM_locate(params, OSSL_RAND_PARAM_MAX_REQUEST); if (p) { ret = OSSL_PARAM_set_size_t(p, MAX_RAND_REQUEST); if (ret != RET_OSSL_OK) { return ret; } } return RET_OSSL_OK; } static int p11prov_rand_enable_locking(void *pctx) { return RET_OSSL_OK; } static int p11prov_rand_lock(void *pctx) { return RET_OSSL_OK; } static void p11prov_rand_unlock(void *pctx) { /* nothing to do */ } const OSSL_DISPATCH p11prov_rand_functions[] = { DISPATCH_RAND_ELEM(rand, NEWCTX, newctx), DISPATCH_RAND_ELEM(rand, FREECTX, freectx), DISPATCH_RAND_ELEM(rand, INSTANTIATE, instantiate), DISPATCH_RAND_ELEM(rand, UNINSTANTIATE, uninstantiate), DISPATCH_RAND_ELEM(rand, GENERATE, generate), DISPATCH_RAND_ELEM(rand, RESEED, reseed), DISPATCH_RAND_ELEM(rand, GET_CTX_PARAMS, get_ctx_params), DISPATCH_RAND_ELEM(rand, ENABLE_LOCKING, enable_locking), DISPATCH_RAND_ELEM(rand, LOCK, lock), DISPATCH_RAND_ELEM(rand, UNLOCK, unlock), { 0, NULL }, }; CK_RV p11prov_check_random(P11PROV_CTX *ctx) { struct p11prov_rand_ctx rctx = { .provctx = ctx, .slotid = CK_UNAVAILABLE_INFORMATION, }; unsigned char test[8]; int ret; ret = p11prov_rand_generate(&rctx, test, 8, 0, 0, NULL, 0); if (ret != RET_OSSL_OK) { return CKR_FUNCTION_NOT_SUPPORTED; } return CKR_OK; } pkcs11-provider-1.0/src/random.h000066400000000000000000000007521475270623700165450ustar00rootroot00000000000000/* Copyright (C) 2023 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _PKCS11_RANDOM_H #define _PKCS11_RANDOM_H #define DISPATCH_RAND_FN(name) DECL_DISPATCH_FUNC(rand, p11prov_rand, name) #define DISPATCH_RAND_ELEM(prefix, NAME, name) \ { \ OSSL_FUNC_RAND_##NAME, (void (*)(void))p11prov_##prefix##_##name \ } extern const OSSL_DISPATCH p11prov_rand_functions[]; CK_RV p11prov_check_random(P11PROV_CTX *ctx); #endif /* _PKCS11_RANDOM_H */ pkcs11-provider-1.0/src/session.c000066400000000000000000001026051475270623700167430ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include #include #define DEFLT_SESSION_FLAGS CKF_SERIAL_SESSION struct p11prov_session { P11PROV_CTX *provctx; P11PROV_SESSION_POOL *pool; CK_SLOT_ID slotid; CK_SESSION_HANDLE session; CK_STATE state; CK_FLAGS flags; pthread_mutex_t lock; bool in_use; p11prov_session_callback_t cb; void *cbarg; }; struct p11prov_session_pool { P11PROV_CTX *provctx; CK_SLOT_ID slotid; CK_ULONG num_sessions; CK_ULONG max_sessions; CK_ULONG open_sessions; CK_ULONG max_cached_sessions; P11PROV_SESSION **sessions; P11PROV_SESSION *login_session; pthread_mutex_t lock; }; static CK_RV token_session_callback(CK_SESSION_HANDLE hSession, CK_NOTIFICATION event, CK_VOID_PTR pApplication) { P11PROV_SESSION *session = (P11PROV_SESSION *)pApplication; if (session->session != hSession) { /* something not right, let's ignore this callback */ return CKR_OK; } if (session->cb) { return session->cb(session->cbarg); } return CKR_OK; } /* in nanoseconds, 1 seconds */ #define MAX_WAIT 1000000000 /* sleep interval, 50 microseconds (max 20 attempts) */ #define SLEEP 50000 static CK_RV token_session_open(P11PROV_SESSION *session, CK_FLAGS flags) { CK_SESSION_INFO session_info; uint64_t startime = 0; CK_RV ret; do { if (p11prov_ctx_no_session_callbacks(session->provctx)) { P11PROV_debug("Opening session without callbacks %lu", session->session); ret = p11prov_OpenSession(session->provctx, session->slotid, flags, NULL, NULL, &session->session); } else { ret = p11prov_OpenSession(session->provctx, session->slotid, flags, session, token_session_callback, &session->session); } P11PROV_debug("C_OpenSession ret:%lu (session: %lu)", ret, session->session); if (ret != CKR_SESSION_COUNT) { break; } } while (cyclewait_with_timeout(MAX_WAIT, SLEEP, &startime)); if (ret != CKR_OK) { session->session = CK_INVALID_HANDLE; session->flags = DEFLT_SESSION_FLAGS; session->state = CK_UNAVAILABLE_INFORMATION; return ret; } session->flags = flags; /* get current state */ ret = p11prov_GetSessionInfo(session->provctx, session->session, &session_info); if (ret == CKR_OK) { session->flags = session_info.flags; session->state = session_info.state; } return ret; } static void token_session_close(P11PROV_SESSION *session) { if (session->session != CK_INVALID_HANDLE) { P11PROV_debug("Closing session %lu", session->session); (void)p11prov_CloseSession(session->provctx, session->session); /* regardless of the result the session is gone */ session->session = CK_INVALID_HANDLE; session->flags = DEFLT_SESSION_FLAGS; session->state = CK_UNAVAILABLE_INFORMATION; } } CK_RV p11prov_session_pool_init(P11PROV_CTX *ctx, CK_TOKEN_INFO *token, CK_SLOT_ID id, P11PROV_SESSION_POOL **_pool) { P11PROV_SESSION_POOL *pool; int ret; P11PROV_debug("Creating new session pool"); pool = OPENSSL_zalloc(sizeof(P11PROV_SESSION_POOL)); if (!pool) { return CKR_HOST_MEMORY; } pool->provctx = ctx; pool->slotid = id; ret = MUTEX_INIT(pool); if (ret != CKR_OK) { OPENSSL_free(pool); return ret; } if (token->ulMaxSessionCount != CK_EFFECTIVELY_INFINITE && token->ulMaxSessionCount != CK_UNAVAILABLE_INFORMATION) { pool->max_sessions = token->ulMaxSessionCount; } else { pool->max_sessions = MAX_CONCURRENT_SESSIONS; } pool->max_cached_sessions = p11prov_ctx_cache_sessions(ctx); if (pool->max_sessions < pool->max_cached_sessions) { pool->max_cached_sessions = pool->max_sessions - 1; } P11PROV_debug("New session pool %p created", pool); *_pool = pool; return CKR_OK; } static void session_free(P11PROV_SESSION *session); void p11prov_session_pool_free(P11PROV_SESSION_POOL *pool) { P11PROV_debug("Freeing session pool %p", pool); if (!pool) { return; } /* LOCKED SECTION ------------- */ if (MUTEX_LOCK(pool) == CKR_OK) { for (int i = 0; i < pool->num_sessions; i++) { session_free(pool->sessions[i]); pool->sessions[i] = NULL; } OPENSSL_free(pool->sessions); (void)MUTEX_UNLOCK(pool); } /* ------------- LOCKED SECTION */ else { return; } (void)MUTEX_DESTROY(pool); OPENSSL_clear_free(pool, sizeof(P11PROV_SESSION_POOL)); } static CK_RV session_new_bare(P11PROV_SESSION_POOL *pool, P11PROV_SESSION **_session); void p11prov_session_pool_fork_reset(P11PROV_SESSION_POOL *pool) { P11PROV_debug("Resetting sessions in pool %p", pool); if (!pool) { return; } if (MUTEX_LOCK(pool) == CKR_OK) { /* LOCKED SECTION ------------- */ pool->login_session = NULL; for (int i = 0; i < pool->num_sessions; i++) { P11PROV_SESSION *session = pool->sessions[i]; CK_RV ret; session->session = CK_INVALID_HANDLE; session->flags = DEFLT_SESSION_FLAGS; session->state = CK_UNAVAILABLE_INFORMATION; session->in_use = false; session->cb = NULL; session->cbarg = NULL; /* at last reinit mutex and replace on failure */ ret = MUTEX_INIT(session); if (ret != CKR_OK) { /* this is bad, but all we can do is hope this * session will never be used and just orphan it */ P11PROV_debug("Failed to reinint session lock"); session->pool = NULL; /* if this fails nothing really we can do, * we leave the current broken session and * it will never be used because lockig it * should always fail */ ret = session_new_bare(pool, &session); if (ret != CKR_OK) { /* session was unchanged, put the pool back */ session->pool = pool; } } } (void)MUTEX_UNLOCK(pool); /* ------------- LOCKED SECTION */ } else { P11PROV_debug("Failed to reset sessions in pool"); } } static CK_RV session_new_bare(P11PROV_SESSION_POOL *pool, P11PROV_SESSION **_session) { P11PROV_SESSION *session; int ret; session = OPENSSL_zalloc(sizeof(P11PROV_SESSION)); if (session == NULL) { ret = CKR_HOST_MEMORY; P11PROV_raise(pool->provctx, ret, "Failed to allocate session"); return ret; } session->provctx = pool->provctx; session->slotid = pool->slotid; session->session = CK_INVALID_HANDLE; session->flags = DEFLT_SESSION_FLAGS; session->state = CK_UNAVAILABLE_INFORMATION; session->pool = pool; ret = MUTEX_INIT(session); if (ret != CKR_OK) { OPENSSL_free(session); return ret; } *_session = session; return CKR_OK; } #define SESS_ALLOC_SIZE 32 /* NOTE: to be called with Pool Lock held, * returns a locked session */ static CK_RV session_new(P11PROV_SESSION_POOL *pool, P11PROV_SESSION **_session) { P11PROV_SESSION *session; int ret; P11PROV_debug("Creating new P11PROV_SESSION session on pool %p", pool); if (pool->num_sessions >= pool->max_sessions) { ret = CKR_SESSION_COUNT; P11PROV_raise(pool->provctx, ret, "Max sessions (%lu) exceeded", pool->max_sessions); return ret; } ret = session_new_bare(pool, &session); if (ret != CKR_OK) { return ret; } /* check if we need to expand the sessions array */ if ((pool->num_sessions % SESS_ALLOC_SIZE) == 0) { P11PROV_SESSION **tmp = OPENSSL_realloc( pool->sessions, (pool->num_sessions + SESS_ALLOC_SIZE) * sizeof(P11PROV_SESSION *)); if (tmp == NULL) { ret = CKR_HOST_MEMORY; P11PROV_raise(pool->provctx, ret, "Failed to re-allocate sessions array"); session_free(session); return ret; } pool->sessions = tmp; } /* mark this session as owned only once nothing else can fail */ session->in_use = true; pool->sessions[pool->num_sessions] = session; pool->num_sessions++; P11PROV_debug("Total sessions: %lu", pool->num_sessions); *_session = session; return CKR_OK; } static CK_RV session_check(P11PROV_SESSION *session, CK_FLAGS flags) { CK_SESSION_INFO session_info; int ret; if (!session) { return CKR_GENERAL_ERROR; } /* lockless check, if this fails in any way it is bad regardless */ if (!session->in_use) { return CKR_GENERAL_ERROR; } /* no handle, nothing to check */ if (session->session == CK_INVALID_HANDLE) { return CKR_OK; } /* check that the pkcs11 session is still ok */ ret = p11prov_GetSessionInfo(session->provctx, session->session, &session_info); if (ret == CKR_OK) { session->state = session_info.state; if (flags == session_info.flags) { return CKR_OK; } (void)p11prov_CloseSession(session->provctx, session->session); /* tell the caller that the session was closed so they can * keep up with accounting */ ret = CKR_SESSION_CLOSED; } /* session has been closed elsewhere, or otherwise unusable */ session->session = CK_INVALID_HANDLE; session->state = CK_UNAVAILABLE_INFORMATION; return ret; } /* only call this from session_new or p11prov_session_pool_free */ static void session_free(P11PROV_SESSION *session) { bool abandon = true; int ret; P11PROV_debug("Session Free %p", session); if (session == NULL) { return; } ret = MUTEX_LOCK(session); /* LOCKED SECTION ------------- */ if (ret == CKR_OK) { if (!session->in_use) { abandon = false; } (void)MUTEX_UNLOCK(session); /* ------------- LOCKED SECTION */ } if (abandon) { /* just orphan this session, will potentially leak memory ... */ session->pool = NULL; return; } (void)MUTEX_DESTROY(session); token_session_close(session); OPENSSL_clear_free(session, sizeof(P11PROV_SESSION)); } CK_SESSION_HANDLE p11prov_session_handle(P11PROV_SESSION *session) { if (!session) { return CK_INVALID_HANDLE; } return session->session; } CK_SLOT_ID p11prov_session_slotid(P11PROV_SESSION *session) { if (!session) { return CK_UNAVAILABLE_INFORMATION; } return session->slotid; } static int p11prov_session_prompt_for_pin(struct p11prov_slot *slot, char *cb_pin, size_t *cb_pin_len) { char *prompt = NULL; UI *ui = UI_new_method(NULL); const char *login_info = p11prov_slot_get_login_info(slot); int ret; P11PROV_debug("Starting internal PIN prompt slot=%p", slot); if (ui == NULL) { ret = RET_OSSL_ERR; goto err; } prompt = UI_construct_prompt(ui, "PIN", login_info); if (!prompt) { ret = RET_OSSL_ERR; goto err; } ret = UI_dup_input_string(ui, prompt, UI_INPUT_FLAG_DEFAULT_PWD, cb_pin, 4, MAX_PIN_LENGTH); if (ret <= 0) { ret = RET_OSSL_ERR; goto err; } if (UI_process(ui)) { ret = RET_OSSL_ERR; goto err; } *cb_pin_len = strlen(cb_pin); err: OPENSSL_free(prompt); UI_free(ui); return ret; } static CK_RV check_pin_flags_ok(P11PROV_CTX *ctx, CK_SLOT_ID slotid) { CK_TOKEN_INFO token; CK_RV ret; ret = p11prov_GetTokenInfo(ctx, slotid, &token); if (ret != CKR_OK) { return ret; } if (token.flags & CKF_USER_PIN_FINAL_TRY) { ret = CKR_CANCEL; P11PROV_raise(ctx, ret, "Only one auth attempt left on token. " "Canceling login attempt to avoid locking the token. " "Manual user login required to reset counter."); } else if (token.flags & CKF_USER_PIN_LOCKED) { ret = CKR_PIN_LOCKED; P11PROV_raise(ctx, ret, "PIN marked as locked, canceling login"); } else if (token.flags & CKF_USER_PIN_TO_BE_CHANGED) { ret = CKR_PIN_EXPIRED; P11PROV_raise(ctx, ret, "PIN marked as expired, canceling login"); } else { ret = CKR_OK; } return ret; } /* returns a locked login_session if _session is not NULL */ static CK_RV token_login(P11PROV_SESSION *session, P11PROV_URI *uri, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg, struct p11prov_slot *slot, CK_USER_TYPE user_type) { char cb_pin[MAX_PIN_LENGTH + 1] = { 0 }; size_t cb_pin_len = 0; CK_UTF8CHAR_PTR pin = NULL_PTR; CK_ULONG pinlen = 0; CK_TOKEN_INFO *token; bool cache = false; CK_RV ret; P11PROV_debug("Log into the token session=%p uri=%p slot=%p type=%lu", session, uri, slot, user_type); token = p11prov_slot_get_token(slot); if (!(token->flags & CKF_PROTECTED_AUTHENTICATION_PATH)) { const char *cached_pin = p11prov_slot_get_cached_pin(slot); const char *bad_pin = p11prov_slot_get_bad_pin(slot); if (uri) { pin = (CK_UTF8CHAR_PTR)p11prov_uri_get_pin(uri); } if (!pin) { pin = p11prov_ctx_pin(session->provctx); } if (!pin && cached_pin) { pin = (CK_UTF8CHAR_PTR)cached_pin; } if (pin && bad_pin && strcmp((char *)pin, bad_pin) == 0) { P11PROV_raise(session->provctx, CKR_PIN_INVALID, "Blocking stored PIN that failed a previous login" " to avoid blocking the token"); pin = NULL; } if (pin) { pinlen = strlen((const char *)pin); } else { if (pw_cb) { const char *login_info = p11prov_slot_get_login_info(slot); OSSL_PARAM params[2] = { OSSL_PARAM_DEFN(OSSL_PASSPHRASE_PARAM_INFO, OSSL_PARAM_UTF8_STRING, (void *)login_info, strlen(login_info)), OSSL_PARAM_END, }; ret = pw_cb(cb_pin, sizeof(cb_pin), &cb_pin_len, params, pw_cbarg); if (ret != RET_OSSL_OK) { /* this error can mean anything from the user canceling * the prompt to no UI method provided. * Fall back to our prompt here */ ret = p11prov_session_prompt_for_pin(slot, (char *)cb_pin, &cb_pin_len); if (ret != RET_OSSL_OK) { /* give up */ ret = CKR_GENERAL_ERROR; goto done; } } } else { /* We are asking the user off-band for the user consent -- from * store we will always receive non-null (but unusable) callback */ ret = p11prov_session_prompt_for_pin(slot, (char *)cb_pin, &cb_pin_len); if (ret != RET_OSSL_OK) { ret = CKR_GENERAL_ERROR; goto done; } } if (cb_pin_len == 0) { ret = CKR_CANCEL; goto done; } pin = (CK_UTF8CHAR_PTR)cb_pin; pinlen = cb_pin_len; cache = p11prov_ctx_cache_pins(session->provctx); } } ret = check_pin_flags_ok(session->provctx, session->slotid); if (ret != CKR_OK) { goto done; } P11PROV_debug("Attempt Login on session %lu", session->session); /* Supports only USER login sessions for now */ ret = p11prov_Login(session->provctx, session->session, user_type, pin, pinlen); if (ret == CKR_USER_ALREADY_LOGGED_IN) { ret = CKR_OK; } else { if (pin && ret == CKR_PIN_INCORRECT) { CK_RV trv; /* mark this pin as bad or we may end up locking the token */ trv = p11prov_slot_set_bad_pin(slot, (const char *)pin); /* not much we can do on failure */ if (trv != CKR_OK) { P11PROV_raise(session->provctx, trv, "Failed to set bad_pin"); } } } if (ret == CKR_OK && pin && cache) { CK_RV trv; trv = p11prov_slot_set_cached_pin(slot, (const char *)pin); /* not much we can do on failure */ if (trv != CKR_OK) { P11PROV_raise(session->provctx, trv, "Failed to cache pin"); } } done: OPENSSL_cleanse(cb_pin, cb_pin_len); return ret; } CK_RV p11prov_context_specific_login(P11PROV_SESSION *session, P11PROV_URI *uri, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) { P11PROV_SLOTS_CTX *sctx = NULL; P11PROV_SLOT *slot = NULL; CK_RV ret; P11PROV_debug("Providing context specific login session=%p uri=%p", session, uri); ret = p11prov_take_slots(session->provctx, &sctx); if (ret != CKR_OK) { return CKR_GENERAL_ERROR; } slot = p11prov_get_slot_by_id(sctx, p11prov_session_slotid(session)); if (!slot) { ret = CKR_GENERAL_ERROR; goto done; } ret = token_login(session, uri, pw_cb, pw_cbarg, slot, CKU_CONTEXT_SPECIFIC); done: p11prov_return_slots(sctx); return ret; } static CK_RV check_slot(P11PROV_CTX *ctx, P11PROV_SLOT *slot, P11PROV_URI *uri, CK_MECHANISM_TYPE mechtype, bool rw) { CK_TOKEN_INFO *token; CK_SLOT_INFO *ck_slot; CK_SLOT_ID slotid; CK_RV ret; slotid = p11prov_slot_get_slot_id(slot); P11PROV_debug("Checking Slot id=%lu, uri=%p, mechtype=%lx, rw=%s)", slotid, uri, mechtype, rw ? "true" : "false"); ck_slot = p11prov_slot_get_slot(slot); if ((ck_slot->flags & CKF_TOKEN_PRESENT) == 0) { return CKR_TOKEN_NOT_PRESENT; } token = p11prov_slot_get_token(slot); if ((token->flags & CKF_TOKEN_INITIALIZED) == 0) { return CKR_TOKEN_NOT_PRESENT; } if (rw && (token->flags & CKF_WRITE_PROTECTED)) { return CKR_TOKEN_WRITE_PROTECTED; } if (uri) { ret = p11prov_uri_match_token(uri, slotid, ck_slot, token); if (ret != CKR_OK) { return ret; } } if (mechtype != CK_UNAVAILABLE_INFORMATION) { ret = p11prov_check_mechanism(ctx, slotid, mechtype); if (ret != CKR_OK) { return ret; } } return CKR_OK; } static bool is_login_state(CK_STATE state) { switch (state) { case CKS_RO_USER_FUNCTIONS: case CKS_RW_USER_FUNCTIONS: case CKS_RW_SO_FUNCTIONS: return true; default: break; } return false; } static CK_RV fetch_session(P11PROV_SESSION_POOL *pool, CK_FLAGS flags, bool login_session, P11PROV_SESSION **_session) { P11PROV_SESSION *session = NULL; bool found = false; int ret; ret = MUTEX_LOCK(pool); if (ret != CKR_OK) { return ret; } /* LOCKED SECTION ------------- */ if (login_session && pool->login_session) { ret = MUTEX_LOCK(pool->login_session); if (ret == CKR_OK) { if (pool->login_session->in_use) { if (is_login_state(pool->login_session->state)) { ret = CKR_USER_ALREADY_LOGGED_IN; } else { ret = CKR_CANT_LOCK; } } else { session = pool->login_session; session->in_use = true; found = true; } (void)MUTEX_UNLOCK(pool->login_session); } goto done; } /* try to find session with a cached handle first */ for (int i = 0; i < pool->num_sessions && !found; i++) { session = pool->sessions[i]; if (session == pool->login_session) { continue; } if (session->flags == flags) { if (session->session != CK_INVALID_HANDLE) { ret = MUTEX_LOCK(session); if (ret == CKR_OK) { /* LOCKED SECTION ------------- */ if (!session->in_use) { /* Bingo! A compatible session with a cached handle */ session->in_use = true; found = true; } /* No luck */ (void)MUTEX_UNLOCK(session); /* ------------- LOCKED SECTION */ } } } } /* try again, get any free session */ for (int i = 0; i < pool->num_sessions && !found; i++) { session = pool->sessions[i]; if (session == pool->login_session) { continue; } ret = MUTEX_LOCK(session); if (ret == CKR_OK) { /* LOCKED SECTION ------------- */ if (!session->in_use) { /* we got a free session */ session->in_use = true; found = true; } /* No luck */ (void)MUTEX_UNLOCK(session); /* ------------- LOCKED SECTION */ } } if (!found) { session = NULL; /* no free sessions, try to allocate a new one */ ret = session_new(pool, &session); if (ret == CKR_OK) { found = true; } } done: if (login_session && found) { pool->login_session = session; } (void)MUTEX_UNLOCK(pool); /* ------------- LOCKED SECTION */ if (ret == CKR_OK) { *_session = session; } return ret; } /* sleep interval, 5 microseconds */ #define LOCK_SLEEP 5000 static CK_RV slot_login(P11PROV_SLOT *slot, P11PROV_URI *uri, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg, bool reqlogin, P11PROV_SESSION **_session) { P11PROV_SESSION_POOL *pool = p11prov_slot_get_session_pool(slot); P11PROV_SESSION *session = NULL; CK_FLAGS flags = DEFLT_SESSION_FLAGS; int num_open_sessions = 0; CK_RV ret; /* try to get a login_session */ ret = fetch_session(pool, flags, true, &session); if (ret == CKR_USER_ALREADY_LOGGED_IN && _session == NULL) { P11PROV_debug("A login session already exists"); return CKR_OK; } if (ret != CKR_OK) { if (reqlogin) { /* try a few times to get a login session, * but eventually timeout if it doesn't work to avoid deadlocks */ uint64_t startime = 0; do { ret = fetch_session(pool, flags, true, &session); if (ret == CKR_OK) { break; } } while (cyclewait_with_timeout(MAX_WAIT, LOCK_SLEEP, &startime)); } if (ret != CKR_OK) { P11PROV_raise(pool->provctx, ret, "Failed to fetch login_session"); return ret; } } /* we acquired the session, check that it is ok */ ret = session_check(session, session->flags); if (ret != CKR_OK) { num_open_sessions--; } if (session->session == CK_INVALID_HANDLE) { ret = token_session_open(session, flags); if (ret == CKR_OK) { num_open_sessions++; } else { goto done; } } if (is_login_state(session->state)) { /* we seem to already have a valid logged in session */ ret = CKR_OK; } else { ret = token_login(session, uri, pw_cb, pw_cbarg, slot, CKU_USER); } done: /* lock the pool only if needed */ if (num_open_sessions != 0 || ret != CKR_OK) { /* LOCKED SECTION ------------- */ if (MUTEX_LOCK(pool) == CKR_OK) { pool->open_sessions += num_open_sessions; if (ret != CKR_OK) { if (pool->login_session != session) { /* something raced us during the login and replaced * the login session, hands off */ } else { /* remove the session, as it is not a good one */ pool->login_session = NULL; } } (void)MUTEX_UNLOCK(pool); } /* ------------- LOCKED SECTION */ } if (_session) { *_session = session; } else { /* unlock the session */ p11prov_return_session(session); } return ret; } static bool check_skip_login(P11PROV_CTX *ctx, P11PROV_SLOT *slot) { return p11prov_ctx_login_behavior(ctx) != PUBKEY_LOGIN_ALWAYS && !p11prov_slot_check_req_login(slot); } /* There are three possible ways to call this function. * 1. One shot call on a specific slot * slotid must point to a specific slot number * next_slotid must be NULL * 2. Find first viable slot * slotid must point to a slot value of CK_UNAVAILABLE_INFORMATION * next_slotid must be NULL * 3. slot iteration * slotid must initially specify a value of CK_UNAVAILABLE_INFORMATION * next_sloitd must NOT be NULL * on following iterations the next_slotid value must be handed back * as the slotid value * if the function returns CK_UNAVAILABLE_INFORMATION in next_slotid * it means there is no more slots to iterate over */ CK_RV p11prov_get_session(P11PROV_CTX *provctx, CK_SLOT_ID *slotid, CK_SLOT_ID *next_slotid, P11PROV_URI *uri, CK_MECHANISM_TYPE mechtype, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg, bool reqlogin, bool rw, P11PROV_SESSION **_session) { P11PROV_SLOTS_CTX *slots = NULL; P11PROV_SLOT *slot = NULL; P11PROV_SESSION_POOL *pool = NULL; CK_SLOT_ID id = *slotid; P11PROV_SESSION *session = NULL; int num_open_sessions = 0; CK_FLAGS flags = DEFLT_SESSION_FLAGS; int slot_idx; CK_RV ret; P11PROV_debug("Get session on slot %lu, reqlogin=%s, rw=%s", id, reqlogin ? "true" : "false", rw ? "true" : "false"); ret = p11prov_take_slots(provctx, &slots); if (ret != CKR_OK) { return ret; } if (id != CK_UNAVAILABLE_INFORMATION && next_slotid == NULL) { P11PROV_debug("single-shot request for slot %lu", id); slot_idx = 0; /* single shot request for a specific slot */ for (slot = p11prov_fetch_slot(slots, &slot_idx); slot != NULL; slot = p11prov_fetch_slot(slots, &slot_idx)) { if (p11prov_slot_get_slot_id(slot) == id) { break; } } if (!slot) { ret = CKR_SLOT_ID_INVALID; goto done; } ret = check_slot(provctx, slot, uri, mechtype, rw); if (ret != CKR_OK) { goto done; } if (reqlogin && !check_skip_login(provctx, slot)) { ret = slot_login(slot, uri, pw_cb, pw_cbarg, reqlogin, NULL); if (ret != CKR_OK) { goto done; } } } else { P11PROV_debug("cycle through available slots"); slot_idx = 0; ret = CKR_CANCEL; /* set error mark so we can clear spurious errors on success */ p11prov_set_error_mark(provctx); /* caller is cycling through slots, find the next viable one */ for (slot = p11prov_fetch_slot(slots, &slot_idx); slot != NULL; slot = p11prov_fetch_slot(slots, &slot_idx)) { CK_SLOT_ID slot_id = p11prov_slot_get_slot_id(slot); if (id != CK_UNAVAILABLE_INFORMATION && id != slot_id) { /* seek to next slot to check */ continue; } else { /* Found "next" slot. * Reset the id, so from now on we check every following slot * and return the first one that successfully passes checks. */ id = CK_UNAVAILABLE_INFORMATION; } ret = check_slot(provctx, slot, uri, mechtype, rw); if (ret != CKR_OK) { /* keep going */ continue; } if (reqlogin && !check_skip_login(provctx, slot)) { ret = slot_login(slot, uri, pw_cb, pw_cbarg, reqlogin, NULL); if (ret != CKR_OK) { /* keep going */ continue; } } id = slot_id; P11PROV_debug("Found a slot %lu", id); break; } if (ret == CKR_OK) { /* Found a slot, return it and the next slot to the caller for * continuation if the current slot does not yield the desired * results */ /* if there was any error, remove it, as we got success */ p11prov_pop_error_to_mark(provctx); *slotid = id; if (next_slotid) { P11PROV_SLOT *next_slot; next_slot = p11prov_fetch_slot(slots, &slot_idx); if (next_slot) { *next_slotid = p11prov_slot_get_slot_id(next_slot); } else { *next_slotid = CK_UNAVAILABLE_INFORMATION; } } } else { /* otherwise clear the mark and leave errors on the stack */ p11prov_clear_last_error_mark(provctx); if (next_slotid) { *next_slotid = CK_UNAVAILABLE_INFORMATION; } goto done; } } pool = p11prov_slot_get_session_pool(slot); if (rw) { flags |= CKF_RW_SESSION; } ret = fetch_session(pool, flags, false, &session); if (ret == CKR_OK) { ret = session_check(session, flags); if (ret != CKR_OK) { num_open_sessions--; ret = CKR_OK; } if (session->session == CK_INVALID_HANDLE) { ret = token_session_open(session, flags); if (ret == CKR_OK) { num_open_sessions++; } } } done: if (pool && num_open_sessions != 0) { /* if locking fails here we have bigger problems than * just bad accounting */ /* LOCKED SECTION ------------- */ if (MUTEX_LOCK(pool) == CKR_OK) { pool->open_sessions += num_open_sessions; (void)MUTEX_UNLOCK(pool); } /* ------------- LOCKED SECTION */ } if (ret == CKR_OK) { *_session = session; } else { p11prov_return_session(session); } p11prov_return_slots(slots); return ret; } CK_RV p11prov_take_login_session(P11PROV_CTX *provctx, CK_SLOT_ID slotid, P11PROV_SESSION **_session) { P11PROV_SLOTS_CTX *slots = NULL; P11PROV_SLOT *slot = NULL; int slot_idx = 0; CK_RV ret; P11PROV_debug("Get login session from slot %lu", slotid); ret = p11prov_take_slots(provctx, &slots); if (ret != CKR_OK) { return ret; } for (slot = p11prov_fetch_slot(slots, &slot_idx); slot != NULL; slot = p11prov_fetch_slot(slots, &slot_idx)) { if (slotid == p11prov_slot_get_slot_id(slot)) { break; } } if (!slot || !p11prov_slot_get_session_pool(slot)) { ret = CKR_SLOT_ID_INVALID; goto done; } ret = slot_login(slot, NULL, NULL, NULL, false, _session); done: p11prov_return_slots(slots); return ret; } void p11prov_return_session(P11PROV_SESSION *session) { P11PROV_SESSION_POOL *pool; CK_RV ret; if (!session) { return; } /* remove any callback */ p11prov_session_set_callback(session, NULL, NULL); pool = session->pool; if (pool) { /* LOCKED SECTION ------------- */ if (MUTEX_LOCK(pool) == CKR_OK) { if (pool->open_sessions >= pool->max_cached_sessions && session != pool->login_session) { token_session_close(session); pool->open_sessions--; } (void)MUTEX_UNLOCK(pool); } /* ------------- LOCKED SECTION */ } ret = MUTEX_LOCK(session); if (ret == CKR_OK) { /* LOCKED SECTION ------------- */ session->in_use = false; (void)MUTEX_UNLOCK(session); /* ------------- LOCKED SECTION */ } else { /* not much we can do if this fails */ P11PROV_raise(session->provctx, ret, "Failed to release session object"); return; } if (!pool) { /* handle case where session was orphaned because in use while * the pool was being freed */ session_free(session); } } void p11prov_session_set_callback(P11PROV_SESSION *session, p11prov_session_callback_t cb, void *cbarg) { session->cb = cb; session->cbarg = cbarg; } pkcs11-provider-1.0/src/session.h000066400000000000000000000031151475270623700167440ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _SESSION_H #define _SESSION_H /* Sessions */ CK_RV p11prov_session_pool_init(P11PROV_CTX *ctx, CK_TOKEN_INFO *token, CK_SLOT_ID id, P11PROV_SESSION_POOL **_pool); void p11prov_session_pool_free(P11PROV_SESSION_POOL *pool); void p11prov_session_pool_fork_reset(P11PROV_SESSION_POOL *pool); CK_SESSION_HANDLE p11prov_session_handle(P11PROV_SESSION *session); CK_SLOT_ID p11prov_session_slotid(P11PROV_SESSION *session); CK_RV p11prov_get_session(P11PROV_CTX *provctx, CK_SLOT_ID *slotid, CK_SLOT_ID *next_slotid, P11PROV_URI *uri, CK_MECHANISM_TYPE mechtype, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg, bool reqlogin, bool rw, P11PROV_SESSION **session); CK_RV p11prov_take_login_session(P11PROV_CTX *provctx, CK_SLOT_ID slotid, P11PROV_SESSION **_session); void p11prov_return_session(P11PROV_SESSION *session); CK_RV p11prov_context_specific_login(P11PROV_SESSION *session, P11PROV_URI *uri, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg); typedef CK_RV (*p11prov_session_callback_t)(void *cbarg); void p11prov_session_set_callback(P11PROV_SESSION *session, p11prov_session_callback_t cb, void *cbarg); /* Some reasonable limit */ #define MAX_CONCURRENT_SESSIONS 1024 #define MAX_CACHE_SESSIONS 5 #endif /* _SESSION_H */ pkcs11-provider-1.0/src/signature.c000066400000000000000000002405451475270623700172670ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include #include "openssl/evp.h" #include "openssl/rsa.h" #include "openssl/ec.h" #include "openssl/sha.h" struct p11prov_sig_ctx { P11PROV_CTX *provctx; char *properties; P11PROV_OBJ *key; CK_MECHANISM_TYPE mechtype; CK_MECHANISM_TYPE digest; CK_FLAGS operation; P11PROV_SESSION *session; CK_RSA_PKCS_PSS_PARAMS pss_params; /* EdDSA param data */ CK_EDDSA_PARAMS eddsa_params; CK_BBOOL use_eddsa_params; /* If not NULL this indicates that the requested mechanism to calculate * digest+signature (C_SignUpdate/C_VerifyUpdate) is not supported by * the token, so we try to fall back to calculating the digest * separately and then applying a raw signature on the result. */ EVP_MD_CTX *mechanism_fallback; }; typedef struct p11prov_sig_ctx P11PROV_SIG_CTX; DISPATCH_SIG_FN(freectx); DISPATCH_SIG_FN(dupctx); static P11PROV_SIG_CTX *p11prov_sig_newctx(P11PROV_CTX *ctx, CK_MECHANISM_TYPE type, const char *properties) { P11PROV_SIG_CTX *sigctx; sigctx = OPENSSL_zalloc(sizeof(P11PROV_SIG_CTX)); if (sigctx == NULL) { return NULL; } sigctx->provctx = ctx; if (properties) { sigctx->properties = OPENSSL_strdup(properties); if (sigctx->properties == NULL) { OPENSSL_free(sigctx); return NULL; } } sigctx->mechtype = type; return sigctx; } static void *p11prov_sig_dupctx(void *ctx) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; P11PROV_SIG_CTX *newctx; CK_SLOT_ID slotid = CK_UNAVAILABLE_INFORMATION; CK_OBJECT_HANDLE handle = CK_INVALID_HANDLE; CK_BYTE_PTR state = NULL; CK_ULONG state_len; bool reqlogin = false; CK_RV ret; if (sigctx == NULL) { return NULL; } P11PROV_debug("Duplicating context %p", ctx); switch (sigctx->operation) { case CKF_SIGN: reqlogin = true; /* fallthrough */ case CKF_VERIFY: slotid = p11prov_obj_get_slotid(sigctx->key); handle = p11prov_obj_get_handle(sigctx->key); break; default: return NULL; } newctx = p11prov_sig_newctx(sigctx->provctx, sigctx->mechtype, sigctx->properties); if (newctx == NULL) { return NULL; } newctx->key = p11prov_obj_ref(sigctx->key); newctx->mechtype = sigctx->mechtype; newctx->digest = sigctx->digest; newctx->pss_params = sigctx->pss_params; newctx->operation = sigctx->operation; newctx->eddsa_params = sigctx->eddsa_params; if (sigctx->eddsa_params.pContextData) { newctx->eddsa_params.pContextData = OPENSSL_memdup(sigctx->eddsa_params.pContextData, sigctx->eddsa_params.ulContextDataLen); } newctx->use_eddsa_params = sigctx->use_eddsa_params; if (sigctx->mechanism_fallback) { int err; newctx->mechanism_fallback = EVP_MD_CTX_new(); if (!newctx->mechanism_fallback) { p11prov_sig_freectx(newctx); return NULL; } err = EVP_MD_CTX_copy_ex(newctx->mechanism_fallback, sigctx->mechanism_fallback); if (err != RET_OSSL_OK) { p11prov_sig_freectx(newctx); return NULL; } } if (sigctx->session == NULL) { return newctx; } /* This is not really funny. OpenSSL by default assumes contexts with * operations in flight can be easily duplicated, with all the * cryptographic status and then both contexts can keep going * independently. We'll try here, but on failure we just 'move' the * session to the new context (because that's what OpenSSL seem to * prefer to use after duplication) and hope for the best. */ newctx->session = sigctx->session; sigctx->session = NULL; if (slotid != CK_UNAVAILABLE_INFORMATION && handle != CK_INVALID_HANDLE) { CK_SESSION_HANDLE newsess = p11prov_session_handle(newctx->session); CK_SESSION_HANDLE sess = CK_INVALID_HANDLE; /* NOTE: most tokens will probably return errors trying to do this on * sign sessions. If GetOperationState fails we don't try to duplicate * the context and just return. */ ret = p11prov_GetOperationState(sigctx->provctx, newsess, NULL_PTR, &state_len); if (ret != CKR_OK) { goto done; } state = OPENSSL_malloc(state_len); if (state == NULL) { goto done; } ret = p11prov_GetOperationState(sigctx->provctx, newsess, state, &state_len); if (ret != CKR_OK) { goto done; } ret = p11prov_get_session(sigctx->provctx, &slotid, NULL, NULL, sigctx->mechtype, NULL, NULL, reqlogin, false, &sigctx->session); if (ret != CKR_OK) { P11PROV_raise(sigctx->provctx, ret, "Failed to open session on slot %lu", slotid); goto done; } sess = p11prov_session_handle(sigctx->session); ret = p11prov_SetOperationState(sigctx->provctx, sess, state, state_len, handle, handle); if (ret != CKR_OK) { p11prov_return_session(sigctx->session); sigctx->session = NULL; } } done: OPENSSL_free(state); return newctx; } static void p11prov_sig_freectx(void *ctx) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; if (sigctx == NULL) { return; } OPENSSL_clear_free(sigctx->eddsa_params.pContextData, sigctx->eddsa_params.ulContextDataLen); p11prov_return_session(sigctx->session); EVP_MD_CTX_free(sigctx->mechanism_fallback); p11prov_obj_free(sigctx->key); OPENSSL_free(sigctx->properties); OPENSSL_clear_free(sigctx, sizeof(P11PROV_SIG_CTX)); } #define DER_SEQUENCE 0x30 #define DER_OBJECT 0x06 #define DER_NULL 0x05 #define DER_OCTET_STRING 0x04 #define DER_INTEGER 0x02 /* iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) pkcs-1(1) */ #define DER_RSADSI_PKCS1 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01 #define DER_RSADSI_PKCS1_LEN 0x08 /* iso(1) member-body(2) us(840) ansi-x962(10045) signatures(4) */ #define DER_ANSIX962_SIG 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04 #define DER_ANSIX962_SIG_LEN 0x06 /* ... ansi-x962(10045) signatures(4) ecdsa-with-SHA2(3) */ #define DER_ANSIX962_SHA2_SIG DER_ANSIX962_SIG, 0x03 #define DER_ANSIX962_SHA2_SIG_LEN (DER_ANSIX962_SIG_LEN + 1) /* joint-iso-itu-t(2) country(16) us(840) organization(1) gov(101) csor(3) * nistAlgorithms(4) */ #define DER_NIST_ALGS 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04 #define DER_NIST_ALGS_LEN 0x07 /* ... csor(3) nistAlgorithms(4) hashalgs(2) */ #define DER_NIST_HASHALGS DER_NIST_ALGS, 0x02 #define DER_NIST_HASHALGS_LEN (DER_NIST_ALGS_LEN + 1) /* ... csor(3) nistAlgorithms(4) sigAlgs(3) */ #define DER_NIST_SIGALGS DER_NIST_ALGS, 0x03 #define DER_NIST_SIGALGS_LEN (DER_NIST_ALGS_LEN + 1) /* clang-format off */ #define DEFINE_DER_DIGESTINFO(name, alg_id, digest_size) \ static const unsigned char der_digestinfo_##name[] = { \ DER_SEQUENCE, DER_NIST_HASHALGS_LEN+9+digest_size, \ DER_SEQUENCE, DER_NIST_HASHALGS_LEN+5, \ DER_OBJECT, DER_NIST_HASHALGS_LEN+1, DER_NIST_HASHALGS, alg_id, \ DER_NULL, 0, \ DER_OCTET_STRING, digest_size \ }; #define DEFINE_DER_RSA_PSS_PARAMS(name, obj_base, obj_alg, obj_len, digest_len) \ static const unsigned char der_rsa_pss_params_##name[] = { \ DER_SEQUENCE, 25 + DER_RSASSA_PSS_LEN + DER_MGF1_LEN + obj_len + obj_len, \ DER_OBJECT, DER_RSASSA_PSS_LEN, DER_RSASSA_PSS, \ DER_SEQUENCE, 21 + DER_MGF1_LEN + obj_len + obj_len, \ 0xA0, 4 + obj_len, \ DER_SEQUENCE, 2 + obj_len, \ DER_OBJECT, obj_len, obj_base, obj_alg, \ 0xA1, 8 + DER_MGF1_LEN + obj_len, \ DER_SEQUENCE, 6 + DER_MGF1_LEN + obj_len, \ DER_OBJECT, DER_MGF1_LEN, DER_MGF1, \ DER_SEQUENCE, 2 + obj_len, \ DER_OBJECT, obj_len, obj_base, obj_alg, \ 0xA2, 3, \ DER_INTEGER, 1, digest_len, \ }; #define DEFINE_DER_SEQ_SHA(bits, rsa_algid, ecdsa_algid, digestinfo_algid) \ static const unsigned char der_rsa_sha##bits[] = { \ DER_SEQUENCE, DER_RSADSI_PKCS1_LEN+5, \ DER_OBJECT, DER_RSADSI_PKCS1_LEN+1, DER_RSADSI_PKCS1, rsa_algid, \ DER_NULL, 0, \ }; \ static const unsigned char der_ecdsa_sha##bits[] = { \ DER_SEQUENCE, DER_ANSIX962_SHA2_SIG_LEN+3, \ DER_OBJECT, DER_ANSIX962_SHA2_SIG_LEN+1, DER_ANSIX962_SHA2_SIG, ecdsa_algid, \ }; \ DEFINE_DER_DIGESTINFO(sha##bits, digestinfo_algid, bits/8) \ DEFINE_DER_RSA_PSS_PARAMS(sha##bits, DER_NIST_HASHALGS, digestinfo_algid, \ DER_NIST_HASHALGS_LEN+1, SHA##bits##_DIGEST_LENGTH) #define DEFINE_DER_SEQ_SHA3(bits, rsa_algid, ecdsa_algid, digestinfo_algid) \ static const unsigned char der_rsa_sha3_##bits[] = { \ DER_SEQUENCE, DER_NIST_SIGALGS_LEN+5, \ DER_OBJECT, DER_NIST_SIGALGS_LEN+1, DER_NIST_SIGALGS, rsa_algid, \ DER_NULL, 0 \ }; \ static const unsigned char der_ecdsa_sha3_##bits[] = { \ DER_SEQUENCE, DER_NIST_SIGALGS_LEN+3, \ DER_OBJECT, DER_NIST_SIGALGS_LEN+1, DER_NIST_SIGALGS, ecdsa_algid \ }; \ DEFINE_DER_DIGESTINFO(sha3_##bits, digestinfo_algid, bits/8) \ DEFINE_DER_RSA_PSS_PARAMS(sha3_##bits, DER_NIST_HASHALGS, digestinfo_algid, \ DER_NIST_HASHALGS_LEN+1, SHA##bits##_DIGEST_LENGTH) /* ... pkcs(1) 10 (id-RSASSA-PSS) */ #define DER_RSASSA_PSS DER_RSADSI_PKCS1, 0x0A #define DER_RSASSA_PSS_LEN (DER_RSADSI_PKCS1_LEN + 1) /* ... pkcs(1) 8 (id-RSASSA-PSS) */ #define DER_MGF1 DER_RSADSI_PKCS1, 0x08 #define DER_MGF1_LEN (DER_RSADSI_PKCS1_LEN + 1) static const unsigned char der_rsa_sha1[] = { DER_SEQUENCE, DER_RSADSI_PKCS1_LEN+5, DER_OBJECT, DER_RSADSI_PKCS1_LEN+1, DER_RSADSI_PKCS1, 0x05, DER_NULL, 0 }; static const unsigned char der_ecdsa_sha1[] = { DER_SEQUENCE, DER_ANSIX962_SIG_LEN+3, DER_OBJECT, DER_ANSIX962_SIG_LEN+1, DER_ANSIX962_SIG, 0x01 }; /* iso(1) org(3) oiw(14) secsig(3) algorithms(2) */ #define DER_SECSIG_ALGO 1 * 40 + 3, 14, 3, 2 #define DER_SECSIG_ALGO_LEN 4 /* iso(1) org(3) oiw(14) secsig(3) algorithms(2) hashAlgorithmIdentifier(26) */ #define ID_SHA1 DER_SECSIG_ALGO, 26 #define ID_SHA1_LEN DER_SECSIG_ALGO_LEN+1 static const unsigned char der_digestinfo_sha1[] = { DER_SEQUENCE, 0x0d + SHA_DIGEST_LENGTH, DER_SEQUENCE, 0x09, DER_OBJECT, ID_SHA1_LEN, ID_SHA1, DER_NULL, 0x00, DER_OCTET_STRING, SHA_DIGEST_LENGTH }; DEFINE_DER_RSA_PSS_PARAMS(sha1, DER_SECSIG_ALGO, 26, DER_SECSIG_ALGO_LEN, SHA_DIGEST_LENGTH); /* clang-format on */ DEFINE_DER_SEQ_SHA(512, 0x0D, 0x04, 0x03); DEFINE_DER_SEQ_SHA(384, 0x0C, 0x03, 0x02); DEFINE_DER_SEQ_SHA(256, 0x0B, 0x02, 0x01); DEFINE_DER_SEQ_SHA(224, 0x0E, 0x01, 0x04); DEFINE_DER_SEQ_SHA3(512, 0x10, 0x0C, 0x0A); DEFINE_DER_SEQ_SHA3(384, 0x0F, 0x0B, 0x09); DEFINE_DER_SEQ_SHA3(256, 0x0E, 0x0A, 0x08); DEFINE_DER_SEQ_SHA3(224, 0x0D, 0x09, 0x07); #define DM_ELEM_SHA(bits) \ { \ .digest = CKM_SHA##bits, \ .pkcs_mech = CKM_SHA##bits##_RSA_PKCS, \ .pkcs_pss = CKM_SHA##bits##_RSA_PKCS_PSS, \ .ecdsa_mech = CKM_ECDSA_SHA##bits, \ .mgf = CKG_MGF1_SHA##bits, \ .der_rsa_algorithm_id = der_rsa_sha##bits, \ .der_rsa_algorithm_id_len = sizeof(der_rsa_sha##bits), \ .der_ecdsa_algorithm_id = der_ecdsa_sha##bits, \ .der_ecdsa_algorithm_id_len = sizeof(der_ecdsa_sha##bits), \ .der_digestinfo = der_digestinfo_sha##bits, \ .der_digestinfo_len = sizeof(der_digestinfo_sha##bits), \ .der_rsa_pss_params = der_rsa_pss_params_sha##bits, \ .der_rsa_pss_params_len = sizeof(der_rsa_pss_params_sha##bits), \ } #define DM_ELEM_SHA3(bits) \ { \ .digest = CKM_SHA3_##bits, \ .pkcs_mech = CKM_SHA3_##bits##_RSA_PKCS, \ .pkcs_pss = CKM_SHA3_##bits##_RSA_PKCS_PSS, \ .ecdsa_mech = CKM_ECDSA_SHA3_##bits, \ .mgf = CKG_MGF1_SHA3_##bits, \ .der_rsa_algorithm_id = der_rsa_sha3_##bits, \ .der_rsa_algorithm_id_len = sizeof(der_rsa_sha3_##bits), \ .der_ecdsa_algorithm_id = der_ecdsa_sha3_##bits, \ .der_ecdsa_algorithm_id_len = sizeof(der_ecdsa_sha3_##bits), \ .der_digestinfo = der_digestinfo_sha3_##bits, \ .der_digestinfo_len = sizeof(der_digestinfo_sha3_##bits), \ .der_rsa_pss_params = der_rsa_pss_params_sha3_##bits, \ .der_rsa_pss_params_len = sizeof(der_rsa_pss_params_sha3_##bits), \ } /* only the ones we can support */ struct p11prov_mech { CK_MECHANISM_TYPE digest; CK_MECHANISM_TYPE pkcs_mech; CK_MECHANISM_TYPE pkcs_pss; CK_MECHANISM_TYPE ecdsa_mech; CK_RSA_PKCS_MGF_TYPE mgf; const unsigned char *der_rsa_algorithm_id; int der_rsa_algorithm_id_len; const unsigned char *der_ecdsa_algorithm_id; int der_ecdsa_algorithm_id_len; const unsigned char *der_digestinfo; int der_digestinfo_len; const unsigned char *der_rsa_pss_params; int der_rsa_pss_params_len; }; typedef struct p11prov_mech P11PROV_MECH; static const P11PROV_MECH mech_map[] = { DM_ELEM_SHA3(256), DM_ELEM_SHA3(512), DM_ELEM_SHA3(384), DM_ELEM_SHA3(224), DM_ELEM_SHA(256), DM_ELEM_SHA(512), DM_ELEM_SHA(384), DM_ELEM_SHA(224), { CKM_SHA_1, CKM_SHA1_RSA_PKCS, CKM_SHA1_RSA_PKCS_PSS, CKM_ECDSA_SHA1, CKG_MGF1_SHA1, der_rsa_sha1, sizeof(der_rsa_sha1), der_ecdsa_sha1, sizeof(der_ecdsa_sha1), der_digestinfo_sha1, sizeof(der_digestinfo_sha1), der_rsa_pss_params_sha1, sizeof(der_rsa_pss_params_sha1), }, { CK_UNAVAILABLE_INFORMATION, 0, 0, 0, 0, 0, 0, 0, 0 }, }; #define DER_ED25519_OID 0x06, 0x03, 0x2B, 0x65, 0x70 #define DER_ED25519_OID_LEN 0x05 static const unsigned char der_ed25519_algorithm_id[] = { DER_SEQUENCE, DER_ED25519_OID_LEN, DER_ED25519_OID }; #define DER_ED448_OID 0x06, 0x03, 0x2B, 0x65, 0x71 #define DER_ED448_OID_LEN 0x05 static const unsigned char der_ed448_algorithm_id[] = { DER_SEQUENCE, DER_ED448_OID_LEN, DER_ED448_OID }; static CK_RV p11prov_mech_by_mechanism(CK_MECHANISM_TYPE mechanism, const P11PROV_MECH **mech) { for (int i = 0; mech_map[i].digest != CK_UNAVAILABLE_INFORMATION; i++) { if (mech_map[i].digest == mechanism) { *mech = &mech_map[i]; return CKR_OK; } } return CKR_MECHANISM_INVALID; } static CK_RV p11prov_mech_by_mgf(CK_RSA_PKCS_MGF_TYPE mgf, const P11PROV_MECH **mech) { for (int i = 0; mech_map[i].digest != CK_UNAVAILABLE_INFORMATION; i++) { if (mech_map[i].mgf == mgf) { *mech = &mech_map[i]; return CKR_OK; } } return CKR_MECHANISM_INVALID; } static const char *p11prov_sig_mgf_name(CK_RSA_PKCS_MGF_TYPE mgf) { const P11PROV_MECH *mech = NULL; const char *digest_name; CK_RV rv; rv = p11prov_mech_by_mgf(mgf, &mech); if (rv != CKR_OK) { return NULL; } rv = p11prov_digest_get_name(mech->digest, &digest_name); if (rv != CKR_OK) { return NULL; } return digest_name; } static CK_RSA_PKCS_MGF_TYPE p11prov_sig_map_mgf(const char *digest_name) { CK_MECHANISM_TYPE digest; const P11PROV_MECH *mech = NULL; CK_RV rv; rv = p11prov_digest_get_by_name(digest_name, &digest); if (rv != CKR_OK) { return CK_UNAVAILABLE_INFORMATION; } rv = p11prov_mech_by_mechanism(digest, &mech); if (rv != CKR_OK) { return CK_UNAVAILABLE_INFORMATION; } return mech->mgf; } static CK_RV p11prov_sig_pss_restrictions(P11PROV_SIG_CTX *sigctx, CK_MECHANISM *mechanism) { CK_BBOOL token_supports_allowed_mechs = CK_TRUE; CK_ATTRIBUTE *allowed_mechs = NULL; CK_RV ret; /* check if token supports CKA_ALLOWED_MECHANISMS at all */ ret = p11prov_token_sup_attr( sigctx->provctx, p11prov_obj_get_slotid(sigctx->key), GET_ATTR, CKA_ALLOWED_MECHANISMS, &token_supports_allowed_mechs); if (ret != CKR_OK) { P11PROV_raise(sigctx->provctx, ret, "Failed to probe CKA_ALLOWED_MECHANISMS quirk"); return ret; } if (token_supports_allowed_mechs == CK_FALSE) { /* Token does not support CKA_ALLOWED_MECHANISMS so there are no restrictions */ return CKR_OK; } allowed_mechs = p11prov_obj_get_attr(sigctx->key, CKA_ALLOWED_MECHANISMS); if (allowed_mechs) { CK_ATTRIBUTE_TYPE *mechs = (CK_ATTRIBUTE_TYPE *)allowed_mechs->pValue; int num_mechs = allowed_mechs->ulValueLen / sizeof(CK_MECHANISM_TYPE); bool allowed = false; if (num_mechs == 0) { /* It makes no sense to return 0 allowed mechanisms for a key, * this just means the token is bogus, let's ignore the check * and try the operation and see what happens */ P11PROV_debug("Buggy CKA_ALLOWED_MECHANISMS implementation"); return CKR_OK; } for (int i = 0; i < num_mechs; i++) { if (mechs[i] == mechanism->mechanism) { allowed = true; break; } } if (allowed) { return CKR_OK; } P11PROV_raise(sigctx->provctx, CKR_ACTION_PROHIBITED, "mechanism not allowed with this key"); return CKR_ACTION_PROHIBITED; } /* there are no restrictions on this key */ return CKR_OK; } /* fixates pss_params based on defaults if values are not set */ static CK_RV pss_defaults(P11PROV_SIG_CTX *sigctx, CK_MECHANISM *mechanism, bool set_mech) { const P11PROV_MECH *mech; CK_RV ret; ret = p11prov_mech_by_mechanism(sigctx->digest, &mech); if (ret != CKR_OK) { return ret; } sigctx->pss_params.hashAlg = mech->digest; if (sigctx->pss_params.mgf == 0) { sigctx->pss_params.mgf = mech->mgf; } if (sigctx->pss_params.sLen == 0) { /* default to digest size if not set */ size_t size; ret = p11prov_digest_get_digest_size(mech->digest, &size); if (ret != CKR_OK) { return ret; } sigctx->pss_params.sLen = size; } if (mechanism) { mechanism->pParameter = &sigctx->pss_params; mechanism->ulParameterLen = sizeof(sigctx->pss_params); if (set_mech) { mechanism->mechanism = mech->pkcs_pss; } } return CKR_OK; } static int p11prov_sig_set_mechanism(P11PROV_SIG_CTX *sigctx, bool digest_sign, CK_MECHANISM *mechanism) { int result = CKR_DATA_INVALID; mechanism->mechanism = sigctx->mechtype; mechanism->pParameter = NULL; mechanism->ulParameterLen = 0; switch (sigctx->mechtype) { case CKM_RSA_PKCS: if (digest_sign) { const P11PROV_MECH *mech; result = p11prov_mech_by_mechanism(sigctx->digest, &mech); if (result == CKR_OK) { mechanism->mechanism = mech->pkcs_mech; } } else { result = CKR_OK; } break; case CKM_RSA_X_509: break; case CKM_RSA_PKCS_PSS: result = pss_defaults(sigctx, mechanism, digest_sign); if (result == CKR_OK && digest_sign) { result = p11prov_sig_pss_restrictions(sigctx, mechanism); } break; case CKM_ECDSA: if (digest_sign) { const P11PROV_MECH *mech; result = p11prov_mech_by_mechanism(sigctx->digest, &mech); if (result == CKR_OK) { mechanism->mechanism = mech->ecdsa_mech; } } else { result = CKR_OK; } break; case CKM_EDDSA: if (sigctx->use_eddsa_params == CK_TRUE) { mechanism->pParameter = &sigctx->eddsa_params; mechanism->ulParameterLen = sizeof(sigctx->eddsa_params); } result = CKR_OK; } if (result == CKR_OK) { P11PROV_debug_mechanism(sigctx->provctx, p11prov_obj_get_slotid(sigctx->key), mechanism->mechanism); } return result; } static CK_RV p11prov_sig_get_sig_size(void *ctx, size_t *siglen) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; CK_KEY_TYPE type = p11prov_obj_get_key_type(sigctx->key); CK_ULONG size = p11prov_obj_get_key_size(sigctx->key); if (type == CK_UNAVAILABLE_INFORMATION) { return CKR_KEY_NEEDED; } if (size == CK_UNAVAILABLE_INFORMATION) { return CKR_KEY_NEEDED; } switch (type) { case CKK_RSA: *siglen = size; break; case CKK_EC: /* add room for ECDSA Signature DER overhead */ *siglen = 3 + (size + 4) * 2; break; case CKK_EC_EDWARDS: if (size == ED25519_BYTE_SIZE) { *siglen = ED25519_SIG_SIZE; } else if (size == ED448_BYTE_SIZE) { *siglen = ED448_SIG_SIZE; } else { return CKR_KEY_TYPE_INCONSISTENT; } break; default: return CKR_KEY_TYPE_INCONSISTENT; } return CKR_OK; } static int p11prov_rsasig_set_pss_saltlen_from_digest(void *ctx) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; size_t digest_size; CK_RV rv; if (sigctx->digest == 0) { ERR_raise_data(ERR_LIB_PROV, PROV_R_NOT_SUPPORTED, "Can only be set if Digest was set first."); return RET_OSSL_ERR; } rv = p11prov_digest_get_digest_size(sigctx->digest, &digest_size); if (rv != CKR_OK) { P11PROV_raise(sigctx->provctx, rv, "Unavailable digest"); return RET_OSSL_ERR; } sigctx->pss_params.sLen = digest_size; return RET_OSSL_OK; } static int p11prov_rsasig_set_pss_saltlen_max(void *ctx, bool max_to_digest) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; size_t digest_size; CK_ULONG key_size; CK_ULONG key_bit_size; CK_RV rv; if (sigctx->digest == 0) { ERR_raise_data(ERR_LIB_PROV, PROV_R_NOT_SUPPORTED, "Can only be set if Digest was set first."); return RET_OSSL_ERR; } rv = p11prov_digest_get_digest_size(sigctx->digest, &digest_size); if (rv != CKR_OK) { P11PROV_raise(sigctx->provctx, rv, "Unavailable digest"); return RET_OSSL_ERR; } key_size = p11prov_obj_get_key_size(sigctx->key); if (key_size == CK_UNAVAILABLE_INFORMATION) { P11PROV_raise(sigctx->provctx, rv, "Unavailable key"); return RET_OSSL_ERR; } key_bit_size = p11prov_obj_get_key_bit_size(sigctx->key); if (key_bit_size == CK_UNAVAILABLE_INFORMATION) { P11PROV_raise(sigctx->provctx, rv, "Unavailable key"); return RET_OSSL_ERR; } /* from openssl */ sigctx->pss_params.sLen = key_size - digest_size - 2; if ((key_bit_size & 0x07) == 1) { sigctx->pss_params.sLen -= 1; } if (max_to_digest && sigctx->pss_params.sLen > digest_size) { sigctx->pss_params.sLen = digest_size; } return RET_OSSL_OK; } static CK_RV p11prov_sig_op_init(void *ctx, void *provkey, CK_FLAGS operation, const char *digest) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; P11PROV_OBJ *key = (P11PROV_OBJ *)provkey; CK_OBJECT_CLASS class; CK_RV ret; ret = p11prov_ctx_status(sigctx->provctx); if (ret != CKR_OK) { return ret; } class = p11prov_obj_get_class(key); switch (operation) { case CKF_SIGN: if (class != CKO_PRIVATE_KEY) { return CKR_KEY_TYPE_INCONSISTENT; } break; case CKF_VERIFY: if (class != CKO_PUBLIC_KEY) { key = p11prov_obj_get_associated(key); if (!key || p11prov_obj_get_class(key) != CKO_PUBLIC_KEY) { return CKR_KEY_TYPE_INCONSISTENT; } } break; default: return CKR_GENERAL_ERROR; } sigctx->key = p11prov_obj_ref(key); if (sigctx->key == NULL) { return CKR_KEY_NEEDED; } sigctx->operation = operation; if (digest) { ret = p11prov_digest_get_by_name(digest, &sigctx->digest); if (ret != CKR_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return ret; } } return CKR_OK; } static CK_RV mech_fallback_init(P11PROV_SIG_CTX *sigctx, CK_SLOT_ID slotid) { const OSSL_PROVIDER *prov; void *provctx; const char *digest; EVP_MD *md = NULL; OSSL_LIB_CTX *libctx; const OSSL_PARAM *pparams = NULL; OSSL_PARAM params[] = { OSSL_PARAM_construct_ulong(P11PROV_PARAM_SLOT_ID, &slotid), OSSL_PARAM_construct_end(), }; CK_RV ret; int err; P11PROV_debug("Enable fallback for mechanism %lx", sigctx->mechtype); ret = p11prov_digest_get_name(sigctx->digest, &digest); if (ret != CKR_OK) { P11PROV_raise(sigctx->provctx, ret, "Failed to get name for digest %lx", sigctx->digest); goto done; } libctx = p11prov_ctx_get_libctx(sigctx->provctx); /* FIXME: should we add sigctx->properties here ? (ex: fips=yes) */ /* try to keep digest on token but allow default (via "?") to provide * digests. */ md = EVP_MD_fetch(libctx, digest, "?" P11PROV_DEFAULT_PROPERTIES); if (!md) { ret = CKR_GENERAL_ERROR; P11PROV_raise(sigctx->provctx, ret, "Failed to get context for EVP digest '%s'", digest); goto done; } sigctx->mechanism_fallback = EVP_MD_CTX_new(); if (!sigctx->mechanism_fallback) { ret = CKR_HOST_MEMORY; P11PROV_raise(sigctx->provctx, ret, "Failed to init fallback context"); goto done; } /* if it is us, set a slot preference */ prov = EVP_MD_get0_provider(md); if (prov) { provctx = OSSL_PROVIDER_get0_provider_ctx(prov); if (provctx == sigctx->provctx) { pparams = params; } } err = EVP_DigestInit_ex2(sigctx->mechanism_fallback, md, pparams); if (err != RET_OSSL_OK) { ret = CKR_GENERAL_ERROR; P11PROV_raise(sigctx->provctx, ret, "Failed to init EVP digest"); goto done; } /* done */ ret = CKR_OK; done: EVP_MD_free(md); return ret; } static CK_RV p11prov_sig_operate_init(P11PROV_SIG_CTX *sigctx, bool digest_op, P11PROV_SESSION **_session) { P11PROV_SESSION *session = NULL; CK_OBJECT_HANDLE handle; CK_MECHANISM mechanism; CK_SESSION_HANDLE sess; CK_SLOT_ID slotid; bool reqlogin = false; bool always_auth = false; CK_RV ret; P11PROV_debug("called (sigctx=%p, digest_op=%s)", sigctx, digest_op ? "true" : "false"); ret = p11prov_ctx_status(sigctx->provctx); if (ret != CKR_OK) { return ret; } handle = p11prov_obj_get_handle(sigctx->key); if (handle == CK_INVALID_HANDLE) { P11PROV_raise(sigctx->provctx, CKR_KEY_HANDLE_INVALID, "Provided key has invalid handle"); return CKR_KEY_HANDLE_INVALID; } slotid = p11prov_obj_get_slotid(sigctx->key); if (slotid == CK_UNAVAILABLE_INFORMATION) { P11PROV_raise(sigctx->provctx, CKR_SLOT_ID_INVALID, "Provided key has invalid slot"); return CKR_SLOT_ID_INVALID; } ret = p11prov_sig_set_mechanism(sigctx, digest_op, &mechanism); if (ret != CKR_OK) { return ret; } if (sigctx->operation == CKF_SIGN) { reqlogin = true; } ret = p11prov_get_session(sigctx->provctx, &slotid, NULL, NULL, mechanism.mechanism, NULL, NULL, reqlogin, false, &session); switch (ret) { case CKR_OK: sess = p11prov_session_handle(session); if (sigctx->operation == CKF_SIGN) { ret = p11prov_SignInit(sigctx->provctx, sess, &mechanism, handle); } else { ret = p11prov_VerifyInit(sigctx->provctx, sess, &mechanism, handle); } break; case CKR_MECHANISM_INVALID: if (!digest_op || mechanism.mechanism == sigctx->mechtype) { /* Even the raw signature mechanism is not supported */ P11PROV_raise(sigctx->provctx, ret, "Unsupported mechanism family %lx for slot %lu", sigctx->mechtype, slotid); goto done; } slotid = p11prov_obj_get_slotid(sigctx->key); ret = mech_fallback_init(sigctx, slotid); goto done; break; default: P11PROV_raise(sigctx->provctx, ret, "Failed to open session on slot %lu", slotid); goto done; } if (reqlogin) { always_auth = p11prov_obj_get_bool(sigctx->key, CKA_ALWAYS_AUTHENTICATE, false); } if (always_auth) { ret = p11prov_context_specific_login(session, NULL, NULL, NULL); } done: if (ret != CKR_OK) { p11prov_return_session(session); } else { *_session = session; } return ret; } static CK_RV p11prov_sig_operate(P11PROV_SIG_CTX *sigctx, unsigned char *sig, size_t *siglen, size_t sigsize, unsigned char *tbs, size_t tbslen) { P11PROV_SESSION *session; CK_SESSION_HANDLE sess; CK_ULONG sig_size = sigsize; CK_RV ret; /* The 64 is the largest possible der_digestinfo prefix encoding */ unsigned char data[EVP_MAX_MD_SIZE + 64]; if (sig == NULL) { if (sigctx->operation == CKF_VERIFY) { return CKR_ARGUMENTS_BAD; } if (siglen == NULL) { return CKR_ARGUMENTS_BAD; } return p11prov_sig_get_sig_size(sigctx, siglen); } if (sigctx->operation == CKF_SIGN && sigctx->mechtype == CKM_RSA_X_509) { /* some tokens allow raw signatures on any data size. * Enforce data size is the same as modulus as that is * what OpenSSL expects and does internally in rsa_sign * when there is no padding. */ if (tbslen < sigsize) { ERR_raise(ERR_LIB_RSA, RSA_R_DATA_TOO_SMALL_FOR_KEY_SIZE); return CKR_DATA_LEN_RANGE; } } if (sigctx->mechtype == CKM_RSA_PKCS && sigctx->digest != 0) { const P11PROV_MECH *mech = NULL; size_t digest_size = 0; ret = p11prov_mech_by_mechanism(sigctx->digest, &mech); if (ret != CKR_OK) { ERR_raise(ERR_LIB_RSA, PROV_R_INVALID_DIGEST); return ret; } ret = p11prov_digest_get_digest_size(sigctx->digest, &digest_size); if (ret != CKR_OK) { ERR_raise(ERR_LIB_RSA, PROV_R_INVALID_DIGEST); return ret; } if (tbslen != digest_size || tbslen + mech->der_digestinfo_len >= sizeof(data)) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_INPUT_LENGTH); return ret; } memcpy(data, mech->der_digestinfo, mech->der_digestinfo_len); memcpy(data + mech->der_digestinfo_len, tbs, tbslen); tbs = data; tbslen += mech->der_digestinfo_len; } ret = p11prov_sig_operate_init(sigctx, false, &session); if (ret != CKR_OK) { return ret; } sess = p11prov_session_handle(session); if (sigctx->operation == CKF_SIGN) { ret = p11prov_Sign(sigctx->provctx, sess, tbs, tbslen, sig, &sig_size); } else { ret = p11prov_Verify(sigctx->provctx, sess, tbs, tbslen, sig, sigsize); } if (ret == CKR_OK) { if (siglen) { *siglen = sig_size; } } p11prov_return_session(session); if (tbs == data) { OPENSSL_cleanse(data, sizeof(data)); } return ret; } static int p11prov_sig_digest_update(P11PROV_SIG_CTX *sigctx, unsigned char *data, size_t datalen) { CK_SESSION_HANDLE sess; CK_RV ret; if (!sigctx->mechanism_fallback && !sigctx->session) { ret = p11prov_sig_operate_init(sigctx, true, &sigctx->session); if (ret != CKR_OK) { return RET_OSSL_ERR; } } if (sigctx->mechanism_fallback) { return EVP_DigestUpdate(sigctx->mechanism_fallback, data, datalen); } if (!sigctx->session) { return RET_OSSL_ERR; } /* we have an initialized session */ sess = p11prov_session_handle(sigctx->session); if (sigctx->operation == CKF_SIGN) { ret = p11prov_SignUpdate(sigctx->provctx, sess, data, datalen); } else { ret = p11prov_VerifyUpdate(sigctx->provctx, sess, data, datalen); } if (ret != CKR_OK) { p11prov_return_session(sigctx->session); sigctx->session = NULL; return RET_OSSL_ERR; } return RET_OSSL_OK; } static CK_RV mech_fallback_final(P11PROV_SIG_CTX *sigctx, unsigned char *sig, size_t *siglen, size_t sigsize, size_t mdsize) { P11PROV_SIG_CTX *subctx = NULL; CK_BYTE digest[mdsize]; unsigned int digest_len = mdsize; CK_OBJECT_HANDLE handle; int err; CK_RV ret; err = EVP_DigestFinal_ex(sigctx->mechanism_fallback, digest, &digest_len); if (err != RET_OSSL_OK) { ret = CKR_GENERAL_ERROR; P11PROV_raise(sigctx->provctx, ret, "EVP_DigestFinal_ex() failed"); goto done; } if (digest_len != mdsize) { ret = CKR_GENERAL_ERROR; P11PROV_raise(sigctx->provctx, ret, "Inconsistent digest size"); goto done; } handle = p11prov_obj_get_handle(sigctx->key); if (handle == CK_INVALID_HANDLE) { ret = CKR_KEY_HANDLE_INVALID; P11PROV_raise(sigctx->provctx, ret, "Provided key has invalid handle"); goto done; } subctx = p11prov_sig_newctx(sigctx->provctx, sigctx->mechtype, sigctx->properties); if (!subctx) { ret = CKR_HOST_MEMORY; goto done; } ret = p11prov_sig_op_init(subctx, sigctx->key, sigctx->operation, NULL); if (ret != CKR_OK) { P11PROV_raise(sigctx->provctx, ret, "Failed to setup sigver fallback"); goto done; } ret = p11prov_sig_operate(subctx, sig, siglen, sigsize, digest, mdsize); if (ret != CKR_OK) { P11PROV_raise(sigctx->provctx, ret, "Failure in sigver fallback"); goto done; } done: p11prov_sig_freectx(subctx); return ret; } static int p11prov_sig_digest_final(P11PROV_SIG_CTX *sigctx, unsigned char *sig, size_t *siglen, size_t sigsize) { CK_SESSION_HANDLE sess; CK_ULONG sig_size = sigsize; int result = RET_OSSL_ERR; CK_RV ret; if (sig == NULL) { if (sigctx->operation == CKF_VERIFY) { goto done; } if (siglen == NULL) { goto done; } ret = p11prov_sig_get_sig_size(sigctx, siglen); if (ret == CKR_OK) { result = RET_OSSL_OK; } return result; } if (sigctx->mechanism_fallback) { size_t mdsize; ret = p11prov_digest_get_digest_size(sigctx->digest, &mdsize); if (ret != CKR_OK) { P11PROV_raise(sigctx->provctx, ret, "Unexpected get_digest_size error"); goto done; } ret = mech_fallback_final(sigctx, sig, siglen, sigsize, mdsize); if (ret == CKR_OK) { result = RET_OSSL_OK; } goto done; } if (!sigctx->session) { goto done; } sess = p11prov_session_handle(sigctx->session); if (sigctx->operation == CKF_SIGN) { ret = p11prov_SignFinal(sigctx->provctx, sess, sig, &sig_size); } else { ret = p11prov_VerifyFinal(sigctx->provctx, sess, sig, sigsize); } if (ret == CKR_OK) { if (siglen) { *siglen = sig_size; } result = RET_OSSL_OK; } done: p11prov_return_session(sigctx->session); sigctx->session = NULL; return result; } DISPATCH_RSASIG_FN(newctx); DISPATCH_RSASIG_FN(sign_init); DISPATCH_RSASIG_FN(sign); DISPATCH_RSASIG_FN(verify_init); DISPATCH_RSASIG_FN(verify); DISPATCH_RSASIG_FN(digest_sign_init); DISPATCH_RSASIG_FN(digest_sign_update); DISPATCH_RSASIG_FN(digest_sign_final); DISPATCH_RSASIG_FN(digest_verify_init); DISPATCH_RSASIG_FN(digest_verify_update); DISPATCH_RSASIG_FN(digest_verify_final); DISPATCH_RSASIG_FN(get_ctx_params); DISPATCH_RSASIG_FN(set_ctx_params); DISPATCH_RSASIG_FN(gettable_ctx_params); DISPATCH_RSASIG_FN(settable_ctx_params); static void *p11prov_rsasig_newctx(void *provctx, const char *properties) { P11PROV_CTX *ctx = (P11PROV_CTX *)provctx; P11PROV_SIG_CTX *sigctx; /* PKCS1.5 is the default, PSS set via padding params */ sigctx = p11prov_sig_newctx(ctx, CKM_RSA_PKCS, properties); if (sigctx == NULL) { return NULL; } return sigctx; } static int p11prov_rsasig_sign_init(void *ctx, void *provkey, const OSSL_PARAM params[]) { CK_RV ret; P11PROV_debug("rsa sign init (ctx=%p, key=%p, params=%p)", ctx, provkey, params); ret = p11prov_sig_op_init(ctx, provkey, CKF_SIGN, NULL); if (ret != CKR_OK) { return RET_OSSL_ERR; } return p11prov_rsasig_set_ctx_params(ctx, params); } static int p11prov_rsasig_sign(void *ctx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, size_t tbslen) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; CK_RV ret; P11PROV_debug("rsa sign (ctx=%p)", ctx); ret = p11prov_sig_operate(sigctx, sig, siglen, sigsize, (void *)tbs, tbslen); if (ret != CKR_OK) { return RET_OSSL_ERR; } return RET_OSSL_OK; } static int p11prov_rsasig_verify_init(void *ctx, void *provkey, const OSSL_PARAM params[]) { CK_RV ret; P11PROV_debug("rsa verify init (ctx=%p, key=%p, params=%p)", ctx, provkey, params); ret = p11prov_sig_op_init(ctx, provkey, CKF_VERIFY, NULL); if (ret != CKR_OK) { return RET_OSSL_ERR; } return p11prov_rsasig_set_ctx_params(ctx, params); } static int p11prov_rsasig_verify(void *ctx, const unsigned char *sig, size_t siglen, const unsigned char *tbs, size_t tbslen) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; CK_RV ret; P11PROV_debug("rsa verify (ctx=%p)", ctx); ret = p11prov_sig_operate(sigctx, (void *)sig, NULL, siglen, (void *)tbs, tbslen); if (ret != CKR_OK) { return RET_OSSL_ERR; } return RET_OSSL_OK; } static int p11prov_rsasig_digest_sign_init(void *ctx, const char *digest, void *provkey, const OSSL_PARAM params[]) { CK_RV ret; P11PROV_debug("rsa digest sign init (ctx=%p, digest=%s, key=%p, params=%p)", ctx, digest ? digest : "", provkey, params); /* use a default of sha2 256 if not provided */ if (!digest) { digest = "sha256"; } ret = p11prov_sig_op_init(ctx, provkey, CKF_SIGN, digest); if (ret != CKR_OK) { return RET_OSSL_ERR; } return p11prov_rsasig_set_ctx_params(ctx, params); } static int p11prov_rsasig_digest_sign_update(void *ctx, const unsigned char *data, size_t datalen) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; P11PROV_debug("rsa digest sign update (ctx=%p, data=%p, datalen=%zu)", ctx, data, datalen); if (sigctx == NULL) { return RET_OSSL_ERR; } return p11prov_sig_digest_update(sigctx, (void *)data, datalen); } static int p11prov_rsasig_digest_sign_final(void *ctx, unsigned char *sig, size_t *siglen, size_t sigsize) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; /* the siglen might be uninitialized when called from openssl */ *siglen = 0; P11PROV_debug( "rsa digest sign final (ctx=%p, sig=%p, siglen=%zu, " "sigsize=%zu)", ctx, sig, *siglen, sigsize); if (sigctx == NULL) { return RET_OSSL_ERR; } return p11prov_sig_digest_final(sigctx, sig, siglen, sigsize); } static int p11prov_rsasig_digest_verify_init(void *ctx, const char *digest, void *provkey, const OSSL_PARAM params[]) { CK_RV ret; P11PROV_debug("rsa digest verify init (ctx=%p, key=%p, params=%p)", ctx, provkey, params); /* use a default of sha2 256 if not provided */ if (!digest) { digest = "sha256"; } ret = p11prov_sig_op_init(ctx, provkey, CKF_VERIFY, digest); if (ret != CKR_OK) { return RET_OSSL_ERR; } return p11prov_rsasig_set_ctx_params(ctx, params); } static int p11prov_rsasig_digest_verify_update(void *ctx, const unsigned char *data, size_t datalen) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; P11PROV_debug("rsa digest verify update (ctx=%p, data=%p, datalen=%zu)", ctx, data, datalen); if (sigctx == NULL) { return RET_OSSL_ERR; } return p11prov_sig_digest_update(sigctx, (void *)data, datalen); } static int p11prov_rsasig_digest_verify_final(void *ctx, const unsigned char *sig, size_t siglen) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; P11PROV_debug("rsa digest verify final (ctx=%p, sig=%p, siglen=%zu)", ctx, sig, siglen); if (sigctx == NULL) { return RET_OSSL_ERR; } return p11prov_sig_digest_final(sigctx, (void *)sig, NULL, siglen); } static struct { CK_MECHANISM_TYPE type; int ossl_id; const char *string; } padding_map[] = { { CKM_RSA_X_509, RSA_NO_PADDING, OSSL_PKEY_RSA_PAD_MODE_NONE }, { CKM_RSA_PKCS, RSA_PKCS1_PADDING, OSSL_PKEY_RSA_PAD_MODE_PKCSV15 }, { CKM_RSA_X9_31, RSA_X931_PADDING, OSSL_PKEY_RSA_PAD_MODE_X931 }, { CKM_RSA_PKCS_PSS, RSA_PKCS1_PSS_PADDING, OSSL_PKEY_RSA_PAD_MODE_PSS }, { CK_UNAVAILABLE_INFORMATION, 0, NULL }, }; static unsigned char * p11prov_encode_rsa_pss_algorithm_id(CK_MECHANISM_TYPE digest, int saltlen, size_t *outlen) { unsigned char *buffer = NULL; const P11PROV_MECH *mech; int ret; ret = p11prov_mech_by_mechanism(digest, &mech); if (ret != CKR_OK) { return NULL; } buffer = OPENSSL_malloc(mech->der_rsa_pss_params_len); if (buffer == NULL) { return NULL; } memcpy(buffer, mech->der_rsa_pss_params, mech->der_rsa_pss_params_len); *outlen = mech->der_rsa_pss_params_len; /* The last byte of Algorithm Identifier is the salt length, which is * not hardcoded and needs to be fitted here */ buffer[mech->der_rsa_pss_params_len - 1] = saltlen; return buffer; } static unsigned char * p11prov_rsapss_encode_algorithm_id(P11PROV_SIG_CTX *sigctx, size_t *outlen) { const P11PROV_MECH *mech, *mgf_mech; int ret; /* when OpenSSL calls this before it makes the signature, we still might not * have the defaults set so do it now */ ret = pss_defaults(sigctx, NULL, false); if (ret != CKR_OK) { P11PROV_raise(sigctx->provctx, ret, "Failed to set PSS defaults"); goto err; } ret = p11prov_mech_by_mechanism(sigctx->pss_params.hashAlg, &mech); if (ret != CKR_OK) { P11PROV_raise(sigctx->provctx, ret, "Failed to get mech for digest %lx", sigctx->pss_params.hashAlg); goto err; } ret = p11prov_mech_by_mgf(sigctx->pss_params.mgf, &mgf_mech); if (ret != CKR_OK) { P11PROV_raise(sigctx->provctx, ret, "Failed to get mech for mgf %lx", sigctx->pss_params.mgf); goto err; } /* Here we assume that the hashAlg and mgf1 hash algorithms are the same. * If not, it will need some more love */ if (mech != mgf_mech) { P11PROV_raise(sigctx->provctx, ret, "Inconsistent digest (%lx) and mgf1 (%lx) combination", sigctx->pss_params.hashAlg, sigctx->pss_params.mgf); goto err; } return p11prov_encode_rsa_pss_algorithm_id(sigctx->pss_params.hashAlg, sigctx->pss_params.sLen, outlen); err: return NULL; } static int p11prov_rsasig_get_ctx_params(void *ctx, OSSL_PARAM *params) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; OSSL_PARAM *p; size_t len; unsigned char *algorithm_id = NULL; int ret; P11PROV_debug("rsasig get ctx params (ctx=%p, params=%p)", ctx, params); if (params == NULL) { return RET_OSSL_OK; } p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID); if (p) { const P11PROV_MECH *mech = NULL; CK_RV result; switch (sigctx->mechtype) { case CKM_RSA_PKCS: result = p11prov_mech_by_mechanism(sigctx->digest, &mech); if (result != CKR_OK) { P11PROV_raise( sigctx->provctx, result, "Failed to get digest for signature algorithm ID"); return RET_OSSL_ERR; } ret = OSSL_PARAM_set_octet_string(p, mech->der_rsa_algorithm_id, mech->der_rsa_algorithm_id_len); if (ret != RET_OSSL_OK) { return ret; } break; case CKM_RSA_X_509: return RET_OSSL_ERR; case CKM_RSA_PKCS_PSS: /* The AlgorithmIdentifier here needs to contain also the * information about the RSA-PSS parameters as defined in * https://datatracker.ietf.org/doc/html/rfc8017#appendix-A.2.3 */ algorithm_id = p11prov_rsapss_encode_algorithm_id(sigctx, &len); if (algorithm_id == NULL) { P11PROV_raise(sigctx->provctx, CKR_GENERAL_ERROR, "Failed to encode algorithm ID for RSA-PSS"); return RET_OSSL_ERR; } ret = OSSL_PARAM_set_octet_string(p, algorithm_id, len); OPENSSL_free(algorithm_id); if (ret != RET_OSSL_OK) { return ret; } break; } } p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST); if (p) { const char *digest; CK_RV rv; rv = p11prov_digest_get_name(sigctx->digest, &digest); if (rv != CKR_OK) { P11PROV_raise(sigctx->provctx, rv, "Unavailable digest name"); return RET_OSSL_ERR; } ret = OSSL_PARAM_set_utf8_string(p, digest); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_PAD_MODE); if (p) { ret = RET_OSSL_ERR; for (int i = 0; padding_map[i].string != NULL; i++) { if (padding_map[i].type == sigctx->mechtype) { switch (p->data_type) { case OSSL_PARAM_INTEGER: ret = OSSL_PARAM_set_int(p, padding_map[i].ossl_id); break; case OSSL_PARAM_UTF8_STRING: ret = OSSL_PARAM_set_utf8_string(p, padding_map[i].string); break; } break; } } if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_MGF1_DIGEST); if (p) { const char *digest = NULL; CK_RV rv = CKR_GENERAL_ERROR; if (sigctx->pss_params.mgf != 0) { digest = p11prov_sig_mgf_name(sigctx->pss_params.mgf); } else { const P11PROV_MECH *pssmech; rv = p11prov_mech_by_mechanism(sigctx->mechtype, &pssmech); if (rv == CKR_OK) { rv = p11prov_digest_get_name(pssmech->digest, &digest); if (rv != CKR_OK) { digest = NULL; } } } if (!digest) { P11PROV_raise(sigctx->provctx, rv, "Failed to get digest for MGF1"); return RET_OSSL_ERR; } ret = OSSL_PARAM_set_utf8_string(p, digest); if (ret != RET_OSSL_OK) { return ret; } } return RET_OSSL_OK; } /* only available in recent OpenSSL 3.0.x headers */ #ifndef RSA_PSS_SALTLEN_AUTO_DIGEST_MAX #define RSA_PSS_SALTLEN_AUTO_DIGEST_MAX -4 #endif #ifndef OSSL_PKEY_RSA_PSS_SALT_LEN_AUTO_DIGEST_MAX #define OSSL_PKEY_RSA_PSS_SALT_LEN_AUTO_DIGEST_MAX "auto-digestmax" #endif static int rsasig_set_saltlen(P11PROV_SIG_CTX *sigctx, int saltlen) { if (saltlen >= 0) { sigctx->pss_params.sLen = saltlen; return RET_OSSL_OK; } if (saltlen == RSA_PSS_SALTLEN_DIGEST) { return p11prov_rsasig_set_pss_saltlen_from_digest(sigctx); } if (saltlen == RSA_PSS_SALTLEN_AUTO || saltlen == RSA_PSS_SALTLEN_MAX) { return p11prov_rsasig_set_pss_saltlen_max(sigctx, false); } if (saltlen == RSA_PSS_SALTLEN_AUTO_DIGEST_MAX) { return p11prov_rsasig_set_pss_saltlen_max(sigctx, true); } return RET_OSSL_ERR; } static int p11prov_rsasig_set_ctx_params(void *ctx, const OSSL_PARAM params[]) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; const OSSL_PARAM *p; int ret; P11PROV_debug("rsasig set ctx params (ctx=%p, params=%p)", sigctx, params); if (params == NULL) { return RET_OSSL_OK; } p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST); if (p) { const char *digest = NULL; CK_RV rv; ret = OSSL_PARAM_get_utf8_string_ptr(p, &digest); if (ret != RET_OSSL_OK) { return ret; } P11PROV_debug("Set OSSL_SIGNATURE_PARAM_DIGEST to %s", digest); rv = p11prov_digest_get_by_name(digest, &sigctx->digest); if (rv != CKR_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return RET_OSSL_ERR; } } p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PAD_MODE); if (p) { CK_MECHANISM_TYPE mechtype = CK_UNAVAILABLE_INFORMATION; CK_SLOT_ID slotid = p11prov_obj_get_slotid(sigctx->key); /* If the object is imported, use the default slot */ if (slotid == CK_UNAVAILABLE_INFORMATION) { P11PROV_SLOTS_CTX *slots = p11prov_ctx_get_slots(sigctx->provctx); if (!slots) { return RET_OSSL_ERR; } slotid = p11prov_get_default_slot(slots); } if (p->data_type == OSSL_PARAM_INTEGER) { int pad_mode; /* legacy pad mode number */ ret = OSSL_PARAM_get_int(p, &pad_mode); if (ret != RET_OSSL_OK) { return ret; } P11PROV_debug("Set OSSL_SIGNATURE_PARAM_PAD_MODE to %d", pad_mode); for (int i = 0; padding_map[i].string != NULL; i++) { if (padding_map[i].ossl_id == pad_mode) { mechtype = padding_map[i].type; break; } } } else if (p->data_type == OSSL_PARAM_UTF8_STRING) { P11PROV_debug("Set OSSL_SIGNATURE_PARAM_PAD_MODE to %s", p->data ? (const char *)p->data : ""); if (p->data) { for (int i = 0; padding_map[i].string != NULL; i++) { if (strcmp(p->data, padding_map[i].string) == 0) { mechtype = padding_map[i].type; break; } } } } else { return RET_OSSL_ERR; } if (mechtype == CK_UNAVAILABLE_INFORMATION) { ERR_raise(ERR_LIB_PROV, PROV_R_ILLEGAL_OR_UNSUPPORTED_PADDING_MODE); return RET_OSSL_ERR; } if (mechtype == CKM_RSA_PKCS_PSS) { /* some modules do not support PSS so we need to return * an error early if we try to select this. Unfortunately * although openssl has separate keymgmt for PKCS vs PSS * padding, it consider RSA always capable to be performed * regardless, and this is not the case in PKCS#11 */ CK_RV rv; rv = p11prov_check_mechanism(sigctx->provctx, slotid, CKM_RSA_PKCS_PSS); if (rv != CKR_OK) { P11PROV_raise(sigctx->provctx, rv, "CKM_RSA_PKCS_PSS unavailable"); return RET_OSSL_ERR; } } sigctx->mechtype = mechtype; P11PROV_debug_mechanism(sigctx->provctx, slotid, sigctx->mechtype); } p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_PSS_SALTLEN); if (p) { int saltlen; if (sigctx->mechtype != CKM_RSA_PKCS_PSS) { ERR_raise_data(ERR_LIB_PROV, PROV_R_NOT_SUPPORTED, "Can only be set if PSS Padding was first set."); return RET_OSSL_ERR; } if (p->data_type == OSSL_PARAM_INTEGER) { /* legacy saltlen number */ ret = OSSL_PARAM_get_int(p, &saltlen); if (ret != RET_OSSL_OK) { return ret; } P11PROV_debug("Set OSSL_SIGNATURE_PARAM_PSS_SALTLEN to %d", saltlen); } else if (p->data_type == OSSL_PARAM_UTF8_STRING) { P11PROV_debug("Set OSSL_SIGNATURE_PARAM_PSS_SALTLEN to %s", p->data ? (const char *)p->data : ""); if (strcmp(p->data, OSSL_PKEY_RSA_PSS_SALT_LEN_DIGEST) == 0) { saltlen = RSA_PSS_SALTLEN_DIGEST; } else if (strcmp(p->data, OSSL_PKEY_RSA_PSS_SALT_LEN_MAX) == 0) { saltlen = RSA_PSS_SALTLEN_MAX; } else if (strcmp(p->data, OSSL_PKEY_RSA_PSS_SALT_LEN_AUTO) == 0) { saltlen = RSA_PSS_SALTLEN_AUTO; } else if (strcmp(p->data, OSSL_PKEY_RSA_PSS_SALT_LEN_AUTO_DIGEST_MAX) == 0) { saltlen = RSA_PSS_SALTLEN_AUTO_DIGEST_MAX; } else { saltlen = atoi(p->data); } } else { return RET_OSSL_ERR; } ret = rsasig_set_saltlen(sigctx, saltlen); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_MGF1_DIGEST); if (p) { const char *digest = NULL; ret = OSSL_PARAM_get_utf8_string_ptr(p, &digest); if (ret != RET_OSSL_OK) { return ret; } P11PROV_debug("Set OSSL_SIGNATURE_PARAM_MGF1_DIGEST to %s", digest); sigctx->pss_params.mgf = p11prov_sig_map_mgf(digest); if (sigctx->pss_params.mgf == CK_UNAVAILABLE_INFORMATION) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MGF1_MD); return RET_OSSL_ERR; } } return RET_OSSL_OK; } static const OSSL_PARAM *p11prov_rsasig_gettable_ctx_params(void *ctx, void *prov) { static const OSSL_PARAM params[] = { OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0), OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL, 0), OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0), OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0), OSSL_PARAM_END, }; return params; } static const OSSL_PARAM *p11prov_rsasig_settable_ctx_params(void *ctx, void *prov) { static const OSSL_PARAM params[] = { OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PAD_MODE, NULL, 0), /* TODO: support rsa_padding_mode */ OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_MGF1_DIGEST, NULL, 0), OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_PSS_SALTLEN, NULL, 0), OSSL_PARAM_END, }; return params; } const OSSL_DISPATCH p11prov_rsa_signature_functions[] = { DISPATCH_SIG_ELEM(rsasig, NEWCTX, newctx), DISPATCH_SIG_ELEM(sig, FREECTX, freectx), DISPATCH_SIG_ELEM(sig, DUPCTX, dupctx), DISPATCH_SIG_ELEM(rsasig, SIGN_INIT, sign_init), DISPATCH_SIG_ELEM(rsasig, SIGN, sign), DISPATCH_SIG_ELEM(rsasig, VERIFY_INIT, verify_init), DISPATCH_SIG_ELEM(rsasig, VERIFY, verify), DISPATCH_SIG_ELEM(rsasig, DIGEST_SIGN_INIT, digest_sign_init), DISPATCH_SIG_ELEM(rsasig, DIGEST_SIGN_UPDATE, digest_sign_update), DISPATCH_SIG_ELEM(rsasig, DIGEST_SIGN_FINAL, digest_sign_final), DISPATCH_SIG_ELEM(rsasig, DIGEST_VERIFY_INIT, digest_verify_init), DISPATCH_SIG_ELEM(rsasig, DIGEST_VERIFY_UPDATE, digest_verify_update), DISPATCH_SIG_ELEM(rsasig, DIGEST_VERIFY_FINAL, digest_verify_final), DISPATCH_SIG_ELEM(rsasig, GET_CTX_PARAMS, get_ctx_params), DISPATCH_SIG_ELEM(rsasig, GETTABLE_CTX_PARAMS, gettable_ctx_params), DISPATCH_SIG_ELEM(rsasig, SET_CTX_PARAMS, set_ctx_params), DISPATCH_SIG_ELEM(rsasig, SETTABLE_CTX_PARAMS, settable_ctx_params), { 0, NULL }, }; DISPATCH_ECDSA_FN(newctx); DISPATCH_ECDSA_FN(sign_init); DISPATCH_ECDSA_FN(sign); DISPATCH_ECDSA_FN(verify_init); DISPATCH_ECDSA_FN(verify); DISPATCH_ECDSA_FN(digest_sign_init); DISPATCH_ECDSA_FN(digest_sign_update); DISPATCH_ECDSA_FN(digest_sign_final); DISPATCH_ECDSA_FN(digest_verify_init); DISPATCH_ECDSA_FN(digest_verify_update); DISPATCH_ECDSA_FN(digest_verify_final); DISPATCH_ECDSA_FN(get_ctx_params); DISPATCH_ECDSA_FN(set_ctx_params); DISPATCH_ECDSA_FN(gettable_ctx_params); DISPATCH_ECDSA_FN(settable_ctx_params); static void *p11prov_ecdsa_newctx(void *provctx, const char *properties) { P11PROV_CTX *ctx = (P11PROV_CTX *)provctx; P11PROV_SIG_CTX *sigctx; sigctx = p11prov_sig_newctx(ctx, CKM_ECDSA, properties); if (sigctx == NULL) { return NULL; } return sigctx; } static int p11prov_ecdsa_sign_init(void *ctx, void *provkey, const OSSL_PARAM params[]) { CK_RV ret; P11PROV_debug("ecdsa sign init (ctx=%p, key=%p, params=%p)", ctx, provkey, params); ret = p11prov_sig_op_init(ctx, provkey, CKF_SIGN, NULL); if (ret != CKR_OK) { return RET_OSSL_ERR; } return p11prov_ecdsa_set_ctx_params(ctx, params); } /* The raw signature is concatenated r | s padded to the field sizes */ #define P11PROV_MAX_RAW_ECC_SIG_SIZE (2 * (OPENSSL_ECC_MAX_FIELD_BITS + 7) / 8) static int convert_ecdsa_raw_to_der(const unsigned char *raw, size_t rawlen, unsigned char *der, size_t *derlen, size_t dersize) { const CK_ULONG fieldlen = rawlen / 2; ECDSA_SIG *ecdsasig; BIGNUM *r, *s; int ret = RET_OSSL_ERR; ecdsasig = ECDSA_SIG_new(); if (ecdsasig == NULL) { return RET_OSSL_ERR; } r = BN_bin2bn(&raw[0], fieldlen, NULL); s = BN_bin2bn(&raw[fieldlen], fieldlen, NULL); ret = ECDSA_SIG_set0(ecdsasig, r, s); if (ret == RET_OSSL_OK) { *derlen = i2d_ECDSA_SIG(ecdsasig, NULL); if (*derlen <= dersize) { i2d_ECDSA_SIG(ecdsasig, &der); ret = RET_OSSL_OK; } } else { BN_clear_free(r); BN_clear_free(s); } ECDSA_SIG_free(ecdsasig); return ret; } static int convert_ecdsa_der_to_raw(const unsigned char *der, size_t derlen, unsigned char *raw, size_t rawlen, CK_ULONG fieldlen) { ECDSA_SIG *ecdsasig; const BIGNUM *r, *s; if (fieldlen == CK_UNAVAILABLE_INFORMATION) { return RET_OSSL_ERR; } if (rawlen < 2 * fieldlen) { return RET_OSSL_ERR; } ecdsasig = d2i_ECDSA_SIG(NULL, &der, derlen); if (ecdsasig == NULL) { return RET_OSSL_ERR; } ECDSA_SIG_get0(ecdsasig, &r, &s); BN_bn2binpad(r, &raw[0], fieldlen); BN_bn2binpad(s, &raw[fieldlen], fieldlen); ECDSA_SIG_free(ecdsasig); return RET_OSSL_OK; } static int p11prov_ecdsa_sign(void *ctx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, size_t tbslen) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; unsigned char raw[P11PROV_MAX_RAW_ECC_SIG_SIZE]; size_t rawlen; CK_RV ret; int err; P11PROV_debug("ecdsa sign (ctx=%p)", ctx); if (sig == NULL || sigsize == 0) { ret = p11prov_sig_operate(sigctx, 0, siglen, 0, (void *)tbs, tbslen); if (ret != CKR_OK) { return RET_OSSL_ERR; } return RET_OSSL_OK; } ret = p11prov_sig_operate(sigctx, raw, &rawlen, sizeof(raw), (void *)tbs, tbslen); if (ret != CKR_OK) { return RET_OSSL_ERR; } err = convert_ecdsa_raw_to_der(raw, rawlen, sig, siglen, sigsize); OPENSSL_cleanse(raw, rawlen); return err; } static int p11prov_ecdsa_verify_init(void *ctx, void *provkey, const OSSL_PARAM params[]) { CK_RV ret; P11PROV_debug("ecdsa verify init (ctx=%p, key=%p, params=%p)", ctx, provkey, params); ret = p11prov_sig_op_init(ctx, provkey, CKF_VERIFY, NULL); if (ret != CKR_OK) { return RET_OSSL_ERR; } return p11prov_ecdsa_set_ctx_params(ctx, params); } static int p11prov_ecdsa_verify(void *ctx, const unsigned char *sig, size_t siglen, const unsigned char *tbs, size_t tbslen) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; unsigned char raw[P11PROV_MAX_RAW_ECC_SIG_SIZE]; CK_ULONG flen = p11prov_obj_get_key_size(sigctx->key); CK_RV ret; int err; P11PROV_debug("ecdsa verify (ctx=%p)", ctx); err = convert_ecdsa_der_to_raw(sig, siglen, raw, sizeof(raw), flen); if (err != RET_OSSL_OK) { return err; } ret = p11prov_sig_operate(sigctx, (void *)raw, NULL, 2 * flen, (void *)tbs, tbslen); OPENSSL_cleanse(raw, 2 * flen); if (ret != CKR_OK) { return RET_OSSL_ERR; } return RET_OSSL_OK; } static int p11prov_ecdsa_digest_sign_init(void *ctx, const char *digest, void *provkey, const OSSL_PARAM params[]) { CK_RV ret; P11PROV_debug( "ecdsa digest sign init (ctx=%p, digest=%s, key=%p, params=%p)", ctx, digest ? digest : "", provkey, params); /* use a default of sha2 256 if not provided */ if (!digest) { digest = "sha256"; } ret = p11prov_sig_op_init(ctx, provkey, CKF_SIGN, digest); if (ret != CKR_OK) { return RET_OSSL_ERR; } return p11prov_ecdsa_set_ctx_params(ctx, params); } static int p11prov_ecdsa_digest_sign_update(void *ctx, const unsigned char *data, size_t datalen) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; P11PROV_debug("ecdsa digest sign update (ctx=%p, data=%p, datalen=%zu)", ctx, data, datalen); if (sigctx == NULL) { return RET_OSSL_ERR; } return p11prov_sig_digest_update(sigctx, (void *)data, datalen); } static int p11prov_ecdsa_digest_sign_final(void *ctx, unsigned char *sig, size_t *siglen, size_t sigsize) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; unsigned char raw[P11PROV_MAX_RAW_ECC_SIG_SIZE]; size_t rawlen = 0; int ret; /* the siglen might be uninitialized when called from openssl */ *siglen = 0; P11PROV_debug( "ecdsa digest sign final (ctx=%p, sig=%p, siglen=%zu, " "sigsize=%zu)", ctx, sig, *siglen, sigsize); if (sigctx == NULL) { return RET_OSSL_ERR; } if (sig == NULL || sigsize == 0) { return p11prov_sig_digest_final(sigctx, 0, siglen, 0); } ret = p11prov_sig_digest_final(sigctx, raw, &rawlen, sizeof(raw)); if (ret != RET_OSSL_OK) { return ret; } ret = convert_ecdsa_raw_to_der(raw, rawlen, sig, siglen, sigsize); OPENSSL_cleanse(raw, rawlen); return ret; } static int p11prov_ecdsa_digest_verify_init(void *ctx, const char *digest, void *provkey, const OSSL_PARAM params[]) { CK_RV ret; P11PROV_debug("ecdsa digest verify init (ctx=%p, key=%p, params=%p)", ctx, provkey, params); /* use a default of sha2 256 if not provided */ if (!digest) { digest = "sha256"; } ret = p11prov_sig_op_init(ctx, provkey, CKF_VERIFY, digest); if (ret != CKR_OK) { return RET_OSSL_ERR; } return p11prov_ecdsa_set_ctx_params(ctx, params); } static int p11prov_ecdsa_digest_verify_update(void *ctx, const unsigned char *data, size_t datalen) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; P11PROV_debug("ecdsa digest verify update (ctx=%p, data=%p, datalen=%zu)", ctx, data, datalen); if (sigctx == NULL) { return RET_OSSL_ERR; } return p11prov_sig_digest_update(sigctx, (void *)data, datalen); } static int p11prov_ecdsa_digest_verify_final(void *ctx, const unsigned char *sig, size_t siglen) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; unsigned char raw[P11PROV_MAX_RAW_ECC_SIG_SIZE]; CK_ULONG flen; int ret; P11PROV_debug("ecdsa digest verify final (ctx=%p, sig=%p, siglen=%zu)", ctx, sig, siglen); if (sigctx == NULL) { return RET_OSSL_ERR; } flen = p11prov_obj_get_key_size(sigctx->key); ret = convert_ecdsa_der_to_raw(sig, siglen, raw, sizeof(raw), flen); if (ret != RET_OSSL_OK) { return ret; } ret = p11prov_sig_digest_final(sigctx, (void *)raw, NULL, 2 * flen); OPENSSL_cleanse(raw, 2 * flen); return ret; } static int p11prov_ecdsa_get_ctx_params(void *ctx, OSSL_PARAM *params) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; OSSL_PARAM *p; int ret; /* todo sig params: OSSL_SIGNATURE_PARAM_ALGORITHM_ID */ P11PROV_debug("ecdsa get ctx params (ctx=%p, params=%p)", ctx, params); p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID); if (p) { const P11PROV_MECH *mech = NULL; CK_RV result; switch (sigctx->mechtype) { case CKM_ECDSA: result = p11prov_mech_by_mechanism(sigctx->digest, &mech); if (result != CKR_OK) { P11PROV_raise( sigctx->provctx, result, "Failed to get digest for signature algorithm ID"); return RET_OSSL_ERR; } ret = OSSL_PARAM_set_octet_string(p, mech->der_ecdsa_algorithm_id, mech->der_ecdsa_algorithm_id_len); if (ret != RET_OSSL_OK) { return ret; } break; default: return RET_OSSL_ERR; } } p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST_SIZE); if (p) { size_t digest_size; CK_RV rv; rv = p11prov_digest_get_digest_size(sigctx->digest, &digest_size); if (rv != CKR_OK) { P11PROV_raise(sigctx->provctx, rv, "Unavailable digest size"); return RET_OSSL_ERR; } ret = OSSL_PARAM_set_size_t(p, digest_size); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_DIGEST); if (p) { const char *digest; CK_RV rv; rv = p11prov_digest_get_name(sigctx->digest, &digest); if (rv != CKR_OK) { P11PROV_raise(sigctx->provctx, rv, "Unavailable digest name"); return RET_OSSL_ERR; } ret = OSSL_PARAM_set_utf8_string(p, digest); if (ret != RET_OSSL_OK) { return ret; } } return RET_OSSL_OK; } static int p11prov_ecdsa_set_ctx_params(void *ctx, const OSSL_PARAM params[]) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; const OSSL_PARAM *p; int ret; P11PROV_debug("ecdsa set ctx params (ctx=%p, params=%p)", sigctx, params); if (params == NULL) { return RET_OSSL_OK; } p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_DIGEST); if (p) { const char *digest = NULL; CK_RV rv; ret = OSSL_PARAM_get_utf8_string_ptr(p, &digest); if (ret != RET_OSSL_OK) { return ret; } P11PROV_debug("Set OSSL_SIGNATURE_PARAM_DIGEST to %s", digest); rv = p11prov_digest_get_by_name(digest, &sigctx->digest); if (rv != CKR_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return RET_OSSL_ERR; } } return RET_OSSL_OK; } static const OSSL_PARAM *p11prov_ecdsa_gettable_ctx_params(void *ctx, void *prov) { static const OSSL_PARAM params[] = { OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0), OSSL_PARAM_size_t(OSSL_SIGNATURE_PARAM_DIGEST_SIZE, NULL), OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), OSSL_PARAM_END, }; return params; } static const OSSL_PARAM *p11prov_ecdsa_settable_ctx_params(void *ctx, void *prov) { static const OSSL_PARAM params[] = { OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_DIGEST, NULL, 0), OSSL_PARAM_END, }; return params; } const OSSL_DISPATCH p11prov_ecdsa_signature_functions[] = { DISPATCH_SIG_ELEM(ecdsa, NEWCTX, newctx), DISPATCH_SIG_ELEM(sig, FREECTX, freectx), DISPATCH_SIG_ELEM(sig, DUPCTX, dupctx), DISPATCH_SIG_ELEM(ecdsa, SIGN_INIT, sign_init), DISPATCH_SIG_ELEM(ecdsa, SIGN, sign), DISPATCH_SIG_ELEM(ecdsa, VERIFY_INIT, verify_init), DISPATCH_SIG_ELEM(ecdsa, VERIFY, verify), DISPATCH_SIG_ELEM(ecdsa, DIGEST_SIGN_INIT, digest_sign_init), DISPATCH_SIG_ELEM(ecdsa, DIGEST_SIGN_UPDATE, digest_sign_update), DISPATCH_SIG_ELEM(ecdsa, DIGEST_SIGN_FINAL, digest_sign_final), DISPATCH_SIG_ELEM(ecdsa, DIGEST_VERIFY_INIT, digest_verify_init), DISPATCH_SIG_ELEM(ecdsa, DIGEST_VERIFY_UPDATE, digest_verify_update), DISPATCH_SIG_ELEM(ecdsa, DIGEST_VERIFY_FINAL, digest_verify_final), DISPATCH_SIG_ELEM(ecdsa, GET_CTX_PARAMS, get_ctx_params), DISPATCH_SIG_ELEM(ecdsa, GETTABLE_CTX_PARAMS, gettable_ctx_params), DISPATCH_SIG_ELEM(ecdsa, SET_CTX_PARAMS, set_ctx_params), DISPATCH_SIG_ELEM(ecdsa, SETTABLE_CTX_PARAMS, settable_ctx_params), { 0, NULL }, }; DISPATCH_EDDSA_FN(newctx); DISPATCH_EDDSA_FN(digest_sign_init); DISPATCH_EDDSA_FN(digest_sign); DISPATCH_EDDSA_FN(digest_verify_init); DISPATCH_EDDSA_FN(digest_verify); DISPATCH_EDDSA_FN(get_ctx_params); DISPATCH_EDDSA_FN(set_ctx_params); DISPATCH_EDDSA_FN(gettable_ctx_params); DISPATCH_EDDSA_FN(settable_ctx_params); static void *p11prov_eddsa_newctx(void *provctx, const char *properties) { P11PROV_CTX *ctx = (P11PROV_CTX *)provctx; return p11prov_sig_newctx(ctx, CKM_EDDSA, properties); } static int p11prov_eddsa_digest_sign_init(void *ctx, const char *digest, void *provkey, const OSSL_PARAM params[]) { CK_RV ret; P11PROV_debug( "eddsa digest sign init (ctx=%p, digest=%s, key=%p, params=%p)", ctx, digest ? digest : "", provkey, params); if (digest != NULL && digest[0] != '\0') { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return RET_OSSL_ERR; } ret = p11prov_sig_op_init(ctx, provkey, CKF_SIGN, digest); if (ret != CKR_OK) { return RET_OSSL_ERR; } return p11prov_eddsa_set_ctx_params(ctx, params); } static int p11prov_eddsa_digest_sign(void *ctx, unsigned char *sig, size_t *siglen, size_t sigsize, const unsigned char *tbs, size_t tbslen) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; CK_RV ret; P11PROV_debug("eddsa digest sign (ctx=%p, tbs=%p, tbslen=%zu)", ctx, tbs, tbslen); if (sigctx == NULL) { return RET_OSSL_ERR; } ret = p11prov_sig_operate(sigctx, sig, siglen, sigsize, (void *)tbs, tbslen); if (ret != CKR_OK) { return RET_OSSL_ERR; } return RET_OSSL_OK; } static int p11prov_eddsa_digest_verify_init(void *ctx, const char *digest, void *provkey, const OSSL_PARAM params[]) { CK_RV ret; P11PROV_debug("eddsa digest verify init (ctx=%p, key=%p, params=%p)", ctx, provkey, params); if (digest != NULL && digest[0] != '\0') { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return RET_OSSL_ERR; } ret = p11prov_sig_op_init(ctx, provkey, CKF_VERIFY, digest); if (ret != CKR_OK) { return RET_OSSL_ERR; } return p11prov_eddsa_set_ctx_params(ctx, params); } static int p11prov_eddsa_digest_verify(void *ctx, const unsigned char *sig, size_t siglen, const unsigned char *tbs, size_t tbslen) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; CK_RV ret; P11PROV_debug("eddsa digest verify (ctx=%p, tbs=%p, tbslen=%zu)", ctx, tbs, tbslen); if (sigctx == NULL) { return RET_OSSL_ERR; } ret = p11prov_sig_operate(sigctx, (void *)sig, NULL, siglen, (void *)tbs, tbslen); if (ret != CKR_OK) { return RET_OSSL_ERR; } return RET_OSSL_OK; } static int p11prov_eddsa_get_ctx_params(void *ctx, OSSL_PARAM *params) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; OSSL_PARAM *p; int ret = RET_OSSL_OK; /* todo sig params: OSSL_SIGNATURE_PARAM_ALGORITHM_ID */ P11PROV_debug("eddsa get ctx params (ctx=%p, params=%p)", ctx, params); p = OSSL_PARAM_locate(params, OSSL_SIGNATURE_PARAM_ALGORITHM_ID); if (p) { if (sigctx->mechtype != CKM_EDDSA) { return RET_OSSL_ERR; } CK_ULONG size = p11prov_obj_get_key_bit_size(sigctx->key); switch (size) { case ED25519_BIT_SIZE: ret = OSSL_PARAM_set_octet_string(p, der_ed25519_algorithm_id, sizeof(der_ed25519_algorithm_id)); break; case ED448_BIT_SIZE: ret = OSSL_PARAM_set_octet_string(p, der_ed448_algorithm_id, sizeof(der_ed448_algorithm_id)); break; default: return RET_OSSL_ERR; } } return ret; } #ifndef OSSL_SIGNATURE_PARAM_INSTANCE #define OSSL_SIGNATURE_PARAM_INSTANCE "instance" #endif #ifndef OSSL_SIGNATURE_PARAM_CONTEXT_STRING #define OSSL_SIGNATURE_PARAM_CONTEXT_STRING "context-string" #endif static int p11prov_eddsa_set_ctx_params(void *ctx, const OSSL_PARAM params[]) { P11PROV_SIG_CTX *sigctx = (P11PROV_SIG_CTX *)ctx; const char *instance = "Ed25519"; const OSSL_PARAM *p; CK_ULONG size; bool matched = false; int ret; P11PROV_debug("eddsa set ctx params (ctx=%p, params=%p)", sigctx, params); size = p11prov_obj_get_key_bit_size(sigctx->key); if (size != ED25519_BIT_SIZE && size != ED448_BIT_SIZE) { P11PROV_raise(sigctx->provctx, CKR_KEY_TYPE_INCONSISTENT, "Invalid EdDSA key size %lu", size); return RET_OSSL_ERR; } /* PKCS #11 parameters are mandatory for Ed448 key type anyway */ if (size == ED448_BIT_SIZE) { instance = "Ed448"; } p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_INSTANCE); if (p) { ret = OSSL_PARAM_get_utf8_string_ptr(p, &instance); if (ret != RET_OSSL_OK) { return ret; } P11PROV_debug("Set OSSL_SIGNATURE_PARAM_INSTANCE to %s", instance); } p = OSSL_PARAM_locate_const(params, OSSL_SIGNATURE_PARAM_CONTEXT_STRING); if (p) { size_t datalen; OPENSSL_clear_free(sigctx->eddsa_params.pContextData, sigctx->eddsa_params.ulContextDataLen); sigctx->eddsa_params.pContextData = NULL; ret = OSSL_PARAM_get_octet_string( p, (void **)&sigctx->eddsa_params.pContextData, 0, &datalen); if (ret != RET_OSSL_OK) { return ret; } sigctx->eddsa_params.ulContextDataLen = datalen; } if (size == ED25519_BIT_SIZE) { if (OPENSSL_strcasecmp(instance, "Ed25519") == 0) { matched = true; sigctx->use_eddsa_params = CK_FALSE; } else if (OPENSSL_strcasecmp(instance, "Ed25519ph") == 0) { matched = true; sigctx->use_eddsa_params = CK_TRUE; sigctx->eddsa_params.phFlag = CK_TRUE; } else if (OPENSSL_strcasecmp(instance, "Ed25519ctx") == 0) { matched = true; sigctx->use_eddsa_params = CK_TRUE; sigctx->eddsa_params.phFlag = CK_FALSE; } } else if (size == ED448_BIT_SIZE) { if (OPENSSL_strcasecmp(instance, "Ed448") == 0) { matched = true; sigctx->use_eddsa_params = CK_TRUE; sigctx->eddsa_params.phFlag = CK_FALSE; } else if (OPENSSL_strcasecmp(instance, "Ed448ph") == 0) { matched = true; sigctx->use_eddsa_params = CK_TRUE; sigctx->eddsa_params.phFlag = CK_TRUE; } } if (!matched) { P11PROV_raise(sigctx->provctx, CKR_ARGUMENTS_BAD, "Invalid instance %s", instance); return RET_OSSL_ERR; } return RET_OSSL_OK; } static const OSSL_PARAM *p11prov_eddsa_gettable_ctx_params(void *ctx, void *prov) { static const OSSL_PARAM params[] = { OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_ALGORITHM_ID, NULL, 0), OSSL_PARAM_END, }; return params; } static const OSSL_PARAM *p11prov_eddsa_settable_ctx_params(void *ctx, void *prov) { static const OSSL_PARAM params[] = { OSSL_PARAM_utf8_string(OSSL_SIGNATURE_PARAM_INSTANCE, NULL, 0), OSSL_PARAM_octet_string(OSSL_SIGNATURE_PARAM_CONTEXT_STRING, NULL, 0), OSSL_PARAM_END, }; return params; } const OSSL_DISPATCH p11prov_eddsa_signature_functions[] = { DISPATCH_SIG_ELEM(eddsa, NEWCTX, newctx), DISPATCH_SIG_ELEM(sig, FREECTX, freectx), DISPATCH_SIG_ELEM(sig, DUPCTX, dupctx), DISPATCH_SIG_ELEM(eddsa, DIGEST_SIGN_INIT, digest_sign_init), DISPATCH_SIG_ELEM(eddsa, DIGEST_SIGN, digest_sign), DISPATCH_SIG_ELEM(eddsa, DIGEST_VERIFY_INIT, digest_verify_init), DISPATCH_SIG_ELEM(eddsa, DIGEST_VERIFY, digest_verify), DISPATCH_SIG_ELEM(eddsa, GET_CTX_PARAMS, get_ctx_params), DISPATCH_SIG_ELEM(eddsa, GETTABLE_CTX_PARAMS, gettable_ctx_params), DISPATCH_SIG_ELEM(eddsa, SET_CTX_PARAMS, set_ctx_params), DISPATCH_SIG_ELEM(eddsa, SETTABLE_CTX_PARAMS, settable_ctx_params), { 0, NULL }, }; CK_MECHANISM_TYPE p11prov_digest_to_rsapss_mech(CK_MECHANISM_TYPE digest) { const P11PROV_MECH *mech = NULL; CK_RV rv; rv = p11prov_mech_by_mechanism(digest, &mech); if (rv == CKR_OK) { return mech->pkcs_pss; } return CK_UNAVAILABLE_INFORMATION; } pkcs11-provider-1.0/src/signature.h000066400000000000000000000020021475270623700172540ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _SIGNATURE_H #define _SIGNATURE_H /* common sig functions */ #define DISPATCH_SIG_FN(name) DECL_DISPATCH_FUNC(signature, p11prov_sig, name) #define DISPATCH_SIG_ELEM(prefix, NAME, name) \ { \ OSSL_FUNC_SIGNATURE_##NAME, (void (*)(void))p11prov_##prefix##_##name \ } /* rsa sig functions */ #define DISPATCH_RSASIG_FN(name) \ DECL_DISPATCH_FUNC(signature, p11prov_rsasig, name) extern const OSSL_DISPATCH p11prov_rsa_signature_functions[]; /* ecdsa sig functions */ #define DISPATCH_ECDSA_FN(name) \ DECL_DISPATCH_FUNC(signature, p11prov_ecdsa, name) extern const OSSL_DISPATCH p11prov_ecdsa_signature_functions[]; /* eddsa sig functions */ #define DISPATCH_EDDSA_FN(name) \ DECL_DISPATCH_FUNC(signature, p11prov_eddsa, name) extern const OSSL_DISPATCH p11prov_eddsa_signature_functions[]; CK_MECHANISM_TYPE p11prov_digest_to_rsapss_mech(CK_MECHANISM_TYPE digest); #endif /* _SIGNATURE_H */ pkcs11-provider-1.0/src/slot.c000066400000000000000000000357001475270623700162420ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include struct p11prov_slot { CK_SLOT_ID id; CK_SLOT_INFO slot; CK_TOKEN_INFO token; char *login_info; char *cached_pin; char *bad_pin; P11PROV_SESSION_POOL *pool; P11PROV_OBJ_POOL *objects; CK_MECHANISM_TYPE *mechs; int nmechs; CK_ULONG profiles[5]; }; struct p11prov_slots_ctx { P11PROV_CTX *provctx; P11PROV_SLOT **slots; int num; pthread_rwlock_t rwlock; /* This is the first slot that can be r/w and * accepts login */ CK_SLOT_ID default_slot; }; static void get_slot_profiles(P11PROV_CTX *ctx, struct p11prov_slot *slot) { CK_SESSION_HANDLE session; CK_BBOOL token = CK_TRUE; CK_OBJECT_CLASS class = CKO_PROFILE; CK_ATTRIBUTE template[2] = { { CKA_TOKEN, &token, sizeof(token) }, { CKA_CLASS, &class, sizeof(class) }, }; CK_OBJECT_HANDLE object[5]; CK_ULONG objcount; int index = 0; int ret; ret = p11prov_OpenSession(ctx, slot->id, CKF_SERIAL_SESSION, NULL, NULL, &session); if (ret != CKR_OK) { return; } ret = p11prov_FindObjectsInit(ctx, session, template, 2); if (ret != CKR_OK) { goto done; } /* at most 5 objects as there are 5 profiles for now */ ret = p11prov_FindObjects(ctx, session, object, 5, &objcount); if (ret != CKR_OK) { (void)p11prov_FindObjectsFinal(ctx, session); goto done; } (void)p11prov_FindObjectsFinal(ctx, session); if (objcount == 0) { P11PROV_debug("No profiles for slot %lu", slot->id); goto done; } for (size_t i = 0; i < objcount; i++) { CK_ULONG value = CK_UNAVAILABLE_INFORMATION; CK_ATTRIBUTE profileid = { CKA_PROFILE_ID, &value, sizeof(value) }; ret = p11prov_GetAttributeValue(ctx, session, object[i], &profileid, 1); if (ret != CKR_OK || value == CK_UNAVAILABLE_INFORMATION) { continue; } slot->profiles[index] = value; index++; } done: (void)p11prov_CloseSession(ctx, session); return; } static void get_slot_mechanisms(P11PROV_CTX *ctx, struct p11prov_slot *slot) { CK_ULONG mechs_num; int ret; ret = p11prov_GetMechanismList(ctx, slot->id, NULL, &mechs_num); if (ret != CKR_OK) { return; } P11PROV_debug("Slot(%lu) mechs found: %lu", slot->id, mechs_num); slot->mechs = OPENSSL_malloc(mechs_num * sizeof(CK_MECHANISM_TYPE)); if (!slot->mechs) { P11PROV_raise(ctx, CKR_HOST_MEMORY, "Failed to alloc for mech list"); return; } ret = p11prov_GetMechanismList(ctx, slot->id, slot->mechs, &mechs_num); if (ret != CKR_OK) { OPENSSL_free(slot->mechs); return; } slot->nmechs = mechs_num; } static const char slot_desc_fmt[] = "PKCS#11 Token (Slot %lu - %s)"; CK_RV p11prov_init_slots(P11PROV_CTX *ctx, P11PROV_SLOTS_CTX **slots) { CK_ULONG num; CK_INFO ck_info; CK_SLOT_ID *slotid = NULL; struct p11prov_slots_ctx *sctx; CK_RV ret; int err; ck_info = p11prov_ctx_get_ck_info(ctx); sctx = OPENSSL_zalloc(sizeof(P11PROV_SLOTS_CTX)); if (!sctx) { return CKR_HOST_MEMORY; } sctx->provctx = ctx; err = pthread_rwlock_init(&sctx->rwlock, NULL); if (err != 0) { err = errno; ret = CKR_CANT_LOCK; P11PROV_raise(ctx, ret, "Failed to init slots lock (errno:%d)", err); goto done; } ret = p11prov_GetSlotList(ctx, CK_FALSE, NULL, &num); if (ret) { goto done; } /* arbitrary number from libp11 */ if (num > 0x10000) { ret = CKR_GENERAL_ERROR; goto done; } slotid = OPENSSL_malloc(num * sizeof(CK_SLOT_ID)); if (!slotid) { ret = CKR_HOST_MEMORY; goto done; } ret = p11prov_GetSlotList(ctx, CK_FALSE, slotid, &num); if (ret) { goto done; } sctx->slots = OPENSSL_zalloc(num * sizeof(P11PROV_SLOT *)); if (!sctx->slots) { ret = CKR_HOST_MEMORY; goto done; } sctx->default_slot = CK_UNAVAILABLE_INFORMATION; for (size_t i = 0; i < num; i++) { P11PROV_SLOT *slot; slot = OPENSSL_zalloc(sizeof(P11PROV_SLOT)); if (!slot) { ret = CKR_HOST_MEMORY; goto done; } ret = p11prov_GetSlotInfo(ctx, slotid[i], &slot->slot); if (ret != CKR_OK || (slot->slot.flags & CKF_TOKEN_PRESENT) == 0) { /* skip slot */ OPENSSL_free(slot); continue; } ret = p11prov_GetTokenInfo(ctx, slotid[i], &slot->token); if (ret) { /* skip slot */ OPENSSL_free(slot); continue; } sctx->slots[sctx->num] = slot; sctx->num++; trim(slot->slot.slotDescription); trim(slot->slot.manufacturerID); trim(slot->token.label); trim(slot->token.manufacturerID); trim(slot->token.model); trim(slot->token.serialNumber); slot->id = slotid[i]; /* upper bound = slot_desc_fmt + LONG_MAX chars + MAX SLOT DESC */ slot->login_info = p11prov_alloc_sprintf( sizeof(slot_desc_fmt) + 20 + sizeof(slot->slot.slotDescription) + 1, slot_desc_fmt, slot->id, slot->slot.slotDescription); if (!slot->login_info) { ret = CKR_HOST_MEMORY; goto done; } ret = p11prov_session_pool_init(ctx, &slot->token, slot->id, &slot->pool); if (ret) { goto done; } ret = p11prov_obj_pool_init(ctx, slot->id, &slot->objects); if (ret) { goto done; } /* profiles not available before version 3 */ if (ck_info.cryptokiVersion.major >= 3) { get_slot_profiles(ctx, slot); } get_slot_mechanisms(ctx, slot); /* set default slot to the first one that can be used (for example * softoken has a slot that can't be used to store session keys) * and the following query excludes it */ if ((sctx->default_slot == CK_UNAVAILABLE_INFORMATION) && (slot->token.flags & CKF_LOGIN_REQUIRED) && (slot->token.flags & CKF_USER_PIN_INITIALIZED) && (slot->token.flags & CKF_TOKEN_INITIALIZED) && (!(slot->token.flags & CKF_USER_PIN_LOCKED))) { sctx->default_slot = slot->id; } P11PROV_debug_slot(ctx, slot->id, &slot->slot, &slot->token, slot->mechs, slot->nmechs, slot->profiles); } done: OPENSSL_free(slotid); if (ret != CKR_OK) { p11prov_free_slots(sctx); sctx = NULL; } *slots = sctx; return ret; } void p11prov_slot_fork_prepare(P11PROV_SLOTS_CTX *sctx) { int err; /* attempt to get a write lock if possible, but fall back to a mere * read lock if not possible (for example because it would cause * a deadlock). * Holding a write lock here is slightly preferable in case the * application decides to create threads immediately after the fork * within an atfork handler that runs before ours. * Holding a write lock will prevent other threads from grabbing a * read lock before we can reset the locks. However we assume this * scenario to be mostly hypothetical and exceedingly rare given most * forks result in a exec(), and atfork() is also a rarely used * function, so falling back to a read lock to avoid deadlocks is ok * in the vast majority of use cases. */ err = pthread_rwlock_trywrlock(&sctx->rwlock); if (err != 0) { err = pthread_rwlock_rdlock(&sctx->rwlock); if (err != 0) { err = errno; P11PROV_debug("Failed to get slots lock (errno:%d)", err); return; } } } void p11prov_slot_fork_release(P11PROV_SLOTS_CTX *sctx) { int err; err = pthread_rwlock_unlock(&sctx->rwlock); if (err != 0) { err = errno; P11PROV_debug("Failed to release slots lock (errno:%d)", err); } } void p11prov_slot_fork_reset(P11PROV_SLOTS_CTX *sctx) { int err; /* rwlock, saves TID internally, so we need to reset * after fork in the child */ p11prov_force_rwlock_reinit(&sctx->rwlock); /* This is running in the fork handler, so there should be no * way to have other threads running, but just in case some * crazy library creates threads in their child handler */ err = pthread_rwlock_wrlock(&sctx->rwlock); if (err != 0) { err = errno; P11PROV_debug("Failed to get slots lock (errno:%d)", err); return; } for (int i = 0; i < sctx->num; i++) { P11PROV_SLOT *slot = sctx->slots[i]; /* invalidate all sessions */ p11prov_session_pool_fork_reset(slot->pool); /* mark each object for revalidation */ p11prov_obj_pool_fork_reset(slot->objects); } err = pthread_rwlock_unlock(&sctx->rwlock); if (err != 0) { err = errno; P11PROV_debug("Failed to release slots lock (errno:%d)", err); } } void p11prov_free_slots(P11PROV_SLOTS_CTX *sctx) { int err; if (!sctx) { return; } err = pthread_rwlock_destroy(&sctx->rwlock); if (err != 0) { err = errno; P11PROV_raise(sctx->provctx, CKR_CANT_LOCK, "Failed to destroy slots lock (errno:%d), leaking memory", err); return; } for (int i = 0; i < sctx->num; i++) { p11prov_session_pool_free(sctx->slots[i]->pool); p11prov_obj_pool_free(sctx->slots[i]->objects); OPENSSL_free(sctx->slots[i]->mechs); if (sctx->slots[i]->bad_pin) { OPENSSL_clear_free(sctx->slots[i]->bad_pin, strlen(sctx->slots[i]->bad_pin)); } if (sctx->slots[i]->cached_pin) { OPENSSL_clear_free(sctx->slots[i]->cached_pin, strlen(sctx->slots[i]->cached_pin)); } OPENSSL_free(sctx->slots[i]->login_info); OPENSSL_clear_free(sctx->slots[i], sizeof(P11PROV_SLOT)); } OPENSSL_free(sctx->slots); OPENSSL_free(sctx); } CK_RV p11prov_take_slots(P11PROV_CTX *ctx, P11PROV_SLOTS_CTX **slots) { P11PROV_SLOTS_CTX *sctx; int err; sctx = p11prov_ctx_get_slots(ctx); if (!sctx) { return CKR_GENERAL_ERROR; } err = pthread_rwlock_rdlock(&sctx->rwlock); if (err != 0) { err = errno; P11PROV_raise(ctx, CKR_CANT_LOCK, "Failed to get slots lock (errno:%d)", err); *slots = NULL; return CKR_CANT_LOCK; } *slots = sctx; return CKR_OK; } void p11prov_return_slots(P11PROV_SLOTS_CTX *sctx) { int err; err = pthread_rwlock_unlock(&sctx->rwlock); if (err != 0) { err = errno; P11PROV_raise(sctx->provctx, CKR_CANT_LOCK, "Failed to release slots lock (errno:%d)", err); } } /* returns the slots at index idx and increments the index */ P11PROV_SLOT *p11prov_fetch_slot(P11PROV_SLOTS_CTX *sctx, int *idx) { int i = *idx; if (i < 0 || i >= sctx->num) { return NULL; } *idx = i + 1; return sctx->slots[i]; } P11PROV_SLOT *p11prov_get_slot_by_id(P11PROV_SLOTS_CTX *sctx, CK_SLOT_ID id) { for (int s = 0; s < sctx->num; s++) { if (sctx->slots[s]->id == id) { return sctx->slots[s]; } } return NULL; } int p11prov_slot_get_mechanisms(P11PROV_SLOT *slot, CK_MECHANISM_TYPE **mechs) { if (!slot) { return 0; } *mechs = slot->mechs; return slot->nmechs; } int p11prov_check_mechanism(P11PROV_CTX *ctx, CK_SLOT_ID id, CK_MECHANISM_TYPE mechtype) { P11PROV_SLOTS_CTX *sctx; CK_RV ret; ret = p11prov_take_slots(ctx, &sctx); if (ret != CKR_OK) { return ret; } ret = CKR_MECHANISM_INVALID; for (int s = 0; s < sctx->num; s++) { if (sctx->slots[s]->id != id) { continue; } for (int i = 0; i < sctx->slots[s]->nmechs; i++) { if (sctx->slots[s]->mechs[i] == mechtype) { ret = CKR_OK; break; } } } p11prov_return_slots(sctx); return ret; } CK_RV p11prov_slot_get_obj_pool(P11PROV_CTX *ctx, CK_SLOT_ID id, P11PROV_OBJ_POOL **pool) { P11PROV_SLOT *slot = NULL; P11PROV_SLOTS_CTX *sctx; CK_RV ret; ret = p11prov_take_slots(ctx, &sctx); if (ret != CKR_OK) { return ret; } for (int s = 0; s < sctx->num; s++) { if (sctx->slots[s]->id == id) { slot = sctx->slots[s]; break; } } if (!slot) { ret = CKR_SLOT_ID_INVALID; } else { if (slot->objects) { *pool = slot->objects; ret = CKR_OK; } else { ret = CKR_GENERAL_ERROR; } } p11prov_return_slots(sctx); return ret; } CK_RV p11prov_slot_find_obj_pool(P11PROV_CTX *ctx, slot_pool_callback cb, void *cb_ctx) { P11PROV_SLOT *slot = NULL; P11PROV_SLOTS_CTX *sctx; bool found = false; CK_RV ret; ret = p11prov_take_slots(ctx, &sctx); if (ret != CKR_OK) { return ret; } for (int s = 0; s < sctx->num; s++) { slot = sctx->slots[s]; if (slot->objects) { found = cb(cb_ctx, slot->objects); } if (found) { break; } } p11prov_return_slots(sctx); return CKR_OK; } CK_SLOT_ID p11prov_slot_get_slot_id(P11PROV_SLOT *slot) { return slot->id; } CK_SLOT_INFO *p11prov_slot_get_slot(P11PROV_SLOT *slot) { return &slot->slot; } CK_TOKEN_INFO *p11prov_slot_get_token(P11PROV_SLOT *slot) { return &slot->token; } const char *p11prov_slot_get_login_info(P11PROV_SLOT *slot) { return slot->login_info; } const char *p11prov_slot_get_bad_pin(P11PROV_SLOT *slot) { return slot->bad_pin; } CK_RV p11prov_slot_set_bad_pin(P11PROV_SLOT *slot, const char *bad_pin) { if (slot->bad_pin) { OPENSSL_clear_free(slot->bad_pin, strlen(slot->bad_pin)); } slot->bad_pin = OPENSSL_strdup(bad_pin); if (!slot->bad_pin) { return CKR_HOST_MEMORY; } return CKR_OK; } const char *p11prov_slot_get_cached_pin(P11PROV_SLOT *slot) { return slot->cached_pin; } CK_RV p11prov_slot_set_cached_pin(P11PROV_SLOT *slot, const char *cached_pin) { if (slot->cached_pin) { OPENSSL_clear_free(slot->cached_pin, strlen(slot->cached_pin)); } slot->cached_pin = OPENSSL_strdup(cached_pin); if (!slot->cached_pin) { return CKR_HOST_MEMORY; } return CKR_OK; } P11PROV_SESSION_POOL *p11prov_slot_get_session_pool(P11PROV_SLOT *slot) { return slot->pool; } bool p11prov_slot_check_req_login(P11PROV_SLOT *slot) { return slot->token.flags & CKF_LOGIN_REQUIRED; } CK_SLOT_ID p11prov_get_default_slot(P11PROV_SLOTS_CTX *sctx) { return sctx->default_slot; } pkcs11-provider-1.0/src/slot.h000066400000000000000000000036111475270623700162430ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _SLOT_H #define _SLOT_H /* Slots */ CK_RV p11prov_init_slots(P11PROV_CTX *ctx, P11PROV_SLOTS_CTX **slots); void p11prov_free_slots(P11PROV_SLOTS_CTX *slots); void p11prov_slot_fork_prepare(P11PROV_SLOTS_CTX *sctx); void p11prov_slot_fork_release(P11PROV_SLOTS_CTX *sctx); void p11prov_slot_fork_reset(P11PROV_SLOTS_CTX *sctx); CK_RV p11prov_take_slots(P11PROV_CTX *ctx, P11PROV_SLOTS_CTX **slots); void p11prov_return_slots(P11PROV_SLOTS_CTX *slots); P11PROV_SLOT *p11prov_fetch_slot(P11PROV_SLOTS_CTX *sctx, int *idx); P11PROV_SLOT *p11prov_get_slot_by_id(P11PROV_SLOTS_CTX *sctx, CK_SLOT_ID id); int p11prov_slot_get_mechanisms(P11PROV_SLOT *slot, CK_MECHANISM_TYPE **mechs); int p11prov_check_mechanism(P11PROV_CTX *ctx, CK_SLOT_ID id, CK_MECHANISM_TYPE mechtype); CK_RV p11prov_slot_get_obj_pool(P11PROV_CTX *provctx, CK_SLOT_ID id, P11PROV_OBJ_POOL **pool); typedef bool (*slot_pool_callback)(void *, P11PROV_OBJ_POOL *); CK_RV p11prov_slot_find_obj_pool(P11PROV_CTX *ctx, slot_pool_callback cb, void *cb_ctx); CK_SLOT_ID p11prov_slot_get_slot_id(P11PROV_SLOT *slot); CK_SLOT_INFO *p11prov_slot_get_slot(P11PROV_SLOT *slot); CK_TOKEN_INFO *p11prov_slot_get_token(P11PROV_SLOT *slot); const char *p11prov_slot_get_login_info(P11PROV_SLOT *slot); const char *p11prov_slot_get_bad_pin(P11PROV_SLOT *slot); CK_RV p11prov_slot_set_bad_pin(P11PROV_SLOT *slot, const char *bad_pin); const char *p11prov_slot_get_cached_pin(P11PROV_SLOT *slot); CK_RV p11prov_slot_set_cached_pin(P11PROV_SLOT *slot, const char *cached_pin); P11PROV_SESSION_POOL *p11prov_slot_get_session_pool(P11PROV_SLOT *slot); bool p11prov_slot_check_req_login(P11PROV_SLOT *slot); CK_SLOT_ID p11prov_get_default_slot(P11PROV_SLOTS_CTX *sctx); #endif /* _SLOT_H */ pkcs11-provider-1.0/src/store.c000066400000000000000000000466521475270623700164250ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include #include "store.h" struct p11prov_store_ctx { P11PROV_CTX *provctx; P11PROV_URI *parsed_uri; /* search filters set via params */ int expect; CK_ATTRIBUTE subject; CK_ATTRIBUTE issuer; BIGNUM *serial; char *digest; CK_ATTRIBUTE fingerprint; char *alias; char *properties; char *input_type; P11PROV_SESSION *session; int loaded; /* objects found */ P11PROV_OBJ **objects; int num_objs; int fetched; }; static void p11prov_store_ctx_free(struct p11prov_store_ctx *ctx) { P11PROV_debug("store ctx free (%p)", ctx); if (ctx == NULL) { return; } p11prov_return_session(ctx->session); p11prov_uri_free(ctx->parsed_uri); OPENSSL_free(ctx->subject.pValue); OPENSSL_free(ctx->issuer.pValue); OPENSSL_free(ctx->digest); OPENSSL_free(ctx->fingerprint.pValue); OPENSSL_free(ctx->alias); OPENSSL_free(ctx->properties); OPENSSL_free(ctx->input_type); BN_free(ctx->serial); for (int i = 0; i < ctx->num_objs; i++) { p11prov_obj_free(ctx->objects[i]); } OPENSSL_free(ctx->objects); OPENSSL_clear_free(ctx, sizeof(struct p11prov_store_ctx)); } #define OBJS_ALLOC_SIZE 8 static CK_RV p11prov_store_ctx_add_obj(void *pctx, P11PROV_OBJ *obj) { struct p11prov_store_ctx *ctx = (struct p11prov_store_ctx *)pctx; if ((ctx->num_objs % OBJS_ALLOC_SIZE) == 0) { P11PROV_OBJ **tmp = OPENSSL_realloc(ctx->objects, (ctx->num_objs + OBJS_ALLOC_SIZE) * sizeof(P11PROV_OBJ *)); if (tmp == NULL) { P11PROV_raise(ctx->provctx, CKR_HOST_MEMORY, "Failed to allocate store objects"); p11prov_obj_free(obj); return CKR_HOST_MEMORY; } ctx->objects = tmp; } ctx->objects[ctx->num_objs] = obj; ctx->num_objs += 1; return CKR_OK; } static void store_fetch(struct p11prov_store_ctx *ctx, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) { CK_SLOT_ID slotid = CK_UNAVAILABLE_INFORMATION; CK_SLOT_ID nextid = CK_UNAVAILABLE_INFORMATION; int login_behavior; bool login = false; CK_RV ret; P11PROV_debug("called (store_ctx=%p)", ctx); login_behavior = p11prov_ctx_login_behavior(ctx->provctx); if (ctx->expect == 0 || ctx->expect == OSSL_STORE_INFO_PKEY || login_behavior == PUBKEY_LOGIN_ALWAYS) { login = true; } if ((p11prov_uri_get_class(ctx->parsed_uri) == CKO_PUBLIC_KEY || p11prov_uri_get_class(ctx->parsed_uri) == CKO_CERTIFICATE) && login_behavior != PUBKEY_LOGIN_ALWAYS) { login = false; } /* error stack mark so we can unwind in case of repeat to avoid * returning bogus errors */ p11prov_set_error_mark(ctx->provctx); again: /* cycle through all available slots, * only stack errors, but not block on any of them */ do { nextid = CK_UNAVAILABLE_INFORMATION; /* mark internal loops as well */ p11prov_set_error_mark(ctx->provctx); if (ctx->session != NULL) { p11prov_return_session(ctx->session); ctx->session = NULL; } ret = p11prov_get_session(ctx->provctx, &slotid, &nextid, ctx->parsed_uri, CK_UNAVAILABLE_INFORMATION, pw_cb, pw_cbarg, login, false, &ctx->session); if (ret != CKR_OK) { P11PROV_debug( "Failed to get session to load keys (slotid=%lx, ret=%lx)", slotid, ret); /* some cases may be recoverable in store_load if we get a pin * prompter, but if we already had one, this is it */ if (pw_cb != NULL && ctx->loaded == 0) { ctx->loaded = -1; } p11prov_pop_error_to_mark(ctx->provctx); continue; } ret = p11prov_obj_find(ctx->provctx, ctx->session, slotid, ctx->parsed_uri, p11prov_store_ctx_add_obj, ctx); if (ret != CKR_OK) { P11PROV_raise(ctx->provctx, ret, "Failed to load keys from slot (%ld)", slotid); } else { /* if we got here w/o error at least once, consider it a success */ ctx->loaded = 1; } slotid = nextid; /* unset the mark, leaving errors on the stack */ p11prov_clear_last_error_mark(ctx->provctx); } while (nextid != CK_UNAVAILABLE_INFORMATION); /* Given the variety of tokens, if we found no object at all, and we did * *not* set login required, we retry again, after setting login required. * This accounts for HW that requires a login even for public objects */ if (login == false && ctx->num_objs == 0 && login_behavior != PUBKEY_LOGIN_NEVER) { P11PROV_debug("No object found. Retrying with login (store_ctx=%p)", ctx); slotid = CK_UNAVAILABLE_INFORMATION; ctx->loaded = 0; login = true; goto again; } if (ctx->loaded == 0) { /* if we get here it means we tried all */ ctx->loaded = -1; } if (ctx->num_objs > 0) { /* if there was any error, remove it, as we got success */ p11prov_pop_error_to_mark(ctx->provctx); } else { /* otherwise clear the mark and leave errors on the stack */ p11prov_clear_last_error_mark(ctx->provctx); } } DISPATCH_STORE_FN(open); DISPATCH_STORE_FN(attach); DISPATCH_STORE_FN(load); DISPATCH_STORE_FN(eof); DISPATCH_STORE_FN(close); DISPATCH_STORE_FN(export_object); DISPATCH_STORE_FN(set_ctx_params); DISPATCH_STORE_FN(settable_ctx_params); static void *p11prov_store_open(void *pctx, const char *uri) { struct p11prov_store_ctx *ctx = NULL; P11PROV_CTX *provctx = (P11PROV_CTX *)pctx; CK_RV ret = CKR_CANCEL; P11PROV_debug("object open (%p, %s)", pctx, uri); ret = p11prov_ctx_status(provctx); if (ret != CKR_OK) { return NULL; } ctx = OPENSSL_zalloc(sizeof(struct p11prov_store_ctx)); if (ctx == NULL) { return NULL; } ctx->provctx = provctx; ctx->parsed_uri = p11prov_parse_uri(ctx->provctx, uri); if (ctx->parsed_uri == NULL) { ret = CKR_HOST_MEMORY; goto done; } ret = CKR_OK; done: if (ret != CKR_OK) { p11prov_store_ctx_free(ctx); ctx = NULL; } return ctx; } static void *p11prov_store_attach(void *pctx, OSSL_CORE_BIO *in) { struct p11prov_store_ctx *ctx = (struct p11prov_store_ctx *)pctx; P11PROV_debug("object attach (%p, %p)", ctx, in); return NULL; } static int p11prov_store_load(void *pctx, OSSL_CALLBACK *object_cb, void *object_cbarg, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) { struct p11prov_store_ctx *ctx = (struct p11prov_store_ctx *)pctx; void *reference = NULL; size_t reference_sz; CK_ATTRIBUTE *cert = NULL; P11PROV_OBJ *obj = NULL; OSSL_PARAM params[4]; int object_type; CK_KEY_TYPE type; char *data_type; bool found = false; P11PROV_debug("store load (%p)", ctx); if (ctx->loaded == 0) { store_fetch(ctx, pw_cb, pw_cbarg); } if (ctx->loaded != 1) { return RET_OSSL_ERR; } while (ctx->fetched < ctx->num_objs) { obj = ctx->objects[ctx->fetched]; ctx->fetched++; /* Supported search types in OSSL_STORE_SEARCH(3) */ switch (p11prov_obj_get_class(obj)) { case CKO_CERTIFICATE: if (ctx->subject.type == CKA_SUBJECT) { CK_ATTRIBUTE *subject; /* unfortunately different but equivalent encodings may be * used for the same attributes by different certificate * generation tools, so a simple memcmp is not possible * for the DER encoding of a DN, for example NSs tools use * PRINTABLESTRING for CN while moder openssl use UTF8STRING * ANS1 tags for the encoding of the same attribute */ subject = p11prov_obj_get_attr(obj, CKA_SUBJECT); if (!subject) { /* no match, try next */ continue; } /* TODO: X509_NAME caching for ctx->subject ? */ if (!p11prov_x509_names_are_equal(&ctx->subject, subject)) { /* no match, try next */ continue; } } if (ctx->issuer.type == CKA_ISSUER) { CK_ATTRIBUTE *issuer; issuer = p11prov_obj_get_attr(obj, CKA_ISSUER); if (!issuer) { /* no match, try next */ continue; } /* TODO: X509_NAME caching for ctx->issuer ? */ if (!p11prov_x509_names_are_equal(&ctx->issuer, issuer)) { /* no match, try next */ continue; } } if (ctx->serial) { const unsigned char *val; CK_ATTRIBUTE *serial; ASN1_INTEGER *asn1_serial; BIGNUM *bn_serial; int cmp; serial = p11prov_obj_get_attr(obj, CKA_SERIAL_NUMBER); if (!serial) { continue; } val = serial->pValue; asn1_serial = d2i_ASN1_INTEGER(NULL, &val, serial->ulValueLen); if (!asn1_serial) { continue; } bn_serial = ASN1_INTEGER_to_BN(asn1_serial, NULL); if (!bn_serial) { ASN1_INTEGER_free(asn1_serial); continue; } cmp = BN_ucmp(ctx->serial, bn_serial); ASN1_INTEGER_free(asn1_serial); BN_free(bn_serial); if (cmp != 0) { /* no match, try next */ continue; } } break; case CKO_PUBLIC_KEY: case CKO_PRIVATE_KEY: /* ctx->digest */ /* ctx->fingerprint */ if (ctx->alias) { CK_ATTRIBUTE *label; label = p11prov_obj_get_attr(obj, CKA_LABEL); if (!label || strcmp(ctx->alias, label->pValue) != 0) { /* no match, try next */ continue; } } break; } /* if we get here it means the object matched */ found = true; break; } if (!found) { return RET_OSSL_ERR; } switch (p11prov_obj_get_class(obj)) { case CKO_PUBLIC_KEY: case CKO_PRIVATE_KEY: object_type = OSSL_OBJECT_PKEY; type = p11prov_obj_get_key_type(obj); switch (type) { case CKK_RSA: if (p11prov_obj_is_rsa_pss(obj)) { data_type = (char *)P11PROV_NAME_RSAPSS; } else { data_type = (char *)P11PROV_NAME_RSA; } break; case CKK_EC: data_type = (char *)P11PROV_NAME_EC; break; case CKK_EC_EDWARDS: switch (p11prov_obj_get_key_bit_size(obj)) { case ED448_BIT_SIZE: data_type = (char *)ED448; break; case ED25519_BIT_SIZE: data_type = (char *)ED25519; break; default: return RET_OSSL_ERR; } break; default: return RET_OSSL_ERR; } p11prov_obj_to_store_reference(obj, &reference, &reference_sz); break; case CKO_CERTIFICATE: object_type = OSSL_OBJECT_CERT; data_type = (char *)P11PROV_NAME_CERTIFICATE; cert = p11prov_obj_get_attr(obj, CKA_VALUE); if (cert == NULL) { return RET_OSSL_ERR; } break; default: return RET_OSSL_ERR; } params[0] = OSSL_PARAM_construct_int(OSSL_OBJECT_PARAM_TYPE, &object_type); params[1] = OSSL_PARAM_construct_utf8_string(OSSL_OBJECT_PARAM_DATA_TYPE, data_type, 0); if (reference) { /* giving away the object by reference */ params[2] = OSSL_PARAM_construct_octet_string( OSSL_OBJECT_PARAM_REFERENCE, reference, reference_sz); } else if (cert) { params[2] = OSSL_PARAM_construct_octet_string( OSSL_OBJECT_PARAM_DATA, cert->pValue, cert->ulValueLen); } else { return RET_OSSL_ERR; } params[3] = OSSL_PARAM_construct_end(); return object_cb(params, object_cbarg); } static int p11prov_store_eof(void *pctx) { struct p11prov_store_ctx *ctx = (struct p11prov_store_ctx *)pctx; P11PROV_debug("store eof (%p)", ctx); if (ctx->loaded == -1) { /* error condition nothing more to return */ return 1; } else if (ctx->loaded && ctx->fetched >= ctx->num_objs) { return 1; } return 0; } static int p11prov_store_close(void *pctx) { struct p11prov_store_ctx *ctx = (struct p11prov_store_ctx *)pctx; P11PROV_debug("store close (%p)", ctx); if (ctx == NULL) { return 0; } p11prov_store_ctx_free(ctx); return 1; } static int p11prov_store_export_object(void *loaderctx, const void *reference, size_t reference_sz, OSSL_CALLBACK *cb_fn, void *cb_arg) { P11PROV_CTX *ctx = NULL; P11PROV_OBJ *obj = NULL; P11PROV_debug("store (%p) export object %p, %zu", loaderctx, reference, reference_sz); obj = p11prov_obj_from_reference(reference, reference_sz); if (!obj) { return RET_OSSL_ERR; } ctx = p11prov_obj_get_prov_ctx(obj); if (!ctx) { return RET_OSSL_ERR; } if (p11prov_ctx_allow_export(ctx) & DISALLOW_EXPORT_PUBLIC) { return RET_OSSL_ERR; } /* we can only export public bits, so that's all we do */ return p11prov_obj_export_public_key(obj, CK_UNAVAILABLE_INFORMATION, false, false, cb_fn, cb_arg); } static const OSSL_PARAM *p11prov_store_settable_ctx_params(void *provctx) { static const OSSL_PARAM known_settable_ctx_params[] = { OSSL_PARAM_int(OSSL_STORE_PARAM_EXPECT, NULL), OSSL_PARAM_octet_string(OSSL_STORE_PARAM_SUBJECT, NULL, 0), OSSL_PARAM_octet_string(OSSL_STORE_PARAM_ISSUER, NULL, 0), OSSL_PARAM_BN(OSSL_STORE_PARAM_SERIAL, NULL, 0), OSSL_PARAM_utf8_string(OSSL_STORE_PARAM_DIGEST, NULL, 0), OSSL_PARAM_octet_string(OSSL_STORE_PARAM_FINGERPRINT, NULL, 0), OSSL_PARAM_utf8_string(OSSL_STORE_PARAM_ALIAS, NULL, 0), OSSL_PARAM_utf8_string(OSSL_STORE_PARAM_PROPERTIES, NULL, 0), OSSL_PARAM_utf8_string(OSSL_STORE_PARAM_INPUT_TYPE, NULL, 0), OSSL_PARAM_END, }; return known_settable_ctx_params; } static int p11prov_store_set_ctx_params(void *pctx, const OSSL_PARAM params[]) { struct p11prov_store_ctx *ctx = (struct p11prov_store_ctx *)pctx; const OSSL_PARAM *p; int ret; P11PROV_debug("set ctx params (%p, %p)", ctx, params); if (params == NULL) { return RET_OSSL_OK; } p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_EXPECT); if (p) { ret = OSSL_PARAM_get_int(p, &ctx->expect); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_SUBJECT); if (p) { size_t len = 0; OPENSSL_free(ctx->subject.pValue); ctx->subject.type = CKA_SUBJECT; ctx->subject.pValue = NULL; ret = OSSL_PARAM_get_octet_string(p, &ctx->subject.pValue, 0, &len); if (ret != RET_OSSL_OK) { return ret; } ctx->subject.ulValueLen = len; } p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_ISSUER); if (p) { size_t len = 0; OPENSSL_free(ctx->issuer.pValue); ctx->issuer.type = CKA_ISSUER; ctx->issuer.pValue = NULL; ret = OSSL_PARAM_get_octet_string(p, &ctx->issuer.pValue, 0, &len); if (ret != RET_OSSL_OK) { return ret; } ctx->issuer.ulValueLen = len; } p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_DIGEST); if (p) { OPENSSL_free(ctx->digest); ctx->digest = NULL; ret = OSSL_PARAM_get_utf8_string(p, &ctx->digest, 0); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_FINGERPRINT); if (p) { size_t len = 0; OPENSSL_free(ctx->fingerprint.pValue); ctx->fingerprint.type = CKA_VALUE; ctx->fingerprint.pValue = NULL; ret = OSSL_PARAM_get_octet_string(p, &ctx->fingerprint.pValue, 0, &len); if (ret != RET_OSSL_OK) { return ret; } ctx->fingerprint.ulValueLen = len; } p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_ALIAS); if (p) { OPENSSL_free(ctx->alias); ctx->alias = NULL; ret = OSSL_PARAM_get_utf8_string(p, &ctx->alias, 0); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_PROPERTIES); if (p) { OPENSSL_free(ctx->properties); ctx->properties = NULL; ret = OSSL_PARAM_get_utf8_string(p, &ctx->properties, 0); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_INPUT_TYPE); if (p) { OPENSSL_free(ctx->input_type); ctx->input_type = NULL; ret = OSSL_PARAM_get_utf8_string(p, &ctx->input_type, 0); if (ret != RET_OSSL_OK) { return ret; } } p = OSSL_PARAM_locate_const(params, OSSL_STORE_PARAM_SERIAL); if (p) { BN_free(ctx->serial); ctx->serial = NULL; ret = OSSL_PARAM_get_BN(p, &ctx->serial); if (ret != RET_OSSL_OK) { return ret; } } return RET_OSSL_OK; } int p11prov_store_direct_fetch(void *provctx, const char *uri, OSSL_CALLBACK *object_cb, void *object_cbarg, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg) { int ret = RET_OSSL_OK; p11prov_set_error_mark(provctx); struct p11prov_store_ctx *ctx = NULL; ctx = p11prov_store_open(provctx, uri); if (!ctx) { ret = RET_OSSL_ERR; goto done; } do { int load_ret = p11prov_store_load(ctx, object_cb, object_cbarg, pw_cb, pw_cbarg); if (load_ret != RET_OSSL_OK) { ret = RET_OSSL_ERR; } } while (!p11prov_store_eof(ctx)); done: p11prov_store_ctx_free(ctx); if (ret == RET_OSSL_OK) { p11prov_pop_error_to_mark(provctx); } else { p11prov_clear_last_error_mark(provctx); } return ret; } const OSSL_DISPATCH p11prov_store_functions[] = { DISPATCH_STORE_ELEM(OPEN, open), DISPATCH_STORE_ELEM(ATTACH, attach), DISPATCH_STORE_ELEM(LOAD, load), DISPATCH_STORE_ELEM(EOF, eof), DISPATCH_STORE_ELEM(CLOSE, close), DISPATCH_STORE_ELEM(SET_CTX_PARAMS, set_ctx_params), DISPATCH_STORE_ELEM(SETTABLE_CTX_PARAMS, settable_ctx_params), DISPATCH_STORE_ELEM(EXPORT_OBJECT, export_object), { 0, NULL }, }; pkcs11-provider-1.0/src/store.h000066400000000000000000000012251475270623700164150ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _STORE_H #define _STORE_H #include #define DISPATCH_STORE_FN(name) DECL_DISPATCH_FUNC(store, p11prov_store, name) #define DISPATCH_STORE_ELEM(NAME, name) \ { \ OSSL_FUNC_STORE_##NAME, (void (*)(void))p11prov_store_##name \ } extern const OSSL_DISPATCH p11prov_store_functions[]; int p11prov_store_direct_fetch(void *provctx, const char *uri, OSSL_CALLBACK *object_cb, void *object_cbarg, OSSL_PASSPHRASE_CALLBACK *pw_cb, void *pw_cbarg); #endif /* _STORE_H */ pkcs11-provider-1.0/src/tls.c000066400000000000000000000145301475270623700160610ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include /* NIST EC */ unsigned int p224_group_id = 0x0015; unsigned int p224_secbits = 112; int p224_mintls = TLS1_VERSION; int p224_maxtls = TLS1_2_VERSION; int p224_mindtls = DTLS1_VERSION; int p224_maxdtls = DTLS1_2_VERSION; unsigned int p256_group_id = 0x0017; unsigned int p256_secbits = 128; int p256_mintls = TLS1_VERSION; int p256_maxtls = 0; int p256_mindtls = DTLS1_VERSION; int p256_maxdtls = 0; unsigned int p384_group_id = 0x0018; unsigned int p384_secbits = 192; int p384_mintls = TLS1_VERSION; int p384_maxtls = 0; int p384_mindtls = DTLS1_VERSION; int p384_maxdtls = 0; unsigned int p521_group_id = 0x0019; unsigned int p521_secbits = 256; int p521_mintls = TLS1_VERSION; int p521_maxtls = 0; int p521_mindtls = DTLS1_VERSION; int p521_maxdtls = 0; /* DH */ unsigned int ffdhe2048_group_id = 0x0100; unsigned int ffdhe2048_secbits = 112; int ffdhe2048_mintls = TLS1_3_VERSION; int ffdhe2048_maxtls = 0; int ffdhe2048_mindtls = -1; int ffdhe2048_maxdtls = -1; unsigned int ffdhe3072_group_id = 0x0101; unsigned int ffdhe3072_secbits = 128; int ffdhe3072_mintls = TLS1_3_VERSION; int ffdhe3072_maxtls = 0; int ffdhe3072_mindtls = -1; int ffdhe3072_maxdtls = -1; unsigned int ffdhe4096_group_id = 0x0102; unsigned int ffdhe4096_secbits = 128; int ffdhe4096_mintls = TLS1_3_VERSION; int ffdhe4096_maxtls = 0; int ffdhe4096_mindtls = -1; int ffdhe4096_maxdtls = -1; unsigned int ffdhe6144_group_id = 0x0103; unsigned int ffdhe6144_secbits = 128; int ffdhe6144_mintls = TLS1_3_VERSION; int ffdhe6144_maxtls = 0; int ffdhe6144_mindtls = -1; int ffdhe6144_maxdtls = -1; unsigned int ffdhe8192_group_id = 0x0104; unsigned int ffdhe8192_secbits = 192; int ffdhe8192_mintls = TLS1_3_VERSION; int ffdhe8192_maxtls = 0; int ffdhe8192_mindtls = -1; int ffdhe8192_maxdtls = -1; #define TLS_PARAMS_ENTRY(name, realname, algorithm, group_id, secbits, mintls, \ maxtls, mindtls, maxdtls) \ { \ OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_GROUP_NAME, (void *)name, \ sizeof(name)), \ OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_GROUP_NAME_INTERNAL, \ (void *)realname, sizeof(realname)), \ OSSL_PARAM_utf8_string(OSSL_CAPABILITY_TLS_GROUP_ALG, \ (void *)algorithm, sizeof(algorithm)), \ OSSL_PARAM_uint(OSSL_CAPABILITY_TLS_GROUP_ID, &group_id), \ OSSL_PARAM_uint(OSSL_CAPABILITY_TLS_GROUP_SECURITY_BITS, \ &secbits), \ OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MIN_TLS, &mintls), \ OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MAX_TLS, &maxtls), \ OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MIN_DTLS, &mindtls), \ OSSL_PARAM_int(OSSL_CAPABILITY_TLS_GROUP_MAX_DTLS, &maxdtls), \ OSSL_PARAM_END \ } struct { const char *name; const OSSL_PARAM list[10]; } tls_params[] = { { "secp224r1", TLS_PARAMS_ENTRY("secp224r1", "secp224r1", "EC", p224_group_id, p224_secbits, p224_mintls, p224_maxtls, p224_mindtls, p224_maxdtls), }, /* alias */ { "P-224", TLS_PARAMS_ENTRY("P-224", "secp224r1", "EC", p224_group_id, p224_secbits, p224_mintls, p224_maxtls, p224_mindtls, p224_maxdtls), }, { "secp256r1", TLS_PARAMS_ENTRY("secp256r1", "prime256v1", "EC", p256_group_id, p256_secbits, p256_mintls, p256_maxtls, p256_mindtls, p256_maxdtls), }, /* alias */ { "P-256", TLS_PARAMS_ENTRY("P-256", "prime256v1", "EC", p256_group_id, p256_secbits, p256_mintls, p256_maxtls, p256_mindtls, p256_maxdtls), }, { "secp384r1", TLS_PARAMS_ENTRY("secp384r1", "secp384r1", "EC", p384_group_id, p384_secbits, p384_mintls, p384_maxtls, p384_mindtls, p384_maxdtls), }, /* alias */ { "P-384", TLS_PARAMS_ENTRY("P-384", "secp384r1", "EC", p384_group_id, p384_secbits, p384_mintls, p384_maxtls, p384_mindtls, p384_maxdtls), }, { "secp521r1", TLS_PARAMS_ENTRY("secp521r1", "secp521r1", "EC", p521_group_id, p521_secbits, p521_mintls, p521_maxtls, p521_mindtls, p521_maxdtls), }, /* alias */ { "P-521", TLS_PARAMS_ENTRY("P-521", "secp521r1", "EC", p521_group_id, p521_secbits, p521_mintls, p521_maxtls, p521_mindtls, p521_maxdtls), }, { "ffdhe2048", TLS_PARAMS_ENTRY("ffdhe2048", "ffdhe2048", "DH", ffdhe2048_group_id, ffdhe2048_secbits, ffdhe2048_mintls, ffdhe2048_maxtls, ffdhe2048_mindtls, ffdhe2048_maxdtls), }, { "ffdhe3072", TLS_PARAMS_ENTRY("ffdhe3072", "ffdhe3072", "DH", ffdhe3072_group_id, ffdhe3072_secbits, ffdhe3072_mintls, ffdhe3072_maxtls, ffdhe3072_mindtls, ffdhe3072_maxdtls), }, { "ffdhe4096", TLS_PARAMS_ENTRY("ffdhe4096", "ffdhe4096", "DH", ffdhe4096_group_id, ffdhe4096_secbits, ffdhe4096_mintls, ffdhe4096_maxtls, ffdhe4096_mindtls, ffdhe4096_maxdtls), }, { "ffdhe6144", TLS_PARAMS_ENTRY("ffdhe6144", "ffdhe6144", "DH", ffdhe6144_group_id, ffdhe6144_secbits, ffdhe6144_mintls, ffdhe6144_maxtls, ffdhe6144_mindtls, ffdhe6144_maxdtls), }, { "ffdhe8192", TLS_PARAMS_ENTRY("ffdhe8192", "ffdhe8192", "DH", ffdhe8192_group_id, ffdhe8192_secbits, ffdhe8192_mintls, ffdhe8192_maxtls, ffdhe8192_mindtls, ffdhe8192_maxdtls), }, }; int tls_group_capabilities(OSSL_CALLBACK *cb, void *arg) { for (size_t i = 0; i < sizeof(tls_params) / sizeof(*tls_params); i++) { int ret = cb(tls_params[i].list, arg); if (ret != RET_OSSL_OK) { return ret; } } return RET_OSSL_OK; } pkcs11-provider-1.0/src/util.c000066400000000000000000000777361475270623700162550ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include #include #include #include "platform/endian.h" #include #include CK_RV p11prov_fetch_attributes(P11PROV_CTX *ctx, P11PROV_SESSION *session, CK_OBJECT_HANDLE object, struct fetch_attrs *attrs, unsigned long attrnums) { CK_SESSION_HANDLE sess = p11prov_session_handle(session); CK_ATTRIBUTE q[attrnums]; CK_ATTRIBUTE r[attrnums]; CK_RV ret; for (size_t i = 0; i < attrnums; i++) { P11PROV_debug("Fetching attributes (%d): 0x%08lx", (int)i, attrs[i].attr.type); q[i] = attrs[i].attr; } /* error stack mark so we can avoid returning bogus errors */ p11prov_set_error_mark(ctx); /* try one shot, then fallback to individual calls if that fails */ ret = p11prov_GetAttributeValue(ctx, sess, object, q, attrnums); if (ret == CKR_OK) { unsigned long retrnums = 0; for (size_t i = 0; i < attrnums; i++) { if (q[i].ulValueLen == CK_UNAVAILABLE_INFORMATION) { /* This can't happen according to the algorithm described * in the spec when the call returns CKR_OK. */ ret = CKR_GENERAL_ERROR; P11PROV_raise(ctx, ret, "Failed to get attributes"); goto done; } if (attrs[i].allocate) { /* always allocate one more, so that zero terminated strings * work automatically */ q[i].pValue = OPENSSL_zalloc(q[i].ulValueLen + 1); if (!q[i].pValue) { ret = CKR_HOST_MEMORY; P11PROV_raise(ctx, ret, "Failed to get attributes"); goto done; } /* add to re-request list */ r[retrnums] = q[i]; retrnums++; } /* always return data to caller so memory can be properly freed if * necessary */ attrs[i].attr = q[i]; } if (retrnums > 0) { P11PROV_debug("(Re)Fetching %lu attributes", retrnums); ret = p11prov_GetAttributeValue(ctx, sess, object, r, retrnums); } for (size_t i = 0; i < attrnums; i++) { P11PROV_debug("Attribute| type:0x%08lX value:%p, len:%lu", attrs[i].attr.type, attrs[i].attr.pValue, attrs[i].attr.ulValueLen); } } else if (attrnums > 1 && (ret == CKR_ATTRIBUTE_SENSITIVE || ret == CKR_ATTRIBUTE_TYPE_INVALID)) { P11PROV_debug("Querying attributes one by one"); /* go one by one as this PKCS11 does not have some attributes * and does not handle it gracefully */ for (size_t i = 0; i < attrnums; i++) { if (attrs[i].allocate) { ret = p11prov_GetAttributeValue(ctx, sess, object, &attrs[i].attr, 1); if (ret != CKR_OK) { if (attrs[i].required) { return ret; } } else { attrs[i].attr.pValue = OPENSSL_zalloc(attrs[i].attr.ulValueLen + 1); if (!attrs[i].attr.pValue) { ret = CKR_HOST_MEMORY; P11PROV_raise(ctx, ret, "Failed to get attributes"); goto done; } } } ret = p11prov_GetAttributeValue(ctx, sess, object, &attrs[i].attr, 1); if (ret != CKR_OK) { if (attrs[i].required) { return ret; } else { if (attrs[i].allocate && attrs[i].attr.pValue) { OPENSSL_free(attrs[i].attr.pValue); attrs[i].attr.pValue = NULL; attrs[i].attr.ulValueLen = CK_UNAVAILABLE_INFORMATION; } } } P11PROV_debug("Attribute| type:0x%08lX value:%p, len:%lu", attrs[i].attr.type, attrs[i].attr.pValue, attrs[i].attr.ulValueLen); } ret = CKR_OK; } done: if (ret == CKR_OK) { /* if there was any error, remove it, as we got success */ p11prov_pop_error_to_mark(ctx); } else { /* otherwise clear the mark and leave errors on the stack */ p11prov_clear_last_error_mark(ctx); } return ret; } void p11prov_move_alloc_attrs(struct fetch_attrs *attrs, int num, CK_ATTRIBUTE *ck_attrs, int *ck_num) { int c = *ck_num; for (int i = 0; i < num; i++) { if (attrs[i].allocate && attrs[i].attr.pValue) { ck_attrs[c] = attrs[i].attr; c++; /* clear moved values for good measure */ attrs[i].attr.pValue = NULL; attrs[i].attr.ulValueLen = CK_UNAVAILABLE_INFORMATION; } } *ck_num = c; } void p11prov_fetch_attrs_free(struct fetch_attrs *attrs, int num) { for (int i = 0; i < num; i++) { if (attrs[i].allocate) { OPENSSL_free(attrs[i].attr.pValue); } } } #define ATTR_library_description "library-description" #define ATTR_library_manufacturer "library-manufacturer" #define ATTR_library_version "library-version" #define ATTR_token "token" #define ATTR_manufacturer "manufacturer" #define ATTR_model "model" #define ATTR_serial "serial" #define ATTR_slot_description "slot-description" #define ATTR_slot_id "slot-id" #define ATTR_slot_manufacturer "slot-manufacturer" #define ATTR_id "id" #define ATTR_object "object" #define ATTR_type "type" #define TYPE_data "data" #define TYPE_cert "cert" #define TYPE_public "public" #define TYPE_private "private" #define TYPE_secret_key "secret-key" struct p11prov_uri { /* CK_INFO attributes */ char *library_description; char *library_manufacturer; CK_VERSION library_version; /* CK_TOKEN_INFO attributes */ char *token; char *manufacturer; char *model; char *serial; /* CK_SLOT_INFO attributes */ char *slot_description; CK_SLOT_ID slot_id; char *slot_manufacturer; /* object attributes */ CK_ATTRIBUTE id; CK_ATTRIBUTE object; CK_OBJECT_CLASS type; /* pin */ char *pin; }; static int hex_to_byte(const char *in, unsigned char *byte) { char c[2], s; int i = 0; for (i = 0; i < 2; i++) { s = in[i]; if ('0' <= s && s <= '9') { c[i] = s - '0'; } else if ('a' <= s && s <= 'f') { c[i] = s - 'a' + 10; } else if ('A' <= s && s <= 'F') { c[i] = s - 'A' + 10; } else { return EINVAL; } } *byte = (c[0] << 4) | c[1]; return 0; } static int parse_attr(const char *str, size_t len, uint8_t **output, size_t *outlen) { uint8_t *out; size_t index = 0; int ret; out = OPENSSL_malloc(len + 1); if (out == NULL) { return ENOMEM; } while (*str && len > 0) { if (*str == '%') { char hex[3] = { 0 }; if (len < 3) { ret = EINVAL; goto done; } hex[0] = str[1]; hex[1] = str[2]; ret = hex_to_byte(hex, &out[index]); if (ret != 0) { goto done; } index++; str += 3; len -= 3; } else { out[index] = *str; index++; str++; len--; } } out[index] = '\0'; ret = 0; done: if (ret != 0) { OPENSSL_free(out); } else { *output = out; if (outlen) { *outlen = index; } } return ret; } static int get_pin_file(P11PROV_CTX *ctx, const char *str, size_t len, void **output) { char pin[MAX_PIN_LENGTH + 1]; char *pinfile; char *filename; BIO *fp; int ret; ret = parse_attr(str, len, (uint8_t **)&pinfile, NULL); if (ret != 0) { return ret; } if (strncmp((const char *)pinfile, "file:", 5) == 0) { filename = pinfile + 5; } else if (*pinfile == '|') { ret = EINVAL; goto done; } else { /* missing 'file:' is accepted */ filename = pinfile; } fp = BIO_new_file(filename, "r"); if (fp == NULL) { P11PROV_debug("Failed to get pin from %s", filename); ret = ENOENT; goto done; } ret = BIO_gets(fp, pin, MAX_PIN_LENGTH); if (ret <= 0) { P11PROV_debug("Failed to get pin from %s (%d)", filename, ret); ret = EINVAL; BIO_free(fp); goto done; } BIO_free(fp); /* files may contain newlines, remove any control character at the end */ for (int i = ret - 1; i >= 0; i--) { if (pin[i] == '\n' || pin[i] == '\r') { pin[i] = '\0'; } else { break; } } *output = OPENSSL_strdup(pin); if (*output == NULL) { ret = ENOMEM; goto done; } ret = 0; done: OPENSSL_free(pinfile); return ret; } #define COPY_STRUCT_MEMBER(dst, src, _name) \ if ((src)->_name) { \ (dst)->_name = OPENSSL_strdup((src)->_name); \ if (!(dst)->_name) { \ p11prov_uri_free((dst)); \ return NULL; \ } \ } static void p11prov_uri_free_int(P11PROV_URI *uri) { OPENSSL_free(uri->library_manufacturer); OPENSSL_free(uri->library_description); OPENSSL_free(uri->token); OPENSSL_free(uri->manufacturer); OPENSSL_free(uri->model); OPENSSL_free(uri->serial); OPENSSL_free(uri->slot_description); OPENSSL_free(uri->slot_manufacturer); OPENSSL_free(uri->id.pValue); OPENSSL_free(uri->object.pValue); if (uri->pin) { OPENSSL_clear_free(uri->pin, strlen(uri->pin)); } } static int parse_utf8str(P11PROV_CTX *ctx, const char *str, size_t len, void **output) { CK_UTF8CHAR *outstr; size_t outlen; size_t chklen; int ret; ret = parse_attr(str, len, &outstr, &outlen); if (ret != 0) { return ret; } chklen = strlen((const char *)outstr); if (outlen != chklen) { P11PROV_raise(ctx, CKR_ARGUMENTS_BAD, "Failed to parse [%.*s] as a string", (int)len, str); OPENSSL_free(outstr); return EINVAL; } P11PROV_debug("String [%.*s] -> [%s]", (int)len, str, outstr); *output = outstr; return 0; } static int parse_ck_attribute(P11PROV_CTX *ctx, const char *str, size_t len, void **output) { CK_ATTRIBUTE *cka = (CK_ATTRIBUTE *)output; CK_UTF8CHAR *outstr; size_t outlen; int ret; switch (cka->type) { case CKA_LABEL: ret = parse_utf8str(ctx, str, len, (void **)&outstr); if (ret != 0) { return ret; } cka->pValue = outstr; cka->ulValueLen = strlen((const char *)outstr); break; case CKA_ID: ret = parse_attr(str, len, &outstr, &outlen); if (ret != 0) { P11PROV_raise(ctx, CKR_ARGUMENTS_BAD, "Failed to parse CKA_ID: [%.*s]", (int)len, str); return ret; } cka->pValue = outstr; cka->ulValueLen = outlen; break; default: return EINVAL; } return 0; } static int parse_class(P11PROV_CTX *ctx, const char *str, size_t len, void **output) { CK_OBJECT_CLASS *class = (CK_OBJECT_CLASS *)output; char *typestr; int ret; ret = parse_utf8str(ctx, str, len, (void **)&typestr); if (ret != 0) { return ret; } if (strcmp(typestr, TYPE_data) == 0) { *class = CKO_DATA; } else if (strcmp(typestr, TYPE_cert) == 0) { *class = CKO_CERTIFICATE; } else if (strcmp(typestr, TYPE_public) == 0) { *class = CKO_PUBLIC_KEY; } else if (strcmp(typestr, TYPE_private) == 0) { *class = CKO_PRIVATE_KEY; } else if (strcmp(typestr, TYPE_secret_key) == 0) { *class = CKO_SECRET_KEY; } else { P11PROV_raise(ctx, CKR_ARGUMENTS_BAD, "Unknown object type [%.*s]", (int)len, str); ret = EINVAL; } OPENSSL_free(typestr); return ret; } static int parse_version(P11PROV_CTX *ctx, const char *str, size_t len, void **output) { CK_VERSION *ver = (CK_VERSION *)output; const char *sep; CK_ULONG val; int ret; if (len < 3 || len > 7) { ret = EINVAL; goto done; } sep = strchr(str, '.'); if (!sep) { ret = EINVAL; goto done; } /* major */ ret = parse_ulong(ctx, str, (sep - str), (void **)&val); if (ret != 0) { goto done; } if (val > 255) { ret = EINVAL; goto done; } ver->major = val; /* minor */ sep++; ret = parse_ulong(ctx, sep, len - (sep - str), (void **)&val); if (ret != 0) { goto done; } if (val > 255) { ret = EINVAL; goto done; } ver->minor = val; ret = 0; done: if (ret != 0) { P11PROV_raise(ctx, CKR_ARGUMENTS_BAD, "Value not a version [%.*s]", (int)len, str); } return ret; } int parse_ulong(P11PROV_CTX *ctx, const char *str, size_t len, void **output) { CK_ULONG *val = (CK_ULONG *)output; char *endptr; int ret; errno = 0; endptr = NULL; *val = strtoul(str, &endptr, 10); if (errno != 0) { ret = errno; goto done; } if (endptr != str + len) { ret = EINVAL; goto done; } ret = 0; done: if (ret != 0) { P11PROV_raise(ctx, CKR_ARGUMENTS_BAD, "Invalid numeric value [%.*s]", (int)len, str); } return ret; } #define DECL_ATTR_COMP(u_attr, handler) \ { \ ATTR_##u_attr, sizeof(ATTR_##u_attr) - 1, handler, (void **)&u.u_attr \ } struct uri_components { const char *attr; size_t attrlen; int (*handler)(P11PROV_CTX *, const char *, size_t, void **); void **output; }; P11PROV_URI *p11prov_parse_uri(P11PROV_CTX *ctx, const char *uri) { struct p11prov_uri u = { .type = CK_UNAVAILABLE_INFORMATION, .slot_id = CK_UNAVAILABLE_INFORMATION, .id = { .type = CKA_ID }, .object = { .type = CKA_LABEL }, }; struct uri_components ucmap[] = { DECL_ATTR_COMP(library_description, parse_utf8str), DECL_ATTR_COMP(library_manufacturer, parse_utf8str), DECL_ATTR_COMP(library_version, parse_version), DECL_ATTR_COMP(token, parse_utf8str), DECL_ATTR_COMP(manufacturer, parse_utf8str), DECL_ATTR_COMP(model, parse_utf8str), DECL_ATTR_COMP(serial, parse_utf8str), DECL_ATTR_COMP(slot_description, parse_utf8str), DECL_ATTR_COMP(slot_id, parse_ulong), DECL_ATTR_COMP(slot_manufacturer, parse_utf8str), DECL_ATTR_COMP(id, parse_ck_attribute), DECL_ATTR_COMP(object, parse_ck_attribute), DECL_ATTR_COMP(type, parse_class), { "pin-value", sizeof("pin-value") - 1, parse_utf8str, (void **)&u.pin }, { "pin-source", sizeof("pin-source") - 1, get_pin_file, (void **)&u.pin }, { "object-type", sizeof("object-type") - 1, parse_class, (void **)&u.type }, { NULL, 0, NULL, NULL } }; const char *p, *end; int ret; P11PROV_debug("ctx=%p uri=%s)", ctx, uri); if (strncmp(uri, "pkcs11:", 7) != 0) { return NULL; } p = uri + 7; while (p) { size_t len; end = strpbrk(p, ";?&"); if (end) { len = end - p; } else { len = strlen(p); } for (int i = 0; ucmap[i].attr != NULL; i++) { if (strncmp(p, ucmap[i].attr, ucmap[i].attrlen) == 0 && p[ucmap[i].attrlen] == '=') { p += ucmap[i].attrlen + 1; len -= ucmap[i].attrlen + 1; ret = ucmap[i].handler(ctx, p, len, ucmap[i].output); if (ret != 0) { goto done; } break; } } if (end) { p = end + 1; } else { p = NULL; } } ret = 0; done: if (ret == 0) { struct p11prov_uri *mu; mu = OPENSSL_malloc(sizeof(struct p11prov_uri)); if (mu) { *mu = u; } else { p11prov_uri_free_int(&u); } return mu; } return NULL; } static void byte_to_hex(uint8_t c, char *out, bool bin, int *written) { if (bin || c < '\'' || c == '/' || c == ';' || c == '?' || c > '~') { (void)snprintf(out, 4, "%%%02X", (unsigned int)c); *written = 3; return; } *out = c; *written = 1; } static char *uri_component(const char *name, const char *val, size_t vlen, size_t *clen) { size_t max_size; size_t name_len; size_t val_len = vlen; size_t ci; bool bin = false; char *c; if (!name || !val) { return NULL; } name_len = strlen(name); if (name_len == 2) { /* id */ bin = true; } if (val_len == 0) { val_len = strlen(val); } max_size = name_len + 1 + val_len * 3 + 2; c = OPENSSL_malloc(max_size); if (!c) { return NULL; } memcpy(c, name, name_len); c[name_len] = '='; ci = name_len + 1; for (size_t vi = 0; vi < val_len; vi++) { int inc = 0; byte_to_hex(val[vi], c + ci, bin, &inc); ci += inc; } c[ci] = ';'; c[ci + 1] = '\0'; *clen = ci; return c; } char *p11prov_key_to_uri(P11PROV_CTX *ctx, P11PROV_OBJ *key) { P11PROV_SLOTS_CTX *slots; P11PROV_SLOT *slot; CK_TOKEN_INFO *token; CK_ATTRIBUTE *cka_label; CK_ATTRIBUTE *cka_id; CK_OBJECT_CLASS class; CK_SLOT_ID slot_id; const char *type; char *model = NULL; char *manufacturer = NULL; char *serial = NULL; char *token_label = NULL; char *object = NULL; char *id = NULL; char *uri = NULL; size_t clen = 0; size_t size_hint = 0; CK_RV ret; class = p11prov_obj_get_class(key); slot_id = p11prov_obj_get_slotid(key); cka_id = p11prov_obj_get_attr(key, CKA_ID); cka_label = p11prov_obj_get_attr(key, CKA_LABEL); switch (class) { case CKO_DATA: type = TYPE_data; break; case CKO_CERTIFICATE: type = TYPE_cert; break; case CKO_PUBLIC_KEY: type = TYPE_public; break; case CKO_PRIVATE_KEY: type = TYPE_private; break; case CKO_SECRET_KEY: type = TYPE_secret_key; break; default: return NULL; } ret = p11prov_take_slots(ctx, &slots); if (ret != CKR_OK) { return NULL; } slot = p11prov_get_slot_by_id(slots, slot_id); if (!slot) { goto done; } token = p11prov_slot_get_token(slot); if (token->model[0] != 0) { const char *str = (const char *)token->model; int len = strnlen(str, 16); clen = 0; model = uri_component(ATTR_model, str, len, &clen); size_hint += clen; } if (token->manufacturerID[0] != 0) { const char *str = (const char *)token->manufacturerID; int len = strnlen(str, 32); clen = 0; manufacturer = uri_component(ATTR_manufacturer, str, len, &clen); size_hint += clen; } if (token->serialNumber[0] != 0) { const char *str = (const char *)token->serialNumber; int len = strnlen(str, 16); clen = 0; serial = uri_component(ATTR_serial, str, len, &clen); size_hint += clen; } if (token->label[0] != 0) { const char *str = (const char *)token->label; int len = strnlen(str, 32); clen = 0; token_label = uri_component(ATTR_token, str, len, &clen); size_hint += clen; } if (cka_id && cka_id->ulValueLen > 0) { clen = 0; id = uri_component(ATTR_id, (const char *)cka_id->pValue, cka_id->ulValueLen, &clen); size_hint += clen; } if (cka_label && cka_label->ulValueLen > 0) { clen = 0; object = uri_component(ATTR_object, (const char *)cka_label->pValue, cka_label->ulValueLen, &clen); size_hint += clen; } size_hint += sizeof("pkcs11:") + sizeof("type=") + strlen(type); uri = p11prov_alloc_sprintf( size_hint, "pkcs11:%s%s%s%s%s%stype=%s", model ? model : "", manufacturer ? manufacturer : "", serial ? serial : "", token_label ? token_label : "", id ? id : "", object ? object : "", type); done: OPENSSL_free(model); OPENSSL_free(manufacturer); OPENSSL_free(serial); OPENSSL_free(token_label); OPENSSL_free(id); OPENSSL_free(object); p11prov_return_slots(slots); return uri; } void p11prov_uri_free(P11PROV_URI *uri) { if (uri == NULL) { return; } p11prov_uri_free_int(uri); OPENSSL_clear_free(uri, sizeof(struct p11prov_uri)); } CK_OBJECT_CLASS p11prov_uri_get_class(P11PROV_URI *uri) { return uri->type; } void p11prov_uri_set_class(P11PROV_URI *uri, CK_OBJECT_CLASS class) { uri->type = class; } CK_ATTRIBUTE p11prov_uri_get_id(P11PROV_URI *uri) { return uri->id; } CK_RV p11prov_uri_set_id(P11PROV_URI *uri, CK_ATTRIBUTE *id) { OPENSSL_free(uri->id.pValue); return p11prov_copy_attr(&uri->id, id); } CK_ATTRIBUTE p11prov_uri_get_label(P11PROV_URI *uri) { return uri->object; } CK_RV p11prov_uri_set_label(P11PROV_URI *uri, CK_ATTRIBUTE *label) { OPENSSL_free(uri->object.pValue); return p11prov_copy_attr(&uri->object, label); } char *p11prov_uri_get_serial(P11PROV_URI *uri) { return uri->serial; } char *p11prov_uri_get_pin(P11PROV_URI *uri) { return uri->pin; } CK_SLOT_ID p11prov_uri_get_slot_id(P11PROV_URI *uri) { return uri->slot_id; } void p11prov_uri_set_slot_id(P11PROV_URI *uri, CK_SLOT_ID slot_id) { uri->slot_id = slot_id; } P11PROV_URI *p11prov_copy_uri(P11PROV_URI *uri) { P11PROV_URI *cu; CK_RV rv; cu = OPENSSL_zalloc(sizeof(P11PROV_URI)); if (!cu) { return NULL; } COPY_STRUCT_MEMBER(cu, uri, library_manufacturer) COPY_STRUCT_MEMBER(cu, uri, library_description) COPY_STRUCT_MEMBER(cu, uri, token) COPY_STRUCT_MEMBER(cu, uri, manufacturer) COPY_STRUCT_MEMBER(cu, uri, model) COPY_STRUCT_MEMBER(cu, uri, serial) COPY_STRUCT_MEMBER(cu, uri, slot_description) COPY_STRUCT_MEMBER(cu, uri, slot_manufacturer) COPY_STRUCT_MEMBER(cu, uri, pin) rv = p11prov_copy_attr(&cu->id, &uri->id); if (rv != CKR_OK) { p11prov_uri_free(cu); return NULL; } rv = p11prov_copy_attr(&cu->object, &uri->object); if (rv != CKR_OK) { p11prov_uri_free(cu); return NULL; } cu->library_version = uri->library_version; cu->slot_id = uri->slot_id; cu->type = uri->type; return cu; } CK_RV p11prov_uri_match_token(P11PROV_URI *uri, CK_SLOT_ID slot_id, CK_SLOT_INFO *slot, CK_TOKEN_INFO *token) { if (uri->slot_id != CK_UNAVAILABLE_INFORMATION && uri->slot_id != slot_id) { return CKR_CANCEL; } if (uri->slot_description && strncmp(uri->slot_description, (const char *)slot->slotDescription, 64) != 0) { return CKR_CANCEL; } if (uri->slot_manufacturer && strncmp(uri->slot_manufacturer, (const char *)slot->manufacturerID, 32) != 0) { return CKR_CANCEL; } if (uri->model && strncmp(uri->model, (const char *)token->model, 16) != 0) { return CKR_CANCEL; } if (uri->manufacturer && strncmp(uri->manufacturer, (const char *)token->manufacturerID, 32) != 0) { return CKR_CANCEL; } if (uri->token && strncmp(uri->token, (const char *)token->label, 32) != 0) { return CKR_CANCEL; } if (uri->serial && strncmp(uri->serial, (const char *)token->serialNumber, 16) != 0) { return CKR_CANCEL; } return CKR_OK; } int p11prov_get_pin(P11PROV_CTX *ctx, const char *in, char **out) { if (strncmp(in, "file:", 5) == 0) { return get_pin_file(ctx, in, strlen(in), (void **)out); } *out = OPENSSL_strdup(in); if (!*out) { return ENOMEM; } return 0; } /* Calculates the start time and then nano-sleeps by 'interval' time. * On the first invocation the content of start_time must be 0. * The content of start_time must not be altered outside this function after * the first invocation. * This function does not guarantee each sleep is 'interval' long. * * Returns true if max_wait has not been reached yet. * Returns false on an error or if max_wait is exceeded. */ bool cyclewait_with_timeout(uint64_t max_wait, uint64_t interval, uint64_t *start_time) { #define NANOS_SEC 1000000000 uint64_t current_time; struct timespec ts; int ret; ret = clock_gettime(CLOCK_MONOTONIC, &ts); if (ret != 0) { return false; } current_time = ts.tv_sec * NANOS_SEC + ts.tv_nsec; if (*start_time == 0) { *start_time = current_time; } else { if (current_time > *start_time + max_wait) { return false; } } ts.tv_sec = interval / NANOS_SEC; ts.tv_nsec = interval % NANOS_SEC; ret = nanosleep(&ts, NULL); if (ret != 0 && ret != EINTR) { return false; } return true; } void byteswap_buf(unsigned char *src, unsigned char *dest, size_t len) { #if __BYTE_ORDER == __LITTLE_ENDIAN int s = 0; int e = len - 1; unsigned char sb; unsigned char eb; while (e >= s) { sb = src[s]; eb = src[e]; dest[s] = eb; dest[e] = sb; s++; e--; } #else memmove(dest, src, len); #endif } CK_RV p11prov_copy_attr(CK_ATTRIBUTE *dst, CK_ATTRIBUTE *src) { if (src->ulValueLen) { dst->pValue = OPENSSL_malloc(src->ulValueLen); if (!dst->pValue) { return CKR_HOST_MEMORY; } memcpy(dst->pValue, src->pValue, src->ulValueLen); } else { dst->pValue = NULL; } dst->ulValueLen = src->ulValueLen; dst->type = src->type; return CKR_OK; } bool p11prov_x509_names_are_equal(CK_ATTRIBUTE *a, CK_ATTRIBUTE *b) { const unsigned char *val; X509_NAME *xa; X509_NAME *xb; int cmp; /* d2i function modify the val pointer */ val = a->pValue; xa = d2i_X509_NAME(NULL, &val, a->ulValueLen); if (!xa) { return false; } val = b->pValue; xb = d2i_X509_NAME(NULL, &val, b->ulValueLen); if (!xb) { X509_NAME_free(xa); return false; } cmp = X509_NAME_cmp(xa, xb); X509_NAME_free(xa); X509_NAME_free(xb); return cmp == 0; } char *p11prov_alloc_sprintf(int size_hint, const char *format, ...) { char *buf = NULL; va_list args; int repeat = 1; int ret; again: if (repeat-- < 0) { ret = -1; goto done; } if (size_hint) { buf = OPENSSL_malloc(size_hint); } va_start(args, format); ret = vsnprintf(buf, size_hint, format, args); va_end(args); if (ret >= size_hint) { size_hint = ret + 1; OPENSSL_free(buf); buf = NULL; goto again; } done: if (ret < 0) { OPENSSL_free(buf); buf = NULL; } else if (size_hint > ret + 1) { buf = OPENSSL_realloc(buf, ret + 1); } return buf; } void trim_padded_field(CK_UTF8CHAR *field, ssize_t n) { for (; n > 0 && field[n - 1] == ' '; n--) { field[n - 1] = 0; } } #define MUTEX_RAISE_ERROR(_errstr) \ P11PROV_raise(provctx, ret, "%s %s mutex (errno=%d)", _errstr, obj, err); \ P11PROV_debug("Called from [%s:%d]%s()", file, line, func) CK_RV p11prov_mutex_init(P11PROV_CTX *provctx, pthread_mutex_t *lock, const char *obj, const char *file, int line, const char *func) { CK_RV ret = CKR_OK; int err; err = pthread_mutex_init(lock, NULL); if (err != 0) { err = errno; ret = CKR_CANT_LOCK; MUTEX_RAISE_ERROR("Failed to init"); } return ret; } CK_RV p11prov_mutex_lock(P11PROV_CTX *provctx, pthread_mutex_t *lock, const char *obj, const char *file, int line, const char *func) { CK_RV ret = CKR_OK; int err; err = pthread_mutex_lock(lock); if (err != 0) { err = errno; ret = CKR_CANT_LOCK; MUTEX_RAISE_ERROR("Failed to lock"); } return ret; } CK_RV p11prov_mutex_unlock(P11PROV_CTX *provctx, pthread_mutex_t *lock, const char *obj, const char *file, int line, const char *func) { CK_RV ret = CKR_OK; int err; err = pthread_mutex_unlock(lock); if (err != 0) { err = errno; ret = CKR_CANT_LOCK; MUTEX_RAISE_ERROR("Failed to unlock"); } return ret; } CK_RV p11prov_mutex_destroy(P11PROV_CTX *provctx, pthread_mutex_t *lock, const char *obj, const char *file, int line, const char *func) { CK_RV ret = CKR_OK; int err; err = pthread_mutex_destroy(lock); if (err != 0) { err = errno; ret = CKR_CANT_LOCK; MUTEX_RAISE_ERROR("Failed to destroy"); } return ret; } void p11prov_force_rwlock_reinit(pthread_rwlock_t *lock) { pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER; memcpy(lock, &rwlock, sizeof(rwlock)); } CK_RV p11prov_digest_util(P11PROV_CTX *ctx, const char *digest, const char *properties, data_buffer data[], data_buffer *output) { EVP_MD_CTX *mdctx = NULL; EVP_MD *md = NULL; unsigned char *dgst = NULL; unsigned int dlen = 0; CK_RV rv; int err; if (!data || !output) { rv = CKR_GENERAL_ERROR; P11PROV_raise(ctx, rv, "Invalid function arguments"); return rv; } md = EVP_MD_fetch(p11prov_ctx_get_libctx(ctx), digest, properties); if (!md) { rv = CKR_GENERAL_ERROR; P11PROV_raise(ctx, rv, "Failed to fetch %s digest", digest); goto done; } dlen = EVP_MD_get_size(md); if (dlen == -1) { rv = CKR_GENERAL_ERROR; P11PROV_raise(ctx, rv, "Failed to get %s digest length", digest); goto done; } if (output->data) { if (output->length < dlen) { rv = CKR_GENERAL_ERROR; P11PROV_raise(ctx, rv, "Invalid function arguments"); goto done; } dgst = output->data; } else { dgst = OPENSSL_malloc(dlen); if (!dgst) { rv = CKR_HOST_MEMORY; goto done; } } mdctx = EVP_MD_CTX_new(); if (!mdctx) { rv = CKR_GENERAL_ERROR; P11PROV_raise(ctx, rv, "EVP_MD_CTX_new failed"); goto done; } err = EVP_DigestInit(mdctx, md); if (err != RET_OSSL_OK) { rv = CKR_GENERAL_ERROR; P11PROV_raise(ctx, rv, "EVP_DigestInit failed"); goto done; } for (int i = 0; data[i].data; i++) { err = EVP_DigestUpdate(mdctx, data[i].data, data[i].length); if (err != RET_OSSL_OK) { rv = CKR_GENERAL_ERROR; P11PROV_raise(ctx, rv, "EVP_DigestUpdate(%d) failed", i); goto done; } } err = EVP_DigestFinal(mdctx, dgst, &dlen); if (err != RET_OSSL_OK || dlen == 0) { rv = CKR_GENERAL_ERROR; P11PROV_raise(ctx, rv, "EVP_DigestFinal failed"); goto done; } output->data = dgst; output->length = dlen; rv = CKR_OK; done: if (output->data != dgst) { OPENSSL_free(dgst); } EVP_MD_CTX_free(mdctx); EVP_MD_free(md); return rv; } pkcs11-provider-1.0/src/util.h000066400000000000000000000130151475270623700162360ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _UTIL_H #define _UTIL_H #define CKATTR_ASSIGN(x, _a, _b, _c) \ do { \ x.type = (_a); \ x.pValue = (void *)(_b); \ x.ulValueLen = (_c); \ } while (0) /* Utilities to fetch objects from tokens */ struct fetch_attrs { CK_ATTRIBUTE attr; bool allocate; bool required; }; #define FA_SET_BUF_VAL(x, n, _t, _v, _l, _r) \ do { \ CKATTR_ASSIGN(x[n].attr, _t, _v, _l); \ x[n].allocate = false; \ x[n].required = _r; \ n++; \ } while (0) #define FA_SET_BUF_ALLOC(x, n, _t, _r) \ do { \ CKATTR_ASSIGN(x[n].attr, _t, NULL, 0); \ x[n].allocate = true; \ x[n].required = _r; \ n++; \ } while (0) #define FA_SET_VAR_VAL(x, n, _t, _v, _r) \ do { \ CKATTR_ASSIGN(x[n].attr, _t, (CK_BYTE *)&(_v), sizeof(_v)); \ x[n].allocate = false; \ x[n].required = _r; \ n++; \ } while (0) #define FA_GET_LEN(x, n, _l) (_l) = x[n].attr.ulValueLen CK_RV p11prov_fetch_attributes(P11PROV_CTX *ctx, P11PROV_SESSION *session, CK_OBJECT_HANDLE object, struct fetch_attrs *attrs, unsigned long attrnums); void p11prov_move_alloc_attrs(struct fetch_attrs *attrs, int num, CK_ATTRIBUTE *ck_attrs, int *retnum); void p11prov_fetch_attrs_free(struct fetch_attrs *attrs, int num); #define MAX_PIN_LENGTH 32 int parse_ulong(P11PROV_CTX *ctx, const char *str, size_t len, void **output); P11PROV_URI *p11prov_parse_uri(P11PROV_CTX *ctx, const char *uri); char *p11prov_key_to_uri(P11PROV_CTX *ctx, P11PROV_OBJ *key); void p11prov_uri_free(P11PROV_URI *parsed_uri); CK_OBJECT_CLASS p11prov_uri_get_class(P11PROV_URI *uri); void p11prov_uri_set_class(P11PROV_URI *uri, CK_OBJECT_CLASS class); CK_ATTRIBUTE p11prov_uri_get_id(P11PROV_URI *uri); CK_RV p11prov_uri_set_id(P11PROV_URI *uri, CK_ATTRIBUTE *id); CK_ATTRIBUTE p11prov_uri_get_label(P11PROV_URI *uri); CK_RV p11prov_uri_set_label(P11PROV_URI *uri, CK_ATTRIBUTE *label); char *p11prov_uri_get_serial(P11PROV_URI *uri); char *p11prov_uri_get_pin(P11PROV_URI *uri); CK_SLOT_ID p11prov_uri_get_slot_id(P11PROV_URI *uri); void p11prov_uri_set_slot_id(P11PROV_URI *uri, CK_SLOT_ID slot_id); P11PROV_URI *p11prov_copy_uri(P11PROV_URI *uri); CK_RV p11prov_uri_match_token(P11PROV_URI *uri, CK_SLOT_ID slot_id, CK_SLOT_INFO *slot, CK_TOKEN_INFO *token); int p11prov_get_pin(P11PROV_CTX *ctx, const char *in, char **out); bool cyclewait_with_timeout(uint64_t max_wait, uint64_t interval, uint64_t *start_time); CK_RV p11prov_copy_attr(CK_ATTRIBUTE *dst, CK_ATTRIBUTE *src); bool p11prov_x509_names_are_equal(CK_ATTRIBUTE *a, CK_ATTRIBUTE *b); char *p11prov_alloc_sprintf(int size_hint, const char *format, ...); void trim_padded_field(CK_UTF8CHAR *field, ssize_t n); #define trim(x) trim_padded_field(x, sizeof(x)) CK_RV p11prov_mutex_init(P11PROV_CTX *provctx, pthread_mutex_t *lock, const char *obj, const char *file, int line, const char *func); CK_RV p11prov_mutex_lock(P11PROV_CTX *provctx, pthread_mutex_t *lock, const char *obj, const char *file, int line, const char *func); CK_RV p11prov_mutex_unlock(P11PROV_CTX *provctx, pthread_mutex_t *lock, const char *obj, const char *file, int line, const char *func); CK_RV p11prov_mutex_destroy(P11PROV_CTX *provctx, pthread_mutex_t *lock, const char *obj, const char *file, int line, const char *func); #define MUTEX_INIT(obj) \ p11prov_mutex_init((obj)->provctx, &(obj)->lock, #obj, OPENSSL_FILE, \ OPENSSL_LINE, OPENSSL_FUNC) #define MUTEX_LOCK(obj) \ p11prov_mutex_lock((obj)->provctx, &(obj)->lock, #obj, OPENSSL_FILE, \ OPENSSL_LINE, OPENSSL_FUNC) #define MUTEX_UNLOCK(obj) \ p11prov_mutex_unlock((obj)->provctx, &(obj)->lock, #obj, OPENSSL_FILE, \ OPENSSL_LINE, OPENSSL_FUNC) #define MUTEX_DESTROY(obj) \ p11prov_mutex_destroy((obj)->provctx, &(obj)->lock, #obj, OPENSSL_FILE, \ OPENSSL_LINE, OPENSSL_FUNC) void p11prov_force_rwlock_reinit(pthread_rwlock_t *lock); static inline CK_ULONG constant_equal(CK_ULONG a, CK_ULONG b) { return ((a ^ b) - 1U) >> (sizeof(CK_ULONG) * 8 - 1); } static inline int constant_select_int(CK_ULONG cond, int a, int b) { volatile unsigned int A = (unsigned int)a; volatile unsigned int B = (unsigned int)b; volatile unsigned int mask = -(unsigned int)cond; return (int)((A & mask) | (B & ~mask)); } static inline void constant_select_buf(CK_ULONG cond, CK_ULONG size, unsigned char *dst, unsigned char *a, unsigned char *b) { for (int i = 0; i < size; i++) { volatile unsigned char A = a[i]; volatile unsigned char B = b[i]; volatile unsigned char mask = -(unsigned char)cond; dst[i] = ((A & mask) | (B & ~mask)); } } struct data_buffer { uint8_t *data; size_t length; }; typedef struct data_buffer data_buffer; CK_RV p11prov_digest_util(P11PROV_CTX *provctx, const char *digest, const char *properties, data_buffer data[], data_buffer *output); #endif /* _UTIL_H */ pkcs11-provider-1.0/tests/000077500000000000000000000000001475270623700154635ustar00rootroot00000000000000pkcs11-provider-1.0/tests/README000077700000000000000000000000001475270623700176152README.mdustar00rootroot00000000000000pkcs11-provider-1.0/tests/README.md000066400000000000000000000015311475270623700167420ustar00rootroot00000000000000Tests are currently available for two different software token implementations, NSS's softokn and softhsm (with some limitations). The easiest way to configure things to run manual tests is to simply execute this command from project's root directory: ```bash meson test -C builddir ``` The 'builddir' argument is the name of the build directory, if you built in another directory you'll have to provide the name of the build directory here. This command will create a temporary directory for each token being tested. If you want to manually test some commands against one of the supported software tokens, execute the test suite first and then source the necessary environment variables via: ```bash $ source tests/tmp./testvars ``` Then code can be executed like: ```bash $ openssl pkey -in $ECPUBURI -pubin -pubout -out ecout.pub ``` pkcs11-provider-1.0/tests/ccerts.c000066400000000000000000000037641475270623700171240ustar00rootroot00000000000000/* Copyright (C) 2025 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include "util.h" struct ui_data { bool nopin; }; static int ui_read_string(UI *ui, UI_STRING *uis) { struct ui_data *user_data; const char *pinvalue; enum UI_string_types type; user_data = (struct ui_data *)UI_get0_user_data(ui); if (user_data->nopin) { fprintf(stderr, "Unexpected request for PIN value"); exit(EXIT_FAILURE); } pinvalue = getenv("PINVALUE"); if (!pinvalue) { fprintf(stderr, "PINVALUE not defined\n"); exit(EXIT_FAILURE); } type = UI_get_string_type(uis); switch (type) { case UIT_PROMPT: fprintf(stderr, "Prompt: \"%s\"\n", UI_get0_output_string(uis)); fprintf(stderr, "Returning: %s\n", pinvalue); UI_set_result(ui, uis, pinvalue); return 1; default: fprintf(stderr, "Unexpected UI type: %d\n", (int)type); exit(EXIT_FAILURE); } return 0; } int main(int argc, char *argv[]) { struct ui_data user_data = { 0 }; UI_METHOD *ui_method = NULL; X509 *cert = NULL; if (argc < 2 || argc > 3) { fprintf(stderr, "Usage: %s [certuri] \n", argv[0]); exit(EXIT_FAILURE); } if (argc > 2) { if (strcmp(argv[2], "nopin")) { fprintf(stderr, "Invalid argument: '%s'\n", argv[2]); fprintf(stderr, "Usage: %s [certuri] \n", argv[0]); exit(EXIT_FAILURE); } else { user_data.nopin = true; } } ui_method = UI_create_method("Load cert test"); if (!ui_method) { fprintf(stderr, "Failed to set up UI_METHOD\n"); exit(EXIT_FAILURE); } (void)UI_method_set_reader(ui_method, ui_read_string); cert = load_cert(argv[1], ui_method, &user_data); fprintf(stderr, "Cert load successfully\n"); X509_free(cert); exit(EXIT_SUCCESS); } pkcs11-provider-1.0/tests/cert.json.ecdsa.in000066400000000000000000000044601475270623700210020ustar00rootroot00000000000000, {"server_command": [@CHECKER@"openssl", "s_server", @PROPQ@"-www", "-port", "@PORT@", "-key", "@PRIURI@", "-cert", "@CRTURI@"], "comment": "Run test with @PRIURI@ without certificate verify", "environment": {"PYTHONPATH" : "."}, "server_hostname": "localhost", "server_port": @PORT@, "common_arguments": ["-p", "@PORT@"], "tests" : [ {"name" : "test-tls13-conversation.py"}, {"name" : "test-conversation.py", "arguments" : ["-d"]}, {"name" : "test-ecdsa-sig-flexibility.py", "arguments" : [ "-n", "0", "-e", "connect with ecdsa_brainpoolP256r1tls13_sha256 only", "-e", "connect with ecdsa_brainpoolP384r1tls13_sha384 only", "-e", "connect with ecdsa_brainpoolP512r1tls13_sha512 only", "-x", "connect with sha1+ecdsa only", "-X", "handshake_failure" ], "comment": "Crypto-Policies disable SHA-1. The brainpool is broken in OpenSSL." }, {"name" : "test-signature-algorithms.py", "arguments" : [ "-n", "0", "--ecdsa", "-x", "explicit SHA-1+RSA/ECDSA", "-X", "handshake_failure", "-x", "explicit SHA-1+RSA/ECDSA", "-X", "handshake_failure", "-x", "implicit SHA-1 check", "-X", "handshake_failure" ], "comment": "Crypto-Policies disable SHA-1." }, {"name" : "test-signature-algorithms.py", "arguments" : [ "-n", "0", "--ecdsa", "-g", "secp384r1", "-x", "sanity", "-X", "handshake_failure", "-x", "explicit SHA-256+RSA or ECDSA", "-X", "handshake_failure", "sanity", "explicit SHA-256+RSA or ECDSA" ], "comment": "Incompatible curve should fail" }, {"name" : "test-tls13-ecdsa-support.py", "arguments" : [ "-n", "0", "-x", "Test with ecdsa_secp384r1_sha384", "-X", "handshake_failure", "-x", "Test with ecdsa_secp521r1_sha512", "-X", "handshake_failure", "-x", "Test with ecdsa_brainpoolP256r1tls13_sha256", "-X", "handshake_failure", "-x", "Test with ecdsa_brainpoolP384r1tls13_sha384", "-X", "handshake_failure", "-x", "Test with ecdsa_brainpoolP512r1tls13_sha512", "-X", "handshake_failure" ], "comment": "We have only P-256 key. The brainpool is broken in OpenSSL." } ] } pkcs11-provider-1.0/tests/cert.json.ed25519.in000066400000000000000000000016611475270623700207210ustar00rootroot00000000000000, {"server_command": [@CHECKER@"openssl", "s_server", @PROPQ@"-www", "-port", "@PORT@", "-key", "@PRIURI@", "-cert", "@CRTURI@"], "comment": "Run test with @PRIURI@ without certificate verify", "environment": {"PYTHONPATH" : "."}, "server_hostname": "localhost", "server_port": @PORT@, "common_arguments": ["-p", "@PORT@"], "tests" : [ {"name" : "test-tls13-conversation.py"}, {"name" : "test-conversation.py", "arguments" : ["-d"]}, {"name" : "test-signature-algorithms.py", "arguments" : [ "--ecdsa", "-x", "implicit SHA-1 check", "-X", "handshake_failure", "sanity", "implicit SHA-1 check" ], "comment": "SHA-1 is disabled by crypto policies." }, {"name" : "test-tls13-eddsa.py", "arguments" : ["-x", "ed448 only", "-X", "handshake_failure"], "comment": "We have only ed25519 key." } ] } pkcs11-provider-1.0/tests/cert.json.ed448.in000066400000000000000000000016611475270623700205530ustar00rootroot00000000000000, {"server_command": [@CHECKER@"openssl", "s_server", @PROPQ@"-www", "-port", "@PORT@", "-key", "@PRIURI@", "-cert", "@CRTURI@"], "comment": "Run test with @PRIURI@ without certificate verify", "environment": {"PYTHONPATH" : "."}, "server_hostname": "localhost", "server_port": @PORT@, "common_arguments": ["-p", "@PORT@"], "tests" : [ {"name" : "test-tls13-conversation.py"}, {"name" : "test-conversation.py", "arguments" : ["-d"]}, {"name" : "test-signature-algorithms.py", "arguments" : [ "--ecdsa", "-x", "implicit SHA-1 check", "-X", "handshake_failure", "sanity", "implicit SHA-1 check" ], "comment": "SHA-1 is disabled by crypto policies." }, {"name" : "test-tls13-eddsa.py", "arguments" : ["-x", "ed25519 only", "-X", "handshake_failure"], "comment": "We have only ed448 key." } ] } pkcs11-provider-1.0/tests/cert.json.in000066400000000000000000000017121475270623700177210ustar00rootroot00000000000000[ {"server_command": [@CHECKER@"openssl", "s_server", @PROPQ@"-www", "-port", "@PORT@", "-key", "@PRIURI@", "-cert", "@CRTURI@", "-verify", "1", "-CAfile", "tests/clientX509Cert.pem"], "comment": "Use ANY certificate just to ensure that server tries to authorise a client", "environment": {"PYTHONPATH" : "."}, "server_hostname": "localhost", "server_port": @PORT@, "tests" : [ {"name" : "test-tls13-certificate-verify.py", "arguments" : ["-k", "tests/clientX509Key.pem", "-c", "tests/clientX509Cert.pem", "-s", "@SIGALGS@", "-p", "@PORT@"]}, {"name" : "test-tls13-ecdsa-in-certificate-verify.py", "arguments" : ["-k", "tests/serverECKey.pem", "-c", "tests/serverECCert.pem", "-s", "@SIGALGS@", "-p", "@PORT@"]} ] } pkcs11-provider-1.0/tests/cert.json.rsa.in000066400000000000000000000040631475270623700205070ustar00rootroot00000000000000, {"server_command": [@CHECKER@"openssl", "s_server", @PROPQ@"-www", "-port", "@PORT@", "-key", "@PRIURI@", "-cert", "@CRTURI@"], "comment": "Run test with @PRIURI@ without certificate verify", "environment": {"PYTHONPATH" : "."}, "server_hostname": "localhost", "server_port": @PORT@, "common_arguments": ["-p", "@PORT@"], "tests" : [ {"name" : "test-tls13-conversation.py"}, {"name" : "test-conversation.py", "arguments" : ["-d"]}, {"name" : "test-dhe-rsa-key-exchange-signatures.py", "arguments" : [ "-n", "0", "-x", "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA sha1 signature", "-X", "handshake_failure", "-x", "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA sha224 signature", "-X", "handshake_failure", "-x", "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA sha256 signature", "-X", "handshake_failure", "-x", "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA sha384 signature", "-X", "handshake_failure", "-x", "TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA sha512 signature", "-X", "handshake_failure", "-x", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 sha1 signature", "-X", "handshake_failure", "-x", "TLS_DHE_RSA_WITH_AES_128_CBC_SHA sha1 signature", "-X", "handshake_failure", "-x", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 sha1 signature", "-X", "handshake_failure", "-x", "TLS_DHE_RSA_WITH_AES_256_CBC_SHA sha1 signature", "-X", "handshake_failure" ], "comment": "The 3DES ciphersuites are not enabled. Crypto-Policies disable SHA-1 signatures." }, {"name" : "test-sig-algs.py", "arguments" : [ "-n", "0", "-x", "rsa_pss_pss_sha256 only", "-X", "handshake_failure", "-x", "rsa_pss_pss_sha384 only", "-X", "handshake_failure", "-x", "rsa_pss_pss_sha512 only", "-X", "handshake_failure" ], "comment": "Server has only RSA key here." }, {"name" : "test-tls13-rsa-signatures.py"}, {"name" : "test-tls13-signature-algorithms.py", "arguments" : ["-n", "0"]} ] } pkcs11-provider-1.0/tests/cert.json.rsapss.in000066400000000000000000000016761475270623700212440ustar00rootroot00000000000000, {"server_command": [ @CHECKER@"openssl", "s_server", @PROPQ@"-www", "-port", "@PORT@", "-key", "@PRIURI@", "-cert", "@CRTURI@"], "comment": "Run test with RSA-PSS key without certificate verify", "environment": {"PYTHONPATH" : "."}, "server_hostname": "localhost", "server_port": @PORT@, "common_arguments": ["-p", "@PORT@"], "tests" : [ {"name" : "test-tls13-conversation.py"}, {"name" : "test-tls13-rsapss-signatures.py"}, {"name" : "test-conversation.py", "arguments" : ["-d"]}, {"name" : "test-sig-algs.py", "comment" : "the server has just one certificate installed", "arguments" : [ "-n", "0", "-x", "rsa_pss_rsae_sha256 only", "-x", "rsa_pss_rsae_sha384 only", "-x", "rsa_pss_rsae_sha512 only"] }, {"name" : "test-tls13-signature-algorithms.py", "arguments" : ["-n", "0"]} ] } pkcs11-provider-1.0/tests/explicit_ec.cnf000066400000000000000000000011021475270623700204350ustar00rootroot00000000000000asn1=SEQUENCE:ec_param [ec_param] version=INTEGER:1 fieldID=SEQUENCE:fieldID curve=SEQUENCE:curve base_point=FORMAT:HEX,OCTETSTRING:043981fb5d14d3808971275dea9831573301cba0117bea9ab25ef767e188fb4a659d4693e1d27edb94bead8c345db51799 point_order=INTEGER:0x2fbe975bf5652816348bcaf164dc6772e88e010fa5c95c21 cof=INTEGER:0x04 [fieldID] oid=OID:1.2.840.10045.1.1 p=INTEGER:0x00befa5d6fd594a058d22f2bc4c22009a83685639a85a54d7d [curve] a=FORMAT:HEX,OCTETSTRING:6f54e1bd75f76fb5d11bec084bd18f94e68e9e02db73852a b=FORMAT:HEX,OCTETSTRING:657510e059c61603405486c8a7550ca6530aed3c98a51763 pkcs11-provider-1.0/tests/explicit_ec.key.der000066400000000000000000000004141475270623700212350ustar00rootroot000000000000000‚_TéÛô¸§nØØìBÉ”nÓvÑeÒâ ²0¯0$*†HÎ=¾ú]oÕ” XÒ/+Ä ¨6…cš…¥M}04oTá½u÷oµÑìKє掞Ûs…*euàYÆ@T†È§U ¦S í<˜¥c19û]Ó€‰q']ê˜1W3Ë {êš²^÷gáˆûJeF“áÒ~Û”¾­Œ4]µ™/¾—[õe(4‹ÊñdÜgr莥É\!¡42“ eñЄœ/ú:W_wW§ÈÄ 4äR^±ãhãŠ>{kM<+ÒÈ-ç u>Ç špkcs11-provider-1.0/tests/explicit_ec.pub.der000066400000000000000000000003651475270623700212400ustar00rootroot000000000000000ò0»*†HÎ=0¯0$*†HÎ=¾ú]oÕ” XÒ/+Ä ¨6…cš…¥M}04oTá½u÷oµÑìKє掞Ûs…*euàYÆ@T†È§U ¦S í<˜¥c19û]Ó€‰q']ê˜1W3Ë {êš²^÷gáˆûJeF“áÒ~Û”¾­Œ4]µ™/¾—[õe(4‹ÊñdÜgr莥É\!2“ eñЄœ/ú:W_wW§ÈÄ 4äR^±ãhãŠ>{kM<+ÒÈ-ç u>Ç špkcs11-provider-1.0/tests/fake_dlclose.c000066400000000000000000000003031475270623700202360ustar00rootroot00000000000000/* Copyright (C) 2023 Jakub Jelen SPDX-License-Identifier: Apache-2.0 */ #include extern int dlclose(void *handle); int dlclose(void *handle) { return 0; } pkcs11-provider-1.0/tests/helpers.sh000077500000000000000000000054551475270623700174750ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2022 Simo Sorce # SPDX-License-Identifier: Apache-2.0 : "${TESTBLDDIR=.}" title() { case "$1" in "SECTION") shift 1 echo "########################################" echo "## $*" echo "" ;; "ENDSECTION") echo "" echo " ##" echo "########################################" echo "" ;; "PARA") shift 1 echo "" echo "## $*" if [ -f "${PPDBGFILE}" ]; then echo "[TEST]: $*" >> "${PPDBGFILE}" fi ;; "LINE") shift 1 echo "$*" ;; *) echo "$*" ;; esac } cleanup_server() { echo "killing $1 server" kill -9 -- "$2" } helper_emit=1 ossl() { helper_output="" echo "# r $1" >> "${TMPPDIR}/gdb-commands.txt" echo "$CHECKER openssl $1" # shellcheck disable=SC2086 # this is intentionally split by words __out=$(eval $CHECKER openssl $1) __res=$? if [ "${2:-0}" -eq "$helper_emit" ]; then # shellcheck disable=SC2034 # used externally by caller helper_output="$__out" else echo "$__out" fi return $__res } gen_unsetvars() { grep "^export" "${TMPPDIR}/testvars" \ | sed -e 's/export/unset/' -e 's/=.*$//' \ >> "${TMPPDIR}/unsetvars" } kill_children() { # make sure it is killed before we continue jobs -p | xargs -r kill -9 || true } # macOS uses BSD sed, which expects the argument after -i (with a space after # it!) to be the backup suffix, while GNU sed expects a potential backup suffix # directly after -i and interprets -i as in-place editing with no # backup. # # Use "${sed_inplace[@]}" to make that work transparently by setting it to the # arguments required to achieve in-place editing without backups depending on # the version of sed. if sed --version 2>/dev/null | grep -q 'GNU sed'; then export sed_inplace=("-i") else export sed_inplace=("-i" "") fi # Generate self-signed certificate using OpenSSL # This is useful for the RSA-PSS certificates that can not be generated by # certtool selfsign_cert() { KEY="$1" export CERT="$2" shift 2 export AARGS="$*" TMPCA=${TMPPDIR}/tmpca TMP_OPENSSL_CONF=${OPENSSL_CONF} sed -e "s|^dir .*|dir = ${TMPCA}|" \ "${OPENSSL_CONF}" > "${OPENSSL_CONF}.tmpca" export OPENSSL_CONF=${OPENSSL_CONF}.tmpca mkdir -p "${TMPCA}/newcerts" "${TMPCA}/private" if [ ! -e "${TMPCA}/serial" ]; then echo "01" > "${TMPCA}/serial" fi touch "${TMPCA}/index.txt" title PARA "Generating a new selfsigned certificate for ${KEY}" ossl 'req -batch -noenc -x509 -new -key ${KEY} ${AARGS} -out ${CERT}' echo "$helper_output" OPENSSL_CONF=${TMP_OPENSSL_CONF} } pkcs11-provider-1.0/tests/integration/000077500000000000000000000000001475270623700200065ustar00rootroot00000000000000pkcs11-provider-1.0/tests/integration/bind.sh000077500000000000000000000071661475270623700212730ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2024 Ondrej Moris # SPDX-License-Identifier: Apache-2.0 if [ $# -ne 1 ]; then echo "Usage bind.sh " exit 1 fi # shellcheck disable=SC1091 source "../helpers.sh" TOKENTYPE=$1 # Temporary dir and Token data dir TMPPDIR="/tmp/bind/${TOKENTYPE}" TOKDIR="$TMPPDIR/tokens" if [ -d "${TMPPDIR}" ]; then rm -fr "${TMPPDIR}" fi mkdir -p "${TMPPDIR}" mkdir "${TOKDIR}" PINVALUE="123456" PINFILE="${TMPPDIR}/pinfile.txt" echo ${PINVALUE} > "${PINFILE}" PKCS11_DEBUG_FILE="${TMPPDIR}/pkcs11-bind-test.log" TEST_RESULT=1 token_setup() { title PARA "Token setup" if [ "${TOKENTYPE}" == "softhsm" ]; then # shellcheck disable=SC1091 source "../softhsm-init.sh" export XDG_RUNTIME_DIR=$PWD eval "$(p11-kit server --provider "$P11LIB" "pkcs11:")" test -n "$P11_KIT_SERVER_PID" export P11LIB="/usr/lib64/pkcs11/p11-kit-client.so" elif [ "${TOKENTYPE}" == "softokn" ]; then # shellcheck disable=SC1091 SHARED_EXT=".so" SOFTOKNPATH="/usr/lib64" source "../softokn-init.sh" elif [ "${TOKENTYPE}" == "kryoptic" ]; then # shellcheck disable=SC1091 source "../kryoptic-init.sh" else echo "Unknown token type: $TOKENTYPE" exit 1 fi export PKCS11_PROVIDER_MODULE=$P11LIB ${TOKENCONFIGVARS} ARGS=("--module=${P11LIB}" "--login" "--pin=${PINVALUE}" "--token-label=${TOKENLABEL}") pkcs11-tool "${ARGS[@]}" --keypairgen --key-type rsa:2048 --id '0001' --label localhost-ksk pkcs11-tool "${ARGS[@]}" --keypairgen --key-type rsa:2048 --id '0002' --label localhost-zsk title SECTION "List token content" pkcs11-tool "${ARGS[@]}" -O title ENDSECTION } openssl_setup() { title PARA "OpenSSL setup" sed \ -e "s|\(default = default_sect\)|\1\npkcs11 = pkcs11_sect\n|" \ -e "s|\(\[default_sect\]\)|\[pkcs11_sect\]\n$TOKENOPTIONS\n\1|" \ -e "s|\(\[default_sect\]\)|module = $PKCS11_MODULE\n\1|" \ -e "s|\(\[default_sect\]\)|activate = 1\n\n\1|" \ -e "s|\(\[default_sect\]\)|pkcs11-module-token-pin = file:$PINFILE\n\1|" \ /etc/pki/tls/openssl.cnf >"${TMPPDIR}"/openssl.cnf } bind_setup() { title PARA "Bind setup" cp /var/named/named.localhost "${TMPPDIR}"/localhost } bind_test() { title PARA "Bind test" ( export OPENSSL_CONF=${TMPPDIR}/openssl.cnf export PKCS11_PROVIDER_DEBUG=file:${PKCS11_DEBUG_FILE} title SECTION "Test 1: Extract KSK and ZSK keys from PKCS11 URIs" dnssec-keyfromlabel -a RSASHA256 -l "pkcs11:object=localhost-zsk" -K "$TMPPDIR" localhost dnssec-keyfromlabel -a RSASHA256 -l "pkcs11:object=localhost-ksk" -K "$TMPPDIR" -f KSK localhost for K in "${TMPPDIR}"/*.key; do cat "$K" >>"${TMPPDIR}/localhost" done test -s "${PKCS11_DEBUG_FILE}" title ENDSECTION title SECTION "Test 2: Sign zone" dnssec-signzone -o localhost -K "$TMPPDIR" "${TMPPDIR}/localhost" test -s "${PKCS11_DEBUG_FILE}" title ENDSECTION ) title LINE "PASSED" TEST_RESULT=0 } # shellcheck disable=SC2317 cleanup() { title PARA "Clean-up" if [ "$TEST_RESULT" -ne 0 ]; then for L in ${TMPPDIR}/openssl.cnf $PKCS11_DEBUG_FILE; do if [ -e "$L" ]; then title SECTION "$L" cat "$L" title ENDSECTION fi done fi if [ "${TOKENTYPE}" == "softhsm" ]; then cleanup_server "p11-kit" "$P11_KIT_SERVER_PID" fi } trap "cleanup" EXIT # Setup. token_setup openssl_setup bind_setup # Test. bind_test exit $TEST_RESULT pkcs11-provider-1.0/tests/integration/httpd.sh000077500000000000000000000127061475270623700214760ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2024 Ondrej Moris # SPDX-License-Identifier: Apache-2.0 # shellcheck disable=SC1091 source "../helpers.sh" BASEDIR=$PWD WORKDIR=$(mktemp -d) PIN="123456" PIN_FILE="${WORKDIR}/pin.txt" PKCS11_DEBUG_FILE="${WORKDIR}/pkcs11-httpd-test.log" MOD_SSL_CONF="/etc/httpd/conf.d/ssl.conf" install_dependencies() { title PARA "Install dependencies" dnf install -y --skip-broken \ meson \ p11-kit httpd mod_ssl openssl-devel gnutls-utils nss-tools \ p11-kit-devel opensc softhsm-devel procps-ng \ openssl util-linux } softhsm_token_setup() { title PARA "Softhsm token setup" pushd "$WORKDIR" mkdir ca server openssl req -x509 -sha256 -newkey rsa:2048 -noenc -batch \ -keyout ca/key.pem -out ca/cert.pem openssl req -newkey rsa:2048 -subj '/CN=localhost' -noenc -batch \ -keyout server/key.pem -out server/csr.pem openssl x509 -req -CA ca/cert.pem -CAkey ca/key.pem \ -in server/csr.pem -out server/cert.pem -CAcreateserial chown -R apache:apache "$WORKDIR" usermod -a -G ods apache cp -rnp /var/lib/softhsm/tokens{,.bck} runuser -u apache -- \ softhsm2-util --init-token --free --label softtoken --pin $PIN --so-pin $PIN TOKENURL=$(p11tool --list-token-urls | grep "softtoken") runuser -u apache -- p11tool \ --write \ --load-privkey server/key.pem \ --label httpd \ --id=%01 \ --login \ --set-pin "$PIN" "$TOKENURL" runuser -u apache -- p11tool \ --write \ --load-certificate server/cert.pem \ --label httpd \ --id=%01 \ --login \ --set-pin "$PIN" "$TOKENURL" popd export PKCS11_PROVIDER_MODULE="/usr/lib64/pkcs11/libsofthsm2.so" title SECTION "List token content" p11tool --login --set-pin "$PIN" --list-all "$TOKENURL" title ENDSECTION } pkcs11_provider_setup() { title PARA "Get, compile and install pkcs11-provider" export PKCS11_PROVIDER_DEBUG=file:$PKCS11_DEBUG_FILE if [ "$GITHUB_ACTIONS" == "true" ]; then if [ -z "$PKCS11_MODULE" ]; then echo "ERROR: Missing PKCS11_MODULE variable!" exit 1 fi echo "Skipped (running in Github Actions)" else git clone \ "${GIT_URL:-"https://github.com/latchset/pkcs11-provider.git"}" \ "${WORKDIR}"/pkcs11-provider pushd "$WORKDIR"/pkcs11-provider git checkout "${GIT_REF:-"main"}" meson setup -Dlibdir=/usr/lib64 builddir meson compile -C builddir meson install -C builddir popd export PKCS11_MODULE=/usr/lib64/ossl-modules/pkcs11.so fi test -e "$PKCS11_MODULE" } openssl_setup() { title PARA "OpenSSL setup" echo "$PIN" >"$PIN_FILE" sed \ -e "s|\(default = default_sect\)|\1\npkcs11 = pkcs11_sect\n|" \ -e "s|\(\[default_sect\]\)|\[pkcs11_sect\]\n\1|" \ -e "s|\(\[default_sect\]\)|module = $PKCS11_MODULE\n\1|" \ -e "s|\(\[default_sect\]\)|pkcs11-module-token-pin = file:$PIN_FILE\n\1|" \ -e "s|\(\[default_sect\]\)|activate = 1\n\n\1|" \ /etc/pki/tls/openssl.cnf >"${WORKDIR}"/openssl.cnf title SECTION "openssl.cnf" cat "${WORKDIR}"/openssl.cnf title ENDSECTION } httpd_setup() { title PARAM "Httpd setup" TOKENURL=$(p11tool --list-token-urls | grep "softtoken") KEYURL="$(p11tool --login --set-pin "$PIN" --list-keys "$TOKENURL" \ | grep 'URL:.*object=httpd;type=private' \ | awk '{ print $NF }')?pin-value=$PIN" CERTURL=$(p11tool --list-all-certs "$TOKENURL" \ | grep "URL:.*object=httpd;type=cert" \ | awk '{ print $NF }') cp -p $MOD_SSL_CONF{,.bck} sed -i -e "/^SSLCryptoDevice/d" \ -e "s/^SSLCertificateFile.*\$/SSLCertificateFile \"$CERTURL\"/" \ -e "s/^SSLCertificateKeyFile.*\$/SSLCertificateKeyFile \"$KEYURL\"/" \ $MOD_SSL_CONF # echo 'ServerName localhost:80' >>/etc/httpd/conf/httpd.conf title SECTION "$MOD_SSL_CONF" cat $MOD_SSL_CONF title ENDSECTION } httpd_test() { title PARA "Httpd test" title PARA "Test 1: Start httpd" PKCS11_PROVIDER_DEBUG=file:${PKCS11_DEBUG_FILE}.httpd_start \ OPENSSL_CONF=${WORKDIR}/openssl.cnf httpd -DFOREGROUND & sleep 3 if ! pgrep httpd >/dev/null; then echo "ERROR: Unable to start httpd!" exit 1 fi title PARA "Test 2: Curl connects to httpd over TLS" PKCS11_PROVIDER_DEBUG=file:${PKCS11_DEBUG_FILE}.curl \ curl -v -sS --cacert "${WORKDIR}"/ca/cert.pem https://localhost >/dev/null echo "Test passed" } # shellcheck disable=SC2317 cleanup() { title PARA "Clean-up" for L in "${PKCS11_DEBUG_FILE}".*; do title SECTION "$L" cat "$L" title ENDSECTION done ssl_log="/var/log/httpd/ssl_error_log" if [ -e "$ssl_log" ]; then title SECTION "$ssl_log" cat "$ssl_log" title ENDSECTION fi pushd "$BASEDIR" >/dev/null rm -rf "$WORKDIR" if pgrep httpd >/dev/null; then pkill httpd fi if [ -e "${MOD_SSL_CONF}".bck ]; then mv "${MOD_SSL_CONF}".bck "$MOD_SSL_CONF" fi if [ -e /var/lib/softhsm/tokens.bck ]; then rm -rf /var/lib/softhsm/tokens mv /var/lib/softhsm/tokens.bck /var/lib/softhsm/tokens fi title LINE "Done" } trap "cleanup" EXIT # Setup. install_dependencies softhsm_token_setup pkcs11_provider_setup openssl_setup httpd_setup # Test. httpd_test pkcs11-provider-1.0/tests/integration/libssh.sh000077500000000000000000000051601475270623700216330ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2024 Ondrej Moris # SPDX-License-Identifier: Apache-2.0 # shellcheck disable=SC1091 source "../helpers.sh" BASEDIR=$PWD WORKDIR=$(mktemp -d) PKCS11_DEBUG_FILE="${WORKDIR}/pkcs11-libssh-test.log" install_dependencies() { title PARA "Install dependencies" dnf install -y --skip-broken cmake libcmocka libcmocka-devel softhsm \ nss-tools gnutls-utils p11-kit p11-kit-devel p11-kit-server opensc \ softhsm-devel socket_wrapper nss_wrapper uid_wrapper pam_wrapper \ priv_wrapper openssh-server zlib-devel git meson \ openssl-devel gcc g++ libcmocka-devel } pkcs11_provider_setup() { title PARA "Get, compile and install pkcs11-provider" if [ "$GITHUB_ACTIONS" == "true" ]; then echo "Skipped (running in Github Actions)" if [ -z "$PKCS11_MODULE" ]; then echo "ERROR: Missing PKCS11_MODULE variable!" exit 1 fi else git clone \ "${GIT_URL:-"https://github.com/latchset/pkcs11-provider.git"}" \ "${WORKDIR}"/pkcs11-provider pushd "$WORKDIR"/pkcs11-provider git checkout "${GIT_REF:-"main"}" meson setup -Dlibdir=/usr/lib64 builddir meson compile -C builddir meson install -C builddir popd export PKCS11_MODULE=/usr/lib64/ossl-modules/pkcs11.so fi test -e "$PKCS11_MODULE" } libssh_setup() { title PARA "Clone, setup and build libssh" git clone https://gitlab.com/libssh/libssh-mirror.git \ "${WORKDIR}"/libssh-mirror mkdir "${WORKDIR}"/libssh-mirror/build pushd "${WORKDIR}"/libssh-mirror/build cmake \ -DUNIT_TESTING=ON \ -DCLIENT_TESTING=ON \ -DCMAKE_BUILD_TYPE=Debug \ -DWITH_PKCS11_URI=ON \ -DWITH_PKCS11_PROVIDER=ON \ -DPKCS11_PROVIDER="${PKCS11_MODULE}" .. make -j "$(nproc)" popd } libssh_test() { title PARA "Run libssh pkcs11 tests" pushd "${WORKDIR}"/libssh-mirror/build PKCS11_PROVIDER_DEBUG=file:$PKCS11_DEBUG_FILE ctest \ --output-on-failure -R \ '(torture_auth_pkcs11|torture_pki_rsa_uri|torture_pki_ecdsa_uri)' \ | tee testout.log 2>&1 grep -q "100% tests passed, 0 tests failed out of 3" testout.log test -s "$PKCS11_DEBUG_FILE" echo "Test passed" popd } # shellcheck disable=SC2317 cleanup() { title PARA "Clean-up" title SECTION "$PKCS11_DEBUG_FILE" cat "$PKCS11_DEBUG_FILE" title ENDSECTION pushd "$BASEDIR" >/dev/null rm -rf "$WORKDIR" title LINE "Done" } trap "cleanup" EXIT # Setup. install_dependencies pkcs11_provider_setup libssh_setup # Test. libssh_test pkcs11-provider-1.0/tests/kryoptic-init.sh000077500000000000000000000030241475270623700206260ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2024 Simo Sorce # SPDX-License-Identifier: Apache-2.0 title SECTION "Searching for Kryoptic module" find_kryoptic() { for _lib in "$@" ; do if test -f "$_lib" ; then echo "Using kryoptic path $_lib" P11LIB="$_lib" return fi done echo "skipped: Unable to find kryoptic PKCS#11 library" exit 0 } find_kryoptic \ "${KRYOPTIC}/target/debug/libkryoptic_pkcs11.so" \ "${KRYOPTIC}/target/release/libkryoptic_pkcs11.so" \ /usr/local/lib/kryoptic/libkryoptic_pkcs11so \ /usr/lib64/pkcs11/libkryoptic_pkcs11.so \ /usr/lib/pkcs11/libkryoptic_pkcs11.so \ /usr/lib/x86_64-linux-gnu/kryoptic/libkryoptic_pkcs11.so title LINE "Creating Kyroptic database" # Kryoptic configuration export KRYOPTIC_CONF="${KRYOPTIC_CONF:-$TOKDIR/kryoptic.sql}" export TOKENLABEL="${TOKENLABEL:-Kryoptic Token}" export TOKENLABELURI="${TOKENLABELURI:-Kryoptic%20Token}" # init token pkcs11-tool --module "${P11LIB}" --init-token \ --label "${TOKENLABEL}" --so-pin "${PINVALUE}" 2>&1 # set user pin pkcs11-tool --module "${P11LIB}" --so-pin "${PINVALUE}" \ --login --login-type so --init-pin --pin "${PINVALUE}" 2>&1 export TOKENCONFIGVARS="export KRYOPTIC_CONF=$TOKDIR/kryoptic.sql" export TESTPORT="34000" # Older versions of certtool do not support non-DER encoded CKA_EC_POINT # so set the kryoptic env var to enforce compatibility for the setup phase export KRYOPTIC_EC_POINT_ENCODING="DER" export SUPPORT_ALLOWED_MECHANISMS=1 pkcs11-provider-1.0/tests/kryoptic.nss-init.sh000066400000000000000000000017531475270623700214340ustar00rootroot00000000000000#!/bin/bash -ex # Copyright (C) 2024 Jakub Jelen # SPDX-License-Identifier: Apache-2.0 # export KRYOPTIC_CONF="${TMPPDIR}/kryoptic.conf" cat >"${KRYOPTIC_CONF}" <<_EOF [[slots]] slot = 42 dbtype = "nssdb" dbargs = "configDir='${TOKDIR}' flags='passwordRequired'" description = "Kryoptic Soft Token" _EOF # flags='passwordRequired' is needed for p11tool to do login before the # search for private objects, otherwise the set up fails. # this overrides what we define in the generic init # the NSS DB can not store custom labels export TOKENLABEL="Kryoptic Soft Token" export TOKENLABELURI="Kryoptic%20Soft%20Token" # the rest is the same source "${TESTSSRCDIR}/kryoptic-init.sh" export TOKENCONFIGVARS="export KRYOPTIC_CONF=${TMPPDIR}/kryoptic.conf" export TOKENOPTIONS="${TOKENOPTIONS}\npkcs11-module-quirks = no-allowed-mechanisms" export TESTPORT="36000" # While this works with the default DB, the NSS DB does not support this # attribute export SUPPORT_ALLOWED_MECHANISMS=0 pkcs11-provider-1.0/tests/lsan.supp000066400000000000000000000003501475270623700173270ustar00rootroot00000000000000#leak:p11prov_module_init #leak:p11prov_obj_from_handle # The SoftHSM leaks memory during performing the Ed25519 signatures leak:/usr/lib/softhsm/libsofthsm2.so # and this is the path on Fedora leak:/usr/lib64/pkcs11/libsofthsm2.so pkcs11-provider-1.0/tests/meson.build000066400000000000000000000137301475270623700176310ustar00rootroot00000000000000conf_env = environment({ 'LIBSPATH': meson.project_build_root() / 'src', 'TESTSSRCDIR': meson.current_source_dir(), 'TESTBLDDIR': meson.current_build_dir(), 'SHARED_EXT': shlext, }) if p11_kit.found() # p11-kit-client module doesn't support Windows, so hard-coding .so is fine p11_module_path = p11_kit.get_variable(pkgconfig: 'p11_module_path') p11_client_path = p11_module_path / 'p11-kit-client.so' conf_env.set('P11KITCLIENTPATH', p11_client_path) endif nss_softokn = dependency('nss-softokn', required: false) if not nss_softokn.found() nss_softokn = dependency('nss', required: false) endif softokendir = '' softokensubdir = '' if nss_softokn.found() fs = import('fs') softokendir = nss_softokn.get_variable(pkgconfig: 'libdir') if fs.exists(softokendir / 'libsoftokn3@0@'.format(shlext)) conf_env.set('SOFTOKNPATH', softokendir) elif fs.exists(softokendir / 'nss' / 'libsoftokn3@0@'.format(shlext)) conf_env.set('SOFTOKNPATH', softokendir / 'nss') else warning('Softoken library missing, tests will be skipped!') endif endif if get_option('enable_explicit_EC_test') conf_env.set('ENABLE_EXPLICIT_EC_TEST', '1') endif setup_script=find_program('setup.sh') foreach suite : ['softokn', 'softhsm', 'kryoptic', 'kryoptic.nss'] test( 'setup', setup_script, args: suite, suite: suite, env: conf_env, is_parallel: false, ) endforeach test_env = environment({ 'TEST_PATH': meson.current_source_dir(), 'TESTBLDDIR': meson.current_build_dir(), }) if get_option('enable_explicit_EC_test') test_env.set('ENABLE_EXPLICIT_EC_TEST', '1') endif valgrind = find_program('valgrind', required: false) if valgrind.found() add_test_setup('valgrind', exe_wrapper: [ valgrind, '--num-callers=30', '-q', '--keep-debuginfo=yes', ], env: test_env, timeout_multiplier: 20, ) endif if get_option('b_sanitize') == 'address' preload_libasan = get_option('preload_libasan') if preload_libasan == 'auto' preload_libasan = run_command( [cc.cmd_array()[0], '-print-file-name=libasan.so'], check: true, capture: true, ).stdout().strip() endif # Avoids closing dlopened libraries for ASan to be able to print usable traces fake_dlclose = shared_library( 'fake_dlclose', 'fake_dlclose.c', name_prefix: '', ) test_env.set('ASAN_OPTIONS', 'fast_unwind_on_malloc=0:detect_leaks=1') test_env.set('LSAN_OPTIONS', 'suppressions=@0@/lsan.supp'.format(meson.current_source_dir())) test_env.set('FAKE_DLCLOSE', fake_dlclose.full_path()) preload_env_var = 'LD_PRELOAD' if host_machine.system() == 'darwin' preload_env_var = 'DYLD_INSERT_LIBRARIES' endif # LD_PRELOAD is needed before invoking openssl as it is not instrumented with # asan and asan needs to be loaded as a first dynamic library of the process. if preload_libasan != 'no' test_env.set('CHECKER', 'env @0@=@1@:@2@'.format(preload_env_var, preload_libasan, fake_dlclose.full_path())) else test_env.set('CHECKER', 'env @0@=@1@'.format(preload_env_var, fake_dlclose.full_path())) endif endif test_programs = { 'tsession': ['tsession.c'], 'tgenkey': ['tgenkey.c', 'util.c'], 'tlsctx': ['tlsctx.c', 'util.c'], 'tlssetkey': ['tlssetkey.c', 'util.c'], 'tdigests': ['tdigests.c'], 'treadkeys': ['treadkeys.c'], 'tcmpkeys': ['tcmpkeys.c', 'util.c'], 'tfork': ['tfork.c', 'util.c'], 'tpkey': ['tpkey.c', 'util.c'], 'pincache': ['pincache.c'], 'ccerts': ['ccerts.c', 'util.c'], } test_executables = [] foreach t, sources : test_programs t = executable(t, sources, build_by_default: false, include_directories: [configinc], dependencies: [libcrypto, libssl]) test_executables += [t] endforeach tests = { 'basic': {'suites': ['softokn', 'softhsm', 'kryoptic', 'kryoptic.nss']}, 'pubkey': {'suites': ['softokn', 'softhsm', 'kryoptic', 'kryoptic.nss']}, 'certs': {'suites': ['softokn', 'softhsm', 'kryoptic', 'kryoptic.nss']}, 'ecc': {'suites': ['softokn', 'softhsm', 'kryoptic', 'kryoptic.nss']}, 'edwards': {'suites': ['softhsm', 'kryoptic', 'kryoptic.nss']}, 'ecdh': {'suites': ['softokn', 'kryoptic', 'kryoptic.nss']}, 'democa': {'suites': ['softokn', 'softhsm', 'kryoptic', 'kryoptic.nss'], 'is_parallel': false}, 'digest': {'suites': ['softokn', 'softhsm', 'kryoptic', 'kryoptic.nss']}, 'fork': {'suites': ['softokn', 'softhsm', 'kryoptic', 'kryoptic.nss']}, 'oaepsha2': {'suites': ['softokn', 'kryoptic', 'kryoptic.nss']}, 'hkdf': {'suites': ['softokn', 'kryoptic', 'kryoptic.nss']}, 'imported' : {'suites': ['softokn', 'kryoptic', 'kryoptic.nss']}, 'rsapss': {'suites': ['softokn', 'softhsm', 'kryoptic', 'kryoptic.nss']}, 'rsapssam': {'suites': ['softhsm', 'kryoptic']}, 'genkey': {'suites': ['softokn', 'softhsm', 'kryoptic', 'kryoptic.nss']}, 'pkey': {'suites': ['softokn', 'softhsm', 'kryoptic', 'kryoptic.nss']}, 'session': {'suites': ['softokn', 'softhsm', 'kryoptic', 'kryoptic.nss']}, 'rand': {'suites': ['softokn', 'softhsm', 'kryoptic', 'kryoptic.nss']}, 'readkeys': {'suites': ['softokn', 'softhsm', 'kryoptic', 'kryoptic.nss']}, 'tls': {'suites': ['softokn', 'softhsm', 'kryoptic', 'kryoptic.nss'], 'is_parallel': false, 'timeout': 60}, 'tlsfuzzer': {'suites': ['softokn', 'softhsm', 'kryoptic', 'kryoptic.nss'], 'timeout': 90}, 'uri': {'suites': ['softokn', 'softhsm', 'kryoptic', 'kryoptic.nss'], 'timeout': 90}, 'ecxc': {'suites': ['softhsm', 'kryoptic', 'kryoptic.nss']}, 'cms': {'suites': ['softokn', 'kryoptic', 'kryoptic.nss']}, 'pinlock': {'suites': ['kryoptic']}, } test_wrapper = find_program('test-wrapper') foreach t, extra_args : tests is_parallel = extra_args.get('is_parallel', true) timeout = extra_args.get('timeout', 30) foreach suite : extra_args.get('suites', []) test( t, test_wrapper, args: '@0@-@1@.t'.format(t, suite), suite: suite, env: test_env, depends: test_executables, is_parallel: false, timeout: timeout, ) endforeach endforeach pkcs11-provider-1.0/tests/openssl.cnf.in000066400000000000000000000100371475270623700202440ustar00rootroot00000000000000HOME = . # Use this in order to automatically load providers. openssl_conf = openssl_init config_diagnostics = 1 [openssl_init] providers = provider_sect #MORECONF [provider_sect] default = default_sect pkcs11 = pkcs11_sect base = base_sect [base_sect] activate = 1 [default_sect] activate = 1 [pkcs11_sect] module = @libtoollibs@/pkcs11@SHARED_EXT@ pkcs11-module-token-pin = file:@PINFILE@ ##TOKENOPTIONS #pkcs11-module-encode-provider-uri-to-pem #pkcs11-module-allow-export #pkcs11-module-load-behavior #pkcs11-module-block-operations activate = 1 #################################################################### [ req ] default_bits = 2048 default_md = sha256 #default_keyfile = privkey.pem distinguished_name = req_distinguished_name attributes = req_attributes x509_extensions = v3_ca # The extensions to add to the self signed cert string_mask = utf8only req_extensions = v3_req # The extensions to add to a certificate request [ req_distinguished_name ] countryName = Country Name (2 letter code) countryName_default = US countryName_min = 2 countryName_max = 2 stateOrProvinceName = State or Province Name (full name) stateOrProvinceName_default = New York localityName = Locality Name (eg, city) localityName_default = New York 0.organizationName = Organization Name (eg, company) 0.organizationName_default = PKCS11 Provider organizationalUnitName = Organizational Unit Name (eg, section) organizationalUnitName_default = Testing Harness commonName = Common Name (eg, your name or your server\'s hostname) commonName_max = 64 emailAddress = Email Address emailAddress_max = 64 [ req_attributes ] challengePassword = A challenge password challengePassword_min = 4 challengePassword_max = 20 unstructuredName = An optional company name [ v3_req ] # Extensions to add to a certificate request basicConstraints = CA:FALSE keyUsage = nonRepudiation, digitalSignature, keyEncipherment [ v3_ca ] # Extensions for a typical CA # PKIX recommendation. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid:always,issuer basicConstraints = critical,CA:true # Key usage: this is typical for a CA certificate. However since it will # prevent it being used as an test self-signed certificate it is best # left out by default. # keyUsage = cRLSign, keyCertSign # Include email address in subject alt name: another PKIX recommendation subjectAltName=email:copy # Copy issuer details issuerAltName=issuer:copy [ ca ] default_ca = CA_default # The default ca section [ CA_default ] dir = @testsdir@/demoCA # Where everything is kept certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. unique_subject = no # Set to 'no' to allow creation of # several certs with same subject. new_certs_dir = $dir/newcerts # default place for new certs. certificate = $dir/cacert.pem # The CA certificate serial = $dir/serial # The current serial number crlnumber = $dir/crlnumber # the current crl number # must be commented out to leave a V1 CRL crl = $dir/crl.pem # The current CRL #private_key = $dir/private/cakey.pem# The private key x509_extensions = usr_cert # The extensions to add to the cert default_days = 365 # how long to certify for default_crl_days= 30 # how long before next CRL default_md = sha256 # use SHA-256 by default preserve = no # keep passed DN ordering policy = policy_anything # For the 'anything' policy # At this point in time, you must list all acceptable 'object' # types. [ policy_anything ] countryName = optional stateOrProvinceName = optional localityName = optional organizationName = optional organizationalUnitName = optional commonName = supplied emailAddress = optional [ usr_cert ] # These extensions are added when 'ca' signs a request. basicConstraints=CA:FALSE # This is typical in keyUsage for a client certificate. keyUsage = nonRepudiation, digitalSignature, keyEncipherment # PKIX recommendations harmless if included in all certificates. subjectKeyIdentifier=hash authorityKeyIdentifier=keyid,issuer pkcs11-provider-1.0/tests/pincache.c000066400000000000000000000101751475270623700174050ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #define PRINTERR(...) \ do { \ fprintf(stderr, __VA_ARGS__); \ fflush(stderr); \ } while (0) #define PRINTERROSSL(...) \ do { \ fprintf(stderr, __VA_ARGS__); \ ERR_print_errors_fp(stderr); \ fflush(stderr); \ } while (0) static void sign_op(EVP_PKEY *key) { size_t size = EVP_PKEY_get_size(key); unsigned char sig[size]; const char *data = "Sign Me!"; EVP_MD_CTX *sign_md; int ret; sign_md = EVP_MD_CTX_new(); ret = EVP_DigestSignInit_ex(sign_md, NULL, "SHA256", NULL, NULL, key, NULL); if (ret != 1) { PRINTERROSSL("Failed to init EVP_DigestSign\n"); exit(EXIT_FAILURE); } ret = EVP_DigestSignUpdate(sign_md, data, sizeof(data)); if (ret != 1) { PRINTERROSSL("Failed to EVP_DigestSignUpdate\n"); exit(EXIT_FAILURE); } ret = EVP_DigestSignFinal(sign_md, sig, &size); if (ret != 1) { PRINTERROSSL("Failed to EVP_DigestSignFinal-ize\n"); exit(EXIT_FAILURE); } EVP_MD_CTX_free(sign_md); } static int ui_read_string(UI *ui, UI_STRING *uis) { const char *pinvalue; enum UI_string_types type; pinvalue = getenv("PINVALUE"); if (!pinvalue) { fprintf(stderr, "PINVALUE not defined\n"); exit(EXIT_FAILURE); } type = UI_get_string_type(uis); switch (type) { case UIT_PROMPT: fprintf(stderr, "Prompt: \"%s\"\n", UI_get0_output_string(uis)); fprintf(stderr, "Returning: %s\n", pinvalue); UI_set_result(ui, uis, pinvalue); return 1; default: fprintf(stderr, "Unexpected UI type: %d\n", (int)type); exit(EXIT_FAILURE); } return 0; } int main(int argc, char *argv[]) { const char *keyuri = NULL; UI_METHOD *ui_method = NULL; OSSL_STORE_CTX *store; OSSL_STORE_INFO *info; EVP_PKEY *key = NULL; pid_t pid; int status; keyuri = getenv("PRIURI"); /* optional first argument is a PKCS#11 uri of the key to test. * Default is provided by environment variable BASEURI */ if (argc > 1) { keyuri = argv[1]; } if (!keyuri) { fprintf(stderr, "PRIURI not defined\n"); exit(EXIT_FAILURE); } ui_method = UI_create_method("Pin Cache Test"); if (!ui_method) { fprintf(stderr, "Failed to set up UI_METHOD\n"); exit(EXIT_FAILURE); } (void)UI_method_set_reader(ui_method, ui_read_string); store = OSSL_STORE_open_ex(keyuri, NULL, "provider=pkcs11", ui_method, NULL, NULL, NULL, NULL); if (store == NULL) { fprintf(stderr, "Failed to open pkcs11 store\n"); exit(EXIT_FAILURE); } for (info = OSSL_STORE_load(store); info != NULL; info = OSSL_STORE_load(store)) { int type = OSSL_STORE_INFO_get_type(info); switch (type) { case OSSL_STORE_INFO_PKEY: key = OSSL_STORE_INFO_get1_PKEY(info); break; default: fprintf(stderr, "Invalid data from store\n"); exit(EXIT_FAILURE); } OSSL_STORE_INFO_free(info); } OSSL_STORE_close(store); if (!key) { fprintf(stderr, "Failed to find key\n"); exit(EXIT_FAILURE); } /* now fork (this forces re-login) and see if operations * succeed in the child */ pid = fork(); if (pid == -1) { PRINTERR("Fork failed\n"); exit(EXIT_FAILURE); } if (pid == 0) { sign_op(key); EVP_PKEY_free(key); UI_destroy_method(ui_method); PRINTERR("Child Done\n"); exit(EXIT_SUCCESS); } waitpid(pid, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { PRINTERR("Child failure\n"); exit(EXIT_FAILURE); } EVP_PKEY_free(key); UI_destroy_method(ui_method); PRINTERR("ALL A-OK!\n"); exit(EXIT_SUCCESS); } pkcs11-provider-1.0/tests/setup.sh000077500000000000000000000503731475270623700171720ustar00rootroot00000000000000#!/bin/bash -ex # Copyright (C) 2024 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" if [ $# -ne 1 ]; then echo "Usage setup.sh " exit 1 fi TOKENTYPE=$1 # defaults -- overridden below or in the per-token setup SUPPORT_ED25519=1 SUPPORT_ED448=1 SUPPORT_RSA_PKCS1_ENCRYPTION=1 SUPPORT_RSA_KEYGEN_PUBLIC_EXPONENT=1 SUPPORT_TLSFUZZER=1 SUPPORT_ALLOWED_MECHANISMS=0 # Ed448 requires OpenSC 0.26.0 OPENSC_VERSION=$(opensc-tool -i | grep OpenSC | sed -e "s/OpenSC 0\.\([0-9]*\).*/\1/") if [[ "$OPENSC_VERSION" -le "25" ]]; then SUPPORT_ED448=0 fi # FIPS Mode if [[ "${OPENSSL_FORCE_FIPS_MODE}" = "1" || "$(cat /proc/sys/crypto/fips_enabled)" = "1" ]]; then # We can not use Edwards curves in FIPS mode SUPPORT_ED25519=0 SUPPORT_ED448=0 # The FIPS does not allow the RSA-PKCS1.5 encryption SUPPORT_RSA_PKCS1_ENCRYPTION=0 # The FIPS does not allow to set custom public exponent during key # generation SUPPORT_RSA_KEYGEN_PUBLIC_EXPONENT=0 # TLS Fuzzer does not work well in FIPS mode SUPPORT_TLSFUZZER=0 # We also need additional configuration in openssl.cnf to assume the token # is FIPS token TOKENOPTIONS="pkcs11-module-assume-fips = true" fi # Temporary dir and Token data dir TMPPDIR="${TESTBLDDIR}/${TOKENTYPE}" TOKDIR="$TMPPDIR/tokens" if [ -d "${TMPPDIR}" ]; then rm -fr "${TMPPDIR}" fi mkdir "${TMPPDIR}" mkdir "${TOKDIR}" PINVALUE="12345678" PINFILE="${TMPPDIR}/pinfile.txt" echo ${PINVALUE} > "${PINFILE}" export GNUTLS_PIN=$PINVALUE if [ "${TOKENTYPE}" == "softhsm" ]; then source "${TESTSSRCDIR}/softhsm-init.sh" elif [ "${TOKENTYPE}" == "softokn" ]; then source "${TESTSSRCDIR}/softokn-init.sh" elif [ "${TOKENTYPE}" == "kryoptic" ]; then source "${TESTSSRCDIR}/kryoptic-init.sh" elif [ "${TOKENTYPE}" == "kryoptic.nss" ]; then source "${TESTSSRCDIR}/kryoptic.nss-init.sh" else echo "Unknown token type: $1" exit 1 fi #RANDOM data SEEDFILE="${TMPPDIR}/noisefile.bin" dd if=/dev/urandom of="${SEEDFILE}" bs=2048 count=1 >/dev/null 2>&1 RAND64FILE="${TMPPDIR}/64krandom.bin" dd if=/dev/urandom of="${RAND64FILE}" bs=2048 count=32 >/dev/null 2>&1 # On macOS, /usr/bin/certtool is a different program. Both MacPorts and # Homebrew rename GnuTLS' certtool to gnutls-certtool, so check for that first. # # https://github.com/macports/macports-ports/blob/4494b720a4807ddfc18bddf876620a5c6b24ce4f/devel/gnutls/Portfile#L206-L209 # https://github.com/Homebrew/homebrew-core/blob/83be349adb47980b4046258b74fa8c1e99ca96a3/Formula/gnutls.rb#L56-L58 if [ "$(uname)" == "Darwin" ]; then certtool=$(type -p gnutls-certtool) else certtool=$(type -p certtool) fi if [ -z "$certtool" ]; then echo "Missing GnuTLS certtool (on macOS, commonly installed as gnutls-certtool)" exit 0 fi # NSS uses the second slot for certificates, so we need to provide the token # label in the args to allow pkcs11-tool to find the right slot P11DEFARGS=("--module=${P11LIB}" "--login" "--pin=${PINVALUE}" "--token-label=${TOKENLABEL}") # prepare certtool configuration cat >> "${TMPPDIR}/cacert.cfg" <&1 pkcs11-tool "${P11DEFARGS[@]}" --write-object "${TMPPDIR}/${LABEL}.crt" --type=cert \ --id="$KEYID" --label="$LABEL" 2>&1 } title LINE "Creating new Self Sign CA" KEYID='0000' URIKEYID="%00%00" CACRTN="caCert" pkcs11-tool "${P11DEFARGS[@]}" --keypairgen --key-type="RSA:2048" \ --label="${CACRTN}" --id="${KEYID}" 2>&1 crt_selfsign $CACRTN "Issuer" $KEYID # convert the DER cert to PEM CACRT_PEM="${TMPPDIR}/${CACRTN}.pem" CACRT="${TMPPDIR}/${CACRTN}.crt" openssl x509 -inform DER -in "$CACRT" -outform PEM -out "$CACRT_PEM" CABASEURIWITHPINVALUE="pkcs11:id=${URIKEYID}?pin-value=${PINVALUE}" CABASEURIWITHPINSOURCE="pkcs11:id=${URIKEYID}?pin-source=file:${PINFILE}" CABASEURI="pkcs11:id=${URIKEYID}" CAPUBURI="pkcs11:type=public;id=${URIKEYID}" CAPRIURI="pkcs11:type=private;id=${URIKEYID}" CACRTURI="pkcs11:type=cert;object=${CACRTN}" title LINE "RSA PKCS11 URIS" echo "${CABASEURIWITHPINVALUE}" echo "${CABASEURIWITHPINSOURCE}" echo "${CABASEURI}" echo "${CAPUBURI}" echo "${CAPRIURI}" echo "${CACRTURI}" echo "" cat "${TMPPDIR}/cacert.cfg" > "${TMPPDIR}/cert.cfg" # the organization identification is not in the CA echo 'organization = "PKCS11 Provider"' >> "${TMPPDIR}/cert.cfg" # the cert_signing_key and "ca" should be only on the CA sed -e "/^cert_signing_key$/d" -e "/^ca$/d" "${sed_inplace[@]}" "${TMPPDIR}/cert.cfg" ca_sign() { LABEL=$1 CN=$2 KEYID=$3 shift 3 ((SERIAL+=1)) sed -e "s|cn = .*|cn = $CN|g" \ -e "s|serial = .*|serial = $SERIAL|g" \ -e "/^ca$/d" \ "${sed_inplace[@]}" \ "${TMPPDIR}/cert.cfg" "${certtool}" --generate-certificate --outfile="${TMPPDIR}/${LABEL}.crt" \ --template="${TMPPDIR}/cert.cfg" --provider="$P11LIB" \ --load-privkey "pkcs11:object=$LABEL;token=$TOKENLABELURI;type=private" \ --load-pubkey "pkcs11:object=$LABEL;token=$TOKENLABELURI;type=public" --outder \ --load-ca-certificate "${CACRT}" --inder \ --load-ca-privkey="pkcs11:object=$CACRTN;token=$TOKENLABELURI;type=private" \ "$@" pkcs11-tool "${P11DEFARGS[@]}" --write-object "${TMPPDIR}/${LABEL}.crt" --type=cert \ --id="$KEYID" --label="$LABEL" 2>&1 } # generate RSA key pair and self-signed certificate KEYID='0001' URIKEYID="%00%01" TSTCRTN="testCert" pkcs11-tool "${P11DEFARGS[@]}" --keypairgen --key-type="RSA:2048" \ --label="${TSTCRTN}" --id="$KEYID" ca_sign "${TSTCRTN}" "My Test Cert" $KEYID BASEURIWITHPINVALUE="pkcs11:id=${URIKEYID}?pin-value=${PINVALUE}" BASEURIWITHPINSOURCE="pkcs11:id=${URIKEYID}?pin-source=file:${PINFILE}" BASEURI="pkcs11:id=${URIKEYID}" PUBURI="pkcs11:type=public;id=${URIKEYID}" PRIURI="pkcs11:type=private;id=${URIKEYID}" CRTURI="pkcs11:type=cert;object=${TSTCRTN}" title LINE "RSA PKCS11 URIS" echo "${BASEURIWITHPINVALUE}" echo "${BASEURIWITHPINSOURCE}" echo "${BASEURI}" echo "${PUBURI}" echo "${PRIURI}" echo "${CRTURI}" echo "" # generate ECC key pair KEYID='0002' URIKEYID="%00%02" ECCRTN="ecCert" pkcs11-tool "${P11DEFARGS[@]}" --keypairgen --key-type="EC:secp256r1" \ --label="${ECCRTN}" --id="$KEYID" ca_sign $ECCRTN "My EC Cert" $KEYID ECBASEURIWITHPINVALUE="pkcs11:id=${URIKEYID}?pin-value=${PINVALUE}" ECBASEURIWITHPINSOURCE="pkcs11:id=${URIKEYID}?pin-source=file:${PINFILE}" ECBASEURI="pkcs11:id=${URIKEYID}" ECPUBURI="pkcs11:type=public;id=${URIKEYID}" ECPRIURI="pkcs11:type=private;id=${URIKEYID}" ECCRTURI="pkcs11:type=cert;object=${ECCRTN}" KEYID='0003' URIKEYID="%00%03" ECPEERCRTN="ecPeerCert" pkcs11-tool "${P11DEFARGS[@]}" --keypairgen --key-type="EC:secp256r1" \ --label="$ECPEERCRTN" --id="$KEYID" crt_selfsign $ECPEERCRTN "My Peer EC Cert" $KEYID ECPEERBASEURIWITHPINVALUE="pkcs11:id=${URIKEYID}?pin-value=${PINVALUE}" ECPEERBASEURIWITHPINSOURCE="pkcs11:id=${URIKEYID}?pin-source=file:${PINFILE}" ECPEERBASEURI="pkcs11:id=${URIKEYID}" ECPEERPUBURI="pkcs11:type=public;id=${URIKEYID}" ECPEERPRIURI="pkcs11:type=private;id=${URIKEYID}" ECPEERCRTURI="pkcs11:type=cert;object=${ECPEERCRTN}" title LINE "EC PKCS11 URIS" echo "${ECBASEURIWITHPINVALUE}" echo "${ECBASEURIWITHPINSOURCE}" echo "${ECBASEURI}" echo "${ECPUBURI}" echo "${ECPRIURI}" echo "${ECCRTURI}" echo "${ECPEERBASEURIWITHPINVALUE}" echo "${ECPEERBASEURIWITHPINSOURCE}" echo "${ECPEERBASEURI}" echo "${ECPEERPUBURI}" echo "${ECPEERPRIURI}" echo "${ECPEERCRTURI}" echo "" ## Softtokn does not support edwards curves yet if [ "${SUPPORT_ED25519}" -eq 1 ]; then # generate ED25519 KEYID='0004' URIKEYID="%00%04" EDCRTN="edCert" pkcs11-tool "${P11DEFARGS[@]}" --keypairgen --key-type="EC:edwards25519" \ --label="${EDCRTN}" --id="$KEYID" ca_sign $EDCRTN "My ED25519 Cert" $KEYID EDBASEURIWITHPINVALUE="pkcs11:id=${URIKEYID};pin-value=${PINVALUE}" EDBASEURIWITHPINSOURCE="pkcs11:id=${URIKEYID};pin-source=file:${PINFILE}" EDBASEURI="pkcs11:id=${URIKEYID}" EDPUBURI="pkcs11:type=public;id=${URIKEYID}" EDPRIURI="pkcs11:type=private;id=${URIKEYID}" EDCRTURI="pkcs11:type=cert;object=${EDCRTN}" title LINE "ED25519 PKCS11 URIS" echo "${EDBASEURIWITHPINVALUE}" echo "${EDBASEURIWITHPINSOURCE}" echo "${EDBASEURI}" echo "${EDPUBURI}" echo "${EDPRIURI}" echo "${EDCRTURI}" fi if [ "${SUPPORT_ED448}" -eq 1 ]; then # generate ED448 KEYID='0009' URIKEYID="%00%09" ED2CRTN="ed2Cert" pkcs11-tool "${P11DEFARGS[@]}" --keypairgen --key-type="EC:Ed448" \ --label="${ED2CRTN}" --id="$KEYID" ca_sign $ED2CRTN "My ED448 Cert" $KEYID ED2BASEURIWITHPINVALUE="pkcs11:id=${URIKEYID};pin-value=${PINVALUE}" ED2BASEURIWITHPINSOURCE="pkcs11:id=${URIKEYID};pin-source=file:${PINFILE}" ED2BASEURI="pkcs11:id=${URIKEYID}" ED2PUBURI="pkcs11:type=public;id=${URIKEYID}" ED2PRIURI="pkcs11:type=private;id=${URIKEYID}" ED2CRTURI="pkcs11:type=cert;object=${ED2CRTN}" title LINE "ED448 PKCS11 URIS" echo "${ED2BASEURIWITHPINVALUE}" echo "${ED2BASEURIWITHPINSOURCE}" echo "${ED2BASEURI}" echo "${ED2PUBURI}" echo "${ED2PRIURI}" echo "${ED2CRTURI}" fi title PARA "generate RSA key pair, self-signed certificate, remove public key" KEYID='0005' URIKEYID="%00%05" TSTCRTN="testCert2" pkcs11-tool "${P11DEFARGS[@]}" --keypairgen --key-type="RSA:2048" \ --label="${TSTCRTN}" --id="$KEYID" ca_sign $TSTCRTN "My Test Cert 2" $KEYID pkcs11-tool "${P11DEFARGS[@]}" --delete-object --type pubkey --id 0005 BASE2URIWITHPINVALUE="pkcs11:id=${URIKEYID}?pin-value=${PINVALUE}" BASE2URIWITHPINSOURCE="pkcs11:id=${URIKEYID}?pin-source=${PINFILE}" BASE2URI="pkcs11:id=${URIKEYID}" PRI2URI="pkcs11:type=private;id=${URIKEYID}" CRT2URI="pkcs11:type=cert;object=${TSTCRTN}" title LINE "RSA2 PKCS11 URIS" echo "${BASE2URIWITHPINVALUE}" echo "${BASE2URIWITHPINSOURCE}" echo "${BASE2URI}" echo "${PRI2URI}" echo "${CRT2URI}" echo "" title PARA "generate EC key pair, self-signed certificate, remove public key" KEYID='0006' URIKEYID="%00%06" TSTCRTN="ecCert2" pkcs11-tool "${P11DEFARGS[@]}" --keypairgen --key-type="EC:secp384r1" \ --label="${TSTCRTN}" --id="$KEYID" ca_sign $TSTCRTN "My EC Cert 2" $KEYID pkcs11-tool "${P11DEFARGS[@]}" --delete-object --type pubkey --id 0006 ECBASE2URIWITHPINVALUE="pkcs11:id=${URIKEYID}?pin-value=${PINVALUE}" ECBASE2URIWITHPINSOURCE="pkcs11:id=${URIKEYID}?pin-source=file${PINFILE}" ECBASE2URI="pkcs11:id=${URIKEYID}" ECPRI2URI="pkcs11:type=private;id=${URIKEYID}" ECCRT2URI="pkcs11:type=cert;object=${TSTCRTN}" title LINE "EC2 PKCS11 URIS" echo "${ECBASE2URIWITHPINVALUE}" echo "${ECBASE2URIWITHPINSOURCE}" echo "${ECBASE2URI}" echo "${ECPRI2URI}" echo "${ECCRT2URI}" echo "" if [ -z "${ENABLE_EXPLICIT_EC_TEST}" ]; then title PARA "explicit EC unsupported" elif [ "${TOKENTYPE}" == "softokn" ]; then title PARA "explicit EC unsupported with softokn" else title PARA "generate explicit EC key pair" KEYID='0007' URIKEYID="%00%07" ECXCRTN="ecExplicitCert" pkcs11-tool "${P11DEFARGS[@]}" --write-object="${TESTSSRCDIR}/explicit_ec.key.der" --type=privkey \ --label="${ECXCRTN}" --id="$KEYID" pkcs11-tool "${P11DEFARGS[@]}" --write-object="${TESTSSRCDIR}/explicit_ec.pub.der" --type=pubkey \ --label="${ECXCRTN}" --id="$KEYID" ECXBASEURIWITHPINVALUE="pkcs11:id=${URIKEYID}?pin-value=${PINVALUE}" ECXBASEURIWITHPINSOURCE="pkcs11:id=${URIKEYID}?pin-source=file:${PINFILE}" ECXBASEURI="pkcs11:id=${URIKEYID}" ECXPUBURI="pkcs11:type=public;id=${URIKEYID}" ECXPRIURI="pkcs11:type=private;id=${URIKEYID}" title LINE "EXPLICIT EC PKCS11 URIS" echo "${ECXBASEURI}" echo "${ECXPUBURI}" echo "${ECXPRIURI}" echo "" fi title PARA "generate EC key pair with ALWAYS AUTHENTICATE flag, self-signed certificate" KEYID='0008' URIKEYID="%00%08" TSTCRTN="ecCert3" pkcs11-tool "${P11DEFARGS[@]}" --keypairgen --key-type="EC:secp521r1" \ --label="${TSTCRTN}" --id="$KEYID" --always-auth ca_sign $TSTCRTN "My EC Cert 3" $KEYID ECBASE3URIWITHPINVALUE="pkcs11:id=${URIKEYID}?pin-value=${PINVALUE}" ECBASE3URIWITHPINSOURCE="pkcs11:id=${URIKEYID}?pin-source=file:${PINFILE}" ECBASE3URI="pkcs11:id=${URIKEYID}" ECPUB3URI="pkcs11:type=public;id=${URIKEYID}" ECPRI3URI="pkcs11:type=private;id=${URIKEYID}" ECCRT3URI="pkcs11:type=cert;object=${TSTCRTN}" title LINE "EC3 PKCS11 URIS" echo "${ECBASE3URIWITHPINVALUE}" echo "${ECBASE3URIWITHPINSOURCE}" echo "${ECBASE3URI}" echo "${ECPUB3URI}" echo "${ECPRI3URI}" echo "${ECCRT3URI}" echo "" if [ "${SUPPORT_ALLOWED_MECHANISMS}" -eq 1 ]; then # generate unrestricted RSA-PSS key pair and self-signed RSA-PSS certificate KEYID='0010' URIKEYID="%00%10" TSTCRTN="testRsaPssCert" pkcs11-tool "${P11DEFARGS[@]}" --keypairgen --key-type="RSA:2048" \ --label="${TSTCRTN}" --id="$KEYID" --allowed-mechanisms \ RSA-PKCS-PSS,SHA1-RSA-PKCS-PSS,SHA224-RSA-PKCS-PSS,SHA256-RSA-PKCS-PSS,SHA384-RSA-PKCS-PSS,SHA512-RSA-PKCS-PSS ca_sign "${TSTCRTN}" "My RsaPss Cert" $KEYID "--sign-params=RSA-PSS" RSAPSSBASEURIWITHPINVALUE="pkcs11:id=${URIKEYID}?pin-value=${PINVALUE}" RSAPSSBASEURIWITHPINSOURCE="pkcs11:id=${URIKEYID}?pin-source=file:${PINFILE}" RSAPSSBASEURI="pkcs11:id=${URIKEYID}" RSAPSSPUBURI="pkcs11:type=public;id=${URIKEYID}" RSAPSSPRIURI="pkcs11:type=private;id=${URIKEYID}" RSAPSSCRTURI="pkcs11:type=cert;object=${TSTCRTN}" title LINE "RSA-PSS PKCS11 URIS" echo "${RSAPSSBASEURIWITHPINVALUE}" echo "${RSAPSSBASEURIWITHPINSOURCE}" echo "${RSAPSSBASEURI}" echo "${RSAPSSPUBURI}" echo "${RSAPSSPRIURI}" echo "${RSAPSSCRTURI}" echo "" # generate RSA-PSS (3k) key pair restricted to SHA256 digests # and self-signed RSA-PSS certificate KEYID='0011' URIKEYID="%00%11" TSTCRTN="testRsaPss2Cert" pkcs11-tool "${P11DEFARGS[@]}" --keypairgen --key-type="RSA:3092" \ --label="${TSTCRTN}" --id="$KEYID" --allowed-mechanisms \ SHA256-RSA-PKCS-PSS ca_sign "${TSTCRTN}" "My RsaPss2 Cert" $KEYID \ "--sign-params=RSA-PSS" "--hash=SHA256" RSAPSS2BASEURIWITHPINVALUE="pkcs11:id=${URIKEYID}?pin-value=${PINVALUE}" RSAPSS2BASEURIWITHPINSOURCE="pkcs11:id=${URIKEYID}?pin-source=file:${PINFILE}" RSAPSS2BASEURI="pkcs11:id=${URIKEYID}" RSAPSS2PUBURI="pkcs11:type=public;id=${URIKEYID}" RSAPSS2PRIURI="pkcs11:type=private;id=${URIKEYID}" RSAPSS2CRTURI="pkcs11:type=cert;object=${TSTCRTN}" title LINE "RSA-PSS 2 PKCS11 URIS" echo "${RSAPSS2BASEURIWITHPINVALUE}" echo "${RSAPSS2BASEURIWITHPINSOURCE}" echo "${RSAPSS2BASEURI}" echo "${RSAPSS2PUBURI}" echo "${RSAPSS2PRIURI}" echo "${RSAPSS2CRTURI}" echo "" fi title PARA "Show contents of ${TOKENTYPE} token" echo " ----------------------------------------------------------------------------------------------------" pkcs11-tool "${P11DEFARGS[@]}" -O echo " ----------------------------------------------------------------------------------------------------" title PARA "Output configurations" OPENSSL_CONF=${TMPPDIR}/openssl.cnf title LINE "Generate openssl config file" sed -e "s|@libtoollibs@|${LIBSPATH}|g" \ -e "s|@testsblddir@|${TESTBLDDIR}|g" \ -e "s|@testsdir@|${TMPPDIR}|g" \ -e "s|@SHARED_EXT@|${SHARED_EXT}|g" \ -e "s|@PINFILE@|${PINFILE}|g" \ -e "s|##TOKENOPTIONS|${TOKENOPTIONS}|g" \ "${TESTSSRCDIR}/openssl.cnf.in" > "${OPENSSL_CONF}" title LINE "Export test variables to ${TMPPDIR}/testvars" cat >> "${TMPPDIR}/testvars" <> "${TMPPDIR}/testvars" <> "${TMPPDIR}/testvars" <> "${TMPPDIR}/testvars" <> "${TMPPDIR}/testvars" <> "${TMPPDIR}/testvars" < # SPDX-License-Identifier: Apache-2.0 title SECTION "Searching for SoftHSM PKCS#11 library" if ! command -v softhsm2-util &> /dev/null then echo "SoftHSM is is required" exit 0 fi find_softhsm() { for _lib in "$@" ; do if test -f "$_lib" ; then echo "Using softhsm path $_lib" P11LIB="$_lib" return fi done echo "skipped: Unable to find softhsm PKCS#11 library" exit 0 } # Attempt to guess the path to libsofthsm2.so relative to that. This fixes # auto-detection on platforms such as macOS with MacPorts (and potentially # Homebrew). # # This should never be empty, since we checked for the presence of # softhsm2-util above and use it below. # Strip bin/softhsm2-util softhsm_prefix=$(dirname "$(dirname "$(type -p softhsm2-util)")") find_softhsm \ "$softhsm_prefix/lib64/softhsm/libsofthsm2.so" \ "$softhsm_prefix/lib/softhsm/libsofthsm2.so" \ "$softhsm_prefix/lib64/pkcs11/libsofthsm2.so" \ "$softhsm_prefix/lib/pkcs11/libsofthsm2.so" \ /usr/local/lib/softhsm/libsofthsm2.so \ /usr/lib64/pkcs11/libsofthsm2.so \ /usr/lib/pkcs11/libsofthsm2.so \ /usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so export P11LIB title SECTION "Set up testing system" # Create SoftHSM configuration file cat >"$TMPPDIR/softhsm.conf" < # SPDX-License-Identifier: Apache-2.0 title SECTION "Setup NSS Softokn" if ! command -v certutil &> /dev/null then echo "NSS's certutil command is required" exit 0 fi title LINE "Creating new NSS Database" certutil -N -d "${TOKDIR}" -f "${PINFILE}" export P11LIB="${SOFTOKNPATH%%/}/libsoftokn3${SHARED_EXT}" export NSS_LIB_PARAMS="configDir=${TOKDIR}" export TOKENLABEL="NSS Certificate DB" export TOKENLABELURI="NSS%20Certificate%20DB" export TOKENOPTIONS="${TOKENOPTIONS}\npkcs11-module-quirks = no-operation-state no-allowed-mechanisms" export TOKENCONFIGVARS="export NSS_LIB_PARAMS=configDir=${TOKDIR}" export TESTPORT="30000" # Edward curves are not supported in NSS yet export SUPPORT_ED25519=0 export SUPPORT_ED448=0 pkcs11-provider-1.0/tests/tbasic000077500000000000000000000301011475270623700166510ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2022 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" title PARA "Raw Sign check error" dd if=/dev/urandom of="${TMPPDIR}/64Brandom.bin" bs=64 count=1 >/dev/null 2>&1 FAIL=0 ossl ' pkeyutl -sign -inkey "${BASEURI}" -pkeyopt pad-mode:none -in ${TMPPDIR}/64Brandom.bin -out ${TMPPDIR}/raw-sig.bin' || FAIL=1 if [ $FAIL -eq 0 ]; then echo "Raw signature should not allow data != modulus size" exit 1 fi # unfortunately pkeyutl simply does not make it possible to sign anything # that is bigger than a hash, which means we'd need a very small RSA key # to really check a raw signature through pkeyutl title PARA "Sign and Verify with provided Hash and RSA" ossl 'dgst -sha256 -binary -out ${TMPPDIR}/sha256.bin ${SEEDFILE}' ossl ' pkeyutl -sign -inkey "${PRIURI}" -in ${TMPPDIR}/sha256.bin -out ${TMPPDIR}/sha256-sig.bin' ossl ' pkeyutl -verify -inkey "${PUBURI}" -pubin -in ${TMPPDIR}/sha256.bin -sigfile ${TMPPDIR}/sha256-sig.bin' title PARA "Sign and Verify with provided Hash and RSA with DigestInfo struct" ossl 'dgst -sha256 -binary -out ${TMPPDIR}/sha256.bin ${SEEDFILE}' ossl ' pkeyutl -sign -inkey "${PRIURI}" -pkeyopt digest:sha256 -in ${TMPPDIR}/sha256.bin -out ${TMPPDIR}/sha256-sig.bin' ossl ' pkeyutl -verify -inkey "${PUBURI}" -pkeyopt digest:sha256 -pubin -in ${TMPPDIR}/sha256.bin -sigfile ${TMPPDIR}/sha256-sig.bin' title PARA "DigestSign and DigestVerify with RSA" ossl ' pkeyutl -sign -inkey "${BASEURI}" -digest sha256 -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha256-dgstsig.bin' ossl ' pkeyutl -verify -inkey "${BASEURI}" -pubin -digest sha256 -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha256-dgstsig.bin' ossl ' pkeyutl -verify -inkey "${PUBURI}" -pubin -digest sha256 -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha256-dgstsig.bin' if [[ "$SUPPORT_RSA_PKCS1_ENCRYPTION" = "1" ]]; then SECRETFILE=${TMPPDIR}/rsasecret.txt echo "Super Secret" > "${SECRETFILE}" title LINE "RSA basic encrypt and decrypt" ossl ' pkeyutl -encrypt -inkey "${PUBURI}" -pubin -in ${SECRETFILE} -out ${SECRETFILE}.enc' ossl ' pkeyutl -decrypt -inkey "${PRIURI}" -in ${SECRETFILE}.enc -out ${SECRETFILE}.dec' diff "${SECRETFILE}" "${SECRETFILE}.dec" fi title PARA "Test Disallow Public Export" ORIG_OPENSSL_CONF=${OPENSSL_CONF} sed "s/#pkcs11-module-allow-export/pkcs11-module-allow-export = 1/" "${OPENSSL_CONF}" > "${OPENSSL_CONF}.noexport" OPENSSL_CONF=${OPENSSL_CONF}.noexport ossl 'pkey -in $PUBURI -pubin -pubout -text' "$helper_emit" output="$helper_output" FAIL=0 echo "$output" | grep "^PKCS11 RSA Public Key (2048 bits)" > /dev/null 2>&1 || FAIL=1 if [ $FAIL -ne 0 ]; then echo "$output" | grep "PUBLIC KEY" > /dev/null 2>&1 || FAIL=2 fi if [ $FAIL -eq 1 ]; then echo "pkcs11 pem export failed" fi if [ $FAIL -eq 2 ]; then echo "pkcs11 pem export succeeded but internal encoder was not used" fi if [ $FAIL -ne 0 ]; then echo echo "Original command output:" echo "$output" echo exit 1 fi OPENSSL_CONF=${ORIG_OPENSSL_CONF} title PARA "Test CSR generation from RSA private keys" ossl ' req -new -batch -key "${PRIURI}" -out ${TMPPDIR}/rsa_csr.pem' ossl ' req -in ${TMPPDIR}/rsa_csr.pem -verify -noout' title PARA "Test fetching public keys without PIN in config files" ORIG_OPENSSL_CONF=${OPENSSL_CONF} sed "s/^pkcs11-module-token-pin.*$/##nopin/" "${OPENSSL_CONF}" > "${OPENSSL_CONF}.nopin" OPENSSL_CONF=${OPENSSL_CONF}.nopin ossl 'pkey -in $PUBURI -pubin -pubout -out ${TMPPDIR}/rsa.pub.nopin.pem' ossl 'pkey -in $ECPUBURI -pubin -pubout -out ${TMPPDIR}/ec.pub.nopin.pem' [[ -n $ECXPUBURI ]] && ossl 'pkey -in $ECXPUBURI -pubin -pubout -out ${TMPPDIR}/ecx.pub.nopin.pem' [[ -n $EDPUBURI ]] && ossl 'pkey -in $EDPUBURI -pubin -pubout -out ${TMPPDIR}/ed.pub.nopin.pem' title PARA "Test fetching public keys with a PIN in URI" ossl 'pkey -in $BASEURIWITHPINVALUE -pubin -pubout -out ${TMPPDIR}/rsa.pub.uripin.pem' ossl 'pkey -in $ECBASEURIWITHPINVALUE -pubin -pubout -out ${TMPPDIR}/ec.pub.uripin.pem' [[ -n $ECXBASEURIWITHPINVALUE ]] && ossl 'pkey -in $ECXBASEURIWITHPINVALUE -pubin -pubout -out ${TMPPDIR}/ecx.pub.uripin.pem' [[ -n $EDBASEURIWITHPINVALUE ]] && ossl 'pkey -in $EDBASEURIWITHPINVALUE -pubin -pubout -out ${TMPPDIR}/ed.pub.uripin.pem' [[ -n $ED2BASEURIWITHPINVALUE ]] && ossl 'pkey -in $ED2BASEURIWITHPINVALUE -pubin -pubout -out ${TMPPDIR}/ed2.pub.uripin.pem' title PARA "Test fetching public keys with a PIN source in URI" ossl 'pkey -in $BASEURIWITHPINSOURCE -pubin -pubout -out ${TMPPDIR}/rsa.pub.uripinsource.pem' ossl 'pkey -in $ECBASEURIWITHPINSOURCE -pubin -pubout -out ${TMPPDIR}/ec.pub.uripinsource.pem' [[ -n $ECXBASEURIWITHPINSOURCE ]] && ossl 'pkey -in $ECXBASEURIWITHPINSOURCE -pubin -pubout -out ${TMPPDIR}/ecx.pub.uripinsource.pem' [[ -n $EDBASEURIWITHPINSOURCE ]] && ossl 'pkey -in $EDBASEURIWITHPINSOURCE -pubin -pubout -out ${TMPPDIR}/ed.pub.uripinsource.pem' [[ -n $ED2BASEURIWITHPINSOURCE ]] && ossl 'pkey -in $ED2BASEURIWITHPINSOURCE -pubin -pubout -out ${TMPPDIR}/ed2.pub.uripinsource.pem' title PARA "Test prompting without PIN in config files" output=$(expect -c "spawn -noecho $CHECKER openssl pkey -in \"${PRIURI}\" -text -noout; expect \"Enter pass phrase for PKCS#11 Token (Slot *:\"; send \"${PINVALUE}\r\"; expect \"Key ID:\";") echo "$output" | grep "Enter pass phrase for PKCS#11 Token (Slot .*):" > /dev/null 2>&1 || FAIL=1 if [ $FAIL -eq 0 ]; then echo "$output" | grep "PKCS11 RSA Private Key" > /dev/null 2>&1 || FAIL=2 fi if [ $FAIL -eq 1 ]; then echo "Failed to obtain expected prompt" fi if [ $FAIL -eq 2 ]; then echo "Failed to get expected command output" fi if [ $FAIL -ne 0 ]; then echo echo "Original command output:" echo "$output" echo exit 1 fi OPENSSL_CONF=${ORIG_OPENSSL_CONF} title PARA "Test EVP_PKEY_eq on public RSA key both on token" # shellcheck disable=SC2153 # PUBURIs is assigned $CHECKER "${TESTBLDDIR}/tcmpkeys" "$PUBURI" "$PUBURI" title PARA "Test EVP_PKEY_eq on public EC key both on token" # shellcheck disable=SC2153 # ECURIs and ECXURIs are assigned $CHECKER "${TESTBLDDIR}/tcmpkeys" "$ECPUBURI" "$ECPUBURI" if [[ -n $ECXPUBURI ]]; then title PARA "Test EVP_PKEY_eq on public explicit EC key both on token" $CHECKER "${TESTBLDDIR}/tcmpkeys" "$ECXPUBURI" "$ECXPUBURI" fi # It's important to test the commutative property since in the # first case the private key (its public part) is exported from # pkcs11 keymgmt and matched using the openssl's keymgmt while # in the second case it's the other way around. title PARA "Test EVP_PKEY_eq on public RSA key via import" $CHECKER "${TESTBLDDIR}/tcmpkeys" "$PUBURI" "${TMPPDIR}"/rsa.pub.uripin.pem $CHECKER "${TESTBLDDIR}/tcmpkeys" "$PUBURI" "${TMPPDIR}"/rsa.pub.uripinsource.pem title PARA "Match private RSA key against public key" $CHECKER "${TESTBLDDIR}/tcmpkeys" "$PRIURI" "${TMPPDIR}"/rsa.pub.uripin.pem $CHECKER "${TESTBLDDIR}/tcmpkeys" "$PRIURI" "${TMPPDIR}"/rsa.pub.uripinsource.pem title PARA "Match private RSA key against public key (commutativity)" $CHECKER "${TESTBLDDIR}/tcmpkeys" "${TMPPDIR}"/rsa.pub.uripin.pem "$PRIURI" $CHECKER "${TESTBLDDIR}/tcmpkeys" "${TMPPDIR}"/rsa.pub.uripinsource.pem "$PRIURI" title PARA "Test EVP_PKEY_eq on public EC key via import" $CHECKER "${TESTBLDDIR}/tcmpkeys" "$ECPUBURI" "${TMPPDIR}"/ec.pub.uripin.pem $CHECKER "${TESTBLDDIR}/tcmpkeys" "$ECPUBURI" "${TMPPDIR}"/ec.pub.uripinsource.pem title PARA "Match private EC key against public key" $CHECKER "${TESTBLDDIR}/tcmpkeys" "$ECPRIURI" "${TMPPDIR}"/ec.pub.uripin.pem $CHECKER "${TESTBLDDIR}/tcmpkeys" "$ECPRIURI" "${TMPPDIR}"/ec.pub.uripinsource.pem title PARA "Match private EC key against public key (commutativity)" $CHECKER "${TESTBLDDIR}/tcmpkeys" "${TMPPDIR}"/ec.pub.uripin.pem "$ECPRIURI" $CHECKER "${TESTBLDDIR}/tcmpkeys" "${TMPPDIR}"/ec.pub.uripinsource.pem "$ECPRIURI" if [[ -n $ECXPUBURI ]]; then echo "ECXPUBURI is $ECXPUBURI" title PARA "Test EVP_PKEY_eq on public explicit EC key via import" $CHECKER "${TESTBLDDIR}/tcmpkeys" "$ECXPUBURI" "${TMPPDIR}"/ecx.pub.uripin.pem $CHECKER "${TESTBLDDIR}/tcmpkeys" "$ECXPUBURI" "${TMPPDIR}"/ecx.pub.uripinsource.pem title PARA "Match private explicit EC key against public key" # shellcheck disable=SC2153 # ECURIs and ECXURIs are assigned $CHECKER "${TESTBLDDIR}/tcmpkeys" "$ECXPRIURI" "${TMPPDIR}"/ecx.pub.uripin.pem $CHECKER "${TESTBLDDIR}/tcmpkeys" "$ECXPRIURI" "${TMPPDIR}"/ecx.pub.uripinsource.pem title PARA "Match private explicit EC key against public key (commutativity)" $CHECKER "${TESTBLDDIR}/tcmpkeys" "${TMPPDIR}"/ecx.pub.uripin.pem "$ECXPRIURI" $CHECKER "${TESTBLDDIR}/tcmpkeys" "${TMPPDIR}"/ecx.pub.uripinsource.pem "$ECXPRIURI" fi title PARA "Test EVP_PKEY_eq with key exporting disabled" ORIG_OPENSSL_CONF=${OPENSSL_CONF} OPENSSL_CONF=${OPENSSL_CONF}.noexport title PARA "Test RSA key" $CHECKER "${TESTBLDDIR}/tcmpkeys" "$PUBURI" "$PUBURI" title PARA "Test EC key" $CHECKER "${TESTBLDDIR}/tcmpkeys" "$ECPUBURI" "$ECPUBURI" if [[ -n $ECXPUBURI ]]; then title PARA "Test explicit EC key" $CHECKER "${TESTBLDDIR}/tcmpkeys" "$ECXPUBURI" "$ECXPUBURI" fi OPENSSL_CONF=${ORIG_OPENSSL_CONF} title PARA "Test PIN caching" ORIG_OPENSSL_CONF=${OPENSSL_CONF} sed "s/^pkcs11-module-token-pin.*$/pkcs11-module-cache-pins = cache/" \ "${OPENSSL_CONF}" > "${OPENSSL_CONF}.pincaching" OPENSSL_CONF=${OPENSSL_CONF}.pincaching $CHECKER "${TESTBLDDIR}/pincache" $CHECKER "${TESTBLDDIR}/pincache" "$ECPRIURI" OPENSSL_CONF=${ORIG_OPENSSL_CONF} OPENSSL_CONF=${OPENSSL_CONF}.nopin title PARA "Test interactive Login on key without ALWAYS AUTHENTICATE" output=$(expect -c "spawn -noecho $CHECKER ${TESTBLDDIR}/tsession \"$BASEURI\"; expect \"Enter PIN for PKCS#11 Token (Slot *:\" { send \"${PINVALUE}\r\"; exp_continue; } expect \"ALL A-OK\";") FAIL=0 echo "$output" | grep "Enter PIN for PKCS#11 Token (Slot .*):" > /dev/null 2>&1 || FAIL=1 prompts=$(echo "$output" | grep -c "Enter PIN for PKCS#11 Token (Slot .*):" 2>&1) # 1 login to read key only if [ "$prompts" -ne "1" ]; then echo "Failed receive expected amount of prompts (got $prompts, expected 1)" FAIL=2 fi if [ $FAIL -eq 1 ]; then echo "Failed to obtain expected prompt" fi if [ $FAIL -ne 0 ]; then echo echo "Original command output:" echo "$output" echo exit 1 fi if [[ -n $ECBASE3URI ]]; then title PARA "Test interactive Login repeated for operation on key with ALWAYS AUTHENTICATE" output=$(expect -c "spawn -noecho $CHECKER ${TESTBLDDIR}/tsession \"$ECBASE3URI\"; expect \"Enter PIN for PKCS#11 Token (Slot *:\" { send \"${PINVALUE}\r\"; exp_continue; } expect \"ALL A-OK\";") FAIL=0 echo "$output" | grep "Enter PIN for PKCS#11 Token (Slot .*):" > /dev/null 2>&1 || FAIL=1 prompts=$(echo "$output" | grep -c "Enter PIN for PKCS#11 Token (Slot .*):" 2>&1) # 1 login to read key + 16 signatures from 2 processes if [ "$prompts" -ne "33" ]; then echo "Failed receive expected amount of prompts (got $prompts, expected 33)" FAIL=2 fi if [ $FAIL -eq 1 ]; then echo "Failed to obtain expected prompt" fi if [ $FAIL -ne 0 ]; then echo echo "Original command output:" echo "$output" echo exit 1 fi fi OPENSSL_CONF=${ORIG_OPENSSL_CONF} title PARA "Test Key generation" FAIL=0 output=$($CHECKER "${TESTBLDDIR}"/tgenkey "RSA,RSA-PSS,EC,RSAKeyUsage" 2>&1) || FAIL=1 echo "$output" | grep "Performed tests: 4" || FAIL=1 if [ $FAIL -ne 0 ]; then echo echo "Original command output:" echo "$output" echo exit 1 fi exit 0 pkcs11-provider-1.0/tests/tcerts000077500000000000000000000032741475270623700167230ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2022 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" title PARA "Check we can fetch certifiatce objects" ossl ' x509 -in ${CRTURI} -subject -out ${TMPPDIR}/crt-subj.txt' DATA=$(sed -e 's/\ =\ /=/g' "${TMPPDIR}/crt-subj.txt") CHECK="subject=O=PKCS11 Provider, CN=My Test Cert" if [[ ! ${DATA} =~ ${CHECK} ]]; then echo "Cert not found looking for ${CHECK}" exit 1 fi ossl ' x509 -in ${ECCRTURI} -subject -out ${TMPPDIR}/eccrt-subj.txt' DATA=$(sed -e 's/\ =\ /=/g' "${TMPPDIR}/eccrt-subj.txt") CHECK="subject=O=PKCS11 Provider, CN=My EC Cert" if [[ ! ${DATA} =~ ${CHECK} ]]; then echo "Cert not found looking for ${CHECK}" exit 1 fi title PARA "Use storeutl command to match specific certs via params" SUBJECTS=("/O=PKCS11 Provider/CN=My Test Cert" "/O=PKCS11 Provider/CN=My EC Cert" "/CN=My Peer EC Cert" "/CN=Issuer") for subj in "${SUBJECTS[@]}"; do ossl ' storeutl -certs -subject "${subj}" -out ${TMPPDIR}/storeutl-crt-subj.txt pkcs11:type=cert' DATA=$(cat "${TMPPDIR}/storeutl-crt-subj.txt") if [[ ! ${DATA} =~ "Total found: 1" ]]; then echo "Cert not found matching by subject=${subj}" exit 1 fi done title PARA "Test fetching certificate without PIN in config files" ORIG_OPENSSL_CONF=${OPENSSL_CONF} sed "s/^pkcs11-module-token-pin.*$/##nopin/" "${OPENSSL_CONF}" > "${OPENSSL_CONF}.nopin" OPENSSL_CONF=${OPENSSL_CONF}.nopin ossl 'x509 -in $CRTURI -subject -out ${TMPPDIR}/crt-subj-nopin.txt' title PARA "Test fetching certificate via STORE api" $CHECKER "${TESTBLDDIR}/ccerts" "${CRTURI}" nopin OPENSSL_CONF=${ORIG_OPENSSL_CONF} exit 0 pkcs11-provider-1.0/tests/tcmpkeys.c000066400000000000000000000012111475270623700174610ustar00rootroot00000000000000/* Copyright (C) 2023 Timo Teräs SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include "util.h" int main(int argc, char *argv[]) { EVP_PKEY *a, *b; int rc = EXIT_FAILURE; if (argc != 3) { fprintf(stderr, "Usage: tcmpkeys [keyuri-a] [keyuri-b]\n"); exit(EXIT_FAILURE); } a = load_key(argv[1]); b = load_key(argv[2]); if (EVP_PKEY_eq(a, b) == 1) { rc = EXIT_SUCCESS; } EVP_PKEY_free(a); EVP_PKEY_free(b); return rc; } pkcs11-provider-1.0/tests/tcms000077500000000000000000000013131475270623700163550ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2022 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" MESSAGEFILE=${TMPPDIR}/cms-message.txt echo "CMS Test Message" > "${MESSAGEFILE}" title PARA "Encrypt CMS with EC" ossl ' cms -encrypt -in "${MESSAGEFILE}" -out "${TMPPDIR}/cms-message.ec.enc" -aes-256-cbc -recip ${ECCRTURI} -binary' title PARA "Decrypt CMS with EC" ossl ' cms -decrypt -in "${TMPPDIR}/cms-message.ec.enc" -out "${TMPPDIR}/cms-message.ec.dec" -inkey ${ECPRIURI} -recip ${ECCRTURI} -binary' cmp "${MESSAGEFILE}" "${TMPPDIR}/cms-message.ec.dec" exit 0 pkcs11-provider-1.0/tests/tdemoca000077500000000000000000000140461475270623700170320ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2022 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" DEMOCA="${TMPPDIR}/demoCA" title PARA "Set up demoCA" mkdir -p "${DEMOCA}/newcerts" "${DEMOCA}/private" if [ ! -e "${DEMOCA}/serial" ]; then echo "01" > "${DEMOCA}/serial" fi touch "${DEMOCA}/index.txt" title PARA "Generating CA cert if needed" if [ ! -e "${DEMOCA}/cacert.pem" ]; then ossl 'req -batch -noenc -x509 -new -key ${PRIURI} -out ${DEMOCA}/cacert.pem' fi title PARA "Generating a new CSR with key in file" ossl ' req -batch -noenc -newkey rsa:2048 -subj "/CN=testing-csr-signing/O=PKCS11 Provider/C=US" -keyout ${DEMOCA}/cert.key -out ${DEMOCA}/cert.csr' title PARA "Signing the new certificate" ossl ' ca -batch -in ${DEMOCA}/cert.csr -keyfile ${PRIURI} -out ${DEMOCA}/cert.pem' title PARA "Generating a new CSR with existing RSA key in token" ossl ' req -batch -noenc -new -key ${PRIURI} -subj "/CN=testing-rsa-signing/O=PKCS11 Provider/C=US" -out ${DEMOCA}/cert-rsa.csr' title PARA "Signing the new RSA key certificate" ossl ' ca -batch -in ${DEMOCA}/cert-rsa.csr -keyfile ${PRIURI} -out ${DEMOCA}/cert.pem' title PARA "Generating a new CSR with existing EC key in token" ossl ' req -batch -noenc -new -key ${ECPRIURI} -subj "/CN=testing-ec-signing/O=PKCS11 Provider/C=US" -out ${DEMOCA}/cert-ec.csr' title PARA "Signing the new EC key certificate" ossl ' ca -batch -in ${DEMOCA}/cert-ec.csr -keyfile ${PRIURI} -out ${DEMOCA}/cert.pem' if [[ -n $EDPRIURI ]]; then title PARA "Generating a new CSR with existing ED key in token" ossl ' req -batch -noenc -new -key ${EDPRIURI} -subj "/CN=testing-ed-signing/O=PKCS11 Provider/C=US" -out ${DEMOCA}/cert-ed.csr' title PARA "Signing the new ED key certificate" ossl ' ca -batch -in ${DEMOCA}/cert-ed.csr -keyfile ${PRIURI} -out ${DEMOCA}/cert.pem' fi if [[ -n $ED2PRIURI ]]; then title PARA "Generating a new CSR with existing ED448 key in token" ossl ' req -batch -noenc -new -key ${ED2PRIURI} -subj "/CN=testing-ed2-signing/O=PKCS11 Provider/C=US" -out ${DEMOCA}/cert-ed2.csr' title PARA "Signing the new ED448 key certificate" ossl ' ca -batch -in ${DEMOCA}/cert-ed2.csr -keyfile ${PRIURI} -out ${DEMOCA}/cert.pem' fi if [[ -n $RSAPSSPRIURI ]]; then title PARA "Generating a new CSR with existing RSA-PSS key in token" ossl ' req -batch -noenc -new -key ${RSAPSSPRIURI} -sigopt rsa_padding_mode:pss -subj "/CN=testing-rsapss-signing/O=PKCS11 Provider/C=US" -sigopt rsa_padding_mode:pss -out ${DEMOCA}/cert-rsa-pss.csr' title PARA "Signing the new RSA-PSS key certificate" ossl ' ca -batch -in ${DEMOCA}/cert-rsa-pss.csr -keyfile ${PRIURI} -out ${DEMOCA}/cert.pem' ossl 'x509 -text -in ${DEMOCA}/cert.pem' "$helper_emit" output="$helper_output" FAIL=1 echo "$output" | grep "No PSS parameter restrictions" > /dev/null 2>&1 && FAIL=0 if [ $FAIL -ne 0 ]; then echo "Generated certificate has some RSA-PSS restrictions while it should not" echo "$output"; exit 1 fi fi if [[ -n $RSAPSS2PRIURI ]]; then title PARA "Generating a new CSR with existing SHA256 restricted RSA-PSS key in token" ossl ' req -batch -noenc -new -key ${RSAPSS2PRIURI} -sigopt rsa_padding_mode:pss -subj "/CN=testing-rsapss-sha2-signing/O=PKCS11 Provider/C=US" -out ${DEMOCA}/cert-rsa-pss2.csr -sigopt rsa_padding_mode:pss -sigopt digest:sha256' title PARA "Signing the new SHA256 restricted RSA-PSS key certificate" ossl ' ca -batch -in ${DEMOCA}/cert-rsa-pss2.csr -keyfile ${PRIURI} -out ${DEMOCA}/cert.pem' ossl 'x509 -text -in ${DEMOCA}/cert.pem' "$helper_emit" output="$helper_output" # TODO we should get restrictions visible here when implemented #FAIL=0 #echo "$output" | grep "No PSS parameter restrictions" > /dev/null 2>&1 && FAIL=1 #if [ $FAIL -ne 0 ]; then # echo "Generated certificate does not have any RSA-PSS restrictions while it should" # echo "$output"; # exit 1 #fi fi if [[ -n $RSAPSS2PRIURI ]]; then title PARA "Generating a new CSR with existing RSA-PSS key in token" ossl ' req -batch -noenc -new -key ${RSAPSS2PRIURI} -sigopt rsa_padding_mode:pss -subj "/CN=testing-rsapss-signing/O=PKCS11 Provider/C=US" -out ${DEMOCA}/cert-rsa-pss2.csr -sigopt rsa_padding_mode:pss -sigopt digest:sha256 -sigopt rsa_pss_saltlen:-2' title PARA "Signing the new RSA-PSS key certificate" ossl ' ca -batch -in ${DEMOCA}/cert-rsa-pss.csr -keyfile ${PRIURI} -out ${DEMOCA}/cert.pem' fi title PARA "Set up OCSP" ossl ' req -batch -noenc -new -subj "/CN=OCSP/O=PKCS11 Provider/C=US" -key ${PRIURI} -out ${DEMOCA}/ocspSigning.csr' ossl ' ca -batch -keyfile ${PRIURI} -cert ${DEMOCA}/cacert.pem -in ${DEMOCA}/ocspSigning.csr -out ${DEMOCA}/ocspSigning.pem' #The next test is not working on Debian for some reason, so skip the rest for now if [ -e /etc/debian_version ]; then exit 0 fi title PARA "Run OCSP" PORT=12345 trap kill_children EXIT #Unclear why but w/o -rmd sha1 this fails #call this without wrapper otherwise we have issues killing it later ... # shellcheck disable=SC2153 # the PRIURI is defined in setup-soft{hsm,okn} $CHECKER openssl ocsp -index "${DEMOCA}/index.txt" -rsigner \ "${DEMOCA}/ocspSigning.pem" -rkey "${PRIURI}" -CA "${DEMOCA}/cacert.pem" \ -rmd sha256 -port "${PORT}" -text & sleep 0.5 # with valgrind, it might take a bit longer if [ -n "$VALGRIND" ]; then sleep 5 fi ossl ' ocsp -CAfile ${DEMOCA}/cacert.pem -issuer ${DEMOCA}/cacert.pem -cert ${DEMOCA}/cert.pem -resp_text -noverify -url http://127.0.0.1:${PORT}' $helper_emit output="$helper_output" FAIL=0 echo "$output" | grep ": good" > /dev/null 2>&1 || FAIL=1 if [ $FAIL -eq 1 ]; then echo "The OCSP response failed" echo echo "Original command output:" echo "$output" echo exit 1 fi title PARA "Kill any remaining children and wait for them" kill_children exit 0 pkcs11-provider-1.0/tests/tdigest000077500000000000000000000022701475270623700170550ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2022 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" # We need to configure early loading otherwise no digests are loaded, # and all checks are skipped sed "s/#pkcs11-module-load-behavior/pkcs11-module-load-behavior = early/" \ "${OPENSSL_CONF}" > "${OPENSSL_CONF}.early_load" OPENSSL_CONF=${OPENSSL_CONF}.early_load title PARA "Test Digests support" $CHECKER "${TESTBLDDIR}/tdigests" echo "PASSED" # Ensure failure if the digest operations are blocked sed "s/#pkcs11-module-block-operations/pkcs11-module-block-operations = digest/" \ "${OPENSSL_CONF}" > "${OPENSSL_CONF}.no_digests" OPENSSL_CONF=${OPENSSL_CONF}.no_digests title PARA "Test Digests Blocked" FAIL=0 OUT=$(eval "${TESTBLDDIR}/tdigests" 2>&1) || FAIL=1 if [ $FAIL -ne 0 ]; then echo "$OUT" | grep "No digest available" || FAIL=2 fi if [ $FAIL -eq 0 ]; then echo "Digests test should have failed" exit 1 fi if [ $FAIL -eq 1 ]; then echo "Digest operations failed as expected" fi if [ $FAIL -eq 2 ]; then echo "Digest operations failed but not as expected" echo "---" echo "${OUT}" echo "---" exit 1 fi exit 0 pkcs11-provider-1.0/tests/tdigest_dupctx.c000066400000000000000000000025671475270623700206730ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include #define EXIT_TEST_SKIPPED 77 int main(int argc, char *argv[]) { const char *propq = "provider=pkcs11"; const char *digest = "sha256"; const char *provname; const OSSL_PROVIDER *pk11prov; EVP_MD *pk11md = EVP_MD_fetch(NULL, digest, propq); if (!pk11md) { fprintf(stderr, "%s: Unsupported by pkcs11 token\n", digest); exit(EXIT_FAILURE); } pk11prov = EVP_MD_get0_provider(pk11md); provname = OSSL_PROVIDER_get0_name(pk11prov); if (strcmp(provname, "pkcs11") != 0) { fprintf(stderr, "%s: Not a pkcs11 method, provider=%s\n", digest, provname); EVP_MD_free(pk11md); exit(EXIT_FAILURE); } EVP_MD_CTX *mdctx = EVP_MD_CTX_new(); EVP_DigestInit_ex(mdctx, pk11md, NULL); EVP_MD_CTX *mdctx_dup = EVP_MD_CTX_new(); EVP_MD_CTX_copy(mdctx_dup, mdctx); char error_string[2048]; ERR_error_string_n(ERR_peek_last_error(), error_string, sizeof error_string); printf("%s\n", error_string); EVP_MD_CTX_free(mdctx); EVP_MD_CTX_free(mdctx_dup); EVP_MD_free(pk11md); exit(EXIT_SUCCESS); } pkcs11-provider-1.0/tests/tdigests.c000066400000000000000000000052151475270623700174600ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #define EXIT_TEST_SKIPPED 77 int main(int argc, char *argv[]) { unsigned char osslout[EVP_MAX_MD_SIZE]; unsigned char pk11out[EVP_MAX_MD_SIZE]; unsigned int ossllen; unsigned int pk11len; bool pk11_tested = false; const char *propq = "provider=pkcs11"; const char *digests[] = { "sha1", "sha224", "sha256", "sha384", "sha512", "sha512-224", "sha512-256", "sha3-224", "sha3-256", "sha3-384", "sha3-512", NULL }; const char *data = "Digest This!"; int ret; for (int i = 0; digests[i] != NULL; i++) { const char *digest = digests[i]; const OSSL_PROVIDER *pk11prov; const char *provname; EVP_MD *osslmd; EVP_MD *pk11md; osslmd = EVP_MD_fetch(NULL, digest, NULL); if (!osslmd) { fprintf(stderr, "%s: Failed to fetch openssl EVP_MD\n", digest); exit(EXIT_FAILURE); } pk11md = EVP_MD_fetch(NULL, digest, propq); if (!pk11md) { fprintf(stderr, "%s: Unsupported by pkcs11 token\n", digest); EVP_MD_free(osslmd); continue; } pk11prov = EVP_MD_get0_provider(pk11md); provname = OSSL_PROVIDER_get0_name(pk11prov); if (strcmp(provname, "pkcs11") != 0) { fprintf(stderr, "%s: Not a pkcs11 method, provider=%s\n", digest, provname); EVP_MD_free(osslmd); EVP_MD_free(pk11md); continue; } ret = EVP_Digest(data, sizeof(data), osslout, &ossllen, osslmd, NULL); if (ret != 1) { fprintf(stderr, "%s: Failed to generate openssl digest\n", digest); exit(EXIT_FAILURE); } ret = EVP_Digest(data, sizeof(data), pk11out, &pk11len, pk11md, NULL); if (ret != 1) { fprintf(stderr, "%s: Failed to generate pkcs11 digest\n", digest); exit(EXIT_FAILURE); } if (ossllen != pk11len || memcmp(osslout, pk11out, ossllen) != 0) { fprintf(stderr, "%s: Digests do not match!\n", digest); exit(EXIT_FAILURE); } pk11_tested = true; EVP_MD_free(osslmd); EVP_MD_free(pk11md); } if (!pk11_tested) { fprintf(stderr, "No digest available for testing pkcs11 provider\n"); exit(EXIT_TEST_SKIPPED); } exit(EXIT_SUCCESS); } pkcs11-provider-1.0/tests/tecc000077500000000000000000000076601475270623700163400ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2023 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" title PARA "Export EC Public key to a file" ossl 'pkey -in $ECPUBURI -pubin -pubout -out ${TMPPDIR}/ecout.pub' title LINE "Print EC Public key from private" ossl 'pkey -in $ECPRIURI -pubout -text' "$helper_emit" output="$helper_output" FAIL=0 echo "$output" | grep "PKCS11 EC Public Key (256 bits)" > /dev/null 2>&1 || FAIL=1 if [ $FAIL -eq 1 ]; then echo "Pkcs11 encoder function failed" echo echo "Original command output:" echo "$output" echo exit 1 fi title PARA "Sign and Verify with provided Hash and EC" ossl 'dgst -sha256 -binary -out ${TMPPDIR}/sha256.bin ${SEEDFILE}' ossl ' pkeyutl -sign -inkey "${ECBASEURI}" -in ${TMPPDIR}/sha256.bin -out ${TMPPDIR}/sha256-ecsig.bin' ossl ' pkeyutl -verify -inkey "${ECBASEURI}" -pubin -in ${TMPPDIR}/sha256.bin -sigfile ${TMPPDIR}/sha256-ecsig.bin' ossl ' pkeyutl -verify -inkey "${TMPPDIR}/ecout.pub" -pubin -in ${TMPPDIR}/sha256.bin -sigfile ${TMPPDIR}/sha256-ecsig.bin' title PARA "DigestSign and DigestVerify with ECC (SHA-256)" ossl ' pkeyutl -sign -inkey "${ECBASEURI}" -digest sha256 -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha256-ecdgstsig.bin' ossl ' pkeyutl -verify -inkey "${ECBASEURI}" -pubin -digest sha256 -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha256-ecdgstsig.bin' title PARA "DigestSign and DigestVerify with ECC (SHA-384)" ossl ' pkeyutl -sign -inkey "${ECBASEURI}" -digest sha384 -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha384-ecdgstsig.bin' ossl ' pkeyutl -verify -inkey "${ECBASEURI}" -pubin -digest sha384 -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha384-ecdgstsig.bin' title PARA "DigestSign and DigestVerify with ECC (SHA-512)" ossl ' pkeyutl -sign -inkey "${ECBASEURI}" -digest sha512 -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha512-ecdgstsig.bin' ossl ' pkeyutl -verify -inkey "${ECBASEURI}" -pubin -digest sha512 -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha512-ecdgstsig.bin' title PARA "DigestSign and DigestVerify with ECC (SHA3-256)" ossl ' pkeyutl -sign -inkey "${ECBASEURI}" -digest sha3-256 -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha3-256-ecdgstsig.bin' ossl ' pkeyutl -verify -inkey "${ECBASEURI}" -pubin -digest sha3-256 -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha3-256-ecdgstsig.bin' title PARA "DigestSign and DigestVerify with ECC (SHA3-384)" ossl ' pkeyutl -sign -inkey "${ECBASEURI}" -digest sha3-384 -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha3-384-ecdgstsig.bin' ossl ' pkeyutl -verify -inkey "${ECBASEURI}" -pubin -digest sha3-384 -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha3-384-ecdgstsig.bin' title PARA "DigestSign and DigestVerify with ECC (SHA3-512)" ossl ' pkeyutl -sign -inkey "${ECBASEURI}" -digest sha3-512 -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha3-512-ecdgstsig.bin' ossl ' pkeyutl -verify -inkey "${ECBASEURI}" -pubin -digest sha3-512 -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha3-512-ecdgstsig.bin' title PARA "Test CSR generation from private ECC keys" ossl ' req -new -batch -key "${ECPRIURI}" -out ${TMPPDIR}/ecdsa_csr.pem' ossl ' req -in ${TMPPDIR}/ecdsa_csr.pem -verify -noout' exit 0 pkcs11-provider-1.0/tests/tecdh000077500000000000000000000024571475270623700165100ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2022 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" title PARA "ECDH Exchange" ossl ' pkeyutl -derive -inkey ${ECBASEURI} -peerkey ${ECPEERPUBURI} -out ${TMPPDIR}/secret.ecdh.bin' # Now test by forcing all operations on the token title PARA "ECDH Exchange forcing PKCS11 Provider" ORIG_OPENSSL_CONF=${OPENSSL_CONF} sed -e "s/#MORECONF/alg_section = algorithm_sec\n\n[algorithm_sec]\ndefault_properties = ?provider=pkcs11/" \ "${OPENSSL_CONF}" > "${OPENSSL_CONF}.forcetoken" OPENSSL_CONF=${OPENSSL_CONF}.forcetoken title PARA "ECDH Exchange forced: public key in file" ossl ' pkeyutl -derive -inkey ${ECBASEURI} -peerkey ${TESTSSRCDIR}/testp256.pub.pem -out ${TMPPDIR}/forced.pub.ecdh.bin' title PARA "ECDH Exchange forced: private key in file" ossl ' pkeyutl -derive -inkey ${TESTSSRCDIR}/testp256.pri.pem -peerkey ${ECPEERPUBURI} -out ${TMPPDIR}/forced.pri.ecdh.bin' title PARA "ECDH Exchange forced: both key in file" ossl ' pkeyutl -derive -inkey ${TESTSSRCDIR}/testp256.pri.pem -peerkey ${TESTSSRCDIR}/testp256.pub.pem -out ${TMPPDIR}/forced.both.ecdh.bin' OPENSSL_CONF=${ORIG_OPENSSL_CONF} exit 0 pkcs11-provider-1.0/tests/tecxc000077500000000000000000000102171475270623700165200ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2023 Simo Sorce # SPDX-License-Identifier: Apache-2.0 # Some distributions completely removed support for explicit EC from libcrypto. # If `-Denable_explicit_EC_test=true` is not set, skip the test. if [ -z "${ENABLE_EXPLICIT_EC_TEST}" ]; then exit 77 fi source "${TESTSSRCDIR}/helpers.sh" title PARA "Export EC Public key to a file" ossl 'pkey -in $ECXPUBURI -pubin -pubout -out ${TMPPDIR}/ecout.pub' title LINE "Print EC Public key from private" ossl 'pkey -in $ECXPRIURI -pubout -text' "$helper_emit" output="$helper_output" FAIL=0 echo "$output" | grep "PKCS11 EC Public Key (190 bits)" > /dev/null 2>&1 || FAIL=1 if [ $FAIL -eq 1 ]; then echo "Pkcs11 encoder function failed" echo echo "Original command output:" echo "$output" echo exit 1 fi title PARA "Sign and Verify with provided Hash and EC" ossl 'dgst -sha256 -binary -out ${TMPPDIR}/sha256.bin ${SEEDFILE}' ossl ' pkeyutl -sign -inkey "${ECXBASEURI}" -in ${TMPPDIR}/sha256.bin -out ${TMPPDIR}/sha256-ecsig.bin' ossl ' pkeyutl -verify -inkey "${ECXBASEURI}" -pubin -in ${TMPPDIR}/sha256.bin -sigfile ${TMPPDIR}/sha256-ecsig.bin' ossl ' pkeyutl -verify -inkey "${TMPPDIR}/ecout.pub" -pubin -in ${TMPPDIR}/sha256.bin -sigfile ${TMPPDIR}/sha256-ecsig.bin' title PARA "DigestSign and DigestVerify with ECC (SHA-256)" ossl ' pkeyutl -sign -inkey "${ECXBASEURI}" -digest sha256 -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha256-ecdgstsig.bin' ossl ' pkeyutl -verify -inkey "${ECXBASEURI}" -pubin -digest sha256 -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha256-ecdgstsig.bin' title PARA "DigestSign and DigestVerify with ECC (SHA-384)" ossl ' pkeyutl -sign -inkey "${ECXBASEURI}" -digest sha384 -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha384-ecdgstsig.bin' ossl ' pkeyutl -verify -inkey "${ECXBASEURI}" -pubin -digest sha384 -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha384-ecdgstsig.bin' title PARA "DigestSign and DigestVerify with ECC (SHA-512)" ossl ' pkeyutl -sign -inkey "${ECXBASEURI}" -digest sha512 -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha512-ecdgstsig.bin' ossl ' pkeyutl -verify -inkey "${ECXBASEURI}" -pubin -digest sha512 -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha512-ecdgstsig.bin' title PARA "DigestSign and DigestVerify with ECC (SHA3-256)" ossl ' pkeyutl -sign -inkey "${ECXBASEURI}" -digest sha3-256 -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha3-256-ecdgstsig.bin' ossl ' pkeyutl -verify -inkey "${ECXBASEURI}" -pubin -digest sha3-256 -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha3-256-ecdgstsig.bin' title PARA "DigestSign and DigestVerify with ECC (SHA3-384)" ossl ' pkeyutl -sign -inkey "${ECXBASEURI}" -digest sha3-384 -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha3-384-ecdgstsig.bin' ossl ' pkeyutl -verify -inkey "${ECXBASEURI}" -pubin -digest sha3-384 -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha3-384-ecdgstsig.bin' title PARA "DigestSign and DigestVerify with ECC (SHA3-512)" ossl ' pkeyutl -sign -inkey "${ECXBASEURI}" -digest sha3-512 -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha3-512-ecdgstsig.bin' ossl ' pkeyutl -verify -inkey "${ECXBASEURI}" -pubin -digest sha3-512 -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha3-512-ecdgstsig.bin' title PARA "Test CSR generation from private ECC keys" ossl ' req -new -batch -key "${ECXPRIURI}" -out ${TMPPDIR}/ecdsa_csr.pem' ossl ' req -in ${TMPPDIR}/ecdsa_csr.pem -verify -noout' exit 0 pkcs11-provider-1.0/tests/tedwards000077500000000000000000000121061475270623700172260ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2023 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" if [[ "${SUPPORT_ED25519}" = "0" ]]; then exit 77; fi title PARA "Export ED25519 Public key to a file" ossl 'pkey -in $EDPUBURI -pubin -pubout -out ${TMPPDIR}/edout.pub' title LINE "Print ED25519 Public key from private" ossl 'pkey -in $EDPRIURI -pubout -text' $helper_emit output="$helper_output" FAIL=0 echo "$output" | grep "ED25519 Public Key" > /dev/null 2>&1 || FAIL=1 if [ $FAIL -eq 1 ]; then echo "Could not extract public key from private" echo echo "Original command output:" echo "$output" echo exit 1 fi title PARA "DigestSign and DigestVerify with ED25519" ossl ' pkeyutl -sign -inkey "${EDBASEURI}" -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha256-eddgstsig.bin' ossl ' pkeyutl -verify -inkey "${EDBASEURI}" -pubin -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha256-eddgstsig.bin' title PARA "Test CSR generation from private ED25519 keys" ossl ' req -new -batch -key "${EDPRIURI}" -out ${TMPPDIR}/ed25519_csr.pem' ossl ' req -in ${TMPPDIR}/ed25519_csr.pem -verify -noout' title PARA "Test EVP_PKEY_eq on public Edwards key both on token" $CHECKER "${TESTBLDDIR}/tcmpkeys" "$EDPUBURI" "$EDPUBURI" title PARA "Test EVP_PKEY_eq on public ED key via import" $CHECKER "${TESTBLDDIR}/tcmpkeys" "$EDPUBURI" "${TMPPDIR}"/edout.pub title PARA "Match private ED key against public key" $CHECKER "${TESTBLDDIR}/tcmpkeys" "$EDPRIURI" "${TMPPDIR}"/edout.pub title PARA "Match private ED key against public key (commutativity)" $CHECKER "${TESTBLDDIR}/tcmpkeys" "${TMPPDIR}"/edout.pub "$EDPRIURI" title PARA "Test Key generation" output=$("${TESTBLDDIR}"/tgenkey "ED25519" 2>&1 || true) FAIL=0 echo "$output" | grep "Performed tests: 1" || FAIL=1 if [ $FAIL -ne 0 ]; then echo echo "Original command output:" echo "$output" echo exit 1 fi # Test Ed448 too if supported if [[ -n $ED2BASEURI ]]; then title PARA "Export ED448 Public key to a file" ossl 'pkey -in $ED2PUBURI -pubin -pubout -out ${TMPPDIR}/ed2out.pub' title LINE "Print ED448 Public key from private" ossl 'pkey -in $ED2PRIURI -pubout -text' $helper_emit output="$helper_output" FAIL=0 echo "$output" | grep "ED448 Public Key" > /dev/null 2>&1 || FAIL=1 if [ $FAIL -eq 1 ]; then echo "Could not extract public key from private" echo echo "Original command output:" echo "$output" echo exit 1 fi title PARA "DigestSign and DigestVerify with ED448" ossl ' pkeyutl -sign -inkey "${ED2BASEURI}" -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha256-eddgstsig.bin' ossl ' pkeyutl -verify -inkey "${ED2BASEURI}" -pubin -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha256-eddgstsig.bin' title PARA "Test CSR generation from private ED448 keys" ossl ' req -new -batch -key "${ED2PRIURI}" -out ${TMPPDIR}/ed448_csr.pem' ossl ' req -in ${TMPPDIR}/ed448_csr.pem -verify -noout' title PARA "Test EVP_PKEY_eq on public Edwards key both on token" $CHECKER "${TESTBLDDIR}/tcmpkeys" "$ED2PUBURI" "$ED2PUBURI" title PARA "Test EVP_PKEY_eq on public ED448 key via import" $CHECKER "${TESTBLDDIR}/tcmpkeys" "$ED2PUBURI" "${TMPPDIR}"/ed2out.pub title PARA "Match private ED448 key against public key" $CHECKER "${TESTBLDDIR}/tcmpkeys" "$ED2PRIURI" "${TMPPDIR}"/ed2out.pub title PARA "Match private ED448 key against public key (commutativity)" $CHECKER "${TESTBLDDIR}/tcmpkeys" "${TMPPDIR}"/ed2out.pub "$ED2PRIURI" fi title PARA "Test Ed448 Key generation" output=$("${TESTBLDDIR}"/tgenkey "ED448" 2>&1 || true) FAIL=0 echo "$output" | grep "Performed tests: 1" || FAIL=1 if [ $FAIL -ne 0 ]; then echo echo "Original command output:" echo "$output" echo exit 1 fi ORIG_OPENSSL_CONF=${OPENSSL_CONF} sed "s/^pkcs11-module-token-pin.*$/##nopin/" "${OPENSSL_CONF}" > "${OPENSSL_CONF}.nopin" OPENSSL_CONF=${OPENSSL_CONF}.nopin title PARA "Test interactive Login on key without ALWAYS AUTHENTICATE" # shellcheck disable=SC2153 # It is correctly defined in the testvars output=$(expect -c "spawn -noecho $CHECKER ${TESTBLDDIR}/tsession \"$EDBASEURI\"; expect \"Enter PIN for PKCS#11 Token (Slot *:\" { send \"${PINVALUE}\r\"; exp_continue; } expect \"ALL A-OK\";") FAIL=0 echo "$output" | grep "Enter PIN for PKCS#11 Token (Slot .*):" > /dev/null 2>&1 || FAIL=1 prompts=$(echo "$output" | grep -c "Enter PIN for PKCS#11 Token (Slot .*):" 2>&1) # 1 login to read key only if [ "$prompts" -ne "1" ]; then echo "Failed receive expected amount of prompts (got $prompts, expected 1)" FAIL=2 fi if [ $FAIL -eq 1 ]; then echo "Failed to obtain expected prompt" fi if [ $FAIL -ne 0 ]; then echo echo "Original command output:" echo "$output" echo exit 1 fi OPENSSL_CONF=${ORIG_OPENSSL_CONF} exit 0 pkcs11-provider-1.0/tests/test-wrapper000077500000000000000000000024731475270623700200540ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2022 Simo sorce # SPDX-License-Identifier: Apache-2.0 DNAME=$(dirname "${1}") BNAME=$(basename "${1}") : "${TEST_PATH=$DNAME}" : "${TESTBLDDIR=.}" # the test name is {TEST_NAME}-{TOKEN_DRIVER}.t # split extension NAME=${BNAME%.*} TEST_NAME=${NAME%-*} TOKEN_DRIVER=${NAME#*-} if [ -f "${TESTBLDDIR}/${TOKEN_DRIVER}/testvars" ]; then # shellcheck source=/dev/null # we do not care about linting this source source "${TESTBLDDIR}/${TOKEN_DRIVER}/testvars" else exit 77 # token not configured, skip fi # some tests are compiled, others are just distributed scripts # so we need to check both the current tests build dir and the # source tests dir in the out-of-source build case (used by # make distcheck for example) if [ -f "${TEST_PATH}/t${TEST_NAME}" ]; then COMMAND="${TEST_PATH}/t${TEST_NAME}" else COMMAND="${TESTBLDDIR}/t${TEST_NAME}" fi # Run the tests under valgrind with appropriate flags if [ -n "$VALGRIND" ] && [ -n "$LOG_COMPILER" ]; then CHECKER="$LOG_COMPILER" fi # for compiled tests, we need to add valgrind/checker if [ -f "${TEST_PATH}/t${TEST_NAME}.c" ]; then COMMAND="$CHECKER $COMMAND" fi LOGFILE="${TESTBLDDIR}/${TEST_NAME}.${TOKEN_DRIVER}.log" echo "Executing ${COMMAND}" ( set -o pipefail ${COMMAND} 2>&1 | tee "${LOGFILE}" ) pkcs11-provider-1.0/tests/testp256.pri.pem000066400000000000000000000003611475270623700203530ustar00rootroot00000000000000-----BEGIN PRIVATE KEY----- MIGHAgEAMBMGByqGSM49AgEGCCqGSM49AwEHBG0wawIBAQQgQj80pwUNIHHjzQaJ yP+vAPE8KPBmrVwafor5xar9sq+hRANCAATXOFIB00W2LsAwzDxBpg/uFzFu4uIK 5otxalZiroOusrSBYA/vS2MC/6vaR+zrdnxRlYoHIbhe7H+PlEHPuq/a -----END PRIVATE KEY----- pkcs11-provider-1.0/tests/testp256.pub.pem000066400000000000000000000002621475270623700203470ustar00rootroot00000000000000-----BEGIN PUBLIC KEY----- MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE1zhSAdNFti7AMMw8QaYP7hcxbuLi CuaLcWpWYq6DrrK0gWAP70tjAv+r2kfs63Z8UZWKByG4Xux/j5RBz7qv2g== -----END PUBLIC KEY----- pkcs11-provider-1.0/tests/tfork.c000066400000000000000000000066231475270623700167630ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #define _GNU_SOURCE #include #include #include #include #include #include #include "util.h" static void sign_op(EVP_PKEY *key, pid_t pid) { size_t size = EVP_PKEY_get_size(key); unsigned char sig[size]; const char *data = "Sign Me!"; EVP_MD_CTX *sign_md; int ret; sign_md = EVP_MD_CTX_new(); ret = EVP_DigestSignInit_ex(sign_md, NULL, "SHA256", NULL, NULL, key, NULL); if (ret != 1) { PRINTERROSSL("Failed to init EVP_DigestSign (pid = %d)\n", pid); exit(EXIT_FAILURE); } ret = EVP_DigestSignUpdate(sign_md, data, sizeof(data)); if (ret != 1) { PRINTERROSSL("Failed to EVP_DigestSignUpdate (pid = %d)\n", pid); exit(EXIT_FAILURE); } ret = EVP_DigestSignFinal(sign_md, sig, &size); if (ret != 1) { PRINTERROSSL("Failed to EVP_DigestSignFinal-ize (pid = %d)\n", pid); exit(EXIT_FAILURE); } EVP_MD_CTX_free(sign_md); if (pid == 0) { EVP_PKEY_free(key); PRINTERR("Child Done\n"); exit(EXIT_SUCCESS); } } /* forks in the middle of an op to check the child one fails */ static void fork_sign_op(EVP_PKEY *key) { size_t size = EVP_PKEY_get_size(key); unsigned char sig[size]; const char *data = "Sign Me!"; EVP_MD_CTX *sign_md; pid_t pid; int ret; sign_md = EVP_MD_CTX_new(); ret = EVP_DigestSignInit_ex(sign_md, NULL, "SHA256", NULL, NULL, key, NULL); if (ret != 1) { PRINTERROSSL("Failed to init EVP_DigestSign\n"); exit(EXIT_FAILURE); } ret = EVP_DigestSignUpdate(sign_md, data, sizeof(data)); if (ret != 1) { PRINTERROSSL("Failed to EVP_DigestSignUpdate\n"); exit(EXIT_FAILURE); } pid = fork(); if (pid == -1) { PRINTERR("Fork failed"); exit(EXIT_FAILURE); } ret = EVP_DigestSignFinal(sign_md, sig, &size); EVP_MD_CTX_free(sign_md); if (pid == 0) { /* child */ if (ret != 0) { /* should have returned error in the child */ PRINTERR("Child failed to fail!\n"); exit(EXIT_FAILURE); } EVP_PKEY_free(key); PRINTERR("Child Done\n"); fflush(stderr); exit(EXIT_SUCCESS); } else { int status; EVP_PKEY_free(key); /* parent */ if (ret != 1) { PRINTERROSSL("Failed to EVP_DigestSignFinal-ize\n"); exit(EXIT_FAILURE); } waitpid(pid, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { PRINTERR("Child failure\n"); exit(EXIT_FAILURE); } } } int main(int argc, char *argv[]) { EVP_PKEY *key; pid_t pid; int status; key = util_gen_key("Fork-Test"); /* test a simple op first */ sign_op(key, -1); /* now fork and see if operations keep succeeding on both sides */ pid = fork(); if (pid == -1) { PRINTERR("Fork failed\n"); exit(EXIT_FAILURE); } /* child just exits in sign_po */ sign_op(key, pid); waitpid(pid, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { PRINTERR("Child failure\n"); exit(EXIT_FAILURE); } fork_sign_op(key); PRINTERR("ALL A-OK!\n"); exit(EXIT_SUCCESS); } pkcs11-provider-1.0/tests/tfork_deadlock.c000066400000000000000000000135421475270623700206070ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #define PRINTERR(...) \ do { \ fprintf(stderr, __VA_ARGS__); \ fflush(stderr); \ } while (0) #define PRINTERROSSL(...) \ do { \ fprintf(stderr, __VA_ARGS__); \ ERR_print_errors_fp(stderr); \ fflush(stderr); \ } while (0) static void sign_op(EVP_PKEY *key) { size_t size = EVP_PKEY_get_size(key); unsigned char sig[size]; const char *data = "Sign Me!"; EVP_MD_CTX *sign_md; int ret; sign_md = EVP_MD_CTX_new(); ret = EVP_DigestSignInit_ex(sign_md, NULL, "SHA256", NULL, NULL, key, NULL); if (ret != 1) { PRINTERROSSL("Failed to init EVP_DigestSign\n"); exit(EXIT_FAILURE); } ret = EVP_DigestSignUpdate(sign_md, data, sizeof(data)); if (ret != 1) { PRINTERROSSL("Failed to EVP_DigestSignUpdate\n"); exit(EXIT_FAILURE); } ret = EVP_DigestSignFinal(sign_md, sig, &size); if (ret != 1) { PRINTERROSSL("Failed to EVP_DigestSignFinal-ize\n"); exit(EXIT_FAILURE); } EVP_MD_CTX_free(sign_md); } static int ui_fork_in_callback(UI *ui, UI_STRING *uis) { const char *pinvalue; enum UI_string_types type; pid_t pid; int status; pinvalue = getenv("PINVALUE"); if (!pinvalue) { fprintf(stderr, "PINVALUE not defined\n"); exit(EXIT_FAILURE); } /* now fork while in the callback to check if we deadlock */ pid = fork(); if (pid == -1) { PRINTERR("Fork failed\n"); exit(EXIT_FAILURE); } if (pid == 0) { PRINTERR("Child Done"); exit(EXIT_SUCCESS); } waitpid(pid, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { PRINTERR("Child failure\n"); exit(EXIT_FAILURE); } type = UI_get_string_type(uis); switch (type) { case UIT_PROMPT: fprintf(stderr, "Prompt: \"%s\"\n", UI_get0_output_string(uis)); fprintf(stderr, "Returning: %s\n", pinvalue); UI_set_result(ui, uis, pinvalue); return 1; default: fprintf(stderr, "Unexpected UI type: %d\n", (int)type); exit(EXIT_FAILURE); } return 0; } #ifdef __APPLE__ /* No sigtimedwait on MacOS, so let's just fail this test */ static int sigtimedwait(const sigset_t *set, siginfo_t *info, const struct timespec *timeout) { errno = EPERM; return -1; } #endif int main(int argc, char *argv[]) { const char *keyuri = NULL; UI_METHOD *ui_method = NULL; OSSL_STORE_CTX *store; OSSL_STORE_INFO *info; EVP_PKEY *key = NULL; sigset_t mask; sigset_t orig_mask; struct timespec timeout; pid_t pid; int status; keyuri = getenv("PRIURI"); /* optional first argument is a PKCS#11 uri of the key to test. * Default is provided by environment variable BASEURI */ if (argc > 1) { keyuri = argv[1]; } if (!keyuri) { fprintf(stderr, "PRIURI not defined\n"); exit(EXIT_FAILURE); } ui_method = UI_create_method("Pin Fork Test"); if (!ui_method) { fprintf(stderr, "Failed to set up UI_METHOD\n"); exit(EXIT_FAILURE); } (void)UI_method_set_reader(ui_method, ui_fork_in_callback); /* prepare timeout handler */ sigemptyset(&mask); sigaddset(&mask, SIGCHLD); status = sigprocmask(SIG_BLOCK, &mask, &orig_mask); if (status == -1) { PRINTERR("Sigprocmask failed\n"); exit(EXIT_FAILURE); } /* now fork so we can monitor the "parent" process */ pid = fork(); if (pid == -1) { PRINTERR("Fork failed\n"); exit(EXIT_FAILURE); } /* controller parent */ if (pid != 0) { /* Wait a max of 5 seconds. Should be enough even on slow * containers */ timeout.tv_sec = 5; timeout.tv_nsec = 0; retry: status = sigtimedwait(&mask, NULL, &timeout); if (status == -1) { if (errno == EINTR) { /* not the right signal */ goto retry; } if (errno == EAGAIN) { PRINTERR("Timeout, Child likely deadlocked!\n"); kill(pid, SIGKILL); exit(EXIT_FAILURE); } PRINTERR("Unknown Error: %d", errno); kill(pid, SIGKILL); exit(EXIT_FAILURE); } waitpid(pid, &status, 0); if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) { PRINTERR("Parent's failure\n"); exit(EXIT_FAILURE); } PRINTERR("ALL A-OK!\n"); UI_destroy_method(ui_method); exit(EXIT_SUCCESS); } /* regular "parent" process (child of controlling parent) */ store = OSSL_STORE_open_ex(keyuri, NULL, "provider=pkcs11", ui_method, NULL, NULL, NULL, NULL); if (store == NULL) { fprintf(stderr, "Failed to open pkcs11 store\n"); exit(EXIT_FAILURE); } for (info = OSSL_STORE_load(store); info != NULL; info = OSSL_STORE_load(store)) { int type = OSSL_STORE_INFO_get_type(info); switch (type) { case OSSL_STORE_INFO_PKEY: key = OSSL_STORE_INFO_get1_PKEY(info); break; default: fprintf(stderr, "Invalid data from store\n"); exit(EXIT_FAILURE); } OSSL_STORE_INFO_free(info); } OSSL_STORE_close(store); if (!key) { fprintf(stderr, "Failed to find key\n"); exit(EXIT_FAILURE); } sign_op(key); EVP_PKEY_free(key); UI_destroy_method(ui_method); PRINTERR("Parent Done"); exit(EXIT_SUCCESS); } pkcs11-provider-1.0/tests/tforking000077500000000000000000000012711475270623700172350ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2024 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" title PARA "Regular forking test" $CHECKER "${TESTBLDDIR}/tfork" # MacOS can't compile the fork_deadlock.c test because it lacks # some POSIX functions ... so we completely disable the test if [ "$(uname)" == "Darwin" ]; then exit 0 fi title PARA "Pinless config file to cause prompting callback in fork deadlock test" ORIG_OPENSSL_CONF=${OPENSSL_CONF} sed "s/^pkcs11-module-token-pin.*$/##nopin/" "${OPENSSL_CONF}" > "${OPENSSL_CONF}.nopin" OPENSSL_CONF=${OPENSSL_CONF}.nopin $CHECKER "${TESTBLDDIR}/tfork_deadlock" OPENSSL_CONF=${ORIG_OPENSSL_CONF} pkcs11-provider-1.0/tests/tgenkey.c000066400000000000000000000425531475270623700173060ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include "util.h" static void check_rsa_key(EVP_PKEY *pubkey) { BIGNUM *tmp = NULL; int ret; ret = EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_E, &tmp); if (ret != 1) { PRINTERR("Failed to get E param from public key\n"); exit(EXIT_FAILURE); } else { BN_free(tmp); tmp = NULL; } ret = EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_RSA_N, &tmp); if (ret != 1) { PRINTERR("Failed to get N param from public key\n"); exit(EXIT_FAILURE); } else { int bits; bits = EVP_PKEY_get_bits(pubkey); if (bits < 3072) { PRINTERR("Expected 3072 bits key, got %d\n", bits); exit(EXIT_FAILURE); } BN_free(tmp); tmp = NULL; } } static void check_ec_key(EVP_PKEY *pubkey) { BIGNUM *tmp = NULL; int ret; ret = EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_EC_PUB_X, &tmp); if (ret != 1) { PRINTERR("Failed to get X param from public key\n"); exit(EXIT_FAILURE); } else { BN_free(tmp); tmp = NULL; } ret = EVP_PKEY_get_bn_param(pubkey, OSSL_PKEY_PARAM_EC_PUB_Y, &tmp); if (ret != 1) { PRINTERR("Failed to get Y param from public key\n"); exit(EXIT_FAILURE); } else { BN_free(tmp); tmp = NULL; } } static void check_eddsa_key(EVP_PKEY *pubkey) { unsigned char *tmp = NULL; size_t len = 0; int ret; ret = EVP_PKEY_get_octet_string_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, NULL, 0, &len); if (ret != 1) { PRINTERR("Failed to get public key size\n"); exit(EXIT_FAILURE); } tmp = malloc(len); if (tmp == NULL) { PRINTERR("Failed to allocate memory for public key\n"); exit(EXIT_FAILURE); } ret = EVP_PKEY_get_octet_string_param(pubkey, OSSL_PKEY_PARAM_PUB_KEY, tmp, len, NULL); if (ret != 1) { PRINTERR("Failed to get public key\n"); exit(EXIT_FAILURE); } else { free(tmp); tmp = NULL; } } static void check_keys(OSSL_STORE_CTX *store, const char *key_type) { OSSL_STORE_INFO *info; EVP_PKEY *pubkey = NULL; EVP_PKEY *privkey = NULL; for (info = OSSL_STORE_load(store); info != NULL; info = OSSL_STORE_load(store)) { int type = OSSL_STORE_INFO_get_type(info); switch (type) { case OSSL_STORE_INFO_PUBKEY: if (pubkey != NULL) { PRINTERR("Duplicate public key found!\n"); exit(EXIT_FAILURE); } pubkey = OSSL_STORE_INFO_get1_PUBKEY(info); break; case OSSL_STORE_INFO_PKEY: if (privkey != NULL) { PRINTERR("Duplicate private key found!\n"); exit(EXIT_FAILURE); } privkey = OSSL_STORE_INFO_get1_PKEY(info); break; } OSSL_STORE_INFO_free(info); } if (pubkey == NULL) { PRINTERR("Failed to load public key\n"); exit(EXIT_FAILURE); } if (privkey == NULL) { PRINTERR("Failed to load private key\n"); exit(EXIT_FAILURE); } /* check we can get pub params from key */ if (strcmp(key_type, "RSA") == 0 || strcmp(key_type, "RSA-PSS") == 0) { check_rsa_key(pubkey); } else if (strcmp(key_type, "EC") == 0) { check_ec_key(pubkey); } else if (strcmp(key_type, "ED25519") == 0 || strcmp(key_type, "ED448") == 0) { check_eddsa_key(pubkey); } EVP_PKEY_free(privkey); EVP_PKEY_free(pubkey); } static void gen_keys(const char *key_type, const char *label, const char *idhex, const OSSL_PARAM *params, bool fail) { EVP_PKEY_CTX *ctx; EVP_PKEY *key = NULL; char *uri; OSSL_STORE_CTX *store; OSSL_STORE_SEARCH *search; int ret; fprintf(stdout, "Generate %s\n", key_type); ctx = EVP_PKEY_CTX_new_from_name(NULL, key_type, "provider=pkcs11"); if (ctx == NULL) { PRINTERR("Failed to init PKEY context\n"); exit(EXIT_FAILURE); } ret = EVP_PKEY_keygen_init(ctx); if (ret != 1) { PRINTERR("Failed to init keygen\n"); exit(EXIT_FAILURE); } ret = EVP_PKEY_CTX_set_params(ctx, params); if (ret != 1) { PRINTERR("Failed to set params\n"); exit(EXIT_FAILURE); } ret = EVP_PKEY_generate(ctx, &key); if (ret != 1) { if (!fail) { PRINTERR("Failed to generate key\n"); exit(EXIT_FAILURE); } EVP_PKEY_CTX_free(ctx); return; } if (fail) { PRINTERR("Key generation unexpectedly succeeded\n"); exit(EXIT_FAILURE); } if (strcmp(key_type, "RSA") == 0 || strcmp(key_type, "RSA-PSS") == 0) { check_rsa_key(key); } else if (strcmp(key_type, "EC") == 0) { check_ec_key(key); } else if (strcmp(key_type, "ED25519") == 0 || strcmp(key_type, "ED448") == 0) { check_eddsa_key(key); } EVP_PKEY_free(key); key = NULL; EVP_PKEY_CTX_free(ctx); ctx = NULL; /* now try to search by id */ fprintf(stdout, "Search by ID\n"); ret = asprintf(&uri, "pkcs11:id=%s", idhex); if (ret == -1) { PRINTERR("Failed to allocate uri\n"); exit(EXIT_FAILURE); } store = OSSL_STORE_open(uri, NULL, NULL, NULL, NULL); if (store == NULL) { PRINTERR("Failed to open pkcs11 store\n"); exit(EXIT_FAILURE); } free(uri); check_keys(store, key_type); OSSL_STORE_close(store); /* now make sure we can filter by label */ fprintf(stdout, "Search by Label\n"); store = OSSL_STORE_open("pkcs11:", NULL, NULL, NULL, NULL); if (store == NULL) { PRINTERR("Failed to open pkcs11 store\n"); exit(EXIT_FAILURE); } search = OSSL_STORE_SEARCH_by_alias(label); if (search == NULL) { PRINTERR("Failed to create store search filter\n"); exit(EXIT_FAILURE); } ret = OSSL_STORE_find(store, search); if (ret != 1) { PRINTERR("Failed to set store search filter\n"); exit(EXIT_FAILURE); } OSSL_STORE_SEARCH_free(search); check_keys(store, key_type); OSSL_STORE_close(store); } static void sign_test(const char *label, const char *mdname, const OSSL_PARAM *params, bool fail) { OSSL_STORE_CTX *store; OSSL_STORE_SEARCH *search; OSSL_STORE_INFO *info; EVP_PKEY *privkey = NULL; EVP_MD_CTX *ctx = NULL; EVP_PKEY_CTX *pctx = NULL; const unsigned char data[] = "Plaintext Data"; unsigned char sigret[4096]; size_t siglen = 4096; int ret; fprintf(stdout, "Test signature\n"); store = OSSL_STORE_open("pkcs11:", NULL, NULL, NULL, NULL); if (store == NULL) { PRINTERR("Failed to open pkcs11 store\n"); exit(EXIT_FAILURE); } search = OSSL_STORE_SEARCH_by_alias(label); if (search == NULL) { PRINTERR("Failed to create store search filter\n"); exit(EXIT_FAILURE); } ret = OSSL_STORE_find(store, search); if (ret != 1) { PRINTERR("Failed to set store search filter\n"); exit(EXIT_FAILURE); } OSSL_STORE_SEARCH_free(search); for (info = OSSL_STORE_load(store); info != NULL; info = OSSL_STORE_load(store)) { int type = OSSL_STORE_INFO_get_type(info); if (type == OSSL_STORE_INFO_PKEY) { privkey = OSSL_STORE_INFO_get1_PKEY(info); OSSL_STORE_INFO_free(info); break; } OSSL_STORE_INFO_free(info); } OSSL_STORE_close(store); if (privkey == NULL) { PRINTERR("Failed to load private key\n"); exit(EXIT_FAILURE); } ctx = EVP_MD_CTX_new(); if (!ctx) { PRINTERR("Failed to init MD_CTX\n"); exit(EXIT_FAILURE); } ret = EVP_DigestSignInit_ex(ctx, &pctx, mdname, NULL, NULL, privkey, params); if (ret == 0) { PRINTERR("Failed to init Sig Ctx\n"); exit(EXIT_FAILURE); } ret = EVP_DigestSign(ctx, sigret, &siglen, data, sizeof(data)); if (ret == 0) { if (!fail) { PRINTERR("Failed to generate signature\n"); exit(EXIT_FAILURE); } } else { if (fail) { PRINTERR("Expected failure, but signature worked\n"); exit(EXIT_FAILURE); } } EVP_PKEY_free(privkey); EVP_MD_CTX_free(ctx); } static char *tokenize(char **result, int max, char *str) { char *copy; char *ptr; char *saveptr; int num = 0; copy = strdup(str); if (!copy) { PRINTERR("strdup failed\n"); exit(EXIT_FAILURE); } ptr = copy; saveptr = NULL; while (num < max) { char *tok = strtok_r(ptr, ",", &saveptr); ptr = NULL; if (tok == NULL) { break; } result[num] = strdup(tok); if (!result[num]) { PRINTERR("strdup failed\n"); exit(EXIT_FAILURE); } num++; } result[num] = NULL; return copy; } static void freetokens(char **tokens) { for (int num = 0; tokens[num] != NULL; num++) { free(tokens[num]); tokens[num] = NULL; } } int main(int argc, char *argv[]) { char *tests[11] = { 0 }; char *label; unsigned char id[16]; char idhex[16 * 3 + 1]; char *uri; size_t rsa_bits = 3072; const char *key_usage = "dataEncipherment keyEncipherment"; const char *bad_usage = "dataEncipherment gibberish "; char *copy = NULL; OSSL_PARAM params[4]; int miniid; int num; int ret; if (argc > 1) { copy = tokenize(tests, 10, argv[1]); } for (num = 0; num < 10 && tests[num] != NULL; num++) { if (strcmp(tests[num], "RSA") == 0) { ret = RAND_bytes(id, 16); if (ret != 1) { PRINTERR("Failed to generate key id\n"); exit(EXIT_FAILURE); } miniid = (id[0] << 24) + (id[1] << 16) + (id[2] << 8) + id[3]; ret = asprintf(&label, "Test-RSA-gen-%08x", miniid); if (ret == -1) { PRINTERR("Failed to make label\n"); exit(EXIT_FAILURE); } hexify(idhex, id, 16); ret = asprintf(&uri, "pkcs11:object=%s;id=%s", label, idhex); if (ret == -1) { PRINTERR("Failed to compose PKCS#11 URI\n"); exit(EXIT_FAILURE); } params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0); params[1] = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_RSA_BITS, &rsa_bits); params[2] = OSSL_PARAM_construct_end(); gen_keys("RSA", label, idhex, params, false); sign_test(label, "SHA256", NULL, false); free(label); free(uri); } else if (strcmp(tests[num], "RSA-PSS") == 0) { ret = RAND_bytes(id, 16); if (ret != 1) { PRINTERR("Failed to generate key id\n"); exit(EXIT_FAILURE); } miniid = (id[0] << 24) + (id[1] << 16) + (id[2] << 8) + id[3]; ret = asprintf(&label, "Test-RSA-PSS-gen-%08x", miniid); if (ret == -1) { PRINTERR("Failed to make label\n"); exit(EXIT_FAILURE); } hexify(idhex, id, 16); ret = asprintf(&uri, "pkcs11:object=%s;id=%s", label, idhex); if (ret == -1) { PRINTERR("Failed to compose PKCS#11 URI\n"); exit(EXIT_FAILURE); } params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0); params[1] = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_RSA_BITS, &rsa_bits); params[2] = OSSL_PARAM_construct_utf8_string("rsa_pss_keygen_md", (char *)"SHA256", 0); params[3] = OSSL_PARAM_construct_end(); gen_keys("RSA-PSS", label, idhex, params, false); free(label); free(uri); } else if (strcmp(tests[num], "EC") == 0) { ret = RAND_bytes(id, 16); if (ret != 1) { PRINTERR("Failed to generate key id\n"); exit(EXIT_FAILURE); } miniid = (id[0] << 24) + (id[1] << 16) + (id[2] << 8) + id[3]; ret = asprintf(&label, "Test-EC-gen-%08x", miniid); if (ret == -1) { PRINTERR("Failed to make label\n"); exit(EXIT_FAILURE); } hexify(idhex, id, 16); ret = asprintf(&uri, "pkcs11:object=%s;id=%s", label, idhex); if (ret == -1) { PRINTERR("Failed to compose PKCS#11 URI\n"); exit(EXIT_FAILURE); } params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0); params[1] = OSSL_PARAM_construct_utf8_string("ec_paramgen_curve", (char *)"P-256", 0); params[2] = OSSL_PARAM_construct_end(); gen_keys("EC", label, idhex, params, false); sign_test(label, "SHA256", NULL, false); free(label); free(uri); } else if (strcmp(tests[num], "RSAKeyUsage") == 0) { ret = RAND_bytes(id, 16); if (ret != 1) { PRINTERR("Failed to generate key id\n"); exit(EXIT_FAILURE); } miniid = (id[0] << 24) + (id[1] << 16) + (id[2] << 8) + id[3]; ret = asprintf(&label, "Test-RSA-Key-Usage-%08x", miniid); if (ret == -1) { PRINTERR("Failed to make label\n"); exit(EXIT_FAILURE); } hexify(idhex, id, 16); ret = asprintf(&uri, "pkcs11:object=%s;id=%s", label, idhex); if (ret == -1) { PRINTERR("Failed to compose PKCS#11 URI\n"); exit(EXIT_FAILURE); } params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0); params[1] = OSSL_PARAM_construct_utf8_string("pkcs11_key_usage", (char *)key_usage, 0); params[2] = OSSL_PARAM_construct_size_t(OSSL_PKEY_PARAM_RSA_BITS, &rsa_bits); params[3] = OSSL_PARAM_construct_end(); gen_keys("RSA", label, idhex, params, false); sign_test(label, "SHA256", NULL, true); params[1] = OSSL_PARAM_construct_utf8_string("pkcs11_key_usage", (char *)bad_usage, 0); gen_keys("RSA", label, idhex, params, true); free(label); free(uri); } else if (strcmp(tests[num], "ED25519") == 0 || strcmp(tests[num], "ED448") == 0) { const char *context = "context string"; const char *instance = "Ed25519ph"; if (strcmp(tests[num], "ED448") == 0) { instance = "Ed448ph"; } ret = RAND_bytes(id, 16); if (ret != 1) { PRINTERR("Failed to generate key id\n"); exit(EXIT_FAILURE); } miniid = (id[0] << 24) + (id[1] << 16) + (id[2] << 8) + id[3]; ret = asprintf(&label, "Test-Ed-gen-%08x", miniid); if (ret == -1) { PRINTERR("Failed to make label\n"); exit(EXIT_FAILURE); } hexify(idhex, id, 16); ret = asprintf(&uri, "pkcs11:object=%s;id=%s", label, idhex); if (ret == -1) { PRINTERR("Failed to compose PKCS#11 URI\n"); exit(EXIT_FAILURE); } params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0); params[1] = OSSL_PARAM_construct_end(); gen_keys(tests[num], label, idhex, params, false); sign_test(label, NULL, NULL, false); /* these are not defined in OpenSSL 3.0 so just skip the test */ #ifdef OSSL_SIGNATURE_PARAM_CONTEXT_STRING /* Test again with context string */ params[0] = OSSL_PARAM_construct_octet_string( OSSL_SIGNATURE_PARAM_CONTEXT_STRING, (void *)context, sizeof(context)); params[1] = OSSL_PARAM_construct_end(); sign_test(label, NULL, params, false); /* Test again with prehash */ params[0] = OSSL_PARAM_construct_utf8_string( OSSL_SIGNATURE_PARAM_INSTANCE, (char *)instance, strlen(instance)); params[1] = OSSL_PARAM_construct_end(); sign_test(label, NULL, params, false); #else (void)instance; (void)context; #endif free(label); free(uri); } else { PRINTERR("Unknown test type [%s]\n", tests[num]); exit(EXIT_FAILURE); } } freetokens(tests); free(copy); PRINTERR("Performed tests: %d\n", num); exit(EXIT_SUCCESS); } pkcs11-provider-1.0/tests/thkdf000077500000000000000000000036311475270623700165140ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2022 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" title PARA "HKDF Derivation" export HKDF_HEX_SECRET=ffeeddccbbaa export HKDF_HEX_SALT=ffeeddccbbaa export HKDF_HEX_INFO=ffeeddccbbaa ossl ' pkeyutl -derive -kdf HKDF -kdflen 48 -pkeyopt md:SHA256 -pkeyopt mode:EXTRACT_AND_EXPAND -pkeyopt hexkey:${HKDF_HEX_SECRET} -pkeyopt hexsalt:${HKDF_HEX_SALT} -pkeyopt hexinfo:${HKDF_HEX_INFO} -out ${TMPPDIR}/hkdf1-out-pkcs11.bin -propquery provider=pkcs11' ossl ' pkeyutl -derive -kdf HKDF -kdflen 48 -pkeyopt md:SHA256 -pkeyopt mode:EXTRACT_AND_EXPAND -pkeyopt hexkey:${HKDF_HEX_SECRET} -pkeyopt hexsalt:${HKDF_HEX_SALT} -pkeyopt hexinfo:${HKDF_HEX_INFO} -out ${TMPPDIR}/hkdf1-out.bin' diff "${TMPPDIR}/hkdf1-out-pkcs11.bin" "${TMPPDIR}/hkdf1-out.bin" export HKDF_HEX_SECRET=6dc3bcf529a350e0423befb3deef8aef78d912c4f1dc3e6e52bf61f681e40904 export HKDF_SALT="I'm a Salt!" export HKDF_INFO="And I'm an Info?" ossl ' pkeyutl -derive -kdf HKDF -kdflen 48 -pkeyopt md:SHA256 -pkeyopt mode:EXTRACT_AND_EXPAND -pkeyopt hexkey:${HKDF_HEX_SECRET} -pkeyopt salt:"${HKDF_SALT}" -pkeyopt info:"${HKDF_INFO}" -out ${TMPPDIR}/hkdf2-out-pkcs11.bin -propquery provider=pkcs11' ossl ' pkeyutl -derive -kdf HKDF -kdflen 48 -pkeyopt md:SHA256 -pkeyopt mode:EXTRACT_AND_EXPAND -pkeyopt hexkey:${HKDF_HEX_SECRET} -pkeyopt salt:"${HKDF_SALT}" -pkeyopt info:"${HKDF_INFO}" -out ${TMPPDIR}/hkdf2-out.bin' diff "${TMPPDIR}/hkdf2-out-pkcs11.bin" "${TMPPDIR}/hkdf2-out.bin" pkcs11-provider-1.0/tests/timported000077500000000000000000000046621475270623700174300ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2024 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" title PARA "Test imported key in token session" title LINE "Generate EC keypair in files" # older versions of openssl don't support -outpubkey ... #ossl 'genpkey -algorithm EC -out ${TMPPDIR}/file.ec.key.pem # -pkeyopt ec_paramgen_curve:P-256 # -pkeyopt ec_param_enc:named_curve # -outpubkey ${TMPPDIR}/file.ec.pub.key.pem' # .. so we'll use two steps ossl 'genpkey -algorithm EC -out ${TMPPDIR}/file.ec.key.pem -pkeyopt ec_paramgen_curve:P-256' ossl 'pkey -in ${TMPPDIR}/file.ec.key.pem -pubout -out ${TMPPDIR}/file.ec.pub.key.pem' title LINE "Generate RSA keypair in files" # older versions of openssl don't support -outpubkey ... # .. so we'll use two steps export OPTS="" if [[ "${SUPPORT_RSA_KEYGEN_PUBLIC_EXPONENT}" = "1" ]]; then export OPTS="-pkeyopt rsa_keygen_pubexp:3" fi ossl 'genpkey -algorithm RSA -out ${TMPPDIR}/file.rsa.key.pem -pkeyopt rsa_keygen_bits:2048 ${OPTS}' ossl 'pkey -in ${TMPPDIR}/file.rsa.key.pem -pubout -out ${TMPPDIR}/file.rsa.pub.key.pem' #After key generation force all operations to happen on the token ORIG_OPENSSL_CONF=${OPENSSL_CONF} sed -e "s/#MORECONF/alg_section = algorithm_sec\n\n[algorithm_sec]\ndefault_properties = ?provider=pkcs11/" \ "${OPENSSL_CONF}" > "${OPENSSL_CONF}.forcetoken" OPENSSL_CONF=${OPENSSL_CONF}.forcetoken title LINE "Test Signing with private EC key imported from file" ossl 'pkeyutl -sign -inkey ${TMPPDIR}/file.ec.key.pem -in ${TMPPDIR}/sha256.bin -out ${TMPPDIR}/file.ec.sig.bin' title LINE "Test Verifying with public EC key imported from file" ossl 'pkeyutl -verify -pubin -inkey ${TMPPDIR}/file.ec.pub.key.pem -sigfile ${TMPPDIR}/file.ec.sig.bin -in ${TMPPDIR}/sha256.bin' title LINE "Test Signing with private RSA key imported from file" ossl 'pkeyutl -sign -inkey ${TMPPDIR}/file.rsa.key.pem -in ${TMPPDIR}/sha256.bin -out ${TMPPDIR}/file.rsa.sig.bin' title LINE "Test Verifying with public RSA key imported from file" ossl 'pkeyutl -verify -pubin -inkey ${TMPPDIR}/file.rsa.pub.key.pem -sigfile ${TMPPDIR}/file.rsa.sig.bin -in ${TMPPDIR}/sha256.bin' OPENSSL_CONF=${ORIG_OPENSSL_CONF} exit 0 pkcs11-provider-1.0/tests/tlsctx.c000066400000000000000000000066041475270623700171560ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include "util.h" static void test_pkcs1_with_tls_padding(void) { EVP_PKEY_CTX *ctx; EVP_PKEY *prikey; EVP_PKEY *pubkey; unsigned char plain[SSL_MAX_MASTER_KEY_LENGTH] = { 0x03, 0x03, 0x01 }; unsigned char enc[1024]; unsigned char dec[1024]; size_t enclen; size_t declen; unsigned int ver = 0x0303; const OSSL_PARAM ver_params[] = { OSSL_PARAM_uint(OSSL_ASYM_CIPHER_PARAM_TLS_CLIENT_VERSION, &ver), OSSL_PARAM_END }; int err; pubkey = load_key(getenv("PUBURI")); ctx = EVP_PKEY_CTX_new_from_pkey(NULL, pubkey, NULL); if (!ctx) { fprintf(stderr, "Failed to init pkey ctx for puburi\n"); ossl_err_print(); exit(EXIT_FAILURE); } err = EVP_PKEY_encrypt_init(ctx); if (err != 1) { fprintf(stderr, "Failed to init encrypt ctx\n"); ossl_err_print(); exit(EXIT_FAILURE); } err = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_PADDING); if (err != 1) { fprintf(stderr, "Failed to set padding on encrypt ctx\n"); ossl_err_print(); exit(EXIT_FAILURE); } enclen = sizeof(enc); err = EVP_PKEY_encrypt(ctx, enc, &enclen, plain, sizeof(plain)); if (err != 1) { fprintf(stderr, "Failed to encrypt TLS master key\n"); ossl_err_print(); exit(EXIT_FAILURE); } EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(pubkey); prikey = load_key(getenv("PRIURI")); ctx = EVP_PKEY_CTX_new_from_pkey(NULL, prikey, NULL); if (!ctx) { fprintf(stderr, "Failed to init pkey ctx for priuri\n"); ossl_err_print(); exit(EXIT_FAILURE); } err = EVP_PKEY_decrypt_init(ctx); if (err != 1) { fprintf(stderr, "Failed to init decrypt ctx\n"); ossl_err_print(); exit(EXIT_FAILURE); } err = EVP_PKEY_CTX_set_rsa_padding(ctx, RSA_PKCS1_WITH_TLS_PADDING); if (err != 1) { fprintf(stderr, "Failed to set padding on decrypt ctx\n"); ossl_err_print(); exit(EXIT_FAILURE); } err = EVP_PKEY_CTX_set_params(ctx, ver_params); if (err != 1) { fprintf(stderr, "Failed to set version params\n"); ossl_err_print(); exit(EXIT_FAILURE); } declen = sizeof(dec); err = EVP_PKEY_decrypt(ctx, dec, &declen, enc, enclen); if (err != 1) { fprintf(stderr, "Failed to decrypt TLS master key\n"); ossl_err_print(); exit(EXIT_FAILURE); } EVP_PKEY_CTX_free(ctx); EVP_PKEY_free(prikey); if ((declen != sizeof(plain)) || (memcmp(plain, dec, declen) != 0)) { fprintf(stderr, "Fail, decrypted master secret differs from input\n"); ossl_err_print(); exit(EXIT_FAILURE); } } int main(int argc, char *argv[]) { SSL_CTX *ctx; char *env; ctx = SSL_CTX_new(TLS_server_method()); if (!ctx) { fprintf(stderr, "Failed to create SSL Context\n"); ossl_err_print(); exit(EXIT_FAILURE); } fprintf(stderr, "SSL Context works!\n"); SSL_CTX_free(ctx); env = getenv("SUPPORT_RSA_PKCS1_ENCRYPTION"); if (env && env[0] == '1') { test_pkcs1_with_tls_padding(); } exit(EXIT_SUCCESS); } pkcs11-provider-1.0/tests/tlssetkey.c000066400000000000000000000024061475270623700176600ustar00rootroot00000000000000/* Copyright (C) 2024 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include "util.h" int main(int argc, char *argv[]) { EVP_PKEY *pkey = NULL; X509 *cert = NULL; SSL_CTX *ctx; int ret = 0; if (argc != 3) { fprintf(stderr, "Usage: tlssetkey [certuri] [pkeyuri]\n"); exit(EXIT_FAILURE); } cert = load_cert(argv[1], NULL, NULL); pkey = load_key(argv[2]); ctx = SSL_CTX_new(TLS_client_method()); if (!ctx) { fprintf(stderr, "Failed to create SSL Context\n"); ossl_err_print(); exit(EXIT_FAILURE); } ret = SSL_CTX_use_certificate(ctx, cert); if (ret != 1) { fprintf(stderr, "Failed to set Certificate"); ossl_err_print(); exit(EXIT_FAILURE); } ret = SSL_CTX_use_PrivateKey(ctx, pkey); if (ret != 1) { fprintf(stderr, "Failed to set Private Key"); ossl_err_print(); exit(EXIT_FAILURE); } fprintf(stderr, "Cert and Key successfully set on TLS Context!\n"); SSL_CTX_free(ctx); EVP_PKEY_free(pkey); X509_free(cert); exit(EXIT_SUCCESS); } pkcs11-provider-1.0/tests/toaepsha2000077500000000000000000000015531475270623700173030ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2022 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" SECRETFILE=${TMPPDIR}/rsa-oaep-secret.txt echo "Super Secret" > "${SECRETFILE}" title PARA "Encrypt and decrypt with RSA OAEP" # Let openssl encrypt by importing the public key ossl ' pkeyutl -encrypt -inkey "${BASEURI}" -pubin -pkeyopt pad-mode:oaep -pkeyopt digest:sha256 -pkeyopt mgf1-digest:sha256 -in ${SECRETFILE} -out ${SECRETFILE}.enc' ossl ' pkeyutl -decrypt -inkey "${PRIURI}" -pkeyopt pad-mode:oaep -pkeyopt digest:sha256 -pkeyopt mgf1-digest:sha256 -in ${SECRETFILE}.enc -out ${SECRETFILE}.dec' diff "${SECRETFILE}" "${SECRETFILE}.dec" pkcs11-provider-1.0/tests/top_state000077500000000000000000000023271475270623700174170ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2022 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" title PARA "OSSL error stack has error from failing C_Get/SetOperationState" # We need to configure early loading otherwise no digests are loaded, # and all checks are skipped sed "s/#pkcs11-module-load-behavior/pkcs11-module-load-behavior = early/" \ "${OPENSSL_CONF}" > "${OPENSSL_CONF}.op_state.early_load" OPENSSL_CONF=${OPENSSL_CONF}.op_state.early_load $CHECKER ./tdigest_dupctx | grep -e "error:.*:pkcs11::reason(84)" title PARA "No error is logged when quirk no-operation-state is enabled" sed "s/pkcs11-module-quirks = /pkcs11-module-quirks = no-operation-state /" \ "${OPENSSL_CONF}" > "${OPENSSL_CONF}.no_op_state" OPENSSL_CONF=${OPENSSL_CONF}.no_op_state title PARA "Test Digests support" $CHECKER ./tdigest_dupctx | grep -e "error:.*:lib(0)::reason(0)" title PARA "No errors occur with no-session-callbacks quirk enabled" sed "s/pkcs11-module-quirks = /pkcs11-module-quirks = no-session-callbacks /" \ "${OPENSSL_CONF}" > "${OPENSSL_CONF}.no_callbacks" OPENSSL_CONF=${OPENSSL_CONF}.no_callbacks $CHECKER ./tdigest_dupctx | grep -e "error:.*:lib(0)::reason(0)" exit 0 pkcs11-provider-1.0/tests/tpem_encoder000077500000000000000000000145701475270623700200640ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2022 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" # Forward declaration to avoid shellcheck's SC2153 did you mean ... : "${PRIURI:?}" "${ECPRIURI:?}" "${EDPRIURI:=}" : "${PUBURI:?}" "${ECPUBURI:?}" "${EDPUBURI:=}" # We need to configure early loading otherwise no digests are loaded, # and all checks are skipped sed -e "s/#pkcs11-module-encode-provider-uri-to-pem/pkcs11-module-encode-provider-uri-to-pem = true/" \ -e "s/#pkcs11-module-load-behavior/pkcs11-module-load-behavior = early/" \ "${OPENSSL_CONF}" > "${OPENSSL_CONF}.encode_to_pem" OPENSSL_CONF=${OPENSSL_CONF}.encode_to_pem make-uri-pem() { export LC_ALL=C URI=$1 OUT=$2 DESC="${3:-PKCS#11 Provider URI v1.0}" DESC_HEX=$(printf '%s' "${DESC}" | od -An -t x1) URI_HEX=$(printf '%s' "${URI}" | od -An -t x1) PEM_HEX=$(printf '30 82 %04x 1a 82 %04x %s 0c 82 %04x %s' \ "$((${#URI} + ${#DESC} + 8))" \ "${#DESC}" \ "${DESC_HEX[*]}" \ "${#URI}" \ "${URI_HEX[*]}" \ | tr -d '\r\n\t ' \ | sed -e 's,\(.\{2\}\),\\x\1,g') { echo "-----BEGIN PKCS#11 PROVIDER URI-----" # shellcheck disable=SC2059 # printf should treat variable as format string printf "${PEM_HEX}" | base64 echo "-----END PKCS#11 PROVIDER URI-----" } > "${OUT}" } sign-verify() { PRIV_KEY=$1 PUB_KEY=$2 FILE=$3 NO_DIGEST=$4 RANDOM_HEX=$(od -A n -N 15 -t x1 /dev/random) TMP_FILE="${TMPPDIR}/sign-verify-pem-encoder-${RANDOM_HEX// /}.bin" if [[ -z "${NO_DIGEST}" ]]; then $CHECKER openssl pkeyutl -sign -rawin -digest sha256 \ -inkey "${PRIV_KEY}" \ -in "${FILE}" \ -out "${TMP_FILE}" $CHECKER openssl pkeyutl -verify -rawin -digest sha256 \ -inkey "${PUB_KEY}" \ -pubin \ -in "${FILE}" \ -sigfile "${TMP_FILE}" else $CHECKER openssl pkeyutl -sign -rawin \ -inkey "${PRIV_KEY}" \ -in "${FILE}" \ -out "${TMP_FILE}" $CHECKER openssl pkeyutl -verify -rawin \ -inkey "${PUB_KEY}" \ -pubin \ -in "${FILE}" \ -sigfile "${TMP_FILE}" fi; rm "${TMP_FILE}" } RANDOM_HEX=$(od -A n -N 15 -t x1 /dev/random) export LABEL_SUFFIX_URI=${RANDOM_HEX// /} title PARA "Test PEM Encoding RSA support" make-uri-pem "${PRIURI}" "${TMPPDIR}/priuri-pkey.pem" sign-verify "${TMPPDIR}/priuri-pkey.pem" "${PUBURI}" "${TMPPDIR}/64krandom.bin" export ALGORITHM=rsa export ALGORITHM_OPT=rsa_keygen_bits:2048 ossl ' genpkey -propquery "provider=pkcs11" -algorithm "${ALGORITHM}" -pkeyopt "${ALGORITHM_OPT}" -pkeyopt "pkcs11_uri:pkcs11:object=Test-PEM-Encode-RSA-${LABEL_SUFFIX_URI}" -out "${TMPPDIR}/rsa-pkey-uri.pem"' grep -e "-----BEGIN PKCS#11 PROVIDER URI-----" "${TMPPDIR}/rsa-pkey-uri.pem" sign-verify "${TMPPDIR}/rsa-pkey-uri.pem" \ "pkcs11:object=Test-PEM-Encode-RSA-${LABEL_SUFFIX_URI}" \ "${TMPPDIR}/64krandom.bin" title PARA "Test PEM Encoding EC support" make-uri-pem "${ECPRIURI}" "${TMPPDIR}/ecpriuri-pkey.pem" sign-verify "${TMPPDIR}/ecpriuri-pkey.pem" "${ECPUBURI}" "${TMPPDIR}/64krandom.bin" export ALGORITHM=EC export ALGORITHM_OPT=ec_paramgen_curve:prime256v1 ossl ' genpkey -propquery "provider=pkcs11" -algorithm "${ALGORITHM}" -pkeyopt "${ALGORITHM_OPT}" -pkeyopt "pkcs11_uri:pkcs11:object=Test-PEM-Encode-EC-${LABEL_SUFFIX_URI}" -out "${TMPPDIR}/ec-pkey-uri.pem"' grep -e "-----BEGIN PKCS#11 PROVIDER URI-----" "${TMPPDIR}/ec-pkey-uri.pem" sign-verify "${TMPPDIR}/ec-pkey-uri.pem" \ "pkcs11:object=Test-PEM-Encode-EC-${LABEL_SUFFIX_URI}" \ "${TMPPDIR}/64krandom.bin" # Only run ED test if setup created ed key if [[ -n "${EDPRIURI}" ]]; then title PARA "Test PEM Encoding ED support" make-uri-pem "${EDPRIURI}" "${TMPPDIR}/ed25519priuri-pkey.pem" sign-verify "${TMPPDIR}/ed25519priuri-pkey.pem" "${EDPUBURI}" "${TMPPDIR}/64krandom.bin" "no-digest" export ALGORITHM=ED25519 ossl ' genpkey -propquery "provider=pkcs11" -algorithm "${ALGORITHM}" -pkeyopt "pkcs11_uri:pkcs11:object=Test-PEM-Encode-ED25519-${LABEL_SUFFIX_URI}" -out "${TMPPDIR}/ed25519-pkey-uri.pem"' grep -e "-----BEGIN PKCS#11 PROVIDER URI-----" "${TMPPDIR}/ed25519-pkey-uri.pem" sign-verify "${TMPPDIR}/ed25519-pkey-uri.pem" \ "pkcs11:object=Test-PEM-Encode-ED25519-${LABEL_SUFFIX_URI}" \ "${TMPPDIR}/64krandom.bin" "no-digest" else title PARA "Skipping Test PEM Encoding ED support" fi; title PARA "Test visible string has to match" make-uri-pem "${PRIURI}" "${TMPPDIR}/priuri-wrong-version-key.pem" "PKCS#11 Provider URI v2.0" ossl ' storeutl -out "${TMPPDIR}/storeutl-priuri-wrong-version-key.txt" "${TMPPDIR}/priuri-wrong-version-key.pem"' || : DATA=$(cat "${TMPPDIR}/storeutl-priuri-wrong-version-key.txt") if [[ ! ${DATA} =~ "Total found: 0" ]]; then echo "Should fail because visible string does not match" exit 1 fi make-uri-pem "${PRIURI}" "${TMPPDIR}/priuri-too-long-key.pem" "PKCS#11 Provider URI v1.0-INVALID" ossl ' storeutl -out "${TMPPDIR}/storeutl-priuri-too-long-key.txt" "${TMPPDIR}/priuri-too-long-key.pem"' || : DATA=$(cat "${TMPPDIR}/storeutl-priuri-too-long-key.txt") if [[ ! ${DATA} =~ "Total found: 0" ]]; then echo "Should fail because visible string does not match" exit 1 fi make-uri-pem "${PRIURI}" "${TMPPDIR}/priuri-too-short-key.pem" "PKCS#11 Provider URI v1" ossl ' storeutl -out "${TMPPDIR}/storeutl-priuri-too-short-key.txt" "${TMPPDIR}/priuri-too-short-key.pem"' || : DATA=$(cat "${TMPPDIR}/storeutl-priuri-too-short-key.txt") if [[ ! ${DATA} =~ "Total found: 0" ]]; then echo "Should fail because visible string does not match" exit 1 fi title PARA "Test public key is usable" make-uri-pem "${PUBURI}" "${TMPPDIR}/puburi-key.pem" ossl ' storeutl -out "${TMPPDIR}/storeutl-puburi-key.txt" "${TMPPDIR}/puburi-key.pem"' DATA=$(cat "${TMPPDIR}/storeutl-puburi-key.txt") if [[ ! ${DATA} =~ "Total found: 1" ]]; then echo "Should return public key" exit 1 fi exit 0 pkcs11-provider-1.0/tests/tpinlock000077500000000000000000000043151475270623700172370ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2024 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" title PARA "Test PIN lock prevention" ORIG_OPENSSL_CONF=${OPENSSL_CONF} sed "s/^pkcs11-module-token-pin.*$/##nopin/" "${OPENSSL_CONF}" > "${OPENSSL_CONF}.nopin" OPENSSL_CONF=${OPENSSL_CONF}.nopin BADPIN="bad" export BADPINURI="${PRIURI}?pin-value=${BADPIN}" export GOODPINURI="${PRIURI}?pin-value=${PINVALUE}" TOOLDEFARGS=("--module=${P11LIB}" "--token-label=${TOKENLABEL}") FAIL=0 pkcs11-tool "${TOOLDEFARGS[@]}" -T | grep "PIN initialized" && FAIL=1 if [ $FAIL -eq 0 ]; then echo "Failed to detect PIN status" exit 1 fi # Kryoptic allows for 10 tries by default for i in {1..10}; do echo "Login attempt: $i" pkcs11-tool "${TOOLDEFARGS[@]}" -l -I -p "${BADPIN}" && false DETECT=0 pkcs11-tool "${TOOLDEFARGS[@]}" -T | grep "final user PIN try" && DETECT=1 if [ $DETECT -eq 1 ]; then break fi done FAIL=0 pkcs11-tool "${TOOLDEFARGS[@]}" -T | grep "final user PIN try" && FAIL=1 if [ $FAIL -eq 0 ]; then echo "Failed to reach "final try" status" exit 1 fi # Now we test one operation with a bad pin. # It should fail but not lock the token title LINE "Try op with bad pin and fail" FAIL=0 ossl ' pkeyutl -sign -inkey "${BADPINURI}" -in ${TMPPDIR}/sha256.bin -out ${TMPPDIR}/pinlock-sig.bin' || FAIL=1 if [ $FAIL -eq 0 ]; then echo "Operation should have failed, pin lock prevention not working" exit 1 fi # Now we test one operation with a good pin. # It should fail because the token is on last try title LINE "Try op with good pin and fail" FAIL=0 ossl ' pkeyutl -sign -inkey "${GOODPINURI}" -in ${TMPPDIR}/sha256.bin -out ${TMPPDIR}/pinlock-sig.bin' || FAIL=1 if [ $FAIL -eq 0 ]; then echo "Operation should have failed, pin lock prevention not working" exit 1 fi # Now reset the token counter with a good try pkcs11-tool "${TOOLDEFARGS[@]}" -l -T -p "${PINVALUE}" # Now we test one operation with a good pin. # It should succeed title LINE "Try op with good pin and succeed" ossl ' pkeyutl -sign -inkey "${GOODPINURI}" -in ${TMPPDIR}/sha256.bin -out ${TMPPDIR}/pinlock-sig.bin' OPENSSL_CONF=${ORIG_OPENSSL_CONF} pkcs11-provider-1.0/tests/tpkey.c000066400000000000000000000066201475270623700167670ustar00rootroot00000000000000/* Copyright (C) 2025 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include #include #include "util.h" static void sign_op(EVP_PKEY *key, const char *data, size_t len, unsigned char **signature, size_t *siglen) { size_t size = EVP_PKEY_get_size(key); unsigned char *sig; EVP_MD_CTX *sign_md; int ret; sig = OPENSSL_zalloc(size); if (!sig) { PRINTERROSSL("Failed to allocate signature buffer\n"); exit(EXIT_FAILURE); } *signature = sig; *siglen = size; sign_md = EVP_MD_CTX_new(); ret = EVP_DigestSignInit_ex(sign_md, NULL, "SHA256", NULL, NULL, key, NULL); if (ret != 1) { PRINTERROSSL("Failed to init EVP_DigestSign\n"); exit(EXIT_FAILURE); } ret = EVP_DigestSignUpdate(sign_md, data, len); if (ret != 1) { PRINTERROSSL("Failed to EVP_DigestSignUpdate\n"); exit(EXIT_FAILURE); } ret = EVP_DigestSignFinal(sign_md, sig, siglen); if (ret != 1) { PRINTERROSSL("Failed to EVP_DigestSignFinal-ize\n"); exit(EXIT_FAILURE); } EVP_MD_CTX_free(sign_md); } static void verify_op(EVP_PKEY *key, const char *data, size_t len, unsigned char *signature, size_t siglen) { EVP_MD_CTX *ver_md; int ret; ver_md = EVP_MD_CTX_new(); ret = EVP_DigestVerifyInit_ex(ver_md, NULL, "SHA256", NULL, NULL, key, NULL); if (ret != 1) { PRINTERROSSL("Failed to init EVP_DigestVerify\n"); exit(EXIT_FAILURE); } ret = EVP_DigestVerifyUpdate(ver_md, data, len); if (ret != 1) { PRINTERROSSL("Failed to EVP_DigestVerifyUpdate\n"); exit(EXIT_FAILURE); } ret = EVP_DigestVerifyFinal(ver_md, signature, siglen); if (ret != 1) { PRINTERROSSL("Failed to EVP_DigestVerifyFinal-ize/bad signature\n"); exit(EXIT_FAILURE); } EVP_MD_CTX_free(ver_md); } static void check_public_info(EVP_PKEY *key) { BIO *membio = BIO_new(BIO_s_mem()); BUF_MEM *memdata = NULL; const char *type = "type=public"; void *found = NULL; int ret; if (!membio) { PRINTERROSSL("Failed to instantiate Memory BIO\n"); exit(EXIT_FAILURE); } ret = EVP_PKEY_print_public(membio, key, 0, NULL); if (ret != 1) { PRINTERROSSL("Failed to print public key info\n"); exit(EXIT_FAILURE); } BIO_get_mem_ptr(membio, &memdata); if (!memdata) { PRINTERROSSL("Failed to fetch BIO memory pointer\n"); exit(EXIT_FAILURE); } found = memmem(memdata->data, memdata->length, type, sizeof(type) - 1); if (!found) { PRINTERR("%.*s\n", (int)memdata->length, memdata->data); PRINTERROSSL("Public type indicator not found in printout!\n"); exit(EXIT_FAILURE); } BIO_free(membio); } int main(int argc, char *argv[]) { const char *data = "Sign Me!"; unsigned char *sig; size_t siglen; EVP_PKEY *key; key = util_gen_key("Pkey sigver Test"); /* test a simple op first */ sign_op(key, data, sizeof(data), &sig, &siglen); verify_op(key, data, sizeof(data), sig, siglen); check_public_info(key); PRINTERR("ALL A-OK!\n"); exit(EXIT_SUCCESS); } pkcs11-provider-1.0/tests/tpubkey000077500000000000000000000047551475270623700171070ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2022 Jakub Jelen # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" title PARA "Export RSA Public key to a file" ossl 'pkey -in $BASEURI -pubin -pubout -out ${TMPPDIR}/baseout.pub' title LINE "Export Public key to a file (pub-uri)" ossl 'pkey -in $PUBURI -pubin -pubout -out ${TMPPDIR}/pubout.pub' title LINE "Print Public key from private" ossl 'pkey -in $PRIURI -pubout -text' "$helper_emit" output="$helper_output" FAIL=0 echo "$output" | grep "PKCS11 RSA Public Key (2048 bits)" > /dev/null 2>&1 || FAIL=1 if [ $FAIL -eq 1 ]; then echo "Pkcs11 encoder function failed" echo echo "Original command output:" echo "$output" echo exit 1 fi title PARA "Export Public check error" FAIL=0 ossl 'pkey -in pkcs11:id=%de%ad -pubin -pubout -out ${TMPPDIR}/pubout-invlid.pub' || FAIL=1 if [ $FAIL -eq 0 ]; then echo "Invalid pkcs11 uri resulted in no error exporting key" exit 1 fi title PARA "Export EC Public key to a file" ossl 'pkey -in $ECBASEURI -pubin -pubout -out ${TMPPDIR}/baseecout.pub' title LINE "Export EC Public key to a file (pub-uri)" ossl 'pkey -in $ECPUBURI -pubin -pubout -out ${TMPPDIR}/pubecout.pub' title LINE "Print EC Public key from private" ossl 'pkey -in $ECPRIURI -pubout -text' "$helper_emit" output="$helper_output" FAIL=0 echo "$output" | grep "PKCS11 EC Public Key (256 bits)" > /dev/null 2>&1 || FAIL=1 if [ $FAIL -eq 1 ]; then echo "Pkcs11 encoder function failed" echo echo "Original command output:" echo "$output" echo exit 1 fi # The softokn does not support removing only public key from the key pair if [ -n "$BASE2URI" ]; then title PARA "Check we can get RSA public keys from certificate objects" title LINE "Export Public key to a file (priv-uri)" ossl 'pkey -in $PRI2URI -pubout -out ${TMPPDIR}/priv-cert.pub' title LINE "Export Public key to a file (base-uri)" ossl 'pkey -in $BASE2URI -pubout -out ${TMPPDIR}/base-cert.pub' diff "${TMPPDIR}/base-cert.pub" "${TMPPDIR}/priv-cert.pub" fi if [ -n "$ECBASE2URI" ]; then title PARA "Check we can get EC public keys from certificate objects" title LINE "Export Public EC key to a file (priv-uri)" ossl 'pkey -in $ECPRI2URI -pubout -out ${TMPPDIR}/ec-priv-cert.pub' title LINE "Export Public key to a file (base-uri)" ossl 'pkey -in $ECBASE2URI -pubout -out ${TMPPDIR}/ec-base-cert.pub' diff "${TMPPDIR}/ec-base-cert.pub" "${TMPPDIR}/ec-priv-cert.pub" fi exit 0 pkcs11-provider-1.0/tests/trand000077500000000000000000000013771475270623700165310ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2023 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" title PARA "Test PKCS11 RNG" ORIG_OPENSSL_CONF=${OPENSSL_CONF} sed -e "s/#MORECONF/random = random\n\n[random]\nrandom = PKCS11-RAND/" \ "${OPENSSL_CONF}" > "${OPENSSL_CONF}.failrandom" OPENSSL_CONF=${OPENSSL_CONF}.failrandom FAIL=0 ossl 'rand 1' || FAIL=1 if [ $FAIL -eq 0 ]; then echo "Random call should fail as module without early load" exit 1 fi OPENSSL_CONF=${ORIG_OPENSSL_CONF} sed -e "s/#pkcs11-module-load-behavior/pkcs11-module-load-behavior = early/" \ "${OPENSSL_CONF}.failrandom" > "${OPENSSL_CONF}.random" OPENSSL_CONF="${OPENSSL_CONF}.random" ossl 'rand 1' OPENSSL_CONF=${ORIG_OPENSSL_CONF} pkcs11-provider-1.0/tests/treadkeys.c000066400000000000000000000037251475270623700176310ustar00rootroot00000000000000/* Copyright (C) 2023 Jakub Jelen SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include static void test_group_name(EVP_PKEY *pkey) { char gname[25] = { 0 }; int ret; ret = EVP_PKEY_get_utf8_string_param(pkey, OSSL_PKEY_PARAM_GROUP_NAME, gname, 25, NULL); if (ret != 1) { fprintf(stderr, "Failed to get the group name\n"); exit(EXIT_FAILURE); } if (strcmp(gname, "prime256v1") != 0) { fprintf(stderr, "Received unexpected group name. Got %s\n", gname); exit(EXIT_FAILURE); } } int main(int argc, char *argv[]) { const char *baseuri; OSSL_STORE_CTX *store; OSSL_STORE_INFO *info; EVP_PKEY *prikey = NULL; EVP_PKEY *pubkey = NULL; baseuri = getenv("ECBASEURI"); if (baseuri == NULL) { fprintf(stderr, "No ECBASEURI\n"); exit(EXIT_FAILURE); } store = OSSL_STORE_open(baseuri, NULL, NULL, NULL, NULL); if (store == NULL) { fprintf(stderr, "Failed to open pkcs11 store\n"); exit(EXIT_FAILURE); } for (info = OSSL_STORE_load(store); info != NULL; info = OSSL_STORE_load(store)) { int type = OSSL_STORE_INFO_get_type(info); switch (type) { case OSSL_STORE_INFO_PUBKEY: pubkey = OSSL_STORE_INFO_get1_PUBKEY(info); break; case OSSL_STORE_INFO_PKEY: prikey = OSSL_STORE_INFO_get1_PKEY(info); break; } OSSL_STORE_INFO_free(info); } if (pubkey == NULL) { fprintf(stderr, "Failed to load public key\n"); exit(EXIT_FAILURE); } test_group_name(pubkey); EVP_PKEY_free(pubkey); if (prikey == NULL) { fprintf(stderr, "Failed to load private key\n"); exit(EXIT_FAILURE); } test_group_name(prikey); EVP_PKEY_free(prikey); OSSL_STORE_close(store); } pkcs11-provider-1.0/tests/trsapss000077500000000000000000000040451475270623700171130ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2022 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" title PARA "DigestSign and DigestVerify with RSA PSS" ossl ' pkeyutl -sign -inkey "${BASEURI}" -digest sha256 -pkeyopt pad-mode:pss -pkeyopt mgf1-digest:sha256 -pkeyopt saltlen:digest -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha256-dgstsig.bin' ossl ' pkeyutl -verify -inkey "${BASEURI}" -pubin -digest sha256 -pkeyopt pad-mode:pss -pkeyopt mgf1-digest:sha256 -pkeyopt saltlen:digest -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha256-dgstsig.bin' title LINE "Re-verify using OpenSSL default provider" #(-pubin causes us to export a public key and OpenSSL to import it in the default provider) ossl ' pkeyutl -verify -inkey "${PUBURI}" -pubin -digest sha256 -pkeyopt pad-mode:pss -pkeyopt mgf1-digest:sha256 -pkeyopt saltlen:digest -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha256-dgstsig.bin' title PARA "DigestSign and DigestVerify with RSA PSS with default params" ossl ' pkeyutl -sign -inkey "${BASEURI}" -pkeyopt pad-mode:pss -in ${RAND64FILE} -rawin -out ${TMPPDIR}/def-dgstsig.bin' ossl ' pkeyutl -verify -inkey "${BASEURI}" -pubin -pkeyopt pad-mode:pss -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/def-dgstsig.bin' title LINE "Re-verify using OpenSSL default provider" #(-pubin causes us to export a public key and OpenSSL to import it in the default provider) ossl ' pkeyutl -verify -inkey "${PUBURI}" -pubin -pkeyopt pad-mode:pss -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/def-dgstsig.bin' pkcs11-provider-1.0/tests/trsapssam000077500000000000000000000044651475270623700174370ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2022 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" if [[ "${SUPPORT_ALLOWED_MECHANISMS}" = "0" ]]; then exit 77; fi title PARA "DigestSign and DigestVerify with RSA PSS (SHA256 restriction)" ossl ' pkeyutl -sign -inkey "${RSAPSS2PRIURI}" -digest sha256 -pkeyopt pad-mode:pss -pkeyopt mgf1-digest:sha256 -pkeyopt saltlen:digest -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha256-rsapps-genpkey-dgstsig.bin' ossl ' pkeyutl -verify -inkey "${RSAPSS2PUBURI}" -pubin -digest sha256 -pkeyopt pad-mode:pss -pkeyopt mgf1-digest:sha256 -pkeyopt saltlen:digest -in ${RAND64FILE} -rawin -sigfile ${TMPPDIR}/sha256-rsapps-genpkey-dgstsig.bin' FAIL=0 title PARA "Fail DigestSign with RSA PSS because of restricted Digest" ossl ' pkeyutl -sign -inkey "${RSAPSS2PRIURI}" -digest sha384 -pkeyopt pad-mode:pss -pkeyopt mgf1-digest:sha384 -pkeyopt saltlen:digest -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha384-rsapps-genpkey-dgstsig.bin 2>&1' "$helper_emit" || FAIL=1 if [ $FAIL -eq 0 ]; then echo "Signature should have failed due to Digest restrictions" exit 1 fi output="$helper_output" FAIL=0 echo "$output" | grep "Public Key operation error" > /dev/null 2>&1 || FAIL=1 if [ $FAIL -ne 0 ]; then echo "Signature seem to have failed for unrelated reasons" echo "$output"; exit 1 fi FAIL=0 title PARA "Fail Signing with RSA PKCS1 mech and RSA-PSS key" ossl ' pkeyutl -sign -inkey "${RSAPSSPRIURI}" -digest sha256 -pkeyopt rsa_padding_mode:pkcs1 -in ${RAND64FILE} -rawin -out ${TMPPDIR}/sha384-rsa-not-rsapss-sig.bin 2>&1' "$helper_emit" || FAIL=1 if [ $FAIL -eq 0 ]; then echo "Signature should have failed due to PSS restrictions" exit 1 fi output="$helper_output" FAIL=0 echo "$output" | grep "Public Key operation error" > /dev/null 2>&1 || FAIL=1 if [ $FAIL -ne 0 ]; then echo "Signature seem to have failed for unrelated reasons" echo "$output"; exit 1 fi pkcs11-provider-1.0/tests/tsession.c000066400000000000000000000062771475270623700175120ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include #include #include /* concurrent operations */ #define CNUM 16 int main(int argc, char *argv[]) { const char *baseuri; OSSL_STORE_CTX *store; OSSL_STORE_INFO *info; EVP_PKEY *prikey = NULL; EVP_PKEY *pubkey = NULL; EVP_MD_CTX *sign_md[CNUM] = {}; const char *mdname = "SHA256"; int ret; baseuri = getenv("BASEURI"); /* optional first argument is a PKCS#11 uri of the key to test. * Default is provided by environment variable BASEURI */ if (argc > 1) { baseuri = argv[1]; } if (baseuri == NULL) { fprintf(stderr, "No BASEURI\n"); exit(EXIT_FAILURE); } store = OSSL_STORE_open(baseuri, NULL, NULL, NULL, NULL); if (store == NULL) { fprintf(stderr, "Failed to open pkcs11 store\n"); exit(EXIT_FAILURE); } for (info = OSSL_STORE_load(store); info != NULL; info = OSSL_STORE_load(store)) { int type = OSSL_STORE_INFO_get_type(info); switch (type) { case OSSL_STORE_INFO_PUBKEY: pubkey = OSSL_STORE_INFO_get1_PUBKEY(info); break; case OSSL_STORE_INFO_PKEY: prikey = OSSL_STORE_INFO_get1_PKEY(info); break; } OSSL_STORE_INFO_free(info); } if (pubkey == NULL) { fprintf(stderr, "Failed to load public key\n"); exit(EXIT_FAILURE); } if (prikey == NULL) { fprintf(stderr, "Failed to load private key\n"); exit(EXIT_FAILURE); } if (EVP_PKEY_get_id(prikey) == EVP_PKEY_ED25519 || EVP_PKEY_get_id(prikey) == EVP_PKEY_ED448) { mdname = NULL; } /* Do this twice to check that freeing and taling again sessions * works correctly and caching of open sessions work as expected */ for (int r = 0; r < 2; r++) { const unsigned char *data = (unsigned char *)"Sign Me!"; /* Start a series of signing operation so code grabs sessions */ for (int c = 0; c < CNUM; c++) { sign_md[c] = EVP_MD_CTX_new(); if (sign_md[c] == NULL) { fprintf(stderr, "Failed to init EVP_MD_CTX\n"); exit(EXIT_FAILURE); } ret = EVP_DigestSignInit_ex(sign_md[c], NULL, mdname, NULL, NULL, prikey, NULL); if (ret != 1) { fprintf(stderr, "Failed to init EVP_DigestSign\n"); exit(EXIT_FAILURE); } /* do not finalize just yet, leave this open to hold on sessions */ } for (int c = 0; c < CNUM; c++) { size_t size = EVP_PKEY_get_size(prikey); unsigned char sig[size]; ret = EVP_DigestSign(sign_md[c], sig, &size, data, sizeof(data)); if (ret != 1) { fprintf(stderr, "Failed to EVP_DigestSignFinal-ize\n"); exit(EXIT_FAILURE); } EVP_MD_CTX_free(sign_md[c]); } } OSSL_STORE_close(store); EVP_PKEY_free(prikey); EVP_PKEY_free(pubkey); fprintf(stderr, "ALL A-OK!"); exit(EXIT_SUCCESS); } pkcs11-provider-1.0/tests/ttls000077500000000000000000000125731475270623700164070ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2023 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" title PARA "Test SSL_CTX creation" $CHECKER "${TESTBLDDIR}/tlsctx" title PARA "Test setting cert/keys on TLS Context" $CHECKER "${TESTBLDDIR}/tlssetkey" "${ECCRTURI}" "${ECPRIURI}" if [ -n "$ECBASE2URI" ]; then title PARA "Test setting cert/keys on TLS Context w/o pub key" $CHECKER "${TESTBLDDIR}/tlssetkey" "${ECCRT2URI}" "${ECPRI2URI}" fi title PARA "Test an actual TLS connection" rm -f "${TMPPDIR}/s_server_output" rm -f "${TMPPDIR}/s_server_ready" mkfifo "${TMPPDIR}/s_server_ready" SERVER_PID=-1 # Make sure we terminate programs if test fails in the middle # shellcheck disable=SC2317 # Shellcheck for some reason does not follow trap wait_for_server_at_exit() { wait "$1" || : echo "Server output:" cat "${TMPPDIR}/s_server_output" } trap 'wait_for_server_at_exit $SERVER_PID;' EXIT PORT=23456 run_test() { KEY="$1" CERT="$2" SRV_ARGS=$3 CLNT_ARGS=$4 export PKCS11_PROVIDER_DEBUG="file:${TMPPDIR}/p11prov-debug-tls-server.log" expect -c "spawn $CHECKER openssl s_server $PROPQ -accept \"${PORT}\" -naccept 1 -key \"${KEY}\" -cert \"${CERT}\" $SRV_ARGS; set timeout 10; expect { \"ACCEPT\" {}; eof { exit 2; } timeout { exit 5; } default { send \" NO ACCEPT \n\"; exit 1; }; } set server_ready [open \"${TMPPDIR}/s_server_ready\" w+]; puts \$server_ready \"READY\n\"; close \$server_ready; expect { \"END SSL SESSION PARAMETERS\" {}; eof { exit 2; } timeout { exit 5; } default { send \" NO SESSION PARAMETERS \n\"; exit 1; }; } send \" TLS SUCCESSFUL \n\" send \"Q\n\" expect { eof {exit 0;}; timeout { exit 5; } default { send \" NO EOF \n\"; exit 1; }; }" &> "${TMPPDIR}/s_server_output" & SERVER_PID=$! read -r < "${TMPPDIR}/s_server_ready" export PKCS11_PROVIDER_DEBUG="file:${TMPPDIR}/p11prov-debug-tls-client.log" expect -c "spawn $CHECKER openssl s_client $PROPQ -connect \"localhost:${PORT}\" -CAfile \"${CACRT}\" $CLNT_ARGS; set timeout 10; expect { \" TLS SUCCESSFUL \" {}; eof { exit 2; } timeout { exit 5; } default { send \" NO TLS SUCCESSFUL MESSAGE \n\"; exit 1; }; } expect { eof {exit 0;}; timeout { exit 5; } default { send \" NO EOF \n\"; exit 1; }; }" || (wait_for_server_at_exit $SERVER_PID; exit 1; ) wait_for_server_at_exit $SERVER_PID } run_tests() { title PARA "Run sanity test with default values (RSA)" run_test "$PRIURI" "$CRTURI" if [[ -n "$RSAPSSPRIURI" ]]; then title PARA "Run sanity test with default values (RSA-PSS)" selfsign_cert "${RSAPSSPRIURI}" "${TMPPDIR}/rsapss-default.pem" \ "-sigopt rsa_padding_mode:pss" run_test "$RSAPSSPRIURI" "${TMPPDIR}/rsapss-default.pem" fi if [[ -n "$RSAPSS2PRIURI" ]]; then title PARA "Run sanity test with RSA-PSS and SHA256" selfsign_cert "${RSAPSS2PRIURI}" "${TMPPDIR}/rsapss-sha256.pem" \ "-sigopt rsa_padding_mode:pss" \ "-sigopt digest:sha256" \ "-sigopt rsa_pss_saltlen:-1" run_test "$RSAPSS2PRIURI" "${TMPPDIR}/rsapss-sha256.pem" fi title PARA "Run sanity test with default values (ECDSA)" run_test "$ECPRIURI" "$ECCRTURI" if [[ -n "$EDBASEURI" ]]; then title PARA "Run sanity test with default values (Ed25519)" run_test "$EDPRIURI" "$EDCRTURI" fi if [[ -n "$ED2BASEURI" ]]; then title PARA "Run sanity test with default values (Ed448)" run_test "$ED2PRIURI" "$ED2CRTURI" fi title PARA "Run test with TLS 1.2" run_test "$PRIURI" "$CRTURI" "" "-tls1_2" title PARA "Run test with explicit TLS 1.3" run_test "$PRIURI" "$CRTURI" "" "-tls1_3" title PARA "Run test with TLS 1.2 (ECDSA)" run_test "$ECPRIURI" "$ECCRTURI" "-tls1_2" "-tls1_2" title PARA "Run test with TLS 1.2 and ECDH" run_test "$ECPRIURI" "$ECCRTURI" "" "-tls1_2 -cipher ECDHE-ECDSA-AES128-GCM-SHA256 -groups secp256r1" title PARA "Run test with TLS 1.3 and specific suite" run_test "$ECPRIURI" "$ECCRTURI" "" "-tls1_3 -ciphersuites TLS_AES_256_GCM_SHA384 -groups secp256r1" } title SECTION "TLS with key in provider" PROPQ="" run_tests title ENDSECTION title SECTION "Forcing the provider for all server operations" # We can not put this into the openssl.cnf directly, as it would be picked up by softhsm # causing infinite recursion when doing EdDSA key operations. PROPQ="-propquery \"?provider=pkcs11\"" # Try again forcing all operations on the token # We need to disable digest operations as OpenSSL depends on context duplication working ORIG_OPENSSL_CONF=${OPENSSL_CONF} sed -e "s/^#pkcs11-module-block-operations/pkcs11-module-block-operations = digest/" \ "${OPENSSL_CONF}" > "${OPENSSL_CONF}.forcetoken" OPENSSL_CONF=${OPENSSL_CONF}.forcetoken run_tests OPENSSL_CONF=${ORIG_OPENSSL_CONF} title ENDSECTION exit 0; pkcs11-provider-1.0/tests/ttlsfuzzer000077500000000000000000000102521475270623700176450ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2024 Jakub Jelen # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" if [[ ! -d "${TESTSSRCDIR}/../tlsfuzzer/tlsfuzzer" ]]; then title "TLS fuzzer is not available -- skipping" exit 77; fi if [[ "${SUPPORT_TLSFUZZER}" = "0" ]]; then title "TLS fuzzer does not work in FIPS Mode" exit 77; fi TMPFILE="${TMPPDIR}/tls-fuzzer.$$.tmp" PORT="$TESTPORT" PYTHON=$(which python3) if [[ -f /etc/debian_version ]] && grep Ubuntu /etc/lsb-release; then # the ubuntu builds miss Brainpool curves, but Debian has them already SIGALGS="ecdsa_secp256r1_sha256 ecdsa_secp384r1_sha384 ecdsa_secp521r1_sha512 ed25519 ed448 rsa_pss_pss_sha256 rsa_pss_pss_sha384 rsa_pss_pss_sha512 rsa_pss_rsae_sha256 rsa_pss_rsae_sha384 rsa_pss_rsae_sha512 rsa_pkcs1_sha256 rsa_pkcs1_sha384 rsa_pkcs1_sha512 ecdsa_sha224 rsa_pkcs1_sha224" else SIGALGS="ecdsa_secp256r1_sha256 ecdsa_secp384r1_sha384 ecdsa_secp521r1_sha512 ed25519 ed448 8+26 8+27 8+28 rsa_pss_pss_sha256 rsa_pss_pss_sha384 rsa_pss_pss_sha512 rsa_pss_rsae_sha256 rsa_pss_rsae_sha384 rsa_pss_rsae_sha512 rsa_pkcs1_sha256 rsa_pkcs1_sha384 rsa_pkcs1_sha512 ecdsa_sha224 rsa_pkcs1_sha224" fi prepare_test() { TEMPLATE="$1" KEY="$2" CERT="$3" # Prepare the tlsfuzzer configuration sed -e "s|@PRIURI@|$KEY|g" -e "s|@CRTURI@|$CERT|g" \ -e "s/@PORT@/$PORT/g" \ -e "s/@PROPQ@/$PROPQ/g" \ -e "s/@SIGALGS@/$SIGALGS/g" "${TESTSSRCDIR}/${TEMPLATE}" >>"${TMPFILE}" } run_test() { # Run openssl under checker program if needed if [[ -n "$CHECKER" ]]; then IFS=" " read -r -a ARR <<< "$CHECKER" sed -e "s|@CHECKER@|$(printf "\"%s\", " "${ARR[@]}")|g" "${sed_inplace[@]}" "${TMPFILE}" else sed -e "s|@CHECKER@||g" "${sed_inplace[@]}" "${TMPFILE}" fi pushd "${TESTSSRCDIR}/../tlsfuzzer" test -L ecdsa || ln -s ../python-ecdsa/src/ecdsa ecdsa test -L tlslite || ln -s ../tlslite-ng/tlslite tlslite 2>/dev/null PYTHONPATH=. "${PYTHON}" tests/scripts_retention.py "${TMPFILE}" openssl 821 popd } run_tests() { # truncate true > "${TMPFILE}" title PARA "Prepare CertificateVerify test with RSA" prepare_test cert.json.in "$PRIURI" "$CRTURI" title PARA "Prepare test for RSA" prepare_test cert.json.rsa.in "$PRIURI" "$CRTURI" if [[ -n "$RSAPSSBASEURI" ]]; then title PARA "Prepare test for RSA-PSS" # do selfsign now using openssl as certool can not create SPKI using # RSA-PSS selfsign_cert "${RSAPSSPRIURI}" "${TMPPDIR}/rsapss-default.pem" \ "-sigopt rsa_padding_mode:pss" \ "-sigopt digest:sha256" \ "-sigopt rsa_pss_saltlen:-1" prepare_test cert.json.rsapss.in \ "$RSAPSSPRIURI" "${TMPPDIR}/rsapss-default.pem" fi title PARA "Prepare test for ECDSA" # Note, that tlsfuzzer expects the homogeneous CA and server keys # so we are using here the self-signed peer EC Key, instead of # the default ECC key prepare_test cert.json.ecdsa.in "$ECPEERPRIURI" "$ECPEERCRTURI" if [[ -n "$EDBASEURI" ]]; then title PARA "Prepare test for Ed25519" prepare_test cert.json.ed25519.in "$EDPRIURI" "$EDCRTURI" fi if [[ -n "$ED2BASEURI" ]]; then title PARA "Prepare test for Ed448" prepare_test cert.json.ed448.in "$ED2PRIURI" "$ED2CRTURI" fi # the missing closing brace echo "]" >> "${TMPFILE}" run_test } title SECTION "Run TLS fuzzer with server key on provider" run_tests title ENDSECTION title SECTION "Run TLS fuzzer forcing the provider for all server operations" # We can not put this into the openssl.cnf directly, as it would be picked up by softhsm # causing infinite recursion when doing EdDSA key operations. PROPQ="\"-propquery\", \"?provider=pkcs11\", " # We need to disable digest operations as OpenSSL depends on context duplication working ORIG_OPENSSL_CONF=${OPENSSL_CONF} sed -e "s/^#pkcs11-module-block-operations/pkcs11-module-block-operations = digest/" \ "${OPENSSL_CONF}" > "${OPENSSL_CONF}.forcetoken" export OPENSSL_CONF=${OPENSSL_CONF}.forcetoken run_tests OPENSSL_CONF=${ORIG_OPENSSL_CONF} title ENDSECTION exit 0 pkcs11-provider-1.0/tests/turi000077500000000000000000000026761475270623700164070ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2023 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" title PARA "Check that storeutl returns URIs" ossl 'storeutl -text pkcs11:' "$helper_emit" output="$helper_output" FAIL=0 echo "$output" | grep "URI pkcs11:" > /dev/null 2>&1 || FAIL=1 if [ $FAIL -ne 0 ]; then echo "no URIs returned by storeutl" exit 1 fi URISonly=$(echo "$helper_output" | grep "^URI pkcs11:") # poor mans mapfile for bash 3 on macos declare -a URIS while read -r var; do URIS+=("$var") done <<< "${URISonly//URI /}" title PARA "Check returned URIs work to find objects" for uri in "${URIS[@]}"; do echo "\$uri=${uri}" ossl 'storeutl -text "$uri"' "$helper_emit" output="$helper_output" matchURI=$(echo "$output" | grep "URI pkcs11:" | cut -d ' ' -f 2) if [[ "${uri}" != "${matchURI}" ]]; then echo "Unmatched URI returned by storeutl" echo "Expected $uri" echo "Received $matchURI" exit 1 fi done firstURI=${URIS[0]#URI pkcs11:} IFS=";" read -r -a firstCMPS <<< "$firstURI" title PARA "Check each URI component is tested" for cmp in "${firstCMPS[@]}"; do echo "\$cmp=${cmp}" ossl 'storeutl -text "pkcs11:${cmp}"' "$helper_emit" output="$helper_output" echo "$output" | grep "URI pkcs11:" > /dev/null 2>&1 || FAIL=1 if [ $FAIL -ne 0 ]; then echo "Failed to get an object with URI \"pkcs11:${cmp}\"" fi done pkcs11-provider-1.0/tests/util.c000066400000000000000000000127051475270623700166110ustar00rootroot00000000000000/* Copyright (C) 2024 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #define _GNU_SOURCE #include #include #include #include #include #include #include "util.h" void ossl_err_print(void) { bool first = true; unsigned long err = 0; while (true) { const char *file, *func, *data; int line; err = ERR_get_error_all(&file, &line, &func, &data, NULL); if (err == 0) { break; } char buf[1024]; ERR_error_string_n(err, buf, sizeof(buf)); const char *fmt = first ? ": %s (in function %s in %s:%d): %s\n" : " caused by: %s (in function %s in %s:%d): %s\n"; fprintf(stderr, fmt, buf, func, file, line, data); first = false; } if (first) { fprintf(stderr, "\n"); } } EVP_PKEY *load_key(const char *uri) { OSSL_STORE_CTX *store; OSSL_STORE_INFO *info; EVP_PKEY *key = NULL; if (!uri) { fprintf(stderr, "Invalid NULL uri"); ossl_err_print(); exit(EXIT_FAILURE); } store = OSSL_STORE_open(uri, NULL, NULL, NULL, NULL); if (store == NULL) { fprintf(stderr, "Failed to open store: %s\n", uri); ossl_err_print(); exit(EXIT_FAILURE); } if ((strncmp(uri, "pkcs11:", 7) == 0) && strstr(uri, "type=private") == NULL) { /* This is a workaround for OpenSSL < 3.2.0 where the code fails * to correctly source public keys unless explicitly requested * via an expect hint */ if (OSSL_STORE_expect(store, OSSL_STORE_INFO_PUBKEY) != 1) { fprintf(stderr, "Failed to expect Public Key File\n"); exit(EXIT_FAILURE); } } for (info = OSSL_STORE_load(store); info != NULL; info = OSSL_STORE_load(store)) { int type = OSSL_STORE_INFO_get_type(info); if (key != NULL) { fprintf(stderr, "Multiple keys matching URI: %s\n", uri); exit(EXIT_FAILURE); } switch (type) { case OSSL_STORE_INFO_PUBKEY: key = OSSL_STORE_INFO_get1_PUBKEY(info); break; case OSSL_STORE_INFO_PKEY: key = OSSL_STORE_INFO_get1_PKEY(info); break; } OSSL_STORE_INFO_free(info); } if (key == NULL) { fprintf(stderr, "Failed to load key from URI: %s\n", uri); ossl_err_print(); exit(EXIT_FAILURE); } OSSL_STORE_close(store); return key; } X509 *load_cert(const char *uri, const UI_METHOD *ui_method, void *ui_data) { OSSL_STORE_CTX *store; OSSL_STORE_INFO *info; X509 *cert = NULL; if (!uri) { fprintf(stderr, "Invalid NULL uri"); ossl_err_print(); exit(EXIT_FAILURE); } store = OSSL_STORE_open(uri, ui_method, ui_data, NULL, NULL); if (store == NULL) { fprintf(stderr, "Failed to open store: %s\n", uri); ossl_err_print(); exit(EXIT_FAILURE); } for (info = OSSL_STORE_load(store); info != NULL; info = OSSL_STORE_load(store)) { int type = OSSL_STORE_INFO_get_type(info); if (cert != NULL) { fprintf(stderr, "Multiple certs matching URI: %s\n", uri); exit(EXIT_FAILURE); } switch (type) { case OSSL_STORE_INFO_CERT: cert = OSSL_STORE_INFO_get1_CERT(info); break; } OSSL_STORE_INFO_free(info); } if (cert == NULL) { fprintf(stderr, "Failed to load cert from URI: %s\n", uri); ossl_err_print(); exit(EXIT_FAILURE); } OSSL_STORE_close(store); return cert; } void hexify(char *out, unsigned char *byte, size_t len) { char c[2], s; for (size_t i = 0; i < len; i++) { out[i * 3] = '%'; c[0] = byte[i] >> 4; c[1] = byte[i] & 0x0f; for (int j = 0; j < 2; j++) { if (c[j] < 0x0A) { s = '0'; } else { s = 'a' - 10; } out[i * 3 + 1 + j] = c[j] + s; } } out[len * 3] = '\0'; } EVP_PKEY *util_gen_key(const char *label) { unsigned char id[16]; char idhex[16 * 3 + 1]; char *uri; size_t rsa_bits = 3072; OSSL_PARAM params[3]; EVP_PKEY_CTX *ctx; EVP_PKEY *key = NULL; int ret; /* RSA */ ret = RAND_bytes(id, 16); if (ret != 1) { PRINTERROSSL("Failed to set generate key id\n"); exit(EXIT_FAILURE); } hexify(idhex, id, 16); ret = asprintf(&uri, "pkcs11:object=%s;id=%s", label, idhex); if (ret == -1) { fprintf(stderr, "Failed to allocate uri\n"); exit(EXIT_FAILURE); } params[0] = OSSL_PARAM_construct_utf8_string("pkcs11_uri", uri, 0); params[1] = OSSL_PARAM_construct_size_t("rsa_keygen_bits", &rsa_bits); params[2] = OSSL_PARAM_construct_end(); ctx = EVP_PKEY_CTX_new_from_name(NULL, "RSA", "provider=pkcs11"); if (ctx == NULL) { PRINTERROSSL("Failed to init PKEY context\n"); exit(EXIT_FAILURE); } ret = EVP_PKEY_keygen_init(ctx); if (ret != 1) { PRINTERROSSL("Failed to init keygen\n"); exit(EXIT_FAILURE); } EVP_PKEY_CTX_set_params(ctx, params); ret = EVP_PKEY_generate(ctx, &key); EVP_PKEY_CTX_free(ctx); if (ret != 1) { PRINTERROSSL("Failed to generate key\n"); exit(EXIT_FAILURE); } free(uri); return key; } pkcs11-provider-1.0/tests/util.h000066400000000000000000000011721475270623700166120ustar00rootroot00000000000000/* Copyright (C) 2024 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include #define PRINTERR(...) \ do { \ fprintf(stderr, __VA_ARGS__); \ fflush(stderr); \ } while (0) #define PRINTERROSSL(...) \ do { \ fprintf(stderr, __VA_ARGS__); \ ERR_print_errors_fp(stderr); \ fflush(stderr); \ } while (0) void ossl_err_print(void); EVP_PKEY *load_key(const char *uri); X509 *load_cert(const char *uri, const UI_METHOD *ui_method, void *ui_data); void hexify(char *out, unsigned char *byte, size_t len); EVP_PKEY *util_gen_key(const char *label); pkcs11-provider-1.0/tlsfuzzer/000077500000000000000000000000001475270623700163715ustar00rootroot00000000000000pkcs11-provider-1.0/tlslite-ng/000077500000000000000000000000001475270623700164035ustar00rootroot00000000000000pkcs11-provider-1.0/tools/000077500000000000000000000000001475270623700154615ustar00rootroot00000000000000pkcs11-provider-1.0/tools/README.md000066400000000000000000000014351475270623700167430ustar00rootroot00000000000000# CLI tool uri2pem.py Simple tool to create PEM files for PKCS#11 URI Usage: python uri2pem.py --help python uri2pem.py 'pkcs11:token=MyToken;object=MyObject;type=private' python uri2pem.py --bypass 'someBogusURI' # output python uri2pem.py --out mykey.pem 'pkcs11:token=MyToken;object=MyObject;type=private' # verification, if token is available, requires --out python uri2pem.py --verify --out mykey.pem 'pkcs11:token=MyToken;object=MyObject;type=private' The tool doesn't validate the argument for a valid PKCS#11 URI ## Tests Requires: pytest To run the tests for `uri2pem.py`, first run `make check` to create the test NSS softoken. Then in `tools/`, run `pytest tests`. The test suite enables `pkcs11-module-encode-provider-uri-to-pem = true`. pkcs11-provider-1.0/tools/__init__.py000066400000000000000000000000001475270623700175600ustar00rootroot00000000000000pkcs11-provider-1.0/tools/openssl-tools.cnf000066400000000000000000000001511475270623700207670ustar00rootroot00000000000000.include ../tests/tmp.softokn/openssl.cnf [pkcs11_sect] pkcs11-module-encode-provider-uri-to-pem = true pkcs11-provider-1.0/tools/tests/000077500000000000000000000000001475270623700166235ustar00rootroot00000000000000pkcs11-provider-1.0/tools/tests/__init__.py000066400000000000000000000000001475270623700207220ustar00rootroot00000000000000pkcs11-provider-1.0/tools/tests/test_softoken.py000066400000000000000000000045001475270623700220630ustar00rootroot00000000000000""" Copyright (C) 2024 S-P Chan SPDX-License-Identifier: Apache-2.0 """ import os import pathlib import subprocess import sys import random import string import re from asn1crypto import pem from .. import uri2pem tokens = pathlib.Path("../tests/softokn/tokens/key4.db") if not tokens.exists(): print("Run 'make check' first to create a NSS softoken in tests/softokn/tokens") raise SystemExit(1) P11_TOKEN = "".join(random.choices(string.ascii_letters, k=12)) P11_OBJECT = "".join(random.choices(string.ascii_letters, k=12)) KEY_URI = f"pkcs11:token={P11_TOKEN};object={P11_OBJECT};type=private" KEY_DESC = "PKCS#11 Provider URI v1.0" def test_roundtrip(tmp_path): pem_bytes = uri2pem.uri2pem(KEY_URI) # asn1crypto does not like '#' in PEM labels pem_replace = pem_bytes.decode("ascii").replace("#", "0") # read back the object der_bytes = pem.unarmor(pem_replace.encode("ascii"), multiple=False) key = uri2pem.Pkcs11PrivateKey.load(der_bytes[2]) assert key["desc"].native == KEY_DESC assert key["uri"].native == KEY_URI def test_asn1parse(tmp_path): pem_bytes = uri2pem.uri2pem(KEY_URI) pem_file = pathlib.Path(tmp_path / "test_asn1parse.pem") pathlib.Path(tmp_path / "test_asn1parse.pem").write_bytes(pem_bytes) ret = subprocess.run( ["openssl", "asn1parse", "-in", str(pem_file)], capture_output=True, text=True ) assert ret.returncode == 0 assert "SEQUENCE" in ret.stdout and KEY_DESC in ret.stdout and KEY_URI in ret.stdout def test_storeutl(tmp_path): ret = subprocess.run( ["openssl", "storeutl", "-text", "pkcs11:"], capture_output=True, text=True, env={"OPENSSL_CONF": "./openssl-tools.cnf"} ) assert ret.returncode == 0 private_key = None for line in ret.stdout.splitlines(): if m := re.match("URI (pkcs11.*type=private)$", line): private_key = m.group(1) break assert private_key data = uri2pem.uri2pem(private_key) private_key_pem = pathlib.Path(tmp_path / "private_key.pem") private_key_pem.write_bytes(data) ret = subprocess.run( ["openssl", "pkey", "-in", str(private_key_pem)], capture_output=True, text=True, env={"OPENSSL_CONF": "./openssl-tools.cnf"} ) assert ret.returncode == 0 pkcs11-provider-1.0/tools/uri2pem.py000066400000000000000000000046501475270623700174230ustar00rootroot00000000000000""" Copyright (C) 2024 S-P Chan SPDX-License-Identifier: Apache-2.0 """ """ CLI tool to create pkcs11-provider pem files from a key uri Requirements: asn1crypto Installation: pip install asn1crypto dnf install python3-asn1crypto Usage: python uri2pem.py 'pkcs11:URI-goes-here' """ import sys from asn1crypto.core import Sequence, VisibleString, UTF8String from asn1crypto import pem class Pkcs11PrivateKey(Sequence): _fields = [("desc", VisibleString), ("uri", UTF8String)] def uri2pem(uri: str, bypass: bool = False) -> bytes: if not bypass: if not (uri.startswith("pkcs11:") and "type=private" in uri): print(f"Error: uri({uri}) not a valid PKCS#11 URI") sys.exit(1) if not ("object=" in uri or "id=" in uri): print(f"Error: uri({uri}) does not specify an object by label or id") sys.exit(1) data = Pkcs11PrivateKey( { "desc": VisibleString("PKCS#11 Provider URI v1.0"), "uri": UTF8String(uri), } ) return pem.armor("PKCS#11 PROVIDER URI", data.dump()) if __name__ == "__main__": import argparse import pathlib import subprocess parser = argparse.ArgumentParser() parser.add_argument("--bypass", action='store_true', help='skip basic URI checks') parser.add_argument("--verify", action='store_true', help='verify PEM file with OpenSSL; requires --out to be specified') parser.add_argument("--out", action='store', help='output to PEM file, otherwise to stdout', metavar='OUTPUT_FILE') parser.add_argument("keyuri", action='store', help='the PKCS#11 key URI to encode') opts = parser.parse_args() if opts.verify and not opts.out: print(f"{sys.argv[0]}: --verify option requires --out to be specified") sys.exit(1) data = uri2pem(opts.keyuri, bypass=opts.bypass) if opts.out: out_file = pathlib.Path(opts.out) out_file.write_bytes(data) else: print(data.decode("ascii"), end="") if opts.verify: print("===== OpenSSL pkey output =====") ret = subprocess.run(["openssl", "pkey", "-in", str(out_file), "-pubout"]) print("===== END =====") if ret.returncode != 0: print(f"{sys.argv[0]}: verification of private key PEM({str(out_file)}) failed") else: print(f"{sys.argv[0]}: verification of private key PEM({str(out_file)}) OK")