pax_global_header00006660000000000000000000000064145535235650014527gustar00rootroot0000000000000052 comment=58040b4e32975cc1d7f39e424ee7b0097cd11311 pkcs11-provider-0.3/000077500000000000000000000000001455352356500143235ustar00rootroot00000000000000pkcs11-provider-0.3/.clang-format000066400000000000000000000041431455352356500167000ustar00rootroot00000000000000BasedOnStyle: 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-0.3/.clang-format-ignore000066400000000000000000000000621455352356500201550ustar00rootroot00000000000000# Leave third party code untouched ./src/pkcs11.h pkcs11-provider-0.3/.github/000077500000000000000000000000001455352356500156635ustar00rootroot00000000000000pkcs11-provider-0.3/.github/ISSUE_TEMPLATE/000077500000000000000000000000001455352356500200465ustar00rootroot00000000000000pkcs11-provider-0.3/.github/ISSUE_TEMPLATE/bug_report.md000066400000000000000000000014121455352356500225360ustar00rootroot00000000000000--- 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-0.3/.github/ISSUE_TEMPLATE/config.yml000066400000000000000000000000331455352356500220320ustar00rootroot00000000000000blank_issues_enabled: true pkcs11-provider-0.3/.github/ISSUE_TEMPLATE/rfe.md000066400000000000000000000005561455352356500211520ustar00rootroot00000000000000--- 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-0.3/.github/sid.debug.list000066400000000000000000000000701455352356500204210ustar00rootroot00000000000000deb http://deb.debian.org/debian-debug/ sid-debug main pkcs11-provider-0.3/.github/workflows/000077500000000000000000000000001455352356500177205ustar00rootroot00000000000000pkcs11-provider-0.3/.github/workflows/address-sanitizer.yml000066400000000000000000000045521455352356500241040ustar00rootroot00000000000000--- 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@v3 - name: Install Dependencies run: | if [ -f /etc/fedora-release ]; then dnf -y install git clang gcc automake libtool pkgconf-pkg-config \ autoconf-archive 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 make automake \ libtool pkg-config autoconf-archive libssl-dev openssl expect \ procps libnss3 libnss3-tools libnss3-dev softhsm2 opensc p11-kit \ libp11-kit-dev p11-kit-modules gnutls-bin \ openssl-dbgsym libssl3-dbgsym fi - name: Setup # The detection on debian works ok, but on Fedora, we get linker script, # that is not compabitlbe with LD_PRELOAD so we force the absolute path. run: | if [ -f /etc/fedora-release ]; then autoreconf -fiv CC=gcc \ ./configure --with-address-sanitizer=/usr/lib64/libasan.so.8.0.0 elif [ -f /etc/debian_version ]; then autoreconf -fiv CC=gcc \ ./configure --with-address-sanitizer fi - name: Build and Test run: make check - uses: actions/upload-artifact@v3 if: failure() with: name: Address sanitizer logs on ${{ matrix.name }} path: | tests/*.log tests/openssl.cnf tests/tmp.${{ matrix.token }}/p11prov-debug.log tests/tmp.${{ matrix.token }}/testvars config.log pkcs11-provider-0.3/.github/workflows/build.yml000066400000000000000000000104211455352356500215400ustar00rootroot00000000000000--- 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] compiler: [gcc, clang] token: [softokn, softhsm] include: - name: fedora container: fedora:latest - name: debian container: debian:sid container: ${{ matrix.container }} steps: - name: Install Dependencies run: | if [ -f /etc/fedora-release ]; then dnf -y install git ${{ matrix.compiler }} automake libtool \ pkgconf-pkg-config autoconf-archive openssl-devel openssl \ diffutils expect valgrind if [ "${{ matrix.token }}" = "softokn" ]; then dnf -y install nss-softokn nss-tools nss-softokn-devel elif [ "${{ matrix.token }}" = "softhsm" ]; then dnf -y install softhsm opensc p11-kit-devel p11-kit-server \ gnutls-utils fi elif [ -f /etc/debian_version ]; then apt-get -q update apt-get -yq install git ${{ matrix.compiler }} make automake \ libtool pkg-config autoconf-archive libssl-dev openssl expect \ valgrind procps if [ "${{ matrix.token }}" = "softokn" ]; then apt-get -yq install libnss3 libnss3-tools libnss3-dev elif [ "${{ matrix.token }}" = "softhsm" ]; then apt-get -yq install softhsm2 opensc p11-kit libp11-kit-dev \ p11-kit-modules gnutls-bin fi fi - name: Checkout Repository uses: actions/checkout@v3 - name: Setup run: | autoreconf -fiv CC=${{ matrix.compiler }} ./configure - name: Build and Test run: make check - uses: actions/upload-artifact@v3 if: failure() with: name: Test logs ${{ matrix.name }}, ${{ matrix.compiler }}, ${{ matrix.token }} path: | tests/*.log tests/openssl.cnf tests/tmp.${{ matrix.token }}/p11prov-debug.log tests/tmp.${{ matrix.token }}/testvars config.log - name: Run tests with valgrind run: | if [ "${{ matrix.compiler }}" = "gcc" ]; then make check-valgrind-memcheck fi - uses: actions/upload-artifact@v3 if: failure() with: name: Test valgrind logs ${{ matrix.name }}, ${{ matrix.compiler }}, ${{ matrix.token }} path: | tests/*.log tests/openssl.cnf tests/tmp.${{ matrix.token }}/p11prov-debug.log tests/tmp.${{ matrix.token }}/testvars config.log build-macos: name: CI with software token runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [macos-12] token: [softokn, softhsm] steps: - name: Install Dependencies run: | brew update brew install \ autoconf-archive \ automake \ libtool \ openssl@3 \ pkg-config if [ "${{ matrix.token }}" = "softokn" ]; then brew install nss elif [ "${{ matrix.token }}" = "softhsm" ]; then brew install \ opensc \ p11-kit \ softhsm fi - name: Checkout Repository uses: actions/checkout@v3 - name: Setup run: | export PKG_CONFIG_PATH=$(brew --prefix openssl@3)/lib/pkgconfig export PATH=$(brew --prefix openssl@3)/bin:$PATH autoreconf -fiv CC=clang ./configure - name: Build and Test run: | export PATH=$(brew --prefix openssl@3)/bin:$PATH make -j$(sysctl -n hw.ncpu || echo 2) make check - uses: actions/upload-artifact@v3 if: failure() with: name: Test logs on macOS-12 with ${{ matrix.token }} path: | tests/*.log tests/openssl.cnf tests/tmp.${{ matrix.token }}/p11prov-debug.log tests/tmp.${{ matrix.token }}/testvars config.log pkcs11-provider-0.3/.github/workflows/coverity-scan.yml000066400000000000000000000022661455352356500232370ustar00rootroot00000000000000--- name: Coverity Scan on: push: branches: ["main"] schedule: - cron: '41 3 * * 0' jobs: coverity: name: Coverity Scan runs-on: ubuntu-22.04 container: fedora:latest steps: - name: Install Dependencies run: | dnf -y install git gcc automake libtool pkgconf-pkg-config \ autoconf-archive openssl-devel openssl \ nss-softokn nss-tools nss-softokn-devel - name: Checkout Repository uses: actions/checkout@v3 - name: Setup run: | autoreconf -fiv ./configure - 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 }} pkcs11-provider-0.3/.github/workflows/distcheck.yml000066400000000000000000000032651455352356500224120ustar00rootroot00000000000000--- 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] include: - name: fedora container: fedora:latest - name: debian container: debian:sid container: ${{ matrix.container }} steps: - name: Install Dependencies run: | if [ -f /etc/fedora-release ]; then dnf -y install git gcc automake libtool expect \ pkgconf-pkg-config autoconf-archive 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 make automake expect \ libtool pkg-config autoconf-archive 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@v3 - name: Setup run: | autoreconf -fiv ./configure - name: Distcheck run: make distcheck - name: RPM Build if: ${{ matrix.name == 'fedora' }} run: | mkdir -p rpmbuild/SOURCES cp pkcs11-provider*tar.xz rpmbuild/SOURCES/ rpmbuild --define "_topdir $PWD/rpmbuild" -ba \ packaging/pkcs11-provider.spec pkcs11-provider-0.3/.github/workflows/reuse.yml000066400000000000000000000003321455352356500215640ustar00rootroot00000000000000--- name: REUSE Compliance Check on: [push, pull_request] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: REUSE Compliance Check uses: fsfe/reuse-action@v1 pkcs11-provider-0.3/.github/workflows/scan-build.yml000066400000000000000000000016421455352356500224670ustar00rootroot00000000000000--- 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 automake libtool pkgconf-pkg-config \ autoconf-archive git openssl-devel clang-analyzer - uses: actions/checkout@v3 name: Checkout Repository - name: Setup run: | autoreconf -fiv ./configure - name: Scan Build run: | scan-build --html-title="PKCS#11 Provider ($GITHUB_SHA)" \ --keep-cc \ --status-bugs \ --keep-going \ -o scan-build.reports make - uses: actions/upload-artifact@v3 if: failure() with: name: Scan Build logs path: | scan-build.reports/ pkcs11-provider-0.3/.github/workflows/shellcheck.yml000066400000000000000000000015601455352356500225520ustar00rootroot00000000000000--- name: Shellcheck permissions: {} on: push: branches: ["main"] pull_request: branches: ["main"] jobs: shellcheck: name: Shellcheck runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - 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 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-0.3/.github/workflows/style.yml000066400000000000000000000026341455352356500216100ustar00rootroot00000000000000--- 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 $COMPILER automake libtool pkgconf-pkg-config \ autoconf-archive git openssl-devel clang-tools-extra \ python3-pip codespell - name: Checkout Repository uses: actions/checkout@v3 - name: Install compiledb run: | pip install compiledb - 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: | autoreconf -fiv ./configure compiledb make - name: Run Clang Tidy run: | run-clang-tidy \ -checks=-*,readability-braces-around-statements \ -config "{WarningsAsErrors: '*'}" \ -header-filter "src/pkcs11.h" \ -quiet - 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.am \ configure.ac src tests -S src/pkcs11.h pkcs11-provider-0.3/.gitignore000066400000000000000000000015541455352356500163200ustar00rootroot00000000000000# project-specific ignore patterns tests/openssl.cnf tests/openssl.cnf.softhsm tests/tmp.softhsm tests/tmp.softokn tests/tdigests tests/tdigest_dupctx tests/tsession tests/tgenkey tests/treadkeys tests/pinfile.txt tests/*.log tests/*.trs tests/pincache tests/tfork tests/tlsctx tests/tcmpkeys /pkcs11-provider-?.?/ /pkcs11-provider-?.?.tar.?z # generic ignore patterns (c, autotools, etc) INSTALL Makefile Makefile.in aclocal.m4 ar-lib autom4te.cache/ compile compile_commands.json config.guess config.log config.status config.sub configure depcomp install-sh libtool ltmain.sh m4/libtool.m4 m4/ltoptions.m4 m4/ltsugar.m4 m4/ltversion.m4 m4/lt~obsolete.m4 missing src/config.h src/config.h.in src/stamp-h1 .deps/ .libs/ *.la *.lo *.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 pkcs11-provider-0.3/.reuse/000077500000000000000000000000001455352356500155245ustar00rootroot00000000000000pkcs11-provider-0.3/.reuse/dep5000066400000000000000000000015751455352356500163140ustar00rootroot00000000000000Format: 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: **/Makefile.am .github/* .gitignore Makefile.am *.md configure.ac configure.ac src/Makefile.am src/provider.exports src/*.gen.c tests/Makefile.am tests/README tests/openssl.cnf.in tests/explicit_ec.* .clang-format .clang-format-ignore packaging/pkcs11-provider.spec docs/* tests/lsan.supp Copyright: (C) 2022 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-0.3/AUTHORS000066400000000000000000000000001455352356500153610ustar00rootroot00000000000000pkcs11-provider-0.3/BUILD.md000066400000000000000000000010471455352356500155060ustar00rootroot00000000000000## Build Prerequisites This package requires the following: - OpenSSL 3.0.7+ libraries and development headers - OpenSSL tools (for testing) - autoconf-archive packages for some m4 macros - NSS softoken, tools and development headers (for testing) - a C compiler that supports at least C11 semantics - automake - pkg-config - libtool - p11-kit, p11-kit-server, p11-kit-devel, opensc and softhsm (for testing) The usual command to build are: - autoreconf -fi (if needed) - ./configure (--with-openssl=/path/to/openssl if needed) - make - make check pkcs11-provider-0.3/CODE_OF_CONDUCT.md000066400000000000000000000121411455352356500171210ustar00rootroot00000000000000# 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, socio-economic 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-0.3/CONTRIBUTING.md000066400000000000000000000051471455352356500165630ustar00rootroot00000000000000# 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 contirbute code you need to understand the [PKCS#11](https://www.oasis-open.org/committees/tc_home.php?wg_abbrev=pkcs11) Specifications and the OpneSSL 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-0.3/COPYING000066400000000000000000000010541455352356500153560ustar00rootroot00000000000000Copyright 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-0.3/ChangeLog000066400000000000000000000000001455352356500160630ustar00rootroot00000000000000pkcs11-provider-0.3/HOWTO.md000066400000000000000000000054531455352356500155540ustar00rootroot00000000000000## How To use the PKCS#11 provider The PKCS#11 provider is an OpenSSL module used to access Hardware and Software Tokens. 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. ## Installation After building the module (see BUILD.md) install it via - make install Or simply copy the pkcs11-provide.so (.dylib on Mac) in the appropriate directory for your OpenSSL installation. ## 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): ``` [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 binary ID, or by a label (called "object" in pkcs11 URIs). 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. pkcs11-provider-0.3/LICENSES/000077500000000000000000000000001455352356500155305ustar00rootroot00000000000000pkcs11-provider-0.3/LICENSES/Apache-2.0.txt000066400000000000000000000261361455352356500177570ustar00rootroot00000000000000 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-0.3/LICENSES/LicenseRef-Public-Domain-PKCS11-Headers.txt000066400000000000000000000001221455352356500251750ustar00rootroot00000000000000This file is in the Public Domain See https://github.com/latchset/pkcs11-headers pkcs11-provider-0.3/Makefile.am000066400000000000000000000027141455352356500163630ustar00rootroot00000000000000ACLOCAL_AMFLAGS = -Im4 SUBDIRS = src tests docs dist_doc_DATA = README.md 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 DISTCLEANFILES = \ *~ MAINTAINERCLEANFILES = \ Makefile.in \ aclocal.m4 \ ar-lib compile \ config.guess \ config.sub \ configure \ depcomp \ install-sh \ ltmain.sh \ m4/* \ missing \ test-driver pkcs11-provider-0.3/NEWS000066400000000000000000000000001455352356500150100ustar00rootroot00000000000000pkcs11-provider-0.3/README000077700000000000000000000000001455352356500164552README.mdustar00rootroot00000000000000pkcs11-provider-0.3/README.md000066400000000000000000000010721455352356500156020ustar00rootroot00000000000000[![Build](https://github.com/latchset/pkcs11-provider/actions/workflows/build.yml/badge.svg)](https://github.com/latchset/pkcs11-provider/actions/workflows/build.yml) 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.1 of the interface but should be backwards compatible to previous versions as well. Spec: https://docs.oasis-open.org/pkcs11/pkcs11-spec/v3.1/pkcs11-spec-v3.1.html See the [wiki](https://github.com/latchset/pkcs11-provider/wiki) for more documentation. pkcs11-provider-0.3/SECURITY.md000066400000000000000000000010171455352356500161130ustar00rootroot00000000000000# 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" teplate from the "New issue" workflow, or email simo@redhat.com directly. Please DO NOT open a generic issue for security vulnerabilities. pkcs11-provider-0.3/configure.ac000066400000000000000000000126451455352356500166210ustar00rootroot00000000000000# -*- Autoconf -*- # Process this file with autoconf to produce a configure script. AC_PREREQ([2.69]) AC_INIT([pkcs11-provider], [0.3], [simo@redhat.com]) AC_CONFIG_SRCDIR([src/provider.c]) AC_CONFIG_HEADERS([src/config.h]) AM_INIT_AUTOMAKE([foreign dist-xz -Wall -Werror]) AC_CONFIG_MACRO_DIRS([m4]) # Checks for programs. AC_PROG_CC AM_PROG_AR LT_INIT PKG_PROG_PKG_CONFIG AX_CHECK_COMPILE_FLAG([-std=c11], [CFLAGS="$CFLAGS -std=c11"], AC_MSG_ERROR([C compiler must support at least C11 standard]) ) AX_VALGRIND_CHECK() STD_CFLAGS="-Wall -Wextra -Wwrite-strings -Wpointer-arith -Wno-missing-field-initializers -Wformat -Wshadow" # Temporarily disable unused parameter until the implementation is complete STD_CFLAGS="$STD_CFLAGS -Wno-unused-parameter" # These should be always errors STD_CFLAGS="$STD_CFLAGS -Werror=implicit-function-declaration -Werror=missing-prototypes -Werror=format-security -Werror=parentheses -Werror=implicit -Werror=strict-prototypes" # Don't enable warnings on VLA yet, but I would avoid using VLAs # STD_CFLAGS"$STD_CFLAGS -Werror=vla" AX_CHECK_COMPILE_FLAG([-fno-strict-aliasing], [STD_CFLAGS="$STD_CFLAGS -fno-strict-aliasing"]) AX_CHECK_COMPILE_FLAG([-Werror -fno-delete-null-pointer-checks], [STD_CFLAGS="$STD_CFLAGS -fno-delete-null-pointer-checks"]) AX_CHECK_COMPILE_FLAG([-fdiagnostics-show-option], [STD_CFLAGS="$STD_CFLAGS -fdiagnostics-show-option"]) AC_SUBST([STD_CFLAGS]) AC_ARG_WITH([openssl], [AS_HELP_STRING([--with-openssl],[the path to the OpenSSL files])], [ OPENSSL_DIR=${withval} case "$OPENSSL_DIR" in # Relative paths ./*|../*) OPENSSL_DIR="`pwd`/$OPENSSL_DIR" esac if test -d "$OPENSSL_DIR/lib64"; then libcrypto_path="$OPENSSL_DIR/lib64" elif test -d "$OPENSSL_DIR/lib"; then libcrypto_path="$OPENSSL_DIR/lib" else # Built but not installed libcrypto_path="$OPENSSL_DIR" fi CFLAGS="-I$OPENSSL_DIR/include $CFLAGS" LDFLAGS="-L${libcrypto_path} ${LDFLAGS}" LIBS="$LIBS -L${libcrypto_path}" CRYPTO_LIBS="-lcrypto" OPENSSL_LIBS="-lcrypto -lssl" AC_MSG_WARN([Custom openssl located in $OPENSSL_DIR is used, lib version check is skipped]) ], [ # Checks for libraries. PKG_CHECK_MODULES( [CRYPTO], [libcrypto >= 3.0.7], , [AC_MSG_ERROR([libcrypto >= 3.0.7 is required])] ) PKG_CHECK_MODULES( [OPENSSL], [libcrypto >= 3.0.7, libssl], , [AC_MSG_ERROR([libcrypto >= 3.0.7 is required])] ) ]) address_sanitizer_path="no" AC_MSG_CHECKING(for --with-address-sanitizer) AC_ARG_WITH(address_sanitizer, AS_HELP_STRING([--with-address-sanitizer=yes|path_to_libasan.so], [Enable Address Sanitizer @<:@default=no@:>@]), [ address_sanitizer_path=${withval} CFLAGS="-fsanitize=address -fno-omit-frame-pointer $CFLAGS" LDFLAGS="-fsanitize=address $LDFLAGS" ], [ address_sanitizer_path="no" ]) AS_IF([test "x$address_sanitizer_path" != "xno"], [AS_IF([test "x$address_sanitizer_path" == "xyes"], [address_sanitizer_path=`realpath $($CC -print-file-name=libasan.so)`], [])], []) AC_MSG_RESULT($address_sanitizer_path) AM_CONDITIONAL([ADDRESS_SANITIZER], [test x${address_sanitizer_path} != xno]) AC_SUBST(ADDRESS_SANITIZER_PATH, "$address_sanitizer_path") AC_SUBST([SHARED_EXT], $(eval echo "${shrext_cmds}")) # Check whether we have a p11-kit to use as a default PKCS#11 module PKG_CHECK_EXISTS([p11-kit-1], [PKG_CHECK_VAR([DEFAULT_PKCS11_MODULE], [p11-kit-1], [proxy_module])], [AC_MSG_WARN([The P11-kit proxy is not available. No fallback PKCS11 module used.])]) if test "x$DEFAULT_PKCS11_MODULE" != "x"; then AC_DEFINE_UNQUOTED([DEFAULT_PKCS11_MODULE], "$DEFAULT_PKCS11_MODULE", [Default PKCS11 module]) fi # Try nss-softoken first as used on Fedora, # fallback to "nss" as used on Debian PKG_CHECK_EXISTS( [nss-softokn], [PKG_CHECK_VAR([SOFTOKENDIR], [nss-softokn], [libdir])], [PKG_CHECK_EXISTS( [nss], [PKG_CHECK_VAR([SOFTOKENDIR], [nss], [libdir])] )] ) if ! test -f $SOFTOKENDIR/libsoftokn3$SHARED_EXT; then if test -f $SOFTOKENDIR/nss/libsoftokn3$SHARED_EXT; then AC_SUBST([SOFTOKEN_SUBDIR], "nss/") else AC_MSG_WARN([Softoken library missing, tests will fail!]) fi fi # find p11-kit-client to separate softhsm openssl context from our tests PKG_CHECK_EXISTS([p11-kit-1], [PKG_CHECK_VAR([P11_MODULE_PATH], [p11-kit-1], [p11_module_path])], [AC_MSG_WARN([The p11-kit client not found. Can not run SoftHSM tests])]) if test "$P11_MODULE_PATH" != "" ; then # p11-kit-client is a module, so its name ends with .so also on macOS! AC_SUBST([P11KITCLIENTPATH], "$P11_MODULE_PATH/p11-kit-client.so") fi # Checks for header files. AC_CHECK_HEADERS([string.h dlfcn.h]) # Checks for typedefs, structures, and compiler characteristics. AC_CHECK_HEADER_STDBOOL AC_C_BIGENDIAN AC_C_INLINE AC_TYPE_SIZE_T # Checks for library functions. AC_CHECK_FUNCS([strpbrk]) AC_CONFIG_FILES([ Makefile docs/Makefile src/Makefile tests/Makefile ]) AC_OUTPUT pkcs11-provider-0.3/docs/000077500000000000000000000000001455352356500152535ustar00rootroot00000000000000pkcs11-provider-0.3/docs/Makefile.am000066400000000000000000000000431455352356500173040ustar00rootroot00000000000000 dist_man_MANS = provider-pkcs11.7 pkcs11-provider-0.3/docs/provider-pkcs11.7000066400000000000000000000173501455352356500203030ustar00rootroot00000000000000.\" Automatically generated by Pandoc 2.14.0.3 .\" .TH "provider-pkcs11" "7" "" "" "Configuration directives" .hy .SH NAME .PP pkcs11-provider - An OpenSSL provider that allows to directly interface with pkcs11 drivers. .SH DESCRIPTION .PP 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 .PP Configuration options recognized by the provider .SS pkcs11-module-path .PP 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[C]pkcs11-module-path = /usr/lib64/opensc-pkcs11.so\f[R] .SS pkcs11-module-init-args .PP 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[C]pkcs11-module-init-args = configDir=/etc/pki/token\f[R] .SS pkcs11-module-token-pin .PP 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[C]pkcs11-module-token-pin = file:/etc/pki/pin.txt\f[R] .IP .nf \f[C] cat /etc/pki/pin.txt 123456 \f[R] .fi .SS pkcs11-module-allow-export .PP 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[C]pkcs11-module-allow-export = 1\f[R] (This disallows export of public keys) .SS pkcs11-module-cache-keys .PP 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[C]pkcs11-module-cache-keys = false\f[R] (Disable any attempt of caching keys in the session) .SS pkcs11-module-cache-pins .PP 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[C]pkcs11-module-cache-pins = cache\f[R] (Will cache a pin that has been entered manually) .SS pkcs11-module-cache-sessions .PP 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[C]pkcs11-module-cache-sessions = 0\f[R] (Disables caching) .SS pkcs11-module-login-behavior .PP 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[C]pkcs11-module-login-behavior = always\f[R] (Always tries to login before loading public keys) .SS pkcs11-module-load-behavior .PP 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[C]pkcs11-module-load-behavior = early\f[R] (Loads pkcs11 module immediately at application startup) .SS pkcs11-module-quirks .PP Workarounds that may be needed to deal with some tokens and cannot be autodetcted yet are not appropriate defaults. .SS no-deinit .PP 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 .PP 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. .PP Default: none .PP Example: .PP \f[C]pkcs11-module-quirks = no-deinit no-operation-state\f[R] (Disables deinitialization) .SH ENVIRONMENT VARIABLES .PP Environment variables recognized by the provider .SS PKCS11_PROVIDER_MODULE .PP 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[C]PKCS11_PROVIDER_MODULE = /usr/lib64/opensc-pkcs11.so\f[R] .SS PKCS11_PROVIDER_DEBUG .PP 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[C]PKCS11_PROVIDER_DEBUG=file:/tmp/debug.log\f[R] .PP \f[C]PKCS11_PROVIDER_DEBUG=file:/dev/stderr,level:2\f[R] .SH EXAMPLES .PP openssl.cnf: .IP .nf \f[C] 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 \f[R] .fi .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-0.3/docs/provider-pkcs11.7.md000066400000000000000000000167471455352356500207130ustar00rootroot00000000000000% 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. Default: none Example: ```pkcs11-module-quirks = no-deinit no-operation-state``` (Disables deinitialization) 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``` 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-0.3/packaging/000077500000000000000000000000001455352356500162475ustar00rootroot00000000000000pkcs11-provider-0.3/packaging/pkcs11-provider.spec000066400000000000000000000035701455352356500220620ustar00rootroot00000000000000#Enable gpg signature verification %bcond_with gpgcheck Name: pkcs11-provider Version: 0.3 Release: 1%{?dist} 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: autoconf-archive BuildRequires: automake BuildRequires: libtool BuildRequires: make %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: p11-kit-server 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 autoreconf -fi %configure %make_build %install %make_install %check # do not run them in parrallel with %{?_smp_mflags} make check || if [ $? -ne 0 ]; then cat tests/*.log; exit 1; fi; %files %license COPYING %{_mandir}/man7/provider-pkcs11.* %doc README.md %{_libdir}/ossl-modules/pkcs11.so %changelog * Mon Jul 10 2023 Sahana Prasad - 0.2-1 + New upstream release * Mon Oct 24 2022 Jakub Jelen - 0.1-1 + Initial Fedora release pkcs11-provider-0.3/src/000077500000000000000000000000001455352356500151125ustar00rootroot00000000000000pkcs11-provider-0.3/src/Makefile.am000066400000000000000000000020231455352356500171430ustar00rootroot00000000000000 AM_CFLAGS = $(STD_CFLAGS) noinst_HEADERS = \ asymmetric_cipher.h \ debug.h \ encoder.h \ digests.h \ exchange.h \ kdf.h \ keymgmt.h \ interface.h \ objects.h \ pkcs11.h \ platform/endian.h \ provider.h \ random.h \ session.h \ signature.h \ slot.h \ store.h \ util.h pkcs11_LTLIBRARIES = pkcs11.la SHARED_EXT=@SHARED_EXT@ pkcs11dir = $(libdir)/ossl-modules pkcs11_la_SOURCES = \ asymmetric_cipher.c \ debug.c \ encoder.c \ digests.c \ exchange.c \ kdf.c \ keymgmt.c \ interface.c \ objects.c \ provider.h \ provider.c \ random.c \ session.c \ signature.c \ slot.c \ store.c \ tls.c \ util.c \ provider.exports \ $(NULL) EXTRA_DIST = \ interface.gen.c \ encoder.gen.c \ $(NULL) pkcs11_la_CFLAGS = $(AM_CFLAGS) $(OPENSSL_CFLAGS) -Wall -Werror pkcs11_la_LIBADD = $(CRYPTO_LIBS) pkcs11_la_LDFLAGS = \ $(AM_LDFLAGS) -module \ -shared -shrext $(SHARED_EXT) \ -avoid-version \ -export-symbols "$(srcdir)/provider.exports" DISTCLEANFILES = \ *~ MAINTAINERCLEANFILES = \ Makefile.in config.h.in pkcs11-provider-0.3/src/asymmetric_cipher.c000066400000000000000000000464231455352356500207760ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include #include "openssl/rsa.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 p11prov_rsaenc_ctx { P11PROV_CTX *provctx; P11PROV_OBJ *key; CK_MECHANISM_TYPE mechtype; CK_RSA_PKCS_OAEP_PARAMS oaep_params; }; 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; } 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); } 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; CK_SESSION_HANDLE sess; CK_SLOT_ID slotid; CK_OBJECT_HANDLE handle; CK_ULONG out_size = *outlen; int result = RET_OSSL_ERR; bool always_auth = false; CK_RV ret; P11PROV_debug("decrypt (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, true, 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_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); } goto endsess; } 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) { goto endsess; } } /* 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, out, &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 */ *outlen = out_size; cond = constant_equal(ret, CKR_OK); result = constant_select_int(cond, RET_OSSL_OK, RET_OSSL_ERR); goto endsess; } ret = p11prov_Decrypt(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 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_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; } } 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; } } } 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; } 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-0.3/src/asymmetric_cipher.h000066400000000000000000000007421455352356500207750ustar00rootroot00000000000000/* 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-0.3/src/debug.c000066400000000000000000000612051455352356500163500ustar00rootroot00000000000000/* 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; } } 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); } } } } 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; c++) { for (int i = 0; profile_ids[i].name != NULL; i++) { if (profiles[c] == slot_flags[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-0.3/src/debug.h000066400000000000000000000033751455352356500163610ustar00rootroot00000000000000/* 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-0.3/src/digests.c000066400000000000000000000355211455352356500167260ustar00rootroot00000000000000/* 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 the configuration indicates that GetOperationState will fail * we don't even try to duplicate the context. */ if (p11prov_ctx_no_operation_state(dctx->provctx)) { goto done; } 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-0.3/src/digests.h000066400000000000000000000063321455352356500167310ustar00rootroot00000000000000/* 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-0.3/src/encoder.c000066400000000000000000000554211455352356500167040ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.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); 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_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; } 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) { CK_OBJECT_CLASS class = p11prov_obj_get_class(key); if (class != CKO_PRIVATE_KEY) { return RET_OSSL_ERR; } 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) { BIO_printf(out, "PKCS11 RSA Public Key (%lu bits)\n", keysize); ret = p11prov_obj_export_public_key(key, CKK_RSA, true, 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); free(uri); } 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, 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; 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; } ret = X509_PUBKEY_set0_param(pubkey, OBJ_nid2obj(NID_rsaEncryption), V_ASN1_NULL, NULL, 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 }, }; /* 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, 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_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; } 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) { CK_OBJECT_CLASS class = p11prov_obj_get_class(key); if (class != CKO_PRIVATE_KEY) { return RET_OSSL_ERR; } 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) { BIO_printf(out, "PKCS11 EC Public Key (%lu bits)\n", keysize); ret = p11prov_obj_export_public_key(key, CKK_EC, true, 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); 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 }, }; pkcs11-provider-0.3/src/encoder.gen.c000066400000000000000000000050571455352356500174540ustar00rootroot00000000000000/* 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-0.3/src/encoder.h000066400000000000000000000032601455352356500167030ustar00rootroot00000000000000/* 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_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[]; #endif /* _ENCODER_H */ pkcs11-provider-0.3/src/encoder.pre000066400000000000000000000013021455352356500172350ustar00rootroot00000000000000/* 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-0.3/src/exchange.c000066400000000000000000000466241455352356500170540ustar00rootroot00000000000000/* 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[5] = { { 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) }, }; 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_attr(ecdhctx->peer_key, CKA_EC_POINT); 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, 5, &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-0.3/src/exchange.h000066400000000000000000000014271455352356500170510ustar00rootroot00000000000000/* 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-0.3/src/interface.c000066400000000000000000000335441455352356500172270ustar00rootroot00000000000000/* 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; } ret = CKR_FUNCTION_NOT_SUPPORTED; 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-0.3/src/interface.gen.c000066400000000000000000000707441455352356500200020ustar00rootroot00000000000000/* 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; } P11PROV_debug("Calling C_" "Initialize"); ret = intf->Initialize(pInitArgs); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "Initialize"); } 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; } P11PROV_debug("Calling C_" "Finalize"); ret = intf->Finalize(pReserved); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "Finalize"); } 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; } P11PROV_debug("Calling C_" "GetInfo"); ret = intf->GetInfo(pInfo); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "GetInfo"); } 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; } P11PROV_debug("Calling C_" "GetInterface"); ret = intf->GetInterface(pInterfaceName, pVersion, ppInterface, flags); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "GetInterface"); } 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; } P11PROV_debug("Calling C_" "GetFunctionList"); ret = intf->GetFunctionList(ppFunctionList); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "GetFunctionList"); } 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; } P11PROV_debug("Calling C_" "GetSlotList"); ret = intf->GetSlotList(tokenPresent, pSlotList, pulCount); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "GetSlotList"); } 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; } P11PROV_debug("Calling C_" "GetSlotInfo"); ret = intf->GetSlotInfo(slotID, pInfo); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "GetSlotInfo"); } 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; } P11PROV_debug("Calling C_" "GetTokenInfo"); ret = intf->GetTokenInfo(slotID, pInfo); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "GetTokenInfo"); } 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; } P11PROV_debug("Calling C_" "GetMechanismList"); ret = intf->GetMechanismList(slotID, pMechanismList, pulCount); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "GetMechanismList"); } 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; } P11PROV_debug("Calling C_" "GetMechanismInfo"); ret = intf->GetMechanismInfo(slotID, type, pInfo); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "GetMechanismInfo"); } 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; } P11PROV_debug("Calling C_" "OpenSession"); ret = intf->OpenSession(slotID, flags, pApplication, Notify, phSession); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "OpenSession"); } 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; } P11PROV_debug("Calling C_" "CloseSession"); ret = intf->CloseSession(hSession); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "CloseSession"); } 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; } P11PROV_debug("Calling C_" "GetSessionInfo"); ret = intf->GetSessionInfo(hSession, pInfo); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "GetSessionInfo"); } 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; } P11PROV_debug("Calling C_" "GetOperationState"); ret = intf->GetOperationState(hSession, pOperationState, pulOperationStateLen); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "GetOperationState"); } 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; } P11PROV_debug("Calling C_" "SetOperationState"); ret = intf->SetOperationState(hSession, pOperationState, ulOperationStateLen, hEncryptionKey, hAuthenticationKey); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "SetOperationState"); } 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; } P11PROV_debug("Calling C_" "Login"); ret = intf->Login(hSession, userType, pPin, ulPinLen); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "Login"); } 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; } P11PROV_debug("Calling C_" "CreateObject"); ret = intf->CreateObject(hSession, pTemplate, ulCount, phObject); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "CreateObject"); } 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; } P11PROV_debug("Calling C_" "CopyObject"); ret = intf->CopyObject(hSession, hObject, pTemplate, ulCount, phNewObject); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "CopyObject"); } 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; } P11PROV_debug("Calling C_" "DestroyObject"); ret = intf->DestroyObject(hSession, hObject); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "DestroyObject"); } 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; } P11PROV_debug("Calling C_" "GetAttributeValue"); ret = intf->GetAttributeValue(hSession, hObject, pTemplate, ulCount); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "GetAttributeValue"); } 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; } P11PROV_debug("Calling C_" "SetAttributeValue"); ret = intf->SetAttributeValue(hSession, hObject, pTemplate, ulCount); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "SetAttributeValue"); } 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; } P11PROV_debug("Calling C_" "FindObjectsInit"); ret = intf->FindObjectsInit(hSession, pTemplate, ulCount); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "FindObjectsInit"); } 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; } P11PROV_debug("Calling C_" "FindObjects"); ret = intf->FindObjects(hSession, phObject, ulMaxObjectCount, pulObjectCount); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "FindObjects"); } 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; } P11PROV_debug("Calling C_" "FindObjectsFinal"); ret = intf->FindObjectsFinal(hSession); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "FindObjectsFinal"); } 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; } P11PROV_debug("Calling C_" "EncryptInit"); ret = intf->EncryptInit(hSession, pMechanism, hKey); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "EncryptInit"); } 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; } P11PROV_debug("Calling C_" "Encrypt"); ret = intf->Encrypt(hSession, pData, ulDataLen, pEncryptedData, pulEncryptedDataLen); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "Encrypt"); } 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; } P11PROV_debug("Calling C_" "DecryptInit"); ret = intf->DecryptInit(hSession, pMechanism, hKey); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "DecryptInit"); } 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; } P11PROV_debug("Calling C_" "Decrypt"); ret = intf->Decrypt(hSession, pEncryptedData, ulEncryptedDataLen, pData, pulDataLen); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "Decrypt"); } 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; } P11PROV_debug("Calling C_" "DigestInit"); ret = intf->DigestInit(hSession, pMechanism); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "DigestInit"); } 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; } P11PROV_debug("Calling C_" "DigestUpdate"); ret = intf->DigestUpdate(hSession, pPart, ulPartLen); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "DigestUpdate"); } 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; } P11PROV_debug("Calling C_" "DigestFinal"); ret = intf->DigestFinal(hSession, pDigest, pulDigestLen); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "DigestFinal"); } 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; } P11PROV_debug("Calling C_" "SignInit"); ret = intf->SignInit(hSession, pMechanism, hKey); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "SignInit"); } 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; } P11PROV_debug("Calling C_" "Sign"); ret = intf->Sign(hSession, pData, ulDataLen, pSignature, pulSignatureLen); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "Sign"); } 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; } P11PROV_debug("Calling C_" "SignUpdate"); ret = intf->SignUpdate(hSession, pPart, ulPartLen); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "SignUpdate"); } 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; } P11PROV_debug("Calling C_" "SignFinal"); ret = intf->SignFinal(hSession, pSignature, pulSignatureLen); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "SignFinal"); } 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; } P11PROV_debug("Calling C_" "VerifyInit"); ret = intf->VerifyInit(hSession, pMechanism, hKey); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "VerifyInit"); } 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; } P11PROV_debug("Calling C_" "Verify"); ret = intf->Verify(hSession, pData, ulDataLen, pSignature, ulSignatureLen); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "Verify"); } 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; } P11PROV_debug("Calling C_" "VerifyUpdate"); ret = intf->VerifyUpdate(hSession, pPart, ulPartLen); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "VerifyUpdate"); } 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; } P11PROV_debug("Calling C_" "VerifyFinal"); ret = intf->VerifyFinal(hSession, pSignature, ulSignatureLen); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "VerifyFinal"); } 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; } P11PROV_debug("Calling C_" "GenerateKeyPair"); ret = intf->GenerateKeyPair(hSession, pMechanism, pPublicKeyTemplate, ulPublicKeyAttributeCount, pPrivateKeyTemplate, ulPrivateKeyAttributeCount, phPublicKey, phPrivateKey); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "GenerateKeyPair"); } 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; } P11PROV_debug("Calling C_" "DeriveKey"); ret = intf->DeriveKey(hSession, pMechanism, hBaseKey, pTemplate, ulAttributeCount, phKey); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "DeriveKey"); } 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; } P11PROV_debug("Calling C_" "SeedRandom"); ret = intf->SeedRandom(hSession, pSeed, ulSeedLen); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "SeedRandom"); } 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; } P11PROV_debug("Calling C_" "GenerateRandom"); ret = intf->GenerateRandom(hSession, RandomData, ulRandomLen); if (ret != CKR_OK) { P11PROV_raise(ctx, ret, "Error returned by C_" "GenerateRandom"); } return ret; } pkcs11-provider-0.3/src/interface.h000066400000000000000000000204231455352356500172240ustar00rootroot00000000000000/* 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); #endif /* _INTERFACE_H */ pkcs11-provider-0.3/src/interface.pre000066400000000000000000000223301455352356500175620ustar00rootroot00000000000000/* 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; \ } \ P11PROV_debug("Calling C_" #name); #define IMPL_CALL_EPILOG(name) \ if (ret != CKR_OK) { \ P11PROV_raise(ctx, ret, "Error returned by C_" #name); \ } \ 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-0.3/src/kdf.c000066400000000000000000000301631455352356500160250ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include #include struct p11prov_kdf_ctx { P11PROV_CTX *provctx; P11PROV_OBJ *key; CK_MECHANISM_TYPE mechtype; CK_HKDF_PARAMS params; P11PROV_SESSION *session; }; 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_DERIVE; 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->params.pSalt, hkdfctx->params.ulSaltLen); OPENSSL_clear_free(hkdfctx->params.pInfo, hkdfctx->params.ulInfoLen); /* zero all */ memset(hkdfctx, 0, sizeof(*hkdfctx)); /* restore defaults */ hkdfctx->provctx = provctx; hkdfctx->mechtype = CKM_HKDF_DERIVE; } 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_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 = keylen; CK_ATTRIBUTE key_template[5] = { { 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) }, }; CK_MECHANISM mechanism; CK_OBJECT_HANDLE pkey_handle; CK_OBJECT_HANDLE dkey_handle; CK_SLOT_ID slotid; struct fetch_attrs attrs[1]; int num = 0; CK_RV ret; P11PROV_debug("hkdf derive (ctx:%p, key:%p[%zu], params:%p)", ctx, key, keylen, params); 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; } mechanism.mechanism = hkdfctx->mechtype; mechanism.pParameter = &hkdfctx->params; mechanism.ulParameterLen = sizeof(hkdfctx->params); pkey_handle = p11prov_obj_get_handle(hkdfctx->key); if (pkey_handle == CK_INVALID_HANDLE) { P11PROV_raise(hkdfctx->provctx, CKR_KEY_HANDLE_INVALID, "Provided key has invalid handle"); return RET_OSSL_ERR; } /* no salt ? */ if (hkdfctx->params.ulSaltType == 0) { hkdfctx->params.ulSaltType = CKF_HKDF_SALT_NULL; } slotid = p11prov_obj_get_slotid(hkdfctx->key); if (slotid == CK_UNAVAILABLE_INFORMATION) { P11PROV_raise(hkdfctx->provctx, CKR_SLOT_ID_INVALID, "Provided key has invalid slot"); return RET_OSSL_ERR; } ret = p11prov_derive_key(hkdfctx->provctx, slotid, &mechanism, pkey_handle, key_template, 5, &hkdfctx->session, &dkey_handle); if (ret != CKR_OK) { return RET_OSSL_ERR; } P11PROV_debug("HKDF derived hey handle: %lu", dkey_handle); FA_SET_BUF_VAL(attrs, num, CKA_VALUE, key, keylen, true); ret = p11prov_fetch_attributes(hkdfctx->provctx, hkdfctx->session, dkey_handle, attrs, num); if (ret != CKR_OK) { P11PROV_raise(hkdfctx->provctx, ret, "Failed to retrieve derived key"); return RET_OSSL_ERR; } FA_GET_LEN(attrs, 0, key_size); if (key_size != keylen) { ret = CKR_GENERAL_ERROR; P11PROV_raise(hkdfctx->provctx, ret, "Expected derived key of len %zu, but got %lu", keylen, key_size); 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; } 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->params.prfHashMechanism); if (rv != CKR_OK) { ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_DIGEST); return RET_OSSL_ERR; } P11PROV_debug("set digest to %lu", hkdfctx->params.prfHashMechanism); } p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_MODE); if (p) { int mode; if (p->data_type == OSSL_PARAM_UTF8_STRING) { if (OPENSSL_strcasecmp(p->data, "EXTRACT_AND_EXPAND") == 0) { mode = EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND; } else if (OPENSSL_strcasecmp(p->data, "EXTRACT_ONLY") == 0) { mode = EVP_KDF_HKDF_MODE_EXTRACT_ONLY; } else if (OPENSSL_strcasecmp(p->data, "EXPAND_ONLY") == 0) { mode = EVP_KDF_HKDF_MODE_EXPAND_ONLY; } else { mode = 1; } } else { ret = OSSL_PARAM_get_int(p, &mode); if (ret != RET_OSSL_OK) { return ret; } } switch (mode) { case EVP_KDF_HKDF_MODE_EXTRACT_AND_EXPAND: hkdfctx->params.bExtract = CK_TRUE; hkdfctx->params.bExpand = CK_TRUE; break; case EVP_KDF_HKDF_MODE_EXTRACT_ONLY: hkdfctx->params.bExtract = CK_TRUE; hkdfctx->params.bExpand = CK_FALSE; break; case EVP_KDF_HKDF_MODE_EXPAND_ONLY: hkdfctx->params.bExtract = CK_FALSE; hkdfctx->params.bExpand = CK_TRUE; break; default: ERR_raise(ERR_LIB_PROV, PROV_R_INVALID_MODE); return RET_OSSL_ERR; } P11PROV_debug("set mode to extract:%d expand:%d", (int)hkdfctx->params.bExtract, (int)hkdfctx->params.bExpand); } p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_KEY); if (p) { CK_SLOT_ID slotid = CK_UNAVAILABLE_INFORMATION; void *secret = NULL; size_t secret_len; /* TODO: import into a pkcs11 key? */ ret = OSSL_PARAM_get_octet_string(p, &secret, 0, &secret_len); if (ret != RET_OSSL_OK) { return ret; } /* Create Session and key from key material */ 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_OSSL_ERR; } } if (hkdfctx->session == NULL) { return RET_OSSL_ERR; } hkdfctx->key = p11prov_create_secret_key( hkdfctx->provctx, hkdfctx->session, true, secret, secret_len); OPENSSL_clear_free(secret, secret_len); if (hkdfctx->key == NULL) { return RET_OSSL_ERR; } } p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_SALT); if (p) { void *ptr = NULL; size_t len; OPENSSL_cleanse(hkdfctx->params.pSalt, hkdfctx->params.ulSaltLen); hkdfctx->params.pSalt = NULL; ret = OSSL_PARAM_get_octet_string(p, &ptr, 0, &len); if (ret != RET_OSSL_OK) { return ret; } hkdfctx->params.ulSaltType = CKF_HKDF_SALT_DATA; hkdfctx->params.pSalt = ptr; hkdfctx->params.ulSaltLen = len; P11PROV_debug("set salt (len:%lu)", hkdfctx->params.ulSaltLen); } /* can be multiple parameters, which will be all concatenated */ for (p = OSSL_PARAM_locate_const(params, OSSL_KDF_PARAM_INFO); p != NULL; 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->params.ulInfoLen + p->data_size; ptr = OPENSSL_realloc(hkdfctx->params.pInfo, len); if (ptr == NULL) { OPENSSL_cleanse(hkdfctx->params.pInfo, hkdfctx->params.ulInfoLen); return RET_OSSL_ERR; } memcpy(ptr + hkdfctx->params.ulInfoLen, p->data, p->data_size); hkdfctx->params.pInfo = ptr; hkdfctx->params.ulInfoLen = len; P11PROV_debug("set info (len:%lu)", hkdfctx->params.ulInfoLen); } 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->params.bExpand != CK_FALSE) { ret_size = SIZE_MAX; } else { CK_RV rv; rv = p11prov_digest_get_digest_size( hkdfctx->params.prfHashMechanism, &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 }, }; pkcs11-provider-0.3/src/kdf.h000066400000000000000000000007361455352356500160350ustar00rootroot00000000000000/* 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[]; #endif /* _KDF_H */ pkcs11-provider-0.3/src/keymgmt.c000066400000000000000000001644141455352356500167450ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include "platform/endian.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; }; static void *p11prov_common_gen_init(void *provctx, int selection, CK_KEY_TYPE type, const OSSL_PARAM params[]) { struct key_generator *ctx = NULL; /* big endian 65537 */ unsigned char def_e[] = { 0x01, 0x00, 0x01 }; int ret; P11PROV_debug("common 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 = type; /* set defaults */ switch (type) { case CKK_RSA: 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); break; case CKK_EC: ctx->mechanism.mechanism = CKM_EC_KEY_PAIR_GEN; ctx->data.ec.ec_params = prime256v1_param; ctx->data.ec.ec_params_size = sizeof(prime256v1_param); break; case CKK_EC_EDWARDS: ctx->mechanism.mechanism = CKM_EC_EDWARDS_KEY_PAIR_GEN; break; default: P11PROV_raise(provctx, CKR_ARGUMENTS_BAD, "Invalid type %lu", type); OPENSSL_free(ctx); return NULL; } 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_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 void *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) { 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 NULL; } 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 NULL; } 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) { /* generate unique id for the key */ ret = p11prov_GenerateRandom(ctx->provctx, sh, id, sizeof(id)); if (ret != CKR_OK) { 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; } ret = p11prov_merge_pub_attrs_into_priv(pub_key, priv_key); done: if (ret != CKR_OK) { p11prov_obj_free(priv_key); priv_key = NULL; } p11prov_return_session(session); p11prov_obj_free(pub_key); return priv_key; } 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[]) { P11PROV_debug("rsa gen_init %p", provctx); return p11prov_common_gen_init(provctx, selection, CKK_RSA, params); } static void *p11prov_rsa_gen(void *genctx, OSSL_CALLBACK *cb_fn, void *cb_arg) { 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 CK_ATTRIBUTE privkey_template[RSA_PRIVKEY_TMPL_SIZE + COMMON_TMPL_SIZE] = { { 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) }, /* TODO? * CKA_SUBJECT * CKA_COPYABLE = true ? */ }; int pubtsize = RSA_PUBKEY_TMPL_SIZE; int privtsize = RSA_PRIVKEY_TMPL_SIZE; 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); } 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_INVALID_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", keydata); 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, 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) { CK_MECHANISM_TYPE 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 }; ctx->data.rsa.allowed_types = OPENSSL_malloc(sizeof(rsapss_mechs)); 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, rsapss_mechs, sizeof(rsapss_mechs)); ctx->data.rsa.allowed_types_size = sizeof(rsapss_mechs) / sizeof(CK_MECHANISM_TYPE); 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; P11PROV_OBJ *key = NULL; CK_RV ret; key = p11prov_rsa_gen(genctx, cb_fn, cb_arg); if (!key) { return NULL; } /* params could already be caying pss restriction. If allowed_types * is already set, skip setting defaults */ if (!ctx->data.rsa.allowed_types) { ret = set_default_rsapss_mechanisms(ctx); if (ret != CKR_OK) { P11PROV_raise(ctx->provctx, ret, "Failed to get pss params"); goto done; } } 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"); goto done; } if (token_supports_allowed_mechs == CK_TRUE) { CK_ATTRIBUTE template[] = { { CKA_ALLOWED_MECHANISMS, ctx->data.rsa.allowed_types, ctx->data.rsa.allowed_types_size }, }; CK_ULONG tsize = 1; ret = p11prov_obj_set_attributes(ctx->provctx, NULL, key, template, tsize); if (ret != CKR_OK) { P11PROV_debug("Failed to add RSAPSS restrictions (%lu)", ret); if (ret == CKR_ATTRIBUTE_TYPE_INVALID) { /* set quirk to disable future attempts for this token */ 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_obj_free(key); key = NULL; } return key; } 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(common, 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, 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_INVALID_HANDLE, CK_UNAVAILABLE_INFORMATION); } static void *p11prov_ec_gen_init(void *provctx, int selection, const OSSL_PARAM params[]) { P11PROV_debug("ec gen_init %p", provctx); return p11prov_common_gen_init(provctx, selection, CKK_EC, params); } static void *p11prov_ec_gen(void *genctx, OSSL_CALLBACK *cb_fn, void *cb_arg) { struct key_generator *ctx = (struct key_generator *)genctx; /* 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 5 CK_ATTRIBUTE privkey_template[EC_PRIVKEY_TMPL_SIZE + COMMON_TMPL_SIZE] = { { 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_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); return p11prov_common_gen(ctx, pubkey_template, privkey_template, pubtsize, privtsize, cb_fn, cb_arg); } 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(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("ec 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_PRIV_KEY); if (!p) { /* not really a private key */ class = CKO_PUBLIC_KEY; } } rv = p11prov_obj_import_key(key, CKK_EC, class, params); if (rv != CKR_OK) { return RET_OSSL_ERR; } return RET_OSSL_OK; } 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); CK_OBJECT_CLASS class = p11prov_obj_get_class(key); P11PROV_debug("ec export %p", keydata); if (key == NULL) { return RET_OSSL_ERR; } if (p11prov_ctx_allow_export(ctx) & DISALLOW_EXPORT_PUBLIC) { return RET_OSSL_ERR; } /* this will return the public EC_POINT as well as DOMAIN_PARAMTERS */ if ((class == CKO_PUBLIC_KEY) || (selection & ~(PUBLIC_PARAMS)) == 0) { return p11prov_obj_export_public_key(key, CKK_EC, true, cb_fn, cb_arg); } return RET_OSSL_ERR; } 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; } 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); 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; } } 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_PKEY_PARAM_ENCODED_PUBLIC_KEY * OSSL_PKEY_PARAM_EC_DECODED_FROM_EXPLICIT_PARAM * OSSL_PKEY_PARAM_EC_ENCODING * OSSL_PKEY_PARAM_EC_POINT_CONVERSION_FORMAT * 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); ctx = p11prov_common_gen_init(provctx, selection, CKK_EC_EDWARDS, curve); if (!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); ctx = p11prov_common_gen_init(provctx, selection, CKK_EC_EDWARDS, curve); if (!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); CK_OBJECT_CLASS class = p11prov_obj_get_class(key); P11PROV_debug("ed export %p", keydata); if (key == NULL) { return RET_OSSL_ERR; } if (p11prov_ctx_allow_export(ctx) & DISALLOW_EXPORT_PUBLIC) { return RET_OSSL_ERR; } /* this will return the public EC_POINT */ if ((class == CKO_PUBLIC_KEY) || (selection & ~(PUBLIC_PARAMS)) == 0) { return p11prov_obj_export_public_key(key, CKK_EC_EDWARDS, true, cb_fn, cb_arg); } return RET_OSSL_ERR; } 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; } } return RET_OSSL_OK; } static const OSSL_PARAM *p11prov_ed_gettable_params(void *provctx) { static const OSSL_PARAM params[] = { /* TODO: 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(ec, 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: match, 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(ec, 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: match, 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-0.3/src/keymgmt.h000066400000000000000000000014111455352356500167350ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _KEYMGMT_H #define _KEYMGMT_H /* keymgmt */ #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-0.3/src/objects.c000066400000000000000000002504701455352356500167170ustar00rootroot00000000000000/* 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; }; 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 */ } 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_INVALID_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); 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; } 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; } 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; } /* 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); 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; } 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; ASN1_OCTET_STRING *octet; 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; } val = attr->pValue; octet = d2i_ASN1_OCTET_STRING(NULL, (const unsigned char **)&val, attr->ulValueLen); if (!octet) { return CKR_KEY_INDIGESTIBLE; } CKATTR_ASSIGN(key->attrs[key->numattrs], CKA_P11PROV_PUB_KEY, octet->data, octet->length); key->numattrs++; /* moved octet data to attrs, do not free it */ octet->data = NULL; octet->length = 0; ASN1_OCTET_STRING_free(octet); 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); } FA_SET_BUF_ALLOC(attrs, num, CKA_ID, false); FA_SET_BUF_ALLOC(attrs, num, CKA_LABEL, false); 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); 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; } static P11PROV_OBJ *find_associated_obj(P11PROV_CTX *provctx, 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"); id = p11prov_obj_get_attr(obj, CKA_ID); if (!id || id->ulValueLen == 0) { P11PROV_raise(provctx, 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(provctx, &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(provctx, sess, template, 2); if (ret != CKR_OK) { goto done; } /* we expect a single entry */ ret = p11prov_FindObjects(provctx, sess, &handle, 1, &objcount); fret = p11prov_FindObjectsFinal(provctx, sess); if (fret != CKR_OK) { /* this is not fatal */ P11PROV_raise(provctx, fret, "Failed to terminate object search"); } if (ret != CKR_OK) { goto done; } if (objcount != 1) { P11PROV_raise(provctx, ret, "Error in C_FindObjects (count=%ld)", objcount); goto done; } ret = p11prov_obj_from_handle(provctx, session, handle, &retobj); if (ret != CKR_OK) { P11PROV_raise(provctx, ret, "Failed to get object from handle"); } 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; 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 = find_associated_obj(obj->ctx, 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 = find_associated_obj(obj->ctx, 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 + 1]; CK_RV rv; int ret; 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[0] = 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[1] = OSSL_PARAM_construct_BN(OSSL_PKEY_PARAM_RSA_E, attrs[1].pValue, attrs[1].ulValueLen); params[RSA_PUB_ATTRS] = 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; } 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, 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 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; nattr = 1; 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); attrs[0].type = CKA_P11PROV_PUB_KEY; if (curve_nid == NID_undef) { attrs[1].type = CKA_EC_PARAMS; } else { attrs[1].type = CKA_P11PROV_CURVE_NAME; } nattr = 2; break; case CKK_EC_EDWARDS: attrs[0].type = CKA_P11PROV_PUB_KEY; nattr = 1; break; default: return RET_OSSL_ERR; } 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; } params[nparam] = OSSL_PARAM_construct_octet_string( OSSL_PKEY_PARAM_PUB_KEY, attrs[0].pValue, attrs[0].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[1].pValue; group = d2i_ECPKParameters(NULL, &val, attrs[1].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[1].pValue, attrs[1].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, 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, cb_fn, cb_arg); default: P11PROV_raise(obj->ctx, CKR_GENERAL_ERROR, "Unsupported key type"); return RET_OSSL_ERR; } } 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; } /* 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; } 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: ret = cmp_attr(pub_key1, pub_key2, CKA_MODULUS); 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_public_keys(P11PROV_OBJ *key1, P11PROV_OBJ *key2) { P11PROV_OBJ *pub_key, *assoc_pub_key; P11PROV_OBJ *priv_key; int ret = RET_OSSL_ERR; if (key1->class == CKO_PUBLIC_KEY && key2->class == CKO_PUBLIC_KEY) { /* both keys are public, match directly their public values */ return cmp_public_key_values(key1, key2); } /* 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 = find_associated_obj(priv_key->ctx, priv_key, CKO_PUBLIC_KEY); if (!assoc_pub_key) { P11PROV_raise(priv_key->ctx, CKR_GENERAL_ERROR, "Could not find associated public key object"); return RET_OSSL_ERR; } 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; } 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: ret = cmp_attr(key1, key2, CKA_PUBLIC_EXPONENT); 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 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: case CKK_EC_EDWARDS: 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; 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) { CK_RV rv; if (findctx->numattrs != MAX_ATTRS_SIZE) { return CKR_ARGUMENTS_BAD; } findctx->numattrs = 0; 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++; 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++; findctx->key_size = findctx->attrs[0].ulValueLen; findctx->bit_size = findctx->key_size * 8; return CKR_OK; } static CK_RV prep_ec_find(P11PROV_CTX *ctx, const OSSL_PARAM params[], struct pool_find_ctx *findctx) { EC_GROUP *group = NULL; OSSL_PARAM tmp; const char *curve_name = NULL; int curve_nid; unsigned char *ecparams = NULL; int len; CK_RV rv; if (findctx->numattrs != MAX_ATTRS_SIZE) { return CKR_ARGUMENTS_BAD; } findctx->numattrs = 0; rv = param_to_attr(ctx, params, OSSL_PKEY_PARAM_PUB_KEY, &findctx->attrs[0], CKA_P11PROV_PUB_KEY, false); if (rv != CKR_OK) { return rv; } findctx->numattrs++; 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; } } 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 != NULL) { 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++; } 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; } 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++; 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); 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; dst->attrs = OPENSSL_malloc(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; } CK_RV p11prov_obj_import_key(P11PROV_OBJ *key, CK_KEY_TYPE type, CK_OBJECT_CLASS class, const OSSL_PARAM params[]) { P11PROV_CTX *ctx; struct pool_find_ctx findctx = { .type = type, .class = class, .bit_size = 0, .attrs = { { 0 } }, .numattrs = MAX_ATTRS_SIZE, .found = NULL, }; int allocattrs = 0; CK_RV rv; /* 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; } if (class != CKO_PUBLIC_KEY) { P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE, "Only public keys are supported"); return CKR_KEY_INDIGESTIBLE; } 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: case CKK_EC_EDWARDS: rv = prep_ec_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 objects 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; } 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 len; if (key->handle != CK_INVALID_HANDLE) { /* * not a mock object, cannot set public key to a token object backed by * an actual handle */ P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE, "Cannot change public key of a token object"); return CKR_KEY_INDIGESTIBLE; } 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; } ecpoint = p11prov_obj_get_attr(key, CKA_EC_POINT); if (!ecpoint) { P11PROV_raise(key->ctx, CKR_KEY_INDIGESTIBLE, "No public key found"); return CKR_KEY_INDIGESTIBLE; } OPENSSL_free(pub->pValue); memset(pub, 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; } OPENSSL_free(ecpoint->pValue); 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; } /* *Copy attributes from public key to private key *so that the public key can be reconstructed from *a private key directly. */ #define RSA_PRIV_ATTRS_NUM 2 #define EC_PRIV_ATTRS_NUM 3 CK_RV p11prov_merge_pub_attrs_into_priv(P11PROV_OBJ *pub_key, P11PROV_OBJ *priv_key) { CK_RV ret = CKR_OK; if (!pub_key || !priv_key) { P11PROV_debug( "Empty keys. Cannot copy public key attributes into private key"); return CKR_ARGUMENTS_BAD; } switch (pub_key->data.key.type) { case CKK_RSA: priv_key->attrs = OPENSSL_realloc( priv_key->attrs, (priv_key->numattrs + RSA_PRIV_ATTRS_NUM) * sizeof(CK_ATTRIBUTE)); if (!priv_key->attrs) { ret = CKR_HOST_MEMORY; P11PROV_raise(priv_key->ctx, ret, "Failed allocation"); return ret; } ret = p11prov_obj_copy_specific_attr(pub_key, priv_key, CKA_MODULUS); if (ret != CKR_OK) { goto err; } ret = p11prov_obj_copy_specific_attr(pub_key, priv_key, CKA_PUBLIC_EXPONENT); if (ret != CKR_OK) { goto err; } break; case CKK_EC: case CKK_EC_EDWARDS: priv_key->attrs = OPENSSL_realloc( priv_key->attrs, (priv_key->numattrs + EC_PRIV_ATTRS_NUM) * sizeof(CK_ATTRIBUTE)); if (!priv_key->attrs) { ret = CKR_HOST_MEMORY; P11PROV_raise(priv_key->ctx, ret, "Failed allocation"); return ret; } ret = p11prov_obj_copy_specific_attr(pub_key, priv_key, CKA_EC_POINT); if (ret != CKR_OK) { goto err; } ret = p11prov_obj_copy_specific_attr(pub_key, priv_key, CKA_EC_PARAMS); if (ret != CKR_OK) { goto err; } ret = p11prov_obj_copy_specific_attr(pub_key, priv_key, CKA_P11PROV_PUB_KEY); if (ret != CKR_OK) { goto err; } break; default: /* unknown key type, we can't copy public key attributes */ P11PROV_debug("Unsupported key type (%lu)", pub_key->data.key.type); return CKR_ARGUMENTS_BAD; } return ret; err: P11PROV_raise(priv_key->ctx, ret, "Failed attr copy"); return CKR_GENERAL_ERROR; } pkcs11-provider-0.3/src/objects.h000066400000000000000000000111271455352356500167160ustar00rootroot00000000000000/* 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 /* 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); 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); int p11prov_obj_export_public_key(P11PROV_OBJ *obj, CK_KEY_TYPE key_type, bool search_related, 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); #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); CK_RV p11prov_merge_pub_attrs_into_priv(P11PROV_OBJ *pub_key, P11PROV_OBJ *priv_key); #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-0.3/src/pkcs11.h000066400000000000000000002500261455352356500163720ustar00rootroot00000000000000/* 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-0.3/src/platform/000077500000000000000000000000001455352356500167365ustar00rootroot00000000000000pkcs11-provider-0.3/src/platform/endian.h000066400000000000000000000101571455352356500203510ustar00rootroot00000000000000/* 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-0.3/src/provider.c000066400000000000000000001421021455352356500171100ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.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; /* TODO: ui_method */ /* TODO: fork id */ /* cfg quirks */ bool no_deinit; bool no_allowed_mechanisms; bool no_operation_state; /* 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; 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--; } 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); /* keymgmt is static */ OPENSSL_free(ctx->op_exchange); OPENSSL_free(ctx->op_signature); OPENSSL_free(ctx->op_asym_cipher); OPENSSL_free(ctx->op_encoder); /* store is static */ 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_no_operation_state(P11PROV_CTX *ctx) { return ctx->no_operation_state; } 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) \ ADD_ALGO_EXT(NAME, operation, P11PROV_DEFAULT_PROPERTIES, \ 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 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 encoder_idx = 0; int slot_idx = 0; 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); 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); UNCHECK_MECHS(CKM_EC_KEY_PAIR_GEN, CKM_ECDH1_DERIVE, CKM_ECDH1_COFACTOR_DERIVE); break; case CKM_HKDF_DERIVE: ADD_ALGO(HKDF, hkdf, kdf); ADD_ALGO(HKDF, hkdf, exchange); UNCHECK_MECHS(CKM_HKDF_DERIVE); break; case CKM_SHA_1: ADD_ALGO(SHA1, sha1, digest); UNCHECK_MECHS(CKM_SHA_1); break; case CKM_SHA224: ADD_ALGO(SHA2_224, sha224, digest); UNCHECK_MECHS(CKM_SHA224); break; case CKM_SHA256: ADD_ALGO(SHA2_256, sha256, digest); UNCHECK_MECHS(CKM_SHA256); break; case CKM_SHA384: ADD_ALGO(SHA2_384, sha384, digest); UNCHECK_MECHS(CKM_SHA384); break; case CKM_SHA512: ADD_ALGO(SHA2_512, sha512, digest); UNCHECK_MECHS(CKM_SHA512); break; case CKM_SHA512_224: ADD_ALGO(SHA2_512_224, sha512_224, digest); UNCHECK_MECHS(CKM_SHA512_224); break; case CKM_SHA512_256: ADD_ALGO(SHA2_512_256, sha512_256, digest); UNCHECK_MECHS(CKM_SHA512_256); break; case CKM_SHA3_224: ADD_ALGO(SHA3_224, sha3_224, digest); UNCHECK_MECHS(CKM_SHA3_224); break; case CKM_SHA3_256: ADD_ALGO(SHA3_256, sha3_256, digest); UNCHECK_MECHS(CKM_SHA3_256); break; case CKM_SHA3_384: ADD_ALGO(SHA3_384, sha3_384, digest); UNCHECK_MECHS(CKM_SHA3_384); break; case CKM_SHA3_512: ADD_ALGO(SHA3_512, sha3_512, digest); UNCHECK_MECHS(CKM_SHA3_512); break; case CKM_EDDSA: ADD_ALGO_EXT(ED25519, signature, P11PROV_DEFAULT_PROPERTIES, p11prov_eddsa_signature_functions); ADD_ALGO_EXT(ED448, signature, P11PROV_DEFAULT_PROPERTIES, 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); } if (add_rsaenc) { ADD_ALGO(RSA, rsa, asym_cipher); } /* terminations */ TERM_ALGO(digest); TERM_ALGO(kdf); TERM_ALGO(exchange); TERM_ALGO(signature); TERM_ALGO(asym_cipher); /* encoder/decoder */ ADD_ALGO_EXT(RSA, encoder, "provider=pkcs11,output=text", p11prov_rsa_encoder_text_functions); ADD_ALGO_EXT(RSA, encoder, "provider=pkcs11,output=der,structure=pkcs1", p11prov_rsa_encoder_pkcs1_der_functions); ADD_ALGO_EXT(RSA, encoder, "provider=pkcs11,output=pem,structure=pkcs1", p11prov_rsa_encoder_pkcs1_pem_functions); ADD_ALGO_EXT(RSA, encoder, "provider=pkcs11,output=der,structure=SubjectPublicKeyInfo", p11prov_rsa_encoder_spki_der_functions); ADD_ALGO_EXT(RSA, encoder, "provider=pkcs11,output=pem,structure=SubjectPublicKeyInfo", p11prov_rsa_encoder_spki_pem_functions); ADD_ALGO_EXT(EC, encoder, "provider=pkcs11,output=text", p11prov_ec_encoder_text_functions); ADD_ALGO_EXT(EC, encoder, "provider=pkcs11,output=der,structure=pkcs1", p11prov_ec_encoder_pkcs1_der_functions); ADD_ALGO_EXT(EC, encoder, "provider=pkcs11,output=pem,structure=pkcs1", p11prov_ec_encoder_pkcs1_pem_functions); ADD_ALGO_EXT(EC, encoder, "provider=pkcs11,output=der,structure=SubjectPublicKeyInfo", p11prov_ec_encoder_spki_der_functions); TERM_ALGO(encoder); /* handle random */ ret = p11prov_check_random(ctx); if (ret == CKR_OK) { ADD_ALGO_EXT(RAND, random, "provider=pkcs11", p11prov_rand_functions); TERM_ALGO(random); } return CKR_OK; } static const OSSL_ALGORITHM p11prov_keymgmt[] = { { P11PROV_NAMES_RSA, P11PROV_DEFAULT_PROPERTIES, p11prov_rsa_keymgmt_functions, P11PROV_DESCS_RSA }, { P11PROV_NAMES_RSAPSS, P11PROV_DEFAULT_PROPERTIES, p11prov_rsapss_keymgmt_functions, P11PROV_DESCS_RSAPSS }, { P11PROV_NAMES_EC, P11PROV_DEFAULT_PROPERTIES, p11prov_ec_keymgmt_functions, P11PROV_DESCS_EC }, { P11PROV_NAMES_HKDF, P11PROV_DEFAULT_PROPERTIES, p11prov_hkdf_keymgmt_functions, P11PROV_DESCS_HKDF }, { P11PROV_NAMES_ED25519, P11PROV_DEFAULT_PROPERTIES, p11prov_ed25519_keymgmt_functions, P11PROV_DESCS_ED25519 }, { P11PROV_NAMES_ED448, P11PROV_DEFAULT_PROPERTIES, p11prov_ed448_keymgmt_functions, P11PROV_DESCS_ED448 }, { NULL, NULL, NULL, NULL }, }; static const OSSL_ALGORITHM p11prov_store[] = { { "pkcs11", P11PROV_DEFAULT_PROPERTIES, p11prov_store_functions, P11PROV_DESCS_URI, }, { NULL, NULL, NULL, NULL }, }; static const OSSL_ALGORITHM * p11prov_query_operation(void *provctx, int operation_id, int *no_cache) { P11PROV_CTX *ctx = (P11PROV_CTX *)provctx; *no_cache = 0; switch (operation_id) { case OSSL_OP_DIGEST: return ctx->op_digest; case OSSL_OP_KDF: return ctx->op_kdf; case OSSL_OP_RAND: return ctx->op_random; case OSSL_OP_KEYMGMT: return p11prov_keymgmt; case OSSL_OP_KEYEXCH: return ctx->op_exchange; case OSSL_OP_SIGNATURE: return ctx->op_signature; case OSSL_OP_ASYM_CIPHER: return ctx->op_asym_cipher; case OSSL_OP_ENCODER: return ctx->op_encoder; case OSSL_OP_STORE: return p11prov_store; } 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_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" }, }; 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; 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) { ctx->no_deinit = true; } else if (strncmp(str, "no-allowed-mechanisms", toklen) == 0) { ctx->no_allowed_mechanisms = true; } else if (strncmp(str, "no-operation-state", toklen) == 0) { ctx->no_operation_state = true; } len -= toklen; if (sep) { str = sep + 1; len--; } else { str = NULL; } } } if (ctx->no_deinit || ctx->no_allowed_mechanisms) { 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"); } } 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); /* 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-0.3/src/provider.exports000066400000000000000000000000231455352356500203650ustar00rootroot00000000000000OSSL_provider_init pkcs11-provider-0.3/src/provider.h000066400000000000000000000125371455352356500171250ustar00rootroot00000000000000/* 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_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_DESCS_URI "PKCS11 URI Store" #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_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_no_operation_state(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" /* TLS */ int tls_group_capabilities(OSSL_CALLBACK *cb, void *arg); #endif /* _PROVIDER_H */ pkcs11-provider-0.3/src/random.c000066400000000000000000000135111455352356500165370ustar00rootroot00000000000000/* 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-0.3/src/random.h000066400000000000000000000007521455352356500165470ustar00rootroot00000000000000/* 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-0.3/src/session.c000066400000000000000000000775701455352356500167610ustar00rootroot00000000000000/* 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; int num_sessions; int max_sessions; int open_sessions; int 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 { 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 (%d) 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: %d", 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) { return session->session; } CK_SLOT_ID p11prov_session_slotid(P11PROV_SESSION *session) { 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; } /* 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); } } 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-0.3/src/session.h000066400000000000000000000031151455352356500167460ustar00rootroot00000000000000/* 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-0.3/src/signature.c000066400000000000000000002236531455352356500172720ustar00rootroot00000000000000/* 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; /* NOTE: most tokens will probably return errors trying to do this on sign * sessions. If the configuration indicates that GetOperationState will fail * we don't even try to duplicate the context. */ if (p11prov_ctx_no_operation_state(sigctx->provctx)) { goto done; } 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; 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 /* 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_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 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) 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) hashAlgorithmIdentifier(26) */ static const unsigned char der_digestinfo_sha1[] = { DER_SEQUENCE, 0x0d + SHA_DIGEST_LENGTH, DER_SEQUENCE, 0x09, DER_OBJECT, 0x05, 1 * 40 + 3, 14, 3, 2, 26, DER_NULL, 0x00, DER_OCTET_STRING, 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), \ } #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), \ } /* 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; }; 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) }, { 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_ATTRIBUTE *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; } 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; } sigctx->key = p11prov_obj_ref(key); if (sigctx->key == NULL) { return CKR_KEY_NEEDED; } class = p11prov_obj_get_class(sigctx->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) { return CKR_KEY_TYPE_INCONSISTENT; } break; default: return CKR_GENERAL_ERROR; } 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; } 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; } 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 int p11prov_rsasig_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("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: /* TODO */ return RET_OSSL_ERR; } } 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; 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, p11prov_obj_get_slotid(sigctx->key), 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, p11prov_obj_get_slotid(sigctx->key), 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; 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 OSSL_PARAM *p; int ret; P11PROV_debug("eddsa 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_INSTANCE); if (p) { const char *instance = NULL; bool matched = false; CK_ULONG size; 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); 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; } 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"); return RET_OSSL_ERR; } } 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; } 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 }, }; pkcs11-provider-0.3/src/signature.h000066400000000000000000000016661455352356500172750ustar00rootroot00000000000000/* 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[]; #endif /* _SIGNATURE_H */ pkcs11-provider-0.3/src/slot.c000066400000000000000000000324461455352356500162500ustar00rootroot00000000000000/* 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; }; 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; } 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; } sctx->slots[sctx->num] = slot; ret = p11prov_GetSlotInfo(ctx, slotid[i], &slot->slot); if (ret != CKR_OK || (slot->slot.flags & CKF_TOKEN_PRESENT) == 0) { /* skip slot */ continue; } ret = p11prov_GetTokenInfo(ctx, slotid[i], &slot->token); if (ret) { /* skip slot */ continue; } 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); P11PROV_debug_slot(ctx, slot->id, &slot->slot, &slot->token, slot->mechs, slot->nmechs, slot->profiles); sctx->num++; } 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; err = pthread_rwlock_wrlock(&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; } if (sctx->num == 0) { 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; } pkcs11-provider-0.3/src/slot.h000066400000000000000000000035131455352356500162460ustar00rootroot00000000000000/* 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); #endif /* _SLOT_H */ pkcs11-provider-0.3/src/store.c000066400000000000000000000445031455352356500164200ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include "provider.h" #include 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 && 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: 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 *)"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, 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; } 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-0.3/src/store.h000066400000000000000000000006341455352356500164220ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #ifndef _STORE_H #define _STORE_H #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[]; #endif /* _STORE_H */ pkcs11-provider-0.3/src/tls.c000066400000000000000000000145261455352356500160700ustar00rootroot00000000000000/* 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", "secp256r1", "EC", p256_group_id, p256_secbits, p256_mintls, p256_maxtls, p256_mindtls, p256_maxdtls), }, /* alias */ { "P-256", TLS_PARAMS_ENTRY("P-256", "secp256r1", "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-0.3/src/util.c000066400000000000000000000732661455352356500162510ustar00rootroot00000000000000/* 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; } void p11prov_uri_set_id(P11PROV_URI *uri, CK_ATTRIBUTE *id) { OPENSSL_free(uri->id.pValue); p11prov_copy_attr(&uri->id, id); } CK_ATTRIBUTE p11prov_uri_get_label(P11PROV_URI *uri) { return uri->object; } void p11prov_uri_set_label(P11PROV_URI *uri, CK_ATTRIBUTE *label) { OPENSSL_free(uri->object.pValue); 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); 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)); } pkcs11-provider-0.3/src/util.h000066400000000000000000000114631455352356500162450ustar00rootroot00000000000000/* 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); void p11prov_uri_set_id(P11PROV_URI *uri, CK_ATTRIBUTE *id); CK_ATTRIBUTE p11prov_uri_get_label(P11PROV_URI *uri); void 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)); } #endif /* _UTIL_H */ pkcs11-provider-0.3/tests/000077500000000000000000000000001455352356500154655ustar00rootroot00000000000000pkcs11-provider-0.3/tests/Makefile.am000066400000000000000000000075431455352356500175320ustar00rootroot00000000000000EXTRA_DIST = openssl.cnf.in \ lsan.supp \ explicit_ec.key.der explicit_ec.pub.der libspath=@abs_top_builddir@/src/.libs testsblddir=@abs_top_builddir@/tests testssrcdir=@abs_srcdir@ @VALGRIND_CHECK_RULES@ #VALGRIND_SUPPRESSIONS_FILES = $(top_srcdir)/tests/pkcs11-provider.supp VALGRIND_FLAGS = --num-callers=30 -q --keep-debuginfo=yes check_PROGRAMS = tsession tgenkey tlsctx tdigests tdigest_dupctx treadkeys tcmpkeys tfork pincache tsession_SOURCES = tsession.c tsession_CFLAGS = $(STD_CFLAGS) $(OPENSSL_CFLAGS) tsession_LDADD = $(OPENSSL_LIBS) tgenkey_SOURCES = tgenkey.c tgenkey_CFLAGS = $(STD_CFLAGS) $(OPENSSL_CFLAGS) tgenkey_LDADD = $(OPENSSL_LIBS) tlsctx_SOURCES = tlsctx.c tlsctx_CFLAGS = $(STD_CFLAGS) $(OPENSSL_CFLAGS) tlsctx_LDADD = $(OPENSSL_LIBS) tdigests_SOURCES = tdigests.c tdigests_CFLAGS = $(STD_CFLAGS) $(OPENSSL_CFLAGS) tdigests_LDADD = $(OPENSSL_LIBS) tdigest_dupctx_SOURCES = tdigest_dupctx.c tdigest_dupctx_CFLAGS = $(STD_CFLAGS) $(OPENSSL_CFLAGS) tdigest_dupctx_LDADD = $(OPENSSL_LIBS) treadkeys_SOURCES = treadkeys.c treadkeys_CFLAGS = $(STD_CFLAGS) $(OPENSSL_CFLAGS) treadkeys_LDADD = $(OPENSSL_LIBS) tcmpkeys_SOURCES = tcmpkeys.c tcmpkeys_CFLAGS = $(STD_CFLAGS) $(OPENSSL_CFLAGS) tcmpkeys_LDADD = $(OPENSSL_LIBS) tfork_SOURCES = tfork.c tfork_CFLAGS = $(STD_CFLAGS) $(OPENSSL_CFLAGS) tfork_LDADD = $(OPENSSL_LIBS) pincache_SOURCES = pincache.c pincache_CFLAGS = $(STD_CFLAGS) $(OPENSSL_CFLAGS) pincache_LDADD = $(OPENSSL_LIBS) tmp.softokn: LIBSPATH=$(libspath) \ TESTSSRCDIR=$(testssrcdir) \ TESTBLDDIR=$(testsblddir) \ SHARED_EXT=$(SHARED_EXT) \ SOFTOKNPATH="$(SOFTOKENDIR)/$(SOFTOKEN_SUBDIR)" \ $(testssrcdir)/setup-softokn.sh > setup-softokn.log 2>&1 tmp.softhsm: LIBSPATH=$(libspath) \ TESTSSRCDIR=$(testssrcdir) \ TESTBLDDIR=$(testsblddir) \ SHARED_EXT=$(SHARED_EXT) \ P11KITCLIENTPATH="$(P11KITCLIENTPATH)" \ $(testssrcdir)/setup-softhsm.sh > setup-softhsm.log 2>&1 dist_check_SCRIPTS = \ helpers.sh setup-softhsm.sh setup-softokn.sh softhsm-proxy.sh \ test-wrapper tbasic tcerts tecc tecdh tedwards tdemoca thkdf \ toaepsha2 trsapss tdigest ttls tpubkey tfork turi trand tecxc \ tcms top_state test_LIST = \ basic-softokn.t basic-softhsm.t \ pubkey-softokn.t pubkey-softhsm.t \ certs-softokn.t certs-softhsm.t \ ecc-softokn.t ecc-softhsm.t \ edwards-softhsm.t \ ecdh-softokn.t \ democa-softokn.t democa-softhsm.t \ digest-softokn.t digest-softhsm.t \ fork-softokn.t fork-softhsm.t \ oaepsha2-softokn.t \ hkdf-softokn.t \ rsapss-softokn.t \ genkey-softokn.t genkey-softhsm.t \ session-softokn.t session-softhsm.t \ rand-softokn.t rand-softhsm.t \ readkeys-softokn.t readkeys-softhsm.t \ tls-softokn.t tls-softhsm.t \ uri-softokn.t uri-softhsm.t \ ecxc-softhsm.t \ cms-softokn.t \ op_state-softhsm.t .PHONY: $(test_LIST) TESTS = $(test_LIST) AM_TESTS_ENVIRONMENT = \ export LC_ALL='C'; TEST_EXTENSIONS = .t T_LOG_COMPILER = $(testssrcdir)/test-wrapper if ADDRESS_SANITIZER # Avoids closing dlopened libraries for ASan to be able to print usable traces FAKE_DLCLOSE=.libs/fake_dlclose.so lib_LTLIBRARIES = fake_dlclose.la fake_dlclose_la_SOURCES = fake_dlclose.c fake_dlclose_la_CFLAGS = $(AM_CFLAGS) -Wall -Werror fake_dlclose_la_LDFLAGS = $(AM_LDFLAGS) -module -shared -avoid-version # LD_PRELOAD is needed before invoking openssl as it is not instrumented with # asan and asan needs to be loaded as a firs dynamic library of the process. AM_TESTS_ENVIRONMENT += \ export ASAN_OPTIONS='fast_unwind_on_malloc=0'; \ export LSAN_OPTIONS='suppressions=$(testssrcdir)/lsan.supp'; \ export DLCLOSE='$(testsblddir)/$(FAKE_DLCLOSE)'; \ export CHECKER='env LD_PRELOAD=$(ADDRESS_SANITIZER_PATH):$(testsblddir)/$(FAKE_DLCLOSE)'; endif $(TESTS): tmp.softokn tmp.softhsm $(FAKE_DLCLOSE) CLEANFILES = \ setup-*.log \ pinfile.txt clean-local: rm -Rf tmp.softhsm rm -Rf tmp.softokn DISTCLEANFILES = \ *~ MAINTAINERCLEANFILES = \ Makefile.in pkcs11-provider-0.3/tests/README000066400000000000000000000007411455352356500163470ustar00rootroot00000000000000Tests 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 make check; this will create two temporary directories with each token's configurations. After make check has run, set up your environment with: $ source tests/tmp./testvars Then you can run code like: $ openssl pkey -in $ECPUBURI -pubin -pubout -out ecout.pub pkcs11-provider-0.3/tests/explicit_ec.cnf000066400000000000000000000011021455352356500204370ustar00rootroot00000000000000asn1=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-0.3/tests/explicit_ec.key.der000066400000000000000000000004141455352356500212370ustar00rootroot000000000000000‚_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-0.3/tests/explicit_ec.pub.der000066400000000000000000000003651455352356500212420ustar00rootroot000000000000000ò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-0.3/tests/fake_dlclose.c000066400000000000000000000002401455352356500202400ustar00rootroot00000000000000/* Copyright (C) 2023 Jakub Jelen SPDX-License-Identifier: Apache-2.0 */ #include int dlclose(void *handle) { return 0; } pkcs11-provider-0.3/tests/helpers.sh000077500000000000000000000025561455352356500174760ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2022 Simo Sorce # SPDX-License-Identifier: Apache-2.0 title() { case "$1" in "SECTION") shift 1 echo "########################################" echo "## $*" echo "" ;; "ENDSECTION") echo "" echo " ##" echo "########################################" echo "" ;; "PARA") shift 1 echo "" echo "## $*" ;; "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 } pkcs11-provider-0.3/tests/lsan.supp000066400000000000000000000003501455352356500173310ustar00rootroot00000000000000#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-0.3/tests/openssl.cnf.in000066400000000000000000000100441455352356500202440ustar00rootroot00000000000000HOME = . # 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-init-args = configDir=@testsblddir@/tmp.softokn/tokens pkcs11-module-token-pin = file:@testsblddir@/pinfile.txt #pkcs11-module-allow-export #pkcs11-module-load-behavior ##QUIRKS 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-0.3/tests/pincache.c000066400000000000000000000101751455352356500174070ustar00rootroot00000000000000/* 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-0.3/tests/setup-softhsm.sh000077500000000000000000000327321455352356500206540ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2022 Jakub Jelen # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" if ! command -v softhsm2-util &> /dev/null then echo "SoftHSM is is required" exit 0 fi # 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 # 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 sed_inplace=("-i") else sed_inplace=("-i" "") fi if [ "$P11KITCLIENTPATH" = "" ]; then echo "Missing P11KITCLIENTPATH env variable" 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 } title SECTION "Searching for SoftHSM PKCS#11 library" # 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 title SECTION "Set up testing system" TMPPDIR="tmp.softhsm" if [ -d ${TMPPDIR} ]; then rm -fr ${TMPPDIR} fi mkdir ${TMPPDIR} PINVALUE="12345678" PINFILE="${PWD}/pinfile.txt" echo ${PINVALUE} > "${PINFILE}" #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 # Create brand new tokens and certs TOKDIR="$TMPPDIR/tokens" if [ -d ${TOKDIR} ]; then rm -fr ${TOKDIR} fi mkdir ${TOKDIR} # Create SoftHSM configuration file cat >"$TMPPDIR/softhsm.conf" <> ${TMPPDIR}/cert.cfg <> ${TMPPDIR}/cert.cfg ca_sign() { CRT=$1 LABEL=$2 CN=$3 KEYID=$4 ((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="${CRT}.crt" \ --template=${TMPPDIR}/cert.cfg --provider="$P11LIB" \ --load-privkey "pkcs11:object=$LABEL;type=private" \ --load-pubkey "pkcs11:object=$LABEL;type=public" --outder \ --load-ca-certificate "${CACRT}.crt" --inder \ --load-ca-privkey="pkcs11:object=$CACRTN;type=private" pkcs11-tool --write-object "${CRT}.crt" --type=cert --id="$KEYID" \ --label="$LABEL" --module="$P11LIB" } # generate RSA key pair and self-signed certificate KEYID='0001' URIKEYID="%00%01" TSTCRT="${TMPPDIR}/testcert" TSTCRTN="testCert" pkcs11-tool --keypairgen --key-type="RSA:2048" --login --pin=$PINVALUE \ --module="$P11LIB" --label="${TSTCRTN}" --id="$KEYID" ca_sign $TSTCRT $TSTCRTN "My Test Cert" $KEYID BASEURIWITHPIN="pkcs11:id=${URIKEYID};pin-value=${PINVALUE}" 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 "${BASEURIWITHPIN}" echo "${BASEURI}" echo "${PUBURI}" echo "${PRIURI}" echo "${CRTURI}" echo "" # generate ECC key pair KEYID='0002' URIKEYID="%00%02" ECCRT="${TMPPDIR}/eccert" ECCRTN="ecCert" pkcs11-tool --keypairgen --key-type="EC:secp256r1" --login --pin=$PINVALUE \ --module="$P11LIB" --label="${ECCRTN}" --id="$KEYID" ca_sign $ECCRT $ECCRTN "My EC Cert" $KEYID ECBASEURIWITHPIN="pkcs11:id=${URIKEYID};pin-value=${PINVALUE}" 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" ECPEERCRT="${TMPPDIR}/ecpeercert" ECPEERCRTN="ecPeerCert" pkcs11-tool --keypairgen --key-type="EC:secp256r1" --login --pin=$PINVALUE \ --module="$P11LIB" --label="$ECPEERCRTN" --id="$KEYID" ca_sign $ECPEERCRT $ECPEERCRTN "My Peer EC Cert" $KEYID ECPEERBASEURIWITHPIN="pkcs11:id=${URIKEYID};pin-value=${PINVALUE}" 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 "${ECBASEURIWITHPIN}" echo "${ECBASEURI}" echo "${ECPUBURI}" echo "${ECPRIURI}" echo "${ECCRTURI}" echo "${ECPEERBASEURIWITHPIN}" echo "${ECPEERBASEURI}" echo "${ECPEERPUBURI}" echo "${ECPEERPRIURI}" echo "${ECPEERCRTURI}" echo "" # generate ED25519 KEYID='0004' URIKEYID="%00%04" EDCRT="${TMPPDIR}/edcert" EDCRTN="edCert" pkcs11-tool --keypairgen --key-type="EC:edwards25519" --login --pin=$PINVALUE --module="$P11LIB" \ --label="${EDCRTN}" --id="$KEYID" ca_sign $EDCRT $EDCRTN "My ED25519 Cert" $KEYID 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 "${EDBASEURI}" echo "${EDPUBURI}" echo "${EDPRIURI}" echo "${EDCRTURI}" title PARA "generate RSA key pair, self-signed certificate, remove public key" KEYID='0005' URIKEYID="%00%05" TSTCRT="${TMPPDIR}/testcert2" TSTCRTN="testCert2" pkcs11-tool --keypairgen --key-type="RSA:2048" --login --pin=$PINVALUE \ --module="$P11LIB" --label="${TSTCRTN}" --id="$KEYID" ca_sign $TSTCRT $TSTCRTN "My Test Cert 2" $KEYID pkcs11-tool --delete-object --type pubkey --id 0005 --module="$P11LIB" BASE2URIWITHPIN="pkcs11:id=${URIKEYID};pin-value=${PINVALUE}" BASE2URI="pkcs11:id=${URIKEYID}" PRI2URI="pkcs11:type=private;id=${URIKEYID}" CRT2URI="pkcs11:type=cert;object=${TSTCRTN}" title LINE "RSA2 PKCS11 URIS" echo "${BASE2URIWITHPIN}" echo "${BASE2URI}" echo "${PRI2URI}" echo "${CRT2URI}" echo "" title PARA "generate EC key pair, self-signed certificate, remove public key" KEYID='0006' URIKEYID="%00%06" TSTCRT="${TMPPDIR}/eccert2" TSTCRTN="ecCert2" pkcs11-tool --keypairgen --key-type="EC:secp384r1" --login --pin=$PINVALUE \ --module="$P11LIB" --label="${TSTCRTN}" --id="$KEYID" ca_sign $TSTCRT $TSTCRTN "My EC Cert 2" $KEYID pkcs11-tool --delete-object --type pubkey --id 0006 --module="$P11LIB" ECBASE2URIWITHPIN="pkcs11:id=${URIKEYID};pin-value=${PINVALUE}" ECBASE2URI="pkcs11:id=${URIKEYID}" ECPRI2URI="pkcs11:type=private;id=${URIKEYID}" ECCRT2URI="pkcs11:type=cert;object=${TSTCRTN}" title LINE "EC2 PKCS11 URIS" echo "${ECBASE2URIWITHPIN}" echo "${ECBASE2URI}" echo "${ECPRI2URI}" echo "${ECCRT2URI}" echo "" if [ -f /etc/fedora-release ]; then title PARA "explicit EC unsupported on Fedora" else title PARA "generate explicit EC key pair" KEYID='0007' URIKEYID="%00%07" ECXCRTN="ecExplicitCert" pkcs11-tool --write-object="${TESTSSRCDIR}/explicit_ec.key.der" --type=privkey --login --pin=$PINVALUE \ --module="$P11LIB" --label="${ECXCRTN}" --id="$KEYID" pkcs11-tool --write-object="${TESTSSRCDIR}/explicit_ec.pub.der" --type=pubkey --login --pin=$PINVALUE \ --module="$P11LIB" --label="${ECXCRTN}" --id="$KEYID" ECXBASEURIWITHPIN="pkcs11:id=${URIKEYID};pin-value=${PINVALUE}" 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" TSTCRT="${TMPPDIR}/eccert3" TSTCRTN="ecCert3" pkcs11-tool --keypairgen --key-type="EC:secp521r1" --login --pin=$PINVALUE \ --module="$P11LIB" --label="${TSTCRTN}" --id="$KEYID" --always-auth ca_sign $TSTCRT $TSTCRTN "My EC Cert 3" $KEYID ECBASE3URIWITHPIN="pkcs11:id=${URIKEYID};pin-value=${PINVALUE}" 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 "${ECBASE3URIWITHPIN}" echo "${ECBASE3URI}" echo "${ECPUB3URI}" echo "${ECPRI3URI}" echo "${ECCRT3URI}" echo "" title PARA "Show contents of softhsm token" echo " ----------------------------------------------------------------------------------------------------" pkcs11-tool -O --login --pin=$PINVALUE --module="$P11LIB" echo " ----------------------------------------------------------------------------------------------------" title PARA "Output configurations" BASEDIR=$(pwd) OPENSSL_CONF=${BASEDIR}/${TMPPDIR}/openssl.cnf title LINE "Generate openssl config file" sed -e "s|@libtoollibs[@]|${LIBSPATH}|g" \ -e "s|@testsblddir@|${TESTBLDDIR}|g" \ -e "s|@testsdir[@]|${BASEDIR}/${TMPPDIR}|g" \ -e "s|@SHARED_EXT@|${SHARED_EXT}|g" \ -e "s|##QUIRKS|pkcs11-module-quirks = no-deinit|g" \ -e "/pkcs11-module-init-args/d" \ "${TESTSSRCDIR}/openssl.cnf.in" > "${OPENSSL_CONF}" title LINE "Export test variables to ${TMPPDIR}/testvars" cat >> ${TMPPDIR}/testvars <> ${TMPPDIR}/testvars <> ${TMPPDIR}/testvars < # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" if ! command -v certutil &> /dev/null then echo "NSS's certutil command is required" exit 0 fi title SECTION "Set up testing system" TMPPDIR="tmp.softokn" if [ -d ${TMPPDIR} ]; then rm -fr ${TMPPDIR} fi mkdir ${TMPPDIR} PINVALUE="12345678" PINFILE="${PWD}/pinfile.txt" echo ${PINVALUE} > "${PINFILE}" #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 # Create brand new tokens and certs TOKDIR="$TMPPDIR/tokens" if [ -d ${TOKDIR} ]; then rm -fr ${TOKDIR} fi mkdir ${TOKDIR} SERIAL=0 title LINE "Creating new NSS Database" certutil -N -d "${TOKDIR}" -f "${PINFILE}" title LINE "Creating new Self Sign CA" ((SERIAL+=1)) certutil -S -s "CN=Issuer" -n selfCA -x -t "C,C,C" \ -m "${SERIAL}" -1 -2 -5 --keyUsage certSigning,crlSigning \ --nsCertType sslCA,smimeCA,objectSigningCA \ -f "${PINFILE}" -d "${TOKDIR}" -z "${SEEDFILE}" >/dev/null 2>&1 </dev/null 2>&1 ((SERIAL+=1)) certutil -C -m "${SERIAL}" -i "${TSTCRT}.req" -o "${TSTCRT}.crt" -c selfCA \ -d "${TOKDIR}" -f "${PINFILE}" >/dev/null 2>&1 certutil -A -n "${TSTCRTN}" -i "${TSTCRT}.crt" -t "u,u,u" -d "${TOKDIR}" \ -f "${PINFILE}" >/dev/null 2>&1 KEYID=$(certutil -K -d "${TOKDIR}" -f "${PINFILE}" |grep "${TSTCRTN}"| cut -b 15-54) URIKEYID="" for (( i=0; i<${#KEYID}; i+=2 )); do line="${KEYID:$i:2}" URIKEYID="$URIKEYID%$line" done BASEURIWITHPIN="pkcs11:id=${URIKEYID};pin-value=${PINVALUE}" 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 "${BASEURIWITHPIN}" echo "${BASEURI}" echo "${PUBURI}" echo "${PRIURI}" echo "${CRTURI}" echo "" # ECC ECCRT="${TMPPDIR}/eccert" ECCRTN="ecCert" title LINE "Creating Certificate request for 'My EC Cert'" certutil -R -s "CN=My EC Cert, O=PKCS11 Provider" -k ec -q nistp256 \ -o "${ECCRT}.req" -d "${TOKDIR}" -f "${PINFILE}" -z "${SEEDFILE}" >/dev/null 2>&1 ((SERIAL+=1)) certutil -C -m "${SERIAL}" -i "${ECCRT}.req" -o "${ECCRT}.crt" -c selfCA \ -d "${TOKDIR}" -f "${PINFILE}" >/dev/null 2>&1 certutil -A -n "${ECCRTN}" -i "${ECCRT}.crt" -t "u,u,u" \ -d "${TOKDIR}" -f "${PINFILE}" >/dev/null 2>&1 KEYID=$(certutil -K -d "${TOKDIR}" -f "${PINFILE}" |grep "${ECCRTN}"| cut -b 15-54) URIKEYID="" for (( i=0; i<${#KEYID}; i+=2 )); do line="${KEYID:$i:2}" URIKEYID="$URIKEYID%$line" done ECBASEURIWITHPIN="pkcs11:id=${URIKEYID};pin-value=${PINVALUE}" ECBASEURI="pkcs11:id=${URIKEYID}" ECPUBURI="pkcs11:type=public;id=${URIKEYID}" ECPRIURI="pkcs11:type=private;id=${URIKEYID}" ECCRTURI="pkcs11:type=cert;object=${ECCRTN}" title LINE "Creating Certificate request for 'My Peer EC Cert'" ECPEERCRT="${TMPPDIR}/ecpeercert" ECPEERCRTN="ecPeerCert" certutil -R -s "CN=My Peer EC Cert, O=PKCS11 Provider" \ -k ec -q nistp256 -o "${ECPEERCRT}.req" \ -d "${TOKDIR}" -f "${PINFILE}" -z "${SEEDFILE}" >/dev/null 2>&1 ((SERIAL+=1)) certutil -C -m "${SERIAL}" -i "${ECPEERCRT}.req" -o "${ECPEERCRT}.crt" \ -c selfCA -d "${TOKDIR}" -f "${PINFILE}" >/dev/null 2>&1 certutil -A -n "${ECPEERCRTN}" -i "${ECPEERCRT}.crt" -t "u,u,u" \ -d "${TOKDIR}" -f "${PINFILE}" >/dev/null 2>&1 KEYID=$(certutil -K -d "${TOKDIR}" -f "${PINFILE}" |grep "${ECPEERCRTN}"| cut -b 15-54) URIKEYID="" for (( i=0; i<${#KEYID}; i+=2 )); do line="${KEYID:$i:2}" URIKEYID="$URIKEYID%$line" done 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 "${ECBASEURIWITHPIN}" echo "${ECBASEURI}" echo "${ECPUBURI}" echo "${ECPRIURI}" echo "${ECCRTURI}" echo "${ECPEERBASEURI}" echo "${ECPEERPUBURI}" echo "${ECPEERPRIURI}" echo "${ECPEERCRTURI}" echo "" title PARA "Show contents of softoken" echo " ----------------------------------------------------------------------------------------------------" certutil -L -d "${TOKDIR}" certutil -K -d "${TOKDIR}" -f "${PINFILE}" echo " ----------------------------------------------------------------------------------------------------" title PARA "Output configurations" BASEDIR=$(pwd) OPENSSL_CONF=${BASEDIR}/${TMPPDIR}/openssl.cnf title LINE "Generate openssl config file" sed -e "s|@libtoollibs[@]|${LIBSPATH}|g" \ -e "s|@testsblddir@|${TESTBLDDIR}|g" \ -e "s|@testsdir[@]|${BASEDIR}/${TMPPDIR}|g" \ -e "s|@SHARED_EXT@|${SHARED_EXT}|g" \ "${TESTSSRCDIR}/openssl.cnf.in" > "${OPENSSL_CONF}" title LINE "Export tests variables to ${TMPPDIR}/testvars" cat > "${TMPPDIR}/testvars" < # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" # p11-kit complains if there is not runtime directory if [ -z "$XDG_RUNTIME_DIR" ]; then export XDG_RUNTIME_DIR=$PWD fi title PARA "Start the p11-kit server and check if it works" # shellcheck disable=SC2046 # we want to split these for eval eval $(p11-kit server --provider "$P11LIB" "pkcs11:") # unset OPENSSL_CONF here to avoid automatically loading the provider # and SoftHSM from pkcs11-tool and crashing during the cleanup again. OPENSSL_CONF='' pkcs11-tool -O --login --pin="$PINVALUE" --module="$P11KITCLIENTPATH" > /dev/null #register clean function to kill p11-kit-server trap 'cleanup_server p11-kit $P11_KIT_SERVER_PID' EXIT #Set up environment variables export PKCS11_PROVIDER_MODULE="${P11KITCLIENTPATH}" "$*" pkcs11-provider-0.3/tests/tbasic000077500000000000000000000233231455352356500166630ustar00rootroot00000000000000#!/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' 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" 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' title PARA "Test fetching public keys with a PIN in URI" ossl 'pkey -in $BASEURIWITHPIN -pubin -pubout -out ${TMPPDIR}/rsa.pub.uripin.pem' ossl 'pkey -in $ECBASEURIWITHPIN -pubin -pubout -out ${TMPPDIR}/ec.pub.uripin.pem' [[ -n $ECXBASEURIWITHPIN ]] && ossl 'pkey -in $ECXBASEURIWITHPIN -pubin -pubout -out ${TMPPDIR}/ecx.pub.uripin.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" $CHECKER ./tcmpkeys "$PUBURI" "$PUBURI" title PARA "Test EVP_PKEY_eq on public EC key both on token" # shellcheck disable=SC2153 # ECURIs and ECXURIs are not spelling errors $CHECKER ./tcmpkeys "$ECPUBURI" "$ECPUBURI" if [[ -n $ECXPUBURI ]]; then title PARA "Test EVP_PKEY_eq on public explicit EC key both on token" $CHECKER ./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 ./tcmpkeys "$PUBURI" "${TMPPDIR}"/rsa.pub.uripin.pem title PARA "Match private RSA key against public key" $CHECKER ./tcmpkeys "$PRIURI" "${TMPPDIR}"/rsa.pub.uripin.pem title PARA "Match private RSA key against public key (commutativity)" $CHECKER ./tcmpkeys "${TMPPDIR}"/rsa.pub.uripin.pem "$PRIURI" title PARA "Test EVP_PKEY_eq on public EC key via import" $CHECKER ./tcmpkeys "$ECPUBURI" "${TMPPDIR}"/ec.pub.uripin.pem title PARA "Match private EC key against public key" $CHECKER ./tcmpkeys "$ECPRIURI" "${TMPPDIR}"/ec.pub.uripin.pem title PARA "Match private EC key against public key (commutativity)" $CHECKER ./tcmpkeys "${TMPPDIR}"/ec.pub.uripin.pem "$ECPRIURI" if [[ -n $ECXPUBURI ]]; then echo "ECXPUBURI is $ECXPUBURI" title PARA "Test EVP_PKEY_eq on public explicit EC key via import" $CHECKER ./tcmpkeys "$ECXPUBURI" "${TMPPDIR}"/ecx.pub.uripin.pem title PARA "Match private explicit EC key against public key" # shellcheck disable=SC2153 # ECURIs and ECXURIs are not spelling errors $CHECKER ./tcmpkeys "$ECXPRIURI" "${TMPPDIR}"/ecx.pub.uripin.pem title PARA "Match private explicit EC key against public key (commutativity)" $CHECKER ./tcmpkeys "${TMPPDIR}"/ecx.pub.uripin.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 ./tcmpkeys "$PUBURI" "$PUBURI" title PARA "Test EC key" $CHECKER ./tcmpkeys "$ECPUBURI" "$ECPUBURI" if [[ -n $ECXPUBURI ]]; then title PARA "Test explicit EC key" $CHECKER ./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} exit 0 pkcs11-provider-0.3/tests/tcerts000077500000000000000000000024361455352356500167240ustar00rootroot00000000000000#!/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" "/O=PKCS11 Provider/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 exit 0 pkcs11-provider-0.3/tests/tcmpkeys.c000066400000000000000000000044701455352356500174750ustar00rootroot00000000000000/* Copyright (C) 2023 Timo Teräs SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include static 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"); } static EVP_PKEY *load_key(const char *uri) { OSSL_STORE_CTX *store; OSSL_STORE_INFO *info; EVP_PKEY *key = NULL; 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); } 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; } 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-0.3/tests/tcms000077500000000000000000000013131455352356500163570ustar00rootroot00000000000000#!/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-0.3/tests/tdemoca000077500000000000000000000064321455352356500170340ustar00rootroot00000000000000#!/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 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 sha1 -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-0.3/tests/tdigest000077500000000000000000000007271455352356500170640ustar00rootroot00000000000000#!/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 ./tdigests exit 0 pkcs11-provider-0.3/tests/tdigest_dupctx.c000066400000000000000000000025671455352356500206750ustar00rootroot00000000000000/* 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-0.3/tests/tdigests.c000066400000000000000000000052151455352356500174620ustar00rootroot00000000000000/* 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-0.3/tests/tecc000077500000000000000000000076601455352356500163420ustar00rootroot00000000000000#!/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-0.3/tests/tecdh000077500000000000000000000004641455352356500165060ustar00rootroot00000000000000#!/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' exit 0 pkcs11-provider-0.3/tests/tecxc000077500000000000000000000101361455352356500165220ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2023 Simo Sorce # SPDX-License-Identifier: Apache-2.0 # On Fedora they completely removed support for explicit EC from libcrypto, # so skip the test completely if [ -f /etc/fedora-release ]; then exit 0 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-0.3/tests/tedwards000077500000000000000000000022561455352356500172350ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2023 Simo Sorce # SPDX-License-Identifier: Apache-2.0 source "${TESTSSRCDIR}/helpers.sh" 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' exit 0 pkcs11-provider-0.3/tests/test-wrapper000077500000000000000000000024421455352356500200520ustar00rootroot00000000000000#!/bin/bash -e # Copyright (C) 2022 Simo sorce # SPDX-License-Identifier: Apache-2.0 TEST_PATH=$(dirname "${1}") BNAME=$(basename "${1}") # the test name is {TEST_NAME}-{TOKEN_DRIVER}.t # split extension NAME=${BNAME%.*} TEST_NAME=${NAME%-*} TOKEN_DRIVER=${NAME#*-} if [ -f "./tmp.${TOKEN_DRIVER}/testvars" ]; then # shellcheck source=/dev/null # we do not care about linting this source source "./tmp.${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 buils case (used by # make distcheck for example) if [ -f "${TEST_PATH}/t${TEST_NAME}" ]; then COMMAND="${TEST_PATH}/t${TEST_NAME}" else COMMAND="./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 for option in "${TEST_PARAMS[@]}"; do if [[ "$option" == "proxy" ]]; then COMMAND="${TESTSSRCDIR}/softhsm-proxy.sh $COMMAND" fi done echo "Executing ${COMMAND}" ${COMMAND} pkcs11-provider-0.3/tests/tfork.c000066400000000000000000000130331455352356500167560ustar00rootroot00000000000000/* 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 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'; } static EVP_PKEY *gen_key(void) { 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 miniid; 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); miniid = (id[0] << 24) + (id[1] << 16) + (id[2] << 8) + id[3]; ret = asprintf(&uri, "pkcs11:object=Fork-Test-%08x;id=%s", miniid, 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; } 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 = gen_key(); /* 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-0.3/tests/tgenkey.c000066400000000000000000000307661455352356500173130ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #define _GNU_SOURCE #include #include #include #include #include #include #include static 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'; } 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) { fprintf(stderr, "Failed to get E param from public key"); 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) { fprintf(stderr, "Failed to get N param from public key"); exit(EXIT_FAILURE); } else { int bits; bits = EVP_PKEY_get_bits(pubkey); if (bits < 3072) { fprintf(stderr, "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) { fprintf(stderr, "Failed to get X param from public key"); 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) { fprintf(stderr, "Failed to get Y param from public key"); exit(EXIT_FAILURE); } else { BN_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) { fprintf(stderr, "Duplicate public key found!"); exit(EXIT_FAILURE); } pubkey = OSSL_STORE_INFO_get1_PUBKEY(info); break; case OSSL_STORE_INFO_PKEY: if (privkey != NULL) { fprintf(stderr, "Duplicate private key found!"); exit(EXIT_FAILURE); } privkey = 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 (privkey == NULL) { fprintf(stderr, "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); } 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) { fprintf(stderr, "Failed to init PKEY context\n"); exit(EXIT_FAILURE); } ret = EVP_PKEY_keygen_init(ctx); if (ret != 1) { fprintf(stderr, "Failed to init keygen\n"); exit(EXIT_FAILURE); } ret = EVP_PKEY_CTX_set_params(ctx, params); if (ret != 1) { fprintf(stderr, "Failed to set params\n"); exit(EXIT_FAILURE); } ret = EVP_PKEY_generate(ctx, &key); if (ret != 1) { if (!fail) { fprintf(stderr, "Failed to generate key\n"); exit(EXIT_FAILURE); } EVP_PKEY_CTX_free(ctx); return; } if (fail) { fprintf(stderr, "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); } 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) { fprintf(stderr, "Failed to allocate uri\n"); exit(EXIT_FAILURE); } store = OSSL_STORE_open(uri, NULL, NULL, NULL, NULL); if (store == NULL) { fprintf(stderr, "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) { fprintf(stderr, "Failed to open pkcs11 store\n"); exit(EXIT_FAILURE); } search = OSSL_STORE_SEARCH_by_alias(label); if (search == NULL) { fprintf(stderr, "Failed to create store search filter\n"); exit(EXIT_FAILURE); } ret = OSSL_STORE_find(store, search); if (ret != 1) { fprintf(stderr, "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, 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; store = OSSL_STORE_open("pkcs11:", NULL, NULL, NULL, NULL); if (store == NULL) { fprintf(stderr, "Failed to open pkcs11 store\n"); exit(EXIT_FAILURE); } search = OSSL_STORE_SEARCH_by_alias(label); if (search == NULL) { fprintf(stderr, "Failed to create store search filter\n"); exit(EXIT_FAILURE); } ret = OSSL_STORE_find(store, search); if (ret != 1) { fprintf(stderr, "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) { fprintf(stderr, "Failed to load private key\n"); exit(EXIT_FAILURE); } ctx = EVP_MD_CTX_new(); if (!ctx) { fprintf(stderr, "Failed to init MD_CTX\n"); exit(EXIT_FAILURE); } ret = EVP_DigestSignInit(ctx, &pctx, EVP_sha256(), NULL, privkey); if (ret == 0) { fprintf(stderr, "Failed to init Sig Ctx\n"); exit(EXIT_FAILURE); } ret = EVP_DigestSign(ctx, sigret, &siglen, data, sizeof(data)); if (ret == 0) { if (!fail) { fprintf(stderr, "Failed to generate signature\n"); exit(EXIT_FAILURE); } } else { if (fail) { fprintf(stderr, "Expected failure, but signature worked\n"); exit(EXIT_FAILURE); } } EVP_PKEY_free(privkey); EVP_MD_CTX_free(ctx); } int main(int argc, char *argv[]) { 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 "; OSSL_PARAM params[4]; int miniid; int ret; /* RSA */ ret = RAND_bytes(id, 16); if (ret != 1) { fprintf(stderr, "Failed to set 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) { fprintf(stderr, "Failed to make label"); exit(EXIT_FAILURE); } hexify(idhex, id, 16); ret = asprintf(&uri, "pkcs11:object=%s;id=%s", label, idhex); if (ret == -1) { fprintf(stderr, "Failed to make label"); 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); free(label); free(uri); /* RSA-PSS */ ret = RAND_bytes(id, 16); if (ret != 1) { fprintf(stderr, "Failed to set 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) { fprintf(stderr, "Failed to make label"); exit(EXIT_FAILURE); } hexify(idhex, id, 16); ret = asprintf(&uri, "pkcs11:object=%s;id=%s", label, idhex); if (ret == -1) { fprintf(stderr, "Failed to make label"); 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); /* EC */ ret = RAND_bytes(id, 16); if (ret != 1) { fprintf(stderr, "Failed to set 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) { fprintf(stderr, "Failed to make label"); exit(EXIT_FAILURE); } hexify(idhex, id, 16); ret = asprintf(&uri, "pkcs11:object=%s;id=%s", label, idhex); if (ret == -1) { fprintf(stderr, "Failed to make label"); 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); free(label); free(uri); /* RSA with Key Usage restrictions */ ret = RAND_bytes(id, 16); if (ret != 1) { fprintf(stderr, "Failed to set 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) { fprintf(stderr, "Failed to make label"); exit(EXIT_FAILURE); } hexify(idhex, id, 16); ret = asprintf(&uri, "pkcs11:object=%s;id=%s", label, idhex); if (ret == -1) { fprintf(stderr, "Failed to make label"); 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, 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); fprintf(stderr, "ALL A-OK!"); exit(EXIT_SUCCESS); } pkcs11-provider-0.3/tests/thkdf000077500000000000000000000036311455352356500165160ustar00rootroot00000000000000#!/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-0.3/tests/tlsctx.c000066400000000000000000000021601455352356500171510ustar00rootroot00000000000000/* Copyright (C) 2022 Simo Sorce SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include static 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"); } int main(int argc, char *argv[]) { SSL_CTX *ctx; 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); exit(EXIT_SUCCESS); } pkcs11-provider-0.3/tests/toaepsha2000077500000000000000000000015531455352356500173050ustar00rootroot00000000000000#!/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-0.3/tests/top_state000077500000000000000000000016361455352356500174230ustar00rootroot00000000000000#!/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)" exit 0 pkcs11-provider-0.3/tests/tpubkey000077500000000000000000000050151455352356500170770ustar00rootroot00000000000000#!/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" # The MacOS keeps crashing in this step so lets skip the remaining tests if [ "$(uname)" == "Darwin" ]; then exit 0 fi 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-0.3/tests/trand000077500000000000000000000013771455352356500165330ustar00rootroot00000000000000#!/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-0.3/tests/treadkeys.c000066400000000000000000000037251455352356500176330ustar00rootroot00000000000000/* 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-0.3/tests/trsapss000077500000000000000000000023741455352356500171200ustar00rootroot00000000000000#!/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' pkcs11-provider-0.3/tests/tsession.c000066400000000000000000000063121455352356500175020ustar00rootroot00000000000000/* 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] = {}; 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); } /* 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++) { /* Start a series of signin operation so code grabs sessions */ for (int c = 0; c < CNUM; c++) { const char *data = "Sign Me!"; 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, "SHA256", NULL, NULL, prikey, NULL); if (ret != 1) { fprintf(stderr, "Failed to init EVP_DigestSign\n"); exit(EXIT_FAILURE); } ret = EVP_DigestSignUpdate(sign_md[c], data, sizeof(data)); if (ret != 1) { fprintf(stderr, "Failed to EVP_DigestSignUpdate\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_DigestSignFinal(sign_md[c], sig, &size); 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-0.3/tests/ttls000077500000000000000000000030071455352356500164010ustar00rootroot00000000000000#!/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 ./tlsctx 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 expect -c "spawn $CHECKER openssl s_server -accept \"${PORT}\" -naccept 1 -key \"${PRIURI}\" -cert \"${CRTURI}\"; set timeout 60; expect { \"ACCEPT\" {}; default {exit 1;}; } set server_ready [open \"${TMPPDIR}/s_server_ready\" w+]; puts \$server_ready \"READY\n\"; close \$server_ready; expect { \"END SSL SESSION PARAMETERS\" {}; default {exit 1;}; } send \" TLS SUCCESSFUL \n\" send \"Q\n\" expect { eof {exit 0;}; default {exit 1;}; }" > "${TMPPDIR}/s_server_output" & SERVER_PID=$! read -r < "${TMPPDIR}/s_server_ready" expect -c "spawn $CHECKER openssl s_client -connect \"localhost:${PORT}\"; set timeout 60; expect { \" TLS SUCCESSFUL \" {}; default {exit 1;}; } expect { eof {exit 0;}; default {exit 1;}; }" exit 0; pkcs11-provider-0.3/tests/turi000077500000000000000000000026661455352356500164100ustar00rootroot00000000000000#!/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") # 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