diff --git a/.codespell-ignore-words b/.codespell-ignore-words new file mode 100644 index 0000000..0be12c7 --- /dev/null +++ b/.codespell-ignore-words @@ -0,0 +1,3 @@ +gost +keypair +standarts diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 0000000..e07ca4a --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,525 @@ +--- +name: build + +####################################### +# GITHUB WORKFLOW BAD LOG +# +# Cannot check cache hit, the actions/cache always extract the cache +# No wait to share cache between branches +# Cannot depend on matrix instance +# Matrix instance cannot depend +# Cannot matrix when calling workflows +# No way to reuse matrix +# Cannot call nested workflows +# Cannot run workflow from a step +# No way for a step to call step + +on: + pull_request: + push: + +env: + caches_version: v1 + +jobs: + + ############################################################################################################# + # CACHES + ############################################################################################################# + + C-openssl-binaries: + name: ${{ matrix.version}}-${{ matrix.os }}@C-openssl-binaries + runs-on: ubuntu-latest + strategy: + matrix: + include: + - version: "1.1.1" + os: windows + dependencies: mingw-w64 + branch: OpenSSL_1_1_1-stable + cross-compile-prefix: x86_64-w64-mingw32- + target: mingw64 + - version: "3.0" + os: linux + dependencies: + branch: openssl-3.0 + cross-compile-prefix: + target: + - version: "3.0" + os: windows + dependencies: mingw-w64 + branch: openssl-3.0 + cross-compile-prefix: x86_64-w64-mingw32- + target: mingw64 + env: + openssl_name: openssl-${{ matrix.version }}-binaries-${{ matrix.os }} + + steps: + - name: cache + id: cache + uses: actions/cache@v3 + with: + path: ${{ env.openssl_name }} + key: ${{ env.openssl_name }}-${{ env.caches_version }} + - name: dependencies + if: steps.cache.outputs.cache-hit != 'true' + run: | + sudo apt update + sudo apt install -y \ + build-essential \ + ${{ matrix.dependencies }} + - name: checkout + if: steps.cache.outputs.cache-hit != 'true' + uses: actions/checkout@v3 + with: + repository: openssl/openssl + ref: ${{ matrix.branch }} + path: openssl + - name: build + if: steps.cache.outputs.cache-hit != 'true' + working-directory: openssl + run: | + ./Configure \ + --prefix="${GITHUB_WORKSPACE}/${{ env.openssl_name }}" \ + --libdir=lib \ + --cross-compile-prefix=${{ matrix.cross-compile-prefix }} \ + ${{ matrix.target }} + make install_dev + + ############################################################################################################# + # SOURCES + ############################################################################################################# + + B-P-mycms-dist: + name: B-P-mycms-dist + runs-on: ubuntu-latest + + steps: + - name: dependencies + run: | + sudo apt update + sudo apt install -y \ + autoconf \ + automake \ + autotools-dev \ + easy-rsa \ + libssl-dev \ + libtool \ + pkg-config \ + softhsm + - name: mycms-checkout + uses: actions/checkout@v3 + with: + path: mycms + - name: mycms-prepare + run: | + mkdir -p mycms-build/distcheck + - name: mycms-generate + working-directory: mycms + run: | + autoreconf -ivf + - name: mycms-distcheck + working-directory: mycms-build/distcheck + run: | + "${GITHUB_WORKSPACE}/mycms/configure" + make distcheck + - name: mycms-dist-misc + run: | + tar -C mycms -czf mycms-packaging.tar.gz --transform 's#^[^/]*#mycms-packaging#' packaging + - name: mycms-dist-upload + uses: actions/upload-artifact@v3 + with: + name: mycms-dist + path: | + mycms-build/distcheck/mycms-*.bz2 + - name: mycms-misc-upload + uses: actions/upload-artifact@v3 + with: + name: mycms-misc + path: | + mycms-packaging.tar.gz + - name: logs-upload + if: always() + uses: actions/upload-artifact@v3 + with: + name: logs + path: | + **/*.log + + ############################################################################################################# + # BUILD + ############################################################################################################# + + B-generic: + name: ${{ matrix.os }}-${{ matrix.crypto }} (V=${{ matrix.valgrind }})@B-generic + needs: + - B-P-mycms-dist + - C-openssl-binaries + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + os: + - windows + - linux + valgrind: + - 0 + - 1 + crypto: + - openssl-1.1.1 + - openssl-3.0 + exclude: + - os: windows + valgrind: 1 + + env: + crypto_name: ${{ matrix.crypto }}-binaries-${{ matrix.os }} + mycms_name: mycms-binaries-${{ matrix.os }}-${{ matrix.crypto }} + + steps: + - name: env + run: | + export MYCMS_DO_VALGRIND=0 + export MYCMS_COPY= + export MYCMS_DEPS= + export MYCMS_EXTRA_CONF= + export MYCMS_HOST= + export MYCMS_INSTALL=0 + export MYCMS_PACKAGE=0 + + case "${{ matrix.os }}/${{ matrix.crypto}}/${{ matrix.valgrind }}" in + */*/0) + MYCMS_INSTALL=1 + ;; + */*/1) + MYCMS_DO_VALGRIND=1 + MYCMS_DEPS="${MYCMS_DEPS} valgrind" + MYCMS_INSTALL=0 + ;; + esac + case "${{ matrix.os }}/${{ matrix.crypto}}/${{ matrix.valgrind }}" in + linux/*/*) + MYCMS_DEPS="${MYCMS_DEPS} softhsm" + ;; + windows/*/*) + MYCMS_HOST="x86_64-w64-mingw32" + MYCMS_DEPS="${MYCMS_DEPS} mingw-w64" + MYCMS_PACKAGE="1" + ;; + esac + case "${{ matrix.os }}/${{ matrix.crypto}}/${{ matrix.valgrind }}" in + linux/openssl-1.1.1/*) + MYCMS_DEPS="${MYCMS_DEPS} libssl-dev" + ;; + windows/openssl-*/*) + MYCMS_COPY="bin/libcrypto-*-x64.dll" + ;; + esac + env | grep '^MYCMS_' >> "${GITHUB_ENV}" + env | grep '.*_CFLAGS\|.*_LIBS' >> "${GITHUB_ENV}" || true + - name: ${{ env.crypto_name }} cache + uses: actions/cache@v3 + with: + path: ${{ env.crypto_name }} + key: ${{ env.crypto_name }}-${{ env.caches_version }} + - name: dependencies + run: | + sudo apt update + sudo apt install -y \ + build-essential \ + easy-rsa \ + pkg-config \ + ${MYCMS_DEPS} + - name: mycms-dist-download + uses: actions/download-artifact@v3 + with: + name: mycms-dist + path: dist + - name: mycms-prepare + run: | + tar -xf dist/mycms-*.bz2 + ln -s mycms-* mycms + mkdir -p mycms-build/${{ env.mycms_name }}-${{ matrix.valgrind }} + - name: mycms-build + working-directory: mycms-build/${{ env.mycms_name }}-${{ matrix.valgrind }} + run: | + "${GITHUB_WORKSPACE}/mycms/conf-dev.sh" \ + --host=${MYCMS_HOST} \ + PKG_CONFIG_PATH="${GITHUB_WORKSPACE}/${{ env.crypto_name }}/lib/pkgconfig" \ + ${MYCMS_EXTRA_CONF} + LD_LIBRARY_PATH="${GITHUB_WORKSPACE}/${{ env.crypto_name }}/lib" \ + make check + if [ "${MYCMS_INSTALL}" = "1" ]; then + make install DESTDIR="${GITHUB_WORKSPACE}/${{ env.mycms_name }}" + fi + if [ -n "${MYCMS_COPY}" ]; then + cp "${GITHUB_WORKSPACE}/${{ env.crypto_name }}"/${MYCMS_COPY} "${GITHUB_WORKSPACE}/${{ env.mycms_name }}/usr/local/bin" + fi + - name: binaries-upload + if: ${{ env.MYCMS_PACKAGE == 1 }} + uses: actions/upload-artifact@v3 + with: + name: ${{ env.mycms_name }} + path: | + ${{ env.mycms_name }}/usr/local + - name: logs-upload + if: always() + uses: actions/upload-artifact@v3 + with: + name: logs + path: | + **/*.log + + B-generic-wsl: + name: ${{ matrix.crypto }}@B-generic-wsl + needs: + - B-P-mycms-dist + - C-openssl-binaries + runs-on: windows-latest + strategy: + fail-fast: false + matrix: + crypto: + - openssl-1.1.1 + - openssl-3.0 + defaults: + run: + shell: wsl-bash {0} + env: + crypto_name: ${{ matrix.crypto }}-binaries-windows + mycms_name: mycms-binaries-windows-${{ matrix.crypto }} + WSLENV: GITHUB_WORKSPACE/p + + steps: + - name: "Use GNU tar instead BSD tar" + # https://github.com/actions/cache/issues/591 + shell: cmd + run: echo C:\Program Files\Git\usr\bin>>"%GITHUB_PATH%" + - name: ${{ env.crypto_name }} cache + uses: actions/cache@v3 + with: + path: ${{ env.crypto_name }} + key: ${{ env.crypto_name }}-${{ env.caches_version }} + - name: wsl-setup + uses: Vampire/setup-wsl@v1 + with: + distribution: Ubuntu-20.04 + additional-packages: + build-essential + easy-rsa + mingw-w64 + pkg-config + wsl-conf: | + [interop] + enabled=true + appendWindowsPath=false + - name: mycms-dist-download + uses: actions/download-artifact@v3 + with: + name: mycms-dist + path: dist + - name: mycms-prepare + run: | + tar -xf dist/mycms-*.bz2 + ln -s mycms-* mycms + mkdir -p mycms-build/${{ env.mycms_name }}-wsl + - name: patch + working-directory: mycms + run: | + patch -p0 < wsl-fixup-libtool-argv0.patch + patch -p0 < wsl-fixup-wsl1-skip-env.patch + - name: mycms-build + env: + WSLENV: GITHUB_WORKSPACE/p:Path/l:LT_SKIP_ENV + working-directory: mycms-build/${{ env.mycms_name }}-wsl + run: | + # @BEGIN: WSL1 Workarounds + # Libtool path injection breaks runtime environment + export Path="$(pwd)/src/libmycms/.libs:$(pwd)/src/libmycms-util/.libs:${GITHUB_WORKSPACE}/${{ env.crypto_name }}/bin/:${Path}" + export LT_SKIP_ENV=1 + # Absolute POSIX paths are not supported + export TMPDIR=. + # @END: WSL1 Workarounds + + "${GITHUB_WORKSPACE}/mycms/conf-dev.sh" \ + --host=x86_64-w64-mingw32 \ + --prefix=/ \ + PKG_CONFIG_PATH="${GITHUB_WORKSPACE}/${{ env.crypto_name }}/lib/pkgconfig" \ + PKG_CONFIG="pkg-config --define-prefix" + make check + - name: logs-upload + if: always() + uses: actions/upload-artifact@v3 + with: + name: logs + path: | + **/*.log + + ############################################################################################################# + # PACKAGING + ############################################################################################################# + + B-P-ubuntu: + name: B-P-ubuntu + needs: + - B-P-mycms-dist + runs-on: ubuntu-latest + container: + image: ubuntu:latest + env: + DEBIAN_FRONTEND: noninteractive + TZ: America/New_York + + steps: + - name: dependencies + run: | + apt update + apt install -y \ + build-essential \ + devscripts \ + equivs + - name: mycms-dist-download + uses: actions/download-artifact@v3 + with: + name: mycms-dist + path: dist + - name: extract + run: | + tar -xf dist/mycms-*.bz2 + ln -s mycms-* mycms + - name: prepare + working-directory: mycms + run: | + ln -s packaging/debian + - name: dependencies + working-directory: mycms + run: | + mk-build-deps -i --tool="apt-get -y -o Debug::pkgProblemResolver=yes --no-install-recommends" + - name: build + working-directory: mycms + run: | + debuild -b -uc -us -i + - name: create-repo + run: | + mkdir mycms-repo + cp *.deb mycms-repo + cd mycms-repo + dpkg-scanpackages . /dev/null | gzip -9c > Packages.gz + - name: mycms-deb-repo-upload + uses: actions/upload-artifact@v3 + with: + name: mycms-deb-repo + path: | + mycms-repo + + P-installers-windows: + name: ${{ matrix.crypto }}@P-installers-windows + needs: + - B-generic + runs-on: ubuntu-latest + strategy: + matrix: + crypto: + - openssl-1.1.1 + - openssl-3.0 + + steps: + - name: dependencies + run: | + sudo apt update + sudo apt install \ + nsis + - name: mycms-misc-download + uses: actions/download-artifact@v3 + with: + name: mycms-binaries-windows-${{ matrix.crypto }} + path: mycms-binaries-windows-${{ matrix.crypto }} + - name: mycms-misc-download + uses: actions/download-artifact@v3 + with: + name: mycms-misc + path: misc + - name: prepare + run: | + tar -xf misc/mycms-packaging.tar.gz + - name: mycms-package + run: | + DESTDIR="mycms-binaries-windows-${{ matrix.crypto }}" \ + EXTRA_NAME="$(echo "${{ matrix.crypto }}" | sed -n -e 's/.*\(-.*\)/\1/p')" \ + mycms-packaging/windows-nsis/build + - name: installers-upload + uses: actions/upload-artifact@v3 + with: + name: mycms-installers-windows-${{ matrix.crypto }} + path: | + mycms-*-setup.exe + + ############################################################################################################# + # TESTS + ############################################################################################################# + + T-P-ubuntu: + name: T-P-ubuntu + needs: + - B-P-ubuntu + runs-on: ubuntu-latest + container: + image: ubuntu:latest + options: --privileged + env: + DEBIAN_FRONTEND: noninteractive + TZ: America/New_York + + steps: + - name: mycms-deb-repo-download + uses: actions/download-artifact@v3 + with: + name: mycms-deb-repo + path: mycms-repo + - name: setup-repo + run: | + cat > /etc/apt/sources.list.d/mycms.list << __EOF__ + deb [trusted=yes] file://${GITHUB_WORKSPACE}/mycms-repo ./ + __EOF__ + - name: install + run: | + apt update + apt install -y \ + mycms + - name: test + run: | + mycms-tool --version + + T-P-installers-windows: + name: ${{ matrix.crypto }}@T-P-installers-windows + needs: + - P-installers-windows + runs-on: windows-latest + strategy: + matrix: + crypto: + - openssl-1.1.1 + - openssl-3.0 + + steps: + - name: mycms-misc-download + uses: actions/download-artifact@v3 + with: + name: mycms-installers-windows-${{ matrix.crypto }} + - name: test + run: | + $f = Get-ChildItem mycms-*-${{ matrix.crypto }}-setup.exe | Select-Object -First 1 + + $p = Start-Process -FilePath $f -Wait -Verb RunAs -PassThru -ArgumentList "/S","/SELECT_MYCMS_TOOLS=1","/SELECT_MYCMS_SDK=1","/D=C:\Program Files\mycms" + if ($p.ExitCode -ne 0) { + throw "FAIL (Install)" + } + + if (-not(Test-Path -Path "C:\Program Files\mycms\include\mycms\mycms.h" -PathType Leaf)) { + throw "The install failed" + } + + $p = Start-Process -FilePath "C:\Program Files\mycms\bin\mycms-tool.exe" -ArgumentList "--version" -NoNewWindow -Wait -PassThru + if ($p.ExitCode -ne 0) { + throw "FAIL (Sanity)" + } diff --git a/.github/workflows/codespell.yaml b/.github/workflows/codespell.yaml new file mode 100644 index 0000000..47558a3 --- /dev/null +++ b/.github/workflows/codespell.yaml @@ -0,0 +1,18 @@ +--- +name: codespell + +on: + pull_request: + push: + +jobs: + codespell: + name: Check for spelling errors + runs-on: ubuntu-latest + + steps: + - name: mycms-checkout + uses: actions/checkout@v3 + - uses: codespell-project/actions-codespell@master + with: + ignore_words_file: ./.codespell-ignore-words diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..44a3633 --- /dev/null +++ b/.gitignore @@ -0,0 +1,63 @@ +*.a +*.bz2 +*.deb +*.def +*.dll +*.exe +*.exp +*.gz +*.idb +*.la +*.lib +*.lo +*.log +*.manifest +*.o +*.obj +*.out +*.swp +*.trs +*~ +.deps +.libs +Makefile +Makefile.in +aclocal.m4 +autom4te.cache +built.* +compile +config.guess +config.h +config.h.in +config.log +config.status +config.sub +configure +debian +depcomp +gen +install-sh +libtool +ltmain.sh +m4/libtool.m4 +m4/ltoptions.m4 +m4/ltsugar.m4 +m4/ltversion.m4 +m4/lt~obsolete.m4 +m4/pkg.m4 +missing +package.info +packaging/rpm/mycms.spec +src/libmycms-util/libmycms-util.pc +src/libmycms-util/mycms-util-all.exports +src/libmycms/libmycms.pc +src/libmycms/mycms-all.exports +src/mycms-tool/mycms-tool +stamp-h1 +test-driver +test/ca/rootca.pki +test/ca/rootca.vars +test/ca/subca.pki +test/ca/subca.vars +test/ca/vars +versioninfo.rc diff --git a/COPYING b/COPYING new file mode 100644 index 0000000..cb976bf --- /dev/null +++ b/COPYING @@ -0,0 +1,26 @@ +Copyright (c) , +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. +3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. diff --git a/ChangeLog b/ChangeLog new file mode 100644 index 0000000..61a2de1 --- /dev/null +++ b/ChangeLog @@ -0,0 +1,6 @@ +mycms +Copyright (c) 2022 Alon Bar-Lev + +2022-05-11 - Version 0.1.0 + + * Initial release. diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..7203c0e --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,93 @@ +# mycms Installation + +POSIX and Windows (using mingw-w64) are supported. + +## Dependencies + +### Standard Dependencies + +* `pkg-config` complaint +* `>=openssl-1.1` + +### Test Dependencies + +* softhsm2 +* easy-rsa +* awk compliant +* Optional + * `valgrind` + +### Checkout Dependencies + +* autoconf +* automake +* libtool + +Run: + +``` +$ autoreconf -ivf +``` + +## Development + +Use `conf-dev.sh` to configure all features during development. + +Use `MYCMS_DO_VALGRIND=1 make check` to check using `valgrind`. + +## Packaging + +### Debian + +#### Dependencies + +##### Prepare + +``` +$ ln -s packaging/debian +``` + +##### Install + +``` +$ sudo apt install build-essential devscripts equivs +$ sudo mk-build-deps -i +``` + +##### Remove + +``` +$ sudo apt remove mycms-build-deps +``` + +#### Build + +``` +$ debuild -b -uc -us -i +``` + +#### Release + +Due to `deb` magics, before release version must be updated manually in `packaging/debian/changelog`. + +#### Install Manually + +``` +$ dpkg -i mycms*.deb +``` + +### Windows NSIS + +#### Dependencies + +``` +$ sudo apt install nsis +``` + +#### Build + +``` +$ ./configure --host=x86-w64-mingw32 --prefix=/ ... +$ make install DESTDIR="$(pwd)/tmp" +$ DESTDIR=tmp ./packaging/windows-nsis/build +``` diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 0000000..2150b68 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,78 @@ +AUTOMAKE_OPTIONS = foreign dist-bzip2 1.10 +ACLOCAL_AMFLAGS = -I m4 --install + +#@AM_DISTCHECK_CONFIGURE_FLAGS-BEGIN +AM_DISTCHECK_CONFIGURE_FLAGS = \ + --enable-certificate-driver-file \ + --enable-certificate-driver-pkcs11 \ + --enable-cms-decrypt \ + --enable-cms-encrypt \ + --enable-cms-sign \ + --enable-cms-verify \ + --enable-io-driver-file \ + --enable-openssl-err-strings \ + --enable-pedantic \ + --enable-pinentry \ + --enable-strict \ + --enable-tests \ + --enable-tool \ + $(NULL) +#@AM_DISTCHECK_CONFIGURE_FLAGS-END + +MAINTAINERCLEANFILES = \ + config.log config.status \ + $(srcdir)/Makefile.in \ + $(srcdir)/config.h.in $(srcdir)/config.h.in~ $(srcdir)/configure \ + $(srcdir)/install-sh $(srcdir)/ltmain.sh $(srcdir)/missing \ + $(srcdir)/depcomp $(srcdir)/compile $(srcdir)/aclocal.m4 \ + $(srcdir)/test-driver \ + $(srcdir)/config.guess $(srcdir)/config.sub \ + $(srcdir)/m4/ltsugar.m4 $(srcdir)/m4/libtool.m4 \ + $(srcdir)/m4/ltversion.m4 $(srcdir)/m4/lt~obsolete.m4 \ + $(srcdir)/m4/ltoptions.m4 $(srcdir)/m4/pkg.m4 \ + $(NULL) + +EXTRA_DIST = \ + .gitignore \ + $(NULL) + +SUBDIRS = \ + build \ + include \ + packaging \ + src \ + $(NULL) +if ENABLE_TESTS +SUBDIRS += \ + test \ + $(NULL) +endif + +dist_doc_DATA = \ + $(NULL) + +dist_noinst_DATA = \ + INSTALL.md \ + $(NULL) + +dist_noinst_SCRIPTS = \ + conf-dev.sh \ + wsl-fixup-libtool-argv0.patch \ + wsl-fixup-wsl1-skip-env.patch \ + $(NULL) + +if BUILD_WINDOWS +rootdir=$(prefix) +root_DATA = \ + package.info \ + $(NULL) +dist_doc_DATA += \ + COPYING \ + README.md \ + $(NULL) +else +dist_noinst_DATA += \ + COPYING \ + README.md \ + $(NULL) +endif diff --git a/README.md b/README.md new file mode 100644 index 0000000..a7e9fb1 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# mycms + +## Outline + +A simple CMS tool. + +## Interfaces + +### Tool + +#### Common + +``` +``` + +TODO + +### C API + +Refer to `include/mycms` + +Please review `mycms-tool` as a reference implementation. diff --git a/build/Makefile.am b/build/Makefile.am new file mode 100644 index 0000000..3f2e744 --- /dev/null +++ b/build/Makefile.am @@ -0,0 +1,7 @@ +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in \ + $(NULL) + +EXTRA_DIST = \ + ltrc.inc \ + $(NULL) diff --git a/build/ltrc.inc b/build/ltrc.inc new file mode 100644 index 0000000..7c32a64 --- /dev/null +++ b/build/ltrc.inc @@ -0,0 +1,9 @@ +RCCOMPILE = $(RC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) +LTRCCOMPILE = $(LIBTOOL) --mode=compile --tag=RC $(RCCOMPILE) + +.rc.lo: + $(LTRCCOMPILE) -i "$<" -o "$@" + +.rc.o: + $(RCCOMPILE) -i "$<" -o "$@" diff --git a/conf-dev.sh b/conf-dev.sh new file mode 100755 index 0000000..9810c75 --- /dev/null +++ b/conf-dev.sh @@ -0,0 +1,21 @@ +#!/bin/sh + +NULL= + +srcdir="$(dirname "$0")" + +eval "$( + sed -n \ + -e '/^#@AM_DISTCHECK_CONFIGURE_FLAGS-BEGIN$/,/^#@AM_DISTCHECK_CONFIGURE_FLAGS-END$/p' \ + "${srcdir}/Makefile.am" | + sed \ + -e 's/ =/="/' \ + -e 's/$(NULL)/"/' +)" + +exec "${srcdir}/configure" \ + --enable-strict \ + --enable-pedantic \ + ${AM_DISTCHECK_CONFIGURE_FLAGS} \ + "${@}" \ + ${NULL} diff --git a/configure.ac b/configure.ac new file mode 100644 index 0000000..7a37af1 --- /dev/null +++ b/configure.ac @@ -0,0 +1,385 @@ +AC_PREREQ([2.60]) + +define([PACKAGE_VERSION_MAJOR], [0]) +define([PACKAGE_VERSION_MINOR], [1]) +define([PACKAGE_VERSION_FIX], [0]) +define([PACKAGE_VERSION_REVISION], [0]) +define([PACKAGE_SUFFIX], []) + +AC_INIT([mycms], [PACKAGE_VERSION_MAJOR.PACKAGE_VERSION_MINOR.PACKAGE_VERSION_FIX[]PACKAGE_SUFFIX]) +AC_CONFIG_AUX_DIR([.]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_MACRO_DIRS([m4]) +AC_CONFIG_SRCDIR([include/mycms/mycms.h]) +AM_INIT_AUTOMAKE + +MYCMS_VERSION_MAJOR="PACKAGE_VERSION_MAJOR" +MYCMS_VERSION_MINOR="PACKAGE_VERSION_MINOR" +MYCMS_VERSION_FIX="PACKAGE_VERSION_FIX" +MYCMS_VERSION_REVISION="PACKAGE_VERSION_REVISION" + +AC_SUBST([MYCMS_VERSION_MAJOR]) +AC_SUBST([MYCMS_VERSION_MINOR]) +AC_SUBST([MYCMS_VERSION_FIX]) +AC_SUBST([MYCMS_VERSION_REVISION]) + +LIBMYCMS_LT_CURRENT="1" +LIBMYCMS_LT_OLDEST="1" +LIBMYCMS_LT_REVISION="0" +LIBMYCMS_LT_AGE="$((${LIBMYCMS_LT_CURRENT}-${LIBMYCMS_LT_OLDEST}))" + +AC_CANONICAL_HOST + +AC_ARG_ENABLE( + [strict], + [AS_HELP_STRING([--enable-strict], [enable strict compiler warnings])], + , + [enable_strict="no"] +) + +AC_ARG_ENABLE( + [pedantic], + [AS_HELP_STRING([--enable-pedantic], [enable pedantic compiler warnings])], + , + [enable_pedantic="no"] +) + +AC_ARG_ENABLE( + [all-static], + [AS_HELP_STRING([--enable-all-static], [enable all static mode])], + , + [enable_all_static="no"] +) + +AC_ARG_ENABLE( + [system-driver-default], + [AS_HELP_STRING([--disable-system-driver-default], [disable default system driver])], + , + [enable_system_driver_default="yes"] +) + +AC_ARG_ENABLE( + [tests], + [AS_HELP_STRING([--enable-tests], [enable tests])], + , + [enable_tests="no"] +) + +AC_ARG_ENABLE( + [tool], + [AS_HELP_STRING([--enable-tool], [enable tool])], + , + [enable_tool="no"] +) + +AC_ARG_ENABLE( + [openssl-err-strings], + [AS_HELP_STRING([--enable-openssl-err-strings], [enable openssl error strings])], + , + [enable_openssl_err_strings="no"] +) + +AC_ARG_ENABLE( + [pinentry], + [AS_HELP_STRING([--enable-pinentry], [enable pinentry support])], + , + [enable_pinentry="no"] +) + +AC_ARG_ENABLE( + [cms-sign], + [AS_HELP_STRING([--enable-cms-sign], [enable cms sign support])], + , + [enable_cms_sign="no"] +) + +AC_ARG_ENABLE( + [cms-verify], + [AS_HELP_STRING([--enable-cms-verify], [enable cms verify support])], + , + [enable_cms_verify="no"] +) + +AC_ARG_ENABLE( + [cms-decrypt], + [AS_HELP_STRING([--enable-cms-decrypt], [enable cms decrypt support])], + , + [enable_cms_decrypt="no"] +) + +AC_ARG_ENABLE( + [cms-encrypt], + [AS_HELP_STRING([--enable-cms-encrypt], [enable cms encrypt support])], + , + [enable_cms_encrypt="no"] +) + +AC_ARG_ENABLE( + [io-driver-file], + [AS_HELP_STRING([--enable-io-driver-file], [enable io file driver support])], + , + [enable_io_driver_file="no"] +) + +AC_ARG_ENABLE( + [certificate-driver-file], + [AS_HELP_STRING([--enable-certificate-driver-file], [enable certificate file driver support])], + , + [enable_certificate_driver_file="no"] +) + +AC_ARG_ENABLE( + [certificate-driver-pkcs11], + [AS_HELP_STRING([--enable-certificate-driver-pkcs11], [enable certificate PKCS@%:@11 driver support])], + , + [enable_certificate_driver_pkcs11="no"] +) + +AC_ARG_WITH( + [build-id], + [AS_HELP_STRING([--with-build-id=STR], [use this as build identifier])], + , + [with_build_id=""] +) +AC_ARG_WITH( + [md-suffix], + [AS_HELP_STRING([--with-md-suffix=STR], [use this suffix as netadata file suffix @<:@default=.mycms@:>@])], + , + [with_md_suffix=".mycms"] +) + +AC_PROG_CC +AC_PROG_INSTALL +PKG_PROG_PKG_CONFIG +LT_INIT([win32-dll]) +LT_LANG([Windows Resource]) + +AC_CHECK_FUNCS([ \ + getopt_long \ +]) + +AC_MSG_CHECKING([Checking C99 vararg macros]) +AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[ + #define test(x, ...) xxx(x __VA_OPT__(,) __VA_ARGS__) + void xxx(int, ...); + ]], + [[ + test(1); + ]] + )], + [ + AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_C99_VARARGS_MACROS], [1], [Have C99 varargs macros]) + ], + [ + AC_MSG_RESULT([no]) + AC_MSG_CHECKING([Checking GCC vararg macros]) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[ + #define test(x, ...) xxx(x, ##__VA_ARGS__) + void xxx(int, ...); + ]], + [[ + test(1); + ]] + )], + [ + AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_GCC_VARARGS_MACROS], [1], [Have GCC varags macros]) + ], + [AC_MSG_ERROR([cannot find supported varargs macros])] + ) + ] +) + +if test "${enable_all_static}" = "yes"; then + ifdef( + [PKG_CHECK_MODULES_STATIC], + [PKG_CHECK_MODULES_STATIC( + [OPENSSLCRYPTO], + [libcrypto >= 1.1.0], + , + [AC_MSG_ERROR([Cannot locate openssl libcrypto])] + )], + [ + # Old pkg.m4 hack + saved_PKG_CONFIG="${PKG_CONFIG}" + PKG_CONFIG="${PKG_CONFIG} --static" + PKG_CHECK_MODULES( + [OPENSSLCRYPTO], + [libcrypto >= 1.1.0], + , + [AC_MSG_ERROR([Cannot locate openssl libcrypto])] + ) + PKG_CONFIG="${saved_PKG_CONFIG}" + ] + ) + # Fix segmentation error per pthread_setspecific is linked but pthread_mutex_lock is not + if echo "${OPENSSLCRYPTO_LIBS}" | grep -q pthread; then + LDFLAGS="${LDFLAGS} -Wl,-u,pthread_mutex_lock -Wl,-u,pthread_mutex_unlock" + fi +else + PKG_CHECK_MODULES( + [OPENSSLCRYPTO], + [libcrypto >= 1.1.0], + , + [AC_MSG_ERROR([Cannot locate openssl libcrypto])] + ) +fi + +if test "${enable_pedantic}" = "yes"; then + enable_strict="yes" + CFLAGS="${CFLAGS} -pedantic -D_ISOC99_SOURCE -D_DEFAULT_SOURCE" +fi + +if test "${enable_strict}" = "yes"; then + CFLAGS="${CFLAGS} -Wall -Wextra" +fi + +AC_HEADER_STDBOOL +AC_C_CONST +AC_C_INLINE +AC_C_VOLATILE +AC_TYPE_SIZE_T +AC_TYPE_SSIZE_T + +AC_CHECK_HEADERS([ \ + dnfcn.h \ +]) + +AC_CHECK_FUNCS([ \ + explicit_bzero \ +]) + +case "${host}" in + *-mingw*) + BUILD_WINDOWS=yes + CPPFLAGS="${CPPFLAGS} -DWIN32_LEAN_AND_MEAN" + AC_DEFINE([BUILD_WINDOWS], [1], [Build windows]) + AC_DEFINE([strerror_r(n, b, s)], [strerror_s((b), (s), (n))], [strerror_r]) + AC_DEFINE([HAVE_SECUREZEROMEMORY], [1], [Have SecureZeroMemory]) + ;; +esac + +AC_PROG_AWK +AC_ARG_VAR([VALGRIND], [path to valgrind utility]) +AC_PATH_PROGS([VALGRIND], [valgrind]) +AC_ARG_VAR([PKCS11_TOOL], [path to pkcs11-tool utility]) +AC_PATH_PROGS([PKCS11_TOOL], [pkcs11-tool]) +AC_ARG_VAR([OPENSSL], [path to openssl utility]) +AC_PATH_PROGS([OPENSSL], [openssl]) +AC_ARG_VAR([EASYRSA], [path to easyrsa utility]) +AC_PATH_PROGS([EASYRSA], [easyrsa],, [/usr/share/easy-rsa]) +AC_ARG_VAR([SOFTHSM2_UTIL], [path to softhsm2-util utility]) +AC_PATH_PROGS([SOFTHSM2_UTIL], [softhsm2-util]) +AC_ARG_VAR([SOFTHSM2_MODULE], [path to SoftHSM2 module]) + +AC_MSG_CHECKING([path to SoftHSM2 module]) +if test -z "${SOFTHSM2_MODULE}"; then + for x in /usr/lib*/softhsm/libsofthsm2.so /usr/lib*/*/softhsm/libsofthsm2.so; do + if test -r "${x}"; then + SOFTHSM2_MODULE="${x}" + break + fi + done +fi +AC_MSG_RESULT([${SOFTHSM2_MODULE}]) + +test "${enable_all_static}" = "yes" && \ + LDFLAGS="${LDFLAGS} -all-static" + +if test "${cross_compiling}" = "yes"; then + enable_tests="no" +fi + +test "${enable_system_driver_default}" = "yes" && AC_DEFINE([ENABLE_SYSTEM_DRIVER_DEFAULT], [1], [Enable default system driver]) +test "${enable_tool}" = "yes" && AC_DEFINE([ENABLE_TOOL], [1], [Enable tool]) +test "${enable_openssl_err_strings}" = "yes" && AC_DEFINE([ENABLE_OPENSSL_ERR_STRINGS], [1], [Enable openssl error strings]) +test "${enable_pinentry}" = "yes" && AC_DEFINE([ENABLE_PINENTRY], [1], [Enable pinentry]) +test "${enable_cms_sign}" = "yes" && AC_DEFINE([ENABLE_CMS_SIGN], [1], [Enable cms sign]) +test "${enable_cms_verify}" = "yes" && AC_DEFINE([ENABLE_CMS_VERIFY], [1], [Enable cms verify]) +test "${enable_cms_decrypt}" = "yes" && AC_DEFINE([ENABLE_CMS_DECRYPT], [1], [Enable cms decrypt]) +test "${enable_cms_encrypt}" = "yes" && AC_DEFINE([ENABLE_CMS_ENCRYPT], [1], [Enable cms encrypt]) +test "${enable_io_driver_file}" = "yes" && AC_DEFINE([ENABLE_IO_DRIVER_FILE], [1], [Enable io file driver]) +test "${enable_certificate_driver_file}" = "yes" && AC_DEFINE([ENABLE_CERTIFICATE_DRIVER_FILE], [1], [Enable cms certificate file driver]) +if test "${enable_certificate_driver_pkcs11}" = "yes"; then + AC_DEFINE([ENABLE_CERTIFICATE_DRIVER_PKCS11], [1], [Enable cms pkcs11 file driver]) + LIBS="${LIBS} ${LIBDL_LIBS}" +fi + +if test "${enable_tests}" = "yes"; then + test -z "${OPENSSL}" && \ + AC_MSG_ERROR([openssl is required for test]) + test -z "${EASYRSA}" && \ + AC_MSG_ERROR([easyrsa is required for test]) + test -z "${AWK}" && \ + AC_MSG_ERROR([awk is required for easyrsa]) + if test "${enable_certificate_driver_pkcs11}" = "yes" -a "${BUILD_WINDOWS}" != "yes"; then + test -z "${SOFTHSM2_UTIL}" && + AC_MSG_ERROR([softhsm2 is required for PKCS@%:@11 tests]) + test -z "${SOFTHSM2_MODULE}" && + AC_MSG_ERROR([softhsm2 module is required for PKCS@%:@11 tests]) + test -z "${PKCS11_TOOL}" && + AC_MSG_ERROR([pkcs11-tool (opensc) is required for PKCS@%:@11 tests]) + fi +fi +test "${enable_tool}" = "yes" -a "${enable_io_driver_file}" != "yes" && \ + AC_MSG_ERROR([IO file driver is required for tool]) +test "${enable_all_static}" = "yes" -a "${enable_certificate_driver_pkcs11}" = "yes" && \ + AC_MSG_ERROR([PKCS11 uses dynamic library]) + +AC_DEFINE_UNQUOTED([PACKAGE_BUILD_ID], ["${with_build_id}"], [Build identifier]) + +pkgconfigdir="\$(libdir)/pkgconfig" +mycmsincludedir="\$(includedir)/mycms" +AC_SUBST([pkgconfigdir]) +AC_SUBST([mycmsincludedir]) +AC_SUBST([LIBMYCMS_LT_CURRENT]) +AC_SUBST([LIBMYCMS_LT_REVISION]) +AC_SUBST([LIBMYCMS_LT_AGE]) +AC_SUBST([LIBMYCMS_LT_OLDEST]) +AC_SUBST([PACKAGE_BUILD_ID]) +AM_CONDITIONAL([CROSS_COMPILING], [test "${cross_compiling}" = "yes"]) +AM_CONDITIONAL([BUILD_WINDOWS], [test "${BUILD_WINDOWS}" = "yes"]) +AM_CONDITIONAL([ENABLE_TESTS], [test "${enable_tests}" = "yes"]) +AM_CONDITIONAL([ENABLE_TOOL], [test "${enable_tool}" = "yes"]) +AM_CONDITIONAL([ENABLE_PINENTRY], [test "${enable_pinentry}" = "yes"]) +AM_CONDITIONAL([ENABLE_CMS_SIGN], [test "${enable_cms_sign}" = "yes"]) +AM_CONDITIONAL([ENABLE_CMS_VERIFY], [test "${enable_cms_verify}" = "yes"]) +AM_CONDITIONAL([ENABLE_CMS_DECRYPT], [test "${enable_cms_decrypt}" = "yes"]) +AM_CONDITIONAL([ENABLE_CMS_ENCRYPT], [test "${enable_cms_encrypt}" = "yes"]) +AM_CONDITIONAL([ENABLE_IO_DRIVER_FILE], [test "${enable_io_driver_file}" = "yes"]) +AM_CONDITIONAL([ENABLE_CERTIFICATE_DRIVER_FILE], [test "${enable_certificate_driver_file}" = "yes"]) +AM_CONDITIONAL([ENABLE_CERTIFICATE_DRIVER_PKCS11], [test "${enable_certificate_driver_pkcs11}" = "yes"]) +AC_CONFIG_FILES([ + Makefile + build/Makefile + include/Makefile + include/mycms/Makefile + package.info + packaging/Makefile + packaging/debian/Makefile + packaging/windows-nsis/Makefile + src/Makefile + src/libmycms-util/Makefile + src/libmycms-util/libmycms-util.pc + src/libmycms-util/versioninfo.rc + src/libmycms/Makefile + src/libmycms/libmycms.pc + src/libmycms/versioninfo.rc + src/mycms-tool/Makefile + src/mycms-tool/versioninfo.rc + test/Makefile + test/ca/Makefile + test/ca/rootca.vars + test/ca/subca.vars + test/ca/vars + test/mycms-tool/Makefile + test/mycms-tool/encrypt/Makefile + test/mycms-tool/sign/Makefile + test/mycms-tool/windows/Makefile +]) +AC_OUTPUT diff --git a/include/Makefile.am b/include/Makefile.am new file mode 100644 index 0000000..173a5cb --- /dev/null +++ b/include/Makefile.am @@ -0,0 +1,7 @@ +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in \ + $(NULL) + +SUBDIRS = \ + mycms \ + $(NULL) diff --git a/include/mycms/Makefile.am b/include/mycms/Makefile.am new file mode 100644 index 0000000..4ea9b2c --- /dev/null +++ b/include/mycms/Makefile.am @@ -0,0 +1,21 @@ +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in \ + $(NULL) + +mycmsinclude_HEADERS = \ + mycms-blob.h \ + mycms-certificate-driver-file.h \ + mycms-certificate-driver-pkcs11.h \ + mycms-certificate.h \ + mycms-context.h \ + mycms-dict.h \ + mycms-error.h \ + mycms-io.h \ + mycms-list.h \ + mycms-static.h \ + mycms-system-driver-core.h \ + mycms-system.h \ + mycms-util-getpass.h \ + mycms-variant.h \ + mycms.h \ + $(NULL) diff --git a/include/mycms/mycms-blob.h b/include/mycms/mycms-blob.h new file mode 100644 index 0000000..959b7a6 --- /dev/null +++ b/include/mycms/mycms-blob.h @@ -0,0 +1,14 @@ +#ifndef __MYCMS_BLOB_H +#define __MYCMS_BLOB_H + +#include "mycms-list.h" + +struct mycms_blob_s { + unsigned char * data; + size_t size; +}; +typedef struct mycms_blob_s mycms_blob; + +MYCMS_LIST_DECLARE(blob, mycms_blob, blob) + +#endif diff --git a/include/mycms/mycms-certificate-driver-file.h b/include/mycms/mycms-certificate-driver-file.h new file mode 100644 index 0000000..6a20954 --- /dev/null +++ b/include/mycms/mycms-certificate-driver-file.h @@ -0,0 +1,14 @@ +#ifndef __MYCMS_CERTIFICATE_DRIVER_FILE_H +#define __MYCMS_CERTIFICATE_DRIVER_FILE_H + +#include "mycms-certificate.h" + +const char * +mycms_certificate_driver_file_usage(void); + +bool +mycms_certificate_driver_file_apply( + const mycms_certificate certificate +); + +#endif diff --git a/include/mycms/mycms-certificate-driver-pkcs11.h b/include/mycms/mycms-certificate-driver-pkcs11.h new file mode 100644 index 0000000..e139eb1 --- /dev/null +++ b/include/mycms/mycms-certificate-driver-pkcs11.h @@ -0,0 +1,14 @@ +#ifndef __MYCMS_CERTIFICATE_DRIVER_PKCS11_H +#define __MYCMS_CERTIFICATE_DRIVER_PKCS11_H + +#include "mycms-certificate.h" + +const char * +mycms_certificate_driver_pkcs11_usage(void); + +bool +mycms_certificate_driver_pkcs11_apply( + const mycms_certificate certificate +); + +#endif diff --git a/include/mycms/mycms-certificate.h b/include/mycms/mycms-certificate.h new file mode 100644 index 0000000..5e23c79 --- /dev/null +++ b/include/mycms/mycms-certificate.h @@ -0,0 +1,133 @@ +#ifndef __MYCMS_CERTIFICATE_H +#define __MYCMS_CERTIFICATE_H + +#include + +#include "mycms-blob.h" +#include "mycms-context.h" +#include "mycms-dict.h" + +#define MYCMS_PRIVATE_OP_ENCRYPT 0 +#define MYCMS_PRIVATE_OP_DECRYPT 1 + +#define MYCMS_PADDING_INVALID -1 +#define MYCMS_PADDING_NONE 0 +#define MYCMS_PADDING_PKCS1 1 +#define MYCMS_PADDING_OEAP 2 + +struct mycms_certificate_s; +typedef struct mycms_certificate_s *mycms_certificate; + +typedef bool (*mycms_certificate_driver_free)( + const mycms_certificate certificate +); + +typedef bool (*mycms_certificate_driver_load)( + const mycms_certificate certificate, + const mycms_dict dict +); + +typedef int (*mycms_certificate_driver_rsa_private_op)( + const mycms_certificate certificate, + const int op, + const unsigned char * const from, + const size_t from_size, + unsigned char * const to, + const size_t to_size, + const int padding +); + +typedef bool (*mycms_certificate_passphrase_callback)( + const mycms_certificate certificate, + const char * const what, + char **p, + const size_t size +); + +mycms_certificate +mycms_certificate_new( + const mycms_context context +); + +bool +mycms_certificate_construct( + const mycms_certificate certificate +); + +bool +mycms_certificate_destruct( + const mycms_certificate certificate +); + +mycms_context +mycms_certificate_get_context( + const mycms_certificate certificate +); + +const void * +mycms_certificate_get_userdata( + const mycms_certificate certificate +); + +bool +mycms_certificate_set_userdata( + const mycms_certificate certificate, + const void *userdata +); + +const void * +mycms_certificate_get_driverdata( + const mycms_certificate certificate +); + +bool +mycms_certificate_set_driverdata( + const mycms_certificate certificate, + const void *userdata +); + +bool +mycms_certificate_set_driver_load( + const mycms_certificate certificate, + const mycms_certificate_driver_load driver_load +); + +bool +mycms_certificate_set_driver_free( + const mycms_certificate certificate, + const mycms_certificate_driver_free driver_free +); + +bool +mycms_certificate_set_driver_rsa_private_op( + const mycms_certificate certificate, + const mycms_certificate_driver_rsa_private_op driver_rsa_private_op +); + +bool +mycms_certificate_set_passphrase_callback( + const mycms_certificate certificate, + const mycms_certificate_passphrase_callback passphrase_callback +); + +bool +mycms_certificate_apply_certificate( + const mycms_certificate certificate, + const mycms_blob *blob +); + +bool +mycms_certificate_load( + const mycms_certificate certificate, + const mycms_dict parameters +); + +bool +mycms_certificate_acquire_passphrase( + const mycms_certificate certificate, + const char * const what, + char **p, + const size_t size +); + +#endif diff --git a/include/mycms/mycms-context.h b/include/mycms/mycms-context.h new file mode 100644 index 0000000..34a1b78 --- /dev/null +++ b/include/mycms/mycms-context.h @@ -0,0 +1,64 @@ +#ifndef __MYCMS_CONTEXT_H +#define __MYCMS_CONTEXT_H + +#include +#include +#include + +#include "mycms-error.h" +#include "mycms-system.h" + + +#ifdef __cplusplus +extern "C" { +#endif + +struct __mycms_context_s; +typedef struct __mycms_context_s *mycms_context; + +mycms_context +mycms_context_new( + const mycms_system system +); + +bool +mycms_context_construct( + const mycms_context context +); + +bool +mycms_context_destruct( + const mycms_context context +); + +mycms_system +mycms_context_get_system( + const mycms_context context +); + +const void * +mycms_context_get_user_context( + const mycms_context context +); + +bool +mycms_context_set_user_context( + const mycms_context context, + void *user_context +); + +mycms_error +mycms_context_get_error( + const mycms_context context +); + +void +mycms_context_error_reset( + const mycms_context context +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/mycms/mycms-dict.h b/include/mycms/mycms-dict.h new file mode 100644 index 0000000..41aa0c2 --- /dev/null +++ b/include/mycms/mycms-dict.h @@ -0,0 +1,71 @@ +#ifndef __MYCMS_DICT_H +#define __MYCMS_DICT_H + +#include "mycms-context.h" +#include "mycms-list.h" + +typedef struct { + const char *k; + const char *v; +} mycms_dict_entry; + +MYCMS_LIST_DECLARE(dict_entry, mycms_dict_entry, entry) + +struct mycms_dict_s; +typedef struct mycms_dict_s *mycms_dict; +typedef void (*mycms_dict_free_callback)( + const mycms_dict dict, + const void *p +); + +mycms_dict +mycms_dict_new( + const mycms_context context +); + +bool +mycms_dict_construct( + const mycms_dict dict +); + +bool +mycms_dict_destruct( + const mycms_dict dict +); + +mycms_context +mycms_dict_get_context( + const mycms_dict dict +); + +bool +mycms_dict_entry_clear( + const mycms_dict dict +); + +bool +mycms_dict_entry_put( + const mycms_dict dict, + const char * const k, + const char * const v +); + +const char * +mycms_dict_entry_get( + const mycms_dict dict, + const char * const k, + bool * const found +); + +bool +mycms_dict_entry_del( + const mycms_dict dict, + const char * const k +); + +mycms_list_dict_entry +mycms_dict_entries( + const mycms_dict dict +); + +#endif diff --git a/include/mycms/mycms-error.h b/include/mycms/mycms-error.h new file mode 100644 index 0000000..4ac5bb3 --- /dev/null +++ b/include/mycms/mycms-error.h @@ -0,0 +1,113 @@ +#ifndef __MYCMS_ERROR_H +#define __MYCMS_ERROR_H + +#include "mycms-variant.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define MYCMS_ERROR_CODE_SUCCESS 0x00000000 +#define MYCMS_ERROR_CODE_FAILED 0x00000001 +#define MYCMS_ERROR_CODE_MEMORY 0x00000002 +#define MYCMS_ERROR_CODE_NO_CONTEXT 0x00000003 +#define MYCMS_ERROR_CODE_RELEASE 0x00000004 +#define MYCMS_ERROR_CODE_ARGS 0x00000005 +#define MYCMS_ERROR_CODE_IO 0x00000006 +#define MYCMS_ERROR_CODE_STATE 0x00000007 +#define MYCMS_ERROR_CODE_RESOURCE_ACCESS 0x00000008 +#define MYCMS_ERROR_CODE_DEPENDENCY 0x00000009 +#define MYCMS_ERROR_CODE_NOT_IMPLEMENTED 0x0000000A + +#define MYCMS_ERROR_CODE_INTEGRITY_SIZE 0x00100001 +#define MYCMS_ERROR_CODE_INTEGRITY 0x00100002 +#define MYCMS_ERROR_CODE_NO_KEY 0x00100003 +#define MYCMS_ERROR_CODE_CRYPTO 0x00100004 + +#define MYCMS_ERROR_CODE_USER_BASE 0x80000000 + +#define MYCMS_ERROR_KEY_AUTHORITATIVE 0x00000000 +#define MYCMS_ERROR_KEY_CODE 0x00000001 +#define MYCMS_ERROR_KEY_SOURCE_FILE 0x00000002 +#define MYCMS_ERROR_KEY_SOURCE_LINE 0x00000003 +#define MYCMS_ERROR_KEY_SOURCE_FUNC 0x00000004 +#define MYCMS_ERROR_KEY_HINT 0x00000005 +#define MYCMS_ERROR_KEY_DESCRIPTION 0x00000006 +#define MYCMS_ERROR_KEY_RESOURCE_SIZE 0x00000007 +#define MYCMS_ERROR_KEY_RESOURCE_NAME 0x00000008 + +#define MYCMS_ERROR_KEY_ERRNO 0x00010001 +#define MYCMS_ERROR_KEY_ERRNO_STR 0x00010002 +#define MYCMS_ERROR_KEY_NTSTATUS 0x00010003 +#define MYCMS_ERROR_KEY_OPENSSL_STATUS 0x00010006 +#define MYCMS_ERROR_KEY_OPENSSL_STATUS_STR 0x00010007 +#define MYCMS_ERROR_KEY_PKCS11_RV 0x00010008 +#define MYCMS_ERROR_KEY_PKCS11_RV_STR 0x00010009 + +#define MYCMS_ERROR_KEY_USER_BASE 0x80000000 + +typedef struct mycms_error_desc_s { + uint32_t key; + char *desc; + char *format; +} *mycms_error_desc; + +typedef struct mycms_error_prm_s { + uint32_t k; + mycms_variant *v; +} *mycms_error_prm; + +struct __mycms_error_s; +typedef struct __mycms_error_s *mycms_error; +struct __mycms_error_entry_s; +typedef struct __mycms_error_entry_s *mycms_error_entry; + +/* TODO: consider property interface */ +mycms_error_desc +mycms_error_get_key_desc( + const uint32_t key +); + +bool +mycms_error_has_error( + const mycms_error error +); + +void +mycms_error_reset( + const mycms_error error +); + +bool +mycms_error_format_callback( + const mycms_error error, + void (*f)( + const mycms_error error, + const unsigned index, + const mycms_error_prm prms, + const unsigned prms_len, + void *d + ), + void *p +); + +bool +mycms_error_format_simple( + const mycms_error error, + uint32_t * const code, + char * const buf, + const size_t buf_size +); + +void +mycms_error_format( + const mycms_error error, + char * const buf, + const size_t buf_size +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/mycms/mycms-io.h b/include/mycms/mycms-io.h new file mode 100644 index 0000000..6c2e1a5 --- /dev/null +++ b/include/mycms/mycms-io.h @@ -0,0 +1,58 @@ +#ifndef __MYCMS_IO_H +#define __MYCMS_IO_H + +#include "mycms-context.h" + +struct mycms_io_s; +typedef struct mycms_io_s *mycms_io; +typedef void (*mycms_io_free_callback)( + const mycms_io io, + const void *p +); + +mycms_io +mycms_io_new( + const mycms_context context +); + +bool +mycms_io_construct( + const mycms_io io +); + +bool +mycms_io_destruct( + const mycms_io io +); + +mycms_context +mycms_io_get_context( + const mycms_io io +); + +bool +mycms_io_open_file( + const mycms_io io, + const char * const file, + const char * const mode +); + +bool +mycms_io_map_mem( + const mycms_io io, + const void *p, + const size_t s +); + +bool +mycms_io_open_mem( + const mycms_io io +); + +ssize_t +mycms_io_get_mem_ptr( + const mycms_io io, + char **p +); + +#endif diff --git a/include/mycms/mycms-list.h b/include/mycms/mycms-list.h new file mode 100644 index 0000000..5f9cbde --- /dev/null +++ b/include/mycms/mycms-list.h @@ -0,0 +1,12 @@ +#ifndef __MYCMS_LIST_H +#define __MYCMS_LIST_H + +#define MYCMS_LIST_DECLARE(name, type, element) \ +struct mycms_list_ ## name ## _s; \ +typedef struct mycms_list_ ## name ## _s *mycms_list_ ## name; \ +struct mycms_list_ ## name ## _s { \ + mycms_list_ ## name next; \ + type element; \ +}; + +#endif diff --git a/include/mycms/mycms-static.h b/include/mycms/mycms-static.h new file mode 100644 index 0000000..d6155fc --- /dev/null +++ b/include/mycms/mycms-static.h @@ -0,0 +1,24 @@ +#ifndef __MYCMS_STATIC_H +#define __MYCMS_STATIC_H + +#include "mycms-system.h" + +#ifdef __cplusplus +extern "C" { +#endif + +bool +mycms_static_init( + const mycms_system system +); + +bool +mycms_static_clean( + const mycms_system system +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/mycms/mycms-system-driver-core.h b/include/mycms/mycms-system-driver-core.h new file mode 100644 index 0000000..4c60893 --- /dev/null +++ b/include/mycms/mycms-system-driver-core.h @@ -0,0 +1,41 @@ +#ifndef __MYCMS_SYSTEM_DRIVER_CORE_H +#define __MYCMS_SYSTEM_DRIVER_CORE_H + +#ifdef _WIN32 +#include +#define RTLD_NOW 0 +#define RTLD_LOCAL 0 +#endif + +#include +#include +#include + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* MYCMS_SYSTEM_DRIVER_ID__ MSB_32bit(sha1(_)) */ +#define MYCMS_SYSTEM_DRIVER_ID_core_explicit_bzero 0xf6ac4e65 +#define MYCMS_SYSTEM_DRIVER_ID_core_free 0x4e483569 +#define MYCMS_SYSTEM_DRIVER_ID_core_realloc 0xc4a51b02 +#define MYCMS_SYSTEM_DRIVER_ID_core_dlclose 0xbb14c6ec +#define MYCMS_SYSTEM_DRIVER_ID_core_dlopen 0x1b328d93 +#define MYCMS_SYSTEM_DRIVER_ID_core_dlsym 0xe37d4adf + +#pragma GCC diagnostic ignored "-Wcast-function-type" +MYCMS_SYSTEM_DRIVER_FUNC(core, void, explicit_bzero, void * const s, size_t size) +MYCMS_SYSTEM_DRIVER_FUNC(core, void *, realloc, const char * const hint, void * const p, size_t size) +MYCMS_SYSTEM_DRIVER_FUNC(core, bool, free, const char * const hint, void * const p) +MYCMS_SYSTEM_DRIVER_FUNC(core, int, dlclose, void *handle) +MYCMS_SYSTEM_DRIVER_FUNC(core, void *, dlopen, const char *filename, int flags) +MYCMS_SYSTEM_DRIVER_FUNC(core, void *, dlsym, void *handle, const char *symbol) +#pragma GCC diagnostic pop + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/mycms/mycms-system.h b/include/mycms/mycms-system.h new file mode 100644 index 0000000..1f96d58 --- /dev/null +++ b/include/mycms/mycms-system.h @@ -0,0 +1,134 @@ +#ifndef __MYCMS_SYSTEM_H +#define __MYCMS_SYSTEM_H + +#include +#include + +#include "mycms-error.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#define __MYCMS_SYSTEM_DRIVER_FUNC_COMMON(group, name) \ + static inline mycms_system_driver_p_##group##_##name mycms_system_driver_##group##_##name (const mycms_system system) { \ + return (mycms_system_driver_p_##group##_##name)mycms_system_driver_find(system, MYCMS_SYSTEM_DRIVER_ID_##group##_##name); \ + } +#if defined(HAVE_C99_VARARGS_MACROS) +#define MYCMS_SYSTEM_DRIVER_FUNC(group, ret, name, ...) \ + typedef ret (*mycms_system_driver_p_##group##_##name)(const mycms_system system __VA_OPT__(,) __VA_ARGS__); \ + __MYCMS_SYSTEM_DRIVER_FUNC_COMMON(group, name) +#elif defined(HAVE_GCC_VARARGS_MACROS) +#define MYCMS_SYSTEM_DRIVER_FUNC(group, ret, name, ...) \ + typedef ret (*mycms_system_driver_p_##group##_##name)(const mycms_system system, ##__VA_ARGS__); \ + __MYCMS_SYSTEM_DRIVER_FUNC_COMMON(group, name) +#else +#error no available varargs macros method +#endif + +#define MYCMS_SYSTEM_CONTEXT_SIZE 4096 * 10 + +struct mycms_system_s; +typedef struct mycms_system_s *mycms_system; + +struct mycms_system_driver_entry_s { + unsigned id; + void (*f)(); +}; + +size_t +mycms_system_get_context_size(void); + +mycms_system +mycms_system_new(); + +bool +mycms_system_init( + const mycms_system system, + const size_t size +); + +bool +mycms_system_construct( + const mycms_system system +); + +bool +mycms_system_destruct( + const mycms_system system +); + +bool +mycms_system_clean( + const mycms_system system, + const size_t size +); + +bool +mycms_system_driver_register( + const mycms_system system, + const struct mycms_system_driver_entry_s * const entries +); + +void (*mycms_system_driver_find( + const mycms_system system, + const unsigned id +))(); + +const void * +mycms_system_get_userdata( + const mycms_system system +); + +bool +mycms_system_set_userdata( + const mycms_system system, + const void *userdata +); + +mycms_error +mycms_system_get_error( + const mycms_system system +); + +void +mycms_system_explicit_bzero( + const mycms_system system, + void * const p, + const size_t size +); + +void * +mycms_system_realloc( + const mycms_system system, + const char * const hint, + void * const p, + const size_t size +); + +bool +mycms_system_free( + const mycms_system system, + const char * const hint, + void * const p +); + +void * +mycms_system_zalloc( + const mycms_system system, + const char * const hint, + const size_t size +); + +char * +mycms_system_strdup( + const mycms_system system, + const char * const hint, + const char * const s +); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/mycms/mycms-util-getpass.h b/include/mycms/mycms-util-getpass.h new file mode 100644 index 0000000..48df190 --- /dev/null +++ b/include/mycms/mycms-util-getpass.h @@ -0,0 +1,19 @@ +#ifndef __MYCMS_GETPASS_H +#define __MYCMS_GETPASS_H + +#include "mycms-context.h" + +const char * +mycms_util_getpass_usage(void); + +bool +mycms_util_getpass( + const mycms_context context, + const char * const title, + const char * const prompt, + const char * const exp, + char * const pass, + const size_t size +); + +#endif diff --git a/include/mycms/mycms-variant.h b/include/mycms/mycms-variant.h new file mode 100644 index 0000000..aacb291 --- /dev/null +++ b/include/mycms/mycms-variant.h @@ -0,0 +1,36 @@ +#ifndef __MYCMS_VARIANT_H +#define __MYCMS_VARIANT_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum mycms_variant_type_e { + mycms_variant_type_none, + mycms_variant_type_u32, + mycms_variant_type_u64, + mycms_variant_type_str, + mycms_variant_type_blob, + __mycms_variant_type_end +} mycms_variant_type; + +typedef struct mycms_variant_s { + mycms_variant_type t; + union { + uint32_t u32; + uint64_t u64; + char str[1024]; + struct { + unsigned char *d[1024 - sizeof(size_t)]; + size_t s; + } blob[1]; + } d[1]; +} mycms_variant; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/include/mycms/mycms.h b/include/mycms/mycms.h new file mode 100644 index 0000000..58e19d1 --- /dev/null +++ b/include/mycms/mycms.h @@ -0,0 +1,124 @@ +#ifndef __MYCMS_H +#define __MYCMS_H + +#include + +#include "mycms-certificate.h" +#include "mycms-io.h" +#include "mycms-dict.h" +#include "mycms-context.h" + +struct mycms_signer_s { + mycms_blob cert; + mycms_blob keyid; + char *digest; +}; + +MYCMS_LIST_DECLARE(str, char *, str) +MYCMS_LIST_DECLARE(signer, struct mycms_signer_s, signer) + +struct __mycms_s; +typedef struct __mycms_s *mycms; + +mycms +mycms_new( + const mycms_context context +); + +bool +mycms_construct( + const mycms mycms +); + +bool +mycms_destruct( + const mycms mycms +); + +mycms_context +mycms_get_context( + const mycms mycms +); + +mycms_system +mycms_get_system( + const mycms mycms +); + +mycms_error +mycms_get_error( + const mycms mycms +); + +bool +mycms_sign( + const mycms mycms __attribute__((unused)), + const mycms_certificate certificate, + const mycms_list_str digests, + const mycms_dict keyopt, + const mycms_io cms_in, + const mycms_io cms_out, + const mycms_io data_in +); + +bool +mycms_verify_list_free( + const mycms mycms, + const mycms_list_signer l +); + +bool +mycms_verify_list( + const mycms mycms, + const mycms_io cms_in, + mycms_list_signer * const signers +); + +bool +mycms_verify( + const mycms mycms, + const mycms_io cms_in, + const mycms_io data_in, + const mycms_list_signer signers, + bool * const verified +); + +bool +mycms_encrypt( + const mycms mycms, + const char * const cipher_name, + const mycms_list_blob to, + const mycms_dict keyopt, + const mycms_io cms_out, + const mycms_io data_pt, + const mycms_io data_ct +); + +bool +mycms_encrypt_add( + const mycms mycms, + const mycms_certificate certificate, + const mycms_list_blob to, + const mycms_dict keyopt, + const mycms_io cms_in, + const mycms_io cms_out +); + +bool +mycms_encrypt_reset( + const mycms mycms, + const mycms_list_blob to, + const mycms_io cms_in, + const mycms_io cms_out +); + +bool +mycms_decrypt( + const mycms mycms, + const mycms_certificate certificate, + const mycms_io cms_in, + const mycms_io data_pt, + const mycms_io data_ct +); + +#endif diff --git a/m4/.keep b/m4/.keep new file mode 100644 index 0000000..e69de29 diff --git a/package.info.in b/package.info.in new file mode 100644 index 0000000..57bb37a --- /dev/null +++ b/package.info.in @@ -0,0 +1,3 @@ +PACKAGE_NAME="@PACKAGE_NAME@" +PACKAGE_VERSION="@PACKAGE_VERSION@" +PACKAGE_BUILD_ID="@PACKAGE_BUILD_ID@" diff --git a/packaging/Makefile.am b/packaging/Makefile.am new file mode 100644 index 0000000..145de63 --- /dev/null +++ b/packaging/Makefile.am @@ -0,0 +1,8 @@ +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in \ + $(NULL) + +SUBDIRS = \ + debian \ + windows-nsis \ + $(NULL) diff --git a/packaging/debian/.gitignore b/packaging/debian/.gitignore new file mode 100644 index 0000000..0bc38fd --- /dev/null +++ b/packaging/debian/.gitignore @@ -0,0 +1,9 @@ +*-stamp +*.substvars +.debhelper +autoreconf.* +files +libmycms-dev +libmycms1 +mycms +tmp diff --git a/packaging/debian/Makefile.am b/packaging/debian/Makefile.am new file mode 100644 index 0000000..8d857ea --- /dev/null +++ b/packaging/debian/Makefile.am @@ -0,0 +1,25 @@ +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in \ + $(NULL) + +EXTRA_DIST = \ + .gitignore \ + Makefile.am \ + changelog \ + compat \ + control \ + copyright \ + gbp.conf \ + libmycms-dev.dirs \ + libmycms-dev.install \ + libmycms1.install \ + libmycms1.symbols \ + mycms.install \ + not-installed \ + rules \ + source \ + source/format \ + upstream \ + upstream/metadata \ + watch \ + $(NULL) diff --git a/packaging/debian/changelog b/packaging/debian/changelog new file mode 100644 index 0000000..78f1ddd --- /dev/null +++ b/packaging/debian/changelog @@ -0,0 +1,5 @@ +mycms (0.1.0-build1) devel; urgency=low + + * Initial package + + -- Alon Bar-Lev Wed, 11 May 2022 00:00:00 +0000 diff --git a/packaging/debian/compat b/packaging/debian/compat new file mode 100644 index 0000000..f599e28 --- /dev/null +++ b/packaging/debian/compat @@ -0,0 +1 @@ +10 diff --git a/packaging/debian/control b/packaging/debian/control new file mode 100644 index 0000000..5a9fd51 --- /dev/null +++ b/packaging/debian/control @@ -0,0 +1,37 @@ +Source: mycms +Section: utils +Priority: optional +Maintainer: Alon Bar-Lev +Uploaders: Alon Bar-Lev +Rules-Requires-Root: no +Build-Depends: debhelper, + libssl-dev, + pkg-config +Standards-Version: 4.6.0.2 +Homepage: https://github.com/alonbl/mycms +Vcs-Git: https://github.com/alonbl/mycms.git +Vcs-Browser: https://github.com/alonbl/mycms.git + +Package: libmycms1 +Section: libs +Architecture: any +Multi-Arch: same +Pre-Depends: ${misc:Pre-Depends} +Depends: ${shlibs:Depends}, ${misc:Depends}, +Description: library for simple cms tools. + mycms is a simple cms tool. + +Package: libmycms-dev +Section: libdevel +Architecture: any +Multi-Arch: same +Depends: libmycms1 (= ${binary:Version}), ${misc:Depends} +Description: development files for simple cms tools. + mycms is a simple cms tool. + +Package: mycms +Architecture: any +Multi-Arch: foreign +Depends: ${shlibs:Depends}, ${misc:Depends} +Description: simple cms tools. + mycms is a simple cms tool. diff --git a/packaging/debian/copyright b/packaging/debian/copyright new file mode 100644 index 0000000..5177401 --- /dev/null +++ b/packaging/debian/copyright @@ -0,0 +1,36 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: mycms +Upstream-Contact: Alon Bar-Lev +Source: https://github.com/alonbl/mycms + +Files: * +Copyright: 2022, Alon Bar-Lev +License: BSD-3-clause + +License: BSD-3-clause + Copyright (c) , + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + 3. Neither the name of the copyright holder nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER AND CONTRIBUTORS "AS IS" + AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. diff --git a/packaging/debian/gbp.conf b/packaging/debian/gbp.conf new file mode 100644 index 0000000..e871394 --- /dev/null +++ b/packaging/debian/gbp.conf @@ -0,0 +1,3 @@ +[DEFAULT] +pristine-tar = True +upstream-vcs-tag = mycms-%(version)s diff --git a/packaging/debian/libmycms-dev.dirs b/packaging/debian/libmycms-dev.dirs new file mode 100644 index 0000000..d90d2b1 --- /dev/null +++ b/packaging/debian/libmycms-dev.dirs @@ -0,0 +1 @@ +usr/include/mycms diff --git a/packaging/debian/libmycms-dev.install b/packaging/debian/libmycms-dev.install new file mode 100644 index 0000000..ae36d89 --- /dev/null +++ b/packaging/debian/libmycms-dev.install @@ -0,0 +1,4 @@ +usr/include/mycms/*.h +usr/lib/*/lib*.a +usr/lib/*/lib*.so +usr/lib/*/pkgconfig/*.pc diff --git a/packaging/debian/libmycms1.install b/packaging/debian/libmycms1.install new file mode 100644 index 0000000..3ddde58 --- /dev/null +++ b/packaging/debian/libmycms1.install @@ -0,0 +1 @@ +usr/lib/*/lib*.so.* diff --git a/packaging/debian/libmycms1.symbols b/packaging/debian/libmycms1.symbols new file mode 100644 index 0000000..18d8f54 --- /dev/null +++ b/packaging/debian/libmycms1.symbols @@ -0,0 +1,84 @@ +libmycms-util.so.1 libmycms1 #MINVER# +* Build-Depends-Package: libmycms-dev + mycms_util_getpass@Base 0.1.0 + mycms_util_getpass_usage@Base 0.1.0 +libmycms.so.1 libmycms1 #MINVER# +* Build-Depends-Package: libmycms-dev + mycms_certificate_construct@Base 0.1.0 + mycms_certificate_destruct@Base 0.1.0 + mycms_certificate_driver_file_apply@Base 0.1.0 + mycms_certificate_driver_file_usage@Base 0.1.0 + mycms_certificate_driver_pkcs11_apply@Base 0.1.0 + mycms_certificate_driver_pkcs11_usage@Base 0.1.0 + mycms_certificate_get_context@Base 0.1.0 + mycms_certificate_get_driverdata@Base 0.1.0 + mycms_certificate_get_userdata@Base 0.1.0 + mycms_certificate_load@Base 0.1.0 + mycms_certificate_new@Base 0.1.0 + mycms_certificate_set_driver_load@Base 0.1.0 + mycms_certificate_set_driverdata@Base 0.1.0 + mycms_certificate_set_passphrase_callback@Base 0.1.0 + mycms_certificate_set_userdata@Base 0.1.0 + mycms_construct@Base 0.1.0 + mycms_context_construct@Base 0.1.0 + mycms_context_destruct@Base 0.1.0 + mycms_context_error_reset@Base 0.1.0 + mycms_context_get_error@Base 0.1.0 + mycms_context_get_system@Base 0.1.0 + mycms_context_get_user_context@Base 0.1.0 + mycms_context_new@Base 0.1.0 + mycms_context_set_user_context@Base 0.1.0 + mycms_decrypt@Base 0.1.0 + mycms_destruct@Base 0.1.0 + mycms_dict_construct@Base 0.1.0 + mycms_dict_destruct@Base 0.1.0 + mycms_dict_entries@Base 0.1.0 + mycms_dict_entry_clear@Base 0.1.0 + mycms_dict_entry_del@Base 0.1.0 + mycms_dict_entry_get@Base 0.1.0 + mycms_dict_entry_put@Base 0.1.0 + mycms_dict_get_context@Base 0.1.0 + mycms_dict_new@Base 0.1.0 + mycms_encrypt@Base 0.1.0 + mycms_encrypt_add@Base 0.1.0 + mycms_encrypt_reset@Base 0.1.0 + mycms_error_format@Base 0.1.0 + mycms_error_format_callback@Base 0.1.0 + mycms_error_format_simple@Base 0.1.0 + mycms_error_get_key_desc@Base 0.1.0 + mycms_error_has_error@Base 0.1.0 + mycms_error_reset@Base 0.1.0 + mycms_get_context@Base 0.1.0 + mycms_get_error@Base 0.1.0 + mycms_get_system@Base 0.1.0 + mycms_io_construct@Base 0.1.0 + mycms_io_destruct@Base 0.1.0 + mycms_io_get_context@Base 0.1.0 + mycms_io_get_mem_ptr@Base 0.1.0 + mycms_io_map_mem@Base 0.1.0 + mycms_io_new@Base 0.1.0 + mycms_io_open_file@Base 0.1.0 + mycms_io_open_mem@Base 0.1.0 + mycms_new@Base 0.1.0 + mycms_sign@Base 0.1.0 + mycms_static_clean@Base 0.1.0 + mycms_static_init@Base 0.1.0 + mycms_system_clean@Base 0.1.0 + mycms_system_construct@Base 0.1.0 + mycms_system_destruct@Base 0.1.0 + mycms_system_driver_find@Base 0.1.0 + mycms_system_driver_register@Base 0.1.0 + mycms_system_explicit_bzero@Base 0.1.0 + mycms_system_free@Base 0.1.0 + mycms_system_get_context_size@Base 0.1.0 + mycms_system_get_error@Base 0.1.0 + mycms_system_get_userdata@Base 0.1.0 + mycms_system_init@Base 0.1.0 + mycms_system_new@Base 0.1.0 + mycms_system_realloc@Base 0.1.0 + mycms_system_set_userdata@Base 0.1.0 + mycms_system_strdup@Base 0.1.0 + mycms_system_zalloc@Base 0.1.0 + mycms_verify@Base 0.1.0 + mycms_verify_list@Base 0.1.0 + mycms_verify_list_free@Base 0.1.0 diff --git a/packaging/debian/mycms.install b/packaging/debian/mycms.install new file mode 100644 index 0000000..1b80f78 --- /dev/null +++ b/packaging/debian/mycms.install @@ -0,0 +1 @@ +usr/bin/mycms-tool diff --git a/packaging/debian/not-installed b/packaging/debian/not-installed new file mode 100644 index 0000000..1c93d96 --- /dev/null +++ b/packaging/debian/not-installed @@ -0,0 +1,2 @@ +usr/lib/*/*.la +usr/share/doc/mycms/README.md diff --git a/packaging/debian/rules b/packaging/debian/rules new file mode 100755 index 0000000..2244ef0 --- /dev/null +++ b/packaging/debian/rules @@ -0,0 +1,23 @@ +#!/usr/bin/make -f + +include /usr/share/dpkg/pkg-info.mk + +%: + dh $@ + +override_dh_auto_configure: + dh_auto_configure -- \ + --enable-certificate-driver-file \ + --enable-certificate-driver-pkcs11 \ + --enable-cms-decrypt \ + --enable-cms-encrypt \ + --enable-cms-sign \ + --enable-cms-verify \ + --enable-io-driver-file \ + --enable-openssl-err-strings \ + --enable-pinentry \ + --enable-tool \ + --with-build-id="${DEB_VERSION}" + +override_dh_installdocs: + dh_installdocs -A README.md diff --git a/packaging/debian/source/format b/packaging/debian/source/format new file mode 100644 index 0000000..163aaf8 --- /dev/null +++ b/packaging/debian/source/format @@ -0,0 +1 @@ +3.0 (quilt) diff --git a/packaging/debian/upstream/metadata b/packaging/debian/upstream/metadata new file mode 100644 index 0000000..151c866 --- /dev/null +++ b/packaging/debian/upstream/metadata @@ -0,0 +1,4 @@ +Bug-Database: https://github.com/alonbl/mycms/issues +Bug-Submit: https://github.com/alonbl/mycms/issues/new +Repository: https://github.com/alonbl/mycms.git +Repository-Browse: https://github.com/alonbl/mycms diff --git a/packaging/debian/watch b/packaging/debian/watch new file mode 100644 index 0000000..85f8f35 --- /dev/null +++ b/packaging/debian/watch @@ -0,0 +1,3 @@ +version=4 + +https://github.com/alonbl/mycms/releases/latest (?:.*/)?mycms-(\d[\d\.]*)\.tar\.bz2 diff --git a/packaging/windows-nsis/Makefile.am b/packaging/windows-nsis/Makefile.am new file mode 100644 index 0000000..6c3e644 --- /dev/null +++ b/packaging/windows-nsis/Makefile.am @@ -0,0 +1,10 @@ +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in \ + $(NULL) + +EXTRA_DIST = \ + build \ + icon.ico \ + install-whirl.bmp \ + mycms.nsi \ + $(NULL) diff --git a/packaging/windows-nsis/build b/packaging/windows-nsis/build new file mode 100755 index 0000000..d77b7af --- /dev/null +++ b/packaging/windows-nsis/build @@ -0,0 +1,31 @@ +#!/bin/sh + +die() { + local m="$1" + echo "FATAL: ${m}" >&2 + exit 1 +} + +dospath() { + local p="$1" + realpath "${p}" | sed 's#/#\\#g' +} + +srcdir="$(dirname "$0")" + +MAKENSIS="${MAKENSIS:-makensis}" +DESTDIR="${DESTDIR:-destdir}" +OUTPUTDIR="${OUTPUTDIR:-.}" + +. "${DESTDIR}/package.info" + +WITH_CRYPTO="openssl" + +exec "${MAKENSIS}" \ + -DPACKAGE_NAME="${PACKAGE_NAME}" \ + -DPACKAGE_VERSION="${PACKAGE_VERSION}" \ + -DPACKAGE_BUILD_ID="${PACKAGE_BUILD_ID}" \ + -DDESTDIR="$(dospath "${DESTDIR}")" \ + -DWITH_CRYPTO="${WITH_CRYPTO}" \ + -DOUTPUT="$(dospath "${OUTPUTDIR}/${PACKAGE_NAME}-${PACKAGE_VERSION}-${WITH_CRYPTO}${EXTRA_NAME}-setup.exe")" \ + "${srcdir}/mycms.nsi" || die "makensis" diff --git a/packaging/windows-nsis/icon.ico b/packaging/windows-nsis/icon.ico new file mode 100644 index 0000000..3d26b0e Binary files /dev/null and b/packaging/windows-nsis/icon.ico differ diff --git a/packaging/windows-nsis/install-whirl.bmp b/packaging/windows-nsis/install-whirl.bmp new file mode 100644 index 0000000..94eb851 Binary files /dev/null and b/packaging/windows-nsis/install-whirl.bmp differ diff --git a/packaging/windows-nsis/mycms.nsi b/packaging/windows-nsis/mycms.nsi new file mode 100644 index 0000000..9f374f0 --- /dev/null +++ b/packaging/windows-nsis/mycms.nsi @@ -0,0 +1,277 @@ +SetCompressor /SOLID lzma +Unicode True + +!define MULTIUSER_EXECUTIONLEVEL Highest +!define MULTIUSER_MUI +!define MULTIUSER_INSTALLMODE_COMMANDLINE +!include "MultiUser.nsh" +!include "MUI2.nsh" + +!include "x64.nsh" + +; Read the command-line parameters +!insertmacro GetParameters +!insertmacro GetOptions + +;-------------------------------- +;Configuration + +;General + +; Package name as shown in the installer GUI +Name "mycms ${PACKAGE_NAME}-${PACKAGE_VERSION} (${PACKAGE_BUILD_ID})" + +InstallDir "$PROGRAMFILES64\mycms" + +; Installer filename +OutFile "${OUTPUT}" + +ShowInstDetails show +ShowUninstDetails show + +;Remember install folder +InstallDirRegKey HKLM "SOFTWARE\${PACKAGE_NAME}" "" + +;====================================================== +; Version Information + +VIProductVersion "1.0.0.0" +VIAddVersionKey "ProductName" "${PACKAGE_NAME}-Installer" +VIAddVersionKey "Comments" "" +VIAddVersionKey "CompanyName" "mycms" +VIAddVersionKey "LegalTrademarks" "mycms" +VIAddVersionKey "LegalCopyright" "mycms" +VIAddVersionKey "FileDescription" "${PACKAGE_NAME}-Installer" +VIAddVersionKey "FileVersion" "1.0.0" + +;-------------------------------- +;Modern UI Configuration + +; Compile-time constants which we'll need during install +!define MUI_WELCOMEPAGE_TEXT "This wizard will guide you through the installation of mycms.$\r$\n$\r$\n" + +!define MUI_COMPONENTSPAGE_TEXT_TOP "Select the components to install/upgrade. Stop any mycms processes or the mycms service if it is running. All DLLs are installed locally." + +!define MUI_COMPONENTSPAGE_SMALLDESC + +!define MUI_ABORTWARNING +!define MUI_ICON "icon.ico" +!define MUI_UNICON "icon.ico" +!define MUI_HEADERIMAGE +!define MUI_HEADERIMAGE_BITMAP "install-whirl.bmp" +!define MUI_UNFINISHPAGE_NOAUTOCLOSE + +!insertmacro MUI_PAGE_WELCOME +!insertmacro MUI_PAGE_LICENSE "${DESTDIR}\share\doc\mycms\COPYING" +!insertmacro MULTIUSER_PAGE_INSTALLMODE +!insertmacro MUI_PAGE_COMPONENTS +!insertmacro MUI_PAGE_DIRECTORY +!insertmacro MUI_PAGE_INSTFILES +!insertmacro MUI_PAGE_FINISH + +!insertmacro MUI_UNPAGE_CONFIRM +!insertmacro MUI_UNPAGE_INSTFILES +!insertmacro MUI_UNPAGE_FINISH + +;-------------------------------- +;Languages + +!insertmacro MUI_LANGUAGE "English" + +;-------------------------------- +;Language Strings + +!if ${WITH_CRYPTO} == "openssl" +LangString DESC_SecOpenSSLLibraries ${LANG_ENGLISH} "Install OpenSSL libraries" +!endif +LangString DESC_SecMycmsLibraries ${LANG_ENGLISH} "Install mycms libraries" +LangString DESC_SecMycmsTools ${LANG_ENGLISH} "Install mycms tools" +LangString DESC_SecMycmsSDK ${LANG_ENGLISH} "Install mycms SDK" + +;-------------------------------- +;Reserve Files + +;Things that need to be extracted on first (keep these lines before any File command!) +;Only useful for BZIP2 compression + +ReserveFile "install-whirl.bmp" + +;-------------------------------- +;Macros + +!macro SelectByParameter SECT PARAMETER DEFAULT + ${GetOptions} $R0 "/${PARAMETER}=" $0 + ${If} ${DEFAULT} == 0 + ${If} $0 == 1 + !insertmacro SelectSection ${SECT} + ${EndIf} + ${Else} + ${If} $0 != 0 + !insertmacro SelectSection ${SECT} + ${EndIf} + ${EndIf} +!macroend + +;-------------------- +;Pre-install section + +!if ${WITH_CRYPTO} == "openssl" +Section "openssl libraries" SecOpenSSLLibraries + + SetOverwrite on + + SetOutPath "$INSTDIR\bin" + File "${DESTDIR}\bin\libcrypto-*-x64.dll" + +SectionEnd +!endif + +Section "mycms libraries" SecMycmsLibraries + + SectionIn RO ; section cannot be unchecked by user + SetOverwrite on + + SetOutPath "$INSTDIR\bin" + File "${DESTDIR}\bin\libmycms-1.dll" + File "${DESTDIR}\bin\libmycms-util-1.dll" + + SetOutPath "$INSTDIR\doc" + File "${DESTDIR}\share\doc\mycms\README.md" + +SectionEnd + +Section /o "mycms Tools" SecMycmsTools + + SetOverwrite on + + SetOutPath "$INSTDIR\bin" + File "${DESTDIR}\bin\mycms-tool.exe" + +SectionEnd + +Section /o "mycms SDK" SecMycmsSDK + + SetOverwrite on + + SetOutPath "$INSTDIR\include\mycms" + File "${DESTDIR}\include\mycms\*" + + SetOutPath "$INSTDIR\lib" + File "${DESTDIR}\lib\libmycms-1.dll.def" + File "${DESTDIR}\lib\libmycms-util-1.dll.def" + +SectionEnd + +;-------------------------------- +;Installer Sections + +Function .onInit + ${GetParameters} $R0 + ClearErrors + + SetRegView 64 + +!if ${WITH_CRYPTO} == "openssl" + !insertmacro SelectByParameter ${SecOpenSSLLibraries} SELECT_OPENVPN_LIBRARIES 1 +!endif + !insertmacro SelectByParameter ${SecMycmsLibraries} SELECT_MYCMS_LIBRARIES 1 + !insertmacro SelectByParameter ${SecMycmsTools} SELECT_MYCMS_TOOLS 1 + !insertmacro SelectByParameter ${SecMycmsSDK} SELECT_MYCMS_SDK 0 + + !insertmacro MULTIUSER_INIT + SetShellVarContext all + +FunctionEnd + +;-------------------------------- +;Dependencies + +Function .onSelChange + ${If} ${SectionIsSelected} ${SecMycmsTools} + !insertmacro SelectSection ${SecMycmsLibraries} + ${EndIf} + ${If} ${SectionIsSelected} ${SecMycmsSDK} + !insertmacro SelectSection ${SecMycmsLibraries} + ${EndIf} +FunctionEnd + +;-------------------- +;Post-install section + +Section -post + + SetOverwrite on + + SetOutPath "$INSTDIR" + File "icon.ico" + + SetOutPath "$INSTDIR\doc" + File "${DESTDIR}\share\doc\mycms\COPYING" + + ; Store install folder in registry + WriteRegStr HKLM "SOFTWARE\${PACKAGE_NAME}" "" "$INSTDIR" + + ; Create uninstaller + WriteUninstaller "$INSTDIR\Uninstall.exe" + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PACKAGE_NAME}" "DisplayName" "${PACKAGE_NAME}-${PACKAGE_VERSION} (${PACKAGE_BUILD_ID})" + WriteRegExpandStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PACKAGE_NAME}" "UninstallString" "$INSTDIR\Uninstall.exe" + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PACKAGE_NAME}" "DisplayIcon" "$INSTDIR\icon.ico" + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PACKAGE_NAME}" "DisplayVersion" "${PACKAGE_VERSION} (${PACKAGE_BUILD_ID})}" + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PACKAGE_NAME}" "HelpLink" "https://github.com/alonbl/mycms" + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PACKAGE_NAME}" "InstallLocation" "$INSTDIR\" + WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PACKAGE_NAME}" "Language" 1033 + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PACKAGE_NAME}" "Publisher" "mycms" + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PACKAGE_NAME}" "UninstallString" "$INSTDIR\Uninstall.exe" + WriteRegStr HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PACKAGE_NAME}" "URLInfoAbout" "https://github.com/alonbl/mycms" + + ${GetSize} "$INSTDIR" "/S=0K" $0 $1 $2 + IntFmt $0 "0x%08X" $0 + WriteRegDWORD HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PACKAGE_NAME}" "EstimatedSize" "$0" + +SectionEnd + +;-------------------------------- +;Descriptions + +!insertmacro MUI_FUNCTION_DESCRIPTION_BEGIN +!if ${WITH_CRYPTO} == "openssl" + !insertmacro MUI_DESCRIPTION_TEXT ${SecOpenSSLLibraries} $(DESC_SecOpenSSLLibraries) +!endif + !insertmacro MUI_DESCRIPTION_TEXT ${SecMycmsLibraries} $(DESC_SecMycmsLibraries) + !insertmacro MUI_DESCRIPTION_TEXT ${SecMycmsTools} $(DESC_SecMycmsTools) + !insertmacro MUI_DESCRIPTION_TEXT ${SecMycmsSDK} $(DESC_SecMycmsSDK) +!insertmacro MUI_FUNCTION_DESCRIPTION_END + +;-------------------------------- +;Uninstaller Section + +Function un.onInit + + ClearErrors + !insertmacro MULTIUSER_UNINIT + SetShellVarContext all + SetRegView 64 + +FunctionEnd + +Section "Uninstall" + + Delete "$INSTDIR\Uninstall.exe" + Delete "$INSTDIR\bin\libcrypto-*-x64.dll" + Delete "$INSTDIR\bin\libmycms-1.dll" + Delete "$INSTDIR\bin\libmycms-util-1.dll" + Delete "$INSTDIR\bin\mycms-tool.exe" + Delete "$INSTDIR\doc\COPYING" + Delete "$INSTDIR\doc\README.md" + Delete "$INSTDIR\icon.ico" + + RMDir "$INSTDIR\bin" + RMDir "$INSTDIR\doc" + RMDir /r "$INSTDIR\include" + RMDir /r "$INSTDIR\lib" + + RMDir "$INSTDIR" + + DeleteRegKey HKLM "SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\${PACKAGE_NAME}" + +SectionEnd diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..e2f55e5 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,9 @@ +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in \ + $(NULL) + +SUBDIRS = \ + libmycms \ + libmycms-util \ + mycms-tool \ + $(NULL) diff --git a/src/libmycms-util/Makefile.am b/src/libmycms-util/Makefile.am new file mode 100644 index 0000000..6355356 --- /dev/null +++ b/src/libmycms-util/Makefile.am @@ -0,0 +1,83 @@ +include $(top_srcdir)/build/ltrc.inc + +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in \ + $(NULL) +DISTCLEANFILES = \ + libmycms-util.pc \ + $(NULL) +CLEANFILES = \ + mycms-util-all.exports \ + mycms-util-all.exports.tmp \ + $(NULL) + +MYCMS_UTIL_COMMON_EXPORTS = \ + mycms-util-getpass.exports \ + $(NULL) +MYCMS_UTIL_SELECTIVE_EXPORTS = \ + $(NULL) + +dist_noinst_DATA = \ + $(MYCMS_UTIL_COMMON_EXPORTS) \ + $(MYCMS_UTIL_SELECTIVE_EXPORTS) \ + $(NULL) + +pkgconfig_DATA = libmycms-util.pc +noinst_LTLIBRARIES = libmycms-util-internal.la +lib_LTLIBRARIES = libmycms-util.la + +AM_CPPFLAGS = \ + -I$(top_srcdir)/include \ + $(NULL) + +libmycms_util_internal_la_SOURCES = \ + mycms-util-getpass.c \ + $(NULL) +nodist_libmycms_util_internal_la_SOURCES = \ + $(NULL) +if ENABLE_PINENTRY +libmycms_util_internal_la_SOURCES += \ + mycms-util-pinentry.c \ + mycms-util-pinentry.h \ + $(NULL) +endif +libmycms_util_internal_la_LIBADD = \ + $(builddir)/../libmycms/libmycms.la \ + $(NULL) + +libmycms_util_la_DEPENDENCIES = \ + libmycms-util-internal.la \ + mycms-util-all.exports \ + $(NULL) +if BUILD_WINDOWS +nodist_libmycms_util_la_SOURCES = \ + versioninfo.rc \ + $(NULL) +endif +libmycms_util_la_LIBADD = \ + libmycms-util-internal.la \ + $(NULL) +libmycms_util_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -version-info @LIBMYCMS_LT_CURRENT@:@LIBMYCMS_LT_REVISION@:@LIBMYCMS_LT_AGE@ \ + -export-symbols "mycms-util-all.exports" \ + -no-undefined \ + $(NULL) + +mycms-util-all.exports: \ + $(MYCMS_UTIL_COMMON_EXPORTS) \ + $(MYCMS_UTIL_SELECTIVE_EXPORTS) \ + $(builddir)/Makefile \ + $(top_builddir)/config.h \ + $(NULL) + rm -f mycms-util-all.exports.tmp + for f in $(MYCMS_UTIL_COMMON_EXPORTS); do \ + cat "$(srcdir)/$$f" >> mycms-util-all.exports.tmp; \ + done + mv mycms-util-all.exports.tmp mycms-util-all.exports + +if BUILD_WINDOWS +mylibdir=$(libdir) +mylib_DATA=.libs/libmycms-util-@LIBMYCMS_LT_OLDEST@.dll.def +.libs/libmycms-util-@LIBMYCMS_LT_OLDEST@.dll.def: libmycms-util.la +endif diff --git a/src/libmycms-util/libmycms-util.pc.in b/src/libmycms-util/libmycms-util.pc.in new file mode 100644 index 0000000..a399cf9 --- /dev/null +++ b/src/libmycms-util/libmycms-util.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: mycms +Description: mycms +Version: @PACKAGE_VERSION@ +Requires: mycms = @PACKAGE_VERSION@ +Cflags: -I${includedir} +Libs: @LIBS@ -L${libdir} -lmycms-util diff --git a/src/libmycms-util/mycms-util-getpass.c b/src/libmycms-util/mycms-util-getpass.c new file mode 100644 index 0000000..6232a9f --- /dev/null +++ b/src/libmycms-util/mycms-util-getpass.c @@ -0,0 +1,156 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#ifndef BUILD_WINDOWS +#include +#endif + +#include + +#include "mycms-util-pinentry.h" + +static +void +__chop(const char *s) { + if (s != NULL) { + char *p; + if ((p = strchr(s, '\n')) != NULL) { + *p = '\0'; + } + if ((p = strchr(s, '\r')) != NULL) { + *p = '\0'; + } + } +} + +const char * +mycms_util_getpass_usage(void) { + return ( + "PASSPHRASE EXPRESSION ATTRIBUTES\n" + "pass=string: read passphrase from string\n" + "env=key: read the passphrase from environment\n" + "file=name: read the passphrase from file\n" +#ifndef BUILD_WINDOWS + "fd=n: read the passphrase from file descriptor\n" +#endif +#ifdef ENABLE_PINENTRY + "pinentry=/path/to/program: read the passphrase from gpg pinentry\n" +#endif + "" + ); +} + +bool +mycms_util_getpass( + const mycms_context context, + const char * const title +#ifndef ENABLE_PINENTRY + __attribute__((unused)) +#endif + , + const char * const prompt +#ifndef ENABLE_PINENTRY + __attribute__((unused)) +#endif + , + const char * const exp, + char * const pass, + const size_t size +) { + static const char PASS_PASS[] = "pass="; + static const char PASS_ENV[] = "env="; + static const char PASS_FILE[] = "file="; +#ifndef BUILD_WINDOWS + static const char PASS_FD[] = "fd="; +#endif +#ifdef ENABLE_PINENTRY + static const char PASS_PINENTRY[] = "pinentry="; +#endif + bool ret = false; + + if (pass == NULL) { + goto cleanup; + } + + if (exp == NULL) { + *pass = '\0'; + ret = true; + } else if (!strncmp(exp, PASS_PASS, sizeof(PASS_PASS)-1)) { + const char *p = exp + strlen(PASS_PASS); + if (strlen(p) >= size) { + goto cleanup; + } + strcpy(pass, p); + ret = true; + } else if (!strncmp(exp, PASS_ENV, sizeof(PASS_ENV)-1)) { + const char *p = exp + strlen(PASS_ENV); + char *x = getenv(p); + if (x == NULL || strlen(x) >= size) { + goto cleanup; + } + strcpy(pass, x); + ret = true; + } else if (!strncmp(exp, PASS_FILE, sizeof(PASS_FILE)-1)) { + const char *p = exp + strlen(PASS_FILE); + FILE *fp; + + if ((fp = fopen(p, "r")) != NULL) { + char *x = fgets(pass, size, fp); + fclose(fp); + if (x == NULL) { + goto cleanup; + } + pass[size-1] = '\0'; + __chop(pass); + } + ret = true; +#ifndef BUILD_WINDOWS + } else if (!strncmp(exp, PASS_FD, sizeof(PASS_FD)-1)) { + const char *p = exp + strlen(PASS_FD); + int fd = atoi(p); + ssize_t s; + + if ((s = read(fd, pass, size - 1)) == -1) { + goto cleanup; + } + + pass[s] = '\0'; + __chop(pass); + ret = true; +#endif +#ifdef ENABLE_PINENTRY + } else if (!strncmp(exp, PASS_PINENTRY, sizeof(PASS_PINENTRY)-1)) { + const char *p = exp + strlen(PASS_PINENTRY); + _mycms_pinentry pinentry = NULL; + + if ((pinentry = _mycms_util_pinentry_new(context)) == NULL) { + goto cleanup1; + } + + if (!_mycms_util_pinentry_construct(pinentry, p)) { + goto cleanup1; + } + + if (!_mycms_util_pinentry_exec(pinentry, title, prompt, pass, size)) { + goto cleanup1; + } + + ret = true; + +cleanup1: + _mycms_util_pinentry_destruct(pinentry); + +#endif + } else { + goto cleanup; + } + +cleanup: + + return ret; +} diff --git a/src/libmycms-util/mycms-util-getpass.exports b/src/libmycms-util/mycms-util-getpass.exports new file mode 100644 index 0000000..423be0b --- /dev/null +++ b/src/libmycms-util/mycms-util-getpass.exports @@ -0,0 +1,2 @@ +mycms_util_getpass +mycms_util_getpass_usage diff --git a/src/libmycms-util/mycms-util-pinentry.c b/src/libmycms-util/mycms-util-pinentry.c new file mode 100644 index 0000000..8c7f965 --- /dev/null +++ b/src/libmycms-util/mycms-util-pinentry.c @@ -0,0 +1,742 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef BUILD_WINDOWS +#include +#else +#include +#include +#include +#include + +#ifndef __NR_pidfd_open +#define __NR_pidfd_open 434 +#endif + +#endif + +#include +#include +#include +#include + +#include "mycms-util-pinentry.h" + +struct _mycms_util_pinentry_s { + mycms_context context; +#ifdef BUILD_WINDOWS + HANDLE channel; + HANDLE process; +#else + int channel; + pid_t process; +#endif + int dummy; +}; + +static const struct _mycms_util_pinentry_s __MYCMS_ENTRY_INIT = { + NULL, +#ifdef BUILD_WINDOWS + INVALID_HANDLE_VALUE, + INVALID_HANDLE_VALUE, +#else + -1, + -1, +#endif + 0 +}; + +#ifndef BUILD_WINDOWS +extern char **environ; + +static +inline +int +pidfd_open( + pid_t pid, + unsigned int flags +) { + return syscall(__NR_pidfd_open, pid, flags); +} +#endif + +#ifdef BUILD_WINDOWS + +static +bool +__pinentry_native_exec( + const _mycms_pinentry pinentry, + const char * const prog +) { + mycms_system system = NULL; + STARTUPINFOA startinfo; + PROCESS_INFORMATION procinfo; + OVERLAPPED overlapped; + HANDLE h = INVALID_HANDLE_VALUE; + char name_unique[1024]; + bool ret = false; + + if ((system = mycms_context_get_system(pinentry->context)) == NULL) { + goto cleanup; + } + + mycms_system_explicit_bzero(system, &startinfo, sizeof(startinfo)); + startinfo.hStdInput = startinfo.hStdOutput = startinfo.hStdError = INVALID_HANDLE_VALUE; + mycms_system_explicit_bzero(system, &procinfo, sizeof(procinfo)); + procinfo.hProcess = INVALID_HANDLE_VALUE; + mycms_system_explicit_bzero(system, &overlapped, sizeof(overlapped)); + overlapped.hEvent = CreateEventA(NULL, TRUE, FALSE, NULL); + + snprintf( + name_unique, + sizeof(name_unique), + "\\\\.\\pipe\\mycms-%08lx-%08lx", + GetCurrentProcessId(), + GetCurrentThreadId() + ); + + if ((pinentry->channel = CreateNamedPipeA( + name_unique, + PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, + PIPE_TYPE_BYTE, + PIPE_UNLIMITED_INSTANCES, + 0, + 0, + INFINITE, + NULL + )) == INVALID_HANDLE_VALUE) { + goto cleanup; + } + + if (!ConnectNamedPipe(pinentry->channel, &overlapped)) { + if (GetLastError() != ERROR_IO_PENDING) { + goto cleanup; + } + } + + if ((h = CreateFileA( + name_unique, + GENERIC_READ | GENERIC_WRITE, + 0, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL, + NULL + )) == INVALID_HANDLE_VALUE) { + goto cleanup; + } + + + { + DWORD dw; + if (!GetOverlappedResult( + pinentry->channel, + &overlapped, + &dw, + TRUE)) { + goto cleanup; + } + } + + startinfo.cb = sizeof(startinfo); + startinfo.dwFlags = STARTF_USESTDHANDLES; + if (!DuplicateHandle( + GetCurrentProcess(), + h, + GetCurrentProcess(), + &startinfo.hStdInput, + 0, + TRUE, + DUPLICATE_SAME_ACCESS + )) { + goto cleanup; + } + if (!DuplicateHandle( + GetCurrentProcess(), + h, + GetCurrentProcess(), + &startinfo.hStdOutput, + 0, + TRUE, + DUPLICATE_SAME_ACCESS + )) { + goto cleanup; + } + if (!DuplicateHandle( + GetCurrentProcess(), + GetStdHandle(STD_ERROR_HANDLE), + GetCurrentProcess(), + &startinfo.hStdError, + 0, + TRUE, + DUPLICATE_SAME_ACCESS + )) { + goto cleanup; + } + + if (!CreateProcessA( + prog, + NULL, + NULL, + NULL, + TRUE, + 0, + NULL, + NULL, + &startinfo, + &procinfo + )) { + goto cleanup; + } + + pinentry->process = procinfo.hProcess; + procinfo.hProcess = INVALID_HANDLE_VALUE; + + ret = true; + +cleanup: + + if (h != INVALID_HANDLE_VALUE) { + CloseHandle(h); + h = INVALID_HANDLE_VALUE; + } + + if (startinfo.hStdInput != INVALID_HANDLE_VALUE) { + CloseHandle(startinfo.hStdInput); + startinfo.hStdInput = INVALID_HANDLE_VALUE; + } + + if (startinfo.hStdOutput != INVALID_HANDLE_VALUE) { + CloseHandle(startinfo.hStdOutput); + startinfo.hStdOutput = INVALID_HANDLE_VALUE; + } + + if (startinfo.hStdError != INVALID_HANDLE_VALUE) { + CloseHandle(startinfo.hStdError); + startinfo.hStdError = INVALID_HANDLE_VALUE; + } + + return ret; +} + +static +bool +__pinentry_native_close( + const _mycms_pinentry pinentry +) { + mycms_system system = NULL; + bool ret = false; + + if ((system = mycms_context_get_system(pinentry->context)) == NULL) { + goto cleanup; + } + + if (pinentry->channel != INVALID_HANDLE_VALUE) { + CloseHandle(pinentry->channel); + pinentry->channel = INVALID_HANDLE_VALUE; + } + + if (pinentry->process != INVALID_HANDLE_VALUE) { + + if (WaitForSingleObject(pinentry->process, 5000) == WAIT_OBJECT_0) { + TerminateProcess(pinentry->process, 1); + } + + CloseHandle(pinentry->process); + pinentry->process = INVALID_HANDLE_VALUE; + } + + ret = true; + +cleanup: + + return ret; +} + +static +ssize_t +__pinentry_native_read( + const _mycms_pinentry pinentry, + void * const p, + size_t s +) { + mycms_system system = NULL; + DWORD r; + + if ((system = mycms_context_get_system(pinentry->context)) == NULL) { + return -1; + } + + if (ReadFile(pinentry->channel, p, s, &r, NULL)) { + return r; + } + return -1; +} + +static +ssize_t +__pinentry_native_write( + const _mycms_pinentry pinentry, + void * const p, + size_t s +) { + mycms_system system = NULL; + DWORD r; + + if ((system = mycms_context_get_system(pinentry->context)) == NULL) { + return -1; + } + + if (WriteFile(pinentry->channel, p, s, &r, NULL)) { + return r; + } + return -1; +} + +#else + +#include +#include +#include + +static +bool +__pinentry_native_exec( + const _mycms_pinentry pinentry, + const char * const prog +) { + char tty[1024]; + const char * const args[] = { + prog, + "--ttyname", + tty, + NULL + }; + int sockets[2] = {-1, -1}; + bool ret = false; + pid_t child; + + if (ttyname_r(0, tty, sizeof(tty)) != 0) { + tty[0] = '\0'; + } + + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) < 0) { + goto cleanup; + } + + if ((child = fork()) == -1) { + goto cleanup; + } + + if (child == 0) { + struct rlimit r; + unsigned long i; + + close(sockets[0]); + + if (dup2(sockets[1], 0) == -1) { + goto child_cleanup; + } + if (dup2(sockets[1], 1) == -1) { + goto child_cleanup; + } + + if (getrlimit(RLIMIT_NOFILE, &r) == -1) { + goto child_cleanup; + } + for (i = 4;i < r.rlim_cur;i++) { + close(i); + } + + if (execve( + prog, + (char **)args, + environ + ) == -1) { + goto child_cleanup; + } + + child_cleanup: + + _exit(1); + } + + pinentry->channel = sockets[0]; + sockets[0] = -1; + pinentry->process = child; + + ret = true; + +cleanup: + + if (sockets[0] != -1) { + close(sockets[0]); + sockets[0] = -1; + } + + if (sockets[1] != -1) { + close(sockets[1]); + sockets[1] = -1; + } + + return ret; +} + +static +bool +__pinentry_native_close( + const _mycms_pinentry pinentry +) { + if (pinentry->channel != -1) { + close(pinentry->channel); + pinentry->channel = -1; + } + + if (pinentry->process != -1) { + int fd; + if ((fd = pidfd_open(pinentry->process, 0)) == -1) { + if (errno == ENOSYS) { + kill(pinentry->process, SIGKILL); + waitpid(pinentry->process, NULL, 0); + } + } else { + struct pollfd pfd = {fd, POLLIN, 0}; + int r; + while ( + (r = poll(&pfd, 1, 5000)) == -1 && + errno == EINTR + ); + if (r == 0) { + kill(pinentry->process, SIGKILL); + } + waitpid(pinentry->process, NULL, 0); + close(fd); + } + + pinentry->process = -1; + } + + return true; +} + +static +ssize_t +__pinentry_native_read( + const _mycms_pinentry pinentry, + void * const p, + size_t s +) { + ssize_t r = -1; + + while (1) { + if ((r = read(pinentry->channel, p, s)) < 0) { + int e = errno; + if (e != EAGAIN && e != EINTR) { + break; + } + } else { + break; + } + } + + return r; +} + +static +ssize_t +__pinentry_native_write( + const _mycms_pinentry pinentry, + void * const p, + size_t s +) { + ssize_t r = -1; + + while (1) { + if ((r = write(pinentry->channel, p, s)) < 0) { + int e = errno; + if (e != EAGAIN && e != EINTR) { + break; + } + } else { + break; + } + } + + return r; +} + +#endif + +static +bool +__pinentry_readline( + const _mycms_pinentry pinentry, + char * const line, + const size_t size +) { + char *p = line; + size_t s = size; + ssize_t r; + bool ret = false; + + while (s > 0) { + if ((r = __pinentry_native_read(pinentry, p, sizeof(*p))) < 0) { + goto cleanup; + } else if (r == 0) { + goto cleanup; + } + + s--; + if (*p == '\n') { + *p = '\0'; + break; + } + p++; + } + + if (s == 0) { + goto cleanup; + } + + ret = true; + +cleanup: + + return ret; +} + +static +bool +__pinentry_read_ok( + const _mycms_pinentry pinentry +) { + char buffer[1024]; + bool ret = false; + + if (!__pinentry_readline(pinentry, buffer, sizeof(buffer))) { + goto cleanup; + } + + if (strncmp(buffer, "OK", 2)) { + goto cleanup; + } + + ret = true; + +cleanup: + + return ret; +} + +static +bool +__pinentry_read_data( + const _mycms_pinentry pinentry, + char * const buffer, + const size_t size +) { + char b[1024]; + bool ret = false; + + if (!__pinentry_readline(pinentry, b, sizeof(b))) { + goto cleanup; + } + + if (strncmp(b, "D ", 2)) { + goto cleanup; + } + + if (strlen(b) - 2 >= size) { + goto cleanup; + } + + strcpy(buffer, b+2); + + ret = true; + +cleanup: + + return ret; +} + +static +bool +__pinentry_printf( + const _mycms_pinentry pinentry, + const char *format, + ... +) __attribute__ ((format (printf, 2, 3))); + +static +bool +__pinentry_printf( + const _mycms_pinentry pinentry, + const char *format, + ... +) { + va_list args; + char buffer[1024]; + char *p; + size_t s; + ssize_t r; + bool ret = false; + + va_start(args, format); + vsnprintf(buffer, sizeof(buffer), format, args); + va_end(args); + + p = buffer; + s = strlen(buffer); + while (s > 0) { + if ((r = __pinentry_native_write(pinentry, p, s)) < 0) { + goto cleanup; + } else if (r == 0) { + goto cleanup; + } + p += r; + s -= r; + } + + ret = true; + +cleanup: + + return ret; +} + +_mycms_pinentry +_mycms_util_pinentry_new( + const mycms_context context +) { + mycms_system system = NULL; + _mycms_pinentry pinentry = NULL; + + if (context == NULL) { + goto cleanup; + } + + if ((system = mycms_context_get_system(context)) == NULL) { + goto cleanup; + } + + if ((pinentry = mycms_system_zalloc(system, "pinentry", sizeof(*pinentry))) == NULL) { + goto cleanup; + } + + memcpy(pinentry, &__MYCMS_ENTRY_INIT, sizeof(*pinentry)); + + pinentry->context = context; + +cleanup: + + return pinentry; +} + +bool +_mycms_util_pinentry_construct( + const _mycms_pinentry pinentry, + const char * const prog +) { + bool ret = false; + + if (pinentry == NULL) { + goto cleanup; + } + + if (!__pinentry_native_exec(pinentry, prog)) { + goto cleanup; + } + + ret = true; + +cleanup: + + return ret; +} + +bool +_mycms_util_pinentry_destruct( + const _mycms_pinentry pinentry +) { + mycms_system system = NULL; + bool ret = false; + + if (pinentry == NULL) { + ret = true; + goto cleanup; + } + + if ((system = mycms_context_get_system(pinentry->context)) == NULL) { + goto cleanup; + } + + __pinentry_printf(pinentry, "BYE\n"); + + if (!__pinentry_native_close(pinentry)) { + goto cleanup; + } + + if (!mycms_system_free(system, "pinentry", pinentry)) { + goto cleanup; + } + + ret = true; + +cleanup: + + return ret; +} + +mycms_context +_mycms_util_pinentry_get_context( + const _mycms_pinentry pinentry +) { + if (pinentry == NULL) { + return NULL; + } + + return pinentry->context; +} + +bool +_mycms_util_pinentry_exec( + const _mycms_pinentry pinentry, + const char * const title, + const char * const prompt, + char * const pin, + const size_t pin_size +) { + bool ret = false; + + if (!__pinentry_read_ok(pinentry)) { + goto cleanup; + } + if (!__pinentry_printf(pinentry, "SETTITLE %s\n", title)) { + goto cleanup; + } + if (!__pinentry_read_ok(pinentry)) { + goto cleanup; + } + if (!__pinentry_printf(pinentry, "SETPROMPT %s\n", prompt)) { + goto cleanup; + } + if (!__pinentry_read_ok(pinentry)) { + goto cleanup; + } + if (!__pinentry_printf(pinentry, "GETPIN\n")) { + goto cleanup; + } + if (!__pinentry_read_data(pinentry, pin, pin_size)) { + goto cleanup; + } + if (!__pinentry_read_ok(pinentry)) { + goto cleanup; + } + + ret = true; + +cleanup: + + return ret; +} diff --git a/src/libmycms-util/mycms-util-pinentry.h b/src/libmycms-util/mycms-util-pinentry.h new file mode 100644 index 0000000..4c20f4e --- /dev/null +++ b/src/libmycms-util/mycms-util-pinentry.h @@ -0,0 +1,40 @@ +#ifndef __MYCMS_PINENTRY_H +#define __MYCMS_PINENTRY_H + +#include + +struct _mycms_util_pinentry_s; +typedef struct _mycms_util_pinentry_s *_mycms_pinentry; + + +_mycms_pinentry +_mycms_util_pinentry_new( + const mycms_context context +); + +bool +_mycms_util_pinentry_construct( + const _mycms_pinentry pinentry, + const char * const prog +); + +bool +_mycms_util_pinentry_destruct( + const _mycms_pinentry pinentry +); + +mycms_context +_mycms_util_pinentry_get_context( + const _mycms_pinentry pinentry +); + +bool +_mycms_util_pinentry_exec( + const _mycms_pinentry pinentry, + const char * const title, + const char * const prompt, + char * const pin, + const size_t pin_size +); + +#endif diff --git a/src/libmycms-util/versioninfo.rc.in b/src/libmycms-util/versioninfo.rc.in new file mode 100644 index 0000000..3984780 --- /dev/null +++ b/src/libmycms-util/versioninfo.rc.in @@ -0,0 +1,31 @@ +#include + +VS_VERSION_INFO VERSIONINFO + FILEVERSION @MYCMS_VERSION_MAJOR@,@MYCMS_VERSION_MINOR@,@MYCMS_VERSION_FIX@,@MYCMS_VERSION_REVISION@ + PRODUCTVERSION @MYCMS_VERSION_MAJOR@,@MYCMS_VERSION_MINOR@,@MYCMS_VERSION_FIX@,@MYCMS_VERSION_REVISION@ + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x21L +#else + FILEFLAGS 0x20L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileVersion", "@MYCMS_VERSION_MAJOR@.@MYCMS_VERSION_MINOR@.@MYCMS_VERSION_FIX@.@MYCMS_VERSION_REVISION@" + VALUE "InternalName", "@PACKAGE_NAME@" + VALUE "ProductName", "@PACKAGE_NAME@" + VALUE "ProductVersion", "@MYCMS_VERSION_MAJOR@,@MYCMS_VERSION_MINOR@,@MYCMS_VERSION_FIX@,@MYCMS_VERSION_REVISION@" + VALUE "FileDescription", "@PACKAGE_NAME@ Utilities Library" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src/libmycms/Makefile.am b/src/libmycms/Makefile.am new file mode 100644 index 0000000..cba3d7f --- /dev/null +++ b/src/libmycms/Makefile.am @@ -0,0 +1,157 @@ +include $(top_srcdir)/build/ltrc.inc + +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in \ + $(NULL) +DISTCLEANFILES = \ + libmycms.pc \ + $(NULL) +CLEANFILES = \ + mycms-all.exports \ + mycms-all.exports.tmp \ + $(NULL) + +MYCMS_COMMON_EXPORTS = \ + mycms-certificate.exports \ + mycms-context.exports \ + mycms-dict.exports \ + mycms-error.exports \ + mycms-io.exports \ + mycms-static.exports \ + mycms-system.exports \ + mycms.exports \ + $(NULL) +MYCMS_SELECTIVE_EXPORTS = \ + mycms-certificate-driver-file.exports \ + mycms-certificate-driver-pkcs11.exports \ + mycms-core-decrypt.exports \ + mycms-core-encrypt.exports \ + mycms-core-sign.exports \ + mycms-core-verify.exports \ + $(NULL) + +dist_noinst_DATA = \ + $(MYCMS_COMMON_EXPORTS) \ + $(MYCMS_SELECTIVE_EXPORTS) \ + $(NULL) + +pkgconfig_DATA = libmycms.pc +noinst_LTLIBRARIES = libmycms-internal.la +lib_LTLIBRARIES = libmycms.la + +AM_CFLAGS = \ + $(OPENSSLCRYPTO_CFLAGS) \ + $(NULL) +AM_CPPFLAGS = \ + -I$(top_srcdir)/include \ + $(NULL) + +libmycms_internal_la_SOURCES = \ + mycms-certificate-private.h \ + mycms-certificate.c \ + mycms-context-internal.h \ + mycms-context.c \ + mycms-dict.c \ + mycms-error-internal.h \ + mycms-error.c \ + mycms-internal.h \ + mycms-io-private.h \ + mycms-io.c \ + mycms-openssl.c \ + mycms-openssl.h \ + mycms-static.c \ + mycms-system.c \ + mycms-util.c \ + mycms-util.h \ + mycms.c \ + $(NULL) +libmycms_internal_la_LIBADD = \ + $(OPENSSLCRYPTO_LIBS) \ + $(NULL) + +libmycms_la_DEPENDENCIES = \ + libmycms-internal.la \ + mycms-all.exports \ + $(NULL) +if BUILD_WINDOWS +nodist_libmycms_la_SOURCES = \ + versioninfo.rc \ + $(NULL) +endif +if ENABLE_CMS_SIGN +libmycms_internal_la_SOURCES += \ + mycms-core-sign.c \ + $(NULL) +endif +if ENABLE_CMS_VERIFY +libmycms_internal_la_SOURCES += \ + mycms-core-verify.c \ + $(NULL) +endif +if ENABLE_CMS_ENCRYPT +libmycms_internal_la_SOURCES += \ + mycms-core-encrypt.c \ + $(NULL) +endif +if ENABLE_CMS_DECRYPT +libmycms_internal_la_SOURCES += \ + mycms-core-decrypt.c \ + $(NULL) +endif +if ENABLE_CERTIFICATE_DRIVER_FILE +libmycms_internal_la_SOURCES += \ + mycms-certificate-driver-file.c \ + $(NULL) +endif +if ENABLE_CERTIFICATE_DRIVER_PKCS11 +libmycms_internal_la_SOURCES += \ + mycms-certificate-driver-pkcs11.c \ + pkcs11.h \ + $(NULL) +endif + +libmycms_la_LIBADD = \ + libmycms-internal.la \ + $(NULL) +libmycms_la_LDFLAGS = \ + $(AM_LDFLAGS) \ + -version-info @LIBMYCMS_LT_CURRENT@:@LIBMYCMS_LT_REVISION@:@LIBMYCMS_LT_AGE@ \ + -export-symbols "mycms-all.exports" \ + -no-undefined \ + $(NULL) + +mycms-all.exports: \ + $(MYCMS_COMMON_EXPORTS) \ + $(MYCMS_SELECTIVE_EXPORTS) \ + $(builddir)/Makefile \ + $(top_builddir)/config.h \ + $(NULL) + rm -f mycms-all.exports.tmp + for f in $(MYCMS_COMMON_EXPORTS); do \ + cat "$(srcdir)/$$f" >> mycms-all.exports.tmp; \ + done +if ENABLE_CMS_SIGN + cat "$(srcdir)/mycms-core-sign.exports" >> mycms-all.exports.tmp +endif +if ENABLE_CMS_VERIFY + cat "$(srcdir)/mycms-core-verify.exports" >> mycms-all.exports.tmp +endif +if ENABLE_CMS_ENCRYPT + cat "$(srcdir)/mycms-core-encrypt.exports" >> mycms-all.exports.tmp +endif +if ENABLE_CMS_DECRYPT + cat "$(srcdir)/mycms-core-decrypt.exports" >> mycms-all.exports.tmp +endif +if ENABLE_CERTIFICATE_DRIVER_FILE + cat "$(srcdir)/mycms-certificate-driver-file.exports" >> mycms-all.exports.tmp +endif +if ENABLE_CERTIFICATE_DRIVER_PKCS11 + cat "$(srcdir)/mycms-certificate-driver-pkcs11.exports" >> mycms-all.exports.tmp +endif + mv mycms-all.exports.tmp mycms-all.exports + +if BUILD_WINDOWS +mylibdir=$(libdir) +mylib_DATA=.libs/libmycms-@LIBMYCMS_LT_OLDEST@.dll.def +.libs/libmycms-@LIBMYCMS_LT_OLDEST@.dll.def: libmycms.la +endif diff --git a/src/libmycms/libmycms.pc.in b/src/libmycms/libmycms.pc.in new file mode 100644 index 0000000..20b42a6 --- /dev/null +++ b/src/libmycms/libmycms.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: mycms +Description: mycms +Version: @PACKAGE_VERSION@ +Cflags: -I${includedir} +Libs: @LIBS@ -L${libdir} -lmycms diff --git a/src/libmycms/mycms-certificate-driver-file.c b/src/libmycms/mycms-certificate-driver-file.c new file mode 100644 index 0000000..a8fe145 --- /dev/null +++ b/src/libmycms/mycms-certificate-driver-file.c @@ -0,0 +1,483 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include + +#include + +#include "mycms-error-internal.h" +#include "mycms-openssl.h" + +struct __mycms_certificate_driver_file_s { +#ifndef OPENSSL_NO_RSA + RSA *rsa; +#endif +}; +typedef struct __mycms_certificate_driver_file_s *__mycms_certificate_driver_file; + +static int __convert_padding(const int padding) { + int ret; + switch (padding) { +#ifndef OPENSSL_NO_RSA + case MYCMS_PADDING_PKCS1: + ret = RSA_PKCS1_PADDING; + break; + case MYCMS_PADDING_OEAP: + ret = RSA_PKCS1_OAEP_PADDING; + break; + case MYCMS_PADDING_NONE: + ret = RSA_NO_PADDING; + break; +#endif + default: + ret = -1; + break; + } + return ret; +} + +static +mycms_system +__get_system( + const mycms_certificate certificate +) { + mycms_context context = NULL; + + if ((context = mycms_certificate_get_context(certificate)) == NULL) { + return NULL; + } + + return mycms_context_get_system(context); +} + +static +EVP_PKEY * +__driver_load_pkey( + const mycms_certificate certificate, + const char *file +) { + EVP_PKEY *k = NULL; + BIO *bio = NULL; + + if (file == NULL) { + goto cleanup; + } + + if ((bio = BIO_new_file(file, "rb")) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.load.pkey", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot open private key file '%s'", + file + ))); + goto cleanup; + } + + if ((k = d2i_PrivateKey_bio(bio, NULL)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.load.pkey", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot parse private key from file '%s'", + file + ))); + goto cleanup; + } + +cleanup: + + BIO_free(bio); + bio = NULL; + + return k; +} + +#ifndef OPENSSL_NO_RSA +static +int +__driver_rsa_private_op( + const mycms_certificate certificate, + const int op, + const unsigned char * const from, + const size_t from_size, + unsigned char * const to, + const size_t to_size, + const int padding +) { + __mycms_certificate_driver_file certificate_file = NULL; + const RSA_METHOD *rsa_method = NULL; + int cpadding; + int ret = -1; + + if ((certificate_file = (__mycms_certificate_driver_file)mycms_certificate_get_driverdata(certificate)) == NULL) { + goto cleanup; + } + + if (from == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.op.from", + MYCMS_ERROR_CODE_ARGS, + true, + "From buffer must not be null" + )); + goto cleanup; + } + + if (to == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.op.to", + MYCMS_ERROR_CODE_ARGS, + true, + "To buffer must not be null" + )); + goto cleanup; + } + + if (from_size == 0) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.op.from_size", + MYCMS_ERROR_CODE_ARGS, + true, + "From size must be greater than zero" + )); + goto cleanup; + } + + if (to_size < from_size) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.op.from_size", + MYCMS_ERROR_CODE_ARGS, + true, + "To size must be greater than from (%ld>=%ld)", + to_size, + from_size + )); + goto cleanup; + } + + if ((cpadding = __convert_padding(padding)) == -1) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.op.padding", + MYCMS_ERROR_CODE_ARGS, + true, + "Invalid padding %d", + padding + )); + goto cleanup; + } + + if ((rsa_method = RSA_get_method(certificate_file->rsa)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.op", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot get RSA method" + ))); + goto cleanup; + } + + switch (op) { + default: + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.op.type", + MYCMS_ERROR_CODE_ARGS, + true, + "Invalid op type %d", + op + )); + goto cleanup; + case MYCMS_PRIVATE_OP_ENCRYPT: + ret = RSA_meth_get_priv_enc(rsa_method)(from_size, from, to, certificate_file->rsa, cpadding); + break; + case MYCMS_PRIVATE_OP_DECRYPT: + ret = RSA_meth_get_priv_dec(rsa_method)(from_size, from, to, certificate_file->rsa, cpadding); + break; + } + +cleanup: + + return ret; +} +#endif + +static +bool +__driver_free( + const mycms_certificate certificate +) { + mycms_system system = NULL; + __mycms_certificate_driver_file certificate_file; + bool ret = false; + + if ((system = __get_system(certificate)) == NULL) { + return false; + } + + if ((certificate_file = (__mycms_certificate_driver_file)mycms_certificate_get_driverdata(certificate)) == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.free", + MYCMS_ERROR_CODE_ARGS, + false, + "No context" + )); + goto cleanup; + } + +#ifndef OPENSSL_NO_RSA + RSA_free(certificate_file->rsa); + certificate_file->rsa = NULL; +#endif + + if (!mycms_system_free(system, "ccertificate_file", certificate_file)) { + goto cleanup; + } + + ret = true; + +cleanup: + + return ret; +} + +static +bool +__driver_load( + const mycms_certificate certificate, + const mycms_dict parameters +) { + mycms_system system = NULL; + __mycms_certificate_driver_file certificate_file = NULL; + + EVP_PKEY *evp = NULL; + BIO *bio_in = NULL; + BIO *bio_out = NULL; + + const char *cert_file; + const char *key_file; + mycms_blob blob; + bool ret = false; + + if (certificate == NULL) { + return false; + } + + if (parameters == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.load", + MYCMS_ERROR_CODE_ARGS, + true, + "Parameters must be provided" + )); + goto cleanup; + } + + if ((system = __get_system(certificate)) == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.load", + MYCMS_ERROR_CODE_ARGS, + true, + "Cannot get system context" + )); + goto cleanup; + } + + if ((cert_file = mycms_dict_entry_get(parameters, "cert", NULL)) == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.load", + MYCMS_ERROR_CODE_ARGS, + true, + "No cert attribute in parameters" + )); + goto cleanup; + } + + if ((key_file = mycms_dict_entry_get(parameters, "key", NULL)) == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.load", + MYCMS_ERROR_CODE_ARGS, + true, + "No key attribute in parameters" + )); + goto cleanup; + } + + if ((bio_in = BIO_new_file(cert_file, "rb")) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.load", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot open certificate file '%s'", + cert_file + ))); + goto cleanup; + } + + if ((bio_out = BIO_new(BIO_s_mem())) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.load.cert", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot allocate cache BIO" + ))); + goto cleanup; + } + + { + unsigned char buffer[1024]; + int n; + + while ((n = BIO_read(bio_in, buffer, sizeof(buffer))) > 0) { + if (BIO_write(bio_out, buffer, n) != n) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.load.cert", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot write to cache BIO" + ))); + goto cleanup; + } + } + if (n != 0) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.load.cert", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot read certificate file '%s'", + cert_file + ))); + goto cleanup; + } + } + + blob.size = BIO_get_mem_data(bio_out, &blob.data); + + if ((evp = __driver_load_pkey(certificate, key_file)) == NULL) { + goto cleanup; + } + + if ((certificate_file = mycms_system_zalloc(system, "certificate_file", sizeof(*certificate_file))) == NULL) { + goto cleanup; + } + + switch (EVP_PKEY_id(evp)) { + default: + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.load.type", + MYCMS_ERROR_CODE_ARGS, + true, + "Unsupported key type %d", + EVP_PKEY_id(evp) + )); + goto cleanup; +#ifndef OPENSSL_NO_RSA + case EVP_PKEY_RSA: + if ((certificate_file->rsa = EVP_PKEY_get1_RSA(evp)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.file.load.rsa", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot get RSA out of certificate" + ))); + goto cleanup; + } + break; +#endif + } + + if (!mycms_certificate_set_driverdata(certificate, certificate_file)) { + goto cleanup; + } + certificate_file = NULL; + + if (!mycms_certificate_apply_certificate(certificate, &blob)) { + goto cleanup; + } + + ret = true; + +cleanup: + BIO_free(bio_in); + bio_in = NULL; + + BIO_free(bio_out); + bio_out = NULL; + + EVP_PKEY_free(evp); + evp = NULL; + + if (certificate_file != NULL) { +#ifndef OPENSSL_NO_RSA + RSA_free(certificate_file->rsa); + certificate_file->rsa = NULL; +#endif + mycms_system_free(system, "certificate_file", certificate_file); + certificate_file = NULL; + } + + return ret; +} + +const char * +mycms_certificate_driver_file_usage(void) { + return ( + "CERTIFICATE EXPRESSION ATTRIBUTES\n" + "cert: DER encoded certificate file\n" + "key: DER encoded PKCS#8 file\n" + ); +} + +bool +mycms_certificate_driver_file_apply( + const mycms_certificate certificate +) { + bool ret = false; + + if (certificate == NULL) { + return false; + } + + if (!mycms_certificate_set_driver_free(certificate, __driver_free)) { + goto cleanup; + } + + if (!mycms_certificate_set_driver_load(certificate, __driver_load)) { + goto cleanup; + } + +#ifndef OPENSSL_NO_RSA + if (!mycms_certificate_set_driver_rsa_private_op(certificate, __driver_rsa_private_op)) { + goto cleanup; + } +#endif + ret = true; + +cleanup: + + return ret; +} diff --git a/src/libmycms/mycms-certificate-driver-file.exports b/src/libmycms/mycms-certificate-driver-file.exports new file mode 100644 index 0000000..5b1e45a --- /dev/null +++ b/src/libmycms/mycms-certificate-driver-file.exports @@ -0,0 +1,2 @@ +mycms_certificate_driver_file_apply +mycms_certificate_driver_file_usage diff --git a/src/libmycms/mycms-certificate-driver-pkcs11.c b/src/libmycms/mycms-certificate-driver-pkcs11.c new file mode 100644 index 0000000..480845b --- /dev/null +++ b/src/libmycms/mycms-certificate-driver-pkcs11.c @@ -0,0 +1,1429 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#ifdef HAVE_DLFCN_H +#include +#endif + +#include +#include + +#include +#include +#include + +#include "mycms-context-internal.h" +#include "mycms-error-internal.h" +#include "pkcs11.h" + +#define __INVALID_SESSION_HANDLE ((CK_SESSION_HANDLE)-1) +#define __INVALID_OBJECT_HANDLE ((CK_OBJECT_HANDLE)-1) + +struct __pkcs11_provider_s { + char *name; + int reference_count; + void *module_handle; + bool should_finalize; + CK_FUNCTION_LIST_PTR f; +}; + +MYCMS_LIST_DECLARE(pkcs11_provider, struct __pkcs11_provider_s, entry) + +struct __mycms_certificate_driver_pkcs11_s { + char display[1024]; + mycms_certificate certificate; + struct __pkcs11_provider_s *p; + char *token_label; + CK_SESSION_HANDLE session_handle; + CK_OBJECT_HANDLE key_handle; + bool protected_auth; + bool login_required; + bool always_authenticate; + mycms_blob id; + + bool assume_loggedin; + bool key_attributes_valid; +}; +typedef struct __mycms_certificate_driver_pkcs11_s *__mycms_certificate_driver_pkcs11; + +const char * +__rv2str( + const CK_RV rv +) { + switch (rv) { + case CKR_OK: return "CKR_OK"; + case CKR_CANCEL: return "CKR_CANCEL"; + case CKR_HOST_MEMORY: return "CKR_HOST_MEMORY"; + case CKR_SLOT_ID_INVALID: return "CKR_SLOT_ID_INVALID"; + case CKR_GENERAL_ERROR: return "CKR_GENERAL_ERROR"; + case CKR_FUNCTION_FAILED: return "CKR_FUNCTION_FAILED"; + case CKR_ARGUMENTS_BAD: return "CKR_ARGUMENTS_BAD"; + case CKR_NO_EVENT: return "CKR_NO_EVENT"; + case CKR_NEED_TO_CREATE_THREADS: return "CKR_NEED_TO_CREATE_THREADS"; + case CKR_CANT_LOCK: return "CKR_CANT_LOCK"; + case CKR_ATTRIBUTE_READ_ONLY: return "CKR_ATTRIBUTE_READ_ONLY"; + case CKR_ATTRIBUTE_SENSITIVE: return "CKR_ATTRIBUTE_SENSITIVE"; + case CKR_ATTRIBUTE_TYPE_INVALID: return "CKR_ATTRIBUTE_TYPE_INVALID"; + case CKR_ATTRIBUTE_VALUE_INVALID: return "CKR_ATTRIBUTE_VALUE_INVALID"; + case CKR_DATA_INVALID: return "CKR_DATA_INVALID"; + case CKR_DATA_LEN_RANGE: return "CKR_DATA_LEN_RANGE"; + case CKR_DEVICE_ERROR: return "CKR_DEVICE_ERROR"; + case CKR_DEVICE_MEMORY: return "CKR_DEVICE_MEMORY"; + case CKR_DEVICE_REMOVED: return "CKR_DEVICE_REMOVED"; + case CKR_ENCRYPTED_DATA_INVALID: return "CKR_ENCRYPTED_DATA_INVALID"; + case CKR_ENCRYPTED_DATA_LEN_RANGE: return "CKR_ENCRYPTED_DATA_LEN_RANGE"; + case CKR_FUNCTION_CANCELED: return "CKR_FUNCTION_CANCELED"; + case CKR_FUNCTION_NOT_PARALLEL: return "CKR_FUNCTION_NOT_PARALLEL"; + case CKR_FUNCTION_NOT_SUPPORTED: return "CKR_FUNCTION_NOT_SUPPORTED"; + case CKR_KEY_HANDLE_INVALID: return "CKR_KEY_HANDLE_INVALID"; + case CKR_KEY_SIZE_RANGE: return "CKR_KEY_SIZE_RANGE"; + case CKR_KEY_TYPE_INCONSISTENT: return "CKR_KEY_TYPE_INCONSISTENT"; + case CKR_KEY_NOT_NEEDED: return "CKR_KEY_NOT_NEEDED"; + case CKR_KEY_CHANGED: return "CKR_KEY_CHANGED"; + case CKR_KEY_NEEDED: return "CKR_KEY_NEEDED"; + case CKR_KEY_INDIGESTIBLE: return "CKR_KEY_INDIGESTIBLE"; + case CKR_KEY_FUNCTION_NOT_PERMITTED: return "CKR_KEY_FUNCTION_NOT_PERMITTED"; + case CKR_KEY_NOT_WRAPPABLE: return "CKR_KEY_NOT_WRAPPABLE"; + case CKR_KEY_UNEXTRACTABLE: return "CKR_KEY_UNEXTRACTABLE"; + case CKR_MECHANISM_INVALID: return "CKR_MECHANISM_INVALID"; + case CKR_MECHANISM_PARAM_INVALID: return "CKR_MECHANISM_PARAM_INVALID"; + case CKR_OBJECT_HANDLE_INVALID: return "CKR_OBJECT_HANDLE_INVALID"; + case CKR_OPERATION_ACTIVE: return "CKR_OPERATION_ACTIVE"; + case CKR_OPERATION_NOT_INITIALIZED: return "CKR_OPERATION_NOT_INITIALIZED"; + case CKR_PIN_INCORRECT: return "CKR_PIN_INCORRECT"; + case CKR_PIN_INVALID: return "CKR_PIN_INVALID"; + case CKR_PIN_LEN_RANGE: return "CKR_PIN_LEN_RANGE"; + case CKR_PIN_EXPIRED: return "CKR_PIN_EXPIRED"; + case CKR_PIN_LOCKED: return "CKR_PIN_LOCKED"; + case CKR_SESSION_CLOSED: return "CKR_SESSION_CLOSED"; + case CKR_SESSION_COUNT: return "CKR_SESSION_COUNT"; + case CKR_SESSION_HANDLE_INVALID: return "CKR_SESSION_HANDLE_INVALID"; + case CKR_SESSION_PARALLEL_NOT_SUPPORTED: return "CKR_SESSION_PARALLEL_NOT_SUPPORTED"; + case CKR_SESSION_READ_ONLY: return "CKR_SESSION_READ_ONLY"; + case CKR_SESSION_EXISTS: return "CKR_SESSION_EXISTS"; + case CKR_SESSION_READ_ONLY_EXISTS: return "CKR_SESSION_READ_ONLY_EXISTS"; + case CKR_SESSION_READ_WRITE_SO_EXISTS: return "CKR_SESSION_READ_WRITE_SO_EXISTS"; + case CKR_SIGNATURE_INVALID: return "CKR_SIGNATURE_INVALID"; + case CKR_SIGNATURE_LEN_RANGE: return "CKR_SIGNATURE_LEN_RANGE"; + case CKR_TEMPLATE_INCOMPLETE: return "CKR_TEMPLATE_INCOMPLETE"; + case CKR_TEMPLATE_INCONSISTENT: return "CKR_TEMPLATE_INCONSISTENT"; + case CKR_TOKEN_NOT_PRESENT: return "CKR_TOKEN_NOT_PRESENT"; + case CKR_TOKEN_NOT_RECOGNIZED: return "CKR_TOKEN_NOT_RECOGNIZED"; + case CKR_TOKEN_WRITE_PROTECTED: return "CKR_TOKEN_WRITE_PROTECTED"; + case CKR_USER_ALREADY_LOGGED_IN: return "CKR_USER_ALREADY_LOGGED_IN"; + case CKR_USER_NOT_LOGGED_IN: return "CKR_USER_NOT_LOGGED_IN"; + case CKR_USER_PIN_NOT_INITIALIZED: return "CKR_USER_PIN_NOT_INITIALIZED"; + case CKR_USER_TYPE_INVALID: return "CKR_USER_TYPE_INVALID"; + case CKR_USER_ANOTHER_ALREADY_LOGGED_IN: return "CKR_USER_ANOTHER_ALREADY_LOGGED_IN"; + case CKR_USER_TOO_MANY_TYPES: return "CKR_USER_TOO_MANY_TYPES"; + case CKR_BUFFER_TOO_SMALL: return "CKR_BUFFER_TOO_SMALL"; + case CKR_SAVED_STATE_INVALID: return "CKR_SAVED_STATE_INVALID"; + case CKR_INFORMATION_SENSITIVE: return "CKR_INFORMATION_SENSITIVE"; + case CKR_STATE_UNSAVEABLE: return "CKR_STATE_UNSAVEABLE"; + case CKR_CRYPTOKI_NOT_INITIALIZED: return "CKR_CRYPTOKI_NOT_INITIALIZED"; + case CKR_CRYPTOKI_ALREADY_INITIALIZED: return "CKR_CRYPTOKI_ALREADY_INITIALIZED"; + case CKR_MUTEX_BAD: return "CKR_MUTEX_BAD"; + case CKR_MUTEX_NOT_LOCKED: return "CKR_MUTEX_NOT_LOCKED"; + case CKR_FUNCTION_REJECTED: return "CKR_FUNCTION_REJECTED"; + case CKR_VENDOR_DEFINED: return "CKR_VENDOR_DEFINED"; + default: return "Unmapped PKCS#11 error"; + } +} + +static +mycms_error_entry +__error_entry_pkcs11_rv( + const CK_RV rv, + const mycms_error_entry entry +) { + _mycms_error_entry_prm_add_u32(entry, MYCMS_ERROR_KEY_PKCS11_RV, rv); + _mycms_error_entry_prm_add_str(entry, MYCMS_ERROR_KEY_OPENSSL_STATUS_STR, __rv2str(rv)); + return entry; +} + +static +void +__fixup_fixed_string( + char * const target, /* MUST BE >= length+1 */ + const char * const source, + const size_t length /* FIXED STRING LENGTH */ +) { + char *p; + + memmove (target, source, length); + p = target+length; + *p = '\0'; + p--; + while (p >= target && *p == ' ') { + *p = '\0'; + p--; + } +} + +static +mycms_system +__get_system( + const mycms_certificate certificate +) { + mycms_context context = NULL; + + if ((context = mycms_certificate_get_context(certificate)) == NULL) { + return NULL; + } + + return mycms_context_get_system(context); +} + +static +CK_MECHANISM_TYPE +__convert_padding(const int padding) { + int ret; + switch (padding) { + case MYCMS_PADDING_PKCS1: + ret = CKM_RSA_PKCS; + break; + case MYCMS_PADDING_OEAP: + ret = CKM_RSA_PKCS_OAEP; + break; + case MYCMS_PADDING_NONE: + ret = CKM_RSA_X_509; + break; + default: + ret = CKR_MECHANISM_INVALID; + break; + } + return ret; +} + +static +CK_RV +__get_object_attributes( + const mycms_system system, + const __mycms_certificate_driver_pkcs11 certificate_pkcs11, + const CK_OBJECT_HANDLE object, + const CK_ATTRIBUTE_PTR attrs, + const unsigned count +) { + CK_RV rv = CKR_FUNCTION_FAILED; + unsigned i; + + if (certificate_pkcs11->session_handle == __INVALID_SESSION_HANDLE) { + rv = CKR_SESSION_HANDLE_INVALID; + goto cleanup; + } + + if ( + (rv = certificate_pkcs11->p->f->C_GetAttributeValue( + certificate_pkcs11->session_handle, + object, + attrs, + count + )) != CKR_OK + ) { + if (rv != CKR_ATTRIBUTE_SENSITIVE && rv != CKR_ATTRIBUTE_TYPE_INVALID) { + _mycms_error_entry_dispatch(__error_entry_pkcs11_rv(rv, _mycms_error_entry_base( + _mycms_error_capture(mycms_system_get_error(system)), + "certificate.driver.pkcs11.attrs.pre", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot get object attributes" + ))); + goto cleanup; + } + } + + for (i=0;ip->f->C_GetAttributeValue( + certificate_pkcs11->session_handle, + object, + attrs, + count + )) != CKR_OK + ) { + if (rv != CKR_ATTRIBUTE_SENSITIVE && rv != CKR_ATTRIBUTE_TYPE_INVALID) { + _mycms_error_entry_dispatch(__error_entry_pkcs11_rv(rv, _mycms_error_entry_base( + _mycms_error_capture(mycms_system_get_error(system)), + "certificate.driver.pkcs11.attrs.post", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot get object attributes" + ))); + goto cleanup; + } + } + +cleanup: + + return rv; +} + +static +CK_RV +__free_attributes ( + const mycms_system system, + const CK_ATTRIBUTE_PTR attrs, + const unsigned count +) { + unsigned i; + + for (i=0;isession_handle == __INVALID_SESSION_HANDLE) { + rv = CKR_SESSION_HANDLE_INVALID; + goto cleanup; + } + + if ( + (rv = certificate_pkcs11->p->f->C_FindObjectsInit( + certificate_pkcs11->session_handle, + (CK_ATTRIBUTE_PTR)filter, + filter_attrs + )) != CKR_OK + ) { + _mycms_error_entry_dispatch(__error_entry_pkcs11_rv(rv, _mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate_pkcs11->certificate))), + "certificate.driver.pkcs11.find.init", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot initiate object find" + ))); + goto cleanup; + } + should_FindObjectsFinal = true; + + if ((rv = certificate_pkcs11->p->f->C_FindObjects( + certificate_pkcs11->session_handle, + object_handle, + 1, + &objects_size + )) != CKR_OK) { + _mycms_error_entry_dispatch(__error_entry_pkcs11_rv(rv, _mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate_pkcs11->certificate))), + "certificate.driver.pkcs11.find", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to search objects" + ))); + goto cleanup; + } + + if (objects_size == 0) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate_pkcs11->certificate))), + "certificate.driver.pkcs11.find", + MYCMS_ERROR_CODE_CRYPTO, + true, + "No object found" + )); + *object_handle = __INVALID_OBJECT_HANDLE; + } + + rv = CKR_OK; + +cleanup: + + if (should_FindObjectsFinal) { + certificate_pkcs11->p->f->C_FindObjectsFinal( + certificate_pkcs11->session_handle + ); + } + + return rv; +} + +static +void +__unload_provider( + const mycms_certificate certificate +) { + mycms_system system = NULL; + + mycms_list_pkcs11_provider head; + bool found; + + if ((system = __get_system(certificate)) == NULL) { + goto cleanup; + } + + head = (mycms_list_pkcs11_provider)_mycms_context_get_pkcs11_state(mycms_certificate_get_context(certificate)); + found = true; + while (found) { + mycms_list_pkcs11_provider p; + mycms_list_pkcs11_provider t; + found = false; + + for ( + p = NULL, t = head; + t != NULL; + p = t, t = t->next + ) { + if (t->entry.reference_count == 0) { + break; + } + } + + if (t != NULL) { + if (p == NULL) { + head = t->next; + } else { + p->next = t->next; + } + + + if (t->entry.should_finalize) { + t->entry.f->C_Finalize(NULL); + t->entry.should_finalize = false; + } + t->entry.f = NULL; + if (t->entry.module_handle != NULL) { + mycms_system_driver_core_dlclose(system)( + system, + t->entry.module_handle + ); + t->entry.module_handle = NULL; + } + mycms_system_free(system, "pkcs11_provider.name", t->entry.name); + mycms_system_free(system, "pkcs11_provider.entry", t); + t = NULL; + } + } + + _mycms_context_set_pkcs11_state(mycms_certificate_get_context(certificate), head); + +cleanup: + ; +} + +static +struct __pkcs11_provider_s * +__load_provider( + const mycms_certificate certificate, + const char * const module, + const char * const reserved +) { + mycms_system system = NULL; + mycms_list_pkcs11_provider t = NULL; + mycms_list_pkcs11_provider pkcs11_provider = NULL; + CK_C_GetFunctionList gfl = NULL; + CK_C_INITIALIZE_ARGS initargs; + CK_C_INITIALIZE_ARGS_PTR pinitargs = NULL; + CK_RV rv; + struct __pkcs11_provider_s *ret = NULL; + + if ((system = __get_system(certificate)) == NULL) { + return NULL; + } + + for ( + t = (mycms_list_pkcs11_provider)_mycms_context_get_pkcs11_state(mycms_certificate_get_context(certificate)); + t != NULL; + t = t->next + ) { + if (!strcmp(t->entry.name, module)) { + break; + } + } + + if (t != NULL) { + pkcs11_provider = t; + } else { + if ((pkcs11_provider = mycms_system_zalloc(system, "pkcs11_provider", sizeof(*pkcs11_provider))) == NULL) { + goto cleanup; + } + + if ((pkcs11_provider->entry.name = mycms_system_strdup(system, "pkcs11_provider.name", module)) == NULL) { + goto cleanup; + } + + pkcs11_provider->next = (mycms_list_pkcs11_provider)_mycms_context_get_pkcs11_state(mycms_certificate_get_context(certificate)); + _mycms_context_set_pkcs11_state(mycms_certificate_get_context(certificate), pkcs11_provider); + + if ((pkcs11_provider->entry.module_handle = mycms_system_driver_core_dlopen(system)( + system, + pkcs11_provider->entry.name, + RTLD_NOW | RTLD_LOCAL + )) == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_system_get_error(system)), + "certificate.driver.pkcs11.load", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to load PKCS#11 provider `%s`", + module + )); + goto cleanup; + } + + { + void *p; + + /* + * Make compiler happy! + */ + p = mycms_system_driver_core_dlsym(system)( + system, + pkcs11_provider->entry.module_handle, + "C_GetFunctionList" + ); + memmove(&gfl, &p, sizeof(gfl)); + } + + if (gfl == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_system_get_error(system)), + "certificate.driver.pkcs11.gfl.entry", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to resolve PKCS#11 provider `%s` function list entry", + pkcs11_provider->entry.name + )); + goto cleanup; + } + + if ((rv = gfl(&pkcs11_provider->entry.f)) != CKR_OK) { + _mycms_error_entry_dispatch(__error_entry_pkcs11_rv(rv, _mycms_error_entry_base( + _mycms_error_capture(mycms_system_get_error(system)), + "certificate.driver.pkcs11.gfl", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to acquire PKCS#11 provider `%s` function list", + pkcs11_provider->entry.name + ))); + goto cleanup; + } + + memset(&initargs, 0, sizeof(initargs)); + if (reserved != NULL) { + initargs.pReserved = (char *)reserved; + pinitargs = &initargs; + } + + if ((rv = pkcs11_provider->entry.f->C_Initialize(pinitargs)) != CKR_OK) { + if (rv != CKR_CRYPTOKI_ALREADY_INITIALIZED) { + _mycms_error_entry_dispatch(__error_entry_pkcs11_rv(rv, _mycms_error_entry_base( + _mycms_error_capture(mycms_system_get_error(system)), + "certificate.driver.pkcs11.init", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to initialize PKCS#11 provider `%s`", + pkcs11_provider->entry.name + ))); + goto cleanup; + } + } + else { + pkcs11_provider->entry.should_finalize = true; + } + } + + pkcs11_provider->entry.reference_count++; + ret = &pkcs11_provider->entry; + pkcs11_provider = NULL; + +cleanup: + __unload_provider(certificate); + + return ret; +} + +static +CK_RV +__common_login( + const mycms_certificate certificate, + const CK_USER_TYPE user, + const char * const what +) { + mycms_system system = NULL; + __mycms_certificate_driver_pkcs11 certificate_pkcs11 = NULL; + + char pin[512]; + char *p; + bool loggedin = false; + CK_RV rv = CKR_FUNCTION_FAILED; + + if ((system = __get_system(certificate)) == NULL) { + goto cleanup; + } + + if ((certificate_pkcs11 = (__mycms_certificate_driver_pkcs11)mycms_certificate_get_driverdata(certificate)) == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.login", + MYCMS_ERROR_CODE_CRYPTO, + false, + "Failed to acquire PKCS#11 context" + )); + goto cleanup; + } + + if (certificate_pkcs11->session_handle == __INVALID_SESSION_HANDLE) { + rv = CKR_SESSION_HANDLE_INVALID; + goto cleanup; + } + + if (!loggedin && certificate_pkcs11->protected_auth) { + if ((rv = certificate_pkcs11->p->f->C_Login ( + certificate_pkcs11->session_handle, + user, + NULL_PTR, + 0 + )) == CKR_OK || rv != CKR_USER_ALREADY_LOGGED_IN) { + loggedin = true; + } + } + + if (!loggedin) { + p = pin; + if (!mycms_certificate_acquire_passphrase(certificate, what, &p, sizeof(pin))) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_system_get_error(system)), + "certificate.driver.pkcs11.login.pass", + MYCMS_ERROR_CODE_CRYPTO, + false, + "Failed to acquire passphrase for '%s' for '%s'", + certificate_pkcs11->display, + what + )); + goto cleanup; + } + + if ((rv = certificate_pkcs11->p->f->C_Login ( + certificate_pkcs11->session_handle, + user, + (CK_UTF8CHAR_PTR)p, + p == NULL ? 0 : strlen(p) + )) == CKR_OK || rv != CKR_USER_ALREADY_LOGGED_IN) { + loggedin = true; + } + } + + if (!loggedin) { + _mycms_error_entry_dispatch(__error_entry_pkcs11_rv(rv, _mycms_error_entry_base( + _mycms_error_capture(mycms_system_get_error(system)), + "certificate.driver.pkcs11.login", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Login to '%s' failed for '%s'", + certificate_pkcs11->display, + what + ))); + goto cleanup; + } + + rv = CKR_OK; + +cleanup: + mycms_system_explicit_bzero(system, pin, sizeof(pin)); + + return rv; +} + +static +CK_RV +__context_login( + const mycms_certificate certificate +) { + __mycms_certificate_driver_pkcs11 certificate_pkcs11 = NULL; + + CK_RV rv = CKR_FUNCTION_FAILED; + + if ((certificate_pkcs11 = (__mycms_certificate_driver_pkcs11)mycms_certificate_get_driverdata(certificate)) == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.login.context", + MYCMS_ERROR_CODE_CRYPTO, + false, + "Failed to get PKCS#11 context" + )); + goto cleanup; + } + + if (certificate_pkcs11->always_authenticate) { + if ((rv = __common_login(certificate, CKU_CONTEXT_SPECIFIC, "key")) != CKR_OK) { + _mycms_error_entry_dispatch(__error_entry_pkcs11_rv(rv, _mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.login", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Context specific login failed for '%s'", + certificate_pkcs11->display + ))); + goto cleanup; + } + } + + rv = CKR_OK; + +cleanup: + + return rv; +} + +static +bool +__open_slot( + const mycms_certificate certificate +) { + mycms_system system = NULL; + __mycms_certificate_driver_pkcs11 certificate_pkcs11 = NULL; + + CK_SLOT_ID_PTR slots = NULL; + CK_ULONG slotnum = 0; + CK_ULONG slot_index; + CK_RV rv = CKR_FUNCTION_FAILED; + + bool found; + bool ret = false; + + if ((system = __get_system(certificate)) == NULL) { + goto cleanup; + } + + if ((certificate_pkcs11 = (__mycms_certificate_driver_pkcs11)mycms_certificate_get_driverdata(certificate)) == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.login", + MYCMS_ERROR_CODE_CRYPTO, + false, + "Failed to acquire PKCS#11 context" + )); + goto cleanup; + } + + if ( + (rv = certificate_pkcs11->p->f->C_GetSlotList ( + CK_TRUE, + NULL_PTR, + &slotnum + )) != CKR_OK + ) { + _mycms_error_entry_dispatch(__error_entry_pkcs11_rv(rv, _mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.login.slots.pre", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to list slots for '%s'", + certificate_pkcs11->display + ))); + goto cleanup; + } + + if ((slots = mycms_system_zalloc(system, "pkcs11.slots", sizeof(*slots) * slotnum)) == NULL) { + goto cleanup; + } + + if ( + (rv = certificate_pkcs11->p->f->C_GetSlotList ( + CK_TRUE, + slots, + &slotnum + )) != CKR_OK + ) { + _mycms_error_entry_dispatch(__error_entry_pkcs11_rv(rv, _mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.login.slots.post", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to list slots for '%s'", + certificate_pkcs11->display + ))); + goto cleanup; + } + + for ( + found = false, slot_index = 0; + ( + slot_index < slotnum && + !found + ); + slot_index++ + ) { + CK_TOKEN_INFO info; + + if (certificate_pkcs11->p->f->C_GetTokenInfo ( + slots[slot_index], + &info + ) != CKR_OK) { + } else { + char label[sizeof(info.label)+1]; + __fixup_fixed_string(label, (char *)info.label, sizeof(info.label)); + if (!strcmp(label, certificate_pkcs11->token_label)) { + found = true; + certificate_pkcs11->protected_auth = (info.flags & CKF_PROTECTED_AUTHENTICATION_PATH) != 0; + certificate_pkcs11->login_required = (info.flags & CKF_LOGIN_REQUIRED) != 0; + break; + } + } + } + + if (!found) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.login.token", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot find certificate '%s'", + certificate_pkcs11->display + )); + goto cleanup; + } + + if ((rv = certificate_pkcs11->p->f->C_OpenSession ( + slots[slot_index], + CKF_SERIAL_SESSION, + NULL_PTR, + NULL_PTR, + &certificate_pkcs11->session_handle + )) != CKR_OK) { + _mycms_error_entry_dispatch(__error_entry_pkcs11_rv(rv, _mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.login.session", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to open session to '%s' slot %ld", + certificate_pkcs11->display, + slots[slot_index] + ))); + certificate_pkcs11->session_handle = __INVALID_SESSION_HANDLE; + goto cleanup; + } + + ret = true; + +cleanup: + + mycms_system_free(system, "pkcs11.slots", slots); + slots = NULL; + + return ret; +} + +static +bool +__open_private_key( + const mycms_certificate certificate +) { + mycms_system system = NULL; + __mycms_certificate_driver_pkcs11 certificate_pkcs11 = NULL; + + CK_ATTRIBUTE key_attrs[] = { + {CKA_ALWAYS_AUTHENTICATE, NULL, 0} + }; + CK_RV rv = CKR_FUNCTION_FAILED; + + int retry; + bool ret = false; + + if ((system = __get_system(certificate)) == NULL) { + goto cleanup; + } + + if ((certificate_pkcs11 = (__mycms_certificate_driver_pkcs11)mycms_certificate_get_driverdata(certificate)) == NULL) { + goto cleanup; + } + + retry = 3; + while(retry--) { + if (!certificate_pkcs11->assume_loggedin && certificate_pkcs11->login_required) { + if ((rv = __common_login(certificate, CKU_USER, "token")) != CKR_OK) { + switch (rv) { + default: + _mycms_error_entry_dispatch(__error_entry_pkcs11_rv(rv, _mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.private", + MYCMS_ERROR_CODE_CRYPTO, + false, + "Failed to login into '%s'", + certificate_pkcs11->display + ))); + goto cleanup; + case CKR_SESSION_CLOSED: + case CKR_SESSION_HANDLE_INVALID: + case CKR_USER_NOT_LOGGED_IN: + goto retry; + } + } + certificate_pkcs11->assume_loggedin = true; + } + + if (!certificate_pkcs11->key_attributes_valid) { + CK_OBJECT_CLASS c = CKO_PRIVATE_KEY; + const CK_ATTRIBUTE filter[] = { + {CKA_CLASS, &c, sizeof(c)}, + {CKA_ID, certificate_pkcs11->id.data, certificate_pkcs11->id.size} + }; + + if ((rv = __find_object( + certificate_pkcs11, + filter, + sizeof(filter) / sizeof(*filter), + &certificate_pkcs11->key_handle + )) != CKR_OK) { + switch (rv) { + default: + _mycms_error_entry_dispatch(__error_entry_pkcs11_rv(rv, _mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.private", + MYCMS_ERROR_CODE_CRYPTO, + false, + "Failed to find private key '%s'", + certificate_pkcs11->display + ))); + goto cleanup; + case CKR_SESSION_CLOSED: + case CKR_SESSION_HANDLE_INVALID: + case CKR_USER_NOT_LOGGED_IN: + goto retry; + } + goto cleanup; + } + + if (certificate_pkcs11->key_handle == __INVALID_OBJECT_HANDLE) { + goto cleanup; + } + + if (__get_object_attributes( + system, + certificate_pkcs11, + certificate_pkcs11->key_handle, + key_attrs, + sizeof(key_attrs) / sizeof(*key_attrs) + ) == CKR_OK) { + if (key_attrs[0].ulValueLen != CK_UNAVAILABLE_INFORMATION) { + certificate_pkcs11->always_authenticate = *(CK_BBOOL *)key_attrs[0].pValue != CK_FALSE; + } + } + + certificate_pkcs11->key_attributes_valid = true; + } + + break; + + retry: + + certificate_pkcs11->assume_loggedin = false; + if (!__open_slot(certificate)) { + goto cleanup; + } + } + + ret = true; + +cleanup: + + __free_attributes( + system, + key_attrs, + sizeof(key_attrs) / sizeof(*key_attrs) + ); + + return ret; +} + +static +int +__driver_rsa_private_op( + const mycms_certificate certificate, + const int op, + const unsigned char * const from, + const size_t from_size, + unsigned char * const to, + const size_t to_size, + const int padding +) { + __mycms_certificate_driver_pkcs11 certificate_pkcs11 = NULL; + + CK_MECHANISM mech = {0, NULL, 0}; + CK_ULONG size; + CK_RV rv = CKR_FUNCTION_FAILED; + int ret = -1; + + if ((certificate_pkcs11 = (__mycms_certificate_driver_pkcs11)mycms_certificate_get_driverdata(certificate)) == NULL) { + goto cleanup; + } + + if (from == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.op.from", + MYCMS_ERROR_CODE_ARGS, + true, + "From buffer must not be null" + )); + goto cleanup; + } + + if (to == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.op.to", + MYCMS_ERROR_CODE_ARGS, + true, + "To buffer must not be null" + )); + goto cleanup; + } + + if (from_size == 0) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.op.from_size", + MYCMS_ERROR_CODE_ARGS, + true, + "From size must be greater than zero" + )); + goto cleanup; + } + + if (to_size < from_size) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.op.from_size", + MYCMS_ERROR_CODE_ARGS, + true, + "To size must be greater than from (%ld>=%ld)", + to_size, + from_size + )); + goto cleanup; + } + + if ((mech.mechanism = __convert_padding(padding)) == CKR_MECHANISM_INVALID) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.op.padding", + MYCMS_ERROR_CODE_ARGS, + true, + "Invalid padding %d", + padding + )); + goto cleanup; + } + + if (!__open_private_key(certificate)) { + goto cleanup; + } + + switch (op) { + default: + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.op.type", + MYCMS_ERROR_CODE_ARGS, + true, + "Invalid op type %d", + op + )); + goto cleanup; + case MYCMS_PRIVATE_OP_ENCRYPT: + if ((rv = certificate_pkcs11->p->f->C_SignInit ( + certificate_pkcs11->session_handle, + &mech, + certificate_pkcs11->key_handle + )) != CKR_OK) { + _mycms_error_entry_dispatch(__error_entry_pkcs11_rv(rv, _mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.op.sign.pre", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Sign failed for '%s'", + certificate_pkcs11->display + ))); + goto cleanup; + } + if (__context_login(certificate) != CKR_OK) { + goto cleanup; + } + size = to_size; + if ((rv = certificate_pkcs11->p->f->C_Sign ( + certificate_pkcs11->session_handle, + (CK_BYTE_PTR)from, + from_size, + (CK_BYTE_PTR)to, + &size + )) != CKR_OK) { + _mycms_error_entry_dispatch(__error_entry_pkcs11_rv(rv, _mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.op.sign.post", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Sign failed for '%s'", + certificate_pkcs11->display + ))); + goto cleanup; + } + break; + case MYCMS_PRIVATE_OP_DECRYPT: + if ((rv = certificate_pkcs11->p->f->C_DecryptInit ( + certificate_pkcs11->session_handle, + &mech, + certificate_pkcs11->key_handle + )) != CKR_OK) { + _mycms_error_entry_dispatch(__error_entry_pkcs11_rv(rv, _mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.op.decrypt.pre", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Decrypt failed for '%s'", + certificate_pkcs11->display + ))); + goto cleanup; + } + if (__context_login(certificate) != CKR_OK) { + goto cleanup; + } + size = to_size; + if ((rv = certificate_pkcs11->p->f->C_Decrypt ( + certificate_pkcs11->session_handle, + (CK_BYTE_PTR)from, + from_size, + (CK_BYTE_PTR)to, + &size + )) != CKR_OK) { + _mycms_error_entry_dispatch(__error_entry_pkcs11_rv(rv, _mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.op.decrypt.post", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Decrypt failed for '%s'", + certificate_pkcs11->display + ))); + goto cleanup; + } + break; + } + + ret = size; + +cleanup: + + return ret; +} + +static +bool +__driver_free( + const mycms_certificate certificate +) { + mycms_system system = NULL; + __mycms_certificate_driver_pkcs11 certificate_pkcs11 = NULL; + bool ret = false; + + if ((system = __get_system(certificate)) == NULL) { + goto cleanup; + } + + if ((certificate_pkcs11 = (__mycms_certificate_driver_pkcs11)mycms_certificate_get_driverdata(certificate)) == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.free", + MYCMS_ERROR_CODE_CRYPTO, + false, + "Failed to acquire PKCS#11 context" + )); + goto cleanup; + } + + certificate_pkcs11->key_handle = __INVALID_OBJECT_HANDLE; + if (certificate_pkcs11->session_handle != __INVALID_SESSION_HANDLE) { + certificate_pkcs11->p->f->C_Logout(certificate_pkcs11->session_handle); + certificate_pkcs11->p->f->C_CloseSession(certificate_pkcs11->session_handle); + certificate_pkcs11->session_handle = __INVALID_SESSION_HANDLE; + } + + mycms_system_free(system, "certificate_pkcs11.id.data", certificate_pkcs11->id.data); + certificate_pkcs11->id.data = NULL; + + mycms_system_free(system, "certificate_pkcs11.token_label", certificate_pkcs11->token_label); + certificate_pkcs11->token_label = NULL; + + if (certificate_pkcs11->p != NULL) { + certificate_pkcs11->p->reference_count--; + certificate_pkcs11->p = NULL; + } + mycms_system_free(system, "certificate_pkcs11", certificate_pkcs11); + + __unload_provider(certificate); + + ret = true; + +cleanup: + + return ret; +} + +static +bool +__driver_load( + const mycms_certificate certificate, + const mycms_dict parameters +) { + mycms_system system = NULL; + __mycms_certificate_driver_pkcs11 certificate_pkcs11 = NULL; + + CK_RV rv = CKR_FUNCTION_FAILED; + + const char *module = NULL; + const char *token_label = NULL; + const char *cert_label = NULL; + + bool ret = false; + + const int CERT_ATTRS_ID = 0; + const int CERT_ATTRS_VALUE = 1; + CK_ATTRIBUTE cert_attrs[] = { + {CKA_ID, NULL, 0}, + {CKA_VALUE, NULL, 0} + }; + + if (certificate == NULL) { + return false; + } + + if (parameters == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.load", + MYCMS_ERROR_CODE_ARGS, + true, + "Parameters must be provided" + )); + goto cleanup; + } + + if ((system = __get_system(certificate)) == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.load", + MYCMS_ERROR_CODE_ARGS, + true, + "Cannot get system context" + )); + goto cleanup; + } + + if ((module = mycms_dict_entry_get(parameters, "module", NULL)) == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.load", + MYCMS_ERROR_CODE_ARGS, + true, + "No module attribute in parameters" + )); + goto cleanup; + } + + if ((token_label = mycms_dict_entry_get(parameters, "token-label", NULL)) == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.load", + MYCMS_ERROR_CODE_ARGS, + true, + "No token-label attribute in parameters" + )); + goto cleanup; + } + + if ((cert_label = mycms_dict_entry_get(parameters, "cert-label", NULL)) == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.load", + MYCMS_ERROR_CODE_ARGS, + true, + "No cert-label attribute in parameters" + )); + goto cleanup; + } + + if ((certificate_pkcs11 = mycms_system_zalloc(system, "certificate_pkcs11", sizeof(*certificate_pkcs11))) == NULL) { + goto cleanup; + } + snprintf( + certificate_pkcs11->display, + sizeof(certificate_pkcs11->display), + "PKCS#11: module='%s', token='%s', cert='%s'", + module, + token_label, + cert_label + ); + certificate_pkcs11->certificate = certificate; + certificate_pkcs11->token_label = mycms_system_strdup(system, "certificate_pkcs11.token_label", token_label); + certificate_pkcs11->session_handle = __INVALID_SESSION_HANDLE; + certificate_pkcs11->key_handle = __INVALID_OBJECT_HANDLE; + + if (!mycms_certificate_set_driverdata(certificate, certificate_pkcs11)) { + goto cleanup; + } + + if ((certificate_pkcs11->p = __load_provider(certificate, module, mycms_dict_entry_get(parameters, "init-reserved", NULL))) == NULL) { + goto cleanup; + } + + if (!__open_slot(certificate)) { + goto cleanup; + } + + { + CK_OBJECT_CLASS c = CKO_CERTIFICATE; + const CK_ATTRIBUTE filter[] = { + {CKA_CLASS, &c, sizeof(c)}, + {CKA_LABEL, (char *)cert_label, strlen(cert_label)} + }; + mycms_blob blob; + CK_OBJECT_HANDLE o; + + if ((rv = __find_object( + certificate_pkcs11, + filter, + sizeof(filter) / sizeof(*filter), + &o + )) != CKR_OK) { + _mycms_error_entry_dispatch(__error_entry_pkcs11_rv(rv, _mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_certificate_get_context(certificate))), + "certificate.driver.pkcs11.load.objects", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to find '%s'", + certificate_pkcs11->display + ))); + goto cleanup; + } + + if (o == __INVALID_OBJECT_HANDLE) { + goto cleanup; + } + + if (__get_object_attributes( + system, + certificate_pkcs11, + o, + cert_attrs, + sizeof(cert_attrs) / sizeof(*cert_attrs) + ) != CKR_OK) { + goto cleanup; + } + + if (cert_attrs[CERT_ATTRS_ID].ulValueLen == CK_UNAVAILABLE_INFORMATION) { + goto cleanup; + } + + if (cert_attrs[CERT_ATTRS_VALUE].ulValueLen == CK_UNAVAILABLE_INFORMATION) { + goto cleanup; + } + + if (cert_attrs[CERT_ATTRS_ID].ulValueLen < 1) { + goto cleanup; + } + + certificate_pkcs11->id.size = cert_attrs[CERT_ATTRS_ID].ulValueLen; + if ((certificate_pkcs11->id.data = mycms_system_zalloc(system, "certificate_pkcs11.id", certificate_pkcs11->id.size)) == NULL) { + goto cleanup; + } + memcpy(certificate_pkcs11->id.data, cert_attrs[CERT_ATTRS_ID].pValue, certificate_pkcs11->id.size); + blob.data = cert_attrs[CERT_ATTRS_VALUE].pValue; + blob.size = cert_attrs[CERT_ATTRS_VALUE].ulValueLen; + if (!mycms_certificate_apply_certificate(certificate, &blob)) { + goto cleanup; + } + } + + ret = true; + +cleanup: + + __free_attributes( + system, + cert_attrs, + sizeof(cert_attrs) / sizeof(*cert_attrs) + ); + + return ret; +} + +const char * +mycms_certificate_driver_pkcs11_usage(void) { + return ( + "CERTIFICATE EXPRESSION ATTRIBUTES\n" + "module: PKCS#11 module to load\n" + "token-label: token label\n" + "cert-label: certificate label\n" + "init-reserved: reserved C_Initialize argument\n" + "\n" + "PASSPHRASE EXPRESSION WHAT\n" + "token: token passphrase\n" + "key: key passphrase\n" + ); +} + +bool +mycms_certificate_driver_pkcs11_apply( + const mycms_certificate certificate +) { + bool ret = false; + + if (certificate == NULL) { + return false; + } + + if (!mycms_certificate_set_driver_free(certificate, __driver_free)) { + goto cleanup; + } + + if (!mycms_certificate_set_driver_load(certificate, __driver_load)) { + goto cleanup; + } + + if (!mycms_certificate_set_driver_rsa_private_op(certificate, __driver_rsa_private_op)) { + goto cleanup; + } + + ret = true; + +cleanup: + + return ret; +} diff --git a/src/libmycms/mycms-certificate-driver-pkcs11.exports b/src/libmycms/mycms-certificate-driver-pkcs11.exports new file mode 100644 index 0000000..e784453 --- /dev/null +++ b/src/libmycms/mycms-certificate-driver-pkcs11.exports @@ -0,0 +1,2 @@ +mycms_certificate_driver_pkcs11_apply +mycms_certificate_driver_pkcs11_usage diff --git a/src/libmycms/mycms-certificate-private.h b/src/libmycms/mycms-certificate-private.h new file mode 100644 index 0000000..4d48221 --- /dev/null +++ b/src/libmycms/mycms-certificate-private.h @@ -0,0 +1,19 @@ +#ifndef __MYCMS_CERTIFICATE_PRIVATE_H +#define __MYCMS_CERTIFICATE_PRIVATE_H + +#include +#include + +#include + +X509 * +_mycms_certificate_get_X509( + const mycms_certificate certificate +); + +EVP_PKEY * +_mycms_certificate_get_EVP_PKEY( + const mycms_certificate certificate +); + +#endif diff --git a/src/libmycms/mycms-certificate.c b/src/libmycms/mycms-certificate.c new file mode 100644 index 0000000..7795471 --- /dev/null +++ b/src/libmycms/mycms-certificate.c @@ -0,0 +1,788 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include + +#include "mycms-error-internal.h" +#include "mycms-openssl.h" + +struct mycms_certificate_s { + mycms_context context; + const void *userdata; + const void *driverdata; + mycms_certificate_driver_free driver_free; + mycms_certificate_driver_load driver_load; + mycms_certificate_driver_rsa_private_op driver_rsa_private_op; + mycms_certificate_passphrase_callback passphrase_callback; + X509 *x509; + EVP_PKEY *evp; +}; + +static struct { +#ifndef OPENSSL_NO_RSA + RSA_METHOD *rsa_method; + int rsa_index; +#endif +} __openssl_methods; + +static int __convert_padding(const int padding) { + int ret; + switch (padding) { +#ifndef OPENSSL_NO_RSA + case RSA_PKCS1_PADDING: + ret = MYCMS_PADDING_PKCS1; + break; + case RSA_PKCS1_OAEP_PADDING: + ret = MYCMS_PADDING_OEAP; + break; + case RSA_NO_PADDING: + ret = MYCMS_PADDING_NONE; + break; +#endif + default: + ret = MYCMS_PADDING_INVALID; + break; + } + return ret; +} + +static +bool +__driver_free_default( + const mycms_certificate certificate __attribute__((unused)) +) { + return true; +} + +static +bool +__driver_load_default( + const mycms_certificate certificate, + const mycms_dict dict __attribute__((unused)) +) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(certificate->context)), + "certificate.load", + MYCMS_ERROR_CODE_NOT_IMPLEMENTED, + true, + "Certificate load is not implemented" + )); + + return false; +} + +static +int +driver_rsa_private_op_default( + const mycms_certificate certificate __attribute__((unused)), + const int op __attribute__((unused)), + const unsigned char * const from __attribute__((unused)), + const size_t from_size __attribute__((unused)), + unsigned char * const to __attribute__((unused)), + const size_t to_size __attribute__((unused)), + const int padding __attribute__((unused)) +) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(certificate->context)), + "certificate.op", + MYCMS_ERROR_CODE_NOT_IMPLEMENTED, + true, + "Private key is not available" + )); + + return -1; +} + +static +bool +passphrase_callback_default( + const mycms_certificate certificate __attribute__((unused)), + const char * const what __attribute__((unused)), + char **p, + const size_t size __attribute__((unused)) +) { + *p = NULL; + return true; +} + +static const struct mycms_certificate_s __MYCMS_CERTIFICATE_INIT[1] = {{ + NULL, + NULL, + NULL, + __driver_free_default, + __driver_load_default, + driver_rsa_private_op_default, + passphrase_callback_default, + NULL, + NULL +}}; + +#ifndef OPENSSL_NO_RSA + +static +bool +__setup_rsa_evp( + mycms_certificate certificate, + EVP_PKEY *evp +) { + RSA *rsa = NULL; + bool ret = false; + + if ((rsa = EVP_PKEY_get1_RSA(evp)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(certificate->context)), + "certificate.setup.rsa", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot get RSA out of EVP" + ))); + goto cleanup; + } + + if (!RSA_set_method(rsa, __openssl_methods.rsa_method)) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(certificate->context)), + "certificate.setup.method", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot set RSA method" + ))); + goto cleanup; + } + + if (!RSA_set_ex_data(rsa, __openssl_methods.rsa_index, certificate)) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(certificate->context)), + "certificate.setup.exdata", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot set RSA exdata" + ))); + goto cleanup; + } + + if (EVP_PKEY_set1_RSA(evp, rsa) != 1) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(certificate->context)), + "certificate.setup.rsa", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot set RSA of EVP" + ))); + goto cleanup; + } + + ret = true; + +cleanup: + + RSA_free(rsa); + rsa = NULL; + + return ret; +} + +static +mycms_certificate +__get_rsa_certificate( + RSA *rsa +) { + mycms_certificate certificate = NULL; + + if (rsa == NULL) { + goto cleanup; + } + + certificate = (mycms_certificate)RSA_get_ex_data(rsa, __openssl_methods.rsa_index); + +cleanup: + + return certificate; +} + +static +inline +int +__rsa_op( + int private_op, + int flen, + const unsigned char *from, + int tlen, + unsigned char *to, + RSA *rsa, + int padding +) { + mycms_certificate certificate; + int cpadding; + int ret = -1; + + if ((certificate = __get_rsa_certificate(rsa)) == NULL) { + goto cleanup; + } + + if (certificate->driver_rsa_private_op == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(certificate->context)), + "certificate.op", + MYCMS_ERROR_CODE_CRYPTO, + true, + "No registered RSA private key operation" + )); + goto cleanup; + } + + if ((cpadding = __convert_padding(padding)) == MYCMS_PADDING_INVALID) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(certificate->context)), + "certificate.op", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Padding %d is not supported", + padding + )); + goto cleanup; + } + + ret = certificate->driver_rsa_private_op( + certificate, + private_op, + from, + flen, + to, + tlen, + cpadding + ); + +cleanup: + + return ret; +} + +static +int +__openssl_rsa_enc( + int flen, + const unsigned char *from, + unsigned char *to, + RSA *rsa, + int padding +) { + return __rsa_op( + MYCMS_PRIVATE_OP_ENCRYPT, + flen, + from, + RSA_size(rsa), + to, + rsa, + padding + ); +} + +static +int +__openssl_rsa_dec( + int flen, + const unsigned char *from, + unsigned char *to, + RSA *rsa, + int padding +) { + return __rsa_op( + MYCMS_PRIVATE_OP_DECRYPT, + flen, + from, + flen, + to, + rsa, + padding + ); +} +#endif + +bool +_mycms_certificate_static_init( + const mycms_system system +) { +#ifndef OPENSSL_NO_RSA + RSA_METHOD *rsa_method = NULL; + int rsa_index = -1; +#endif + bool ret = false; + +#ifndef OPENSSL_NO_RSA + if (__openssl_methods.rsa_method == NULL) { + + if ((rsa_method = RSA_meth_dup(RSA_get_default_method())) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_system_get_error(system)), + "certificate.init.method", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot get RSA default method" + ))); + goto cleanup; + } + if (!RSA_meth_set1_name(rsa_method, "mycms")) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_system_get_error(system)), + "certificate.init.method.name", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot set method name" + ))); + goto cleanup; + } + if (!RSA_meth_set_priv_dec(rsa_method, __openssl_rsa_dec)) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_system_get_error(system)), + "certificate.init.method.op", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot set method priv dec" + ))); + goto cleanup; + } + if (!RSA_meth_set_priv_enc(rsa_method, __openssl_rsa_enc)) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_system_get_error(system)), + "certificate.init.method.op", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot set method priv enc" + ))); + goto cleanup; + } + + if ((rsa_index = RSA_get_ex_new_index( + 0, + "mycms", + NULL, + NULL, + NULL + )) == -1) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_system_get_error(system)), + "certificate.init.method.exdata.index", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot get exdata index" + ))); + goto cleanup; + } + } +#endif + +#ifndef OPENSSL_NO_RSA + __openssl_methods.rsa_method = rsa_method; + rsa_method = NULL; + __openssl_methods.rsa_index = rsa_index; +#endif + + ret = true; + +cleanup: + RSA_meth_free (rsa_method); + rsa_method = NULL; + + return ret; +} + +bool +_mycms_certificate_static_clean(void) { +#ifndef OPENSSL_NO_RSA + if (__openssl_methods.rsa_method != NULL) { + RSA_meth_free (__openssl_methods.rsa_method); + __openssl_methods.rsa_method = NULL; + } +#endif + return 1; +} + +mycms_certificate +mycms_certificate_new( + const mycms_context context +) { + mycms_system system = NULL; + mycms_certificate certificate = NULL; + + if (context == NULL) { + goto cleanup; + } + + if ((system = mycms_context_get_system(context)) == NULL) { + goto cleanup; + } + + if ((certificate = mycms_system_zalloc(system, "certificate", sizeof(*certificate))) == NULL) { + goto cleanup; + } + + memcpy(certificate, __MYCMS_CERTIFICATE_INIT, sizeof(__MYCMS_CERTIFICATE_INIT)); + certificate->context = context; + +cleanup: + + return certificate; +} + +bool +mycms_certificate_construct( + const mycms_certificate certificate __attribute__((unused)) +) { + if (certificate == NULL) { + return false; + } + + return true; +} + +bool +mycms_certificate_destruct( + const mycms_certificate certificate +) { + bool ret = true; + + if (certificate != NULL) { + mycms_system system = mycms_context_get_system(certificate->context); + + EVP_PKEY_free(certificate->evp); + certificate->evp = NULL; + + X509_free(certificate->x509); + certificate->x509 = NULL; + + ret = certificate->driver_free(certificate) && ret; + + ret = mycms_system_free(system, "certificate", certificate) && ret; + } + + return ret; +} + +mycms_context +mycms_certificate_get_context( + const mycms_certificate certificate +) { + if (certificate == NULL) { + return NULL; + } + + return certificate->context; +} + +const void * +mycms_certificate_get_userdata( + const mycms_certificate certificate +) { + if (certificate == NULL) { + return NULL; + } + + return certificate->userdata; +} + +bool +mycms_certificate_set_userdata( + const mycms_certificate certificate, + const void *userdata +) { + if (certificate == NULL) { + return NULL; + } + + certificate->userdata = userdata; + + return true; +} + +const void * +mycms_certificate_get_driverdata( + const mycms_certificate certificate +) { + if (certificate == NULL) { + return NULL; + } + + return certificate->driverdata; +} + +bool +mycms_certificate_set_driverdata( + const mycms_certificate certificate, + const void *driverdata +) { + certificate->driverdata = driverdata; + return true; +} + +bool +mycms_certificate_set_driver_load( + const mycms_certificate certificate, + const mycms_certificate_driver_load driver_load +) { + bool ret = false; + + if (certificate == NULL) { + return false; + } + + if (driver_load == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(certificate->context)), + "certificate.driver.load", + MYCMS_ERROR_CODE_ARGS, + true, + "Certificate driver load callback must be provided" + )); + goto cleanup; + } + + certificate->driver_load = driver_load; + + ret = true; + +cleanup: + + return ret; +} + +bool +mycms_certificate_set_driver_free( + const mycms_certificate certificate, + const mycms_certificate_driver_free driver_free +) { + bool ret = false; + + if (certificate == NULL) { + return false; + } + + if (driver_free == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(certificate->context)), + "certificate.driver.free", + MYCMS_ERROR_CODE_ARGS, + true, + "Certificate driver free callback must be provided" + )); + goto cleanup; + } + + certificate->driver_free = driver_free; + + ret = true; + +cleanup: + + return ret; +} + +bool +mycms_certificate_set_driver_rsa_private_op( + const mycms_certificate certificate, + const mycms_certificate_driver_rsa_private_op driver_rsa_private_op +) { + bool ret = false; + + if (certificate == NULL) { + return false; + } + + if (driver_rsa_private_op == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(certificate->context)), + "certificate.driver.op", + MYCMS_ERROR_CODE_ARGS, + true, + "Certificate driver private op callback must be provided" + )); + goto cleanup; + } + + certificate->driver_rsa_private_op = driver_rsa_private_op; + + ret = true; + +cleanup: + + return ret; +} + +bool +mycms_certificate_set_passphrase_callback( + const mycms_certificate certificate, + const mycms_certificate_passphrase_callback passphrase_callback +) { + bool ret = false; + + if (certificate == NULL) { + return false; + } + + if (passphrase_callback == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(certificate->context)), + "certificate.driver.passphrase", + MYCMS_ERROR_CODE_ARGS, + true, + "Certificate driver passphrase callback must be provided" + )); + goto cleanup; + } + + certificate->passphrase_callback = passphrase_callback; + + ret = true; + +cleanup: + + return ret; +} + +bool +mycms_certificate_load( + const mycms_certificate certificate, + const mycms_dict parameters +) { + if (certificate == NULL) { + return false; + } + + return certificate->driver_load(certificate, parameters); +} + +bool +mycms_certificate_apply_certificate( + const mycms_certificate certificate, + const mycms_blob *blob +) { + unsigned const char * p; + X509 *x509 = NULL; + EVP_PKEY *evp = NULL; + bool ret = false; + + if (certificate == NULL) { + return false; + } + + if (blob == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(certificate->context)), + "certificate.apply", + MYCMS_ERROR_CODE_ARGS, + true, + "Certificate must be provided" + )); + goto cleanup; + } + + p = blob->data; + if ((x509 = d2i_X509(NULL, &p, blob->size)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(certificate->context)), + "certificate.apply.x509", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot parse certificate" + ))); + goto cleanup; + } + + if ((evp = X509_get_pubkey(x509)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(certificate->context)), + "certificate.apply.pubkey", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot get public key out of certificate" + ))); + goto cleanup; + } + + switch (EVP_PKEY_id(evp)) { +#ifndef OPENSSL_NO_RSA + case EVP_PKEY_RSA: + if (!__setup_rsa_evp(certificate, evp)) { + goto cleanup; + } + break; +#endif + default: + goto cleanup; + } + + certificate->x509 = x509; + x509 = NULL; + certificate->evp = evp; + evp = NULL; + + ret = true; + +cleanup: + X509_free(x509); + x509 = NULL; + + EVP_PKEY_free(evp); + evp = NULL; + + return ret; +} + +bool +mycms_certificate_acquire_passphrase( + const mycms_certificate certificate, + const char * const what, + char **p, + const size_t size +) { + bool ret = false; + + if (certificate == NULL) { + return false; + } + + if (p == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(certificate->context)), + "certificate.passphrase", + MYCMS_ERROR_CODE_ARGS, + true, + "Passphrase buffer must be provided" + )); + goto cleanup; + } + + ret = certificate->passphrase_callback(certificate, what, p, size); + +cleanup: + + return ret; +} + +X509 * +_mycms_certificate_get_X509( + const mycms_certificate certificate +) { + if (certificate == NULL) { + return NULL; + } + + return certificate->x509; +} + +EVP_PKEY * +_mycms_certificate_get_EVP_PKEY( + const mycms_certificate certificate +) { + if (certificate == NULL) { + return NULL; + } + + return certificate->evp; +} diff --git a/src/libmycms/mycms-certificate.exports b/src/libmycms/mycms-certificate.exports new file mode 100644 index 0000000..b6d3f4e --- /dev/null +++ b/src/libmycms/mycms-certificate.exports @@ -0,0 +1,11 @@ +mycms_certificate_construct +mycms_certificate_destruct +mycms_certificate_get_driverdata +mycms_certificate_get_context +mycms_certificate_get_userdata +mycms_certificate_load +mycms_certificate_new +mycms_certificate_set_driver_load +mycms_certificate_set_driverdata +mycms_certificate_set_passphrase_callback +mycms_certificate_set_userdata diff --git a/src/libmycms/mycms-context-internal.h b/src/libmycms/mycms-context-internal.h new file mode 100644 index 0000000..0d7e481 --- /dev/null +++ b/src/libmycms/mycms-context-internal.h @@ -0,0 +1,17 @@ +#ifndef __MYCMS_CONTEXT_INTERNAL_H +#define __MYCMS_CONTEXT_INTERNAL_H + +#include + +void * +_mycms_context_get_pkcs11_state( + const mycms_context context +); + +bool +_mycms_context_set_pkcs11_state( + const mycms_context context, + void *pkcs11_state +); + +#endif diff --git a/src/libmycms/mycms-context.c b/src/libmycms/mycms-context.c new file mode 100644 index 0000000..c810269 --- /dev/null +++ b/src/libmycms/mycms-context.c @@ -0,0 +1,136 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include "mycms-context-internal.h" +#include "mycms-error-internal.h" + +struct __mycms_context_s { + mycms_system system; + void *pkcs11_state; + void *user_context; +}; + +mycms_context +mycms_context_new( + const mycms_system system +) { + mycms_context context = NULL; + mycms_context ret = NULL; + + mycms_static_init(system); + + if ((context = mycms_system_zalloc(system, "mycms_context", sizeof(*context))) == NULL) { + goto cleanup; + } + + context->system = system; + + ret = context; + context = NULL; + +cleanup: + + mycms_context_destruct(context); + + return ret; +} + +bool +mycms_context_construct( + const mycms_context context __attribute__((unused)) +) { + return true; +} + +bool +mycms_context_destruct( + const mycms_context context +) { + bool ret = true; + + if (context != NULL) { + ret = mycms_system_free(context->system, "mycms_context", context) && ret; + } + + return ret; +} + +mycms_system +mycms_context_get_system( + const mycms_context context +) { + if (context == NULL) { + return NULL; + } + return context->system; +} + +const void * +mycms_context_get_user_context( + const mycms_context context +) { + if (context == NULL) { + return NULL; + } + return context->user_context; +} + +bool +mycms_context_set_user_context( + const mycms_context context, + void *user_context +) { + if (context == NULL) { + return false; + } + context->user_context = user_context; + return true; +} + +mycms_error +mycms_context_get_error( + const mycms_context context +) { + if (context == NULL) { + return NULL; + } + return mycms_system_get_error(context->system); +} + +void +mycms_context_error_reset( + const mycms_context context +) { + mycms_error_reset(mycms_context_get_error(context)); +} + +void * +_mycms_context_get_pkcs11_state( + const mycms_context context +) { + if (context == NULL) { + return NULL; + } + + return context->pkcs11_state; +} + +bool +_mycms_context_set_pkcs11_state( + const mycms_context context, + void *pkcs11_state +) { + if (context == NULL) { + return false; + } + + context->pkcs11_state = pkcs11_state; + + return true; +} diff --git a/src/libmycms/mycms-context.exports b/src/libmycms/mycms-context.exports new file mode 100644 index 0000000..b35b160 --- /dev/null +++ b/src/libmycms/mycms-context.exports @@ -0,0 +1,8 @@ +mycms_context_construct +mycms_context_destruct +mycms_context_error_reset +mycms_context_get_error +mycms_context_get_system +mycms_context_get_user_context +mycms_context_new +mycms_context_set_user_context diff --git a/src/libmycms/mycms-core-decrypt.c b/src/libmycms/mycms-core-decrypt.c new file mode 100644 index 0000000..3966406 --- /dev/null +++ b/src/libmycms/mycms-core-decrypt.c @@ -0,0 +1,116 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include "mycms-certificate-private.h" +#include "mycms-error-internal.h" +#include "mycms-io-private.h" +#include "mycms-openssl.h" + +bool +mycms_decrypt( + const mycms mycms, + const mycms_certificate certificate, + const mycms_io cms_in, + const mycms_io data_pt, + const mycms_io data_ct +) { + CMS_ContentInfo *cms = NULL; + int flags = CMS_BINARY | CMS_DETACHED; + bool ret = false; + + if (mycms == NULL) { + goto cleanup; + } + + if (certificate == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.decrypt.args", + MYCMS_ERROR_CODE_ARGS, + true, + "Certificate is mandatory" + )); + goto cleanup; + } + + if (cms_in == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.decrypt.args", + MYCMS_ERROR_CODE_ARGS, + true, + "CMS input is mandatory" + )); + goto cleanup; + } + + if (data_pt == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.decrypt.args", + MYCMS_ERROR_CODE_ARGS, + true, + "Plaintext data is mandatory" + )); + goto cleanup; + } + + if (data_ct == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.decrypt.args", + MYCMS_ERROR_CODE_ARGS, + true, + "Ciphertext data is mandatory" + )); + goto cleanup; + } + + if ((cms = d2i_CMS_bio(_mycms_io_get_BIO(cms_in), NULL)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.decrypt.bio", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to parse CMS" + ))); + goto cleanup; + } + + if (!CMS_decrypt_set1_pkey(cms, _mycms_certificate_get_EVP_PKEY(certificate), _mycms_certificate_get_X509(certificate))) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.decrypt.key", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to set private key for CMS" + ))); + goto cleanup; + } + + if (!CMS_decrypt(cms, NULL, NULL, _mycms_io_get_BIO(data_ct), _mycms_io_get_BIO(data_pt), flags)) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.decrypt.decrypt", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to decrypt CMS" + ))); + goto cleanup; + } + + ret = true; + +cleanup: + + CMS_ContentInfo_free(cms); + cms = NULL; + + return ret; +} diff --git a/src/libmycms/mycms-core-decrypt.exports b/src/libmycms/mycms-core-decrypt.exports new file mode 100644 index 0000000..cf883aa --- /dev/null +++ b/src/libmycms/mycms-core-decrypt.exports @@ -0,0 +1 @@ +mycms_decrypt diff --git a/src/libmycms/mycms-core-encrypt.c b/src/libmycms/mycms-core-encrypt.c new file mode 100644 index 0000000..afaf8fc --- /dev/null +++ b/src/libmycms/mycms-core-encrypt.c @@ -0,0 +1,559 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include +#include + +#include "mycms-certificate-private.h" +#include "mycms-error-internal.h" +#include "mycms-io-private.h" +#include "mycms-openssl.h" + +static +STACK_OF(CMS_RecipientInfo) * +__add_recipients( + const mycms mycms, + CMS_ContentInfo *cms, + const mycms_list_blob to, + const mycms_dict keyopt, + int flags +) { + STACK_OF(CMS_RecipientInfo) *ret = NULL; + STACK_OF(CMS_RecipientInfo) *added = NULL; + X509 *x509 = NULL; + mycms_list_blob t; + + if ((added = sk_CMS_RecipientInfo_new_null()) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt.add.rcpt", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to create recipient info" + ))); + goto cleanup; + } + + for (t = to;t != NULL;t = t->next) { + CMS_RecipientInfo *ri; + EVP_PKEY_CTX *ctx; + mycms_list_dict_entry opt; + unsigned const char * p; + + p = t->blob.data; + if ((x509 = d2i_X509(NULL, &p, t->blob.size)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt.add.cert", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to parse certificate" + ))); + goto cleanup; + } + + if ((ri = CMS_add1_recipient_cert(cms, x509, flags | CMS_KEY_PARAM)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt.add.cert", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to add certificate as recipient" + ))); + goto cleanup; + } + + X509_free(x509); + x509 = NULL; + + if ((ctx = CMS_RecipientInfo_get0_pkey_ctx(ri)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt.add.prms", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to get key context" + ))); + goto cleanup; + } + + for (opt = mycms_dict_entries(keyopt); opt != NULL; opt = opt->next) { + if (!EVP_PKEY_CTX_ctrl_str(ctx, opt->entry.k, opt->entry.v)) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt.add.prms", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to get key parameters" + ))); + goto cleanup; + } + } + + sk_CMS_RecipientInfo_push(added, ri); + } + + ret = added; + added = NULL; + +cleanup: + X509_free(x509); + x509 = NULL; + + sk_CMS_RecipientInfo_free(added); + added = NULL; + + return ret; +} + +bool +mycms_encrypt( + const mycms mycms, + const char * const cipher_name, + const mycms_list_blob to, + const mycms_dict keyopt, + const mycms_io cms_out, + const mycms_io data_pt, + const mycms_io data_ct +) { + STACK_OF(CMS_RecipientInfo) *added = NULL; + const EVP_CIPHER *c = NULL; + CMS_ContentInfo *cms = NULL; + int flags = CMS_BINARY | CMS_DETACHED | CMS_PARTIAL | CMS_USE_KEYID; + bool ret = false; + + if (mycms == NULL) { + goto cleanup; + } + + if (cipher_name == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt.args", + MYCMS_ERROR_CODE_ARGS, + true, + "Cipher name is mandatory" + )); + goto cleanup; + } + + if (to == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt.args", + MYCMS_ERROR_CODE_ARGS, + true, + "Recipient name is mandatory" + )); + goto cleanup; + } + + if (cms_out == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt.args", + MYCMS_ERROR_CODE_ARGS, + true, + "CMS out is mandatory" + )); + goto cleanup; + } + + if (data_pt == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt.args", + MYCMS_ERROR_CODE_ARGS, + true, + "Plaintext data is mandatory" + )); + goto cleanup; + } + + if (data_ct == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt.args", + MYCMS_ERROR_CODE_ARGS, + true, + "Ciphertext data is mandatory" + )); + goto cleanup; + } + + if ((c = EVP_get_cipherbyname(cipher_name)) == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt.args", + MYCMS_ERROR_CODE_ARGS, + true, + "Cannot resolve cipher '%s'", + cipher_name + )); + goto cleanup; + } + + if ((cms = CMS_encrypt(NULL, NULL, c, flags)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt.encrypt", + MYCMS_ERROR_CODE_CRYPTO, + true, + "CMS encrypt failed" + ))); + goto cleanup; + } + + if ((added = __add_recipients(mycms, cms, to, keyopt, flags)) == NULL) { + goto cleanup; + } + + if (!CMS_final(cms, _mycms_io_get_BIO(data_pt), _mycms_io_get_BIO(data_ct), flags)) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt.encrypt", + MYCMS_ERROR_CODE_CRYPTO, + true, + "CMS final failed" + ))); + goto cleanup; + } + + if (i2d_CMS_bio(_mycms_io_get_BIO(cms_out), cms) <= 0) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt.encrypt", + MYCMS_ERROR_CODE_CRYPTO, + true, + "CMS serialization failed" + ))); + goto cleanup; + } + + ret = true; + +cleanup: + + sk_CMS_RecipientInfo_free(added); + added = NULL; + + CMS_ContentInfo_free(cms); + cms = NULL; + + return ret; +} + +bool +mycms_encrypt_add( + const mycms mycms, + const mycms_certificate certificate, + const mycms_list_blob to, + const mycms_dict keyopt, + const mycms_io cms_in, + const mycms_io cms_out +) { + STACK_OF(CMS_RecipientInfo) *added = NULL; + CMS_ContentInfo *cms = NULL; + int flags = CMS_BINARY | CMS_DETACHED | CMS_PARTIAL | CMS_USE_KEYID; + bool ret = false; + int i; + + if (mycms == NULL) { + goto cleanup; + } + + if (certificate == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt-add.args", + MYCMS_ERROR_CODE_ARGS, + true, + "Certificate is mandatory" + )); + goto cleanup; + } + + if (to == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt-add.args", + MYCMS_ERROR_CODE_ARGS, + true, + "Recipient is mandatory" + )); + goto cleanup; + } + + if (cms_in == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt-add.args", + MYCMS_ERROR_CODE_ARGS, + true, + "CMS input is mandatory" + )); + goto cleanup; + } + + if (cms_out == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt-add.args", + MYCMS_ERROR_CODE_ARGS, + true, + "CMS output is mandatory" + )); + goto cleanup; + } + + if ((cms = d2i_CMS_bio(_mycms_io_get_BIO(cms_in), NULL)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt-add.bio", + MYCMS_ERROR_CODE_CRYPTO, + true, + "CMS deserialization failed" + ))); + goto cleanup; + } + + if (!CMS_decrypt_set1_pkey(cms, _mycms_certificate_get_EVP_PKEY(certificate), _mycms_certificate_get_X509(certificate))) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt-add.bio", + MYCMS_ERROR_CODE_CRYPTO, + true, + "CMS set key failed" + ))); + goto cleanup; + } + + if ((added = __add_recipients(mycms, cms, to, keyopt, flags)) == NULL) { + goto cleanup; + } + + for (i = 0; i < sk_CMS_RecipientInfo_num(added); i++) { + CMS_RecipientInfo *ri = sk_CMS_RecipientInfo_value(added, i); + + if (!CMS_RecipientInfo_encrypt(cms, ri)) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt-add.encrypt", + MYCMS_ERROR_CODE_CRYPTO, + true, + "CMS recipient encryption failed" + ))); + goto cleanup; + } + } + + if (!CMS_final(cms, NULL, NULL, flags)) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt-add.encrypt", + MYCMS_ERROR_CODE_CRYPTO, + true, + "CMS encryption final failed" + ))); + goto cleanup; + } + + if (i2d_CMS_bio(_mycms_io_get_BIO(cms_out), cms) <= 0) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt-add.out", + MYCMS_ERROR_CODE_CRYPTO, + true, + "CMS serialization failed" + ))); + goto cleanup; + } + + ret = true; + +cleanup: + + sk_CMS_RecipientInfo_free(added); + added = NULL; + + CMS_ContentInfo_free(cms); + cms = NULL; + + return ret; +} + +bool +mycms_encrypt_reset( + const mycms mycms, + const mycms_list_blob to, + const mycms_io cms_in, + const mycms_io cms_out +) { + mycms_list_blob t; + CMS_ContentInfo *cms = NULL; + STACK_OF(CMS_RecipientInfo) *recps = NULL; + STACK_OF(CMS_RecipientInfo) *stash = NULL; + STACK_OF(X509) *certs = NULL; + bool ret = false; + int i; + + + if (mycms == NULL) { + goto cleanup; + } + + if (to == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt-reset.args", + MYCMS_ERROR_CODE_ARGS, + true, + "Recipient is mandatory" + )); + goto cleanup; + } + + if (cms_in == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt-reset.args", + MYCMS_ERROR_CODE_ARGS, + true, + "CMS input is mandatory" + )); + goto cleanup; + } + + if (cms_out == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt-reset.args", + MYCMS_ERROR_CODE_ARGS, + true, + "CMS output is mandatory" + )); + goto cleanup; + } + + if ((stash = sk_CMS_RecipientInfo_new_null()) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt-reset.init", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to allocate recipient info stack" + ))); + goto cleanup; + } + + if ((certs = sk_X509_new_null()) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt-reset.init", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to allocate certificate stack" + ))); + goto cleanup; + } + + if ((cms = d2i_CMS_bio(_mycms_io_get_BIO(cms_in), NULL)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt-reset.in", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to deserialize CMS" + ))); + goto cleanup; + } + + if ((recps = CMS_get0_RecipientInfos(cms)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt-reset.rcpt", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to get recipients out of CMS" + ))); + goto cleanup; + } + + for (t = to;t != NULL;t = t->next) { + X509 *x509; + unsigned const char * p; + + p = t->blob.data; + if ((x509 = d2i_X509(NULL, &p, t->blob.size)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt-reset.cert", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to parse recipient certificate" + ))); + goto cleanup; + } + + sk_X509_push(certs, x509); + } + + for (i = 0; i < sk_CMS_RecipientInfo_num(recps); ) { + CMS_RecipientInfo *ri = sk_CMS_RecipientInfo_value(recps, i); + bool found = false; + int j; + + for (j = 0; j < sk_X509_num(certs); j++) { + X509 *x509 = sk_X509_value(certs, j); + + if (CMS_RecipientInfo_ktri_cert_cmp(ri, x509) == 0) { + found = true; + break; + } + } + + if (found) { + i++; + } else { + sk_CMS_RecipientInfo_push(stash, sk_CMS_RecipientInfo_delete(recps, i)); + } + } + + if (i2d_CMS_bio(_mycms_io_get_BIO(cms_out), cms) <= 0) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.encrypt-reset.out", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to serialize CMS" + ))); + goto cleanup; + } + + ret = true; + +cleanup: + + /* + * HACK-BEGIN: + * There is no way to directly free CMS_RecipientInfo so reapply these to CMS_ContentInfo. + */ + for (i = 0; i < sk_CMS_RecipientInfo_num(stash); i++) { + CMS_RecipientInfo *ri = sk_CMS_RecipientInfo_value(stash, i); + sk_CMS_RecipientInfo_push(recps, ri); + } + /* HACK-END */ + + sk_CMS_RecipientInfo_free(stash); + + sk_X509_pop_free(certs, X509_free); + + CMS_ContentInfo_free(cms); + cms = NULL; + + return ret; +} diff --git a/src/libmycms/mycms-core-encrypt.exports b/src/libmycms/mycms-core-encrypt.exports new file mode 100644 index 0000000..91dd6c9 --- /dev/null +++ b/src/libmycms/mycms-core-encrypt.exports @@ -0,0 +1,3 @@ +mycms_encrypt +mycms_encrypt_add +mycms_encrypt_reset diff --git a/src/libmycms/mycms-core-sign.c b/src/libmycms/mycms-core-sign.c new file mode 100644 index 0000000..d06dda1 --- /dev/null +++ b/src/libmycms/mycms-core-sign.c @@ -0,0 +1,178 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include "mycms-certificate-private.h" +#include "mycms-error-internal.h" +#include "mycms-io-private.h" +#include "mycms-openssl.h" + +bool +mycms_sign( + const mycms mycms, + const mycms_certificate certificate, + const mycms_list_str digests, + const mycms_dict keyopt, + const mycms_io cms_in, + const mycms_io cms_out, + const mycms_io data_in +) { + CMS_ContentInfo *cms = NULL; + EVP_PKEY_CTX *ctx = NULL; + mycms_list_str t; + int flags = CMS_BINARY | CMS_DETACHED | CMS_USE_KEYID | CMS_NOCERTS | CMS_NOSMIMECAP; + bool ret = false; + + if (mycms == NULL) { + goto cleanup; + } + + if (certificate == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.sign.args", + MYCMS_ERROR_CODE_ARGS, + true, + "Certificate is mandatory" + )); + goto cleanup; + } + + if (cms_in == NULL) { + flags |= CMS_PARTIAL; + if ((cms = CMS_sign(NULL, NULL, NULL, NULL, flags)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.sign.init", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to initiate CMS sign" + ))); + goto cleanup; + } + } else { + if ((cms = d2i_CMS_bio(_mycms_io_get_BIO(cms_in), NULL)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.sign.init", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to deserialize CMS" + ))); + goto cleanup; + } + } + + if (data_in == NULL) { + flags |= CMS_REUSE_DIGEST; + } + + for (t = digests;t != NULL; t = t->next) { + const EVP_MD *digest = NULL; + CMS_SignerInfo *signer = NULL; + mycms_list_dict_entry opt; + + if ((digest = EVP_get_digestbyname(t->str)) == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.sign.algo", + MYCMS_ERROR_CODE_ARGS, + true, + "Failed to resolve digest '%s'", + t->str + )); + goto cleanup; + } + + if ((signer = CMS_add1_signer( + cms, + _mycms_certificate_get_X509(certificate), + _mycms_certificate_get_EVP_PKEY(certificate), + digest, + flags | (mycms_dict_entries(keyopt) == NULL ? 0 : CMS_KEY_PARAM) /* Does not work for 2nd sign, see https://github.com/openssl/openssl/issues/14257 */ + )) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.sign.add", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to add signer" + ))); + goto cleanup; + } + + if (mycms_dict_entries(keyopt) != NULL) { /* TODO: remove when openssl bug fixed */ + if ((ctx = CMS_SignerInfo_get0_pkey_ctx(signer)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.sign.add.prm", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to resolve signer key" + ))); + goto cleanup; + } + + for (opt = mycms_dict_entries(keyopt); opt != NULL; opt = opt->next) { + if (!EVP_PKEY_CTX_ctrl_str(ctx, opt->entry.k, opt->entry.v)) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.sign.add.prm", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to set signer key parameters" + ))); + goto cleanup; + } + } + } + } + + if (cms_in != NULL) { + if (!i2d_CMS_bio_stream(_mycms_io_get_BIO(cms_out), cms, _mycms_io_get_BIO(data_in), flags)) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.sign.out", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Failed to serialize CMS (redo)" + ))); + goto cleanup; + } + } else { + if (!CMS_final(cms, _mycms_io_get_BIO(data_in), NULL, flags)) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.sign.out", + MYCMS_ERROR_CODE_CRYPTO, + true, + "CMS serialization final" + ))); + goto cleanup; + } + if (i2d_CMS_bio(_mycms_io_get_BIO(cms_out), cms) <= 0) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.sign.out", + MYCMS_ERROR_CODE_CRYPTO, + true, + "CMS serialization write" + ))); + goto cleanup; + } + } + + ret = true; + +cleanup: + + CMS_ContentInfo_free(cms); + cms = NULL; + + return ret; +} diff --git a/src/libmycms/mycms-core-sign.exports b/src/libmycms/mycms-core-sign.exports new file mode 100644 index 0000000..9fca196 --- /dev/null +++ b/src/libmycms/mycms-core-sign.exports @@ -0,0 +1 @@ +mycms_sign diff --git a/src/libmycms/mycms-core-verify.c b/src/libmycms/mycms-core-verify.c new file mode 100644 index 0000000..5a02792 --- /dev/null +++ b/src/libmycms/mycms-core-verify.c @@ -0,0 +1,461 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include +#include + +#include "mycms-error-internal.h" +#include "mycms-io-private.h" +#include "mycms-openssl.h" + +struct internal_signer_s { + X509 *x509; + ASN1_OBJECT *digest; + bool found; +}; +MYCMS_LIST_DECLARE(internal_signer, struct internal_signer_s, signer) + +static +void +__internal_signer_free( + mycms_system system, + const mycms_list_internal_signer l +) { + mycms_list_internal_signer _l = l; + while (_l != NULL) { + mycms_list_internal_signer t = _l; + _l = _l->next; + + X509_free(t->signer.x509); + t->signer.x509 = NULL; + ASN1_OBJECT_free(t->signer.digest); + t->signer.digest = NULL; + mycms_system_free(system, "signer", t); + } +} + +static +mycms_list_internal_signer +__mycms_list_signer_to_internal( + mycms_system system, + const mycms_list_signer l +) { + mycms_list_signer e; + mycms_list_internal_signer ret = NULL; + mycms_list_internal_signer signers = NULL; + + for (e = l;e != NULL;e = e->next) { + mycms_list_internal_signer t; + unsigned const char * p; + + if ((t = mycms_system_zalloc(system, "signer", sizeof(*t))) == NULL) { + goto cleanup; + } + t->next = signers; + signers = t; + + p = e->signer.cert.data; + if ((t->signer.x509 = d2i_X509(NULL, &p, e->signer.cert.size)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_system_get_error(system)), + "core.verify.list", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot parse signer certificate" + ))); + goto cleanup; + } + + if (e->signer.digest != NULL) { + if ((t->signer.digest = OBJ_txt2obj(e->signer.digest, 0)) == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_system_get_error(system)), + "core.verify.list", + MYCMS_ERROR_CODE_ARGS, + true, + "Cannot resolve signer digest" + )); + goto cleanup; + } + } + } + + ret = signers; + signers = NULL; + +cleanup: + + __internal_signer_free(system, signers); + signers = NULL; + + return ret; +} + +bool +mycms_verify_list_free( + const mycms mycms, + const mycms_list_signer l +) { + mycms_system system = NULL; + mycms_list_signer t; + bool ret = false; + + if (mycms == NULL) { + goto cleanup; + } + + if ((system = mycms_get_system(mycms)) == NULL) { + goto cleanup; + } + + t = l; + while(t != NULL) { + mycms_list_signer x = t; + t = x->next; + mycms_system_free(system, "signer.keyid", x->signer.keyid.data); + mycms_system_free(system, "signer.digest", x->signer.digest); + mycms_system_free(system, "signer", x); + } + + ret = true; + +cleanup: + + return ret; +} + +bool +mycms_verify_list( + const mycms mycms, + const mycms_io cms_in, + mycms_list_signer * const signers +) { + mycms_system system = NULL; + CMS_ContentInfo *cms = NULL; + STACK_OF(CMS_SignerInfo) *signerids = NULL; + mycms_list_signer _signers = NULL; + int i; + bool ret = false; + + if (mycms == NULL) { + goto cleanup; + } + + if ((system = mycms_get_system(mycms)) == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.verify-list.args", + MYCMS_ERROR_CODE_ARGS, + true, + "Cannot get system context" + )); + goto cleanup; + } + + if (cms_in == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.verify-list.args", + MYCMS_ERROR_CODE_ARGS, + true, + "CMS input is mandatory" + )); + goto cleanup; + } + + if (signers == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.verify-list.args", + MYCMS_ERROR_CODE_ARGS, + true, + "Signers are mandatory" + )); + goto cleanup; + } + + *signers = NULL; + + if ((cms = d2i_CMS_bio(_mycms_io_get_BIO(cms_in), NULL)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.verify-list.list", + MYCMS_ERROR_CODE_CRYPTO, + true, + "CMS deserialization failed" + ))); + goto cleanup; + } + + if ((signerids = CMS_get0_SignerInfos(cms)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.verify-list.list", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot get signers out of CMS" + ))); + goto cleanup; + } + + for (i = 0; i < sk_CMS_SignerInfo_num(signerids); i++) { + CMS_SignerInfo *signer = sk_CMS_SignerInfo_value(signerids, i); + ASN1_OCTET_STRING *keyid = NULL; + + if (CMS_SignerInfo_get0_signer_id(signer, &keyid, NULL, NULL)) { + mycms_list_signer t = NULL; + X509_ALGOR *dig = NULL; + char digest[256]; + + if ((t = mycms_system_zalloc(system, "signer", sizeof(*t))) == NULL) { + goto cleanup; + } + + t->next = _signers; + _signers = t; + + t->signer.keyid.size = keyid->length; + if ((t->signer.keyid.data = mycms_system_zalloc(system, "signer.keyid", t->signer.keyid.size)) == NULL) { + goto cleanup; + } + memcpy(t->signer.keyid.data, keyid->data, t->signer.keyid.size); + + CMS_SignerInfo_get0_algs(signer, NULL, NULL, &dig, NULL); + if (!OBJ_obj2txt(digest, sizeof(digest), dig->algorithm, 0)) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.verify-list.do", + MYCMS_ERROR_CODE_ARGS, + true, + "Cannot resolve signer algorithm" + )); + goto cleanup; + } + t->signer.digest = mycms_system_strdup(system, "signer.digest", digest); + } + } + + *signers = _signers; + _signers = NULL; + + ret = true; + +cleanup: + + mycms_verify_list_free(mycms, _signers); + _signers = NULL; + + CMS_ContentInfo_free(cms); + cms = NULL; + + return ret; +} + +bool +mycms_verify( + const mycms mycms, + mycms_io cms_in, + mycms_io data_in, + const mycms_list_signer signers, + bool * const verified +) { +#if 0 + const int flags = CMS_DETACHED | CMS_BINARY | CMS_NO_SIGNER_CERT_VERIFY | CMS_NO_CONTENT_VERIFY; + CMS_verify(cms, _certs, NULL, _mycms_io_get_BIO(data_in), NULL, flags); +#endif + mycms_system system = NULL; + mycms_list_internal_signer isigners = NULL; + mycms_list_internal_signer isigners_i = NULL; + CMS_ContentInfo *cms = NULL; + STACK_OF(CMS_SignerInfo) *signerids = NULL; + BIO *cmsbio = NULL; + unsigned char buf[4096]; + bool ret = false; + + if (mycms == NULL) { + goto cleanup; + } + + if ((system = mycms_get_system(mycms)) == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.verify.args", + MYCMS_ERROR_CODE_ARGS, + true, + "Cannot get system context" + )); + goto cleanup; + } + + if (cms_in == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.verify.args", + MYCMS_ERROR_CODE_ARGS, + true, + "CMS input is mandatory" + )); + goto cleanup; + } + + if (data_in == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.verify.args", + MYCMS_ERROR_CODE_ARGS, + true, + "Data input is mandatory" + )); + goto cleanup; + } + + if (verified == NULL) { + _mycms_error_entry_dispatch(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.verify.args", + MYCMS_ERROR_CODE_ARGS, + true, + "Verified flag is mandatory" + )); + goto cleanup; + } + + *verified = false; + + if ((isigners = __mycms_list_signer_to_internal(system, signers)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.verify.list", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot get signers out of CMS" + ))); + goto cleanup; + } + + if ((cms = d2i_CMS_bio(_mycms_io_get_BIO(cms_in), NULL)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.verify.in", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot deserialize CMS" + ))); + goto cleanup; + } + + if ((signerids = CMS_get0_SignerInfos(cms)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.verify.in", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot get signers out of the CMS" + ))); + goto cleanup; + } + + if (sk_CMS_SignerInfo_num(signerids) <= 0) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.verify.in", + MYCMS_ERROR_CODE_CRYPTO, + true, + "No signers" + ))); + goto cleanup; + } + + /* + * Do not use CMS_verify: + * 1. It iterates all certificates and verify signature (resources) + * 2. It must have access to all signer certificates + */ + if ((cmsbio = CMS_dataInit(cms, _mycms_io_get_BIO(data_in))) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.verify.do", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot initialize CMS data input" + ))); + goto cleanup; + } + + { + /* + * Run through input and update digest + */ + int x; + while ((x = BIO_read(cmsbio, buf, sizeof(buf))) > 0); + if (x < 0) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.verify.do", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Cannot read CMS data" + ))); + goto cleanup; + } + } + + ret = true; + + for (isigners_i = isigners; isigners_i != NULL; isigners_i = isigners_i->next) { + int i; + for (i = 0; i < sk_CMS_SignerInfo_num(signerids); i++) { + CMS_SignerInfo *signer = sk_CMS_SignerInfo_value(signerids, i); + + if (!CMS_SignerInfo_cert_cmp(signer, isigners_i->signer.x509)) { + X509_ALGOR *dig = NULL; + + CMS_SignerInfo_get0_algs(signer, NULL, NULL, &dig, NULL); + + if (isigners_i->signer.digest == NULL || OBJ_cmp(dig->algorithm, isigners_i->signer.digest) == 0) { + if (CMS_SignerInfo_verify_content(signer, cmsbio) <= 0) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(mycms_get_context(mycms))), + "core.verify.do", + MYCMS_ERROR_CODE_CRYPTO, + true, + "Verify failed" + ))); + goto cleanup; + } + isigners_i->signer.found = true; + } + } + } + } + + *verified = true; + for (isigners_i = isigners; isigners_i != NULL; isigners_i = isigners_i->next) { + *verified = *verified && isigners_i->signer.found; + } + +cleanup: + + __internal_signer_free(system, isigners); + isigners = NULL; + + { + BIO *tbio; + do { + tbio = BIO_pop(cmsbio); + BIO_free(cmsbio); + cmsbio = tbio; + } while (cmsbio != NULL && cmsbio != _mycms_io_get_BIO(data_in)); + } + cmsbio = NULL; + + CMS_ContentInfo_free(cms); + cms = NULL; + + return ret; +} diff --git a/src/libmycms/mycms-core-verify.exports b/src/libmycms/mycms-core-verify.exports new file mode 100644 index 0000000..8554ff0 --- /dev/null +++ b/src/libmycms/mycms-core-verify.exports @@ -0,0 +1,3 @@ +mycms_verify +mycms_verify_list +mycms_verify_list_free diff --git a/src/libmycms/mycms-dict.c b/src/libmycms/mycms-dict.c new file mode 100644 index 0000000..a361004 --- /dev/null +++ b/src/libmycms/mycms-dict.c @@ -0,0 +1,285 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include + +#include + +struct mycms_dict_s { + mycms_context context; + mycms_list_dict_entry head; +}; + +static +void +__free_entry( + const mycms_system system, + const mycms_list_dict_entry entry +) { + if (entry != NULL) { + mycms_system_free(system, "dict.entry.k", (void *)entry->entry.k); + entry->entry.k = NULL; + + mycms_system_free(system, "dict.entry.v", (void *)entry->entry.v); + entry->entry.v = NULL; + + mycms_system_free(system, "dict.entry", entry); + } +} + +mycms_dict +mycms_dict_new( + const mycms_context context +) { + mycms_system system = NULL; + mycms_dict dict = NULL; + + if (context == NULL) { + return NULL; + } + + if ((system = mycms_context_get_system(context)) == NULL) { + goto cleanup; + } + + if ((dict = mycms_system_zalloc(system, "dict", sizeof(*dict))) == NULL) { + goto cleanup; + } + + dict->context = context; + +cleanup: + + return dict; +} + +bool +mycms_dict_construct( + const mycms_dict dict +) { + if (dict == NULL) { + return false; + } + + return true; +} + +bool +mycms_dict_destruct( + const mycms_dict dict +) { + bool ret = true; + + if (dict != NULL) { + mycms_system system = mycms_context_get_system(dict->context); + + ret = mycms_dict_entry_clear(dict) && ret; + ret = mycms_system_free(system, "dict", dict) && ret; + } + + return ret; +} + +mycms_context +mycms_dict_get_context( + const mycms_dict dict +) { + mycms_context ret = NULL; + + if (dict == NULL) { + goto cleanup; + } + + ret = dict->context; + +cleanup: + + return ret; +} + +bool +mycms_dict_entry_clear( + const mycms_dict dict +) { + mycms_system system = NULL; + bool ret = false; + + if (dict == NULL) { + goto cleanup; + } + + if ((system = mycms_context_get_system(dict->context)) == NULL) { + goto cleanup; + } + + while(dict->head != NULL) { + mycms_list_dict_entry t = dict->head; + dict->head = dict->head->next; + __free_entry(system, t); + } + + ret = true; + +cleanup: + + return ret; +} + +bool +mycms_dict_entry_put( + const mycms_dict dict, + const char * const k, + const char * const v +) { + mycms_system system = NULL; + mycms_list_dict_entry t = NULL; + const char *vdup = NULL; + bool ret = false; + + if (dict == NULL) { + return false; + } + + if (k == NULL) { + goto cleanup; + } + + if ((system = mycms_context_get_system(dict->context)) == NULL) { + goto cleanup; + } + + if (v != NULL) { + if ((vdup = mycms_system_strdup(system, "dict.entry.v", v)) == NULL) { + goto cleanup; + } + } + + for (t = dict->head; t != NULL; t = t->next) { + if (!strcmp(k, t->entry.k)) { + break; + } + } + if (t != NULL) { + mycms_system_free(system, "dict.entry.v", (void *)t->entry.v); + t->entry.v = vdup; + vdup = NULL; + t = NULL; + } else { + if ((t = mycms_system_zalloc(system, "dict.entry", sizeof(*t))) == NULL) { + goto cleanup; + } + if ((t->entry.k = mycms_system_strdup(system, "dict.entry.k", k)) == NULL) { + goto cleanup; + } + t->entry.v = vdup; + vdup = NULL; + t->next = dict->head; + dict->head = t; + t = NULL; + } + + ret = true; + +cleanup: + __free_entry(system, t); + + return ret; +} + +const char * +mycms_dict_entry_get( + const mycms_dict dict, + const char * const k, + bool * const found +) { + mycms_list_dict_entry t; + const char *ret = NULL; + + if (found != NULL) { + *found = false; + } + + if (dict == NULL) { + return NULL; + } + + if (k == NULL) { + goto cleanup; + } + + for (t = dict->head; t != NULL; t = t->next) { + if (!strcmp(k, t->entry.k)) { + break; + } + } + + if (t != NULL) { + if (found != NULL) { + *found = true; + } + ret = t->entry.v; + } + +cleanup: + + return ret; +} + +bool +mycms_dict_entry_del( + const mycms_dict dict, + const char * const k +) { + mycms_system system = NULL; + mycms_list_dict_entry p; + mycms_list_dict_entry t; + bool ret = false; + + if (dict == NULL) { + goto cleanup; + } + + if (k == NULL) { + goto cleanup; + } + + if ((system = mycms_context_get_system(dict->context)) == NULL) { + goto cleanup; + } + + for (p = NULL, t = dict->head; t != NULL; p = t, t = t->next) { + if (!strcmp(k, t->entry.k)) { + break; + } + } + + if (t != NULL) { + if (p == NULL) { + dict->head = t->next; + } else { + p->next = t->next; + } + __free_entry(system, t); + t = NULL; + } + + ret = true; + +cleanup: + + return ret; +} + +mycms_list_dict_entry +mycms_dict_entries( + const mycms_dict dict +) { + if (dict == NULL) { + return NULL; + } + + return dict->head; +} diff --git a/src/libmycms/mycms-dict.exports b/src/libmycms/mycms-dict.exports new file mode 100644 index 0000000..d0791c8 --- /dev/null +++ b/src/libmycms/mycms-dict.exports @@ -0,0 +1,9 @@ +mycms_dict_construct +mycms_dict_destruct +mycms_dict_entries +mycms_dict_entry_clear +mycms_dict_entry_del +mycms_dict_entry_get +mycms_dict_entry_put +mycms_dict_get_context +mycms_dict_new diff --git a/src/libmycms/mycms-error-internal.h b/src/libmycms/mycms-error-internal.h new file mode 100644 index 0000000..8a8cc95 --- /dev/null +++ b/src/libmycms/mycms-error-internal.h @@ -0,0 +1,113 @@ +#ifndef __MYCMS_ERROR_INTERNAL_H +#define __MYCMS_ERROR_INTERNAL_H + +#include +#include +#include + +#include +#include + +void +_mycms_error_register_key_desc( + struct mycms_error_desc_s * const _desc, + const size_t n +); + +mycms_error +_mycms_error_new( + const mycms_system system +); + +bool +_mycms_error_construct( + const mycms_error error +); + +bool +_mycms_error_destruct( + const mycms_error error +); + +mycms_error_entry +_mycms_error_entry_new( + const mycms_error error +); + +void +_mycms_error_entry_dispatch( + const mycms_error_entry entry +); + +mycms_variant * +_mycms_error_entry_prm_new_variant( + const mycms_error_entry entry, + const int k +); + +mycms_error_entry +_mycms_error_entry_prm_add_u32( + const mycms_error_entry entry, + const int k, + const uint32_t u32 +); + +mycms_error_entry +_mycms_error_entry_prm_add_u64( + const mycms_error_entry entry, + const int k, + const uint32_t u64 +); + +mycms_error_entry +_mycms_error_entry_prm_add_str( + const mycms_error_entry entry, + const int k, + const char * const str +); + +mycms_error_entry +_mycms_error_entry_prm_add_blob( + const mycms_error_entry entry, + const int k, + const unsigned char * const d, + const size_t s +); + +mycms_error_entry +_mycms_error_entry_vsprintf( + const mycms_error_entry entry, + const int k, + const char * const format, + va_list ap +); + +mycms_error_entry +_mycms_error_entry_sprintf( + const mycms_error_entry entry, + const int k, + const char * const format, + ... +) __attribute__((format(printf, 3, 4))); + +mycms_error_entry +_mycms_error_capture_indirect( + const mycms_error error, + const char * const file, + const int line, + const char * const func +); +#define _mycms_error_capture(error) \ + _mycms_error_capture_indirect((error), __FILE__, __LINE__, __func__) + +mycms_error_entry +_mycms_error_entry_base( + const mycms_error_entry entry, + const char * const hint, + const uint32_t code, + const bool authoritative, + const char * const format, + ... +) __attribute__((format(printf, 5, 6))); + +#endif diff --git a/src/libmycms/mycms-error.c b/src/libmycms/mycms-error.c new file mode 100644 index 0000000..88f3396 --- /dev/null +++ b/src/libmycms/mycms-error.c @@ -0,0 +1,586 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include "mycms-error-internal.h" +#include "mycms-util.h" + +#define __MYCMS_ERROR_MAX_KEY_DESC 256 +#define __MYCMS_ERROR_MAX_ENTRIES 50 +#define __MYCMS_ERROR_MAX_PRMS 20 + +struct __mycms_error_entry_s { + mycms_error error; + unsigned n; + struct mycms_error_prm_s prms[__MYCMS_ERROR_MAX_PRMS]; +}; + +struct __mycms_error_s { + mycms_system system; + mycms_variant vars[__MYCMS_ERROR_MAX_ENTRIES][__MYCMS_ERROR_MAX_PRMS]; + unsigned entries_num; + struct __mycms_error_entry_s entries[__MYCMS_ERROR_MAX_ENTRIES]; +}; + +static struct mycms_error_desc_s __common_error_key_desc[] = { + {MYCMS_ERROR_KEY_AUTHORITATIVE, "AUTHORITATIVE", "%ld"}, + {MYCMS_ERROR_KEY_CODE, "CODE", "0x%08lx"}, + {MYCMS_ERROR_KEY_SOURCE_FILE, "SOURCE_FILE", "%s"}, + {MYCMS_ERROR_KEY_SOURCE_LINE, "SOURCE_LINE", "%ld"}, + {MYCMS_ERROR_KEY_SOURCE_FUNC, "SOURCE_FUNC", "%s"}, + {MYCMS_ERROR_KEY_HINT, "HINT", "%s"}, + {MYCMS_ERROR_KEY_DESCRIPTION, "DESCRIPTION", "%s"}, + {MYCMS_ERROR_KEY_RESOURCE_SIZE, "RESOURCE_SIZE", "%lld"}, + {MYCMS_ERROR_KEY_RESOURCE_NAME, "RESOURCE_NAME", "%s"}, + {MYCMS_ERROR_KEY_ERRNO, "ERRNO", "%ld"}, + {MYCMS_ERROR_KEY_ERRNO_STR, "ERRNO_STR", "%s"}, + {MYCMS_ERROR_KEY_NTSTATUS, "NTSTATUS", "%08x"}, + {MYCMS_ERROR_KEY_OPENSSL_STATUS, "OPENSSL_STATUS", "%ld"}, + {MYCMS_ERROR_KEY_OPENSSL_STATUS_STR, "OPENSSL_STATUS_STR", "%s"} +}; + +static struct { + bool init; + unsigned error_key_desc_size; + char error_key_desc_desc[__MYCMS_ERROR_MAX_KEY_DESC][256]; + char error_key_desc_format[__MYCMS_ERROR_MAX_KEY_DESC][16]; + struct mycms_error_desc_s error_key_desc[__MYCMS_ERROR_MAX_KEY_DESC]; +} __private[1]; + +void +_mycms_error_static_init(void) { + if (!__private->init) { + unsigned i; + for (i=0;i<__MYCMS_ERROR_MAX_KEY_DESC;i++) { + __private->error_key_desc[i].desc = __private->error_key_desc_desc[i]; + __private->error_key_desc[i].format = __private->error_key_desc_format[i]; + } + _mycms_error_register_key_desc( + __common_error_key_desc, + sizeof(__common_error_key_desc) / sizeof(__common_error_key_desc[0]) + ); + __private->init = true; + } +} + +mycms_error_desc +mycms_error_get_key_desc( + const uint32_t key +) { + unsigned i; + + for (i=0;i < __private->error_key_desc_size; i++) { + if (__private->error_key_desc[i].key == key) { + return &__private->error_key_desc[i]; + } + } + + return NULL; +} + +void +_mycms_error_register_key_desc( + struct mycms_error_desc_s * const _desc, + const size_t n +) { + struct mycms_error_desc_s *last = &__private->error_key_desc[__private->error_key_desc_size]; + struct mycms_error_desc_s *desc = _desc; + size_t i; + + for (i=0;ierror_key_desc_size >= sizeof(__private->error_key_desc) / sizeof(__private->error_key_desc[0])) { + break; + } + + last->key = desc->key; + strncpy(last->desc, desc->desc, sizeof(__private->error_key_desc_desc[0]) - 1); + strncpy(last->format, desc->format, sizeof(__private->error_key_desc_format[0]) - 1); + + last++; + desc++; + __private->error_key_desc_size++; + } +} + +mycms_error +_mycms_error_new( + const mycms_system system +) { + mycms_error error = NULL; + unsigned i; + + if ((error = mycms_system_zalloc(system, "mycms_error", sizeof(*error))) == NULL) { + goto cleanup; + } + + error->system = system; + + for (i=0;i < __MYCMS_ERROR_MAX_ENTRIES;i++) { + unsigned j; + error->entries[i].error = error; + for (j=0;j < __MYCMS_ERROR_MAX_PRMS;j++) { + error->entries[i].prms[j].v = &error->vars[i][j]; + } + } + +cleanup: + + return error; +} + +bool +_mycms_error_construct( + const mycms_error error __attribute__((unused)) +) { + return true; +} + +bool +_mycms_error_destruct( + const mycms_error error +) { + int ret = true; + + if (error != NULL) { + ret = mycms_system_free(error->system, "mycms_error", error) && ret; + } + + return ret; +} + +bool +mycms_error_has_error( + const mycms_error error +) { + if (error == NULL) { + return false; + } + return error->entries_num != 0; +} + +void +mycms_error_reset( + const mycms_error error +) { + if (error != NULL) { + unsigned i; + for (i=0;i < error->entries_num; i++) { + error->entries[i].n = 0; + } + error->entries_num = 0; + } +} + +bool +mycms_error_format_callback( + const mycms_error error, + void (*f)( + const mycms_error error, + const unsigned index, + const mycms_error_prm prms, + const unsigned prms_len, + void *d + ), + void *p +) { + unsigned i; + + if (error == NULL) { + return false; + } + + for (i=error->entries_num; i > 0; i--) { + f(error, i-1, error->entries[i-1].prms, error->entries[i-1].n, p); + } + + return true; +} + +struct __format_state { + uint32_t *code; + bool found; + char *start; + size_t size; + char *pos; + size_t remain; +}; + +static +void +__format_state_fixup( + struct __format_state *buf, + size_t n +) { + n = _MYCMS_UTIL_MIN(buf->remain, n); + buf->pos += n; + buf->remain -= n; +} + +static +void +__format_strncpy( + char * const dst, + const char * const src, + const size_t size +) { + if (dst != NULL) { + strncpy(dst, src, size-1); + dst[size-1] = '\0'; + } +} + + +static +void +__error_format_simple_callback( + const mycms_error error __attribute__((unused)), + const unsigned index, + const mycms_error_prm prms, + const unsigned prms_len, + void *d +) { + struct __format_state *buf = (struct __format_state *)d; + + if (!buf->found) { + bool found = false; + unsigned i; + + for (i=0;!found && i < prms_len; i++) { + if (prms[i].k == MYCMS_ERROR_KEY_AUTHORITATIVE) { + found = true; + } + } + + if (found || index == 0) { + buf->found = true; + for (i=0;i < prms_len; i++) { + switch (prms[i].k) { + case MYCMS_ERROR_KEY_CODE: + *buf->code = prms[i].v->d->u32; + break; + case MYCMS_ERROR_KEY_DESCRIPTION: + __format_strncpy(buf->start, prms[i].v->d->str, buf->size - 1); + break; + } + } + } + } +} + +bool +mycms_error_format_simple( + const mycms_error error, + uint32_t * const code, + char * const buf, + const size_t buf_size +) { + if (error == NULL) { + *code = MYCMS_ERROR_CODE_NO_CONTEXT; + __format_strncpy(buf, "No context", buf_size - 1); + goto cleanup; + } else if (error->entries_num == 0) { + *code = MYCMS_ERROR_CODE_SUCCESS; + __format_strncpy(buf, "Success", buf_size - 1); + goto cleanup; + } else { + struct __format_state _buf[1] = {{code, false, buf, buf_size, buf, buf_size}}; + mycms_error_format_callback( + error, + __error_format_simple_callback, + _buf + ); + } + +cleanup: + + return *code != MYCMS_ERROR_CODE_SUCCESS; +} + +static +void +__error_format_callback( + const mycms_error error __attribute__((unused)), + const unsigned index, + const mycms_error_prm prms, + const unsigned prms_len, + void *d +) { +#define __MY_DEF(x, d) ((x) == NULL ? (d) : (x->format)) + struct __format_state *buf = (struct __format_state *)d; + unsigned i; + + __format_state_fixup(buf, snprintf(buf->pos, buf->remain, "%4s#%d\n", "", index)); + + for (i=0;i < prms_len; i++) { + const mycms_error_prm prm = &prms[i]; + mycms_error_desc desc = mycms_error_get_key_desc(prm->k); + unsigned n; + + if (desc == NULL) { + __format_state_fixup(buf, snprintf(buf->pos, buf->remain, "%8s%08lx=", "", (unsigned long)prm->k)); + } else { + __format_state_fixup(buf, snprintf(buf->pos, buf->remain, "%8s%s=", "", desc->desc)); + } + + switch (prm->v->t) { + default: + n = snprintf(buf->pos, buf->remain, "*ERROR*"); + break; + case mycms_variant_type_none: + n = snprintf(buf->pos, buf->remain, "(none)"); + break; + case mycms_variant_type_u32: + n = snprintf(buf->pos, buf->remain, __MY_DEF(desc, "%08lx"), (unsigned long)prm->v->d->u32); + break; + case mycms_variant_type_u64: + n = snprintf(buf->pos, buf->remain, __MY_DEF(desc, "%08llx"), (unsigned long long)prm->v->d->u64); + break; + case mycms_variant_type_str: + n = snprintf(buf->pos, buf->remain, __MY_DEF(desc, "%s"), prm->v->d->str); + break; + case mycms_variant_type_blob: + n = snprintf(buf->pos, buf->remain, "BLOB"); + break; + } + __format_state_fixup(buf, n); + __format_state_fixup(buf, snprintf(buf->pos, buf->remain, "\n")); + } +#undef __MY_DEF +} + +void +mycms_error_format( + const mycms_error error, + char * const _buf, + const size_t buf_size +) { + struct __format_state buf[1] = {{NULL, false, _buf, buf_size, _buf, buf_size}}; + + __format_state_fixup(buf, snprintf( + buf->pos, buf->remain, + ( + "MYCMS ERROR DUMP - BEGIN\n" + "Version: %s-%s (%s)\n" + "Entries (most recent call last):\n" + ), + PACKAGE_NAME, + PACKAGE_VERSION, + PACKAGE_BUILD_ID + )); + + if (!mycms_error_format_callback( + error, + __error_format_callback, + buf + )) { + __format_state_fixup(buf, snprintf(buf->pos, buf->remain, "%4sNot available\n", "")); + } + + __format_state_fixup(buf, snprintf(buf->pos, buf->remain, "MYCMS ERROR DUMP - END\n")); +} + +mycms_error_entry +_mycms_error_entry_new( + mycms_error error +) { + if (error == NULL) { + return NULL; + } + if (error->entries_num >= __MYCMS_ERROR_MAX_ENTRIES) { + return NULL; + } + return &error->entries[error->entries_num++]; +} + +void +_mycms_error_entry_dispatch( + const mycms_error_entry entry __attribute__((unused)) +) { +} + + mycms_variant * + _mycms_error_entry_prm_new_variant( + const mycms_error_entry entry, + const int k +) { + if (entry == NULL) { + return NULL; + } + + if (entry->n >= __MYCMS_ERROR_MAX_PRMS) { + return NULL; + } else { + mycms_error_prm prm = &entry->prms[entry->n++]; + prm->k = k; + return prm->v; + } +} + +mycms_error_entry + _mycms_error_entry_prm_add_u32( + const mycms_error_entry entry, + const int k, + const uint32_t u32 +) { + mycms_variant *v; + + if (entry == NULL) { + return NULL; + } + + if ((v = _mycms_error_entry_prm_new_variant(entry, k)) != NULL) { + v->t = mycms_variant_type_u32; + v->d->u32 = u32; + } + + return entry; +} + +mycms_error_entry +_mycms_error_entry_prm_add_u64( + const mycms_error_entry entry, + const int k, + const uint32_t u64 +) { + mycms_variant *v; + + if (entry == NULL) { + return NULL; + } + + if ((v = _mycms_error_entry_prm_new_variant(entry, k)) != NULL) { + v->t = mycms_variant_type_u64; + v->d->u64 = u64; + } + + return entry; +} + +mycms_error_entry +_mycms_error_entry_prm_add_str( + const mycms_error_entry entry, + const int k, + const char * const str +) { + mycms_variant *v; + + if (entry == NULL) { + return NULL; + } + + if ((v = _mycms_error_entry_prm_new_variant(entry, k)) != NULL) { + v->t = mycms_variant_type_str; + strncpy(v->d->str, str, sizeof(v->d->str) - 1); + } + + return entry; +} + +mycms_error_entry +_mycms_error_entry_prm_add_blob( + const mycms_error_entry entry, + const int k, + const unsigned char * const d, + const size_t s +) { + mycms_variant *v; + + if (entry == NULL) { + return NULL; + } + + if ((v = _mycms_error_entry_prm_new_variant(entry, k)) != NULL) { + v->t = mycms_variant_type_blob; + v->d->blob->s = s < sizeof(v->d->blob->d) ? s : sizeof(v->d->blob->d); + memcpy(v->d->blob->d, d, v->d->blob->s = s); + } + + return entry; +} + +mycms_error_entry +_mycms_error_entry_vsprintf( + const mycms_error_entry entry, + const int k, + const char * const format, + va_list ap +) { + mycms_variant *v; + + if ((v = _mycms_error_entry_prm_new_variant(entry, k)) != NULL) { + v->t = mycms_variant_type_str; + vsnprintf(v->d->str, sizeof(v->d->str), format, ap); + } + + return entry; +} + +mycms_error_entry +_mycms_error_entry_sprintf( + const mycms_error_entry entry, + const int k, + const char * const format, + ... +) { + mycms_error_entry ret; + va_list ap; + + va_start(ap, format); + ret = _mycms_error_entry_vsprintf(entry, k, format, ap); + va_end(ap); + + return ret; +} + +mycms_error_entry +_mycms_error_capture_indirect( + const mycms_error error, + const char * const file, + const int line, + const char * const func +) { + mycms_error_entry entry = _mycms_error_entry_new(error); + + if (error == NULL) { + return NULL; + } + + _mycms_error_entry_prm_add_str(entry, MYCMS_ERROR_KEY_SOURCE_FILE, file); + _mycms_error_entry_prm_add_u32(entry, MYCMS_ERROR_KEY_SOURCE_LINE, line); + _mycms_error_entry_prm_add_str(entry, MYCMS_ERROR_KEY_SOURCE_FUNC, func); + + return entry; +} + +mycms_error_entry +_mycms_error_entry_base( + const mycms_error_entry entry, + const char * const hint, + const uint32_t code, + const bool authoritative, + const char * const format, + ... +) { + if (entry == NULL) { + return NULL; + } + + _mycms_error_entry_prm_add_str(entry, MYCMS_ERROR_KEY_HINT, hint); + _mycms_error_entry_prm_add_u32(entry, MYCMS_ERROR_KEY_CODE, code); + + if (authoritative) { + _mycms_error_entry_prm_add_u32(entry, MYCMS_ERROR_KEY_AUTHORITATIVE, true); + } + + if (format != NULL) { + va_list ap; + va_start(ap, format); + _mycms_error_entry_vsprintf(entry, MYCMS_ERROR_KEY_DESCRIPTION, format, ap); + va_end(ap); + } + + return entry; +} diff --git a/src/libmycms/mycms-error.exports b/src/libmycms/mycms-error.exports new file mode 100644 index 0000000..2898e63 --- /dev/null +++ b/src/libmycms/mycms-error.exports @@ -0,0 +1,6 @@ +mycms_error_format +mycms_error_format_callback +mycms_error_format_simple +mycms_error_get_key_desc +mycms_error_has_error +mycms_error_reset diff --git a/src/libmycms/mycms-internal.h b/src/libmycms/mycms-internal.h new file mode 100644 index 0000000..ec32d75 --- /dev/null +++ b/src/libmycms/mycms-internal.h @@ -0,0 +1,24 @@ +#ifndef __MYCMS_INTERNAL_H +#define __MYCMS_INTERNAL_H + +#include + +#include "mycms-crypto.h" + +struct _mycms_internal_s { + char *base_ct; + char *base_pt; + char *md_suffix; + _mycms_crypto crypto; + mycms_bio bio_random; + mycms_key_callback key_callback; + char *encryption_key_id; +}; +typedef struct _mycms_internal_s *mycms_internal; + +mycms_internal +_mycms_get_internal( + const mycms mycms +); + +#endif diff --git a/src/libmycms/mycms-io-private.h b/src/libmycms/mycms-io-private.h new file mode 100644 index 0000000..ee240fa --- /dev/null +++ b/src/libmycms/mycms-io-private.h @@ -0,0 +1,13 @@ +#ifndef __MYCMS_IO_PRIVATE_H +#define __MYCMS_IO_PRIVATE_H + +#include + +#include + +BIO * +_mycms_io_get_BIO( + const mycms_io io +); + +#endif diff --git a/src/libmycms/mycms-io.c b/src/libmycms/mycms-io.c new file mode 100644 index 0000000..7ab6094 --- /dev/null +++ b/src/libmycms/mycms-io.c @@ -0,0 +1,206 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include "mycms-error-internal.h" +#include "mycms-io-private.h" +#include "mycms-openssl.h" + +struct mycms_io_s { + mycms_context context; + BIO *bio; +}; + +mycms_io +mycms_io_new( + const mycms_context context +) { + mycms_system system = NULL; + mycms_io io = NULL; + + if (context == NULL) { + return NULL; + } + + if ((system = mycms_context_get_system(context)) == NULL) { + goto cleanup; + } + + if ((io = mycms_system_zalloc(system, "io", sizeof(*io))) == NULL) { + goto cleanup; + } + + io->context = context; + +cleanup: + + return io; +} + +bool +mycms_io_construct( + const mycms_io io +) { + if (io == NULL) { + return false; + } + + return true; +} + +bool +mycms_io_destruct( + const mycms_io io +) { + bool ret = true; + + if (io != NULL) { + mycms_system system = mycms_context_get_system(io->context); + + BIO_free(io->bio); + io->bio = NULL; + + ret = mycms_system_free(system, "io", io) && ret; + } + + return ret; +} + +mycms_context +mycms_io_get_context( + const mycms_io io +) { + if (io == NULL) { + return false; + } + + return io->context; +} + +bool +mycms_io_open_file( + const mycms_io io, + const char * const file, + const char * const mode +) { + bool ret = false; + + if (io == NULL) { + return false; + } + + BIO_free(io->bio); + io->bio = NULL; + +#ifdef ENABLE_IO_DRIVER_FILE + if ((io->bio = BIO_new_file(file, mode)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(io->context)), + "io.open", + MYCMS_ERROR_CODE_IO, + true, + "Cannot open '%s' at mode '%s'", + file, + mode + ))); + goto cleanup; + } +#else + (void)file; + (void)mode; + goto cleanup; +#endif + + ret = true; + +cleanup: + + return ret; +} + +bool +mycms_io_map_mem( + const mycms_io io, + const void *p, + const size_t s +) { + bool ret = false; + + if (io == NULL) { + return false; + } + + BIO_free(io->bio); + io->bio = NULL; + + if ((io->bio = BIO_new_mem_buf(p, s)) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(io->context)), + "io.map", + MYCMS_ERROR_CODE_MEMORY, + true, + "Cannot allocate buffer" + ))); + goto cleanup; + } + + ret = true; + +cleanup: + + return ret; +} + +bool +mycms_io_open_mem( + const mycms_io io +) { + bool ret = false; + + if (io == NULL) { + return false; + } + + BIO_free(io->bio); + io->bio = NULL; + + if ((io->bio = BIO_new(BIO_s_mem())) == NULL) { + _mycms_error_entry_dispatch(_error_entry_openssl_status(_mycms_error_entry_base( + _mycms_error_capture(mycms_context_get_error(io->context)), + "io.mem", + MYCMS_ERROR_CODE_MEMORY, + true, + "Cannot allocate buffer" + ))); + goto cleanup; + } + + ret = true; + +cleanup: + + return ret; +} + +ssize_t +mycms_io_get_mem_ptr( + const mycms_io io, + char **p +) { + if (io == NULL) { + return -1; + } + + return BIO_get_mem_data(io->bio, &p); +} + +BIO * +_mycms_io_get_BIO( + const mycms_io io +) { + if (io == NULL) { + return NULL; + } + + return io->bio; +} diff --git a/src/libmycms/mycms-io.exports b/src/libmycms/mycms-io.exports new file mode 100644 index 0000000..541ec98 --- /dev/null +++ b/src/libmycms/mycms-io.exports @@ -0,0 +1,8 @@ +mycms_io_new +mycms_io_construct +mycms_io_destruct +mycms_io_get_context +mycms_io_open_file +mycms_io_map_mem +mycms_io_open_mem +mycms_io_get_mem_ptr diff --git a/src/libmycms/mycms-openssl.c b/src/libmycms/mycms-openssl.c new file mode 100644 index 0000000..04bad70 --- /dev/null +++ b/src/libmycms/mycms-openssl.c @@ -0,0 +1,151 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include + +#include + +#include "mycms-error-internal.h" + +static struct { + bool init; + mycms_system system; + void *(*orig_m)(size_t, const char *, int); + void *(*orig_r)(void *, size_t, const char *, int); + void (*orig_f)(void *, const char *, int); +} __static_context[1]; + +static +void * +__openssl_malloc( + size_t num, + const char *file __attribute__((unused)), + int line __attribute__((unused)) +) { + return mycms_system_realloc(__static_context->system, "openssl", NULL, num); +} + +static +void * +__openssl_realloc( + void *p, + size_t num, + const char *file __attribute__((unused)), + int line __attribute__((unused)) +) { + return mycms_system_realloc(__static_context->system, "openssl", p, num); +} + +static +void +__openssl_free( + void *p, + const char *file __attribute__((unused)), + int line __attribute__((unused)) +) { + mycms_system_free(__static_context->system, "openssl", p); +} + +void +_mycms_openssl_static_init( + const mycms_system system +) { + /* + * PKCS#11 provider with openssl 3 sets hooks at atexit causing system + * to be triggered after system is freed. + * need much more complex solutions to hook memory management without + * openssl support polls. + */ + (void)system; +#if 0 + if (!__static_context->init) { + __static_context->init = true; + __static_context->system = system; + CRYPTO_get_mem_functions( + &__static_context->orig_m, + &__static_context->orig_r, + &__static_context->orig_f + ); + if (!CRYPTO_set_mem_functions( + __openssl_malloc, + __openssl_realloc, + __openssl_free + )) { + /* can we do anything? */ + } + +#if 0 + OPENSSL_init_crypto( +#ifdef ENABLE_OPENSSL_ERR_STRINGS + OPENSSL_INIT_LOAD_CRYPTO_STRINGS +#endif + | OPENSSL_INIT_NO_ATEXIT, + NULL + ); +#endif + } +#endif +} + +void +_mycms_openssl_static_clean( + const mycms_system system __attribute__((unused)) +) { + /* + * PKCS#11 provider with openssl usage such as softhsm + * has library conflict with parent initialization + * and leaks memory. + * openssl atexit or other hook is taking care of releasing + * resources. + */ +#if 0 + if (__static_context->init) { + CRYPTO_set_mem_functions( + __static_context->orig_m, + __static_context->orig_r, + __static_context->orig_f + ); + memset(__static_context, 0, sizeof(*__static_context)); + + OPENSSL_cleanup(); + } +#endif +} + +#define __OPENSSL_MSG_SIZE 1024 + +static +int +__error_entry_openssl_status_cb( + const char *str, + size_t len __attribute__((unused)), + void *u +) { + char *buf = (char *)u; + size_t s = strlen(buf); + + buf += s; + s = __OPENSSL_MSG_SIZE - s; + + strncpy(buf, str, s-1); + buf[s-1] = '\x0'; + + return 1; +} + +mycms_error_entry +_error_entry_openssl_status( + const mycms_error_entry entry +) { + char buf[__OPENSSL_MSG_SIZE]; + + memset(buf, 0, sizeof(buf)); + _mycms_error_entry_prm_add_u32(entry, MYCMS_ERROR_KEY_OPENSSL_STATUS, ERR_peek_last_error()); + ERR_print_errors_cb(__error_entry_openssl_status_cb, buf); + _mycms_error_entry_prm_add_str(entry, MYCMS_ERROR_KEY_OPENSSL_STATUS_STR, buf); + return entry; +} diff --git a/src/libmycms/mycms-openssl.h b/src/libmycms/mycms-openssl.h new file mode 100644 index 0000000..ba0a17b --- /dev/null +++ b/src/libmycms/mycms-openssl.h @@ -0,0 +1,11 @@ +#ifndef __MYCMS_OPENSSL_H +#define __MYCMS_OPENSSL_H + +#include + +mycms_error_entry +_error_entry_openssl_status( + const mycms_error_entry entry +); + +#endif diff --git a/src/libmycms/mycms-static.c b/src/libmycms/mycms-static.c new file mode 100644 index 0000000..1162f7c --- /dev/null +++ b/src/libmycms/mycms-static.c @@ -0,0 +1,60 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +static struct { + bool init; +} __static_context[1]; + +void +_mycms_error_static_init(void); + +void +_mycms_openssl_static_init( + const mycms_system system +); + +void +_mycms_openssl_static_clean( + const mycms_system system +); + +bool +_mycms_certificate_static_init( + const mycms_system system +); + +bool +_mycms_certificate_static_clean(void); + +bool +mycms_static_init( + const mycms_system system __attribute__((unused)) +) { + if (!__static_context->init) { + _mycms_error_static_init(); + _mycms_openssl_static_init(system); + _mycms_certificate_static_init(system); + __static_context->init = true; + } + + return true; +} + +bool +mycms_static_clean( + const mycms_system system __attribute__((unused)) +) { + if (__static_context->init) { + _mycms_openssl_static_clean(system); + _mycms_certificate_static_clean(); + memset(__static_context, 0, sizeof(__static_context)); + } + + return true; +} diff --git a/src/libmycms/mycms-static.exports b/src/libmycms/mycms-static.exports new file mode 100644 index 0000000..0087d1d --- /dev/null +++ b/src/libmycms/mycms-static.exports @@ -0,0 +1,2 @@ +mycms_static_clean +mycms_static_init diff --git a/src/libmycms/mycms-system.c b/src/libmycms/mycms-system.c new file mode 100644 index 0000000..d043cfd --- /dev/null +++ b/src/libmycms/mycms-system.c @@ -0,0 +1,468 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#if defined(_WIN32) +#include +#else +#include +#include +#endif + +#include +#include +#include + +#include + +#include "mycms-error-internal.h" +#include "mycms-util.h" + +struct mycms_system_s { + const void *userdata; + struct mycms_system_driver_entry_s driver_entries[256]; + mycms_error error; +}; + +#if 0 +static +mycms_error_entry +__error_entry_errno( + const mycms_error_entry entry +) { + char msg[1024]; + int old_errno; + + _mycms_error_entry_prm_add_u32(entry, MYCMS_ERROR_KEY_ERRNO, errno); + + old_errno = errno; + errno = 0; + msg[0] = '\0'; + strerror_r(old_errno, msg, sizeof(msg)); + if (errno == 0) { + _mycms_error_entry_prm_add_str(entry, MYCMS_ERROR_KEY_ERRNO_STR, msg); + } + errno = old_errno; + + return entry; +} +#endif + +#ifdef ENABLE_SYSTEM_DRIVER_DEFAULT + +static +void +__driver_default_explicit_bzero( + const mycms_system system __attribute__((unused)), + void * const p, + const size_t size +) { +#if defined(HAVE_EXPLICIT_BZERO) + explicit_bzero(p, size); +#elif defined(HAVE_SECUREZEROMEMORY) + SecureZeroMemory(p, size); +#else + memset(p, 0, size); +#endif +} + +static +void * +__driver_default_realloc( + const mycms_system system, + const char * const hint, + void * const p, + const size_t size +) { + void *ret = NULL; + + if (system == NULL) { + return NULL; + } + + if ((ret = realloc(p, size)) == NULL && size != 0) { + _mycms_error_entry_dispatch( + _mycms_error_entry_prm_add_u64( + _mycms_error_entry_base( + _mycms_error_capture(system->error), + hint, + MYCMS_ERROR_CODE_MEMORY, + true, + "Memory allocation failed" + ), + MYCMS_ERROR_KEY_RESOURCE_SIZE, + size + ) + ); + } + + return ret; +} + +static +bool +__driver_default_free( + const mycms_system system __attribute__((unused)), + const char * const hint __attribute__((unused)), + void * const p +) { + free(p); + return true; +} + +static +void * +__driver_default_dlopen( + const mycms_system system __attribute__((unused)), + const char *filename, + const int flags +) { +#ifdef _WIN32 + (void)flags; + return (void *)LoadLibraryA(filename); +#else + return dlopen(filename, flags); +#endif +} + +static +bool +__driver_default_dlclose( + const mycms_system system __attribute__((unused)), + void *handle +) { +#ifdef _WIN32 + return FreeLibrary((HMODULE)handle); +#else + return dlclose(handle) == 0; +#endif +} + +static +void * +__driver_default_dlsym( + const mycms_system system __attribute__((unused)), + void *handle, + const char *symbol +) { +#ifdef _WIN32 + FARPROC r; + void *p; + r = GetProcAddress((HMODULE)handle, symbol); + memcpy(&p, &r, sizeof(p)); + return p; +#else + return dlsym(handle, symbol); +#endif +} + +#pragma GCC diagnostic ignored "-Wcast-function-type" +static const struct mycms_system_driver_entry_s __DRIVER_ENTRIES[] = { + { MYCMS_SYSTEM_DRIVER_ID_core_explicit_bzero, (void (*)()) __driver_default_explicit_bzero}, + { MYCMS_SYSTEM_DRIVER_ID_core_free, (void (*)()) __driver_default_free}, + { MYCMS_SYSTEM_DRIVER_ID_core_realloc, (void (*)()) __driver_default_realloc}, + { MYCMS_SYSTEM_DRIVER_ID_core_dlopen, (void (*)()) __driver_default_dlopen}, + { MYCMS_SYSTEM_DRIVER_ID_core_dlclose, (void (*)()) __driver_default_dlclose}, + { MYCMS_SYSTEM_DRIVER_ID_core_dlsym, (void (*)()) __driver_default_dlsym}, + { 0, NULL} +}; +#pragma GCC diagnostic pop +#else +static const struct mycms_system_driver_entry_s __DRIVER_ENTRIES[] = { + { 0, NULL} +}; +#endif + +size_t +mycms_system_get_context_size(void) { + return sizeof(*(mycms_system)NULL); +} + +mycms_system +mycms_system_new() { +#ifdef ENABLE_SYSTEM_DRIVER_DEFAULT + mycms_system system = NULL; + mycms_system ret = NULL; + + if ((system = realloc(NULL, sizeof(*system))) == NULL) { + goto cleanup; + } + + memset(system, 0, sizeof(*system)); + + if (!mycms_system_init(system, sizeof(*system))) { + goto cleanup; + } + + ret = system; + system = NULL; + +cleanup: + + free(system); + + return ret; +#else + return NULL; +#endif +} + +bool +mycms_system_init( + const mycms_system system, + const size_t size +) { + bool ret = false; + + if (system == NULL) { + return false; + } + + if (MYCMS_SYSTEM_CONTEXT_SIZE < mycms_system_get_context_size()) { + goto cleanup; + } + + if (size < mycms_system_get_context_size()) { + goto cleanup; + } + + mycms_system_clean(system, size); + + mycms_system_driver_register(system, __DRIVER_ENTRIES); + + ret = true; + +cleanup: + + return ret; +} + +bool +mycms_system_construct( + const mycms_system system +) { + bool ret = false; + + if (system == NULL) { + return false; + } + + if ((system->error = _mycms_error_new(system)) == NULL) { + goto cleanup; + } + + if (!_mycms_error_construct(system->error)) { + goto cleanup; + } + + ret = true; + +cleanup: + + return ret; +} + +bool +mycms_system_destruct( + const mycms_system system __attribute__((unused)) +) { + bool ret = true; +#ifdef ENABLE_SYSTEM_DRIVER_DEFAULT + ret = mycms_system_clean(system, sizeof(*system)); + free(system); +#endif + return ret; +} + +bool +mycms_system_clean( + const mycms_system system, + const size_t size +) { + bool ret = false; + + if (size < mycms_system_get_context_size()) { + goto cleanup; + } + + if (system != NULL) { + mycms_error error = system->error; + system->error = NULL; + _mycms_error_destruct(error); + memset(system, 0, sizeof(*system)); + } + + ret = true; + +cleanup: + + return ret; +} + +bool +mycms_system_driver_register( + const mycms_system system, + const struct mycms_system_driver_entry_s * const entries +) { + struct mycms_system_driver_entry_s *t; + const struct mycms_system_driver_entry_s *s; + bool ret = false; + + if (system == NULL) { + return false; + } + + for (t = system->driver_entries; t->id != 0; t++); + for (s = entries; s->id != 0; s++); + s++; + + if (s - entries >= system->driver_entries + sizeof(system->driver_entries) / sizeof(*system->driver_entries) - t) { + goto cleanup; + } + + memcpy(t, entries, sizeof(*entries) * (s - entries)); + + ret = true; + +cleanup: + + return ret; +} + +void (*mycms_system_driver_find( + const mycms_system system, + const unsigned id +))() { + struct mycms_system_driver_entry_s *x; + void (*ret)() = NULL; + + if (system == NULL) { + return NULL; + } + + /* TODO: optimize */ + for (x = system->driver_entries; x->id != 0; x++) { + if (x->id == id) { + ret = x->f; + } + } + + return ret; +} + +const void * +mycms_system_get_userdata( + const mycms_system system +) { + if (system == NULL) { + return NULL; + } + + return system->userdata; +} + +bool +mycms_system_set_userdata( + const mycms_system system, + const void *userdata +) { + if (system == NULL) { + return false; + } + + system->userdata = userdata; + return true; +} + +mycms_error +mycms_system_get_error( + const mycms_system system +) { + if (system == NULL) { + return NULL; + } + + return system->error; +} + +void +mycms_system_explicit_bzero( + const mycms_system system, + void * const p, + const size_t size +) { + mycms_system_driver_core_explicit_bzero(system)(system, p, size); +} + +void * +mycms_system_realloc( + const mycms_system system, + const char * const hint, + void * const p, + const size_t size +) { + return mycms_system_driver_core_realloc(system)(system, hint, p, size); +} + +bool +mycms_system_free( + const mycms_system system, + const char * const hint, + void * const p +) { + mycms_system_driver_core_free(system)(system, hint, p); + return true; +} + +void * +mycms_system_zalloc( + const mycms_system system, + const char * const hint, + const size_t size +) { + void *ret = NULL; + + if (system == NULL) { + return NULL; + } + + if ((ret = mycms_system_realloc(system, hint, NULL, size)) == NULL) { + goto cleanup; + } + + mycms_system_explicit_bzero(system, ret, size); + +cleanup: + + return ret; +} + +char * +mycms_system_strdup( + const mycms_system system, + const char * const hint, + const char * const s +) { + char *ret = NULL; + size_t size; + + if (system == NULL) { + return NULL; + } + + if (s == NULL) { + goto cleanup; + } + + size = strlen(s) + 1; + + if ((ret = mycms_system_realloc(system, hint, NULL, size)) == NULL) { + goto cleanup; + } + + memcpy(ret, s, size); + +cleanup: + + return ret; +} diff --git a/src/libmycms/mycms-system.exports b/src/libmycms/mycms-system.exports new file mode 100644 index 0000000..aec65bb --- /dev/null +++ b/src/libmycms/mycms-system.exports @@ -0,0 +1,16 @@ +mycms_system_clean +mycms_system_construct +mycms_system_destruct +mycms_system_driver_find +mycms_system_driver_register +mycms_system_explicit_bzero +mycms_system_free +mycms_system_get_context_size +mycms_system_get_error +mycms_system_get_userdata +mycms_system_init +mycms_system_new +mycms_system_realloc +mycms_system_set_userdata +mycms_system_strdup +mycms_system_zalloc diff --git a/src/libmycms/mycms-util.c b/src/libmycms/mycms-util.c new file mode 100644 index 0000000..038db8a --- /dev/null +++ b/src/libmycms/mycms-util.c @@ -0,0 +1,29 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#include + +#include "mycms-error-internal.h" +#include "mycms-util.h" + +const char * +_mycms_util_snprintf( + char * const buf, + size_t size, + const char * const format, + ... +) { + va_list ap; + + va_start(ap, format); + vsnprintf(buf, size, format, ap); + va_end(ap); + + return buf; +} diff --git a/src/libmycms/mycms-util.h b/src/libmycms/mycms-util.h new file mode 100644 index 0000000..418050c --- /dev/null +++ b/src/libmycms/mycms-util.h @@ -0,0 +1,17 @@ +#ifndef __MYCMS_UTIL_H +#define __MYCMS_UTIL_H + +#include + +#define _MYCMS_UTIL_MIN(x, y) ((x) < (y) ? (x) : (y)) +#define _MYCMS_UTIL_MAX(x, y) ((x) > (y) ? (x) : (y)) + +const char * +_mycms_util_snprintf( + char * const buf, + size_t size, + const char * const format, + ... +) __attribute__((format(printf, 3, 4))); + +#endif diff --git a/src/libmycms/mycms.c b/src/libmycms/mycms.c new file mode 100644 index 0000000..3d31dc6 --- /dev/null +++ b/src/libmycms/mycms.c @@ -0,0 +1,96 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include + +struct __mycms_s { + mycms_context context; +}; + +mycms +mycms_new( + const mycms_context context +) { + mycms_system system = mycms_context_get_system(context); + mycms ret = NULL; + mycms mycms = NULL; + + if (context == NULL) { + return NULL; + } + + if ((mycms = mycms_system_zalloc(system, "mycms", sizeof(*mycms))) == NULL) { + goto cleanup; + } + + mycms->context = context; + + ret = mycms; + mycms = NULL; + +cleanup: + + mycms_destruct(mycms); + + return ret; +} + +bool +mycms_construct( + const mycms mycms +) { + if (mycms == NULL) { + return false; + } + + return true; +} + +bool +mycms_destruct( + const mycms mycms +) { + int ret = true; + + if (mycms != NULL) { + mycms_system system = mycms_get_system(mycms); + + ret = mycms_system_free(system, "mycms", mycms) && ret; + } + + return ret; +} + +mycms_context +mycms_get_context( + const mycms mycms +) { + if (mycms == NULL) { + return NULL; + } + + return mycms->context; +} + +mycms_system +mycms_get_system( + const mycms mycms +) { + if (mycms == NULL) { + return NULL; + } + return mycms_context_get_system(mycms->context); +} + +mycms_error +mycms_get_error( + const mycms mycms +) { + return mycms_context_get_error(mycms_get_context(mycms)); +} diff --git a/src/libmycms/mycms.exports b/src/libmycms/mycms.exports new file mode 100644 index 0000000..477286c --- /dev/null +++ b/src/libmycms/mycms.exports @@ -0,0 +1,6 @@ +mycms_construct +mycms_destruct +mycms_get_context +mycms_get_error +mycms_get_system +mycms_new diff --git a/src/libmycms/pkcs11.h b/src/libmycms/pkcs11.h new file mode 100644 index 0000000..1ea46d3 --- /dev/null +++ b/src/libmycms/pkcs11.h @@ -0,0 +1,1863 @@ +/* pkcs11.h + Copyright 2006, 2007 g10 Code GmbH + Copyright 2006 Andreas Jellinghaus + + This file is free software; as a special exception the author gives + unlimited permission to copy and/or distribute it, with or without + modifications, as long as this notice is preserved. + + This file is distributed in the hope that it will be useful, but + WITHOUT ANY WARRANTY, to the extent permitted by law; without even + the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + PURPOSE. */ + +/* Please submit changes back to the Scute project at + http://www.scute.org/ (or send them to marcus@g10code.com), so that + they can be picked up by other projects from there as well. */ + +/* This file is a modified implementation of the PKCS #11 standard by + RSA Security Inc. It is mostly a drop-in replacement, with the + following change: + + This header file does not require any macro definitions by the user + (like CK_DEFINE_FUNCTION etc). In fact, it defines those macros + for you (if useful, some are missing, let me know if you need + more). + + There is an additional API available that does comply better to the + GNU coding standard. It can be switched on by defining + CRYPTOKI_GNU before including this header file. For this, the + following changes are made to the specification: + + All structure types are changed to a "struct ck_foo" where CK_FOO + is the type name in PKCS #11. + + All non-structure types are changed to ck_foo_t where CK_FOO is the + lowercase version of the type name in PKCS #11. The basic types + (CK_ULONG et al.) are removed without substitute. + + All members of structures are modified in the following way: Type + indication prefixes are removed, and underscore characters are + inserted before words. Then the result is lowercased. + + Note that function names are still in the original case, as they + need for ABI compatibility. + + CK_FALSE, CK_TRUE and NULL_PTR are removed without substitute. Use + . + + If CRYPTOKI_COMPAT is defined before including this header file, + then none of the API changes above take place, and the API is the + one defined by the PKCS #11 standard. */ + +#ifndef PKCS11_H +#define PKCS11_H 1 + +#if defined(__cplusplus) +extern "C" { +#endif + + +/* The version of cryptoki we implement. The revision is changed with + each modification of this file. If you do not use the "official" + version of this file, please consider deleting the revision macro + (you may use a macro with a different name to keep track of your + versions). */ +#define CRYPTOKI_VERSION_MAJOR 3 +#define CRYPTOKI_VERSION_MINOR 0 +#define CRYPTOKI_VERSION_REVISION 0 + + +/* Compatibility interface is default, unless CRYPTOKI_GNU is + given. */ +#ifndef CRYPTOKI_GNU +#ifndef CRYPTOKI_COMPAT +#define CRYPTOKI_COMPAT 1 +#endif +#endif + +/* System dependencies. */ + +#if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32) + +/* There is a matching pop below. */ +#pragma pack(push, cryptoki, 1) + +#ifdef CRYPTOKI_EXPORTS +#define CK_SPEC __declspec(dllexport) +#else +#define CK_SPEC __declspec(dllimport) +#endif + +#else + +#define CK_SPEC + +#endif + +#ifdef CRYPTOKI_COMPAT + /* If we are in compatibility mode, switch all exposed names to the + PKCS #11 variant. There are corresponding #undefs below. */ + +#define ck_flags_t CK_FLAGS +#define ck_version _CK_VERSION + +#define ck_info _CK_INFO +#define cryptoki_version cryptokiVersion +#define manufacturer_id manufacturerID +#define library_description libraryDescription +#define library_version libraryVersion + +#define ck_notification_t CK_NOTIFICATION +#define ck_slot_id_t CK_SLOT_ID + +#define ck_slot_info _CK_SLOT_INFO +#define slot_description slotDescription +#define hardware_version hardwareVersion +#define firmware_version firmwareVersion + +#define ck_token_info _CK_TOKEN_INFO +#define serial_number serialNumber +#define max_session_count ulMaxSessionCount +#define session_count ulSessionCount +#define max_rw_session_count ulMaxRwSessionCount +#define rw_session_count ulRwSessionCount +#define max_pin_len ulMaxPinLen +#define min_pin_len ulMinPinLen +#define total_public_memory ulTotalPublicMemory +#define free_public_memory ulFreePublicMemory +#define total_private_memory ulTotalPrivateMemory +#define free_private_memory ulFreePrivateMemory +#define utc_time utcTime + +#define ck_session_handle_t CK_SESSION_HANDLE +#define ck_user_type_t CK_USER_TYPE +#define ck_state_t CK_STATE + +#define ck_session_info _CK_SESSION_INFO +#define slot_id slotID +#define device_error ulDeviceError + +#define ck_object_handle_t CK_OBJECT_HANDLE +#define ck_object_class_t CK_OBJECT_CLASS +#define ck_hw_feature_type_t CK_HW_FEATURE_TYPE +#define ck_key_type_t CK_KEY_TYPE +#define ck_certificate_type_t CK_CERTIFICATE_TYPE +#define ck_attribute_type_t CK_ATTRIBUTE_TYPE + +#define ck_attribute _CK_ATTRIBUTE +#define value pValue +#define value_len ulValueLen + +#define ck_date _CK_DATE + +#define ck_mechanism_type_t CK_MECHANISM_TYPE + +#define ck_rsa_pkcs_mgf_type_t CK_RSA_PKCS_MGF_TYPE + +#define ck_mechanism _CK_MECHANISM +#define parameter pParameter +#define parameter_len ulParameterLen + +#define ck_mechanism_info _CK_MECHANISM_INFO +#define min_key_size ulMinKeySize +#define max_key_size ulMaxKeySize + +#define ck_rv_t CK_RV +#define ck_notify_t CK_NOTIFY + +#define ck_interface CK_INTERFACE + +#define ck_function_list _CK_FUNCTION_LIST +#define ck_function_list_3_0 _CK_FUNCTION_LIST_3_0 + +#define ck_createmutex_t CK_CREATEMUTEX +#define ck_destroymutex_t CK_DESTROYMUTEX +#define ck_lockmutex_t CK_LOCKMUTEX +#define ck_unlockmutex_t CK_UNLOCKMUTEX + +#define ck_c_initialize_args _CK_C_INITIALIZE_ARGS +#define create_mutex CreateMutex +#define destroy_mutex DestroyMutex +#define lock_mutex LockMutex +#define unlock_mutex UnlockMutex +#define reserved pReserved + +#endif /* CRYPTOKI_COMPAT */ + + +typedef unsigned long ck_flags_t; + +struct ck_version +{ + unsigned char major; + unsigned char minor; +}; + + +struct ck_info +{ + struct ck_version cryptoki_version; + unsigned char manufacturer_id[32]; + ck_flags_t flags; + unsigned char library_description[32]; + struct ck_version library_version; +}; + + +typedef unsigned long ck_notification_t; + +#define CKN_SURRENDER (0UL) + + +typedef unsigned long ck_slot_id_t; + + +struct ck_slot_info +{ + unsigned char slot_description[64]; + unsigned char manufacturer_id[32]; + ck_flags_t flags; + struct ck_version hardware_version; + struct ck_version firmware_version; +}; + + +#define CKF_TOKEN_PRESENT (1UL << 0) +#define CKF_REMOVABLE_DEVICE (1UL << 1) +#define CKF_HW_SLOT (1UL << 2) +#define CKF_ARRAY_ATTRIBUTE (1UL << 30) + + +struct ck_token_info +{ + unsigned char label[32]; + unsigned char manufacturer_id[32]; + unsigned char model[16]; + unsigned char serial_number[16]; + ck_flags_t flags; + unsigned long max_session_count; + unsigned long session_count; + unsigned long max_rw_session_count; + unsigned long rw_session_count; + unsigned long max_pin_len; + unsigned long min_pin_len; + unsigned long total_public_memory; + unsigned long free_public_memory; + unsigned long total_private_memory; + unsigned long free_private_memory; + struct ck_version hardware_version; + struct ck_version firmware_version; + unsigned char utc_time[16]; +}; + + +#define CKF_RNG (1UL << 0) +#define CKF_WRITE_PROTECTED (1UL << 1) +#define CKF_LOGIN_REQUIRED (1UL << 2) +#define CKF_USER_PIN_INITIALIZED (1UL << 3) +#define CKF_RESTORE_KEY_NOT_NEEDED (1UL << 5) +#define CKF_CLOCK_ON_TOKEN (1UL << 6) +#define CKF_PROTECTED_AUTHENTICATION_PATH (1UL << 8) +#define CKF_DUAL_CRYPTO_OPERATIONS (1UL << 9) +#define CKF_TOKEN_INITIALIZED (1UL << 10) +#define CKF_SECONDARY_AUTHENTICATION (1UL << 11) +#define CKF_USER_PIN_COUNT_LOW (1UL << 16) +#define CKF_USER_PIN_FINAL_TRY (1UL << 17) +#define CKF_USER_PIN_LOCKED (1UL << 18) +#define CKF_USER_PIN_TO_BE_CHANGED (1UL << 19) +#define CKF_SO_PIN_COUNT_LOW (1UL << 20) +#define CKF_SO_PIN_FINAL_TRY (1UL << 21) +#define CKF_SO_PIN_LOCKED (1UL << 22) +#define CKF_SO_PIN_TO_BE_CHANGED (1UL << 23) + +#define CK_UNAVAILABLE_INFORMATION ((unsigned long) -1) +#define CK_EFFECTIVELY_INFINITE (0UL) + + +typedef unsigned long ck_session_handle_t; + +#define CK_INVALID_HANDLE (0UL) + + +typedef unsigned long ck_user_type_t; + +#define CKU_SO (0UL) +#define CKU_USER (1UL) +#define CKU_CONTEXT_SPECIFIC (2UL) + + +typedef unsigned long ck_state_t; + +#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) + + +struct ck_session_info +{ + ck_slot_id_t slot_id; + ck_state_t state; + ck_flags_t flags; + unsigned long device_error; +}; + +#define CKF_RW_SESSION (1UL << 1) +#define CKF_SERIAL_SESSION (1UL << 2) + + +typedef unsigned long ck_object_handle_t; + + +typedef unsigned long ck_object_class_t; + +#define CKO_DATA (0UL) +#define CKO_CERTIFICATE (1UL) +#define CKO_PUBLIC_KEY (2UL) +#define CKO_PRIVATE_KEY (3UL) +#define CKO_SECRET_KEY (4UL) +#define CKO_HW_FEATURE (5UL) +#define CKO_DOMAIN_PARAMETERS (6UL) +#define CKO_MECHANISM (7UL) +#define CKO_OTP_KEY (8UL) +#define CKO_PROFILE (9UL) +#define CKO_VENDOR_DEFINED (1UL << 31) + +#define CKP_INVALID_ID (0UL) +#define CKP_BASELINE_PROVIDER (1UL) +#define CKP_EXTENDED_PROVIDER (2UL) +#define CKP_AUTHENTICATION_TOKEN (3UL) +#define CKP_PUBLIC_CERTIFICATES_TOKEN (4UL) +#define CKP_VENDOR_DEFINED (1UL << 31) + +typedef unsigned long ck_hw_feature_type_t; + +#define CKH_MONOTONIC_COUNTER (1UL) +#define CKH_CLOCK (2UL) +#define CKH_USER_INTERFACE (3UL) +#define CKH_VENDOR_DEFINED (1UL << 31) + + +typedef unsigned long ck_key_type_t; + +#define CKK_RSA (0UL) +#define CKK_DSA (1UL) +#define CKK_DH (2UL) +#define CKK_ECDSA (3UL) +#define CKK_EC (3UL) +#define CKK_X9_42_DH (4UL) +#define CKK_KEA (5UL) +#define CKK_GENERIC_SECRET (0x10UL) +#define CKK_RC2 (0x11UL) +#define CKK_RC4 (0x12UL) +#define CKK_DES (0x13UL) +#define CKK_DES2 (0x14UL) +#define CKK_DES3 (0x15UL) +#define CKK_CAST (0x16UL) +#define CKK_CAST3 (0x17UL) +#define CKK_CAST128 (0x18UL) +#define CKK_RC5 (0x19UL) +#define CKK_IDEA (0x1aUL) +#define CKK_SKIPJACK (0x1bUL) +#define CKK_BATON (0x1cUL) +#define CKK_JUNIPER (0x1dUL) +#define CKK_CDMF (0x1eUL) +#define CKK_AES (0x1fUL) +#define CKK_BLOWFISH (0x20UL) +#define CKK_TWOFISH (0x21UL) +#define CKK_GOSTR3410 (0x30UL) +#define CKK_GOSTR3411 (0x31UL) +#define CKK_GOST28147 (0x32UL) +#define CKK_EC_EDWARDS (0x40UL) +#define CKK_EC_MONTGOMERY (0x41UL) +#define CKK_VENDOR_DEFINED (1UL << 31) + +/* + * A mask for new GOST algorithms. + * For details visit https://tc26.ru/standarts/perevody/guidelines-the-pkcs-11-extensions-for-implementing-the-gost-r-34-10-2012-and-gost-r-34-11-2012-russian-standards-.html + */ +#define NSSCK_VENDOR_PKCS11_RU_TEAM (CKK_VENDOR_DEFINED | 0x54321000) +#define CK_VENDOR_PKCS11_RU_TEAM_TK26 NSSCK_VENDOR_PKCS11_RU_TEAM + +#define CKK_GOSTR3410_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x003) + +typedef unsigned long ck_certificate_type_t; + +#define CKC_X_509 (0UL) +#define CKC_X_509_ATTR_CERT (1UL) +#define CKC_WTLS (2UL) +#define CKC_VENDOR_DEFINED (1UL << 31) + + +typedef unsigned long ck_attribute_type_t; + +#define CKA_CLASS (0UL) +#define CKA_TOKEN (1UL) +#define CKA_PRIVATE (2UL) +#define CKA_LABEL (3UL) +#define CKA_APPLICATION (0x10UL) +#define CKA_VALUE (0x11UL) +#define CKA_OBJECT_ID (0x12UL) +#define CKA_CERTIFICATE_TYPE (0x80UL) +#define CKA_ISSUER (0x81UL) +#define CKA_SERIAL_NUMBER (0x82UL) +#define CKA_AC_ISSUER (0x83UL) +#define CKA_OWNER (0x84UL) +#define CKA_ATTR_TYPES (0x85UL) +#define CKA_TRUSTED (0x86UL) +#define CKA_CERTIFICATE_CATEGORY (0x87UL) +#define CKA_JAVA_MIDP_SECURITY_DOMAIN (0x88UL) +#define CKA_URL (0x89UL) +#define CKA_HASH_OF_SUBJECT_PUBLIC_KEY (0x8aUL) +#define CKA_HASH_OF_ISSUER_PUBLIC_KEY (0x8bUL) +#define CKA_CHECK_VALUE (0x90UL) +#define CKA_KEY_TYPE (0x100UL) +#define CKA_SUBJECT (0x101UL) +#define CKA_ID (0x102UL) +#define CKA_SENSITIVE (0x103UL) +#define CKA_ENCRYPT (0x104UL) +#define CKA_DECRYPT (0x105UL) +#define CKA_WRAP (0x106UL) +#define CKA_UNWRAP (0x107UL) +#define CKA_SIGN (0x108UL) +#define CKA_SIGN_RECOVER (0x109UL) +#define CKA_VERIFY (0x10aUL) +#define CKA_VERIFY_RECOVER (0x10bUL) +#define CKA_DERIVE (0x10cUL) +#define CKA_START_DATE (0x110UL) +#define CKA_END_DATE (0x111UL) +#define CKA_MODULUS (0x120UL) +#define CKA_MODULUS_BITS (0x121UL) +#define CKA_PUBLIC_EXPONENT (0x122UL) +#define CKA_PRIVATE_EXPONENT (0x123UL) +#define CKA_PRIME_1 (0x124UL) +#define CKA_PRIME_2 (0x125UL) +#define CKA_EXPONENT_1 (0x126UL) +#define CKA_EXPONENT_2 (0x127UL) +#define CKA_COEFFICIENT (0x128UL) +#define CKA_PRIME (0x130UL) +#define CKA_SUBPRIME (0x131UL) +#define CKA_BASE (0x132UL) +#define CKA_PRIME_BITS (0x133UL) +#define CKA_SUB_PRIME_BITS (0x134UL) +#define CKA_VALUE_BITS (0x160UL) +#define CKA_VALUE_LEN (0x161UL) +#define CKA_EXTRACTABLE (0x162UL) +#define CKA_LOCAL (0x163UL) +#define CKA_NEVER_EXTRACTABLE (0x164UL) +#define CKA_ALWAYS_SENSITIVE (0x165UL) +#define CKA_KEY_GEN_MECHANISM (0x166UL) +#define CKA_MODIFIABLE (0x170UL) +#define CKA_ECDSA_PARAMS (0x180UL) +#define CKA_EC_PARAMS (0x180UL) +#define CKA_EC_POINT (0x181UL) +#define CKA_SECONDARY_AUTH (0x200UL) +#define CKA_AUTH_PIN_FLAGS (0x201UL) +#define CKA_ALWAYS_AUTHENTICATE (0x202UL) +#define CKA_WRAP_WITH_TRUSTED (0x210UL) +#define CKA_GOSTR3410_PARAMS (0x250UL) +#define CKA_GOSTR3411_PARAMS (0x251UL) +#define CKA_GOST28147_PARAMS (0x252UL) +#define CKA_HW_FEATURE_TYPE (0x300UL) +#define CKA_RESET_ON_INIT (0x301UL) +#define CKA_HAS_RESET (0x302UL) +#define CKA_PIXEL_X (0x400UL) +#define CKA_PIXEL_Y (0x401UL) +#define CKA_RESOLUTION (0x402UL) +#define CKA_CHAR_ROWS (0x403UL) +#define CKA_CHAR_COLUMNS (0x404UL) +#define CKA_COLOR (0x405UL) +#define CKA_BITS_PER_PIXEL (0x406UL) +#define CKA_CHAR_SETS (0x480UL) +#define CKA_ENCODING_METHODS (0x481UL) +#define CKA_MIME_TYPES (0x482UL) +#define CKA_MECHANISM_TYPE (0x500UL) +#define CKA_REQUIRED_CMS_ATTRIBUTES (0x501UL) +#define CKA_DEFAULT_CMS_ATTRIBUTES (0x502UL) +#define CKA_SUPPORTED_CMS_ATTRIBUTES (0x503UL) +#define CKA_WRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x211UL) +#define CKA_UNWRAP_TEMPLATE (CKF_ARRAY_ATTRIBUTE | 0x212UL) +#define CKA_OTP_FORMAT (0x220UL) +#define CKA_OTP_LENGTH (0x221UL) +#define CKA_OTP_TIME_INTERVAL (0x222UL) +#define CKA_OTP_USER_FRIENDLY_MODE (0x223UL) +#define CKA_OTP_CHALLENGE_REQUIREMENT (0x224UL) +#define CKA_OTP_TIME_REQUIREMENT (0x225UL) +#define CKA_OTP_COUNTER_REQUIREMENT (0x226UL) +#define CKA_OTP_PIN_REQUIREMENT (0x227UL) +#define CKA_OTP_USER_IDENTIFIER (0x22AUL) +#define CKA_OTP_SERVICE_IDENTIFIER (0x22BUL) +#define CKA_OTP_SERVICE_LOGO (0x22CUL) +#define CKA_OTP_SERVICE_LOGO_TYPE (0x22DUL) +#define CKA_OTP_COUNTER (0x22EUL) +#define CKA_OTP_TIME (0x22FUL) +#define CKA_ALLOWED_MECHANISMS (CKF_ARRAY_ATTRIBUTE | 0x600UL) +#define CKA_PROFILE_ID (0x601UL) +#define CKA_VENDOR_DEFINED (1UL << 31) + + +struct ck_attribute +{ + ck_attribute_type_t type; + void *value; + unsigned long value_len; +}; + + +struct ck_date +{ + unsigned char year[4]; + unsigned char month[2]; + unsigned char day[2]; +}; + + +typedef unsigned long ck_mechanism_type_t; + +#define CKM_RSA_PKCS_KEY_PAIR_GEN (0UL) +#define CKM_RSA_PKCS (1UL) +#define CKM_RSA_9796 (2UL) +#define CKM_RSA_X_509 (3UL) +#define CKM_MD2_RSA_PKCS (4UL) +#define CKM_MD5_RSA_PKCS (5UL) +#define CKM_SHA1_RSA_PKCS (6UL) +#define CKM_RIPEMD128_RSA_PKCS (7UL) +#define CKM_RIPEMD160_RSA_PKCS (8UL) +#define CKM_RSA_PKCS_OAEP (9UL) +#define CKM_RSA_X9_31_KEY_PAIR_GEN (0xaUL) +#define CKM_RSA_X9_31 (0xbUL) +#define CKM_SHA1_RSA_X9_31 (0xcUL) +#define CKM_RSA_PKCS_PSS (0xdUL) +#define CKM_SHA1_RSA_PKCS_PSS (0xeUL) +#define CKM_DSA_KEY_PAIR_GEN (0x10UL) +#define CKM_DSA (0x11UL) +#define CKM_DSA_SHA1 (0x12UL) +#define CKM_DSA_SHA224 (0x13UL) +#define CKM_DSA_SHA256 (0x14UL) +#define CKM_DSA_SHA384 (0x15UL) +#define CKM_DSA_SHA512 (0x16UL) +#define CKM_DH_PKCS_KEY_PAIR_GEN (0x20UL) +#define CKM_DH_PKCS_DERIVE (0x21UL) +#define CKM_X9_42_DH_KEY_PAIR_GEN (0x30UL) +#define CKM_X9_42_DH_DERIVE (0x31UL) +#define CKM_X9_42_DH_HYBRID_DERIVE (0x32UL) +#define CKM_X9_42_MQV_DERIVE (0x33UL) +#define CKM_SHA256_RSA_PKCS (0x40UL) +#define CKM_SHA384_RSA_PKCS (0x41UL) +#define CKM_SHA512_RSA_PKCS (0x42UL) +#define CKM_SHA256_RSA_PKCS_PSS (0x43UL) +#define CKM_SHA384_RSA_PKCS_PSS (0x44UL) +#define CKM_SHA512_RSA_PKCS_PSS (0x45UL) +#define CKM_SHA224_RSA_PKCS (0x46UL) +#define CKM_SHA224_RSA_PKCS_PSS (0x47UL) +#define CKM_SHA3_256_RSA_PKCS (0x60UL) +#define CKM_SHA3_384_RSA_PKCS (0x61UL) +#define CKM_SHA3_512_RSA_PKCS (0x62UL) +#define CKM_SHA3_256_RSA_PKCS_PSS (0x63UL) +#define CKM_SHA3_384_RSA_PKCS_PSS (0x64UL) +#define CKM_SHA3_512_RSA_PKCS_PSS (0x65UL) +#define CKM_SHA3_224_RSA_PKCS (0x66UL) +#define CKM_SHA3_224_RSA_PKCS_PSS (0x67UL) +#define CKM_RC2_KEY_GEN (0x100UL) +#define CKM_RC2_ECB (0x101UL) +#define CKM_RC2_CBC (0x102UL) +#define CKM_RC2_MAC (0x103UL) +#define CKM_RC2_MAC_GENERAL (0x104UL) +#define CKM_RC2_CBC_PAD (0x105UL) +#define CKM_RC4_KEY_GEN (0x110UL) +#define CKM_RC4 (0x111UL) +#define CKM_DES_KEY_GEN (0x120UL) +#define CKM_DES_ECB (0x121UL) +#define CKM_DES_CBC (0x122UL) +#define CKM_DES_MAC (0x123UL) +#define CKM_DES_MAC_GENERAL (0x124UL) +#define CKM_DES_CBC_PAD (0x125UL) +#define CKM_DES2_KEY_GEN (0x130UL) +#define CKM_DES3_KEY_GEN (0x131UL) +#define CKM_DES3_ECB (0x132UL) +#define CKM_DES3_CBC (0x133UL) +#define CKM_DES3_MAC (0x134UL) +#define CKM_DES3_MAC_GENERAL (0x135UL) +#define CKM_DES3_CBC_PAD (0x136UL) +#define CKM_DES3_CMAC_GENERAL (0x137UL) +#define CKM_DES3_CMAC (0x138UL) +#define CKM_CDMF_KEY_GEN (0x140UL) +#define CKM_CDMF_ECB (0x141UL) +#define CKM_CDMF_CBC (0x142UL) +#define CKM_CDMF_MAC (0x143UL) +#define CKM_CDMF_MAC_GENERAL (0x144UL) +#define CKM_CDMF_CBC_PAD (0x145UL) +#define CKM_MD2 (0x200UL) +#define CKM_MD2_HMAC (0x201UL) +#define CKM_MD2_HMAC_GENERAL (0x202UL) +#define CKM_MD5 (0x210UL) +#define CKM_MD5_HMAC (0x211UL) +#define CKM_MD5_HMAC_GENERAL (0x212UL) +#define CKM_SHA_1 (0x220UL) +#define CKM_SHA_1_HMAC (0x221UL) +#define CKM_SHA_1_HMAC_GENERAL (0x222UL) +#define CKM_RIPEMD128 (0x230UL) +#define CKM_RIPEMD128_HMAC (0x231UL) +#define CKM_RIPEMD128_HMAC_GENERAL (0x232UL) +#define CKM_RIPEMD160 (0x240UL) +#define CKM_RIPEMD160_HMAC (0x241UL) +#define CKM_RIPEMD160_HMAC_GENERAL (0x242UL) +#define CKM_SHA256 (0x250UL) +#define CKM_SHA256_HMAC (0x251UL) +#define CKM_SHA256_HMAC_GENERAL (0x252UL) +#define CKM_SHA224 (0x255UL) +#define CKM_SHA224_HMAC (0x256UL) +#define CKM_SHA224_HMAC_GENERAL (0x257UL) +#define CKM_SHA384 (0x260UL) +#define CKM_SHA384_HMAC (0x261UL) +#define CKM_SHA384_HMAC_GENERAL (0x262UL) +#define CKM_SHA512 (0x270UL) +#define CKM_SHA512_HMAC (0x271UL) +#define CKM_SHA512_HMAC_GENERAL (0x272UL) +#define CKM_SHA3_256 (0x2B0UL) +#define CKM_SHA3_256_HMAC (0x2B1UL) +#define CKM_SHA3_256_HMAC_GENERAL (0x2B2UL) +#define CKM_SHA3_256_KEY_GEN (0x2B3UL) +#define CKM_SHA3_224 (0x2B5UL) +#define CKM_SHA3_224_HMAC (0x2B6UL) +#define CKM_SHA3_224_HMAC_GENERAL (0x2B7UL) +#define CKM_SHA3_224_KEY_GEN (0x2B8UL) +#define CKM_SHA3_384 (0x2C0UL) +#define CKM_SHA3_384_HMAC (0x2C1UL) +#define CKM_SHA3_384_HMAC_GENERAL (0x2C2UL) +#define CKM_SHA3_384_KEY_GEN (0x2C3UL) +#define CKM_SHA3_512 (0x2D0UL) +#define CKM_SHA3_512_HMAC (0x2D1UL) +#define CKM_SHA3_512_HMAC_GENERAL (0x2D2UL) +#define CKM_SHA3_512_KEY_GEN (0x2D3UL) +#define CKM_CAST_KEY_GEN (0x300UL) +#define CKM_CAST_ECB (0x301UL) +#define CKM_CAST_CBC (0x302UL) +#define CKM_CAST_MAC (0x303UL) +#define CKM_CAST_MAC_GENERAL (0x304UL) +#define CKM_CAST_CBC_PAD (0x305UL) +#define CKM_CAST3_KEY_GEN (0x310UL) +#define CKM_CAST3_ECB (0x311UL) +#define CKM_CAST3_CBC (0x312UL) +#define CKM_CAST3_MAC (0x313UL) +#define CKM_CAST3_MAC_GENERAL (0x314UL) +#define CKM_CAST3_CBC_PAD (0x315UL) +#define CKM_CAST5_KEY_GEN (0x320UL) +#define CKM_CAST128_KEY_GEN (0x320UL) +#define CKM_CAST5_ECB (0x321UL) +#define CKM_CAST128_ECB (0x321UL) +#define CKM_CAST5_CBC (0x322UL) +#define CKM_CAST128_CBC (0x322UL) +#define CKM_CAST5_MAC (0x323UL) +#define CKM_CAST128_MAC (0x323UL) +#define CKM_CAST5_MAC_GENERAL (0x324UL) +#define CKM_CAST128_MAC_GENERAL (0x324UL) +#define CKM_CAST5_CBC_PAD (0x325UL) +#define CKM_CAST128_CBC_PAD (0x325UL) +#define CKM_RC5_KEY_GEN (0x330UL) +#define CKM_RC5_ECB (0x331UL) +#define CKM_RC5_CBC (0x332UL) +#define CKM_RC5_MAC (0x333UL) +#define CKM_RC5_MAC_GENERAL (0x334UL) +#define CKM_RC5_CBC_PAD (0x335UL) +#define CKM_IDEA_KEY_GEN (0x340UL) +#define CKM_IDEA_ECB (0x341UL) +#define CKM_IDEA_CBC (0x342UL) +#define CKM_IDEA_MAC (0x343UL) +#define CKM_IDEA_MAC_GENERAL (0x344UL) +#define CKM_IDEA_CBC_PAD (0x345UL) +#define CKM_GENERIC_SECRET_KEY_GEN (0x350UL) +#define CKM_CONCATENATE_BASE_AND_KEY (0x360UL) +#define CKM_CONCATENATE_BASE_AND_DATA (0x362UL) +#define CKM_CONCATENATE_DATA_AND_BASE (0x363UL) +#define CKM_XOR_BASE_AND_DATA (0x364UL) +#define CKM_EXTRACT_KEY_FROM_KEY (0x365UL) +#define CKM_SSL3_PRE_MASTER_KEY_GEN (0x370UL) +#define CKM_SSL3_MASTER_KEY_DERIVE (0x371UL) +#define CKM_SSL3_KEY_AND_MAC_DERIVE (0x372UL) +#define CKM_SSL3_MASTER_KEY_DERIVE_DH (0x373UL) +#define CKM_TLS_PRE_MASTER_KEY_GEN (0x374UL) +#define CKM_TLS_MASTER_KEY_DERIVE (0x375UL) +#define CKM_TLS_KEY_AND_MAC_DERIVE (0x376UL) +#define CKM_TLS_MASTER_KEY_DERIVE_DH (0x377UL) +#define CKM_SSL3_MD5_MAC (0x380UL) +#define CKM_SSL3_SHA1_MAC (0x381UL) +#define CKM_MD5_KEY_DERIVATION (0x390UL) +#define CKM_MD2_KEY_DERIVATION (0x391UL) +#define CKM_SHA1_KEY_DERIVATION (0x392UL) +#define CKM_PBE_MD2_DES_CBC (0x3a0UL) +#define CKM_PBE_MD5_DES_CBC (0x3a1UL) +#define CKM_PBE_MD5_CAST_CBC (0x3a2UL) +#define CKM_PBE_MD5_CAST3_CBC (0x3a3UL) +#define CKM_PBE_MD5_CAST5_CBC (0x3a4UL) +#define CKM_PBE_MD5_CAST128_CBC (0x3a4UL) +#define CKM_PBE_SHA1_CAST5_CBC (0x3a5UL) +#define CKM_PBE_SHA1_CAST128_CBC (0x3a5UL) +#define CKM_PBE_SHA1_RC4_128 (0x3a6UL) +#define CKM_PBE_SHA1_RC4_40 (0x3a7UL) +#define CKM_PBE_SHA1_DES3_EDE_CBC (0x3a8UL) +#define CKM_PBE_SHA1_DES2_EDE_CBC (0x3a9UL) +#define CKM_PBE_SHA1_RC2_128_CBC (0x3aaUL) +#define CKM_PBE_SHA1_RC2_40_CBC (0x3abUL) +#define CKM_PKCS5_PBKD2 (0x3b0UL) +#define CKM_PBA_SHA1_WITH_SHA1_HMAC (0x3c0UL) +#define CKM_KEY_WRAP_LYNKS (0x400UL) +#define CKM_KEY_WRAP_SET_OAEP (0x401UL) +#define CKM_SKIPJACK_KEY_GEN (0x1000UL) +#define CKM_SKIPJACK_ECB64 (0x1001UL) +#define CKM_SKIPJACK_CBC64 (0x1002UL) +#define CKM_SKIPJACK_OFB64 (0x1003UL) +#define CKM_SKIPJACK_CFB64 (0x1004UL) +#define CKM_SKIPJACK_CFB32 (0x1005UL) +#define CKM_SKIPJACK_CFB16 (0x1006UL) +#define CKM_SKIPJACK_CFB8 (0x1007UL) +#define CKM_SKIPJACK_WRAP (0x1008UL) +#define CKM_SKIPJACK_PRIVATE_WRAP (0x1009UL) +#define CKM_SKIPJACK_RELAYX (0x100aUL) +#define CKM_KEA_KEY_PAIR_GEN (0x1010UL) +#define CKM_KEA_KEY_DERIVE (0x1011UL) +#define CKM_FORTEZZA_TIMESTAMP (0x1020UL) +#define CKM_BATON_KEY_GEN (0x1030UL) +#define CKM_BATON_ECB128 (0x1031UL) +#define CKM_BATON_ECB96 (0x1032UL) +#define CKM_BATON_CBC128 (0x1033UL) +#define CKM_BATON_COUNTER (0x1034UL) +#define CKM_BATON_SHUFFLE (0x1035UL) +#define CKM_BATON_WRAP (0x1036UL) +#define CKM_ECDSA_KEY_PAIR_GEN (0x1040UL) +#define CKM_EC_KEY_PAIR_GEN (0x1040UL) +#define CKM_ECDSA (0x1041UL) +#define CKM_ECDSA_SHA1 (0x1042UL) +#define CKM_ECDSA_SHA224 (0x1043UL) +#define CKM_ECDSA_SHA256 (0x1044UL) +#define CKM_ECDSA_SHA384 (0x1045UL) +#define CKM_ECDSA_SHA512 (0x1046UL) +#define CKM_ECDSA_SHA3_224 (0x1047UL) +#define CKM_ECDSA_SHA3_256 (0x1048UL) +#define CKM_ECDSA_SHA3_384 (0x1049UL) +#define CKM_ECDSA_SHA3_512 (0x104AUL) +#define CKM_ECDH1_DERIVE (0x1050UL) +#define CKM_ECDH1_COFACTOR_DERIVE (0x1051UL) +#define CKM_ECMQV_DERIVE (0x1052UL) +#define CKM_EC_EDWARDS_KEY_PAIR_GEN (0x1055UL) +#define CKM_EC_MONTGOMERY_KEY_PAIR_GEN (0x1056UL) +#define CKM_EDDSA (0x1057UL) +#define CKM_JUNIPER_KEY_GEN (0x1060UL) +#define CKM_JUNIPER_ECB128 (0x1061UL) +#define CKM_JUNIPER_CBC128 (0x1062UL) +#define CKM_JUNIPER_COUNTER (0x1063UL) +#define CKM_JUNIPER_SHUFFLE (0x1064UL) +#define CKM_JUNIPER_WRAP (0x1065UL) +#define CKM_FASTHASH (0x1070UL) +#define CKM_AES_KEY_GEN (0x1080UL) +#define CKM_AES_ECB (0x1081UL) +#define CKM_AES_CBC (0x1082UL) +#define CKM_AES_MAC (0x1083UL) +#define CKM_AES_MAC_GENERAL (0x1084UL) +#define CKM_AES_CBC_PAD (0x1085UL) +#define CKM_AES_CTR (0x1086UL) +#define CKM_AES_GCM (0x1087UL) +#define CKM_AES_CCM (0x1088UL) +#define CKM_AES_CTS (0x1089UL) +#define CKM_AES_CMAC (0x108AUL) +#define CKM_AES_CMAC_GENERAL (0x108BUL) +#define CKM_AES_XCBC_MAC (0x108CUL) +#define CKM_AES_XCBC_MAC_96 (0x108DUL) +#define CKM_AES_GMAC (0x108EUL) +#define CKM_BLOWFISH_KEY_GEN (0x1090UL) +#define CKM_BLOWFISH_CBC (0x1091UL) +#define CKM_TWOFISH_KEY_GEN (0x1092UL) +#define CKM_TWOFISH_CBC (0x1093UL) +#define CKM_DES_ECB_ENCRYPT_DATA (0x1100UL) +#define CKM_DES_CBC_ENCRYPT_DATA (0x1101UL) +#define CKM_DES3_ECB_ENCRYPT_DATA (0x1102UL) +#define CKM_DES3_CBC_ENCRYPT_DATA (0x1103UL) +#define CKM_AES_ECB_ENCRYPT_DATA (0x1104UL) +#define CKM_AES_CBC_ENCRYPT_DATA (0x1105UL) +#define CKM_GOSTR3410_KEY_PAIR_GEN (0x1200UL) +#define CKM_GOSTR3410 (0x1201UL) +#define CKM_GOSTR3410_WITH_GOSTR3411 (0x1202UL) +#define CKM_GOSTR3410_KEY_WRAP (0x1203UL) +#define CKM_GOSTR3410_DERIVE (0x1204UL) +#define CKM_GOSTR3410_512_KEY_PAIR_GEN (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x005) +#define CKM_GOSTR3410_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x006) +#define CKM_GOSTR3410_12_DERIVE (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x007) +#define CKM_GOSTR3410_WITH_GOSTR3411_12_256 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x008) +#define CKM_GOSTR3410_WITH_GOSTR3411_12_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x009) +#define CKM_GOSTR3411 (0x1210UL) +#define CKM_GOSTR3411_HMAC (0x1211UL) +#define CKM_GOSTR3411_12_256 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x012) +#define CKM_GOSTR3411_12_512 (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x013) +#define CKM_GOSTR3411_12_256_HMAC (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x014) +#define CKM_GOSTR3411_12_512_HMAC (CK_VENDOR_PKCS11_RU_TEAM_TK26 | 0x015) +#define CKM_GOST28147_KEY_GEN (0x1220UL) +#define CKM_GOST28147_ECB (0x1221UL) +#define CKM_GOST28147 (0x1222UL) +#define CKM_GOST28147_MAC (0x1223UL) +#define CKM_GOST28147_KEY_WRAP (0x1224UL) + +#define CKM_DSA_PARAMETER_GEN (0x2000UL) +#define CKM_DH_PKCS_PARAMETER_GEN (0x2001UL) +#define CKM_X9_42_DH_PARAMETER_GEN (0x2002UL) +#define CKM_AES_OFB (0x2104UL) +#define CKM_AES_CFB64 (0x2105UL) +#define CKM_AES_CFB8 (0x2106UL) +#define CKM_AES_CFB128 (0x2107UL) +#define CKM_AES_KEY_WRAP (0x2109UL) +#define CKM_AES_KEY_WRAP_PAD (0x210AUL) +#define CKM_XEDDSA (0x4029UL) + + +#define CKM_VENDOR_DEFINED (1UL << 31) + +struct ck_mechanism +{ + ck_mechanism_type_t mechanism; + void *parameter; + unsigned long parameter_len; +}; + + +struct ck_mechanism_info +{ + unsigned long min_key_size; + unsigned long max_key_size; + ck_flags_t flags; +}; + +#define CKF_HW (1UL << 0) + +#define CKF_MESSAGE_ENCRYPT (1UL << 1) +#define CKF_MESSAGE_DECRYPT (1UL << 2) +#define CKF_MESSAGE_SIGN (1UL << 3) +#define CKF_MESSAGE_VERIFY (1UL << 4) +#define CKF_MULTI_MESSAGE (1UL << 5) +#define CKF_FIND_OBJECTS (1UL << 6) + +#define CKF_ENCRYPT (1UL << 8) +#define CKF_DECRYPT (1UL << 9) +#define CKF_DIGEST (1UL << 10) +#define CKF_SIGN (1UL << 11) +#define CKF_SIGN_RECOVER (1UL << 12) +#define CKF_VERIFY (1UL << 13) +#define CKF_VERIFY_RECOVER (1UL << 14) +#define CKF_GENERATE (1UL << 15) +#define CKF_GENERATE_KEY_PAIR (1UL << 16) +#define CKF_WRAP (1UL << 17) +#define CKF_UNWRAP (1UL << 18) +#define CKF_DERIVE (1UL << 19) +#define CKF_EXTENSION (1UL << 31) + +#define CKF_EC_F_P (1UL << 20) +#define CKF_EC_F_2M (1UL << 21) +#define CKF_EC_ECPARAMETERS (1UL << 22) +#define CKF_EC_OID (1UL << 23) +#define CKF_EC_NAMEDCURVE CKF_EC_OID +#define CKF_EC_UNCOMPRESS (1UL << 24) +#define CKF_EC_COMPRESS (1UL << 25) +#define CKF_EC_CURVENAME (1UL << 26) + +/* Flags for C_WaitForSlotEvent. */ +#define CKF_DONT_BLOCK (1UL) + +/* Flags for Key derivation */ +#define CKD_NULL (0x1UL) +#define CKD_SHA1_KDF (0x2UL) +#define CKD_SHA224_KDF (0x5UL) +#define CKD_SHA256_KDF (0x6UL) +#define CKD_SHA384_KDF (0x7UL) +#define CKD_SHA512_KDF (0x8UL) + +typedef struct CK_ECDH1_DERIVE_PARAMS { + unsigned long kdf; + unsigned long ulSharedDataLen; + unsigned char * pSharedData; + unsigned long ulPublicDataLen; + unsigned char * pPublicData; +} CK_ECDH1_DERIVE_PARAMS; + +typedef struct CK_ECMQV_DERIVE_PARAMS { + unsigned long kdf; + unsigned long ulSharedDataLen; + unsigned char * pSharedData; + unsigned long ulPublicDataLen; + unsigned char * pPublicData; + unsigned long ulPrivateDataLen; + CK_OBJECT_HANDLE hPrivateData; + unsigned long ulPublicDataLen2; + unsigned char * pPublicData2; + CK_OBJECT_HANDLE publicKey; +} CK_ECMQV_DERIVE_PARAMS; + +typedef unsigned long ck_rsa_pkcs_mgf_type_t; +typedef unsigned long CK_RSA_PKCS_OAEP_SOURCE_TYPE; + +typedef 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; + unsigned long ulSourceDataLen; +} CK_RSA_PKCS_OAEP_PARAMS; + +typedef struct CK_RSA_PKCS_PSS_PARAMS { + ck_mechanism_type_t hashAlg; + CK_RSA_PKCS_MGF_TYPE mgf; + unsigned long sLen; +} CK_RSA_PKCS_PSS_PARAMS; + +#define CKG_MGF1_SHA1 (0x00000001UL) +#define CKG_MGF1_SHA224 (0x00000005UL) +#define CKG_MGF1_SHA256 (0x00000002UL) +#define CKG_MGF1_SHA384 (0x00000003UL) +#define CKG_MGF1_SHA512 (0x00000004UL) +#define CKG_MGF1_SHA3_224 (0x00000006UL) +#define CKG_MGF1_SHA3_256 (0x00000007UL) +#define CKG_MGF1_SHA3_384 (0x00000008UL) +#define CKG_MGF1_SHA3_512 (0x00000009UL) + +#define CKZ_DATA_SPECIFIED (0x00000001UL) + +typedef struct CK_GCM_PARAMS { + void * pIv; + unsigned long ulIvLen; + unsigned long ulIvBits; + void * pAAD; + unsigned long ulAADLen; + unsigned long ulTagBits; +} CK_GCM_PARAMS; + +/* EDDSA */ +typedef struct CK_EDDSA_PARAMS { + unsigned char phFlag; + unsigned long ulContextDataLen; + unsigned char *pContextData; +} CK_EDDSA_PARAMS; + +typedef CK_EDDSA_PARAMS *CK_EDDSA_PARAMS_PTR; + +/* XEDDSA */ +typedef struct CK_XEDDSA_PARAMS { + unsigned long hash; +} CK_XEDDSA_PARAMS; + +typedef CK_XEDDSA_PARAMS *CK_XEDDSA_PARAMS_PTR; + +typedef struct CK_AES_CTR_PARAMS { + unsigned long ulCounterBits; + unsigned char cb[16]; +} CK_AES_CTR_PARAMS; + +typedef CK_AES_CTR_PARAMS *CK_AES_CTR_PARAMS_PTR; + +typedef unsigned long ck_rv_t; + + +typedef ck_rv_t (*ck_notify_t) (ck_session_handle_t session, + ck_notification_t event, void *application); + +struct ck_interface { + char * pInterfaceName; + void * pFunctionList; + ck_flags_t flags; +}; + +#define CKF_INTERFACE_FORK_SAFE (0x00000001UL) + +/* Forward reference. */ +struct ck_function_list; +struct ck_function_list_3_0; + +#define _CK_DECLARE_FUNCTION(name, args) \ +typedef ck_rv_t (*CK_ ## name) args; \ +ck_rv_t CK_SPEC name args + +_CK_DECLARE_FUNCTION (C_Initialize, (void *init_args)); +_CK_DECLARE_FUNCTION (C_Finalize, (void *reserved)); +_CK_DECLARE_FUNCTION (C_GetInfo, (struct ck_info *info)); +_CK_DECLARE_FUNCTION (C_GetFunctionList, + (struct ck_function_list **function_list)); + +_CK_DECLARE_FUNCTION (C_GetSlotList, + (unsigned char token_present, ck_slot_id_t *slot_list, + unsigned long *count)); +_CK_DECLARE_FUNCTION (C_GetSlotInfo, + (ck_slot_id_t slot_id, struct ck_slot_info *info)); +_CK_DECLARE_FUNCTION (C_GetTokenInfo, + (ck_slot_id_t slot_id, struct ck_token_info *info)); +_CK_DECLARE_FUNCTION (C_WaitForSlotEvent, + (ck_flags_t flags, ck_slot_id_t *slot, void *reserved)); +_CK_DECLARE_FUNCTION (C_GetMechanismList, + (ck_slot_id_t slot_id, + ck_mechanism_type_t *mechanism_list, + unsigned long *count)); +_CK_DECLARE_FUNCTION (C_GetMechanismInfo, + (ck_slot_id_t slot_id, ck_mechanism_type_t type, + struct ck_mechanism_info *info)); +_CK_DECLARE_FUNCTION (C_InitToken, + (ck_slot_id_t slot_id, unsigned char *pin, + unsigned long pin_len, unsigned char *label)); +_CK_DECLARE_FUNCTION (C_InitPIN, + (ck_session_handle_t session, unsigned char *pin, + unsigned long pin_len)); +_CK_DECLARE_FUNCTION (C_SetPIN, + (ck_session_handle_t session, unsigned char *old_pin, + unsigned long old_len, unsigned char *new_pin, + unsigned long new_len)); + +_CK_DECLARE_FUNCTION (C_OpenSession, + (ck_slot_id_t slot_id, ck_flags_t flags, + void *application, ck_notify_t notify, + ck_session_handle_t *session)); +_CK_DECLARE_FUNCTION (C_CloseSession, (ck_session_handle_t session)); +_CK_DECLARE_FUNCTION (C_CloseAllSessions, (ck_slot_id_t slot_id)); +_CK_DECLARE_FUNCTION (C_GetSessionInfo, + (ck_session_handle_t session, + struct ck_session_info *info)); +_CK_DECLARE_FUNCTION (C_GetOperationState, + (ck_session_handle_t session, + unsigned char *operation_state, + unsigned long *operation_state_len)); +_CK_DECLARE_FUNCTION (C_SetOperationState, + (ck_session_handle_t session, + unsigned char *operation_state, + unsigned long operation_state_len, + ck_object_handle_t encryption_key, + ck_object_handle_t authentication_key)); +_CK_DECLARE_FUNCTION (C_Login, + (ck_session_handle_t session, ck_user_type_t user_type, + unsigned char *pin, unsigned long pin_len)); +_CK_DECLARE_FUNCTION (C_Logout, (ck_session_handle_t session)); + +_CK_DECLARE_FUNCTION (C_CreateObject, + (ck_session_handle_t session, + struct ck_attribute *templ, + unsigned long count, ck_object_handle_t *object)); +_CK_DECLARE_FUNCTION (C_CopyObject, + (ck_session_handle_t session, ck_object_handle_t object, + struct ck_attribute *templ, unsigned long count, + ck_object_handle_t *new_object)); +_CK_DECLARE_FUNCTION (C_DestroyObject, + (ck_session_handle_t session, + ck_object_handle_t object)); +_CK_DECLARE_FUNCTION (C_GetObjectSize, + (ck_session_handle_t session, + ck_object_handle_t object, + unsigned long *size)); +_CK_DECLARE_FUNCTION (C_GetAttributeValue, + (ck_session_handle_t session, + ck_object_handle_t object, + struct ck_attribute *templ, + unsigned long count)); +_CK_DECLARE_FUNCTION (C_SetAttributeValue, + (ck_session_handle_t session, + ck_object_handle_t object, + struct ck_attribute *templ, + unsigned long count)); +_CK_DECLARE_FUNCTION (C_FindObjectsInit, + (ck_session_handle_t session, + struct ck_attribute *templ, + unsigned long count)); +_CK_DECLARE_FUNCTION (C_FindObjects, + (ck_session_handle_t session, + ck_object_handle_t *object, + unsigned long max_object_count, + unsigned long *object_count)); +_CK_DECLARE_FUNCTION (C_FindObjectsFinal, + (ck_session_handle_t session)); + +_CK_DECLARE_FUNCTION (C_EncryptInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_Encrypt, + (ck_session_handle_t session, + unsigned char *data, unsigned long data_len, + unsigned char *encrypted_data, + unsigned long *encrypted_data_len)); +_CK_DECLARE_FUNCTION (C_EncryptUpdate, + (ck_session_handle_t session, + unsigned char *part, unsigned long part_len, + unsigned char *encrypted_part, + unsigned long *encrypted_part_len)); +_CK_DECLARE_FUNCTION (C_EncryptFinal, + (ck_session_handle_t session, + unsigned char *last_encrypted_part, + unsigned long *last_encrypted_part_len)); + +_CK_DECLARE_FUNCTION (C_DecryptInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_Decrypt, + (ck_session_handle_t session, + unsigned char *encrypted_data, + unsigned long encrypted_data_len, + unsigned char *data, unsigned long *data_len)); +_CK_DECLARE_FUNCTION (C_DecryptUpdate, + (ck_session_handle_t session, + unsigned char *encrypted_part, + unsigned long encrypted_part_len, + unsigned char *part, unsigned long *part_len)); +_CK_DECLARE_FUNCTION (C_DecryptFinal, + (ck_session_handle_t session, + unsigned char *last_part, + unsigned long *last_part_len)); + +_CK_DECLARE_FUNCTION (C_DigestInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism)); +_CK_DECLARE_FUNCTION (C_Digest, + (ck_session_handle_t session, + unsigned char *data, unsigned long data_len, + unsigned char *digest, + unsigned long *digest_len)); +_CK_DECLARE_FUNCTION (C_DigestUpdate, + (ck_session_handle_t session, + unsigned char *part, unsigned long part_len)); +_CK_DECLARE_FUNCTION (C_DigestKey, + (ck_session_handle_t session, ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_DigestFinal, + (ck_session_handle_t session, + unsigned char *digest, + unsigned long *digest_len)); + +_CK_DECLARE_FUNCTION (C_SignInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_Sign, + (ck_session_handle_t session, + unsigned char *data, unsigned long data_len, + unsigned char *signature, + unsigned long *signature_len)); +_CK_DECLARE_FUNCTION (C_SignUpdate, + (ck_session_handle_t session, + unsigned char *part, unsigned long part_len)); +_CK_DECLARE_FUNCTION (C_SignFinal, + (ck_session_handle_t session, + unsigned char *signature, + unsigned long *signature_len)); +_CK_DECLARE_FUNCTION (C_SignRecoverInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_SignRecover, + (ck_session_handle_t session, + unsigned char *data, unsigned long data_len, + unsigned char *signature, + unsigned long *signature_len)); + +_CK_DECLARE_FUNCTION (C_VerifyInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_Verify, + (ck_session_handle_t session, + unsigned char *data, unsigned long data_len, + unsigned char *signature, + unsigned long signature_len)); +_CK_DECLARE_FUNCTION (C_VerifyUpdate, + (ck_session_handle_t session, + unsigned char *part, unsigned long part_len)); +_CK_DECLARE_FUNCTION (C_VerifyFinal, + (ck_session_handle_t session, + unsigned char *signature, + unsigned long signature_len)); +_CK_DECLARE_FUNCTION (C_VerifyRecoverInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_VerifyRecover, + (ck_session_handle_t session, + unsigned char *signature, + unsigned long signature_len, + unsigned char *data, + unsigned long *data_len)); + +_CK_DECLARE_FUNCTION (C_DigestEncryptUpdate, + (ck_session_handle_t session, + unsigned char *part, unsigned long part_len, + unsigned char *encrypted_part, + unsigned long *encrypted_part_len)); +_CK_DECLARE_FUNCTION (C_DecryptDigestUpdate, + (ck_session_handle_t session, + unsigned char *encrypted_part, + unsigned long encrypted_part_len, + unsigned char *part, + unsigned long *part_len)); +_CK_DECLARE_FUNCTION (C_SignEncryptUpdate, + (ck_session_handle_t session, + unsigned char *part, unsigned long part_len, + unsigned char *encrypted_part, + unsigned long *encrypted_part_len)); +_CK_DECLARE_FUNCTION (C_DecryptVerifyUpdate, + (ck_session_handle_t session, + unsigned char *encrypted_part, + unsigned long encrypted_part_len, + unsigned char *part, + unsigned long *part_len)); + +_CK_DECLARE_FUNCTION (C_GenerateKey, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + struct ck_attribute *templ, + unsigned long count, + ck_object_handle_t *key)); +_CK_DECLARE_FUNCTION (C_GenerateKeyPair, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + struct ck_attribute *public_key_template, + unsigned long public_key_attribute_count, + struct ck_attribute *private_key_template, + unsigned long private_key_attribute_count, + ck_object_handle_t *public_key, + ck_object_handle_t *private_key)); +_CK_DECLARE_FUNCTION (C_WrapKey, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t wrapping_key, + ck_object_handle_t key, + unsigned char *wrapped_key, + unsigned long *wrapped_key_len)); +_CK_DECLARE_FUNCTION (C_UnwrapKey, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t unwrapping_key, + unsigned char *wrapped_key, + unsigned long wrapped_key_len, + struct ck_attribute *templ, + unsigned long attribute_count, + ck_object_handle_t *key)); +_CK_DECLARE_FUNCTION (C_DeriveKey, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t base_key, + struct ck_attribute *templ, + unsigned long attribute_count, + ck_object_handle_t *key)); + +_CK_DECLARE_FUNCTION (C_SeedRandom, + (ck_session_handle_t session, unsigned char *seed, + unsigned long seed_len)); +_CK_DECLARE_FUNCTION (C_GenerateRandom, + (ck_session_handle_t session, + unsigned char *random_data, + unsigned long random_len)); + +_CK_DECLARE_FUNCTION (C_GetFunctionStatus, (ck_session_handle_t session)); +_CK_DECLARE_FUNCTION (C_CancelFunction, (ck_session_handle_t session)); + +_CK_DECLARE_FUNCTION (C_GetInterfaceList, + (struct ck_interface *interfaces_list, + unsigned long *count)); +_CK_DECLARE_FUNCTION (C_GetInterface, + (unsigned char *interface_name, + struct ck_version *version, + struct ck_interface **interface_ptr, + ck_flags_t flags)); + +_CK_DECLARE_FUNCTION (C_LoginUser, + (ck_session_handle_t session, + ck_user_type_t user_type, + unsigned char *pin, + unsigned long pin_len, + unsigned char *username, + unsigned long username_len)); + +_CK_DECLARE_FUNCTION (C_SessionCancel, + (ck_session_handle_t session, + ck_flags_t flags)); + +_CK_DECLARE_FUNCTION (C_MessageEncryptInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_EncryptMessage, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *associated_data, + unsigned long associated_data_len, + unsigned char *plaintext, + unsigned long plaintext_len, + unsigned char *ciphertext, + unsigned long *ciphertext_len)); +_CK_DECLARE_FUNCTION (C_EncryptMessageBegin, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *associated_data, + unsigned long associated_data_len)); +_CK_DECLARE_FUNCTION (C_EncryptMessageNext, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *plaintext_part, + unsigned long plaintext_part_len, + unsigned char *ciphertext_part, + unsigned long *ciphertext_part_len, + ck_flags_t flags)); +_CK_DECLARE_FUNCTION (C_MessageEncryptFinal, + (ck_session_handle_t session)); + +_CK_DECLARE_FUNCTION (C_MessageDecryptInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_DecryptMessage, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *associated_data, + unsigned long associated_data_len, + unsigned char *ciphertext, + unsigned long ciphertext_len, + unsigned char *plaintext, + unsigned long *plaintext_len)); +_CK_DECLARE_FUNCTION (C_DecryptMessageBegin, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *associated_data, + unsigned long associated_data_len)); +_CK_DECLARE_FUNCTION (C_DecryptMessageNext, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *ciphertext_part, + unsigned long ciphertext_part_len, + unsigned char *plaintext_part, + unsigned long *plaintext_part_len, + ck_flags_t flags)); +_CK_DECLARE_FUNCTION (C_MessageDecryptFinal, + (ck_session_handle_t session)); + +_CK_DECLARE_FUNCTION (C_MessageSignInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_SignMessage, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *data, + unsigned long data_len, + unsigned char *signature, + unsigned long *signature_len)); +_CK_DECLARE_FUNCTION (C_SignMessageBegin, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len)); +_CK_DECLARE_FUNCTION (C_SignMessageNext, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *data, + unsigned long data_len, + unsigned char *signature, + unsigned long *signature_len)); +_CK_DECLARE_FUNCTION (C_MessageSignFinal, + (ck_session_handle_t session)); + +_CK_DECLARE_FUNCTION (C_MessageVerifyInit, + (ck_session_handle_t session, + struct ck_mechanism *mechanism, + ck_object_handle_t key)); +_CK_DECLARE_FUNCTION (C_VerifyMessage, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *data, + unsigned long data_len, + unsigned char *signature, + unsigned long signature_len)); +_CK_DECLARE_FUNCTION (C_VerifyMessageBegin, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len)); +_CK_DECLARE_FUNCTION (C_VerifyMessageNext, + (ck_session_handle_t session, + void *parameter, + unsigned long parameter_len, + unsigned char *data, + unsigned long data_len, + unsigned char *signature, + unsigned long signature_len)); +_CK_DECLARE_FUNCTION (C_MessageVerifyFinal, + (ck_session_handle_t session)); + +/* Flags in Message-based encryption/decryption API */ +#define CKF_END_OF_MESSAGE (0x00000001UL) + +struct ck_function_list +{ + struct 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; +}; + +struct ck_function_list_3_0 +{ + struct 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; + /* PKCS #11 3.0 functions */ + 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; +}; + + + +typedef ck_rv_t (*ck_createmutex_t) (void **mutex); +typedef ck_rv_t (*ck_destroymutex_t) (void *mutex); +typedef ck_rv_t (*ck_lockmutex_t) (void *mutex); +typedef ck_rv_t (*ck_unlockmutex_t) (void *mutex); + + +struct ck_c_initialize_args +{ + ck_createmutex_t create_mutex; + ck_destroymutex_t destroy_mutex; + ck_lockmutex_t lock_mutex; + ck_unlockmutex_t unlock_mutex; + ck_flags_t flags; + void *reserved; +}; + + +#define CKF_LIBRARY_CANT_CREATE_OS_THREADS (1UL << 0) +#define CKF_OS_LOCKING_OK (1UL << 1) + +#define CKR_OK (0UL) +#define CKR_CANCEL (1UL) +#define CKR_HOST_MEMORY (2UL) +#define CKR_SLOT_ID_INVALID (3UL) +#define CKR_GENERAL_ERROR (5UL) +#define CKR_FUNCTION_FAILED (6UL) +#define CKR_ARGUMENTS_BAD (7UL) +#define CKR_NO_EVENT (8UL) +#define CKR_NEED_TO_CREATE_THREADS (9UL) +#define CKR_CANT_LOCK (0xaUL) +#define CKR_ATTRIBUTE_READ_ONLY (0x10UL) +#define CKR_ATTRIBUTE_SENSITIVE (0x11UL) +#define CKR_ATTRIBUTE_TYPE_INVALID (0x12UL) +#define CKR_ATTRIBUTE_VALUE_INVALID (0x13UL) +#define CKR_ACTION_PROHIBITED (0x1BUL) +#define CKR_DATA_INVALID (0x20UL) +#define CKR_DATA_LEN_RANGE (0x21UL) +#define CKR_DEVICE_ERROR (0x30UL) +#define CKR_DEVICE_MEMORY (0x31UL) +#define CKR_DEVICE_REMOVED (0x32UL) +#define CKR_ENCRYPTED_DATA_INVALID (0x40UL) +#define CKR_ENCRYPTED_DATA_LEN_RANGE (0x41UL) +#define CKR_FUNCTION_CANCELED (0x50UL) +#define CKR_FUNCTION_NOT_PARALLEL (0x51UL) +#define CKR_FUNCTION_NOT_SUPPORTED (0x54UL) +#define CKR_KEY_HANDLE_INVALID (0x60UL) +#define CKR_KEY_SIZE_RANGE (0x62UL) +#define CKR_KEY_TYPE_INCONSISTENT (0x63UL) +#define CKR_KEY_NOT_NEEDED (0x64UL) +#define CKR_KEY_CHANGED (0x65UL) +#define CKR_KEY_NEEDED (0x66UL) +#define CKR_KEY_INDIGESTIBLE (0x67UL) +#define CKR_KEY_FUNCTION_NOT_PERMITTED (0x68UL) +#define CKR_KEY_NOT_WRAPPABLE (0x69UL) +#define CKR_KEY_UNEXTRACTABLE (0x6aUL) +#define CKR_MECHANISM_INVALID (0x70UL) +#define CKR_MECHANISM_PARAM_INVALID (0x71UL) +#define CKR_OBJECT_HANDLE_INVALID (0x82UL) +#define CKR_OPERATION_ACTIVE (0x90UL) +#define CKR_OPERATION_NOT_INITIALIZED (0x91UL) +#define CKR_PIN_INCORRECT (0xa0UL) +#define CKR_PIN_INVALID (0xa1UL) +#define CKR_PIN_LEN_RANGE (0xa2UL) +#define CKR_PIN_EXPIRED (0xa3UL) +#define CKR_PIN_LOCKED (0xa4UL) +#define CKR_SESSION_CLOSED (0xb0UL) +#define CKR_SESSION_COUNT (0xb1UL) +#define CKR_SESSION_HANDLE_INVALID (0xb3UL) +#define CKR_SESSION_PARALLEL_NOT_SUPPORTED (0xb4UL) +#define CKR_SESSION_READ_ONLY (0xb5UL) +#define CKR_SESSION_EXISTS (0xb6UL) +#define CKR_SESSION_READ_ONLY_EXISTS (0xb7UL) +#define CKR_SESSION_READ_WRITE_SO_EXISTS (0xb8UL) +#define CKR_SIGNATURE_INVALID (0xc0UL) +#define CKR_SIGNATURE_LEN_RANGE (0xc1UL) +#define CKR_TEMPLATE_INCOMPLETE (0xd0UL) +#define CKR_TEMPLATE_INCONSISTENT (0xd1UL) +#define CKR_TOKEN_NOT_PRESENT (0xe0UL) +#define CKR_TOKEN_NOT_RECOGNIZED (0xe1UL) +#define CKR_TOKEN_WRITE_PROTECTED (0xe2UL) +#define CKR_UNWRAPPING_KEY_HANDLE_INVALID (0xf0UL) +#define CKR_UNWRAPPING_KEY_SIZE_RANGE (0xf1UL) +#define CKR_UNWRAPPING_KEY_TYPE_INCONSISTENT (0xf2UL) +#define CKR_USER_ALREADY_LOGGED_IN (0x100UL) +#define CKR_USER_NOT_LOGGED_IN (0x101UL) +#define CKR_USER_PIN_NOT_INITIALIZED (0x102UL) +#define CKR_USER_TYPE_INVALID (0x103UL) +#define CKR_USER_ANOTHER_ALREADY_LOGGED_IN (0x104UL) +#define CKR_USER_TOO_MANY_TYPES (0x105UL) +#define CKR_WRAPPED_KEY_INVALID (0x110UL) +#define CKR_WRAPPED_KEY_LEN_RANGE (0x112UL) +#define CKR_WRAPPING_KEY_HANDLE_INVALID (0x113UL) +#define CKR_WRAPPING_KEY_SIZE_RANGE (0x114UL) +#define CKR_WRAPPING_KEY_TYPE_INCONSISTENT (0x115UL) +#define CKR_RANDOM_SEED_NOT_SUPPORTED (0x120UL) +#define CKR_RANDOM_NO_RNG (0x121UL) +#define CKR_DOMAIN_PARAMS_INVALID (0x130UL) +#define CKR_CURVE_NOT_SUPPORTED (0x140UL) +#define CKR_BUFFER_TOO_SMALL (0x150UL) +#define CKR_SAVED_STATE_INVALID (0x160UL) +#define CKR_INFORMATION_SENSITIVE (0x170UL) +#define CKR_STATE_UNSAVEABLE (0x180UL) +#define CKR_CRYPTOKI_NOT_INITIALIZED (0x190UL) +#define CKR_CRYPTOKI_ALREADY_INITIALIZED (0x191UL) +#define CKR_MUTEX_BAD (0x1a0UL) +#define CKR_MUTEX_NOT_LOCKED (0x1a1UL) +#define CKR_FUNCTION_REJECTED (0x200UL) +#define CKR_VENDOR_DEFINED (1UL << 31) + + +/* Compatibility layer. */ + +#ifdef CRYPTOKI_COMPAT + +#undef CK_DEFINE_FUNCTION +#define CK_DEFINE_FUNCTION(retval, name) retval CK_SPEC name + +/* For NULL. */ +#include + +typedef unsigned char CK_BYTE; +typedef unsigned char CK_CHAR; +typedef unsigned char CK_UTF8CHAR; +typedef unsigned char CK_BBOOL; +typedef unsigned long int CK_ULONG; +typedef long int CK_LONG; +typedef CK_BYTE *CK_BYTE_PTR; +typedef CK_CHAR *CK_CHAR_PTR; +typedef CK_UTF8CHAR *CK_UTF8CHAR_PTR; +typedef CK_ULONG *CK_ULONG_PTR; +typedef void *CK_VOID_PTR; +typedef void **CK_VOID_PTR_PTR; +#define CK_FALSE 0 +#define CK_TRUE 1 +#ifndef CK_DISABLE_TRUE_FALSE +#ifndef FALSE +#define FALSE 0 +#endif +#ifndef TRUE +#define TRUE 1 +#endif +#endif + +typedef struct ck_version CK_VERSION; +typedef struct ck_version *CK_VERSION_PTR; + +typedef struct ck_info CK_INFO; +typedef struct ck_info *CK_INFO_PTR; + +typedef ck_slot_id_t *CK_SLOT_ID_PTR; + +typedef struct ck_slot_info CK_SLOT_INFO; +typedef struct ck_slot_info *CK_SLOT_INFO_PTR; + +typedef struct ck_token_info CK_TOKEN_INFO; +typedef struct ck_token_info *CK_TOKEN_INFO_PTR; + +typedef ck_session_handle_t *CK_SESSION_HANDLE_PTR; + +typedef struct ck_session_info CK_SESSION_INFO; +typedef struct ck_session_info *CK_SESSION_INFO_PTR; + +typedef ck_object_handle_t *CK_OBJECT_HANDLE_PTR; + +typedef ck_object_class_t *CK_OBJECT_CLASS_PTR; + +typedef struct ck_attribute CK_ATTRIBUTE; +typedef struct ck_attribute *CK_ATTRIBUTE_PTR; + +typedef struct ck_date CK_DATE; +typedef struct ck_date *CK_DATE_PTR; + +typedef ck_mechanism_type_t *CK_MECHANISM_TYPE_PTR; + +typedef ck_rsa_pkcs_mgf_type_t *CK_RSA_PKCS_MGF_TYPE_PTR; + +typedef struct ck_mechanism CK_MECHANISM; +typedef struct ck_mechanism *CK_MECHANISM_PTR; + +typedef struct ck_mechanism_info CK_MECHANISM_INFO; +typedef struct ck_mechanism_info *CK_MECHANISM_INFO_PTR; + +typedef struct ck_interface CK_INTERFACE; +typedef struct ck_interface *CK_INTERFACE_PTR; +typedef struct ck_interface **CK_INTERFACE_PTR_PTR; + +typedef struct ck_function_list CK_FUNCTION_LIST; +typedef struct ck_function_list *CK_FUNCTION_LIST_PTR; +typedef struct ck_function_list **CK_FUNCTION_LIST_PTR_PTR; + +typedef struct ck_function_list_3_0 CK_FUNCTION_LIST_3_0; +typedef struct ck_function_list_3_0 *CK_FUNCTION_LIST_3_0_PTR; +typedef struct ck_function_list_3_0 **CK_FUNCTION_LIST_3_0_PTR_PTR; + +typedef struct ck_c_initialize_args CK_C_INITIALIZE_ARGS; +typedef struct ck_c_initialize_args *CK_C_INITIALIZE_ARGS_PTR; + +#define NULL_PTR NULL + +/* Delete the helper macros defined at the top of the file. */ +#undef ck_flags_t +#undef ck_version + +#undef ck_info +#undef cryptoki_version +#undef manufacturer_id +#undef library_description +#undef library_version + +#undef ck_notification_t +#undef ck_slot_id_t + +#undef ck_slot_info +#undef slot_description +#undef hardware_version +#undef firmware_version + +#undef ck_token_info +#undef serial_number +#undef max_session_count +#undef session_count +#undef max_rw_session_count +#undef rw_session_count +#undef max_pin_len +#undef min_pin_len +#undef total_public_memory +#undef free_public_memory +#undef total_private_memory +#undef free_private_memory +#undef utc_time + +#undef ck_session_handle_t +#undef ck_user_type_t +#undef ck_state_t + +#undef ck_session_info +#undef slot_id +#undef device_error + +#undef ck_object_handle_t +#undef ck_object_class_t +#undef ck_hw_feature_type_t +#undef ck_key_type_t +#undef ck_certificate_type_t +#undef ck_attribute_type_t + +#undef ck_attribute +#undef value +#undef value_len + +#undef ck_date + +#undef ck_mechanism_type_t + +#undef ck_rsa_pkcs_mgf_type_t + +#undef ck_mechanism +#undef parameter +#undef parameter_len + +#undef ck_mechanism_info +#undef min_key_size +#undef max_key_size + +#undef ck_rv_t +#undef ck_notify_t + +#undef ck_interface + +#undef ck_function_list +#undef ck_function_list_3_0 + +#undef ck_createmutex_t +#undef ck_destroymutex_t +#undef ck_lockmutex_t +#undef ck_unlockmutex_t + +#undef ck_c_initialize_args +#undef create_mutex +#undef destroy_mutex +#undef lock_mutex +#undef unlock_mutex +#undef reserved + +#endif /* CRYPTOKI_COMPAT */ + +/* System dependencies. */ +#if defined(_WIN32) || defined(CRYPTOKI_FORCE_WIN32) +#pragma pack(pop, cryptoki) +#endif + +#if defined(__cplusplus) +} +#endif + +#endif /* PKCS11_H */ diff --git a/src/libmycms/versioninfo.rc.in b/src/libmycms/versioninfo.rc.in new file mode 100644 index 0000000..64bc12c --- /dev/null +++ b/src/libmycms/versioninfo.rc.in @@ -0,0 +1,31 @@ +#include + +VS_VERSION_INFO VERSIONINFO + FILEVERSION @MYCMS_VERSION_MAJOR@,@MYCMS_VERSION_MINOR@,@MYCMS_VERSION_FIX@,@MYCMS_VERSION_REVISION@ + PRODUCTVERSION @MYCMS_VERSION_MAJOR@,@MYCMS_VERSION_MINOR@,@MYCMS_VERSION_FIX@,@MYCMS_VERSION_REVISION@ + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x21L +#else + FILEFLAGS 0x20L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileVersion", "@MYCMS_VERSION_MAJOR@.@MYCMS_VERSION_MINOR@.@MYCMS_VERSION_FIX@.@MYCMS_VERSION_REVISION@" + VALUE "InternalName", "@PACKAGE_NAME@" + VALUE "ProductName", "@PACKAGE_NAME@" + VALUE "ProductVersion", "@MYCMS_VERSION_MAJOR@,@MYCMS_VERSION_MINOR@,@MYCMS_VERSION_FIX@,@MYCMS_VERSION_REVISION@" + VALUE "FileDescription", "@PACKAGE_NAME@-@PACKAGE_VERSION@ (@PACKAGE_BUILD_ID@) Library" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/src/mycms-tool/Makefile.am b/src/mycms-tool/Makefile.am new file mode 100644 index 0000000..f6c0169 --- /dev/null +++ b/src/mycms-tool/Makefile.am @@ -0,0 +1,59 @@ +include $(top_srcdir)/build/ltrc.inc + +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in \ + $(NULL) + +if ENABLE_TOOL +bin_PROGRAMS = mycms-tool +endif + +AM_CPPFLAGS = \ + -I$(top_srcdir)/include \ + $(NULL) + +mycms_tool_SOURCES = \ + cmd-common.c \ + cmd-common.h \ + getoptutil.c \ + getoptutil.h \ + main.c \ + util.c \ + util.h \ + $(NULL) +if ENABLE_CMS_SIGN +mycms_tool_SOURCES += \ + cmd-sign.c \ + cmd-sign.h \ + $(NULL) +endif +if ENABLE_CMS_VERIFY +mycms_tool_SOURCES += \ + cmd-verify.c \ + cmd-verify.h \ + $(NULL) +endif +if ENABLE_CMS_ENCRYPT +mycms_tool_SOURCES += \ + cmd-encrypt.c \ + cmd-encrypt.h \ + $(NULL) +endif +if ENABLE_CMS_DECRYPT +mycms_tool_SOURCES += \ + cmd-decrypt.c \ + cmd-decrypt.h \ + $(NULL) +endif +nodist_mycms_tool_SOURCES = \ + $(NULL) +if BUILD_WINDOWS +nodist_mycms_tool_SOURCES += \ + versioninfo.rc \ + $(NULL) +endif +mycms_tool_LDADD = \ + $(builddir)/../libmycms-util/libmycms-util.la \ + $(builddir)/../libmycms/libmycms.la \ + $(OPENSSLCRYPTO_LIBS) \ + $(NULL) diff --git a/src/mycms-tool/cmd-common.c b/src/mycms-tool/cmd-common.c new file mode 100644 index 0000000..53198cb --- /dev/null +++ b/src/mycms-tool/cmd-common.c @@ -0,0 +1,174 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include +#include +#include + +#include "cmd-common.h" + +typedef const char *(*__certificate_driver_usage)(void); +static const struct __certificate_driver_s { + const char *name; + __certificate_driver_usage u; + _cmd_common_certificate_driver_apply p; +} __CERTIFICATE_DRIVERS[] = { +#ifdef ENABLE_CERTIFICATE_DRIVER_FILE + {"file", mycms_certificate_driver_file_usage, mycms_certificate_driver_file_apply}, +#endif +#ifdef ENABLE_CERTIFICATE_DRIVER_PKCS11 + {"pkcs11", mycms_certificate_driver_pkcs11_usage, mycms_certificate_driver_pkcs11_apply}, +#endif + {NULL, NULL, NULL} +}; + +_cmd_common_certificate_driver_apply +_cmd_common_get_certificate_driver( + const char ** what +) { + const struct __certificate_driver_s *sd = __CERTIFICATE_DRIVERS; + const char *p; + _cmd_common_certificate_driver_apply ret = NULL; + + if (what == NULL || *what == NULL) { + goto cleanup; + } + + p = *what; + if ((*what = strchr(p, ':')) == NULL) { + goto cleanup; + } + (*what) = '\0'; + (*what)++; + + for (sd = __CERTIFICATE_DRIVERS; sd->name != NULL; sd++) { + if (!strncmp(p, sd->name, strlen(sd->name))) { + ret = sd->p; + break; + } + } + +cleanup: + + return ret; +} + +void +_cmd_common_extra_usage() { + const struct __certificate_driver_s *sd; + + printf("\nPASSPHRASE_EXPRESSION\n%4swhat=attribute=value:what=attribute=value\n", ""); + { + char x[1024]; + char *p1; + strncpy(x, mycms_util_getpass_usage(), sizeof(x)-1); + x[sizeof(x) - 1] = '\0'; + p1 = x; + while (p1 != NULL) { + char *p2; + if ((p2 = strchr(p1, '\n')) != NULL) { + *p2 = '\0'; + p2++; + } + printf("%12s%s\n", "", p1); + p1 = p2; + } + } + + printf("\nCERTIFICATE_EXPRESSION\n%4sdriver:attribute=value:attribute=value\n", ""); + + printf("\nCERTIFICATE DRIVERS\n"); + for (sd = __CERTIFICATE_DRIVERS; sd->name != NULL; sd++) { + char x[1024]; + char *p1; + + strncpy(x, sd->u(), sizeof(x) - 1); + x[sizeof(x) - 1] = '\0'; + + printf("%4s%s:\n", "", sd->name); + p1 = x; + while (p1 != NULL) { + char *p2; + if ((p2 = strchr(p1, '\n')) != NULL) { + *p2 = '\0'; + p2++; + } + printf("%12s%s\n", "", p1); + p1 = p2; + } + } +} + +bool +_cmd_common_load_cert( + const mycms_system system, + const char * const file, + mycms_blob *blob +) { + + FILE *fp = NULL; + unsigned char * data = NULL; + bool ret = false; + + if ((fp = fopen(file, "rb")) == NULL) { + goto cleanup; + } + + if (fseek(fp, 0L, SEEK_END) != 0) { + goto cleanup; + } + { + long l; + if ((l = ftell(fp)) == -1) { + goto cleanup; + } + blob->size = l; + } + if (fseek(fp, 0L, SEEK_SET) != 0) { + goto cleanup; + } + + if ((data = mycms_system_zalloc(system, "cert", blob->size)) == NULL) { + goto cleanup; + } + + if (fread(data, blob->size, 1, fp) != 1) { + goto cleanup; + } + + blob->data = data; + data = NULL; + ret = true; + +cleanup: + if (fp != NULL) { + fclose(fp); + fp = NULL; + } + + mycms_system_free(system, "cert", data); + data = NULL; + + return ret; +} + +bool +_cmd_common_passphrase_callback( + const mycms_certificate certificate, + const char * const what, + char **p, + const size_t size +) { + mycms_context context = mycms_certificate_get_context(certificate); + mycms_dict pass_dict = (mycms_dict)mycms_certificate_get_userdata(certificate); + const char *exp = mycms_dict_entry_get(pass_dict, what, NULL); + char prompt[1024]; + snprintf(prompt, sizeof(prompt), "%s PIN", what); + prompt[sizeof(prompt)-1] = '\0'; + return mycms_util_getpass(context, "MyCMS", prompt, exp, *p, size); +} diff --git a/src/mycms-tool/cmd-common.h b/src/mycms-tool/cmd-common.h new file mode 100644 index 0000000..cefd8c9 --- /dev/null +++ b/src/mycms-tool/cmd-common.h @@ -0,0 +1,31 @@ +#ifndef __MYCMS_CMD_COMMON_H +#define __MYCMS_CMD_COMMON_H + +#include + +typedef bool (*_cmd_common_certificate_driver_apply)(const mycms_certificate c); + +_cmd_common_certificate_driver_apply +_cmd_common_get_certificate_driver( + const char ** what +); + +void +_cmd_common_extra_usage(); + +bool +_cmd_common_load_cert( + const mycms_system system, + const char * const file, + mycms_blob *blob +); + +bool +_cmd_common_passphrase_callback( + const mycms_certificate certificate, + const char * const what, + char **p, + const size_t size +); + +#endif diff --git a/src/mycms-tool/cmd-decrypt.c b/src/mycms-tool/cmd-decrypt.c new file mode 100644 index 0000000..b31b56c --- /dev/null +++ b/src/mycms-tool/cmd-decrypt.c @@ -0,0 +1,233 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include "getoptutil.h" +#include "util.h" + +#include "cmd-common.h" +#include "cmd-decrypt.h" + +int +_cmd_decrypt( + const mycms_context context, + int argc, + char *argv[] +) { + enum { + OPT_HELP = 0x1000, + OPT_CMS_IN, + OPT_RECIP_CERT, + OPT_RECIP_CERT_PASS, + OPT_DATA_PT, + OPT_DATA_CT, + OPT_MAX + }; + + static struct option long_options[] = { + {"help\0this usage", no_argument, NULL, OPT_HELP}, + {"cms-in\0FILE|input cms", required_argument, NULL, OPT_CMS_IN}, + {"recip-cert\0CERTIFICATE_EXPRESSION|recipient certificate to use", required_argument, NULL, OPT_RECIP_CERT}, + {"recip-cert-pass\0PASSPHRASE_EXPRESSION|recipient certificate passphrase to use", required_argument, NULL, OPT_RECIP_CERT_PASS}, + {"data-ct\0FILE|input ciphered text data", required_argument, NULL, OPT_DATA_CT}, + {"data-pt\0FILE|output plain text data", required_argument, NULL, OPT_DATA_PT}, + {NULL, 0, NULL, 0} + }; + + char optstring[1024]; + int option; + int ret = 1; + + const char * certificate_exp = NULL; + const char * pass_exp = NULL; + + mycms mycms = NULL; + mycms_io cms_in = NULL; + mycms_io data_pt = NULL; + mycms_io data_ct = NULL; + mycms_dict certificate_dict = NULL; + mycms_dict pass_dict = NULL; + mycms_certificate certificate = NULL; + + if ((mycms = mycms_new(context)) == NULL) { + goto cleanup; + } + + if (!mycms_construct(mycms)) { + goto cleanup; + } + + if (!getoptutil_short_from_long(long_options, "+", optstring, sizeof(optstring))) { + fprintf(stderr, "Failed to construct options"); + goto cleanup; + } + + while ((option = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { + switch (option) { + case OPT_HELP: + getoptutil_usage(stdout, argv[0], "decrypt [options]", long_options); + _cmd_common_extra_usage(); + ret = 0; + goto cleanup; + case OPT_CMS_IN: + if ((cms_in = mycms_io_new(context)) == NULL) { + goto cleanup; + } + if (!mycms_io_construct(cms_in)) { + goto cleanup; + } + if (!mycms_io_open_file(cms_in, optarg, "rb")) { + goto cleanup; + } + break; + case OPT_RECIP_CERT: + certificate_exp = optarg; + break; + case OPT_RECIP_CERT_PASS: + pass_exp = optarg; + break; + case OPT_DATA_PT: + if ((data_pt = mycms_io_new(context)) == NULL) { + goto cleanup; + } + if (!mycms_io_construct(data_pt)) { + goto cleanup; + } + if (!mycms_io_open_file(data_pt, optarg, "wb")) { + goto cleanup; + } + break; + case OPT_DATA_CT: + if ((data_ct = mycms_io_new(context)) == NULL) { + goto cleanup; + } + if (!mycms_io_construct(data_ct)) { + goto cleanup; + } + if (!mycms_io_open_file(data_ct, optarg, "rb")) { + goto cleanup; + } + break; + default: + fprintf(stderr, "Invalid option\n"); + goto cleanup; + } + } + + if (optind != argc) { + fprintf(stderr, "Unexpected positional options\n"); + goto cleanup; + } + if (certificate_exp == NULL) { + fprintf(stderr, "Certificate is mandatory\n"); + goto cleanup; + } + if (cms_in == NULL) { + fprintf(stderr, "CMS in is mandatory\n"); + goto cleanup; + } + + if (data_pt == NULL) { + fprintf(stderr, "Data PT is mandatory\n"); + goto cleanup; + } + if (data_ct == NULL) { + fprintf(stderr, "Data CT is mandatory\n"); + goto cleanup; + } + + if ((certificate_dict = mycms_dict_new(context)) == NULL) { + goto cleanup; + } + + if (!mycms_dict_construct(certificate_dict)) { + goto cleanup; + } + + if (!util_split_string(certificate_dict, certificate_exp)) { + goto cleanup; + } + + if ((pass_dict = mycms_dict_new(context)) == NULL) { + goto cleanup; + } + + if (!mycms_dict_construct(pass_dict)) { + goto cleanup; + } + + if (!util_split_string(pass_dict, pass_exp)) { + goto cleanup; + } + + if ((certificate = mycms_certificate_new(context)) == NULL) { + goto cleanup; + } + + if (!mycms_certificate_construct(certificate)) { + goto cleanup; + } + + if (!mycms_certificate_set_userdata(certificate, pass_dict)) { + goto cleanup; + } + + if (!mycms_certificate_set_passphrase_callback(certificate, _cmd_common_passphrase_callback)) { + goto cleanup; + } + + { + _cmd_common_certificate_driver_apply x; + if ((x = _cmd_common_get_certificate_driver(&certificate_exp)) == NULL) { + fprintf(stderr, "Cannot resolve certificate expression"); + goto cleanup; + } + if (!x(certificate)) { + fprintf(stderr, "Cannot apply certificate expression"); + goto cleanup; + } + } + + if (!mycms_certificate_load(certificate, certificate_dict)) { + goto cleanup; + } + + if (!mycms_decrypt(mycms, certificate, cms_in, data_pt, data_ct)) { + goto cleanup; + } + + ret = 0; + +cleanup: + + mycms_io_destruct(cms_in); + cms_in = NULL; + + mycms_io_destruct(data_pt); + data_pt = NULL; + + mycms_io_destruct(data_ct); + data_ct = NULL; + + mycms_certificate_destruct(certificate); + certificate = NULL; + + mycms_dict_destruct(certificate_dict); + certificate_dict = NULL; + + mycms_dict_destruct(pass_dict); + pass_dict = NULL; + + mycms_destruct(mycms); + mycms = NULL; + + mycms_destruct(mycms); + mycms = NULL; + + return ret; +} diff --git a/src/mycms-tool/cmd-decrypt.h b/src/mycms-tool/cmd-decrypt.h new file mode 100644 index 0000000..91220fd --- /dev/null +++ b/src/mycms-tool/cmd-decrypt.h @@ -0,0 +1,11 @@ +#ifndef __MYCMS_CMD_DECRYPT_H +#define __MYCMS_CMD_DECRYPT_H + +int +_cmd_decrypt( + const mycms_context context, + int argc, + char *argv[] +); + +#endif diff --git a/src/mycms-tool/cmd-encrypt.c b/src/mycms-tool/cmd-encrypt.c new file mode 100644 index 0000000..e845e8a --- /dev/null +++ b/src/mycms-tool/cmd-encrypt.c @@ -0,0 +1,600 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include "getoptutil.h" +#include "util.h" + +#include "cmd-common.h" +#include "cmd-encrypt.h" + +int +_cmd_encrypt( + const mycms_context context, + int argc, + char *argv[] +) { + enum { + OPT_HELP = 0x1000, + OPT_CIPHER, + OPT_CMS_OUT, + OPT_DATA_PT, + OPT_DATA_CT, + OPT_TO, + OPT_KEYOPT, + OPT_MAX + }; + + static struct option long_options[] = { + {"help\0this usage", no_argument, NULL, OPT_HELP}, + {"cipher\0CIPHER|cipher to use, default is AES-256-CBC", required_argument, NULL, OPT_CIPHER}, + {"cms-out\0FILE|output cms", required_argument, NULL, OPT_CMS_OUT}, + {"data-pt\0FILE|input plain text data", required_argument, NULL, OPT_DATA_PT}, + {"data-ct\0FILE|output plain text data", required_argument, NULL, OPT_DATA_CT}, + {"to\0FILE|target DER encoded certificate, may be specified several times", required_argument, NULL, OPT_TO}, + {"keyopt\0KEYOPT_EXPRESSION|key options expression", required_argument, NULL, OPT_KEYOPT}, + {NULL, 0, NULL, 0} + }; + + char optstring[1024]; + int option; + int ret = 1; + + const char *cipher = "AES-256-CBC"; + + const char * keyopt_exp = NULL; + + mycms_system system = mycms_context_get_system(context); + mycms mycms = NULL; + mycms_io cms_out = NULL; + mycms_io data_pt = NULL; + mycms_io data_ct = NULL; + mycms_list_blob to = NULL; + mycms_dict keyopt_dict = NULL; + + if ((mycms = mycms_new(context)) == NULL) { + goto cleanup; + } + + if (!mycms_construct(mycms)) { + goto cleanup; + } + + if (!getoptutil_short_from_long(long_options, "+", optstring, sizeof(optstring))) { + fprintf(stderr, "Failed to construct options"); + goto cleanup; + } + + while ((option = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { + switch (option) { + case OPT_HELP: + getoptutil_usage(stdout, argv[0], "encrypt [options]", long_options); + _cmd_common_extra_usage(); + ret = 0; + goto cleanup; + case OPT_CIPHER: + cipher = optarg; + break; + case OPT_CMS_OUT: + if ((cms_out = mycms_io_new(context)) == NULL) { + goto cleanup; + } + if (!mycms_io_construct(cms_out)) { + goto cleanup; + } + if (!mycms_io_open_file(cms_out, optarg, "wb")) { + goto cleanup; + } + break; + case OPT_DATA_PT: + if ((data_pt = mycms_io_new(context)) == NULL) { + goto cleanup; + } + if (!mycms_io_construct(data_pt)) { + goto cleanup; + } + if (!mycms_io_open_file(data_pt, optarg, "rb")) { + goto cleanup; + } + break; + case OPT_DATA_CT: + if ((data_ct = mycms_io_new(context)) == NULL) { + goto cleanup; + } + if (!mycms_io_construct(data_ct)) { + goto cleanup; + } + if (!mycms_io_open_file(data_ct, optarg, "wb")) { + goto cleanup; + } + break; + case OPT_TO: + { + mycms_list_blob t; + + if ((t = mycms_system_zalloc(system, "to", sizeof(*t))) == NULL) { + goto cleanup; + } + + if (!_cmd_common_load_cert(system, optarg, &t->blob)) { + fprintf(stderr, "Cannot load certificate"); + mycms_system_free(system, "to", t); + goto cleanup; + } + + t->next = to; + to = t; + } + break; + case OPT_KEYOPT: + keyopt_exp = optarg; + break; + default: + fprintf(stderr, "Invalid option\n"); + goto cleanup; + } + } + if (optind != argc) { + fprintf(stderr, "Unexpected positional options\n"); + goto cleanup; + } + + if (cms_out == NULL) { + fprintf(stderr, "CMS out is mandatory\n"); + goto cleanup; + } + if (data_pt == NULL) { + fprintf(stderr, "Data PT is mandatory\n"); + goto cleanup; + } + if (data_ct == NULL) { + fprintf(stderr, "Data CT is mandatory\n"); + goto cleanup; + } + + if ((keyopt_dict = mycms_dict_new(context)) == NULL) { + goto cleanup; + } + + if (!mycms_dict_construct(keyopt_dict)) { + goto cleanup; + } + + if (!util_split_string(keyopt_dict, keyopt_exp)) { + goto cleanup; + } + + if (!mycms_encrypt(mycms, cipher, to, keyopt_dict, cms_out, data_pt, data_ct)) { + goto cleanup; + } + + ret = 0; + +cleanup: + + mycms_io_destruct(cms_out); + cms_out = NULL; + + mycms_io_destruct(data_pt); + data_pt = NULL; + + mycms_io_destruct(data_ct); + data_ct = NULL; + + mycms_dict_destruct(keyopt_dict); + keyopt_dict = NULL; + + while(to != NULL) { + mycms_list_blob t = to; + to = to->next; + t->next = NULL; + mycms_system_free(system, "to.data", t->blob.data); + t->blob.data = NULL; + mycms_system_free(system, "to", t); + } + + mycms_destruct(mycms); + mycms = NULL; + + return ret; +} + +int +_cmd_encrypt_add( + const mycms_context context, + int argc, + char *argv[] +) { + enum { + OPT_HELP = 0x1000, + OPT_CMS_IN, + OPT_CMS_OUT, + OPT_RECIP_CERT, + OPT_RECIP_CERT_PASS, + OPT_TO, + OPT_KEYOPT, + OPT_MAX + }; + + static struct option long_options[] = { + {"help\0this usage", no_argument, NULL, OPT_HELP}, + {"cms-in\0FILE|input cms", required_argument, NULL, OPT_CMS_IN}, + {"cms-out\0FILE|output cms", required_argument, NULL, OPT_CMS_OUT}, + {"recip-cert\0CERTIFICATE_EXPRESSION|recipient certificate to use", required_argument, NULL, OPT_RECIP_CERT}, + {"recip-cert-pass\0PASSPHRASE_EXPRESSION|recipient certificate passphrase to use", required_argument, NULL, OPT_RECIP_CERT_PASS}, + {"to\0FILE|target DER encoded certificate, may be specified several times", required_argument, NULL, OPT_TO}, + {"keyopt\0KEYOPT_EXPRESSION|key options expression", required_argument, NULL, OPT_KEYOPT}, + {NULL, 0, NULL, 0} + }; + + char optstring[1024]; + int option; + int ret = 1; + + const char * certificate_exp = NULL; + const char * pass_exp = NULL; + const char * keyopt_exp = NULL; + + mycms_system system = mycms_context_get_system(context); + mycms mycms = NULL; + mycms_io cms_in = NULL; + mycms_io cms_out = NULL; + mycms_list_blob to = NULL; + mycms_dict keyopt_dict = NULL; + mycms_dict certificate_dict = NULL; + mycms_dict pass_dict = NULL; + mycms_certificate certificate = NULL; + + if ((mycms = mycms_new(context)) == NULL) { + goto cleanup; + } + + if (!mycms_construct(mycms)) { + goto cleanup; + } + + if (!getoptutil_short_from_long(long_options, "+", optstring, sizeof(optstring))) { + fprintf(stderr, "Failed to construct options"); + goto cleanup; + } + + while ((option = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { + switch (option) { + case OPT_HELP: + getoptutil_usage(stdout, argv[0], "encrypt-add [options]", long_options); + _cmd_common_extra_usage(); + ret = 0; + goto cleanup; + case OPT_CMS_IN: + if ((cms_in = mycms_io_new(context)) == NULL) { + goto cleanup; + } + if (!mycms_io_construct(cms_in)) { + goto cleanup; + } + if (!mycms_io_open_file(cms_in, optarg, "rb")) { + goto cleanup; + } + break; + case OPT_CMS_OUT: + if ((cms_out = mycms_io_new(context)) == NULL) { + goto cleanup; + } + if (!mycms_io_construct(cms_out)) { + goto cleanup; + } + if (!mycms_io_open_file(cms_out, optarg, "wb")) { + goto cleanup; + } + break; + case OPT_RECIP_CERT: + certificate_exp = optarg; + break; + case OPT_RECIP_CERT_PASS: + pass_exp = optarg; + break; + case OPT_TO: + { + mycms_list_blob t; + + if ((t = mycms_system_zalloc(system, "to", sizeof(*t))) == NULL) { + goto cleanup; + } + + if (!_cmd_common_load_cert(system, optarg, &t->blob)) { + fprintf(stderr, "Cannot load certificate"); + mycms_system_free(system, "to", t); + goto cleanup; + } + + t->next = to; + to = t; + } + break; + case OPT_KEYOPT: + keyopt_exp = optarg; + break; + default: + fprintf(stderr, "Invalid option\n"); + goto cleanup; + } + } + + if (optind != argc) { + fprintf(stderr, "Unexpected positional options\n"); + goto cleanup; + } + if (certificate_exp == NULL) { + fprintf(stderr, "Certificate is mandatory\n"); + goto cleanup; + } + if (cms_in == NULL) { + fprintf(stderr, "CMS in is mandatory\n"); + goto cleanup; + } + if (cms_out == NULL) { + fprintf(stderr, "CMS out is mandatory\n"); + goto cleanup; + } + if (to == NULL) { + fprintf(stderr, "To is mandatory\n"); + goto cleanup; + } + + if ((certificate = mycms_certificate_new(context)) == NULL) { + goto cleanup; + } + + if ((certificate_dict = mycms_dict_new(context)) == NULL) { + goto cleanup; + } + + if (!mycms_dict_construct(certificate_dict)) { + goto cleanup; + } + + if (!util_split_string(certificate_dict, certificate_exp)) { + goto cleanup; + } + + if ((pass_dict = mycms_dict_new(context)) == NULL) { + goto cleanup; + } + + if (!mycms_dict_construct(pass_dict)) { + goto cleanup; + } + + if (!util_split_string(pass_dict, pass_exp)) { + goto cleanup; + } + + if (!mycms_certificate_construct(certificate)) { + goto cleanup; + } + + if (!mycms_certificate_set_userdata(certificate, pass_dict)) { + goto cleanup; + } + + if ((keyopt_dict = mycms_dict_new(context)) == NULL) { + goto cleanup; + } + + if (!mycms_dict_construct(keyopt_dict)) { + goto cleanup; + } + + if (!util_split_string(keyopt_dict, keyopt_exp)) { + goto cleanup; + } + + if (!mycms_certificate_set_passphrase_callback(certificate, _cmd_common_passphrase_callback)) { + goto cleanup; + } + + { + _cmd_common_certificate_driver_apply x; + if ((x = _cmd_common_get_certificate_driver(&certificate_exp)) == NULL) { + fprintf(stderr, "Cannot resolve certificate expression"); + goto cleanup; + } + if (!x(certificate)) { + fprintf(stderr, "Cannot apply certificate expression"); + goto cleanup; + } + } + + if (!mycms_certificate_load(certificate, certificate_dict)) { + goto cleanup; + } + + if (!mycms_encrypt_add(mycms, certificate, to, keyopt_dict, cms_in, cms_out)) { + goto cleanup; + } + + ret = 0; + +cleanup: + + mycms_io_destruct(cms_in); + cms_in = NULL; + + mycms_io_destruct(cms_out); + cms_out = NULL; + + mycms_certificate_destruct(certificate); + certificate = NULL; + + mycms_dict_destruct(certificate_dict); + certificate_dict = NULL; + + mycms_dict_destruct(pass_dict); + pass_dict = NULL; + + mycms_dict_destruct(keyopt_dict); + keyopt_dict = NULL; + + while(to != NULL) { + mycms_list_blob t = to; + to = to->next; + t->next = NULL; + mycms_system_free(system, "to.data", t->blob.data); + t->blob.data = NULL; + mycms_system_free(system, "to", t); + } + + mycms_destruct(mycms); + mycms = NULL; + + return ret; +} + +int +_cmd_encrypt_reset( + const mycms_context context, + int argc, + char *argv[] +) { + enum { + OPT_HELP = 0x1000, + OPT_CMS_IN, + OPT_CMS_OUT, + OPT_TO, + OPT_MAX + }; + + static struct option long_options[] = { + {"help\0this usage", no_argument, NULL, OPT_HELP}, + {"cms-in\0FILE|input cms", required_argument, NULL, OPT_CMS_IN}, + {"cms-out\0FILE|output cms", required_argument, NULL, OPT_CMS_OUT}, + {"to\0FILE|target DER encoded certificate, may be specified several times", required_argument, NULL, OPT_TO}, + {NULL, 0, NULL, 0} + }; + + char optstring[1024]; + int option; + int ret = 1; + + mycms_system system = mycms_context_get_system(context); + mycms mycms = NULL; + mycms_io cms_in = NULL; + mycms_io cms_out = NULL; + mycms_list_blob to = NULL; + + if ((mycms = mycms_new(context)) == NULL) { + goto cleanup; + } + + if (!mycms_construct(mycms)) { + goto cleanup; + } + + if (!getoptutil_short_from_long(long_options, "+", optstring, sizeof(optstring))) { + fprintf(stderr, "Failed to construct options"); + goto cleanup; + } + + while ((option = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { + switch (option) { + case OPT_HELP: + getoptutil_usage(stdout, argv[0], "encrypt-add [options]", long_options); + _cmd_common_extra_usage(); + ret = 0; + goto cleanup; + case OPT_CMS_IN: + if ((cms_in = mycms_io_new(context)) == NULL) { + goto cleanup; + } + if (!mycms_io_construct(cms_in)) { + goto cleanup; + } + if (!mycms_io_open_file(cms_in, optarg, "rb")) { + goto cleanup; + } + break; + case OPT_CMS_OUT: + if ((cms_out = mycms_io_new(context)) == NULL) { + goto cleanup; + } + if (!mycms_io_construct(cms_out)) { + goto cleanup; + } + if (!mycms_io_open_file(cms_out, optarg, "wb")) { + goto cleanup; + } + break; + case OPT_TO: + { + mycms_list_blob t; + + if ((t = mycms_system_zalloc(system, "to", sizeof(*t))) == NULL) { + goto cleanup; + } + + if (!_cmd_common_load_cert(system, optarg, &t->blob)) { + fprintf(stderr, "Cannot load certificate"); + mycms_system_free(system, "to", t); + goto cleanup; + } + + t->next = to; + to = t; + } + break; + default: + fprintf(stderr, "Invalid option\n"); + goto cleanup; + } + } + + if (optind != argc) { + fprintf(stderr, "Unexpected positional options\n"); + goto cleanup; + } + if (cms_in == NULL) { + fprintf(stderr, "CMS in is mandatory\n"); + goto cleanup; + } + if (cms_out == NULL) { + fprintf(stderr, "CMS out is mandatory\n"); + goto cleanup; + } + if (to == NULL) { + fprintf(stderr, "To is mandatory\n"); + goto cleanup; + } + + if (!mycms_encrypt_reset(mycms, to, cms_in, cms_out)) { + goto cleanup; + } + + ret = 0; + +cleanup: + + mycms_io_destruct(cms_in); + cms_in = NULL; + + mycms_io_destruct(cms_out); + cms_out = NULL; + + while(to != NULL) { + mycms_list_blob t = to; + to = to->next; + t->next = NULL; + mycms_system_free(system, "to.data", t->blob.data); + t->blob.data = NULL; + mycms_system_free(system, "to", t); + } + + mycms_destruct(mycms); + mycms = NULL; + + return ret; +} diff --git a/src/mycms-tool/cmd-encrypt.h b/src/mycms-tool/cmd-encrypt.h new file mode 100644 index 0000000..56716a9 --- /dev/null +++ b/src/mycms-tool/cmd-encrypt.h @@ -0,0 +1,25 @@ +#ifndef __MYCMS_CMD_ENCRYPT_H +#define __MYCMS_CMD_ENCRYPT_H + +int +_cmd_encrypt( + const mycms_context context, + int argc, + char *argv[] +); + +int +_cmd_encrypt_add( + const mycms_context context, + int argc, + char *argv[] +); + +int +_cmd_encrypt_reset( + const mycms_context context, + int argc, + char *argv[] +); + +#endif diff --git a/src/mycms-tool/cmd-sign.c b/src/mycms-tool/cmd-sign.c new file mode 100644 index 0000000..7712106 --- /dev/null +++ b/src/mycms-tool/cmd-sign.c @@ -0,0 +1,270 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include "getoptutil.h" +#include "util.h" + +#include "cmd-common.h" +#include "cmd-sign.h" + +int +_cmd_sign( + const mycms_context context, + int argc, + char *argv[] +) { + enum { + OPT_HELP = 0x1000, + OPT_DIGEST, + OPT_SIGNER_CERT, + OPT_SIGNER_CERT_PASS, + OPT_KEYOPT, + OPT_CMS_IN, + OPT_CMS_OUT, + OPT_DATA_IN, + OPT_MAX + }; + + static struct option long_options[] = { + {"help\0this usage", no_argument, NULL, OPT_HELP}, + {"digest\0DIGEST|digest to use, default is SHA3-256", required_argument, NULL, OPT_DIGEST}, + {"signer-cert\0CERTIFICATE_EXPRESSION|signer certificate to use", required_argument, NULL, OPT_SIGNER_CERT}, + {"signer-cert-pass\0PASSPHRASE_EXPRESSION|signer certificate passphrase to use", required_argument, NULL, OPT_SIGNER_CERT_PASS}, + {"keyopt\0KEYOPT_EXPRESSION|key options expression", required_argument, NULL, OPT_KEYOPT}, + {"cms-in\0FILE|input cms for resign", required_argument, NULL, OPT_CMS_IN}, + {"cms-out\0FILE|output cms", required_argument, NULL, OPT_CMS_OUT}, + {"data-in\0FILE|input text data", required_argument, NULL, OPT_DATA_IN}, + {NULL, 0, NULL, 0} + }; + + char optstring[1024]; + int option; + int ret = 1; + + const char * certificate_exp = NULL; + const char * pass_exp = NULL; + const char * keyopt_exp = NULL; + + mycms_system system = mycms_context_get_system(context); + mycms mycms = NULL; + mycms_io cms_in = NULL; + mycms_io cms_out = NULL; + mycms_io data_in = NULL; + mycms_dict certificate_dict = NULL; + mycms_dict pass_dict = NULL; + mycms_dict keyopt_dict = NULL; + mycms_certificate certificate = NULL; + mycms_list_str digests = NULL; + + if ((mycms = mycms_new(context)) == NULL) { + goto cleanup; + } + + if (!mycms_construct(mycms)) { + goto cleanup; + } + + if (!getoptutil_short_from_long(long_options, "+", optstring, sizeof(optstring))) { + fprintf(stderr, "Failed to construct options"); + goto cleanup; + } + + while ((option = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { + switch (option) { + case OPT_HELP: + getoptutil_usage(stdout, argv[0], "sign [options]", long_options); + _cmd_common_extra_usage(); + ret = 0; + goto cleanup; + case OPT_DIGEST: + { + mycms_list_str t; + + if ((t = mycms_system_zalloc(system, "opt.digest", sizeof(*t))) == NULL) { + goto cleanup; + } + t->next = digests; + digests = t; + t->str = optarg; + } + break; + case OPT_CMS_IN: + if ((cms_in = mycms_io_new(context)) == NULL) { + goto cleanup; + } + if (!mycms_io_construct(cms_in)) { + goto cleanup; + } + if (!mycms_io_open_file(cms_in, optarg, "rb")) { + goto cleanup; + } + break; + case OPT_CMS_OUT: + if ((cms_out = mycms_io_new(context)) == NULL) { + goto cleanup; + } + if (!mycms_io_construct(cms_out)) { + goto cleanup; + } + if (!mycms_io_open_file(cms_out, optarg, "wb")) { + goto cleanup; + } + break; + case OPT_DATA_IN: + if ((data_in = mycms_io_new(context)) == NULL) { + goto cleanup; + } + if (!mycms_io_construct(data_in)) { + goto cleanup; + } + if (!mycms_io_open_file(data_in, optarg, "rb")) { + goto cleanup; + } + break; + case OPT_SIGNER_CERT: + certificate_exp = optarg; + break; + case OPT_SIGNER_CERT_PASS: + pass_exp = optarg; + break; + case OPT_KEYOPT: + keyopt_exp = optarg; + break; + default: + fprintf(stderr, "Invalid option\n"); + goto cleanup; + } + } + if (optind != argc) { + fprintf(stderr, "Unexpected positional options\n"); + goto cleanup; + } + + if (certificate_exp == NULL) { + fprintf(stderr, "Certificate is mandatory\n"); + goto cleanup; + } + if (cms_out == NULL) { + fprintf(stderr, "CMS out is mandatory\n"); + goto cleanup; + } + + if (digests == NULL) { + digests = mycms_system_zalloc(system, "digests", sizeof(*digests)); + digests->str = "SHA3-256"; + } + + if ((certificate_dict = mycms_dict_new(context)) == NULL) { + goto cleanup; + } + + if (!mycms_dict_construct(certificate_dict)) { + goto cleanup; + } + + if (!util_split_string(certificate_dict, certificate_exp)) { + goto cleanup; + } + + if ((pass_dict = mycms_dict_new(context)) == NULL) { + goto cleanup; + } + + if (!mycms_dict_construct(pass_dict)) { + goto cleanup; + } + + if (!util_split_string(pass_dict, pass_exp)) { + goto cleanup; + } + + if ((keyopt_dict = mycms_dict_new(context)) == NULL) { + goto cleanup; + } + + if (!mycms_dict_construct(keyopt_dict)) { + goto cleanup; + } + + if (!util_split_string(keyopt_dict, keyopt_exp)) { + goto cleanup; + } + + if ((certificate = mycms_certificate_new(context)) == NULL) { + goto cleanup; + } + + if (!mycms_certificate_construct(certificate)) { + goto cleanup; + } + + if (!mycms_certificate_set_userdata(certificate, pass_dict)) { + goto cleanup; + } + + if (!mycms_certificate_set_passphrase_callback(certificate, _cmd_common_passphrase_callback)) { + goto cleanup; + } + + { + _cmd_common_certificate_driver_apply x; + if ((x = _cmd_common_get_certificate_driver(&certificate_exp)) == NULL) { + fprintf(stderr, "Cannot resolve certificate expression"); + goto cleanup; + } + if (!x(certificate)) { + fprintf(stderr, "Cannot apply certificate expression"); + goto cleanup; + } + } + + if (!mycms_certificate_load(certificate, certificate_dict)) { + goto cleanup; + } + + if (!mycms_sign(mycms, certificate, digests, keyopt_dict, cms_in, cms_out, data_in)) { + goto cleanup; + } + + ret = 0; + +cleanup: + + while (digests != NULL) { + mycms_list_str t = digests; + digests = digests->next; + mycms_system_free(system, "digests", t); + } + + mycms_io_destruct(cms_in); + cms_in = NULL; + + mycms_io_destruct(cms_out); + cms_out = NULL; + + mycms_io_destruct(data_in); + data_in = NULL; + + mycms_certificate_destruct(certificate); + certificate = NULL; + + mycms_dict_destruct(certificate_dict); + certificate_dict = NULL; + + mycms_dict_destruct(pass_dict); + pass_dict = NULL; + + mycms_dict_destruct(keyopt_dict); + keyopt_dict = NULL; + + mycms_destruct(mycms); + mycms = NULL; + + return ret; +} diff --git a/src/mycms-tool/cmd-sign.h b/src/mycms-tool/cmd-sign.h new file mode 100644 index 0000000..db337f5 --- /dev/null +++ b/src/mycms-tool/cmd-sign.h @@ -0,0 +1,11 @@ +#ifndef __MYCMS_CMD_SIGN_H +#define __MYCMS_CMD_SIGN_H + +int +_cmd_sign( + const mycms_context context, + int argc, + char *argv[] +); + +#endif diff --git a/src/mycms-tool/cmd-verify.c b/src/mycms-tool/cmd-verify.c new file mode 100644 index 0000000..3cf5d91 --- /dev/null +++ b/src/mycms-tool/cmd-verify.c @@ -0,0 +1,269 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#include + +#include "getoptutil.h" +#include "util.h" + +#include "cmd-common.h" +#include "cmd-verify.h" + +int +_cmd_verify_list( + const mycms_context context, + int argc, + char *argv[] +) { + enum { + OPT_HELP = 0x1000, + OPT_CMS_IN, + OPT_MAX + }; + + static struct option long_options[] = { + {"help\0this usage", no_argument, NULL, OPT_HELP}, + {"cms-in\0FILE|input cms", required_argument, NULL, OPT_CMS_IN}, + {NULL, 0, NULL, 0} + }; + + char optstring[1024]; + int option; + int ret = 1; + + mycms mycms = NULL; + mycms_io cms_in = NULL; + mycms_list_signer signers = NULL; + mycms_list_signer t = NULL; + + if ((mycms = mycms_new(context)) == NULL) { + goto cleanup; + } + + if (!mycms_construct(mycms)) { + goto cleanup; + } + + if (!getoptutil_short_from_long(long_options, "+", optstring, sizeof(optstring))) { + fprintf(stderr, "Failed to construct options"); + goto cleanup; + } + + while ((option = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { + switch (option) { + case OPT_HELP: + getoptutil_usage(stdout, argv[0], "sign [options]", long_options); + _cmd_common_extra_usage(); + ret = 0; + goto cleanup; + case OPT_CMS_IN: + if ((cms_in = mycms_io_new(context)) == NULL) { + goto cleanup; + } + if (!mycms_io_construct(cms_in)) { + goto cleanup; + } + if (!mycms_io_open_file(cms_in, optarg, "rb")) { + goto cleanup; + } + break; + default: + fprintf(stderr, "Invalid option\n"); + goto cleanup; + } + } + if (optind != argc) { + fprintf(stderr, "Unexpected positional options\n"); + goto cleanup; + } + + if (cms_in == NULL) { + fprintf(stderr, "CMS in is mandatory\n"); + goto cleanup; + } + + if (!mycms_verify_list(mycms, cms_in, &signers)) { + goto cleanup; + } + + for (t = signers; t != NULL; t = t->next) { + size_t i; + for (i = 0; i < t->signer.keyid.size; i++) { + printf("%02x", t->signer.keyid.data[i]); + } + printf(" %s\n", t->signer.digest); + } + + ret = 0; + +cleanup: + + mycms_io_destruct(cms_in); + cms_in = NULL; + + mycms_verify_list_free(mycms, signers); + signers = NULL; + + mycms_destruct(mycms); + mycms = NULL; + + return ret; +} + +int +_cmd_verify( + const mycms_context context, + int argc, + char *argv[] +) { + enum { + OPT_HELP = 0x1000, + OPT_CMS_IN, + OPT_DATA_IN, + OPT_DIGEST, + OPT_CERT, + OPT_MAX + }; + + static struct option long_options[] = { + {"help\0this usage", no_argument, NULL, OPT_HELP}, + {"cms-in\0FILE|input cms", required_argument, NULL, OPT_CMS_IN}, + {"data-in\0FILE|input text data", required_argument, NULL, OPT_DATA_IN}, + {"digest\0DIGEST|digest to use, default is any", required_argument, NULL, OPT_DIGEST}, + {"cert\0FILE|add certificate to consider", required_argument, NULL, OPT_CERT}, + {NULL, 0, NULL, 0} + }; + + char optstring[1024]; + int option; + char *digest = NULL; + bool verified = false; + int ret = 1; + + mycms_system system = mycms_context_get_system(context); + mycms mycms = NULL; + mycms_io cms_in = NULL; + mycms_io data_in = NULL; + mycms_list_signer signers = NULL; + + if ((mycms = mycms_new(context)) == NULL) { + goto cleanup; + } + + if (!mycms_construct(mycms)) { + goto cleanup; + } + + if (!getoptutil_short_from_long(long_options, "+", optstring, sizeof(optstring))) { + goto cleanup; + } + + while ((option = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { + switch (option) { + case OPT_HELP: + getoptutil_usage(stdout, argv[0], "sign [options]", long_options); + _cmd_common_extra_usage(); + ret = 0; + goto cleanup; + case OPT_CMS_IN: + if ((cms_in = mycms_io_new(context)) == NULL) { + goto cleanup; + } + if (!mycms_io_construct(cms_in)) { + goto cleanup; + } + if (!mycms_io_open_file(cms_in, optarg, "rb")) { + goto cleanup; + } + break; + case OPT_DATA_IN: + if ((data_in = mycms_io_new(context)) == NULL) { + goto cleanup; + } + if (!mycms_io_construct(data_in)) { + goto cleanup; + } + if (!mycms_io_open_file(data_in, optarg, "rb")) { + goto cleanup; + } + break; + case OPT_DIGEST: + digest = optarg; + break; + case OPT_CERT: + { + mycms_list_signer t; + + if ((t = mycms_system_zalloc(system, "cert", sizeof(*t))) == NULL) { + goto cleanup; + } + t->next = signers; + signers = t; + + if (!_cmd_common_load_cert(system, optarg, &t->signer.cert)) { + fprintf(stderr, "Cannot load certificate"); + goto cleanup; + } + + if (digest != NULL) { + if ((t->signer.digest = mycms_system_strdup(system, "signer.digest", digest)) == NULL) { + goto cleanup; + } + } + } + break; + default: + fprintf(stderr, "Invalid option\n"); + goto cleanup; + } + } + if (optind != argc) { + fprintf(stderr, "Unexpected positional options\n"); + goto cleanup; + } + + if (cms_in == NULL) { + fprintf(stderr, "CMS in is mandatory\n"); + goto cleanup; + } + + if (!mycms_verify(mycms, cms_in, data_in, signers, &verified)) { + goto cleanup; + } + + if (verified) { + printf("VERIFIED"); + } else { + printf("FAILED"); + } + + ret = 0; + +cleanup: + + mycms_io_destruct(cms_in); + cms_in = NULL; + + mycms_io_destruct(data_in); + data_in = NULL; + + mycms_destruct(mycms); + mycms = NULL; + + while(signers != NULL) { + mycms_list_signer t = signers; + signers = signers->next; + t->next = NULL; + mycms_system_free(system, "signer.cert", t->signer.cert.data); + t->signer.cert.data = NULL; + mycms_system_free(system, "signer.digest", t->signer.digest); + t->signer.digest = NULL; + mycms_system_free(system, "signer", t); + } + + return ret; +} diff --git a/src/mycms-tool/cmd-verify.h b/src/mycms-tool/cmd-verify.h new file mode 100644 index 0000000..f7e958a --- /dev/null +++ b/src/mycms-tool/cmd-verify.h @@ -0,0 +1,18 @@ +#ifndef __MYCMS_CMD_VERIFY_H +#define __MYCMS_CMD_VERIFY_H + +int +_cmd_verify_list( + const mycms_context context, + int argc, + char *argv[] +); + +int +_cmd_verify( + const mycms_context context, + int argc, + char *argv[] +); + +#endif diff --git a/src/mycms-tool/getoptutil.c b/src/mycms-tool/getoptutil.c new file mode 100644 index 0000000..483c54b --- /dev/null +++ b/src/mycms-tool/getoptutil.c @@ -0,0 +1,104 @@ +/** + * @file + * @brief getopt_long utilities. + */ + +#include +#include +#include + +#include "getoptutil.h" + +void +getoptutil_usage( + FILE *out, + const char * const argv0, + const char * const extra_usage, + const struct option * const options +) { + const struct option *option; + + fprintf(out, "Usage: %s [options] %s\n", argv0, extra_usage); + for ( + option = options; + option->name != NULL; + option++ + ) { + const char *h = option->name+strlen(option->name)+1; + const char *k = NULL; + char key[1024]; + const char *p; + + if ((p = strchr(h, '|')) != NULL) { + if (p-h < (off_t)sizeof(key) - 1) { + strncpy(key, h, p-h); + key[p-h] = '\0'; + k = key; + h = p+1; + } + } + + fprintf(out, "%2s", ""); + if (option->val < 0x100) { + fprintf(out, "-%c, ", option->val); + } + else { + fprintf(out, "%4s", ""); + } + + fprintf(out, " --%s", option->name); + if ( + k != NULL && + (option->has_arg == required_argument || option->has_arg == optional_argument) + ) { + fprintf(out, "=%s", k); + } + fprintf( + out, + "\n%12s%s\n", + "", + h + ); + } +} + +bool +getoptutil_short_from_long( + const struct option * const options, + const char * const prefix, + char * const optstring, + size_t optstring_size +) { + const struct option *option; + + memset(optstring, 0, optstring_size); + + if (strlen(prefix) >= optstring_size) { + return false; + } + strcpy(optstring, prefix); + + for ( + option = options; + ( + option->name != NULL && + strlen(optstring) < optstring_size-4 + ); + option++ + ) { + if (option->val < 0x100) { + optstring[strlen(optstring)] = option->val; + switch (option->has_arg) { + case optional_argument: + optstring[strlen(optstring)] = ':'; + /* NO BREAK */ + __attribute__ ((fallthrough)); + case required_argument: + optstring[strlen(optstring)] = ':'; + break; + } + } + } + + return option->name == NULL; +} diff --git a/src/mycms-tool/getoptutil.h b/src/mycms-tool/getoptutil.h new file mode 100644 index 0000000..69ecba3 --- /dev/null +++ b/src/mycms-tool/getoptutil.h @@ -0,0 +1,44 @@ +#ifndef __GETOPTUTIL_H +#define __GETOPTUTIL_H + +/** + * @file + * @brief getopt_long utilities. + */ + + +#include +#include +#include + +/** + * Construct usage out of options. + * @param out output file. + * @param argv0 program file. + * @param extra_usage some additional notes. + * @param options the options, description is after null character. + */ +void +getoptutil_usage( + FILE *out, + const char * const argv0, + const char * const extra_usage, + const struct option * const options +); + +/** + * Construct short options out of long options. + * @param options the options. + * @param optstring the output short options. + * @param optstring_size the output size. + * @return 0 if buffer too short. + */ +bool +getoptutil_short_from_long( + const struct option * const options, + const char * const prefix, + char * const optstring, + size_t optstring_size +); + +#endif diff --git a/src/mycms-tool/main.c b/src/mycms-tool/main.c new file mode 100644 index 0000000..5dba1a3 --- /dev/null +++ b/src/mycms-tool/main.c @@ -0,0 +1,207 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include + +#include "cmd-common.h" +#include "cmd-decrypt.h" +#include "cmd-encrypt.h" +#include "cmd-sign.h" +#include "cmd-verify.h" +#include "getoptutil.h" + +static const char *__FEATURES[] = { + "sane", +#if defined(ENABLE_PINENTRY) + "pinentry", +#endif +#if defined(ENABLE_IO_DRIVER_FILE) + "io-driver-file", +#endif +#if defined(ENABLE_CERTIFICATE_DRIVER_FILE) + "certificate-driver-file", +#endif +#if defined(ENABLE_CERTIFICATE_DRIVER_PKCS11) + "certificate-driver-pkcs11", +#endif +#if defined(ENABLE_CMS_SIGN) + "sign", +#endif +#if defined(ENABLE_CMS_VERIFY) + "verify", +#endif +#if defined(ENABLE_CMS_ENCRYPT) + "encrypt", +#endif +#if defined(ENABLE_CMS_DECRYPT) + "decrypt", +#endif + NULL +}; + +int main(int argc, char *argv[]) { + enum { + OPT_HELP = 0x1000, + OPT_VERSION, + OPT_VERBOSE, + OPT_STDIO_EOL, + OPT_MAX + }; + + static struct commands_s { + const char *c; + const char *m; + int (*f)(const mycms_context context, int argc, char *argv[]); + } commands[] = { +#if defined(ENABLE_CMS_SIGN) + {"sign", "sign data", _cmd_sign}, +#endif +#if defined(ENABLE_CMS_VERIFY) + {"verify-list", "list signers", _cmd_verify_list}, + {"verify", "verift signature", _cmd_verify}, +#endif +#if defined(ENABLE_CMS_ENCRYPT) + {"encrypt", "encrypt data to recipients", _cmd_encrypt}, + {"encrypt-add", "add recipients in existing cms", _cmd_encrypt_add}, + {"encrypt-reset", "reset recipients in existing cms", _cmd_encrypt_reset}, +#endif +#if defined(ENABLE_CMS_DECRYPT) + {"decrypt", "decrypt cms", _cmd_decrypt}, +#endif + {NULL, NULL, NULL} + }; + + static struct option long_options[] = { + {"help\0this usage", no_argument, NULL, OPT_HELP}, + {"version\0print version", no_argument, NULL, OPT_VERSION}, + {"verbose\0verbose diagnostics", no_argument, NULL, OPT_VERBOSE}, + {"stdio-eol\0stdio eol, either crlf or lf", required_argument, NULL, OPT_STDIO_EOL}, + {NULL, 0, NULL, 0} + }; + + mycms_system system = NULL; + mycms_context context = NULL; + struct commands_s *cmd; + const char *command; + bool verbose = false; + char optstring[1024]; + int option; + int ret = 1; + + if ((system = mycms_system_new()) == NULL) { + goto cleanup; + } + + if (!mycms_system_construct(system)) { + goto cleanup; + } + + if (!mycms_static_init(system)) { + fprintf(stderr, "Failed to initialize certificate interface\n"); + goto cleanup; + } + + if ((context = mycms_context_new(system)) == NULL) { + goto cleanup; + } + + if (!mycms_context_construct(context)) { + goto cleanup; + } + + if (!getoptutil_short_from_long(long_options, "+", optstring, sizeof(optstring))) { + fprintf(stderr, "Failed to construct options"); + goto cleanup; + } + + while ((option = getopt_long(argc, argv, optstring, long_options, NULL)) != -1) { + switch (option) { + default: + fprintf(stderr, "Invalid option\n"); + goto cleanup; + case OPT_HELP: + getoptutil_usage(stdout, argv[0], "command [options]", long_options); + printf("\nAvailable commands:\n"); + for (cmd = commands; cmd->c != NULL; cmd++) { + printf("%8s%-16s - %s\n", "", cmd->c, cmd->m); + } + ret = 0; + goto cleanup; + case OPT_VERSION: + printf("%s-%s\n", PACKAGE_NAME, PACKAGE_VERSION); + printf("Features:"); + { + const char **p; + for (p = __FEATURES; *p != NULL; p++) { + printf(" %s", *p); + } + } + printf("\n"); + ret = 0; + goto cleanup; + case OPT_VERBOSE: + verbose = true; + break; + case OPT_STDIO_EOL: +#ifdef _WIN32 + if (!strcmp(optarg, "crlf")) { + } else if (!strcmp(optarg, "lf")) { + _setmode(0, _O_BINARY); + _setmode(1, _O_BINARY); + _setmode(2, _O_BINARY); +#else + if (!strcmp(optarg, "lf")) { +#endif + } else { + fprintf(stderr, "Invalid stdio eol '%s'\n", optarg); + } + break; + } + } + + if (optind == argc) { + fprintf(stderr, "Command is missing\n"); + goto cleanup; + } + + command = argv[optind++]; + + for (cmd = commands; cmd->c != NULL; cmd++) { + if (!strcmp(command, cmd->c)) { + ret = cmd->f(context, argc, argv); + goto cleanup; + } + } + + fprintf(stderr, "Unknown command '%s'\n", command); + +cleanup: + + if (system != NULL) { + mycms_error error = mycms_system_get_error(system); + + if (mycms_error_has_error(error)) { + char buf[10 * 1024]; + uint32_t code; + + mycms_error_format_simple(error, &code, buf, sizeof(buf)); + fprintf(stderr, "ERROR: %08x: %s\n", code, buf); + + if (verbose) { + mycms_error_format(error, buf, sizeof(buf)); + fputs(buf, stderr); + } + } + } + + mycms_context_destruct(context); + mycms_static_clean(system); + mycms_system_destruct(system); + + return ret; +} diff --git a/src/mycms-tool/util.c b/src/mycms-tool/util.c new file mode 100644 index 0000000..e6c6453 --- /dev/null +++ b/src/mycms-tool/util.c @@ -0,0 +1,91 @@ +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include + +#include "util.h" + +char * +util_strchr_escape( + char * const s, + const char c +) { + char *p1 = s; + char *p2 = p1; + bool escape = false; + + while (*p1 != '\0' && (escape || *p1 != c)) { + if (escape) { + escape = false; + *p2 = *p1; + p2++; + } else { + if (*p1 == '\\') { + escape = true; + } else { + *p2 = *p1; + p2++; + } + } + p1++; + } + + if (p1 != p2) { + *p2 = '\0'; + } + if (*p1 != '\0') { + *p1 = '\0'; + p1++; + } + + return *p1 == '\0' ? NULL : (char *)p1; +} + +bool +util_split_string( + const mycms_dict dict, + const char * const str +) { + char *s = NULL; + char *p0; + char *p1; + char *p2; + bool ret = false; + + if (str == NULL) { + return true; + } + + if ((s = mycms_system_strdup(mycms_context_get_system(mycms_dict_get_context(dict)), "split_string", str)) == NULL) { + goto cleanup; + } + + p0 = s; + + while (p0 != NULL) { + p1 = util_strchr_escape(p0, ':'); + + if ((p2 = strchr(p0, '=')) != NULL) { + *p2 = '\0'; + p2++; + + if (!mycms_dict_entry_put(dict, p0, p2)) { + goto cleanup; + } + } + + p0 = p1; + } + + ret = true; + +cleanup: + + free(s); + s = NULL; + + return ret; +} diff --git a/src/mycms-tool/util.h b/src/mycms-tool/util.h new file mode 100644 index 0000000..9640606 --- /dev/null +++ b/src/mycms-tool/util.h @@ -0,0 +1,18 @@ +#ifndef __UTIL_H +#define __UTIL_H + +#include + +char * +util_strchr_escape( + char * const s, + const char c +); + +bool +util_split_string( + const mycms_dict dict, + const char * const str +); + +#endif diff --git a/src/mycms-tool/versioninfo.rc.in b/src/mycms-tool/versioninfo.rc.in new file mode 100644 index 0000000..7964a69 --- /dev/null +++ b/src/mycms-tool/versioninfo.rc.in @@ -0,0 +1,31 @@ +#include + +VS_VERSION_INFO VERSIONINFO + FILEVERSION @MYCMS_VERSION_MAJOR@,@MYCMS_VERSION_MINOR@,@MYCMS_VERSION_FIX@,@MYCMS_VERSION_REVISION@ + PRODUCTVERSION @MYCMS_VERSION_MAJOR@,@MYCMS_VERSION_MINOR@,@MYCMS_VERSION_FIX@,@MYCMS_VERSION_REVISION@ + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x21L +#else + FILEFLAGS 0x20L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "FileVersion", "@MYCMS_VERSION_MAJOR@.@MYCMS_VERSION_MINOR@.@MYCMS_VERSION_FIX@.@MYCMS_VERSION_REVISION@" + VALUE "InternalName", "@PACKAGE_NAME@" + VALUE "ProductName", "@PACKAGE_NAME@" + VALUE "ProductVersion", "@MYCMS_VERSION_MAJOR@,@MYCMS_VERSION_MINOR@,@MYCMS_VERSION_FIX@,@MYCMS_VERSION_REVISION@" + VALUE "FileDescription", "@PACKAGE_NAME@ Tool" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END diff --git a/test/Makefile.am b/test/Makefile.am new file mode 100644 index 0000000..8c78936 --- /dev/null +++ b/test/Makefile.am @@ -0,0 +1,8 @@ +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in \ + $(NULL) + +SUBDIRS = \ + ca \ + mycms-tool \ + $(NULL) diff --git a/test/ca/Makefile.am b/test/ca/Makefile.am new file mode 100644 index 0000000..36fa183 --- /dev/null +++ b/test/ca/Makefile.am @@ -0,0 +1,50 @@ +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in \ + $(NULL) + +clean-local: + rm -fr rootca.pki built.rootca + rm -fr subca.pki built.subca + +check-local: \ + built.rootca \ + built.subca \ + $(NULL) + +dist_noinst_SCRIPTS = \ + issue.sh \ + $(NULL) + +dist_noinst_DATA = \ + oids.cnf \ + x509-types/COMMON \ + x509-types/ca \ + x509-types/encrypt \ + x509-types/sign \ + $(NULL) + +built.rootca: \ + oids.cnf \ + $(NULL) + rm -f built.rootca init-pki + $(EASYRSA) --vars="./rootca.vars" init-pki + touch rootca.pki/.rnd + $(EASYRSA) --vars="./rootca.vars" build-ca nopass + touch built.rootca + +built.subca: \ + built.rootca \ + oids.cnf \ + $(NULL) + rm -f built.subca subca.pki + $(EASYRSA) --vars="./subca.vars" init-pki + touch subca.pki/.rnd + + cat "$(srcdir)/oids.cnf" >> subca.pki/openssl-easyrsa.cnf + sed -i '1i oid_section = oids' subca.pki/openssl-easyrsa.cnf + + $(EASYRSA) --vars="./subca.vars" build-ca nopass subca + $(EASYRSA) --vars="./rootca.vars" import-req ./subca.pki/reqs/ca.req subca + $(EASYRSA) --vars="./rootca.vars" sign-req ca subca + cp ./rootca.pki/issued/subca.crt ./subca.pki/ca.crt + touch built.subca diff --git a/test/ca/issue.sh b/test/ca/issue.sh new file mode 100755 index 0000000..6ea7d06 --- /dev/null +++ b/test/ca/issue.sh @@ -0,0 +1,23 @@ +#!/bin/sh + +abs_builddir="${abs_builddir:-$(dirname "$0")}" +. "${abs_builddir}/vars" + +die() { + local m="$1" + echo "FATAL: ${m}" >&2 + exit 1 +} + +TEMPLATE="$1"; shift +NAME="$1"; shift +CERT="$1"; shift +KEY="$1"; shift + +"${EASYRSA}" --vars="${abs_builddir}/subca.vars" gen-req "${NAME}" nopass || die "req" +"${EASYRSA}" --vars="${abs_builddir}/subca.vars" --subject-alt-name="URI:test:${NAME}" sign-req "${TEMPLATE}" "${NAME}" nopass || die "sign" + +"${OPENSSL}" x509 -in "${abs_builddir}/subca.pki/issued/${NAME}.crt" -inform PEM -out "${CERT}" -outform DER || die "export.cert" +"${OPENSSL}" pkcs8 -in "${abs_builddir}/subca.pki/private/${NAME}.key" -inform PEM -out "${KEY}" -outform DER -nocrypt || die "export.key" + +exit 0 diff --git a/test/ca/oids.cnf b/test/ca/oids.cnf new file mode 100644 index 0000000..ced7861 --- /dev/null +++ b/test/ca/oids.cnf @@ -0,0 +1,3 @@ +[oids] +oidSign1 = 1.2.3.4 +oidEncrypt1 = 1.2.3.5 diff --git a/test/ca/rootca.vars.in b/test/ca/rootca.vars.in new file mode 100644 index 0000000..c455f62 --- /dev/null +++ b/test/ca/rootca.vars.in @@ -0,0 +1,15 @@ +set_var EASYRSA_OPENSSL "@OPENSSL@" +alias awk="@AWK@" +set_var EASYRSA_PKI "@abs_builddir@/rootca.pki" +set_var EASYRSA_EXT_DIR "@abs_srcdir@/x509-types" +set_var EASYRSA_DN "cn_only" +set_var EASYRSA_KEY_SIZE 4096 +set_var EASYRSA_ALGO rsa +set_var EASYRSA_CA_EXPIRE 3650 +set_var EASYRSA_CERT_EXPIRE 1080 +set_var EASYRSA_CRL_DAYS 180 +set_var EASYRSA_NS_SUPPORT "no" +set_var EASYRSA_TEMP_FILE "$EASYRSA_PKI/extensions.temp" +set_var EASYRSA_REQ_CN "CA1" +set_var EASYRSA_DIGEST "sha256" +set_var EASYRSA_BATCH "1" diff --git a/test/ca/subca.vars.in b/test/ca/subca.vars.in new file mode 100644 index 0000000..42f9edd --- /dev/null +++ b/test/ca/subca.vars.in @@ -0,0 +1,15 @@ +set_var EASYRSA_OPENSSL "@OPENSSL@" +alias awk="@AWK@" +set_var EASYRSA_PKI "@abs_builddir@/subca.pki" +set_var EASYRSA_EXT_DIR "@abs_srcdir@/x509-types" +set_var EASYRSA_DN "cn_only" +set_var EASYRSA_KEY_SIZE 4096 +set_var EASYRSA_ALGO rsa +set_var EASYRSA_CA_EXPIRE 3650 +set_var EASYRSA_CERT_EXPIRE 1080 +set_var EASYRSA_CRL_DAYS 180 +set_var EASYRSA_NS_SUPPORT "no" +set_var EASYRSA_TEMP_FILE "$EASYRSA_PKI/extensions.temp" +set_var EASYRSA_REQ_CN "CA2" +set_var EASYRSA_DIGEST "sha256" +set_var EASYRSA_BATCH "1" diff --git a/test/ca/vars.in b/test/ca/vars.in new file mode 100644 index 0000000..20c0264 --- /dev/null +++ b/test/ca/vars.in @@ -0,0 +1,3 @@ +abs_builddir="@abs_builddir@" +EASYRSA="@EASYRSA@" +OPENSSL="@OPENSSL@" diff --git a/test/ca/x509-types/COMMON b/test/ca/x509-types/COMMON new file mode 100644 index 0000000..3e9b633 --- /dev/null +++ b/test/ca/x509-types/COMMON @@ -0,0 +1,7 @@ +# X509 extensions added to every signed cert + +# This file is included for every cert signed, and by default does nothing. +# It could be used to add values every cert should have, such as a CDP as +# demonstrated in the following example: + +#crlDistributionPoints = URI:http://example.net/pki/my_ca.crl diff --git a/test/ca/x509-types/ca b/test/ca/x509-types/ca new file mode 100644 index 0000000..ef525b6 --- /dev/null +++ b/test/ca/x509-types/ca @@ -0,0 +1,13 @@ +# X509 extensions for a ca + +# Note that basicConstraints will be overridden by Easy-RSA when defining a +# CA_PATH_LEN for CA path length limits. You could also do this here +# manually as in the following example in place of the existing line: +# +# basicConstraints = CA:TRUE, pathlen:1 + +basicConstraints = CA:TRUE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid:always,issuer:always +keyUsage = cRLSign, keyCertSign + diff --git a/test/ca/x509-types/encrypt b/test/ca/x509-types/encrypt new file mode 100644 index 0000000..5196f3a --- /dev/null +++ b/test/ca/x509-types/encrypt @@ -0,0 +1,8 @@ +# X509 extensions for a server + +basicConstraints = CA:FALSE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +extendedKeyUsage = oidEncrypt1 +keyUsage = keyEncipherment + diff --git a/test/ca/x509-types/sign b/test/ca/x509-types/sign new file mode 100644 index 0000000..1c07fd0 --- /dev/null +++ b/test/ca/x509-types/sign @@ -0,0 +1,8 @@ +# X509 extensions for a client + +basicConstraints = CA:FALSE +subjectKeyIdentifier = hash +authorityKeyIdentifier = keyid,issuer:always +extendedKeyUsage = oidSign1 +keyUsage = digitalSignature + diff --git a/test/mycms-tool/Makefile.am b/test/mycms-tool/Makefile.am new file mode 100644 index 0000000..eea16fe --- /dev/null +++ b/test/mycms-tool/Makefile.am @@ -0,0 +1,9 @@ +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in \ + $(NULL) + +SUBDIRS = \ + encrypt \ + sign \ + windows \ + $(NULL) diff --git a/test/mycms-tool/encrypt/Makefile.am b/test/mycms-tool/encrypt/Makefile.am new file mode 100644 index 0000000..7a87290 --- /dev/null +++ b/test/mycms-tool/encrypt/Makefile.am @@ -0,0 +1,51 @@ +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in \ + $(NULL) + +CLEANFILES = \ + built.pki \ + $(NULL) + +clean-local: + rm -fr gen + +check-am: built.pki + +TESTS = \ + test-file.sh \ + $(NULL) +if !BUILD_WINDOWS +TESTS += \ + test-pkcs11.sh \ + $(NULL) +endif + +dist_noinst_SCRIPTS = \ + test-file.sh \ + test-pkcs11.sh \ + $(NULL) + +dist_noinst_DATA = \ + softhsm2.conf.in \ + test-pkcs11.valgrind.supp \ + $(NULL) + +TESTS_ENVIRONMENT = \ + LIBTOOL="$(LIBTOOL)" \ + MYCMS_TOOL="$(top_builddir)/src/mycms-tool/mycms-tool$(EXEEXT)" \ + OPENSSL="$(OPENSSL)" \ + PKCS11_TOOL="$(PKCS11_TOOL)" \ + SOFTHSM2_MODULE="$(SOFTHSM2_MODULE)" \ + SOFTHSM2_UTIL="$(SOFTHSM2_UTIL)" \ + VALGRIND="$(VALGRIND)" \ + builddir="$(builddir)" \ + top_builddir="$(top_builddir)" \ + $(NULL) + +built.pki: Makefile + rm -fr gen + mkdir gen + for i in 1 2 3 4 5; do \ + abs_builddir="$(abs_top_builddir)/test/ca" "$(top_srcdir)/test/ca/issue.sh" encrypt test$$i gen/test$$i.crt gen/test$$i.key; \ + done + touch built.pki diff --git a/test/mycms-tool/encrypt/softhsm2.conf.in b/test/mycms-tool/encrypt/softhsm2.conf.in new file mode 100644 index 0000000..feab15b --- /dev/null +++ b/test/mycms-tool/encrypt/softhsm2.conf.in @@ -0,0 +1,2 @@ +directories.tokendir = @TOKENDIR@ +objectstore.backend = file diff --git a/test/mycms-tool/encrypt/test-file.sh b/test/mycms-tool/encrypt/test-file.sh new file mode 100755 index 0000000..73da287 --- /dev/null +++ b/test/mycms-tool/encrypt/test-file.sh @@ -0,0 +1,276 @@ +#!/bin/sh + +srcdir="${srcdir:-.}" +builddir="${builddir:-${srcdir}}" +MYCMS_TOOL="${MYCMS_TOOL:-mycms-tool}" +OPENSSL="${OPENSSL:-openssl}" +VALGRIND="${VALGRIND:-valgrind}" +LIBTOOL="${LIBTOOL:-libtool}" + +VALGRIND_CMD="${VALGRIND_CMD:-"${LIBTOOL}" --mode=execute ${VALGRIND}}" + +die() { + local m="$1" + echo "FATAL: ${m}" >&2 + exit 1 +} + +skip() { + local m="$1" + echo "SKIP: ${m}" >&2 + exit 77 +} + +MYTMP= +cleanup() { + rm -fr "${MYTMP}" +} +trap cleanup 0 + +doval() { + if [ "${MYCMS_DO_VALGRIND}" = 1 ]; then + ${VALGRIND_CMD} -q --leak-check=full --leak-resolution=high --show-leak-kinds=all --error-exitcode=99 "$@" + else + "$@" + fi +} + +test_sanity() { + local PREFIX="${MYTMP}/sanity" + local CMS="${PREFIX}-cms" + local CT="${PREFIX}-ct" + local OUTPT="${PREFIX}-pt" + + echo "Encrypting to test1" + doval "${MYCMS_TOOL}" encrypt \ + --cms-out="${CMS}" \ + --data-pt="${PT}" \ + --data-ct="${CT}" \ + --to="${builddir}/gen/test1.crt" \ + || die "sanity.encrypt" + + echo "Decrypting by test1" + doval "${MYCMS_TOOL}" decrypt \ + --cms-in="${CMS}" \ + --recip-cert="file:cert=${builddir}/gen/test1.crt:key=${builddir}/gen/test1.key" \ + --data-pt="${OUTPT}" \ + --data-ct="${CT}" \ + || die "sanity.decrypt" + cmp -s "${PT}" "${CT}" && die "sanity.cmp.ct" + cmp -s "${PT}" "${OUTPT}" || die "sanity.cmp" + + echo "Decrypting by test2 (should fail)" + doval "${MYCMS_TOOL}" decrypt \ + --cms-in="${CMS}" \ + --recip-cert="file:cert=${builddir}/gen/test2.crt:key=${builddir}/gen/test2.key" \ + --data-pt="${OUTPT}" \ + --data-ct="${CT}" \ + && die "sanity.decrypt succeeded with other" + + return 0 +} + +test_multiple_recepients() { + local PREFIX="${MYTMP}/mrecip" + local CMS="${PREFIX}-cms" + local CT="${PREFIX}-ct1" + local OUTPT1="${PREFIX}-pt1" + local OUTPT2="${PREFIX}-pt2" + + echo "Encrypting to test1 and test2" + doval "${MYCMS_TOOL}" encrypt \ + --cms-out="${CMS}" \ + --data-pt="${PT}" \ + --data-ct="${CT}" \ + --to="${builddir}/gen/test1.crt" \ + --to="${builddir}/gen/test2.crt" \ + || die "multi-recip.encrypt" + echo "Decrypting by test1" + doval "${MYCMS_TOOL}" decrypt \ + --cms-in="${CMS}" \ + --recip-cert="file:cert=${builddir}/gen/test1.crt:key=${builddir}/gen/test1.key" \ + --data-pt="${OUTPT1}" \ + --data-ct="${CT}" \ + || die "multi-recip.decrypt" + cmp -s "${PT}" "${OUTPT1}" || die "sanity.cmp" + echo "Decrypting by test2" + doval "${MYCMS_TOOL}" decrypt \ + --cms-in="${CMS}" \ + --recip-cert="file:cert=${builddir}/gen/test2.crt:key=${builddir}/gen/test2.key" \ + --data-pt="${OUTPT2}" \ + --data-ct="${CT}" \ + || die "multi-recip.decrypt" + cmp -s "${PT}" "${OUTPT2}" || die "sanity.cmp" + + return 0 +} + +test_add_recepients() { + local PREFIX="${MYTMP}/addrecip" + local CMS1="${PREFIX}-cms1" + local CMS2="${PREFIX}-cms2" + local CT="${PREFIX}-ct1" + local OUTPT="${PREFIX}-pt" + + echo "Encrypting to test1 and test2" + doval "${MYCMS_TOOL}" encrypt \ + --cms-out="${CMS1}" \ + --data-pt="${PT}" \ + --data-ct="${CT}" \ + --to="${builddir}/gen/test1.crt" \ + --to="${builddir}/gen/test2.crt" \ + || die "add-recip.encrypt" + + echo "Ading to test3 and test4 using test1" + doval "${MYCMS_TOOL}" encrypt-add \ + --cms-in="${CMS1}" \ + --cms-out="${CMS2}" \ + --recip-cert="file:cert=${builddir}/gen/test1.crt:key=${builddir}/gen/test1.key" \ + --to="${builddir}/gen/test3.crt" \ + --to="${builddir}/gen/test4.crt" \ + || die "add-recip.encrypt" + + local x + for x in test1 test2 test3 test4; do + echo "Decrypting by '${x}'" + doval "${MYCMS_TOOL}" decrypt \ + --cms-in="${CMS2}" \ + --recip-cert="file:cert=${builddir}/gen/${x}.crt:key=${builddir}/gen/${x}.key" \ + --data-pt="${OUTPT}-${x}" \ + --data-ct="${CT}" \ + || die "add-recip.decrypt.${x}" + cmp -s "${PT}" "${OUTPT}-${x}" || die "sanity.cmp" + done + + echo "Decrypting by test5 (should fail)" + doval "${MYCMS_TOOL}" decrypt \ + --cms-in="${CMS2}" \ + --recip-cert="file:cert=${builddir}/gen/test5.crt:key=${builddir}/gen/test5.key" \ + --data-pt="${OUTPT}-test5" \ + --data-ct="${CT}" \ + && die "sanity.decrypt should not succeed" + + return 0 +} + +test_reset_recepients() { + local PREFIX="${MYTMP}/resetrecip" + local CMS1="${PREFIX}-cms1" + local CMS2="${PREFIX}-cms2" + local CT="${PREFIX}-ct1" + local OUTPT="${PREFIX}-pt" + + echo "Encrypting to test1 and test2" + doval "${MYCMS_TOOL}" encrypt \ + --cms-out="${CMS1}" \ + --data-pt="${PT}" \ + --data-ct="${CT}" \ + --to="${builddir}/gen/test1.crt" \ + --to="${builddir}/gen/test2.crt" \ + --to="${builddir}/gen/test3.crt" \ + --to="${builddir}/gen/test4.crt" \ + || die "reset-recip.encrypt" + + echo "Reset to test3 and test4" + doval "${MYCMS_TOOL}" encrypt-reset \ + --cms-in="${CMS1}" \ + --cms-out="${CMS2}" \ + --to="${builddir}/gen/test2.crt" \ + --to="${builddir}/gen/test3.crt" \ + || die "reset-recip.encrypt" + + local x + for x in test2 test3; do + echo "Decrypting by '${x}'" + doval "${MYCMS_TOOL}" decrypt \ + --cms-in="${CMS2}" \ + --recip-cert="file:cert=${builddir}/gen/${x}.crt:key=${builddir}/gen/${x}.key" \ + --data-pt="${OUTPT}-${x}" \ + --data-ct="${CT}" \ + || die "reset-recip.decrypt.${x}" + cmp -s "${PT}" "${OUTPT}-${x}" || die "reset-recip.decrypt.cmp" + done + + for x in test1 test4; do + echo "Decrypting by '${x}' [SHOULD FAIL]" + doval "${MYCMS_TOOL}" decrypt \ + --cms-in="${CMS2}" \ + --recip-cert="file:cert=${builddir}/gen/${x}.crt:key=${builddir}/gen/${x}.key" \ + --data-pt="${OUTPT}-${x}" \ + --data-ct="${CT}" \ + && die "reset-recip.decrypt.${x} should fail" + done + + return 0 +} + +test_keyopt() { + local PREFIX="${MYTMP}/keyopt" + local CMS1="${PREFIX}-cms1" + local CMS2="${PREFIX}-cms2" + local CT="${PREFIX}-ct1" + local OUTPT="${PREFIX}-pt" + + while IFS=":" read padding padding_str; do + echo "Using ${padding}" + + echo "Encrypting to test1 and test2" + doval "${MYCMS_TOOL}" encrypt \ + --cms-out="${CMS1}" \ + --data-pt="${PT}" \ + --data-ct="${CT}" \ + --to="${builddir}/gen/test1.crt" \ + --to="${builddir}/gen/test2.crt" \ + --keyopt="rsa_padding_mode=${padding}" \ + || die "add-recip.encrypt" + + echo "Ading to test3 and test4 using test1" + doval "${MYCMS_TOOL}" encrypt-add \ + --cms-in="${CMS1}" \ + --cms-out="${CMS2}" \ + --recip-cert="file:cert=${builddir}/gen/test1.crt:key=${builddir}/gen/test1.key" \ + --to="${builddir}/gen/test3.crt" \ + --to="${builddir}/gen/test4.crt" \ + --keyopt="rsa_padding_mode=${padding}" \ + || die "add-recip.encrypt" + + [ 4 -eq $("${OPENSSL}" asn1parse -in "${CMS2}" -inform DER | grep "${padding_str}" | wc -l) ] || die "Expected '${padding_str}' for '${padding}'" + + local x + for x in test1 test2 test3 test4; do + echo "Decrypting by '${x}'" + doval "${MYCMS_TOOL}" decrypt \ + --cms-in="${CMS2}" \ + --recip-cert="file:cert=${builddir}/gen/${x}.crt:key=${builddir}/gen/${x}.key" \ + --data-pt="${OUTPT}-${x}" \ + --data-ct="${CT}" \ + || die "add-recip.decrypt.${x}" + cmp -s "${PT}" "${OUTPT}-${x}" || die "sanity.cmp" + done + done << __EOF__ +pkcs1:rsaEncryption +oaep:rsaesOaep +__EOF__ + + return 0 +} + +[ -x "${MYCMS_TOOL}" ] || skip "no tool" +features="$("${MYCMS_TOOL}" --version | grep "Features")" || die "Cannot execute tool" +echo "${features}" | grep -q "sane" || die "tool is insane" +echo "${features}" | grep -q "encrypt" || skip "encrypt feature is not available" +echo "${features}" | grep -q "decrypt" || skip "decrypt feature is not available" +echo "${features}" | grep -q "certificate-driver-file" || skip "certificate-driver-file feature is not available" + +MYTMP="$(mktemp -d)" +PT="${MYTMP}/pt" +dd if=/dev/urandom bs=512 count=20 of="${PT}" status=none || die "dd plain" + +TESTS="${TESTS:-test_sanity test_multiple_recepients test_add_recepients test_reset_recepients test_keyopt}" + +for test in $TESTS; do + echo "------------------------" + echo "${test}" + echo "------------------------" + "${test}" +done diff --git a/test/mycms-tool/encrypt/test-pkcs11.sh b/test/mycms-tool/encrypt/test-pkcs11.sh new file mode 100755 index 0000000..b71eccf --- /dev/null +++ b/test/mycms-tool/encrypt/test-pkcs11.sh @@ -0,0 +1,191 @@ +#!/bin/sh + +srcdir="${srcdir:-.}" +builddir="${builddir:-${srcdir}}" +MYCMS_TOOL="${MYCMS_TOOL:-mycms-tool}" +SOFTHSM2_UTIL="${SOFTHSM2_UTIL:-softhsm2-util}" +PKCS11_TOOL="${PKCS11_TOOL:-pkcs11-tool}" +OPENSSL="${OPENSSL:-openssl}" +VALGRIND="${VALGRIND:-valgrind}" +LIBTOOL="${LIBTOOL:-libtool}" + +VALGRIND_CMD="${VALGRIND_CMD:-"${LIBTOOL}" --mode=execute ${VALGRIND}}" + +die() { + local m="$1" + echo "FATAL: ${m}" >&2 + exit 1 +} + +skip() { + local m="$1" + echo "SKIP: ${m}" >&2 + exit 77 +} + +MYTMP= +cleanup() { + rm -fr "${MYTMP}" +} +trap cleanup 0 + +doval() { + if [ "${MYCMS_DO_VALGRIND}" = 1 ]; then + ${VALGRIND_CMD} -q --leak-check=full --leak-resolution=high --show-leak-kinds=all --error-exitcode=99 --suppressions="${srcdir}/test-pkcs11.valgrind.supp" "$@" + else + "$@" + fi +} + +prepare_token() { + "${SOFTHSM2_UTIL}" --init-token --free --label token1 --so-pin sosecret --pin secret || die "init-token" + for o in 1 2 3 4 5; do +if [ -n "${__MYCMS_USE_CERTUTIL}" ]; then + local k="${MYTMP}/k" + local c="${MYTMP}/c" + openssl pkcs8 -topk8 -inform DER -in "${builddir}/gen/test${o}.key" -out "${k}" -nocrypt || die "openssl.p8" + openssl x509 -inform DER -in "${builddir}/gen/test${o}.crt" -out "${c}" || die "openssl.crt" + "${SOFTHSM2_UTIL}" \ + --import "${MYTMP}/k" \ + --import-type=keypair \ + --token token1 \ + --id $(printf "%02x" ${o}) \ + --label test${o} \ + --pin secret \ + || die "softhsm.import.key.${o}" + "${SOFTHSM2_UTIL}" \ + --import "${MYTMP}/c" \ + --import-type=cert \ + --token token1 \ + --id $(printf "%02x" ${o}) \ + --label test${o} \ + --pin secret \ + || die "softhsm.import.cert.${o}" +else + "${PKCS11_TOOL}" \ + --module "${SOFTHSM2_MODULE}" \ + --token-label token1 \ + --login \ + --pin secret \ + --private \ + --id ${o} \ + --label test${o} \ + --type privkey \ + --usage-decrypt \ + --write-object "${builddir}/gen/test${o}.key" \ + || die "pkcs11-tool.key.${o}" + "${PKCS11_TOOL}" \ + --module "${SOFTHSM2_MODULE}" \ + --token-label token1 \ + --login \ + --pin secret \ + --id ${o} \ + --label test${o} \ + --type cert \ + --write-object "${builddir}/gen/test${o}.crt" \ + || die "pkcs11-tool.crt.${o}" +fi + done +} + +test_sanity() { + local PREFIX="${MYTMP}/sanity" + local CMS="${PREFIX}-cms" + local CT="${PREFIX}-ct" + local OUTPT="${PREFIX}-pt" + + echo "Encrypting to test1" + doval "${MYCMS_TOOL}" encrypt \ + --cms-out="${CMS}" \ + --data-pt="${PT}" \ + --data-ct="${CT}" \ + --to="${builddir}/gen/test1.crt" \ + || die "sanity.encrypt" + echo "Decrypting by test1" + doval "${MYCMS_TOOL}" decrypt \ + --cms-in="${CMS}" \ + --recip-cert="pkcs11:module=${SOFTHSM2_MODULE}:token-label=token1:cert-label=test1" \ + --recip-cert-pass="token=pass=secret" \ + --data-pt="${OUTPT}" \ + --data-ct="${CT}" \ + || die "sanity.decrypt" + + cmp -s "${PT}" "${CT}" && die "sanity.cmp.ct" + cmp -s "${PT}" "${OUTPT}" || die "sanity.cmp" + + return 0 +} + +test_add_recepients() { + local PREFIX="${MYTMP}/addrecip" + local CMS1="${PREFIX}-cms1" + local CMS2="${PREFIX}-cms2" + local CT="${PREFIX}-ct1" + local OUTPT="${PREFIX}-pt" + + echo "Encrypting to test1 and test2" + doval "${MYCMS_TOOL}" encrypt \ + --cms-out="${CMS1}" \ + --data-pt="${PT}" \ + --data-ct="${CT}" \ + --to="${builddir}/gen/test1.crt" \ + --to="${builddir}/gen/test2.crt" \ + || die "add-recip.encrypt" + + echo "Ading to test3 and test4 using test1" + doval "${MYCMS_TOOL}" encrypt-add \ + --cms-in="${CMS1}" \ + --cms-out="${CMS2}" \ + --recip-cert="pkcs11:module=${SOFTHSM2_MODULE}:token-label=token1:cert-label=test1" \ + --recip-cert-pass="token=pass=secret" \ + --to="${builddir}/gen/test3.crt" \ + --to="${builddir}/gen/test4.crt" \ + || die "add-recip.encrypt" + + local x + for x in test1 test2 test3 test4; do + echo "Decrypting by '${x}'" + doval "${MYCMS_TOOL}" decrypt \ + --cms-in="${CMS2}" \ + --recip-cert="pkcs11:module=${SOFTHSM2_MODULE}:token-label=token1:cert-label=${x}" \ + --recip-cert-pass="token=pass=secret" \ + --data-pt="${OUTPT}-${x}" \ + --data-ct="${CT}" \ + || die "add-recip.decrypt.${x}" + cmp -s "${PT}" "${OUTPT}-${x}" || die "sanity.cmp" + done + + return 0 +} + +[ -x "${MYCMS_TOOL}" ] || skip "no tool" +features="$("${MYCMS_TOOL}" --version | grep "Features")" || die "Cannot execute tool" +echo "${features}" | grep -q "sane" || die "tool is insane" +echo "${features}" | grep -q "encrypt" || skip "encrypt feature is not available" +echo "${features}" | grep -q "decrypt" || skip "decrypt feature is not available" +echo "${features}" | grep -q "certificate-driver-pkcs11" || skip "certificate-driver-pkcs11 feature is not available" + +"${SOFTHSM2_UTIL}" --version > /dev/null || skip "softhsm2-util not found" +"${PKCS11_TOOL}" --version 2>&1 | grep -q "Usage:" || skip "pkcs11-tool not found" + +[ -z "${SOFTHSM2_MODULE}" ] && die "Cannot find softhsm module" + +MYTMP="$(mktemp -d)" +PT="${MYTMP}/pt" +dd if=/dev/urandom bs=512 count=20 of="${PT}" status=none || die "dd plain" + +tokendir="${MYTMP}/token" +mkdir -p "${tokendir}" +sed "s#@TOKENDIR@#${tokendir}#" "${srcdir}/softhsm2.conf.in" > "${MYTMP}/softhsm2.conf" +export SOFTHSM2_CONF="${MYTMP}/softhsm2.conf" + +prepare_token + +TESTS="${TESTS:-test_sanity test_add_recepients}" + +for test in $TESTS; do + echo "------------------------" + echo "${test}" + echo "------------------------" + "${test}" +done diff --git a/test/mycms-tool/encrypt/test-pkcs11.valgrind.supp b/test/mycms-tool/encrypt/test-pkcs11.valgrind.supp new file mode 100644 index 0000000..52545b4 --- /dev/null +++ b/test/mycms-tool/encrypt/test-pkcs11.valgrind.supp @@ -0,0 +1,29 @@ +{ + C_Initialize + Memcheck:Leak + match-leak-kinds: definite + ... + obj:/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so + fun:C_Initialize +} +{ + _dl_catch_exception + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:_dl_catch_exception +} +{ + dlopen + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:dlopen@@* +} +{ + _dlerror_run + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:_dlerror_run +} diff --git a/test/mycms-tool/sign/Makefile.am b/test/mycms-tool/sign/Makefile.am new file mode 100644 index 0000000..9fad9ee --- /dev/null +++ b/test/mycms-tool/sign/Makefile.am @@ -0,0 +1,51 @@ +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in \ + $(NULL) + +CLEANFILES = \ + built.pki \ + $(NULL) + +clean-local: + rm -fr gen + +check-am: built.pki + +TESTS = \ + test-file.sh \ + $(NULL) +if !BUILD_WINDOWS +TESTS += \ + test-pkcs11.sh \ + $(NULL) +endif + +dist_noinst_SCRIPTS = \ + test-file.sh \ + test-pkcs11.sh \ + $(NULL) + +dist_noinst_DATA = \ + softhsm2.conf.in \ + test-pkcs11.valgrind.supp \ + $(NULL) + +TESTS_ENVIRONMENT = \ + LIBTOOL="$(LIBTOOL)" \ + MYCMS_TOOL="$(top_builddir)/src/mycms-tool/mycms-tool$(EXEEXT)" \ + OPENSSL="$(OPENSSL)" \ + PKCS11_TOOL="$(PKCS11_TOOL)" \ + SOFTHSM2_MODULE="$(SOFTHSM2_MODULE)" \ + SOFTHSM2_UTIL="$(SOFTHSM2_UTIL)" \ + VALGRIND="$(VALGRIND)" \ + builddir="$(builddir)" \ + top_builddir="$(top_builddir)" \ + $(NULL) + +built.pki: Makefile + rm -fr gen + mkdir gen + for i in 1 2 3; do \ + abs_builddir="$(abs_top_builddir)/test/ca" "$(top_srcdir)/test/ca/issue.sh" sign test$$i gen/test$$i.crt gen/test$$i.key; \ + done + touch built.pki diff --git a/test/mycms-tool/sign/softhsm2.conf.in b/test/mycms-tool/sign/softhsm2.conf.in new file mode 100644 index 0000000..feab15b --- /dev/null +++ b/test/mycms-tool/sign/softhsm2.conf.in @@ -0,0 +1,2 @@ +directories.tokendir = @TOKENDIR@ +objectstore.backend = file diff --git a/test/mycms-tool/sign/test-file.sh b/test/mycms-tool/sign/test-file.sh new file mode 100755 index 0000000..1c76af5 --- /dev/null +++ b/test/mycms-tool/sign/test-file.sh @@ -0,0 +1,381 @@ +#!/bin/sh + +srcdir="${srcdir:-.}" +builddir="${builddir:-${srcdir}}" +MYCMS_TOOL="${MYCMS_TOOL:-mycms-tool}" +OPENSSL="${OPENSSL:-openssl}" +VALGRIND="${VALGRIND:-valgrind}" +LIBTOOL="${LIBTOOL:-libtool}" + +VALGRIND_CMD="${VALGRIND_CMD:-"${LIBTOOL}" --mode=execute ${VALGRIND}}" + +die() { + local m="$1" + echo "FATAL: ${m}" >&2 + exit 1 +} + +skip() { + local m="$1" + echo "SKIP: ${m}" >&2 + exit 77 +} + +MYTMP= +cleanup() { + rm -fr "${MYTMP}" +} +trap cleanup 0 + +doval() { + if [ "${MYCMS_DO_VALGRIND}" = 1 ]; then + ${VALGRIND_CMD} -q --leak-check=full --leak-resolution=high --show-leak-kinds=all --error-exitcode=99 "$@" + else + "$@" + fi +} + +get_keyid() { + local cert="$1" + + "${OPENSSL}" x509 -noout -in "$1" -inform DER -ext subjectKeyIdentifier | + sed -e '1d' -e 's/ //g' -e 's/://g' +} + +test_sanity() { + local PREFIX="${MYTMP}/sanity" + local CMS="${PREFIX}-cms" + local BADDATA="${PREFIX}-baddata" + local out + local test1_keyid + local test2_keyid + + cp "${DATA}" "${BADDATA}" + echo 1 >> "${BADDATA}" + + test1_keyid="$(get_keyid "${builddir}/gen/test1.crt")" || die "test1.keyid" + + echo "Signing by test1" + doval "${MYCMS_TOOL}" sign \ + --cms-out="${CMS}" \ + --data-in="${DATA}" \ + --signer-cert="file:cert=${builddir}/gen/test1.crt:key=${builddir}/gen/test1.key" \ + || die "sanity.sign.test1" + + echo "List signers test1" + out="$(doval "${MYCMS_TOOL}" --stdio-eol=lf verify-list \ + --cms-in="${CMS}" \ + )" || die "sanity.verify-list '${out}'" + + [ "$(echo "${out}" | wc -l)" = 1 ] || die "Incorrect number of keys '${out}'" + echo "${out}" | grep -iq "^${test1_keyid} SHA3-256$" || die "Keyid mismatch expected '${test1_keyid}' actual '${out}'" + + echo "Verify signature" + out="$(doval "${MYCMS_TOOL}" --stdio-eol=lf verify \ + --cms-in="${CMS}" \ + --data-in="${DATA}" \ + --cert="${builddir}/gen/test1.crt" \ + )" || die "sanity.verify.test1" + + [ "${out}" = "VERIFIED" ] || die "sanity.verify.result '${out}'" + + echo "Verify signature wrong signer" + out="$(doval "${MYCMS_TOOL}" --stdio-eol=lf verify \ + --cms-in="${CMS}" \ + --data-in="${DATA}" \ + --cert="${builddir}/gen/test2.crt" \ + )" || die "sanity.verify.wrong" + + [ "${out}" = "VERIFIED" ] && die "sanity.verify.wrong.result '${out}'" + + echo "Verify signature with bad data" + out="$(doval "${MYCMS_TOOL}" --stdio-eol=lf verify \ + --cms-in="${CMS}" \ + --data-in="${BADDATA}" \ + --cert="${builddir}/gen/test1.crt" \ + )" || die "sanity.verify.bad" + + [ "${out}" = "VERIFIED" ] && die "sanity.verify.bad.result '${out}'" + + return 0 +} + +test_two() { + local PREFIX="${MYTMP}/two" + local CMS="${PREFIX}-cms" + local CMS2="${PREFIX}-cms2" + local out + local test1_keyid + local test2_keyid + + test1_keyid="$(get_keyid "${builddir}/gen/test1.crt")" || die "test1.keyid" + test2_keyid="$(get_keyid "${builddir}/gen/test2.crt")" || die "test2.keyid" + + echo "Signing by test1" + doval "${MYCMS_TOOL}" sign \ + --cms-out="${CMS}" \ + --data-in="${DATA}" \ + --signer-cert="file:cert=${builddir}/gen/test1.crt:key=${builddir}/gen/test1.key" \ + || die "sanity.sign.test1" + + echo "Signing by test2" + doval "${MYCMS_TOOL}" sign \ + --cms-in="${CMS}" \ + --cms-out="${CMS2}" \ + --signer-cert="file:cert=${builddir}/gen/test2.crt:key=${builddir}/gen/test2.key" \ + || die "sanity.sign.test2" + + echo "List signers test2" + out="$(doval "${MYCMS_TOOL}" --stdio-eol=lf verify-list \ + --cms-in="${CMS2}" \ + )" || die "sanity.verify-list.test2 '${out}'" + + [ "$(echo "${out}" | wc -l)" = 2 ] || die "Incorrect number of keys '${out}'" + echo "${out}" | grep -iq "^${test1_keyid} SHA3-256$" || die "Keyid mismatch expected '${test1_keyid}' actual '${out}'" + echo "${out}" | grep -iq "^${test2_keyid} SHA3-256$" || die "Keyid mismatch expected '${test2_keyid}' actual '${out}'" + + echo "Verify signature" + out="$(doval "${MYCMS_TOOL}" --stdio-eol=lf verify \ + --cms-in="${CMS2}" \ + --data-in="${DATA}" \ + --cert="${builddir}/gen/test1.crt" \ + --cert="${builddir}/gen/test2.crt" \ + )" || die "sanity.verify.${x}" + + [ "${out}" = "VERIFIED" ] || die "sanity.verify2.result '${out}'" + + echo "Verify signature single signer" + out="$(doval "${MYCMS_TOOL}" --stdio-eol=lf verify \ + --cms-in="${CMS2}" \ + --data-in="${DATA}" \ + --cert="${builddir}/gen/test1.crt" \ + )" || die "sanity.verify.single" + + [ "${out}" = "VERIFIED" ] || die "sanity.verify.single.result '${out}'" + + echo "Verify signature wrong signer" + out="$(doval "${MYCMS_TOOL}" --stdio-eol=lf verify \ + --cms-in="${CMS2}" \ + --data-in="${DATA}" \ + --cert="${builddir}/gen/test3.crt" \ + )" || die "sanity.verify.wrong" + + [ "${out}" = "VERIFIED" ] && die "sanity.verify.wrong.result '${out}'" + + return 0 +} + +test_multi_digest() { + local PREFIX="${MYTMP}/sanity" + local CMS="${PREFIX}-cms" + local CMS2="${PREFIX}-cms2" + local CMS3="${PREFIX}-cms3" + local out + local expected + local digest + local test1_keyid + local test2_keyid + local test3_keyid + + test1_keyid="$(get_keyid "${builddir}/gen/test1.crt")" || die "test1.keyid" + test2_keyid="$(get_keyid "${builddir}/gen/test2.crt")" || die "test2.keyid" + test3_keyid="$(get_keyid "${builddir}/gen/test3.crt")" || die "test3.keyid" + + echo "Signing by test1" + doval "${MYCMS_TOOL}" sign \ + --cms-out="${CMS}" \ + --data-in="${DATA}" \ + --digest=sha3-256 \ + --digest=sha256 \ + --digest=sha1 \ + --signer-cert="file:cert=${builddir}/gen/test1.crt:key=${builddir}/gen/test1.key" \ + || die "sanity.sign.test1" + + echo "Signing by test2" + doval "${MYCMS_TOOL}" sign \ + --cms-in="${CMS}" \ + --cms-out="${CMS2}" \ + --digest=sha256 \ + --digest=sha1 \ + --signer-cert="file:cert=${builddir}/gen/test2.crt:key=${builddir}/gen/test2.key" \ + || die "sanity.sign.test2" + + echo "Signing by test3" + doval "${MYCMS_TOOL}" sign \ + --cms-in="${CMS2}" \ + --cms-out="${CMS3}" \ + --digest=sha3-256 \ + --signer-cert="file:cert=${builddir}/gen/test3.crt:key=${builddir}/gen/test3.key" \ + || die "sanity.sign.test3" + + echo "List signers test2" + out="$(doval "${MYCMS_TOOL}" --stdio-eol=lf verify-list \ + --cms-in="${CMS3}" \ + )" || die "sanity.verify-list.test2 '${out}'" + + [ "$(echo "${out}" | wc -l)" = 6 ] || die "Incorrect number of keys '${out}'" + expected="\ +${test1_keyid} SHA3-256 +${test1_keyid} SHA256 +${test2_keyid} SHA256 +${test1_keyid} SHA1 +${test2_keyid} SHA1 +${test3_keyid} SHA3-256" + [ "$(echo "${out}" | sort | tr [a-z] [A-Z])" = "$(echo "${expected}" | sort | tr [a-z] [A-Z])" ] || die "Incorrect output expected='${expected}' actual='${out}'" + + echo "Verify signature" + out="$(doval "${MYCMS_TOOL}" --stdio-eol=lf verify \ + --cms-in="${CMS3}" \ + --data-in="${DATA}" \ + --cert="${builddir}/gen/test1.crt" \ + --cert="${builddir}/gen/test2.crt" \ + )" || die "sanity.verify.sanity" + + [ "${out}" = "VERIFIED" ] || die "sanity.verify2.result '${out}'" + + for digest in sha1 sha256; do + for cert in test1 test2; do + echo "Verify signature with specific digest [${digest}/${cert}]" + out="$(doval "${MYCMS_TOOL}" --stdio-eol=lf verify \ + --cms-in="${CMS3}" \ + --data-in="${DATA}" \ + --digest="${digest}" \ + --cert="${builddir}/gen/${cert}.crt" \ + )" || die "sanity.verify.${digest}.${cert}" + + [ "${out}" = "VERIFIED" ] || die "sanity.verify3.result '${out}'" + done + done + + digest=sha3-256 + for cert in test1 test3; do + echo "Verify signature with specific digest [${digest}/${cert}]" + out="$(doval "${MYCMS_TOOL}" --stdio-eol=lf verify \ + --cms-in="${CMS3}" \ + --data-in="${DATA}" \ + --digest="${digest}" \ + --cert="${builddir}/gen/${cert}.crt" \ + )" || die "sanity.verify.${digest}.${cert}" + + [ "${out}" = "VERIFIED" ] || die "sanity.verify3.result '${out}'" + done + + for digest in sha1 sha256; do + echo "Should fail verify with unused digest" + out="$(doval "${MYCMS_TOOL}" --stdio-eol=lf verify \ + --cms-in="${CMS3}" \ + --data-in="${DATA}" \ + --digest="${digest}" \ + --cert="${builddir}/gen/test3.crt" \ + )" || die "sanity.verify.invalid.digest.${digest}" + + [ "${out}" = "VERIFIED" ] && die "sanity.verify.invalid.digest.digest.${digest} '${out}'" + done + + return 0 +} + +test_keyopt() { + local PREFIX="${MYTMP}/keyopt" + local CMS="${PREFIX}-cms" + local CMS2="${PREFIX}-cms2" + local out + local test1_keyid + local test2_keyid + + test1_keyid="$(get_keyid "${builddir}/gen/test1.crt")" || die "test1.keyid" + test2_keyid="$(get_keyid "${builddir}/gen/test2.crt")" || die "test2.keyid" + + while IFS=":" read padding padding_str; do + echo "Using ${padding}" + + echo "Signing by test1" + doval "${MYCMS_TOOL}" sign \ + --cms-out="${CMS}" \ + --data-in="${DATA}" \ + --signer-cert="file:cert=${builddir}/gen/test1.crt:key=${builddir}/gen/test1.key" \ + --keyopt="rsa_padding_mode=${padding}" \ + || die "keyopt.sign.test1" + + [ 1 -eq $("${OPENSSL}" asn1parse -in "${CMS}" -inform DER | grep "${padding_str}" | wc -l) ] || die "Expected '${padding_str}' for '${padding}'" + + echo "Verify signature" + out="$(doval "${MYCMS_TOOL}" --stdio-eol=lf verify \ + --cms-in="${CMS}" \ + --data-in="${DATA}" \ + --cert="${builddir}/gen/test1.crt" \ + )" || die "keyopt.verify.${x}" + + [ "${out}" = "VERIFIED" ] || die "keyopt.verify2.result '${out}'" + + done << __EOF__ +pkcs1:rsaEncryption +pss:rsassaPss +__EOF__ + + + # second signer does not add signature + # https://github.com/openssl/openssl/issues/14257 + echo "Checking if openssl bug resolved" + +( + while IFS=":" read padding padding_str; do + echo "Using ${padding}" + + echo "Signing by test1" + doval "${MYCMS_TOOL}" sign \ + --cms-out="${CMS}" \ + --data-in="${DATA}" \ + --signer-cert="file:cert=${builddir}/gen/test1.crt:key=${builddir}/gen/test1.key" \ + --keyopt="rsa_padding_mode=${padding}" \ + || die "keyopt.sign.test1" + + echo "Signing by test2" + doval "${MYCMS_TOOL}" sign \ + --cms-in="${CMS}" \ + --cms-out="${CMS2}" \ + --signer-cert="file:cert=${builddir}/gen/test2.crt:key=${builddir}/gen/test2.key" \ + --keyopt="rsa_padding_mode=${padding}" \ + || die "sanity.sign.test2" + + [ 2 -eq $("${OPENSSL}" asn1parse -in "${CMS2}" -inform DER | grep "${padding_str}" | wc -l) ] || die "Expected '${padding_str}' for '${padding}'" + + echo "Verify signature" + out="$(doval "${MYCMS_TOOL}" --stdio-eol=lf verify \ + --cms-in="${CMS2}" \ + --data-in="${DATA}" \ + --cert="${builddir}/gen/test1.crt" \ + --cert="${builddir}/gen/test2.crt" \ + )" || die "keyopt.verify2.${x}" + + [ "${out}" = "VERIFIED" ] || die "keyopt.verify2.result '${out}'" + + done << __EOF__ +pkcs1:rsaEncryption +pss:rsassaPss +__EOF__ + +) && echo "OPENSSL KEYOPT BUG RESOLVED!" || echo "OPENSSL KEYOPT BUG exists" + + return 0 +} + +[ -x "${MYCMS_TOOL}" ] || skip "no tool" +features="$("${MYCMS_TOOL}" --version | grep "Features")" || die "Cannot execute tool" +echo "${features}" | grep -q "sane" || die "tool is insane" +echo "${features}" | grep -q "sign" || skip "sign feature is not available" +echo "${features}" | grep -q "verify" || skip "verify feature is not available" +echo "${features}" | grep -q "certificate-driver-file" || skip "certificate-driver-file feature is not available" + +MYTMP="$(mktemp -d)" +DATA="${MYTMP}/data" +dd if=/dev/urandom bs=512 count=20 of="${DATA}" status=none || die "dd plain" + +TESTS="${TESTS:-test_sanity test_two test_multi_digest test_keyopt}" + +for test in $TESTS; do + echo "------------------------" + echo "${test}" + echo "------------------------" + "${test}" +done diff --git a/test/mycms-tool/sign/test-pkcs11.sh b/test/mycms-tool/sign/test-pkcs11.sh new file mode 100755 index 0000000..64f689f --- /dev/null +++ b/test/mycms-tool/sign/test-pkcs11.sh @@ -0,0 +1,189 @@ +#!/bin/sh + +srcdir="${srcdir:-.}" +builddir="${builddir:-${srcdir}}" +MYCMS_TOOL="${MYCMS_TOOL:-mycms-tool}" +SOFTHSM2_UTIL="${SOFTHSM2_UTIL:-softhsm2-util}" +PKCS11_TOOL="${PKCS11_TOOL:-pkcs11-tool}" +OPENSSL="${OPENSSL:-openssl}" +VALGRIND="${VALGRIND:-valgrind}" +LIBTOOL="${LIBTOOL:-libtool}" + +VALGRIND_CMD="${VALGRIND_CMD:-"${LIBTOOL}" --mode=execute ${VALGRIND}}" + +die() { + local m="$1" + echo "FATAL: ${m}" >&2 + exit 1 +} + +skip() { + local m="$1" + echo "SKIP: ${m}" >&2 + exit 77 +} + +MYTMP= +cleanup() { + rm -fr "${MYTMP}" +} +trap cleanup 0 + +doval() { + if [ "${MYCMS_DO_VALGRIND}" = 1 ]; then + ${VALGRIND_CMD} -q --leak-check=full --leak-resolution=high --show-leak-kinds=all --error-exitcode=99 --suppressions="${srcdir}/test-pkcs11.valgrind.supp" "$@" + else + "$@" + fi +} + +get_keyid() { + local cert="$1" + + "${OPENSSL}" x509 -noout -in "$1" -inform DER -ext subjectKeyIdentifier | + sed -e '1d' -e 's/ //g' -e 's/://g' +} + +prepare_token() { + "${SOFTHSM2_UTIL}" --init-token --free --label token1 --so-pin sosecret --pin secret || die "init-token" + for o in 1 2 3; do +if [ -n "${__MYCMS_USE_CERTUTIL}" ]; then + local k="${MYTMP}/k" + local c="${MYTMP}/c" + openssl pkcs8 -topk8 -inform DER -in "${builddir}/gen/test${o}.key" -out "${k}" -nocrypt || die "openssl.p8" + openssl x509 -inform DER -in "${builddir}/gen/test${o}.crt" -out "${c}" || die "openssl.crt" + "${SOFTHSM2_UTIL}" \ + --import "${MYTMP}/k" \ + --import-type=keypair \ + --token token1 \ + --id $(printf "%02x" ${o}) \ + --label test${o} \ + --pin secret \ + || die "softhsm.import.key.${o}" + "${SOFTHSM2_UTIL}" \ + --import "${MYTMP}/c" \ + --import-type=cert \ + --token token1 \ + --id $(printf "%02x" ${o}) \ + --label test${o} \ + --pin secret \ + || die "softhsm.import.cert.${o}" +else + "${PKCS11_TOOL}" \ + --module "${SOFTHSM2_MODULE}" \ + --token-label token1 \ + --login \ + --pin secret \ + --private \ + --id ${o} \ + --label test${o} \ + --type privkey \ + --usage-sign \ + --write-object "${builddir}/gen/test${o}.key" \ + || die "pkcs11-tool.key.${o}" + "${PKCS11_TOOL}" \ + --module "${SOFTHSM2_MODULE}" \ + --token-label token1 \ + --login \ + --pin secret \ + --id ${o} \ + --label test${o} \ + --type cert \ + --write-object "${builddir}/gen/test${o}.crt" \ + || die "pkcs11-tool.crt.${o}" +fi + done +} + +test_sanity() { + local PREFIX="${MYTMP}/sanity" + local CMS="${PREFIX}-cms" + local BADDATA="${PREFIX}-baddata" + local out + local test1_keyid + local test2_keyid + + cp "${DATA}" "${BADDATA}" + echo 1 >> "${BADDATA}" + + test1_keyid="$(get_keyid "${builddir}/gen/test1.crt")" || die "test1.keyid" + + echo "Signing by test1" + doval "${MYCMS_TOOL}" sign \ + --cms-out="${CMS}" \ + --data-in="${DATA}" \ + --signer-cert="pkcs11:module=${SOFTHSM2_MODULE}:token-label=token1:cert-label=test1" \ + --signer-cert-pass="token=pass=secret" \ + || die "sanity.sign.test1" + + echo "List signers test1" + out="$(doval "${MYCMS_TOOL}" verify-list \ + --cms-in="${CMS}" \ + )" || die "sanity.verify-list '${out}'" + + keyid="$(get_keyid "${builddir}/gen/test1.crt")" || die "test1.keyid" + + [ "$(echo "${out}" | wc -l)" = 1 ] || die "Too many keys '${out}'" + echo "${out}" | grep -iq "^${test1_keyid} SHA3-256$" || die "Keyid mismatch expected '${test1_keyid}' actual '${out}'" + + echo "Verify signature" + out="$(doval "${MYCMS_TOOL}" verify \ + --cms-in="${CMS}" \ + --data-in="${DATA}" \ + --cert="${builddir}/gen/test1.crt" \ + )" || die "sanity.verify.test1" + + [ "${out}" = "VERIFIED" ] || die "sanity.verify.result '${out}'" + + echo "Verify signature wrong signer" + out="$(doval "${MYCMS_TOOL}" verify \ + --cms-in="${CMS}" \ + --data-in="${DATA}" \ + --cert="${builddir}/gen/test2.crt" \ + )" || die "sanity.verify.wrong" + + [ "${out}" = "VERIFIED" ] && die "sanity.verify.wrong.result '${out}'" + + echo "Verify signature with bad data" + out="$(doval "${MYCMS_TOOL}" verify \ + --cms-in="${CMS}" \ + --data-in="${BADDATA}" \ + --cert="${builddir}/gen/test1.crt" \ + )" || die "sanity.verify.bad" + + [ "${out}" = "VERIFIED" ] && die "sanity.verify.bad.result '${out}'" + + return 0 +} + +[ -x "${MYCMS_TOOL}" ] || skip "no tool" +features="$("${MYCMS_TOOL}" --version | grep "Features")" || die "Cannot execute tool" +echo "${features}" | grep -q "sane" || die "tool is insane" +echo "${features}" | grep -q "sign" || skip "sign feature is not available" +echo "${features}" | grep -q "verify" || skip "verify feature is not available" +echo "${features}" | grep -q "certificate-driver-pkcs11" || skip "certificate-driver-pkcs11 feature is not available" + +"${SOFTHSM2_UTIL}" --version > /dev/null || skip "softhsm2-util not found" +"${PKCS11_TOOL}" --version 2>&1 | grep -q "Usage:" || skip "pkcs11-tool not found" + +[ -z "${SOFTHSM2_MODULE}" ] && die "Cannot find softhsm module" + +MYTMP="$(mktemp -d)" +DATA="${MYTMP}/data" +dd if=/dev/urandom bs=512 count=20 of="${DATA}" status=none || die "dd plain" + +tokendir="${MYTMP}/token" +mkdir -p "${tokendir}" +sed "s#@TOKENDIR@#${tokendir}#" "${srcdir}/softhsm2.conf.in" > "${MYTMP}/softhsm2.conf" +export SOFTHSM2_CONF="${MYTMP}/softhsm2.conf" + +prepare_token + +TESTS="${TESTS:-test_sanity}" + +for test in $TESTS; do + echo "------------------------" + echo "${test}" + echo "------------------------" + "${test}" +done diff --git a/test/mycms-tool/sign/test-pkcs11.valgrind.supp b/test/mycms-tool/sign/test-pkcs11.valgrind.supp new file mode 100644 index 0000000..52545b4 --- /dev/null +++ b/test/mycms-tool/sign/test-pkcs11.valgrind.supp @@ -0,0 +1,29 @@ +{ + C_Initialize + Memcheck:Leak + match-leak-kinds: definite + ... + obj:/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so + fun:C_Initialize +} +{ + _dl_catch_exception + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:_dl_catch_exception +} +{ + dlopen + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:dlopen@@* +} +{ + _dlerror_run + Memcheck:Leak + match-leak-kinds: reachable + ... + fun:_dlerror_run +} diff --git a/test/mycms-tool/windows/Makefile.am b/test/mycms-tool/windows/Makefile.am new file mode 100644 index 0000000..e0220e1 --- /dev/null +++ b/test/mycms-tool/windows/Makefile.am @@ -0,0 +1,24 @@ +MAINTAINERCLEANFILES = \ + $(srcdir)/Makefile.in \ + $(NULL) + +CLEANFILES = \ + built.pki \ + $(NULL) + +clean-local: + rm -fr gen + +check-am: built.pki + +dist_noinst_DATA = \ + test-file.bat \ + $(NULL) + +built.pki: Makefile + rm -fr gen + mkdir gen + for i in 1; do \ + abs_builddir="$(abs_top_builddir)/test/ca" "$(top_srcdir)/test/ca/issue.sh" sign test$$i gen/test$$i.crt gen/test$$i.key; \ + done + touch built.pki diff --git a/test/mycms-tool/windows/test-file.bat b/test/mycms-tool/windows/test-file.bat new file mode 100644 index 0000000..0efe31b --- /dev/null +++ b/test/mycms-tool/windows/test-file.bat @@ -0,0 +1,12 @@ +@echo off +echo sign +mycms-tool sign --cms-out=cms1 --data-in=mycms-tool.exe --signer-cert="file:cert=gen\\test1.crt:key=gen\\test1.key" +if errorlevel 1 goto error +echo verify +mycms-tool verify --cms-in=cms1 --data-in=mycms-tool.exe --cert="gen\\test1.crt" +if errorlevel 1 goto error +echo success +goto end +:error +echo ERROR +:end diff --git a/wsl-fixup-libtool-argv0.patch b/wsl-fixup-libtool-argv0.patch new file mode 100644 index 0000000..e9b01b9 --- /dev/null +++ b/wsl-fixup-libtool-argv0.patch @@ -0,0 +1,31 @@ +[PATCH] wsl2 interop overrides argv[0] + +https://github.com/microsoft/WSL/issues/8162 + +--- + +--- ltmain.sh.org 2022-04-01 02:00:42.719606700 +0300 ++++ ltmain.sh 2022-04-01 02:01:33.139606700 +0300 +@@ -5620,6 +5620,9 @@ EOF + #ifdef _MSC_VER + # define _CRT_SECURE_NO_DEPRECATE 1 + #endif ++#ifdef _WIN32 ++#include ++#endif + #include + #include + #ifdef _MSC_VER +@@ -5831,6 +5834,12 @@ main (int argc, char *argv[]) + + int i; + ++#ifdef _WIN32 ++ char modulepath[1024]; ++ GetModuleFileNameA(GetModuleHandleA(NULL), modulepath, sizeof(modulepath)); ++ argv[0] = modulepath; ++#endif ++ + program_name = (char *) xstrdup (base_name (argv[0])); + newargz = XMALLOC (char *, (size_t) argc + 1); + diff --git a/wsl-fixup-wsl1-skip-env.patch b/wsl-fixup-wsl1-skip-env.patch new file mode 100644 index 0000000..c9ffa66 --- /dev/null +++ b/wsl-fixup-wsl1-skip-env.patch @@ -0,0 +1,18 @@ +[PATCH] Do not modify environment + +WSL1 has issues when setting the path to fully qualified POSIX paths. +It ignores the other components for some reason. + +--- + +--- ltmain.sh.org 2022-04-01 02:00:42.719606700 +0300 ++++ ltmain.sh 2022-04-01 20:15:05.183466800 +0300 +@@ -6324,6 +6333,8 @@ nonempty (const char *s) + void + lt_setenv (const char *name, const char *value) + { ++ if (getenv("LT_SKIP_ENV") != NULL) ++ return; + lt_debugprintf (__FILE__, __LINE__, + "(lt_setenv) setting '%s' to '%s'\n", + nonnull (name), nonnull (value));